1 /*- 2 * Copyright (c) 1997 Michael Graff. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of other contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <fcntl.h> 34 #include <errno.h> 35 #include <err.h> 36 #include <string.h> 37 38 #include <sys/types.h> 39 #include <sys/ioctl.h> 40 #include <sys/rnd.h> 41 42 typedef struct { 43 char *name; 44 u_int32_t type; 45 } arg_t; 46 47 arg_t source_types[] = { 48 { "unknown", RND_TYPE_UNKNOWN }, 49 { "disk", RND_TYPE_DISK }, 50 { "network", RND_TYPE_NET }, 51 { "net", RND_TYPE_NET }, 52 { "tape", RND_TYPE_TAPE }, 53 { "tty", RND_TYPE_TTY }, 54 { NULL, 0 } 55 }; 56 57 static void usage(void); 58 u_int32_t find_type(char *name); 59 char *find_name(u_int32_t); 60 void do_ioctl(rndctl_t *); 61 char * strflags(u_int32_t); 62 void do_list(int, u_int32_t, char *); 63 64 static void 65 usage(void) 66 { 67 errx(1, "Usage: rndctl [-CEce | -l] [-d name | -t type]"); 68 } 69 70 u_int32_t 71 find_type(char *name) 72 { 73 arg_t *a; 74 75 a = source_types; 76 77 while (a->name != NULL) { 78 if (strcmp(a->name, name) == 0) 79 return a->type; 80 a++; 81 } 82 83 errx(1, "Error: Device type %s unknown", name); 84 return 0; 85 } 86 87 char * 88 find_name(u_int32_t type) 89 { 90 arg_t *a; 91 92 a = source_types; 93 94 while (a->name != NULL) { 95 if (type == a->type) 96 return a->name; 97 a++; 98 } 99 100 errx(1, "Error: Device type %u unknown", type); 101 return 0; 102 } 103 104 void 105 do_ioctl(rndctl_t *rctl) 106 { 107 int fd; 108 int res; 109 110 fd = open("/dev/urandom", O_RDONLY, 0644); 111 if (fd < 0) 112 err(1, "open"); 113 114 res = ioctl(fd, RNDCTL, rctl); 115 if (res < 0) 116 err(1, "ioctl(RNDCTL)"); 117 118 close(fd); 119 } 120 121 char * 122 strflags(u_int32_t fl) 123 { 124 static char str[512]; 125 126 str[0] = 0; 127 strcat(str, "<"); 128 129 if (fl & RND_FLAG_NO_ESTIMATE) 130 strcat(str, "no"); 131 strcat(str, "estimate, "); 132 if (fl & RND_FLAG_NO_COLLECT) 133 strcat(str, "no"); 134 strcat(str, "collect>"); 135 136 return str; 137 } 138 139 #define HEADER "Device Name Type Bits Flags\n" \ 140 "---------------- -------- ---------- -----\n" 141 142 void 143 do_list(int all, u_int32_t type, char *name) 144 { 145 rndstat_t rstat; 146 rndstat_name_t rstat_name; 147 int fd; 148 int res; 149 u_int32_t start; 150 151 fd = open("/dev/urandom", O_RDONLY, 0644); 152 if (fd < 0) 153 err(1, "open"); 154 155 if (all == 0 && type == 0xff) { 156 strncpy(rstat_name.name, name, 16); 157 res = ioctl(fd, RNDGETSRCNAME, &rstat_name); 158 if (res < 0) 159 err(1, "ioctl(RNDGETSRCNAME)"); 160 printf(HEADER); 161 printf("%-16s %-8s %10u %s\n", 162 rstat_name.source.name, 163 find_name(rstat_name.source.tyfl & 0xff), 164 rstat_name.source.total, 165 strflags(rstat_name.source.tyfl)); 166 close(fd); 167 return; 168 } 169 170 /* 171 * run through all the devices present in the system, and either 172 * print out ones that match, or print out all of them. 173 */ 174 printf(HEADER); 175 start = 0; 176 for (;;) { 177 rstat.count = RND_MAXSTATCOUNT; 178 rstat.start = start; 179 res = ioctl(fd, RNDGETSRCNUM, &rstat); 180 if (res < 0) 181 err(1, "ioctl(RNDGETSRCNUM)"); 182 183 if (rstat.count == 0) 184 break; 185 186 for (res = 0 ; res < rstat.count ; res++) { 187 if ((all != 0) 188 || (type == (rstat.source[res].tyfl & 0xff))) 189 printf("%-16s %-8s %10u %s\n", 190 rstat.source[res].name, 191 find_name(rstat.source[res].tyfl & 0xff), 192 rstat.source[res].total, 193 strflags(rstat.source[res].tyfl)); 194 } 195 start += rstat.count; 196 } 197 198 close(fd); 199 } 200 201 int 202 main(int argc, char **argv) 203 { 204 rndctl_t rctl; 205 int ch; 206 int cmd; 207 int lflag; 208 int mflag; 209 u_int32_t type; 210 char name[16]; 211 212 rctl.mask = 0; 213 rctl.flags = 0; 214 215 cmd = 0; 216 lflag = 0; 217 mflag = 0; 218 type = 0xff; 219 220 while ((ch = getopt(argc, argv, "CEcelt:d:")) != -1) 221 switch(ch) { 222 case 'C': 223 rctl.flags |= RND_FLAG_NO_COLLECT; 224 rctl.mask |= RND_FLAG_NO_COLLECT; 225 mflag++; 226 break; 227 case 'E': 228 rctl.flags |= RND_FLAG_NO_ESTIMATE; 229 rctl.mask |= RND_FLAG_NO_ESTIMATE; 230 mflag++; 231 break; 232 case 'c': 233 rctl.flags &= ~RND_FLAG_NO_COLLECT; 234 rctl.mask |= RND_FLAG_NO_COLLECT; 235 mflag++; 236 break; 237 case 'e': 238 rctl.flags &= ~RND_FLAG_NO_ESTIMATE; 239 rctl.mask |= RND_FLAG_NO_ESTIMATE; 240 mflag++; 241 break; 242 case 'l': 243 lflag++; 244 break; 245 case 't': 246 if (cmd != 0) 247 usage(); 248 cmd = 't'; 249 250 type = find_type(optarg); 251 break; 252 case 'd': 253 if (cmd != 0) 254 usage(); 255 cmd = 'd'; 256 257 type = 0xff; 258 strncpy(name, optarg, 16); 259 break; 260 case '?': 261 default: 262 usage(); 263 } 264 265 /* 266 * cannot list and modify at the same time 267 */ 268 if (lflag != 0 && mflag != 0) 269 usage(); 270 271 /* 272 * bomb out on no-ops 273 */ 274 if (lflag == 0 && mflag == 0) 275 usage(); 276 277 /* 278 * if not listing, we need a device name or a type 279 */ 280 if (lflag == 0 && cmd == 0) 281 usage(); 282 283 /* 284 * modify request 285 */ 286 if (mflag != 0) { 287 rctl.type = type; 288 strncpy(rctl.name, name, 16); 289 do_ioctl(&rctl); 290 291 exit(0); 292 } 293 294 /* 295 * list sources 296 */ 297 if (lflag != 0) 298 do_list(cmd == 0, type, name); 299 300 return 0; 301 } 302