rndctl.c revision 1.6 1 /* $NetBSD: rndctl.c,v 1.6 2000/06/20 02:40:10 sommerfeld 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 -l [-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 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 return 0;
341 }
342