2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2002 Dima Dorfman.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * Rule subsystem manipulation.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
38 #include <sys/ioctl.h>
52 static void rulespec_infp(FILE *fp, unsigned long request, devfs_rsnum rsnum);
53 static void rulespec_instr(struct devfs_rule *dr, const char *str,
55 static void rulespec_intok(struct devfs_rule *dr, int ac, char **av,
57 static void rulespec_outfp(FILE *fp, struct devfs_rule *dr);
59 static command_t rule_add, rule_apply, rule_applyset;
60 static command_t rule_del, rule_delset, rule_show, rule_showsets;
62 static ctbl_t ctbl_rule = {
64 { "apply", rule_apply },
65 { "applyset", rule_applyset },
67 { "delset", rule_delset },
68 { "show", rule_show },
69 { "showsets", rule_showsets },
73 static struct intstr ist_type[] = {
81 static devfs_rsnum in_rsnum;
84 rule_main(int ac, char **av)
89 setprogname("devfs rule");
90 optreset = optind = 1;
91 while ((ch = getopt(ac, av, "s:")) != -1)
94 in_rsnum = eatonum(optarg);
104 for (c = ctbl_rule; c->name != NULL; ++c)
105 if (strcmp(c->name, av[0]) == 0)
106 exit((*c->handler)(ac, av));
107 errx(1, "unknown command: %s", av[0]);
111 rule_add(int ac, char **av)
113 struct devfs_rule dr;
118 if (strcmp(av[1], "-") == 0)
119 rulespec_infp(stdin, DEVFSIO_RADD, in_rsnum);
121 rulespec_intok(&dr, ac - 1, av + 1, in_rsnum);
122 rv = ioctl(mpfd, DEVFSIO_RADD, &dr);
124 err(1, "ioctl DEVFSIO_RADD");
130 rule_apply(int ac __unused, char **av __unused)
132 struct devfs_rule dr;
139 if (!atonum(av[1], &rnum)) {
140 if (strcmp(av[1], "-") == 0)
141 rulespec_infp(stdin, DEVFSIO_RAPPLY, in_rsnum);
143 rulespec_intok(&dr, ac - 1, av + 1, in_rsnum);
144 rv = ioctl(mpfd, DEVFSIO_RAPPLY, &dr);
146 err(1, "ioctl DEVFSIO_RAPPLY");
149 rid = mkrid(in_rsnum, rnum);
150 rv = ioctl(mpfd, DEVFSIO_RAPPLYID, &rid);
152 err(1, "ioctl DEVFSIO_RAPPLYID");
158 rule_applyset(int ac, char **av __unused)
164 rv = ioctl(mpfd, DEVFSIO_SAPPLY, &in_rsnum);
166 err(1, "ioctl DEVFSIO_SAPPLY");
171 rule_del(int ac __unused, char **av)
178 rid = mkrid(in_rsnum, eatoi(av[1]));
179 rv = ioctl(mpfd, DEVFSIO_RDEL, &rid);
181 err(1, "ioctl DEVFSIO_RDEL");
186 rule_delset(int ac, char **av __unused)
188 struct devfs_rule dr;
193 memset(&dr, '\0', sizeof(dr));
194 dr.dr_magic = DEVFS_MAGIC;
195 dr.dr_id = mkrid(in_rsnum, 0);
196 while (ioctl(mpfd, DEVFSIO_RGETNEXT, &dr) != -1) {
197 rv = ioctl(mpfd, DEVFSIO_RDEL, &dr.dr_id);
199 err(1, "ioctl DEVFSIO_RDEL");
202 err(1, "ioctl DEVFSIO_RGETNEXT");
207 rule_show(int ac __unused, char **av)
209 struct devfs_rule dr;
213 memset(&dr, '\0', sizeof(dr));
214 dr.dr_magic = DEVFS_MAGIC;
217 dr.dr_id = mkrid(in_rsnum, rnum - 1);
218 rv = ioctl(mpfd, DEVFSIO_RGETNEXT, &dr);
220 err(1, "ioctl DEVFSIO_RGETNEXT");
221 if (rid2rn(dr.dr_id) == rnum)
222 rulespec_outfp(stdout, &dr);
224 dr.dr_id = mkrid(in_rsnum, 0);
225 while (ioctl(mpfd, DEVFSIO_RGETNEXT, &dr) != -1)
226 rulespec_outfp(stdout, &dr);
228 err(1, "ioctl DEVFSIO_RGETNEXT");
234 rule_showsets(int ac, char **av __unused)
241 while (ioctl(mpfd, DEVFSIO_SGETNEXT, &rsnum) != -1)
242 printf("%d\n", rsnum);
244 err(1, "ioctl DEVFSIO_SGETNEXT");
249 ruleset_main(int ac, char **av)
254 setprogname("devfs ruleset");
257 rsnum = eatonum(av[1]);
258 rv = ioctl(mpfd, DEVFSIO_SUSE, &rsnum);
260 err(1, "ioctl DEVFSIO_SUSE");
266 * Input rules from a file (probably the standard input). This
267 * differs from the other rulespec_in*() routines in that it also
268 * calls ioctl() for the rules, since it is impractical (and not very
269 * useful) to return a list (or array) of rules, just so the caller
270 * can call ioctl() for each of them.
273 rulespec_infp(FILE *fp, unsigned long request, devfs_rsnum rsnum)
275 struct devfs_rule dr;
279 assert(fp == stdin); /* XXX: De-hardcode "stdin" from error msg. */
280 while (efgetln(fp, &line)) {
281 rulespec_instr(&dr, line, rsnum);
282 rv = ioctl(mpfd, request, &dr);
285 free(line); /* efgetln() always malloc()s. */
292 * Construct a /struct devfs_rule/ from a string.
295 rulespec_instr(struct devfs_rule *dr, const char *str, devfs_rsnum rsnum)
300 tokenize(str, &ac, &av);
302 errx(1, "unexpected end of rulespec");
303 rulespec_intok(dr, ac, av, rsnum);
309 * Construct a /struct devfs_rule/ from ac and av.
312 rulespec_intok(struct devfs_rule *dr, int ac __unused, char **av,
321 memset(dr, '\0', sizeof(*dr));
324 * We don't maintain ac hereinafter.
327 errx(1, "unexpected end of rulespec");
329 /* If the first argument is an integer, treat it as a rule number. */
330 if (!atonum(av[0], &rnum))
331 rnum = 0; /* auto-number */
336 * These aren't table-driven since that would result in more
337 * tiny functions than I care to deal with.
342 else if (strcmp(av[0], "type") == 0) {
344 errx(1, "expecting argument for type");
345 for (is = ist_type; is->s != NULL; ++is)
346 if (strcmp(av[1], is->s) == 0) {
347 dr->dr_dswflags |= is->i;
351 errx(1, "unknown type: %s", av[1]);
352 dr->dr_icond |= DRC_DSWFLAGS;
354 } else if (strcmp(av[0], "path") == 0) {
356 errx(1, "expecting argument for path");
357 if (strlcpy(dr->dr_pathptrn, av[1], DEVFS_MAXPTRNLEN)
359 warnx("pattern specified too long; truncated");
360 dr->dr_icond |= DRC_PATHPTRN;
365 while (av[0] != NULL) {
366 if (strcmp(av[0], "hide") == 0) {
367 dr->dr_iacts |= DRA_BACTS;
368 dr->dr_bacts |= DRB_HIDE;
370 } else if (strcmp(av[0], "unhide") == 0) {
371 dr->dr_iacts |= DRA_BACTS;
372 dr->dr_bacts |= DRB_UNHIDE;
374 } else if (strcmp(av[0], "user") == 0) {
376 errx(1, "expecting argument for user");
377 dr->dr_iacts |= DRA_UID;
378 pw = getpwnam(av[1]);
380 dr->dr_uid = pw->pw_uid;
382 dr->dr_uid = eatoi(av[1]); /* XXX overflow */
384 } else if (strcmp(av[0], "group") == 0) {
386 errx(1, "expecting argument for group");
387 dr->dr_iacts |= DRA_GID;
388 gr = getgrnam(av[1]);
390 dr->dr_gid = gr->gr_gid;
392 dr->dr_gid = eatoi(av[1]); /* XXX overflow */
394 } else if (strcmp(av[0], "mode") == 0) {
396 errx(1, "expecting argument for mode");
397 dr->dr_iacts |= DRA_MODE;
398 set = setmode(av[1]);
400 errx(1, "invalid mode: %s", av[1]);
401 dr->dr_mode = getmode(set, 0);
403 } else if (strcmp(av[0], "include") == 0) {
405 errx(1, "expecting argument for include");
406 dr->dr_iacts |= DRA_INCSET;
407 dr->dr_incset = eatonum(av[1]);
410 errx(1, "unknown argument: %s", av[0]);
413 dr->dr_id = mkrid(rsnum, rnum);
414 dr->dr_magic = DEVFS_MAGIC;
418 * Write a human-readable (and machine-parsable, by rulespec_in*())
419 * representation of dr to bufp. *bufp should be free(3)'d when the
420 * caller is finished with it.
423 rulespec_outfp(FILE *fp, struct devfs_rule *dr)
429 fprintf(fp, "%d", rid2rn(dr->dr_id));
431 if (dr->dr_icond & DRC_DSWFLAGS)
432 for (is = ist_type; is->s != NULL; ++is)
433 if (dr->dr_dswflags & is->i)
434 fprintf(fp, " type %s", is->s);
435 if (dr->dr_icond & DRC_PATHPTRN)
436 fprintf(fp, " path %s", dr->dr_pathptrn);
438 if (dr->dr_iacts & DRA_BACTS) {
439 if (dr->dr_bacts & DRB_HIDE)
440 fprintf(fp, " hide");
441 if (dr->dr_bacts & DRB_UNHIDE)
442 fprintf(fp, " unhide");
444 if (dr->dr_iacts & DRA_UID) {
445 pw = getpwuid(dr->dr_uid);
447 fprintf(fp, " user %d", dr->dr_uid);
449 fprintf(fp, " user %s", pw->pw_name);
451 if (dr->dr_iacts & DRA_GID) {
452 gr = getgrgid(dr->dr_gid);
454 fprintf(fp, " group %d", dr->dr_gid);
456 fprintf(fp, " group %s", gr->gr_name);
458 if (dr->dr_iacts & DRA_MODE)
459 fprintf(fp, " mode %o", dr->dr_mode);
460 if (dr->dr_iacts & DRA_INCSET)
461 fprintf(fp, " include %d", dr->dr_incset);