Coverage Report

Created: 2024-02-11 06:22

/src/util-linux/libmount/src/tab_parse.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
/*
3
 * This file is part of libmount from util-linux project.
4
 *
5
 * Copyright (C) 2009-2018 Karel Zak <kzak@redhat.com>
6
 *
7
 * libmount is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU Lesser General Public License as published by
9
 * the Free Software Foundation; either version 2.1 of the License, or
10
 * (at your option) any later version.
11
 */
12
#ifdef HAVE_SCANDIRAT
13
#ifndef __USE_GNU
14
#define __USE_GNU
15
#endif  /* !__USE_GNU */
16
#endif  /* HAVE_SCANDIRAT */
17
18
#include <ctype.h>
19
#include <limits.h>
20
#include <dirent.h>
21
#include <fcntl.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <sys/stat.h>
25
26
#include "fileutils.h"
27
#include "mangle.h"
28
#include "mountP.h"
29
#include "pathnames.h"
30
#include "strutils.h"
31
32
struct libmnt_parser {
33
  FILE  *f;   /* fstab, swaps or mountinfo ... */
34
  const char *filename; /* file name or NULL */
35
  char  *buf;   /* buffer (the current line content) */
36
  size_t  bufsiz;   /* size of the buffer */
37
  size_t  line;   /* current line */
38
  int     sysroot_rc; /* rc from mnt_guess_system_root() */
39
  char  *sysroot; /* guess from mmnt_guess_system_root() */
40
};
41
42
static void parser_cleanup(struct libmnt_parser *pa)
43
3.39k
{
44
3.39k
  if (!pa)
45
0
    return;
46
3.39k
  free(pa->buf);
47
3.39k
  free(pa->sysroot);
48
3.39k
  memset(pa, 0, sizeof(*pa));
49
3.39k
}
50
51
static const char *next_s32(const char *s, int *num, int *rc)
52
18.5k
{
53
18.5k
  char *end = NULL;
54
55
18.5k
  if (!s || !*s)
56
806
    return s;
57
58
17.7k
  errno = 0;
59
17.7k
  *rc = -EINVAL;
60
17.7k
  *num = strtol(s, &end, 10);
61
17.7k
  if (end == NULL || s == end)
62
1.47k
         return s;
63
16.3k
  if (errno == 0 && (*end == ' ' || *end == '\t' || *end == '\0'))
64
15.0k
    *rc = 0;
65
16.3k
  return end;
66
17.7k
}
67
68
static const char *next_u64(const char *s, uint64_t *num, int *rc)
69
4.67k
{
70
4.67k
  char *end = NULL;
71
72
4.67k
  if (!s || !*s)
73
625
    return s;
74
75
4.05k
  errno = 0;
76
4.05k
  *rc = -EINVAL;
77
4.05k
  *num = (uint64_t) strtoumax(s, &end, 10);
78
4.05k
  if (end == NULL || s == end)
79
433
         return s;
80
3.61k
  if (errno == 0 && (*end == ' ' || *end == '\t' || *end == '\0'))
81
2.80k
    *rc = 0;
82
3.61k
  return end;
83
4.05k
}
84
85
static inline const char *skip_separator(const char *p)
86
203k
{
87
357k
  while (p && (*p == ' ' || *p == '\t'))
88
153k
    ++p;
89
203k
  return p;
90
203k
}
91
92
static inline const char *skip_nonspearator(const char *p)
93
5.15k
{
94
15.7k
  while (p && *p && !(*p == ' ' || *p == '\t'))
95
10.6k
    p++;
96
5.15k
  return p;
97
5.15k
}
98
99
/*
100
 * Parses one line from {fs,m}tab
101
 */
102
static int mnt_parse_table_line(struct libmnt_fs *fs, const char *s)
103
54.3k
{
104
54.3k
  int rc = 0;
105
54.3k
  char *p = NULL;
106
107
54.3k
  fs->passno = fs->freq = 0;
108
109
  /* (1) source */
110
54.3k
  p = unmangle(s, &s);
111
54.3k
  if (!p || (rc = __mnt_fs_set_source_ptr(fs, p))) {
112
0
    DBG(TAB, ul_debug("tab parse error: [source]"));
113
0
    free(p);
114
0
    goto fail;
115
0
  }
116
117
54.3k
  s = skip_separator(s);
118
119
  /* (2) target */
120
54.3k
  fs->target = unmangle(s, &s);
121
54.3k
  if (!fs->target) {
122
4.57k
    DBG(TAB, ul_debug("tab parse error: [target]"));
123
4.57k
    goto fail;
124
4.57k
  }
125
126
49.8k
  s = skip_separator(s);
127
128
  /* (3) FS type */
129
49.8k
  p = unmangle(s, &s);
130
49.8k
  if (!p || (rc = __mnt_fs_set_fstype_ptr(fs, p))) {
131
320
    DBG(TAB, ul_debug("tab parse error: [fstype]"));
132
320
    free(p);
133
320
    goto fail;
134
320
  }
135
136
49.4k
  s = skip_separator(s);
137
138
  /* (4) options (optional) */
139
49.4k
  p = unmangle(s, &s);
140
49.4k
  if (p && (rc = mnt_fs_set_options(fs, p))) {
141
0
    DBG(TAB, ul_debug("tab parse error: [options]"));
142
0
    free(p);
143
0
    goto fail;
144
0
  }
145
49.4k
  if (!p)
146
46.1k
    goto done;
147
3.36k
  free(p);
148
149
3.36k
  s = skip_separator(s);
150
3.36k
  if (!s || !*s)
151
1.51k
    goto done;
152
153
  /* (5) freq (optional) */
154
1.84k
  s = next_s32(s, &fs->freq, &rc);
155
1.84k
  if (s && *s && rc) {
156
428
    DBG(TAB, ul_debug("tab parse error: [freq]"));
157
428
    goto fail;
158
428
  }
159
160
1.42k
  s = skip_separator(s);
161
1.42k
  if (!s || !*s)
162
602
    goto done;
163
164
  /* (6) passno (optional) */
165
819
  s = next_s32(s, &fs->passno, &rc);
166
819
  if (s && *s && rc) {
167
270
    DBG(TAB, ul_debug("tab parse error: [passno]"));
168
270
    goto fail;
169
270
  }
170
171
48.8k
done:
172
48.8k
  return 0;
173
5.59k
fail:
174
5.59k
  if (rc == 0)
175
4.89k
    rc = -EINVAL;
176
5.59k
  DBG(TAB, ul_debug("tab parse error on: '%s' [rc=%d]", s, rc));
177
5.59k
  return rc;
178
819
}
179
180
181
/*
182
 * Parses one line from a mountinfo file
183
 */
