xref: /netbsd-src/sbin/rndctl/rndctl.c (revision 4472dbe5e3bd91ef2540bada7a7ca7384627ff9b)
1 /*	$NetBSD: rndctl.c,v 1.5 1999/03/30 17:32:44 mycroft 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 	{ "unknown", RND_TYPE_UNKNOWN },
51 	{ "disk",    RND_TYPE_DISK },
52 	{ "network", 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 
66 static void
67 usage(void)
68 {
69 	fprintf(stderr, "usage: rndctl -CEce [-t devtype] [-d devname]\n");
70 	fprintf(stderr, "       rndctl -l [-t devtype] [-d devname]\n");
71 	exit(1);
72 }
73 
74 u_int32_t
75 find_type(char *name)
76 {
77 	arg_t *a;
78 
79 	a = source_types;
80 
81 	while (a->name != NULL) {
82 		if (strcmp(a->name, name) == 0)
83 			return a->type;
84 		a++;
85 	}
86 
87 	errx(1, "Error:  Device type %s unknown", name);
88 	return 0;
89 }
90 
91 char *
92 find_name(u_int32_t type)
93 {
94 	arg_t *a;
95 
96 	a = source_types;
97 
98 	while (a->name != NULL) {
99 		if (type == a->type)
100 			return a->name;
101 		a++;
102 	}
103 
104 	errx(1, "Error:  Device type %u unknown", type);
105 	return 0;
106 }
107 
108 void
109 do_ioctl(rndctl_t *rctl)
110 {
111 	int fd;
112 	int res;
113 
114 	fd = open("/dev/urandom", O_RDONLY, 0644);
115 	if (fd < 0)
116 		err(1, "open");
117 
118 	res = ioctl(fd, RNDCTL, rctl);
119 	if (res < 0)
120 		err(1, "ioctl(RNDCTL)");
121 
122 	close(fd);
123 }
124 
125 char *
126 strflags(u_int32_t fl)
127 {
128 	static char str[512];
129 
130 	str[0] = 0;
131 	strcat(str, "<");
132 
133 	if (fl & RND_FLAG_NO_ESTIMATE)
134 		strcat(str, "no");
135 	strcat(str, "estimate, ");
136 	if (fl & RND_FLAG_NO_COLLECT)
137 		strcat(str, "no");
138 	strcat(str, "collect>");
139 
140 	return str;
141 }
142 
143 #define HEADER "Device Name      Type           Bits Flags\n" \
144                "---------------- -------- ---------- -----\n"
145 
146 void
147 do_list(int all, u_int32_t type, char *name)
148 {
149 	rndstat_t       rstat;
150 	rndstat_name_t  rstat_name;
151 	int             fd;
152 	int             res;
153 	u_int32_t	start;
154 
155 	fd = open("/dev/urandom", O_RDONLY, 0644);
156 	if (fd < 0)
157 		err(1, "open");
158 
159 	if (all == 0 && type == 0xff) {
160 		strncpy(rstat_name.name, name, 16);
161 		res = ioctl(fd, RNDGETSRCNAME, &rstat_name);
162 		if (res < 0)
163 			err(1, "ioctl(RNDGETSRCNAME)");
164 		printf(HEADER);
165 		printf("%-16s %-8s %10u %s\n",
166 		       rstat_name.source.name,
167 		       find_name(rstat_name.source.type),
168 		       rstat_name.source.total,
169 		       strflags(rstat_name.source.flags));
170 		close(fd);
171 		return;
172 	}
173 
174 	/*
175 	 * run through all the devices present in the system, and either
176 	 * print out ones that match, or print out all of them.
177 	 */
178 	printf(HEADER);
179 	start = 0;
180 	for (;;) {
181 		rstat.count = RND_MAXSTATCOUNT;
182 		rstat.start = start;
183 		res = ioctl(fd, RNDGETSRCNUM, &rstat);
184 		if (res < 0)
185 			err(1, "ioctl(RNDGETSRCNUM)");
186 
187 		if (rstat.count == 0)
188 			break;
189 
190 		for (res = 0 ; res < rstat.count ; res++) {
191 			if ((all != 0)
192 			    || (type == rstat.source[res].type))
193 				printf("%-16s %-8s %10u %s\n",
194 				       rstat.source[res].name,
195 				       find_name(rstat.source[res].type),
196 				       rstat.source[res].total,
197 				       strflags(rstat.source[res].flags));
198 		}
199 		start += rstat.count;
200 	}
201 
202 	close(fd);
203 }
204 
205 int
206 main(int argc, char **argv)
207 {
208 	rndctl_t  rctl;
209 	int       ch;
210 	int       cmd;
211 	int       lflag;
212 	int       mflag;
213 	u_int32_t type;
214 	char      name[16];
215 
216 	rctl.mask = 0;
217 	rctl.flags = 0;
218 
219 	cmd = 0;
220 	lflag = 0;
221 	mflag = 0;
222 	type = 0xff;
223 
224 	while ((ch = getopt(argc, argv, "CEcelt:d:")) != -1)
225 		switch(ch) {
226 		case 'C':
227 			rctl.flags |= RND_FLAG_NO_COLLECT;
228 			rctl.mask |= RND_FLAG_NO_COLLECT;
229 			mflag++;
230 			break;
231 		case 'E':
232 			rctl.flags |= RND_FLAG_NO_ESTIMATE;
233 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
234 			mflag++;
235 			break;
236 		case 'c':
237 			rctl.flags &= ~RND_FLAG_NO_COLLECT;
238 			rctl.mask |= RND_FLAG_NO_COLLECT;
239 			mflag++;
240 			break;
241 		case 'e':
242 			rctl.flags &= ~RND_FLAG_NO_ESTIMATE;
243 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
244 			mflag++;
245 			break;
246 		case 'l':
247 			lflag++;
248 			break;
249 		case 't':
250 			if (cmd != 0)
251 				usage();
252 			cmd = 't';
253 
254 			type = find_type(optarg);
255 			break;
256 		case 'd':
257 			if (cmd != 0)
258 				usage();
259 			cmd = 'd';
260 
261 			type = 0xff;
262 			strncpy(name, optarg, 16);
263 			break;
264 		case '?':
265 		default:
266 			usage();
267 		}
268 
269 	/*
270 	 * cannot list and modify at the same time
271 	 */
272 	if (lflag != 0 && mflag != 0)
273 		usage();
274 
275 	/*
276 	 * bomb out on no-ops
277 	 */
278 	if (lflag == 0 && mflag == 0)
279 		usage();
280 
281 	/*
282 	 * if not listing, we need a device name or a type
283 	 */
284 	if (lflag == 0 && cmd == 0)
285 		usage();
286 
287 	/*
288 	 * modify request
289 	 */
290 	if (mflag != 0) {
291 		rctl.type = type;
292 		strncpy(rctl.name, name, 16);
293 		do_ioctl(&rctl);
294 
295 		exit(0);
296 	}
297 
298 	/*
299 	 * list sources
300 	 */
301 	if (lflag != 0)
302 		do_list(cmd == 0, type, name);
303 
304 	return 0;
305 }
306