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