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