]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: read all types of kernel messages
authorKarel Zak <kzak@redhat.com>
Tue, 3 Dec 2024 17:56:41 +0000 (18:56 +0100)
committerKarel Zak <kzak@redhat.com>
Wed, 8 Jan 2025 12:58:13 +0000 (13:58 +0100)
Previously, libmount only read error messages from fsopen() file
descriptor. This commit improves the library to read all messages
and keep them in their original format ("<type> <mesg>") in the library mount context.
Applications can now read all messages by using mnt_context_get_mesgs().

Furthermore, private functions have been implemented to include new
library-specific messages in the log. Currently, these messages are
only managed in mnt_context_get_excode(), but it would be beneficial
to relocate them to the appropriate locations where errors are
triggered.

In the future, mnt_context_get_excode() should only be utilized by
basic applications that require an one error message. For more
critical purposes (e.g. mount(8)), it will be recommended to utilize
the messages array.

The public function mnt_context_get_excode() has been modified to use
the new functionality and provide messages in a backwardly compatible
way.

Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/docs/libmount-sections.txt
libmount/src/context.c
libmount/src/context_mount.c
libmount/src/hook_loopdev.c
libmount/src/hook_mount.c
libmount/src/libmount.h.in
libmount/src/libmount.sym
libmount/src/mountP.h

index 0b4adb5950e786b69a7df422ba383e88a47118c4..02158ff89393e0a368806f42b60338d26ffdca01 100644 (file)
@@ -107,6 +107,8 @@ mnt_context_set_target
 mnt_context_set_target_ns
 mnt_context_set_target_prefix
 mnt_context_set_user_mflags
+mnt_context_get_mesgs
+mnt_context_get_nmesgs
 mnt_context_strerror
 mnt_context_switch_ns
 mnt_context_switch_origin_ns
index 565825ca5dd490622e150ccc1b60fce14af242a2..a3bc33ab93a2dd2adbad672009b4dbb92f93857e 100644 (file)
@@ -45,6 +45,7 @@
 #include <sys/wait.h>
 
 #include "mount-api-utils.h"
