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