]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/fstab-util.c
6b73e25f89aa635cf1ffb99ae60a638088845641
[thirdparty/systemd.git] / src / shared / fstab-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <mntent.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7
8 #include "alloc-util.h"
9 #include "device-nodes.h"
10 #include "fstab-util.h"
11 #include "macro.h"
12 #include "mount-util.h"
13 #include "nulstr-util.h"
14 #include "parse-util.h"
15 #include "path-util.h"
16 #include "string-util.h"
17 #include "strv.h"
18
19 int fstab_has_fstype(const char *fstype) {
20 _cleanup_endmntent_ FILE *f = NULL;
21 struct mntent *m;
22
23 f = setmntent("/etc/fstab", "re");
24 if (!f)
25 return errno == ENOENT ? false : -errno;
26
27 for (;;) {
28 errno = 0;
29 m = getmntent(f);
30 if (!m)
31 return errno != 0 ? -errno : false;
32
33 if (streq(m->mnt_type, fstype))
34 return true;
35 }
36 return false;
37 }
38
39 int fstab_is_mount_point(const char *mount) {
40 _cleanup_endmntent_ FILE *f = NULL;
41 struct mntent *m;
42
43 f = setmntent("/etc/fstab", "re");
44 if (!f)
45 return errno == ENOENT ? false : -errno;
46
47 for (;;) {
48 errno = 0;
49 m = getmntent(f);
50 if (!m)
51 return errno != 0 ? -errno : false;
52
53 if (path_equal(m->mnt_dir, mount))
54 return true;
55 }
56 return false;
57 }
58
59 int fstab_filter_options(const char *opts, const char *names,
60 const char **namefound, char **value, char **filtered) {
61 const char *name, *n = NULL, *x;
62 _cleanup_strv_free_ char **stor = NULL;
63 _cleanup_free_ char *v = NULL, **strv = NULL;
64
65 assert(names && *names);
66
67 if (!opts)
68 goto answer;
69
70 /* If !value and !filtered, this function is not allowed to fail. */
71
72 if (!filtered) {
73 const char *word, *state;
74 size_t l;
75
76 FOREACH_WORD_SEPARATOR(word, l, opts, ",", state)
77 NULSTR_FOREACH(name, names) {
78 if (l < strlen(name))
79 continue;
80 if (!strneq(word, name, strlen(name)))
81 continue;
82
83 /* we know that the string is NUL
84 * terminated, so *x is valid */
85 x = word + strlen(name);
86 if (IN_SET(*x, '\0', '=', ',')) {
87 n = name;
88 if (value) {
89 free(v);
90 if (IN_SET(*x, '\0', ','))
91 v = NULL;
92 else {
93 assert(*x == '=');
94 x++;
95 v = strndup(x, l - strlen(name) - 1);
96 if (!v)
97 return -ENOMEM;
98 }
99 }
100 }
101 }
102 } else {
103 char **t, **s;
104
105 stor = strv_split(opts, ",");
106 if (!stor)
107 return -ENOMEM;
108 strv = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
109 if (!strv)
110 return -ENOMEM;
111
112 for (s = t = strv; *s; s++) {
113 NULSTR_FOREACH(name, names) {
114 x = startswith(*s, name);
115 if (x && IN_SET(*x, '\0', '='))
116 goto found;
117 }
118
119 *t = *s;
120 t++;
121 continue;
122 found:
123 /* Keep the last occurrence found */
124 n = name;
125 if (value) {
126 free(v);
127 if (*x == '\0')
128 v = NULL;
129 else {
130 assert(*x == '=');
131 x++;
132 v = strdup(x);
133 if (!v)
134 return -ENOMEM;
135 }
136 }
137 }
138 *t = NULL;
139 }
140
141 answer:
142 if (namefound)
143 *namefound = n;
144 if (filtered) {
145 char *f;
146
147 f = strv_join(strv, ",");
148 if (!f)
149 return -ENOMEM;
150
151 *filtered = f;
152 }
153 if (value)
154 *value = TAKE_PTR(v);
155
156 return !!n;
157 }
158
159 int fstab_extract_values(const char *opts, const char *name, char ***values) {
160 _cleanup_strv_free_ char **optsv = NULL, **res = NULL;
161 char **s;
162
163 assert(opts);
164 assert(name);
165 assert(values);
166
167 optsv = strv_split(opts, ",");
168 if (!optsv)
169 return -ENOMEM;
170
171 STRV_FOREACH(s, optsv) {
172 char *arg;
173 int r;
174
175 arg = startswith(*s, name);
176 if (!arg || *arg != '=')
177 continue;
178 r = strv_extend(&res, arg + 1);
179 if (r < 0)
180 return r;
181 }
182
183 *values = TAKE_PTR(res);
184
185 return !!*values;
186 }
187
188 int fstab_find_pri(const char *options, int *ret) {
189 _cleanup_free_ char *opt = NULL;
190 int r;
191 unsigned pri;
192
193 assert(ret);
194
195 r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL);
196 if (r < 0)
197 return r;
198 if (r == 0 || !opt)
199 return 0;
200
201 r = safe_atou(opt, &pri);
202 if (r < 0)
203 return r;
204
205 if ((int) pri < 0)
206 return -ERANGE;
207
208 *ret = (int) pri;
209 return 1;
210 }
211
212 static char *unquote(const char *s, const char* quotes) {
213 size_t l;
214 assert(s);
215
216 /* This is rather stupid, simply removes the heading and
217 * trailing quotes if there is one. Doesn't care about
218 * escaping or anything.
219 *
220 * DON'T USE THIS FOR NEW CODE ANYMORE! */
221
222 l = strlen(s);
223 if (l < 2)
224 return strdup(s);
225
226 if (strchr(quotes, s[0]) && s[l-1] == s[0])
227 return strndup(s+1, l-2);
228
229 return strdup(s);
230 }
231
232 static char *tag_to_udev_node(const char *tagvalue, const char *by) {
233 _cleanup_free_ char *t = NULL, *u = NULL;
234 size_t enc_len;
235
236 u = unquote(tagvalue, QUOTES);
237 if (!u)
238 return NULL;
239
240 enc_len = strlen(u) * 4 + 1;
241 t = new(char, enc_len);
242 if (!t)
243 return NULL;
244
245 if (encode_devnode_name(u, t, enc_len) < 0)
246 return NULL;
247
248 return strjoin("/dev/disk/by-", by, "/", t);
249 }
250
251 char *fstab_node_to_udev_node(const char *p) {
252 assert(p);
253
254 if (startswith(p, "LABEL="))
255 return tag_to_udev_node(p+6, "label");
256
257 if (startswith(p, "UUID="))
258 return tag_to_udev_node(p+5, "uuid");
259
260 if (startswith(p, "PARTUUID="))
261 return tag_to_udev_node(p+9, "partuuid");
262
263 if (startswith(p, "PARTLABEL="))
264 return tag_to_udev_node(p+10, "partlabel");
265
266 return strdup(p);
267 }