getmountlist.c revision 25fe0e0bea85f1d851ce03a90c0f1bf41ab431f2
19e035921494cb8f101c3bfc22956fa968c6ab41fBarry Warsaw/* getmountlist.c - Get a linked list of mount points, with stat information.
2ff6d8136574e9f4e1b11f75a945af5f8ab44a6fdBarry Warsaw *
3a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw * Copyright 2006 Rob Landley <rob@landley.net>
49e035921494cb8f101c3bfc22956fa968c6ab41fBarry Warsaw */
5d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
6a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw#include "toys.h"
7ee8712cda46338d223509cc5751fd36509ad3860Benjamin Peterson#include <mntent.h>
8a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
9004d5e6880940ddbb38460986ac62ee0f1bae97dFred Drake// Realloc *old with oldstring,newstring
10d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
11d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwisvoid comma_collate(char **old, char *new)
12d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis{
13d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  char *temp, *atold = *old;
14d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
1564dab4602e17878e816ae1d3f48b2f589ceebdfbBarry Warsaw  // Only add a comma if old string didn't end with one
1639478e852827a4ca6955151bf004c7a15099a4b1Guido van Rossum  if (atold && *atold) {
17d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    char *comma = ",";
18d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
19d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    if (atold[strlen(atold)-1] == ',') comma = "";
20d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    temp = xmprintf("%s%s%s", atold, comma, new);
21d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  } else temp = xstrdup(new);
22d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  free (atold);
23d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  *old = temp;
24d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis}
25d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
26d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis// iterate through strings in a comma separated list.
27d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis// returns start of next entry or NULL if none
28d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis// sets *len to length of entry (not including comma)
29d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis// advances *list to start of next entry
30d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwischar *comma_iterate(char **list, int *len)
31d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis{
32d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  char *start = *list, *end;
33d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
34d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  if (!*list || !**list) return 0;
35d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
3639478e852827a4ca6955151bf004c7a15099a4b1Guido van Rossum  if (!(end = strchr(*list, ','))) {
37a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    *len = strlen(*list);
38a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    *list = 0;
39a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  } else *list += (*len = end-start)+1;
40a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
41a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  return start;
42a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw}
43a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
44a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsawstatic void deslash(char *s)
45d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis{
4639478e852827a4ca6955151bf004c7a15099a4b1Guido van Rossum  char *o = s;
47e960e22579838419541357712bbbc3317c219071Barry Warsaw
48e960e22579838419541357712bbbc3317c219071Barry Warsaw  while (*s) {
49e960e22579838419541357712bbbc3317c219071Barry Warsaw    if (*s == '\\') {
50e960e22579838419541357712bbbc3317c219071Barry Warsaw      int i, oct = 0;
51e960e22579838419541357712bbbc3317c219071Barry Warsaw
52e960e22579838419541357712bbbc3317c219071Barry Warsaw      for (i = 1; i < 4; i++) {
53e960e22579838419541357712bbbc3317c219071Barry Warsaw        if (!isdigit(s[i])) break;
54e960e22579838419541357712bbbc3317c219071Barry Warsaw        oct = (oct<<3)+s[i]-'0';
55e960e22579838419541357712bbbc3317c219071Barry Warsaw      }
56e960e22579838419541357712bbbc3317c219071Barry Warsaw      if (i == 4) {
57d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis        *o++ = oct;
58d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis        s += i;
59a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw        continue;
60e960e22579838419541357712bbbc3317c219071Barry Warsaw      }
61d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    }
62d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    *o++ = *s++;
63a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  }
64a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
65a0e0cd3013840299a789f05be239d6ecb6387cdfNeal Norwitz  *o = 0;
66a0e0cd3013840299a789f05be239d6ecb6387cdfNeal Norwitz}
677fa886df3622bbedbeb9c2486a8af5f05334a928Éric Araujo
687fa886df3622bbedbeb9c2486a8af5f05334a928Éric Araujo// check all instances of opt and "no"opt in optlist, return true if opt
697fa886df3622bbedbeb9c2486a8af5f05334a928Éric Araujo// found and last instance wasn't no. If clean, remove each instance from list.
707fa886df3622bbedbeb9c2486a8af5f05334a928Éric Araujoint comma_scan(char *optlist, char *opt, int clean)
717fa886df3622bbedbeb9c2486a8af5f05334a928Éric Araujo{
727fa886df3622bbedbeb9c2486a8af5f05334a928Éric Araujo  int optlen = strlen(opt), len, no, got = 0;
73155374d95d8ecd235d3a3edd92dd6f6a23d59f11Walter Dörwald
74155374d95d8ecd235d3a3edd92dd6f6a23d59f11Walter Dörwald  if (optlist) for (;;) {
7537a89334da1fbe5b30f5a03a97b8f8c2a59adc1bÉric Araujo    char *s = comma_iterate(&optlist, &len);
76a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
77a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    if (!s) break;
78155374d95d8ecd235d3a3edd92dd6f6a23d59f11Walter Dörwald    no = 2*(*s == 'n' && s[1] == 'o');
79155374d95d8ecd235d3a3edd92dd6f6a23d59f11Walter Dörwald    if (optlen == len+no && !strcmp(opt, s+no)) {
804aebbb044942ad17d761491b46ff05b6ab8387c9Brett Cannon      got = !no;
81d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis      if (clean) memmove(s, optlist, strlen(optlist)+1);
82ff6d8136574e9f4e1b11f75a945af5f8ab44a6fdBarry Warsaw    }
83a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  }
84d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
85a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  return got;
86d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis}
87d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
88d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis// return true if all scanlist options enabled in optlist
89ff6d8136574e9f4e1b11f75a945af5f8ab44a6fdBarry Warsawint comma_scanall(char *optlist, char *scanlist)
90d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis{
91a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  int i = 1;
92d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
93a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  for (;;) {
94ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum    char *opt = comma_iterate(&scanlist, &i), *s = xstrndup(opt, i);
95a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
96ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum    i = comma_scan(optlist, s, 0);
97d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    free(s);
98d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    if (!i) break;
99a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  }
100d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
101a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  return i;
102ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum}
103a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
104ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum// Check if this type matches list.
105d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis// Odd syntax: typelist all yes = if any, typelist all no = if none.
106d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
107a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsawint mountlist_istype(struct mtab_list *ml, char *typelist)
108d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis{
109a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  int len, skip;
110ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum  char *t;
111a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
112ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum  if (!typelist) return 1;
113d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
114d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  skip = strncmp(typelist, "no", 2);
115a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
116d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  for (;;) {
117a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    if (!(t = comma_iterate(&typelist, &len))) break;
118ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum    if (!skip) {
119a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw      // If one -t starts with "no", the rest must too
120ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum      if (strncmp(t, "no", 2)) error_exit("bad typelist");
121d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis      if (!strncmp(t+2, ml->type, len-2)) {
122d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis        skip = 1;
123a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw        break;
124d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis      }
125a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    } else if (!strncmp(t, ml->type, len) && !ml->type[len]) {
1269e035921494cb8f101c3bfc22956fa968c6ab41fBarry Warsaw      skip = 0;
127a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw      break;
128a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    }
129d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  }
130a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
131ff6d8136574e9f4e1b11f75a945af5f8ab44a6fdBarry Warsaw  return !skip;
132d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis}
133a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
134d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis// Get list of mounted filesystems, including stat and statvfs info.
1357fa886df3622bbedbeb9c2486a8af5f05334a928Éric Araujo// Returns a reversed list, which is good for finding overmounts and such.
1367fa886df3622bbedbeb9c2486a8af5f05334a928Éric Araujo
137a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsawstruct mtab_list *xgetmountlist(char *path)
138d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis{
139a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  struct mtab_list *mtlist = 0, *mt;
140a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  struct mntent *me;
141801844d6fc8b48cfa969dd2573bd522a2b26f974Benjamin Peterson  FILE *fp;
142a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  char *p = path ? path : "/proc/mounts";
143602b9ba6b37c4ac4ed445f8c9e9dccd68d631899Georg Brandl
1441a3284ed69d545e4ef59869998cb8c29233a45faGeorg Brandl  if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p);
145801844d6fc8b48cfa969dd2573bd522a2b26f974Benjamin Peterson
146801844d6fc8b48cfa969dd2573bd522a2b26f974Benjamin Peterson  // The "test" part of the loop is done before the first time through and
147801844d6fc8b48cfa969dd2573bd522a2b26f974Benjamin Peterson  // again after each "increment", so putting the actual load there avoids
148602b9ba6b37c4ac4ed445f8c9e9dccd68d631899Georg Brandl  // duplicating it. If the load was NULL, the loop stops.
1491a3284ed69d545e4ef59869998cb8c29233a45faGeorg Brandl
1501a3284ed69d545e4ef59869998cb8c29233a45faGeorg Brandl  while ((me = getmntent(fp))) {
151d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) +
152ff6d8136574e9f4e1b11f75a945af5f8ab44a6fdBarry Warsaw      strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4);
153a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    dlist_add_nomalloc((void *)&mtlist, (void *)mt);
154d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
155a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    // Collect details about mounted filesystem
156d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    // Don't report errors, just leave data zeroed
157a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    if (!path) {
158d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis      stat(me->mnt_dir, &(mt->stat));
159d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis      statvfs(me->mnt_dir, &(mt->statvfs));
160a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    }
161d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis
16264dab4602e17878e816ae1d3f48b2f589ceebdfbBarry Warsaw    // Remember information from /proc/mounts
163d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    mt->dir = stpcpy(mt->type, me->mnt_type)+1;
164a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw    mt->device = stpcpy(mt->dir, me->mnt_dir)+1;
16564dab4602e17878e816ae1d3f48b2f589ceebdfbBarry Warsaw    mt->opts = stpcpy(mt->device, me->mnt_fsname)+1;
166d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    strcpy(mt->opts, me->mnt_opts);
167a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
16864dab4602e17878e816ae1d3f48b2f589ceebdfbBarry Warsaw    deslash(mt->dir);
169d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis    deslash(mt->device);
170a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw  }
171d899605e30eef8e77f70184eac15fad1bf770586Martin v. Löwis  endmntent(fp);
172a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw
173ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum  return mtlist;
174a1ce93f87cb221be9a7466c2f9d2b7dc494f458dBarry Warsaw}
175ef87d6ed94780fe00250a551031023aeb2898365Guido van Rossum