From 1a0bd01529d42bc4fed71d94c914b590b8c6ff7e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 8 Dec 2020 22:37:12 +0900 Subject: [PATCH] udev: introduce new OPTIONS="log_level=" udev rule --- src/test/test-udev.c | 2 +- src/udev/udev-event.c | 4 +++- src/udev/udev-event.h | 4 +++- src/udev/udev-rules.c | 29 +++++++++++++++++++++++++++++ src/udev/udevadm-test.c | 2 +- src/udev/udevd.c | 9 ++++++++- 6 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 8acf86da37..488b965c82 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -102,7 +102,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_debug_errno(r, "Failed to open device '%s'", devpath); - assert_se(event = udev_event_new(dev, 0, NULL)); + assert_se(event = udev_event_new(dev, 0, NULL, log_get_max_level())); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0); diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 5159d19a38..307f949fde 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -51,7 +51,7 @@ typedef struct Spawn { size_t result_len; } Spawn; -UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl) { +UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl, int log_level) { UdevEvent *event; assert(dev); @@ -68,6 +68,8 @@ UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rt .uid = UID_INVALID, .gid = GID_INVALID, .mode = MODE_INVALID, + .log_level_was_debug = log_level == LOG_DEBUG, + .default_log_level = log_level, }; return event; diff --git a/src/udev/udev-event.h b/src/udev/udev-event.h index a34b85176d..27bf8f9372 100644 --- a/src/udev/udev-event.h +++ b/src/udev/udev-event.h @@ -42,9 +42,11 @@ typedef struct UdevEvent { bool name_final; bool devlink_final; bool run_final; + bool log_level_was_debug; + int default_log_level; } UdevEvent; -UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl); +UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl, int log_level); UdevEvent *udev_event_free(UdevEvent *event); DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free); diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index ef6a0c112c..48fd33fded 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -25,6 +25,7 @@ #include "strv.h" #include "strxcpyx.h" #include "sysctl-util.h" +#include "syslog-util.h" #include "udev-builtin.h" #include "udev-event.h" #include "udev-rules.h" @@ -104,6 +105,7 @@ typedef enum { TK_A_OPTIONS_DB_PERSIST, /* no argument */ TK_A_OPTIONS_INOTIFY_WATCH, /* boolean */ TK_A_OPTIONS_DEVLINK_PRIORITY, /* int */ + TK_A_OPTIONS_LOG_LEVEL, /* string of log level or "reset" */ TK_A_OWNER, /* user name */ TK_A_GROUP, /* group name */ TK_A_MODE, /* mode string */ @@ -834,6 +836,17 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp if (r < 0) return log_token_error_errno(rules, r, "Failed to parse link priority '%s': %m", tmp); r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio)); + } else if ((tmp = startswith(value, "log_level="))) { + int level; + + if (streq(tmp, "reset")) + level = -1; + else { + level = log_level_from_string(tmp); + if (level < 0) + return log_token_error_errno(rules, level, "Failed to parse log level '%s': %m", tmp); + } + r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level)); } else { log_token_warning(rules, "Invalid value for OPTIONS key, ignoring: '%s'", value); return 0; @@ -1858,6 +1871,22 @@ static int udev_rule_apply_token_to_event( case TK_A_OPTIONS_DEVLINK_PRIORITY: device_set_devlink_priority(dev, PTR_TO_INT(token->data)); break; + case TK_A_OPTIONS_LOG_LEVEL: { + int level = PTR_TO_INT(token->data); + + if (level < 0) + level = event->default_log_level; + + log_set_max_level_all_realms(level); + + if (level == LOG_DEBUG && !event->log_level_was_debug) { + /* The log level becomes LOG_DEBUG at first time. Let's log basic information. */ + log_device_uevent(dev, "The log level is changed to 'debug' while processing device"); + event->log_level_was_debug = true; + } + + break; + } case TK_A_OWNER: { char owner[UTIL_NAME_SIZE]; const char *ow = owner; diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index a029622af9..747047dac8 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -138,7 +138,7 @@ int test_main(int argc, char *argv[], void *userdata) { /* don't read info from the db */ device_seal(dev); - event = udev_event_new(dev, 0, NULL); + event = udev_event_new(dev, 0, NULL, LOG_DEBUG); assert_se(sigfillset(&mask) >= 0); assert_se(sigprocmask(SIG_SETMASK, &mask, &sigmask_orig) >= 0); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 3961e76305..5d02a9d27c 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -84,6 +84,7 @@ typedef struct Manager { LIST_HEAD(struct event, events); const char *cgroup; pid_t pid; /* the process that originally allocated the manager object */ + int log_level; UdevRules *rules; Hashmap *properties; @@ -443,7 +444,7 @@ static int worker_process_device(Manager *manager, sd_device *dev) { log_device_uevent(dev, "Processing device"); - udev_event = udev_event_new(dev, arg_exec_delay_usec, manager->rtnl); + udev_event = udev_event_new(dev, arg_exec_delay_usec, manager->rtnl, manager->log_level); if (!udev_event) return -ENOMEM; @@ -540,6 +541,9 @@ static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device * if (r < 0) log_device_warning_errno(dev, r, "Failed to send signal to main daemon, ignoring: %m"); + /* Reset the log level, as it might be changed by "OPTIONS=log_level=". */ + log_set_max_level_all_realms(manager->log_level); + return 1; } @@ -1064,6 +1068,7 @@ static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, co case UDEV_CTRL_SET_LOG_LEVEL: log_debug("Received udev control message (SET_LOG_LEVEL), setting log_level=%i", value->intval); log_set_max_level_all_realms(value->intval); + manager->log_level = value->intval; manager_kill_workers(manager); break; case UDEV_CTRL_STOP_EXEC_QUEUE: @@ -1708,6 +1713,8 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg if (r < 0) return log_error_errno(r, "Failed to bind netlink socket: %m"); + manager->log_level = log_get_max_level(); + *ret = TAKE_PTR(manager); return 0;