fsck.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187
  1. /* 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. /* All filesystem specific hooks have been removed.
  29. * If filesystem cannot be determined, we will execute
  30. * "fsck.auto". Currently this also happens if you specify
  31. * UUID=xxx or LABEL=xxx as an object to check.
  32. * Detection code for that is also probably has to be in fsck.auto.
  33. *
  34. * In other words, this is _really_ is just a driver program which
  35. * spawns actual fsck.something for each filesystem to check.
  36. * It doesn't guess filesystem types from on-disk format.
  37. */
  38. #include "libbb.h"
  39. /* "progress indicator" code is somewhat buggy and ext[23] specific.
  40. * We should be filesystem agnostic. IOW: there should be a well-defined
  41. * API for fsck.something, NOT ad-hoc hacks in generic fsck. */
  42. #define DO_PROGRESS_INDICATOR 0
  43. #define EXIT_OK 0
  44. #define EXIT_NONDESTRUCT 1
  45. #define EXIT_DESTRUCT 2
  46. #define EXIT_UNCORRECTED 4
  47. #define EXIT_ERROR 8
  48. #define EXIT_USAGE 16
  49. #define FSCK_CANCELED 32 /* Aborted with a signal or ^C */
  50. /*
  51. * Internal structure for mount table entries.
  52. */
  53. struct fs_info {
  54. struct fs_info *next;
  55. char *device;
  56. char *mountpt;
  57. char *type;
  58. char *opts;
  59. int passno;
  60. int flags;
  61. };
  62. #define FLAG_DONE 1
  63. #define FLAG_PROGRESS 2
  64. /*
  65. * Structure to allow exit codes to be stored
  66. */
  67. struct fsck_instance {
  68. struct fsck_instance *next;
  69. int pid;
  70. int flags;
  71. #if DO_PROGRESS_INDICATOR
  72. time_t start_time;
  73. #endif
  74. char *prog;
  75. char *device;
  76. char *base_device; /* /dev/hda for /dev/hdaN etc */
  77. };
  78. static const char ignored_types[] ALIGN1 =
  79. "ignore\0"
  80. "iso9660\0"
  81. "nfs\0"
  82. "proc\0"
  83. "sw\0"
  84. "swap\0"
  85. "tmpfs\0"
  86. "devpts\0";
  87. #if 0
  88. static const char really_wanted[] ALIGN1 =
  89. "minix\0"
  90. "ext2\0"
  91. "ext3\0"
  92. "jfs\0"
  93. "reiserfs\0"
  94. "xiafs\0"
  95. "xfs\0";
  96. #endif
  97. #define BASE_MD "/dev/md"
  98. static char **devices;
  99. static char **args;
  100. static int num_devices;
  101. static int num_args;
  102. static int verbose;
  103. #define FS_TYPE_FLAG_NORMAL 0
  104. #define FS_TYPE_FLAG_OPT 1
  105. #define FS_TYPE_FLAG_NEGOPT 2
  106. static char **fs_type_list;
  107. static uint8_t *fs_type_flag;
  108. static smallint fs_type_negated;
  109. static volatile smallint cancel_requested;
  110. static smallint doall;
  111. static smallint noexecute;
  112. static smallint serialize;
  113. static smallint skip_root;
  114. /* static smallint like_mount; */
  115. static smallint notitle;
  116. static smallint parallel_root;
  117. static smallint force_all_parallel;
  118. #if DO_PROGRESS_INDICATOR
  119. static smallint progress;
  120. static int progress_fd;
  121. #endif
  122. static int num_running;
  123. static int max_running;
  124. static char *fstype;
  125. static struct fs_info *filesys_info;
  126. static struct fs_info *filesys_last;
  127. static struct fsck_instance *instance_list;
  128. /*
  129. * Return the "base device" given a particular device; this is used to
  130. * assure that we only fsck one partition on a particular drive at any
  131. * one time. Otherwise, the disk heads will be seeking all over the
  132. * place. If the base device cannot be determined, return NULL.
  133. *
  134. * The base_device() function returns an allocated string which must
  135. * be freed.
  136. */
  137. #if ENABLE_FEATURE_DEVFS
  138. /*
  139. * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
  140. * pathames.
  141. */
  142. static const char *const devfs_hier[] = {
  143. "host", "bus", "target", "lun", NULL
  144. };
  145. #endif
  146. static char *base_device(const char *device)
  147. {
  148. char *str, *cp;
  149. #if ENABLE_FEATURE_DEVFS
  150. const char *const *hier;
  151. const char *disk;
  152. int len;
  153. #endif
  154. cp = str = xstrdup(device);
  155. /* Skip over /dev/; if it's not present, give up. */
  156. if (strncmp(cp, "/dev/", 5) != 0)
  157. goto errout;
  158. cp += 5;
  159. /*
  160. * For md devices, we treat them all as if they were all
  161. * on one disk, since we don't know how to parallelize them.
  162. */
  163. if (cp[0] == 'm' && cp[1] == 'd') {
  164. cp[2] = 0;
  165. return str;
  166. }
  167. /* Handle DAC 960 devices */
  168. if (strncmp(cp, "rd/", 3) == 0) {
  169. cp += 3;
  170. if (cp[0] != 'c' || !isdigit(cp[1])
  171. || cp[2] != 'd' || !isdigit(cp[3]))
  172. goto errout;
  173. cp[4] = 0;
  174. return str;
  175. }
  176. /* Now let's handle /dev/hd* and /dev/sd* devices.... */
  177. if ((cp[0] == 'h' || cp[0] == 's') && cp[1] == 'd') {
  178. cp += 2;
  179. /* If there's a single number after /dev/hd, skip it */
  180. if (isdigit(*cp))
  181. cp++;
  182. /* What follows must be an alpha char, or give up */
  183. if (!isalpha(*cp))
  184. goto errout;
  185. cp[1] = 0;
  186. return str;
  187. }
  188. #if ENABLE_FEATURE_DEVFS
  189. /* Now let's handle devfs (ugh) names */
  190. len = 0;
  191. if (strncmp(cp, "ide/", 4) == 0)
  192. len = 4;
  193. if (strncmp(cp, "scsi/", 5) == 0)
  194. len = 5;
  195. if (len) {
  196. cp += len;
  197. /*
  198. * Now we proceed down the expected devfs hierarchy.
  199. * i.e., .../host1/bus2/target3/lun4/...
  200. * If we don't find the expected token, followed by
  201. * some number of digits at each level, abort.
  202. */
  203. for (hier = devfs_hier; *hier; hier++) {
  204. len = strlen(*hier);
  205. if (strncmp(cp, *hier, len) != 0)
  206. goto errout;
  207. cp += len;
  208. while (*cp != '/' && *cp != 0) {
  209. if (!isdigit(*cp))
  210. goto errout;
  211. cp++;
  212. }
  213. cp++;
  214. }
  215. cp[-1] = 0;
  216. return str;
  217. }
  218. /* Now handle devfs /dev/disc or /dev/disk names */
  219. disk = 0;
  220. if (strncmp(cp, "discs/", 6) == 0)
  221. disk = "disc";
  222. else if (strncmp(cp, "disks/", 6) == 0)
  223. disk = "disk";
  224. if (disk) {
  225. cp += 6;
  226. if (strncmp(cp, disk, 4) != 0)
  227. goto errout;
  228. cp += 4;
  229. while (*cp != '/' && *cp != 0) {
  230. if (!isdigit(*cp))
  231. goto errout;
  232. cp++;
  233. }
  234. *cp = 0;
  235. return str;
  236. }
  237. #endif
  238. errout:
  239. free(str);
  240. return NULL;
  241. }
  242. static void free_instance(struct fsck_instance *p)
  243. {
  244. free(p->prog);
  245. free(p->device);
  246. free(p->base_device);
  247. free(p);
  248. }
  249. static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
  250. const char *type, const char *opts,
  251. int passno)
  252. {
  253. struct fs_info *fs;
  254. fs = xzalloc(sizeof(*fs));
  255. fs->device = xstrdup(device);
  256. fs->mountpt = xstrdup(mntpnt);
  257. fs->type = xstrdup(type);
  258. fs->opts = xstrdup(opts ? opts : "");
  259. fs->passno = passno;
  260. /*fs->flags = 0; */
  261. /*fs->next = NULL; */
  262. if (!filesys_info)
  263. filesys_info = fs;
  264. else
  265. filesys_last->next = fs;
  266. filesys_last = fs;
  267. return fs;
  268. }
  269. static void strip_line(char *line)
  270. {
  271. char *p = line + strlen(line) - 1;
  272. while (*line) {
  273. if (*p != '\n' && *p != '\r')
  274. break;
  275. *p-- = '\0';
  276. }
  277. }
  278. static char *parse_word(char **buf)
  279. {
  280. char *word, *next;
  281. word = *buf;
  282. if (*word == '\0')
  283. return NULL;
  284. word = skip_whitespace(word);
  285. next = skip_non_whitespace(word);
  286. if (*next)
  287. *next++ = '\0';
  288. *buf = next;
  289. return word;
  290. }
  291. static void parse_escape(char *word)
  292. {
  293. char *q, c;
  294. const char *p;
  295. if (!word)
  296. return;
  297. for (p = q = word; *p; q++) {
  298. c = *p++;
  299. if (c != '\\') {
  300. *q = c;
  301. } else {
  302. *q = bb_process_escape_sequence(&p);
  303. }
  304. }
  305. *q = '\0';
  306. }
  307. static int parse_fstab_line(char *line, struct fs_info **ret_fs)
  308. {
  309. char *device, *mntpnt, *type, *opts, *passno, *cp;
  310. struct fs_info *fs;
  311. *ret_fs = NULL;
  312. strip_line(line);
  313. *strchrnul(line, '#') = '\0'; /* Ignore everything after comment */
  314. cp = line;
  315. device = parse_word(&cp);
  316. if (!device) return 0; /* Allow blank lines */
  317. mntpnt = parse_word(&cp);
  318. type = parse_word(&cp);
  319. opts = parse_word(&cp);
  320. /*freq =*/ parse_word(&cp);
  321. passno = parse_word(&cp);
  322. if (!mntpnt || !type)
  323. return -1;
  324. parse_escape(device);
  325. parse_escape(mntpnt);
  326. parse_escape(type);
  327. parse_escape(opts);
  328. parse_escape(passno);
  329. if (strchr(type, ','))
  330. type = NULL;
  331. fs = create_fs_device(device, mntpnt, type ? type : "auto", opts,
  332. (passno ? atoi(passno) : -1));
  333. *ret_fs = fs;
  334. return 0;
  335. }
  336. /* Load the filesystem database from /etc/fstab */
  337. static void load_fs_info(const char *filename)
  338. {
  339. FILE *f;
  340. int lineno = 0;
  341. int old_fstab = 1;
  342. struct fs_info *fs;
  343. f = fopen_or_warn(filename, "r");
  344. if (f == NULL) {
  345. return;
  346. }
  347. while (1) {
  348. int r;
  349. char *buf = xmalloc_fgetline(f);
  350. if (!buf) break;
  351. r = parse_fstab_line(buf, &fs);
  352. free(buf);
  353. lineno++;
  354. if (r < 0) {
  355. bb_error_msg("WARNING: bad format "
  356. "on line %d of %s", lineno, filename);
  357. continue;
  358. }
  359. if (!fs)
  360. continue;
  361. if (fs->passno < 0)
  362. fs->passno = 0;
  363. else
  364. old_fstab = 0;
  365. }
  366. fclose(f);
  367. if (old_fstab) {
  368. fputs("\007"
  369. "WARNING: Your /etc/fstab does not contain the fsck passno field.\n"
  370. "I will kludge around things for you, but you should fix\n"
  371. "your /etc/fstab file as soon as you can.\n\n", stderr);
  372. for (fs = filesys_info; fs; fs = fs->next) {
  373. fs->passno = 1;
  374. }
  375. }
  376. }
  377. /* Lookup filesys in /etc/fstab and return the corresponding entry. */
  378. static struct fs_info *lookup(char *filesys)
  379. {
  380. struct fs_info *fs;
  381. for (fs = filesys_info; fs; fs = fs->next) {
  382. if (strcmp(filesys, fs->device) == 0
  383. || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0)
  384. )
  385. break;
  386. }
  387. return fs;
  388. }
  389. #if DO_PROGRESS_INDICATOR
  390. static int progress_active(void)
  391. {
  392. struct fsck_instance *inst;
  393. for (inst = instance_list; inst; inst = inst->next) {
  394. if (inst->flags & FLAG_DONE)
  395. continue;
  396. if (inst->flags & FLAG_PROGRESS)
  397. return 1;
  398. }
  399. return 0;
  400. }
  401. #endif
  402. /*
  403. * Send a signal to all outstanding fsck child processes
  404. */
  405. static void kill_all_if_cancel_requested(void)
  406. {
  407. static smallint kill_sent;
  408. struct fsck_instance *inst;
  409. if (!cancel_requested || kill_sent)
  410. return;
  411. for (inst = instance_list; inst; inst = inst->next) {
  412. if (inst->flags & FLAG_DONE)
  413. continue;
  414. kill(inst->pid, SIGTERM);
  415. }
  416. kill_sent = 1;
  417. }
  418. /*
  419. * Wait for one child process to exit; when it does, unlink it from
  420. * the list of executing child processes, free, and return its exit status.
  421. * If there is no exited child, return -1.
  422. */
  423. static int wait_one(int flags)
  424. {
  425. int status;
  426. int sig;
  427. struct fsck_instance *inst, *prev;
  428. pid_t pid;
  429. if (!instance_list)
  430. return -1;
  431. /* if (noexecute) { already returned -1; } */
  432. while (1) {
  433. pid = waitpid(-1, &status, flags);
  434. kill_all_if_cancel_requested();
  435. if (pid == 0) /* flags == WNOHANG and no children exited */
  436. return -1;
  437. if (pid < 0) {
  438. if (errno == EINTR)
  439. continue;
  440. if (errno == ECHILD) { /* paranoia */
  441. bb_error_msg("wait: no more children");
  442. return -1;
  443. }
  444. bb_perror_msg("wait");
  445. continue;
  446. }
  447. prev = NULL;
  448. inst = instance_list;
  449. do {
  450. if (inst->pid == pid)
  451. goto child_died;
  452. prev = inst;
  453. inst = inst->next;
  454. } while (inst);
  455. }
  456. child_died:
  457. if (WIFEXITED(status))
  458. status = WEXITSTATUS(status);
  459. else if (WIFSIGNALED(status)) {
  460. sig = WTERMSIG(status);
  461. status = EXIT_UNCORRECTED;
  462. if (sig != SIGINT) {
  463. printf("Warning: %s %s terminated "
  464. "by signal %d\n",
  465. inst->prog, inst->device, sig);
  466. status = EXIT_ERROR;
  467. }
  468. } else {
  469. printf("%s %s: status is %x, should never happen\n",
  470. inst->prog, inst->device, status);
  471. status = EXIT_ERROR;
  472. }
  473. #if DO_PROGRESS_INDICATOR
  474. if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) {
  475. struct fsck_instance *inst2;
  476. for (inst2 = instance_list; inst2; inst2 = inst2->next) {
  477. if (inst2->flags & FLAG_DONE)
  478. continue;
  479. if (strcmp(inst2->type, "ext2") != 0
  480. && strcmp(inst2->type, "ext3") != 0
  481. ) {
  482. continue;
  483. }
  484. /* ext[23], we will send USR1
  485. * (request to start displaying progress bar)
  486. *
  487. * If we've just started the fsck, wait a tiny
  488. * bit before sending the kill, to give it
  489. * time to set up the signal handler
  490. */
  491. if (inst2->start_time >= time(NULL) - 1)
  492. sleep(1);
  493. kill(inst2->pid, SIGUSR1);
  494. inst2->flags |= FLAG_PROGRESS;
  495. break;
  496. }
  497. }
  498. #endif
  499. if (prev)
  500. prev->next = inst->next;
  501. else
  502. instance_list = inst->next;
  503. if (verbose > 1)
  504. printf("Finished with %s (exit status %d)\n",
  505. inst->device, status);
  506. num_running--;
  507. free_instance(inst);
  508. return status;
  509. }
  510. /*
  511. * Wait until all executing child processes have exited; return the
  512. * logical OR of all of their exit code values.
  513. */
  514. #define FLAG_WAIT_ALL 0
  515. #define FLAG_WAIT_ATLEAST_ONE WNOHANG
  516. static int wait_many(int flags)
  517. {
  518. int exit_status;
  519. int global_status = 0;
  520. int wait_flags = 0;
  521. while ((exit_status = wait_one(wait_flags)) != -1) {
  522. global_status |= exit_status;
  523. wait_flags |= flags;
  524. }
  525. return global_status;
  526. }
  527. /*
  528. * Execute a particular fsck program, and link it into the list of
  529. * child processes we are waiting for.
  530. */
  531. static void execute(const char *type, const char *device,
  532. const char *mntpt /*, int interactive */)
  533. {
  534. char *argv[num_args + 4]; /* see count below: */
  535. int argc;
  536. int i;
  537. struct fsck_instance *inst;
  538. pid_t pid;
  539. argv[0] = xasprintf("fsck.%s", type); /* 1 */
  540. for (i = 0; i < num_args; i++)
  541. argv[i+1] = args[i]; /* num_args */
  542. argc = num_args + 1;
  543. #if DO_PROGRESS_INDICATOR
  544. if (progress && !progress_active()) {
  545. if (strcmp(type, "ext2") == 0
  546. || strcmp(type, "ext3") == 0
  547. ) {
  548. argv[argc++] = xasprintf("-C%d", progress_fd); /* 1 */
  549. inst->flags |= FLAG_PROGRESS;
  550. }
  551. }
  552. #endif
  553. argv[argc++] = (char*)device; /* 1 */
  554. argv[argc] = NULL; /* 1 */
  555. if (verbose || noexecute) {
  556. printf("[%s (%d) -- %s]", argv[0], num_running,
  557. mntpt ? mntpt : device);
  558. for (i = 0; i < argc; i++)
  559. printf(" %s", argv[i]);
  560. bb_putchar('\n');
  561. }
  562. /* Fork and execute the correct program. */
  563. pid = -1;
  564. if (!noexecute) {
  565. pid = spawn(argv);
  566. if (pid < 0)
  567. bb_simple_perror_msg(argv[0]);
  568. }
  569. #if DO_PROGRESS_INDICATOR
  570. free(argv[num_args + 1]);
  571. #endif
  572. /* No child, so don't record an instance */
  573. if (pid <= 0) {
  574. free(argv[0]);
  575. return;
  576. }
  577. inst = xzalloc(sizeof(*inst));
  578. inst->pid = pid;
  579. inst->prog = argv[0];
  580. inst->device = xstrdup(device);
  581. inst->base_device = base_device(device);
  582. #if DO_PROGRESS_INDICATOR
  583. inst->start_time = time(NULL);
  584. #endif
  585. /* Add to the list of running fsck's.
  586. * (was adding to the end, but adding to the front is simpler...) */
  587. inst->next = instance_list;
  588. instance_list = inst;
  589. }
  590. /*
  591. * Run the fsck program on a particular device
  592. *
  593. * If the type is specified using -t, and it isn't prefixed with "no"
  594. * (as in "noext2") and only one filesystem type is specified, then
  595. * use that type regardless of what is specified in /etc/fstab.
  596. *
  597. * If the type isn't specified by the user, then use either the type
  598. * specified in /etc/fstab, or "auto".
  599. */
  600. static void fsck_device(struct fs_info *fs /*, int interactive */)
  601. {
  602. const char *type;
  603. if (strcmp(fs->type, "auto") != 0) {
  604. type = fs->type;
  605. if (verbose > 2)
  606. bb_info_msg("using filesystem type '%s' %s",
  607. type, "from fstab");
  608. } else if (fstype
  609. && (fstype[0] != 'n' || fstype[1] != 'o') /* != "no" */
  610. && strncmp(fstype, "opts=", 5) != 0
  611. && strncmp(fstype, "loop", 4) != 0
  612. && !strchr(fstype, ',')
  613. ) {
  614. type = fstype;
  615. if (verbose > 2)
  616. bb_info_msg("using filesystem type '%s' %s",
  617. type, "from -t");
  618. } else {
  619. type = "auto";
  620. if (verbose > 2)
  621. bb_info_msg("using filesystem type '%s' %s",
  622. type, "(default)");
  623. }
  624. num_running++;
  625. execute(type, fs->device, fs->mountpt /*, interactive */);
  626. }
  627. /*
  628. * Returns TRUE if a partition on the same disk is already being
  629. * checked.
  630. */
  631. static int device_already_active(char *device)
  632. {
  633. struct fsck_instance *inst;
  634. char *base;
  635. if (force_all_parallel)
  636. return 0;
  637. #ifdef BASE_MD
  638. /* Don't check a soft raid disk with any other disk */
  639. if (instance_list
  640. && (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1)
  641. || !strncmp(device, BASE_MD, sizeof(BASE_MD)-1))
  642. ) {
  643. return 1;
  644. }
  645. #endif
  646. base = base_device(device);
  647. /*
  648. * If we don't know the base device, assume that the device is
  649. * already active if there are any fsck instances running.
  650. */
  651. if (!base)
  652. return (instance_list != NULL);
  653. for (inst = instance_list; inst; inst = inst->next) {
  654. if (!inst->base_device || !strcmp(base, inst->base_device)) {
  655. free(base);
  656. return 1;
  657. }
  658. }
  659. free(base);
  660. return 0;
  661. }
  662. /*
  663. * This function returns true if a particular option appears in a
  664. * comma-delimited options list
  665. */
  666. static int opt_in_list(char *opt, char *optlist)
  667. {
  668. char *s;
  669. int len;
  670. if (!optlist)
  671. return 0;
  672. len = strlen(opt);
  673. s = optlist - 1;
  674. while (1) {
  675. s = strstr(s + 1, opt);
  676. if (!s)
  677. return 0;
  678. /* neither "opt.." nor "xxx,opt.."? */
  679. if (s != optlist && s[-1] != ',')
  680. continue;
  681. /* neither "..opt" nor "..opt,xxx"? */
  682. if (s[len] != '\0' && s[len] != ',')
  683. continue;
  684. return 1;
  685. }
  686. }
  687. /* See if the filesystem matches the criteria given by the -t option */
  688. static int fs_match(struct fs_info *fs)
  689. {
  690. int n, ret, checked_type;
  691. char *cp;
  692. if (!fs_type_list)
  693. return 1;
  694. ret = 0;
  695. checked_type = 0;
  696. n = 0;
  697. while (1) {
  698. cp = fs_type_list[n];
  699. if (!cp)
  700. break;
  701. switch (fs_type_flag[n]) {
  702. case FS_TYPE_FLAG_NORMAL:
  703. checked_type++;
  704. if (strcmp(cp, fs->type) == 0)
  705. ret = 1;
  706. break;
  707. case FS_TYPE_FLAG_NEGOPT:
  708. if (opt_in_list(cp, fs->opts))
  709. return 0;
  710. break;
  711. case FS_TYPE_FLAG_OPT:
  712. if (!opt_in_list(cp, fs->opts))
  713. return 0;
  714. break;
  715. }
  716. n++;
  717. }
  718. if (checked_type == 0)
  719. return 1;
  720. return (fs_type_negated ? !ret : ret);
  721. }
  722. /* Check if we should ignore this filesystem. */
  723. static int ignore(struct fs_info *fs)
  724. {
  725. /*
  726. * If the pass number is 0, ignore it.
  727. */
  728. if (fs->passno == 0)
  729. return 1;
  730. /*
  731. * If a specific fstype is specified, and it doesn't match,
  732. * ignore it.
  733. */
  734. if (!fs_match(fs))
  735. return 1;
  736. /* Are we ignoring this type? */
  737. if (index_in_strings(ignored_types, fs->type) >= 0)
  738. return 1;
  739. /* We can and want to check this file system type. */
  740. return 0;
  741. }
  742. /* Check all file systems, using the /etc/fstab table. */
  743. static int check_all(void)
  744. {
  745. struct fs_info *fs;
  746. int status = EXIT_OK;
  747. smallint not_done_yet;
  748. smallint pass_done;
  749. int passno;
  750. if (verbose)
  751. puts("Checking all filesystems");
  752. /*
  753. * Do an initial scan over the filesystem; mark filesystems
  754. * which should be ignored as done, and resolve any "auto"
  755. * filesystem types (done as a side-effect of calling ignore()).
  756. */
  757. for (fs = filesys_info; fs; fs = fs->next)
  758. if (ignore(fs))
  759. fs->flags |= FLAG_DONE;
  760. /*
  761. * Find and check the root filesystem.
  762. */
  763. if (!parallel_root) {
  764. for (fs = filesys_info; fs; fs = fs->next) {
  765. if (LONE_CHAR(fs->mountpt, '/')) {
  766. if (!skip_root && !ignore(fs)) {
  767. fsck_device(fs /*, 1*/);
  768. status |= wait_many(FLAG_WAIT_ALL);
  769. if (status > EXIT_NONDESTRUCT)
  770. return status;
  771. }
  772. fs->flags |= FLAG_DONE;
  773. break;
  774. }
  775. }
  776. }
  777. /*
  778. * This is for the bone-headed user who has root
  779. * filesystem listed twice.
  780. * "Skip root" will skip _all_ root entries.
  781. */
  782. if (skip_root)
  783. for (fs = filesys_info; fs; fs = fs->next)
  784. if (LONE_CHAR(fs->mountpt, '/'))
  785. fs->flags |= FLAG_DONE;
  786. not_done_yet = 1;
  787. passno = 1;
  788. while (not_done_yet) {
  789. not_done_yet = 0;
  790. pass_done = 1;
  791. for (fs = filesys_info; fs; fs = fs->next) {
  792. if (cancel_requested)
  793. break;
  794. if (fs->flags & FLAG_DONE)
  795. continue;
  796. /*
  797. * If the filesystem's pass number is higher
  798. * than the current pass number, then we didn't
  799. * do it yet.
  800. */
  801. if (fs->passno > passno) {
  802. not_done_yet = 1;
  803. continue;
  804. }
  805. /*
  806. * If a filesystem on a particular device has
  807. * already been spawned, then we need to defer
  808. * this to another pass.
  809. */
  810. if (device_already_active(fs->device)) {
  811. pass_done = 0;
  812. continue;
  813. }
  814. /*
  815. * Spawn off the fsck process
  816. */
  817. fsck_device(fs /*, serialize*/);
  818. fs->flags |= FLAG_DONE;
  819. /*
  820. * Only do one filesystem at a time, or if we
  821. * have a limit on the number of fsck's extant
  822. * at one time, apply that limit.
  823. */
  824. if (serialize
  825. || (max_running && (num_running >= max_running))
  826. ) {
  827. pass_done = 0;
  828. break;
  829. }
  830. }
  831. if (cancel_requested)
  832. break;
  833. if (verbose > 1)
  834. printf("--waiting-- (pass %d)\n", passno);
  835. status |= wait_many(pass_done ? FLAG_WAIT_ALL :
  836. FLAG_WAIT_ATLEAST_ONE);
  837. if (pass_done) {
  838. if (verbose > 1)
  839. puts("----------------------------------");
  840. passno++;
  841. } else
  842. not_done_yet = 1;
  843. }
  844. kill_all_if_cancel_requested();
  845. status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
  846. return status;
  847. }
  848. /*
  849. * Deal with the fsck -t argument.
  850. * Huh, for mount "-t novfat,nfs" means "neither vfat nor nfs"!
  851. * Why here we require "-t novfat,nonfs" ??
  852. */
  853. static void compile_fs_type(char *fs_type)
  854. {
  855. char *s;
  856. int num = 2;
  857. smallint negate;
  858. s = fs_type;
  859. while ((s = strchr(s, ','))) {
  860. num++;
  861. s++;
  862. }
  863. fs_type_list = xzalloc(num * sizeof(fs_type_list[0]));
  864. fs_type_flag = xzalloc(num * sizeof(fs_type_flag[0]));
  865. fs_type_negated = -1; /* not yet known is it negated or not */
  866. num = 0;
  867. s = fs_type;
  868. while (1) {
  869. char *comma;
  870. negate = 0;
  871. if (s[0] == 'n' && s[1] == 'o') { /* "no.." */
  872. s += 2;
  873. negate = 1;
  874. } else if (s[0] == '!') {
  875. s++;
  876. negate = 1;
  877. }
  878. if (strcmp(s, "loop") == 0)
  879. /* loop is really short-hand for opts=loop */
  880. goto loop_special_case;
  881. if (strncmp(s, "opts=", 5) == 0) {
  882. s += 5;
  883. loop_special_case:
  884. fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT;
  885. } else {
  886. if (fs_type_negated == -1)
  887. fs_type_negated = negate;
  888. if (fs_type_negated != negate)
  889. bb_error_msg_and_die(
  890. "either all or none of the filesystem types passed to -t must be prefixed "
  891. "with 'no' or '!'");
  892. }
  893. comma = strchr(s, ',');
  894. fs_type_list[num++] = comma ? xstrndup(s, comma-s) : xstrdup(s);
  895. if (!comma)
  896. break;
  897. s = comma + 1;
  898. }
  899. }
  900. static void parse_args(char **argv)
  901. {
  902. int i, j;
  903. char *arg, *tmp;
  904. char *options;
  905. int optpos;
  906. int opts_for_fsck = 0;
  907. /* in bss, so already zeroed
  908. num_devices = 0;
  909. num_args = 0;
  910. instance_list = NULL;
  911. */
  912. for (i = 1; argv[i]; i++) {
  913. arg = argv[i];
  914. /* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */
  915. if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
  916. // FIXME: must check that arg is a blkdev, or resolve
  917. // "/path", "UUID=xxx" or "LABEL=xxx" into block device name
  918. // ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties)
  919. devices = xrealloc(devices, (num_devices+1) * sizeof(devices[0]));
  920. devices[num_devices++] = xstrdup(arg);
  921. continue;
  922. }
  923. if (arg[0] != '-' || opts_for_fsck) {
  924. args = xrealloc(args, (num_args+1) * sizeof(args[0]));
  925. args[num_args++] = xstrdup(arg);
  926. continue;
  927. }
  928. if (LONE_CHAR(arg + 1, '-')) { /* "--" ? */
  929. opts_for_fsck = 1;
  930. continue;
  931. }
  932. optpos = 0;
  933. options = NULL;
  934. for (j = 1; arg[j]; j++) {
  935. switch (arg[j]) {
  936. case 'A':
  937. doall = 1;
  938. break;
  939. #if DO_PROGRESS_INDICATOR
  940. case 'C':
  941. progress = 1;
  942. if (arg[++j]) { /* -Cn */
  943. progress_fd = xatoi_u(&arg[j]);
  944. goto next_arg;
  945. }
  946. /* -C n */
  947. if (!argv[++i]) bb_show_usage();
  948. progress_fd = xatoi_u(argv[i]);
  949. goto next_arg;
  950. #endif
  951. case 'V':
  952. verbose++;
  953. break;
  954. case 'N':
  955. noexecute = 1;
  956. break;
  957. case 'R':
  958. skip_root = 1;
  959. break;
  960. case 'T':
  961. notitle = 1;
  962. break;
  963. /* case 'M':
  964. like_mount = 1;
  965. break; */
  966. case 'P':
  967. parallel_root = 1;
  968. break;
  969. case 's':
  970. serialize = 1;
  971. break;
  972. case 't':
  973. if (fstype)
  974. bb_show_usage();
  975. if (arg[++j])
  976. tmp = &arg[j];
  977. else if (argv[++i])
  978. tmp = argv[i];
  979. else
  980. bb_show_usage();
  981. fstype = xstrdup(tmp);
  982. compile_fs_type(fstype);
  983. goto next_arg;
  984. case '?':
  985. bb_show_usage();
  986. break;
  987. default:
  988. optpos++;
  989. /* one extra for '\0' */
  990. options = xrealloc(options, optpos + 2);
  991. options[optpos] = arg[j];
  992. break;
  993. }
  994. }
  995. next_arg:
  996. if (optpos) {
  997. options[0] = '-';
  998. options[optpos + 1] = '\0';
  999. args = xrealloc(args, (num_args+1) * sizeof(args[0]));
  1000. args[num_args++] = options;
  1001. }
  1002. }
  1003. if (getenv("FSCK_FORCE_ALL_PARALLEL"))
  1004. force_all_parallel = 1;
  1005. tmp = getenv("FSCK_MAX_INST");
  1006. if (tmp)
  1007. max_running = xatoi(tmp);
  1008. }
  1009. static void signal_cancel(int sig ATTRIBUTE_UNUSED)
  1010. {
  1011. cancel_requested = 1;
  1012. }
  1013. int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  1014. int fsck_main(int argc ATTRIBUTE_UNUSED, char **argv)
  1015. {
  1016. int i, status;
  1017. /*int interactive;*/
  1018. const char *fstab;
  1019. struct fs_info *fs;
  1020. /* we want wait() to be interruptible */
  1021. signal_no_SA_RESTART_empty_mask(SIGINT, signal_cancel);
  1022. signal_no_SA_RESTART_empty_mask(SIGTERM, signal_cancel);
  1023. setbuf(stdout, NULL);
  1024. parse_args(argv);
  1025. if (!notitle)
  1026. puts("fsck (busybox "BB_VER", "BB_BT")");
  1027. /* Even plain "fsck /dev/hda1" needs fstab to get fs type,
  1028. * so we are scanning it anyway */
  1029. fstab = getenv("FSTAB_FILE");
  1030. if (!fstab)
  1031. fstab = "/etc/fstab";
  1032. load_fs_info(fstab);
  1033. /*interactive = (num_devices == 1) | serialize;*/
  1034. if (num_devices == 0)
  1035. /*interactive =*/ serialize = doall = 1;
  1036. if (doall)
  1037. return check_all();
  1038. status = 0;
  1039. for (i = 0; i < num_devices; i++) {
  1040. if (cancel_requested) {
  1041. kill_all_if_cancel_requested();
  1042. break;
  1043. }
  1044. fs = lookup(devices[i]);
  1045. if (!fs)
  1046. fs = create_fs_device(devices[i], "", "auto", NULL, -1);
  1047. fsck_device(fs /*, interactive */);
  1048. if (serialize
  1049. || (max_running && (num_running >= max_running))
  1050. ) {
  1051. int exit_status = wait_one(0);
  1052. if (exit_status >= 0)
  1053. status |= exit_status;
  1054. if (verbose > 1)
  1055. puts("----------------------------------");
  1056. }
  1057. }
  1058. status |= wait_many(FLAG_WAIT_ALL);
  1059. return status;
  1060. }