summaryrefslogtreecommitdiff
path: root/libmount/src/tab_update.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmount/src/tab_update.c')
-rw-r--r--libmount/src/tab_update.c178
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 }
};