chiark / gitweb /
udevadm: settle - add --exit-if-exists=<file>
[elogind.git] / udev / udevd.c
index d1a226673e6df8244ce8e5bbb071539ccb84657d..5ee61d2e23c296c853a453b97729741e973da6f5 100644 (file)
@@ -65,12 +65,13 @@ static void reap_sigchilds(void);
 
 static int debug_trace;
 static struct udev_rules *rules;
+static struct udev_queue_export *udev_queue_export;
 static struct udev_ctrl *udev_ctrl;
 static struct udev_monitor *kernel_monitor;
-static volatile int sigchilds_waiting;
-static volatile int udev_exit;
-static volatile int reload_config;
-static volatile int signal_received;
+static volatile sig_atomic_t sigchilds_waiting;
+static volatile sig_atomic_t udev_exit;
+static volatile sig_atomic_t reload_config;
+static volatile sig_atomic_t signal_received;
 static volatile pid_t settle_pid;
 static int run_exec_q;
 static int stop_exec_q;
@@ -78,12 +79,6 @@ static int max_childs;
 static int childs;
 static struct udev_list_node event_list;
 
-enum event_state {
-       EVENT_QUEUED,
-       EVENT_FINISHED,
-       EVENT_FAILED,
-};
-
 static struct udev_event *node_to_event(struct udev_list_node *node)
 {
        char *event;
@@ -93,89 +88,24 @@ static struct udev_event *node_to_event(struct udev_list_node *node)
        return (struct udev_event *)event;
 }
 
-static void export_event_state(struct udev_event *event, enum event_state state)
-{
-       char filename[UTIL_PATH_SIZE];
-       char filename_failed[UTIL_PATH_SIZE];
-       size_t start;
-
-       /* location of queue file */
-       snprintf(filename, sizeof(filename), "%s/.udev/queue/%llu",
-                udev_get_dev_path(event->udev), udev_device_get_seqnum(event->dev));
-
-       /* location of failed file */
-       util_strlcpy(filename_failed, udev_get_dev_path(event->udev), sizeof(filename_failed));
-       util_strlcat(filename_failed, "/", sizeof(filename_failed));
-       start = util_strlcat(filename_failed, ".udev/failed/", sizeof(filename_failed));
-       util_strlcat(filename_failed, udev_device_get_devpath(event->dev), sizeof(filename_failed));
-       util_path_encode(&filename_failed[start], sizeof(filename_failed) - start);
-
-       switch (state) {
-       case EVENT_QUEUED:
-               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);
-               break;
-       case EVENT_FINISHED:
-               if (udev_device_get_devpath_old(event->dev) != NULL) {
-                       /* "move" event - rename failed file to current name, do not delete failed */
-                       char filename_failed_old[UTIL_PATH_SIZE];
-
-                       util_strlcpy(filename_failed_old, udev_get_dev_path(event->udev), sizeof(filename_failed_old));
-                       util_strlcat(filename_failed_old, "/", sizeof(filename_failed_old));
-                       start = util_strlcat(filename_failed_old, ".udev/failed/", sizeof(filename_failed_old));
-                       util_strlcat(filename_failed_old, udev_device_get_devpath_old(event->dev), sizeof(filename_failed_old));
-                       util_path_encode(&filename_failed_old[start], sizeof(filename) - start);
-
-                       if (rename(filename_failed_old, filename_failed) == 0)
-                               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 {
-                       if (unlink(filename_failed) == 0)
-                               util_delete_path(event->udev, filename_failed);
-               }
-
-               unlink(filename);
-
-               /* clean up possibly empty queue directory */
-               if (udev_list_is_empty(&event_list))
-                       util_delete_path(event->udev, filename);
-               break;
-       case EVENT_FAILED:
-               /* move failed event to the failed directory */
-               util_create_path(event->udev, filename_failed);
-               rename(filename, filename_failed);
-
-               /* clean up possibly empty queue directory */
-               if (udev_list_is_empty(&event_list))
-                       util_delete_path(event->udev, filename);
-               break;
-       }
-
-       return;
-}
-
 static void event_queue_delete(struct udev_event *event)
 {
        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)
-               export_event_state(event, EVENT_FAILED);
+               udev_queue_export_device_failed(udev_queue_export, event->dev);
        else
-               export_event_state(event, EVENT_FINISHED);
+               udev_queue_export_device_finished(udev_queue_export, event->dev);
 
        udev_device_unref(event->dev);
        udev_event_unref(event);
 }
 
-static void asmlinkage event_sig_handler(int signum)
+static void event_sig_handler(int signum)
 {
        if (signum == SIGALRM)
-               exit(1);
+               _exit(1);
 }
 
 static void event_fork(struct udev_event *event)
