1 /* $NetBSD: rndctl.c,v 1.16 2003/07/13 07:59:24 itojun 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.16 2003/07/13 07:59:24 itojun 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 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 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 [-t devtype] [-d devname]\n", 78 getprogname()); 79 fprintf(stderr, " %s -ls [-t devtype] [-d devname]\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 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 u_int32_t start; 167 168 fd = open("/dev/urandom", O_RDONLY, 0644); 169 if (fd < 0) 170 err(1, "open"); 171 172 if (all == 0 && type == 0xff) { 173 strncpy(rstat_name.name, name, sizeof(rstat_name.name)); 174 res = ioctl(fd, RNDGETSRCNAME, &rstat_name); 175 if (res < 0) 176 err(1, "ioctl(RNDGETSRCNAME)"); 177 printf(HEADER); 178 printf("%-16s %10u %-4s %s\n", 179 rstat_name.source.name, 180 rstat_name.source.total, 181 find_name(rstat_name.source.type), 182 strflags(rstat_name.source.flags)); 183 close(fd); 184 return; 185 } 186 187 /* 188 * Run through all the devices present in the system, and either 189 * print out ones that match, or print out all of them. 190 */ 191 printf(HEADER); 192 start = 0; 193 for (;;) { 194 rstat.count = RND_MAXSTATCOUNT; 195 rstat.start = start; 196 res = ioctl(fd, RNDGETSRCNUM, &rstat); 197 if (res < 0) 198 err(1, "ioctl(RNDGETSRCNUM)"); 199 200 if (rstat.count == 0) 201 break; 202 203 for (res = 0; res < rstat.count; res++) { 204 if (all != 0 || 205 type == rstat.source[res].type) 206 printf("%-16s %10u %-4s %s\n", 207 rstat.source[res].name, 208 rstat.source[res].total, 209 find_name(rstat.source[res].type), 210 strflags(rstat.source[res].flags)); 211 } 212 start += rstat.count; 213 } 214 215 close(fd); 216 } 217 218 void 219 do_stats() 220 { 221 rndpoolstat_t rs; 222 int fd; 223 224 fd = open("/dev/urandom", O_RDONLY, 0644); 225 if (fd < 0) 226 err(1, "open"); 227 228 if (ioctl(fd, RNDGETPOOLSTAT, &rs) < 0) 229 err(1, "ioctl(RNDGETPOOLSTAT)"); 230 231 printf("\t%9u bits mixed into pool\n", rs.added); 232 printf("\t%9u bits currently stored in pool (max %u)\n", 233 rs.curentropy, rs.maxentropy); 234 printf("\t%9u bits of entropy discarded due to full pool\n", 235 rs.discarded); 236 printf("\t%9u hard-random bits generated\n", rs.removed); 237 printf("\t%9u pseudo-random bits generated\n", rs.generated); 238 239 close(fd); 240 } 241 242 int 243 main(int argc, char **argv) 244 { 245 rndctl_t rctl; 246 int ch, cmd, lflag, mflag, sflag; 247 u_int32_t type; 248 char name[16]; 249 250 rctl.mask = 0; 251 rctl.flags = 0; 252 253 cmd = 0; 254 lflag = 0; 255 mflag = 0; 256 sflag = 0; 257 type = 0xff; 258 259 while ((ch = getopt(argc, argv, "CEcelt:d:s")) != -1) 260 switch (ch) { 261 case 'C': 262 rctl.flags |= RND_FLAG_NO_COLLECT; 263 rctl.mask |= RND_FLAG_NO_COLLECT; 264 mflag++; 265 break; 266 case 'E': 267 rctl.flags |= RND_FLAG_NO_ESTIMATE; 268 rctl.mask |= RND_FLAG_NO_ESTIMATE; 269 mflag++; 270 break; 271 case 'c': 272 rctl.flags &= ~RND_FLAG_NO_COLLECT; 273 rctl.mask |= RND_FLAG_NO_COLLECT; 274 mflag++; 275 break; 276 case 'e': 277 rctl.flags &= ~RND_FLAG_NO_ESTIMATE; 278 rctl.mask |= RND_FLAG_NO_ESTIMATE; 279 mflag++; 280 break; 281 case 'l': 282 lflag++; 283 break; 284 case 't': 285 if (cmd != 0) 286 usage(); 287 cmd = 't'; 288 289 type = find_type(optarg); 290 break; 291 case 'd': 292 if (cmd != 0) 293 usage(); 294 cmd = 'd'; 295 296 type = 0xff; 297 strlcpy(name, optarg, sizeof(name)); 298 break; 299 case 's': 300 sflag++; 301 break; 302 case '?': 303 default: 304 usage(); 305 } 306 307 /* 308 * Cannot list and modify at the same time. 309 */ 310 if ((lflag != 0 || sflag != 0) && mflag != 0) 311 usage(); 312 313 /* 314 * Bomb out on no-ops. 315 */ 316 if (lflag == 0 && mflag == 0 && sflag == 0) 317 usage(); 318 319 /* 320 * If not listing, we need a device name or a type. 321 */ 322 if (lflag == 0 && cmd == 0 && sflag == 0) 323 usage(); 324 325 /* 326 * Modify request. 327 */ 328 if (mflag != 0) { 329 rctl.type = type; 330 strncpy(rctl.name, name, sizeof(rctl.name)); 331 do_ioctl(&rctl); 332 333 exit(0); 334 } 335 336 /* 337 * List sources. 338 */ 339 if (lflag != 0) 340 do_list(cmd == 0, type, name); 341 342 if (sflag != 0) 343 do_stats(); 344 345 exit(0); 346 } 347