1 /* $NetBSD: rndctl.c,v 1.19 2009/04/05 12:06:33 lukem 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 #include <sys/cdefs.h> 32 33 #ifndef lint 34 __RCSID("$NetBSD: rndctl.c,v 1.19 2009/04/05 12:06:33 lukem Exp $"); 35 #endif 36 37 38 #include <sys/types.h> 39 #include <sys/ioctl.h> 40 #include <sys/rnd.h> 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 #include <fcntl.h> 46 #include <errno.h> 47 #include <err.h> 48 #include <string.h> 49 50 typedef struct { 51 const char *a_name; 52 u_int32_t a_type; 53 } arg_t; 54 55 arg_t source_types[] = { 56 { "???", RND_TYPE_UNKNOWN }, 57 { "disk", RND_TYPE_DISK }, 58 { "net", RND_TYPE_NET }, 59 { "tape", RND_TYPE_TAPE }, 60 { "tty", RND_TYPE_TTY }, 61 { "rng", RND_TYPE_RNG }, 62 { NULL, 0 } 63 }; 64 65 static void usage(void); 66 u_int32_t find_type(char *name); 67 const char *find_name(u_int32_t); 68 void do_ioctl(rndctl_t *); 69 char * strflags(u_int32_t); 70 void do_list(int, u_int32_t, char *); 71 void do_stats(void); 72 73 static void 74 usage(void) 75 { 76 77 fprintf(stderr, "usage: %s -CEce [-d devname | -t devtype]\n", 78 getprogname()); 79 fprintf(stderr, " %s -ls [-d devname | -t devtype]\n", 80 getprogname()); 81 exit(1); 82 } 83 84 u_int32_t 85 find_type(char *name) 86 { 87 arg_t *a; 88 89 a = source_types; 90 91 while (a->a_name != NULL) { 92 if (strcmp(a->a_name, name) == 0) 93 return (a->a_type); 94 a++; 95 } 96 97 errx(1, "device name %s unknown", name); 98 return (0); 99 } 100 101 const char * 102 find_name(u_int32_t type) 103 { 104 arg_t *a; 105 106 a = source_types; 107 108 while (a->a_name != NULL) { 109 if (type == a->a_type) 110 return (a->a_name); 111 a++; 112 } 113 114 warnx("device type %u unknown", type); 115 return ("???"); 116 } 117 118 void 119 do_ioctl(rndctl_t *rctl) 120 { 121 int fd; 122 int res; 123 124 fd = open("/dev/urandom", O_RDONLY, 0644); 125 if (fd < 0) 126 err(1, "open"); 127 128 res = ioctl(fd, RNDCTL, rctl); 129 if (res < 0) 130 err(1, "ioctl(RNDCTL)"); 131 132 close(fd); 133 } 134 135 char * 136 strflags(u_int32_t fl) 137 { 138 static char str[512]; 139 140 str[0] = 0; 141 if (fl & RND_FLAG_NO_ESTIMATE) 142 ; 143 else 144 strlcat(str, "estimate", sizeof(str)); 145 146 if (fl & RND_FLAG_NO_COLLECT) 147 ; 148 else { 149 if (str[0]) 150 strlcat(str, ", ", sizeof(str)); 151 strlcat(str, "collect", sizeof(str)); 152 } 153 154 return (str); 155 } 156 157 #define HEADER "Source Bits Type Flags\n" 158 159 void 160 do_list(int all, u_int32_t type, char *name) 161 { 162 rndstat_t rstat; 163 rndstat_name_t rstat_name; 164 int fd; 165 int res; 166 uint32_t i; 167 u_int32_t start; 168 169 fd = open("/dev/urandom", O_RDONLY, 0644); 170 if (fd < 0) 171 err(1, "open"); 172 173 if (all == 0 && type == 0xff) { 174 strncpy(rstat_name.name, name, sizeof(rstat_name.name)); 175 res = ioctl(fd, RNDGETSRCNAME, &rstat_name); 176 if (res < 0) 177 err(1, "ioctl(RNDGETSRCNAME)"); 178 printf(HEADER); 179 printf("%-16s %10u %-4s %s\n", 180 rstat_name.source.name, 181 rstat_name.source.total, 182 find_name(rstat_name.source.type), 183 strflags(rstat_name.source.flags)); 184 close(fd); 185 return; 186 } 187 188 /* 189 * Run through all the devices present in the system, and either 190 * print out ones that match, or print out all of them. 191 */ 192 printf(HEADER); 193 start = 0; 194 for (;;) { 195 rstat.count = RND_MAXSTATCOUNT; 196 rstat.start = start; 197 res = ioctl(fd, RNDGETSRCNUM, &rstat); 198 if (res < 0) 199 err(1, "ioctl(RNDGETSRCNUM)"); 200 201 if (rstat.count == 0) 202 break; 203 204 for (i = 0; i < rstat.count; i++) { 205 if (all != 0 || 206 type == rstat.source[i].type) 207 printf("%-16s %10u %-4s %s\n", 208 rstat.source[i].name, 209 rstat.source[i].total, 210 find_name(rstat.source[i].type), 211 strflags(rstat.source[i].flags)); 212 } 213 start += rstat.count; 214 } 215 216 close(fd); 217 } 218 219 void 220 do_stats() 221 { 222 rndpoolstat_t rs; 223 int fd; 224 225 fd = open("/dev/urandom", O_RDONLY, 0644); 226 if (fd < 0) 227 err(1, "open"); 228 229 if (ioctl(fd, RNDGETPOOLSTAT, &rs) < 0) 230 err(1, "ioctl(RNDGETPOOLSTAT)"); 231 232 printf("\t%9u bits mixed into pool\n", rs.added); 233 printf("\t%9u bits currently stored in pool (max %u)\n", 234 rs.curentropy, rs.maxentropy); 235 printf("\t%9u bits of entropy discarded due to full pool\n", 236 rs.discarded); 237 printf("\t%9u hard-random bits generated\n", rs.removed); 238 printf("\t%9u pseudo-random bits generated\n", rs.generated); 239 240 close(fd); 241 } 242 243 int 244 main(int argc, char **argv) 245 { 246 rndctl_t rctl; 247 int ch, cmd, lflag, mflag, sflag; 248 u_int32_t type; 249 char name[16]; 250 251 rctl.mask = 0; 252 rctl.flags = 0; 253 254 cmd = 0; 255 lflag = 0; 256 mflag = 0; 257 sflag = 0; 258 type = 0xff; 259 260 while ((ch = getopt(argc, argv, "CEcelt:d:s")) != -1) { 261 switch (ch) { 262 case 'C': 263 rctl.flags |= RND_FLAG_NO_COLLECT; 264 rctl.mask |= RND_FLAG_NO_COLLECT; 265 mflag++; 266 break; 267 case 'E': 268 rctl.flags |= RND_FLAG_NO_ESTIMATE; 269 rctl.mask |= RND_FLAG_NO_ESTIMATE; 270 mflag++; 271 break; 272 case 'c': 273 rctl.flags &= ~RND_FLAG_NO_COLLECT; 274 rctl.mask |= RND_FLAG_NO_COLLECT; 275 mflag++; 276 break; 277 case 'e': 278 rctl.flags &= ~RND_FLAG_NO_ESTIMATE; 279 rctl.mask |= RND_FLAG_NO_ESTIMATE; 280 mflag++; 281 break; 282 case 'l': 283 lflag++; 284 break; 285 case 't': 286 if (cmd != 0) 287 usage(); 288 cmd = 't'; 289 290 type = find_type(optarg); 291 break; 292 case 'd': 293 if (cmd != 0) 294 usage(); 295 cmd = 'd'; 296 297 type = 0xff; 298 strlcpy(name, optarg, sizeof(name)); 299 break; 300 case 's': 301 sflag++; 302 break; 303 case '?': 304 default: 305 usage(); 306 } 307 } 308 argc -= optind; 309 argv += optind; 310 311 /* 312 * No leftover non-option arguments. 313 */ 314 if (argc > 0) 315 usage(); 316 317 /* 318 * Cannot list and modify at the same time. 319 */ 320 if ((lflag != 0 || sflag != 0) && mflag != 0) 321 usage(); 322 323 /* 324 * Bomb out on no-ops. 325 */ 326 if (lflag == 0 && mflag == 0 && sflag == 0) 327 usage(); 328 329 /* 330 * If not listing, we need a device name or a type. 331 */ 332 if (lflag == 0 && cmd == 0 && sflag == 0) 333 usage(); 334 335 /* 336 * Modify request. 337 */ 338 if (mflag != 0) { 339 rctl.type = type; 340 strncpy(rctl.name, name, sizeof(rctl.name)); 341 do_ioctl(&rctl); 342 343 exit(0); 344 } 345 346 /* 347 * List sources. 348 */ 349 if (lflag != 0) 350 do_list(cmd == 0, type, name); 351 352 if (sflag != 0) 353 do_stats(); 354 355 exit(0); 356 } 357