@@ -184,6 +114,16 @@ static void event_fork(struct udev_event *event)
        struct sigaction act;
        int err;
 
+#if 0
+       /* single process, no forking, just for testing/profiling */
+       err = udev_event_execute_rules(event, rules);
+       if (err == 0 && !event->ignore_device && udev_get_run(event->udev))
+               udev_event_execute_run(event);
+       info(event->udev, "seq %llu exit with %i\n", udev_device_get_seqnum(event->dev), err);
+       event_queue_delete(event);
+       return;
+#endif
+
        if (debug_trace) {
                event->trace = 1;
                fprintf(stderr, "fork %s (%llu)\n",
@@ -195,6 +135,7 @@ static void event_fork(struct udev_event *event)
        switch (pid) {
        case 0:
                /* child */
+               udev_queue_export_unref(udev_queue_export);
                udev_ctrl_unref(udev_ctrl);
                logging_close();
                logging_init("udevd-event");
@@ -202,7 +143,7 @@ static void event_fork(struct udev_event *event)
 
                /* set signal handlers */
                memset(&act, 0x00, sizeof(act));
-               act.sa_handler = (void (*)(int)) event_sig_handler;
+               act.sa_handler = event_sig_handler;
                sigemptyset (&act.sa_mask);
                act.sa_flags = 0;
                sigaction(SIGALRM, &act, NULL);
@@ -261,28 +202,12 @@ static void event_fork(struct udev_event *event)
 
 static void event_queue_insert(struct udev_event *event)
 {
-       char filename[UTIL_PATH_SIZE];
-       int fd;
-
        event->queue_time = time(NULL);
 
-       export_event_state(event, EVENT_QUEUED);
+       udev_queue_export_device_queued(udev_queue_export, 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));
-       fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
-       if (fd >= 0) {
-               char str[32];
-               int len;
-
-               len = sprintf(str, "%llu\n", udev_device_get_seqnum(event->dev));
-               write(fd, str, len);
-               close(fd);
-       }
-
-
        udev_list_node_append(&event->node, &event_list);
        run_exec_q = 1;
 
@@ -339,13 +264,11 @@ static int compare_devpath(const char *running, const char *waiting)
        return 0;
 }
 
-/* lookup event for identical, parent, child, or physical device */
+/* lookup event for identical, parent, child device */
 static int devpath_busy(struct udev_event *event)
 {
        struct udev_list_node *loop;
 
-       if (event->delaying_seqnum > 0) {
-       }
        /* check if queue contains events we depend on */
        udev_list_node_foreach(loop, &event_list) {
                struct udev_event *loop_event = node_to_event(loop);
@@ -390,19 +313,6 @@ static int devpath_busy(struct udev_event *event)
                        event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev);
                        return 5;
                }
-
-               /* check physical device event (special case of parent) */
-               if (udev_device_get_physdevpath(event->dev) != NULL &&
-                   strcmp(udev_device_get_action(event->dev), "add") == 0)
-                       if (compare_devpath(udev_device_get_devpath(loop_event->dev),
-                                           udev_device_get_physdevpath(event->dev)) != 0) {
-                               dbg(event->udev, "%llu, physical device event still pending %llu (%s)\n",
-                                   udev_device_get_seqnum(event->dev),
-                                   udev_device_get_seqnum(loop_event->dev),
-                                   udev_device_get_devpath(loop_event->dev));
-                               event->delaying_seqnum = udev_device_get_seqnum(loop_event->dev);
-                               return 6;
-                       }
        }
        return 0;
 }
@@ -564,8 +474,7 @@ static int handle_inotify(struct udev *udev)
                                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));
+                               util_strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
                                fd = open(filename, O_WRONLY);
                                if (fd < 0 || write(fd, "change", 6) < 0)
                                        info(udev, "error writing uevent: %m\n");
@@ -583,7 +492,7 @@ static int handle_inotify(struct udev *udev)
        return 0;
 }
 
-static void asmlinkage sig_handler(int signum)
+static void sig_handler(int signum)
 {
        switch (signum) {
                case SIGINT:
@@ -648,88 +557,6 @@ static void reap_sigchilds(void)
        }
 }
 
