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