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