X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=udev%2Fudevd.c;h=f730cab4849d45f190f630c170bc7edb65ba049a;hb=1e47c28bc575cfed063be7df6bbb822422e2db75;hp=051e8fe527b21e0c4f92983c9156070941489744;hpb=2903820a62de1085f6b5def0fb622070805dd90b;p=elogind.git diff --git a/udev/udevd.c b/udev/udevd.c index 051e8fe52..f730cab48 100644 --- a/udev/udevd.c +++ b/udev/udevd.c @@ -47,9 +47,6 @@ #include "udev.h" #include "sd-daemon.h" -#define UDEVD_PRIORITY -4 -#define UDEV_PRIORITY -2 - static bool debug; static void log_fn(struct udev *udev, int priority, @@ -88,7 +85,6 @@ static sigset_t orig_sigmask; static UDEV_LIST(event_list); static UDEV_LIST(worker_list); static bool udev_exit; -static volatile sig_atomic_t worker_exit; enum event_state { EVENT_UNDEF, @@ -171,18 +167,6 @@ static void event_queue_delete(struct event *event, bool export) free(event); } -static void event_sig_handler(int signum) -{ - switch (signum) { - case SIGALRM: - _exit(1); - break; - case SIGTERM: - worker_exit = true; - break; - } -} - static struct worker *worker_ref(struct worker *worker) { worker->refcount++; @@ -223,7 +207,6 @@ static void worker_new(struct event *event) struct worker *worker; struct udev_monitor *worker_monitor; pid_t pid; - struct sigaction act; /* listen for new events */ worker_monitor = udev_monitor_new_from_netlink(udev, NULL); @@ -245,12 +228,11 @@ static void worker_new(struct event *event) pid = fork(); switch (pid) { case 0: { - sigset_t sigmask; - struct udev_device *dev; - struct pollfd pmon = { - .fd = udev_monitor_get_fd(worker_monitor), - .events = POLLIN, - }; + struct udev_device *dev = NULL; + int fd_monitor; + struct epoll_event ep_signal, ep_monitor; + sigset_t mask; + int rc = EXIT_SUCCESS; /* move initial device from queue */ dev = event->dev; @@ -267,27 +249,42 @@ static void worker_new(struct event *event) close(worker_watch[READ_END]); udev_log_close(); udev_log_init("udevd-work"); - setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY); - - /* set signal handlers */ - memset(&act, 0x00, sizeof(act)); - act.sa_handler = event_sig_handler; - sigemptyset (&act.sa_mask); - act.sa_flags = 0; - sigaction(SIGTERM, &act, NULL); - sigaction(SIGALRM, &act, NULL); - - /* unblock SIGALRM */ - sigfillset(&sigmask); - sigdelset(&sigmask, SIGALRM); - sigprocmask(SIG_SETMASK, &sigmask, NULL); - /* SIGTERM is unblocked in ppoll() */ - sigdelset(&sigmask, SIGTERM); + + sigfillset(&mask); + fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); + if (fd_signal < 0) { + err(udev, "error creating signalfd %m\n"); + rc = 2; + goto out; + } + + fd_ep = epoll_create1(EPOLL_CLOEXEC); + if (fd_ep < 0) { + err(udev, "error creating epoll fd: %m\n"); + rc = 3; + goto out; + } + + memset(&ep_signal, 0, sizeof(struct epoll_event)); + ep_signal.events = EPOLLIN; + ep_signal.data.fd = fd_signal; + + fd_monitor = udev_monitor_get_fd(worker_monitor); + memset(&ep_monitor, 0, sizeof(struct epoll_event)); + ep_monitor.events = EPOLLIN; + ep_monitor.data.fd = fd_monitor; + + if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 || + epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) { + err(udev, "fail to add fds to epoll: %m\n"); + rc = 4; + goto out; + } /* request TERM signal if parent exits */ prctl(PR_SET_PDEATHSIG, SIGTERM); - do { + for (;;) { struct udev_event *udev_event; struct worker_message msg = {}; int err; @@ -295,8 +292,10 @@ static void worker_new(struct event *event) info(udev, "seq %llu running\n", udev_device_get_seqnum(dev)); udev_event = udev_event_new(dev); - if (udev_event == NULL) - _exit(3); + if (udev_event == NULL) { + rc = 5; + goto out; + } /* set timeout to prevent hanging processes */ alarm(UDEV_EVENT_TIMEOUT); @@ -338,29 +337,50 @@ static void worker_new(struct event *event) udev_device_unref(dev); dev = NULL; - /* wait for more device messages or signal from udevd */ - while (!worker_exit) { + /* wait for more device messages from main udevd, or term signal */ + while (dev == NULL) { + struct epoll_event ev[4]; int fdcount; + int i; - fdcount = ppoll(&pmon, 1, NULL, &sigmask); + fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); if (fdcount < 0) continue; - if (pmon.revents & POLLIN) { - dev = udev_monitor_receive_device(worker_monitor); - if (dev != NULL) - break; + for (i = 0; i < fdcount; i++) { + if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) { + dev = udev_monitor_receive_device(worker_monitor); + } else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) { + struct signalfd_siginfo fdsi; + ssize_t size; + + size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo)); + if (size != sizeof(struct signalfd_siginfo)) + continue; + switch (fdsi.ssi_signo) { + case SIGTERM: + goto out; + case SIGALRM: + rc = EXIT_FAILURE; + goto out; + } + } } } - } while (dev != NULL); - + } +out: + udev_device_unref(dev); + if (fd_signal >= 0) + close(fd_signal); + if (fd_ep >= 0) + close(fd_ep); close(fd_inotify); close(worker_watch[WRITE_END]); udev_rules_unref(rules); udev_monitor_unref(worker_monitor); udev_unref(udev); udev_log_close(); - exit(EXIT_SUCCESS); + exit(rc); } case -1: udev_monitor_unref(worker_monitor); @@ -1103,10 +1123,45 @@ static int convert_db(struct udev *udev) return 0; } +static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) +{ + int ctrl = -1, netlink = -1; + int fd, n; + + n = sd_listen_fds(true); + if (n <= 0) + return -1; + + for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) { + if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) { + if (ctrl >= 0) + return -1; + ctrl = fd; + continue; + } + + if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) { + if (netlink >= 0) + return -1; + netlink = fd; + continue; + } + + return -1; + } + + if (ctrl < 0 || netlink < 0) + return -1; + + info(udev, "ctrl=%i netlink=%i\n", ctrl, netlink); + *rctrl = ctrl; + *rnetlink = netlink; + return 0; +} + int main(int argc, char *argv[]) { struct udev *udev; - int fd; FILE *f; sigset_t mask; int daemonize = false; @@ -1265,47 +1320,78 @@ int main(int argc, char *argv[]) static_dev_create_from_modules(udev); /* before opening new files, make sure std{in,out,err} fds are in a sane state */ - fd = open("/dev/null", O_RDWR); - if (fd < 0) { - fprintf(stderr, "cannot open /dev/null\n"); - err(udev, "cannot open /dev/null\n"); + if (daemonize) { + int fd; + + fd = open("/dev/null", O_RDWR); + if (fd >= 0) { + if (write(STDOUT_FILENO, 0, 0) < 0) + dup2(fd, STDOUT_FILENO); + if (write(STDERR_FILENO, 0, 0) < 0) + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) + close(fd); + } else { + fprintf(stderr, "cannot open /dev/null\n"); + err(udev, "cannot open /dev/null\n"); + } } - if (write(STDOUT_FILENO, 0, 0) < 0) - dup2(fd, STDOUT_FILENO); - if (write(STDERR_FILENO, 0, 0) < 0) - dup2(fd, STDERR_FILENO); - - /* udevadm control socket */ - if (sd_listen_fds(true) == 1 && sd_is_socket(SD_LISTEN_FDS_START, AF_LOCAL, SOCK_SEQPACKET, -1)) - udev_ctrl = udev_ctrl_new_from_fd(udev, SD_LISTEN_FDS_START); - else + + 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); + if (udev_ctrl == NULL) { + err(udev, "error taking over udev control socket"); + rc = 1; + goto exit; + } + + monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink); + if (monitor == NULL) { + err(udev, "error taking over netlink socket\n"); + rc = 3; + goto exit; + } + } else { + /* open control and netlink socket */ udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH); - if (udev_ctrl == NULL) { - fprintf(stderr, "error initializing udev control socket"); - err(udev, "error initializing udev control socket"); - rc = 1; + if (udev_ctrl == NULL) { + fprintf(stderr, "error initializing udev control socket"); + err(udev, "error initializing udev control socket"); + rc = 1; + goto exit; + } + fd_ctrl = udev_ctrl_get_fd(udev_ctrl); + + monitor = udev_monitor_new_from_netlink(udev, "kernel"); + if (monitor == NULL) { + fprintf(stderr, "error initializing netlink socket\n"); + err(udev, "error initializing netlink socket\n"); + rc = 3; + goto exit; + } + fd_netlink = udev_monitor_get_fd(monitor); + } + + if (udev_monitor_enable_receiving(monitor) < 0) { + fprintf(stderr, "error binding netlink socket\n"); + err(udev, "error binding netlink socket\n"); + rc = 3; goto exit; } + if (udev_ctrl_enable_receiving(udev_ctrl) < 0) { fprintf(stderr, "error binding udev control socket\n"); err(udev, "error binding udev control socket\n"); rc = 1; goto exit; } - fd_ctrl = udev_ctrl_get_fd(udev_ctrl); - monitor = udev_monitor_new_from_netlink(udev, "kernel"); - if (monitor == NULL || udev_monitor_enable_receiving(monitor) < 0) { - fprintf(stderr, "error initializing netlink socket\n"); - err(udev, "error initializing netlink socket\n"); - rc = 3; - goto exit; - } udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024); - fd_netlink = udev_monitor_get_fd(monitor); if (daemonize) { pid_t pid; + int fd; pid = fork(); switch (pid) { @@ -1319,10 +1405,46 @@ int main(int argc, char *argv[]) rc = 0; goto exit; } + + setsid(); + + fd = open("/proc/self/oom_score_adj", O_RDWR); + if (fd < 0) { + /* Fallback to old interface */ + fd = open("/proc/self/oom_adj", O_RDWR); + if (fd < 0) { + err(udev, "error disabling OOM: %m\n"); + } else { + /* OOM_DISABLE == -17 */ + write(fd, "-17", 3); + close(fd); + } + } else { + write(fd, "-1000", 5); + close(fd); + } } else { sd_notify(1, "READY=1"); } + f = fopen("/dev/kmsg", "w"); + if (f != NULL) { + fprintf(f, "<30>udev[%u]: starting version " VERSION "\n", getpid()); + fclose(f); + } + + if (!debug) { + int fd; + + fd = open("/dev/null", O_RDWR); + if (fd >= 0) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + } + } + fd_inotify = udev_watch_init(udev); if (fd_inotify < 0) { fprintf(stderr, "error initializing inotify\n"); @@ -1357,18 +1479,18 @@ int main(int argc, char *argv[]) /* block and listen to all signals on signalfd */ sigfillset(&mask); sigprocmask(SIG_SETMASK, &mask, &orig_sigmask); - fd_signal = signalfd(-1, &mask, SFD_CLOEXEC); + fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); if (fd_signal < 0) { - fprintf(stderr, "error getting signalfd\n"); - err(udev, "error getting signalfd\n"); + fprintf(stderr, "error creating signalfd\n"); + err(udev, "error creating signalfd\n"); rc = 5; goto exit; } /* unnamed socket from workers to the main daemon */ if (socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, worker_watch) < 0) { - fprintf(stderr, "error getting socketpair\n"); - err(udev, "error getting socketpair\n"); + fprintf(stderr, "error creating socketpair\n"); + err(udev, "error creating socketpair\n"); rc = 6; goto exit; } @@ -1389,18 +1511,23 @@ int main(int argc, char *argv[]) memset(&ep_ctrl, 0, sizeof(struct epoll_event)); ep_ctrl.events = EPOLLIN; ep_ctrl.data.fd = fd_ctrl; + memset(&ep_inotify, 0, sizeof(struct epoll_event)); ep_inotify.events = EPOLLIN; ep_inotify.data.fd = fd_inotify; + memset(&ep_signal, 0, sizeof(struct epoll_event)); ep_signal.events = EPOLLIN; ep_signal.data.fd = fd_signal; + memset(&ep_netlink, 0, sizeof(struct epoll_event)); ep_netlink.events = EPOLLIN; ep_netlink.data.fd = fd_netlink; + memset(&ep_worker, 0, sizeof(struct epoll_event)); ep_worker.events = EPOLLIN; ep_worker.data.fd = fd_worker; + fd_ep = epoll_create1(EPOLL_CLOEXEC); if (fd_ep < 0) { err(udev, "error creating epoll fd: %m\n"); @@ -1418,41 +1545,6 @@ int main(int argc, char *argv[]) /* if needed, convert old database from earlier udev version */ convert_db(udev); - if (!debug) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - } - if (fd > STDERR_FILENO) - close(fd); - - /* set scheduling priority for the main daemon process */ - setpriority(PRIO_PROCESS, 0, UDEVD_PRIORITY); - - setsid(); - - f = fopen("/dev/kmsg", "w"); - if (f != NULL) { - fprintf(f, "<30>udev[%u]: starting version " VERSION "\n", getpid()); - fclose(f); - } - - fd = open("/proc/self/oom_score_adj", O_RDWR); - if (fd < 0) { - /* Fallback to old interface */ - fd = open("/proc/self/oom_adj", O_RDWR); - if (fd < 0) { - err(udev, "error disabling OOM: %m\n"); - } else { - /* OOM_DISABLE == -17 */ - write(fd, "-17", 3); - close(fd); - } - } else { - write(fd, "-1000", 5); - close(fd); - } - if (children_max <= 0) { int memsize = mem_size_mb();