X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=udev%2Fudevd.c;h=cfc091b699067e7d2e47214880b85ef9feb99d2f;hb=80be8c48c59708c52993ceddeedef8c2ed417016;hp=7d82d2132e3921505e49c1a92ec894689c73df45;hpb=4b0faa2aa0e7ca87fc0fdb637c69e978a7241e1c;p=elogind.git diff --git a/udev/udevd.c b/udev/udevd.c index 7d82d2132..cfc091b69 100644 --- a/udev/udevd.c +++ b/udev/udevd.c @@ -65,7 +65,6 @@ static int debug_trace; static struct udev_rules *rules; static struct udev_ctrl *udev_ctrl; static struct udev_monitor *kernel_monitor; -static int inotify_fd = -1; static volatile int sigchilds_waiting; static volatile int udev_exit; static volatile int reload_config; @@ -195,8 +194,6 @@ static void event_fork(struct udev_event *event) /* child */ udev_monitor_unref(kernel_monitor); udev_ctrl_unref(udev_ctrl); - if (inotify_fd >= 0) - close(inotify_fd); logging_close(); logging_init("udevd-event"); setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY); @@ -218,6 +215,17 @@ static void event_fork(struct udev_event *event) /* set timeout to prevent hanging processes */ alarm(UDEV_EVENT_TIMEOUT); + /* clear any existing udev watch on the node */ + if (inotify_fd != -1) { + struct udev_device *dev_old; + + dev_old = udev_device_new_from_syspath(event->udev, udev_device_get_syspath(event->dev)); + if (dev_old != NULL) { + udev_watch_end(event->udev, dev_old); + udev_device_unref(dev_old); + } + } + /* apply rules, create node, symlinks */ err = udev_event_execute_rules(event, rules); @@ -229,6 +237,11 @@ static void event_fork(struct udev_event *event) if (err == 0 && !event->ignore_device && udev_get_run(event->udev)) udev_event_execute_run(event); + /* apply/restore inotify watch */ + if (err == 0 && event->inotify_watch && + strcmp(udev_device_get_action(event->dev), "remove") != 0) + udev_watch_begin(event->udev, event->dev); + info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err); logging_close(); if (err != 0) @@ -513,6 +526,63 @@ static void handle_ctrl_msg(struct udev_ctrl *uctrl) udev_ctrl_msg_unref(ctrl_msg); } +/* read inotify messages */ +static int handle_inotify(struct udev *udev) +{ + int nbytes, pos; + char *buf; + struct inotify_event *ev; + + if ((ioctl(inotify_fd, FIONREAD, &nbytes) < 0) || (nbytes <= 0)) + return 0; + + buf = malloc(nbytes); + if (buf == NULL) { + err(udev, "error getting buffer for inotify, disable watching\n"); + close(inotify_fd); + inotify_fd = -1; + return 0; + } + + read(inotify_fd, buf, nbytes); + + for (pos = 0; pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) { + struct udev_device *dev; + + ev = (struct inotify_event *)(buf + pos); + if (ev->len) { + dbg(udev, "inotify event: %x for %s\n", ev->mask, ev->name); + reload_config = 1; + continue; + } + + dev = udev_watch_lookup(udev, ev->wd); + if (dev != NULL) { + dbg(udev, "inotify event: %x for %s\n", ev->mask, udev_device_get_devnode(dev)); + if (ev->mask & IN_CLOSE_WRITE) { + char filename[UTIL_PATH_SIZE]; + int fd; + + info(udev, "device %s closed, synthesising 'change'\n", udev_device_get_devnode(dev)); + util_strlcpy(filename, udev_device_get_syspath(dev), sizeof(filename)); + util_strlcat(filename, "/uevent", sizeof(filename)); + fd = open(filename, O_WRONLY); + if (fd < 0 || write(fd, "change", 6) < 0) + info(udev, "error writing uevent: %m\n"); + close(fd); + } + if (ev->mask & IN_IGNORED) + udev_watch_end(udev, dev); + + udev_device_unref(dev); + } + + } + + free (buf); + return 0; +} + static void asmlinkage sig_handler(int signum) { switch (signum) { @@ -699,7 +769,8 @@ int main(int argc, char *argv[]) } break; case 'h': - printf("Usage: udevd [--help] [--daemon] [--debug-trace] [--debug] [--resolve-names=early|late|never] [--version]\n"); + printf("Usage: udevd [--help] [--daemon] [--debug-trace] [--debug] " + "[--resolve-names=early|late|never] [--version]\n"); goto exit; case 'V': printf("%s\n", VERSION); @@ -830,13 +901,14 @@ int main(int argc, char *argv[]) memset(&act, 0x00, sizeof(struct sigaction)); act.sa_handler = (void (*)(int)) sig_handler; sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; sigaction(SIGINT, &act, NULL); sigaction(SIGTERM, &act, NULL); sigaction(SIGCHLD, &act, NULL); sigaction(SIGHUP, &act, NULL); /* watch rules directory */ - inotify_fd = inotify_init(); + udev_watch_init(udev); if (inotify_fd >= 0) { if (udev_get_rules_path(udev) != NULL) { inotify_add_watch(inotify_fd, udev_get_rules_path(udev), @@ -855,10 +927,9 @@ int main(int argc, char *argv[]) inotify_add_watch(inotify_fd, filename, IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE); } - } else if (errno == ENOSYS) - info(udev, "unable to use inotify, udevd will not monitor rule files changes\n"); - else - err(udev, "inotify_init failed: %m\n"); + + udev_watch_restore(udev); + } /* in trace mode run one event after the other */ if (debug_trace) { @@ -934,24 +1005,8 @@ int main(int argc, char *argv[]) } /* rules directory inotify watch */ - if (inotify_poll && (inotify_poll->revents & POLLIN)) { - int nbytes; - - /* discard all possible events, we can just reload the config */ - if ((ioctl(inotify_fd, FIONREAD, &nbytes) == 0) && nbytes > 0) { - char *buf; - - reload_config = 1; - buf = malloc(nbytes); - if (buf == NULL) { - err(udev, "error getting buffer for inotify, disable watching\n"); - close(inotify_fd); - inotify_fd = -1; - } - read(inotify_fd, buf, nbytes); - free(buf); - } - } + if (inotify_poll && (inotify_poll->revents & POLLIN)) + handle_inotify(udev); handle_signals: signal_received = 0;