From 172aeb36e9d98c235cf63ebd630c4c67ea43d26b Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 27 May 2024 14:04:31 +0200 Subject: [PATCH] libmount: expose exec errors * Introduce special exit status 126 to inform about failed execl of the /sbin/[u]mount. helpers. * Introduce MNT_ERR_EXEC as an API return code to inform about failed execl() calls. * Add mount and umount messages for failed execl() calls. * Add EXIT STATUS section to umount man page. Addresses: https://github.com/util-linux/util-linux/pull/3063 Signed-off-by: Karel Zak --- libmount/src/context_mount.c | 28 +++++++++++++++++++++------- libmount/src/context_umount.c | 22 ++++++++++++++++------ libmount/src/libmount.h.in | 13 +++++++++++++ sys-utils/mount.8.adoc | 5 +++++ sys-utils/umount.8.adoc | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 13 deletions(-) diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c index 53918c3fca..6762877330 100644 --- a/libmount/src/context_mount.c +++ b/libmount/src/context_mount.c @@ -460,7 +460,7 @@ static int exec_helper(struct libmnt_context *cxt) i, args[i])); DBG_FLUSH; execv(cxt->helper, (char * const *) args); - _exit(EXIT_FAILURE); + _exit(MNT_EX_EXEC); } default: { @@ -469,14 +469,20 @@ static int exec_helper(struct libmnt_context *cxt) if (waitpid(pid, &st, 0) == (pid_t) -1) { cxt->helper_status = -1; rc = -errno; + DBG(CXT, ul_debugobj(cxt, "waitpid failed [errno=%d]", -rc)); } else { cxt->helper_status = WIFEXITED(st) ? WEXITSTATUS(st) : -1; cxt->helper_exec_status = rc = 0; - } - DBG(CXT, ul_debugobj(cxt, "%s executed [status=%d, rc=%d%s]", + + if (cxt->helper_status == MNT_EX_EXEC) { + rc = -MNT_ERR_EXEC; + DBG(CXT, ul_debugobj(cxt, "%s exec failed", cxt->helper)); + } + + DBG(CXT, ul_debugobj(cxt, "%s forked [status=%d, rc=%d]", cxt->helper, - cxt->helper_status, rc, - rc ? " waitpid failed" : "")); + cxt->helper_status, rc)); + } break; } @@ -1414,8 +1420,16 @@ int mnt_context_get_mount_excode( /* * /sbin/mount. called, return status */ - if (rc == -MNT_ERR_APPLYFLAGS && buf) - snprintf(buf, bufsz, _("WARNING: failed to apply propagation flags")); + if (buf) { + switch (rc) { + case -MNT_ERR_APPLYFLAGS: + snprintf(buf, bufsz, _("WARNING: failed to apply propagation flags")); + break; + case -MNT_ERR_EXEC: + snprintf(buf, bufsz, _("failed to execute %s"), cxt->helper); + break; + } + } return mnt_context_get_helper_status(cxt); } diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c index bf70ed2ee7..adfaf7fa6b 100644 --- a/libmount/src/context_umount.c +++ b/libmount/src/context_umount.c @@ -741,7 +741,7 @@ static int exec_helper(struct libmnt_context *cxt) i, args[i])); DBG_FLUSH; execv(cxt->helper, (char * const *) args); - _exit(EXIT_FAILURE); + _exit(MNT_EX_EXEC); } default: { @@ -750,14 +750,20 @@ static int exec_helper(struct libmnt_context *cxt) if (waitpid(pid, &st, 0) == (pid_t) -1) { cxt->helper_status = -1; rc = -errno; + DBG(CXT, ul_debugobj(cxt, "waitpid failed [errno=%d]", -rc)); } else { cxt->helper_status = WIFEXITED(st) ? WEXITSTATUS(st) : -1; cxt->helper_exec_status = rc = 0; - } - DBG(CXT, ul_debugobj(cxt, "%s executed [status=%d, rc=%d%s]", + + if (cxt->helper_status == MNT_EX_EXEC) { + rc = -MNT_ERR_EXEC; + DBG(CXT, ul_debugobj(cxt, "%s exec failed", cxt->helper)); + } + + DBG(CXT, ul_debugobj(cxt, "%s forked [status=%d, rc=%d]", cxt->helper, - cxt->helper_status, rc, - rc ? " waitpid failed" : "")); + cxt->helper_status, rc)); + } break; } @@ -1238,11 +1244,15 @@ int mnt_context_get_umount_excode( char *buf, size_t bufsz) { - if (mnt_context_helper_executed(cxt)) + if (mnt_context_helper_executed(cxt)) { /* * /sbin/umount. called, return status */ + if (rc == -MNT_ERR_EXEC && buf) + snprintf(buf, bufsz, _("failed to execute %s"), cxt->helper); + return mnt_context_get_helper_status(cxt); + } if (rc == 0 && mnt_context_get_status(cxt) == 1) /* diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in index d893c26493..0a2d821996 100644 --- a/libmount/src/libmount.h.in +++ b/libmount/src/libmount.h.in @@ -241,6 +241,13 @@ enum { * filesystem mounted, but subsequent X-mount.idmap= failed */ #define MNT_ERR_IDMAP 5013 +/** + * MNT_ERR_EXEC: + * + * failed to execute external program + */ +#define MNT_ERR_EXEC 5014 + /* @@ -305,6 +312,12 @@ enum { */ #define MNT_EX_SOMEOK 64 +/** + * MNT_EX_EXEC: + * + * [u]mount(8) exit code: external program execution failed + */ +#define MNT_EX_EXEC 126 #ifndef __GNUC_PREREQ diff --git a/sys-utils/mount.8.adoc b/sys-utils/mount.8.adoc index 43628adce5..4c9bef6f4f 100644 --- a/sys-utils/mount.8.adoc +++ b/sys-utils/mount.8.adoc @@ -1612,6 +1612,9 @@ some mount succeeded + The command *mount -a* returns 0 (all succeeded), 32 (all failed), or 64 (some failed, some succeeded). +*126*:: +failed to execute external /sbin/mount. mount helper (since util-linux v2.41) + == EXTERNAL HELPERS The syntax of external mount helpers is: @@ -1622,6 +1625,8 @@ where the _suffix_ is the filesystem type and the *-sfnvoN* options have the sam The command *mount* does not pass the mount options *unbindable*, *runbindable*, *private*, *rprivate*, *slave*, *rslave*, *shared*, *rshared*, *auto*, *noauto*, *comment*, *x-**, *loop*, *offset* and *sizelimit* to the mount. helpers. All other options are used in a comma-separated list as an argument to the *-o* option. +The exit status value of the helper is returned as the exit status of *mount*(8). The value 126 is sed if the mount helper program is found, but the execl() failed. + == ENVIRONMENT *LIBMOUNT_FORCE_MOUNT2*={always|never|auto}:: diff --git a/sys-utils/umount.8.adoc b/sys-utils/umount.8.adoc index 47011316b9..f9b96e1ff8 100644 --- a/sys-utils/umount.8.adoc +++ b/sys-utils/umount.8.adoc @@ -127,6 +127,39 @@ The *umount* command will automatically detach loop device previously initialize In this case the device is initialized with "autoclear" flag (see *losetup*(8) output for more details), otherwise it's necessary to use the option *--detach-loop* or call *losetup -d* _device_. The autoclear feature is supported since Linux 2.6.25. +== EXIT STATUS + +*umount* has the following exit status values (the bits can be ORed): + +*0*:: +success + +*1*:: +incorrect invocation or permissions + +*2*:: +system error (out of memory, cannot fork, no more loop devices) + +*4*:: +internal *mount* bug + +*8*:: +user interrupt + +*16*:: +problems writing or locking _/etc/mtab_ + +*32*:: +mount failure + +*64*:: +some umount succeeded ++ +The command *umount -a* returns 0 (all succeeded), 32 (all failed), or 64 (some failed, some succeeded). + +*126*:: +failed to execute external /sbin/umount. mount helper (since util-linux v2.41) + == EXTERNAL HELPERS The syntax of external unmount helpers is: @@ -147,6 +180,8 @@ A **helper=**__type__ marker in the _mtab_ file will redirect all unmount reques Note that _/etc/mtab_ is currently deprecated and *helper=* and other userspace mount options are maintained by *libmount*. +The exit status value of the helper is returned as the exit status of *umount*(8). The value 126 is used if the mount helper program is found, but the execl() failed. + == ENVIRONMENT *LIBMOUNT_FSTAB*=:: -- 2.47.3