Implement this (quoted from the updated man page): If the first token

of a rule specification is a single dash (``-''), rules are read from
the standard input and the rest of the specification is ignored.
This commit is contained in:
dd 2002-07-28 06:45:30 +00:00
parent e3d769e493
commit 833e15959c
4 changed files with 181 additions and 9 deletions

View File

@ -143,6 +143,10 @@ and the actions determine what should be done when a rule matches a node.
For example, a rule can be written that sets the GID to For example, a rule can be written that sets the GID to
.Li games .Li games
for all devices with major number 53. for all devices with major number 53.
If the first token of a rule specification is a single dash
.Pq Dq - ,
rules are read from the standard input and the rest of the specification
is ignored.
.Pp .Pp
The following conditions are recognized. The following conditions are recognized.
Conditions are ANDed together when matching a device; Conditions are ANDed together when matching a device;
@ -311,6 +315,28 @@ will be applied to all nodes.
Since hiding all nodes isn't very useful, we can undo like so: Since hiding all nodes isn't very useful, we can undo like so:
.Pp .Pp
.Dl devfs rule apply unhide .Dl devfs rule apply unhide
.Pp
which applies
.Cm unhide
to all the nodes,
causing them to reappear.
.Pp
.Dl cat my_rules | devfs rule -s 10 add -
.Pp
Add all the rules from the file
.Pa my_rules
to ruleset 10.
.Pp
.Dl devfs rule -s 20 show | devfs rule -s 10 add -
.Pp
Since
.Cm show
outputs valid rules,
this feature can be used to copy rulesets.
The above copies all the rules from ruleset 20 into ruleset 10.
The rule numbers are preserved,
but ruleset 10 may already have rules with non-conflicting numbers
(these will be preserved).
.Sh SEE ALSO .Sh SEE ALSO
.Xr jail 2 , .Xr jail 2 ,
.Xr glob 3 , .Xr glob 3 ,

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2002 Dima Dorfman. * Copyright (c) 2001, 2002 Dima Dorfman.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -32,7 +32,9 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include <sys/param.h> #include <sys/param.h>
#include <sys/queue.h>
#include <assert.h>
#include <err.h> #include <err.h>
#include <fcntl.h> #include <fcntl.h>
#include <paths.h> #include <paths.h>
@ -131,6 +133,93 @@ eatonum(const char *s)
return (num); return (num);
} }
/*
* Read a line from a /FILE/. If the return value isn't 0, it is the
* length of the line, a pointer to which exists in /line/. It is the
* caller's responsibility to free(3) it. If the return value is 0,
* there was an error or we reached EOF, and /line/ is undefined (so,
* obviously, the caller shouldn't try to free(3) it).
*/
size_t
efgetln(FILE *fp, char **line)
{
size_t rv;
char *cp;
cp = fgetln(fp, &rv);
if (cp == NULL) {
*line = NULL;
return (rv);
}
if (cp[rv - 1] == '\n') {
cp[rv - 1] = '\0';
*line = strdup(cp);
if (*line == NULL)
errx(1, "cannot allocate memory");
--rv;
} else {
*line = malloc(rv + 1);
if (*line == NULL)
errx(1, "cannot allocate memory");
memcpy(*line, cp, rv);
*line[rv] = '\0';
}
assert(rv == strlen(*line));
return (rv);
}
struct ptrstq {
STAILQ_ENTRY(ptrstq) tq;
void *ptr;
};
/*
* Create an argument vector from /line/. The caller must free(3)
* /avp/, and /avp[0]/ when the argument vector is no longer
* needed unless /acp/ is 0, in which case /avp/ is undefined.
* /avp/ is NULL-terminated, so it is actually one longer than /acp/.
*/
void
tokenize(const char *line, int *acp, char ***avp)
{
static const char *delims = " \t\n";
struct ptrstq *pt;
STAILQ_HEAD(, ptrstq) plist;
char **ap, *cp, *wline, *xcp;
line += strspn(line, delims);
wline = strdup(line);
if (wline == NULL)
errx(1, "cannot allocate memory");
STAILQ_INIT(&plist);
for (xcp = wline, *acp = 0;
(cp = strsep(&xcp, delims)) != NULL;)
if (*cp != '\0') {
pt = calloc(1, sizeof(*pt));
if (pt == NULL)
errx(1, "cannot allocate memory");
pt->ptr = cp;
STAILQ_INSERT_TAIL(&plist, pt, tq);
++*acp;
}
if (*acp == 0)
return;
assert(STAILQ_FIRST(&plist)->ptr == wline);
*avp = malloc(sizeof(**avp) * (*acp + 1));
if (*avp == NULL)
errx(1, "cannot allocate memory");
for (ap = *avp; !STAILQ_EMPTY(&plist);) {
pt = STAILQ_FIRST(&plist);
*ap = pt->ptr;
++ap;
assert(ap <= *avp + (*acp));
STAILQ_REMOVE_HEAD(&plist, tq);
free(pt);
}
*ap = NULL;
}
void void
usage(void) usage(void)
{ {

View File

@ -48,6 +48,8 @@ command_t rule_main, ruleset_main;
int atonum(const char *, uint16_t *); int atonum(const char *, uint16_t *);
int eatoi(const char *); int eatoi(const char *);
uint16_t eatonum(const char *); uint16_t eatonum(const char *);
size_t efgetln(FILE *, char **);
void tokenize(const char *, int *, char ***);
void usage(void) __dead2; void usage(void) __dead2;
extern int mpfd; /* Mount-point file descriptor. */ extern int mpfd; /* Mount-point file descriptor. */

View File

@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/conf.h> #include <sys/conf.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <assert.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>
#include <grp.h> #include <grp.h>
@ -46,6 +47,9 @@ __FBSDID("$FreeBSD$");
#include "extern.h" #include "extern.h"
static void rulespec_infp(FILE *fp, int cmd, devfs_rsnum rsnum);
static void rulespec_instr(struct devfs_rule *dr, const char *str,
devfs_rsnum rsnum);
static void rulespec_intok(struct devfs_rule *dr, int ac, char **av, static void rulespec_intok(struct devfs_rule *dr, int ac, char **av,
devfs_rsnum rsnum); devfs_rsnum rsnum);
static void rulespec_outfp(FILE *fp, struct devfs_rule *dr); static void rulespec_outfp(FILE *fp, struct devfs_rule *dr);
@ -109,10 +113,14 @@ rule_add(int ac, char **av)
if (ac < 2) if (ac < 2)
usage(); usage();
rulespec_intok(&dr, ac - 1, av + 1, in_rsnum); if (strcmp(av[1], "-") == 0)
rv = ioctl(mpfd, DEVFSIO_RADD, &dr); rulespec_infp(stdin, DEVFSIO_RADD, in_rsnum);
if (rv == -1) else {
err(1, "ioctl DEVFSIO_RADD"); rulespec_intok(&dr, ac - 1, av + 1, in_rsnum);
rv = ioctl(mpfd, DEVFSIO_RADD, &dr);
if (rv == -1)
err(1, "ioctl DEVFSIO_RADD");
}
return (0); return (0);
} }
@ -127,10 +135,14 @@ rule_apply(int ac __unused, char **av __unused)
if (ac < 2) if (ac < 2)
usage(); usage();
if (!atonum(av[1], &rnum)) { if (!atonum(av[1], &rnum)) {
rulespec_intok(&dr, ac - 1, av + 1, in_rsnum); if (strcmp(av[1], "-") == 0)
rv = ioctl(mpfd, DEVFSIO_RAPPLY, &dr); rulespec_infp(stdin, DEVFSIO_RAPPLY, in_rsnum);
if (rv == -1) else {
err(1, "ioctl DEVFSIO_RAPPLY"); rulespec_intok(&dr, ac - 1, av + 1, in_rsnum);
rv = ioctl(mpfd, DEVFSIO_RAPPLY, &dr);
if (rv == -1)
err(1, "ioctl DEVFSIO_RAPPLY");
}
} else { } else {
rid = mkrid(in_rsnum, rnum); rid = mkrid(in_rsnum, rnum);
rv = ioctl(mpfd, DEVFSIO_RAPPLYID, &rid); rv = ioctl(mpfd, DEVFSIO_RAPPLYID, &rid);
@ -248,6 +260,49 @@ ruleset_main(int ac, char **av)
} }
/*
* Input rules from a file (probably the standard input). This
* differs from the other rulespec_in*() routines in that it also
* calls ioctl() for the rules, since it is impractical (and not very
* useful) to return a list (or array) of rules, just so the caller
* can call call ioctl() for each of them.
*/
static void
rulespec_infp(FILE *fp, int cmd, devfs_rsnum rsnum)
{
struct devfs_rule dr;
char *line;
int rv;
assert(fp == stdin); /* XXX: De-hardcode "stdin" from error msg. */
while (efgetln(fp, &line)) {
rulespec_instr(&dr, line, rsnum);
rv = ioctl(mpfd, cmd, &dr);
if (rv == -1)
err(1, "ioctl");
free(line); /* efgetln() always malloc()s. */
}
if (ferror(stdin))
err(1, "stdin");
}
/*
* Construct a /struct devfs_rule/ from a string.
*/
static void
rulespec_instr(struct devfs_rule *dr, const char *str, devfs_rsnum rsnum)
{
char **av;
int ac;
tokenize(str, &ac, &av);
if (ac == 0)
errx(1, "unexpected end of rulespec");
rulespec_intok(dr, ac, av, rsnum);
free(av[0]);
free(av);
}
/* /*
* Construct a /struct devfs_rule/ from ac and av. * Construct a /struct devfs_rule/ from ac and av.
*/ */