X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Fudevd.c;h=d9de26ea6cc705e8912bebc897ae3451f8d021fc;hp=d08cf30f29b806340f3e5099193fc831a607314d;hb=116254097ad3c07d9f7ed06042dbec7ba4f0f4fd;hpb=5db88229d1d1d727ee1e60de583cedc6c6aa6d73 diff --git a/udev/udevd.c b/udev/udevd.c index d08cf30f2..d9de26ea6 100644 --- a/udev/udevd.c +++ b/udev/udevd.c @@ -1,6 +1,8 @@ /* * Copyright (C) 2004-2008 Kay Sievers * Copyright (C) 2004 Chris Friesen + * Copyright (C) 2009 Canonical Ltd. + * Copyright (C) 2009 Scott James Remnant * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -65,11 +67,11 @@ 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; static volatile int signal_received; +static volatile pid_t settle_pid; static int run_exec_q; static int stop_exec_q; static int max_childs; @@ -193,10 +195,7 @@ static void event_fork(struct udev_event *event) switch (pid) { case 0: /* 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); @@ -229,6 +228,15 @@ 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) { + udev_watch_begin(event->udev, event->dev); + udev_device_update_db(event->dev); + } + + /* send processed event back to the kernel netlink socket */ + udev_monitor_send_device(kernel_monitor, event->dev); + info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err); logging_close(); if (err != 0) @@ -510,9 +518,71 @@ static void handle_ctrl_msg(struct udev_ctrl *uctrl) info(udev, "udevd message (SET_MAX_CHILDS) received, max_childs=%i\n", i); max_childs = i; } + + settle_pid = udev_ctrl_get_settle(ctrl_msg); + if (settle_pid > 0) { + info(udev, "udevd message (SETTLE) received\n"); + } 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) { @@ -743,7 +813,7 @@ int main(int argc, char *argv[]) goto exit; } - kernel_monitor = udev_monitor_new_from_netlink(udev); + kernel_monitor = udev_monitor_new_from_netlink(udev, UDEV_MONITOR_KERNEL); if (kernel_monitor == NULL || udev_monitor_enable_receiving(kernel_monitor) < 0) { fprintf(stderr, "error initializing netlink socket\n"); err(udev, "error initializing netlink socket\n"); @@ -838,7 +908,7 @@ int main(int argc, char *argv[]) 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), @@ -857,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) { @@ -936,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; @@ -980,6 +1033,11 @@ handle_signals: if (!stop_exec_q) event_queue_manager(udev); } + + if (settle_pid > 0) { + kill(settle_pid, SIGUSR1); + settle_pid = 0; + } } cleanup_queue_dir(udev); rc = 0;