Merge pull request #10603 from yuwata/udevd-parser

udevd: several cleanups for parsing options
This commit is contained in:
Lennart Poettering 2018-11-12 18:39:51 +01:00 committed by GitHub
commit 60d540fabd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 108 additions and 144 deletions

View File

@ -99,7 +99,6 @@ void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num);
#define UTIL_NAME_SIZE 512
#define UTIL_LINE_SIZE 16384
#define UDEV_ALLOWED_CHARS_INPUT "/ $%?,"
int util_log_priority(const char *priority);
size_t util_path_encode(const char *src, char *dest, size_t size);
int util_replace_whitespace(const char *str, char *to, size_t len);
int util_replace_chars(char *str, const char *white);

View File

@ -12,7 +12,6 @@
#include "MurmurHash2.h"
#include "device-nodes.h"
#include "libudev-private.h"
#include "syslog-util.h"
#include "utf8.h"
/**
@ -84,21 +83,6 @@ int util_resolve_subsys_kernel(const char *string,
return 0;
}
int util_log_priority(const char *priority) {
char *endptr;
int prio;
prio = strtoul(priority, &endptr, 10);
if (endptr[0] == '\0' || isspace(endptr[0])) {
if (prio >= 0 && prio <= 7)
return prio;
else
return -ERANGE;
}
return log_level_from_string(priority);
}
size_t util_path_encode(const char *src, char *dest, size_t size) {
size_t i, j;

View File

@ -84,7 +84,7 @@ int main(int argc, char *argv[]) {
action = argv[1];
devpath = argv[2];
rules = udev_rules_new(1);
rules = udev_rules_new(RESOLVE_NAME_EARLY);
const char *syspath = strjoina("/sys", devpath);
r = device_new_from_synthetic_event(&dev, syspath, action);

View File

@ -42,7 +42,7 @@ typedef struct Spawn {
size_t result_len;
} Spawn;
struct udev_event *udev_event_new(sd_device *dev, int exec_delay, sd_netlink *rtnl) {
struct udev_event *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl) {
struct udev_event *event;
assert(dev);
@ -54,7 +54,7 @@ struct udev_event *udev_event_new(sd_device *dev, int exec_delay, sd_netlink *rt
*event = (struct udev_event) {
.dev = sd_device_ref(dev),
.birth_usec = now(CLOCK_MONOTONIC),
.exec_delay = exec_delay,
.exec_delay_usec = exec_delay_usec,
.rtnl = sd_netlink_ref(rtnl),
};
@ -896,9 +896,9 @@ void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_
if (builtin_cmd >= 0 && builtin_cmd < _UDEV_BUILTIN_MAX)
udev_builtin_run(event->dev, builtin_cmd, command, false);
else {
if (event->exec_delay > 0) {
if (event->exec_delay_usec > 0) {
log_debug("delay execution of '%s'", command);
sleep(event->exec_delay);
(void) usleep(event->exec_delay_usec);
}
udev_event_spawn(event, timeout_usec, timeout_warn_usec, false, command, NULL, 0);

View File

@ -30,6 +30,7 @@
#include "stat-util.h"
#include "stdio-util.h"
#include "strbuf.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "sysctl-util.h"
@ -57,7 +58,7 @@ static const char* const rules_dirs[] = {
struct udev_rules {
usec_t dirs_ts_usec;
int resolve_names;
ResolveNameTiming resolve_name_timing;
/* every key in the rules file becomes a token */
struct token *tokens;
@ -1335,10 +1336,10 @@ static void add_rule(struct udev_rules *rules, char *line,
uid = strtoul(value, &endptr, 10);
if (endptr[0] == '\0')
rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
else if (rules->resolve_names > 0 && strchr("$%", value[0]) == NULL) {
else if (rules->resolve_name_timing == RESOLVE_NAME_EARLY && strchr("$%", value[0]) == NULL) {
uid = add_uid(rules, value);
rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
} else if (rules->resolve_names >= 0)
} else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER)
rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL);
rule_tmp.rule.rule.can_set_name = true;
@ -1353,10 +1354,10 @@ static void add_rule(struct udev_rules *rules, char *line,
gid = strtoul(value, &endptr, 10);
if (endptr[0] == '\0')
rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) {
else if ((rules->resolve_name_timing == RESOLVE_NAME_EARLY) && strchr("$%", value[0]) == NULL) {
gid = add_gid(rules, value);
rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
} else if (rules->resolve_names >= 0)
} else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER)
rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL);
rule_tmp.rule.rule.can_set_name = true;
@ -1512,18 +1513,20 @@ static int parse_file(struct udev_rules *rules, const char *filename) {
return 0;
}
struct udev_rules *udev_rules_new(int resolve_names) {
struct udev_rules *udev_rules_new(ResolveNameTiming resolve_name_timing) {
struct udev_rules *rules;
struct token end_token;
char **files, **f;
int r;
assert(resolve_name_timing >= 0 && resolve_name_timing < _RESOLVE_NAME_TIMING_MAX);
rules = new(struct udev_rules, 1);
if (!rules)
return NULL;
*rules = (struct udev_rules) {
.resolve_names = resolve_names,
.resolve_name_timing = resolve_name_timing,
};
/* init token array and string buffer */
@ -2598,3 +2601,11 @@ finish:
return 0;
}
static const char* const resolve_name_timing_table[_RESOLVE_NAME_TIMING_MAX] = {
[RESOLVE_NAME_NEVER] = "never",
[RESOLVE_NAME_LATE] = "late",
[RESOLVE_NAME_EARLY] = "early",
};
DEFINE_STRING_TABLE_LOOKUP(resolve_name_timing, ResolveNameTiming);

View File

@ -30,7 +30,7 @@ struct udev_event {
gid_t gid;
Hashmap *seclabel_list;
Hashmap *run_list;
int exec_delay;
usec_t exec_delay_usec;
usec_t birth_usec;
sd_netlink *rtnl;
unsigned builtin_run;
@ -48,9 +48,17 @@ struct udev_event {
bool run_final;
};
typedef enum ResolveNameTiming {
RESOLVE_NAME_NEVER,
RESOLVE_NAME_LATE,
RESOLVE_NAME_EARLY,
_RESOLVE_NAME_TIMING_MAX,
_RESOLVE_NAME_TIMING_INVALID = -1,
} ResolveNameTiming;
/* udev-rules.c */
struct udev_rules;
struct udev_rules *udev_rules_new(int resolve_names);
struct udev_rules *udev_rules_new(ResolveNameTiming resolve_name_timing);
struct udev_rules *udev_rules_unref(struct udev_rules *rules);
bool udev_rules_check_timestamp(struct udev_rules *rules);
int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event,
@ -58,8 +66,11 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
Hashmap *properties_list);
int udev_rules_apply_static_dev_perms(struct udev_rules *rules);
ResolveNameTiming resolve_name_timing_from_string(const char *s) _pure_;
const char *resolve_name_timing_to_string(ResolveNameTiming i) _const_;
/* udev-event.c */
struct udev_event *udev_event_new(sd_device *dev, int exec_delay, sd_netlink *rtnl);
struct udev_event *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl);
struct udev_event *udev_event_free(struct udev_event *event);
ssize_t udev_event_apply_format(struct udev_event *event,
const char *src, char *dest, size_t size,

View File

@ -19,9 +19,9 @@
#include <string.h>
#include <unistd.h>
#include "libudev-private.h"
#include "parse-util.h"
#include "process-util.h"
#include "syslog-util.h"
#include "time-util.h"
#include "udevadm.h"
#include "udev-ctrl.h"
@ -84,18 +84,15 @@ int control_main(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
break;
case 'l': {
int i;
case 'l':
r = log_level_from_string(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse log priority '%s': %m", optarg);
i = util_log_priority(optarg);
if (i < 0)
return log_error_errno(i, "invalid number '%s'", optarg);
r = udev_ctrl_send_set_log_level(uctrl, i, timeout);
r = udev_ctrl_send_set_log_level(uctrl, r, timeout);
if (r < 0)
return r;
break;
}
case 's':
r = udev_ctrl_send_stop_exec_queue(uctrl, timeout);
if (r < 0)

View File

@ -22,7 +22,7 @@
#include "udevadm.h"
static const char *arg_action = "add";
static int arg_resolve_names = 1;
static ResolveNameTiming arg_resolve_name_timing = RESOLVE_NAME_EARLY;
static char arg_syspath[UTIL_PATH_SIZE] = {};
static int help(void) {
@ -55,14 +55,9 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = optarg;
break;
case 'N':
if (streq (optarg, "early")) {
arg_resolve_names = 1;
} else if (streq (optarg, "late")) {
arg_resolve_names = 0;
} else if (streq (optarg, "never")) {
arg_resolve_names = -1;
} else {
log_error("resolve-names must be early, late or never");
arg_resolve_name_timing = resolve_name_timing_from_string(optarg);
if (arg_resolve_name_timing < 0) {
log_error("--resolve-names= must be early, late or never");
return -EINVAL;
}
break;
@ -115,7 +110,7 @@ int test_main(int argc, char *argv[], void *userdata) {
udev_builtin_init();
rules = udev_rules_new(arg_resolve_names);
rules = udev_rules_new(arg_resolve_name_timing);
if (!rules) {
log_error("Failed to read udev rules.");
r = -ENOMEM;

View File

@ -51,6 +51,7 @@
#include "signal-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "syslog-util.h"
#include "terminal-util.h"
#include "udev-builtin.h"
#include "udev-ctrl.h"
@ -61,9 +62,9 @@
static bool arg_debug = false;
static int arg_daemonize = false;
static int arg_resolve_names = 1;
static unsigned arg_children_max;
static int arg_exec_delay;
static ResolveNameTiming arg_resolve_name_timing = RESOLVE_NAME_EARLY;
static unsigned arg_children_max = 0;
static usec_t arg_exec_delay_usec = 0;
static usec_t arg_event_timeout_usec = 180 * USEC_PER_SEC;
static usec_t arg_event_timeout_warn_usec = 180 * USEC_PER_SEC / 3;
@ -409,7 +410,7 @@ static void worker_spawn(Manager *manager, struct event *event) {
assert(dev);
log_debug("seq %llu running", udev_device_get_seqnum(dev));
udev_event = udev_event_new(dev->device, arg_exec_delay, rtnl);
udev_event = udev_event_new(dev->device, arg_exec_delay_usec, rtnl);
if (!udev_event) {
r = -ENOMEM;
goto out;
@ -851,7 +852,7 @@ static void event_queue_start(Manager *manager) {
udev_builtin_init();
if (!manager->rules) {
manager->rules = udev_rules_new(arg_resolve_names);
manager->rules = udev_rules_new(arg_resolve_name_timing);
if (!manager->rules)
return;
}
@ -1355,26 +1356,26 @@ static int on_post(sd_event_source *s, void *userdata) {
return 1;
}
static int listen_fds(int *rctrl, int *rnetlink) {
static int listen_fds(int *ret_ctrl, int *ret_netlink) {
int ctrl_fd = -1, netlink_fd = -1;
int fd, n, r;
int fd, n;
assert(rctrl);
assert(rnetlink);
assert(ret_ctrl);
assert(ret_netlink);
n = sd_listen_fds(true);
if (n < 0)
return n;
for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) {
if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) {
if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1) > 0) {
if (ctrl_fd >= 0)
return -EINVAL;
ctrl_fd = fd;
continue;
}
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) {
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
if (netlink_fd >= 0)
return -EINVAL;
netlink_fd = fd;
@ -1384,50 +1385,8 @@ static int listen_fds(int *rctrl, int *rnetlink) {
return -EINVAL;
}
if (ctrl_fd < 0) {
_cleanup_(udev_ctrl_unrefp) struct udev_ctrl *ctrl = NULL;
ctrl = udev_ctrl_new();
if (!ctrl)
return log_error_errno(EINVAL, "error initializing udev control socket");
r = udev_ctrl_enable_receiving(ctrl);
if (r < 0)
return log_error_errno(EINVAL, "error binding udev control socket");
fd = udev_ctrl_get_fd(ctrl);
if (fd < 0)
return log_error_errno(EIO, "could not get ctrl fd");
ctrl_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (ctrl_fd < 0)
return log_error_errno(errno, "could not dup ctrl fd: %m");
}
if (netlink_fd < 0) {
_cleanup_(udev_monitor_unrefp) struct udev_monitor *monitor = NULL;
monitor = udev_monitor_new_from_netlink(NULL, "kernel");
if (!monitor)
return log_error_errno(EINVAL, "error initializing netlink socket");
(void) udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
r = udev_monitor_enable_receiving(monitor);
if (r < 0)
return log_error_errno(EINVAL, "error binding netlink socket");
fd = udev_monitor_get_fd(monitor);
if (fd < 0)
return log_error_errno(netlink_fd, "could not get uevent fd: %m");
netlink_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (netlink_fd < 0)
return log_error_errno(errno, "could not dup netlink fd: %m");
}
*rctrl = ctrl_fd;
*rnetlink = netlink_fd;
*ret_ctrl = ctrl_fd;
*ret_netlink = netlink_fd;
return 0;
}
@ -1452,7 +1411,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (proc_cmdline_value_missing(key, value))
return 0;
r = util_log_priority(value);
r = log_level_from_string(value);
if (r >= 0)
log_set_max_level(r);
@ -1461,11 +1420,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (proc_cmdline_value_missing(key, value))
return 0;
r = safe_atou64(value, &arg_event_timeout_usec);
if (r >= 0) {
arg_event_timeout_usec *= USEC_PER_SEC;
arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
}
r = parse_sec(value, &arg_event_timeout_usec);
if (r >= 0)
arg_event_timeout_warn_usec = DIV_ROUND_UP(arg_event_timeout_usec, 3);
} else if (proc_cmdline_key_streq(key, "udev.children_max")) {
@ -1479,7 +1436,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (proc_cmdline_value_missing(key, value))
return 0;
r = safe_atoi(value, &arg_exec_delay);
r = parse_sec(value, &arg_exec_delay_usec);
} else if (startswith(key, "udev."))
log_warning("Unknown udev kernel command line option \"%s\"", key);
@ -1546,37 +1503,33 @@ static int parse_argv(int argc, char *argv[]) {
case 'c':
r = safe_atou(optarg, &arg_children_max);
if (r < 0)
log_warning("Invalid --children-max ignored: %s", optarg);
log_warning_errno(r, "Failed to parse --children-max= value '%s', ignoring: %m", optarg);
break;
case 'e':
r = safe_atoi(optarg, &arg_exec_delay);
r = parse_sec(optarg, &arg_exec_delay_usec);
if (r < 0)
log_warning("Invalid --exec-delay ignored: %s", optarg);
log_warning_errno(r, "Failed to parse --exec-delay= value '%s', ignoring: %m", optarg);
break;
case 't':
r = safe_atou64(optarg, &arg_event_timeout_usec);
r = parse_sec(optarg, &arg_event_timeout_usec);
if (r < 0)
log_warning("Invalid --event-timeout ignored: %s", optarg);
else {
arg_event_timeout_usec *= USEC_PER_SEC;
arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
}
log_warning_errno(r, "Failed to parse --event-timeout= value '%s', ignoring: %m", optarg);
arg_event_timeout_warn_usec = DIV_ROUND_UP(arg_event_timeout_usec, 3);
break;
case 'D':
arg_debug = true;
break;
case 'N':
if (streq(optarg, "early")) {
arg_resolve_names = 1;
} else if (streq(optarg, "late")) {
arg_resolve_names = 0;
} else if (streq(optarg, "never")) {
arg_resolve_names = -1;
} else {
log_error("resolve-names must be early, late or never");
return 0;
}
case 'N': {
ResolveNameTiming t;
t = resolve_name_timing_from_string(optarg);
if (t < 0)
log_warning("Invalid --resolve-names= value '%s', ignoring.", optarg);
else
arg_resolve_name_timing = t;
break;
}
case 'h':
return help();
case 'V':
@ -1598,35 +1551,49 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
int r, fd_worker;
assert(ret);
assert(fd_ctrl >= 0);
assert(fd_uevent >= 0);
manager = new0(Manager, 1);
manager = new(Manager, 1);
if (!manager)
return log_oom();
manager->fd_inotify = -1;
manager->worker_watch[WRITE_END] = -1;
manager->worker_watch[READ_END] = -1;
*manager = (Manager) {
.fd_inotify = -1,
.worker_watch = { -1, -1 },
.cgroup = cgroup,
};
udev_builtin_init();
manager->rules = udev_rules_new(arg_resolve_names);
manager->rules = udev_rules_new(arg_resolve_name_timing);
if (!manager->rules)
return log_error_errno(ENOMEM, "error reading rules");
LIST_HEAD_INIT(manager->events);
manager->cgroup = cgroup;
manager->ctrl = udev_ctrl_new_from_fd(fd_ctrl);
if (!manager->ctrl)
return log_error_errno(EINVAL, "error taking over udev control socket");
r = udev_ctrl_enable_receiving(manager->ctrl);
if (r < 0)
return log_error_errno(r, "Failed to bind udev control socket: %m");
fd_ctrl = udev_ctrl_get_fd(manager->ctrl);
if (fd_ctrl < 0)
return log_error_errno(fd_ctrl, "Failed to get udev control fd: %m");
manager->monitor = udev_monitor_new_from_netlink_fd(NULL, "kernel", fd_uevent);
if (!manager->monitor)
return log_error_errno(EINVAL, "error taking over netlink socket");
(void) udev_monitor_set_receive_buffer_size(manager->monitor, 128 * 1024 * 1024);
r = udev_monitor_enable_receiving(manager->monitor);
if (r < 0)
return log_error_errno(r, "Failed to bind netlink socket; %m");
fd_uevent = udev_monitor_get_fd(manager->monitor);
if (fd_uevent < 0)
return log_error_errno(fd_uevent, "Failed to get uevent fd: %m");
/* unnamed socket from workers to the main daemon */
r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
if (r < 0)