+ udev_list_node_foreach_safe(loop, tmp, &worker_list) {
+ struct worker *worker = node_to_worker(loop);
+
+ if (worker->pid != pid)
+ continue;
+
+ info(udev, "worker [%u] exit\n", pid);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ if (WEXITSTATUS(status))
+ err(udev, "worker [%u] unexpectedly returned with status %d\n", pid, WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ err(udev, "worker [%u] killed by signal %d (%s)\n", pid,
+ WTERMSIG(status), strsignal(WTERMSIG(status)));
+ else if (WIFSTOPPED(status))
+ err(udev, "worker [%u] unexpectedly stopped\n", pid);
+ else if (WIFCONTINUED(status))
+ err(udev, "worker [%u] continued\n", pid);
+
+ if (worker->event != NULL) {
+ err(udev, "worker [%u] failed while handling '%s'\n", pid, worker->event->devpath);
+ worker->event->exitcode = -32;
+ event_queue_delete(worker->event, true);
+ /* drop reference from running event */
+ worker_unref(worker);
+ }
+ }
+ worker_unref(worker);
+ break;
+ }
+ }
+ break;
+ case SIGHUP:
+ reload_config = true;
+ break;
+ }
+}
+
+static void static_dev_create_from_modules(struct udev *udev)
+{
+ struct utsname kernel;
+ char modules[UTIL_PATH_SIZE];
+ char buf[4096];
+ FILE *f;
+
+ uname(&kernel);
+ util_strscpyl(modules, sizeof(modules), "/lib/modules/", kernel.release, "/modules.devname", NULL);
+ f = fopen(modules, "r");
+ if (f == NULL)
+ return;
+
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+ char *s;
+ const char *modname;
+ const char *devname;
+ const char *devno;
+ int maj, min;
+ char type;
+ mode_t mode;
+ char filename[UTIL_PATH_SIZE];
+
+ if (buf[0] == '#')
+ continue;
+
+ modname = buf;
+ s = strchr(modname, ' ');
+ if (s == NULL)
+ continue;
+ s[0] = '\0';
+
+ devname = &s[1];
+ s = strchr(devname, ' ');
+ if (s == NULL)
+ continue;
+ s[0] = '\0';
+
+ devno = &s[1];
+ s = strchr(devno, ' ');
+ if (s == NULL)
+ s = strchr(devno, '\n');
+ if (s != NULL)
+ s[0] = '\0';
+ if (sscanf(devno, "%c%u:%u", &type, &maj, &min) != 3)
+ continue;
+
+ if (type == 'c')
+ mode = 0600 | S_IFCHR;
+ else if (type == 'b')
+ mode = 0600 | S_IFBLK;
+ else
+ continue;
+
+ util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/", devname, NULL);
+ util_create_path_selinux(udev, filename);
+ udev_selinux_setfscreatecon(udev, filename, mode);
+ info(udev, "mknod '%s' %c%u:%u\n", filename, type, maj, min);
+ if (mknod(filename, mode, makedev(maj, min)) < 0 && errno == EEXIST)
+ utimensat(AT_FDCWD, filename, NULL, 0);
+ udev_selinux_resetfscreatecon(udev);
+ }
+
+ fclose(f);
+}
+
+static int copy_dev_dir(struct udev *udev, DIR *dir_from, DIR *dir_to, int maxdepth)
+{
+ struct dirent *dent;
+
+ for (dent = readdir(dir_from); dent != NULL; dent = readdir(dir_from)) {
+ struct stat stats;
+
+ if (dent->d_name[0] == '.')
+ continue;
+ if (fstatat(dirfd(dir_from), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
+ continue;
+
+ if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
+ udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, stats.st_mode & 0777);
+ if (mknodat(dirfd(dir_to), dent->d_name, stats.st_mode, stats.st_rdev) == 0) {
+ fchmodat(dirfd(dir_to), dent->d_name, stats.st_mode & 0777, 0);
+ fchownat(dirfd(dir_to), dent->d_name, stats.st_uid, stats.st_gid, 0);
+ } else {
+ utimensat(dirfd(dir_to), dent->d_name, NULL, 0);
+ }
+ udev_selinux_resetfscreatecon(udev);
+ } else if (S_ISLNK(stats.st_mode)) {
+ char target[UTIL_PATH_SIZE];
+ ssize_t len;
+
+ len = readlinkat(dirfd(dir_from), dent->d_name, target, sizeof(target));
+ if (len <= 0 || len == (ssize_t)sizeof(target))
+ continue;
+ target[len] = '\0';
+ udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFLNK);
+ if (symlinkat(target, dirfd(dir_to), dent->d_name) < 0 && errno == EEXIST)
+ utimensat(dirfd(dir_to), dent->d_name, NULL, AT_SYMLINK_NOFOLLOW);
+ udev_selinux_resetfscreatecon(udev);
+ } else if (S_ISDIR(stats.st_mode)) {
+ DIR *dir2_from, *dir2_to;
+
+ if (maxdepth == 0)
+ continue;