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 <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_intok(struct devfs_rule *dr, int ac, char **av, 50 devfs_rsnum rsnum); 51 static void rulespec_outfp(FILE *fp, struct devfs_rule *dr); 52 53 static command_t rule_add, rule_apply, rule_applyset; 54 static command_t rule_del, rule_delset, rule_show, rule_showsets; 55 56 static ctbl_t ctbl_rule = { 57 { "add", rule_add }, 58 { "apply", rule_apply }, 59 { "applyset", rule_applyset }, 60 { "del", rule_del }, 61 { "delset", rule_delset }, 62 { "show", rule_show }, 63 { "showsets", rule_showsets }, 64 { NULL, NULL } 65 }; 66 67 static struct intstr ist_type[] = { 68 { "disk", D_DISK }, 69 { "mem", D_MEM }, 70 { "tape", D_TAPE }, 71 { "tty", D_TTY }, 72 { NULL, -1 } 73 }; 74 75 devfs_rsnum in_rsnum; 76 77 int 78 rule_main(int ac, char **av) 79 { 80 struct cmd *c; 81 char ch; 82 83 setprogname("devfs rule"); 84 optreset = optind = 1; 85 while ((ch = getopt(ac, av, "s:")) != -1) 86 switch (ch) { 87 case 's': 88 in_rsnum = eatonum(optarg); 89 break; 90 default: 91 usage(); 92 } 93 ac -= optind; 94 av += optind; 95 if (ac < 1) 96 usage(); 97 98 for (c = ctbl_rule; c->name != NULL; ++c) 99 if (strcmp(c->name, av[0]) == 0) 100 exit((*c->handler)(ac, av)); 101 errx(1, "unknown command: %s", av[0]); 102 } 103 104 static int 105 rule_add(int ac, char **av) 106 { 107 struct devfs_rule dr; 108 int rv; 109 110 if (ac < 2) 111 usage(); 112 rulespec_intok(&dr, ac - 1, av + 1, in_rsnum); 113 rv = ioctl(mpfd, DEVFSIO_RADD, &dr); 114 if (rv == -1) 115 err(1, "ioctl DEVFSIO_RADD"); 116 return (0); 117 } 118 119 static int 120 rule_apply(int ac __unused, char **av __unused) 121 { 122 struct devfs_rule dr; 123 devfs_rnum rnum; 124 devfs_rid rid; 125 int rv; 126 127 if (ac < 2) 128 usage(); 129 if (!atonum(av[1], &rnum)) { 130 rulespec_intok(&dr, ac - 1, av + 1, in_rsnum); 131 rv = ioctl(mpfd, DEVFSIO_RAPPLY, &dr); 132 if (rv == -1) 133 err(1, "ioctl DEVFSIO_RAPPLY"); 134 } else { 135 rid = mkrid(in_rsnum, rnum); 136 rv = ioctl(mpfd, DEVFSIO_RAPPLYID, &rid); 137 if (rv == -1) 138 err(1, "ioctl DEVFSIO_RAPPLYID"); 139 } 140 return (0); 141 } 142 143 static int 144 rule_applyset(int ac, char **av __unused) 145 { 146 int rv; 147 148 if (ac != 1) 149 usage(); 150 rv = ioctl(mpfd, DEVFSIO_SAPPLY, &in_rsnum); 151 if (rv == -1) 152 err(1, "ioctl DEVFSIO_SAPPLY"); 153 return (0); 154 } 155 156 static int 157 rule_del(int ac __unused, char **av) 158 { 159 devfs_rid rid; 160 int rv; 161 162 if (av[1] == NULL) 163 usage(); 164 rid = mkrid(in_rsnum, eatoi(av[1])); 165 rv = ioctl(mpfd, DEVFSIO_RDEL, &rid); 166 if (rv == -1) 167 err(1, "ioctl DEVFSIO_RDEL"); 168 return (0); 169 } 170 171 static int 172 rule_delset(int ac, char **av __unused) 173 { 174 struct devfs_rule dr; 175 int rv; 176 177 if (ac != 1) 178 usage(); 179 memset(&dr, '\0', sizeof(dr)); 180 dr.dr_magic = DEVFS_MAGIC; 181 dr.dr_id = mkrid(in_rsnum, 0); 182 while (ioctl(mpfd, DEVFSIO_RGETNEXT, &dr) != -1) { 183 rv = ioctl(mpfd, DEVFSIO_RDEL, &dr.dr_id); 184 if (rv == -1) 185 err(1, "ioctl DEVFSIO_RDEL"); 186 } 187 if (errno != ENOENT) 188 err(1, "ioctl DEVFSIO_RGETNEXT"); 189 return (0); 190 } 191 192 static int 193 rule_show(int ac __unused, char **av) 194 { 195 struct devfs_rule dr; 196 devfs_rnum rnum; 197 int rv; 198 199 memset(&dr, '\0', sizeof(dr)); 200 dr.dr_magic = DEVFS_MAGIC; 201 if (av[1] != NULL) { 202 rnum = eatoi(av[1]); 203 dr.dr_id = mkrid(in_rsnum, rnum - 1); 204 rv = ioctl(mpfd, DEVFSIO_RGETNEXT, &dr); 205 if (rv == -1) 206 err(1, "ioctl DEVFSIO_RGETNEXT"); 207 if (rid2rn(dr.dr_id) == rnum) 208 rulespec_outfp(stdout, &dr); 209 } else { 210 dr.dr_id = mkrid(in_rsnum, 0); 211 while (ioctl(mpfd, DEVFSIO_RGETNEXT, &dr) != -1) 212 rulespec_outfp(stdout, &dr); 213 if (errno != ENOENT) 214 err(1, "ioctl DEVFSIO_RGETNEXT"); 215 } 216 return (0); 217 } 218 219 static int 220 rule_showsets(int ac, char **av __unused) 221 { 222 devfs_rsnum rsnum; 223 224 if (ac != 1) 225 usage(); 226 rsnum = 0; 227 while (ioctl(mpfd, DEVFSIO_SGETNEXT, &rsnum) != -1) 228 printf("%d\n", rsnum); 229 if (errno != ENOENT) 230 err(1, "ioctl DEVFSIO_SGETNEXT"); 231 return (0); 232 } 233 234 int 235 ruleset_main(int ac, char **av) 236 { 237 devfs_rsnum rsnum; 238 int rv; 239 240 setprogname("devfs ruleset"); 241 if (ac < 2) 242 usage(); 243 rsnum = eatonum(av[1]); 244 rv = ioctl(mpfd, DEVFSIO_SUSE, &rsnum); 245 if (rv == -1) 246 err(1, "ioctl DEVFSIO_SUSE"); 247 return (0); 248 } 249 250 251 /* 252 * Construct a /struct devfs_rule/ from ac and av. 253 */ 254 static void 255 rulespec_intok(struct devfs_rule *dr, int ac __unused, char **av, 256 devfs_rsnum rsnum) 257 { 258 struct intstr *is; 259 struct passwd *pw; 260 struct group *gr; 261 devfs_rnum rnum; 262 char *cp; 263 long l; 264 265 memset(dr, '\0', sizeof(*dr)); 266 267 /* 268 * We don't maintain ac hereinafter. 269 */ 270 if (av[0] == NULL) 271 errx(1, "unexpected end of rulespec"); 272 273 /* If the first argument is an integer, treat it as a rule number. */ 274 if (!atonum(av[0], &rnum)) 275 rnum = 0; /* auto-number */ 276 else 277 ++av; 278 279 /* 280 * These aren't table-driven since that would result in more 281 * tiny functions than I care to deal with. 282 */ 283 for (;;) { 284 if (av[0] == NULL) 285 break; 286 else if (strcmp(av[0], "type") == 0) { 287 if (av[1] == NULL) 288 errx(1, "expecting argument for type"); 289 for (is = ist_type; is->s != NULL; ++is) 290 if (strcmp(av[1], is->s) == 0) { 291 dr->dr_dswflags |= is->i; 292 break; 293 } 294 if (is->s == NULL) 295 errx(1, "unknown type: %s", av[1]); 296 dr->dr_icond |= DRC_DSWFLAGS; 297 av += 2; 298 } else if (strcmp(av[0], "path") == 0) { 299 if (av[1] == NULL) 300 errx(1, "expecting argument for path"); 301 if (strlcpy(dr->dr_pathptrn, av[1], DEVFS_MAXPTRNLEN) 302 >= DEVFS_MAXPTRNLEN) 303 warnx("pattern specified too long; truncated"); 304 dr->dr_icond |= DRC_PATHPTRN; 305 av += 2; 306 } else if (strcmp(av[0], "major") == 0) { 307 if (av[1] == NULL) 308 errx(1, "expecting argument for major"); 309 dr->dr_major = eatoi(av[1]); 310 dr->dr_icond |= DRC_MAJOR; 311 av += 2; 312 } else 313 break; 314 } 315 for (;;) { 316 if (av[0] == NULL) 317 break; 318 else if (strcmp(av[0], "hide") == 0) { 319 dr->dr_iacts |= DRA_BACTS; 320 dr->dr_bacts |= DRB_HIDE; 321 ++av; 322 } else if (strcmp(av[0], "unhide") == 0) { 323 dr->dr_iacts |= DRA_BACTS; 324 dr->dr_bacts |= DRB_UNHIDE; 325 ++av; 326 } else if (strcmp(av[0], "user") == 0) { 327 if (av[1] == NULL) 328 errx(1, "expecting argument for user"); 329 dr->dr_iacts |= DRA_UID; 330 pw = getpwnam(av[1]); 331 if (pw != NULL) 332 dr->dr_uid = pw->pw_uid; 333 else 334 dr->dr_uid = eatoi(av[1]); /* XXX overflow */ 335 av += 2; 336 } else if (strcmp(av[0], "group") == 0) { 337 if (av[1] == NULL) 338 errx(1, "expecting argument for group"); 339 dr->dr_iacts |= DRA_GID; 340 gr = getgrnam(av[1]); 341 if (gr != NULL) 342 dr->dr_gid = gr->gr_gid; 343 else 344 dr->dr_gid = eatoi(av[1]); /* XXX overflow */ 345 av += 2; 346 } else if (strcmp(av[0], "mode") == 0) { 347 if (av[1] == NULL) 348 errx(1, "expecting argument for mode"); 349 dr->dr_iacts |= DRA_MODE; 350 l = strtol(av[1], &cp, 8); 351 if (l > (1 << (sizeof(dr->dr_mode) * 8)) - 1 || 352 *cp != '\0') 353 errx(1, "invalid mode: %s", av[1]); 354 dr->dr_mode = l; 355 av += 2; 356 } else if (strcmp(av[0], "include") == 0) { 357 if (av[1] == NULL) 358 errx(1, "expecting argument for include"); 359 dr->dr_iacts |= DRA_INCSET; 360 dr->dr_incset = eatonum(av[1]); 361 av += 2; 362 } else 363 errx(1, "unknown argument: %s", av[0]); 364 } 365 366 dr->dr_id = mkrid(rsnum, rnum); 367 dr->dr_magic = DEVFS_MAGIC; 368 } 369 370 /* 371 * Write a human-readable (and machine-parsable, by rulespec_in*()) 372 * representation of dr to bufp. *bufp should be free(3)'d when the 373 * caller is finished with it. 374 */ 375 static void 376 rulespec_outfp(FILE *fp, struct devfs_rule *dr) 377 { 378 struct intstr *is; 379 struct passwd *pw; 380 struct group *gr; 381 382 fprintf(fp, "%d", rid2rn(dr->dr_id)); 383 384 if (dr->dr_icond & DRC_DSWFLAGS) 385 for (is = ist_type; is->s != NULL; ++is) 386 if (dr->dr_dswflags & is->i) 387 fprintf(fp, " type %s", is->s); 388 if (dr->dr_icond & DRC_PATHPTRN) 389 fprintf(fp, " path %s", dr->dr_pathptrn); 390 if (dr->dr_icond & DRC_MAJOR) 391 fprintf(fp, " major %d", dr->dr_major); 392 393 if (dr->dr_iacts & DRA_BACTS) { 394 if (dr->dr_bacts & DRB_HIDE) 395 fprintf(fp, " hide"); 396 if (dr->dr_bacts & DRB_UNHIDE) 397 fprintf(fp, " unhide"); 398 } 399 if (dr->dr_iacts & DRA_UID) { 400 pw = getpwuid(dr->dr_uid); 401 if (pw == NULL) 402 fprintf(fp, " user %d", dr->dr_uid); 403 else 404 fprintf(fp, " user %s", pw->pw_name); 405 } 406 if (dr->dr_iacts & DRA_GID) { 407 gr = getgrgid(dr->dr_gid); 408 if (gr == NULL) 409 fprintf(fp, " group %d", dr->dr_gid); 410 else 411 fprintf(fp, " group %s", gr->gr_name); 412 } 413 if (dr->dr_iacts & DRA_MODE) 414 fprintf(fp, " mode %o", dr->dr_mode); 415 if (dr->dr_iacts & DRA_INCSET) 416 fprintf(fp, " include %d", dr->dr_incset); 417 418 fprintf(fp, "\n"); 419 } 420