2 * Copyright (c) 2002 Dima Dorfman.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
28 * Rule subsystem manipulation.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
36 #include <sys/ioctl.h>
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
,
53 static void rulespec_intok(struct devfs_rule
*dr
, int ac
, char **av
,
55 static void rulespec_outfp(FILE *fp
, struct devfs_rule
*dr
);
57 static command_t rule_add
, rule_apply
, rule_applyset
;
58 static command_t rule_del
, rule_delset
, rule_show
, rule_showsets
;
60 static ctbl_t ctbl_rule
= {
62 { "apply", rule_apply
},
63 { "applyset", rule_applyset
},
65 { "delset", rule_delset
},
66 { "show", rule_show
},
67 { "showsets", rule_showsets
},
71 static struct intstr ist_type
[] = {
79 static devfs_rsnum in_rsnum
;
82 rule_main(int ac
, char **av
)
87 setprogname("devfs rule");
88 optreset
= optind
= 1;
89 while ((ch
= getopt(ac
, av
, "s:")) != -1)
92 in_rsnum
= eatonum(optarg
);
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]);
109 rule_add(int ac
, char **av
)
111 struct devfs_rule dr
;
116 if (strcmp(av
[1], "-") == 0)
117 rulespec_infp(stdin
, DEVFSIO_RADD
, in_rsnum
);
119 rulespec_intok(&dr
, ac
- 1, av
+ 1, in_rsnum
);
120 rv
= ioctl(mpfd
, DEVFSIO_RADD
, &dr
);
122 err(1, "ioctl DEVFSIO_RADD");
128 rule_apply(int ac __unused
, char **av __unused
)
130 struct devfs_rule dr
;
137 if (!atonum(av
[1], &rnum
)) {
138 if (strcmp(av
[1], "-") == 0)
139 rulespec_infp(stdin
, DEVFSIO_RAPPLY
, in_rsnum
);
141 rulespec_intok(&dr
, ac
- 1, av
+ 1, in_rsnum
);
142 rv
= ioctl(mpfd
, DEVFSIO_RAPPLY
, &dr
);
144 err(1, "ioctl DEVFSIO_RAPPLY");
147 rid
= mkrid(in_rsnum
, rnum
);
148 rv
= ioctl(mpfd
, DEVFSIO_RAPPLYID
, &rid
);
150 err(1, "ioctl DEVFSIO_RAPPLYID");
156 rule_applyset(int ac
, char **av __unused
)
162 rv
= ioctl(mpfd
, DEVFSIO_SAPPLY
, &in_rsnum
);
164 err(1, "ioctl DEVFSIO_SAPPLY");
169 rule_del(int ac __unused
, char **av
)
176 rid
= mkrid(in_rsnum
, eatoi(av
[1]));
177 rv
= ioctl(mpfd
, DEVFSIO_RDEL
, &rid
);
179 err(1, "ioctl DEVFSIO_RDEL");
184 rule_delset(int ac
, char **av __unused
)
186 struct devfs_rule dr
;
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
);
197 err(1, "ioctl DEVFSIO_RDEL");
200 err(1, "ioctl DEVFSIO_RGETNEXT");
205 rule_show(int ac __unused
, char **av
)
207 struct devfs_rule dr
;
211 memset(&dr
, '\0', sizeof(dr
));
212 dr
.dr_magic
= DEVFS_MAGIC
;
215 dr
.dr_id
= mkrid(in_rsnum
, rnum
- 1);
216 rv
= ioctl(mpfd
, DEVFSIO_RGETNEXT
, &dr
);
218 err(1, "ioctl DEVFSIO_RGETNEXT");
219 if (rid2rn(dr
.dr_id
) == rnum
)
220 rulespec_outfp(stdout
, &dr
);
222 dr
.dr_id
= mkrid(in_rsnum
, 0);
223 while (ioctl(mpfd
, DEVFSIO_RGETNEXT
, &dr
) != -1)
224 rulespec_outfp(stdout
, &dr
);
226 err(1, "ioctl DEVFSIO_RGETNEXT");
232 rule_showsets(int ac
, char **av __unused
)
239 while (ioctl(mpfd
, DEVFSIO_SGETNEXT
, &rsnum
) != -1)
240 printf("%d\n", rsnum
);
242 err(1, "ioctl DEVFSIO_SGETNEXT");
247 ruleset_main(int ac
, char **av
)
252 setprogname("devfs ruleset");
255 rsnum
= eatonum(av
[1]);
256 rv
= ioctl(mpfd
, DEVFSIO_SUSE
, &rsnum
);
258 err(1, "ioctl DEVFSIO_SUSE");
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.
271 rulespec_infp(FILE *fp
, unsigned long request
, devfs_rsnum rsnum
)
273 struct devfs_rule dr
;
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
);
283 free(line
); /* efgetln() always malloc()s. */
290 * Construct a /struct devfs_rule/ from a string.
293 rulespec_instr(struct devfs_rule
*dr
, const char *str
, devfs_rsnum rsnum
)
298 tokenize(str
, &ac
, &av
);
300 errx(1, "unexpected end of rulespec");
301 rulespec_intok(dr
, ac
, av
, rsnum
);
307 * Construct a /struct devfs_rule/ from ac and av.
310 rulespec_intok(struct devfs_rule
*dr
, int ac __unused
, char **av
,
319 memset(dr
, '\0', sizeof(*dr
));
322 * We don't maintain ac hereinafter.
325 errx(1, "unexpected end of rulespec");
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 */
334 * These aren't table-driven since that would result in more
335 * tiny functions than I care to deal with.
340 else if (strcmp(av
[0], "type") == 0) {
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
;
349 errx(1, "unknown type: %s", av
[1]);
350 dr
->dr_icond
|= DRC_DSWFLAGS
;
352 } else if (strcmp(av
[0], "path") == 0) {
354 errx(1, "expecting argument for path");
355 if (strlcpy(dr
->dr_pathptrn
, av
[1], DEVFS_MAXPTRNLEN
)
357 warnx("pattern specified too long; truncated");
358 dr
->dr_icond
|= DRC_PATHPTRN
;
363 while (av
[0] != NULL
) {
364 if (strcmp(av
[0], "hide") == 0) {
365 dr
->dr_iacts
|= DRA_BACTS
;
366 dr
->dr_bacts
|= DRB_HIDE
;
368 } else if (strcmp(av
[0], "unhide") == 0) {
369 dr
->dr_iacts
|= DRA_BACTS
;
370 dr
->dr_bacts
|= DRB_UNHIDE
;
372 } else if (strcmp(av
[0], "user") == 0) {
374 errx(1, "expecting argument for user");
375 dr
->dr_iacts
|= DRA_UID
;
376 pw
= getpwnam(av
[1]);
378 dr
->dr_uid
= pw
->pw_uid
;
380 dr
->dr_uid
= eatoi(av
[1]); /* XXX overflow */
382 } else if (strcmp(av
[0], "group") == 0) {
384 errx(1, "expecting argument for group");
385 dr
->dr_iacts
|= DRA_GID
;
386 gr
= getgrnam(av
[1]);
388 dr
->dr_gid
= gr
->gr_gid
;
390 dr
->dr_gid
= eatoi(av
[1]); /* XXX overflow */
392 } else if (strcmp(av
[0], "mode") == 0) {
394 errx(1, "expecting argument for mode");
395 dr
->dr_iacts
|= DRA_MODE
;
396 set
= setmode(av
[1]);
398 errx(1, "invalid mode: %s", av
[1]);
399 dr
->dr_mode
= getmode(set
, 0);
401 } else if (strcmp(av
[0], "include") == 0) {
403 errx(1, "expecting argument for include");
404 dr
->dr_iacts
|= DRA_INCSET
;
405 dr
->dr_incset
= eatonum(av
[1]);
408 errx(1, "unknown argument: %s", av
[0]);
411 dr
->dr_id
= mkrid(rsnum
, rnum
);
412 dr
->dr_magic
= DEVFS_MAGIC
;
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.
421 rulespec_outfp(FILE *fp
, struct devfs_rule
*dr
)
427 fprintf(fp
, "%d", rid2rn(dr
->dr_id
));
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
);
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");
442 if (dr
->dr_iacts
& DRA_UID
) {
443 pw
= getpwuid(dr
->dr_uid
);
445 fprintf(fp
, " user %d", dr
->dr_uid
);
447 fprintf(fp
, " user %s", pw
->pw_name
);
449 if (dr
->dr_iacts
& DRA_GID
) {
450 gr
= getgrgid(dr
->dr_gid
);
452 fprintf(fp
, " group %d", dr
->dr_gid
);
454 fprintf(fp
, " group %s", gr
->gr_name
);
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
);