]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: add support for mount -a --fork
authorKarel Zak <kzak@redhat.com>
Fri, 2 Dec 2011 17:20:34 +0000 (18:20 +0100)
committerKarel Zak <kzak@redhat.com>
Fri, 2 Dec 2011 17:20:34 +0000 (18:20 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/samples/mount.c
libmount/src/context.c
libmount/src/context_mount.c
libmount/src/libmount.h.in
libmount/src/libmount.sym
libmount/src/mountP.h

index 2d995fd1884bfd76049cb18fdb2cdfc2c9c49ec8..08b92332ba7a95ab8e3287f4bdf9bf348fa330cf 100644 (file)
@@ -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) {
index e971003cb20a9a9046dcd9debf8cf3ef2670440d..c61a144736411f65abae73c07e2728796b7e7b7f 100644 (file)
@@ -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;
 }
 
@@ -253,6 +261,21 @@ int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable)
        return set_flag(cxt, MNT_FL_LAZY, 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;
index 7b4c0bae3b7f667df42cd20097c9f0d683e60d5b..8fba9c6be3b87653cfe5ed586a7bc6a081e5acc4 100644 (file)
@@ -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;
 }
 
index c991764b9572243c7fb8487cfe1612c83739cf5f..95a710e2fc7e0d86edaf03f83aaa7e3bc1c1d557 100644 (file)
@@ -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);
 
index 6f4eda71db26b8175f5e09d5190e78f70ec63086..6f4d1c02bff97b82a97595dae9ccaa70d205936f 100644 (file)
@@ -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;
index cce4c5c3543168194a43e5b3467a4c4818146668..9be3aabed902ad873ee15df82d8c9f7c8d3e3d50 100644 (file)
 
 # 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,