1 /* $OpenBSD: fsck.c,v 1.39 2018/09/24 21:26:00 deraadt Exp $ */ 2 /* $NetBSD: fsck.c,v 1.7 1996/10/03 20:06:30 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1996 Christos Zoulas. All rights reserved. 6 * Copyright (c) 1980, 1989, 1993, 1994 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * From: @(#)mount.c 8.19 (Berkeley) 4/19/94 34 * From: NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp 35 * 36 */ 37 38 #include <sys/types.h> 39 #include <sys/mount.h> 40 #include <sys/queue.h> 41 #include <sys/resource.h> 42 #include <sys/stat.h> 43 #include <sys/wait.h> 44 45 #include <err.h> 46 #include <errno.h> 47 #include <fstab.h> 48 #include <signal.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 #include <limits.h> 54 #include <util.h> 55 56 #include "pathnames.h" 57 #include "fsutil.h" 58 59 static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST; 60 static enum { NONET_FILTER, NET_FILTER } filter = NONET_FILTER; 61 62 TAILQ_HEAD(fstypelist, entry) opthead, selhead; 63 64 struct entry { 65 char *type; 66 char *options; 67 TAILQ_ENTRY(entry) entries; 68 }; 69 70 static int maxrun; 71 static char *options; 72 static int flags; 73 74 int main(int, char *[]); 75 76 static int checkfs(const char *, const char *, const char *, void *, pid_t *); 77 static int selected(const char *); 78 static void addoption(char *); 79 static const char *getoptions(const char *); 80 static void addentry(struct fstypelist *, const char *, const char *); 81 static void maketypelist(char *); 82 static char *catopt(char *, const char *, int); 83 static void mangle(char *, int *, const char ***, int *); 84 static void usage(void); 85 static void *isok(struct fstab *); 86 static int hasopt(const char *, const char *); 87 88 89 int 90 main(int argc, char *argv[]) 91 { 92 const char *errstr; 93 struct fstab *fs; 94 int i, rval = 0; 95 char *vfstype = NULL; 96 char *p, globopt[3]; 97 struct rlimit rl; 98 99 /* Increase our data size to the max */ 100 if (getrlimit(RLIMIT_DATA, &rl) == 0) { 101 if (geteuid() == 0) 102 rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; 103 else 104 rl.rlim_cur = rl.rlim_max; 105 if (setrlimit(RLIMIT_DATA, &rl) < 0) 106 warn("Can't set resource limit to max data size"); 107 } else 108 warn("Can't get resource limit for data size"); 109 110 checkroot(); 111 112 if (unveil("/dev", "rw") == -1) 113 err(1, "unveil"); 114 if (unveil(_PATH_FSTAB, "r") == -1) 115 err(1, "unveil"); 116 if (unveil("/sbin", "x") == -1) 117 err(1, "unveil"); 118 if (pledge("stdio rpath wpath disklabel proc exec", NULL) == -1) 119 err(1, "pledge"); 120 121 globopt[0] = '-'; 122 globopt[2] = '\0'; 123 124 TAILQ_INIT(&selhead); 125 TAILQ_INIT(&opthead); 126 127 while ((i = getopt(argc, argv, "b:dfl:nNpT:t:vy")) != -1) 128 switch (i) { 129 case 'd': 130 flags |= CHECK_DEBUG; 131 break; 132 133 case 'v': 134 flags |= CHECK_VERBOSE; 135 break; 136 137 case 'p': 138 flags |= CHECK_PREEN; 139 /*FALLTHROUGH*/ 140 case 'n': 141 case 'f': 142 case 'y': 143 globopt[1] = i; 144 options = catopt(options, globopt, 1); 145 break; 146 147 case 'b': 148 if (asprintf(&p, "-b %s", optarg) == -1) 149 err(1, "malloc failed"); 150 options = catopt(options, p, 1); 151 free(p); 152 break; 153 154 case 'l': 155 maxrun = strtonum(optarg, 0, INT_MAX, &errstr); 156 if (errstr) 157 errx(1, "-l %s: %s", optarg, errstr); 158 159 break; 160 161 case 'T': 162 if (*optarg) 163 addoption(optarg); 164 break; 165 166 case 't': 167 if (!TAILQ_EMPTY(&selhead)) 168 errx(1, "only one -t option may be specified."); 169 170 maketypelist(optarg); 171 vfstype = optarg; 172 break; 173 174 case 'N': 175 filter = NET_FILTER; 176 break; 177 178 case '?': 179 default: 180 usage(); 181 /* NOTREACHED */ 182 } 183 184 argc -= optind; 185 argv += optind; 186 187 if (argc == 0) 188 return checkfstab(flags, maxrun, isok, checkfs); 189 190 #define BADTYPE(type) \ 191 (strcmp(type, FSTAB_RO) && \ 192 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 193 194 195 for (; argc--; argv++) { 196 char *spec, *type; 197 198 if ((strncmp(*argv, "/dev/", 5) == 0 || isduid(*argv, 0)) && 199 (type = readlabelfs(*argv, 0))) { 200 spec = *argv; 201 } else if ((fs = getfsfile(*argv)) == NULL && 202 (fs = getfsspec(*argv)) == NULL) { 203 if (vfstype == NULL) 204 errx(1, 205 "%s: unknown special file or file system.", 206 *argv); 207 spec = *argv; 208 type = vfstype; 209 } else { 210 spec = fs->fs_spec; 211 type = fs->fs_vfstype; 212 if (BADTYPE(fs->fs_type)) 213 errx(1, "%s has unknown file system type.", 214 *argv); 215 } 216 217 rval |= checkfs(type, blockcheck(spec), *argv, NULL, NULL); 218 } 219 220 return rval; 221 } 222 223 224 static void * 225 isok(struct fstab *fs) 226 { 227 if (fs->fs_passno == 0) 228 return NULL; 229 230 if (BADTYPE(fs->fs_type)) 231 return NULL; 232 233 switch (filter) { 234 case NET_FILTER: 235 if (!hasopt(fs->fs_mntops, "net")) 236 return NULL; 237 break; 238 case NONET_FILTER: 239 if (hasopt(fs->fs_mntops, "net")) 240 return NULL; 241 break; 242 } 243 if (!selected(fs->fs_vfstype)) 244 return NULL; 245 246 return fs; 247 } 248 249 250 static int 251 checkfs(const char *vfstype, const char *spec, const char *mntpt, void *auxarg, 252 pid_t *pidp) 253 { 254 /* List of directories containing fsck_xxx subcommands. */ 255 static const char *edirs[] = { 256 _PATH_SBIN, 257 _PATH_USRSBIN, 258 NULL 259 }; 260 const char **argv, **edir; 261 pid_t pid; 262 int argc, i, status, maxargc; 263 char *optbuf = NULL, fsname[PATH_MAX], execname[PATH_MAX]; 264 const char *extra = getoptions(vfstype); 265 266 if (strcmp(vfstype, "ufs") == 0) 267 vfstype = MOUNT_UFS; 268 269 maxargc = 100; 270 argv = ereallocarray(NULL, maxargc, sizeof(char *)); 271 272 argc = 0; 273 (void)snprintf(fsname, sizeof(fsname), "fsck_%s", vfstype); 274 argv[argc++] = fsname; 275 276 if (options) { 277 if (extra != NULL) 278 optbuf = catopt(options, extra, 0); 279 else 280 optbuf = estrdup(options); 281 } 282 else if (extra) 283 optbuf = estrdup(extra); 284 285 if (optbuf) 286 mangle(optbuf, &argc, &argv, &maxargc); 287 288 argv[argc++] = spec; 289 argv[argc] = NULL; 290 291 if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) { 292 (void)printf("start %s %swait %s", mntpt, 293 pidp ? "no" : "", fsname); 294 for (i = 1; i < argc; i++) 295 (void)printf(" %s", argv[i]); 296 (void)printf("\n"); 297 } 298 299 switch (pid = fork()) { 300 case -1: /* Error. */ 301 warn("fork"); 302 free(optbuf); 303 free(argv); 304 return (1); 305 306 case 0: /* Child. */ 307 if (flags & CHECK_DEBUG) 308 _exit(0); 309 310 /* Go find an executable. */ 311 edir = edirs; 312 do { 313 (void)snprintf(execname, 314 sizeof(execname), "%s/fsck_%s", *edir, vfstype); 315 execv(execname, (char * const *)argv); 316 if (errno != ENOENT) { 317 if (spec) 318 warn("exec %s for %s", execname, spec); 319 else 320 warn("exec %s", execname); 321 } 322 } while (*++edir != NULL); 323 324 if (errno == ENOENT) { 325 if (spec) 326 warn("exec %s for %s", execname, spec); 327 else 328 warn("exec %s", execname); 329 } 330 exit(1); 331 /* NOTREACHED */ 332 333 default: /* Parent. */ 334 free(optbuf); 335 free(argv); 336 337 if (pidp) { 338 *pidp = pid; 339 return 0; 340 } 341 342 if (waitpid(pid, &status, 0) < 0) { 343 warn("waitpid"); 344 return (1); 345 } 346 347 if (WIFEXITED(status)) { 348 if (WEXITSTATUS(status) != 0) 349 return (WEXITSTATUS(status)); 350 } 351 else if (WIFSIGNALED(status)) { 352 warnx("%s: %s", spec, strsignal(WTERMSIG(status))); 353 return (1); 354 } 355 break; 356 } 357 358 return (0); 359 } 360 361 362 static int 363 selected(const char *type) 364 { 365 struct entry *e; 366 367 /* If no type specified, it's always selected. */ 368 TAILQ_FOREACH(e, &selhead, entries) 369 if (!strncmp(e->type, type, MFSNAMELEN)) 370 return which == IN_LIST ? 1 : 0; 371 372 return which == IN_LIST ? 0 : 1; 373 } 374 375 376 static const char * 377 getoptions(const char *type) 378 { 379 struct entry *e; 380 381 TAILQ_FOREACH(e, &opthead, entries) 382 if (!strncmp(e->type, type, MFSNAMELEN)) 383 return e->options; 384 return ""; 385 } 386 387 388 static void 389 addoption(char *optstr) 390 { 391 char *newoptions; 392 struct entry *e; 393 394 if ((newoptions = strchr(optstr, ':')) == NULL) 395 errx(1, "Invalid option string"); 396 397 *newoptions++ = '\0'; 398 399 TAILQ_FOREACH(e, &opthead, entries) 400 if (!strncmp(e->type, optstr, MFSNAMELEN)) { 401 e->options = catopt(e->options, newoptions, 1); 402 return; 403 } 404 addentry(&opthead, optstr, newoptions); 405 } 406 407 408 static void 409 addentry(struct fstypelist *list, const char *type, const char *opts) 410 { 411 struct entry *e; 412 413 e = emalloc(sizeof(struct entry)); 414 e->type = estrdup(type); 415 e->options = estrdup(opts); 416 TAILQ_INSERT_TAIL(list, e, entries); 417 } 418 419 420 static void 421 maketypelist(char *fslist) 422 { 423 char *ptr; 424 425 if ((fslist == NULL) || (fslist[0] == '\0')) 426 errx(1, "empty type list"); 427 428 if (fslist[0] == 'n' && fslist[1] == 'o') { 429 fslist += 2; 430 which = NOT_IN_LIST; 431 } 432 else 433 which = IN_LIST; 434 435 while ((ptr = strsep(&fslist, ",")) != NULL) 436 addentry(&selhead, ptr, ""); 437 438 } 439 440 441 static char * 442 catopt(char *s0, const char *s1, int fr) 443 { 444 char *cp; 445 446 if (s0 && *s0) { 447 if (asprintf(&cp, "%s,%s", s0, s1) == -1) 448 err(1, "malloc failed"); 449 } else 450 cp = estrdup(s1); 451 452 if (fr) 453 free(s0); 454 return (cp); 455 } 456 457 458 static void 459 mangle(char *opts, int *argcp, const char ***argvp, int *maxargcp) 460 { 461 char *p, *s; 462 int argc = *argcp, maxargc = *maxargcp; 463 const char **argv = *argvp; 464 465 for (s = opts; (p = strsep(&s, ",")) != NULL;) { 466 /* always leave space for one more argument and the NULL */ 467 if (argc >= maxargc - 3) { 468 int newmaxargc = maxargc + 50; 469 470 argv = ereallocarray(argv, newmaxargc, sizeof(char *)); 471 maxargc = newmaxargc; 472 } 473 if (*p != '\0') { 474 if (*p == '-') { 475 argv[argc++] = p; 476 p = strchr(p, '='); 477 if (p) { 478 *p = '\0'; 479 argv[argc++] = p+1; 480 } 481 } 482 else { 483 argv[argc++] = "-o"; 484 argv[argc++] = p; 485 } 486 } 487 } 488 489 *argcp = argc; 490 *argvp = argv; 491 *maxargcp = maxargc; 492 } 493 494 static int 495 hasopt(const char *mntopts, const char *option) 496 { 497 int found; 498 char *opt, *optbuf; 499 500 if (mntopts == NULL) 501 return (0); 502 optbuf = strdup(mntopts); 503 found = 0; 504 for (opt = optbuf; !found && opt != NULL; strsep(&opt, ",")) 505 found = !strncmp(opt, option, strlen(option)); 506 free(optbuf); 507 return (found); 508 } 509 510 511 static void 512 usage(void) 513 { 514 extern char *__progname; 515 516 fprintf(stderr, "usage: %s " 517 "[-dfNnpvy] [-b block#] [-l maxparallel] [-T fstype:fsoptions]\n" 518 " [-t fstype] [special | node ...]\n", __progname); 519 exit(1); 520 } 521