X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=udev%2Fudevd.c;h=6b561977dc84a2f483e02c44e48fa107711a479f;hb=220893b3cbdbf8932f95c44811b169a8f0d33939;hp=60edea98e1144774ef5a5145d077aefc9d8c92b9;hpb=1f5a5100f3bdfdaf9ef71b29931574b678ff0d82;p=elogind.git diff --git a/udev/udevd.c b/udev/udevd.c index 60edea98e..6b561977d 100644 --- a/udev/udevd.c +++ b/udev/udevd.c @@ -49,7 +49,7 @@ static bool debug; -static void log_fn(struct udev *udev, int priority, +void udev_main_log(struct udev *udev, int priority, const char *file, int line, const char *fn, const char *format, va_list args) { @@ -76,7 +76,7 @@ static int fd_signal = -1; static int fd_ep = -1; static int fd_inotify = -1; static bool stop_exec_queue; -static bool reload_config; +static bool reload; static int children; static int children_max; static int exec_delay; @@ -398,7 +398,7 @@ out: } } -static void event_run(struct event *event, bool force) +static void event_run(struct event *event) { struct udev_list_node *loop; @@ -423,7 +423,7 @@ static void event_run(struct event *event, bool force) return; } - if (!force && children >= children_max) { + if (children >= children_max) { if (children_max > 1) info(event->udev, "maximum number (%i) of children reached\n", children); return; @@ -457,13 +457,6 @@ static int event_queue_insert(struct udev_device *dev) event->state = EVENT_QUEUED; udev_list_node_append(&event->node, &event_list); - - /* run all events with a timeout set immediately */ - if (udev_device_get_timeout(dev) > 0) { - event_run(event, true); - return 0; - } - return 0; } @@ -580,7 +573,7 @@ static void event_queue_start(struct udev *udev) continue; } - event_run(event, false); + event_run(event); } } @@ -662,9 +655,9 @@ static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) stop_exec_queue = false; } - if (udev_ctrl_get_reload_rules(ctrl_msg) > 0) { - info(udev, "udevd message (RELOAD_RULES) received\n"); - reload_config = true; + if (udev_ctrl_get_reload(ctrl_msg) > 0) { + info(udev, "udevd message (RELOAD) received\n"); + reload = true; } str = udev_ctrl_get_set_env(ctrl_msg); @@ -736,19 +729,6 @@ static int handle_inotify(struct udev *udev) struct udev_device *dev; ev = (struct inotify_event *)(buf + pos); - if (ev->len) { - const char *s; - - info(udev, "inotify event: %x for %s\n", ev->mask, ev->name); - s = strstr(ev->name, ".rules"); - if (s == NULL) - continue; - if (strlen(s) != strlen(".rules")) - continue; - reload_config = true; - continue; - } - dev = udev_watch_lookup(udev, ev->wd); if (dev != NULL) { info(udev, "inotify event: %x for %s\n", ev->mask, udev_device_get_devnode(dev)); @@ -831,7 +811,7 @@ static void handle_signal(struct udev *udev, int signo) } break; case SIGHUP: - reload_config = true; + reload = true; break; } } @@ -883,11 +863,10 @@ static void static_dev_create_from_modules(struct udev *udev) if (sscanf(devno, "%c%u:%u", &type, &maj, &min) != 3) continue; - /* set sticky bit, so we do not remove the node on module unload */ if (type == 'c') - mode = 01600|S_IFCHR; + mode = S_IFCHR; else if (type == 'b') - mode = 01600|S_IFBLK; + mode = S_IFBLK; else continue; @@ -1169,6 +1148,36 @@ static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) return 0; } +static bool check_rules_timestamp(struct udev *udev) +{ + char **p; + unsigned long long *stamp_usec; + int i, n; + bool changed = false; + + n = udev_get_rules_path(udev, &p, &stamp_usec); + for (i = 0; i < n; i++) { + struct stat stats; + + if (stat(p[i], &stats) < 0) + continue; + + if (stamp_usec[i] == ts_usec(&stats.st_mtim)) + continue; + + /* first check */ + if (stamp_usec[i] != 0) { + info(udev, "reload - timestamp of '%s' changed\n", p[i]); + changed = true; + } + + /* update timestamp */ + stamp_usec[i] = ts_usec(&stats.st_mtim); + } + + return changed; +} + int main(int argc, char *argv[]) { struct udev *udev; @@ -1191,6 +1200,7 @@ int main(int argc, char *argv[]) int fd_worker = -1; struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_worker; struct udev_ctrl_connection *ctrl_conn = NULL; + char **s; int rc = 1; udev = udev_new(); @@ -1198,35 +1208,10 @@ int main(int argc, char *argv[]) goto exit; udev_log_init("udevd"); - udev_set_log_fn(udev, log_fn); + udev_set_log_fn(udev, udev_main_log); info(udev, "version %s\n", VERSION); udev_selinux_init(udev); - /* make sure, that our runtime dir exists and is writable */ - if (utimensat(AT_FDCWD, udev_get_run_config_path(udev), NULL, 0) < 0) { - /* try to create our own subdirectory, do not create parent directories */ - mkdir(udev_get_run_config_path(udev), 0755); - - if (utimensat(AT_FDCWD, udev_get_run_config_path(udev), NULL, 0) >= 0) { - /* directory seems writable now */ - udev_set_run_path(udev, udev_get_run_config_path(udev)); - } else { - /* fall back to /dev/.udev */ - char filename[UTIL_PATH_SIZE]; - - util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev", NULL); - if (udev_set_run_path(udev, filename) == NULL) - goto exit; - mkdir(udev_get_run_path(udev), 0755); - err(udev, "error: runtime directory '%s' not writable, for now falling back to '%s'", - udev_get_run_config_path(udev), udev_get_run_path(udev)); - } - } - /* relabel runtime dir only if it resides below /dev */ - if (strncmp(udev_get_run_path(udev), udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0) - udev_selinux_lsetfilecon(udev, udev_get_run_path(udev), 0755); - info(udev, "runtime dir '%s'\n", udev_get_run_path(udev)); - for (;;) { int option; @@ -1325,6 +1310,9 @@ int main(int argc, char *argv[]) chdir("/"); umask(022); + /* /run/udev */ + mkdir(udev_get_run_path(udev), 0755); + /* create standard links, copy static nodes, create nodes from modules */ static_dev_create(udev); static_dev_create_from_modules(udev); @@ -1469,28 +1457,6 @@ int main(int argc, char *argv[]) rc = 4; goto exit; } - - if (udev_get_rules_path(udev) != NULL) { - inotify_add_watch(fd_inotify, udev_get_rules_path(udev), - IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); - } else { - char filename[UTIL_PATH_SIZE]; - struct stat statbuf; - - inotify_add_watch(fd_inotify, LIBEXECDIR "/rules.d", - IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); - inotify_add_watch(fd_inotify, SYSCONFDIR "/udev/rules.d", - IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); - - /* watch dynamic rules directory */ - util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/rules.d", NULL); - if (stat(filename, &statbuf) != 0) { - util_create_path(udev, filename); - mkdir(filename, 0755); - } - inotify_add_watch(fd_inotify, filename, - IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); - } udev_watch_restore(udev); /* block and listen to all signals on signalfd */ @@ -1513,6 +1479,8 @@ int main(int argc, char *argv[]) } fd_worker = worker_watch[READ_END]; + udev_builtin_init(udev); + rules = udev_rules_new(udev, resolve_names); if (rules == NULL) { err(udev, "error reading rules\n"); @@ -1573,6 +1541,7 @@ int main(int argc, char *argv[]) udev_list_node_init(&worker_list); for (;;) { + static unsigned long long last_usec; struct epoll_event ev[8]; int fdcount; int timeout; @@ -1640,6 +1609,24 @@ int main(int argc, char *argv[]) is_ctrl = true; } + /* check for changed config, every 3 seconds at most */ + if ((now_usec() - last_usec) > 3 * 1000 * 1000) { + if (check_rules_timestamp(udev)) + reload = true; + if (udev_builtin_validate(udev)) + reload = true; + + last_usec = now_usec(); + } + + /* reload requested, HUP signal received, rules changed, builtin changed */ + if (reload) { + worker_kill(udev, 0); + rules = udev_rules_unref(rules); + udev_builtin_exit(udev); + reload = 0; + } + /* event has finished */ if (is_worker) worker_returned(fd_worker); @@ -1648,15 +1635,20 @@ int main(int argc, char *argv[]) struct udev_device *dev; dev = udev_monitor_receive_device(monitor); - if (dev != NULL) + if (dev != NULL) { udev_device_set_usec_initialized(dev, now_usec()); if (event_queue_insert(dev) < 0) udev_device_unref(dev); + } } /* start new events */ - if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) - event_queue_start(udev); + if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) { + if (rules == NULL) + rules = udev_rules_new(udev, resolve_names); + if (rules != NULL) + event_queue_start(udev); + } if (is_signal) { struct signalfd_siginfo fdsi; @@ -1671,7 +1663,7 @@ int main(int argc, char *argv[]) if (udev_exit) continue; - /* device node and rules directory inotify watch */ + /* device node watch */ if (is_inotify) handle_inotify(udev); @@ -1686,19 +1678,6 @@ int main(int argc, char *argv[]) */ if (is_ctrl) ctrl_conn = handle_ctrl_msg(udev_ctrl); - - /* rules changed, set by inotify or a HUP signal */ - if (reload_config) { - struct udev_rules *rules_new; - - worker_kill(udev, 0); - rules_new = udev_rules_new(udev, resolve_names); - if (rules_new != NULL) { - udev_rules_unref(rules); - rules = rules_new; - } - reload_config = 0; - } } rc = EXIT_SUCCESS; @@ -1711,6 +1690,7 @@ exit_daemonize: worker_list_cleanup(udev); event_queue_cleanup(udev, EVENT_UNDEF); udev_rules_unref(rules); + udev_builtin_exit(udev); if (fd_signal >= 0) close(fd_signal); if (worker_watch[READ_END] >= 0)