184
static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, const char *s)
185
8.24k
{
186
8.24k
  int rc = 0;
187
8.24k
  unsigned int maj, min;
188
8.24k
  char *p;
189
190
8.24k
  fs->flags |= MNT_FS_KERNEL;
191
192
  /* (1) id */
193
8.24k
  s = next_s32(s, &fs->id, &rc);
194
8.24k
  if (!s || !*s || rc) {
195
1.17k
    DBG(TAB, ul_debug("tab parse error: [id]"));
196
1.17k
    goto fail;
197
1.17k
  }
198
199
7.07k
  s = skip_separator(s);
200
201
  /* (2) parent */
202
7.07k
  s = next_s32(s, &fs->parent, &rc);
203
7.07k
  if (!s || !*s || rc) {
204
1.49k
    DBG(TAB, ul_debug("tab parse error: [parent]"));
205
1.49k
    goto fail;
206
1.49k
  }
207
208
5.57k
  s = skip_separator(s);
209
210
  /* (3) maj:min */
211
5.57k
  if (sscanf(s, "%u:%u", &maj, &min) != 2) {
212
425
    DBG(TAB, ul_debug("tab parse error: [maj:min]"));
213
425
    goto fail;
214
425
  }
215
5.15k
  fs->devno = makedev(maj, min);
216
5.15k
  s = skip_nonspearator(s);
217
5.15k
  s = skip_separator(s);
218
219
  /* (4) mountroot */
220
5.15k
  fs->root = unmangle(s, &s);
221
5.15k
  if (!fs->root) {
222
223
    DBG(TAB, ul_debug("tab parse error: [mountroot]"));
223
223
    goto fail;
224
223
  }
225
226
4.92k
  s = skip_separator(s);
227
228
  /* (5) target */
229
4.92k
  fs->target = unmangle(s, &s);
230
4.92k
  if (!fs->target) {
231
230
    DBG(TAB, ul_debug("tab parse error: [target]"));
232
230
    goto fail;
233
230
  }
234
235
4.69k
  s = skip_separator(s);
236
237
  /* (6) vfs options (fs-independent) */
238
4.69k
  fs->vfs_optstr = unmangle(s, &s);
239
4.69k
  if (!fs->vfs_optstr) {
240
221
    DBG(TAB, ul_debug("tab parse error: [VFS options]"));
241
221
    goto fail;
242
221
  }
243
244
  /* (7) optional fields, terminated by " - " */
245
4.47k
  p = strstr(s, " - ");
246
4.47k
  if (!p) {
247
357
    DBG(TAB, ul_debug("mountinfo parse error: separator not found"));
248
357
    return -EINVAL;
249
357
  }
250
4.12k
  if (p > s + 1)
251
201
    fs->opt_fields = strndup(s + 1, p - s - 1);
252
253
4.12k
  s = skip_separator(p + 3);
254
255
  /* (8) FS type */
256
4.12k
  p = unmangle(s, &s);
257
4.12k
  if (!p || (rc = __mnt_fs_set_fstype_ptr(fs, p))) {
258
404
    DBG(TAB, ul_debug("tab parse error: [fstype]"));
259
404
    free(p);
260
404
    goto fail;
261
404
  }
262
263
  /* (9) source -- maybe empty string */
264
3.71k
  if (!s || !*s) {
265
209
    DBG(TAB, ul_debug("tab parse error: [source]"));
266
209
    goto fail;
267
3.50k
  } else if (*s == ' ' && *(s+1) == ' ') {
268
2.18k
    if ((rc = mnt_fs_set_source(fs, ""))) {
269
0
      DBG(TAB, ul_debug("tab parse error: [empty source]"));
270
0
      goto fail;
271
0
    }
272
2.18k
  } else {
273
1.32k
    s = skip_separator(s);
274
1.32k
    p = unmangle(s, &s);
275
1.32k
    if (!p || (rc = __mnt_fs_set_source_ptr(fs, p))) {
276
405
      DBG(TAB, ul_debug("tab parse error: [regular source]"));
277
405
      free(p);
278
405
      goto fail;
279
405
    }
280
1.32k
  }
281
282
3.10k
  s = skip_separator(s);
283
284
  /* (10) fs options (fs specific) */
285
3.10k
  fs->fs_optstr = unmangle(s, &s);
286
3.10k
  if (!fs->fs_optstr) {
287
415
    DBG(TAB, ul_debug("tab parse error: [FS options]"));
288
415
    goto fail;
289
415
  }
290
291
  /* merge VFS and FS options to one string */
292
2.68k
  fs->optstr = mnt_fs_strdup_options(fs);
293
2.68k
  if (!fs->optstr) {
294
0
    rc = -ENOMEM;
295
0
    DBG(TAB, ul_debug("tab parse error: [merge VFS and FS options]"));
296
0
    goto fail;
297
0
  }
298
299
2.68k
  return 0;
300
5.20k
fail:
301
5.20k
  if (rc == 0)
302
3.60k
    rc = -EINVAL;
303
5.20k
  DBG(TAB, ul_debug("tab parse error on: '%s' [rc=%d]", s, rc));
304
5.20k
  return rc;
305
2.68k
}
306
307
/*
308
 * Parses one line from utab file
309
 */
