getmountlist.c revision 562af2c0f2f4bd8420a26560f1816b6a81ac417e
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/* getmountlist.c - Get a linked list of mount points, with stat information. 23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * 33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Copyright 2006 Rob Landley <rob@landley.net> 43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */ 53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 63839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include "toys.h" 73839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <mntent.h> 821c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o// Realloc *old with oldstring,newstring 103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o 113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ovoid comma_collate(char **old, char *new) 123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{ 133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o char *temp, *atold = *old; 141e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 1550e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o // Only add a comma if old string didn't end with one 161e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o if (atold && *atold) { 17f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o char *comma = ","; 18f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o if (atold[strlen(atold)-1] == ',') comma = ""; 203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o temp = xmprintf("%s%s%s", atold, comma, new); 213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o } else temp = xstrdup(new); 223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o free (atold); 2353d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o *old = temp; 24f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o} 25f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 26f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o// iterate through strings in a comma separated list. 2753d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o// returns start of next entry or NULL if none 28f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o// sets *len to length of entry (not including comma) 29f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o// advances *list to start of next entry 3053d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'ochar *comma_iterate(char **list, int *len) 31f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 3253d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o char *start = *list, *end; 33f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 34f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (!*list || !**list) return 0; 3553d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o 36f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o if (!(end = strchr(*list, ','))) { 37f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o *len = strlen(*list); 38f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o *list = 0; 3953d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o } else *list += (*len = end-start)+1; 40f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 41f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o return start; 4253d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o} 43f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o 4453d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'ostatic void deslash(char *s) 45f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o{ 46f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o char *o = s; 471e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 481e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o while (*s) { 491e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o if (*s == '\\') { 501e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o int i, oct = 0; 511e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 521e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o for (i = 1; i < 4; i++) { 5321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o if (!isdigit(s[i])) break; 541e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o oct = (oct<<3)+s[i]-'0'; 551e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o } 561e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o if (i == 4) { 571e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o *o++ = oct; 581e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o s += i; 591e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o continue; 6021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 6121c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 6221c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o *o++ = *s++; 631e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o } 641e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 651e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o *o = 0; 661e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o} 671e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 681e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o// check all instances of opt and "no"opt in optlist, return true if opt 691e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o// found and last instance wasn't no. If clean, remove each instance from list. 701e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'oint comma_scan(char *optlist, char *opt, int clean) 711e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o{ 721e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o int optlen = strlen(opt), len, no, got = 0; 731e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 741e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o if (optlist) for (;;) { 751e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o char *s = comma_iterate(&optlist, &len); 761e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 771e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o if (!s) break; 781e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o no = 2*(*s == 'n' && s[1] == 'o'); 791e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o if (optlen == len-no && !strncmp(opt, s+no, optlen)) { 801e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o got = !no; 811e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o if (clean) memmove(s, optlist, strlen(optlist)+1); 821e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o } 831e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o } 841e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 851e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o return got; 861e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o} 871e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 881e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o// return true if all scanlist options enabled in optlist 891e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'oint comma_scanall(char *optlist, char *scanlist) 901e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o{ 911e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o int i = 1; 921e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 931e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o for (;;) { 9453d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o char *opt = comma_iterate(&scanlist, &i), *s = xstrndup(opt, i); 95d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o 96d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o i = comma_scan(optlist, s, 0); 97d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o free(s); 98d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o if (!i) break; 99d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o } 10053d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o 101d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o return i; 102d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o} 103d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o 10453d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o// Check if this type matches list. 105d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o// Odd syntax: typelist all yes = if any, typelist all no = if none. 106d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o 107d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'oint mountlist_istype(struct mtab_list *ml, char *typelist) 108d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o{ 109d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o int len, skip; 1106d21621c0ce194fd3c8474b8066a06c4781fb4bcTheodore Ts'o char *t; 11153d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o 112d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o if (!typelist) return 1; 113d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o 114d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o skip = strncmp(typelist, "no", 2); 115a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o 116a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o for (;;) { 117a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o if (!(t = comma_iterate(&typelist, &len))) break; 118a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o if (!skip) { 119a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o // If one -t starts with "no", the rest must too 120a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o if (strncmp(t, "no", 2)) error_exit("bad typelist"); 121a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o if (!strncmp(t+2, ml->type, len-2)) { 1224a959fe6f18a3b6023234a66f4455f7ec660b8b4Theodore Ts'o skip = 1; 1234a959fe6f18a3b6023234a66f4455f7ec660b8b4Theodore Ts'o break; 1244a959fe6f18a3b6023234a66f4455f7ec660b8b4Theodore Ts'o } 1254a959fe6f18a3b6023234a66f4455f7ec660b8b4Theodore Ts'o } else if (!strncmp(t, ml->type, len) && !ml->type[len]) { 126a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o skip = 0; 1274a959fe6f18a3b6023234a66f4455f7ec660b8b4Theodore Ts'o break; 1284a959fe6f18a3b6023234a66f4455f7ec660b8b4Theodore Ts'o } 129a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o } 1304a959fe6f18a3b6023234a66f4455f7ec660b8b4Theodore Ts'o 131a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o return !skip; 132a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o} 133a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o 134a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o// Get list of mounted filesystems, including stat and statvfs info. 135a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o// Returns a reversed list, which is good for finding overmounts and such. 136a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o 137a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'ostruct mtab_list *xgetmountlist(char *path) 138a0c3fd5e4cdc2e0b032c9ace89d960a622069c32Theodore Ts'o{ 139d7b701ded6fda284d7c77cd5ac48c2607ff72b13Theodore Ts'o struct mtab_list *mtlist = 0, *mt; 1401e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o struct mntent *me; 1417f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o FILE *fp; 1427f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o char *p = path ? path : "/proc/mounts"; 1437f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o 1447f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p); 145a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o 146a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o // The "test" part of the loop is done before the first time through and 147a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o // again after each "increment", so putting the actual load there avoids 148a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o // duplicating it. If the load was NULL, the loop stops. 149379955feee57506fc1f1824c5223399690ea0465Theodore Ts'o 1503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o while ((me = getmntent(fp))) { 1517f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) + 1521e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4); 1531e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o dlist_add_nomalloc((void *)&mtlist, (void *)mt); 15421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o 1557f88b04341d88c5df0360d930832c38040303b61Theodore Ts'o // Collect details about mounted filesystem 156379955feee57506fc1f1824c5223399690ea0465Theodore Ts'o // Don't report errors, just leave data zeroed 157379955feee57506fc1f1824c5223399690ea0465Theodore Ts'o if (!path) { 158379955feee57506fc1f1824c5223399690ea0465Theodore Ts'o stat(me->mnt_dir, &(mt->stat)); 159379955feee57506fc1f1824c5223399690ea0465Theodore Ts'o statvfs(me->mnt_dir, &(mt->statvfs)); 1601e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o } 1611e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 1621e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o // Remember information from /proc/mounts 16321c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o mt->dir = stpcpy(mt->type, me->mnt_type)+1; 16421c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o mt->device = stpcpy(mt->dir, me->mnt_dir)+1; 16553d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o mt->opts = stpcpy(mt->device, me->mnt_fsname)+1; 1661e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o strcpy(mt->opts, me->mnt_opts); 1671e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o 1681e3472c5f37ca3686dd69b079d4d02a302f5798dTheodore Ts'o deslash(mt->dir); 16921c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o deslash(mt->device); 17021c84b71e205b5ab13f14343da5645dcc985856dTheodore Ts'o } 17153d3955001593b668b15e2d10b3a191f689f9779Theodore Ts'o endmntent(fp); 172f61fc0b5d98ef2455252d596e7b20131526d6762Theodore Ts'o 173379955feee57506fc1f1824c5223399690ea0465Theodore Ts'o return mtlist; 174379955feee57506fc1f1824c5223399690ea0465Theodore Ts'o} 175379955feee57506fc1f1824c5223399690ea0465Theodore Ts'o