+#include "strv.h"
 
 /**
  * mnt_new_context:
@@ -2716,54 +2717,73 @@ void mnt_context_syscall_reset_status(struct libmnt_context *cxt)
        cxt->syscall_status = 0;
        cxt->syscall_name = NULL;
 
-       free(cxt->errmsg);
-       cxt->errmsg = NULL;
+       mnt_context_reset_mesgs(cxt);
 }
 
-int mnt_context_set_errmsg(struct libmnt_context *cxt, const char *msg)
+void mnt_context_reset_mesgs(struct libmnt_context *cxt)
 {
-       char *p = NULL;
-
-       if (msg) {
-               p = strdup(msg);
-               if (!p)
-                       return -ENOMEM;
-       }
-
-       free(cxt->errmsg);
-       cxt->errmsg = p;
-
-       return 0;
+       DBG(CXT, ul_debug("reset messages"));
+       strv_free(cxt->mesgs);
+       cxt->mesgs = NULL;
 }
 
-int mnt_context_append_errmsg(struct libmnt_context *cxt, const char *msg)
+int mnt_context_append_mesg(struct libmnt_context *cxt, const char *msg)
 {
-       if (cxt->errmsg) {
-               int rc = strappend(&cxt->errmsg, "; ");
-               if (rc)
-                       return rc;
-       }
-
-       return strappend(&cxt->errmsg, msg);
+       return strv_extend(&cxt->mesgs, msg);
 }
 
-int mnt_context_sprintf_errmsg(struct libmnt_context *cxt, const char *msg, ...)
+int mnt_context_sprintf_mesg(struct libmnt_context *cxt, const char *msg, ...)
 {
        int rc;
        va_list ap;
-       char *p = NULL;
 
        va_start(ap, msg);
-       rc = vasprintf(&p, msg, ap);
+       rc = strv_extendv(&cxt->mesgs, msg, ap);
        va_end(ap);
 
-       if (rc < 0 || !p)
-               return rc;
+       return rc;
+}
 
-       free(cxt->errmsg);
-       cxt->errmsg = p;
+/**
+ * mnt_context_get_nmesgs:
+ * @cxt: mount context
+ * @type: type of message (see fsopen() man page) or zero for all types
+ *
+ * Returns: number of messages
+ *
+ * Since: 2.41
+ */
+size_t mnt_context_get_nmesgs(struct libmnt_context *cxt, char type)
+{
+       size_t n;
+       char **s;
 
-       return 0;
+       if (!cxt || !cxt->mesgs)
+               return 0;
+
+       n = strv_length(cxt->mesgs);
+       if (n && type) {
+               n = 0;
+               STRV_FOREACH(s, cxt->mesgs) {
+                       if (*s && **s == type)
+                               n++;
+               }
+       }
+
+       return n;
+}
+
+/**
+ * mnt_context_get_mesgs:
+ * @cxt: mount context
+ *
+ * Returns: NULL terminated array of messages or NULL
+ *
+ * Since: 2.41
+ */
+char **mnt_context_get_mesgs(struct libmnt_context *cxt)
+{
+       return cxt ? cxt->mesgs : NULL;
 }
 
 /**
index c64e735da57fd765827ba81172fb6892cb4536b7..76b24cd84b68bad6774cc7de113dff22b4ed7e58 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "mountP.h"
 #include "strutils.h"
+#include "strv.h"
 
 #if defined(HAVE_SMACK)
 static int is_option(const char *name, const char *const *names)
@@ -1445,6 +1446,31 @@ done:
        return rc;
 }
 
+static void join_err_mesgs(struct libmnt_context *cxt, char *buf, size_t bufsz)
+{
+       char **s;
+       int n = 0;
+
+       if (!cxt || !buf || strv_isempty(cxt->mesgs))
+               return;
+
+       STRV_FOREACH(s, cxt->mesgs) {
+               size_t len;
+
+               if (!bufsz)
+                       break;
+               if (!startswith(*s, "e "))
+                       continue;
+               if (n) {
+                       len = xstrncpy(buf, "; ", bufsz);
+                       buf += len, bufsz -= len;
+               }
+               len = xstrncpy(buf, (*s) + 2, bufsz);
+               buf += len, bufsz -= len;
+               n++;
+       }
+}
+
 int mnt_context_get_mount_excode(
                        struct libmnt_context *cxt,
                        int rc,
@@ -1490,8 +1516,10 @@ int mnt_context_get_mount_excode(
        mnt_context_get_user_mflags(cxt, &uflags);      /* userspace flags */
 
        if (!mnt_context_syscall_called(cxt)) {
-               if (buf && cxt->errmsg) {
-                       xstrncpy(buf, cxt->errmsg, bufsz);
+
+               /* libmount errors already added to context log */
+               if (buf && mnt_context_get_nmesgs(cxt, 'e')) {
+                       join_err_mesgs(cxt, buf, bufsz);
                        return MNT_EX_USAGE;
                }
 
@@ -1634,16 +1662,20 @@ int mnt_context_get_mount_excode(
         */
        syserr = mnt_context_get_syscall_errno(cxt);
 
-       if (buf && cxt->errmsg) {
-               if (cxt->syscall_name)
-                       snprintf(buf, bufsz, _("%s system call failed: %s"),
-                                       cxt->syscall_name, cxt->errmsg);
-               else
-                       xstrncpy(buf, cxt->errmsg, bufsz);
+       /* Error with already generated messages (by kernel or libmount) */
+       if (buf && mnt_context_get_nmesgs(cxt, 'e')) {
+               if (cxt->syscall_name) {
+                       size_t len = snprintf(buf, bufsz,
+                                       _("%s system call failed: "),
+                                       cxt->syscall_name);
+                       join_err_mesgs(cxt, buf + len, bufsz - len);
+               } else
+                       join_err_mesgs(cxt, buf, bufsz);
 
                return MNT_EX_FAIL;
        }
 
+       /* Classic mount(2) errors */
        switch(syserr) {
        case EPERM:
                if (!buf)
index 65d0f739e830b8beb07de71e166395438581ba30..4f831e0d888d248f3c49dd0fd9b96292dc260524 100644 (file)
@@ -281,7 +281,8 @@ static int setup_loopdev(struct libmnt_context *cxt,
                        DBG(LOOP, ul_debugobj(cxt, "node lost"));
 
                        dev_t devno = loopcxt_get_devno(&lc);
-                       mnt_context_sprintf_errmsg(cxt, _("device node %s (%u:%u) is lost"),
+                       /* TRANSLATORS: Do not translate "e ". It is a message classifier. */
+                       mnt_context_sprintf_mesg(cxt, _("e device node %s (%u:%u) is lost"),
                                        loopcxt_get_device(&lc), major(devno), minor(devno));
                        rc = -EINVAL;
                }
index 7622cc86395a5c5a77f7bb06cd15d240704872c8..a2a4aa63613b852494ac0827bc1390225b33a68a 100644 (file)
@@ -70,8 +70,6 @@ static void save_fd_messages(struct libmnt_context *cxt, int fd)
        uint8_t buf[BUFSIZ];
        int rc;
 
-       mnt_context_set_errmsg(cxt, NULL);
-
        while ((rc = read(fd, buf, sizeof(buf) - 1)) != -1) {
 
                if (rc == 0)
@@ -82,10 +80,7 @@ static void save_fd_messages(struct libmnt_context *cxt, int fd)
                        buf[rc] = '\0';
 
                DBG(CXT, ul_debug("message from kernel: \"%*s\"", rc, buf));
-
-               if (rc < 3 || strncmp((char *) buf, "e ", 2) != 0)
-                       continue;
-               mnt_context_append_errmsg(cxt, ((char *) buf) + 2);
+               mnt_context_append_mesg(cxt, (char *) buf);
        }
 }
 
@@ -96,11 +91,12 @@ static void hookset_set_syscall_status(struct libmnt_context *cxt,
 
        mnt_context_syscall_save_status(cxt, name, x);
 
-       if (!x) {
-               api = get_sysapi(cxt);
-               if (api && api->fd_fs >= 0)
-                       save_fd_messages(cxt, api->fd_fs);
-       }
+       if (!x)
+               mnt_context_reset_mesgs(cxt);   /* reset om error */
+
+       api = get_sysapi(cxt);
+       if (api && api->fd_fs >= 0)
+               save_fd_messages(cxt, api->fd_fs);
 }
 
 /*
index 0a2d821996efd175af25d98cd1abe39d9e630674..0300584eccaa067fa6314705e5d01a9b1c7cde16 100644 (file)
@@ -886,6 +886,9 @@ extern int mnt_context_syscall_called(struct libmnt_context *cxt);
 
 extern int mnt_context_get_syscall_errno(struct libmnt_context *cxt);
 
+extern size_t mnt_context_get_nmesgs(struct libmnt_context *cxt, char type);
+extern char **mnt_context_get_mesgs(struct libmnt_context *cxt);
+
 extern int mnt_context_strerror(struct libmnt_context *cxt, char *buf,
                                size_t bufsiz)
                                __ul_attribute__((deprecated));
index 2b6b12d5c3b774efe15334030e419be75bee59f8..ed5acbb2f6dcdab30aaa599ed04536519f2f1952 100644 (file)
@@ -381,3 +381,8 @@ MOUNT_2_40 {
        mnt_unref_lock;
        mnt_monitor_veil_kernel;
 } MOUNT_2_39;
+
+MOUNT_2_41 {
+       mnt_context_get_nmesgs;
+       mnt_context_get_mesgs;
+} MOUNT_2_40;
index 893f9e72947a3a10d027df778ebe16b025f79fc7..365a6e0f0fcacb10cca256a255bb1f42a43a0aaa 100644 (file)
@@ -432,7 +432,8 @@ struct libmnt_context
 
        int     syscall_status; /* 1: not called yet, 0: success, <0: -errno */
        const char *syscall_name;       /* failed syscall name */
-       char    *errmsg;        /* library or kernel message */
+
+       char    **mesgs;                /* library or kernel messages (NULL terminated array) */
 
        struct libmnt_ns        ns_orig;        /* original namespace */
        struct libmnt_ns        ns_tgt;         /* target namespace */
@@ -627,9 +628,9 @@ extern int mnt_context_update_tabs(struct libmnt_context *cxt);
 extern int mnt_context_umount_setopt(struct libmnt_context *cxt, int c, char *arg);
 extern int mnt_context_mount_setopt(struct libmnt_context *cxt, int c, char *arg);
 
-extern int mnt_context_set_errmsg(struct libmnt_context *cxt, const char *msg);
-extern int mnt_context_append_errmsg(struct libmnt_context *cxt, const char *msg);
-extern int mnt_context_sprintf_errmsg(struct libmnt_context *cxt, const char *msg, ...);
+extern void mnt_context_reset_mesgs(struct libmnt_context *cxt);
+extern int mnt_context_append_mesg(struct libmnt_context *cxt, const char *msg);
+extern int mnt_context_sprintf_mesg(struct libmnt_context *cxt, const char *msg, ...);
 
 extern int mnt_context_propagation_only(struct libmnt_context *cxt)
                        __attribute__((nonnull));