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