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