From 3a5b1b1d5d8cae6e7c4ee4f33f2fc20be3ddf6f4 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 21 Oct 2010 08:57:02 +0200 Subject: libmount: allow to overwrite mtab/fstab paths Signed-off-by: Karel Zak --- shlibs/mount/src/context.c | 4 +-- shlibs/mount/src/lock.c | 11 ++++--- shlibs/mount/src/mount.h.in | 6 ++-- shlibs/mount/src/mount.sym | 2 ++ shlibs/mount/src/tab_parse.c | 73 ++++++++++++++++++++++++++++--------------- shlibs/mount/src/tab_update.c | 58 ++++++++++++++++++++-------------- shlibs/mount/src/utils.c | 48 ++++++++++++++++++++++++---- 7 files changed, 140 insertions(+), 62 deletions(-) (limited to 'shlibs/mount/src') diff --git a/shlibs/mount/src/context.c b/shlibs/mount/src/context.c index 863003926..21a5d8a1d 100644 --- a/shlibs/mount/src/context.c +++ b/shlibs/mount/src/context.c @@ -547,7 +547,7 @@ int mnt_context_get_fstab(mnt_context *cxt, mnt_tab **tb) if (!cxt->fstab) return -ENOMEM; cxt->flags &= ~MNT_FL_EXTERN_FSTAB; - rc = mnt_tab_parse_fstab(cxt->fstab); + rc = mnt_tab_parse_fstab(cxt->fstab, NULL); if (rc) return rc; } @@ -585,7 +585,7 @@ int mnt_context_get_mtab(mnt_context *cxt, mnt_tab **tb) cxt->mtab = mnt_new_tab(); if (!cxt->mtab) return -ENOMEM; - rc = mnt_tab_parse_mtab(cxt->mtab); + rc = mnt_tab_parse_mtab(cxt->mtab, NULL); if (rc) return rc; } diff --git a/shlibs/mount/src/lock.c b/shlibs/mount/src/lock.c index 5e18ba250..9149c7b90 100644 --- a/shlibs/mount/src/lock.c +++ b/shlibs/mount/src/lock.c @@ -231,7 +231,6 @@ void mnt_unlock_file(mnt_lock *ml) if (!ml) return; - DBG(LOCKS, mnt_debug_h(ml, "(%d) unlocking/cleaning", getpid())); if (ml->locked == 0 && ml->lockfile && ml->linkfile) { @@ -247,6 +246,10 @@ void mnt_unlock_file(mnt_lock *ml) lo.st_dev == li.st_dev && lo.st_ino == li.st_ino) ml->locked = 1; } + + DBG(LOCKS, mnt_debug_h(ml, "(%d) %s", getpid(), + ml->locked ? "unlocking" : "cleaning")); + if (ml->linkfile) unlink(ml->linkfile); if (ml->lockfile_fd >= 0) @@ -468,7 +471,6 @@ void increment_data(const char *filename, int verbose, int loopno) void clean_lock(void) { - fprintf(stderr, "%d: cleaning\n", getpid()); if (!lock) return; mnt_unlock_file(lock); @@ -508,8 +510,9 @@ int test_lock(struct mtest *ts, int argc, char *argv[]) if (!datafile || !loops) return -EINVAL; - fprintf(stderr, "%d: start: synctime=%u, verbose=%d, datafile=%s, loops=%d\n", - getpid(), (int) synctime, verbose, datafile, loops); + if (verbose) + fprintf(stderr, "%d: start: synctime=%u, datafile=%s, loops=%d\n", + getpid(), (int) synctime, datafile, loops); atexit(clean_lock); diff --git a/shlibs/mount/src/mount.h.in b/shlibs/mount/src/mount.h.in index a1143ee27..01ba5a6d6 100644 --- a/shlibs/mount/src/mount.h.in +++ b/shlibs/mount/src/mount.h.in @@ -132,6 +132,8 @@ extern int mnt_fstype_is_pseudofs(const char *type); extern int mnt_match_fstype(const char *type, const char *pattern); extern int mnt_match_options(const char *optstr, const char *pattern); extern const char *mnt_get_writable_mtab_path(void); +extern const char *mnt_get_fstab_path(void); +extern const char *mnt_get_mtab_path(void); /* cache.c */ extern mnt_cache *mnt_new_cache(void); @@ -251,8 +253,8 @@ extern int mnt_fs_print_debug(mnt_fs *ent, FILE *file); extern mnt_tab *mnt_new_tab_from_file(const char *filename); extern int mnt_tab_parse_stream(mnt_tab *tb, FILE *f, const char *filename); extern int mnt_tab_parse_file(mnt_tab *tb, const char *filename); -extern int mnt_tab_parse_fstab(mnt_tab *tb); -extern int mnt_tab_parse_mtab(mnt_tab *tb); +extern int mnt_tab_parse_fstab(mnt_tab *tb, const char *filename); +extern int mnt_tab_parse_mtab(mnt_tab *tb, const char *filename); extern int mnt_tab_set_parser_errcb(mnt_tab *tb, int (*cb)(mnt_tab *tb, const char *filename, int line)); diff --git a/shlibs/mount/src/mount.sym b/shlibs/mount/src/mount.sym index f97d0048b..2db74df34 100644 --- a/shlibs/mount/src/mount.sym +++ b/shlibs/mount/src/mount.sym @@ -55,6 +55,8 @@ global: mnt_get_builtin_optmap; mnt_get_library_version; mnt_get_writable_mtab_path; + mnt_get_fstab_path; + mnt_get_mtab_path; mnt_init_debug; mnt_iter_get_direction; mnt_lock_file; diff --git a/shlibs/mount/src/tab_parse.c b/shlibs/mount/src/tab_parse.c index 224fcb68f..5ac51ab87 100644 --- a/shlibs/mount/src/tab_parse.c +++ b/shlibs/mount/src/tab_parse.c @@ -437,6 +437,7 @@ int mnt_tab_set_parser_errcb(mnt_tab *tb, /** * mnt_tab_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 @@ -452,28 +453,30 @@ int mnt_tab_set_parser_errcb(mnt_tab *tb, * Returns: 0 on success (least one record has been successfully parsed) or * negative number in case of error. */ -int mnt_tab_parse_fstab(mnt_tab *tb) +int mnt_tab_parse_fstab(mnt_tab *tb, const char *filename) { int num, n = 0, i; DIR *dir = NULL; FILE *f; struct dirent **namelist = NULL; - const char *env; assert(tb); if (!tb) return -EINVAL; num = mnt_tab_get_nents(tb); - env = mnt_getenv_safe("LIBMOUNT_FSTAB"); - f = fopen(env ? : _PATH_MNTTAB, "r"); + if (!filename) + filename = mnt_get_fstab_path(); + + f = fopen(filename, "r"); if (f) { - mnt_tab_parse_stream(tb, f, _PATH_MNTTAB); + mnt_tab_parse_stream(tb, f, filename); fclose(f); - if (env) - goto done; /* ignore /etc/fstab.d if $LIBMOUNT_FSTAB defined */ + if (strcmp(filename, _PATH_MNTTAB)) + /* /etc/fstab.d sould be used together with /etc/fstab only */ + goto done; } /* TODO: it would be nice to have a scandir() implementaion that @@ -581,46 +584,66 @@ static mnt_fs *mnt_tab_merge_userspace_fs(mnt_tab *tb, mnt_fs *uf) /** * mnt_tab_parse_mtab: * @tb: table + * @filename: overwrites default (/etc/mtab or $LIBMOUNT_MTAB) or NULL * * This function parses /etc/mtab or {/proc/self,/var/run/mount}/mountinfo or * /proc/mounts. Note that the /var/run/mount/mountinfo file is optional and * contains userspace specific mount options only. * + * Note that /var/run/mount/mountinfo is ignored if /etc/mtab is writable or + * $LIBMOUNT_MTAB or @filename does not end with "mountinfo" postfix. + * * See also mnt_tab_set_parser_errcb(). * * Returns: 0 on success or negative number in case of error. */ -int mnt_tab_parse_mtab(mnt_tab *tb) +int mnt_tab_parse_mtab(mnt_tab *tb, const char *filename) { int rc; - mnt_tab *u_tb; - mnt_fs *u_fs; - mnt_iter itr; - const char *env = mnt_getenv_safe("LIBMOUNT_MTAB"); - if ((env && !endswith(env, "mountinfo")) || mnt_has_regular_mtab()) { - rc = mnt_tab_parse_file(tb, env ? : _PATH_MOUNTED); + if (!filename) + filename = mnt_get_writable_mtab_path(); + + /* + * Regular mtab file + */ + if (filename && !endswith(filename, "mountinfo")) { + rc = mnt_tab_parse_file(tb, filename); if (!rc) - return 0; /* system with regular mtab */ + return 0; + filename = NULL; } - /* read kernel information from /proc/self/mountinfo */ + /* + * useless /etc/mtab or /var/run/mount/mountinfo is supported + * -- read kernel information from /proc/self/mountinfo + */ rc = mnt_tab_parse_file(tb, _PATH_PROC_MOUNTINFO); if (rc) /* hmm, old kernel? ...try /proc/mounts */ return mnt_tab_parse_file(tb, _PATH_PROC_MOUNTS); - /* try to read userspace specific information from /var/run/mount */ - u_tb = mnt_new_tab_from_file(env ? : MNT_PATH_MOUNTINFO); - if (!u_tb) - return 0; /* private mountinfo does not exist */ + /* + * try to read userspace specific information from + * /var/run/mount/mountinfo + */ + if (filename) { + mnt_tab *u_tb = mnt_new_tab_from_file(filename); + + assert(endswith(filename, "mountinfo")); - mnt_reset_iter(&itr, MNT_ITER_BACKWARD); + if (u_tb) { + mnt_fs *u_fs; + mnt_iter itr; - /* merge userspace options into mountinfo from kernel */ - while(mnt_tab_next_fs(u_tb, &itr, &u_fs) == 0) - mnt_tab_merge_userspace_fs(tb, u_fs); + mnt_reset_iter(&itr, MNT_ITER_BACKWARD); - mnt_free_tab(u_tb); + /* merge userspace options into mountinfo from kernel */ + while(mnt_tab_next_fs(u_tb, &itr, &u_fs) == 0) + mnt_tab_merge_userspace_fs(tb, u_fs); + + mnt_free_tab(u_tb); + } + } return 0; } diff --git a/shlibs/mount/src/tab_update.c b/shlibs/mount/src/tab_update.c index 830225277..946cdc090 100644 --- a/shlibs/mount/src/tab_update.c +++ b/shlibs/mount/src/tab_update.c @@ -27,6 +27,12 @@ * /var/run/mount/mountinfo file (the file format compatible to * /proc/self/mountinfo) * + * Note that mnt_update_* interface does not manage mount options. It's callers + * responsibility set the right mount options (for example merge options from + * mtab with command line on MS_REMOUNT). + * + * The small exception is the /var/run/mount/mountinfo file where are store + * userspace mount options only. This is done by mnt_prepare_update(). * * The mtab is always updated in two steps. The first step is to prepare a new * update entry -- mnt_prepare_update(), this step has to be done before @@ -126,11 +132,11 @@ int mnt_update_set_filename(mnt_update *upd, const char *filename) assert(upd); if (!upd) - return -1; + return -EINVAL; if (filename) { p = strdup(filename); if (!p) - return -1; + return -ENOMEM; } free(upd->filename); upd->filename = p; @@ -164,7 +170,7 @@ int mnt_update_set_action(mnt_update *upd, int action) { assert(upd); if (!upd) - return -1; + return -EINVAL; upd->action = action; return 0; } @@ -184,7 +190,7 @@ int mnt_update_set_format(mnt_update *upd, int format) { assert(upd); if (!upd) - return -1; + return -EINVAL; upd->format = format; return 0; } @@ -219,11 +225,11 @@ int mnt_update_set_fs(mnt_update *upd, const mnt_fs *fs) assert(upd); if (!upd) - return -1; + return -EINVAL; if (fs) { x = mnt_copy_fs(fs); if (!x) - return -1; + return -ENOMEM; } mnt_free_fs(upd->fs); @@ -247,7 +253,7 @@ int mnt_update_set_mountflags(mnt_update *upd, unsigned long flags) { assert(upd); if (!upd) - return -1; + return -EINVAL; upd->mountflags = flags; return 0; } @@ -305,8 +311,8 @@ int mnt_update_set_old_target(mnt_update *upd, const char *target) char *p = NULL; if (!upd) - return -1; - if (p) { + return -EINVAL; + if (target) { p = strdup(target); if (!p) return -1; @@ -331,7 +337,7 @@ static int fprintf_mountinfo_fs(FILE *f, mnt_fs *fs) assert(f); if (!fs || !f) - return -1; + return -EINVAL; devno = mnt_fs_get_devno(fs); source = mangle(mnt_fs_get_source(fs)); root = mangle(mnt_fs_get_root(fs)); @@ -372,7 +378,7 @@ static int fprintf_mtab_fs(FILE *f, mnt_fs *fs) assert(f); if (!fs || !f) - return -1; + return -EINVAL; m1 = mangle(mnt_fs_get_source(fs)); m2 = mangle(mnt_fs_get_target(fs)); @@ -408,7 +414,7 @@ static int update_file(const char *filename, int fmt, mnt_tab *tb) assert(tb); if (!tb) - goto error; + return -EINVAL; DBG(UPDATE, mnt_debug("%s: update from tab %p", filename, tb)); @@ -450,7 +456,7 @@ error: DBG(UPDATE, mnt_debug("%s: update from tab %p failed", filename, tb)); if (f) fclose(f); - return -1; + return errno ? -errno : -1; } static int set_fs_root(mnt_update *upd, mnt_fs *fs) @@ -602,10 +608,8 @@ int mnt_prepare_update(mnt_update *upd) mnt_fs_get_optstr(upd->fs))); if (!upd->filename) { - const char *p = mnt_getenv_safe("LIBMOUNT_MTAB"); + const char *p = mnt_get_writable_mtab_path(); - if (!p) - p = mnt_get_writable_mtab_path(); if (!p) { if (errno) { rc = -errno; @@ -631,6 +635,10 @@ int mnt_prepare_update(mnt_update *upd) upd->format = MNT_FMT_MTAB; } + DBG(UPDATE, mnt_debug_h(upd, "format: %s", + upd->format == MNT_FMT_MOUNTINFO ? "mountinfo" : + upd->format == MNT_FMT_FSTAB ? "fstab" : "mtab")); + /* TODO: cannonicalize source and target paths on mnt->fs */ if (upd->format != MNT_FMT_FSTAB) { @@ -643,13 +651,13 @@ int mnt_prepare_update(mnt_update *upd) /* umount */ if (upd->action == MNT_ACT_UMOUNT) - return 0; + goto done; /* * A) classic /etc/mtab or /etc/fstab update */ if (upd->format != MNT_FMT_MOUNTINFO) - return 0; + goto done; /* * B) /var/run/mount/mountinfo @@ -680,6 +688,7 @@ int mnt_prepare_update(mnt_update *upd) u = NULL; } +done: if (!upd->nolock && !upd->lc) { upd->lc = mnt_new_lock(upd->filename, 0); if (!upd->lc) { @@ -908,15 +917,17 @@ static int update(mnt_update *upd) rc = mnt_prepare_update(upd); if (!rc) { /* setup lock fallback */ + int rc; + lock = mnt_update_get_lock(upd); atexit(lock_fallback); - return mnt_update_file(upd); + rc = mnt_update_file(upd); + lock = NULL; + return rc; } - if (rc == 1) { - printf("update: update is not reuquired\n"); + if (rc == 1) return 0; - } fprintf(stderr, "update: failed to prepare update\n"); return -1; } @@ -966,7 +977,8 @@ int test_add_fstab(struct mtest *ts, int argc, char *argv[]) return -1; mnt_update_disable_lock(upd, TRUE); /* lock is unnecessary */ - mnt_update_set_filename(upd, _PATH_MNTTAB); /* fstab */ + + mnt_update_set_filename(upd, mnt_get_fstab_path()); mnt_update_set_format(upd, MNT_FMT_FSTAB); rc = update(upd); diff --git a/shlibs/mount/src/utils.c b/shlibs/mount/src/utils.c index 3aa8d9b82..09457345c 100644 --- a/shlibs/mount/src/utils.c +++ b/shlibs/mount/src/utils.c @@ -416,20 +416,56 @@ int mnt_has_regular_mtab(void) return 0; } +/** + * mnt_get_fstab_path: + * + * Returns: path to /etc/fstab or $LIBMOUNT_FSTAB. + */ +const char *mnt_get_fstab_path(void) +{ + const char *p = mnt_getenv_safe("LIBMOUNT_FSTAB"); + return p ? : _PATH_MNTTAB; +} + +/** + * mnt_get_mtab_path: + * + * This function returns *default* location of the mtab file. The result does not have to + * be writable. See also mnt_get_writable_mtab_path(). + * + * It's possible that libmount uses /proc/self/mountinfo together with + * /var/run/mount/mountinfo file (or files). The ideal solution is to use + * mnt_tab_parse_mtab() that provides abstraction and returns mtab records + * independently on the way how things are managed by libmount. + * + * Returns: path to /etc/mtab or $LIBMOUNT_MTAB. + */ +const char *mnt_get_mtab_path(void) +{ + const char *p = mnt_getenv_safe("LIBMOUNT_MTAB"); + return p ? : _PATH_MOUNTED; +} + /** * mnt_get_writable_mtab_path: * - * It's not error if this function return NULL and errno is not set. In case of + * It's not error if this function returns NULL and errno is not set. In case of * error the errno is set by open(2). * - * Returns: pointer to the static string with path to mtab or NULL. + * Note that writable mtab does not have to contains all necessary information. + * For example /var/run/mount/mountinfo is used for userspace mount options + * only. FS depend information are usually maintaibed by kernel only. + * + * Returns: pointer to the static string with path to mtab or NULL if writable + * mtab is unsupported. */ const char *mnt_get_writable_mtab_path(void) { struct stat mst, ist; int mtab, info; + const char *path = mnt_get_mtab_path(); - mtab = !lstat(_PATH_MOUNTED, &mst); + mtab = !lstat(path, &mst); info = !stat(MNT_PATH_RUNDIR, &ist); errno = 0; @@ -444,12 +480,12 @@ const char *mnt_get_writable_mtab_path(void) return NULL; /* probably EACCES */ } - /* B) classis system with /etc/mtab */ + /* B) classis system with /etc/mtab or $LIBMOUNT_MTAB */ if (mtab && S_ISREG(mst.st_mode)) { - int fd = open(_PATH_MOUNTED, O_RDWR, 0644); + int fd = open(path, O_RDWR, 0644); if (fd >= 0) { close(fd); - return _PATH_MOUNTED; + return path; } return NULL; /* probably EACCES */ } -- cgit v1.2.3-55-g7522