310
static int mnt_parse_utab_line(struct libmnt_fs *fs, const char *s)
311
0
{
312
0
  const char *p = s;
313
314
0
  assert(fs);
315
0
  assert(s);
316
0
  assert(!fs->source);
317
0
  assert(!fs->target);
318
319
0
  while (p && *p) {
320
0
    const char *end = NULL;
321
322
0
    while (*p == ' ') p++;
323
0
    if (!*p)
324
0
      break;
325
326
0
    if (!fs->id && !strncmp(p, "ID=", 3)) {
327
0
      int rc = 0;
328
329
0
      end = next_s32(p + 3, &fs->id, &rc);
330
0
      if (!end || rc)
331
0
        return rc;
332
333
0
    } else if (!fs->source && !strncmp(p, "SRC=", 4)) {
334
0
      char *v = unmangle(p + 4, &end);
335
0
      if (!v)
336
0
        goto enomem;
337
0
      if (__mnt_fs_set_source_ptr(fs, v))
338
0
        free(v);
339
340
0
    } else if (!fs->target && !strncmp(p, "TARGET=", 7)) {
341
0
      fs->target = unmangle(p + 7, &end);
342
0
      if (!fs->target)
343
0
        goto enomem;
344
345
0
    } else if (!fs->root && !strncmp(p, "ROOT=", 5)) {
346
0
      fs->root = unmangle(p + 5, &end);
347
0
      if (!fs->root)
348
0
        goto enomem;
349
350
0
    } else if (!fs->bindsrc && !strncmp(p, "BINDSRC=", 8)) {
351
0
      fs->bindsrc = unmangle(p + 8, &end);
352
0
      if (!fs->bindsrc)
353
0
        goto enomem;
354
355
0
    } else if (!fs->user_optstr && !strncmp(p, "OPTS=", 5)) {
356
0
      fs->user_optstr = unmangle(p + 5, &end);
357
0
      if (!fs->user_optstr)
358
0
        goto enomem;
359
360
0
    } else if (!fs->attrs && !strncmp(p, "ATTRS=", 6)) {
361
0
      fs->attrs = unmangle(p + 6, &end);
362
0
      if (!fs->attrs)
363
0
        goto enomem;
364
365
0
    } else {
366
      /* unknown variable */
367
0
      while (*p && *p != ' ') p++;
368
0
    }
369
0
    if (end)
370
0
      p = end;
371
0
  }
372
373
0
  return 0;
374
0
enomem:
375
0
  DBG(TAB, ul_debug("utab parse error: ENOMEM"));
376
0
  return -ENOMEM;
377
0
}
378
379
/*
380
 * Parses one line from /proc/swaps
381
 */
382
static int mnt_parse_swaps_line(struct libmnt_fs *fs, const char *s)
383
3.87k
{
384
3.87k
  uint64_t num;
385
3.87k
  int rc = 0;
386
3.87k
  char *p;
387
388
  /* (1) source */
389
3.87k
  p = unmangle(s, &s);
390
3.87k
  if (p) {
391
3.87k
    char *x = (char *) endswith(p, PATH_DELETED_SUFFIX);
392
3.87k
    if (x && *x)
393
194
      *x = '\0';
394
3.87k
  }
395
3.87k
  if (!p || (rc = __mnt_fs_set_source_ptr(fs, p))) {
396
0
    DBG(TAB, ul_debug("tab parse error: [source]"));
397
0
    free(p);
398
0
    goto fail;
399
0
  }
400
401
3.87k
  s = skip_separator(s);
402
403
  /* (2) type */
404
3.87k
  fs->swaptype = unmangle(s, &s);
405
3.87k
  if (!fs->swaptype) {
406
1.00k
    DBG(TAB, ul_debug("tab parse error: [swaptype]"));
407
1.00k
    goto fail;
408
1.00k
  }
409
410
2.86k
  s = skip_separator(s);
411
412
  /* (3) size */
413
2.86k
  s = next_u64(s, &num, &rc);
414
2.86k
  if (!s || !*s || rc) {
415
1.05k
    DBG(TAB, ul_debug("tab parse error: [size]"));
416
1.05k
    goto fail;
417
1.05k
  }
418
1.80k
  fs->size = num;
419
420
1.80k
  s = skip_separator(s);
421
422
  /* (4) size */
423
1.80k
  s = next_u64(s, &num, &rc);
424
1.80k
  if (!s || !*s || rc) {
425
1.20k
    DBG(TAB, ul_debug("tab parse error: [used size]"));
426
1.20k
    goto fail;
427
1.20k
  }
428
607
  fs->usedsize = num;
429
430
607
  s = skip_separator(s);
431
432
  /* (5) priority */
433
607
  s = next_s32(s, &fs->priority, &rc);
434
607
  if (rc) {
435
204
    DBG(TAB, ul_debug("tab parse error: [priority]"));
436
204
    goto fail;
437
204
  }
438
439
403
  mnt_fs_set_fstype(fs, "swap");
440
403
  return 0;
441
3.46k
fail:
442
3.46k
  if (rc == 0)
443
2.02k
    rc = -EINVAL;
444
3.46k
  DBG(TAB, ul_debug("tab parse error on: '%s' [rc=%d]", s, rc));
445
3.46k
  return rc;
446
607
}
447
448
449
/*
450
 * Returns {m,fs}tab or mountinfo file format (MNT_FMT_*)
451
 *
452
 * Note that we aren't trying to guess the utab file format, because this file
453
 * always has to be parsed by private libmount routines with an explicitly defined
454
 * format.
455
 *
456
 * mountinfo: "<number> <number> ... "
457
 */
458
static int guess_table_format(const char *line)
459
3.19k
{
460
3.19k
  unsigned int a, b;
461
462
3.19k
  DBG(TAB, ul_debug("trying to guess table type"));
463
464
3.19k
  if (sscanf(line, "%u %u", &a, &b) == 2)
465
922
    return MNT_FMT_MOUNTINFO;
466
467
2.27k
  if (strncmp(line, "Filename\t", 9) == 0)
468
438
    return MNT_FMT_SWAPS;
469
470
1.83k
  return MNT_FMT_FSTAB;   /* fstab, or /proc/mounts */
471
2.27k
}
472
473
static int is_comment_line(const char *line)
474
56.8k
{
475
56.8k
  const char *p = skip_blank(line);
476
477
56.8k
  if (p && (*p == '#' || *p == '\n'))
478
2.81k
    return 1;
479
53.9k
  return 0;
480
56.8k
}
481
482
/* returns 1 if the last line in the @str is blank */
483
static int is_terminated_by_blank(const char *str)
484
2.81k
{
485
2.81k
  size_t sz = str ? strlen(str) : 0;
486
2.81k
  const char *p = sz ? str + (sz - 1) : NULL;
487
488
2.81k
  if (!sz || !p || *p != '\n')
489
443
    return 0;    /* empty or not terminated by '\n' */
490
2.37k
  if (p == str)
491
1.66k
    return 1;    /* only '\n' */
492
711
  p--;
493
1.27k
  while (p > str && (*p == ' ' || *p == '\t'))
494
564
    p--;
495
711
  return *p == '\n' ? 1 : 0;
496
2.37k
}
497
498
/*
499
 * Reads the next line from the file.
500
 *
501
 * Returns 0 if the line is a comment
502
 *         1 if the line is not a comment
503
 *        <0 on error
504
 */
