]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/devfs/rule.c
Do not build the majority of the games. Remaining are the
[FreeBSD/FreeBSD.git] / sbin / devfs / rule.c
1 /*-
2  * Copyright (c) 2002 Dima Dorfman.
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  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * Rule subsystem manipulation.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/conf.h>
36 #include <sys/ioctl.h>
37
38 #include <assert.h>
39 #include <err.h>
40 #include <errno.h>
41 #include <grp.h>
42 #include <pwd.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include "extern.h"
49
50 static void rulespec_infp(FILE *fp, unsigned long reqest, devfs_rsnum rsnum);
51 static void rulespec_instr(struct devfs_rule *dr, const char *str,
52     devfs_rsnum rsnum);
53 static void rulespec_intok(struct devfs_rule *dr, int ac, char **av,
54     devfs_rsnum rsnum);
55 static void rulespec_outfp(FILE *fp, struct devfs_rule *dr);
56
57 static command_t rule_add, rule_apply, rule_applyset;
58 static command_t rule_del, rule_delset, rule_show, rule_showsets;
59
60 static ctbl_t ctbl_rule = {
61         { "add",                rule_add },
62         { "apply",              rule_apply },
63         { "applyset",           rule_applyset },
64         { "del",                rule_del },
65         { "delset",             rule_delset },
66         { "show",               rule_show },
67         { "showsets",           rule_showsets },
68         { NULL,                 NULL }
69 };
70
71 static struct intstr ist_type[] = {
72         { "disk",               D_DISK },
73         { "mem",                D_MEM },
74         { "tape",               D_TAPE },
75         { "tty",                D_TTY },
76         { NULL,                 -1 }
77 };
78
79 devfs_rsnum in_rsnum;
80
81 int
82 rule_main(int ac, char **av)
83 {
84         struct cmd *c;
85         char ch;
86
87         setprogname("devfs rule");
88         optreset = optind = 1;
89         while ((ch = getopt(ac, av, "s:")) != -1)
90                 switch (ch) {
91                 case 's':
92                         in_rsnum = eatonum(optarg);
93                         break;
94                 default:
95                         usage();
96                 }
97         ac -= optind;
98         av += optind;
99         if (ac < 1)
100                 usage();
101
102         for (c = ctbl_rule; c->name != NULL; ++c)
103                 if (strcmp(c->name, av[0]) == 0)
104                         exit((*c->handler)(ac, av));
105         errx(1, "unknown command: %s", av[0]);
106 }
107
108 static int
109 rule_add(int ac, char **av)
110 {
111         struct devfs_rule dr;
112         int rv;
113
114         if (ac < 2)
115                 usage();
116         if (strcmp(av[1], "-") == 0)
117                 rulespec_infp(stdin, DEVFSIO_RADD, in_rsnum);
118         else {
119                 rulespec_intok(&dr, ac - 1, av + 1, in_rsnum);
120                 rv = ioctl(mpfd, DEVFSIO_RADD, &dr);
121                 if (rv == -1)
122                         err(1, "ioctl DEVFSIO_RADD");
123         }
124         return (0);
125 }
126
127 static int
128 rule_apply(int ac __unused, char **av __unused)
129 {
130         struct devfs_rule dr;
131         devfs_rnum rnum;
132         devfs_rid rid;
133         int rv;
134
135         if (ac < 2)
136                 usage();
137         if (!atonum(av[1], &rnum)) {
138                 if (strcmp(av[1], "-") == 0)
139                         rulespec_infp(stdin, DEVFSIO_RAPPLY, in_rsnum);
140                 else {
141                         rulespec_intok(&dr, ac - 1, av + 1, in_rsnum);
142                         rv = ioctl(mpfd, DEVFSIO_RAPPLY, &dr);
143                         if (rv == -1)
144                                 err(1, "ioctl DEVFSIO_RAPPLY");
145                 }
146         } else {
147                 rid = mkrid(in_rsnum, rnum);
148                 rv = ioctl(mpfd, DEVFSIO_RAPPLYID, &rid);
149                 if (rv == -1)
150                         err(1, "ioctl DEVFSIO_RAPPLYID");
151         }
152         return (0);
153 }
154
155 static int
156 rule_applyset(int ac, char **av __unused)
157 {
158         int rv;
159
160         if (ac != 1)
161                 usage();
162         rv = ioctl(mpfd, DEVFSIO_SAPPLY, &in_rsnum);
163         if (rv == -1)
164                 err(1, "ioctl DEVFSIO_SAPPLY");
165         return (0);
166 }
167
168 static int
169 rule_del(int ac __unused, char **av)
170 {
171         devfs_rid rid;
172         int rv;
173
174         if (av[1] == NULL)
175                 usage();
176         rid = mkrid(in_rsnum, eatoi(av[1]));
177         rv = ioctl(mpfd, DEVFSIO_RDEL, &rid);
178         if (rv == -1)
179                 err(1, "ioctl DEVFSIO_RDEL");
180         return (0);
181 }
182
183 static int
184 rule_delset(int ac, char **av __unused)
185 {
186         struct devfs_rule dr;
187         int rv;
188
189         if (ac != 1)
190                 usage();
191         memset(&dr, '\0', sizeof(dr));
192         dr.dr_magic = DEVFS_MAGIC;
193         dr.dr_id = mkrid(in_rsnum, 0);
194         while (ioctl(mpfd, DEVFSIO_RGETNEXT, &dr) != -1) {
195                 rv = ioctl(mpfd, DEVFSIO_RDEL, &dr.dr_id);
196                 if (rv == -1)
197                         err(1, "ioctl DEVFSIO_RDEL");
198         }
199         if (errno != ENOENT)
200                 err(1, "ioctl DEVFSIO_RGETNEXT");
201         return (0);
202 }
203
204 static int
205 rule_show(int ac __unused, char **av)
206 {
207         struct devfs_rule dr;
208         devfs_rnum rnum;
209         int rv;
210
211         memset(&dr, '\0', sizeof(dr));
212         dr.dr_magic = DEVFS_MAGIC;
213         if (av[1] != NULL) {
214                 rnum = eatoi(av[1]);
215                 dr.dr_id = mkrid(in_rsnum, rnum - 1);
216                 rv = ioctl(mpfd, DEVFSIO_RGETNEXT, &dr);
217                 if (rv == -1)
218                         err(1, "ioctl DEVFSIO_RGETNEXT");
219                 if (rid2rn(dr.dr_id) == rnum)
220                         rulespec_outfp(stdout, &dr);
221         } else {
222                 dr.dr_id = mkrid(in_rsnum, 0);
223                 while (ioctl(mpfd, DEVFSIO_RGETNEXT, &dr) != -1)
224                         rulespec_outfp(stdout, &dr);
225                 if (errno != ENOENT)
226                         err(1, "ioctl DEVFSIO_RGETNEXT");
227         }
228         return (0);
229 }
230
231 static int
232 rule_showsets(int ac, char **av __unused)
233 {
234         devfs_rsnum rsnum;
235
236         if (ac != 1)
237                 usage();
238         rsnum = 0;
239         while (ioctl(mpfd, DEVFSIO_SGETNEXT, &rsnum) != -1)
240                 printf("%d\n", rsnum);
241         if (errno != ENOENT)
242                 err(1, "ioctl DEVFSIO_SGETNEXT");
243         return (0);
244 }
245
246 int
247 ruleset_main(int ac, char **av)
248 {
249         devfs_rsnum rsnum;
250         int rv;
251
252         setprogname("devfs ruleset");
253         if (ac < 2)
254                 usage();
255         rsnum = eatonum(av[1]);
256         rv = ioctl(mpfd, DEVFSIO_SUSE, &rsnum);
257         if (rv == -1)
258                 err(1, "ioctl DEVFSIO_SUSE");
259         return (0);
260 }
261
262
263 /*
264  * Input rules from a file (probably the standard input).  This
265  * differs from the other rulespec_in*() routines in that it also
266  * calls ioctl() for the rules, since it is impractical (and not very
267  * useful) to return a list (or array) of rules, just so the caller
268  * can call call ioctl() for each of them.
269  */
270 static void
271 rulespec_infp(FILE *fp, unsigned long request, devfs_rsnum rsnum)
272 {
273         struct devfs_rule dr;
274         char *line;
275         int rv;
276
277         assert(fp == stdin);    /* XXX: De-hardcode "stdin" from error msg. */
278         while (efgetln(fp, &line)) {
279                 rulespec_instr(&dr, line, rsnum);
280                 rv = ioctl(mpfd, request, &dr);
281                 if (rv == -1)
282                         err(1, "ioctl");
283                 free(line);     /* efgetln() always malloc()s. */
284         }
285         if (ferror(stdin))
286                 err(1, "stdin");
287 }
288
289 /*
290  * Construct a /struct devfs_rule/ from a string.
291  */
292 static void
293 rulespec_instr(struct devfs_rule *dr, const char *str, devfs_rsnum rsnum)
294 {
295         char **av;
296         int ac;
297
298         tokenize(str, &ac, &av);
299         if (ac == 0)
300                 errx(1, "unexpected end of rulespec");
301         rulespec_intok(dr, ac, av, rsnum);
302         free(av[0]);
303         free(av);
304 }
305
306 /*
307  * Construct a /struct devfs_rule/ from ac and av.
308  */
309 static void
310 rulespec_intok(struct devfs_rule *dr, int ac __unused, char **av,
311     devfs_rsnum rsnum)
312 {
313         struct intstr *is;
314         struct passwd *pw;
315         struct group *gr;
316         devfs_rnum rnum;
317         char *cp;
318         long l;
319
320         memset(dr, '\0', sizeof(*dr));
321
322         /*
323          * We don't maintain ac hereinafter.
324          */
325         if (av[0] == NULL)
326                 errx(1, "unexpected end of rulespec");
327
328         /* If the first argument is an integer, treat it as a rule number. */
329         if (!atonum(av[0], &rnum))
330                 rnum = 0;               /* auto-number */
331         else
332                 ++av;
333
334         /*
335          * These aren't table-driven since that would result in more
336          * tiny functions than I care to deal with.
337          */
338         for (;;) {
339                 if (av[0] == NULL)
340                         break;
341                 else if (strcmp(av[0], "type") == 0) {
342                         if (av[1] == NULL)
343                                 errx(1, "expecting argument for type");
344                         for (is = ist_type; is->s != NULL; ++is)
345                                 if (strcmp(av[1], is->s) == 0) {
346                                         dr->dr_dswflags |= is->i;
347                                         break;
348                                 }
349                         if (is->s == NULL)
350                                 errx(1, "unknown type: %s", av[1]);
351                         dr->dr_icond |= DRC_DSWFLAGS;
352                         av += 2;
353                 } else if (strcmp(av[0], "path") == 0) {
354                         if (av[1] == NULL)
355                                 errx(1, "expecting argument for path");
356                         if (strlcpy(dr->dr_pathptrn, av[1], DEVFS_MAXPTRNLEN)
357                             >= DEVFS_MAXPTRNLEN)
358                                 warnx("pattern specified too long; truncated");
359                         dr->dr_icond |= DRC_PATHPTRN;
360                         av += 2;
361                 } else if (strcmp(av[0], "major") == 0) {
362                         if (av[1] == NULL)
363                                 errx(1, "expecting argument for major");
364                         dr->dr_major = eatoi(av[1]);
365                         dr->dr_icond |= DRC_MAJOR;
366                         av += 2;
367                 } else
368                         break;
369         }
370         for (;;) {
371                 if (av[0] == NULL)
372                         break;
373                 else if (strcmp(av[0], "hide") == 0) {
374                         dr->dr_iacts |= DRA_BACTS;
375                         dr->dr_bacts |= DRB_HIDE;
376                         ++av;
377                 } else if (strcmp(av[0], "unhide") == 0) {
378                         dr->dr_iacts |= DRA_BACTS;
379                         dr->dr_bacts |= DRB_UNHIDE;
380                         ++av;
381                 } else if (strcmp(av[0], "user") == 0) {
382                         if (av[1] == NULL)
383                                 errx(1, "expecting argument for user");
384                         dr->dr_iacts |= DRA_UID;
385                         pw = getpwnam(av[1]);
386                         if (pw != NULL)
387                                 dr->dr_uid = pw->pw_uid;
388                         else
389                                 dr->dr_uid = eatoi(av[1]); /* XXX overflow */
390                         av += 2;
391                 } else if (strcmp(av[0], "group") == 0) {
392                         if (av[1] == NULL)
393                                 errx(1, "expecting argument for group");
394                         dr->dr_iacts |= DRA_GID;
395                         gr = getgrnam(av[1]);
396                         if (gr != NULL)
397                                 dr->dr_gid = gr->gr_gid;
398                         else
399                                 dr->dr_gid = eatoi(av[1]); /* XXX overflow */
400                         av += 2;
401                 } else if (strcmp(av[0], "mode") == 0) {
402                         if (av[1] == NULL)
403                                 errx(1, "expecting argument for mode");
404                         dr->dr_iacts |= DRA_MODE;
405                         l = strtol(av[1], &cp, 8);
406                         if (l > (1 << (sizeof(dr->dr_mode) * 8)) - 1 ||
407                             *cp != '\0')
408                                 errx(1, "invalid mode: %s", av[1]);
409                         dr->dr_mode = l;
410                         av += 2;
411                 } else if (strcmp(av[0], "include") == 0) {
412                         if (av[1] == NULL)
413                                 errx(1, "expecting argument for include");
414                         dr->dr_iacts |= DRA_INCSET;
415                         dr->dr_incset = eatonum(av[1]);
416                         av += 2;
417                 } else
418                         errx(1, "unknown argument: %s", av[0]);
419         }
420
421         dr->dr_id = mkrid(rsnum, rnum);
422         dr->dr_magic = DEVFS_MAGIC;
423 }
424
425 /*
426  * Write a human-readable (and machine-parsable, by rulespec_in*())
427  * representation of dr to bufp.  *bufp should be free(3)'d when the
428  * caller is finished with it.
429  */
430 static void
431 rulespec_outfp(FILE *fp, struct devfs_rule *dr)
432 {
433         struct intstr *is;
434         struct passwd *pw;
435         struct group *gr;
436
437         fprintf(fp, "%d", rid2rn(dr->dr_id));
438
439         if (dr->dr_icond & DRC_DSWFLAGS)
440                 for (is = ist_type; is->s != NULL; ++is)
441                         if (dr->dr_dswflags & is->i)
442                                 fprintf(fp, " type %s", is->s);
443         if (dr->dr_icond & DRC_PATHPTRN)
444                 fprintf(fp, " path %s", dr->dr_pathptrn);
445         if (dr->dr_icond & DRC_MAJOR)
446                 fprintf(fp, " major %d", dr->dr_major);
447
448         if (dr->dr_iacts & DRA_BACTS) {
449                 if (dr->dr_bacts & DRB_HIDE)
450                         fprintf(fp, " hide");
451                 if (dr->dr_bacts & DRB_UNHIDE)
452                         fprintf(fp, " unhide");
453         }
454         if (dr->dr_iacts & DRA_UID) {
455                 pw = getpwuid(dr->dr_uid);
456                 if (pw == NULL)
457                         fprintf(fp, " user %d", dr->dr_uid);
458                 else
459                         fprintf(fp, " user %s", pw->pw_name);
460         }
461         if (dr->dr_iacts & DRA_GID) {
462                 gr = getgrgid(dr->dr_gid);
463                 if (gr == NULL)
464                         fprintf(fp, " group %d", dr->dr_gid);
465                 else
466                         fprintf(fp, " group %s", gr->gr_name);
467         }
468         if (dr->dr_iacts & DRA_MODE)
469                 fprintf(fp, " mode %o", dr->dr_mode);
470         if (dr->dr_iacts & DRA_INCSET)
471                 fprintf(fp, " include %d", dr->dr_incset);
472
473         fprintf(fp, "\n");
474 }