1 /* getmountlist.c - Get a linked list of mount points, with stat information.
2 *
3 * Copyright 2006 Rob Landley <rob@landley.net>
4 */
5
6 #include "toys.h"
7 #include <mntent.h>
8
9 // Realloc *old with oldstring,newstring
10
comma_collate(char ** old,char * new)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
comma_iterate(char ** list,int * len)30 char *comma_iterate(char **list, int *len)
31 {
32 char *start = *list, *end;
33
34 if (!*list || !**list) return 0;
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
octal_deslash(char * s)44 static void octal_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.
comma_scan(char * optlist,char * opt,int clean)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');
79 if (optlen == len-no && !strncmp(opt, s+no, optlen)) {
80 got = !no;
81 if (clean) memmove(s, optlist, strlen(optlist)+1);
82 }
83 }
84
85 return got;
86 }
87
88 // return true if all scanlist options enabled in optlist
comma_scanall(char * optlist,char * scanlist)89 int comma_scanall(char *optlist, char *scanlist)
90 {
91 int i = 1;
92
93 while (scanlist && *scanlist) {
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
mountlist_istype(struct mtab_list * ml,char * typelist)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
134 // Get list of mounted filesystems, including stat and statvfs info.
135 // Returns a reversed list, which is good for finding overmounts and such.
136
xgetmountlist(char * path)137 struct mtab_list *xgetmountlist(char *path)
138 {
139 struct mtab_list *mtlist = 0, *mt;
140 struct mntent *me;
141 FILE *fp;
142 char *p = path ? path : "/proc/mounts";
143
144 if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p);
145
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
150 while ((me = getmntent(fp))) {
151 mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) +
152 strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4);
153 dlist_add_nomalloc((void *)&mtlist, (void *)mt);
154
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 }
161
162 // Remember information from /proc/mounts
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);
167
168 octal_deslash(mt->dir);
169 octal_deslash(mt->device);
170 }
171 endmntent(fp);
172
173 return mtlist;
174 }
175