#include <fcntl.h>
#include <net/if.h>
#include <stddef.h>
-#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "user-util.h"
typedef struct Spawn {
+ sd_device *device;
const char *cmd;
pid_t pid;
usec_t timeout_warn_usec;
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;
}
/* 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;
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;
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')
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);
}
assert(dest);
assert(size > 0);
- while (s[0] != '\0') {
+ while (*s) {
FormatSubstitutionType type;
char attr[UTIL_PATH_SIZE];
ssize_t subst_len;
}
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;
+ }
}
}
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;
}
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;
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;
}
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;
}
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);
/* 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])) {
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);
errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
spawn = (Spawn) {
+ .device = event->dev,
.cmd = cmd,
.pid = pid,
.accept_failure = accept_failure,
};
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';
static int update_devnode(UdevEvent *event) {
sd_device *dev = event->dev;
- bool apply;
int r;
r = sd_device_get_devnum(dev, NULL);
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");
}
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(