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