1 /* getmountlist.c - Get a linked list of mount points, with stat information. 2 * 3 * Copyright 2006 Rob Landley <rob (at) landley.net> 4 */ 5 6 #include "toys.h" 7 #include <mntent.h> 8 9 // Traverse arg_list of csv, calling callback on each value 10 void 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 30 void 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 49 char *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 63 static 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. 89 int 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 && optlist) memmove(s, optlist, strlen(optlist)+1); 101 } 102 } 103 104 return got; 105 } 106 107 // return true if all scanlist options enabled in optlist 108 int comma_scanall(char *optlist, char *scanlist) 109 { 110 int i = 1; 111 112 while (scanlist && *scanlist) { 113 char *opt = comma_iterate(&scanlist, &i), *s = xstrndup(opt, i); 114 115 i = comma_scan(optlist, s, 0); 116 free(s); 117 if (!i) break; 118 } 119 120 return i; 121 } 122 123 // Check if this type matches list. 124 // Odd syntax: typelist all yes = if any, typelist all no = if none. 125 126 int mountlist_istype(struct mtab_list *ml, char *typelist) 127 { 128 int len, skip; 129 char *t; 130 131 if (!typelist) return 1; 132 133 skip = strncmp(typelist, "no", 2); 134 135 for (;;) { 136 if (!(t = comma_iterate(&typelist, &len))) break; 137 if (!skip) { 138 // If one -t starts with "no", the rest must too 139 if (strncmp(t, "no", 2)) error_exit("bad typelist"); 140 if (!strncmp(t+2, ml->type, len-2)) { 141 skip = 1; 142 break; 143 } 144 } else if (!strncmp(t, ml->type, len) && !ml->type[len]) { 145 skip = 0; 146 break; 147 } 148 } 149 150 return !skip; 151 } 152 153 // Get list of mounted filesystems, including stat and statvfs info. 154 // Returns a reversed list, which is good for finding overmounts and such. 155 156 struct mtab_list *xgetmountlist(char *path) 157 { 158 struct mtab_list *mtlist = 0, *mt; 159 struct mntent *me; 160 FILE *fp; 161 char *p = path ? path : "/proc/mounts"; 162 163 if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p); 164 165 // The "test" part of the loop is done before the first time through and 166 // again after each "increment", so putting the actual load there avoids 167 // duplicating it. If the load was NULL, the loop stops. 168 169 while ((me = getmntent(fp))) { 170 mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) + 171 strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4); 172 dlist_add_nomalloc((void *)&mtlist, (void *)mt); 173 174 // Collect details about mounted filesystem 175 // Don't report errors, just leave data zeroed 176 if (!path) { 177 stat(me->mnt_dir, &(mt->stat)); 178 statvfs(me->mnt_dir, &(mt->statvfs)); 179 } 180 181 // Remember information from /proc/mounts 182 mt->dir = stpcpy(mt->type, me->mnt_type)+1; 183 mt->device = stpcpy(mt->dir, me->mnt_dir)+1; 184 mt->opts = stpcpy(mt->device, me->mnt_fsname)+1; 185 strcpy(mt->opts, me->mnt_opts); 186 187 octal_deslash(mt->dir); 188 octal_deslash(mt->device); 189 } 190 endmntent(fp); 191 192 return mtlist; 193 } 194