]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/fstab-util.c
Add SPDX license identifiers to source files under the LGPL
[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 = v;
174 v = NULL;
175 }
176
177 return !!n;
178 }
179
180 int fstab_extract_values(const char *opts, const char *name, char ***values) {
181 _cleanup_strv_free_ char **optsv = NULL, **res = NULL;
182 char **s;
183
184 assert(opts);
185 assert(name);
186 assert(values);
187
188 optsv = strv_split(opts, ",");
189 if (!optsv)
190 return -ENOMEM;
191
192 STRV_FOREACH(s, optsv) {
193 char *arg;
194 int r;
195
196 arg = startswith(*s, name);
197 if (!arg || *arg != '=')
198 continue;
199 r = strv_extend(&res, arg + 1);
200 if (r < 0)
201 return r;
202 }
203
204 *values = res;
205 res = NULL;
206
207 return !!*values;
208 }
209
210 int fstab_find_pri(const char *options, int *ret) {
211 _cleanup_free_ char *opt = NULL;
212 int r;
213 unsigned pri;
214
215 assert(ret);
216
217 r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL);
218 if (r < 0)
219 return r;
220 if (r == 0 || !opt)
221 return 0;
222
223 r = safe_atou(opt, &pri);
224 if (r < 0)
225 return r;
226
227 if ((int) pri < 0)
228 return -ERANGE;
229
230 *ret = (int) pri;
231 return 1;
232 }
233
234 static char *unquote(const char *s, const char* quotes) {
235 size_t l;
236 assert(s);
237
238 /* This is rather stupid, simply removes the heading and
239 * trailing quotes if there is one. Doesn't care about
240 * escaping or anything.
241 *
242 * DON'T USE THIS FOR NEW CODE ANYMORE! */
243
244 l = strlen(s);
245 if (l < 2)
246 return strdup(s);
247
248 if (strchr(quotes, s[0]) && s[l-1] == s[0])
249 return strndup(s+1, l-2);
250
251 return strdup(s);
252 }
253
254 static char *tag_to_udev_node(const char *tagvalue, const char *by) {
255 _cleanup_free_ char *t = NULL, *u = NULL;
256 size_t enc_len;
257
258 u = unquote(tagvalue, QUOTES);
259 if (!u)
260 return NULL;
261
262 enc_len = strlen(u) * 4 + 1;
263 t = new(char, enc_len);
264 if (!t)
265 return NULL;
266
267 if (encode_devnode_name(u, t, enc_len) < 0)
268 return NULL;
269
270 return strjoin("/dev/disk/by-", by, "/", t);
271 }
272
273 char *fstab_node_to_udev_node(const char *p) {
274 assert(p);
275
276 if (startswith(p, "LABEL="))
277 return tag_to_udev_node(p+6, "label");
278
279 if (startswith(p, "UUID="))
280 return tag_to_udev_node(p+5, "uuid");
281
282 if (startswith(p, "PARTUUID="))
283 return tag_to_udev_node(p+9, "partuuid");
284
285 if (startswith(p, "PARTLABEL="))
286 return tag_to_udev_node(p+10, "partlabel");
287
288 return strdup(p);
289 }