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