10f66f451Sopenharmony_ci/* fsck.c -  check and repair a Linux filesystem
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com>
50f66f451Sopenharmony_ci
60f66f451Sopenharmony_ciUSE_FSCK(NEWTOY(fsck, "?t:ANPRTVsC#", TOYFLAG_USR|TOYFLAG_BIN))
70f66f451Sopenharmony_ci
80f66f451Sopenharmony_ciconfig FSCK
90f66f451Sopenharmony_ci  bool "fsck"
100f66f451Sopenharmony_ci  default n
110f66f451Sopenharmony_ci  help
120f66f451Sopenharmony_ci    usage: fsck [-ANPRTV] [-C FD] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]...
130f66f451Sopenharmony_ci
140f66f451Sopenharmony_ci    Check and repair filesystems
150f66f451Sopenharmony_ci
160f66f451Sopenharmony_ci    -A      Walk /etc/fstab and check all filesystems
170f66f451Sopenharmony_ci    -N      Don't execute, just show what would be done
180f66f451Sopenharmony_ci    -P      With -A, check filesystems in parallel
190f66f451Sopenharmony_ci    -R      With -A, skip the root filesystem
200f66f451Sopenharmony_ci    -T      Don't show title on startup
210f66f451Sopenharmony_ci    -V      Verbose
220f66f451Sopenharmony_ci    -C n    Write status information to specified file descriptor
230f66f451Sopenharmony_ci    -t TYPE List of filesystem types to check
240f66f451Sopenharmony_ci
250f66f451Sopenharmony_ci*/
260f66f451Sopenharmony_ci
270f66f451Sopenharmony_ci#define FOR_fsck
280f66f451Sopenharmony_ci#include "toys.h"
290f66f451Sopenharmony_ci#include <mntent.h>
300f66f451Sopenharmony_ci
310f66f451Sopenharmony_ci#define FLAG_WITHOUT_NO_PRFX 1
320f66f451Sopenharmony_ci#define FLAG_WITH_NO_PRFX 2
330f66f451Sopenharmony_ci#define FLAG_DONE 1
340f66f451Sopenharmony_ci
350f66f451Sopenharmony_ciGLOBALS(
360f66f451Sopenharmony_ci  int fd_num;
370f66f451Sopenharmony_ci  char *t_list;
380f66f451Sopenharmony_ci
390f66f451Sopenharmony_ci  struct double_list *devices;
400f66f451Sopenharmony_ci  char *arr_flag;
410f66f451Sopenharmony_ci  char **arr_type;
420f66f451Sopenharmony_ci  int negate;
430f66f451Sopenharmony_ci  int sum_status;
440f66f451Sopenharmony_ci  int nr_run;
450f66f451Sopenharmony_ci  int sig_num;
460f66f451Sopenharmony_ci  long max_nr_run;
470f66f451Sopenharmony_ci)
480f66f451Sopenharmony_ci
490f66f451Sopenharmony_cistruct f_sys_info {
500f66f451Sopenharmony_ci  char *device, *mountpt, *type, *opts;
510f66f451Sopenharmony_ci  int passno, flag;
520f66f451Sopenharmony_ci  struct f_sys_info *next;
530f66f451Sopenharmony_ci};
540f66f451Sopenharmony_ci
550f66f451Sopenharmony_cistruct child_list {
560f66f451Sopenharmony_ci  struct child_list *next;
570f66f451Sopenharmony_ci  pid_t pid;
580f66f451Sopenharmony_ci  char *prog_name, *dev_name;
590f66f451Sopenharmony_ci};
600f66f451Sopenharmony_ci
610f66f451Sopenharmony_cistatic struct f_sys_info *filesys_info = NULL; //fstab entry list
620f66f451Sopenharmony_cistatic struct child_list *c_list = NULL; //fsck.type child list.
630f66f451Sopenharmony_ci
640f66f451Sopenharmony_cistatic void kill_all(void)
650f66f451Sopenharmony_ci{
660f66f451Sopenharmony_ci  struct child_list *child;
670f66f451Sopenharmony_ci
680f66f451Sopenharmony_ci  for (child = c_list; child; child = child->next)
690f66f451Sopenharmony_ci    kill(child->pid, SIGTERM);
700f66f451Sopenharmony_ci  _exit(0);
710f66f451Sopenharmony_ci}
720f66f451Sopenharmony_ci
730f66f451Sopenharmony_cistatic long strtol_range(char *str, int min, int max)
740f66f451Sopenharmony_ci{
750f66f451Sopenharmony_ci  char *endptr = NULL;
760f66f451Sopenharmony_ci  errno = 0;
770f66f451Sopenharmony_ci  long ret_value = strtol(str, &endptr, 10);
780f66f451Sopenharmony_ci
790f66f451Sopenharmony_ci  if(errno) perror_exit("Invalid num %s", str);
800f66f451Sopenharmony_ci  else if(endptr && (*endptr != '\0' || endptr == str))
810f66f451Sopenharmony_ci    perror_exit("Not a valid num %s", str);
820f66f451Sopenharmony_ci  if(ret_value >= min && ret_value <= max) return ret_value;
830f66f451Sopenharmony_ci  else perror_exit("Number %s is not in valid [%d-%d] Range", str, min, max);
840f66f451Sopenharmony_ci}
850f66f451Sopenharmony_ci
860f66f451Sopenharmony_ci//create fstab entries list.
870f66f451Sopenharmony_cistatic struct f_sys_info* create_db(struct mntent *f_info)
880f66f451Sopenharmony_ci{
890f66f451Sopenharmony_ci  struct f_sys_info *temp = filesys_info;
900f66f451Sopenharmony_ci  if (temp) {
910f66f451Sopenharmony_ci    while (temp->next) temp = temp->next;
920f66f451Sopenharmony_ci    temp->next = xzalloc(sizeof(struct f_sys_info));
930f66f451Sopenharmony_ci    temp = temp->next;
940f66f451Sopenharmony_ci  } else filesys_info = temp = xzalloc(sizeof(struct f_sys_info));
950f66f451Sopenharmony_ci
960f66f451Sopenharmony_ci  temp->device = xstrdup(f_info->mnt_fsname);
970f66f451Sopenharmony_ci  temp->mountpt = xstrdup(f_info->mnt_dir);
980f66f451Sopenharmony_ci  if (strchr(f_info->mnt_type, ',')) temp->type = xstrdup("auto");
990f66f451Sopenharmony_ci  else  temp->type = xstrdup(f_info->mnt_type);
1000f66f451Sopenharmony_ci  temp->opts = xstrdup(f_info->mnt_opts);
1010f66f451Sopenharmony_ci  temp->passno = f_info->mnt_passno;
1020f66f451Sopenharmony_ci  return temp;
1030f66f451Sopenharmony_ci}
1040f66f451Sopenharmony_ci
1050f66f451Sopenharmony_ci//is we have 'no' or ! before type.
1060f66f451Sopenharmony_cistatic int is_no_prefix(char **p)
1070f66f451Sopenharmony_ci{
1080f66f451Sopenharmony_ci  int no = 0;
1090f66f451Sopenharmony_ci
1100f66f451Sopenharmony_ci  if ((*p[0] == 'n' && *(*p + 1) == 'o')) no = 2;
1110f66f451Sopenharmony_ci  else if (*p[0] == '!') no = 1;
1120f66f451Sopenharmony_ci  *p += no;
1130f66f451Sopenharmony_ci  return ((no) ? 1 :0);
1140f66f451Sopenharmony_ci}
1150f66f451Sopenharmony_ci
1160f66f451Sopenharmony_cistatic void fix_tlist(void)
1170f66f451Sopenharmony_ci{
1180f66f451Sopenharmony_ci  char *p, *s = TT.t_list;
1190f66f451Sopenharmony_ci  int n = 1, no;
1200f66f451Sopenharmony_ci
1210f66f451Sopenharmony_ci  while ((s = strchr(s, ','))) {
1220f66f451Sopenharmony_ci    s++;
1230f66f451Sopenharmony_ci    n++;
1240f66f451Sopenharmony_ci  }
1250f66f451Sopenharmony_ci
1260f66f451Sopenharmony_ci  TT.arr_flag = xzalloc(n + 1);
1270f66f451Sopenharmony_ci  TT.arr_type = xzalloc((n + 1) * sizeof(char *));
1280f66f451Sopenharmony_ci  s = TT.t_list;
1290f66f451Sopenharmony_ci  n = 0;
1300f66f451Sopenharmony_ci  while ((p = strsep(&s, ","))) {
1310f66f451Sopenharmony_ci    no = is_no_prefix(&p);
1320f66f451Sopenharmony_ci    if (!strcmp(p, "loop")) {
1330f66f451Sopenharmony_ci      TT.arr_flag[n] = no ? FLAG_WITH_NO_PRFX :FLAG_WITHOUT_NO_PRFX;
1340f66f451Sopenharmony_ci      TT.negate = no;
1350f66f451Sopenharmony_ci    } else if (!strncmp(p, "opts=", 5)) {
1360f66f451Sopenharmony_ci      p+=5;
1370f66f451Sopenharmony_ci      TT.arr_flag[n] = is_no_prefix(&p) ?FLAG_WITH_NO_PRFX :FLAG_WITHOUT_NO_PRFX;
1380f66f451Sopenharmony_ci      TT.negate = no;
1390f66f451Sopenharmony_ci    } else {
1400f66f451Sopenharmony_ci      if (!n) TT.negate = no;
1410f66f451Sopenharmony_ci      if (n && TT.negate != no) error_exit("either all or none of the filesystem"
1420f66f451Sopenharmony_ci          " types passed to -t must be prefixed with 'no' or '!'");
1430f66f451Sopenharmony_ci    }
1440f66f451Sopenharmony_ci    TT.arr_type[n++] = p;
1450f66f451Sopenharmony_ci  }
1460f66f451Sopenharmony_ci}
1470f66f451Sopenharmony_ci
1480f66f451Sopenharmony_ci//ignore these types...
1490f66f451Sopenharmony_cistatic int ignore_type(char *type)
1500f66f451Sopenharmony_ci{
1510f66f451Sopenharmony_ci  int i = 0;
1520f66f451Sopenharmony_ci  char *str;
1530f66f451Sopenharmony_ci  char *ignored_types[] = {
1540f66f451Sopenharmony_ci    "ignore","iso9660", "nfs","proc",
1550f66f451Sopenharmony_ci    "sw","swap", "tmpfs","devpts",NULL
1560f66f451Sopenharmony_ci  };
1570f66f451Sopenharmony_ci  while ((str = ignored_types[i++])) {
1580f66f451Sopenharmony_ci    if (!strcmp(str, type)) return 1;
1590f66f451Sopenharmony_ci  }
1600f66f451Sopenharmony_ci  return 0;
1610f66f451Sopenharmony_ci}
1620f66f451Sopenharmony_ci
1630f66f451Sopenharmony_ci// return true if has to ignore the filesystem.
1640f66f451Sopenharmony_cistatic int to_be_ignored(struct f_sys_info *finfo)
1650f66f451Sopenharmony_ci{
1660f66f451Sopenharmony_ci  int i, ret = 0, type_present = 0;
1670f66f451Sopenharmony_ci
1680f66f451Sopenharmony_ci  if (!finfo->passno) return 1; //Ignore with pass num = 0
1690f66f451Sopenharmony_ci  if (TT.arr_type) {
1700f66f451Sopenharmony_ci    for (i = 0; TT.arr_type[i]; i++) {
1710f66f451Sopenharmony_ci      if (!TT.arr_flag[i]) { //it is type of filesys.
1720f66f451Sopenharmony_ci        type_present = 2;
1730f66f451Sopenharmony_ci        if (!strcmp(TT.arr_type[i], finfo->type)) ret = 0;
1740f66f451Sopenharmony_ci        else ret = 1;
1750f66f451Sopenharmony_ci      } else if (TT.arr_flag[i] == FLAG_WITH_NO_PRFX) { //it is option of filesys
1760f66f451Sopenharmony_ci        if (hasmntopt((const struct mntent *)finfo, TT.arr_type[i])) return 1;
1770f66f451Sopenharmony_ci      } else { //FLAG_WITHOUT_NO_PRFX
1780f66f451Sopenharmony_ci        if (!hasmntopt((const struct mntent *)finfo, TT.arr_type[i])) return 1;
1790f66f451Sopenharmony_ci      }
1800f66f451Sopenharmony_ci    }
1810f66f451Sopenharmony_ci  }
1820f66f451Sopenharmony_ci  if (ignore_type(finfo->type)) return 1;
1830f66f451Sopenharmony_ci  if (TT.arr_type && type_present != 2) return 0;
1840f66f451Sopenharmony_ci  return ((TT.negate) ? !ret : ret);
1850f66f451Sopenharmony_ci}
1860f66f451Sopenharmony_ci
1870f66f451Sopenharmony_ci// find type and execute corresponding fsck.type prog.
1880f66f451Sopenharmony_cistatic void do_fsck(struct f_sys_info *finfo)
1890f66f451Sopenharmony_ci{
1900f66f451Sopenharmony_ci  struct child_list *child;
1910f66f451Sopenharmony_ci  char **args;
1920f66f451Sopenharmony_ci  char *type;
1930f66f451Sopenharmony_ci  pid_t pid;
1940f66f451Sopenharmony_ci  int i = 1, j = 0;
1950f66f451Sopenharmony_ci
1960f66f451Sopenharmony_ci  if (strcmp(finfo->type, "auto")) type = finfo->type;
1970f66f451Sopenharmony_ci  else if (TT.t_list && (TT.t_list[0] != 'n' || TT.t_list[1] != 'o' || TT.t_list[0] != '!')
1980f66f451Sopenharmony_ci      && strncmp(TT.t_list, "opts=", 5) && strncmp(TT.t_list , "loop", 4)
1990f66f451Sopenharmony_ci      && !TT.arr_type[1]) type = TT.t_list; //one file sys at cmdline
2000f66f451Sopenharmony_ci  else type = "auto";
2010f66f451Sopenharmony_ci
2020f66f451Sopenharmony_ci  args = xzalloc((toys.optc + 2 + 1 + 1) * sizeof(char*)); //+1, for NULL, +1 if -C
2030f66f451Sopenharmony_ci  args[0] = xmprintf("fsck.%s", type);
2040f66f451Sopenharmony_ci
2050f66f451Sopenharmony_ci  if(toys.optflags & FLAG_C) args[i++] = xmprintf("%s %d","-C", TT.fd_num);
2060f66f451Sopenharmony_ci  while(toys.optargs[j]) {
2070f66f451Sopenharmony_ci    if(*toys.optargs[j]) args[i++] = xstrdup(toys.optargs[j]);
2080f66f451Sopenharmony_ci    j++;
2090f66f451Sopenharmony_ci  }
2100f66f451Sopenharmony_ci  args[i] = finfo->device;
2110f66f451Sopenharmony_ci
2120f66f451Sopenharmony_ci  TT.nr_run++;
2130f66f451Sopenharmony_ci  if ((toys.optflags & FLAG_V) || (toys.optflags & FLAG_N)) {
2140f66f451Sopenharmony_ci    printf("[%s (%d) -- %s]", args[0], TT.nr_run,
2150f66f451Sopenharmony_ci        finfo->mountpt ? finfo->mountpt : finfo->device);
2160f66f451Sopenharmony_ci    for (i = 0; args[i]; i++) xprintf(" %s", args[i]);
2170f66f451Sopenharmony_ci    xputc('\n');
2180f66f451Sopenharmony_ci  }
2190f66f451Sopenharmony_ci
2200f66f451Sopenharmony_ci  if (toys.optflags & FLAG_N) {
2210f66f451Sopenharmony_ci    for (j=0;j<i;j++) free(args[i]);
2220f66f451Sopenharmony_ci    free(args);
2230f66f451Sopenharmony_ci    return;
2240f66f451Sopenharmony_ci  } else {
2250f66f451Sopenharmony_ci    if ((pid = fork()) < 0) {
2260f66f451Sopenharmony_ci      perror_msg_raw(*args);
2270f66f451Sopenharmony_ci      for (j=0;j<i;j++) free(args[i]);
2280f66f451Sopenharmony_ci      free(args);
2290f66f451Sopenharmony_ci      return;
2300f66f451Sopenharmony_ci    }
2310f66f451Sopenharmony_ci    if (!pid) xexec(args); //child, executes fsck.type
2320f66f451Sopenharmony_ci  }
2330f66f451Sopenharmony_ci
2340f66f451Sopenharmony_ci  child = xzalloc(sizeof(struct child_list)); //Parent, add to child list.
2350f66f451Sopenharmony_ci  child->dev_name = xstrdup(finfo->device);
2360f66f451Sopenharmony_ci  child->prog_name = args[0];
2370f66f451Sopenharmony_ci  child->pid = pid;
2380f66f451Sopenharmony_ci
2390f66f451Sopenharmony_ci  if (c_list) {
2400f66f451Sopenharmony_ci    child->next = c_list;
2410f66f451Sopenharmony_ci    c_list = child;
2420f66f451Sopenharmony_ci  } else {
2430f66f451Sopenharmony_ci    c_list = child;
2440f66f451Sopenharmony_ci    child->next =NULL;
2450f66f451Sopenharmony_ci  }
2460f66f451Sopenharmony_ci}
2470f66f451Sopenharmony_ci
2480f66f451Sopenharmony_ci// for_all = 1; wait for all child to exit
2490f66f451Sopenharmony_ci// for_all = 0; wait for any one to exit
2500f66f451Sopenharmony_cistatic int wait_for(int for_all)
2510f66f451Sopenharmony_ci{
2520f66f451Sopenharmony_ci  pid_t pid;
2530f66f451Sopenharmony_ci  int status = 0, child_exited;
2540f66f451Sopenharmony_ci  struct child_list *prev, *temp;
2550f66f451Sopenharmony_ci
2560f66f451Sopenharmony_ci  errno = 0;
2570f66f451Sopenharmony_ci  if (!c_list) return 0;
2580f66f451Sopenharmony_ci  while ((pid = wait(&status))) {
2590f66f451Sopenharmony_ci    temp = c_list;
2600f66f451Sopenharmony_ci    prev = temp;
2610f66f451Sopenharmony_ci    if (TT.sig_num) kill_all();
2620f66f451Sopenharmony_ci    child_exited = 0;
2630f66f451Sopenharmony_ci    if (pid < 0) {
2640f66f451Sopenharmony_ci      if (errno == EINTR) continue;
2650f66f451Sopenharmony_ci      else if (errno == ECHILD) break; //No child to wait, break and return status.
2660f66f451Sopenharmony_ci      else perror_exit("option arg Invalid\n"); //paranoid.
2670f66f451Sopenharmony_ci    }
2680f66f451Sopenharmony_ci    while (temp) {
2690f66f451Sopenharmony_ci      if (temp->pid == pid) {
2700f66f451Sopenharmony_ci        child_exited = 1;
2710f66f451Sopenharmony_ci        break;
2720f66f451Sopenharmony_ci      }
2730f66f451Sopenharmony_ci      prev = temp;
2740f66f451Sopenharmony_ci      temp = temp->next;
2750f66f451Sopenharmony_ci    }
2760f66f451Sopenharmony_ci    if (child_exited) {
2770f66f451Sopenharmony_ci      if (WIFEXITED(status)) TT.sum_status |= WEXITSTATUS(status);
2780f66f451Sopenharmony_ci      else if (WIFSIGNALED(status)) {
2790f66f451Sopenharmony_ci        TT.sum_status |= 4; //Uncorrected.
2800f66f451Sopenharmony_ci        if (WTERMSIG(status) != SIGINT)
2810f66f451Sopenharmony_ci          perror_msg("child Term. by sig: %d\n",(WTERMSIG(status)));
2820f66f451Sopenharmony_ci        TT.sum_status |= 8; //Operatinal error
2830f66f451Sopenharmony_ci      } else {
2840f66f451Sopenharmony_ci        TT.sum_status |= 4; //Uncorrected.
2850f66f451Sopenharmony_ci        perror_msg("%s %s: status is %x, should never happen\n",
2860f66f451Sopenharmony_ci            temp->prog_name, temp->dev_name, status);
2870f66f451Sopenharmony_ci      }
2880f66f451Sopenharmony_ci      TT.nr_run--;
2890f66f451Sopenharmony_ci      if (prev == temp) c_list = c_list->next; //first node
2900f66f451Sopenharmony_ci      else prev->next = temp->next;
2910f66f451Sopenharmony_ci      free(temp->prog_name);
2920f66f451Sopenharmony_ci      free(temp->dev_name);
2930f66f451Sopenharmony_ci      free(temp);
2940f66f451Sopenharmony_ci      if (!for_all) break;
2950f66f451Sopenharmony_ci    }
2960f66f451Sopenharmony_ci  }
2970f66f451Sopenharmony_ci  return TT.sum_status;
2980f66f451Sopenharmony_ci}
2990f66f451Sopenharmony_ci
3000f66f451Sopenharmony_ci//scan all the fstab entries or -t matches with fstab.
3010f66f451Sopenharmony_cistatic int scan_all(void)
3020f66f451Sopenharmony_ci{
3030f66f451Sopenharmony_ci  struct f_sys_info *finfo = filesys_info;
3040f66f451Sopenharmony_ci  int ret = 0, passno;
3050f66f451Sopenharmony_ci
3060f66f451Sopenharmony_ci  if (toys.optflags & FLAG_V) xprintf("Checking all filesystem\n");
3070f66f451Sopenharmony_ci  while (finfo) {
3080f66f451Sopenharmony_ci    if (to_be_ignored(finfo)) finfo->flag |= FLAG_DONE;
3090f66f451Sopenharmony_ci    finfo = finfo->next;
3100f66f451Sopenharmony_ci  }
3110f66f451Sopenharmony_ci  finfo = filesys_info;
3120f66f451Sopenharmony_ci
3130f66f451Sopenharmony_ci  if (!(toys.optflags & FLAG_P)) {
3140f66f451Sopenharmony_ci    while (finfo) {
3150f66f451Sopenharmony_ci      if (!strcmp(finfo->mountpt, "/")) { // man says: check / in parallel with others if -P is absent.
3160f66f451Sopenharmony_ci        if ((toys.optflags & FLAG_R) || to_be_ignored(finfo)) {
3170f66f451Sopenharmony_ci          finfo->flag |= FLAG_DONE;
3180f66f451Sopenharmony_ci          break;
3190f66f451Sopenharmony_ci        } else {
3200f66f451Sopenharmony_ci          do_fsck(finfo);
3210f66f451Sopenharmony_ci          finfo->flag |= FLAG_DONE;
3220f66f451Sopenharmony_ci          if (TT.sig_num) kill_all();
3230f66f451Sopenharmony_ci          if ((ret |= wait_for(1)) > 4) return ret; //destruction in filesys.
3240f66f451Sopenharmony_ci          break;
3250f66f451Sopenharmony_ci        }
3260f66f451Sopenharmony_ci      }
3270f66f451Sopenharmony_ci      finfo = finfo->next;
3280f66f451Sopenharmony_ci    }
3290f66f451Sopenharmony_ci  }
3300f66f451Sopenharmony_ci  if (toys.optflags & FLAG_R) { // with -PR we choose to skip root.
3310f66f451Sopenharmony_ci    for (finfo = filesys_info; finfo; finfo = finfo->next) {
3320f66f451Sopenharmony_ci      if(!strcmp(finfo->mountpt, "/")) finfo->flag |= FLAG_DONE;
3330f66f451Sopenharmony_ci    }
3340f66f451Sopenharmony_ci  }
3350f66f451Sopenharmony_ci  passno = 1;
3360f66f451Sopenharmony_ci  while (1) {
3370f66f451Sopenharmony_ci    for (finfo = filesys_info; finfo; finfo = finfo->next)
3380f66f451Sopenharmony_ci      if (!finfo->flag) break;
3390f66f451Sopenharmony_ci    if (!finfo) break;
3400f66f451Sopenharmony_ci
3410f66f451Sopenharmony_ci    for (finfo = filesys_info; finfo; finfo = finfo->next) {
3420f66f451Sopenharmony_ci      if (finfo->flag) continue;
3430f66f451Sopenharmony_ci      if (finfo->passno == passno) {
3440f66f451Sopenharmony_ci        do_fsck(finfo);
3450f66f451Sopenharmony_ci        finfo->flag |= FLAG_DONE;
3460f66f451Sopenharmony_ci        if ((toys.optflags & FLAG_s) || (TT.nr_run
3470f66f451Sopenharmony_ci              && (TT.nr_run >= TT.max_nr_run))) ret |= wait_for(0);
3480f66f451Sopenharmony_ci      }
3490f66f451Sopenharmony_ci    }
3500f66f451Sopenharmony_ci    if (TT.sig_num) kill_all();
3510f66f451Sopenharmony_ci    ret |= wait_for(1);
3520f66f451Sopenharmony_ci    passno++;
3530f66f451Sopenharmony_ci  }
3540f66f451Sopenharmony_ci  return ret;
3550f66f451Sopenharmony_ci}
3560f66f451Sopenharmony_ci
3570f66f451Sopenharmony_civoid record_sig_num(int sig)
3580f66f451Sopenharmony_ci{
3590f66f451Sopenharmony_ci  TT.sig_num = sig;
3600f66f451Sopenharmony_ci}
3610f66f451Sopenharmony_ci
3620f66f451Sopenharmony_civoid fsck_main(void)
3630f66f451Sopenharmony_ci{
3640f66f451Sopenharmony_ci  struct mntent mt;
3650f66f451Sopenharmony_ci  struct double_list *dev;
3660f66f451Sopenharmony_ci  struct f_sys_info *finfo;
3670f66f451Sopenharmony_ci  FILE *fp;
3680f66f451Sopenharmony_ci  char *tmp, **arg = toys.optargs;
3690f66f451Sopenharmony_ci
3700f66f451Sopenharmony_ci  sigatexit(record_sig_num);
3710f66f451Sopenharmony_ci  while (*arg) {
3720f66f451Sopenharmony_ci    if ((**arg == '/') || strchr(*arg, '=')) {
3730f66f451Sopenharmony_ci      dlist_add(&TT.devices, xstrdup(*arg));
3740f66f451Sopenharmony_ci      **arg = '\0';
3750f66f451Sopenharmony_ci    }
3760f66f451Sopenharmony_ci    arg++;
3770f66f451Sopenharmony_ci  }
3780f66f451Sopenharmony_ci  if (toys.optflags & FLAG_t) fix_tlist();
3790f66f451Sopenharmony_ci  if (!(tmp = getenv("FSTAB_FILE"))) tmp = "/etc/fstab";
3800f66f451Sopenharmony_ci  if (!(fp = setmntent(tmp, "r"))) perror_exit("setmntent failed:");
3810f66f451Sopenharmony_ci  while (getmntent_r(fp, &mt, toybuf, 4096)) create_db(&mt);
3820f66f451Sopenharmony_ci  endmntent(fp);
3830f66f451Sopenharmony_ci
3840f66f451Sopenharmony_ci  if (!(toys.optflags & FLAG_T)) xprintf("fsck ----- (Toybox)\n");
3850f66f451Sopenharmony_ci
3860f66f451Sopenharmony_ci  if ((tmp = getenv("FSCK_MAX_INST")))
3870f66f451Sopenharmony_ci    TT.max_nr_run = strtol_range(tmp, 0, INT_MAX);
3880f66f451Sopenharmony_ci  if (!TT.devices || (toys.optflags & FLAG_A)) {
3890f66f451Sopenharmony_ci    toys.exitval = scan_all();
3900f66f451Sopenharmony_ci    if (CFG_TOYBOX_FREE) goto free_all;
3910f66f451Sopenharmony_ci    return; //if CFG_TOYBOX_FREE is not set, exit.
3920f66f451Sopenharmony_ci  }
3930f66f451Sopenharmony_ci
3940f66f451Sopenharmony_ci  dev = TT.devices;
3950f66f451Sopenharmony_ci  dev->prev->next = NULL; //break double list to traverse.
3960f66f451Sopenharmony_ci  for (; dev; dev = dev->next) {
3970f66f451Sopenharmony_ci    for (finfo = filesys_info; finfo; finfo = finfo->next)
3980f66f451Sopenharmony_ci      if (!strcmp(finfo->device, dev->data)
3990f66f451Sopenharmony_ci          || !strcmp(finfo->mountpt, dev->data)) break;
4000f66f451Sopenharmony_ci    if (!finfo) { //if not present, fill def values.
4010f66f451Sopenharmony_ci      mt.mnt_fsname = dev->data;
4020f66f451Sopenharmony_ci      mt.mnt_dir = "";
4030f66f451Sopenharmony_ci      mt.mnt_type = "auto";
4040f66f451Sopenharmony_ci      mt.mnt_opts = "";
4050f66f451Sopenharmony_ci      mt.mnt_passno = -1;
4060f66f451Sopenharmony_ci      finfo = create_db(&mt);
4070f66f451Sopenharmony_ci    }
4080f66f451Sopenharmony_ci    do_fsck(finfo);
4090f66f451Sopenharmony_ci    finfo->flag |= FLAG_DONE;
4100f66f451Sopenharmony_ci    if ((toys.optflags & FLAG_s) || (TT.nr_run && (TT.nr_run >= TT.max_nr_run)))
4110f66f451Sopenharmony_ci      toys.exitval |= wait_for(0);
4120f66f451Sopenharmony_ci  }
4130f66f451Sopenharmony_ci  if (TT.sig_num) kill_all();
4140f66f451Sopenharmony_ci  toys.exitval |= wait_for(1);
4150f66f451Sopenharmony_ci  finfo = filesys_info;
4160f66f451Sopenharmony_ci
4170f66f451Sopenharmony_cifree_all:
4180f66f451Sopenharmony_ci  if (CFG_TOYBOX_FREE) {
4190f66f451Sopenharmony_ci    struct f_sys_info *finfo, *temp;
4200f66f451Sopenharmony_ci
4210f66f451Sopenharmony_ci    llist_traverse(TT.devices, llist_free_double);
4220f66f451Sopenharmony_ci    free(TT.arr_type);
4230f66f451Sopenharmony_ci    free(TT.arr_flag);
4240f66f451Sopenharmony_ci    for (finfo = filesys_info; finfo;) {
4250f66f451Sopenharmony_ci      temp = finfo->next;
4260f66f451Sopenharmony_ci      free(finfo->device);
4270f66f451Sopenharmony_ci      free(finfo->mountpt);
4280f66f451Sopenharmony_ci      free(finfo->type);
4290f66f451Sopenharmony_ci      free(finfo->opts);
4300f66f451Sopenharmony_ci      free(finfo);
4310f66f451Sopenharmony_ci      finfo = temp;
4320f66f451Sopenharmony_ci    }
4330f66f451Sopenharmony_ci  }
4340f66f451Sopenharmony_ci}
435