1 /* $NetBSD: fsck.c,v 1.11 1997/06/23 01:03:35 mikel 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 * 39 */ 40 41 static char rcsid[] = "$NetBSD: fsck.c,v 1.11 1997/06/23 01:03:35 mikel Exp $"; 42 43 #include <sys/param.h> 44 #include <sys/mount.h> 45 #include <sys/queue.h> 46 #include <sys/wait.h> 47 #define DKTYPENAMES 48 #include <sys/disklabel.h> 49 #include <sys/ioctl.h> 50 51 #include <err.h> 52 #include <errno.h> 53 #include <fstab.h> 54 #include <fcntl.h> 55 #include <signal.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 61 #include "pathnames.h" 62 #include "fsutil.h" 63 64 static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST; 65 66 TAILQ_HEAD(fstypelist, entry) opthead, selhead; 67 68 struct entry { 69 char *type; 70 char *options; 71 TAILQ_ENTRY(entry) entries; 72 }; 73 74 static int maxrun = 0; 75 static char *options = NULL; 76 static int flags = 0; 77 78 int main __P((int, char *[])); 79 80 static int checkfs __P((const char *, const char *, const char *, void *, 81 pid_t *)); 82 static int selected __P((const char *)); 83 static void addoption __P((char *)); 84 static const char *getoptions __P((const char *)); 85 static void addentry __P((struct fstypelist *, const char *, const char *)); 86 static void maketypelist __P((char *)); 87 static char *catopt __P((char *, const char *, int)); 88 static void mangle __P((char *, int *, const char ***, int *)); 89 static char *getfslab __P((const char *)); 90 static void usage __P((void)); 91 static void *isok __P((struct fstab *)); 92 93 int 94 main(argc, argv) 95 int argc; 96 char *argv[]; 97 { 98 struct fstab *fs; 99 int i, rval = 0; 100 char *vfstype = NULL; 101 char globopt[3]; 102 103 globopt[0] = '-'; 104 globopt[2] = '\0'; 105 106 TAILQ_INIT(&selhead); 107 TAILQ_INIT(&opthead); 108 109 while ((i = getopt(argc, argv, "dvpfnyl:t:T:")) != -1) 110 switch (i) { 111 case 'd': 112 flags |= CHECK_DEBUG; 113 break; 114 115 case 'v': 116 flags |= CHECK_VERBOSE; 117 break; 118 119 case 'p': 120 flags |= CHECK_PREEN; 121 /*FALLTHROUGH*/ 122 case 'n': 123 case 'f': 124 case 'y': 125 globopt[1] = i; 126 options = catopt(options, globopt, 1); 127 break; 128 129 case 'l': 130 maxrun = atoi(optarg); 131 break; 132 133 case 'T': 134 if (*optarg) 135 addoption(optarg); 136 break; 137 138 case 't': 139 if (selhead.tqh_first != NULL) 140 errx(1, "only one -t option may be specified."); 141 142 maketypelist(optarg); 143 vfstype = optarg; 144 break; 145 146 case '?': 147 default: 148 usage(); 149 /* NOTREACHED */ 150 } 151 152 argc -= optind; 153 argv += optind; 154 155 if (argc == 0) 156 return checkfstab(flags, maxrun, isok, checkfs); 157 158 #define BADTYPE(type) \ 159 (strcmp(type, FSTAB_RO) && \ 160 strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 161 162 163 for (; argc--; argv++) { 164 char *spec, *type; 165 166 if ((fs = getfsfile(*argv)) == NULL && 167 (fs = getfsspec(*argv)) == NULL) { 168 if (vfstype == NULL) 169 vfstype = getfslab(*argv); 170 spec = *argv; 171 type = vfstype; 172 } 173 else { 174 spec = fs->fs_spec; 175 type = fs->fs_vfstype; 176 if (BADTYPE(fs->fs_type)) 177 errx(1, "%s has unknown file system type.", 178 *argv); 179 } 180 181 rval |= checkfs(type, blockcheck(spec), *argv, NULL, NULL); 182 } 183 184 return rval; 185 } 186 187 188 static void * 189 isok(fs) 190 struct fstab *fs; 191 { 192 if (fs->fs_passno == 0) 193 return NULL; 194 195 if (BADTYPE(fs->fs_type)) 196 return NULL; 197 198 if (!selected(fs->fs_vfstype)) 199 return NULL; 200 201 return fs; 202 } 203 204 205 static int 206 checkfs(vfstype, spec, mntpt, auxarg, pidp) 207 const char *vfstype, *spec, *mntpt; 208 void *auxarg; 209 pid_t *pidp; 210 { 211 /* List of directories containing fsck_xxx subcommands. */ 212 static const char *edirs[] = { 213 _PATH_SBIN, 214 _PATH_USRSBIN, 215 NULL 216 }; 217 char execbase[MAXPATHLEN]; 218 const char **argv, **edir; 219 pid_t pid; 220 int argc = 1, i, status, maxargc; 221 char *optbuf = NULL, execname[MAXPATHLEN + 1]; 222 const char *extra = getoptions(vfstype); 223 224 225 #ifdef __GNUC__ 226 /* Avoid vfork clobbering */ 227 (void) &optbuf; 228 (void) &vfstype; 229 #endif 230 231 if (strcmp(vfstype, "ufs") == 0) 232 vfstype = MOUNT_UFS; 233 234 maxargc = 100; 235 argv = emalloc(sizeof(char *) * maxargc); 236 237 /* construct basename of executable and argv[0] simultaneously */ 238 (void) snprintf(execbase, sizeof(execbase), "fsck_%s", vfstype); 239 argv[0] = vfstype; 240 241 if (options) { 242 if (extra != NULL) 243 optbuf = catopt(options, extra, 0); 244 else 245 optbuf = estrdup(options); 246 } 247 else if (extra) 248 optbuf = estrdup(extra); 249 250 if (optbuf) 251 mangle(optbuf, &argc, &argv, &maxargc); 252 253 argv[argc++] = spec; 254 argv[argc] = NULL; 255 256 if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) { 257 (void)printf("start %s %swait", mntpt, 258 pidp ? "no" : ""); 259 for (i = 0; i < argc; i++) 260 (void)printf(" %s", argv[i]); 261 (void)printf("\n"); 262 } 263 264 switch (pid = vfork()) { 265 case -1: /* Error. */ 266 warn("vfork"); 267 if (optbuf) 268 free(optbuf); 269 return (1); 270 271 case 0: /* Child. */ 272 if (flags & CHECK_DEBUG) 273 _exit(0); 274 275 /* Go find an executable. */ 276 edir = edirs; 277 do { 278 (void)snprintf(execname, 279 sizeof(execname), "%s/%s", *edir, execbase); 280 execv(execname, (char * const *)argv); 281 if (errno != ENOENT) 282 if (spec) 283 warn("exec %s for %s", execname, spec); 284 else 285 warn("exec %s", execname); 286 } while (*++edir != NULL); 287 288 if (errno == ENOENT) 289 if (spec) 290 warn("exec %s for %s", execname, spec); 291 else 292 warn("exec %s", execname); 293 _exit(1); 294 /* NOTREACHED */ 295 296 default: /* Parent. */ 297 if (optbuf) 298 free(optbuf); 299 300 if (pidp) { 301 *pidp = pid; 302 return 0; 303 } 304 305 if (waitpid(pid, &status, 0) < 0) { 306 warn("waitpid"); 307 return (1); 308 } 309 310 if (WIFEXITED(status)) { 311 if (WEXITSTATUS(status) != 0) 312 return (WEXITSTATUS(status)); 313 } 314 else if (WIFSIGNALED(status)) { 315 warnx("%s: %s", spec, strsignal(WTERMSIG(status))); 316 return (1); 317 } 318 break; 319 } 320 321 return (0); 322 } 323 324 325 static int 326 selected(type) 327 const char *type; 328 { 329 struct entry *e; 330 331 /* If no type specified, it's always selected. */ 332 for (e = selhead.tqh_first; e != NULL; e = e->entries.tqe_next) 333 if (!strncmp(e->type, type, MFSNAMELEN)) 334 return which == IN_LIST ? 1 : 0; 335 336 return which == IN_LIST ? 0 : 1; 337 } 338 339 340 static const char * 341 getoptions(type) 342 const char *type; 343 { 344 struct entry *e; 345 346 for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next) 347 if (!strncmp(e->type, type, MFSNAMELEN)) 348 return e->options; 349 return ""; 350 } 351 352 353 static void 354 addoption(optstr) 355 char *optstr; 356 { 357 char *newoptions; 358 struct entry *e; 359 360 if ((newoptions = strchr(optstr, ':')) == NULL) 361 errx(1, "Invalid option string"); 362 363 *newoptions++ = '\0'; 364 365 for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next) 366 if (!strncmp(e->type, optstr, MFSNAMELEN)) { 367 e->options = catopt(e->options, newoptions, 1); 368 return; 369 } 370 addentry(&opthead, optstr, newoptions); 371 } 372 373 374 static void 375 addentry(list, type, opts) 376 struct fstypelist *list; 377 const char *type; 378 const char *opts; 379 { 380 struct entry *e; 381 382 e = emalloc(sizeof(struct entry)); 383 e->type = estrdup(type); 384 e->options = estrdup(opts); 385 TAILQ_INSERT_TAIL(list, e, entries); 386 } 387 388 389 static void 390 maketypelist(fslist) 391 char *fslist; 392 { 393 char *ptr; 394 395 if ((fslist == NULL) || (fslist[0] == '\0')) 396 errx(1, "empty type list"); 397 398 if (fslist[0] == 'n' && fslist[1] == 'o') { 399 fslist += 2; 400 which = NOT_IN_LIST; 401 } 402 else 403 which = IN_LIST; 404 405 while ((ptr = strsep(&fslist, ",")) != NULL) 406 addentry(&selhead, ptr, ""); 407 408 } 409 410 411 static char * 412 catopt(s0, s1, fr) 413 char *s0; 414 const char *s1; 415 int fr; 416 { 417 size_t i; 418 char *cp; 419 420 if (s0 && *s0) { 421 i = strlen(s0) + strlen(s1) + 1 + 1; 422 cp = emalloc(i); 423 (void)snprintf(cp, i, "%s,%s", s0, s1); 424 } 425 else 426 cp = estrdup(s1); 427 428 if (s0 && fr) 429 free(s0); 430 return (cp); 431 } 432 433 434 static void 435 mangle(opts, argcp, argvp, maxargcp) 436 char *opts; 437 int *argcp; 438 const char ***argvp; 439 int *maxargcp; 440 { 441 char *p, *s; 442 int argc = *argcp, maxargc = *maxargcp; 443 const char **argv = *argvp; 444 445 argc = *argcp; 446 maxargc = *maxargcp; 447 448 for (s = opts; (p = strsep(&s, ",")) != NULL;) { 449 /* always leave space for one more argument and the NULL */ 450 if (argc >= maxargc - 3) { 451 maxargc += 50; 452 argv = erealloc(argv, maxargc * sizeof(char *)); 453 } 454 if (*p != '\0') 455 if (*p == '-') { 456 argv[argc++] = p; 457 p = strchr(p, '='); 458 if (p) { 459 *p = '\0'; 460 argv[argc++] = p+1; 461 } 462 } 463 else { 464 argv[argc++] = "-o"; 465 argv[argc++] = p; 466 } 467 } 468 469 *argcp = argc; 470 *argvp = argv; 471 *maxargcp = maxargc; 472 } 473 474 475 static char * 476 getfslab(str) 477 const char *str; 478 { 479 struct disklabel dl; 480 int fd; 481 char p, *vfstype; 482 u_char t; 483 484 /* deduce the filesystem type from the disk label */ 485 if ((fd = open(str, O_RDONLY)) == -1) 486 err(1, "cannot open `%s'", str); 487 488 if (ioctl(fd, DIOCGDINFO, &dl) == -1) 489 err(1, "cannot get disklabel for `%s'", str); 490 491 (void) close(fd); 492 493 p = str[strlen(str) - 1]; 494 495 if ((p - 'a') >= dl.d_npartitions) 496 errx(1, "partition `%s' is not defined on disk", str); 497 498 if ((t = dl.d_partitions[p - 'a'].p_fstype) >= DKMAXTYPES) 499 errx(1, "partition `%s' is not of a legal vfstype", 500 str); 501 502 if ((vfstype = fscknames[t]) == NULL) 503 errx(1, "vfstype `%s' on partition `%s' is not supported", 504 fstypenames[t], str); 505 506 return vfstype; 507 } 508 509 510 static void 511 usage() 512 { 513 extern char *__progname; 514 static const char common[] = 515 "[-dpvlyn] [-T fstype:fsoptions] [-t fstype]"; 516 517 (void)fprintf(stderr, "Usage: %s %s [special|node]...\n", 518 __progname, common); 519 exit(1); 520 } 521