rndctl.c revision 1.12 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