505
static int next_comment_line(struct libmnt_parser *pa, char **last)
506
2.81k
{
507
2.81k
  if (getline(&pa->buf, &pa->bufsiz, pa->f) < 0)
508
169
    return feof(pa->f) ? 1 : -errno;
509
510
2.64k
  pa->line++;
511
2.64k
  *last = strchr(pa->buf, '\n');
512
513
2.64k
  return is_comment_line(pa->buf) ? 0 : 1;
514
2.81k
}
515
516
static int append_comment(struct libmnt_table *tb,
517
        struct libmnt_fs *fs,
518
        const char *comm,
519
        int eof)
520
3.03k
{
521
3.03k
  int rc, intro = mnt_table_get_nents(tb) == 0;
522
523
3.03k
  if (intro && is_terminated_by_blank(mnt_table_get_intro_comment(tb)))
524
1.90k
    intro = 0;
525
526
3.03k
  DBG(TAB, ul_debugobj(tb, "appending %s comment",
527
3.03k
      intro ? "intro" :
528
3.03k
      eof ? "trailing" : "fs"));
529
3.03k
  if (intro)
530
915
    rc = mnt_table_append_intro_comment(tb, comm);
531
2.12k
  else if (eof) {
532
147
    rc = mnt_table_set_trailing_comment(tb,
533
147
        mnt_fs_get_comment(fs));
534
147
    if (!rc)
535
147
      rc = mnt_table_append_trailing_comment(tb, comm);
536
147
    if (!rc)
537
147
      rc = mnt_fs_set_comment(fs, NULL);
538
147
  } else
539
1.97k
    rc = mnt_fs_append_comment(fs, comm);
540
3.03k
  return rc;
541
3.03k
}
542
543
/*
544
 * Read and parse the next line from {fs,m}tab or mountinfo
545
 */
546
static int mnt_table_parse_next(struct libmnt_parser *pa,
547
        struct libmnt_table *tb,
548
        struct libmnt_fs *fs)
549
67.7k
{
550
67.7k
  char *s;
551
67.7k
  int rc;
552
553
67.7k
  assert(tb);
554
67.7k
  assert(pa);
555
67.7k
  assert(fs);
556
557
  /* read the next non-blank non-comment line */
558
68.4k
next_line:
559
69.7k
  do {
560
69.7k
    if (getline(&pa->buf, &pa->bufsiz, pa->f) < 0)
561
201
      return -EINVAL;
562
69.5k
    pa->line++;
563
69.5k
    s = strchr(pa->buf, '\n');
564
69.5k
    if (!s) {
565
3.90k
      DBG(TAB, ul_debugobj(tb, "%s:%zu: no final newline",
566
3.90k
            pa->filename, pa->line));
567
568
      /* Missing final newline?  Otherwise an extremely */
569
      /* long line - assume file was corrupted */
570
3.90k
      if (feof(pa->f))
571
3.12k
        s = memchr(pa->buf, '\0', pa->bufsiz);
572
573
    /* comments parser */
574
65.6k
    } else if (tb->comms
575
65.6k
        && (tb->fmt == MNT_FMT_GUESS || tb->fmt == MNT_FMT_FSTAB)
576
65.6k
        && is_comment_line(pa->buf)) {
577
2.81k
      do {
578
2.81k
        rc = append_comment(tb, fs, pa->buf, feof(pa->f));
579
2.81k
        if (!rc)
580
2.81k
          rc = next_comment_line(pa, &s);
581
2.81k
      } while (rc == 0);
582
583
1.03k
      if (rc == 1 && feof(pa->f))
584
218
        rc = append_comment(tb, fs, NULL, 1);
585
1.03k
      if (rc < 0)
586
0
        return rc;
587
588
1.03k
    }
589
590
69.5k
    if (!s)
591
1.06k
      goto err;
592
68.5k
    *s = '\0';
593
68.5k
    if (s > pa->buf && *(s - 1)  == '\r')
594
388
      *(--s) = '\0';
595
68.5k
    s = (char *) skip_blank(pa->buf);
596
68.5k
  } while (*s == '\0' || *s == '#');
597
598
67.1k
  if (tb->fmt == MNT_FMT_GUESS) {
599
3.19k
    tb->fmt = guess_table_format(s);
600
3.19k
    if (tb->fmt == MNT_FMT_SWAPS)
601
438
      goto next_line;     /* skip swap header */
602
3.19k
  }
603
604
66.7k
  switch (tb->fmt) {
605
54.3k
  case MNT_FMT_FSTAB:
606
54.3k
    rc = mnt_parse_table_line(fs, s);
607
54.3k
    break;
608
8.24k
  case MNT_FMT_MOUNTINFO:
609
8.24k
    rc = mnt_parse_mountinfo_line(fs, s);
610
8.24k
    break;
611
0
  case MNT_FMT_UTAB:
612
0
    rc = mnt_parse_utab_line(fs, s);
613
0
    break;
614
4.08k
  case MNT_FMT_SWAPS:
615
4.08k
    if (strncmp(s, "Filename\t", 9) == 0)
616
213
      goto next_line;      /* skip swap header */
617
3.87k
    rc = mnt_parse_swaps_line(fs, s);
618
3.87k
    break;
619
0
  default:
620
0
    rc = -1;  /* unknown format */
621
0
    break;
622
66.7k
  }
623
624
66.5k
  if (rc == 0)
625
51.8k
    return 0;
626
15.6k
err:
627
15.6k
  DBG(TAB, ul_debugobj(tb, "%s:%zu: %s parse error", pa->filename, pa->line,
628
15.6k
        tb->fmt == MNT_FMT_MOUNTINFO ? "mountinfo" :
629
15.6k
        tb->fmt == MNT_FMT_SWAPS ? "swaps" :
630
15.6k
        tb->fmt == MNT_FMT_FSTAB ? "tab" : "utab"));
631
632
  /* by default all errors are recoverable, otherwise behavior depends on
633
   * the errcb() function. See mnt_table_set_parser_errcb().
634
   */
635
15.6k
  return tb->errcb ? tb->errcb(tb, pa->filename, pa->line) : 1;
636
66.5k
}
637
638
static pid_t path_to_tid(const char *filename)
639
449
{
640
449
  char *path = mnt_resolve_path(filename, NULL);
641
449
  char *p, *end = NULL;
642
449
  pid_t tid = 0;
643
644
449
  if (!path)
645
0
    goto done;
646
449
  p = strrchr(path, '/');
647
449
  if (!p)
648
449
    goto done;
649
0
  *p = '\0';
650
0
  p = strrchr(path, '/');
651
0
  if (!p)
652
0
    goto done;
653
0
  p++;
654
655
0
  errno = 0;
656
0
  tid = strtol(p, &end, 10);
657
0
  if (errno || p == end || (end && *end)) {
658
0
    tid = 0;
659
0
    goto done;
660
0
  }
661
0
  DBG(TAB, ul_debug("TID for %s is %d", filename, tid));
662
449
done:
663
449
  free(path);
664
449
  return tid;
665
0
}
666
667
static int kernel_fs_postparse(struct libmnt_parser *pa,
668
             struct libmnt_table *tb,
669
             struct libmnt_fs *fs, pid_t *tid)
