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