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