]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/udev/udev-event.c
Merge pull request #13936 from keszybz/format-table-uninhibited
[thirdparty/systemd.git] / src / udev / udev-event.c
index 09eb56b97de095d0ced8460e6ee12c190d3c86fd..bff75ed5219e6010e99355a2f27d10f57a3baa9f 100644 (file)
@@ -5,7 +5,6 @@
 #include <fcntl.h>
 #include <net/if.h>
 #include <stddef.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -37,6 +36,7 @@
 #include "user-util.h"
 
 typedef struct Spawn {
+        sd_device *device;
         const char *cmd;
         pid_t pid;
         usec_t timeout_warn_usec;
@@ -156,25 +156,26 @@ static int get_subst_type(const char **str, bool strict, FormatSubstitutionType
         assert(str);
         assert(*str);
         assert(ret_type);
+        assert(ret_attr);
 
-        if (p[0] == '$') {
+        if (*p == '$') {
                 p++;
-                if (p[0] == '$') {
+                if (*p == '$') {
                         *str = p;
                         return 0;
                 }
                 for (i = 0; i < ELEMENTSOF(map); i++)
                         if ((q = startswith(p, map[i].name)))
                                 break;
-        } else if (p[0] == '%') {
+        } else if (*p == '%') {
                 p++;
-                if (p[0] == '%') {
+                if (*p == '%') {
                         *str = p;
                         return 0;
                 }
 
                 for (i = 0; i < ELEMENTSOF(map); i++)
-                        if (p[0] == map[i].fmt) {
+                        if (*p == map[i].fmt) {
                                 q = p + 1;
                                 break;
                         }
@@ -184,7 +185,7 @@ static int get_subst_type(const char **str, bool strict, FormatSubstitutionType
                 /* When 'strict' flag is set, then '$' and '%' must be escaped. */
                 return strict ? -EINVAL : 0;
 
-        if (q[0] == '{') {
+        if (*q == '{') {
                 const char *start, *end;
                 size_t len;
 
@@ -200,7 +201,7 @@ static int get_subst_type(const char **str, bool strict, FormatSubstitutionType
                 strnscpy(ret_attr, UTIL_PATH_SIZE, start, len);
                 q = end + 1;
         } else
-                ret_attr[0] = '\0';
+                *ret_attr = '\0';
 
         *str = q;
         *ret_type = map[i].type;
@@ -311,7 +312,7 @@ static ssize_t udev_event_subst_format(
                         p = skip_leading_chars(event->program_result, NULL);
 
                         for (i = 1; i < index; i++) {
-                                while (p[0] != '\0' && !strchr(WHITESPACE, p[0]))
+                                while (*p && !strchr(WHITESPACE, *p))
                                         p++;
                                 p = skip_leading_chars(p, NULL);
                                 if (*p == '\0')
@@ -327,7 +328,7 @@ static ssize_t udev_event_subst_format(
                         if (has_plus)
                                 l = strpcpy(&s, l, start);
                         else {
-                                while (p[0] != '\0' && !strchr(WHITESPACE, p[0]))
+                                while (*p && !strchr(WHITESPACE, *p))
                                         p++;
                                 l = strnpcpy(&s, l, start, p - start);
                         }
@@ -447,7 +448,7 @@ ssize_t udev_event_apply_format(UdevEvent *event,
         assert(dest);
         assert(size > 0);
 
-        while (s[0] != '\0') {
+        while (*s) {
                 FormatSubstitutionType type;
                 char attr[UTIL_PATH_SIZE];
                 ssize_t subst_len;
@@ -480,33 +481,48 @@ ssize_t udev_event_apply_format(UdevEvent *event,
         }
 
         assert(size >= 1);
-        dest[0] = '\0';
+        *dest = '\0';
         return size;
 }
 
-int udev_check_format(const char *s) {
+int udev_check_format(const char *value, size_t *offset, const char **hint) {
         FormatSubstitutionType type;
+        const char *s = value;
         char attr[UTIL_PATH_SIZE];
         int r;
 
-        while (s[0] != '\0') {
+        while (*s) {
                 r = get_subst_type(&s, true, &type, attr);
-                if (r < 0)
+                if (r < 0) {
+                        if (offset)
+                                *offset = s - value;
+                        if (hint)
+                                *hint = "invalid substitution type";
                         return r;
-                if (r == 0) {
+                } else if (r == 0) {
                         s++;
                         continue;
                 }
 
-                if (IN_SET(type, FORMAT_SUBST_ATTR, FORMAT_SUBST_ENV) && isempty(attr))
+                if (IN_SET(type, FORMAT_SUBST_ATTR, FORMAT_SUBST_ENV) && isempty(attr)) {
+                        if (offset)
+                                *offset = s - value;
+                        if (hint)
+                                *hint = "attribute value missing";
                         return -EINVAL;
+                }
 
                 if (type == FORMAT_SUBST_RESULT && !isempty(attr)) {
                         unsigned i;
 
                         r = safe_atou_optional_plus(attr, &i);
-                        if (r < 0)
+                        if (r < 0) {
+                                if (offset)
+                                        *offset = s - value;
+                                if (hint)
+                                        *hint = "attribute value not a valid number";
                                 return r;
+                        }
                 }
         }
 
@@ -534,7 +550,8 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd
         l = read(fd, p, size - 1);
         if (l < 0) {
                 if (errno != EAGAIN)
-                        log_error_errno(errno, "Failed to read stdout of '%s': %m", spawn->cmd);
+                        log_device_error_errno(spawn->device, errno,
+                                               "Failed to read stdout of '%s': %m", spawn->cmd);
 
                 return 0;
         }
@@ -553,8 +570,8 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd
                         return 0;
 
                 STRV_FOREACH(q, v)
-                        log_debug("'%s'(%s) '%s'", spawn->cmd,
-                                  fd == spawn->fd_stdout ? "out" : "err", *q);
+                        log_device_debug(spawn->device, "'%s'(%s) '%s'", spawn->cmd,
+                                         fd == spawn->fd_stdout ? "out" : "err", *q);
         }
 
         return 0;
@@ -568,8 +585,9 @@ static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
 
         kill_and_sigcont(spawn->pid, SIGKILL);
 
-        log_error("Spawned process '%s' ["PID_FMT"] timed out after %s, killing", spawn->cmd, spawn->pid,
-                  format_timespan(timeout, sizeof(timeout), spawn->timeout_usec, USEC_PER_SEC));
+        log_device_error(spawn->device, "Spawned process '%s' ["PID_FMT"] timed out after %s, killing",
+                         spawn->cmd, spawn->pid,
+                         format_timespan(timeout, sizeof(timeout), spawn->timeout_usec, USEC_PER_SEC));
 
         return 1;
 }
@@ -580,8 +598,9 @@ static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *use
 
         assert(spawn);
 
-        log_warning("Spawned process '%s' ["PID_FMT"] is taking longer than %s to complete", spawn->cmd, spawn->pid,
-                    format_timespan(timeout, sizeof(timeout), spawn->timeout_warn_usec, USEC_PER_SEC));
+        log_device_warning(spawn->device, "Spawned process '%s' ["PID_FMT"] is taking longer than %s to complete",
+                           spawn->cmd, spawn->pid,
+                           format_timespan(timeout, sizeof(timeout), spawn->timeout_warn_usec, USEC_PER_SEC));
 
         return 1;
 }
@@ -595,18 +614,18 @@ static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userd
         switch (si->si_code) {
         case CLD_EXITED:
                 if (si->si_status == 0)
-                        log_debug("Process '%s' succeeded.", spawn->cmd);
+                        log_device_debug(spawn->device, "Process '%s' succeeded.", spawn->cmd);
                 else
-                        log_full(spawn->accept_failure ? LOG_DEBUG : LOG_WARNING,
-                                 "Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
+                        log_device_full(spawn->device, spawn->accept_failure ? LOG_DEBUG : LOG_WARNING, 0,
+                                        "Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
                 ret = si->si_status;
                 break;
         case CLD_KILLED:
         case CLD_DUMPED:
-                log_error("Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
+                log_device_error(spawn->device, "Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
                 break;
         default:
-                log_error("Process '%s' failed due to unknown reason.", spawn->cmd);
+                log_device_error(spawn->device, "Process '%s' failed due to unknown reason.", spawn->cmd);
         }
 
         sd_event_exit(sd_event_source_get_event(s), ret);
@@ -688,19 +707,21 @@ int udev_event_spawn(UdevEvent *event,
         /* pipes from child to parent */
         if (result || log_get_max_level() >= LOG_INFO)
                 if (pipe2(outpipe, O_NONBLOCK|O_CLOEXEC) != 0)
-                        return log_error_errno(errno, "Failed to create pipe for command '%s': %m", cmd);
+                        return log_device_error_errno(event->dev, errno,
+                                                      "Failed to create pipe for command '%s': %m", cmd);
 
         if (log_get_max_level() >= LOG_INFO)
                 if (pipe2(errpipe, O_NONBLOCK|O_CLOEXEC) != 0)
-                        return log_error_errno(errno, "Failed to create pipe for command '%s': %m", cmd);
+                        return log_device_error_errno(event->dev, errno,
+                                                      "Failed to create pipe for command '%s': %m", cmd);
 
         argv = strv_split_full(cmd, NULL, SPLIT_QUOTES|SPLIT_RELAX);
         if (!argv)
                 return log_oom();
 
         if (isempty(argv[0]))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "Invalid command '%s'", cmd);
+                return log_device_error_errno(event->dev, SYNTHETIC_ERRNO(EINVAL),
+                                              "Invalid command '%s'", cmd);
 
         /* allow programs in /usr/lib/udev/ to be called without the path */
         if (!path_is_absolute(argv[0])) {
@@ -717,11 +738,12 @@ int udev_event_spawn(UdevEvent *event,
         if (r < 0)
                 return log_device_error_errno(event->dev, r, "Failed to get device properties");
 
-        log_debug("Starting '%s'", cmd);
+        log_device_debug(event->dev, "Starting '%s'", cmd);
 
         r = safe_fork("(spawn)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
         if (r < 0)
-                return log_error_errno(r, "Failed to fork() to execute command '%s': %m", cmd);
+                return log_device_error_errno(event->dev, r,
+                                              "Failed to fork() to execute command '%s': %m", cmd);
         if (r == 0) {
                 if (rearrange_stdio(-1, outpipe[WRITE_END], errpipe[WRITE_END]) < 0)
                         _exit(EXIT_FAILURE);
@@ -738,6 +760,7 @@ int udev_event_spawn(UdevEvent *event,
         errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
 
         spawn = (Spawn) {
+                .device = event->dev,
                 .cmd = cmd,
                 .pid = pid,
                 .accept_failure = accept_failure,
@@ -751,7 +774,8 @@ int udev_event_spawn(UdevEvent *event,
         };
         r = spawn_wait(&spawn);
         if (r < 0)
-                return log_error_errno(r, "Failed to wait for spawned command '%s': %m", cmd);
+                return log_device_error_errno(event->dev, r,
+                                              "Failed to wait for spawned command '%s': %m", cmd);
 
         if (result)
                 result[spawn.result_len] = '\0';
@@ -804,7 +828,6 @@ static int rename_netif(UdevEvent *event) {
 
 static int update_devnode(UdevEvent *event) {
         sd_device *dev = event->dev;
-        bool apply;
         int r;
 
         r = sd_device_get_devnum(dev, NULL);
@@ -819,17 +842,13 @@ static int update_devnode(UdevEvent *event) {
 
         if (!uid_is_valid(event->uid)) {
                 r = device_get_devnode_uid(dev, &event->uid);
-                if (r == -ENOENT)
-                        event->uid = 0;
-                else if (r < 0)
+                if (r < 0 && r != -ENOENT)
                         return log_device_error_errno(dev, r, "Failed to get devnode UID: %m");
         }
 
         if (!gid_is_valid(event->gid)) {
                 r = device_get_devnode_gid(dev, &event->gid);
-                if (r == -ENOENT)
-                        event->gid = 0;
-                else if (r < 0)
+                if (r < 0 && r != -ENOENT)
                         return log_device_error_errno(dev, r, "Failed to get devnode GID: %m");
         }
 
@@ -837,21 +856,14 @@ static int update_devnode(UdevEvent *event) {
                 r = device_get_devnode_mode(dev, &event->mode);
                 if (r < 0 && r != -ENOENT)
                         return log_device_error_errno(dev, r, "Failed to get devnode mode: %m");
-                if (r == -ENOENT) {
-                        if (event->gid > 0)
-                                /* default 0660 if a group is assigned */
-                                event->mode = 0660;
-                        else
-                                /* default 0600 */
-                                event->mode = 0600;
-                }
         }
+        if (event->mode == MODE_INVALID && gid_is_valid(event->gid) && event->gid > 0)
+                /* If group is set, but mode is not set, "upgrade" mode for the group. */
+                event->mode = 0660;
+
+        bool apply_mac = device_for_action(dev, DEVICE_ACTION_ADD);
 
-        apply = device_for_action(dev, DEVICE_ACTION_ADD) ||
-                uid_is_valid(event->uid) ||
-                gid_is_valid(event->gid) ||
-                event->mode != MODE_INVALID;
-        return udev_node_add(dev, apply, event->mode, event->uid, event->gid, event->seclabel_list);
+        return udev_node_add(dev, apply_mac, event->mode, event->uid, event->gid, event->seclabel_list);
 }
 
 static void event_execute_rules_on_remove(