blob: 30fb9a35ef5a5cbaec26a8034cd4705de6e284f9 [file] [log] [blame]
landley09ea7ac2006-10-30 01:38:00 -05001/* getmountlist.c - Get a linked list of mount points, with stat information.
2 *
3 * Copyright 2006 Rob Landley <rob@landley.net>
4 */
landley4f344e32006-10-05 16:18:03 -04005
6#include "toys.h"
landley4f344e32006-10-05 16:18:03 -04007#include <mntent.h>
8
Rob Landleye996bdd2014-08-24 23:46:23 -05009// Realloc *old with oldstring,newstring
10
11void 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
30char *comma_iterate(char **list, int *len)
31{
32 char *start = *list, *end;
33
Rob Landley25fe0e02014-09-07 14:42:51 -050034 if (!*list || !**list) return 0;
Rob Landleye996bdd2014-08-24 23:46:23 -050035
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
Rob Landleyd111b952015-03-16 13:25:29 -050044static void octal_deslash(char *s)
Rob Landleye996bdd2014-08-24 23:46:23 -050045{
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.
70int 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 Landley562af2c2014-09-28 13:11:20 -050079 if (optlen == len-no && !strncmp(opt, s+no, optlen)) {
Rob Landley25fe0e02014-09-07 14:42:51 -050080 got = !no;
81 if (clean) memmove(s, optlist, strlen(optlist)+1);
82 }
Rob Landleye996bdd2014-08-24 23:46:23 -050083 }
84
85 return got;
86}
87
88// return true if all scanlist options enabled in optlist
89int comma_scanall(char *optlist, char *scanlist)
90{
91 int i = 1;
92
Rob Landley4437be02015-03-16 13:27:16 -050093 while (scanlist && *scanlist) {
Rob Landleye996bdd2014-08-24 23:46:23 -050094 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
107int 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 Landley078d31c2013-05-10 18:57:01 -0500134// Get list of mounted filesystems, including stat and statvfs info.
135// Returns a reversed list, which is good for finding overmounts and such.
landley4f344e32006-10-05 16:18:03 -0400136
Rob Landley42adb7a2013-08-30 17:34:24 -0500137struct mtab_list *xgetmountlist(char *path)
landley4f344e32006-10-05 16:18:03 -0400138{
Rob Landleydc640252014-05-29 05:22:02 -0500139 struct mtab_list *mtlist = 0, *mt;
Rob Landley078d31c2013-05-10 18:57:01 -0500140 struct mntent *me;
141 FILE *fp;
Rob Landleydc640252014-05-29 05:22:02 -0500142 char *p = path ? path : "/proc/mounts";
landley4f344e32006-10-05 16:18:03 -0400143
Rob Landleydc640252014-05-29 05:22:02 -0500144 if (!(fp = setmntent(p, "r"))) perror_exit("bad %s", p);
Rob Landley078d31c2013-05-10 18:57:01 -0500145
Rob Landley00474ef2013-05-14 20:22:23 -0500146 // 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 Landleydc640252014-05-29 05:22:02 -0500150 while ((me = getmntent(fp))) {
Rob Landley078d31c2013-05-10 18:57:01 -0500151 mt = xzalloc(sizeof(struct mtab_list) + strlen(me->mnt_fsname) +
Rob Landley55e9f352014-05-27 07:56:51 -0500152 strlen(me->mnt_dir) + strlen(me->mnt_type) + strlen(me->mnt_opts) + 4);
Rob Landleydc640252014-05-29 05:22:02 -0500153 dlist_add_nomalloc((void *)&mtlist, (void *)mt);
Rob Landley078d31c2013-05-10 18:57:01 -0500154
Rob Landleydc640252014-05-29 05:22:02 -0500155 // 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 Landley078d31c2013-05-10 18:57:01 -0500161
162 // Remember information from /proc/mounts
Rob Landley55e9f352014-05-27 07:56:51 -0500163 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 Landleye996bdd2014-08-24 23:46:23 -0500167
Rob Landleyd111b952015-03-16 13:25:29 -0500168 octal_deslash(mt->dir);
169 octal_deslash(mt->device);
Rob Landley7aa651a2012-11-13 17:14:08 -0600170 }
Rob Landley491eb802012-11-17 22:06:00 -0600171 endmntent(fp);
Rob Landley078d31c2013-05-10 18:57:01 -0500172
Rob Landley7aa651a2012-11-13 17:14:08 -0600173 return mtlist;
landley4f344e32006-10-05 16:18:03 -0400174}