/** * mnt_table_parse_fstab: * @tb: table * @filename: overwrites default (/etc/fstab or $LIBMOUNT_FSTAB) or NULL * * This function parses /etc/fstab or /etc/fstab.d and appends new lines to the * @tab. If the system contains classic fstab file and also fstab.d directory * then the fstab file is parsed before the fstab.d directory. * * The fstab.d directory: * - files are sorted by strverscmp(3) * - files that starts with "." are ignored (e.g. ".10foo.fstab") * - files without the ".fstab" extension are ignored * * See also mnt_table_set_parser_errcb(). * * Returns: 0 on success or negative number in case of error. */ int mnt_table_parse_fstab(struct libmnt_table *tb, const char *filename) { FILE *f; assert(tb); if (!tb) return -EINVAL; if (!filename) filename = mnt_get_fstab_path(); tb->fmt = MNT_FMT_FSTAB; f = fopen(filename, "r"); if (f) { int rc = mnt_table_parse_stream(tb, f, filename); fclose(f); if (rc) return rc; if (strcmp(filename, _PATH_MNTTAB)) /* /etc/fstab.d sould be used together with /etc/fstab only */ return 0; } if (!access(_PATH_MNTTAB_DIR, R_OK)) return mnt_table_parse_dir(tb, _PATH_MNTTAB_DIR); return 0; }
static int mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) { int n = 0, i; DIR *dir = NULL; struct dirent **namelist = NULL; /* TODO: it would be nice to have a scandir() implementation that * is able to use already opened directory */ n = scandir(dirname, &namelist, NULL, versionsort); if (n <= 0) return 0; /* let use "at" functions rather than play crazy games with paths... */ dir = opendir(dirname); if (!dir) return -errno; for (i = 0; i < n; i++) { struct dirent *d = namelist[i]; struct stat st; size_t namesz; FILE *f; #ifdef _DIRENT_HAVE_D_TYPE if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG && d->d_type != DT_LNK) continue; #endif if (*d->d_name == '.') continue; #define MNT_MNTTABDIR_EXTSIZ (sizeof(MNT_MNTTABDIR_EXT) - 1) namesz = strlen(d->d_name); if (!namesz || namesz < MNT_MNTTABDIR_EXTSIZ + 1 || strcmp(d->d_name + (namesz - MNT_MNTTABDIR_EXTSIZ), MNT_MNTTABDIR_EXT)) continue; if (fstat_at(dirfd(dir), _PATH_MNTTAB_DIR, d->d_name, &st, 0) || !S_ISREG(st.st_mode)) continue; f = fopen_at(dirfd(dir), _PATH_MNTTAB_DIR, d->d_name, O_RDONLY, "r"); if (f) { mnt_table_parse_stream(tb, f, d->d_name); fclose(f); } } for (i = 0; i < n; i++) free(namelist[i]); free(namelist); if (dir) closedir(dir); return 0; }
static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) { int n = 0, i, r = 0; DIR *dir = NULL; struct dirent **namelist = NULL; n = scandir(dirname, &namelist, mnt_table_parse_dir_filter, versionsort); if (n <= 0) return 0; /* let use "at" functions rather than play crazy games with paths... */ dir = opendir(dirname); if (!dir) { r = -errno; goto out; } for (i = 0; i < n; i++) { struct dirent *d = namelist[i]; struct stat st; FILE *f; if (fstat_at(dirfd(dir), _PATH_MNTTAB_DIR, d->d_name, &st, 0) || !S_ISREG(st.st_mode)) continue; f = fopen_at(dirfd(dir), _PATH_MNTTAB_DIR, d->d_name, O_RDONLY, "r"); if (f) { mnt_table_parse_stream(tb, f, d->d_name); fclose(f); } } out: for (i = 0; i < n; i++) free(namelist[i]); free(namelist); if (dir) closedir(dir); return r; }
/** * mnt_table_parse_file: * @tb: tab pointer * @filename: file * * Parses whole table (e.g. /etc/mtab) and appends new records to the @tab. * * The libmount parser ignores broken (syntax error) lines, these lines are * reported to caller by errcb() function (see mnt_table_set_parser_errcb()). * * Returns: 0 on success, negative number in case of error. */ int mnt_table_parse_file(struct libmnt_table *tb, const char *filename) { FILE *f; int rc; assert(tb); assert(filename); if (!filename || !tb) return -EINVAL; f = fopen(filename, "r"); if (f) { rc = mnt_table_parse_stream(tb, f, filename); fclose(f); } else return -errno; return rc; }
static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname) { int n = 0, i; int dd; struct dirent **namelist = NULL; dd = open(dirname, O_RDONLY|O_CLOEXEC|O_DIRECTORY); if (dd < 0) return -errno; n = scandirat(dd, ".", &namelist, mnt_table_parse_dir_filter, versionsort); if (n <= 0) { close(dd); return 0; } for (i = 0; i < n; i++) { struct dirent *d = namelist[i]; struct stat st; FILE *f; if (fstat_at(dd, ".", d->d_name, &st, 0) || !S_ISREG(st.st_mode)) continue; f = fopen_at(dd, ".", d->d_name, O_RDONLY, "r"); if (f) { mnt_table_parse_stream(tb, f, d->d_name); fclose(f); } } for (i = 0; i < n; i++) free(namelist[i]); free(namelist); close(dd); return 0; }
/** * mnt_table_parse_stream: * @tb: tab pointer * @f: file stream * @filename: filename used for debug and error messages * * Returns: 0 on success, negative number in case of error. */ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename) { int rc = -1; int flags = 0; pid_t tid = -1; struct libmnt_fs *fs = NULL; struct libmnt_parser pa = { .line = 0 }; assert(tb); assert(f); assert(filename); DBG(TAB, ul_debugobj(tb, "%s: start parsing [entries=%d, filter=%s]", filename, mnt_table_get_nents(tb), tb->fltrcb ? "yes" : "not")); pa.filename = filename; pa.f = f; /* necessary for /proc/mounts only, the /proc/self/mountinfo * parser sets the flag properly */ if (filename && strcmp(filename, _PATH_PROC_MOUNTS) == 0) flags = MNT_FS_KERNEL; while (!feof(f)) { if (!fs) { fs = mnt_new_fs(); if (!fs) goto err; } rc = mnt_table_parse_next(&pa, tb, fs); if (!rc && tb->fltrcb && tb->fltrcb(fs, tb->fltrcb_data)) rc = 1; /* filtered out by callback... */ if (!rc) { rc = mnt_table_add_fs(tb, fs); fs->flags |= flags; if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO) { rc = kernel_fs_postparse(tb, fs, &tid, filename); if (rc) mnt_table_remove_fs(tb, fs); } } if (rc) { if (rc > 0) { mnt_reset_fs(fs); assert(fs->refcount == 1); continue; /* recoverable error, reuse fs*/ } mnt_unref_fs(fs); if (feof(f)) break; goto err; /* fatal error */ } mnt_unref_fs(fs); fs = NULL; } DBG(TAB, ul_debugobj(tb, "%s: stop parsing (%d entries)", filename, mnt_table_get_nents(tb))); parser_cleanup(&pa); return 0; err: DBG(TAB, ul_debugobj(tb, "%s: parse error (rc=%d)", filename, rc)); parser_cleanup(&pa); return rc; } /** * mnt_table_parse_file: * @tb: tab pointer * @filename: file * * Parses the whole table (e.g. /etc/fstab) and appends new records to the @tab. * * The libmount parser ignores broken (syntax error) lines, these lines are * reported to the caller by the errcb() function (see mnt_table_set_parser_errcb()). * * Returns: 0 on success, negative number in case of error. */ int mnt_table_parse_file(struct libmnt_table *tb, const char *filename) { FILE *f; int rc; if (!filename || !tb) return -EINVAL; f = fopen(filename, "r" UL_CLOEXECSTR); if (f) { rc = mnt_table_parse_stream(tb, f, filename); fclose(f); } else rc = -errno; DBG(TAB, ul_debugobj(tb, "parsing done [filename=%s, rc=%d]", filename, rc)); return rc; }