670
2.68k
{
671
2.68k
  int rc = 0;
672
2.68k
  const char *src = mnt_fs_get_srcpath(fs);
673
674
  /* This is a filesystem description from /proc, so we're in some process
675
   * namespace. Let's remember the process PID.
676
   */
677
2.68k
  if (pa->filename && *tid == -1)
678
449
    *tid = path_to_tid(pa->filename);
679
680
2.68k
  fs->tid = *tid;
681
682
  /*
683
   * Convert obscure /dev/root to something more usable
684
   */
685
2.68k
  if (src && strcmp(src, "/dev/root") == 0) {
686
687
    /* We will only call mnt_guess_system_root() if it has not
688
     * been called before. Inside a container, mountinfo can contain
689
     * many lines with /dev/root.
690
     */
691
420
    if (pa->sysroot_rc == 0 && pa->sysroot == NULL)
692
46
      pa->sysroot_rc = mnt_guess_system_root(fs->devno,
693
46
            tb->cache, &pa->sysroot);
694
695
420
    rc = pa->sysroot_rc;
696
420
    if (rc < 0)
697
0
      return rc;
698
699
    /* This means that we already have run the mnt_guess_system_root()
700
     * and that we want to reuse the result.
701
     */
702
420
    if (rc == 0 && pa->sysroot != NULL) {
703
420
      char *real = strdup(pa->sysroot);
704
705
420
      if (!real)
706
0
        return -ENOMEM;
707
708
420
      DBG(TAB, ul_debugobj(tb, "canonical root FS: %s", real));
709
420
      rc = __mnt_fs_set_source_ptr(fs, real);
710
711
420
    } else if (rc == 1) {
712
      /* mnt_guess_system_root() returns 1 if not able to convert to
713
       * the real devname; ignore this problem */
714
0
      rc = 0;
715
0
    }
716
420
  }
717
718
2.68k
  return rc;
719
2.68k
}
720
721
/**
722
 * mnt_table_parse_stream:
723
 * @tb: tab pointer
724
 * @f: file stream
725
 * @filename: filename used for debug and error messages
726
 *
727
 * Returns: 0 on success, negative number in case of error.
728
 */
729
int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename)
730
3.39k
{
731
3.39k
  int rc = -1;
732
3.39k
  int flags = 0;
733
3.39k
  pid_t tid = -1;
734
3.39k
  struct libmnt_parser pa = { .line = 0 };
735
736
3.39k
  assert(tb);
737
3.39k
  assert(f);
738
3.39k
  assert(filename);
739
740
3.39k
  DBG(TAB, ul_debugobj(tb, "%s: start parsing [entries=%d, filter=%s]",
741
3.39k
        filename, mnt_table_get_nents(tb),
742
3.39k
        tb->fltrcb ? "yes" : "not"));
743
744
3.39k
  pa.filename = filename;
745
3.39k
  pa.f = f;
746
747
  /* necessary for /proc/mounts only, the /proc/self/mountinfo
748
   * parser sets the flag properly
749
   */
750
3.39k
  if (tb->fmt == MNT_FMT_SWAPS)
751
0
    flags = MNT_FS_SWAP;
752
3.39k
  else if (filename && strcmp(filename, _PATH_PROC_MOUNTS) == 0)
753
0
    flags = MNT_FS_KERNEL;
754
755
71.1k
  do {
756
71.1k
    struct libmnt_fs *fs;
757
758
71.1k
    if (feof(f)) {
759
3.39k
      DBG(TAB, ul_debugobj(tb, "end-of-file"));
760
3.39k
      break;
761
3.39k
    }
762
67.7k
    fs = mnt_new_fs();
763
67.7k
    if (!fs)
764
0
      goto err;
765
766
    /* parse */
767
67.7k
    rc = mnt_table_parse_next(&pa, tb, fs);
768
769
67.7k
    if (rc == 0 && tb->fltrcb && tb->fltrcb(fs, tb->fltrcb_data))
770
0
      rc = 1; /* filtered out by callback... */
771
772
67.7k
    if (rc == 0 && mnt_table_is_noautofs(tb)) {
773
0
      const char *fstype = mnt_fs_get_fstype(fs);
774
775
0
      if (fstype && strcmp(fstype, "autofs") == 0 &&
776
0
          mnt_fs_get_option(fs, "ignore", NULL, NULL) == 0)
777
0
        rc = 1; /* Skip "ignore" autofs entry */
778
0
    }
779
780
    /* add to the table */
781
67.7k
    if (rc == 0) {
782
51.8k
      rc = mnt_table_add_fs(tb, fs);
783
51.8k
      fs->flags |= flags;
784
785
51.8k
      if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO) {
786
2.68k
        rc = kernel_fs_postparse(&pa, tb, fs, &tid);
787
2.68k
        if (rc)
788
0
          mnt_table_remove_fs(tb, fs);
789
2.68k
      }
790
51.8k
    }
791
792
    /* remove reference (or deallocate on error) */
793
67.7k
    mnt_unref_fs(fs);
794
795
    /* recoverable error */
796
67.7k
    if (rc > 0) {
797
15.6k
      DBG(TAB, ul_debugobj(tb, "recoverable error (continue)"));
798
15.6k
      continue;
799
15.6k
    }
800
801
    /* fatal errors */
802
52.0k
    if (rc < 0 && !feof(f)) {
803
0
      DBG(TAB, ul_debugobj(tb, "fatal error"));
804
0
      goto err;
805
0
    }
806
67.7k
  } while (1);
807
808
3.39k
  DBG(TAB, ul_debugobj(tb, "%s: stop parsing (%d entries)",
809
3.39k
        filename, mnt_table_get_nents(tb)));
810
3.39k
  parser_cleanup(&pa);
811
3.39k
  return 0;
812
0
err:
813
0
  DBG(TAB, ul_debugobj(tb, "%s: parse error (rc=%d)", filename, rc));
814
0
  parser_cleanup(&pa);