-static void cleanup_queue_dir(struct udev *udev)
-{
-       char dirname[UTIL_PATH_SIZE];
-       char filename[UTIL_PATH_SIZE];
-       DIR *dir;
-
-       util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
-       util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename));
-       unlink(filename);
-
-       util_strlcpy(dirname, udev_get_dev_path(udev), sizeof(dirname));
-       util_strlcat(dirname, "/.udev/queue", sizeof(dirname));
-       dir = opendir(dirname);
-       if (dir != NULL) {
-               while (1) {
-                       struct dirent *dent;
-
-                       dent = readdir(dir);
-                       if (dent == NULL || dent->d_name[0] == '\0')
-                               break;
-                       if (dent->d_name[0] == '.')
-                               continue;
-                       util_strlcpy(filename, dirname, sizeof(filename));
-                       util_strlcat(filename, "/", sizeof(filename));
-                       util_strlcat(filename, dent->d_name, sizeof(filename));
-                       unlink(filename);
-               }
-               closedir(dir);
-               rmdir(dirname);
-       }
-}
-
-static void export_initial_seqnum(struct udev *udev)
-{
-       char filename[UTIL_PATH_SIZE];
-       int fd;
-       char seqnum[32];
-       ssize_t len = 0;
-
-       util_strlcpy(filename, udev_get_sys_path(udev), sizeof(filename));
-       util_strlcat(filename, "/kernel/uevent_seqnum", sizeof(filename));
-       fd = open(filename, O_RDONLY);
-       if (fd >= 0) {
-               len = read(fd, seqnum, sizeof(seqnum)-1);
-               close(fd);
-       }
-       if (len <= 0) {
-               strcpy(seqnum, "0\n");
-               len = 3;
-       }
-       util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
-       util_strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename));
-       util_create_path(udev, filename);
-       fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
-       if (fd >= 0) {
-               write(fd, seqnum, len);
-               close(fd);
-       }
-}
-
-/* create the nodes the we depend on to properly start up */
-static void setup_initial_nodes(struct udev *udev)
-{
-       struct udev_device *dev;
-
-       dev = udev_device_new_from_subsystem_sysname(udev, "mem", "null");
-       if (dev != NULL) {
-               udev_node_mknod(dev, "null", makedev(0,0), 0666, 0, 0);
-               udev_device_unref(dev);
-       }
-       dev = udev_device_new_from_subsystem_sysname(udev, "mem", "kmsg");
-       if (dev != NULL) {
-               udev_node_mknod(dev, "kmsg", makedev(0,0), 0660, 0, 0);
-               udev_device_unref(dev);
-       }
-       dev = udev_device_new_from_subsystem_sysname(udev, "tty", "console");
-       if (dev != NULL) {
-               udev_node_mknod(dev, "console", makedev(0,0), 0600, 0, 0);
-               udev_device_unref(dev);
-       }
-}
-
 static void startup_log(struct udev *udev)
 {
        FILE *f;
@@ -740,8 +567,7 @@ static void startup_log(struct udev *udev)
        if (f != NULL)
                fprintf(f, "<6>udev: starting version " VERSION "\n");
 
-       util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
-       util_strlcat(path, "/class/mem/null", sizeof(path));
+       util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/class/mem/null", NULL);
        if (lstat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
                const char *depr_str =
                        "udev: missing sysfs features; please update the kernel "
@@ -836,8 +662,6 @@ int main(int argc, char *argv[])
                goto exit;
        }
 
-       setup_initial_nodes(udev);
-
        /* make sure std{in,out,err} fd's are in a sane state */
        fd = open("/dev/null", O_RDWR);
        if (fd < 0) {
@@ -880,8 +704,11 @@ int main(int argc, char *argv[])
                goto exit;
        }
        udev_list_init(&event_list);
-       cleanup_queue_dir(udev);
-       export_initial_seqnum(udev);
+       udev_queue_export = udev_queue_export_new(udev);
+       if (udev_queue_export == NULL) {
+               err(udev, "error creating queue file\n");
+               goto exit;
+       }
 
        if (daemonize) {
                pid_t pid;
@@ -931,7 +758,7 @@ int main(int argc, char *argv[])
 
        /* set signal handlers */
        memset(&act, 0x00, sizeof(struct sigaction));
-       act.sa_handler = (void (*)(int)) sig_handler;
+       act.sa_handler = sig_handler;
        sigemptyset(&act.sa_mask);
        act.sa_flags = SA_RESTART;
        sigaction(SIGINT, &act, NULL);
@@ -954,8 +781,7 @@ int main(int argc, char *argv[])
                                          IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
 
                        /* watch dynamic rules directory */
-                       util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
-                       util_strlcat(filename, "/.udev/rules.d", sizeof(filename));
+                       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/rules.d", NULL);
                        inotify_add_watch(inotify_fd, filename,
                                          IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE_WRITE);
                }
@@ -1071,9 +897,11 @@ handle_signals:
                        settle_pid = 0;
                }
        }
-       cleanup_queue_dir(udev);
+       udev_queue_export_cleanup(udev_queue_export);
        rc = 0;
 exit:
+
+       udev_queue_export_unref(udev_queue_export);
        udev_rules_unref(rules);
        udev_ctrl_unref(udev_ctrl);
        if (inotify_fd >= 0)