xref: /netbsd-src/sbin/rndctl/rndctl.c (revision c41a4eebefede43f6950f838a387dc18c6a431bf)
1 /*-
2  * Copyright (c) 1997 Michael Graff.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of other contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <err.h>
36 #include <string.h>
37 
38 #include <sys/types.h>
39 #include <sys/ioctl.h>
40 #include <sys/rnd.h>
41 
42 typedef struct {
43 	char *name;
44 	u_int32_t   type;
45 } arg_t;
46 
47 arg_t source_types[] = {
48 	{ "unknown", RND_TYPE_UNKNOWN },
49 	{ "disk",    RND_TYPE_DISK },
50 	{ "network", RND_TYPE_NET },
51 	{ "net",     RND_TYPE_NET },
52 	{ "tape",    RND_TYPE_TAPE },
53 	{ "tty",     RND_TYPE_TTY },
54 	{ NULL,      0 }
55 };
56 
57 static void usage(void);
58 u_int32_t find_type(char *name);
59 char *find_name(u_int32_t);
60 void do_ioctl(rndctl_t *);
61 char * strflags(u_int32_t);
62 void do_list(int, u_int32_t, char *);
63 
64 static void
65 usage(void)
66 {
67 	errx(1, "Usage:  rndctl [-CEce | -l] [-d name | -t type]");
68 }
69 
70 u_int32_t
71 find_type(char *name)
72 {
73 	arg_t *a;
74 
75 	a = source_types;
76 
77 	while (a->name != NULL) {
78 		if (strcmp(a->name, name) == 0)
79 			return a->type;
80 		a++;
81 	}
82 
83 	errx(1, "Error:  Device type %s unknown", name);
84 	return 0;
85 }
86 
87 char *
88 find_name(u_int32_t type)
89 {
90 	arg_t *a;
91 
92 	a = source_types;
93 
94 	while (a->name != NULL) {
95 		if (type == a->type)
96 			return a->name;
97 		a++;
98 	}
99 
100 	errx(1, "Error:  Device type %u unknown", type);
101 	return 0;
102 }
103 
104 void
105 do_ioctl(rndctl_t *rctl)
106 {
107 	int fd;
108 	int res;
109 
110 	fd = open("/dev/urandom", O_RDONLY, 0644);
111 	if (fd < 0)
112 		err(1, "open");
113 
114 	res = ioctl(fd, RNDCTL, rctl);
115 	if (res < 0)
116 		err(1, "ioctl(RNDCTL)");
117 
118 	close(fd);
119 }
120 
121 char *
122 strflags(u_int32_t fl)
123 {
124 	static char str[512];
125 
126 	str[0] = 0;
127 	strcat(str, "<");
128 
129 	if (fl & RND_FLAG_NO_ESTIMATE)
130 		strcat(str, "no");
131 	strcat(str, "estimate, ");
132 	if (fl & RND_FLAG_NO_COLLECT)
133 		strcat(str, "no");
134 	strcat(str, "collect>");
135 
136 	return str;
137 }
138 
139 #define HEADER "Device Name      Type           Bits Flags\n" \
140                "---------------- -------- ---------- -----\n"
141 
142 void
143 do_list(int all, u_int32_t type, char *name)
144 {
145 	rndstat_t       rstat;
146 	rndstat_name_t  rstat_name;
147 	int             fd;
148 	int             res;
149 	u_int32_t	start;
150 
151 	fd = open("/dev/urandom", O_RDONLY, 0644);
152 	if (fd < 0)
153 		err(1, "open");
154 
155 	if (all == 0 && type == 0xff) {
156 		strncpy(rstat_name.name, name, 16);
157 		res = ioctl(fd, RNDGETSRCNAME, &rstat_name);
158 		if (res < 0)
159 			err(1, "ioctl(RNDGETSRCNAME)");
160 		printf(HEADER);
161 		printf("%-16s %-8s %10u %s\n",
162 		       rstat_name.source.name,
163 		       find_name(rstat_name.source.tyfl & 0xff),
164 		       rstat_name.source.total,
165 		       strflags(rstat_name.source.tyfl));
166 		close(fd);
167 		return;
168 	}
169 
170 	/*
171 	 * run through all the devices present in the system, and either
172 	 * print out ones that match, or print out all of them.
173 	 */
174 	printf(HEADER);
175 	start = 0;
176 	for (;;) {
177 		rstat.count = RND_MAXSTATCOUNT;
178 		rstat.start = start;
179 		res = ioctl(fd, RNDGETSRCNUM, &rstat);
180 		if (res < 0)
181 			err(1, "ioctl(RNDGETSRCNUM)");
182 
183 		if (rstat.count == 0)
184 			break;
185 
186 		for (res = 0 ; res < rstat.count ; res++) {
187 			if ((all != 0)
188 			    || (type == (rstat.source[res].tyfl & 0xff)))
189 				printf("%-16s %-8s %10u %s\n",
190 				       rstat.source[res].name,
191 				       find_name(rstat.source[res].tyfl & 0xff),
192 				       rstat.source[res].total,
193 				       strflags(rstat.source[res].tyfl));
194 		}
195 		start += rstat.count;
196 	}
197 
198 	close(fd);
199 }
200 
201 int
202 main(int argc, char **argv)
203 {
204 	rndctl_t  rctl;
205 	int       ch;
206 	int       cmd;
207 	int       lflag;
208 	int       mflag;
209 	u_int32_t type;
210 	char      name[16];
211 
212 	rctl.mask = 0;
213 	rctl.flags = 0;
214 
215 	cmd = 0;
216 	lflag = 0;
217 	mflag = 0;
218 	type = 0xff;
219 
220 	while ((ch = getopt(argc, argv, "CEcelt:d:")) != -1)
221 		switch(ch) {
222 		case 'C':
223 			rctl.flags |= RND_FLAG_NO_COLLECT;
224 			rctl.mask |= RND_FLAG_NO_COLLECT;
225 			mflag++;
226 			break;
227 		case 'E':
228 			rctl.flags |= RND_FLAG_NO_ESTIMATE;
229 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
230 			mflag++;
231 			break;
232 		case 'c':
233 			rctl.flags &= ~RND_FLAG_NO_COLLECT;
234 			rctl.mask |= RND_FLAG_NO_COLLECT;
235 			mflag++;
236 			break;
237 		case 'e':
238 			rctl.flags &= ~RND_FLAG_NO_ESTIMATE;
239 			rctl.mask |= RND_FLAG_NO_ESTIMATE;
240 			mflag++;
241 			break;
242 		case 'l':
243 			lflag++;
244 			break;
245 		case 't':
246 			if (cmd != 0)
247 				usage();
248 			cmd = 't';
249 
250 			type = find_type(optarg);
251 			break;
252 		case 'd':
253 			if (cmd != 0)
254 				usage();
255 			cmd = 'd';
256 
257 			type = 0xff;
258 			strncpy(name, optarg, 16);
259 			break;
260 		case '?':
261 		default:
262 			usage();
263 		}
264 
265 	/*
266 	 * cannot list and modify at the same time
267 	 */
268 	if (lflag != 0 && mflag != 0)
269 		usage();
270 
271 	/*
272 	 * bomb out on no-ops
273 	 */
274 	if (lflag == 0 && mflag == 0)
275 		usage();
276 
277 	/*
278 	 * if not listing, we need a device name or a type
279 	 */
280 	if (lflag == 0 && cmd == 0)
281 		usage();
282 
283 	/*
284 	 * modify request
285 	 */
286 	if (mflag != 0) {
287 		rctl.type = type;
288 		strncpy(rctl.name, name, 16);
289 		do_ioctl(&rctl);
290 
291 		exit(0);
292 	}
293 
294 	/*
295 	 * list sources
296 	 */
297 	if (lflag != 0)
298 		do_list(cmd == 0, type, name);
299 
300 	return 0;
301 }
302