X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udevd.c;h=dccc745eff54eb4169c6381e9c2cb519d3804746;hp=8c550d38aa3b8f2154c2fc0a073ac75811d6476d;hb=285e2f52186c9462a0d3ae1aca94077ea3ddfc63;hpb=ff2eecef88733e669ff5a43083534b32b435e2b0 diff --git a/udevd.c b/udevd.c index 8c550d38a..dccc745ef 100644 --- a/udevd.c +++ b/udevd.c @@ -124,7 +124,7 @@ static int udev_event_process(struct udevd_uevent_msg *msg) for (i = 0; msg->envp[i]; i++) putenv(msg->envp[i]); - udev = udev_device_init(); + udev = udev_device_init(NULL); if (udev == NULL) return -1; strlcpy(udev->action, msg->action, sizeof(udev->action)); @@ -167,35 +167,23 @@ static void export_event_state(struct udevd_uevent_msg *msg, enum event_state st { char filename[PATH_SIZE]; char filename_failed[PATH_SIZE]; - size_t start, end, i; + size_t start; struct udevd_uevent_msg *loop_msg; int fd; /* add location of queue files */ strlcpy(filename, udev_root, sizeof(filename)); strlcat(filename, "/", sizeof(filename)); - start = strlcat(filename, EVENT_QUEUE_DIR, sizeof(filename)); - end = strlcat(filename, msg->devpath, sizeof(filename)); - if (end > sizeof(filename)) - end = sizeof(filename); - - /* replace '/' to transform path into a filename */ - for (i = start+1; i < end; i++) - if (filename[i] == '/') - filename[i] = PATH_TO_NAME_CHAR; + start = strlcat(filename, EVENT_QUEUE_DIR"/", sizeof(filename)); + strlcat(filename, msg->devpath, sizeof(filename)); + path_encode(&filename[start], sizeof(filename) - start); /* add location of failed files */ strlcpy(filename_failed, udev_root, sizeof(filename_failed)); strlcat(filename_failed, "/", sizeof(filename_failed)); - start = strlcat(filename_failed, EVENT_FAILED_DIR, sizeof(filename_failed)); - end = strlcat(filename_failed, msg->devpath, sizeof(filename_failed)); - if (end > sizeof(filename_failed)) - end = sizeof(filename_failed); - - /* replace '/' to transform path into a filename */ - for (i = start+1; i < end; i++) - if (filename_failed[i] == '/') - filename_failed[i] = PATH_TO_NAME_CHAR; + start = strlcat(filename_failed, EVENT_FAILED_DIR"/", sizeof(filename_failed)); + strlcat(filename_failed, msg->devpath, sizeof(filename_failed)); + path_encode(&filename_failed[start], sizeof(filename) - start); switch (state) { case EVENT_QUEUED: @@ -360,7 +348,7 @@ static int mem_size_mb(void) static int cpu_count(void) { int f; - char buf[32768]; + char buf[65536]; int len; const char *pos; int count = 0; @@ -507,26 +495,49 @@ static int compare_devpath(const char *running, const char *waiting) return 0; } -/* returns still running task for the same device, its parent or its physical device */ -static int running_with_devpath(struct udevd_uevent_msg *msg, int limit) +/* lookup event for identical, parent, child, or physical device */ +static int devpath_busy(struct udevd_uevent_msg *msg, int limit) { struct udevd_uevent_msg *loop_msg; int childs_count = 0; + /* check exec-queue which may still contain delayed events we depend on */ + list_for_each_entry(loop_msg, &exec_list, node) { + /* skip ourself and all later events */ + if (loop_msg->seqnum >= msg->seqnum) + break; + + /* check identical, parent, or child device event */ + if (compare_devpath(loop_msg->devpath, msg->devpath) != 0) { + dbg("%llu, device event still pending %llu (%s)", + msg->seqnum, loop_msg->seqnum, loop_msg->devpath); + return 2; + } + + /* check physical device event (special case of parent) */ + if (msg->physdevpath && msg->action && strcmp(msg->action, "add") == 0) + if (compare_devpath(loop_msg->devpath, msg->physdevpath) != 0) { + dbg("%llu, physical device event still pending %llu (%s)", + msg->seqnum, loop_msg->seqnum, loop_msg->devpath); + return 3; + } + } + + /* check runing-queue for still running events */ list_for_each_entry(loop_msg, &running_list, node) { if (limit && childs_count++ > limit) { - dbg("%llu, maximum number (%i) of child reached", msg->seqnum, childs_count); + dbg("%llu, maximum number (%i) of childs reached", msg->seqnum, childs_count); return 1; } - /* return running parent/child device event */ + /* check identical, parent, or child device event */ if (compare_devpath(loop_msg->devpath, msg->devpath) != 0) { - dbg("%llu, child device event still running %llu (%s)", + dbg("%llu, device event still running %llu (%s)", msg->seqnum, loop_msg->seqnum, loop_msg->devpath); return 2; } - /* return running physical device event */ + /* check physical device event (special case of parent) */ if (msg->physdevpath && msg->action && strcmp(msg->action, "add") == 0) if (compare_devpath(loop_msg->devpath, msg->physdevpath) != 0) { dbg("%llu, physical device event still running %llu (%s)", @@ -534,11 +545,10 @@ static int running_with_devpath(struct udevd_uevent_msg *msg, int limit) return 3; } } - return 0; } -/* exec queue management routine executes the events and serializes events in the same sequence */ +/* serializes events for the identical and parent and child devices */ static void msg_queue_manager(void) { struct udevd_uevent_msg *loop_msg; @@ -564,8 +574,8 @@ static void msg_queue_manager(void) } } - /* don't run two processes for the same devpath and wait for the parent*/ - if (running_with_devpath(loop_msg, max_childs)) { + /* serialize and wait for parent or child events */ + if (devpath_busy(loop_msg, max_childs) != 0) { dbg("delay seq %llu (%s)", loop_msg->seqnum, loop_msg->devpath); continue; } @@ -943,6 +953,7 @@ int main(int argc, char *argv[], char *envp[]) { "debug-trace", 0, NULL, 't' }, { "verbose", 0, NULL, 'v' }, { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, {} }; int rc = 1; @@ -955,7 +966,7 @@ int main(int argc, char *argv[], char *envp[]) /* parse commandline options */ while (1) { - option = getopt_long(argc, argv, "dtvh", options, NULL); + option = getopt_long(argc, argv, "dtvhV", options, NULL); if (option == -1) break; @@ -972,7 +983,10 @@ int main(int argc, char *argv[], char *envp[]) udev_log_priority = LOG_INFO; break; case 'h': - printf("Usage: udevd [--help] [--daemon] [--debug-trace] [--verbose]\n"); + printf("Usage: udevd [--help] [--daemon] [--debug-trace] [--verbose] [--version]\n"); + goto exit; + case 'V': + printf("%s\n", UDEV_VERSION); goto exit; default: goto exit; @@ -985,6 +999,19 @@ int main(int argc, char *argv[], char *envp[]) goto exit; } + /* make sure std{in,out,err} fd's are in a sane state */ + fd = open("/dev/null", O_RDWR); + if (fd < 0) { + fprintf(stderr, "cannot open /dev/null\n"); + err("cannot open /dev/null"); + } + if (fd > STDIN_FILENO) + dup2(fd, STDIN_FILENO); + if (write(STDOUT_FILENO, 0, 0) < 0) + dup2(fd, STDOUT_FILENO); + if (write(STDERR_FILENO, 0, 0) < 0) + dup2(fd, STDERR_FILENO); + /* init sockets to receive events */ if (init_udevd_socket() < 0) { if (errno == EADDRINUSE) { @@ -1060,17 +1087,12 @@ int main(int argc, char *argv[], char *envp[]) } } - /* redirect std fd's */ - fd = open("/dev/null", O_RDWR); - if (fd >= 0) { - dup2(fd, STDIN_FILENO); - if (!verbose) - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - if (fd > STDERR_FILENO) - close(fd); - } else - err("error opening /dev/null: %s", strerror(errno)); + /* redirect std{out,err} fd's */ + if (!verbose) + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) + close(fd); /* set scheduling priority for the daemon */ setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY); @@ -1230,6 +1252,7 @@ int main(int argc, char *argv[], char *envp[]) exit: udev_rules_cleanup(&rules); sysfs_cleanup(); + selinux_exit(); if (signal_pipe[READ_END] >= 0) close(signal_pipe[READ_END]);