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