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