815
0
  return rc;
816
3.39k
}
817
818
/**
819
 * mnt_table_parse_file:
820
 * @tb: tab pointer
821
 * @filename: file
822
 *
823
 * Parses the whole table (e.g. /etc/fstab) and appends new records to the @tab.
824
 *
825
 * The libmount parser ignores broken (syntax error) lines, these lines are
826
 * reported to the caller by the errcb() function (see mnt_table_set_parser_errcb()).
827
 *
828
 * Returns: 0 on success, negative number in case of error.
829
 */
830
int mnt_table_parse_file(struct libmnt_table *tb, const char *filename)
831
0
{
832
0
  FILE *f;
833
0
  int rc;
834
835
0
  if (!filename || !tb)
836
0
    return -EINVAL;
837
838
0
  f = fopen(filename, "r" UL_CLOEXECSTR);
839
0
  if (f) {
840
0
    rc = mnt_table_parse_stream(tb, f, filename);
841
0
    fclose(f);
842
0
  } else
843
0
    rc = -errno;
844
845
0
  DBG(TAB, ul_debugobj(tb, "parsing done [filename=%s, rc=%d]", filename, rc));
846
0
  return rc;
847
0
}
848
849
static int mnt_table_parse_dir_filter(const struct dirent *d)
850
0
{
851
0
  size_t namesz;
852
853
0
#ifdef _DIRENT_HAVE_D_TYPE
854
0
  if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG &&
855
0
      d->d_type != DT_LNK)
856
0
    return 0;
857
0
#endif
858
0
  if (*d->d_name == '.')
859
0
    return 0;
860
861
0
#define MNT_MNTTABDIR_EXTSIZ  (sizeof(MNT_MNTTABDIR_EXT) - 1)
862
863
0
  namesz = strlen(d->d_name);
864
0
  if (!namesz || namesz < MNT_MNTTABDIR_EXTSIZ + 1 ||
865
0
      strcmp(d->d_name + (namesz - MNT_MNTTABDIR_EXTSIZ),
866
0
       MNT_MNTTABDIR_EXT) != 0)
867
0
    return 0;
868
869
  /* Accept this */
870
0
  return 1;
871
0
}
872
873
#ifdef HAVE_SCANDIRAT
874
static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname)
875
0
{
876
0
  int n = 0, i;
877
0
  int dd;
878
0
  struct dirent **namelist = NULL;
879
880
0
  dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
881
0
  if (dd < 0)
882
0
          return -errno;
883
884
0
  n = scandirat(dd, ".", &namelist, mnt_table_parse_dir_filter, versionsort);
885
0
  if (n <= 0) {
886
0
          close(dd);
887
0
          return 0;
888
0
  }
889
890
0
  for (i = 0; i < n; i++) {
891
0
    struct dirent *d = namelist[i];
892
0
    struct stat st;
893
0
    FILE *f;
894
895
0
    if (fstatat(dd, d->d_name, &st, 0) ||
896
0
        !S_ISREG(st.st_mode))
897
0
      continue;
898
899
0
    f = fopen_at(dd, d->d_name, O_RDONLY|O_CLOEXEC, "r" UL_CLOEXECSTR);
900
0
    if (f) {
901
0
      mnt_table_parse_stream(tb, f, d->d_name);
902
0
      fclose(f);
903
0
    }
904
0
  }
905
906
0
  for (i = 0; i < n; i++)
907
0
    free(namelist[i]);
908
0
  free(namelist);
909
0
  close(dd);
910
0
  return 0;
911
0
}
912
#else
913
static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname)
914
{
915
  int n = 0, i, r = 0;
916
  DIR *dir = NULL;
917
  struct dirent **namelist = NULL;
918
919
  n = scandir(dirname, &namelist, mnt_table_parse_dir_filter, versionsort);
920
  if (n <= 0)
921
    return 0;
922
923
  /* let's use "at" functions rather than playing crazy games with paths... */
924
  dir = opendir(dirname);
925
  if (!dir) {
926
    r = -errno;
927
    goto out;
928
  }
929
930
  for (i = 0; i < n; i++) {
931
    struct dirent *d = namelist[i];
932
    struct stat st;
933
    FILE *f;
934
935
    if (fstatat(dirfd(dir), d->d_name, &st, 0) ||
936
        !S_ISREG(st.st_mode))
937
      continue;
938
939
    f = fopen_at(dirfd(dir), d->d_name,
940
        O_RDONLY|O_CLOEXEC, "r" UL_CLOEXECSTR);
941
    if (f) {
942
      mnt_table_parse_stream(tb, f, d->d_name);
943
      fclose(f);
944
    }
945
  }
946
947
out:
948
  for (i = 0; i < n; i++)
949
    free(namelist[i]);
950
  free(namelist);
951
  if (dir)
952
    closedir(dir);
953
  return r;
954
}
955
#endif
956
957
/**
958
 * mnt_table_parse_dir:
959
 * @tb: mount table
960
 * @dirname: directory
961
 *
962
 * The directory:
963
 *  - files are sorted by strverscmp(3)
964
 *  - files that start with "." are ignored (e.g. ".10foo.fstab")
965
 *  - files without the ".fstab" extension are ignored
966
 *
967
 * Returns: 0 on success or negative number in case of error.
968
 */
969
int mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname)
970
0
{
971
0
  return __mnt_table_parse_dir(tb, dirname);
972
0
}
973
974
struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt, int empty_for_enoent)
975
0
{
976
0
  struct libmnt_table *tb;
977
978
0
  if (!filename)
979
0
    return NULL;
980
0
  if (!mnt_is_path(filename))
981
0
    return empty_for_enoent ? mnt_new_table() : NULL;
982
983
0
  tb = mnt_new_table();
984
0
  if (tb) {
985
0
    DBG(TAB, ul_debugobj(tb, "new tab for file: %s", filename));
986
0
    tb->fmt = fmt;
987
0
    if (mnt_table_parse_file(tb, filename) != 0) {
988
0
      mnt_unref_table(tb);
989
0
      tb = NULL;
990
0
    }
991
0
  }
992
0
  return tb;
993
0
}
994
995
/**
996
 * mnt_new_table_from_file:
997
 * @filename: /etc/{m,fs}tab or /proc/self/mountinfo path
998
 *
999
 * Same as mnt_new_table() + mnt_table_parse_file(). Use this function for private
1000
 * files only. This function does not allow using the error callback, so you
1001
 * cannot provide any feedback to end-users about broken records in files (e.g.
1002
 * fstab).
1003
 *
1004
 * Returns: newly allocated tab on success and NULL in case of error.
1005
 */
