blob: 627d2be318c337476cda608c9c35e360cc1ea3f4 [file] [log] [blame]
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001/* vi: set sw=4 ts=4: */
2/*
3 * fsck --- A generic, parallelizing front-end for the fsck program.
4 * It will automatically try to run fsck programs in parallel if the
5 * devices are on separate spindles. It is based on the same ideas as
6 * the generic front end for fsck by David Engel and Fred van Kempen,
7 * but it has been completely rewritten from scratch to support
8 * parallel execution.
9 *
10 * Written by Theodore Ts'o, <tytso@mit.edu>
11 *
12 * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994:
13 * o Changed -t fstype to behave like with mount when -A (all file
14 * systems) or -M (like mount) is specified.
15 * o fsck looks if it can find the fsck.type program to decide
16 * if it should ignore the fs type. This way more fsck programs
17 * can be added without changing this front-end.
18 * o -R flag skip root file system.
19 *
20 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
21 * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o.
22 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020023 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000024 */
25
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +000026/* All filesystem specific hooks have been removed.
27 * If filesystem cannot be determined, we will execute
28 * "fsck.auto". Currently this also happens if you specify
29 * UUID=xxx or LABEL=xxx as an object to check.
30 * Detection code for that is also probably has to be in fsck.auto.
31 *
32 * In other words, this is _really_ is just a driver program which
33 * spawns actual fsck.something for each filesystem to check.
34 * It doesn't guess filesystem types from on-disk format.
35 */
Denys Vlasenko000eda42015-10-18 22:40:23 +020036//config:config FSCK
37//config: bool "fsck"
38//config: default y
39//config: help
40//config: fsck is used to check and optionally repair one or more filesystems.
41//config: In actuality, fsck is simply a front-end for the various file system
42//config: checkers (fsck.fstype) available under Linux.
43
44//applet:IF_FSCK(APPLET(fsck, BB_DIR_SBIN, BB_SUID_DROP))
45
46//kbuild:lib-$(CONFIG_FSCK) += fsck.o
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +000047
Pere Orga6a3e01d2011-04-01 22:56:30 +020048//usage:#define fsck_trivial_usage
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +020049//usage: "[-ANPRTV] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]..."
Pere Orga6a3e01d2011-04-01 22:56:30 +020050//usage:#define fsck_full_usage "\n\n"
51//usage: "Check and repair filesystems\n"
Pere Orga6a3e01d2011-04-01 22:56:30 +020052//usage: "\n -A Walk /etc/fstab and check all filesystems"
53//usage: "\n -N Don't execute, just show what would be done"
54//usage: "\n -P With -A, check filesystems in parallel"
55//usage: "\n -R With -A, skip the root filesystem"
56//usage: "\n -T Don't show title on startup"
57//usage: "\n -V Verbose"
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +020058//DO_PROGRESS_INDICATOR is off:
59////usage: "\n -C FD Write status information to specified file descriptor"
Pere Orga6a3e01d2011-04-01 22:56:30 +020060//usage: "\n -t TYPE List of filesystem types to check"
61
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000062#include "libbb.h"
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000063
Denis Vlasenkoa55bd052008-03-17 08:59:19 +000064/* "progress indicator" code is somewhat buggy and ext[23] specific.
65 * We should be filesystem agnostic. IOW: there should be a well-defined
66 * API for fsck.something, NOT ad-hoc hacks in generic fsck. */
67#define DO_PROGRESS_INDICATOR 0
68
Denys Vlasenko0d7e2e72009-11-15 02:36:49 +010069/* fsck 1.41.4 (27-Jan-2009) manpage says:
70 * 0 - No errors
71 * 1 - File system errors corrected
72 * 2 - System should be rebooted
73 * 4 - File system errors left uncorrected
74 * 8 - Operational error
75 * 16 - Usage or syntax error
76 * 32 - Fsck canceled by user request
77 * 128 - Shared library error
78 */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000079#define EXIT_OK 0
80#define EXIT_NONDESTRUCT 1
81#define EXIT_DESTRUCT 2
82#define EXIT_UNCORRECTED 4
83#define EXIT_ERROR 8
84#define EXIT_USAGE 16
85#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
86
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000087/*
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +000088 * Internal structure for mount table entries.
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000089 */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000090struct fs_info {
Denis Vlasenkoe18a2932007-01-19 02:03:14 +000091 struct fs_info *next;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000092 char *device;
93 char *mountpt;
94 char *type;
95 char *opts;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000096 int passno;
97 int flags;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000098};
99
100#define FLAG_DONE 1
101#define FLAG_PROGRESS 2
102/*
103 * Structure to allow exit codes to be stored
104 */
105struct fsck_instance {
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000106 struct fsck_instance *next;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000107 int pid;
108 int flags;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000109#if DO_PROGRESS_INDICATOR
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000110 time_t start_time;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000111#endif
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000112 char *prog;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000113 char *device;
114 char *base_device; /* /dev/hda for /dev/hdaN etc */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000115};
116
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000117static const char ignored_types[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000118 "ignore\0"
119 "iso9660\0"
120 "nfs\0"
121 "proc\0"
122 "sw\0"
123 "swap\0"
124 "tmpfs\0"
125 "devpts\0";
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000126
Denis Vlasenko0de93752006-12-26 02:51:29 +0000127#if 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000128static const char really_wanted[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000129 "minix\0"
130 "ext2\0"
131 "ext3\0"
132 "jfs\0"
133 "reiserfs\0"
134 "xiafs\0"
135 "xfs\0";
Denis Vlasenko0de93752006-12-26 02:51:29 +0000136#endif
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000137
138#define BASE_MD "/dev/md"
139
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200140struct globals {
141 char **args;
142 int num_args;
143 int verbose;
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000144
145#define FS_TYPE_FLAG_NORMAL 0
146#define FS_TYPE_FLAG_OPT 1
147#define FS_TYPE_FLAG_NEGOPT 2
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200148 char **fs_type_list;
149 uint8_t *fs_type_flag;
150 smallint fs_type_negated;
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000151
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200152 smallint noexecute;
153 smallint serialize;
154 smallint skip_root;
155 /* smallint like_mount; */
156 smallint parallel_root;
157 smallint force_all_parallel;
158 smallint kill_sent;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000159
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000160#if DO_PROGRESS_INDICATOR
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200161 smallint progress;
162 int progress_fd;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000163#endif
164
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200165 int num_running;
166 int max_running;
167 char *fstype;
168 struct fs_info *filesys_info;
169 struct fs_info *filesys_last;
170 struct fsck_instance *instance_list;
171} FIX_ALIASING;
172#define G (*(struct globals*)&bb_common_bufsiz1)
173#define INIT_G() do { \
174 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
175} while (0)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000176
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000177/*
178 * Return the "base device" given a particular device; this is used to
179 * assure that we only fsck one partition on a particular drive at any
180 * one time. Otherwise, the disk heads will be seeking all over the
181 * place. If the base device cannot be determined, return NULL.
182 *
183 * The base_device() function returns an allocated string which must
184 * be freed.
185 */
186#if ENABLE_FEATURE_DEVFS
187/*
188 * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
189 * pathames.
190 */
191static const char *const devfs_hier[] = {
192 "host", "bus", "target", "lun", NULL
193};
194#endif
195
196static char *base_device(const char *device)
197{
198 char *str, *cp;
199#if ENABLE_FEATURE_DEVFS
200 const char *const *hier;
201 const char *disk;
202 int len;
203#endif
Denys Vlasenkof8d8aa12010-04-06 18:50:05 +0200204 str = xstrdup(device);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000205
Denys Vlasenkof8d8aa12010-04-06 18:50:05 +0200206 /* Skip over "/dev/"; if it's not present, give up */
207 cp = skip_dev_pfx(str);
208 if (cp == str)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000209 goto errout;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000210
211 /*
212 * For md devices, we treat them all as if they were all
213 * on one disk, since we don't know how to parallelize them.
214 */
215 if (cp[0] == 'm' && cp[1] == 'd') {
216 cp[2] = 0;
217 return str;
218 }
219
220 /* Handle DAC 960 devices */
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100221 if (is_prefixed_with(cp, "rd/")) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000222 cp += 3;
223 if (cp[0] != 'c' || !isdigit(cp[1])
224 || cp[2] != 'd' || !isdigit(cp[3]))
225 goto errout;
226 cp[4] = 0;
227 return str;
228 }
229
230 /* Now let's handle /dev/hd* and /dev/sd* devices.... */
231 if ((cp[0] == 'h' || cp[0] == 's') && cp[1] == 'd') {
232 cp += 2;
233 /* If there's a single number after /dev/hd, skip it */
234 if (isdigit(*cp))
235 cp++;
236 /* What follows must be an alpha char, or give up */
237 if (!isalpha(*cp))
238 goto errout;
239 cp[1] = 0;
240 return str;
241 }
242
243#if ENABLE_FEATURE_DEVFS
244 /* Now let's handle devfs (ugh) names */
245 len = 0;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100246 if (is_prefixed_with(cp, "ide/"))
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000247 len = 4;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100248 if (is_prefixed_with(cp, "scsi/"))
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000249 len = 5;
250 if (len) {
251 cp += len;
252 /*
253 * Now we proceed down the expected devfs hierarchy.
254 * i.e., .../host1/bus2/target3/lun4/...
255 * If we don't find the expected token, followed by
256 * some number of digits at each level, abort.
257 */
258 for (hier = devfs_hier; *hier; hier++) {
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100259 cp = is_prefixed_with(cp, *hier);
260 if (!cp)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000261 goto errout;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100262 while (*cp != '/' && *cp != '\0') {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000263 if (!isdigit(*cp))
264 goto errout;
265 cp++;
266 }
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100267//FIXME: what if *cp = '\0' now? cp++ moves past it!!!
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000268 cp++;
269 }
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100270 cp[-1] = '\0';
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000271 return str;
272 }
273
274 /* Now handle devfs /dev/disc or /dev/disk names */
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100275 disk = NULL;
276 if (is_prefixed_with(cp, "discs/"))
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000277 disk = "disc";
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100278 else if (is_prefixed_with(cp, "disks/"))
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000279 disk = "disk";
280 if (disk) {
281 cp += 6;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100282 cp = is_prefixed_with(cp, disk);
283 if (!cp)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000284 goto errout;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100285 while (*cp != '/' && *cp != '\0') {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000286 if (!isdigit(*cp))
287 goto errout;
288 cp++;
289 }
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100290 *cp = '\0';
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000291 return str;
292 }
293#endif
294 errout:
295 free(str);
296 return NULL;
297}
298
299static void free_instance(struct fsck_instance *p)
300{
301 free(p->prog);
302 free(p->device);
303 free(p->base_device);
304 free(p);
305}
306
307static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
308 const char *type, const char *opts,
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000309 int passno)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000310{
311 struct fs_info *fs;
312
313 fs = xzalloc(sizeof(*fs));
314 fs->device = xstrdup(device);
315 fs->mountpt = xstrdup(mntpnt);
Denis Vlasenkob9f5d592008-08-20 02:38:48 +0000316 if (strchr(type, ','))
317 type = (char *)"auto";
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000318 fs->type = xstrdup(type);
319 fs->opts = xstrdup(opts ? opts : "");
Denis Vlasenkob9f5d592008-08-20 02:38:48 +0000320 fs->passno = passno < 0 ? 1 : passno;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000321 /*fs->flags = 0; */
322 /*fs->next = NULL; */
323
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200324 if (!G.filesys_info)
325 G.filesys_info = fs;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000326 else
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200327 G.filesys_last->next = fs;
328 G.filesys_last = fs;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000329
330 return fs;
331}
332
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000333/* Load the filesystem database from /etc/fstab */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000334static void load_fs_info(const char *filename)
335{
Denis Vlasenkob9f5d592008-08-20 02:38:48 +0000336 FILE *fstab;
337 struct mntent mte;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200338 char buf[1024];
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000339
Denis Vlasenkob9f5d592008-08-20 02:38:48 +0000340 fstab = setmntent(filename, "r");
341 if (!fstab) {
Denys Vlasenko651a2692010-03-23 16:25:17 +0100342 bb_perror_msg("can't read '%s'", filename);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000343 return;
344 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000345
Denis Vlasenkob9f5d592008-08-20 02:38:48 +0000346 // Loop through entries
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200347 while (getmntent_r(fstab, &mte, buf, sizeof(buf))) {
Denis Vlasenkob9f5d592008-08-20 02:38:48 +0000348 //bb_info_msg("CREATE[%s][%s][%s][%s][%d]", mte.mnt_fsname, mte.mnt_dir,
Denis Vlasenkoea7c9b32008-09-25 10:39:10 +0000349 // mte.mnt_type, mte.mnt_opts,
Denis Vlasenkob9f5d592008-08-20 02:38:48 +0000350 // mte.mnt_passno);
Denys Vlasenko60a94142011-05-13 20:57:01 +0200351 create_fs_device(mte.mnt_fsname, mte.mnt_dir,
Denis Vlasenkoea7c9b32008-09-25 10:39:10 +0000352 mte.mnt_type, mte.mnt_opts,
Denis Vlasenkob9f5d592008-08-20 02:38:48 +0000353 mte.mnt_passno);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000354 }
Denis Vlasenkob9f5d592008-08-20 02:38:48 +0000355 endmntent(fstab);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000356}
357
358/* Lookup filesys in /etc/fstab and return the corresponding entry. */
359static struct fs_info *lookup(char *filesys)
360{
361 struct fs_info *fs;
362
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200363 for (fs = G.filesys_info; fs; fs = fs->next) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000364 if (strcmp(filesys, fs->device) == 0
365 || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0)
366 )
367 break;
368 }
369
370 return fs;
371}
372
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000373#if DO_PROGRESS_INDICATOR
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000374static int progress_active(void)
375{
376 struct fsck_instance *inst;
377
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200378 for (inst = G.instance_list; inst; inst = inst->next) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000379 if (inst->flags & FLAG_DONE)
380 continue;
381 if (inst->flags & FLAG_PROGRESS)
382 return 1;
383 }
384 return 0;
385}
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000386#endif
387
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000388
389/*
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000390 * Send a signal to all outstanding fsck child processes
391 */
Denys Vlasenko66837452009-09-13 05:52:03 +0200392static void kill_all_if_got_signal(void)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000393{
394 struct fsck_instance *inst;
Denis Vlasenko0de93752006-12-26 02:51:29 +0000395
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200396 if (!bb_got_signal || G.kill_sent)
Denis Vlasenko0de93752006-12-26 02:51:29 +0000397 return;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000398
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200399 for (inst = G.instance_list; inst; inst = inst->next) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000400 if (inst->flags & FLAG_DONE)
401 continue;
Denis Vlasenko0de93752006-12-26 02:51:29 +0000402 kill(inst->pid, SIGTERM);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000403 }
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200404 G.kill_sent = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000405}
406
407/*
408 * Wait for one child process to exit; when it does, unlink it from
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000409 * the list of executing child processes, free, and return its exit status.
410 * If there is no exited child, return -1.
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000411 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000412static int wait_one(int flags)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000413{
414 int status;
415 int sig;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000416 struct fsck_instance *inst, *prev;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000417 pid_t pid;
418
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200419 if (!G.instance_list)
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000420 return -1;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200421 /* if (G.noexecute) { already returned -1; } */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000422
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000423 while (1) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000424 pid = waitpid(-1, &status, flags);
Denys Vlasenko66837452009-09-13 05:52:03 +0200425 kill_all_if_got_signal();
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000426 if (pid == 0) /* flags == WNOHANG and no children exited */
427 return -1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000428 if (pid < 0) {
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000429 if (errno == EINTR)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000430 continue;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000431 if (errno == ECHILD) { /* paranoia */
432 bb_error_msg("wait: no more children");
433 return -1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000434 }
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000435 bb_perror_msg("wait");
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000436 continue;
437 }
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000438 prev = NULL;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200439 inst = G.instance_list;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000440 do {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000441 if (inst->pid == pid)
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000442 goto child_died;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000443 prev = inst;
444 inst = inst->next;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000445 } while (inst);
446 }
447 child_died:
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000448
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200449 status = WEXITSTATUS(status);
450 if (WIFSIGNALED(status)) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000451 sig = WTERMSIG(status);
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000452 status = EXIT_UNCORRECTED;
453 if (sig != SIGINT) {
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000454 printf("Warning: %s %s terminated "
455 "by signal %d\n",
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000456 inst->prog, inst->device, sig);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000457 status = EXIT_ERROR;
458 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000459 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000460
461#if DO_PROGRESS_INDICATOR
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +0000462 if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) {
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000463 struct fsck_instance *inst2;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200464 for (inst2 = G.instance_list; inst2; inst2 = inst2->next) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000465 if (inst2->flags & FLAG_DONE)
466 continue;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000467 if (strcmp(inst2->type, "ext2") != 0
468 && strcmp(inst2->type, "ext3") != 0
469 ) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000470 continue;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000471 }
472 /* ext[23], we will send USR1
473 * (request to start displaying progress bar)
474 *
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000475 * If we've just started the fsck, wait a tiny
476 * bit before sending the kill, to give it
477 * time to set up the signal handler
478 */
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000479 if (inst2->start_time >= time(NULL) - 1)
480 sleep(1);
481 kill(inst2->pid, SIGUSR1);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000482 inst2->flags |= FLAG_PROGRESS;
483 break;
484 }
485 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000486#endif
487
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000488 if (prev)
489 prev->next = inst->next;
490 else
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200491 G.instance_list = inst->next;
492 if (G.verbose > 1)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000493 printf("Finished with %s (exit status %d)\n",
Denys Vlasenko69675782013-01-14 01:34:48 +0100494 inst->device, status);
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200495 G.num_running--;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000496 free_instance(inst);
497
498 return status;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000499}
500
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000501/*
502 * Wait until all executing child processes have exited; return the
503 * logical OR of all of their exit code values.
504 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000505#define FLAG_WAIT_ALL 0
506#define FLAG_WAIT_ATLEAST_ONE WNOHANG
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000507static int wait_many(int flags)
508{
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000509 int exit_status;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000510 int global_status = 0;
511 int wait_flags = 0;
512
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000513 while ((exit_status = wait_one(wait_flags)) != -1) {
514 global_status |= exit_status;
515 wait_flags |= flags;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000516 }
517 return global_status;
518}
519
520/*
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000521 * Execute a particular fsck program, and link it into the list of
522 * child processes we are waiting for.
523 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000524static void execute(const char *type, const char *device,
525 const char *mntpt /*, int interactive */)
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000526{
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000527 int i;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000528 struct fsck_instance *inst;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000529 pid_t pid;
530
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200531 G.args[0] = xasprintf("fsck.%s", type);
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000532
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000533#if DO_PROGRESS_INDICATOR
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000534 if (progress && !progress_active()) {
535 if (strcmp(type, "ext2") == 0
536 || strcmp(type, "ext3") == 0
537 ) {
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200538 G.args[XXX] = xasprintf("-C%d", progress_fd); /* 1 */
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000539 inst->flags |= FLAG_PROGRESS;
540 }
541 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000542#endif
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000543
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200544 G.args[G.num_args - 2] = (char*)device;
545 /* G.args[G.num_args - 1] = NULL; - already is */
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000546
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200547 if (G.verbose || G.noexecute) {
548 printf("[%s (%d) -- %s]", G.args[0], G.num_running,
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000549 mntpt ? mntpt : device);
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200550 for (i = 0; G.args[i]; i++)
551 printf(" %s", G.args[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000552 bb_putchar('\n');
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000553 }
554
555 /* Fork and execute the correct program. */
556 pid = -1;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200557 if (!G.noexecute) {
558 pid = spawn(G.args);
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000559 if (pid < 0)
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200560 bb_simple_perror_msg(G.args[0]);
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000561 }
562
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000563#if DO_PROGRESS_INDICATOR
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200564 free(G.args[XXX]);
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000565#endif
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000566
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000567 /* No child, so don't record an instance */
568 if (pid <= 0) {
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200569 free(G.args[0]);
Denis Vlasenko30eb3192008-02-02 18:54:58 +0000570 return;
571 }
572
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000573 inst = xzalloc(sizeof(*inst));
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000574 inst->pid = pid;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200575 inst->prog = G.args[0];
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000576 inst->device = xstrdup(device);
577 inst->base_device = base_device(device);
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000578#if DO_PROGRESS_INDICATOR
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000579 inst->start_time = time(NULL);
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000580#endif
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000581
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000582 /* Add to the list of running fsck's.
583 * (was adding to the end, but adding to the front is simpler...) */
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200584 inst->next = G.instance_list;
585 G.instance_list = inst;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000586}
587
588/*
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000589 * Run the fsck program on a particular device
590 *
591 * If the type is specified using -t, and it isn't prefixed with "no"
592 * (as in "noext2") and only one filesystem type is specified, then
593 * use that type regardless of what is specified in /etc/fstab.
594 *
595 * If the type isn't specified by the user, then use either the type
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000596 * specified in /etc/fstab, or "auto".
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000597 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000598static void fsck_device(struct fs_info *fs /*, int interactive */)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000599{
600 const char *type;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000601
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000602 if (strcmp(fs->type, "auto") != 0) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000603 type = fs->type;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200604 if (G.verbose > 2)
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000605 bb_info_msg("using filesystem type '%s' %s",
606 type, "from fstab");
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200607 } else if (G.fstype
608 && (G.fstype[0] != 'n' || G.fstype[1] != 'o') /* != "no" */
609 && !is_prefixed_with(G.fstype, "opts=")
610 && !is_prefixed_with(G.fstype, "loop")
611 && !strchr(G.fstype, ',')
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000612 ) {
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200613 type = G.fstype;
614 if (G.verbose > 2)
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000615 bb_info_msg("using filesystem type '%s' %s",
616 type, "from -t");
617 } else {
618 type = "auto";
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200619 if (G.verbose > 2)
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000620 bb_info_msg("using filesystem type '%s' %s",
621 type, "(default)");
622 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000623
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200624 G.num_running++;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000625 execute(type, fs->device, fs->mountpt /*, interactive */);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000626}
627
628/*
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000629 * Returns TRUE if a partition on the same disk is already being
630 * checked.
631 */
632static int device_already_active(char *device)
633{
634 struct fsck_instance *inst;
635 char *base;
636
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200637 if (G.force_all_parallel)
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000638 return 0;
639
640#ifdef BASE_MD
641 /* Don't check a soft raid disk with any other disk */
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200642 if (G.instance_list
643 && (is_prefixed_with(G.instance_list->device, BASE_MD)
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100644 || is_prefixed_with(device, BASE_MD))
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000645 ) {
646 return 1;
647 }
648#endif
649
650 base = base_device(device);
651 /*
652 * If we don't know the base device, assume that the device is
653 * already active if there are any fsck instances running.
654 */
655 if (!base)
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200656 return (G.instance_list != NULL);
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000657
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200658 for (inst = G.instance_list; inst; inst = inst->next) {
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000659 if (!inst->base_device || !strcmp(base, inst->base_device)) {
660 free(base);
661 return 1;
662 }
663 }
664
665 free(base);
666 return 0;
667}
668
669/*
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000670 * This function returns true if a particular option appears in a
671 * comma-delimited options list
672 */
673static int opt_in_list(char *opt, char *optlist)
674{
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000675 char *s;
676 int len;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000677
678 if (!optlist)
679 return 0;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000680
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000681 len = strlen(opt);
682 s = optlist - 1;
683 while (1) {
684 s = strstr(s + 1, opt);
685 if (!s)
686 return 0;
687 /* neither "opt.." nor "xxx,opt.."? */
688 if (s != optlist && s[-1] != ',')
689 continue;
690 /* neither "..opt" nor "..opt,xxx"? */
691 if (s[len] != '\0' && s[len] != ',')
692 continue;
693 return 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000694 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000695}
696
697/* See if the filesystem matches the criteria given by the -t option */
698static int fs_match(struct fs_info *fs)
699{
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000700 int n, ret, checked_type;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000701 char *cp;
702
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200703 if (!G.fs_type_list)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000704 return 1;
705
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000706 ret = 0;
707 checked_type = 0;
708 n = 0;
709 while (1) {
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200710 cp = G.fs_type_list[n];
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000711 if (!cp)
712 break;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200713 switch (G.fs_type_flag[n]) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000714 case FS_TYPE_FLAG_NORMAL:
715 checked_type++;
716 if (strcmp(cp, fs->type) == 0)
717 ret = 1;
718 break;
719 case FS_TYPE_FLAG_NEGOPT:
720 if (opt_in_list(cp, fs->opts))
721 return 0;
722 break;
723 case FS_TYPE_FLAG_OPT:
724 if (!opt_in_list(cp, fs->opts))
725 return 0;
726 break;
727 }
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000728 n++;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000729 }
730 if (checked_type == 0)
731 return 1;
732
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200733 return (G.fs_type_negated ? !ret : ret);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000734}
735
736/* Check if we should ignore this filesystem. */
737static int ignore(struct fs_info *fs)
738{
739 /*
740 * If the pass number is 0, ignore it.
741 */
742 if (fs->passno == 0)
743 return 1;
744
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000745 /*
746 * If a specific fstype is specified, and it doesn't match,
747 * ignore it.
748 */
749 if (!fs_match(fs))
750 return 1;
751
752 /* Are we ignoring this type? */
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000753 if (index_in_strings(ignored_types, fs->type) >= 0)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000754 return 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000755
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000756 /* We can and want to check this file system type. */
757 return 0;
758}
759
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000760/* Check all file systems, using the /etc/fstab table. */
761static int check_all(void)
762{
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000763 struct fs_info *fs;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000764 int status = EXIT_OK;
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000765 smallint not_done_yet;
766 smallint pass_done;
767 int passno;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000768
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200769 if (G.verbose)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000770 puts("Checking all filesystems");
771
772 /*
773 * Do an initial scan over the filesystem; mark filesystems
774 * which should be ignored as done, and resolve any "auto"
775 * filesystem types (done as a side-effect of calling ignore()).
776 */
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200777 for (fs = G.filesys_info; fs; fs = fs->next)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000778 if (ignore(fs))
779 fs->flags |= FLAG_DONE;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000780
781 /*
782 * Find and check the root filesystem.
783 */
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200784 if (!G.parallel_root) {
785 for (fs = G.filesys_info; fs; fs = fs->next) {
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000786 if (LONE_CHAR(fs->mountpt, '/')) {
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200787 if (!G.skip_root && !ignore(fs)) {
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000788 fsck_device(fs /*, 1*/);
789 status |= wait_many(FLAG_WAIT_ALL);
790 if (status > EXIT_NONDESTRUCT)
791 return status;
792 }
793 fs->flags |= FLAG_DONE;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000794 break;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000795 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000796 }
797 }
798 /*
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000799 * This is for the bone-headed user who has root
800 * filesystem listed twice.
801 * "Skip root" will skip _all_ root entries.
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000802 */
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200803 if (G.skip_root)
804 for (fs = G.filesys_info; fs; fs = fs->next)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000805 if (LONE_CHAR(fs->mountpt, '/'))
806 fs->flags |= FLAG_DONE;
807
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000808 not_done_yet = 1;
809 passno = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000810 while (not_done_yet) {
811 not_done_yet = 0;
812 pass_done = 1;
813
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200814 for (fs = G.filesys_info; fs; fs = fs->next) {
Denys Vlasenko66837452009-09-13 05:52:03 +0200815 if (bb_got_signal)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000816 break;
817 if (fs->flags & FLAG_DONE)
818 continue;
819 /*
820 * If the filesystem's pass number is higher
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000821 * than the current pass number, then we didn't
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000822 * do it yet.
823 */
824 if (fs->passno > passno) {
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000825 not_done_yet = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000826 continue;
827 }
828 /*
829 * If a filesystem on a particular device has
830 * already been spawned, then we need to defer
831 * this to another pass.
832 */
833 if (device_already_active(fs->device)) {
834 pass_done = 0;
835 continue;
836 }
837 /*
838 * Spawn off the fsck process
839 */
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200840 fsck_device(fs /*, G.serialize*/);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000841 fs->flags |= FLAG_DONE;
842
843 /*
844 * Only do one filesystem at a time, or if we
845 * have a limit on the number of fsck's extant
846 * at one time, apply that limit.
847 */
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200848 if (G.serialize
849 || (G.num_running >= G.max_running)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000850 ) {
851 pass_done = 0;
852 break;
853 }
854 }
Denys Vlasenko66837452009-09-13 05:52:03 +0200855 if (bb_got_signal)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000856 break;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200857 if (G.verbose > 1)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000858 printf("--waiting-- (pass %d)\n", passno);
859 status |= wait_many(pass_done ? FLAG_WAIT_ALL :
Denys Vlasenko69675782013-01-14 01:34:48 +0100860 FLAG_WAIT_ATLEAST_ONE);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000861 if (pass_done) {
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200862 if (G.verbose > 1)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000863 puts("----------------------------------");
864 passno++;
865 } else
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000866 not_done_yet = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000867 }
Denys Vlasenko66837452009-09-13 05:52:03 +0200868 kill_all_if_got_signal();
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000869 status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
870 return status;
871}
872
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000873/*
874 * Deal with the fsck -t argument.
875 * Huh, for mount "-t novfat,nfs" means "neither vfat nor nfs"!
876 * Why here we require "-t novfat,nonfs" ??
877 */
878static void compile_fs_type(char *fs_type)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000879{
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000880 char *s;
881 int num = 2;
882 smallint negate;
883
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000884 s = fs_type;
885 while ((s = strchr(s, ','))) {
886 num++;
887 s++;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000888 }
889
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200890 G.fs_type_list = xzalloc(num * sizeof(G.fs_type_list[0]));
891 G.fs_type_flag = xzalloc(num * sizeof(G.fs_type_flag[0]));
892 G.fs_type_negated = -1; /* not yet known is it negated or not */
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000893
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000894 num = 0;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000895 s = fs_type;
896 while (1) {
897 char *comma;
898
899 negate = 0;
900 if (s[0] == 'n' && s[1] == 'o') { /* "no.." */
901 s += 2;
902 negate = 1;
903 } else if (s[0] == '!') {
904 s++;
905 negate = 1;
906 }
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000907
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000908 if (strcmp(s, "loop") == 0)
909 /* loop is really short-hand for opts=loop */
910 goto loop_special_case;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100911 if (is_prefixed_with(s, "opts=")) {
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000912 s += 5;
913 loop_special_case:
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200914 G.fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000915 } else {
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200916 if (G.fs_type_negated == -1)
917 G.fs_type_negated = negate;
918 if (G.fs_type_negated != negate)
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000919 bb_error_msg_and_die(
920"either all or none of the filesystem types passed to -t must be prefixed "
921"with 'no' or '!'");
922 }
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200923 comma = strchrnul(s, ',');
924 G.fs_type_list[num++] = xstrndup(s, comma-s);
925 if (*comma == '\0')
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000926 break;
927 s = comma + 1;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000928 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000929}
930
Denys Vlasenko7649bd02009-09-13 05:52:46 +0200931static char **new_args(void)
932{
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200933 G.args = xrealloc_vector(G.args, 2, G.num_args);
934 return &G.args[G.num_args++];
Denys Vlasenko7649bd02009-09-13 05:52:46 +0200935}
936
Denys Vlasenko66837452009-09-13 05:52:03 +0200937int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
938int fsck_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000939{
Denys Vlasenko66837452009-09-13 05:52:03 +0200940 int i, status;
941 /*int interactive;*/
942 struct fs_info *fs;
943 const char *fstab;
944 char *tmp;
945 char **devices;
946 int num_devices;
947 smallint opts_for_fsck;
948 smallint doall;
949 smallint notitle;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000950
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200951 INIT_G();
952
Denys Vlasenko66837452009-09-13 05:52:03 +0200953 /* we want wait() to be interruptible */
954 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
955 signal_no_SA_RESTART_empty_mask(SIGTERM, record_signo);
956
957 setbuf(stdout, NULL);
958
959 opts_for_fsck = doall = notitle = 0;
960 devices = NULL;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000961 num_devices = 0;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +0200962 new_args(); /* G.args[0] = NULL, will be replaced by fsck.<type> */
963 /* G.instance_list = NULL; - in bss, so already zeroed */
Denys Vlasenko7649bd02009-09-13 05:52:46 +0200964
Denys Vlasenko66837452009-09-13 05:52:03 +0200965 while (*++argv) {
966 int j;
967 int optpos;
968 char *options;
969 char *arg = *argv;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000970
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000971 /* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000972 if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000973// FIXME: must check that arg is a blkdev, or resolve
974// "/path", "UUID=xxx" or "LABEL=xxx" into block device name
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000975// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties)
Denis Vlasenkodeeed592008-07-08 05:14:36 +0000976 devices = xrealloc_vector(devices, 2, num_devices);
Denys Vlasenko66837452009-09-13 05:52:03 +0200977 devices[num_devices++] = arg;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000978 continue;
979 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000980
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000981 if (arg[0] != '-' || opts_for_fsck) {
Denys Vlasenko7649bd02009-09-13 05:52:46 +0200982 *new_args() = arg;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000983 continue;
984 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000985
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000986 if (LONE_CHAR(arg + 1, '-')) { /* "--" ? */
987 opts_for_fsck = 1;
988 continue;
989 }
990
991 optpos = 0;
992 options = NULL;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000993 for (j = 1; arg[j]; j++) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000994 switch (arg[j]) {
995 case 'A':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +0000996 doall = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000997 break;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000998#if DO_PROGRESS_INDICATOR
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000999 case 'C':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001000 progress = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001001 if (arg[++j]) { /* -Cn */
Denys Vlasenko77832482010-08-12 14:14:45 +02001002 progress_fd = xatoi_positive(&arg[j]);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001003 goto next_arg;
1004 }
1005 /* -C n */
Denys Vlasenko66837452009-09-13 05:52:03 +02001006 if (!*++argv)
1007 bb_show_usage();
Denys Vlasenko77832482010-08-12 14:14:45 +02001008 progress_fd = xatoi_positive(*argv);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001009 goto next_arg;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001010#endif
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001011 case 'V':
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001012 G.verbose++;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001013 break;
1014 case 'N':
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001015 G.noexecute = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001016 break;
1017 case 'R':
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001018 G.skip_root = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001019 break;
1020 case 'T':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001021 notitle = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001022 break;
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001023/* case 'M':
1024 like_mount = 1;
1025 break; */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001026 case 'P':
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001027 G.parallel_root = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001028 break;
1029 case 's':
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001030 G.serialize = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001031 break;
1032 case 't':
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001033 if (G.fstype)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001034 bb_show_usage();
1035 if (arg[++j])
1036 tmp = &arg[j];
Denys Vlasenko66837452009-09-13 05:52:03 +02001037 else if (*++argv)
1038 tmp = *argv;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001039 else
1040 bb_show_usage();
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001041 G.fstype = xstrdup(tmp);
1042 compile_fs_type(G.fstype);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001043 goto next_arg;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001044 case '?':
1045 bb_show_usage();
1046 break;
1047 default:
1048 optpos++;
1049 /* one extra for '\0' */
1050 options = xrealloc(options, optpos + 2);
1051 options[optpos] = arg[j];
1052 break;
1053 }
1054 }
1055 next_arg:
1056 if (optpos) {
1057 options[0] = '-';
1058 options[optpos + 1] = '\0';
Denys Vlasenko7649bd02009-09-13 05:52:46 +02001059 *new_args() = options;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001060 }
1061 }
1062 if (getenv("FSCK_FORCE_ALL_PARALLEL"))
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001063 G.force_all_parallel = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001064 tmp = getenv("FSCK_MAX_INST");
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001065 G.max_running = INT_MAX;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001066 if (tmp)
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001067 G.max_running = xatoi(tmp);
1068 new_args(); /* G.args[G.num_args - 2] will be replaced by <device> */
1069 new_args(); /* G.args[G.num_args - 1] is the last, NULL element */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001070
1071 if (!notitle)
1072 puts("fsck (busybox "BB_VER", "BB_BT")");
1073
Denis Vlasenko1abf91a2007-01-19 02:02:33 +00001074 /* Even plain "fsck /dev/hda1" needs fstab to get fs type,
1075 * so we are scanning it anyway */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001076 fstab = getenv("FSTAB_FILE");
1077 if (!fstab)
1078 fstab = "/etc/fstab";
1079 load_fs_info(fstab);
1080
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001081 /*interactive = (num_devices == 1) | G.serialize;*/
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001082
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001083 if (num_devices == 0)
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001084 /*interactive =*/ G.serialize = doall = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001085 if (doall)
1086 return check_all();
1087
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001088 status = 0;
Denis Vlasenko0de93752006-12-26 02:51:29 +00001089 for (i = 0; i < num_devices; i++) {
Denys Vlasenko66837452009-09-13 05:52:03 +02001090 if (bb_got_signal) {
1091 kill_all_if_got_signal();
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001092 break;
1093 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001094
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001095 fs = lookup(devices[i]);
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001096 if (!fs)
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001097 fs = create_fs_device(devices[i], "", "auto", NULL, -1);
1098 fsck_device(fs /*, interactive */);
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001099
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001100 if (G.serialize
1101 || (G.num_running >= G.max_running)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001102 ) {
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001103 int exit_status = wait_one(0);
1104 if (exit_status >= 0)
1105 status |= exit_status;
Denys Vlasenkoc4fb8c62015-10-19 02:24:14 +02001106 if (G.verbose > 1)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001107 puts("----------------------------------");
1108 }
1109 }
1110 status |= wait_many(FLAG_WAIT_ALL);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001111 return status;
1112}