Справочник по консольным командам Toybox для Android 12


  Ver.0.8.4     Ver.0.8.9     Pending  

Путь: Toys/Pending, команды версии: Ver.4     Ver.9


fsck

Комментарии в файле fsck.c :

usage: fsck [-ANPRTV] [-C FD] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]...

Проверка и восстановление файловых систем
  • -A Пройдите /etc/fstab и проверьте все файловые системы
  • -N Не выполняйте, просто покажите, что будет сделано
  • -P С -A, проверьте файловые системы параллельно
  • -R С -A, пропустите корневую файловую систему
  • -T Не показывать заголовок при запуске
  • -V Подробно
  • -C n Записать информацию о состоянии в указанное файловый дескриптор
  • -t TYPE Список типов файловых систем для проверки

  • usage: fsck [-ANPRTV] [-C FD] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]...

    Check and repair filesystems
  • -A Walk /etc/fstab and check all filesystems
  • -N Don't execute, just show what would be done
  • -P With -A, check filesystems in parallel
  • -R With -A, skip the root filesystem
  • -T Don't show title on startup
  • -V Verbose
  • -C n Write status information to specified file descriptor
  • -t TYPE List of filesystem types to check

  • Исходный текст в файле fsck.c

    #define FOR_fsck
    #include "toys.h"
    #include <mntent.h>
    
    #define FLAG_WITHOUT_NO_PRFX 1
    #define FLAG_WITH_NO_PRFX 2
    #define FLAG_DONE 1
    
    GLOBALS(
      int fd_num;
      char *t_list;
    
      struct double_list *devices;
      char *arr_flag;
      char **arr_type;
      int negate;
      int sum_status;
      int nr_run;
      int sig_num;
      long max_nr_run;
    )
    
    struct f_sys_info {
      char *device, *mountpt, *type, *opts;
      int passno, flag;
      struct f_sys_info *next;
    };
    
    struct child_list {
      struct child_list *next;
      pid_t pid;
      char *prog_name, *dev_name;
    };
    
    static struct f_sys_info *filesys_info = NULL; //fstab entry list
    static struct child_list *c_list = NULL; //fsck.type child list.
    
    static void kill_all(void) 
    {
      struct child_list *child;
    
      for (child = c_list; child; child = child->next) 
        kill(child->pid, SIGTERM);
      _exit(0);
    }
    
    static long strtol_range(char *str, int min, int max)
    {
      char *endptr = NULL;
      errno = 0;
      long ret_value = strtol(str, &endptr, 10);
    
      if(errno) perror_exit("Invalid num %s", str);
      else if(endptr && (*endptr != '\0' || endptr == str))
        perror_exit("Not a valid num %s", str);
      if(ret_value >= min && ret_value <= max) return ret_value;
      else perror_exit("Number %s is not in valid [%d-%d] Range", str, min, max);
    }
    
    //create fstab entries list.
    static struct f_sys_info* create_db(struct mntent *f_info)
    {
      struct f_sys_info *temp = filesys_info;
      if (temp) {
        while (temp->next) temp = temp->next;
        temp->next = xzalloc(sizeof(struct f_sys_info));
        temp = temp->next;
      } else filesys_info = temp = xzalloc(sizeof(struct f_sys_info));
    
      temp->device = xstrdup(f_info->mnt_fsname);
      temp->mountpt = xstrdup(f_info->mnt_dir);
      if (strchr(f_info->mnt_type, ',')) temp->type = xstrdup("auto");
      else  temp->type = xstrdup(f_info->mnt_type);
      temp->opts = xstrdup(f_info->mnt_opts);
      temp->passno = f_info->mnt_passno;
      return temp;
    }
    
    //is we have 'no' or ! before type.
    static int is_no_prefix(char **p)
    {
      int no = 0;
    
      if ((*p[0] == 'n' && *(*p + 1) == 'o')) no = 2; 
      else if (*p[0] == '!') no = 1;
      *p += no;
      return ((no) ? 1 :0);
    }
    
    static void fix_tlist(void)
    {
      char *p, *s = TT.t_list;
      int n = 1, no;
    
      while ((s = strchr(s, ','))) {
        s++;
        n++;
      }
    
      TT.arr_flag = xzalloc(n + 1);
      TT.arr_type = xzalloc((n + 1) * sizeof(char *));
      s = TT.t_list;
      n = 0;
      while ((p = strsep(&s, ","))) {
        no = is_no_prefix(&p);
        if (!strcmp(p, "loop")) {
          TT.arr_flag[n] = no ? FLAG_WITH_NO_PRFX :FLAG_WITHOUT_NO_PRFX;
          TT.negate = no;
        } else if (!strncmp(p, "opts=", 5)) {
          p+=5;
          TT.arr_flag[n] = is_no_prefix(&p) ?FLAG_WITH_NO_PRFX :FLAG_WITHOUT_NO_PRFX;
          TT.negate = no;
        } else {
          if (!n) TT.negate = no;
          if (n && TT.negate != no) error_exit("either all or none of the filesystem"
              " types passed to -t must be prefixed with 'no' or '!'");
        }
        TT.arr_type[n++] = p;
      }
    }
    
    //ignore these types...
    static int ignore_type(char *type)
    {
      int i = 0;
      char *str;
      char *ignored_types[] = {
        "ignore","iso9660", "nfs","proc",
        "sw","swap", "tmpfs","devpts",NULL
      };
      while ((str = ignored_types[i++])) {
        if (!strcmp(str, type)) return 1;
      }
      return 0;
    }
    
    // return true if has to ignore the filesystem.
    static int to_be_ignored(struct f_sys_info *finfo) 
    {
      int i, ret = 0, type_present = 0;
    
      if (!finfo->passno) return 1; //Ignore with pass num = 0
      if (TT.arr_type) {
        for (i = 0; TT.arr_type[i]; i++) {
          if (!TT.arr_flag[i]) { //it is type of filesys.
            type_present = 2;
            if (!strcmp(TT.arr_type[i], finfo->type)) ret = 0;
            else ret = 1;
          } else if (TT.arr_flag[i] == FLAG_WITH_NO_PRFX) { //it is option of filesys
            if (hasmntopt((const struct mntent *)finfo, TT.arr_type[i])) return 1;
          } else { //FLAG_WITHOUT_NO_PRFX
            if (!hasmntopt((const struct mntent *)finfo, TT.arr_type[i])) return 1;
          }
        }
      }
      if (ignore_type(finfo->type)) return 1;
      if (TT.arr_type && type_present != 2) return 0;
      return ((TT.negate) ? !ret : ret);
    }
    
    // find type and execute corresponding fsck.type prog.
    static void do_fsck(struct f_sys_info *finfo) 
    {
      struct child_list *child;
      char **args;
      char *type;
      pid_t pid;
      int i = 1, j = 0;
    
      if (strcmp(finfo->type, "auto")) type = finfo->type;
      else if (TT.t_list && (TT.t_list[0] != 'n' || TT.t_list[1] != 'o' || TT.t_list[0] != '!')
          && strncmp(TT.t_list, "opts=", 5) && strncmp(TT.t_list , "loop", 4)
          && !TT.arr_type[1]) type = TT.t_list; //one file sys at cmdline
      else type = "auto";
    
      args = xzalloc((toys.optc + 2 + 1 + 1) * sizeof(char*)); //+1, for NULL, +1 if -C
      args[0] = xmprintf("fsck.%s", type);
      
      if(toys.optflags & FLAG_C) args[i++] = xmprintf("%s %d","-C", TT.fd_num);
      while(toys.optargs[j]) {
        if(*toys.optargs[j]) args[i++] = xstrdup(toys.optargs[j]);
        j++;
      }
      args[i] = finfo->device;
    
      TT.nr_run++;
      if ((toys.optflags & FLAG_V) || (toys.optflags & FLAG_N)) {
        printf("[%s (%d) -- %s]", args[0], TT.nr_run,
            finfo->mountpt ? finfo->mountpt : finfo->device);
        for (i = 0; args[i]; i++) xprintf(" %s", args[i]);
        xputc('\n');
      }
    
      if (toys.optflags & FLAG_N) {
        for (j=0;j<i;j++) free(args[i]);
        free(args);
        return;
      } else { 
        if ((pid = fork()) < 0) {
          perror_msg_raw(*args);
          for (j=0;j<i;j++) free(args[i]);
          free(args);
          return; 
        }
        if (!pid) xexec(args); //child, executes fsck.type
      } 
    
      child = xzalloc(sizeof(struct child_list)); //Parent, add to child list.
      child->dev_name = xstrdup(finfo->device);
      child->prog_name = args[0];
      child->pid = pid;
    
      if (c_list) {
        child->next = c_list;
        c_list = child;
      } else {
        c_list = child;
        child->next =NULL;
      }
    }
    
    // for_all = 1; wait for all child to exit
    // for_all = 0; wait for any one to exit
    static int wait_for(int for_all)
    {
      pid_t pid;
      int status = 0, child_exited;
      struct child_list *prev, *temp;
    
      errno = 0;
      if (!c_list) return 0;
      while ((pid = wait(&status))) {
        temp = c_list;
        prev = temp;
        if (TT.sig_num) kill_all();
        child_exited = 0;
        if (pid < 0) {
          if (errno == EINTR) continue;
          else if (errno == ECHILD) break; //No child to wait, break and return status.
          else perror_exit("option arg Invalid\n"); //paranoid.
        }
        while (temp) {
          if (temp->pid == pid) {
            child_exited = 1;
            break;
          }
          prev = temp;
          temp = temp->next;
        }
        if (child_exited) {
          if (WIFEXITED(status)) TT.sum_status |= WEXITSTATUS(status);
          else if (WIFSIGNALED(status)) { 
            TT.sum_status |= 4; //Uncorrected.
            if (WTERMSIG(status) != SIGINT)
              perror_msg("child Term. by sig: %d\n",(WTERMSIG(status)));
            TT.sum_status |= 8; //Operatinal error
          } else { 
            TT.sum_status |= 4; //Uncorrected.
            perror_msg("%s %s: status is %x, should never happen\n", 
                temp->prog_name, temp->dev_name, status);
          }
          TT.nr_run--;
          if (prev == temp) c_list = c_list->next; //first node 
          else prev->next = temp->next;
          free(temp->prog_name);
          free(temp->dev_name);
          free(temp);
          if (!for_all) break;
        }
      }
      return TT.sum_status;
    }
    
    //scan all the fstab entries or -t matches with fstab.
    static int scan_all(void)
    {
      struct f_sys_info *finfo = filesys_info;
      int ret = 0, passno;
    
      if (toys.optflags & FLAG_V) xprintf("Checking all filesystem\n");
      while (finfo) {
        if (to_be_ignored(finfo)) finfo->flag |= FLAG_DONE;
        finfo = finfo->next;
      }
      finfo = filesys_info;
    
      if (!(toys.optflags & FLAG_P)) {
        while (finfo) {
          if (!strcmp(finfo->mountpt, "/")) { // man says: check / in parallel with others if -P is absent.
            if ((toys.optflags & FLAG_R) || to_be_ignored(finfo)) {
              finfo->flag |= FLAG_DONE;
              break;
            } else {
              do_fsck(finfo);
              finfo->flag |= FLAG_DONE;
              if (TT.sig_num) kill_all();
              if ((ret |= wait_for(1)) > 4) return ret; //destruction in filesys.
              break;
            }
          }
          finfo = finfo->next;
        }
      }
      if (toys.optflags & FLAG_R) { // with -PR we choose to skip root.
        for (finfo = filesys_info; finfo; finfo = finfo->next) {
          if(!strcmp(finfo->mountpt, "/")) finfo->flag |= FLAG_DONE;
        }
      }
      passno = 1;
      while (1) {
        for (finfo = filesys_info; finfo; finfo = finfo->next) 
          if (!finfo->flag) break;
        if (!finfo) break;
    
        for (finfo = filesys_info; finfo; finfo = finfo->next) {
          if (finfo->flag) continue;
          if (finfo->passno == passno) {
            do_fsck(finfo);
            finfo->flag |= FLAG_DONE;
            if ((toys.optflags & FLAG_s) || (TT.nr_run 
                  && (TT.nr_run >= TT.max_nr_run))) ret |= wait_for(0);
          }
        }
        if (TT.sig_num) kill_all();
        ret |= wait_for(1);
        passno++;
      }
      return ret;
    }
    
    void record_sig_num(int sig) 
    {
      TT.sig_num = sig;
    }
    
    void fsck_main(void)
    {
      struct mntent mt;
      struct double_list *dev;
      struct f_sys_info *finfo;
      FILE *fp;
      char *tmp, **arg = toys.optargs;
    
      sigatexit(record_sig_num);
      while (*arg) {
        if ((**arg == '/') || strchr(*arg, '=')) {
          dlist_add(&TT.devices, xstrdup(*arg));
          **arg = '\0';
        }
        arg++;
      }
      if (toys.optflags & FLAG_t) fix_tlist();
      if (!(tmp = getenv("FSTAB_FILE"))) tmp = "/etc/fstab";
      if (!(fp = setmntent(tmp, "r"))) perror_exit("setmntent failed:");
      while (getmntent_r(fp, &mt, toybuf, 4096)) create_db(&mt);
      endmntent(fp);
    
      if (!(toys.optflags & FLAG_T)) xprintf("fsck ----- (Toybox)\n");
    
      if ((tmp = getenv("FSCK_MAX_INST")))
        TT.max_nr_run = strtol_range(tmp, 0, INT_MAX);
      if (!TT.devices || (toys.optflags & FLAG_A)) {
        toys.exitval = scan_all();
        if (CFG_TOYBOX_FREE) goto free_all;
        return; //if CFG_TOYBOX_FREE is not set, exit.
      }
    
      dev = TT.devices;
      dev->prev->next = NULL; //break double list to traverse.
      for (; dev; dev = dev->next) {
        for (finfo = filesys_info; finfo; finfo = finfo->next)
          if (!strcmp(finfo->device, dev->data) 
              || !strcmp(finfo->mountpt, dev->data)) break;
        if (!finfo) { //if not present, fill def values.
          mt.mnt_fsname = dev->data;
          mt.mnt_dir = "";
          mt.mnt_type = "auto";
          mt.mnt_opts = "";
          mt.mnt_passno = -1;
          finfo = create_db(&mt);
        }
        do_fsck(finfo);
        finfo->flag |= FLAG_DONE;
        if ((toys.optflags & FLAG_s) || (TT.nr_run && (TT.nr_run >= TT.max_nr_run))) 
          toys.exitval |= wait_for(0);
      }
      if (TT.sig_num) kill_all();
      toys.exitval |= wait_for(1);
      finfo = filesys_info;
    
    free_all:
      if (CFG_TOYBOX_FREE) {
        struct f_sys_info *finfo, *temp;
    
        llist_traverse(TT.devices, llist_free_double);
        free(TT.arr_type);
        free(TT.arr_flag);
        for (finfo = filesys_info; finfo;) {
          temp = finfo->next;
          free(finfo->device);
          free(finfo->mountpt);
          free(finfo->type);
          free(finfo->opts);
          free(finfo);
          finfo = temp;
        }
      }
    }