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 304 : int fstab_filter_options(const char *opts, const char *names,
61 : const char **namefound, char **value, char **filtered) {
62 304 : const char *name, *n = NULL, *x;
63 304 : _cleanup_strv_free_ char **stor = NULL;
64 304 : _cleanup_free_ char *v = NULL, **strv = NULL;
65 :
66 304 : assert(names && *names);
67 :
68 304 : if (!opts)
69 2 : goto answer;
70 :
71 : /* If !value and !filtered, this function is not allowed to fail. */
72 :
73 302 : if (!filtered) {
74 : const char *word, *state;
75 : size_t l;
76 :
77 1212 : FOREACH_WORD_SEPARATOR(word, l, opts, ",", state)
78 2686 : NULSTR_FOREACH(name, names) {
79 1742 : if (l < strlen(name))
80 505 : continue;
81 1237 : if (!strneq(word, name, strlen(name)))
82 1152 : continue;
83 :
84 : /* we know that the string is NUL
85 : * terminated, so *x is valid */
86 85 : x = word + strlen(name);
87 85 : if (IN_SET(*x, '\0', '=', ',')) {
88 79 : n = name;
89 79 : if (value) {
90 5 : free(v);
91 5 : if (IN_SET(*x, '\0', ','))
92 1 : v = NULL;
93 : else {
94 4 : assert(*x == '=');
95 4 : x++;
96 4 : v = strndup(x, l - strlen(name) - 1);
97 4 : if (!v)
98 0 : return -ENOMEM;
99 : }
100 : }
101 : }
102 : }
103 : } else {
104 : char **t, **s;
105 :
106 34 : stor = strv_split(opts, ",");
107 34 : if (!stor)
108 0 : return -ENOMEM;
109 34 : strv = memdup(stor, sizeof(char*) * (strv_length(stor) + 1));
110 34 : if (!strv)
111 0 : return -ENOMEM;
112 :
113 98 : for (s = t = strv; *s; s++) {
114 144 : NULSTR_FOREACH(name, names) {
115 110 : x = startswith(*s, name);
116 110 : if (x && IN_SET(*x, '\0', '='))
117 30 : goto found;
118 : }
119 :
120 34 : *t = *s;
121 34 : t++;
122 34 : continue;
123 30 : found:
124 : /* Keep the last occurrence found */
125 30 : n = name;
126 30 : if (value) {
127 30 : free(v);
128 30 : if (*x == '\0')
129 11 : v = NULL;
130 : else {
131 19 : assert(*x == '=');
132 19 : x++;
133 19 : v = strdup(x);
134 19 : if (!v)
135 0 : return -ENOMEM;
136 : }
137 : }
138 : }
139 34 : *t = NULL;
140 : }
141 :
142 304 : answer:
143 304 : if (namefound)
144 91 : *namefound = n;
145 304 : if (filtered) {
146 : char *f;
147 :
148 35 : f = strv_join(strv, ",");
149 35 : if (!f)
150 0 : return -ENOMEM;
151 :
152 35 : *filtered = f;
153 : }
154 304 : if (value)
155 39 : *value = TAKE_PTR(v);
156 :
157 304 : 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 4 : int fstab_find_pri(const char *options, int *ret) {
190 4 : _cleanup_free_ char *opt = NULL;
191 : int r;
192 : unsigned pri;
193 :
194 4 : assert(ret);
195 :
196 4 : r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL);
197 4 : if (r < 0)
198 0 : return r;
199 4 : if (r == 0 || !opt)
200 1 : return 0;
201 :
202 3 : r = safe_atou(opt, &pri);
203 3 : if (r < 0)
204 0 : return r;
205 :
206 3 : if ((int) pri < 0)
207 0 : return -ERANGE;
208 :
209 3 : *ret = (int) pri;
210 3 : return 1;
211 : }
212 :
213 4 : static char *unquote(const char *s, const char* quotes) {
214 : size_t l;
215 4 : 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 4 : l = strlen(s);
224 4 : if (l < 2)
225 0 : return strdup(s);
226 :
227 4 : if (strchr(quotes, s[0]) && s[l-1] == s[0])
228 0 : return strndup(s+1, l-2);
229 :
230 4 : return strdup(s);
231 : }
232 :
233 4 : static char *tag_to_udev_node(const char *tagvalue, const char *by) {
234 4 : _cleanup_free_ char *t = NULL, *u = NULL;
235 : size_t enc_len;
236 :
237 4 : u = unquote(tagvalue, QUOTES);
238 4 : if (!u)
239 0 : return NULL;
240 :
241 4 : enc_len = strlen(u) * 4 + 1;
242 4 : t = new(char, enc_len);
243 4 : if (!t)
244 0 : return NULL;
245 :
246 4 : if (encode_devnode_name(u, t, enc_len) < 0)
247 0 : return NULL;
248 :
249 4 : return strjoin("/dev/disk/by-", by, "/", t);
250 : }
251 :
252 6 : char *fstab_node_to_udev_node(const char *p) {
253 6 : assert(p);
254 :
255 6 : if (startswith(p, "LABEL="))
256 1 : return tag_to_udev_node(p+6, "label");
257 :
258 5 : if (startswith(p, "UUID="))
259 1 : return tag_to_udev_node(p+5, "uuid");
260 :
261 4 : if (startswith(p, "PARTUUID="))
262 1 : return tag_to_udev_node(p+9, "partuuid");
263 :
264 3 : if (startswith(p, "PARTLABEL="))
265 1 : return tag_to_udev_node(p+10, "partlabel");
266 :
267 2 : return strdup(p);
268 : }
|