]>
Commit | Line | Data |
---|---|---|
6bd8b7a7 KZ |
1 | /* |
2 | * Copyright (C) 2009 Karel Zak <kzak@redhat.com> | |
3 | * | |
4 | * This file may be redistributed under the terms of the | |
5 | * GNU Lesser General Public License. | |
6 | */ | |
7 | ||
485a8bfa MY |
8 | #ifdef HAVE_SCANDIRAT |
9 | #ifndef __USE_GNU | |
10 | #define __USE_GNU | |
11 | #endif /* !__USE_GNU */ | |
12 | #endif /* HAVE_SCANDIRAT */ | |
13 | ||
6bd8b7a7 KZ |
14 | #include <ctype.h> |
15 | #include <limits.h> | |
9826a637 KZ |
16 | #include <dirent.h> |
17 | #include <fcntl.h> | |
6bd8b7a7 | 18 | |
9826a637 | 19 | #include "at.h" |
7043ced3 | 20 | #include "mangle.h" |
6bd8b7a7 | 21 | #include "mountP.h" |
9826a637 | 22 | #include "pathnames.h" |
b106d052 | 23 | #include "strutils.h" |
6bd8b7a7 | 24 | |
c3b0d5b3 KZ |
25 | static int next_number(char **s, int *num) |
26 | { | |
27 | char *end = NULL; | |
28 | ||
29 | assert(num); | |
30 | assert(s); | |
31 | ||
675de3f5 | 32 | *s = (char *) skip_blank(*s); |
c3b0d5b3 KZ |
33 | if (!**s) |
34 | return -1; | |
35 | *num = strtol(*s, &end, 10); | |
36 | if (end == NULL || *s == end) | |
37 | return -1; | |
38 | ||
39 | *s = end; | |
40 | ||
d58b3157 | 41 | /* valid end of number is a space or a terminator */ |
c3b0d5b3 KZ |
42 | if (*end == ' ' || *end == '\t' || *end == '\0') |
43 | return 0; | |
44 | return -1; | |
45 | } | |
46 | ||
6bd8b7a7 KZ |
47 | /* |
48 | * Parses one line from {fs,m}tab | |
49 | */ | |
68164f6c | 50 | static int mnt_parse_table_line(struct libmnt_fs *fs, char *s) |
6bd8b7a7 | 51 | { |
1e8c9369 KZ |
52 | int rc, n = 0, xrc; |
53 | char *src = NULL, *fstype = NULL, *optstr = NULL; | |
8f3f6383 | 54 | |
640fc1b8 KZ |
55 | rc = sscanf(s, UL_SCNsA" " /* (1) source */ |
56 | UL_SCNsA" " /* (2) target */ | |
57 | UL_SCNsA" " /* (3) FS type */ | |
58 | UL_SCNsA" " /* (4) options */ | |
59 | "%n", /* byte count */ | |
60 | ||
8f3f6383 KZ |
61 | &src, |
62 | &fs->target, | |
63 | &fstype, | |
64 | &optstr, | |
c3b0d5b3 | 65 | &n); |
1e8c9369 | 66 | xrc = rc; |
8f3f6383 | 67 | |
1e8c9369 | 68 | if (rc == 3 || rc == 4) { /* options are optional */ |
8f3f6383 KZ |
69 | unmangle_string(src); |
70 | unmangle_string(fs->target); | |
71 | unmangle_string(fstype); | |
1e8c9369 KZ |
72 | |
73 | if (optstr && *optstr) | |
74 | unmangle_string(optstr); | |
8f3f6383 | 75 | |
d58b3157 | 76 | /* note that __foo functions do not reallocate the string |
53d91134 | 77 | */ |
8f3f6383 | 78 | rc = __mnt_fs_set_source_ptr(fs, src); |
53d91134 KZ |
79 | if (!rc) { |
80 | src = NULL; | |
8f3f6383 | 81 | rc = __mnt_fs_set_fstype_ptr(fs, fstype); |
53d91134 KZ |
82 | if (!rc) |
83 | fstype = NULL; | |
84 | } | |
1e8c9369 | 85 | if (!rc && optstr) |
76a06ca4 KZ |
86 | rc = mnt_fs_set_options(fs, optstr); |
87 | free(optstr); | |
53d91134 | 88 | optstr = NULL; |
8f3f6383 | 89 | } else { |
83a78332 | 90 | DBG(TAB, ul_debug("tab parse error: [sscanf rc=%d]: '%s'", rc, s)); |
8f3f6383 | 91 | rc = -EINVAL; |
b2d0b74d | 92 | } |
6bd8b7a7 | 93 | |
1e8c9369 | 94 | if (rc) { |
53d91134 KZ |
95 | free(src); |
96 | free(fstype); | |
97 | free(optstr); | |
83a78332 | 98 | DBG(TAB, ul_debug("tab parse error: [set vars, rc=%d]\n", rc)); |
c3b0d5b3 | 99 | return rc; /* error */ |
1e8c9369 | 100 | } |
c3b0d5b3 KZ |
101 | |
102 | fs->passno = fs->freq = 0; | |
1e8c9369 KZ |
103 | |
104 | if (xrc == 4 && n) | |
675de3f5 | 105 | s = (char *) skip_blank(s + n); |
1e8c9369 | 106 | if (xrc == 4 && *s) { |
c3b0d5b3 | 107 | if (next_number(&s, &fs->freq) != 0) { |
dd369652 | 108 | if (*s) { |
83a78332 | 109 | DBG(TAB, ul_debug("tab parse error: [freq]")); |
c3b0d5b3 | 110 | rc = -EINVAL; |
dd369652 KZ |
111 | } |
112 | } else if (next_number(&s, &fs->passno) != 0 && *s) { | |
83a78332 | 113 | DBG(TAB, ul_debug("tab parse error: [passno]")); |
c3b0d5b3 | 114 | rc = -EINVAL; |
dd369652 | 115 | } |
c3b0d5b3 KZ |
116 | } |
117 | ||
b2d0b74d | 118 | return rc; |
6bd8b7a7 KZ |
119 | } |
120 | ||
121 | /* | |
d58b3157 | 122 | * Parses one line from a mountinfo file |
6bd8b7a7 | 123 | */ |
68164f6c | 124 | static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, char *s) |
6bd8b7a7 | 125 | { |
fb9d90d5 | 126 | int rc, end = 0; |
efe73c3e | 127 | unsigned int maj, min; |
53d91134 | 128 | char *fstype = NULL, *src = NULL, *p; |
8f3f6383 | 129 | |
ea97feab KZ |
130 | rc = sscanf(s, "%d " /* (1) id */ |
131 | "%d " /* (2) parent */ | |
8f3f6383 | 132 | "%u:%u " /* (3) maj:min */ |
640fc1b8 KZ |
133 | UL_SCNsA" " /* (4) mountroot */ |
134 | UL_SCNsA" " /* (5) target */ | |
135 | UL_SCNsA /* (6) vfs options (fs-independent) */ | |
fb9d90d5 | 136 | "%n", /* number of read bytes */ |
8f3f6383 KZ |
137 | |
138 | &fs->id, | |
139 | &fs->parent, | |
140 | &maj, &min, | |
141 | &fs->root, | |
142 | &fs->target, | |
143 | &fs->vfs_optstr, | |
fb9d90d5 KZ |
144 | &end); |
145 | ||
146 | if (rc >= 7 && end > 0) | |
147 | s += end; | |
148 | ||
149 | /* (7) optional fields, terminated by " - " */ | |
150 | p = strstr(s, " - "); | |
151 | if (!p) { | |
83a78332 | 152 | DBG(TAB, ul_debug("mountinfo parse error: separator not found")); |
fb9d90d5 KZ |
153 | return -EINVAL; |
154 | } | |
e47a1931 OO |
155 | if (p > s + 1) |
156 | fs->opt_fields = strndup(s + 1, p - s - 1); | |
fb9d90d5 KZ |
157 | s = p + 3; |
158 | ||
640fc1b8 KZ |
159 | rc += sscanf(s, UL_SCNsA" " /* (8) FS type */ |
160 | UL_SCNsA" " /* (9) source */ | |
161 | UL_SCNsA, /* (10) fs options (fs specific) */ | |
fb9d90d5 | 162 | |
8f3f6383 KZ |
163 | &fstype, |
164 | &src, | |
165 | &fs->fs_optstr); | |
166 | ||
fb9d90d5 | 167 | if (rc >= 10) { |
5980048e KZ |
168 | size_t sz; |
169 | ||
309139c7 | 170 | fs->flags |= MNT_FS_KERNEL; |
8f3f6383 | 171 | fs->devno = makedev(maj, min); |
efe73c3e | 172 | |
5980048e KZ |
173 | /* remove "(deleted)" suffix */ |
174 | sz = strlen(fs->target); | |
175 | if (sz > PATH_DELETED_SUFFIX_SZ) { | |
176 | char *p = fs->target + (sz - PATH_DELETED_SUFFIX_SZ); | |
177 | ||
178 | if (strcmp(p, PATH_DELETED_SUFFIX) == 0) | |
179 | *p = '\0'; | |
180 | } | |
181 | ||
8f3f6383 KZ |
182 | unmangle_string(fs->root); |
183 | unmangle_string(fs->target); | |
184 | unmangle_string(fs->vfs_optstr); | |
185 | unmangle_string(fstype); | |
5af0769d | 186 | unmangle_string(src); |
d0ce7c07 | 187 | unmangle_string(fs->fs_optstr); |
b2d0b74d | 188 | |
8f3f6383 | 189 | rc = __mnt_fs_set_fstype_ptr(fs, fstype); |
53d91134 KZ |
190 | if (!rc) { |
191 | fstype = NULL; | |
8f3f6383 | 192 | rc = __mnt_fs_set_source_ptr(fs, src); |
53d91134 KZ |
193 | if (!rc) |
194 | src = NULL; | |
195 | } | |
f2b3a3a3 | 196 | |
d58b3157 | 197 | /* merge VFS and FS options to one string */ |
f2b3a3a3 KZ |
198 | fs->optstr = mnt_fs_strdup_options(fs); |
199 | if (!fs->optstr) | |
200 | rc = -ENOMEM; | |
8f3f6383 | 201 | } else { |
53d91134 KZ |
202 | free(fstype); |
203 | free(src); | |
83a78332 | 204 | DBG(TAB, ul_debug( |
dd369652 | 205 | "mountinfo parse error [sscanf rc=%d]: '%s'", rc, s)); |
8f3f6383 | 206 | rc = -EINVAL; |
be1a5180 | 207 | } |
b2d0b74d | 208 | return rc; |
6bd8b7a7 KZ |
209 | } |
210 | ||
dd369652 KZ |
211 | /* |
212 | * Parses one line from utab file | |
213 | */ | |
68164f6c | 214 | static int mnt_parse_utab_line(struct libmnt_fs *fs, const char *s) |
dd369652 KZ |
215 | { |
216 | const char *p = s; | |
217 | ||
218 | assert(fs); | |
219 | assert(s); | |
220 | assert(!fs->source); | |
221 | assert(!fs->target); | |
222 | ||
223 | while (p && *p) { | |
5ac6a133 KZ |
224 | char *end = NULL; |
225 | ||
dd369652 KZ |
226 | while (*p == ' ') p++; |
227 | if (!*p) | |
228 | break; | |
229 | ||
230 | if (!fs->source && !strncmp(p, "SRC=", 4)) { | |
5ac6a133 | 231 | char *v = unmangle(p + 4, &end); |
dd369652 KZ |
232 | if (!v) |
233 | goto enomem; | |
5af0769d | 234 | __mnt_fs_set_source_ptr(fs, v); |
dd369652 KZ |
235 | |
236 | } else if (!fs->target && !strncmp(p, "TARGET=", 7)) { | |
5ac6a133 | 237 | fs->target = unmangle(p + 7, &end); |
dd369652 KZ |
238 | if (!fs->target) |
239 | goto enomem; | |
240 | ||
241 | } else if (!fs->root && !strncmp(p, "ROOT=", 5)) { | |
5ac6a133 | 242 | fs->root = unmangle(p + 5, &end); |
dd369652 KZ |
243 | if (!fs->root) |
244 | goto enomem; | |
245 | ||
246 | } else if (!fs->bindsrc && !strncmp(p, "BINDSRC=", 8)) { | |
5ac6a133 | 247 | fs->bindsrc = unmangle(p + 8, &end); |
dd369652 KZ |
248 | if (!fs->bindsrc) |
249 | goto enomem; | |
250 | ||
76a06ca4 KZ |
251 | } else if (!fs->user_optstr && !strncmp(p, "OPTS=", 5)) { |
252 | fs->user_optstr = unmangle(p + 5, &end); | |
253 | if (!fs->user_optstr) | |
dd369652 | 254 | goto enomem; |
76a06ca4 KZ |
255 | |
256 | } else if (!fs->attrs && !strncmp(p, "ATTRS=", 6)) { | |
257 | fs->attrs = unmangle(p + 6, &end); | |
258 | if (!fs->attrs) | |
259 | goto enomem; | |
260 | ||
dd369652 KZ |
261 | } else { |
262 | /* unknown variable */ | |
263 | while (*p && *p != ' ') p++; | |
264 | } | |
5ac6a133 KZ |
265 | if (end) |
266 | p = end; | |
dd369652 KZ |
267 | } |
268 | ||
269 | return 0; | |
270 | enomem: | |
83a78332 | 271 | DBG(TAB, ul_debug("utab parse error: ENOMEM")); |
dd369652 KZ |
272 | return -ENOMEM; |
273 | } | |
274 | ||
ce4dd666 KZ |
275 | /* |
276 | * Parses one line from /proc/swaps | |
277 | */ | |
278 | static int mnt_parse_swaps_line(struct libmnt_fs *fs, char *s) | |
279 | { | |
280 | uintmax_t fsz, usz; | |
281 | int rc; | |
282 | char *src = NULL; | |
283 | ||
284 | rc = sscanf(s, UL_SCNsA" " /* (1) source */ | |
285 | UL_SCNsA" " /* (2) type */ | |
ea97feab KZ |
286 | "%ju" /* (3) size */ |
287 | "%ju" /* (4) used */ | |
ce4dd666 KZ |
288 | "%d", /* priority */ |
289 | ||
290 | &src, | |
291 | &fs->swaptype, | |
292 | &fsz, | |
293 | &usz, | |
294 | &fs->priority); | |
295 | ||
296 | if (rc == 5) { | |
297 | size_t sz; | |
298 | ||
299 | fs->size = fsz; | |
300 | fs->usedsize = usz; | |
301 | ||
302 | unmangle_string(src); | |
303 | ||
304 | /* remove "(deleted)" suffix */ | |
305 | sz = strlen(src); | |
306 | if (sz > PATH_DELETED_SUFFIX_SZ) { | |
307 | char *p = src + (sz - PATH_DELETED_SUFFIX_SZ); | |
308 | if (strcmp(p, PATH_DELETED_SUFFIX) == 0) | |
309 | *p = '\0'; | |
310 | } | |
311 | ||
312 | rc = mnt_fs_set_source(fs, src); | |
313 | if (!rc) | |
314 | mnt_fs_set_fstype(fs, "swap"); | |
315 | free(src); | |
316 | } else { | |
83a78332 | 317 | DBG(TAB, ul_debug("tab parse error: [sscanf rc=%d]: '%s'", rc, s)); |
ce4dd666 KZ |
318 | rc = -EINVAL; |
319 | } | |
320 | ||
321 | return rc; | |
322 | } | |
323 | ||
324 | ||
6bd8b7a7 KZ |
325 | /* |
326 | * Returns {m,fs}tab or mountinfo file format (MNT_FMT_*) | |
327 | * | |
d58b3157 OO |
328 | * Note that we aren't trying to guess the utab file format, because this file |
329 | * always has to be parsed by private libmount routines with an explicitly defined | |
dd369652 KZ |
330 | * format. |
331 | * | |
332 | * mountinfo: "<number> <number> ... " | |
6bd8b7a7 | 333 | */ |
68164f6c | 334 | static int guess_table_format(char *line) |
6bd8b7a7 | 335 | { |
8f3f6383 | 336 | unsigned int a, b; |
6bd8b7a7 | 337 | |
83a78332 | 338 | DBG(TAB, ul_debug("trying to guess table type")); |
ce4dd666 | 339 | |
dd369652 KZ |
340 | if (sscanf(line, "%u %u", &a, &b) == 2) |
341 | return MNT_FMT_MOUNTINFO; | |
581a4ad9 | 342 | |
ce4dd666 KZ |
343 | if (strncmp(line, "Filename\t", 9) == 0) |
344 | return MNT_FMT_SWAPS; | |
345 | ||
581a4ad9 | 346 | return MNT_FMT_FSTAB; /* fstab, mtab or /proc/mounts */ |
6bd8b7a7 KZ |
347 | } |
348 | ||
cb90e24e OO |
349 | static int is_comment_line(char *line) |
350 | { | |
675de3f5 | 351 | char *p = (char *) skip_blank(line); |
cb90e24e OO |
352 | |
353 | if (p && (*p == '#' || *p == '\n')) | |
354 | return 1; | |
355 | return 0; | |
356 | } | |
357 | ||
358 | /* returns 1 if the last line in the @str is blank */ | |
359 | static int is_terminated_by_blank(const char *str) | |
360 | { | |
361 | size_t sz = str ? strlen(str) : 0; | |
362 | const char *p = sz ? str + (sz - 1) : NULL; | |
363 | ||
364 | if (!sz || !p || *p != '\n') | |
365 | return 0; /* empty or not terminated by '\n' */ | |
366 | if (p == str) | |
367 | return 1; /* only '\n' */ | |
368 | p--; | |
369 | while (p >= str && (*p == ' ' || *p == '\t')) | |
370 | p--; | |
371 | return *p == '\n' ? 1 : 0; | |
372 | } | |
373 | ||
374 | /* | |
375 | * Reads the next line from the file. | |
376 | * | |
d58b3157 OO |
377 | * Returns 0 if the line is a comment |
378 | * 1 if the line is not a comment | |
cb90e24e OO |
379 | * <0 on error |
380 | */ | |
381 | static int next_comment_line(char *buf, size_t bufsz, | |
382 | FILE *f, char **last, int *nlines) | |
383 | { | |
384 | if (fgets(buf, bufsz, f) == NULL) | |
385 | return feof(f) ? 1 : -EINVAL; | |
386 | ||
387 | ++*nlines; | |
388 | *last = strchr(buf, '\n'); | |
389 | ||
390 | return is_comment_line(buf) ? 0 : 1; | |
391 | } | |
392 | ||
393 | static int append_comment(struct libmnt_table *tb, | |
394 | struct libmnt_fs *fs, | |
395 | const char *comm, | |
396 | int eof) | |
397 | { | |
398 | int rc, intro = mnt_table_get_nents(tb) == 0; | |
399 | ||
400 | if (intro && is_terminated_by_blank(mnt_table_get_intro_comment(tb))) | |
401 | intro = 0; | |
402 | ||
83a78332 | 403 | DBG(TAB, ul_debugobj(tb, "appending %s comment", |
cb90e24e | 404 | intro ? "intro" : |
d58b3157 | 405 | eof ? "trailing" : "fs")); |
cb90e24e OO |
406 | if (intro) |
407 | rc = mnt_table_append_intro_comment(tb, comm); | |
408 | else if (eof) { | |
3035ba93 | 409 | rc = mnt_table_set_trailing_comment(tb, |
cb90e24e OO |
410 | mnt_fs_get_comment(fs)); |
411 | if (!rc) | |
3035ba93 | 412 | rc = mnt_table_append_trailing_comment(tb, comm); |
cb90e24e OO |
413 | if (!rc) |
414 | rc = mnt_fs_set_comment(fs, NULL); | |
415 | } else | |
416 | rc = mnt_fs_append_comment(fs, comm); | |
417 | return rc; | |
418 | } | |
419 | ||
6bd8b7a7 KZ |
420 | /* |
421 | * Read and parse the next line from {fs,m}tab or mountinfo | |
422 | */ | |
cb90e24e OO |
423 | static int mnt_table_parse_next(struct libmnt_table *tb, FILE *f, |
424 | struct libmnt_fs *fs, | |
9ed7507c | 425 | const char *filename, int *nlines) |
6bd8b7a7 KZ |
426 | { |
427 | char buf[BUFSIZ]; | |
428 | char *s; | |
7104bedb | 429 | int rc; |
6bd8b7a7 KZ |
430 | |
431 | assert(tb); | |
432 | assert(f); | |
433 | assert(fs); | |
434 | ||
435 | /* read the next non-blank non-comment line */ | |
ce4dd666 | 436 | next_line: |
6bd8b7a7 KZ |
437 | do { |
438 | if (fgets(buf, sizeof(buf), f) == NULL) | |
d8a30749 | 439 | return -EINVAL; |
911238af | 440 | ++*nlines; |
913e43b8 | 441 | s = strchr (buf, '\n'); |
6bd8b7a7 | 442 | if (!s) { |
d58b3157 | 443 | /* Missing final newline? Otherwise an extremely */ |
6bd8b7a7 KZ |
444 | /* long line - assume file was corrupted */ |
445 | if (feof(f)) { | |
83a78332 | 446 | DBG(TAB, ul_debugobj(tb, |
3f31a959 | 447 | "%s: no final newline", filename)); |
913e43b8 | 448 | s = strchr (buf, '\0'); |
6bd8b7a7 | 449 | } else { |
83a78332 | 450 | DBG(TAB, ul_debugobj(tb, |
3f31a959 | 451 | "%s:%d: missing newline at line", |
9ed7507c | 452 | filename, *nlines)); |
6bd8b7a7 KZ |
453 | goto err; |
454 | } | |
455 | } | |
cb90e24e OO |
456 | |
457 | /* comments parser */ | |
458 | if (tb->comms | |
459 | && (tb->fmt == MNT_FMT_GUESS || tb->fmt == MNT_FMT_FSTAB) | |
460 | && is_comment_line(buf)) { | |
461 | do { | |
462 | rc = append_comment(tb, fs, buf, feof(f)); | |
463 | if (!rc) | |
464 | rc = next_comment_line(buf, | |
465 | sizeof(buf), | |
466 | f, &s, nlines); | |
467 | } while (rc == 0); | |
468 | ||
469 | if (rc == 1 && feof(f)) | |
470 | rc = append_comment(tb, fs, NULL, 1); | |
471 | if (rc < 0) | |
472 | return rc; | |
473 | ||
474 | } | |
475 | ||
6bd8b7a7 KZ |
476 | *s = '\0'; |
477 | if (--s >= buf && *s == '\r') | |
478 | *s = '\0'; | |
675de3f5 | 479 | s = (char *) skip_blank(buf); |
6bd8b7a7 KZ |
480 | } while (*s == '\0' || *s == '#'); |
481 | ||
ce4dd666 | 482 | if (tb->fmt == MNT_FMT_GUESS) { |
68164f6c | 483 | tb->fmt = guess_table_format(s); |
ce4dd666 KZ |
484 | if (tb->fmt == MNT_FMT_SWAPS) |
485 | goto next_line; /* skip swap header */ | |
486 | } | |
6bd8b7a7 | 487 | |
7104bedb KZ |
488 | switch (tb->fmt) { |
489 | case MNT_FMT_FSTAB: | |
490 | rc = mnt_parse_table_line(fs, s); | |
491 | break; | |
492 | case MNT_FMT_MOUNTINFO: | |
493 | rc = mnt_parse_mountinfo_line(fs, s); | |
494 | break; | |
495 | case MNT_FMT_UTAB: | |
496 | rc = mnt_parse_utab_line(fs, s); | |
497 | break; | |
ce4dd666 KZ |
498 | case MNT_FMT_SWAPS: |
499 | if (strncmp(s, "Filename\t", 9) == 0) | |
500 | goto next_line; /* skip swap header */ | |
501 | rc = mnt_parse_swaps_line(fs, s); | |
502 | break; | |
7104bedb KZ |
503 | default: |
504 | rc = -1; /* unknown format */ | |
505 | break; | |
6bd8b7a7 KZ |
506 | } |
507 | ||
7104bedb KZ |
508 | if (rc == 0) |
509 | return 0; | |
6bd8b7a7 | 510 | err: |
83a78332 | 511 | DBG(TAB, ul_debugobj(tb, "%s:%d: %s parse error", filename, *nlines, |
dd369652 | 512 | tb->fmt == MNT_FMT_MOUNTINFO ? "mountinfo" : |
ce4dd666 | 513 | tb->fmt == MNT_FMT_SWAPS ? "swaps" : |
581a4ad9 | 514 | tb->fmt == MNT_FMT_FSTAB ? "tab" : "utab")); |
9fd75d76 | 515 | |
c3b0d5b3 | 516 | /* by default all errors are recoverable, otherwise behavior depends on |
d58b3157 | 517 | * the errcb() function. See mnt_table_set_parser_errcb(). |
c3b0d5b3 KZ |
518 | */ |
519 | return tb->errcb ? tb->errcb(tb, filename, *nlines) : 1; | |
6bd8b7a7 KZ |
520 | } |
521 | ||
f7f29b56 KZ |
522 | static pid_t path_to_tid(const char *filename) |
523 | { | |
524 | char *path = mnt_resolve_path(filename, NULL); | |
525 | char *p, *end = NULL; | |
526 | pid_t tid = 0; | |
527 | ||
528 | if (!path) | |
529 | goto done; | |
530 | p = strrchr(path, '/'); | |
531 | if (!p) | |
532 | goto done; | |
533 | *p = '\0'; | |
534 | p = strrchr(path, '/'); | |
535 | if (!p) | |
536 | goto done; | |
537 | p++; | |
538 | ||
539 | errno = 0; | |
540 | tid = strtol(p, &end, 10); | |
541 | if (errno || p == end || (end && *end)) { | |
542 | tid = 0; | |
543 | goto done; | |
544 | } | |
83a78332 | 545 | DBG(TAB, ul_debug("TID for %s is %d", filename, tid)); |
f7f29b56 KZ |
546 | done: |
547 | free(path); | |
548 | return tid; | |
549 | } | |
550 | ||
3da7f698 KZ |
551 | static int kernel_fs_postparse(struct libmnt_table *tb, |
552 | struct libmnt_fs *fs, pid_t *tid, | |
553 | const char *filename) | |
554 | { | |
555 | int rc = 0; | |
556 | const char *src = mnt_fs_get_srcpath(fs); | |
557 | ||
d58b3157 | 558 | /* This is a filesystem description from /proc, so we're in some process |
3da7f698 KZ |
559 | * namespace. Let's remember the process PID. |
560 | */ | |
561 | if (filename && *tid == -1) | |
562 | *tid = path_to_tid(filename); | |
563 | ||
564 | fs->tid = *tid; | |
565 | ||
566 | /* | |
567 | * Convert obscure /dev/root to something more usable | |
568 | */ | |
569 | if (src && strcmp(src, "/dev/root") == 0) { | |
570 | char *spec = mnt_get_kernel_cmdline_option("root="); | |
571 | char *real = NULL; | |
572 | ||
83a78332 | 573 | DBG(TAB, ul_debugobj(tb, "root FS: %s", spec)); |
3da7f698 KZ |
574 | if (spec) |
575 | real = mnt_resolve_spec(spec, tb->cache); | |
576 | if (real) { | |
83a78332 | 577 | DBG(TAB, ul_debugobj(tb, "canonical root FS: %s", real)); |
3da7f698 KZ |
578 | rc = mnt_fs_set_source(fs, real); |
579 | if (!tb->cache) | |
580 | free(real); | |
581 | } | |
582 | free(spec); | |
583 | } | |
584 | ||
585 | return rc; | |
586 | } | |
587 | ||
6bd8b7a7 | 588 | /** |
68164f6c | 589 | * mnt_table_parse_stream: |
6bd8b7a7 | 590 | * @tb: tab pointer |
45d6713e KZ |
591 | * @f: file stream |
592 | * @filename: filename used for debug and error messages | |
9fd75d76 | 593 | * |
d8a30749 | 594 | * Returns: 0 on success, negative number in case of error. |
6bd8b7a7 | 595 | */ |
68164f6c | 596 | int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename) |
6bd8b7a7 | 597 | { |
911238af | 598 | int nlines = 0; |
d8a30749 | 599 | int rc = -1; |
309139c7 | 600 | int flags = 0; |
f7f29b56 | 601 | pid_t tid = -1; |
6bd8b7a7 KZ |
602 | |
603 | assert(tb); | |
45d6713e | 604 | assert(f); |
9ed7507c | 605 | assert(filename); |
6bd8b7a7 | 606 | |
83a78332 | 607 | DBG(TAB, ul_debugobj(tb, "%s: start parsing [entries=%d, filter=%s]", |
9be1607f KZ |
608 | filename, mnt_table_get_nents(tb), |
609 | tb->fltrcb ? "yes" : "not")); | |
9ed7507c | 610 | |
309139c7 | 611 | /* necessary for /proc/mounts only, the /proc/self/mountinfo |
6ad929bb | 612 | * parser sets the flag properly |
309139c7 KZ |
613 | */ |
614 | if (filename && strcmp(filename, _PATH_PROC_MOUNTS) == 0) | |
615 | flags = MNT_FS_KERNEL; | |
616 | ||
6bd8b7a7 | 617 | while (!feof(f)) { |
68164f6c | 618 | struct libmnt_fs *fs = mnt_new_fs(); |
fbb3eb85 | 619 | |
6bd8b7a7 | 620 | if (!fs) |
d8a30749 | 621 | goto err; |
6bd8b7a7 | 622 | |
68164f6c | 623 | rc = mnt_table_parse_next(tb, f, fs, filename, &nlines); |
4709c9e6 KZ |
624 | |
625 | if (!rc && tb->fltrcb && tb->fltrcb(fs, tb->fltrcb_data)) | |
626 | rc = 1; /* filtered out by callback... */ | |
627 | ||
309139c7 | 628 | if (!rc) { |
68164f6c | 629 | rc = mnt_table_add_fs(tb, fs); |
309139c7 | 630 | fs->flags |= flags; |
3da7f698 KZ |
631 | |
632 | if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO) | |
633 | rc = kernel_fs_postparse(tb, fs, &tid, filename); | |
309139c7 | 634 | } |
26d0c0ae KZ |
635 | mnt_unref_fs(fs); |
636 | ||
6bd8b7a7 | 637 | if (rc) { |
fbb3eb85 KZ |
638 | if (rc == 1) |
639 | continue; /* recoverable error */ | |
640 | if (feof(f)) | |
641 | break; | |
d8a30749 | 642 | goto err; /* fatal error */ |
6bd8b7a7 KZ |
643 | } |
644 | } | |
645 | ||
83a78332 | 646 | DBG(TAB, ul_debugobj(tb, "%s: stop parsing (%d entries)", |
0983b5f7 | 647 | filename, mnt_table_get_nents(tb))); |
6bd8b7a7 | 648 | return 0; |
d8a30749 | 649 | err: |
83a78332 | 650 | DBG(TAB, ul_debugobj(tb, "%s: parse error (rc=%d)", filename, rc)); |
d8a30749 | 651 | return rc; |
6bd8b7a7 KZ |
652 | } |
653 | ||
654 | /** | |
68164f6c | 655 | * mnt_table_parse_file: |
45d6713e KZ |
656 | * @tb: tab pointer |
657 | * @filename: file | |
658 | * | |
d58b3157 | 659 | * Parses the whole table (e.g. /etc/mtab) and appends new records to the @tab. |
45d6713e | 660 | * |
45d6713e | 661 | * The libmount parser ignores broken (syntax error) lines, these lines are |
d58b3157 | 662 | * reported to the caller by the errcb() function (see mnt_table_set_parser_errcb()). |
45d6713e | 663 | * |
d8a30749 | 664 | * Returns: 0 on success, negative number in case of error. |
45d6713e | 665 | */ |
68164f6c | 666 | int mnt_table_parse_file(struct libmnt_table *tb, const char *filename) |
45d6713e KZ |
667 | { |
668 | FILE *f; | |
d8a30749 | 669 | int rc; |
45d6713e KZ |
670 | |
671 | assert(tb); | |
672 | assert(filename); | |
673 | ||
674 | if (!filename || !tb) | |
d8a30749 | 675 | return -EINVAL; |
45d6713e | 676 | |
1eb8539d | 677 | f = fopen(filename, "r" UL_CLOEXECSTR); |
45d6713e | 678 | if (f) { |
68164f6c | 679 | rc = mnt_table_parse_stream(tb, f, filename); |
45d6713e | 680 | fclose(f); |
d8a30749 KZ |
681 | } else |
682 | return -errno; | |
683 | ||
45d6713e KZ |
684 | return rc; |
685 | } | |
686 | ||
9deeef8e MY |
687 | static int mnt_table_parse_dir_filter(const struct dirent *d) |
688 | { | |
689 | size_t namesz; | |
690 | ||
691 | #ifdef _DIRENT_HAVE_D_TYPE | |
692 | if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG && | |
693 | d->d_type != DT_LNK) | |
694 | return 0; | |
695 | #endif | |
696 | if (*d->d_name == '.') | |
697 | return 0; | |
698 | ||
699 | #define MNT_MNTTABDIR_EXTSIZ (sizeof(MNT_MNTTABDIR_EXT) - 1) | |
700 | ||
701 | namesz = strlen(d->d_name); | |
702 | if (!namesz || namesz < MNT_MNTTABDIR_EXTSIZ + 1 || | |
703 | strcmp(d->d_name + (namesz - MNT_MNTTABDIR_EXTSIZ), | |
704 | MNT_MNTTABDIR_EXT)) | |
705 | return 0; | |
706 | ||
707 | /* Accept this */ | |
708 | return 1; | |
709 | } | |
710 | ||
485a8bfa | 711 | #ifdef HAVE_SCANDIRAT |
52f83628 | 712 | static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) |
485a8bfa MY |
713 | { |
714 | int n = 0, i; | |
715 | int dd; | |
716 | struct dirent **namelist = NULL; | |
717 | ||
718 | dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY); | |
719 | if (dd < 0) | |
720 | return -errno; | |
9deeef8e MY |
721 | |
722 | n = scandirat(dd, ".", &namelist, mnt_table_parse_dir_filter, versionsort); | |
485a8bfa MY |
723 | if (n <= 0) { |
724 | close(dd); | |
725 | return 0; | |
726 | } | |
727 | ||
728 | for (i = 0; i < n; i++) { | |
729 | struct dirent *d = namelist[i]; | |
730 | struct stat st; | |
485a8bfa MY |
731 | FILE *f; |
732 | ||
485a8bfa MY |
733 | if (fstat_at(dd, ".", d->d_name, &st, 0) || |
734 | !S_ISREG(st.st_mode)) | |
735 | continue; | |
736 | ||
1eb8539d | 737 | f = fopen_at(dd, ".", d->d_name, O_RDONLY|O_CLOEXEC, "r" UL_CLOEXECSTR); |
485a8bfa MY |
738 | if (f) { |
739 | mnt_table_parse_stream(tb, f, d->d_name); | |
740 | fclose(f); | |
741 | } | |
742 | } | |
743 | ||
744 | for (i = 0; i < n; i++) | |
745 | free(namelist[i]); | |
746 | free(namelist); | |
747 | close(dd); | |
748 | return 0; | |
749 | } | |
750 | #else | |
52f83628 | 751 | static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) |
70bf97ae | 752 | { |
b28890b0 | 753 | int n = 0, i, r = 0; |
70bf97ae KZ |
754 | DIR *dir = NULL; |
755 | struct dirent **namelist = NULL; | |
756 | ||
9deeef8e | 757 | n = scandir(dirname, &namelist, mnt_table_parse_dir_filter, versionsort); |
70bf97ae KZ |
758 | if (n <= 0) |
759 | return 0; | |
760 | ||
d58b3157 | 761 | /* let's use "at" functions rather than playing crazy games with paths... */ |
70bf97ae | 762 | dir = opendir(dirname); |
b28890b0 MY |
763 | if (!dir) { |
764 | r = -errno; | |
765 | goto out; | |
766 | } | |
70bf97ae KZ |
767 | |
768 | for (i = 0; i < n; i++) { | |
769 | struct dirent *d = namelist[i]; | |
770 | struct stat st; | |
70bf97ae KZ |
771 | FILE *f; |
772 | ||
70bf97ae KZ |
773 | if (fstat_at(dirfd(dir), _PATH_MNTTAB_DIR, d->d_name, &st, 0) || |
774 | !S_ISREG(st.st_mode)) | |
775 | continue; | |
776 | ||
1eb8539d KZ |
777 | f = fopen_at(dirfd(dir), _PATH_MNTTAB_DIR, d->d_name, |
778 | O_RDONLY|O_CLOEXEC, "r" UL_CLOEXECSTR); | |
70bf97ae | 779 | if (f) { |
68164f6c | 780 | mnt_table_parse_stream(tb, f, d->d_name); |
70bf97ae KZ |
781 | fclose(f); |
782 | } | |
783 | } | |
784 | ||
b28890b0 | 785 | out: |
70bf97ae KZ |
786 | for (i = 0; i < n; i++) |
787 | free(namelist[i]); | |
788 | free(namelist); | |
789 | if (dir) | |
790 | closedir(dir); | |
b28890b0 | 791 | return r; |
70bf97ae | 792 | } |
485a8bfa | 793 | #endif |
70bf97ae | 794 | |
52f83628 KZ |
795 | /** |
796 | * mnt_table_parse_dir: | |
797 | * @tb: mount table | |
798 | * @dirname: directory | |
799 | * | |
800 | * The directory: | |
801 | * - files are sorted by strverscmp(3) | |
d58b3157 | 802 | * - files that start with "." are ignored (e.g. ".10foo.fstab") |
52f83628 KZ |
803 | * - files without the ".fstab" extension are ignored |
804 | * | |
805 | * Returns: 0 on success or negative number in case of error. | |
806 | */ | |
807 | int mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) | |
808 | { | |
809 | return __mnt_table_parse_dir(tb, dirname); | |
810 | } | |
811 | ||
68164f6c | 812 | struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt) |
dd369652 | 813 | { |
68164f6c | 814 | struct libmnt_table *tb; |
dd369652 KZ |
815 | struct stat st; |
816 | ||
817 | assert(filename); | |
dd369652 KZ |
818 | if (!filename) |
819 | return NULL; | |
f84fa6f7 | 820 | if (stat(filename, &st)) |
dd369652 | 821 | return NULL; |
68164f6c | 822 | tb = mnt_new_table(); |
dd369652 KZ |
823 | if (tb) { |
824 | tb->fmt = fmt; | |
68164f6c | 825 | if (mnt_table_parse_file(tb, filename) != 0) { |
c9f1585e | 826 | mnt_unref_table(tb); |
dd369652 KZ |
827 | tb = NULL; |
828 | } | |
829 | } | |
830 | return tb; | |
831 | } | |
70bf97ae | 832 | |
45d6713e | 833 | /** |
68164f6c | 834 | * mnt_new_table_from_file: |
6bd8b7a7 KZ |
835 | * @filename: /etc/{m,fs}tab or /proc/self/mountinfo path |
836 | * | |
68164f6c | 837 | * Same as mnt_new_table() + mnt_table_parse_file(). Use this function for private |
d58b3157 | 838 | * files only. This function does not allow using the error callback, so you |
9826a637 KZ |
839 | * cannot provide any feedback to end-users about broken records in files (e.g. |
840 | * fstab). | |
6bd8b7a7 | 841 | * |
192c6aad | 842 | * Returns: newly allocated tab on success and NULL in case of error. |
6bd8b7a7 | 843 | */ |
68164f6c | 844 | struct libmnt_table *mnt_new_table_from_file(const char *filename) |
6bd8b7a7 | 845 | { |
4569bbea | 846 | assert(filename); |
68164f6c | 847 | return __mnt_new_table_from_file(filename, MNT_FMT_GUESS); |
6bd8b7a7 KZ |
848 | } |
849 | ||
70bf97ae | 850 | /** |
68164f6c | 851 | * mnt_new_table_from_dir |
52f83628 | 852 | * @dirname: directory with *.fstab files |
70bf97ae KZ |
853 | * |
854 | * Returns: newly allocated tab on success and NULL in case of error. | |
855 | */ | |
68164f6c | 856 | struct libmnt_table *mnt_new_table_from_dir(const char *dirname) |
70bf97ae | 857 | { |
68164f6c | 858 | struct libmnt_table *tb; |
70bf97ae KZ |
859 | |
860 | assert(dirname); | |
70bf97ae KZ |
861 | if (!dirname) |
862 | return NULL; | |
68164f6c KZ |
863 | tb = mnt_new_table(); |
864 | if (tb && mnt_table_parse_dir(tb, dirname) != 0) { | |
c9f1585e | 865 | mnt_unref_table(tb); |
70bf97ae KZ |
866 | tb = NULL; |
867 | } | |
868 | return tb; | |
869 | } | |
870 | ||
9fd75d76 | 871 | /** |
68164f6c | 872 | * mnt_table_set_parser_errcb: |
0f32f1e2 | 873 | * @tb: pointer to table |
9fd75d76 KZ |
874 | * @cb: pointer to callback function |
875 | * | |
68164f6c | 876 | * The error callback function is called by table parser (mnt_table_parse_file()) |
d58b3157 | 877 | * in case of a syntax error. The callback function could be used for error |
d8a30749 KZ |
878 | * evaluation, libmount will continue/stop parsing according to callback return |
879 | * codes: | |
880 | * | |
881 | * <0 : fatal error (abort parsing) | |
d58b3157 OO |
882 | * 0 : success (parsing continues) |
883 | * >0 : recoverable error (the line is ignored, parsing continues). | |
9fd75d76 | 884 | * |
d8a30749 | 885 | * Returns: 0 on success or negative number in case of error. |
9fd75d76 | 886 | */ |
68164f6c KZ |
887 | int mnt_table_set_parser_errcb(struct libmnt_table *tb, |
888 | int (*cb)(struct libmnt_table *tb, const char *filename, int line)) | |
9fd75d76 | 889 | { |
4569bbea | 890 | assert(tb); |
ba2bdf41 KZ |
891 | if (!tb) |
892 | return -EINVAL; | |
9fd75d76 KZ |
893 | tb->errcb = cb; |
894 | return 0; | |
895 | } | |
896 | ||
4709c9e6 | 897 | /* |
d58b3157 | 898 | * Filter out entries during tab file parsing. If @cb returns 1, then the entry |
4709c9e6 KZ |
899 | * is ignored. |
900 | */ | |
901 | int mnt_table_set_parser_fltrcb(struct libmnt_table *tb, | |
902 | int (*cb)(struct libmnt_fs *, void *), | |
903 | void *data) | |
904 | { | |
4569bbea | 905 | assert(tb); |
ba2bdf41 KZ |
906 | if (!tb) |
907 | return -EINVAL; | |
4709c9e6 | 908 | |
83a78332 | 909 | DBG(TAB, ul_debugobj(tb, "%s table parser filter", cb ? "set" : "unset")); |
4709c9e6 KZ |
910 | tb->fltrcb = cb; |
911 | tb->fltrcb_data = data; | |
912 | return 0; | |
913 | } | |
914 | ||
ce4dd666 KZ |
915 | /** |
916 | * mnt_table_parse_swaps: | |
917 | * @tb: table | |
918 | * @filename: overwrites default (/proc/swaps or $LIBMOUNT_SWAPS) or NULL | |
919 | * | |
920 | * This function parses /proc/swaps and appends new lines to the @tab. | |
921 | * | |
922 | * See also mnt_table_set_parser_errcb(). | |
923 | * | |
924 | * Returns: 0 on success or negative number in case of error. | |
925 | */ | |
926 | int mnt_table_parse_swaps(struct libmnt_table *tb, const char *filename) | |
927 | { | |
928 | assert(tb); | |
929 | ||
930 | if (!tb) | |
931 | return -EINVAL; | |
932 | if (!filename) { | |
933 | filename = mnt_get_swaps_path(); | |
934 | if (!filename) | |
935 | return -EINVAL; | |
936 | } | |
937 | ||
938 | tb->fmt = MNT_FMT_SWAPS; | |
939 | ||
940 | return mnt_table_parse_file(tb, filename); | |
941 | } | |
942 | ||
9826a637 | 943 | /** |
68164f6c | 944 | * mnt_table_parse_fstab: |
9826a637 | 945 | * @tb: table |
3a5b1b1d | 946 | * @filename: overwrites default (/etc/fstab or $LIBMOUNT_FSTAB) or NULL |
9826a637 | 947 | * |
52f83628 | 948 | * This function parses /etc/fstab and appends new lines to the @tab. If the |
d58b3157 | 949 | * @filename is a directory, then mnt_table_parse_dir() is called. |
9826a637 | 950 | * |
68164f6c | 951 | * See also mnt_table_set_parser_errcb(). |
9826a637 | 952 | * |
70bf97ae | 953 | * Returns: 0 on success or negative number in case of error. |
9826a637 | 954 | */ |
68164f6c | 955 | int mnt_table_parse_fstab(struct libmnt_table *tb, const char *filename) |
9826a637 | 956 | { |
52f83628 KZ |
957 | struct stat st; |
958 | int rc = 0; | |
9826a637 KZ |
959 | |
960 | assert(tb); | |
961 | if (!tb) | |
d8a30749 | 962 | return -EINVAL; |
3a5b1b1d KZ |
963 | if (!filename) |
964 | filename = mnt_get_fstab_path(); | |
965 | ||
52f83628 KZ |
966 | if (!filename || stat(filename, &st)) |
967 | return -EINVAL; | |
dd369652 | 968 | |
52f83628 | 969 | tb->fmt = MNT_FMT_FSTAB; |
1bd1cd2c | 970 | |
52f83628 KZ |
971 | if (S_ISREG(st.st_mode)) |
972 | rc = mnt_table_parse_file(tb, filename); | |
973 | else if (S_ISDIR(st.st_mode)) | |
974 | rc = mnt_table_parse_dir(tb, filename); | |
975 | else | |
976 | rc = -EINVAL; | |
70bf97ae | 977 | |
52f83628 | 978 | return rc; |
9826a637 | 979 | } |
0532ba1d KZ |
980 | |
981 | /* | |
d58b3157 | 982 | * This function uses @uf to find a corresponding record in @tb, then the record |
68164f6c | 983 | * from @tb is updated (user specific mount options are added). |
0532ba1d | 984 | * |
68164f6c | 985 | * Note that @uf must contain only user specific mount options instead of |
6a493fa3 | 986 | * VFS options (note that FS options are ignored). |
0532ba1d | 987 | * |
569f95b7 | 988 | * Returns modified filesystem (from @tb) or NULL. |
0532ba1d | 989 | */ |
68164f6c | 990 | static struct libmnt_fs *mnt_table_merge_user_fs(struct libmnt_table *tb, struct libmnt_fs *uf) |
0532ba1d | 991 | { |
68164f6c KZ |
992 | struct libmnt_fs *fs; |
993 | struct libmnt_iter itr; | |
76a06ca4 | 994 | const char *optstr, *src, *target, *root, *attrs; |
0532ba1d KZ |
995 | |
996 | assert(tb); | |
997 | assert(uf); | |
998 | if (!tb || !uf) | |
999 | return NULL; | |
1000 | ||
83a78332 | 1001 | DBG(TAB, ul_debugobj(tb, "merging user fs")); |
dd369652 | 1002 | |
0532ba1d KZ |
1003 | src = mnt_fs_get_srcpath(uf); |
1004 | target = mnt_fs_get_target(uf); | |
68164f6c | 1005 | optstr = mnt_fs_get_user_options(uf); |
76a06ca4 | 1006 | attrs = mnt_fs_get_attributes(uf); |
0532ba1d KZ |
1007 | root = mnt_fs_get_root(uf); |
1008 | ||
76a06ca4 | 1009 | if (!src || !target || !root || (!attrs && !optstr)) |
0532ba1d KZ |
1010 | return NULL; |
1011 | ||
1012 | mnt_reset_iter(&itr, MNT_ITER_BACKWARD); | |
1013 | ||
68164f6c | 1014 | while(mnt_table_next_fs(tb, &itr, &fs) == 0) { |
6699e742 | 1015 | const char *r = mnt_fs_get_root(fs); |
0532ba1d | 1016 | |
309139c7 KZ |
1017 | if (fs->flags & MNT_FS_MERGED) |
1018 | continue; | |
1019 | ||
6699e742 KZ |
1020 | if (r && strcmp(r, root) == 0 |
1021 | && mnt_fs_streq_target(fs, target) | |
1022 | && mnt_fs_streq_srcpath(fs, src)) | |
0532ba1d KZ |
1023 | break; |
1024 | } | |
1025 | ||
dd369652 | 1026 | if (fs) { |
83a78332 | 1027 | DBG(TAB, ul_debugobj(tb, "found fs -- appending user optstr")); |
f2b3a3a3 | 1028 | mnt_fs_append_options(fs, optstr); |
76a06ca4 | 1029 | mnt_fs_append_attributes(fs, attrs); |
dd369652 | 1030 | mnt_fs_set_bindsrc(fs, mnt_fs_get_bindsrc(uf)); |
309139c7 | 1031 | fs->flags |= MNT_FS_MERGED; |
dd369652 | 1032 | |
83a78332 | 1033 | DBG(TAB, ul_debugobj(tb, "found fs:")); |
dd369652 KZ |
1034 | DBG(TAB, mnt_fs_print_debug(fs, stderr)); |
1035 | } | |
0532ba1d KZ |
1036 | return fs; |
1037 | } | |
1038 | ||
6a52473e KZ |
1039 | int __mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename, |
1040 | struct libmnt_table *u_tb) | |
0532ba1d | 1041 | { |
6a52473e | 1042 | int rc = 0, priv_utab = 0; |
0532ba1d | 1043 | |
4569bbea KZ |
1044 | assert(tb); |
1045 | ||
70bf97ae | 1046 | if (mnt_has_regular_mtab(&filename, NULL)) { |
b0bb8fb6 | 1047 | |
83a78332 | 1048 | DBG(TAB, ul_debugobj(tb, "force %s usage", filename)); |
b0bb8fb6 | 1049 | |
68164f6c | 1050 | rc = mnt_table_parse_file(tb, filename); |
0532ba1d | 1051 | if (!rc) |
3a5b1b1d | 1052 | return 0; |
70bf97ae | 1053 | filename = NULL; /* failed */ |
0532ba1d KZ |
1054 | } |
1055 | ||
3a5b1b1d | 1056 | /* |
70bf97ae | 1057 | * useless /etc/mtab |
3a5b1b1d KZ |
1058 | * -- read kernel information from /proc/self/mountinfo |
1059 | */ | |
dd369652 | 1060 | tb->fmt = MNT_FMT_MOUNTINFO; |
68164f6c | 1061 | rc = mnt_table_parse_file(tb, _PATH_PROC_MOUNTINFO); |
dd369652 | 1062 | if (rc) { |
0532ba1d | 1063 | /* hmm, old kernel? ...try /proc/mounts */ |
dd369652 | 1064 | tb->fmt = MNT_FMT_MTAB; |
68164f6c | 1065 | return mnt_table_parse_file(tb, _PATH_PROC_MOUNTS); |
dd369652 | 1066 | } |
0532ba1d | 1067 | |
dad88cb3 KZ |
1068 | if (mnt_table_get_nents(tb) == 0) |
1069 | return 0; /* empty, ignore utab */ | |
3a5b1b1d | 1070 | /* |
d58b3157 | 1071 | * try to read the user specific information from /run/mount/utabs |
3a5b1b1d | 1072 | */ |
6a52473e KZ |
1073 | if (!u_tb) { |
1074 | const char *utab = mnt_get_utab_path(); | |
1075 | if (!utab || is_file_empty(utab)) | |
1076 | return 0; | |
1077 | ||
1078 | u_tb = mnt_new_table(); | |
1079 | if (!u_tb) | |
1080 | return -ENOMEM; | |
0532ba1d | 1081 | |
6a52473e KZ |
1082 | u_tb->fmt = MNT_FMT_UTAB; |
1083 | mnt_table_set_parser_fltrcb(u_tb, tb->fltrcb, tb->fltrcb_data); | |
0532ba1d | 1084 | |
6a52473e KZ |
1085 | rc = mnt_table_parse_file(u_tb, utab); |
1086 | priv_utab = 1; | |
1087 | } | |
0532ba1d | 1088 | |
6a52473e | 1089 | if (rc == 0) { |
dad88cb3 KZ |
1090 | struct libmnt_fs *u_fs; |
1091 | struct libmnt_iter itr; | |
3a5b1b1d | 1092 | |
dad88cb3 KZ |
1093 | mnt_reset_iter(&itr, MNT_ITER_BACKWARD); |
1094 | ||
d58b3157 | 1095 | /* merge user options into mountinfo from the kernel */ |
dad88cb3 KZ |
1096 | while(mnt_table_next_fs(u_tb, &itr, &u_fs) == 0) |
1097 | mnt_table_merge_user_fs(tb, u_fs); | |
3a5b1b1d | 1098 | } |
dad88cb3 | 1099 | |
6a52473e KZ |
1100 | |
1101 | if (priv_utab) | |
1102 | mnt_unref_table(u_tb); | |
0532ba1d KZ |
1103 | return 0; |
1104 | } | |
6a52473e KZ |
1105 | /** |
1106 | * mnt_table_parse_mtab: | |
1107 | * @tb: table | |
1108 | * @filename: overwrites default (/etc/mtab or $LIBMOUNT_MTAB) or NULL | |
1109 | * | |
1110 | * This function parses /etc/mtab or /proc/self/mountinfo + | |
1111 | * /run/mount/utabs or /proc/mounts. | |
1112 | * | |
1113 | * See also mnt_table_set_parser_errcb(). | |
1114 | * | |
1115 | * Returns: 0 on success or negative number in case of error. | |
1116 | */ | |
1117 | int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename) | |
1118 | { | |
1119 | return __mnt_table_parse_mtab(tb, filename, NULL); | |
1120 | } |