blob: 0707d295ddc00a2fc8a9d5b6c53ebff3531d7424 [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 *
23 * %Begin-Header%
24 * This file may be redistributed under the terms of the GNU Public
25 * License.
26 * %End-Header%
27 */
28
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +000029/* All filesystem specific hooks have been removed.
30 * If filesystem cannot be determined, we will execute
31 * "fsck.auto". Currently this also happens if you specify
32 * UUID=xxx or LABEL=xxx as an object to check.
33 * Detection code for that is also probably has to be in fsck.auto.
34 *
35 * In other words, this is _really_ is just a driver program which
36 * spawns actual fsck.something for each filesystem to check.
37 * It doesn't guess filesystem types from on-disk format.
38 */
39
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000040#include "libbb.h"
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000041
Denis Vlasenkoa55bd052008-03-17 08:59:19 +000042/* "progress indicator" code is somewhat buggy and ext[23] specific.
43 * We should be filesystem agnostic. IOW: there should be a well-defined
44 * API for fsck.something, NOT ad-hoc hacks in generic fsck. */
45#define DO_PROGRESS_INDICATOR 0
46
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000047#define EXIT_OK 0
48#define EXIT_NONDESTRUCT 1
49#define EXIT_DESTRUCT 2
50#define EXIT_UNCORRECTED 4
51#define EXIT_ERROR 8
52#define EXIT_USAGE 16
53#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
54
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000055/*
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +000056 * Internal structure for mount table entries.
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000057 */
58
59struct fs_info {
Denis Vlasenkoe18a2932007-01-19 02:03:14 +000060 struct fs_info *next;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000061 char *device;
62 char *mountpt;
63 char *type;
64 char *opts;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000065 int passno;
66 int flags;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000067};
68
69#define FLAG_DONE 1
70#define FLAG_PROGRESS 2
71/*
72 * Structure to allow exit codes to be stored
73 */
74struct fsck_instance {
Denis Vlasenkoe18a2932007-01-19 02:03:14 +000075 struct fsck_instance *next;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000076 int pid;
77 int flags;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +000078#if DO_PROGRESS_INDICATOR
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000079 time_t start_time;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +000080#endif
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000081 char *prog;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000082 char *device;
83 char *base_device; /* /dev/hda for /dev/hdaN etc */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000084};
85
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000086static const char ignored_types[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +000087 "ignore\0"
88 "iso9660\0"
89 "nfs\0"
90 "proc\0"
91 "sw\0"
92 "swap\0"
93 "tmpfs\0"
94 "devpts\0";
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +000095
Denis Vlasenko0de93752006-12-26 02:51:29 +000096#if 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000097static const char really_wanted[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +000098 "minix\0"
99 "ext2\0"
100 "ext3\0"
101 "jfs\0"
102 "reiserfs\0"
103 "xiafs\0"
104 "xfs\0";
Denis Vlasenko0de93752006-12-26 02:51:29 +0000105#endif
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000106
107#define BASE_MD "/dev/md"
108
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000109static char **devices;
110static char **args;
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +0000111static int num_devices;
112static int num_args;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000113static int verbose;
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000114
115#define FS_TYPE_FLAG_NORMAL 0
116#define FS_TYPE_FLAG_OPT 1
117#define FS_TYPE_FLAG_NEGOPT 2
118static char **fs_type_list;
119static uint8_t *fs_type_flag;
120static smallint fs_type_negated;
121
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +0000122static volatile smallint cancel_requested;
123static smallint doall;
124static smallint noexecute;
125static smallint serialize;
126static smallint skip_root;
127/* static smallint like_mount; */
128static smallint notitle;
129static smallint parallel_root;
130static smallint force_all_parallel;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000131
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000132#if DO_PROGRESS_INDICATOR
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +0000133static smallint progress;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000134static int progress_fd;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000135#endif
136
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000137static int num_running;
138static int max_running;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000139static char *fstype;
Denis Vlasenko0de93752006-12-26 02:51:29 +0000140static struct fs_info *filesys_info;
141static struct fs_info *filesys_last;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000142static struct fsck_instance *instance_list;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000143
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000144/*
145 * Return the "base device" given a particular device; this is used to
146 * assure that we only fsck one partition on a particular drive at any
147 * one time. Otherwise, the disk heads will be seeking all over the
148 * place. If the base device cannot be determined, return NULL.
149 *
150 * The base_device() function returns an allocated string which must
151 * be freed.
152 */
153#if ENABLE_FEATURE_DEVFS
154/*
155 * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
156 * pathames.
157 */
158static const char *const devfs_hier[] = {
159 "host", "bus", "target", "lun", NULL
160};
161#endif
162
163static char *base_device(const char *device)
164{
165 char *str, *cp;
166#if ENABLE_FEATURE_DEVFS
167 const char *const *hier;
168 const char *disk;
169 int len;
170#endif
171 cp = str = xstrdup(device);
172
173 /* Skip over /dev/; if it's not present, give up. */
174 if (strncmp(cp, "/dev/", 5) != 0)
175 goto errout;
176 cp += 5;
177
178 /*
179 * For md devices, we treat them all as if they were all
180 * on one disk, since we don't know how to parallelize them.
181 */
182 if (cp[0] == 'm' && cp[1] == 'd') {
183 cp[2] = 0;
184 return str;
185 }
186
187 /* Handle DAC 960 devices */
188 if (strncmp(cp, "rd/", 3) == 0) {
189 cp += 3;
190 if (cp[0] != 'c' || !isdigit(cp[1])
191 || cp[2] != 'd' || !isdigit(cp[3]))
192 goto errout;
193 cp[4] = 0;
194 return str;
195 }
196
197 /* Now let's handle /dev/hd* and /dev/sd* devices.... */
198 if ((cp[0] == 'h' || cp[0] == 's') && cp[1] == 'd') {
199 cp += 2;
200 /* If there's a single number after /dev/hd, skip it */
201 if (isdigit(*cp))
202 cp++;
203 /* What follows must be an alpha char, or give up */
204 if (!isalpha(*cp))
205 goto errout;
206 cp[1] = 0;
207 return str;
208 }
209
210#if ENABLE_FEATURE_DEVFS
211 /* Now let's handle devfs (ugh) names */
212 len = 0;
213 if (strncmp(cp, "ide/", 4) == 0)
214 len = 4;
215 if (strncmp(cp, "scsi/", 5) == 0)
216 len = 5;
217 if (len) {
218 cp += len;
219 /*
220 * Now we proceed down the expected devfs hierarchy.
221 * i.e., .../host1/bus2/target3/lun4/...
222 * If we don't find the expected token, followed by
223 * some number of digits at each level, abort.
224 */
225 for (hier = devfs_hier; *hier; hier++) {
226 len = strlen(*hier);
227 if (strncmp(cp, *hier, len) != 0)
228 goto errout;
229 cp += len;
230 while (*cp != '/' && *cp != 0) {
231 if (!isdigit(*cp))
232 goto errout;
233 cp++;
234 }
235 cp++;
236 }
237 cp[-1] = 0;
238 return str;
239 }
240
241 /* Now handle devfs /dev/disc or /dev/disk names */
242 disk = 0;
243 if (strncmp(cp, "discs/", 6) == 0)
244 disk = "disc";
245 else if (strncmp(cp, "disks/", 6) == 0)
246 disk = "disk";
247 if (disk) {
248 cp += 6;
249 if (strncmp(cp, disk, 4) != 0)
250 goto errout;
251 cp += 4;
252 while (*cp != '/' && *cp != 0) {
253 if (!isdigit(*cp))
254 goto errout;
255 cp++;
256 }
257 *cp = 0;
258 return str;
259 }
260#endif
261 errout:
262 free(str);
263 return NULL;
264}
265
266static void free_instance(struct fsck_instance *p)
267{
268 free(p->prog);
269 free(p->device);
270 free(p->base_device);
271 free(p);
272}
273
274static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
275 const char *type, const char *opts,
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000276 int passno)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000277{
278 struct fs_info *fs;
279
280 fs = xzalloc(sizeof(*fs));
281 fs->device = xstrdup(device);
282 fs->mountpt = xstrdup(mntpnt);
283 fs->type = xstrdup(type);
284 fs->opts = xstrdup(opts ? opts : "");
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000285 fs->passno = passno;
286 /*fs->flags = 0; */
287 /*fs->next = NULL; */
288
289 if (!filesys_info)
290 filesys_info = fs;
291 else
292 filesys_last->next = fs;
293 filesys_last = fs;
294
295 return fs;
296}
297
298static void strip_line(char *line)
299{
300 char *p = line + strlen(line) - 1;
301
302 while (*line) {
303 if (*p != '\n' && *p != '\r')
304 break;
305 *p-- = '\0';
306 }
307}
308
309static char *parse_word(char **buf)
310{
311 char *word, *next;
312
313 word = *buf;
314 if (*word == '\0')
315 return NULL;
316
317 word = skip_whitespace(word);
318 next = skip_non_whitespace(word);
319 if (*next)
320 *next++ = '\0';
321 *buf = next;
322 return word;
323}
324
325static void parse_escape(char *word)
326{
327 char *q, c;
328 const char *p;
329
330 if (!word)
331 return;
332
333 for (p = q = word; *p; q++) {
334 c = *p++;
335 if (c != '\\') {
336 *q = c;
337 } else {
338 *q = bb_process_escape_sequence(&p);
339 }
340 }
341 *q = '\0';
342}
343
344static int parse_fstab_line(char *line, struct fs_info **ret_fs)
345{
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000346 char *device, *mntpnt, *type, *opts, *passno, *cp;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000347 struct fs_info *fs;
348
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000349 *ret_fs = NULL;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000350 strip_line(line);
Denis Vlasenkoc03e8722007-12-26 20:56:55 +0000351 *strchrnul(line, '#') = '\0'; /* Ignore everything after comment */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000352 cp = line;
353
354 device = parse_word(&cp);
355 if (!device) return 0; /* Allow blank lines */
356 mntpnt = parse_word(&cp);
357 type = parse_word(&cp);
358 opts = parse_word(&cp);
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000359 /*freq =*/ parse_word(&cp);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000360 passno = parse_word(&cp);
361
362 if (!mntpnt || !type)
363 return -1;
364
365 parse_escape(device);
366 parse_escape(mntpnt);
367 parse_escape(type);
368 parse_escape(opts);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000369 parse_escape(passno);
370
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000371 if (strchr(type, ','))
372 type = NULL;
373
374 fs = create_fs_device(device, mntpnt, type ? type : "auto", opts,
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000375 (passno ? atoi(passno) : -1));
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000376 *ret_fs = fs;
377 return 0;
378}
379
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000380/* Load the filesystem database from /etc/fstab */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000381static void load_fs_info(const char *filename)
382{
383 FILE *f;
384 int lineno = 0;
385 int old_fstab = 1;
386 struct fs_info *fs;
387
388 f = fopen_or_warn(filename, "r");
389 if (f == NULL) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000390 return;
391 }
392 while (1) {
393 int r;
Denis Vlasenko8ee649a2008-03-26 20:04:27 +0000394 char *buf = xmalloc_fgetline(f);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000395 if (!buf) break;
396 r = parse_fstab_line(buf, &fs);
397 free(buf);
398 lineno++;
399 if (r < 0) {
400 bb_error_msg("WARNING: bad format "
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +0000401 "on line %d of %s", lineno, filename);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000402 continue;
403 }
404 if (!fs)
405 continue;
406 if (fs->passno < 0)
407 fs->passno = 0;
408 else
409 old_fstab = 0;
410 }
411 fclose(f);
412
413 if (old_fstab) {
Denis Vlasenko0de93752006-12-26 02:51:29 +0000414 fputs("\007"
415"WARNING: Your /etc/fstab does not contain the fsck passno field.\n"
416"I will kludge around things for you, but you should fix\n"
417"your /etc/fstab file as soon as you can.\n\n", stderr);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000418 for (fs = filesys_info; fs; fs = fs->next) {
419 fs->passno = 1;
420 }
421 }
422}
423
424/* Lookup filesys in /etc/fstab and return the corresponding entry. */
425static struct fs_info *lookup(char *filesys)
426{
427 struct fs_info *fs;
428
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000429 for (fs = filesys_info; fs; fs = fs->next) {
430 if (strcmp(filesys, fs->device) == 0
431 || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0)
432 )
433 break;
434 }
435
436 return fs;
437}
438
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000439#if DO_PROGRESS_INDICATOR
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000440static int progress_active(void)
441{
442 struct fsck_instance *inst;
443
444 for (inst = instance_list; inst; inst = inst->next) {
445 if (inst->flags & FLAG_DONE)
446 continue;
447 if (inst->flags & FLAG_PROGRESS)
448 return 1;
449 }
450 return 0;
451}
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000452#endif
453
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000454
455/*
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000456 * Send a signal to all outstanding fsck child processes
457 */
Denis Vlasenko0de93752006-12-26 02:51:29 +0000458static void kill_all_if_cancel_requested(void)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000459{
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +0000460 static smallint kill_sent;
Denis Vlasenko0de93752006-12-26 02:51:29 +0000461
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000462 struct fsck_instance *inst;
Denis Vlasenko0de93752006-12-26 02:51:29 +0000463
464 if (!cancel_requested || kill_sent)
465 return;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000466
467 for (inst = instance_list; inst; inst = inst->next) {
468 if (inst->flags & FLAG_DONE)
469 continue;
Denis Vlasenko0de93752006-12-26 02:51:29 +0000470 kill(inst->pid, SIGTERM);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000471 }
Denis Vlasenko0de93752006-12-26 02:51:29 +0000472 kill_sent = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000473}
474
475/*
476 * Wait for one child process to exit; when it does, unlink it from
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000477 * the list of executing child processes, free, and return its exit status.
478 * If there is no exited child, return -1.
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000479 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000480static int wait_one(int flags)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000481{
482 int status;
483 int sig;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000484 struct fsck_instance *inst, *prev;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000485 pid_t pid;
486
487 if (!instance_list)
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000488 return -1;
489 /* if (noexecute) { already returned -1; } */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000490
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000491 while (1) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000492 pid = waitpid(-1, &status, flags);
Denis Vlasenko0de93752006-12-26 02:51:29 +0000493 kill_all_if_cancel_requested();
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000494 if (pid == 0) /* flags == WNOHANG and no children exited */
495 return -1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000496 if (pid < 0) {
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000497 if (errno == EINTR)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000498 continue;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000499 if (errno == ECHILD) { /* paranoia */
500 bb_error_msg("wait: no more children");
501 return -1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000502 }
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000503 bb_perror_msg("wait");
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000504 continue;
505 }
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000506 prev = NULL;
507 inst = instance_list;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000508 do {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000509 if (inst->pid == pid)
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000510 goto child_died;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000511 prev = inst;
512 inst = inst->next;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000513 } while (inst);
514 }
515 child_died:
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000516
517 if (WIFEXITED(status))
518 status = WEXITSTATUS(status);
519 else if (WIFSIGNALED(status)) {
520 sig = WTERMSIG(status);
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000521 status = EXIT_UNCORRECTED;
522 if (sig != SIGINT) {
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000523 printf("Warning: %s %s terminated "
524 "by signal %d\n",
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000525 inst->prog, inst->device, sig);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000526 status = EXIT_ERROR;
527 }
528 } else {
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000529 printf("%s %s: status is %x, should never happen\n",
530 inst->prog, inst->device, status);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000531 status = EXIT_ERROR;
532 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000533
534#if DO_PROGRESS_INDICATOR
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +0000535 if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) {
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000536 struct fsck_instance *inst2;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000537 for (inst2 = instance_list; inst2; inst2 = inst2->next) {
538 if (inst2->flags & FLAG_DONE)
539 continue;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000540 if (strcmp(inst2->type, "ext2") != 0
541 && strcmp(inst2->type, "ext3") != 0
542 ) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000543 continue;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000544 }
545 /* ext[23], we will send USR1
546 * (request to start displaying progress bar)
547 *
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000548 * If we've just started the fsck, wait a tiny
549 * bit before sending the kill, to give it
550 * time to set up the signal handler
551 */
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000552 if (inst2->start_time >= time(NULL) - 1)
553 sleep(1);
554 kill(inst2->pid, SIGUSR1);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000555 inst2->flags |= FLAG_PROGRESS;
556 break;
557 }
558 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000559#endif
560
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000561 if (prev)
562 prev->next = inst->next;
563 else
564 instance_list = inst->next;
565 if (verbose > 1)
566 printf("Finished with %s (exit status %d)\n",
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000567 inst->device, status);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000568 num_running--;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000569 free_instance(inst);
570
571 return status;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000572}
573
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000574/*
575 * Wait until all executing child processes have exited; return the
576 * logical OR of all of their exit code values.
577 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000578#define FLAG_WAIT_ALL 0
579#define FLAG_WAIT_ATLEAST_ONE WNOHANG
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000580static int wait_many(int flags)
581{
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000582 int exit_status;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000583 int global_status = 0;
584 int wait_flags = 0;
585
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000586 while ((exit_status = wait_one(wait_flags)) != -1) {
587 global_status |= exit_status;
588 wait_flags |= flags;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000589 }
590 return global_status;
591}
592
593/*
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000594 * Execute a particular fsck program, and link it into the list of
595 * child processes we are waiting for.
596 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000597static void execute(const char *type, const char *device,
598 const char *mntpt /*, int interactive */)
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000599{
600 char *argv[num_args + 4]; /* see count below: */
601 int argc;
602 int i;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000603 struct fsck_instance *inst;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000604 pid_t pid;
605
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000606 argv[0] = xasprintf("fsck.%s", type); /* 1 */
607 for (i = 0; i < num_args; i++)
608 argv[i+1] = args[i]; /* num_args */
609 argc = num_args + 1;
610
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000611#if DO_PROGRESS_INDICATOR
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000612 if (progress && !progress_active()) {
613 if (strcmp(type, "ext2") == 0
614 || strcmp(type, "ext3") == 0
615 ) {
616 argv[argc++] = xasprintf("-C%d", progress_fd); /* 1 */
617 inst->flags |= FLAG_PROGRESS;
618 }
619 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000620#endif
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000621
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000622 argv[argc++] = (char*)device; /* 1 */
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000623 argv[argc] = NULL; /* 1 */
624
625 if (verbose || noexecute) {
626 printf("[%s (%d) -- %s]", argv[0], num_running,
627 mntpt ? mntpt : device);
628 for (i = 0; i < argc; i++)
629 printf(" %s", argv[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000630 bb_putchar('\n');
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000631 }
632
633 /* Fork and execute the correct program. */
634 pid = -1;
635 if (!noexecute) {
Denis Vlasenko53091ec2007-03-26 13:35:09 +0000636 pid = spawn(argv);
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000637 if (pid < 0)
Denis Vlasenko0c97c9d2007-10-01 11:58:38 +0000638 bb_simple_perror_msg(argv[0]);
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000639 }
640
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000641#if DO_PROGRESS_INDICATOR
642 free(argv[num_args + 1]);
643#endif
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000644
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000645 /* No child, so don't record an instance */
646 if (pid <= 0) {
647 free(argv[0]);
Denis Vlasenko30eb3192008-02-02 18:54:58 +0000648 return;
649 }
650
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000651 inst = xzalloc(sizeof(*inst));
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000652 inst->pid = pid;
653 inst->prog = argv[0];
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000654 inst->device = xstrdup(device);
655 inst->base_device = base_device(device);
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000656#if DO_PROGRESS_INDICATOR
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000657 inst->start_time = time(NULL);
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000658#endif
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000659
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000660 /* Add to the list of running fsck's.
661 * (was adding to the end, but adding to the front is simpler...) */
662 inst->next = instance_list;
663 instance_list = inst;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000664}
665
666/*
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000667 * Run the fsck program on a particular device
668 *
669 * If the type is specified using -t, and it isn't prefixed with "no"
670 * (as in "noext2") and only one filesystem type is specified, then
671 * use that type regardless of what is specified in /etc/fstab.
672 *
673 * If the type isn't specified by the user, then use either the type
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000674 * specified in /etc/fstab, or "auto".
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000675 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000676static void fsck_device(struct fs_info *fs /*, int interactive */)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000677{
678 const char *type;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000679
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000680 if (strcmp(fs->type, "auto") != 0) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000681 type = fs->type;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000682 if (verbose > 2)
683 bb_info_msg("using filesystem type '%s' %s",
684 type, "from fstab");
685 } else if (fstype
Denis Vlasenko0de93752006-12-26 02:51:29 +0000686 && (fstype[0] != 'n' || fstype[1] != 'o') /* != "no" */
687 && strncmp(fstype, "opts=", 5) != 0
688 && strncmp(fstype, "loop", 4) != 0
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000689 && !strchr(fstype, ',')
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000690 ) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000691 type = fstype;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +0000692 if (verbose > 2)
693 bb_info_msg("using filesystem type '%s' %s",
694 type, "from -t");
695 } else {
696 type = "auto";
697 if (verbose > 2)
698 bb_info_msg("using filesystem type '%s' %s",
699 type, "(default)");
700 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000701
702 num_running++;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000703 execute(type, fs->device, fs->mountpt /*, interactive */);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000704}
705
706/*
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000707 * Returns TRUE if a partition on the same disk is already being
708 * checked.
709 */
710static int device_already_active(char *device)
711{
712 struct fsck_instance *inst;
713 char *base;
714
715 if (force_all_parallel)
716 return 0;
717
718#ifdef BASE_MD
719 /* Don't check a soft raid disk with any other disk */
720 if (instance_list
721 && (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1)
722 || !strncmp(device, BASE_MD, sizeof(BASE_MD)-1))
723 ) {
724 return 1;
725 }
726#endif
727
728 base = base_device(device);
729 /*
730 * If we don't know the base device, assume that the device is
731 * already active if there are any fsck instances running.
732 */
733 if (!base)
734 return (instance_list != NULL);
735
736 for (inst = instance_list; inst; inst = inst->next) {
737 if (!inst->base_device || !strcmp(base, inst->base_device)) {
738 free(base);
739 return 1;
740 }
741 }
742
743 free(base);
744 return 0;
745}
746
747/*
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000748 * This function returns true if a particular option appears in a
749 * comma-delimited options list
750 */
751static int opt_in_list(char *opt, char *optlist)
752{
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000753 char *s;
754 int len;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000755
756 if (!optlist)
757 return 0;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000758
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000759 len = strlen(opt);
760 s = optlist - 1;
761 while (1) {
762 s = strstr(s + 1, opt);
763 if (!s)
764 return 0;
765 /* neither "opt.." nor "xxx,opt.."? */
766 if (s != optlist && s[-1] != ',')
767 continue;
768 /* neither "..opt" nor "..opt,xxx"? */
769 if (s[len] != '\0' && s[len] != ',')
770 continue;
771 return 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000772 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000773}
774
775/* See if the filesystem matches the criteria given by the -t option */
776static int fs_match(struct fs_info *fs)
777{
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000778 int n, ret, checked_type;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000779 char *cp;
780
781 if (!fs_type_list)
782 return 1;
783
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000784 ret = 0;
785 checked_type = 0;
786 n = 0;
787 while (1) {
788 cp = fs_type_list[n];
789 if (!cp)
790 break;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000791 switch (fs_type_flag[n]) {
792 case FS_TYPE_FLAG_NORMAL:
793 checked_type++;
794 if (strcmp(cp, fs->type) == 0)
795 ret = 1;
796 break;
797 case FS_TYPE_FLAG_NEGOPT:
798 if (opt_in_list(cp, fs->opts))
799 return 0;
800 break;
801 case FS_TYPE_FLAG_OPT:
802 if (!opt_in_list(cp, fs->opts))
803 return 0;
804 break;
805 }
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000806 n++;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000807 }
808 if (checked_type == 0)
809 return 1;
810
811 return (fs_type_negated ? !ret : ret);
812}
813
814/* Check if we should ignore this filesystem. */
815static int ignore(struct fs_info *fs)
816{
817 /*
818 * If the pass number is 0, ignore it.
819 */
820 if (fs->passno == 0)
821 return 1;
822
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000823 /*
824 * If a specific fstype is specified, and it doesn't match,
825 * ignore it.
826 */
827 if (!fs_match(fs))
828 return 1;
829
830 /* Are we ignoring this type? */
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000831 if (index_in_strings(ignored_types, fs->type) >= 0)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000832 return 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000833
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000834 /* We can and want to check this file system type. */
835 return 0;
836}
837
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000838/* Check all file systems, using the /etc/fstab table. */
839static int check_all(void)
840{
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000841 struct fs_info *fs;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000842 int status = EXIT_OK;
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000843 smallint not_done_yet;
844 smallint pass_done;
845 int passno;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000846
847 if (verbose)
848 puts("Checking all filesystems");
849
850 /*
851 * Do an initial scan over the filesystem; mark filesystems
852 * which should be ignored as done, and resolve any "auto"
853 * filesystem types (done as a side-effect of calling ignore()).
854 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000855 for (fs = filesys_info; fs; fs = fs->next)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000856 if (ignore(fs))
857 fs->flags |= FLAG_DONE;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000858
859 /*
860 * Find and check the root filesystem.
861 */
862 if (!parallel_root) {
863 for (fs = filesys_info; fs; fs = fs->next) {
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000864 if (LONE_CHAR(fs->mountpt, '/')) {
865 if (!skip_root && !ignore(fs)) {
866 fsck_device(fs /*, 1*/);
867 status |= wait_many(FLAG_WAIT_ALL);
868 if (status > EXIT_NONDESTRUCT)
869 return status;
870 }
871 fs->flags |= FLAG_DONE;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000872 break;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000873 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000874 }
875 }
876 /*
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000877 * This is for the bone-headed user who has root
878 * filesystem listed twice.
879 * "Skip root" will skip _all_ root entries.
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000880 */
881 if (skip_root)
882 for (fs = filesys_info; fs; fs = fs->next)
883 if (LONE_CHAR(fs->mountpt, '/'))
884 fs->flags |= FLAG_DONE;
885
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000886 not_done_yet = 1;
887 passno = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000888 while (not_done_yet) {
889 not_done_yet = 0;
890 pass_done = 1;
891
892 for (fs = filesys_info; fs; fs = fs->next) {
893 if (cancel_requested)
894 break;
895 if (fs->flags & FLAG_DONE)
896 continue;
897 /*
898 * If the filesystem's pass number is higher
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000899 * than the current pass number, then we didn't
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000900 * do it yet.
901 */
902 if (fs->passno > passno) {
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000903 not_done_yet = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000904 continue;
905 }
906 /*
907 * If a filesystem on a particular device has
908 * already been spawned, then we need to defer
909 * this to another pass.
910 */
911 if (device_already_active(fs->device)) {
912 pass_done = 0;
913 continue;
914 }
915 /*
916 * Spawn off the fsck process
917 */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000918 fsck_device(fs /*, serialize*/);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000919 fs->flags |= FLAG_DONE;
920
921 /*
922 * Only do one filesystem at a time, or if we
923 * have a limit on the number of fsck's extant
924 * at one time, apply that limit.
925 */
926 if (serialize
927 || (max_running && (num_running >= max_running))
928 ) {
929 pass_done = 0;
930 break;
931 }
932 }
933 if (cancel_requested)
934 break;
935 if (verbose > 1)
936 printf("--waiting-- (pass %d)\n", passno);
937 status |= wait_many(pass_done ? FLAG_WAIT_ALL :
938 FLAG_WAIT_ATLEAST_ONE);
939 if (pass_done) {
940 if (verbose > 1)
941 puts("----------------------------------");
942 passno++;
943 } else
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000944 not_done_yet = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000945 }
Denis Vlasenko0de93752006-12-26 02:51:29 +0000946 kill_all_if_cancel_requested();
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000947 status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
948 return status;
949}
950
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000951/*
952 * Deal with the fsck -t argument.
953 * Huh, for mount "-t novfat,nfs" means "neither vfat nor nfs"!
954 * Why here we require "-t novfat,nonfs" ??
955 */
956static void compile_fs_type(char *fs_type)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +0000957{
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000958 char *s;
959 int num = 2;
960 smallint negate;
961
Denis Vlasenkoa55bd052008-03-17 08:59:19 +0000962 s = fs_type;
963 while ((s = strchr(s, ','))) {
964 num++;
965 s++;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000966 }
967
968 fs_type_list = xzalloc(num * sizeof(fs_type_list[0]));
969 fs_type_flag = xzalloc(num * sizeof(fs_type_flag[0]));
970 fs_type_negated = -1; /* not yet known is it negated or not */
971
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000972 num = 0;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000973 s = fs_type;
974 while (1) {
975 char *comma;
976
977 negate = 0;
978 if (s[0] == 'n' && s[1] == 'o') { /* "no.." */
979 s += 2;
980 negate = 1;
981 } else if (s[0] == '!') {
982 s++;
983 negate = 1;
984 }
Denis Vlasenkoe18a2932007-01-19 02:03:14 +0000985
Denis Vlasenko1abf91a2007-01-19 02:02:33 +0000986 if (strcmp(s, "loop") == 0)
987 /* loop is really short-hand for opts=loop */
988 goto loop_special_case;
989 if (strncmp(s, "opts=", 5) == 0) {
990 s += 5;
991 loop_special_case:
992 fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT;
993 } else {
994 if (fs_type_negated == -1)
995 fs_type_negated = negate;
996 if (fs_type_negated != negate)
997 bb_error_msg_and_die(
998"either all or none of the filesystem types passed to -t must be prefixed "
999"with 'no' or '!'");
1000 }
1001 comma = strchr(s, ',');
1002 fs_type_list[num++] = comma ? xstrndup(s, comma-s) : xstrdup(s);
1003 if (!comma)
1004 break;
1005 s = comma + 1;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +00001006 }
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001007}
1008
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001009static void parse_args(char **argv)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001010{
1011 int i, j;
1012 char *arg, *tmp;
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001013 char *options;
1014 int optpos;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001015 int opts_for_fsck = 0;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001016
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001017 /* in bss, so already zeroed
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001018 num_devices = 0;
1019 num_args = 0;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +00001020 instance_list = NULL;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001021 */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001022
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001023 for (i = 1; argv[i]; i++) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001024 arg = argv[i];
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001025
Denis Vlasenko1abf91a2007-01-19 02:02:33 +00001026 /* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001027 if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
Denis Vlasenko1abf91a2007-01-19 02:02:33 +00001028// FIXME: must check that arg is a blkdev, or resolve
1029// "/path", "UUID=xxx" or "LABEL=xxx" into block device name
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001030// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001031 devices = xrealloc(devices, (num_devices+1) * sizeof(devices[0]));
1032 devices[num_devices++] = xstrdup(arg);
1033 continue;
1034 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001035
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001036 if (arg[0] != '-' || opts_for_fsck) {
1037 args = xrealloc(args, (num_args+1) * sizeof(args[0]));
1038 args[num_args++] = xstrdup(arg);
1039 continue;
1040 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001041
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001042 if (LONE_CHAR(arg + 1, '-')) { /* "--" ? */
1043 opts_for_fsck = 1;
1044 continue;
1045 }
1046
1047 optpos = 0;
1048 options = NULL;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001049 for (j = 1; arg[j]; j++) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001050 switch (arg[j]) {
1051 case 'A':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001052 doall = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001053 break;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001054#if DO_PROGRESS_INDICATOR
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001055 case 'C':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001056 progress = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001057 if (arg[++j]) { /* -Cn */
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001058 progress_fd = xatoi_u(&arg[j]);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001059 goto next_arg;
1060 }
1061 /* -C n */
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001062 if (!argv[++i]) bb_show_usage();
1063 progress_fd = xatoi_u(argv[i]);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001064 goto next_arg;
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001065#endif
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001066 case 'V':
1067 verbose++;
1068 break;
1069 case 'N':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001070 noexecute = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001071 break;
1072 case 'R':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001073 skip_root = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001074 break;
1075 case 'T':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001076 notitle = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001077 break;
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001078/* case 'M':
1079 like_mount = 1;
1080 break; */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001081 case 'P':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001082 parallel_root = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001083 break;
1084 case 's':
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001085 serialize = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001086 break;
1087 case 't':
1088 if (fstype)
1089 bb_show_usage();
1090 if (arg[++j])
1091 tmp = &arg[j];
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001092 else if (argv[++i])
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001093 tmp = argv[i];
1094 else
1095 bb_show_usage();
1096 fstype = xstrdup(tmp);
1097 compile_fs_type(fstype);
1098 goto next_arg;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001099 case '?':
1100 bb_show_usage();
1101 break;
1102 default:
1103 optpos++;
1104 /* one extra for '\0' */
1105 options = xrealloc(options, optpos + 2);
1106 options[optpos] = arg[j];
1107 break;
1108 }
1109 }
1110 next_arg:
1111 if (optpos) {
1112 options[0] = '-';
1113 options[optpos + 1] = '\0';
1114 args = xrealloc(args, (num_args+1) * sizeof(args[0]));
1115 args[num_args++] = options;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001116 }
1117 }
1118 if (getenv("FSCK_FORCE_ALL_PARALLEL"))
Denis Vlasenkoa0e701d2007-01-19 02:01:19 +00001119 force_all_parallel = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001120 tmp = getenv("FSCK_MAX_INST");
1121 if (tmp)
1122 max_running = xatoi(tmp);
1123}
1124
Denis Vlasenko1abf91a2007-01-19 02:02:33 +00001125static void signal_cancel(int sig ATTRIBUTE_UNUSED)
1126{
1127 cancel_requested = 1;
1128}
1129
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001130int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko68404f12008-03-17 09:00:54 +00001131int fsck_main(int argc ATTRIBUTE_UNUSED, char **argv)
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001132{
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001133 int i, status;
1134 /*int interactive;*/
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001135 const char *fstab;
1136 struct fs_info *fs;
Denis Vlasenko1abf91a2007-01-19 02:02:33 +00001137
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001138 /* we want wait() to be interruptible */
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00001139 signal_no_SA_RESTART_empty_mask(SIGINT, signal_cancel);
1140 signal_no_SA_RESTART_empty_mask(SIGTERM, signal_cancel);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001141
1142 setbuf(stdout, NULL);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001143
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001144 parse_args(argv);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001145
1146 if (!notitle)
1147 puts("fsck (busybox "BB_VER", "BB_BT")");
1148
Denis Vlasenko1abf91a2007-01-19 02:02:33 +00001149 /* Even plain "fsck /dev/hda1" needs fstab to get fs type,
1150 * so we are scanning it anyway */
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001151 fstab = getenv("FSTAB_FILE");
1152 if (!fstab)
1153 fstab = "/etc/fstab";
1154 load_fs_info(fstab);
1155
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001156 /*interactive = (num_devices == 1) | serialize;*/
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001157
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001158 if (num_devices == 0)
1159 /*interactive =*/ serialize = doall = 1;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001160 if (doall)
1161 return check_all();
1162
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001163 status = 0;
Denis Vlasenko0de93752006-12-26 02:51:29 +00001164 for (i = 0; i < num_devices; i++) {
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001165 if (cancel_requested) {
Denis Vlasenko0de93752006-12-26 02:51:29 +00001166 kill_all_if_cancel_requested();
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001167 break;
1168 }
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001169
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001170 fs = lookup(devices[i]);
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001171 if (!fs)
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001172 fs = create_fs_device(devices[i], "", "auto", NULL, -1);
1173 fsck_device(fs /*, interactive */);
Denis Vlasenkof8c11aa2007-01-19 02:04:09 +00001174
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001175 if (serialize
1176 || (max_running && (num_running >= max_running))
1177 ) {
Denis Vlasenkoa55bd052008-03-17 08:59:19 +00001178 int exit_status = wait_one(0);
1179 if (exit_status >= 0)
1180 status |= exit_status;
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001181 if (verbose > 1)
1182 puts("----------------------------------");
1183 }
1184 }
1185 status |= wait_many(FLAG_WAIT_ALL);
Denis Vlasenkoc4f623e2006-12-26 01:30:59 +00001186 return status;
1187}