]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sbin/devfs/rule.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 request, 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 static devfs_rsnum in_rsnum;
80
81 int
82 rule_main(int ac, char **av)
83 {
84         struct cmd *c;
85         int 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         void *set;
318
319         memset(dr, '\0', sizeof(*dr));
320
321         /*
322          * We don't maintain ac hereinafter.
323          */
324         if (av[0] == NULL)
325                 errx(1, "unexpected end of rulespec");
326
327         /* If the first argument is an integer, treat it as a rule number. */
328         if (!atonum(av[0], &rnum))
329                 rnum = 0;               /* auto-number */
330         else
331                 ++av;
332
333         /*
334          * These aren't table-driven since that would result in more
335          * tiny functions than I care to deal with.
336          */
337         for (;;) {
338                 if (av[0] == NULL)
339                         break;
340                 else if (strcmp(av[0], "type") == 0) {
341                         if (av[1] == NULL)
342                                 errx(1, "expecting argument for type");
343                         for (is = ist_type; is->s != NULL; ++is)
344                                 if (strcmp(av[1], is->s) == 0) {
345                                         dr->dr_dswflags |= is->i;
346                                         break;
347                                 }
348                         if (is->s == NULL)
349                                 errx(1, "unknown type: %s", av[1]);
350                         dr->dr_icond |= DRC_DSWFLAGS;
351                         av += 2;
352                 } else if (strcmp(av[0], "path") == 0) {
353                         if (av[1] == NULL)
354                                 errx(1, "expecting argument for path");
355                         if (strlcpy(dr->dr_pathptrn, av[1], DEVFS_MAXPTRNLEN)
356                             >= DEVFS_MAXPTRNLEN)
357                                 warnx("pattern specified too long; truncated");
358                         dr->dr_icond |= DRC_PATHPTRN;
359                         av += 2;
360                 } else
361                         break;
362         }
363         while (av[0] != NULL) {
364                 if (strcmp(av[0], "hide") == 0) {
365                         dr->dr_iacts |= DRA_BACTS;
366                         dr->dr_bacts |= DRB_HIDE;
367                         ++av;
368                 } else if (strcmp(av[0], "unhide") == 0) {
369                         dr->dr_iacts |= DRA_BACTS;
370                         dr->dr_bacts |= DRB_UNHIDE;
371                         ++av;
372                 } else if (strcmp(av[0], "user") == 0) {
373                         if (av[1] == NULL)
374                                 errx(1, "expecting argument for user");
375                         dr->dr_iacts |= DRA_UID;
376                         pw = getpwnam(av[1]);
377                         if (pw != NULL)
378                                 dr->dr_uid = pw->pw_uid;
379                         else
380                                 dr->dr_uid = eatoi(av[1]); /* XXX overflow */
381                         av += 2;
382                 } else if (strcmp(av[0], "group") == 0) {
383                         if (av[1] == NULL)
384                                 errx(1, "expecting argument for group");
385                         dr->dr_iacts |= DRA_GID;
386                         gr = getgrnam(av[1]);
387                         if (gr != NULL)
388                                 dr->dr_gid = gr->gr_gid;
389                         else
390                                 dr->dr_gid = eatoi(av[1]); /* XXX overflow */
391                         av += 2;
392                 } else if (strcmp(av[0], "mode") == 0) {
393                         if (av[1] == NULL)
394                                 errx(1, "expecting argument for mode");
395                         dr->dr_iacts |= DRA_MODE;
396                         set = setmode(av[1]);
397                         if (set == NULL)
398                                 errx(1, "invalid mode: %s", av[1]);
399                         dr->dr_mode = getmode(set, 0);
400                         av += 2;
401                 } else if (strcmp(av[0], "include") == 0) {
402                         if (av[1] == NULL)
403                                 errx(1, "expecting argument for include");
404                         dr->dr_iacts |= DRA_INCSET;
405                         dr->dr_incset = eatonum(av[1]);
406                         av += 2;
407                 } else
408                         errx(1, "unknown argument: %s", av[0]);
409         }
410
411         dr->dr_id = mkrid(rsnum, rnum);
412         dr->dr_magic = DEVFS_MAGIC;
413 }
414
415 /*
416  * Write a human-readable (and machine-parsable, by rulespec_in*())
417  * representation of dr to bufp.  *bufp should be free(3)'d when the
418  * caller is finished with it.
419  */
420 static void
421 rulespec_outfp(FILE *fp, struct devfs_rule *dr)
422 {
423         struct intstr *is;
424         struct passwd *pw;
425         struct group *gr;
426
427         fprintf(fp, "%d", rid2rn(dr->dr_id));
428
429         if (dr->dr_icond & DRC_DSWFLAGS)
430                 for (is = ist_type; is->s != NULL; ++is)
431                         if (dr->dr_dswflags & is->i)
432                                 fprintf(fp, " type %s", is->s);
433         if (dr->dr_icond & DRC_PATHPTRN)
434                 fprintf(fp, " path %s", dr->dr_pathptrn);
435
436         if (dr->dr_iacts & DRA_BACTS) {
437                 if (dr->dr_bacts & DRB_HIDE)
438                         fprintf(fp, " hide");
439                 if (dr->dr_bacts & DRB_UNHIDE)
440                         fprintf(fp, " unhide");
441         }
442         if (dr->dr_iacts & DRA_UID) {
443                 pw = getpwuid(dr->dr_uid);
444                 if (pw == NULL)
445                         fprintf(fp, " user %d", dr->dr_uid);
446                 else
447                         fprintf(fp, " user %s", pw->pw_name);
448         }
449         if (dr->dr_iacts & DRA_GID) {
450                 gr = getgrgid(dr->dr_gid);
451                 if (gr == NULL)
452                         fprintf(fp, " group %d", dr->dr_gid);
453                 else
454                         fprintf(fp, " group %s", gr->gr_name);
455         }
456         if (dr->dr_iacts & DRA_MODE)
457                 fprintf(fp, " mode %o", dr->dr_mode);
458         if (dr->dr_iacts & DRA_INCSET)
459                 fprintf(fp, " include %d", dr->dr_incset);
460
461         fprintf(fp, "\n");
462 }