#include "udev.h"
#include "sd-daemon.h"
#include "cgroup-util.h"
+#include "dev-setup.h"
static bool debug;
int ifindex;
};
-static struct event *node_to_event(struct udev_list_node *node)
+static inline struct event *node_to_event(struct udev_list_node *node)
{
- char *event;
-
- event = (char *)node;
- event -= offsetof(struct event, node);
- return (struct event *)event;
+ return container_of(node, struct event, node);
}
static void event_queue_cleanup(struct udev *udev, enum event_state type);
int exitcode;
};
-static struct worker *node_to_worker(struct udev_list_node *node)
+static inline struct worker *node_to_worker(struct udev_list_node *node)
{
- char *worker;
-
- worker = (char *)node;
- worker -= offsetof(struct worker, node);
- return (struct worker *)worker;
+ return container_of(node, struct worker, node);
}
static void event_queue_delete(struct event *event, bool export)
/* request TERM signal if parent exits */
prctl(PR_SET_PDEATHSIG, SIGTERM);
+ /* reset OOM score, we only protect the main daemon */
+ write_one_line_file("/proc/self/oom_score_adj", "0");
+
for (;;) {
struct udev_event *udev_event;
struct worker_message msg;
FILE *f;
uname(&kernel);
- util_strscpyl(modules, sizeof(modules), "/lib/modules/", kernel.release, "/modules.devname", NULL);
- f = fopen(modules, "r");
+ util_strscpyl(modules, sizeof(modules), ROOTPREFIX "/lib/modules/", kernel.release, "/modules.devname", NULL);
+ f = fopen(modules, "re");
if (f == NULL)
return;
if (sscanf(devno, "%c%u:%u", &type, &maj, &min) != 3)
continue;
+ mode = 0600;
if (type == 'c')
- mode = S_IFCHR;
+ mode |= S_IFCHR;
else if (type == 'b')
- mode = S_IFBLK;
+ mode |= 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);
+ util_strscpyl(filename, sizeof(filename), "/dev/", devname, NULL);
+ mkdir_parents_label(filename, 0755);
+ label_context_set(filename, mode);
log_debug("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);
+ label_context_clear();
}
fclose(f);
}
-/* needed for standalone udev operations */
-static void static_dev_create_links(struct udev *udev)
-{
- DIR *dir;
- struct stdlinks {
- const char *link;
- const char *target;
- };
- static const struct stdlinks stdlinks[] = {
- { "core", "/proc/kcore" },
- { "fd", "/proc/self/fd" },
- { "stdin", "/proc/self/fd/0" },
- { "stdout", "/proc/self/fd/1" },
- { "stderr", "/proc/self/fd/2" },
- };
- unsigned int i;
-
- dir = opendir(udev_get_dev_path(udev));
- if (dir == NULL)
- return;
-
- for (i = 0; i < ELEMENTSOF(stdlinks); i++) {
- struct stat sb;
-
- if (stat(stdlinks[i].target, &sb) == 0) {
- udev_selinux_setfscreateconat(udev, dirfd(dir), stdlinks[i].link, S_IFLNK);
- if (symlinkat(stdlinks[i].target, dirfd(dir), stdlinks[i].link) < 0 && errno == EEXIST)
- utimensat(dirfd(dir), stdlinks[i].link, NULL, AT_SYMLINK_NOFOLLOW);
- udev_selinux_resetfscreatecon(udev);
- }
- }
-
- closedir(dir);
-}
-
static int mem_size_mb(void)
{
FILE *f;
char buf[4096];
long int memsize = -1;
- f = fopen("/proc/meminfo", "r");
+ f = fopen("/proc/meminfo", "re");
if (f == NULL)
return -1;
static int convert_db(struct udev *udev)
{
char filename[UTIL_PATH_SIZE];
- FILE *f;
struct udev_enumerate *udev_enumerate;
struct udev_list_entry *list_entry;
/* current database */
- util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
- if (access(filename, F_OK) >= 0)
+ if (access("/run/udev/data", F_OK) >= 0)
return 0;
/* make sure we do not get here again */
- util_create_path(udev, filename);
- mkdir(filename, 0755);
+ mkdir_p("/run/udev/data", 0755);
/* old database */
- util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db", NULL);
+ util_strscpyl(filename, sizeof(filename), "/dev/.udev/db", NULL);
if (access(filename, F_OK) < 0)
return 0;
- f = fopen("/dev/kmsg", "w");
- if (f != NULL) {
- fprintf(f, "<30>udevd[%u]: converting old udev database\n", getpid());
- fclose(f);
- }
+ print_kmsg("converting old udev database\n");
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
/* find database in old location */
id = udev_device_get_id_filename(device);
- util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
+ util_strscpyl(from, sizeof(from), "/dev/.udev/db/", id, NULL);
if (lstat(from, &stats) == 0) {
if (!have_db) {
udev_device_read_db(device, from);
}
/* find old database with $subsys:$sysname name */
- util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
- "/.udev/db/", udev_device_get_subsystem(device), ":",
- udev_device_get_sysname(device), NULL);
+ util_strscpyl(from, sizeof(from), "/dev/.udev/db/",
+ udev_device_get_subsystem(device), ":", udev_device_get_sysname(device), NULL);
if (lstat(from, &stats) == 0) {
if (!have_db) {
udev_device_read_db(device, from);
/* find old database with the encoded devpath name */
util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
- util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", devpath, NULL);
+ util_strscpyl(from, sizeof(from), "/dev/.udev/db/", devpath, NULL);
if (lstat(from, &stats) == 0) {
if (!have_db) {
udev_device_read_db(device, from);
return 0;
}
-static bool check_rules_timestamp(struct udev *udev)
+/*
+ * read the kernel commandline, in case we need to get into debug mode
+ * udev.log-priority=<level> syslog priority
+ * udev.children-max=<number of workers> events are fully serialized if set to 1
+ * udev.exec-delay=<number of seconds> delay execution of every executed program
+ */
+static void kernel_cmdline_options(struct udev *udev)
{
- char **p;
- unsigned long long *stamp_usec;
- int i, n;
- bool changed = false;
+ char *line, *w, *state;
+ size_t l;
- n = udev_get_rules_path(udev, &p, &stamp_usec);
- for (i = 0; i < n; i++) {
- struct stat stats;
+ if (read_one_line_file("/proc/cmdline", &line) < 0)
+ return;
- if (stat(p[i], &stats) < 0)
- continue;
+ FOREACH_WORD_QUOTED(w, l, line, state) {
+ char *s, *opt;
- if (stamp_usec[i] == ts_usec(&stats.st_mtim))
- continue;
+ s = strndup(w, l);
+ if (!s)
+ break;
- /* first check */
- if (stamp_usec[i] != 0) {
- log_debug("reload - timestamp of '%s' changed\n", p[i]);
- changed = true;
- }
+ /* accept the same options for the initrd, prefixed with "rd." */
+ if (in_initrd() && startswith(s, "rd."))
+ opt = s + 3;
+ else
+ opt = s;
+
+ if (startswith(opt, "udev.log-priority="))
+ udev_set_log_priority(udev, util_log_priority(opt + 18));
- /* update timestamp */
- stamp_usec[i] = ts_usec(&stats.st_mtim);
+ if (startswith(opt, "udev.children-max="))
+ children_max = strtoul(opt + 18, NULL, 0);
+
+ if (startswith(opt, "udev.exec-delay="))
+ exec_delay = strtoul(opt + 16, NULL, 0);
+
+ free(s);
}
- return changed;
+ free(line);
}
int main(int argc, char *argv[])
{
struct udev *udev;
- FILE *f;
sigset_t mask;
int daemonize = false;
int resolve_names = 1;
if (udev == NULL)
goto exit;
- log_open();
+ log_set_target(LOG_TARGET_AUTO);
log_parse_environment();
+ log_open();
udev_set_log_fn(udev, udev_main_log);
log_debug("version %s\n", VERSION);
- udev_selinux_init(udev);
+ label_init("/dev");
for (;;) {
int option;
}
}
- /*
- * read the kernel commandline, in case we need to get into debug mode
- * udev.log-priority=<level> syslog priority
- * udev.children-max=<number of workers> events are fully serialized if set to 1
- *
- */
- f = fopen("/proc/cmdline", "r");
- if (f != NULL) {
- char cmdline[4096];
-
- if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
- char *pos;
-
- pos = strstr(cmdline, "udev.log-priority=");
- if (pos != NULL) {
- pos += strlen("udev.log-priority=");
- udev_set_log_priority(udev, util_log_priority(pos));
- }
-
- pos = strstr(cmdline, "udev.children-max=");
- if (pos != NULL) {
- pos += strlen("udev.children-max=");
- children_max = strtoul(pos, NULL, 0);
- }
-
- pos = strstr(cmdline, "udev.exec-delay=");
- if (pos != NULL) {
- pos += strlen("udev.exec-delay=");
- exec_delay = strtoul(pos, NULL, 0);
- }
- }
- fclose(f);
- }
+ kernel_cmdline_options(udev);
if (getuid() != 0) {
fprintf(stderr, "root privileges required\n");
chdir("/");
umask(022);
- /* /run/udev */
- mkdir(udev_get_run_path(udev), 0755);
+ mkdir("/run/udev", 0755);
- /* create standard links, copy static nodes, create nodes from modules */
- static_dev_create_links(udev);
+ dev_setup();
static_dev_create_from_modules(udev);
/* before opening new files, make sure std{in,out,err} fds are in a sane state */
if (daemonize) {
pid_t pid;
- int fd;
pid = fork();
switch (pid) {
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) {
- log_error("error disabling OOM: %m\n");
- } else {
- /* OOM_DISABLE == -17 */
- write(fd, "-17", 3);
- close(fd);
- }
- } else {
- write(fd, "-1000", 5);
- close(fd);
- }
+ write_one_line_file("/proc/self/oom_score_adj", "-1000");
} else {
sd_notify(1, "READY=1");
}
- f = fopen("/dev/kmsg", "w");
- if (f != NULL) {
- fprintf(f, "<30>udevd[%u]: starting version " VERSION "\n", getpid());
- fclose(f);
- }
+ print_kmsg("starting version " VERSION "\n");
if (!debug) {
int fd;
/* set value depending on the amount of RAM */
if (memsize > 0)
- children_max = 128 + (memsize / 8);
+ children_max = 16 + (memsize / 8);
else
- children_max = 128;
+ children_max = 16;
}
log_debug("set children_max to %u\n", children_max);
/* check for changed config, every 3 seconds at most */
if ((now_usec() - last_usec) > 3 * 1000 * 1000) {
- if (check_rules_timestamp(udev))
+ if (udev_rules_check_timestamp(rules))
reload = true;
if (udev_builtin_validate(udev))
reload = true;
udev_queue_export_unref(udev_queue_export);
udev_ctrl_connection_unref(ctrl_conn);
udev_ctrl_unref(udev_ctrl);
- udev_selinux_exit(udev);
+ label_finish();
udev_unref(udev);
log_close();
return rc;