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