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