toybox/lib/getmountlist.c
<<
>>
Prefs
   1/* getmountlist.c - Get a linked list of mount points, with stat information.
   2 *
   3 * Copyright 2006 Rob Landley <rob@landley.net>
   4 */
   5
   6#include "toys.h"
   7#include <mntent.h>
   8
   9// Traverse arg_list of csv, calling callback on each value
  10void comma_args(struct arg_list *al, void *data, char *err,
  11  char *(*callback)(void *data, char *str, int len))
  12{
  13  char *next, *arg;
  14  int len;
  15
  16  if (CFG_TOYBOX_DEBUG && !err) err = "INTERNAL";
  17
  18  while (al) {
  19    arg = al->arg;
  20    while ((next = comma_iterate(&arg, &len)))
  21      if ((next = callback(data, next, len)))
  22        error_exit("%s '%s'\n%*c", err, al->arg,
  23          (int)(5+strlen(toys.which->name)+strlen(err)+next-al->arg), '^');
  24    al = al->next;
  25  }
  26}
  27
  28// Realloc *old with oldstring,newstring
  29
  30void comma_collate(char **old, char *new)
  31{
  32  char *temp, *atold = *old;
  33
  34  // Only add a comma if old string didn't end with one
  35  if (atold && *atold) {
  36    char *comma = ",";
  37
  38    if (atold[strlen(atold)-1] == ',') comma = "";
  39    temp = xmprintf("%s%s%s", atold, comma, new);
  40  } else temp = xstrdup(new);
  41  free (atold);
  42  *old = temp;
  43}
  44
  45// iterate through strings in a comma separated list.
  46// returns start of next entry or NULL if none
  47// sets *len to length of entry (not including comma)
  48// advances *list to start of next entry
  49char *comma_iterate(char **list, int *len)
  50{
  51  char *start = *list, *end;
  52
  53  if (!*list || !**list) return 0;
  54
  55  if (!(end = strchr(*list, ','))) {
  56    *len = strlen(*list);
  57    *list = 0;
  58  } else *list += (*len = end-start)+1;
  59
  60  return start;
  61}
  62
  63static void octal_deslash(char *s)
  64{
  65  char *o = s;
  66
  67  while (*s) {
  68    if (*s == '\\') {
  69      int i, oct = 0;
  70
  71      for (i = 1; i < 4; i++) {
  72        if (!isdigit(s[i])) break;
  73        oct = (oct<<3)+s[i]-'0';
  74      }
  75      if (i == 4) {
  76        *o++ = oct;
  77        s += i;
  78        continue;
  79      }
  80    }
  81    *o++ = *s++;
  82  }
  83
  84  *o = 0;
  85}
  86
  87// check all instances of opt and "no"opt in optlist, return true if opt
  88// found and last instance wasn't no. If clean, remove each instance from list.
  89int comma_scan(char *optlist, char *opt, int clean)
  90{
  91  int optlen = strlen(opt), len, no, got = 0;
  92
  93  if (optlist) for (;;) {
  94    char *s = comma_iterate(&optlist, &len);
  95
  96    if (!s) break;
  97    no = 2*(*s == 'n' && s[1] == 'o');
  98    if (optlen == len-no && !strncmp(opt, s+no, optlen)) {
  99      got = !no;
 100      if (clean) {
 101        if (optlist) memmove(s, optlist, strlen(optlist)+1);
 102        else *s = 0;
 103      }
 104    }
 105  }
 106
 107  return got;
 108}
 109
 110// return true if all scanlist options enabled in optlist
 111int comma_scanall(char *optlist, char *scanlist)
 112{
 113  int i = 1;
 114
 115  while (scanlist && *scanlist) {
 116    char *opt = comma_iterate(&scanlist, &i), *s = xstrndup(opt, i);
 117
 118    i = comma_scan(optlist, s, 0);
 119    free(s);
 120    if (!i) break;
 121  }
 122
 123  return i;
 124}
 125
 126// Check if this type matches list.
 127// Odd syntax: typelist all yes = if any, typelist all no = if none.
 128
 129int mountlist_istype(struct mtab_list *ml, char *typelist)
 130{
 131  int len, skip;
 132  char *t;
 133
 134  if (!typelist) return 1;
 135
 136  skip = strncmp(typelist, "no", 2);
 137
 138  for (;;) {
 139    if (!(t = comma_iterate(&typelist, &len))) break;
 140    if (!skip) {
 141      // If one -t starts with "no", the rest must too
 142      if (strncmp(t, "no", 2)) error_exit("bad typelist");
 143      if (!strncmp(t+2, ml->type, len-2)) {
 144        skip = 1;
 145        break;
 146      }
 147    } else if (!strncmp(t, ml->type, len) && !ml->type[len]) {
 148      skip = 0;
 149      break;
 150    }
 151  }
 152
 153  return !skip;
 154}
 155
 156// Get list of mounted filesystems, including stat and statvfs info.
 157// Returns a reversed list, which is good for finding overmounts and such.
 158
 159struct mtab_list *xgetmountlist(char *path)
 160{
 161  struct mtab_list *mtlist = 0, *mt;
 162  struct mntent *me;
 163  FILE *fp;
 164  char *p = path ? path : "/proc/mounts";
 165
 166  if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p);
 167
 168  // The "test" part of the loop is done before the first time through and
 169  // again after each "increment", so putting the actual load there avoids
 170  // duplicating it. If the load was NULL, the loop stops.
 171
 172  while ((me = getmntent(fp))) {
 173    mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) +
 174      strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4);
 175    dlist_add_nomalloc((void *)&mtlist, (void *)mt);
 176
 177    // Collect details about mounted filesystem
 178    // Don't report errors, just leave data zeroed
 179    if (!path) {
 180      stat(me->mnt_dir, &(mt->stat));
 181      statvfs(me->mnt_dir, &(mt->statvfs));
 182    }
 183
 184    // Remember information from /proc/mounts
 185    mt->dir = stpcpy(mt->type, me->mnt_type)+1;
 186    mt->device = stpcpy(mt->dir, me->mnt_dir)+1;
 187    mt->opts = stpcpy(mt->device, me->mnt_fsname)+1;
 188    strcpy(mt->opts, me->mnt_opts);
 189
 190    octal_deslash(mt->dir);
 191    octal_deslash(mt->device);
 192  }
 193  endmntent(fp);
 194
 195  return mtlist;
 196}
 197