]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fsck/fsck.c
libmount: improve mnt_tables_is_mounted
[thirdparty/util-linux.git] / fsck / fsck.c
CommitLineData
607c2a72 1/*
41e32d9f 2 * fsck --- A generic, parallelizing front-end for the fsck program.
607c2a72
KZ
3 * It will automatically try to run fsck programs in parallel if the
4 * devices are on separate spindles. It is based on the same ideas as
5 * the generic front end for fsck by David Engel and Fred van Kempen,
6 * but it has been completely rewritten from scratch to support
7 * parallel execution.
8 *
9 * Written by Theodore Ts'o, <tytso@mit.edu>
10 *
11 * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994:
12 * o Changed -t fstype to behave like with mount when -A (all file
13 * systems) or -M (like mount) is specified.
14 * o fsck looks if it can find the fsck.type program to decide
15 * if it should ignore the fs type. This way more fsck programs
16 * can be added without changing this front-end.
17 * o -R flag skip root file system.
18 *
19 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
20 * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
21 *
41e32d9f 22 * Copyright (C) 2009, 2012 Karel Zak <kzak@redhat.com>
607c2a72
KZ
23 *
24 * This file may be redistributed under the terms of the GNU Public
25 * License.
26 */
27
28#define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */
29
30#include <sys/types.h>
31#include <sys/wait.h>
607c2a72 32#include <sys/stat.h>
dd0bd943
KZ
33#include <sys/file.h>
34#include <fcntl.h>
607c2a72
KZ
35#include <limits.h>
36#include <stdio.h>
37#include <ctype.h>
38#include <string.h>
39#include <time.h>
40#include <stdlib.h>
607c2a72
KZ
41#include <paths.h>
42#include <unistd.h>
43#include <errno.h>
607c2a72 44#include <signal.h>
0c0f93fc
KZ
45#include <dirent.h>
46#include <blkid.h>
2b505124 47#include <libmount.h>
607c2a72
KZ
48
49#include "nls.h"
50#include "pathnames.h"
51#include "ismounted.h"
947558f5 52#include "exitcodes.h"
93bd18bc 53#include "c.h"
0a09eb4e
SK
54#include "fsck.h"
55
947558f5 56#define XALLOC_EXIT_CODE FSCK_EX_ERROR
0a09eb4e 57#include "xalloc.h"
607c2a72
KZ
58
59static const char *ignored_types[] = {
60 "ignore",
61 "iso9660",
607c2a72 62 "sw",
607c2a72
KZ
63 NULL
64};
65
66static const char *really_wanted[] = {
67 "minix",
68 "ext2",
69 "ext3",
70 "ext4",
71 "ext4dev",
72 "jfs",
73 "reiserfs",
74 "xiafs",
75 "xfs",
76 NULL
77};
78
79#define BASE_MD "/dev/md"
80
81/*
82 * Global variables for options
83 */
84char *devices[MAX_DEVICES];
85char *args[MAX_ARGS];
86int num_devices, num_args;
87
dd0bd943 88int lockdisk = 0;
607c2a72
KZ
89int verbose = 0;
90int doall = 0;
91int noexecute = 0;
92int serialize = 0;
93int skip_root = 0;
94int ignore_mounted = 0;
95int notitle = 0;
96int parallel_root = 0;
97int progress = 0;
98int progress_fd = 0;
99int force_all_parallel = 0;
100int num_running = 0;
101int max_running = 0;
102volatile int cancel_requested = 0;
103int kill_sent = 0;
607c2a72 104char *fstype = NULL;
607c2a72 105struct fsck_instance *instance_list;
bb4cb69d 106const char fsck_prefix_path[] = FS_SEARCH_PATH;
607c2a72 107char *fsck_path = 0;
607c2a72 108
2b505124
KZ
109/* parsed fstab */
110static struct libmnt_table *fstab;
e33b39a8 111static struct libmnt_cache *mntcache;
2b505124
KZ
112
113static int count_slaves(dev_t disk);
114
607c2a72
KZ
115static int string_to_int(const char *s)
116{
117 long l;
118 char *p;
119
120 l = strtol(s, &p, 0);
121 if (*p || l == LONG_MIN || l == LONG_MAX || l < 0 || l > INT_MAX)
122 return -1;
123 else
124 return (int) l;
125}
126
2b505124 127static int ignore(struct libmnt_fs *);
607c2a72 128
2b505124 129static struct fsck_fs_data *fs_create_data(struct libmnt_fs *fs)
607c2a72 130{
2b505124 131 struct fsck_fs_data *data = mnt_fs_get_userdata(fs);
607c2a72 132
2b505124
KZ
133 if (!data) {
134 data = xcalloc(1, sizeof(*data));
135 mnt_fs_set_userdata(fs, data);
136 }
137 return data;
607c2a72
KZ
138}
139
2b505124
KZ
140/*
141 * fs from fstab might contains real device name as well as symlink,
142 * LABEL or UUID, this function returns canonicalized result.
143 */
144static const char *fs_get_device(struct libmnt_fs *fs)
607c2a72 145{
2b505124 146 struct fsck_fs_data *data = mnt_fs_get_userdata(fs);
607c2a72 147
2b505124
KZ
148 if (!data || !data->eval_device) {
149 const char *spec = mnt_fs_get_source(fs);
150
151 if (!data)
152 data = fs_create_data(fs);
153
154 data->eval_device = 1;
155 data->device = mnt_resolve_spec(spec, mnt_table_get_cache(fstab));
156 if (!data->device)
2a24e16e 157 data->device = xstrdup(spec);
607c2a72 158 }
2b505124
KZ
159
160 return data->device;
607c2a72
KZ
161}
162
2b505124 163static dev_t fs_get_disk(struct libmnt_fs *fs, int check)
607c2a72 164{
2b505124
KZ
165 struct fsck_fs_data *data;
166 const char *device;
167 struct stat st;
168
169 data = mnt_fs_get_userdata(fs);
170 if (data && data->disk)
171 return data->disk;
607c2a72 172
2b505124 173 if (!check)
607c2a72
KZ
174 return 0;
175
2b505124
KZ
176 if (mnt_fs_is_netfs(fs) || mnt_fs_is_pseudofs(fs))
177 return 0;
607c2a72 178
2b505124
KZ
179 device = fs_get_device(fs);
180 if (!device)
181 return 0;
607c2a72 182
2b505124 183 data = fs_create_data(fs);
607c2a72 184
2b505124
KZ
185 if (!stat(device, &st) &&
186 !blkid_devno_to_wholedisk(st.st_rdev, NULL, 0, &data->disk)) {
187
188 if (data->disk)
189 data->stacked = count_slaves(data->disk) > 0 ? 1 : 0;
190 return data->disk;
607c2a72 191 }
2b505124 192 return 0;
607c2a72
KZ
193}
194
2b505124 195static int fs_is_stacked(struct libmnt_fs *fs)
dd0bd943 196{
2b505124
KZ
197 struct fsck_fs_data *data = mnt_fs_get_userdata(fs);
198 return data ? data->stacked : 0;
199}
dd0bd943 200
2b505124
KZ
201static int fs_is_done(struct libmnt_fs *fs)
202{
203 struct fsck_fs_data *data = mnt_fs_get_userdata(fs);
204 return data ? data->done : 0;
205}
dd0bd943 206
2b505124
KZ
207static void fs_set_done(struct libmnt_fs *fs)
208{
209 struct fsck_fs_data *data = fs_create_data(fs);
210
211 if (data)
212 data->done = 1;
dd0bd943
KZ
213}
214
215static int is_irrotational_disk(dev_t disk)
216{
217 char path[PATH_MAX];
218 FILE *f;
219 int rc, x;
220
2b505124 221
dd0bd943
KZ
222 rc = snprintf(path, sizeof(path),
223 "/sys/dev/block/%d:%d/queue/rotational",
224 major(disk), minor(disk));
225
0a09eb4e 226 if (rc < 0 || (unsigned int) (rc + 1) > sizeof(path))
dd0bd943
KZ
227 return 0;
228
229 f = fopen(path, "r");
230 if (!f)
231 return 0;
232
0a09eb4e
SK
233 rc = fscanf(f, "%d", &x);
234 if (rc != 1) {
235 if (ferror(f))
236 warn(_("failed to read: %s"), path);
237 else
238 warnx(_("parse error: %s"), path);
239 }
dd0bd943
KZ
240 fclose(f);
241
242 return rc == 1 ? !x : 0;
243}
244
245static void lock_disk(struct fsck_instance *inst)
246{
2b505124 247 dev_t disk = fs_get_disk(inst->fs, 1);
dd0bd943
KZ
248 char *diskname;
249
250 if (!disk || is_irrotational_disk(disk))
251 return;
252
253 diskname = blkid_devno_to_devname(disk);
254 if (!diskname)
255 return;
256
257 if (verbose)
258 printf(_("Locking disk %s ... "), diskname);
259
260 inst->lock = open(diskname, O_CLOEXEC | O_RDONLY);
261 if (inst->lock >= 0) {
262 int rc = -1;
263
264 /* inform users that we're waiting on the lock */
265 if (verbose &&
266 (rc = flock(inst->lock, LOCK_EX | LOCK_NB)) != 0 &&
267 errno == EWOULDBLOCK)
268 printf(_("(waiting) "));
269
270 if (rc != 0 && flock(inst->lock, LOCK_EX) != 0) {
271 close(inst->lock); /* failed */
272 inst->lock = -1;
273 }
274 }
275
276 if (verbose)
fcc058f4
BS
277 /* TRANSLATORS: These are followups to "Locking disk...". */
278 printf("%s.\n", inst->lock >= 0 ? _("succeeded") : _("failed"));
dd0bd943
KZ
279
280 free(diskname);
281 return;
282}
283
284static void unlock_disk(struct fsck_instance *inst)
285{
286 if (inst->lock >= 0) {
287 /* explicitly unlock, don't rely on close(), maybe some library
288 * (e.g. liblkid) has still open the device.
289 */
290 flock(inst->lock, LOCK_UN);
291 close(inst->lock);
292 }
293}
294
607c2a72
KZ
295static void free_instance(struct fsck_instance *i)
296{
dd0bd943
KZ
297 if (lockdisk)
298 unlock_disk(i);
7009077b 299 free(i->prog);
607c2a72
KZ
300 free(i);
301 return;
302}
303
2b505124 304static struct libmnt_fs *add_dummy_fs(const char *device)
607c2a72 305{
2b505124 306 struct libmnt_fs *fs = mnt_new_fs();
607c2a72 307
2b505124
KZ
308 if (fs && mnt_fs_set_source(fs, device) == 0 &&
309 mnt_table_add_fs(fstab, fs) == 0)
310 return fs;
607c2a72 311
2b505124
KZ
312 mnt_free_fs(fs);
313 err(FSCK_EX_ERROR, _("failed to setup description for %s"), device);
314}
607c2a72 315
2b505124 316static void fs_interpret_type(struct libmnt_fs *fs)
607c2a72 317{
2b505124
KZ
318 const char *device;
319 const char *type = mnt_fs_get_fstype(fs);
607c2a72 320
2b505124
KZ
321 if (type && strcmp(type, "auto") != 0)
322 return;
607c2a72 323
2b505124 324 mnt_fs_set_fstype(fs, NULL);
607c2a72 325
2b505124
KZ
326 device = fs_get_device(fs);
327 if (device) {
328 int ambi = 0;
607c2a72 329
2b505124
KZ
330 type = mnt_get_fstype(device, &ambi, mnt_table_get_cache(fstab));
331 if (!ambi)
332 mnt_fs_set_fstype(fs, type);
333 }
607c2a72
KZ
334}
335
2b505124
KZ
336static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)),
337 const char *filename, int line)
607c2a72 338{
2b505124
KZ
339 warnx(_("%s: parse error at line %d -- ignore"), filename, line);
340 return 0;
607c2a72
KZ
341}
342
343/*
344 * Load the filesystem database from /etc/fstab
345 */
2b505124 346static void load_fs_info(void)
607c2a72 347{
2b505124 348 const char *path;
607c2a72 349
2b505124
KZ
350 fstab = mnt_new_table();
351 if (!fstab)
352 err(FSCK_EX_ERROR, ("failed to initialize libmount table"));
607c2a72 353
2b505124 354 mnt_table_set_parser_errcb(fstab, parser_errcb);
e33b39a8 355 mnt_table_set_cache(fstab, mntcache);
2b505124
KZ
356
357 errno = 0;
358
359 /*
360 * Let's follow libmount defauls if $FSTAB_FILE is not specified
361 */
362 path = getenv("FSTAB_FILE");
363
364 if (mnt_table_parse_fstab(fstab, path)) {
365 mnt_free_table(fstab);
366 if (!path)
367 path = mnt_get_fstab_path();
368 if (errno)
369 warn(_("%s: failed to parse fstab"), path);
370 else
371 warnx(_("%s: failed to parse fstab"), path);
607c2a72
KZ
372 }
373}
374
e33b39a8
KZ
375/*
376 * Lookup filesys in /etc/fstab and return the corresponding entry.
377 * The @path has to be real path (no TAG) by mnt_resolve_spec().
378 */
379static struct libmnt_fs *lookup(char *path)
607c2a72 380{
2b505124 381 struct libmnt_fs *fs;
607c2a72 382
e33b39a8 383 if (!path)
607c2a72
KZ
384 return NULL;
385
e33b39a8 386 fs = mnt_table_find_srcpath(fstab, path, MNT_ITER_FORWARD);
2b505124 387 if (!fs)
e33b39a8 388 fs = mnt_table_find_target(fstab, path, MNT_ITER_FORWARD);
607c2a72
KZ
389
390 return fs;
391}
392
393/* Find fsck program for a given fs type. */
2b505124 394static char *find_fsck(const char *type)
607c2a72 395{
41e32d9f
KZ
396 char *s;
397 const char *tpl;
398 static char prog[256];
2a24e16e 399 char *p = xstrdup(fsck_path);
41e32d9f
KZ
400 struct stat st;
401
402 /* Are we looking for a program or just a type? */
403 tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s");
404
405 for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
406 sprintf(prog, tpl, s, type);
407 if (stat(prog, &st) == 0) break;
408 }
409 free(p);
410
411 return(s ? prog : NULL);
607c2a72
KZ
412}
413
414static int progress_active(NOARGS)
415{
416 struct fsck_instance *inst;
417
418 for (inst = instance_list; inst; inst = inst->next) {
419 if (inst->flags & FLAG_DONE)
420 continue;
421 if (inst->flags & FLAG_PROGRESS)
422 return 1;
423 }
424 return 0;
425}
426
427/*
428 * Execute a particular fsck program, and link it into the list of
429 * child processes we are waiting for.
430 */
2b505124 431static int execute(const char *type, struct libmnt_fs *fs, int interactive)
607c2a72
KZ
432{
433 char *s, *argv[80], prog[80];
434 int argc, i;
435 struct fsck_instance *inst, *p;
436 pid_t pid;
437
0a09eb4e 438 inst = xmalloc(sizeof(struct fsck_instance));
607c2a72
KZ
439 memset(inst, 0, sizeof(struct fsck_instance));
440
441 sprintf(prog, "fsck.%s", type);
2a24e16e 442 argv[0] = xstrdup(prog);
607c2a72
KZ
443 argc = 1;
444
445 for (i=0; i <num_args; i++)
2a24e16e 446 argv[argc++] = xstrdup(args[i]);
607c2a72
KZ
447
448 if (progress) {
449 if ((strcmp(type, "ext2") == 0) ||
450 (strcmp(type, "ext3") == 0) ||
451 (strcmp(type, "ext4") == 0) ||
452 (strcmp(type, "ext4dev") == 0)) {
453 char tmp[80];
454
455 tmp[0] = 0;
456 if (!progress_active()) {
457 snprintf(tmp, 80, "-C%d", progress_fd);
458 inst->flags |= FLAG_PROGRESS;
459 } else if (progress_fd)
460 snprintf(tmp, 80, "-C%d", progress_fd * -1);
461 if (tmp[0])
2a24e16e 462 argv[argc++] = xstrdup(tmp);
607c2a72
KZ
463 }
464 }
465
2a24e16e 466 argv[argc++] = xstrdup(fs_get_device(fs));
607c2a72
KZ
467 argv[argc] = 0;
468
469 s = find_fsck(prog);
470 if (s == NULL) {
0a09eb4e 471 warnx(_("%s: not found"), prog);
607c2a72
KZ
472 free(inst);
473 return ENOENT;
474 }
475
476 if (verbose || noexecute) {
2b505124
KZ
477 const char *tgt = mnt_fs_get_target(fs);
478
479 if (!tgt)
480 tgt = fs_get_device(fs);
481 printf("[%s (%d) -- %s] ", s, num_running, tgt);
607c2a72
KZ
482 for (i=0; i < argc; i++)
483 printf("%s ", argv[i]);
484 printf("\n");
485 }
486
dd0bd943
KZ
487 inst->fs = fs;
488 inst->lock = -1;
489
490 if (lockdisk)
491 lock_disk(inst);
492
607c2a72
KZ
493 /* Fork and execute the correct program. */
494 if (noexecute)
495 pid = -1;
496 else if ((pid = fork()) < 0) {
497 perror("fork");
498 free(inst);
499 return errno;
500 } else if (pid == 0) {
501 if (!interactive)
502 close(0);
503 (void) execv(s, argv);
504 perror(argv[0]);
505 free(inst);
947558f5 506 exit(FSCK_EX_ERROR);
607c2a72
KZ
507 }
508
509 for (i=0; i < argc; i++)
510 free(argv[i]);
511
512 inst->pid = pid;
2a24e16e
KZ
513 inst->prog = xstrdup(prog);
514 inst->type = xstrdup(type);
607c2a72
KZ
515 inst->start_time = time(0);
516 inst->next = NULL;
517
518 /*
519 * Find the end of the list, so we add the instance on at the end.
520 */
521 for (p = instance_list; p && p->next; p = p->next);
522
523 if (p)
524 p->next = inst;
525 else
526 instance_list = inst;
527
528 return 0;
529}
530
531/*
532 * Send a signal to all outstanding fsck child processes
533 */
534static int kill_all(int signum)
535{
536 struct fsck_instance *inst;
537 int n = 0;
538
539 for (inst = instance_list; inst; inst = inst->next) {
540 if (inst->flags & FLAG_DONE)
541 continue;
542 kill(inst->pid, signum);
543 n++;
544 }
545 return n;
546}
547
548/*
549 * Wait for one child process to exit; when it does, unlink it from
550 * the list of executing child processes, and return it.
551 */
552static struct fsck_instance *wait_one(int flags)
553{
554 int status;
555 int sig;
556 struct fsck_instance *inst, *inst2, *prev;
557 pid_t pid;
558
559 if (!instance_list)
560 return NULL;
561
562 if (noexecute) {
563 inst = instance_list;
564 prev = 0;
565#ifdef RANDOM_DEBUG
566 while (inst->next && (random() & 1)) {
567 prev = inst;
568 inst = inst->next;
569 }
570#endif
571 inst->exit_status = 0;
572 goto ret_inst;
573 }
574
575 /*
576 * gcc -Wall fails saving throw against stupidity
577 * (inst and prev are thought to be uninitialized variables)
578 */
579 inst = prev = NULL;
580
581 do {
582 pid = waitpid(-1, &status, flags);
583 if (cancel_requested && !kill_sent) {
584 kill_all(SIGTERM);
585 kill_sent++;
586 }
587 if ((pid == 0) && (flags & WNOHANG))
588 return NULL;
589 if (pid < 0) {
590 if ((errno == EINTR) || (errno == EAGAIN))
591 continue;
592 if (errno == ECHILD) {
0a09eb4e 593 warnx(_("wait: no more child process?!?"));
607c2a72
KZ
594 return NULL;
595 }
596 perror("wait");
597 continue;
598 }
599 for (prev = 0, inst = instance_list;
600 inst;
601 prev = inst, inst = inst->next) {
602 if (inst->pid == pid)
603 break;
604 }
605 } while (!inst);
606
607 if (WIFEXITED(status))
608 status = WEXITSTATUS(status);
609 else if (WIFSIGNALED(status)) {
610 sig = WTERMSIG(status);
611 if (sig == SIGINT) {
947558f5 612 status = FSCK_EX_UNCORRECTED;
607c2a72 613 } else {
0a09eb4e
SK
614 warnx(_("Warning... %s for device %s exited "
615 "with signal %d."),
2b505124 616 inst->prog, fs_get_device(inst->fs), sig);
947558f5 617 status = FSCK_EX_ERROR;
607c2a72
KZ
618 }
619 } else {
0a09eb4e 620 warnx(_("%s %s: status is %x, should never happen."),
2b505124 621 inst->prog, fs_get_device(inst->fs), status);
947558f5 622 status = FSCK_EX_ERROR;
607c2a72
KZ
623 }
624 inst->exit_status = status;
625 inst->flags |= FLAG_DONE;
626 if (progress && (inst->flags & FLAG_PROGRESS) &&
627 !progress_active()) {
628 for (inst2 = instance_list; inst2; inst2 = inst2->next) {
629 if (inst2->flags & FLAG_DONE)
630 continue;
631 if (strcmp(inst2->type, "ext2") &&
632 strcmp(inst2->type, "ext3") &&
633 strcmp(inst2->type, "ext4") &&
634 strcmp(inst2->type, "ext4dev"))
635 continue;
636 /*
637 * If we've just started the fsck, wait a tiny
638 * bit before sending the kill, to give it
639 * time to set up the signal handler
640 */
641 if (inst2->start_time < time(0)+2) {
642 if (fork() == 0) {
643 sleep(1);
644 kill(inst2->pid, SIGUSR1);
947558f5 645 exit(FSCK_EX_OK);
607c2a72
KZ
646 }
647 } else
648 kill(inst2->pid, SIGUSR1);
649 inst2->flags |= FLAG_PROGRESS;
650 break;
651 }
652 }
653ret_inst:
654 if (prev)
655 prev->next = inst->next;
656 else
657 instance_list = inst->next;
658 if (verbose > 1)
659 printf(_("Finished with %s (exit status %d)\n"),
2b505124 660 fs_get_device(inst->fs), inst->exit_status);
607c2a72
KZ
661 num_running--;
662 return inst;
663}
664
665#define FLAG_WAIT_ALL 0
666#define FLAG_WAIT_ATLEAST_ONE 1
667/*
668 * Wait until all executing child processes have exited; return the
669 * logical OR of all of their exit code values.
670 */
671static int wait_many(int flags)
672{
673 struct fsck_instance *inst;
674 int global_status = 0;
675 int wait_flags = 0;
676
677 while ((inst = wait_one(wait_flags))) {
678 global_status |= inst->exit_status;
679 free_instance(inst);
680#ifdef RANDOM_DEBUG
681 if (noexecute && (flags & WNOHANG) && !(random() % 3))
682 break;
683#endif
684 if (flags & FLAG_WAIT_ATLEAST_ONE)
685 wait_flags = WNOHANG;
686 }
687 return global_status;
688}
689
690/*
691 * Run the fsck program on a particular device
692 *
693 * If the type is specified using -t, and it isn't prefixed with "no"
694 * (as in "noext2") and only one filesystem type is specified, then
695 * use that type regardless of what is specified in /etc/fstab.
696 *
697 * If the type isn't specified by the user, then use either the type
698 * specified in /etc/fstab, or DEFAULT_FSTYPE.
699 */
2b505124 700static int fsck_device(struct libmnt_fs *fs, int interactive)
607c2a72
KZ
701{
702 const char *type;
703 int retval;
704
2b505124
KZ
705 fs_interpret_type(fs);
706
707 type = mnt_fs_get_fstype(fs);
607c2a72 708
2b505124
KZ
709 if (type && strcmp(type, "auto") != 0)
710 ;
607c2a72
KZ
711 else if (fstype && strncmp(fstype, "no", 2) &&
712 strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) &&
713 !strchr(fstype, ','))
714 type = fstype;
715 else
716 type = DEFAULT_FSTYPE;
717
718 num_running++;
0c0f93fc 719 retval = execute(type, fs, interactive);
607c2a72 720 if (retval) {
0a09eb4e 721 warnx(_("error %d while executing fsck.%s for %s"),
2b505124 722 retval, type, fs_get_device(fs));
607c2a72 723 num_running--;
947558f5 724 return FSCK_EX_ERROR;
607c2a72 725 }
6c6f2af9 726 return 0;
607c2a72
KZ
727}
728
729
730/*
731 * Deal with the fsck -t argument.
732 */
733struct fs_type_compile {
734 char **list;
735 int *type;
736 int negate;
737} fs_type_compiled;
738
739#define FS_TYPE_NORMAL 0
740#define FS_TYPE_OPT 1
741#define FS_TYPE_NEGOPT 2
742
607c2a72
KZ
743static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp)
744{
745 char *cp, *list, *s;
746 int num = 2;
747 int negate, first_negate = 1;
748
749 if (fs_type) {
750 for (cp=fs_type; *cp; cp++) {
751 if (*cp == ',')
752 num++;
753 }
754 }
755
0a09eb4e
SK
756 cmp->list = xmalloc(num * sizeof(char *));
757 cmp->type = xmalloc(num * sizeof(int));
607c2a72
KZ
758 memset(cmp->list, 0, num * sizeof(char *));
759 memset(cmp->type, 0, num * sizeof(int));
760 cmp->negate = 0;
761
762 if (!fs_type)
763 return;
764
2a24e16e 765 list = xstrdup(fs_type);
607c2a72
KZ
766 num = 0;
767 s = strtok(list, ",");
768 while(s) {
769 negate = 0;
770 if (strncmp(s, "no", 2) == 0) {
771 s += 2;
772 negate = 1;
773 } else if (*s == '!') {
774 s++;
775 negate = 1;
776 }
777 if (strcmp(s, "loop") == 0)
778 /* loop is really short-hand for opts=loop */
779 goto loop_special_case;
780 else if (strncmp(s, "opts=", 5) == 0) {
781 s += 5;
782 loop_special_case:
783 cmp->type[num] = negate ? FS_TYPE_NEGOPT : FS_TYPE_OPT;
784 } else {
785 if (first_negate) {
786 cmp->negate = negate;
787 first_negate = 0;
788 }
789 if ((negate && !cmp->negate) ||
790 (!negate && cmp->negate)) {
947558f5 791 errx(FSCK_EX_USAGE,
e0eadc0d
SK
792 _("Either all or none of the filesystem types passed to -t must be prefixed\n"
793 "with 'no' or '!'."));
607c2a72
KZ
794 }
795 }
796#if 0
797 printf("Adding %s to list (type %d).\n", s, cmp->type[num]);
798#endif
2a24e16e 799 cmp->list[num++] = xstrdup(s);
607c2a72
KZ
800 s = strtok(NULL, ",");
801 }
802 free(list);
803}
804
805/*
806 * This function returns true if a particular option appears in a
807 * comma-delimited options list
808 */
2b505124 809static int opt_in_list(const char *opt, const char *optlist)
607c2a72
KZ
810{
811 char *list, *s;
812
813 if (!optlist)
814 return 0;
2a24e16e 815 list = xstrdup(optlist);
607c2a72
KZ
816
817 s = strtok(list, ",");
818 while(s) {
819 if (strcmp(s, opt) == 0) {
820 free(list);
821 return 1;
822 }
823 s = strtok(NULL, ",");
824 }
0a09eb4e 825 free(list);
607c2a72
KZ
826 return 0;
827}
828
829/* See if the filesystem matches the criteria given by the -t option */
2b505124 830static int fs_match(struct libmnt_fs *fs, struct fs_type_compile *cmp)
607c2a72
KZ
831{
832 int n, ret = 0, checked_type = 0;
833 char *cp;
834
835 if (cmp->list == 0 || cmp->list[0] == 0)
836 return 1;
837
838 for (n=0; (cp = cmp->list[n]); n++) {
839 switch (cmp->type[n]) {
840 case FS_TYPE_NORMAL:
2b505124
KZ
841 {
842 const char *type = mnt_fs_get_fstype(fs);
843
607c2a72 844 checked_type++;
2b505124 845 if (type && strcmp(cp, type) == 0)
607c2a72 846 ret = 1;
607c2a72 847 break;
2b505124 848 }
607c2a72 849 case FS_TYPE_NEGOPT:
2b505124 850 if (opt_in_list(cp, mnt_fs_get_options(fs)))
607c2a72
KZ
851 return 0;
852 break;
853 case FS_TYPE_OPT:
2b505124 854 if (!opt_in_list(cp, mnt_fs_get_options(fs)))
607c2a72
KZ
855 return 0;
856 break;
857 }
858 }
859 if (checked_type == 0)
860 return 1;
861 return (cmp->negate ? !ret : ret);
862}
863
1bb516c3
LN
864/*
865 * Check if a device exists
866 */
867static int device_exists(const char *device)
868{
869 struct stat st;
870
871 if (stat(device, &st) == -1)
872 return 0;
873
874 if (!S_ISBLK(st.st_mode))
875 return 0;
876
877 return 1;
878}
879
2b505124 880static int fs_ignored_type(struct libmnt_fs *fs)
e3174198 881{
2b505124
KZ
882 const char **ip, *type;
883
884 if (mnt_fs_is_netfs(fs) || mnt_fs_is_pseudofs(fs) || mnt_fs_is_swaparea(fs))
885 return 1;
886
887 type = mnt_fs_get_fstype(fs);
e3174198 888
2b505124
KZ
889 for(ip = ignored_types; type && *ip; ip++) {
890 if (strcmp(type, *ip) == 0)
e3174198
KZ
891 return 1;
892 }
893
894 return 0;
895}
896
607c2a72 897/* Check if we should ignore this filesystem. */
2b505124 898static int ignore(struct libmnt_fs *fs)
607c2a72 899{
2b505124 900 const char **ip, *type;
607c2a72
KZ
901 int wanted = 0;
902
903 /*
904 * If the pass number is 0, ignore it.
905 */
2b505124 906 if (mnt_fs_get_passno(fs) == 0)
607c2a72
KZ
907 return 1;
908
909 /*
910 * If this is a bind mount, ignore it.
911 */
2b505124 912 if (opt_in_list("bind", mnt_fs_get_options(fs))) {
0a09eb4e
SK
913 warnx(_("%s: skipping bad line in /etc/fstab: "
914 "bind mount with nonzero fsck pass number"),
2b505124 915 mnt_fs_get_target(fs));
607c2a72
KZ
916 return 1;
917 }
918
1bb516c3
LN
919 /*
920 * ignore devices that don't exist and have the "nofail" mount option
921 */
2b505124
KZ
922 if (!device_exists(fs_get_device(fs))) {
923 if (opt_in_list("nofail", mnt_fs_get_options(fs))) {
236acf2d
KZ
924 if (verbose)
925 printf(_("%s: skipping nonexistent device\n"),
2b505124 926 fs_get_device(fs));
236acf2d
KZ
927 return 1;
928 }
1bb516c3 929 if (verbose)
236acf2d
KZ
930 printf(_("%s: nonexistent device (\"nofail\" fstab "
931 "option may be used to skip this device)\n"),
2b505124 932 fs_get_device(fs));
1bb516c3
LN
933 }
934
2b505124 935 fs_interpret_type(fs);
607c2a72
KZ
936
937 /*
938 * If a specific fstype is specified, and it doesn't match,
939 * ignore it.
940 */
3d4820f4
KZ
941 if (!fs_match(fs, &fs_type_compiled))
942 return 1;
607c2a72 943
2b505124
KZ
944 type = mnt_fs_get_fstype(fs);
945 if (!type)
946 return 0; /* should not happen */
947
607c2a72 948 /* Are we ignoring this type? */
2b505124 949 if (fs_ignored_type(fs))
e3174198 950 return 1;
607c2a72
KZ
951
952 /* Do we really really want to check this fs? */
953 for(ip = really_wanted; *ip; ip++)
2b505124 954 if (strcmp(type, *ip) == 0) {
607c2a72
KZ
955 wanted = 1;
956 break;
957 }
958
959 /* See if the <fsck.fs> program is available. */
2b505124 960 if (find_fsck(type) == NULL) {
607c2a72 961 if (wanted)
0a09eb4e 962 warnx(_("cannot check %s: fsck.%s not found"),
2b505124 963 fs_get_device(fs), type);
607c2a72
KZ
964 return 1;
965 }
966
967 /* We can and want to check this file system type. */
968 return 0;
969}
970
0c0f93fc
KZ
971static int count_slaves(dev_t disk)
972{
973 DIR *dir;
974 struct dirent *dp;
975 char dirname[PATH_MAX];
976 int count = 0;
977
978 snprintf(dirname, sizeof(dirname),
979 "/sys/dev/block/%u:%u/slaves/",
980 major(disk), minor(disk));
981
982 if (!(dir = opendir(dirname)))
983 return -1;
984
985 while ((dp = readdir(dir)) != 0) {
986#ifdef _DIRENT_HAVE_D_TYPE
987 if (dp->d_type != DT_UNKNOWN && dp->d_type != DT_LNK)
988 continue;
989#endif
990 if (dp->d_name[0] == '.' &&
991 ((dp->d_name[1] == 0) ||
992 ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
993 continue;
994
995 count++;
996 }
997 closedir(dir);
998 return count;
999}
1000
607c2a72
KZ
1001/*
1002 * Returns TRUE if a partition on the same disk is already being
1003 * checked.
1004 */
2b505124 1005static int disk_already_active(struct libmnt_fs *fs)
607c2a72
KZ
1006{
1007 struct fsck_instance *inst;
2b505124 1008 dev_t disk;
607c2a72
KZ
1009
1010 if (force_all_parallel)
1011 return 0;
1012
2b505124 1013 if (instance_list && fs_is_stacked(instance_list->fs))
0c0f93fc 1014 /* any instance for a stacked device is already running */
607c2a72 1015 return 1;
607c2a72 1016
2b505124 1017 disk = fs_get_disk(fs, 1);
0c0f93fc 1018
607c2a72
KZ
1019 /*
1020 * If we don't know the base device, assume that the device is
1021 * already active if there are any fsck instances running.
0c0f93fc
KZ
1022 *
1023 * Don't check a stacked device with any other disk too.
607c2a72 1024 */
2b505124 1025 if (!disk || fs_is_stacked(fs))
607c2a72 1026 return (instance_list != 0);
0c0f93fc 1027
607c2a72 1028 for (inst = instance_list; inst; inst = inst->next) {
2b505124
KZ
1029 dev_t idisk = fs_get_disk(inst->fs, 0);
1030
1031 if (!idisk || disk == idisk)
607c2a72 1032 return 1;
607c2a72 1033 }
607c2a72
KZ
1034 return 0;
1035}
1036
1037/* Check all file systems, using the /etc/fstab table. */
2b505124 1038static int check_all(void)
607c2a72 1039{
607c2a72
KZ
1040 int not_done_yet = 1;
1041 int passno = 1;
1042 int pass_done;
2b505124 1043 int status = FSCK_EX_OK;
607c2a72 1044
2b505124
KZ
1045 struct libmnt_fs *fs;
1046 struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
1047
1048 if (!itr)
1049 err(FSCK_EX_ERROR, _("failed to allocate iterator"));
607c2a72
KZ
1050
1051 /*
1052 * Do an initial scan over the filesystem; mark filesystems
1053 * which should be ignored as done, and resolve any "auto"
1054 * filesystem types (done as a side-effect of calling ignore()).
1055 */
2b505124
KZ
1056 while (mnt_table_next_fs(fstab, itr, &fs) == 0) {
1057 if (ignore(fs)) {
1058 fs_set_done(fs);
1059 continue;
1060 }
607c2a72
KZ
1061 }
1062
2b505124
KZ
1063 if (verbose)
1064 fputs(_("Checking all file systems.\n"), stdout);
1065
607c2a72
KZ
1066 /*
1067 * Find and check the root filesystem.
1068 */
1069 if (!parallel_root) {
2b505124 1070 fs = mnt_table_find_target(fstab, "/", MNT_ITER_FORWARD);
607c2a72 1071 if (fs) {
2b505124
KZ
1072 if (!skip_root &&
1073 !fs_is_done(fs) &&
1074 !(ignore_mounted && is_mounted(fs_get_device(fs)))) {
6c6f2af9 1075 status |= fsck_device(fs, 1);
607c2a72 1076 status |= wait_many(FLAG_WAIT_ALL);
2b505124
KZ
1077 if (status > FSCK_EX_NONDESTRUCT) {
1078 mnt_free_iter(itr);
607c2a72 1079 return status;
2b505124 1080 }
607c2a72 1081 }
2b505124 1082 fs_set_done(fs);
607c2a72
KZ
1083 }
1084 }
2b505124 1085
607c2a72
KZ
1086 /*
1087 * This is for the bone-headed user who enters the root
1088 * filesystem twice. Skip root will skep all root entries.
1089 */
2b505124
KZ
1090 if (skip_root) {
1091 mnt_reset_iter(itr, MNT_ITER_FORWARD);
1092
1093 while(mnt_table_next_fs(fstab, itr, &fs) == 0) {
1094 const char *tgt = mnt_fs_get_target(fs);
1095
1096 if (tgt && strcmp(tgt, "/") == 0)
1097 fs_set_done(fs);
1098 }
1099 }
607c2a72
KZ
1100
1101 while (not_done_yet) {
1102 not_done_yet = 0;
1103 pass_done = 1;
1104
2b505124
KZ
1105 mnt_reset_iter(itr, MNT_ITER_FORWARD);
1106
1107 while(mnt_table_next_fs(fstab, itr, &fs) == 0) {
1108
607c2a72
KZ
1109 if (cancel_requested)
1110 break;
2b505124 1111 if (fs_is_done(fs))
607c2a72
KZ
1112 continue;
1113 /*
1114 * If the filesystem's pass number is higher
1115 * than the current pass number, then we don't
1116 * do it yet.
1117 */
2b505124 1118 if (mnt_fs_get_passno(fs) > passno) {
607c2a72
KZ
1119 not_done_yet++;
1120 continue;
1121 }
2b505124
KZ
1122 if (ignore_mounted && is_mounted(fs_get_device(fs))) {
1123 fs_set_done(fs);
607c2a72
KZ
1124 continue;
1125 }
1126 /*
1127 * If a filesystem on a particular device has
1128 * already been spawned, then we need to defer
1129 * this to another pass.
1130 */
0c0f93fc 1131 if (disk_already_active(fs)) {
607c2a72
KZ
1132 pass_done = 0;
1133 continue;
1134 }
1135 /*
1136 * Spawn off the fsck process
1137 */
6c6f2af9 1138 status |= fsck_device(fs, serialize);
2b505124 1139 fs_set_done(fs);
607c2a72
KZ
1140
1141 /*
1142 * Only do one filesystem at a time, or if we
1143 * have a limit on the number of fsck's extant
1144 * at one time, apply that limit.
1145 */
1146 if (serialize ||
1147 (max_running && (num_running >= max_running))) {
1148 pass_done = 0;
1149 break;
1150 }
1151 }
1152 if (cancel_requested)
1153 break;
1154 if (verbose > 1)
1155 printf(_("--waiting-- (pass %d)\n"), passno);
2b505124 1156
607c2a72
KZ
1157 status |= wait_many(pass_done ? FLAG_WAIT_ALL :
1158 FLAG_WAIT_ATLEAST_ONE);
1159 if (pass_done) {
1160 if (verbose > 1)
1161 printf("----------------------------------\n");
1162 passno++;
1163 } else
1164 not_done_yet++;
1165 }
2b505124 1166
607c2a72
KZ
1167 if (cancel_requested && !kill_sent) {
1168 kill_all(SIGTERM);
1169 kill_sent++;
1170 }
2b505124 1171
607c2a72 1172 status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
2b505124 1173 mnt_free_iter(itr);
607c2a72
KZ
1174 return status;
1175}
1176
0a09eb4e 1177static void __attribute__((__noreturn__)) usage(void)
607c2a72 1178{
0a09eb4e
SK
1179 printf(_("\nUsage:\n"
1180 " %s [fsck-options] [fs-options] [filesys ...]\n"),
1181 program_invocation_short_name);
1182
1183 puts(_( "\nOptions:\n"
e6e060ec
KZ
1184 " -A check all filesystems\n"
1185 " -R skip root filesystem; useful only with `-A'\n"
1186 " -M do not check mounted filesystems\n"
be060aa1
KZ
1187 " -t <type> specify filesystem types to be checked;\n"
1188 " type is allowed to be comma-separated list\n"
e6e060ec
KZ
1189 " -P check filesystems in parallel, including root\n"
1190 " -s serialize fsck operations\n"
1191 " -l lock the device using flock()\n"
1192 " -N do not execute, just show what would be done\n"
1193 " -T do not show the title on startup\n"
be060aa1 1194 " -C <fd> display progress bar; file descriptor is for GUIs\n"
e6e060ec
KZ
1195 " -V explain what is being done\n"
1196 " -? display this help and exit\n\n"
0a09eb4e
SK
1197 "See fsck.* commands for fs-options."));
1198
947558f5 1199 exit(FSCK_EX_USAGE);
607c2a72
KZ
1200}
1201
1202static void signal_cancel(int sig FSCK_ATTR((unused)))
1203{
1204 cancel_requested++;
1205}
1206
1207static void PRS(int argc, char *argv[])
1208{
1209 int i, j;
1210 char *arg, *dev, *tmp = 0;
1211 char options[128];
1212 int opt = 0;
1213 int opts_for_fsck = 0;
1214 struct sigaction sa;
1215
1216 /*
1217 * Set up signal action
1218 */
1219 memset(&sa, 0, sizeof(struct sigaction));
1220 sa.sa_handler = signal_cancel;
1221 sigaction(SIGINT, &sa, 0);
1222 sigaction(SIGTERM, &sa, 0);
1223
1224 num_devices = 0;
1225 num_args = 0;
1226 instance_list = 0;
1227
607c2a72
KZ
1228 for (i=1; i < argc; i++) {
1229 arg = argv[i];
1230 if (!arg)
1231 continue;
1232 if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
0a09eb4e 1233 if (num_devices >= MAX_DEVICES)
947558f5 1234 errx(FSCK_EX_ERROR, _("too many devices"));
e33b39a8
KZ
1235
1236 dev = mnt_resolve_spec(arg, mntcache);
1237
607c2a72
KZ
1238 if (!dev && strchr(arg, '=')) {
1239 /*
1240 * Check to see if we failed because
1241 * /proc/partitions isn't found.
1242 */
fb429f22 1243 if (access(_PATH_PROC_PARTITIONS, R_OK) < 0) {
0a09eb4e
SK
1244 warn(_("couldn't open %s"),
1245 _PATH_PROC_PARTITIONS);
947558f5 1246 errx(FSCK_EX_ERROR, _("Is /proc mounted?"));
607c2a72
KZ
1247 }
1248 /*
1249 * Check to see if this is because
1250 * we're not running as root
1251 */
1252 if (geteuid())
947558f5 1253 errx(FSCK_EX_ERROR,
0a09eb4e
SK
1254 _("must be root to scan for matching filesystems: %s"),
1255 arg);
607c2a72 1256 else
947558f5 1257 errx(FSCK_EX_ERROR,
0a09eb4e
SK
1258 _("couldn't find matching filesystem: %s"),
1259 arg);
607c2a72 1260 }
2a24e16e 1261 devices[num_devices++] = dev ? dev : xstrdup(arg);
607c2a72
KZ
1262 continue;
1263 }
1264 if (arg[0] != '-' || opts_for_fsck) {
0a09eb4e 1265 if (num_args >= MAX_ARGS)
947558f5 1266 errx(FSCK_EX_ERROR, _("too many arguments"));
2a24e16e 1267 args[num_args++] = xstrdup(arg);
607c2a72
KZ
1268 continue;
1269 }
1270 for (j=1; arg[j]; j++) {
1271 if (opts_for_fsck) {
1272 options[++opt] = arg[j];
1273 continue;
1274 }
1275 switch (arg[j]) {
1276 case 'A':
0a09eb4e 1277 doall = 1;
607c2a72
KZ
1278 break;
1279 case 'C':
0a09eb4e 1280 progress = 1;
607c2a72
KZ
1281 if (arg[j+1]) {
1282 progress_fd = string_to_int(arg+j+1);
1283 if (progress_fd < 0)
1284 progress_fd = 0;
1285 else
1286 goto next_arg;
1287 } else if ((i+1) < argc &&
1288 !strncmp(argv[i+1], "-", 1) == 0) {
1289 progress_fd = string_to_int(argv[i]);
1290 if (progress_fd < 0)
1291 progress_fd = 0;
1292 else {
f1c2eaac 1293 ++i;
607c2a72 1294 goto next_arg;
607c2a72
KZ
1295 }
1296 }
1297 break;
dd0bd943 1298 case 'l':
0a09eb4e 1299 lockdisk = 1;
dd0bd943 1300 break;
607c2a72
KZ
1301 case 'V':
1302 verbose++;
1303 break;
1304 case 'N':
0a09eb4e 1305 noexecute = 1;
607c2a72
KZ
1306 break;
1307 case 'R':
0a09eb4e 1308 skip_root = 1;
607c2a72
KZ
1309 break;
1310 case 'T':
0a09eb4e 1311 notitle = 1;
607c2a72
KZ
1312 break;
1313 case 'M':
0a09eb4e 1314 ignore_mounted = 1;
607c2a72
KZ
1315 break;
1316 case 'P':
0a09eb4e 1317 parallel_root = 1;
607c2a72
KZ
1318 break;
1319 case 's':
0a09eb4e 1320 serialize = 1;
607c2a72
KZ
1321 break;
1322 case 't':
1323 tmp = 0;
1324 if (fstype)
1325 usage();
1326 if (arg[j+1])
1327 tmp = arg+j+1;
1328 else if ((i+1) < argc)
1329 tmp = argv[++i];
1330 else
1331 usage();
2a24e16e 1332 fstype = xstrdup(tmp);
607c2a72
KZ
1333 compile_fs_type(fstype, &fs_type_compiled);
1334 goto next_arg;
1335 case '-':
1336 opts_for_fsck++;
1337 break;
1338 case '?':
1339 usage();
1340 break;
1341 default:
1342 options[++opt] = arg[j];
1343 break;
1344 }
1345 }
1346 next_arg:
1347 if (opt) {
1348 options[0] = '-';
1349 options[++opt] = '\0';
0a09eb4e 1350 if (num_args >= MAX_ARGS)
947558f5 1351 errx(FSCK_EX_ERROR, _("too many arguments"));
2a24e16e 1352 args[num_args++] = xstrdup(options);
607c2a72
KZ
1353 opt = 0;
1354 }
1355 }
1356 if (getenv("FSCK_FORCE_ALL_PARALLEL"))
1357 force_all_parallel++;
1358 if ((tmp = getenv("FSCK_MAX_INST")))
1359 max_running = atoi(tmp);
1360}
1361
1362int main(int argc, char *argv[])
1363{
1364 int i, status = 0;
1365 int interactive = 0;
1366 char *oldpath = getenv("PATH");
2b505124 1367 struct libmnt_fs *fs;
607c2a72
KZ
1368
1369 setvbuf(stdout, NULL, _IONBF, BUFSIZ);
1370 setvbuf(stderr, NULL, _IONBF, BUFSIZ);
1371
1372 setlocale(LC_MESSAGES, "");
1373 setlocale(LC_CTYPE, "");
1374 bindtextdomain(PACKAGE, LOCALEDIR);
1375 textdomain(PACKAGE);
1376
e33b39a8
KZ
1377 mnt_init_debug(0); /* init libmount debug mask */
1378 mntcache = mnt_new_cache(); /* no fatal error if failed */
1379
607c2a72
KZ
1380 PRS(argc, argv);
1381
1382 if (!notitle)
0a09eb4e 1383 printf(_("%s from %s\n"), program_invocation_short_name, PACKAGE_STRING);
607c2a72 1384
2b505124 1385 load_fs_info();
607c2a72
KZ
1386
1387 /* Update our search path to include uncommon directories. */
1388 if (oldpath) {
0a09eb4e 1389 fsck_path = xmalloc (strlen (fsck_prefix_path) + 1 +
607c2a72 1390 strlen (oldpath) + 1);
607c2a72
KZ
1391 strcpy (fsck_path, fsck_prefix_path);
1392 strcat (fsck_path, ":");
1393 strcat (fsck_path, oldpath);
1394 } else {
2a24e16e 1395 fsck_path = xstrdup(fsck_prefix_path);
607c2a72
KZ
1396 }
1397
1398 if ((num_devices == 1) || (serialize))
1399 interactive = 1;
1400
dd0bd943 1401 if (lockdisk && (doall || num_devices > 1)) {
0a09eb4e
SK
1402 warnx(_("the -l option can be used with one "
1403 "device only -- ignore"));
dd0bd943
KZ
1404 lockdisk = 0;
1405 }
1406
607c2a72
KZ
1407 /* If -A was specified ("check all"), do that! */
1408 if (doall)
1409 return check_all();
1410
1411 if (num_devices == 0) {
1412 serialize++;
1413 interactive++;
1414 return check_all();
1415 }
1416 for (i = 0 ; i < num_devices; i++) {
1417 if (cancel_requested) {
1418 if (!kill_sent) {
1419 kill_all(SIGTERM);
1420 kill_sent++;
1421 }
1422 break;
1423 }
1424 fs = lookup(devices[i]);
2b505124
KZ
1425 if (!fs)
1426 fs = add_dummy_fs(devices[i]);
1427 else if (fs_ignored_type(fs))
e3174198
KZ
1428 continue;
1429
2b505124 1430 if (ignore_mounted && is_mounted(fs_get_device(fs)))
607c2a72 1431 continue;
6c6f2af9 1432 status |= fsck_device(fs, interactive);
607c2a72
KZ
1433 if (serialize ||
1434 (max_running && (num_running >= max_running))) {
1435 struct fsck_instance *inst;
1436
1437 inst = wait_one(0);
1438 if (inst) {
1439 status |= inst->exit_status;
1440 free_instance(inst);
1441 }
1442 if (verbose > 1)
1443 printf("----------------------------------\n");
1444 }
1445 }
1446 status |= wait_many(FLAG_WAIT_ALL);
1447 free(fsck_path);
e33b39a8 1448 mnt_free_cache(mntcache);
2b505124 1449 mnt_free_table(fstab);
607c2a72
KZ
1450 return status;
1451}
fb429f22 1452