X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Fudevd.c;h=0bacb3994b00a716fa2af15aaaa64af7391fa4c5;hp=1583e22ac9806ed0e06772c376b5ced571d7f9f3;hb=be7de4097af70515783cd0030f5e7a7a89bbadc8;hpb=8460299b572eb13e7b97a0956b59c053f9009afa diff --git a/udev/udevd.c b/udev/udevd.c index 1583e22ac..0bacb3994 100644 --- a/udev/udevd.c +++ b/udev/udevd.c @@ -24,15 +24,11 @@ #include #include #include -#include #include -#include #include #include #include #include -#include -#include #include #include #ifdef HAVE_INOTIFY @@ -40,7 +36,6 @@ #endif #include "udev.h" -#include "udev-rules.h" #define UDEVD_PRIORITY -4 #define UDEV_PRIORITY -2 @@ -63,7 +58,7 @@ static void log_fn(struct udev *udev, int priority, } static int debug_trace; -static struct udev_rules rules; +static struct udev_rules *rules; static struct udev_ctrl *udev_ctrl; static struct udev_monitor *kernel_monitor; static int inotify_fd = -1; @@ -76,8 +71,8 @@ static int run_exec_q; static int stop_exec_q; static int max_childs; -static LIST_HEAD(exec_list); -static LIST_HEAD(running_list); +static struct udev_list_node exec_list; +static struct udev_list_node running_list; enum event_state { EVENT_QUEUED, @@ -85,6 +80,15 @@ enum event_state { EVENT_FAILED, }; +static struct udev_event *node_to_event(struct udev_list_node *node) +{ + char *event; + + event = (char *)node; + event -= offsetof(struct udev_event, node); + return (struct udev_event *)event; +} + static void export_event_state(struct udev_event *event, enum event_state state) { char filename[UTIL_PATH_SIZE]; @@ -104,9 +108,9 @@ static void export_event_state(struct udev_event *event, enum event_state state) switch (state) { case EVENT_QUEUED: - unlink(filename_failed); - delete_path(event->udev, filename_failed); - create_path(event->udev, filename); + if(unlink(filename_failed) == 0) + util_delete_path(event->udev, filename_failed); + util_create_path(event->udev, filename); udev_selinux_setfscreatecon(event->udev, filename, S_IFLNK); symlink(udev_device_get_devpath(event->dev), filename); udev_selinux_resetfscreatecon(event->udev); @@ -126,20 +130,24 @@ static void export_event_state(struct udev_event *event, enum event_state state) info(event->udev, "renamed devpath, moved failed state of '%s' to %s'\n", udev_device_get_devpath_old(event->dev), udev_device_get_devpath(event->dev)); } else { - unlink(filename_failed); - delete_path(event->udev, filename_failed); + if (unlink(filename_failed) == 0) + util_delete_path(event->udev, filename_failed); } unlink(filename); - delete_path(event->udev, filename); + + /* clean up possibly empty queue directory */ + if (udev_list_is_empty(&exec_list) && udev_list_is_empty(&running_list)) + util_delete_path(event->udev, filename); break; case EVENT_FAILED: /* move failed event to the failed directory */ - create_path(event->udev, filename_failed); + util_create_path(event->udev, filename_failed); rename(filename, filename_failed); /* clean up possibly empty queue directory */ - delete_path(event->udev, filename); + if (udev_list_is_empty(&exec_list) && udev_list_is_empty(&running_list)) + util_delete_path(event->udev, filename); break; } @@ -148,7 +156,7 @@ static void export_event_state(struct udev_event *event, enum event_state state) static void event_queue_delete(struct udev_event *event) { - list_del(&event->node); + udev_list_node_remove(&event->node); /* mark as failed, if "add" event returns non-zero */ if (event->exitstatus && strcmp(udev_device_get_action(event->dev), "add") == 0) @@ -204,7 +212,7 @@ static void event_fork(struct udev_event *event) alarm(UDEV_EVENT_TIMEOUT); /* apply rules, create node, symlinks */ - err = udev_event_run(event, &rules); + err = udev_event_execute_rules(event, rules); /* rules may change/disable the timeout */ if (udev_device_get_event_timeout(event->dev) >= 0) @@ -212,8 +220,8 @@ static void event_fork(struct udev_event *event) /* execute RUN= */ if (err == 0 && !event->ignore_device && udev_get_run(event->udev)) - udev_rules_run(event); - info(event->udev, "seq %llu finished with %i\n", udev_device_get_seqnum(event->dev), err); + udev_event_execute_run(event); + info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err); logging_close(); if (err != 0) exit(1); @@ -242,7 +250,8 @@ static void event_queue_insert(struct udev_event *event) event->queue_time = time(NULL); export_event_state(event, EVENT_QUEUED); - info(event->udev, "seq %llu queued, '%s' '%s'\n", udev_device_get_seqnum(event->dev), udev_device_get_action(event->dev), udev_device_get_subsystem(event->dev)); + info(event->udev, "seq %llu queued, '%s' '%s'\n", udev_device_get_seqnum(event->dev), + udev_device_get_action(event->dev), udev_device_get_subsystem(event->dev)); util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename)); util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename)); @@ -258,7 +267,7 @@ static void event_queue_insert(struct udev_event *event) /* run one event after the other in debug mode */ if (debug_trace) { - list_add_tail(&event->node, &running_list); + udev_list_node_append(&event->node, &running_list); event_fork(event); waitpid(event->pid, NULL, 0); event_queue_delete(event); @@ -267,12 +276,12 @@ static void event_queue_insert(struct udev_event *event) /* run all events with a timeout set immediately */ if (udev_device_get_timeout(event->dev) > 0) { - list_add_tail(&event->node, &running_list); + udev_list_node_append(&event->node, &running_list); event_fork(event); return; } - list_add_tail(&event->node, &exec_list); + udev_list_node_append(&event->node, &exec_list); run_exec_q = 1; } @@ -301,37 +310,37 @@ static int mem_size_mb(void) static int compare_devpath(const char *running, const char *waiting) { - int i; + int i = 0; - for (i = 0; i < UTIL_PATH_SIZE; i++) { - /* identical device event found */ - if (running[i] == '\0' && waiting[i] == '\0') - return 1; + while (running[i] == waiting[i] && running[i] != '\0') + i++; - /* parent device event found */ - if (running[i] == '\0' && waiting[i] == '/') - return 2; + /* identical device event found */ + if (running[i] == '\0' && waiting[i] == '\0') + return 1; - /* child device event found */ - if (running[i] == '/' && waiting[i] == '\0') - return 3; + /* parent device event found */ + if (running[i] == '\0' && waiting[i] == '/') + return 2; - /* no matching event */ - if (running[i] != waiting[i]) - break; - } + /* child device event found */ + if (running[i] == '/' && waiting[i] == '\0') + return 3; + /* no matching event */ return 0; } /* lookup event for identical, parent, child, or physical device */ static int devpath_busy(struct udev_event *event, int limit) { - struct udev_event *loop_event; + struct udev_list_node *loop; int childs_count = 0; /* check exec-queue which may still contain delayed events we depend on */ - list_for_each_entry(loop_event, &exec_list, node) { + udev_list_node_foreach(loop, &exec_list) { + struct udev_event *loop_event = node_to_event(loop); + /* skip ourself and all later events */ if (udev_device_get_seqnum(loop_event->dev) >= udev_device_get_seqnum(event->dev)) break; @@ -375,8 +384,8 @@ static int devpath_busy(struct udev_event *event, int limit) } /* check run queue for still running events */ - list_for_each_entry(loop_event, &running_list, node) { - childs_count++; + udev_list_node_foreach(loop, &running_list) { + struct udev_event *loop_event = node_to_event(loop); if (childs_count++ >= limit) { info(event->udev, "%llu, maximum number (%i) of childs reached\n", @@ -427,13 +436,15 @@ static int devpath_busy(struct udev_event *event, int limit) /* serializes events for the identical and parent and child devices */ static void event_queue_manager(struct udev *udev) { - struct udev_event *loop_event; - struct udev_event *tmp_event; + struct udev_list_node *loop; + struct udev_list_node *tmp; - if (list_empty(&exec_list)) + if (udev_list_is_empty(&exec_list)) return; - list_for_each_entry_safe(loop_event, tmp_event, &exec_list, node) { + udev_list_node_foreach_safe(loop, tmp, &exec_list) { + struct udev_event *loop_event = node_to_event(loop); + /* serialize and wait for parent or child events */ if (devpath_busy(loop_event, max_childs) != 0) { dbg(udev, "delay seq %llu (%s)\n", @@ -443,7 +454,8 @@ static void event_queue_manager(struct udev *udev) } /* move event to run list */ - list_move_tail(&loop_event->node, &running_list); + udev_list_node_remove(&loop_event->node); + udev_list_node_append(&loop_event->node, &running_list); event_fork(loop_event); dbg(udev, "moved seq %llu to running list\n", udev_device_get_seqnum(loop_event->dev)); } @@ -540,16 +552,18 @@ static void asmlinkage sig_handler(int signum) static void udev_done(int pid, int exitstatus) { + struct udev_list_node *loop; + /* find event associated with pid and delete it */ - struct udev_event *event; + udev_list_node_foreach(loop, &running_list) { + struct udev_event *loop_event = node_to_event(loop); - list_for_each_entry(event, &running_list, node) { - if (event->pid == pid) { - info(event->udev, "seq %llu, pid [%d] exit with %i, %ld seconds old\n", - udev_device_get_seqnum(event->dev), event->pid, - exitstatus, time(NULL) - event->queue_time); - event->exitstatus = exitstatus; - event_queue_delete(event); + if (loop_event->pid == pid) { + info(loop_event->udev, "seq %llu cleanup, pid [%d], status %i, %ld seconds old\n", + udev_device_get_seqnum(loop_event->dev), loop_event->pid, + exitstatus, time(NULL) - loop_event->queue_time); + loop_event->exitstatus = exitstatus; + event_queue_delete(loop_event); /* there may be events waiting with the same devpath */ run_exec_q = 1; @@ -597,7 +611,7 @@ static void export_initial_seqnum(struct udev *udev) } util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename)); util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename)); - create_path(udev, filename); + util_create_path(udev, filename); fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644); if (fd >= 0) { write(fd, seqnum, len); @@ -632,7 +646,7 @@ int main(int argc, char *argv[]) logging_init("udevd"); udev_set_log_fn(udev, log_fn); info(udev, "version %s\n", VERSION); - selinux_init(udev); + udev_selinux_init(udev); while (1) { int option; @@ -705,13 +719,8 @@ int main(int argc, char *argv[]) err(udev, "error initializing netlink socket\n"); rc = 3; goto exit; - } else { - /* set receive buffersize */ - const int buffersize = 32 * 1024 * 1024; - - setsockopt(udev_monitor_get_fd(kernel_monitor), - SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize)); } + udev_monitor_set_receive_buffer_size(kernel_monitor, 128*1024*1024); err = pipe(signal_pipe); if (err < 0) { @@ -741,7 +750,13 @@ int main(int argc, char *argv[]) goto exit; } - udev_rules_init(udev, &rules, 1); + rules = udev_rules_new(udev, 1); + if (rules == NULL) { + err(udev, "error reading rules\n"); + goto exit; + } + udev_list_init(&running_list); + udev_list_init(&exec_list); export_initial_seqnum(udev); if (daemonize) { @@ -860,7 +875,6 @@ int main(int argc, char *argv[]) maxfd = UDEV_MAX(maxfd, udev_monitor_get_fd(kernel_monitor)); maxfd = UDEV_MAX(maxfd, signal_pipe[READ_END]); maxfd = UDEV_MAX(maxfd, inotify_fd); - while (!udev_exit) { int fdcount; @@ -870,7 +884,6 @@ int main(int argc, char *argv[]) FD_SET(udev_monitor_get_fd(kernel_monitor), &readfds); if (inotify_fd >= 0) FD_SET(inotify_fd, &readfds); - fdcount = select(maxfd+1, &readfds, NULL, NULL, NULL); if (fdcount < 0) { if (errno != EINTR) @@ -927,9 +940,14 @@ int main(int argc, char *argv[]) /* rules changed, set by inotify or a HUP signal */ if (reload_config) { + struct udev_rules *rules_new; + reload_config = 0; - udev_rules_cleanup(&rules); - udev_rules_init(udev, &rules, 1); + rules_new = udev_rules_new(udev, 1); + if (rules_new != NULL) { + udev_rules_unref(rules); + rules = rules_new; + } } if (sigchilds_waiting) { @@ -946,7 +964,7 @@ int main(int argc, char *argv[]) rc = 0; exit: - udev_rules_cleanup(&rules); + udev_rules_unref(rules); if (signal_pipe[READ_END] >= 0) close(signal_pipe[READ_END]); @@ -958,7 +976,7 @@ exit: close(inotify_fd); udev_monitor_unref(kernel_monitor); - selinux_exit(udev); + udev_selinux_exit(udev); udev_unref(udev); logging_close(); return rc;