diff options
Diffstat (limited to 'libmount/src/tab_update.c')
| -rw-r--r-- | libmount/src/tab_update.c | 178 |
1 files changed, 153 insertions, 25 deletions
diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c index 1e7f32be0..13f6f6ebe 100644 --- a/libmount/src/tab_update.c +++ b/libmount/src/tab_update.c @@ -10,10 +10,10 @@ * @title: Tables update * @short_description: userspace mount information management * - * The struct libmnt_update provides abstraction to manage mount options in - * userspace independently on system configuration. This low-level API works on - * system with and without /etc/mtab. On systems without the regular /etc/mtab - * file are userspace mount options (e.g. user=) stored to the /run/mount/utab + * The struct libmnt_update provides an abstraction to manage mount options in + * userspace independently of system configuration. This low-level API works on + * systems both with and without /etc/mtab. On systems without the regular /etc/mtab + * file, the userspace mount options (e.g. user=) are stored in the /run/mount/utab * file. * * It's recommended to use high-level struct libmnt_context API. @@ -70,8 +70,8 @@ void mnt_free_update(struct libmnt_update *upd) DBG(UPDATE, mnt_debug_h(upd, "free")); - mnt_free_fs(upd->fs); - mnt_free_table(upd->mountinfo); + mnt_unref_fs(upd->fs); + mnt_unref_table(upd->mountinfo); free(upd->target); free(upd->filename); free(upd); @@ -125,7 +125,7 @@ int mnt_update_set_filename(struct libmnt_update *upd, const char *filename, * mnt_update_get_filename: * @upd: update * - * This function returns file name (e.g. /etc/mtab) for the up-dated file. + * This function returns the file name (e.g. /etc/mtab) of the up-dated file. * * Returns: pointer to filename that will be updated or NULL in case of error. */ @@ -140,7 +140,7 @@ const char *mnt_update_get_filename(struct libmnt_update *upd) * @upd: update handler * * Returns: 1 if entry described by @upd is successfully prepared and will be - * written to mtab/utab file. + * written to the mtab/utab file. */ int mnt_update_is_ready(struct libmnt_update *upd) { @@ -180,7 +180,7 @@ int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags, DBG(UPDATE, mnt_fs_print_debug(fs, stderr)); } - mnt_free_fs(upd->fs); + mnt_unref_fs(upd->fs); free(upd->target); upd->ready = FALSE; upd->fs = NULL; @@ -287,10 +287,10 @@ int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly) } /* - * Allocates utab entry (upd->fs) for mount/remount. This function should be + * Allocates an utab entry (upd->fs) for mount/remount. This function should be * called *before* mount(2) syscall. The @fs is used as a read-only template. * - * Returns: 0 on success, negative number on error, 1 if utabs update is + * Returns: 0 on success, negative number on error, 1 if utab's update is * unnecessary. */ static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs, @@ -350,14 +350,14 @@ static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs, return 0; err: free(u); - mnt_free_fs(upd->fs); + mnt_unref_fs(upd->fs); upd->fs = NULL; return rc; } /* * Sets fs-root and fs-type to @upd->fs according to the @fs template and - * @mountfalgs. For MS_BIND mountflag it reads information about source + * @mountfalgs. For MS_BIND mountflag it reads information about the source * filesystem from /proc/self/mountinfo. */ static int set_fs_root(struct libmnt_update *upd, struct libmnt_fs *fs, @@ -408,13 +408,14 @@ err: */ static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs) { - const char *o, *src, *fstype; + const char *o, *src, *fstype, *comm; char *m1, *m2, *m3, *m4; int rc; assert(fs); assert(f); + comm = mnt_fs_get_comment(fs); src = mnt_fs_get_source(fs); fstype = mnt_fs_get_fstype(fs); o = mnt_fs_get_options(fs); @@ -425,6 +426,8 @@ static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs) m4 = o ? mangle(o) : "rw"; if (m1 && m2 && m3 && m4) { + if (comm) + fputs(comm, f); rc = fprintf(f, "%s %s %s %s %d %d\n", m1, m2, m3, m4, mnt_fs_get_freq(fs), @@ -527,6 +530,10 @@ static int update_table(struct libmnt_update *upd, struct libmnt_table *tb) struct libmnt_fs *fs; mnt_reset_iter(&itr, MNT_ITER_FORWARD); + + if (tb->comms && mnt_table_get_intro_comment(tb)) + fputs(mnt_table_get_intro_comment(tb), f); + while(mnt_table_next_fs(tb, &itr, &fs) == 0) { if (upd->userspace_only) rc = fprintf_utab_fs(f, fs); @@ -538,6 +545,8 @@ static int update_table(struct libmnt_update *upd, struct libmnt_table *tb) goto leave; } } + if (tb->comms && mnt_table_get_trailing_comment(tb)) + fputs(mnt_table_get_trailing_comment(tb), f); if (fflush(f) != 0) { rc = -errno; @@ -570,6 +579,99 @@ leave: return rc; } +/** + * mnt_table_write_file + * @tb: parsed file (e.g. fstab) + * @file: target + * + * This function writes @tb to @file. + * + * Returns: 0 on success, negative number on error. + */ +int mnt_table_write_file(struct libmnt_table *tb, FILE *file) +{ + int rc = 0; + struct libmnt_iter itr; + struct libmnt_fs *fs; + + if (tb->comms && mnt_table_get_intro_comment(tb)) + fputs(mnt_table_get_intro_comment(tb), file); + + mnt_reset_iter(&itr, MNT_ITER_FORWARD); + while(mnt_table_next_fs(tb, &itr, &fs) == 0) { + rc = fprintf_mtab_fs(file, fs); + if (rc) + return rc; + } + if (tb->comms && mnt_table_get_trailing_comment(tb)) + fputs(mnt_table_get_trailing_comment(tb), file); + + if (fflush(file) != 0) + rc = -errno; + + DBG(TAB, mnt_debug_h(tb, "write file done [rc=%d]", rc)); + return rc; +} + +/** + * mnt_table_replace_file + * @tb: parsed file (e.g. fstab) + * @filename: target + * + * This function replaces @file by the new content from @tb. + * + * Returns: 0 on success, negative number on error. + */ +int mnt_table_replace_file(struct libmnt_table *tb, const char *filename) +{ + int fd, rc = 0; + FILE *f; + char *uq = NULL; + + DBG(TAB, mnt_debug_h(tb, "%s: replacing", filename)); + + fd = mnt_open_uniq_filename(filename, &uq); + if (fd < 0) + return fd; /* error */ + + f = fdopen(fd, "w" UL_CLOEXECSTR); + if (f) { + struct stat st; + + mnt_table_write_file(tb, f); + + if (fflush(f) != 0) { + rc = -errno; + DBG(UPDATE, mnt_debug("%s: fflush failed: %m", uq)); + goto leave; + } + + rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0; + + if (!rc && stat(filename, &st) == 0) + /* Copy uid/gid from the present file before renaming. */ + rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0; + + fclose(f); + f = NULL; + + if (!rc) + rc = rename(uq, filename) ? -errno : 0; + } else { + rc = -errno; + close(fd); + } + +leave: + if (f) + fclose(f); + unlink(uq); + free(uq); + + DBG(TAB, mnt_debug_h(tb, "replace done [rc=%d]", rc)); + return rc; +} + static int add_file_entry(struct libmnt_table *tb, struct libmnt_update *upd) { struct libmnt_fs *fs; @@ -581,6 +683,8 @@ static int add_file_entry(struct libmnt_table *tb, struct libmnt_update *upd) return -ENOMEM; mnt_table_add_fs(tb, fs); + mnt_unref_fs(fs); + return update_table(upd, tb); } @@ -606,7 +710,7 @@ static int update_add_entry(struct libmnt_update *upd, struct libmnt_lock *lc) if (lc) mnt_unlock_file(lc); - mnt_free_table(tb); + mnt_unref_table(tb); return rc; } @@ -632,13 +736,12 @@ static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc if (rem) { mnt_table_remove_fs(tb, rem); rc = update_table(upd, tb); - mnt_free_fs(rem); } } if (lc) mnt_unlock_file(lc); - mnt_free_table(tb); + mnt_unref_table(tb); return rc; } @@ -670,7 +773,7 @@ static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *l if (lc) mnt_unlock_file(lc); - mnt_free_table(tb); + mnt_unref_table(tb); return rc; } @@ -712,7 +815,7 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock * if (lc) mnt_unlock_file(lc); - mnt_free_table(tb); + mnt_unref_table(tb); return rc; } @@ -724,7 +827,7 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock * * High-level API to update /etc/mtab (or private /run/mount/utab file). * * The @lc lock is optional and will be created if necessary. Note that - * the automatically created lock blocks all signals. + * an automatically created lock blocks all signals. * * See also mnt_lock_block_signals() and mnt_context_get_lock(). * @@ -794,7 +897,7 @@ static int update(const char *target, struct libmnt_fs *fs, unsigned long mountf goto done; } - /* [... here should be mount(2) call ...] */ + /* [... mount(2) call should be here...] */ rc = mnt_update_table(upd, NULL); done: @@ -815,7 +918,7 @@ static int test_add(struct libmnt_test *ts, int argc, char *argv[]) mnt_fs_set_options(fs, argv[4]); rc = update(NULL, fs, 0); - mnt_free_fs(fs); + mnt_unref_fs(fs); return rc; } @@ -838,7 +941,7 @@ static int test_move(struct libmnt_test *ts, int argc, char *argv[]) rc = update(NULL, fs, MS_MOVE); - mnt_free_fs(fs); + mnt_unref_fs(fs); return rc; } @@ -853,17 +956,42 @@ static int test_remount(struct libmnt_test *ts, int argc, char *argv[]) mnt_fs_set_options(fs, argv[2]); rc = update(NULL, fs, MS_REMOUNT); - mnt_free_fs(fs); + mnt_unref_fs(fs); + return rc; +} + +static int test_replace(struct libmnt_test *ts, int argc, char *argv[]) +{ + struct libmnt_fs *fs = mnt_new_fs(); + struct libmnt_table *tb = mnt_new_table(); + int rc; + + if (argc < 3) + return -1; + + mnt_table_enable_comments(tb, TRUE); + mnt_table_parse_fstab(tb, NULL); + + mnt_fs_set_source(fs, argv[1]); + mnt_fs_set_target(fs, argv[2]); + mnt_fs_append_comment(fs, "# this is new filesystem\n"); + + mnt_table_add_fs(tb, fs); + mnt_unref_fs(fs); + + rc = mnt_table_replace_file(tb, mnt_get_fstab_path()); + mnt_unref_table(tb); return rc; } int main(int argc, char *argv[]) { struct libmnt_test tss[] = { - { "--add", test_add, "<src> <target> <type> <options> add line to mtab" }, + { "--add", test_add, "<src> <target> <type> <options> add a line to mtab" }, { "--remove", test_remove, "<target> MS_REMOUNT mtab change" }, { "--move", test_move, "<old_target> <target> MS_MOVE mtab change" }, { "--remount",test_remount, "<target> <options> MS_REMOUNT mtab change" }, + { "--replace",test_replace, "<src> <target> Add a line to LIBMOUNT_FSTAB and replace the original file" }, { NULL } }; |
