xref: /netbsd-src/sbin/rndctl/rndctl.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: rndctl.c,v 1.8 2000/08/28 13:27:37 joda 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 -ls [-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 	sflag = 0;
253 	type = 0xff;
254 
255 	while ((ch = getopt(argc, argv, "CEcelt:d:s")) != -1)
256 		switch(ch) {
257 		case 'C':
258 			rctl.flags |= RND_FLAG_NO_COLLECT;
259 			rctl.mask |= RND_FLAG_NO_COLLECT;
260 			mflag++;
261 			break;
262 		case 'E':
263 			rctl.flags |= RND_FLAG_NO_ESTIMATE;
264 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
265 			mflag++;
266 			break;
267 		case 'c':
268 			rctl.flags &= ~RND_FLAG_NO_COLLECT;
269 			rctl.mask |= RND_FLAG_NO_COLLECT;
270 			mflag++;
271 			break;
272 		case 'e':
273 			rctl.flags &= ~RND_FLAG_NO_ESTIMATE;
274 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
275 			mflag++;
276 			break;
277 		case 'l':
278 			lflag++;
279 			break;
280 		case 't':
281 			if (cmd != 0)
282 				usage();
283 			cmd = 't';
284 
285 			type = find_type(optarg);
286 			break;
287 		case 'd':
288 			if (cmd != 0)
289 				usage();
290 			cmd = 'd';
291 
292 			type = 0xff;
293 			strncpy(name, optarg, 16);
294 			break;
295 		case 's':
296 			sflag++;
297 			break;
298 		case '?':
299 		default:
300 			usage();
301 		}
302 
303 	/*
304 	 * cannot list and modify at the same time
305 	 */
306 	if ((lflag != 0 || sflag != 0) && mflag != 0)
307 		usage();
308 
309 	/*
310 	 * bomb out on no-ops
311 	 */
312 	if (lflag == 0 && mflag == 0 && sflag == 0)
313 		usage();
314 
315 	/*
316 	 * if not listing, we need a device name or a type
317 	 */
318 	if (lflag == 0 && cmd == 0 && sflag == 0)
319 		usage();
320 
321 	/*
322 	 * modify request
323 	 */
324 	if (mflag != 0) {
325 		rctl.type = type;
326 		strncpy(rctl.name, name, 16);
327 		do_ioctl(&rctl);
328 
329 		exit(0);
330 	}
331 
332 	/*
333 	 * list sources
334 	 */
335 	if (lflag != 0)
336 		do_list(cmd == 0, type, name);
337 
338 	if (sflag != 0)
339 		do_stats();
340 
341 	return 0;
342 }
343