fsck.c revision 88f8af61a48bafe35fdbfcb0d19f4a83f0ce3d66
130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng/* 230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * pfsck --- A generic, parallelizing front-end for the fsck program. 330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * It will automatically try to run fsck programs in parallel if the 430692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * devices are on separate spindles. It is based on the same ideas as 530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * the generic front end for fsck by David Engel and Fred van Kempen, 630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * but it has been completely rewritten from scratch to support 730692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * parallel execution. 830692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * 930692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * Written by Theodore Ts'o, <tytso@mit.edu> 1030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * 1130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * Usage: fsck [-ACVRNTM] [-s] [-t fstype] [fs-options] device 1230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * 1330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994: 1430692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * o Changed -t fstype to behave like with mount when -A (all file 1530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * systems) or -M (like mount) is specified. 1630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * o fsck looks if it can find the fsck.type program to decide 1730692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * if it should ignore the fs type. This way more fsck programs 1830692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * can be added without changing this front-end. 1930692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * o -R flag skip root file system. 2030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * 2130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 Theodore Ts'o. 2230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * 2330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * %Begin-Header% 2430692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * This file may be redistributed under the terms of the GNU Public 2530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * License. 2630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * %End-Header% 2730692c65c4174412c90e79489e98ab85c1a7412fBen Cheng */ 2830692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 2930692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <sys/types.h> 3030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <sys/wait.h> 3130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <sys/signal.h> 3230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <sys/stat.h> 3330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <limits.h> 3430692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <stdio.h> 3530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <ctype.h> 3630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <string.h> 3730692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <time.h> 3830692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#if HAVE_STDLIB_H 3930692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <stdlib.h> 4030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#endif 4130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#if HAVE_ERRNO_H 4230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <errno.h> 4330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#endif 4430692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#if HAVE_PATHS_H 4530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <paths.h> 4630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#endif 4730692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#if HAVE_UNISTD_H 4830692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <unistd.h> 4930692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#endif 5030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#if HAVE_ERRNO_H 5130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <errno.h> 5230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#endif 5330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include <malloc.h> 5430692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 5530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include "../version.h" 5630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include "nls-enable.h" 5730692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include "fsck.h" 5830692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#include "get_device_by_label.h" 5930692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 6030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#ifndef _PATH_MNTTAB 6130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#define _PATH_MNTTAB "/etc/fstab" 6230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#endif 6330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 6430692c65c4174412c90e79489e98ab85c1a7412fBen Chengstatic const char *ignored_types[] = { 6530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "ignore", 6630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "iso9660", 6730692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "nfs", 6830692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "proc", 6930692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "sw", 7030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "swap", 7130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng NULL 7230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng}; 7330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 7430692c65c4174412c90e79489e98ab85c1a7412fBen Chengstatic const char *really_wanted[] = { 7530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "minix", 7630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "ext2", 7730692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "ext3", 7830692c65c4174412c90e79489e98ab85c1a7412fBen Cheng "xiafs", 7930692c65c4174412c90e79489e98ab85c1a7412fBen Cheng NULL 8030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng}; 8130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 8230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng#define BASE_MD "/dev/md" 8330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 8430692c65c4174412c90e79489e98ab85c1a7412fBen Cheng/* 8530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng * Global variables for options 8630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng */ 8730692c65c4174412c90e79489e98ab85c1a7412fBen Chengchar *devices[MAX_DEVICES]; 8830692c65c4174412c90e79489e98ab85c1a7412fBen Chengchar *args[MAX_ARGS]; 8930692c65c4174412c90e79489e98ab85c1a7412fBen Chengint num_devices, num_args; 9030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 9130692c65c4174412c90e79489e98ab85c1a7412fBen Chengint verbose = 0; 9230692c65c4174412c90e79489e98ab85c1a7412fBen Chengint doall = 0; 9330692c65c4174412c90e79489e98ab85c1a7412fBen Chengint noexecute = 0; 9430692c65c4174412c90e79489e98ab85c1a7412fBen Chengint serialize = 0; 9530692c65c4174412c90e79489e98ab85c1a7412fBen Chengint skip_root = 0; 9630692c65c4174412c90e79489e98ab85c1a7412fBen Chengint like_mount = 0; 9730692c65c4174412c90e79489e98ab85c1a7412fBen Chengint notitle = 0; 9830692c65c4174412c90e79489e98ab85c1a7412fBen Chengint parallel_root = 0; 9930692c65c4174412c90e79489e98ab85c1a7412fBen Chengint progress = 0; 10030692c65c4174412c90e79489e98ab85c1a7412fBen Chengint force_all_parallel = 0; 10130692c65c4174412c90e79489e98ab85c1a7412fBen Chengchar *progname; 10230692c65c4174412c90e79489e98ab85c1a7412fBen Chengchar *fstype = NULL; 10330692c65c4174412c90e79489e98ab85c1a7412fBen Chengstruct fs_info *filesys_info; 10430692c65c4174412c90e79489e98ab85c1a7412fBen Chengstruct fsck_instance *instance_list; 10530692c65c4174412c90e79489e98ab85c1a7412fBen Chengconst char *fsck_prefix_path = "/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc"; 10630692c65c4174412c90e79489e98ab85c1a7412fBen Chengchar *fsck_path = 0; 10730692c65c4174412c90e79489e98ab85c1a7412fBen Chengstatic int ignore(struct fs_info *); 10830692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 10930692c65c4174412c90e79489e98ab85c1a7412fBen Chengchar *string_copy(const char *s) 11030692c65c4174412c90e79489e98ab85c1a7412fBen Cheng{ 11130692c65c4174412c90e79489e98ab85c1a7412fBen Cheng char *ret; 11230692c65c4174412c90e79489e98ab85c1a7412fBen Cheng 11330692c65c4174412c90e79489e98ab85c1a7412fBen Cheng ret = malloc(strlen(s)+1); 11430692c65c4174412c90e79489e98ab85c1a7412fBen Cheng if (ret) 11530692c65c4174412c90e79489e98ab85c1a7412fBen Cheng strcpy(ret, s); 11630692c65c4174412c90e79489e98ab85c1a7412fBen Cheng return ret; 11730692c65c4174412c90e79489e98ab85c1a7412fBen Cheng} 118 119static char *skip_over_blank(char *cp) 120{ 121 while (*cp && isspace(*cp)) 122 cp++; 123 return cp; 124} 125 126static char *skip_over_word(char *cp) 127{ 128 while (*cp && !isspace(*cp)) 129 cp++; 130 return cp; 131} 132 133static void strip_line(char *line) 134{ 135 char *p; 136 137 while (*line) { 138 p = line + strlen(line) - 1; 139 if ((*p == '\n') || (*p == '\r')) 140 *p = 0; 141 else 142 break; 143 } 144} 145 146static char *parse_word(char **buf) 147{ 148 char *word, *next; 149 150 word = *buf; 151 if (*word == 0) 152 return 0; 153 154 word = skip_over_blank(word); 155 next = skip_over_word(word); 156 if (*next) 157 *next++ = 0; 158 *buf = next; 159 return word; 160} 161 162static void free_instance(struct fsck_instance *i) 163{ 164 if (i->prog) 165 free(i->prog); 166 if (i->device) 167 free(i->device); 168 if (i->base_device) 169 free(i->base_device); 170 free(i); 171 return; 172} 173 174static int parse_fstab_line(char *line, struct fs_info **ret_fs) 175{ 176 char *device, *mntpnt, *type, *opts, *freq, *passno, *cp; 177 struct fs_info *fs; 178 179 *ret_fs = 0; 180 strip_line(line); 181 if ((cp = strchr(line, '#'))) 182 *cp = 0; /* Ignore everything after the comment char */ 183 cp = line; 184 185 device = parse_word(&cp); 186 mntpnt = parse_word(&cp); 187 type = parse_word(&cp); 188 opts = parse_word(&cp); 189 freq = parse_word(&cp); 190 passno = parse_word(&cp); 191 192 if (!device) 193 return 0; /* Allow blank lines */ 194 195 if (!mntpnt || !type) 196 return -1; 197 198 if (!(fs = malloc(sizeof(struct fs_info)))) 199 return -1; 200 201 fs->device = string_copy(device); 202 fs->mountpt = string_copy(mntpnt); 203 fs->type = string_copy(type); 204 fs->opts = string_copy(opts ? opts : ""); 205 fs->freq = freq ? atoi(freq) : -1; 206 fs->passno = passno ? atoi(passno) : -1; 207 fs->flags = 0; 208 fs->next = NULL; 209 210 *ret_fs = fs; 211 212 return 0; 213} 214 215/* 216 * Interpret the device name if necessary 217 */ 218static char *interpret_device(char *spec) 219{ 220 char *dev = NULL; 221 222 if (!strncmp(spec, "UUID=", 5)) 223 dev = get_spec_by_uuid(spec+5); 224 else if (!strncmp(spec, "LABEL=", 6)) 225 dev = get_spec_by_volume_label(spec+6); 226 else 227 return spec; 228 if (dev) { 229 free(spec); 230 return (dev); 231 } 232 /* 233 * Check to see if this was because /proc/partitions isn't 234 * found. 235 */ 236 if (access("/proc/partitions", R_OK) < 0) { 237 fprintf(stderr, "Couldn't open /proc/partitions: %s\n", 238 strerror(errno)); 239 fprintf(stderr, "Is /proc mounted?\n"); 240 exit(EXIT_ERROR); 241 } 242 /* 243 * Check to see if this is because we're not running as root 244 */ 245 if (geteuid()) 246 fprintf(stderr, "Must be root to scan for matching " 247 "filesystems: %s\n", spec); 248 else 249 fprintf(stderr, "Couldn't find matching filesystem: %s\n", 250 spec); 251 exit(EXIT_ERROR); 252} 253 254/* 255 * Interpret filesystem auto type if necessary 256 */ 257static void interpret_type(struct fs_info *fs) 258{ 259 const char *type; 260 261 if (strcmp(fs->type, "auto") == 0) { 262 type = identify_fs(fs->device); 263 if (type) { 264 free(fs->type); 265 fs->type = string_copy(type); 266 } else 267 fprintf(stderr, _("Could not determine " 268 "filesystem type for %s\n"), 269 fs->device); 270 } 271} 272 273 274/* 275 * Load the filesystem database from /etc/fstab 276 */ 277static void load_fs_info(const char *filename) 278{ 279 FILE *f; 280 char buf[1024]; 281 int lineno = 0; 282 int old_fstab = 1; 283 struct fs_info *fs, *fs_last = NULL; 284 285 filesys_info = NULL; 286 if ((f = fopen(filename, "r")) == NULL) { 287 fprintf(stderr, _("WARNING: couldn't open %s: %s\n"), 288 filename, strerror(errno)); 289 return; 290 } 291 while (!feof(f)) { 292 lineno++; 293 if (!fgets(buf, sizeof(buf), f)) 294 break; 295 buf[sizeof(buf)-1] = 0; 296 if (parse_fstab_line(buf, &fs) < 0) { 297 fprintf(stderr, _("WARNING: bad format " 298 "on line %d of %s\n"), lineno, filename); 299 continue; 300 } 301 if (!fs) 302 continue; 303 if (!filesys_info) 304 filesys_info = fs; 305 else 306 fs_last->next = fs; 307 fs_last = fs; 308 if (fs->passno < 0) 309 fs->passno = 0; 310 else 311 old_fstab = 0; 312 } 313 314 fclose(f); 315 316 if (old_fstab) { 317 fprintf(stderr, _("\007\007\007" 318 "WARNING: Your /etc/fstab does not contain the fsck passno\n" 319 " field. I will kludge around things for you, but you\n" 320 " should fix your /etc/fstab file as soon as you can.\n\n")); 321 322 for (fs = filesys_info; fs; fs = fs->next) { 323 fs->passno = 1; 324 } 325 } 326} 327 328/* Lookup filesys in /etc/fstab and return the corresponding entry. */ 329static struct fs_info *lookup(char *filesys) 330{ 331 struct fs_info *fs; 332 int try_again = 0; 333 334 /* No filesys name given. */ 335 if (filesys == NULL) 336 return NULL; 337 338 for (fs = filesys_info; fs; fs = fs->next) { 339 if (strchr(fs->device, '=')) 340 try_again++; 341 if (!strcmp(filesys, fs->device) || 342 !strcmp(filesys, fs->mountpt)) 343 break; 344 } 345 if (fs && strchr(fs->device, '=')) 346 fs->device = interpret_device(fs->device); 347 348 if (fs || !try_again) 349 return fs; 350 351 for (fs = filesys_info; fs; fs = fs->next) { 352 fs->device = interpret_device(fs->device); 353 if (!strcmp(filesys, fs->device) || 354 !strcmp(filesys, fs->mountpt)) 355 break; 356 } 357 358 return fs; 359} 360 361/* Find fsck program for a given fs type. */ 362static char *find_fsck(char *type) 363{ 364 char *s; 365 const char *tpl; 366 static char prog[256]; 367 char *p = string_copy(fsck_path); 368 struct stat st; 369 370 /* Are we looking for a program or just a type? */ 371 tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s"); 372 373 for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) { 374 sprintf(prog, tpl, s, type); 375 if (stat(prog, &st) == 0) break; 376 } 377 free(p); 378 return(s ? prog : NULL); 379} 380 381static int progress_active(NOARGS) 382{ 383 struct fsck_instance *inst; 384 385 for (inst = instance_list; inst; inst = inst->next) { 386 if (inst->flags & FLAG_DONE) 387 continue; 388 if (inst->flags & FLAG_PROGRESS) 389 return 1; 390 } 391 return 0; 392} 393 394/* 395 * Execute a particular fsck program, and link it into the list of 396 * child processes we are waiting for. 397 */ 398static int execute(const char *type, char *device, char *mntpt, 399 int interactive) 400{ 401 char *s, *argv[80], prog[80]; 402 int argc, i; 403 struct fsck_instance *inst, *p; 404 pid_t pid; 405 406 inst = malloc(sizeof(struct fsck_instance)); 407 if (!inst) 408 return ENOMEM; 409 memset(inst, 0, sizeof(struct fsck_instance)); 410 411 sprintf(prog, "fsck.%s", type); 412 argv[0] = string_copy(prog); 413 argc = 1; 414 415 for (i=0; i <num_args; i++) 416 argv[argc++] = string_copy(args[i]); 417 418 if (progress & !progress_active()) { 419 if ((strcmp(type, "ext2") == 0) || 420 (strcmp(type, "ext3") == 0)) { 421 argv[argc++] = string_copy("-C0"); 422 inst->flags |= FLAG_PROGRESS; 423 } 424 } 425 426 argv[argc++] = string_copy(device); 427 argv[argc] = 0; 428 429 s = find_fsck(prog); 430 if (s == NULL) { 431 fprintf(stderr, _("fsck: %s: not found\n"), prog); 432 return ENOENT; 433 } 434 435 if (verbose || noexecute) { 436 printf("[%s -- %s] ", s, mntpt ? mntpt : device); 437 for (i=0; i < argc; i++) 438 printf("%s ", argv[i]); 439 printf("\n"); 440 } 441 442 /* Fork and execute the correct program. */ 443 if (noexecute) 444 pid = -1; 445 else if ((pid = fork()) < 0) { 446 perror("fork"); 447 return errno; 448 } else if (pid == 0) { 449 if (!interactive) 450 close(0); 451 (void) execv(s, argv); 452 perror(argv[0]); 453 exit(EXIT_ERROR); 454 } 455 456 for (i=0; i < argc; i++) 457 free(argv[i]); 458 459 inst->pid = pid; 460 inst->prog = string_copy(prog); 461 inst->type = string_copy(type); 462 inst->device = string_copy(device); 463 inst->base_device = base_device(device); 464 inst->start_time = time(0); 465 inst->next = NULL; 466 467 /* 468 * Find the end of the list, so we add the instance on at the end. 469 */ 470 for (p = instance_list; p && p->next; p = p->next); 471 472 if (p) 473 p->next = inst; 474 else 475 instance_list = inst; 476 477 return 0; 478} 479 480/* 481 * Wait for one child process to exit; when it does, unlink it from 482 * the list of executing child processes, and return it. 483 */ 484static struct fsck_instance *wait_one(NOARGS) 485{ 486 int status; 487 int sig; 488 struct fsck_instance *inst, *inst2, *prev; 489 pid_t pid; 490 491 if (!instance_list) 492 return NULL; 493 494 if (noexecute) { 495 inst = instance_list; 496 instance_list = inst->next; 497 inst->exit_status = 0; 498 return(inst); 499 } 500 501 /* 502 * gcc -Wall fails saving throw against stupidity 503 * (inst and prev are thought to be uninitialized variables) 504 */ 505 inst = prev = NULL; 506 507 do { 508 pid = wait(&status); 509 if (pid < 0) { 510 if ((errno == EINTR) || (errno == EAGAIN)) 511 continue; 512 if (errno == ECHILD) { 513 fprintf(stderr, 514 _("%s: wait: No more child process?!?\n"), 515 progname); 516 return NULL; 517 } 518 perror("wait"); 519 continue; 520 } 521 for (prev = 0, inst = instance_list; 522 inst; 523 prev = inst, inst = inst->next) { 524 if (inst->pid == pid) 525 break; 526 } 527 } while (!inst); 528 529 if (WIFEXITED(status)) 530 status = WEXITSTATUS(status); 531 else if (WIFSIGNALED(status)) { 532 sig = WTERMSIG(status); 533 if (sig == SIGINT) { 534 status = EXIT_UNCORRECTED; 535 } else { 536 printf(_("Warning... %s for device %s exited " 537 "with signal %d.\n"), 538 inst->prog, inst->device, sig); 539 status = EXIT_ERROR; 540 } 541 } else { 542 printf(_("%s %s: status is %x, should never happen.\n"), 543 inst->prog, inst->device, status); 544 status = EXIT_ERROR; 545 } 546 inst->exit_status = status; 547 if (prev) 548 prev->next = inst->next; 549 else 550 instance_list = inst->next; 551 if (progress && (inst->flags & FLAG_PROGRESS) && 552 !progress_active()) { 553 for (inst2 = instance_list; inst2; inst2 = inst2->next) { 554 if (inst2->flags & FLAG_DONE) 555 continue; 556 if (strcmp(inst2->type, "ext2") && 557 strcmp(inst2->type, "ext3")) 558 continue; 559 /* 560 * If we've just started the fsck, wait a tiny 561 * bit before sending the kill, to give it 562 * time to set up the signal handler 563 */ 564 if (inst2->start_time < time(0)+2) { 565 if (fork() == 0) { 566 sleep(1); 567 kill(inst2->pid, SIGUSR1); 568 exit(0); 569 } 570 } else 571 kill(inst2->pid, SIGUSR1); 572 inst2->flags |= FLAG_PROGRESS; 573 break; 574 } 575 } 576 return inst; 577} 578 579/* 580 * Wait until all executing child processes have exited; return the 581 * logical OR of all of their exit code values. 582 */ 583static int wait_all(NOARGS) 584{ 585 struct fsck_instance *inst; 586 int global_status = 0; 587 588 while (instance_list) { 589 inst = wait_one(); 590 if (!inst) 591 break; 592 global_status |= inst->exit_status; 593 free_instance(inst); 594 } 595 return global_status; 596} 597 598/* 599 * Run the fsck program on a particular device 600 * 601 * If the type is specified using -t, and it isn't prefixed with "no" 602 * (as in "noext2") and only one filesystem type is specified, then 603 * use that type regardless of what is specified in /etc/fstab. 604 * 605 * If the type isn't specified by the user, then use either the type 606 * specified in /etc/fstab, or DEFAULT_FSTYPE. 607 */ 608static void fsck_device(char *device, int interactive) 609{ 610 const char *type = 0; 611 struct fs_info *fsent; 612 int retval; 613 614 if (fstype && strncmp(fstype, "no", 2) && 615 strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) && 616 !strchr(fstype, ',')) 617 type = fstype; 618 619 if ((fsent = lookup(device))) { 620 device = fsent->device; 621 interpret_type(fsent); 622 if (!type) 623 type = fsent->type; 624 } 625 if (!type) 626 type = DEFAULT_FSTYPE; 627 628 retval = execute(type, device, fsent ? fsent->mountpt : 0, 629 interactive); 630 if (retval) { 631 fprintf(stderr, _("%s: Error %d while executing fsck.%s " 632 "for %s\n"), progname, retval, type, device); 633 } 634} 635 636 637/* 638 * Deal with the fsck -t argument. 639 */ 640struct fs_type_compile { 641 char **list; 642 int *type; 643 int negate; 644} fs_type_compiled; 645 646#define FS_TYPE_NORMAL 0 647#define FS_TYPE_OPT 1 648#define FS_TYPE_NEGOPT 2 649 650static const char *fs_type_syntax_error = 651N_("Either all or none of the filesystem types passed to -t must be prefixed\n" 652 "with 'no' or '!'.\n"); 653 654static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp) 655{ 656 char *cp, *list, *s; 657 int num = 2; 658 int negate, first_negate = 1; 659 660 if (fs_type) { 661 for (cp=fs_type; *cp; cp++) { 662 if (*cp == ',') 663 num++; 664 } 665 } 666 667 cmp->list = malloc(num * sizeof(char *)); 668 cmp->type = malloc(num * sizeof(int)); 669 if (!cmp->list || !cmp->type) { 670 fprintf(stderr, _("Couldn't allocate memory for " 671 "filesystem types\n")); 672 exit(EXIT_ERROR); 673 } 674 memset(cmp->list, 0, num * sizeof(char *)); 675 memset(cmp->type, 0, num * sizeof(int)); 676 cmp->negate = 0; 677 678 if (!fs_type) 679 return; 680 681 list = string_copy(fs_type); 682 num = 0; 683 s = strtok(list, ","); 684 while(s) { 685 negate = 0; 686 if (strncmp(s, "no", 2) == 0) { 687 s += 2; 688 negate = 1; 689 } else if (*s == '!') { 690 s++; 691 negate = 1; 692 } 693 if (strcmp(s, "loop") == 0) 694 /* loop is really short-hand for opts=loop */ 695 goto loop_special_case; 696 else if (strncmp(s, "opts=", 5) == 0) { 697 s += 5; 698 loop_special_case: 699 cmp->type[num] = negate ? FS_TYPE_NEGOPT : FS_TYPE_OPT; 700 } else { 701 if (first_negate) { 702 cmp->negate = negate; 703 first_negate = 0; 704 } 705 if ((negate && !cmp->negate) || 706 (!negate && cmp->negate)) { 707 fprintf(stderr, _(fs_type_syntax_error)); 708 exit(EXIT_USAGE); 709 } 710 } 711#if 0 712 printf("Adding %s to list (type %d).\n", s, cmp->type[num]); 713#endif 714 cmp->list[num++] = string_copy(s); 715 s = strtok(NULL, ","); 716 } 717 free(list); 718} 719 720/* 721 * This function returns true if a particular option appears in a 722 * comma-delimited options list 723 */ 724static int opt_in_list(char *opt, char *optlist) 725{ 726 char *list, *s; 727 728 if (!optlist) 729 return 0; 730 list = string_copy(optlist); 731 732 s = strtok(list, ","); 733 while(s) { 734 if (strcmp(s, opt) == 0) { 735 free(list); 736 return 1; 737 } 738 s = strtok(NULL, ","); 739 } 740 free(list); 741 return 0; 742} 743 744/* See if the filesystem matches the criteria given by the -t option */ 745static int fs_match(struct fs_info *fs, struct fs_type_compile *cmp) 746{ 747 int n, ret = 0, checked_type = 0; 748 char *cp; 749 750 if (cmp->list == 0 || cmp->list[0] == 0) 751 return 1; 752 753 for (n=0; cp = cmp->list[n]; n++) { 754 switch (cmp->type[n]) { 755 case FS_TYPE_NORMAL: 756 checked_type++; 757 if (strcmp(cp, fs->type) == 0) { 758 ret = 1; 759 } 760 break; 761 case FS_TYPE_NEGOPT: 762 if (opt_in_list(cp, fs->opts)) 763 return 0; 764 break; 765 case FS_TYPE_OPT: 766 if (!opt_in_list(cp, fs->opts)) 767 return 0; 768 break; 769 } 770 } 771 if (checked_type == 0) 772 return 1; 773 return (cmp->negate ? !ret : ret); 774} 775 776/* Check if we should ignore this filesystem. */ 777static int ignore(struct fs_info *fs) 778{ 779 const char **ip; 780 int wanted = 0; 781 782 /* 783 * If the pass number is 0, ignore it. 784 */ 785 if (fs->passno == 0) 786 return 1; 787 788 interpret_type(fs); 789 790 /* 791 * If a specific fstype is specified, and it doesn't match, 792 * ignore it. 793 */ 794 if (!fs_match(fs, &fs_type_compiled)) return 1; 795 796 /* Are we ignoring this type? */ 797 for(ip = ignored_types; *ip; ip++) 798 if (strcmp(fs->type, *ip) == 0) return 1; 799 800 /* Do we really really want to check this fs? */ 801 for(ip = really_wanted; *ip; ip++) 802 if (strcmp(fs->type, *ip) == 0) { 803 wanted = 1; 804 break; 805 } 806 807 /* See if the <fsck.fs> program is available. */ 808 if (find_fsck(fs->type) == NULL) { 809 if (wanted) 810 fprintf(stderr, _("fsck: cannot check %s: fsck.%s not found\n"), 811 fs->device, fs->type); 812 return 1; 813 } 814 815 /* We can and want to check this file system type. */ 816 return 0; 817} 818 819/* 820 * Returns TRUE if a partition on the same disk is already being 821 * checked. 822 */ 823static int device_already_active(char *device) 824{ 825 struct fsck_instance *inst; 826 char *base; 827 828 if (force_all_parallel) 829 return 0; 830 831#ifdef BASE_MD 832 /* Don't check a soft raid disk with any other disk */ 833 if (instance_list && 834 (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) || 835 !strncmp(device, BASE_MD, sizeof(BASE_MD)-1))) 836 return 1; 837#endif 838 839 base = base_device(device); 840 /* 841 * If we don't know the base device, assume that the device is 842 * already active if there are any fsck instances running. 843 */ 844 if (!base) 845 return (instance_list != 0); 846 for (inst = instance_list; inst; inst = inst->next) { 847 if (!inst->base_device || !strcmp(base, inst->base_device)) { 848 free(base); 849 return 1; 850 } 851 } 852 free(base); 853 return 0; 854} 855 856/* Check all file systems, using the /etc/fstab table. */ 857static int check_all(NOARGS) 858{ 859 struct fs_info *fs = NULL; 860 struct fsck_instance *inst; 861 int status = EXIT_OK; 862 int not_done_yet = 1; 863 int passno = 1; 864 int pass_done; 865 866 if (verbose) 867 printf(_("Checking all file systems.\n")); 868 869 /* 870 * Do an initial scan over the filesystem; mark filesystems 871 * which should be ignored as done, and resolve LABEL= and 872 * UUID= specifications to the real device. 873 */ 874 for (fs = filesys_info; fs; fs = fs->next) { 875 if (ignore(fs)) 876 fs->flags |= FLAG_DONE; 877 else 878 fs->device = interpret_device(fs->device); 879 } 880 881 /* 882 * Find and check the root filesystem. 883 */ 884 if (!parallel_root) { 885 for (fs = filesys_info; fs; fs = fs->next) { 886 if (!strcmp(fs->mountpt, "/")) 887 break; 888 } 889 if (fs) { 890 if (!skip_root && !ignore(fs)) { 891 fsck_device(fs->device, 1); 892 status |= wait_all(); 893 if (status > EXIT_NONDESTRUCT) 894 return status; 895 } 896 fs->flags |= FLAG_DONE; 897 } 898 } 899 900 while (not_done_yet) { 901 not_done_yet = 0; 902 pass_done = 1; 903 904 for (fs = filesys_info; fs; fs = fs->next) { 905 if (fs->flags & FLAG_DONE) 906 continue; 907 /* 908 * If the filesystem's pass number is higher 909 * than the current pass number, then we don't 910 * do it yet. 911 */ 912 if (fs->passno > passno) { 913 not_done_yet++; 914 continue; 915 } 916 /* 917 * If a filesystem on a particular device has 918 * already been spawned, then we need to defer 919 * this to another pass. 920 */ 921 if (device_already_active(fs->device)) { 922 pass_done = 0; 923 continue; 924 } 925 /* 926 * Spawn off the fsck process 927 */ 928 fsck_device(fs->device, serialize); 929 fs->flags |= FLAG_DONE; 930 931 if (serialize) { 932 pass_done = 0; 933 break; /* Only do one filesystem at a time */ 934 } 935 } 936 if (verbose > 1) 937 printf(_("--waiting-- (pass %d)\n"), passno); 938 inst = wait_one(); 939 if (inst) { 940 status |= inst->exit_status; 941 free_instance(inst); 942 } 943 if (pass_done) { 944 status |= wait_all(); 945 if (verbose > 1) 946 printf("----------------------------------\n"); 947 passno++; 948 } else 949 not_done_yet++; 950 } 951 status |= wait_all(); 952 return status; 953} 954 955static void usage(NOARGS) 956{ 957 fprintf(stderr, 958 _("Usage: fsck [-ACNPRTV] [-t fstype] [fs-options] filesys\n")); 959 exit(EXIT_USAGE); 960} 961 962static void PRS(int argc, char *argv[]) 963{ 964 int i, j; 965 char *arg; 966 char options[128]; 967 int opt = 0; 968 int opts_for_fsck = 0; 969 970 num_devices = 0; 971 num_args = 0; 972 instance_list = 0; 973 974 progname = argv[0]; 975 976 for (i=1; i < argc; i++) { 977 arg = argv[i]; 978 if (!arg) 979 continue; 980 if ((arg[0] == '/' && !opts_for_fsck) || 981 (strncmp(arg, "LABEL=", 6) == 0) || 982 (strncmp(arg, "UUID=", 5) == 0)) { 983 if (num_devices >= MAX_DEVICES) { 984 fprintf(stderr, _("%s: too many devices\n"), 985 progname); 986 exit(EXIT_ERROR); 987 } 988 devices[num_devices++] = 989 interpret_device(string_copy(arg)); 990 continue; 991 } 992 if (arg[0] != '-' || opts_for_fsck) { 993 if (num_args >= MAX_ARGS) { 994 fprintf(stderr, _("%s: too many arguments\n"), 995 progname); 996 exit(EXIT_ERROR); 997 } 998 args[num_args++] = string_copy(arg); 999 continue; 1000 } 1001 for (j=1; arg[j]; j++) { 1002 if (opts_for_fsck) { 1003 options[++opt] = arg[j]; 1004 continue; 1005 } 1006 switch (arg[j]) { 1007 case 'A': 1008 doall++; 1009 break; 1010 case 'C': 1011 progress++; 1012 break; 1013 case 'V': 1014 verbose++; 1015 break; 1016 case 'N': 1017 noexecute++; 1018 break; 1019 case 'R': 1020 skip_root++; 1021 break; 1022 case 'T': 1023 notitle++; 1024 break; 1025 case 'M': 1026 like_mount++; 1027 break; 1028 case 'P': 1029 parallel_root++; 1030 break; 1031 case 's': 1032 serialize++; 1033 break; 1034 case 't': 1035 if (arg[j+1]) { 1036 fstype = string_copy(arg+j+1); 1037 compile_fs_type(fstype, &fs_type_compiled); 1038 goto next_arg; 1039 } 1040 if ((i+1) < argc) { 1041 i++; 1042 fstype = string_copy(argv[i]); 1043 compile_fs_type(fstype, &fs_type_compiled); 1044 goto next_arg; 1045 } 1046 usage(); 1047 break; 1048 case '-': 1049 opts_for_fsck++; 1050 break; 1051 case '?': 1052 usage(); 1053 break; 1054 default: 1055 options[++opt] = arg[j]; 1056 break; 1057 } 1058 } 1059 next_arg: 1060 if (opt) { 1061 options[0] = '-'; 1062 options[++opt] = '\0'; 1063 if (num_args >= MAX_ARGS) { 1064 fprintf(stderr, 1065 _("%s: too many arguments\n"), 1066 progname); 1067 exit(EXIT_ERROR); 1068 } 1069 args[num_args++] = string_copy(options); 1070 opt = 0; 1071 } 1072 } 1073 if (getenv("FSCK_FORCE_ALL_PARALLEL")) 1074 force_all_parallel++; 1075} 1076 1077int main(int argc, char *argv[]) 1078{ 1079 int i; 1080 int status = 0; 1081 int interactive = 0; 1082 char *oldpath = getenv("PATH"); 1083 const char *fstab; 1084 1085#ifdef ENABLE_NLS 1086 setlocale(LC_MESSAGES, ""); 1087 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 1088 textdomain(NLS_CAT_NAME); 1089#endif 1090 PRS(argc, argv); 1091 1092 if (!notitle) 1093 printf(_("Parallelizing fsck version %s (%s)\n"), 1094 E2FSPROGS_VERSION, E2FSPROGS_DATE); 1095 1096 fstab = getenv("FSTAB_FILE"); 1097 if (!fstab) 1098 fstab = _PATH_MNTTAB; 1099 load_fs_info(fstab); 1100 1101 /* Update our search path to include uncommon directories. */ 1102 if (oldpath) { 1103 fsck_path = malloc (strlen (fsck_prefix_path) + 1 + 1104 strlen (oldpath) + 1); 1105 strcpy (fsck_path, fsck_prefix_path); 1106 strcat (fsck_path, ":"); 1107 strcat (fsck_path, oldpath); 1108 } else { 1109 fsck_path = string_copy(fsck_prefix_path); 1110 } 1111 1112 if ((num_devices == 1) || (serialize)) 1113 interactive = 1; 1114 1115 /* If -A was specified ("check all"), do that! */ 1116 if (doall) 1117 return check_all(); 1118 1119 for (i = 0 ; i < num_devices; i++) { 1120 fsck_device(devices[i], interactive); 1121 if (serialize) { 1122 struct fsck_instance *inst; 1123 1124 inst = wait_one(); 1125 if (inst) { 1126 status |= inst->exit_status; 1127 free_instance(inst); 1128 } 1129 } 1130 } 1131 status |= wait_all(); 1132 free(fsck_path); 1133 return status; 1134} 1135