libmount: add support for mount -a --fork
Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
parent
ede8a60e05
commit
d2c97887fe
|
@ -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_verbose(cxt))
|
||||
printf("%-25s: successfully mounted\n", tgt);
|
||||
|
||||
rc |= EX_SOMEOK;
|
||||
} else if (mnt_context_is_fork(cxt)) {
|
||||
printf("%-25s: mount successfully forked\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_verbose(cxt))
|
||||
printf("%-25s: successfully mounted\n", tgt);
|
||||
|
||||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue