rndctl.c revision 1.2 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