1006
struct libmnt_table *mnt_new_table_from_file(const char *filename)
1007
0
{
1008
0
  if (!filename)
1009
0
    return NULL;
1010
1011
0
  return __mnt_new_table_from_file(filename, MNT_FMT_GUESS, 0);
1012
0
}
1013
1014
/**
1015
 * mnt_new_table_from_dir
1016
 * @dirname: directory with *.fstab files
1017
 *
1018
 * Returns: newly allocated tab on success and NULL in case of error.
1019
 */
1020
struct libmnt_table *mnt_new_table_from_dir(const char *dirname)
1021
0
{
1022
0
  struct libmnt_table *tb;
1023
1024
0
  if (!dirname)
1025
0
    return NULL;
1026
0
  tb = mnt_new_table();
1027
0
  if (tb && mnt_table_parse_dir(tb, dirname) != 0) {
1028
0
    mnt_unref_table(tb);
1029
0
    tb = NULL;
1030
0
  }
1031
0
  return tb;
1032
0
}
1033
1034
/**
1035
 * mnt_table_set_parser_errcb:
1036
 * @tb: pointer to table
1037
 * @cb: pointer to callback function
1038
 *
1039
 * The error callback function is called by table parser (mnt_table_parse_file())
1040
 * in case of a syntax error. The callback function could be used for error
1041
 * evaluation, libmount will continue/stop parsing according to callback return
1042
 * codes:
1043
 *
1044
 *   <0  : fatal error (abort parsing)
1045
 *    0  : success (parsing continues)
1046
 *   >0  : recoverable error (the line is ignored, parsing continues).
1047
 *
1048
 * Returns: 0 on success or negative number in case of error.
1049
 */
1050
int mnt_table_set_parser_errcb(struct libmnt_table *tb,
1051
    int (*cb)(struct libmnt_table *tb, const char *filename, int line))
1052
0
{
1053
0
  if (!tb)
1054
0
    return -EINVAL;
1055
0
  tb->errcb = cb;
1056
0
  return 0;
1057
0
}
1058
1059
/*
1060
 * Filter out entries during tab file parsing. If @cb returns 1, then the entry
1061
 * is ignored.
1062
 */
1063
int mnt_table_set_parser_fltrcb(struct libmnt_table *tb,
1064
    int (*cb)(struct libmnt_fs *, void *),
1065
    void *data)
1066
0
{
1067
0
  if (!tb)
1068
0
    return -EINVAL;
1069
1070
0
  DBG(TAB, ul_debugobj(tb, "%s table parser filter", cb ? "set" : "unset"));
1071
0
  tb->fltrcb = cb;
1072
0
  tb->fltrcb_data = data;
1073
0
  return 0;
1074
0
}
1075
1076
/*
1077
 * mnt_table_enable_noautofs:
1078
 * @tb: table
1079
 * @ignore: ignore or don't ignore
1080
 *
1081
 * Enable/disable ignore autofs mount table entries on reading.
1082
 */
1083
int mnt_table_enable_noautofs(struct libmnt_table *tb, int ignore)
1084
0
{
1085
0
  if (!tb)
1086
0
    return -EINVAL;
1087
0
  tb->noautofs = ignore ? 1 : 0;
1088
0
  return 0;
1089
0
}
1090
1091
/*
1092
 * mnt_table_is_noautofs:
1093
 * @tb: table
1094
 *
1095
 * Return the the enabled status of ignore autofs mount table entries.
1096
 */
1097
int mnt_table_is_noautofs(struct libmnt_table *tb)
1098
51.8k
{
1099
51.8k
  return tb ? tb->noautofs : 0;
1100
51.8k
}
1101
1102
/**
1103
 * mnt_table_parse_swaps:
1104
 * @tb: table
1105
 * @filename: overwrites default (/proc/swaps or $LIBMOUNT_SWAPS) or NULL
1106
 *
1107
 * This function parses /proc/swaps and appends new lines to the @tab.
1108
 *
1109
 * See also mnt_table_set_parser_errcb().
1110
 *
1111
 * Returns: 0 on success or negative number in case of error.
1112
 */
1113
int mnt_table_parse_swaps(struct libmnt_table *tb, const char *filename)
1114
0
{
1115
0
  if (!tb)
1116
0
    return -EINVAL;
1117
0
  if (!filename) {
1118
0
    filename = mnt_get_swaps_path();
1119
0
    if (!filename)
1120
0
      return -EINVAL;
1121
0
  }
1122
1123
0
  tb->fmt = MNT_FMT_SWAPS;
1124
1125
0
  return mnt_table_parse_file(tb, filename);
1126
0
}
1127
1128
/**
1129
 * mnt_table_parse_fstab:
1130
 * @tb: table
1131
 * @filename: overwrites default (/etc/fstab or $LIBMOUNT_FSTAB) or NULL
1132
 *
1133
 * This function parses /etc/fstab and appends new lines to the @tab. If the
1134
 * @filename is a directory, then mnt_table_parse_dir() is called.
1135
 *
1136
 * See also mnt_table_set_parser_errcb().
1137
 *
1138
 * Returns: 0 on success or negative number in case of error.
1139
 */
1140
int mnt_table_parse_fstab(struct libmnt_table *tb, const char *filename)
1141
0
{
1142
0
  struct stat st;
1143
0
  int rc = 0;
1144
1145
0
  if (!tb)
1146
0
    return -EINVAL;
1147
0
  if (!filename)
1148
0
    filename = mnt_get_fstab_path();
1149
0
  if (!filename)
1150
0
    return -EINVAL;
1151
0
  if (mnt_safe_stat(filename, &st) != 0)
1152
0
    return -errno;
1153
1154
0
  tb->fmt = MNT_FMT_FSTAB;
1155
1156
0
  if (S_ISREG(st.st_mode))
1157
0
    rc = mnt_table_parse_file(tb, filename);
1158
0
  else if (S_ISDIR(st.st_mode))
1159
0
    rc = mnt_table_parse_dir(tb, filename);
1160
0
  else
1161
0
    rc = -EINVAL;
1162
1163
0
  return rc;
1164
0
}
1165
1166
/*
1167
 * This function uses @uf to find a corresponding record in @tb, then the record
1168
 * from @tb is updated (user specific mount options are added).
1169
 *
1170
 * Note that @uf must contain only user specific mount options instead of
1171
 * VFS options (note that FS options are ignored).
1172
 *
1173
 * Returns modified filesystem (from @tb) or NULL.
1174
 */
