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