summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarel Zak2011-12-02 18:20:34 +0100
committerKarel Zak2011-12-02 18:20:34 +0100
commitd2c97887fee6cdb44378190b04c3dd6d059d3fad (patch)
tree3ed9b30ac6edb49f4fe771de526b0b7c6fac1ccc
parentlibmount: add "+" prefix for options pattern (e.g findmnt -O) (diff)
downloadkernel-qcow2-util-linux-d2c97887fee6cdb44378190b04c3dd6d059d3fad.tar.gz
kernel-qcow2-util-linux-d2c97887fee6cdb44378190b04c3dd6d059d3fad.tar.xz
kernel-qcow2-util-linux-d2c97887fee6cdb44378190b04c3dd6d059d3fad.zip
libmount: add support for mount -a --fork
Signed-off-by: Karel Zak <kzak@redhat.com>
-rw-r--r--libmount/samples/mount.c51
-rw-r--r--libmount/src/context.c137
-rw-r--r--libmount/src/context_mount.c28
-rw-r--r--libmount/src/libmount.h.in8
-rw-r--r--libmount/src/libmount.sym5
-rw-r--r--libmount/src/mountP.h16
6 files changed, 217 insertions, 28 deletions
diff --git a/libmount/samples/mount.c b/libmount/samples/mount.c
index 2d995fd18..08b92332b 100644
--- a/libmount/samples/mount.c
+++ b/libmount/samples/mount.c
@@ -136,10 +136,8 @@ static void print_all(struct libmnt_context *cxt, char *pattern, int show_label)
/*
* mount -a [-F]
- * ... -F is not supported yet (TODO)
*/
-static int mount_all(struct libmnt_context *cxt,
- int forkme __attribute__((unused)))
+static int mount_all(struct libmnt_context *cxt)
{
struct libmnt_iter *itr;
struct libmnt_fs *fs;
@@ -160,24 +158,39 @@ static int mount_all(struct libmnt_context *cxt,
printf(ignored == 1 ? _("%-25s: ignored\n") :
_("%-25s: already mounted\n"),
tgt);
- } else if (!mnt_context_get_status(cxt)) {
- if (mntrc > 0) {
- errno = mntrc;
- printf(_("%-25s: failed: %s\n"), tgt,
- strerror(mntrc));
- rc |= EX_FAIL;
- } else {
- printf(_("%-25s: failed\n"), tgt);
- rc |= EX_SYSERR;
- }
+
+ } else if (mnt_context_is_fork(cxt)) {
+ printf("%-25s: mount successfully forked\n", tgt);
+
} else {
- if (mnt_context_is_verbose(cxt))
- printf("%-25s: successfully mounted\n", tgt);
+ if (!mnt_context_get_status(cxt)) {
+ if (mntrc > 0) {
+ errno = mntrc;
+ printf(_("%-25s: failed: %s\n"), tgt,
+ strerror(mntrc));
+ rc |= EX_FAIL;
+ } else {
+ printf(_("%-25s: failed\n"), tgt);
+ rc |= EX_SYSERR;
+ }
+ } else {
+ if (mnt_context_is_verbose(cxt))
+ printf("%-25s: successfully mounted\n", tgt);
- rc |= EX_SOMEOK;
+ rc |= EX_SOMEOK;
+ }
}
}
+ if (mnt_context_is_parent(cxt)) {
+ /* wait for mount --fork children */
+ int nerrs = 0, nchildren = 0;
+
+ rc = mnt_context_wait_for_children(cxt, &nchildren, &nerrs);
+ if (!rc && nchildren)
+ rc = nchildren == nerrs ? EX_FAIL : EX_SOMEOK;
+ }
+
return rc;
}
@@ -251,7 +264,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
int main(int argc, char **argv)
{
- int c, rc = EX_SUCCESS, all = 0, forkme = 0, show_labels = 0;
+ int c, rc = EX_SUCCESS, all = 0, show_labels = 0;
struct libmnt_context *cxt;
char *source = NULL, *srcbuf = NULL;
char *types = NULL;
@@ -332,7 +345,7 @@ int main(int argc, char **argv)
mnt_context_enable_fake(cxt, TRUE);
break;
case 'F':
- forkme = 1;
+ mnt_context_enable_fork(cxt, TRUE);
break;
case 'h':
usage(stdout);
@@ -445,7 +458,7 @@ int main(int argc, char **argv)
/*
* A) Mount all
*/
- rc = mount_all(cxt, forkme);
+ rc = mount_all(cxt);
goto done;
} else if (argc == 0 && source) {
diff --git a/libmount/src/context.c b/libmount/src/context.c
index e971003cb..c61a14473 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -33,6 +33,8 @@
#include "mountP.h"
+#include <sys/wait.h>
+
/**
* mnt_new_context:
*
@@ -94,6 +96,8 @@ void mnt_free_context(struct libmnt_context *cxt)
mnt_free_lock(cxt->lock);
mnt_free_update(cxt->update);
+ free(cxt->children);
+
DBG(CXT, mnt_debug_h(cxt, "<---- free"));
free(cxt);
}
@@ -161,6 +165,7 @@ int mnt_reset_context(struct libmnt_context *cxt)
cxt->flags |= (fl & MNT_FL_NOHELPERS);
cxt->flags |= (fl & MNT_FL_LOOPDEL);
cxt->flags |= (fl & MNT_FL_LAZY);
+ cxt->flags |= (fl & MNT_FL_FORK);
cxt->flags |= (fl & MNT_FL_FORCE);
cxt->flags |= (fl & MNT_FL_NOCANONICALIZE);
cxt->flags |= (fl & MNT_FL_RDONLY_UMOUNT);
@@ -171,10 +176,13 @@ static int set_flag(struct libmnt_context *cxt, int flag, int enable)
{
if (!cxt)
return -EINVAL;
- if (enable)
+ if (enable) {
+ DBG(CXT, mnt_debug_h(cxt, "enabling flag %04x", flag));
cxt->flags |= flag;
- else
+ } else {
+ DBG(CXT, mnt_debug_h(cxt, "disabling flag %04x", flag));
cxt->flags &= ~flag;
+ }
return 0;
}
@@ -254,6 +262,21 @@ int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable)
}
/**
+ * mnt_context_enable_fork:
+ * @cxt: mount context
+ * @enable: TRUE or FALSE
+ *
+ * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
+ * page, option -F).
+ *
+ * Returns: 0 on success, negative number in case of error.
+ */
+int mnt_context_enable_fork(struct libmnt_context *cxt, int enable)
+{
+ return set_flag(cxt, MNT_FL_FORK, enable);
+}
+
+/**
* mnt_context_is_lazy:
* @cxt: mount context
*
@@ -1683,6 +1706,116 @@ int mnt_context_is_fs_mounted(struct libmnt_context *cxt,
return 0;
}
+static int mnt_context_add_child(struct libmnt_context *cxt, pid_t pid)
+{
+ pid_t *pids;
+
+ if (!cxt)
+ return -EINVAL;
+
+ pids = realloc(cxt->children, sizeof(pid_t) * cxt->nchildren + 1);
+ if (!pids)
+ return -ENOMEM;
+
+ DBG(CXT, mnt_debug_h(cxt, "add new child %d", pid));
+ cxt->children = pids;
+ cxt->children[cxt->nchildren++] = pid;
+
+ return 0;
+}
+
+int mnt_fork_context(struct libmnt_context *cxt)
+{
+ int rc = 0;
+ pid_t pid;
+
+ if (!mnt_context_is_parent(cxt))
+ return -EINVAL;
+
+ DBG(CXT, mnt_debug_h(cxt, "forking context"));
+
+ DBG_FLUSH;
+
+ pid = fork();
+
+ switch (pid) {
+ case -1: /* error */
+ DBG(CXT, mnt_debug_h(cxt, "fork failed %m"));
+ return -errno;
+
+ case 0: /* child */
+ cxt->pid = getpid();
+ cxt->flags &= ~MNT_FL_FORK;
+ DBG(CXT, mnt_debug_h(cxt, "child created"));
+ break;
+
+ default:
+ rc = mnt_context_add_child(cxt, pid);
+ break;
+ }
+
+ return rc;
+}
+
+int mnt_context_wait_for_children(struct libmnt_context *cxt,
+ int *nchildren, int *nerrs)
+{
+ int i;
+
+ if (!cxt)
+ return -EINVAL;
+
+ assert(mnt_context_is_parent(cxt));
+
+ for (i = 0; i < cxt->nchildren; i++) {
+ pid_t pid = cxt->children[i];
+ int rc = 0, ret = 0;
+
+ if (!pid)
+ continue;
+ do {
+ DBG(CXT, mnt_debug_h(cxt,
+ "waiting for child (%d/%d): %d",
+ i + 1, cxt->nchildren, pid));
+ errno = 0;
+ rc = waitpid(pid, &ret, 0);
+
+ } while (rc == -1 && errno == EINTR);
+
+ if (nchildren)
+ (*nchildren)++;
+
+ if (rc != -1 && nerrs) {
+ if (WIFEXITED(ret))
+ (*nerrs) += WEXITSTATUS(ret) == 0 ? 0 : 1;
+ else
+ (*nerrs)++;
+ }
+ cxt->children[i] = 0;
+ }
+
+ cxt->nchildren = 0;
+ free(cxt->children);
+ cxt->children = NULL;
+ return 0;
+}
+
+int mnt_context_is_fork(struct libmnt_context *cxt)
+{
+ return cxt && (cxt->flags & MNT_FL_FORK);
+}
+
+
+int mnt_context_is_parent(struct libmnt_context *cxt)
+{
+ return mnt_context_is_fork(cxt) && cxt->pid == 0;
+}
+
+int mnt_context_is_child(struct libmnt_context *cxt)
+{
+ return !mnt_context_is_fork(cxt) && cxt->pid;
+}
+
#ifdef TEST_PROGRAM
struct libmnt_lock *lock;
diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
index 7b4c0bae3..8fba9c6be 100644
--- a/libmount/src/context_mount.c
+++ b/libmount/src/context_mount.c
@@ -762,12 +762,30 @@ int mnt_context_next_mount(struct libmnt_context *cxt,
return 0;
}
+ if (mnt_context_is_fork(cxt)) {
+ rc = mnt_fork_context(cxt);
+ if (rc)
+ return rc; /* fork error */
+
+ if (mnt_context_is_parent(cxt)) {
+ return 0; /* parent */
+ }
+ }
+
+ /* child or non-forked */
+
rc = mnt_context_set_fs(cxt, *fs);
- if (rc)
- return rc;
- rc = mnt_context_mount(cxt);
- if (mntrc)
- *mntrc = rc;
+ if (!rc) {
+ rc = mnt_context_mount(cxt);
+ if (mntrc)
+ *mntrc = rc;
+ }
+
+ if (mnt_context_is_child(cxt)) {
+ DBG(CXT, mnt_debug_h(cxt, "next-mount: child exit [rc=%d]", rc));
+ DBG_FLUSH;
+ exit(rc);
+ }
return 0;
}
diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in
index c991764b9..95a710e2f 100644
--- a/libmount/src/libmount.h.in
+++ b/libmount/src/libmount.h.in
@@ -390,6 +390,7 @@ extern int mnt_context_disable_mtab(struct libmnt_context *cxt, int disable);
extern int mnt_context_enable_force(struct libmnt_context *cxt, int enable);
extern int mnt_context_enable_verbose(struct libmnt_context *cxt, int enable);
extern int mnt_context_enable_loopdel(struct libmnt_context *cxt, int enable);
+extern int mnt_context_enable_fork(struct libmnt_context *cxt, int enable);
extern int mnt_context_get_optsmode(struct libmnt_context *cxt);
extern int mnt_context_is_lazy(struct libmnt_context *cxt);
@@ -400,6 +401,13 @@ extern int mnt_context_is_nomtab(struct libmnt_context *cxt);
extern int mnt_context_is_force(struct libmnt_context *cxt);
extern int mnt_context_is_verbose(struct libmnt_context *cxt);
+extern int mnt_context_is_fork(struct libmnt_context *cxt);
+extern int mnt_context_is_parent(struct libmnt_context *cxt);
+extern int mnt_context_is_child(struct libmnt_context *cxt);
+
+extern int mnt_context_wait_for_children(struct libmnt_context *cxt,
+ int *nchildren, int *nerrs);
+
extern int mnt_context_is_fs_mounted(struct libmnt_context *cxt,
struct libmnt_fs *fs, int *mounted);
diff --git a/libmount/src/libmount.sym b/libmount/src/libmount.sym
index 6f4eda71d..6f4d1c02b 100644
--- a/libmount/src/libmount.sym
+++ b/libmount/src/libmount.sym
@@ -208,5 +208,10 @@ global:
MOUNT_2.21 {
global:
+ mnt_context_enable_fork;
+ mnt_context_is_child;
+ mnt_context_is_fork;
+ mnt_context_is_parent;
mnt_context_next_umount;
+ mnt_context_wait_for_children;
} MOUNT_2.20;
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index cce4c5c35..9be3aabed 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -61,12 +61,16 @@
# define DBG(m, x) do { \
if ((MNT_DEBUG_ ## m) & libmount_debug_mask) { \
- fprintf(stderr, "libmount: %8s: ", # m); \
+ fprintf(stderr, "%d: libmount: %8s: ", getpid(), # m); \
x; \
} \
} while (0)
-# define DBG_FLUSH do { fflush(stderr); } while(0)
+# define DBG_FLUSH do { \
+ if (libmount_debug_mask && \
+ libmount_debug_mask != MNT_DEBUG_INIT) \
+ fflush(stderr); \
+ } while(0)
extern int libmount_debug_mask;
@@ -299,6 +303,11 @@ struct libmnt_context
char *orig_user; /* original (non-fixed) user= option */
+ pid_t *children; /* "mount -a --fork" PIDs */
+ int nchildren; /* number of children */
+ pid_t pid; /* 0=parent; PID=child */
+
+
int syscall_status; /* 1: not called yet, 0: success, <0: -errno */
};
@@ -313,6 +322,7 @@ struct libmnt_context
#define MNT_FL_FORCE (1 << 8)
#define MNT_FL_NOCANONICALIZE (1 << 9)
#define MNT_FL_RDONLY_UMOUNT (1 << 11) /* remount,ro after EBUSY umount(2) */
+#define MNT_FL_FORK (1 << 12)
#define MNT_FL_EXTERN_FS (1 << 15) /* cxt->fs is not private */
#define MNT_FL_EXTERN_FSTAB (1 << 16) /* cxt->fstab is not private */
@@ -370,6 +380,8 @@ extern int mnt_context_setup_loopdev(struct libmnt_context *cxt);
extern int mnt_context_delete_loopdev(struct libmnt_context *cxt);
extern int mnt_context_clear_loopdev(struct libmnt_context *cxt);
+extern int mnt_fork_context(struct libmnt_context *cxt);
+
/* tab_update.c */
extern struct libmnt_fs *mnt_update_get_fs(struct libmnt_update *upd);
extern int mnt_update_set_filename(struct libmnt_update *upd,