1175
static struct libmnt_fs *mnt_table_merge_user_fs(struct libmnt_table *tb, struct libmnt_fs *uf)
1176
0
{
1177
0
  struct libmnt_fs *fs;
1178
0
  struct libmnt_iter itr;
1179
0
  const char *optstr, *src, *target, *root, *attrs;
1180
0
  int id;
1181
1182
0
  if (!tb || !uf)
1183
0
    return NULL;
1184
1185
0
  DBG(TAB, ul_debugobj(tb, "merging user fs"));
1186
1187
0
  src = mnt_fs_get_srcpath(uf);
1188
0
  target = mnt_fs_get_target(uf);
1189
0
  optstr = mnt_fs_get_user_options(uf);
1190
0
  attrs = mnt_fs_get_attributes(uf);
1191
0
  root = mnt_fs_get_root(uf);
1192
0
  id = mnt_fs_get_id(uf);
1193
1194
0
  if (!src || !target || !root || (!attrs && !optstr))
1195
0
    return NULL;
1196
1197
0
  mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
1198
1199
0
  while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
1200
0
    const char *r = mnt_fs_get_root(fs);
1201
1202
0
    if (fs->flags & MNT_FS_MERGED)
1203
0
      continue;
1204
1205
0
    if (id > 0 && mnt_fs_get_id(fs)) {
1206
0
      DBG(TAB, ul_debugobj(tb, " using ID"));
1207
0
      if (mnt_fs_get_id(fs) == id)
1208
0
        break;
1209
0
    } else if (r && strcmp(r, root) == 0
1210
0
        && mnt_fs_streq_target(fs, target)
1211
0
        && mnt_fs_streq_srcpath(fs, src))
1212
0
      break;
1213
0
  }
1214
1215
0
  if (fs) {
1216
0
    DBG(TAB, ul_debugobj(tb, " found"));
1217
0
    mnt_fs_append_options(fs, optstr);
1218
0
    mnt_fs_append_attributes(fs, attrs);
1219
0
    mnt_fs_set_bindsrc(fs, mnt_fs_get_bindsrc(uf));
1220
0
    fs->flags |= MNT_FS_MERGED;
1221
1222
0
    DBG(TAB, mnt_fs_print_debug(fs, stderr));
1223
0
  }
1224
0
  return fs;
1225
0
}
1226
1227
/* default filename is /proc/self/mountinfo
1228
 */
1229
int __mnt_table_parse_mountinfo(struct libmnt_table *tb, const char *filename,
1230
         struct libmnt_table *u_tb)
1231
0
{
1232
0
  int rc = 0, priv_utab = 0;
1233
0
  int explicit_file = filename ? 1 : 0;
1234
1235
0
  assert(tb);
1236
1237
0
  if (filename)
1238
0
    DBG(TAB, ul_debugobj(tb, "%s requested as mount table", filename));
1239
1240
0
  if (!filename || strcmp(filename, _PATH_PROC_MOUNTINFO) == 0) {
1241
0
    filename = _PATH_PROC_MOUNTINFO;
1242
0
    tb->fmt = MNT_FMT_MOUNTINFO;
1243
0
    DBG(TAB, ul_debugobj(tb, "mountinfo parse: #1 read mountinfo"));
1244
0
  } else
1245
0
    tb->fmt = MNT_FMT_GUESS;
1246
1247
0
  rc = mnt_table_parse_file(tb, filename);
1248
0
  if (rc) {
1249
0
    if (explicit_file)
1250
0
      return rc;
1251
1252
    /* hmm, old kernel? ...try /proc/mounts */
1253
0
    tb->fmt = MNT_FMT_MTAB;
1254
0
    return mnt_table_parse_file(tb, _PATH_PROC_MOUNTS);
1255
0
  }
1256
1257
0
  if (!is_mountinfo(tb))
1258
0
    return 0;
1259
0
  DBG(TAB, ul_debugobj(tb, "mountinfo parse: #2 read utab"));
1260
1261
0
  if (mnt_table_get_nents(tb) == 0)
1262
0
    return 0;     /* empty, ignore utab */
1263
  /*
1264
   * try to read the user specific information from /run/mount/utabs
1265
   */
1266
0
  if (!u_tb) {
1267
0
    const char *utab = mnt_get_utab_path();
1268
1269
0
    if (!utab || is_file_empty(utab))
1270
0
      return 0;
1271
1272
0
    u_tb = mnt_new_table();
1273
0
    if (!u_tb)
1274
0
      return -ENOMEM;
1275
1276
0
    u_tb->fmt = MNT_FMT_UTAB;
1277
0
    mnt_table_set_parser_fltrcb(u_tb, tb->fltrcb, tb->fltrcb_data);
1278
1279
0
    rc = mnt_table_parse_file(u_tb, utab);
1280
0
    priv_utab = 1;
1281
0
  }
1282
1283
0
  DBG(TAB, ul_debugobj(tb, "mountinfo parse: #3 merge utab"));
1284
1285
0
  if (rc == 0) {
1286
0
    struct libmnt_fs *u_fs;
1287
0
    struct libmnt_iter itr;
1288
1289
0
    mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
1290
1291
    /*  merge user options into mountinfo from the kernel */
1292
0
    while(mnt_table_next_fs(u_tb, &itr, &u_fs) == 0)
1293
0
      mnt_table_merge_user_fs(tb, u_fs);
1294
0
  }
1295
1296
1297
0
  if (priv_utab)
1298
0
    mnt_unref_table(u_tb);
1299
0
  return 0;
1300
0
}
1301
/**
1302
 * mnt_table_parse_mtab:
1303
 * @tb: table
1304
 * @filename: overwrites default or NULL
1305
 *
1306
 * The default filename is /proc/self/mountinfo. If the mount table is a
1307
 * mountinfo file then /run/mount/utabs is parsed too and both files are merged
1308
 * to the one libmnt_table.
1309
 *
1310
 * The file /etc/mtab is no more used. The function uses "mtab" in the name for
1311
 * backward compatibility only.
1312
 *
1313
 * It's strongly recommended to use NULL as a @filename to keep code portable.
1314
 *
1315
 * See also mnt_table_set_parser_errcb().
1316
 *
1317
 * Returns: 0 on success or negative number in case of error.
1318
 */
1319
int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
1320
0
{
1321
0
  return __mnt_table_parse_mountinfo(tb, filename, NULL);
1322
0
}