]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/tab_update.c
3cb5b30f956c327cfeb65cefaeb3371eddc9fac3
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 * This file is part of libmount from util-linux project.
5 * Copyright (C) 2011-2018 Karel Zak <kzak@redhat.com>
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.
15 * @title: Tables update
16 * @short_description: userspace mount information management
18 * The struct libmnt_update provides an abstraction to manage mount options in
19 * userspace independently of system configuration. The userspace mount options
20 * (e.g. user=) are stored in the /run/mount/utab file.
22 * It's recommended to use high-level struct libmnt_context API.
30 #include "pathnames.h"
33 struct libmnt_update
{
37 unsigned long mountflags
;
42 unsigned int ready
: 1,
45 struct libmnt_table
*mountinfo
;
46 struct libmnt_lock
*lock
;
49 static int set_fs_root(struct libmnt_update
*upd
, struct libmnt_fs
*fs
, unsigned long mountflags
);
50 static int utab_new_entry(struct libmnt_update
*upd
, struct libmnt_fs
*fs
, unsigned long mountflags
);
55 * Returns: newly allocated update handler
57 struct libmnt_update
*mnt_new_update(void)
59 struct libmnt_update
*upd
;
61 upd
= calloc(1, sizeof(*upd
));
66 DBG(UPDATE
, ul_debugobj(upd
, "allocate"));
74 * Deallocates struct libmnt_update handler.
76 void mnt_free_update(struct libmnt_update
*upd
)
81 DBG(UPDATE
, ul_debugobj(upd
, "free"));
83 mnt_unref_lock(upd
->lock
);
84 mnt_unref_fs(upd
->fs
);
85 mnt_unref_table(upd
->mountinfo
);
90 free(upd
->act_filename
);
95 * Returns 0 on success, <0 in case of error.
97 int mnt_update_set_filename(struct libmnt_update
*upd
, const char *filename
)
99 const char *path
= NULL
;
105 /* filename explicitly defined */
107 char *p
= strdup(filename
);
118 /* detect tab filename -- /run/mount/utab
121 mnt_has_regular_utab(&path
, &rw
);
124 upd
->filename
= strdup(path
);
132 * mnt_update_get_filename:
135 * This function returns the file name of the up-dated file.
137 * Returns: pointer to filename that will be updated or NULL in case of error.
139 const char *mnt_update_get_filename(struct libmnt_update
*upd
)
141 return upd
? upd
->filename
: NULL
;
145 * mnt_update_is_ready:
146 * @upd: update handler
148 * Returns: 1 if entry described by @upd is successfully prepared and will be
149 * written to the utab file.
151 int mnt_update_is_ready(struct libmnt_update
*upd
)
153 return upd
? upd
->ready
: FALSE
;
158 * @upd: update handler
159 * @mountflags: MS_* flags
160 * @target: umount target, must be NULL for mount
161 * @fs: mount filesystem description, must be NULL for umount
163 * Returns: <0 in case on error, 0 on success, 1 if update is unnecessary.
165 int mnt_update_set_fs(struct libmnt_update
*upd
, unsigned long mountflags
,
166 const char *target
, struct libmnt_fs
*fs
)
172 if ((mountflags
& MS_MOVE
) && (!fs
|| !mnt_fs_get_srcpath(fs
)))
177 DBG(UPDATE
, ul_debugobj(upd
,
178 "resetting FS [target=%s, flags=0x%08lx]",
179 target
, mountflags
));
181 DBG(UPDATE
, ul_debugobj(upd
, "FS template:"));
182 DBG(UPDATE
, mnt_fs_print_debug(fs
, stderr
));
185 mnt_unref_fs(upd
->fs
);
192 if (mountflags
& MS_PROPAGATION
)
195 upd
->mountflags
= mountflags
;
197 rc
= mnt_update_set_filename(upd
, NULL
);
199 DBG(UPDATE
, ul_debugobj(upd
, "no writable file available [rc=%d]", rc
));
200 return rc
; /* error or no file available (rc = 1) */
203 upd
->target
= strdup(target
);
208 if (!(mountflags
& MS_MOVE
)) {
209 rc
= utab_new_entry(upd
, fs
, mountflags
);
213 upd
->fs
= mnt_copy_mtab_fs(fs
);
219 DBG(UPDATE
, ul_debugobj(upd
, "ready"));
228 * Returns: update filesystem entry or NULL
230 struct libmnt_fs
*mnt_update_get_fs(struct libmnt_update
*upd
)
232 return upd
? upd
->fs
: NULL
;
236 * mnt_update_get_mflags:
239 * Returns: mount flags as was set by mnt_update_set_fs()
241 unsigned long mnt_update_get_mflags(struct libmnt_update
*upd
)
243 return upd
? upd
->mountflags
: 0;
247 * mnt_update_force_rdonly:
249 * @rdonly: is read-only?
251 * Returns: 0 on success and negative number in case of error.
253 int mnt_update_force_rdonly(struct libmnt_update
*upd
, int rdonly
)
257 if (!upd
|| !upd
->fs
)
260 if (rdonly
&& (upd
->mountflags
& MS_RDONLY
))
262 if (!rdonly
&& !(upd
->mountflags
& MS_RDONLY
))
266 upd
->mountflags
&= ~MS_RDONLY
;
268 upd
->mountflags
|= MS_RDONLY
;
275 * Allocates an utab entry (upd->fs) for mount/remount. This function should be
276 * called *before* mount(2) syscall. The @fs is used as a read-only template.
278 * Returns: 0 on success, negative number on error, 1 if utab's update is
281 static int utab_new_entry(struct libmnt_update
*upd
, struct libmnt_fs
*fs
,
282 unsigned long mountflags
)
290 assert(upd
->fs
== NULL
);
291 assert(!(mountflags
& MS_MOVE
));
293 DBG(UPDATE
, ul_debug("prepare utab entry"));
295 o
= mnt_fs_get_user_options(fs
);
296 a
= mnt_fs_get_attributes(fs
);
300 /* remove non-mtab options */
301 rc
= mnt_optstr_get_options(o
, &u
,
302 mnt_get_builtin_optmap(MNT_USERSPACE_MAP
),
309 DBG(UPDATE
, ul_debug("utab entry unnecessary (no options)"));
313 /* allocate the entry */
314 upd
->fs
= mnt_copy_fs(NULL
, fs
);
320 rc
= mnt_fs_set_options(upd
->fs
, u
);
323 rc
= mnt_fs_set_attributes(upd
->fs
, a
);
327 if (!(mountflags
& MS_REMOUNT
)) {
328 rc
= set_fs_root(upd
, fs
, mountflags
);
334 DBG(UPDATE
, ul_debug("utab entry OK"));
338 mnt_unref_fs(upd
->fs
);
344 * Sets fs-root and fs-type to @upd->fs according to the @fs template and
345 * @mountfalgs. For MS_BIND mountflag it reads information about the source
346 * filesystem from /proc/self/mountinfo.
348 static int set_fs_root(struct libmnt_update
*upd
, struct libmnt_fs
*fs
,
349 unsigned long mountflags
)
351 struct libmnt_fs
*src_fs
;
353 const char *src
, *fstype
;
356 DBG(UPDATE
, ul_debug("setting FS root"));
362 fstype
= mnt_fs_get_fstype(fs
);
364 if (mountflags
& MS_BIND
) {
366 upd
->mountinfo
= mnt_new_table_from_file(_PATH_PROC_MOUNTINFO
);
367 src
= mnt_fs_get_srcpath(fs
);
369 rc
= mnt_fs_set_bindsrc(upd
->fs
, src
);
374 } else if (fstype
&& (strcmp(fstype
, "btrfs") == 0 || strcmp(fstype
, "auto") == 0)) {
376 upd
->mountinfo
= mnt_new_table_from_file(_PATH_PROC_MOUNTINFO
);
379 src_fs
= mnt_table_get_fs_root(upd
->mountinfo
, fs
,
380 mountflags
, &fsroot
);
382 src
= mnt_fs_get_srcpath(src_fs
);
383 rc
= mnt_fs_set_source(upd
->fs
, src
);
387 mnt_fs_set_fstype(upd
->fs
, mnt_fs_get_fstype(src_fs
));
390 upd
->fs
->root
= fsroot
;
397 /* mtab and fstab update -- returns zero on success
399 static int fprintf_mtab_fs(FILE *f
, struct libmnt_fs
*fs
)
401 const char *o
, *src
, *fstype
, *comm
;
402 char *m1
, *m2
, *m3
, *m4
;
408 comm
= mnt_fs_get_comment(fs
);
409 src
= mnt_fs_get_source(fs
);
410 fstype
= mnt_fs_get_fstype(fs
);
411 o
= mnt_fs_get_options(fs
);
413 m1
= src
? mangle(src
) : "none";
414 m2
= mangle(mnt_fs_get_target(fs
));
415 m3
= fstype
? mangle(fstype
) : "none";
416 m4
= o
? mangle(o
) : "rw";
418 if (m1
&& m2
&& m3
&& m4
) {
421 rc
= fprintf(f
, "%s %s %s %s %d %d\n",
424 mnt_fs_get_passno(fs
));
441 static int fprintf_utab_fs(FILE *f
, struct libmnt_fs
*fs
)
449 if (mnt_fs_get_id(fs
) > 0)
450 rc
= fprintf(f
, "ID=%d ", mnt_fs_get_id(fs
));
451 if (mnt_fs_get_uniq_id(fs
) > 0)
452 rc
= fprintf(f
, "UNIQID=%" PRIu64
, mnt_fs_get_uniq_id(fs
));
455 p
= mangle(mnt_fs_get_source(fs
));
457 rc
= fprintf(f
, "SRC=%s ", p
);
462 p
= mangle(mnt_fs_get_target(fs
));
464 rc
= fprintf(f
, "TARGET=%s ", p
);
469 p
= mangle(mnt_fs_get_root(fs
));
471 rc
= fprintf(f
, "ROOT=%s ", p
);
476 p
= mangle(mnt_fs_get_bindsrc(fs
));
478 rc
= fprintf(f
, "BINDSRC=%s ", p
);
483 p
= mangle(mnt_fs_get_attributes(fs
));
485 rc
= fprintf(f
, "ATTRS=%s ", p
);
490 p
= mangle(mnt_fs_get_user_options(fs
));
492 rc
= fprintf(f
, "OPTS=%s", p
);
497 rc
= fprintf(f
, "\n");
500 rc
= 0; /* success */
504 static int update_table(struct libmnt_update
*upd
, struct libmnt_table
*tb
)
510 if (!tb
|| !upd
->filename
)
513 DBG(UPDATE
, ul_debugobj(upd
, "%s: updating", upd
->filename
));
515 fd
= mnt_open_uniq_filename(upd
->filename
, &uq
);
517 return fd
; /* error */
519 f
= fdopen(fd
, "w" UL_CLOEXECSTR
);
522 struct libmnt_iter itr
;
523 struct libmnt_fs
*fs
;
525 mnt_reset_iter(&itr
, MNT_ITER_FORWARD
);
527 if (tb
->comms
&& mnt_table_get_intro_comment(tb
))
528 fputs(mnt_table_get_intro_comment(tb
), f
);
530 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
531 rc
= fprintf_utab_fs(f
, fs
);
533 DBG(UPDATE
, ul_debugobj(upd
,
534 "%s: write entry failed: %m", uq
));
538 if (tb
->comms
&& mnt_table_get_trailing_comment(tb
))
539 fputs(mnt_table_get_trailing_comment(tb
), f
);
541 if (fflush(f
) != 0) {
543 DBG(UPDATE
, ul_debugobj(upd
, "%s: fflush failed: %m", uq
));
547 rc
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
) ? -errno
: 0;
549 if (!rc
&& stat(upd
->filename
, &st
) == 0)
550 /* Copy uid/gid from the present file before renaming. */
551 rc
= fchown(fd
, st
.st_uid
, st
.st_gid
) ? -errno
: 0;
557 rc
= rename(uq
, upd
->filename
) ? -errno
: 0;
567 unlink(uq
); /* be paranoid */
569 DBG(UPDATE
, ul_debugobj(upd
, "%s: done [rc=%d]", upd
->filename
, rc
));
574 * mnt_table_write_file
575 * @tb: parsed file (e.g. fstab)
578 * This function writes @tb to @file.
580 * Returns: 0 on success, negative number on error.
582 int mnt_table_write_file(struct libmnt_table
*tb
, FILE *file
)
585 struct libmnt_iter itr
;
586 struct libmnt_fs
*fs
;
588 if (tb
->comms
&& mnt_table_get_intro_comment(tb
))
589 fputs(mnt_table_get_intro_comment(tb
), file
);
591 mnt_reset_iter(&itr
, MNT_ITER_FORWARD
);
592 while(mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
593 rc
= fprintf_mtab_fs(file
, fs
);
597 if (tb
->comms
&& mnt_table_get_trailing_comment(tb
))
598 fputs(mnt_table_get_trailing_comment(tb
), file
);
600 if (fflush(file
) != 0)
603 DBG(TAB
, ul_debugobj(tb
, "write file done [rc=%d]", rc
));
608 * mnt_table_replace_file
609 * @tb: parsed file (e.g. fstab)
612 * This function replaces @file by the new content from @tb.
614 * Returns: 0 on success, negative number on error.
616 int mnt_table_replace_file(struct libmnt_table
*tb
, const char *filename
)
622 DBG(TAB
, ul_debugobj(tb
, "%s: replacing", filename
));
624 fd
= mnt_open_uniq_filename(filename
, &uq
);
626 return fd
; /* error */
628 f
= fdopen(fd
, "w" UL_CLOEXECSTR
);
632 mnt_table_write_file(tb
, f
);
634 if (fflush(f
) != 0) {
636 DBG(UPDATE
, ul_debug("%s: fflush failed: %m", uq
));
640 rc
= fchmod(fd
, S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IROTH
) ? -errno
: 0;
642 if (!rc
&& stat(filename
, &st
) == 0)
643 /* Copy uid/gid from the present file before renaming. */
644 rc
= fchown(fd
, st
.st_uid
, st
.st_gid
) ? -errno
: 0;
650 rc
= rename(uq
, filename
) ? -errno
: 0;
662 DBG(TAB
, ul_debugobj(tb
, "replace done [rc=%d]", rc
));
666 static int add_file_entry(struct libmnt_table
*tb
, struct libmnt_update
*upd
)
668 struct libmnt_fs
*fs
;
672 fs
= mnt_copy_fs(NULL
, upd
->fs
);
676 mnt_table_add_fs(tb
, fs
);
679 return update_table(upd
, tb
);
682 static int update_add_entry(struct libmnt_update
*upd
)
684 struct libmnt_table
*tb
;
691 DBG(UPDATE
, ul_debugobj(upd
, "%s: add entry", upd
->filename
));
693 rc
= mnt_lock_file(upd
->lock
);
695 return -MNT_ERR_LOCK
;
697 tb
= __mnt_new_table_from_file(upd
->filename
, MNT_FMT_UTAB
, 1);
699 rc
= add_file_entry(tb
, upd
);
701 mnt_unlock_file(upd
->lock
);
706 static int update_remove_entry(struct libmnt_update
*upd
)
708 struct libmnt_table
*tb
;
715 DBG(UPDATE
, ul_debugobj(upd
, "%s: remove entry", upd
->filename
));
717 rc
= mnt_lock_file(upd
->lock
);
719 return -MNT_ERR_LOCK
;
721 tb
= __mnt_new_table_from_file(upd
->filename
, MNT_FMT_UTAB
, 1);
723 struct libmnt_fs
*rem
= mnt_table_find_target(tb
, upd
->target
, MNT_ITER_BACKWARD
);
725 mnt_table_remove_fs(tb
, rem
);
726 rc
= update_table(upd
, tb
);
730 mnt_unlock_file(upd
->lock
);
735 static int update_modify_target(struct libmnt_update
*upd
)
737 struct libmnt_table
*tb
= NULL
;
742 DBG(UPDATE
, ul_debugobj(upd
, "%s: modify target", upd
->filename
));
744 rc
= mnt_lock_file(upd
->lock
);
746 return -MNT_ERR_LOCK
;
748 tb
= __mnt_new_table_from_file(upd
->filename
, MNT_FMT_UTAB
, 1);
750 const char *upd_source
= mnt_fs_get_srcpath(upd
->fs
);
751 const char *upd_target
= mnt_fs_get_target(upd
->fs
);
752 struct libmnt_iter itr
;
753 struct libmnt_fs
*fs
;
754 char *cn_target
= mnt_resolve_path(upd_target
, NULL
);
761 mnt_reset_iter(&itr
, MNT_ITER_BACKWARD
);
762 while (mnt_table_next_fs(tb
, &itr
, &fs
) == 0) {
766 e
= ul_startswith(mnt_fs_get_target(fs
), upd_source
);
767 if (!e
|| (*e
&& *e
!= '/'))
770 e
++; /* remove extra '/' */
772 /* no subdirectory, replace entire path */
774 rc
= mnt_fs_set_target(fs
, cn_target
);
776 /* update start of the path, keep subdirectory */
777 else if (asprintf(&p
, "%s/%s", cn_target
, e
) > 0) {
778 rc
= mnt_fs_set_target(fs
, p
);
788 rc
= update_table(upd
, tb
);
793 mnt_unlock_file(upd
->lock
);
798 /* replaces option in the table entry by new options from @udp */
799 static int update_modify_options(struct libmnt_update
*upd
)
801 struct libmnt_table
*tb
= NULL
;
803 struct libmnt_fs
*fs
;
809 DBG(UPDATE
, ul_debugobj(upd
, "%s: modify options", upd
->filename
));
813 rc
= mnt_lock_file(upd
->lock
);
815 return -MNT_ERR_LOCK
;
817 tb
= __mnt_new_table_from_file(upd
->filename
, MNT_FMT_UTAB
, 1);
819 struct libmnt_fs
*cur
= mnt_table_find_target(tb
,
820 mnt_fs_get_target(fs
),
823 rc
= mnt_fs_set_attributes(cur
, mnt_fs_get_attributes(fs
));
825 rc
= mnt_fs_set_options(cur
, mnt_fs_get_options(fs
));
827 rc
= update_table(upd
, tb
);
829 rc
= add_file_entry(tb
, upd
); /* not found, add new */
832 mnt_unlock_file(upd
->lock
);
837 /* add user options missing in the table entry by new options from @udp */
838 static int update_add_options(struct libmnt_update
*upd
)
840 struct libmnt_table
*tb
= NULL
;
842 struct libmnt_fs
*fs
;
848 if (!upd
->fs
->user_optstr
)
851 DBG(UPDATE
, ul_debugobj(upd
, "%s: add options", upd
->filename
));
855 rc
= mnt_lock_file(upd
->lock
);
857 return -MNT_ERR_LOCK
;
859 tb
= __mnt_new_table_from_file(upd
->filename
, MNT_FMT_UTAB
, 1);
861 struct libmnt_fs
*cur
= mnt_table_find_target(tb
,
862 mnt_fs_get_target(fs
),
867 rc
= mnt_optstr_get_missing(cur
->user_optstr
, upd
->fs
->user_optstr
, &u
);
869 DBG(UPDATE
, ul_debugobj(upd
, " add missing: %s", u
));
870 rc
= mnt_optstr_append_option(&cur
->user_optstr
, u
, NULL
);
873 rc
= update_table(upd
, tb
);
875 if (rc
== 1) /* nothing is missing */
878 rc
= add_file_entry(tb
, upd
); /* not found, add new */
881 mnt_unlock_file(upd
->lock
);
887 static int update_init_lock(struct libmnt_update
*upd
, struct libmnt_lock
*lc
)
892 mnt_unref_lock(upd
->lock
);
895 } else if (!upd
->lock
) {
896 upd
->lock
= mnt_new_lock(upd
->filename
, 0);
899 mnt_lock_block_signals(upd
->lock
, TRUE
);
910 * High-level API to update /etc/mtab (or private /run/mount/utab file).
912 * The @lc lock is optional and will be created if necessary. Note that
913 * an automatically created lock blocks all signals.
915 * See also mnt_lock_block_signals() and mnt_context_get_lock().
917 * Returns: 0 on success, negative number on error.
919 int mnt_update_table(struct libmnt_update
*upd
, struct libmnt_lock
*lc
)
923 if (!upd
|| !upd
->filename
)
928 DBG(UPDATE
, ul_debugobj(upd
, "%s: update tab", upd
->filename
));
930 DBG(UPDATE
, mnt_fs_print_debug(upd
->fs
, stderr
));
933 rc
= update_init_lock(upd
, lc
);
937 if (!upd
->fs
&& upd
->target
)
938 rc
= update_remove_entry(upd
); /* umount */
939 else if (upd
->mountflags
& MS_MOVE
)
940 rc
= update_modify_target(upd
); /* move */
941 else if (upd
->mountflags
& MS_REMOUNT
)
942 rc
= update_modify_options(upd
); /* remount */
943 else if (upd
->fs
&& upd
->missing_options
)
944 rc
= update_add_options(upd
); /* mount by external helper */
946 rc
= update_add_entry(upd
); /* mount */
950 DBG(UPDATE
, ul_debugobj(upd
, "%s: update tab: done [rc=%d]",
955 int mnt_update_already_done(struct libmnt_update
*upd
)
957 struct libmnt_table
*tb
= NULL
;
960 if (!upd
|| !upd
->filename
|| (!upd
->fs
&& !upd
->target
))
963 DBG(UPDATE
, ul_debugobj(upd
, "%s: checking for previous update", upd
->filename
));
965 tb
= __mnt_new_table_from_file(upd
->filename
, MNT_FMT_UTAB
, 1);
971 struct libmnt_fs
*fs
;
972 const char *tgt
= mnt_fs_get_target(upd
->fs
);
973 const char *src
= mnt_fs_get_bindsrc(upd
->fs
) ?
974 mnt_fs_get_bindsrc(upd
->fs
) :
975 mnt_fs_get_source(upd
->fs
);
977 fs
= mnt_table_find_pair(tb
, src
, tgt
, MNT_ITER_BACKWARD
);
979 DBG(UPDATE
, ul_debugobj(upd
, "%s: found %s %s",
980 upd
->filename
, src
, tgt
));
982 /* Check if utab entry (probably written by /sbin/mount.<type>
983 * helper) contains all options expected by this update */
984 if (mnt_optstr_get_missing(fs
->user_optstr
, upd
->fs
->user_optstr
, NULL
) == 0) {
985 upd
->missing_options
= 1;
986 DBG(UPDATE
, ul_debugobj(upd
, " missing options detected"));
991 } else if (upd
->target
) {
993 if (!mnt_table_find_target(tb
, upd
->target
, MNT_ITER_BACKWARD
)) {
994 DBG(UPDATE
, ul_debugobj(upd
, "%s: not-found (umounted) %s",
995 upd
->filename
, upd
->target
));
1000 mnt_unref_table(tb
);
1002 DBG(UPDATE
, ul_debugobj(upd
, "%s: previous update check done [rc=%d]",
1003 upd
->filename
, rc
));
1007 int mnt_update_emit_event(struct libmnt_update
*upd
)
1012 if (!upd
|| !upd
->filename
)
1015 if (asprintf(&filename
, "%s.event", upd
->filename
) <= 0)
1018 DBG(UPDATE
, ul_debugobj(upd
, "emitting utab event"));
1020 fd
= open(filename
, O_WRONLY
|O_CREAT
|O_CLOEXEC
,
1021 S_IWUSR
|S_IRUSR
|S_IRGRP
|S_IROTH
);
1030 * Let's use /run/mount/utab.act file to report to libmount monitor that
1031 * libmount is working with utab. In this case, the monitor can ignore all
1032 * events from kernel until entire mount (with all steps) is done.
1034 * For example mount NFS with x-* options, means
1035 * - create utab.act and mark it as used (by LOCK_SH)
1036 * - exec /sbin/mount.nfs
1037 * - call mount(2) (kernel event on /proc/self/mounts)
1038 * - utab update (NFS stuff)
1039 * - utab update (add x-* userspace options)
1040 * - unlink utab.act (if not use anyone else)
1041 * - release event by /run/mount/utab.event
1043 * Note, this is used only when utab is in the game (x-* options).
1045 int mnt_update_start(struct libmnt_update
*upd
)
1050 if (!upd
|| !upd
->filename
)
1053 if (!upd
->act_filename
&&
1054 asprintf(&upd
->act_filename
, "%s.act", upd
->filename
) <= 0)
1057 /* Use exclusive lock to avoid some other process will remove the the
1058 * file before it's marked as used by LOCK_SH (below) */
1059 rc
= update_init_lock(upd
, NULL
);
1063 rc
= mnt_lock_file(upd
->lock
);
1065 return -MNT_ERR_LOCK
;
1067 DBG(UPDATE
, ul_debugobj(upd
, "creating act file"));
1069 oldmask
= umask(S_IRGRP
|S_IWGRP
|S_IXGRP
|S_IROTH
|S_IWOTH
|S_IXOTH
);
1070 upd
->act_fd
= open(upd
->act_filename
, O_WRONLY
|O_CREAT
|O_CLOEXEC
, S_IRUSR
|S_IWUSR
);
1073 if (upd
->act_fd
< 0) {
1078 /* mark the file as used */
1079 rc
= flock(upd
->act_fd
, LOCK_SH
);
1085 mnt_unlock_file(upd
->lock
);
1088 DBG(UPDATE
, ul_debugobj(upd
, "act file failed [rc=%d]", rc
));
1089 mnt_unlock_file(upd
->lock
);
1090 unlink(upd
->act_filename
);
1091 if (upd
->act_fd
>= 0)
1097 int mnt_update_end(struct libmnt_update
*upd
)
1101 if (!upd
|| upd
->act_fd
< 0)
1104 DBG(UPDATE
, ul_debugobj(upd
, "removing act file"));
1106 /* make sure nobody else will use the file */
1107 rc
= mnt_lock_file(upd
->lock
);
1109 return -MNT_ERR_LOCK
;
1111 /* mark the file as unused */
1112 flock(upd
->act_fd
, LOCK_UN
);
1115 /* check if nobody else need the file (if yes, then the file is under LOCK_SH) )*/
1116 if (flock(upd
->act_fd
, LOCK_EX
| LOCK_NB
) != 0) {
1117 if (errno
== EWOULDBLOCK
)
1118 DBG(UPDATE
, ul_debugobj(upd
, "act file used, no unlink"));
1120 DBG(UPDATE
, ul_debugobj(upd
, "unlinking act file"));
1121 unlink(upd
->act_filename
);
1124 mnt_unlock_file(upd
->lock
);
1132 static int update(const char *target
, struct libmnt_fs
*fs
, unsigned long mountflags
)
1135 struct libmnt_update
*upd
;
1137 DBG(UPDATE
, ul_debug("update test"));
1139 upd
= mnt_new_update();
1143 rc
= mnt_update_set_fs(upd
, mountflags
, target
, fs
);
1145 /* update is unnecessary */
1150 fprintf(stderr
, "failed to set FS\n");
1154 /* [... mount(2) call should be here...] */
1156 rc
= mnt_update_table(upd
, NULL
);
1158 mnt_free_update(upd
);
1162 static int test_add(struct libmnt_test
*ts
__attribute__((unused
)),
1163 int argc
, char *argv
[])
1165 struct libmnt_fs
*fs
= mnt_new_fs();
1168 if (argc
< 5 || !fs
)
1170 mnt_fs_set_source(fs
, argv
[1]);
1171 mnt_fs_set_target(fs
, argv
[2]);
1172 mnt_fs_set_fstype(fs
, argv
[3]);
1173 mnt_fs_set_options(fs
, argv
[4]);
1175 rc
= update(NULL
, fs
, 0);
1180 static int test_remove(struct libmnt_test
*ts
__attribute__((unused
)),
1181 int argc
, char *argv
[])
1185 return update(argv
[1], NULL
, 0);
1188 static int test_move(struct libmnt_test
*ts
__attribute__((unused
)),
1189 int argc
, char *argv
[])
1191 struct libmnt_fs
*fs
= mnt_new_fs();
1196 mnt_fs_set_source(fs
, argv
[1]);
1197 mnt_fs_set_target(fs
, argv
[2]);
1199 rc
= update(NULL
, fs
, MS_MOVE
);
1205 static int test_remount(struct libmnt_test
*ts
__attribute__((unused
)),
1206 int argc
, char *argv
[])
1208 struct libmnt_fs
*fs
= mnt_new_fs();
1213 mnt_fs_set_target(fs
, argv
[1]);
1214 mnt_fs_set_options(fs
, argv
[2]);
1216 rc
= update(NULL
, fs
, MS_REMOUNT
);
1221 static int test_replace(struct libmnt_test
*ts
__attribute__((unused
)),
1222 int argc
, char *argv
[])
1224 struct libmnt_fs
*fs
= mnt_new_fs();
1225 struct libmnt_table
*tb
= mnt_new_table();
1231 mnt_table_enable_comments(tb
, TRUE
);
1232 mnt_table_parse_fstab(tb
, NULL
);
1234 mnt_fs_set_source(fs
, argv
[1]);
1235 mnt_fs_set_target(fs
, argv
[2]);
1236 mnt_fs_append_comment(fs
, "# this is new filesystem\n");
1238 mnt_table_add_fs(tb
, fs
);
1241 rc
= mnt_table_replace_file(tb
, mnt_get_fstab_path());
1242 mnt_unref_table(tb
);
1246 int main(int argc
, char *argv
[])
1248 struct libmnt_test tss
[] = {
1249 { "--add", test_add
, "<src> <target> <type> <options> add a line to mtab" },
1250 { "--remove", test_remove
, "<target> MS_REMOUNT mtab change" },
1251 { "--move", test_move
, "<old_target> <target> MS_MOVE mtab change" },
1252 { "--remount",test_remount
, "<target> <options> MS_REMOUNT mtab change" },
1253 { "--replace",test_replace
, "<src> <target> Add a line to LIBMOUNT_FSTAB and replace the original file" },
1257 return mnt_run_test(tss
, argc
, argv
);
1260 #endif /* TEST_PROGRAM */