X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=udev%2Fudevd.c;h=c1a4fcfa7c7c0b7b505d3c18895961a44466cd85;hb=fe6784cfd49f864211bddd1ef161125122c1fb18;hp=2fa2a6a48add9ce28aa692bae2657ac4ca96d0f5;hpb=2dd7eed2eb4f0282c5afbddf777f6c313842890e;p=elogind.git diff --git a/udev/udevd.c b/udev/udevd.c index 2fa2a6a48..c1a4fcfa7 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; @@ -155,11 +155,7 @@ static void event_queue_delete(struct event *event, bool export) udev_list_node_remove(&event->node); if (export) { - /* mark as failed, if "add" event returns non-zero */ - if (event->exitcode != 0 && strcmp(udev_device_get_action(event->dev), "remove") != 0) - udev_queue_export_device_failed(udev_queue_export, event->dev); - else - udev_queue_export_device_finished(udev_queue_export, event->dev); + udev_queue_export_device_finished(udev_queue_export, event->dev); info(event->udev, "seq %llu done with %i\n", udev_device_get_seqnum(event->dev), event->exitcode); } udev_device_unref(event->dev); @@ -284,7 +280,6 @@ static void worker_new(struct event *event) for (;;) { struct udev_event *udev_event; struct worker_message msg; - int failed = 0; int err; info(udev, "seq %llu running\n", udev_device_get_seqnum(dev)); @@ -304,7 +299,7 @@ static void worker_new(struct event *event) err = udev_event_execute_rules(udev_event, rules, &sigmask_orig); if (err == 0) - failed = udev_event_execute_run(udev_event, &sigmask_orig); + udev_event_execute_run(udev_event, &sigmask_orig); /* apply/restore inotify watch */ if (err == 0 && udev_event->inotify_watch) { @@ -319,8 +314,6 @@ static void worker_new(struct event *event) memset(&msg, 0, sizeof(struct worker_message)); if (err != 0) msg.exitcode = err; - else if (failed != 0) - msg.exitcode = failed; msg.pid = getpid(); send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0); @@ -354,6 +347,7 @@ static void worker_new(struct event *event) for (i = 0; i < fdcount; i++) { if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) { dev = udev_monitor_receive_device(worker_monitor); + break; } else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) { struct signalfd_siginfo fdsi; ssize_t size; @@ -668,9 +662,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); @@ -742,19 +736,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)); @@ -837,7 +818,7 @@ static void handle_signal(struct udev *udev, int signo) } break; case SIGHUP: - reload_config = true; + reload = true; break; } } @@ -889,10 +870,11 @@ 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 = 0600 | S_IFCHR; + mode = 01600|S_IFCHR; else if (type == 'b') - mode = 0600 | S_IFBLK; + mode = 01600|S_IFBLK; else continue; @@ -1174,6 +1156,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; @@ -1196,6 +1208,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(); @@ -1203,35 +1216,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; @@ -1330,6 +1318,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); @@ -1354,7 +1345,7 @@ int main(int argc, char *argv[]) if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) { /* get control and netlink socket from from systemd */ - udev_ctrl = udev_ctrl_new_from_socket_fd(udev, UDEV_CTRL_SOCK_PATH, fd_ctrl); + udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl); if (udev_ctrl == NULL) { err(udev, "error taking over udev control socket"); rc = 1; @@ -1369,7 +1360,7 @@ int main(int argc, char *argv[]) } } else { /* open control and netlink socket */ - udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH); + udev_ctrl = udev_ctrl_new(udev); if (udev_ctrl == NULL) { fprintf(stderr, "error initializing udev control socket"); err(udev, "error initializing udev control socket"); @@ -1425,7 +1416,7 @@ int main(int argc, char *argv[]) goto exit; default: rc = EXIT_SUCCESS; - goto exit_keep_queue; + goto exit_daemonize; } setsid(); @@ -1474,28 +1465,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 */ @@ -1518,6 +1487,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"); @@ -1574,10 +1545,11 @@ int main(int argc, char *argv[]) udev_rules_apply_static_dev_perms(rules); - udev_list_init(&event_list); - udev_list_init(&worker_list); + udev_list_node_init(&event_list); + udev_list_node_init(&worker_list); for (;;) { + static unsigned long long last_usec; struct epoll_event ev[8]; int fdcount; int timeout; @@ -1606,12 +1578,12 @@ int main(int argc, char *argv[]) worker_kill(udev, 0); /* exit after all has cleaned up */ - if (udev_list_is_empty(&event_list) && udev_list_is_empty(&worker_list)) + if (udev_list_node_is_empty(&event_list) && udev_list_node_is_empty(&worker_list)) break; /* timeout at exit for workers to finish */ timeout = 60 * 1000; - } else if (udev_list_is_empty(&event_list) && children > 2) { + } else if (udev_list_node_is_empty(&event_list) && children > 2) { /* set timeout to kill idle workers */ timeout = 3 * 1000; } else { @@ -1645,6 +1617,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); @@ -1653,14 +1643,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_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; @@ -1675,7 +1671,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); @@ -1690,30 +1686,19 @@ 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; exit: udev_queue_export_cleanup(udev_queue_export); -exit_keep_queue: + udev_ctrl_cleanup(udev_ctrl); +exit_daemonize: if (fd_ep >= 0) close(fd_ep); 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)