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