X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fmanager.c;h=da766e6d58e0e1de72030a23c14af20ef451f893;hp=c6baf22ae510bb2401458082de18e5f84c8ce550;hb=877d54e9b09e093c2102f519a84e2a52637ae035;hpb=9eb977db5b89b44f254ab40c1876a76b7d7ea2d0 diff --git a/src/core/manager.c b/src/core/manager.c index c6baf22ae..da766e6d5 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -41,7 +41,9 @@ #include #endif -#include +#include "systemd/sd-daemon.h" +#include "systemd/sd-id128.h" +#include "systemd/sd-messages.h" #include "manager.h" #include "transaction.h" @@ -74,8 +76,7 @@ #define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC) /* Where clients shall send notification messages to */ -#define NOTIFY_SOCKET_SYSTEM "/run/systemd/notify" -#define NOTIFY_SOCKET_USER "@/org/freedesktop/systemd1/notify" +#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify" static int manager_setup_notify(Manager *m) { union { @@ -83,13 +84,13 @@ static int manager_setup_notify(Manager *m) { struct sockaddr_un un; } sa; struct epoll_event ev; - int one = 1, r; - mode_t u; + int one = 1; assert(m); m->notify_watch.type = WATCH_NOTIFY; - if ((m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { + m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->notify_watch.fd < 0) { log_error("Failed to allocate notification socket: %m"); return -errno; } @@ -97,21 +98,14 @@ static int manager_setup_notify(Manager *m) { zero(sa); sa.sa.sa_family = AF_UNIX; - if (getpid() != 1) - snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET_USER "/%llu", random_ull()); - else { - unlink(NOTIFY_SOCKET_SYSTEM); - strncpy(sa.un.sun_path, NOTIFY_SOCKET_SYSTEM, sizeof(sa.un.sun_path)); - } - - if (sa.un.sun_path[0] == '@') - sa.un.sun_path[0] = 0; + if (getpid() != 1 || detect_container(NULL) > 0) + snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%llu", random_ull()); + else + strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path)); - u = umask(0111); - r = bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)); - umask(u); + sa.un.sun_path[0] = 0; - if (r < 0) { + if (bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { log_error("bind() failed: %m"); return -errno; } @@ -128,10 +122,9 @@ static int manager_setup_notify(Manager *m) { if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0) return -errno; - if (sa.un.sun_path[0] == 0) - sa.un.sun_path[0] = '@'; - - if (!(m->notify_socket = strdup(sa.un.sun_path))) + sa.un.sun_path[0] = '@'; + m->notify_socket = strdup(sa.un.sun_path); + if (!m->notify_socket) return -ENOMEM; log_debug("Using notification socket %s", m->notify_socket); @@ -299,9 +292,6 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) { if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) goto fail; - if ((r = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0) - goto fail; - if ((r = manager_setup_signals(m)) < 0) goto fail; @@ -476,6 +466,7 @@ static void manager_clear_jobs_and_units(Manager *m) { void manager_free(Manager *m) { UnitType c; + int i; assert(m); @@ -522,6 +513,12 @@ void manager_free(Manager *m) { close_pipe(m->idle_pipe); + free(m->switch_root); + free(m->switch_root_init); + + for (i = 0; i < RLIMIT_NLIMITS; i++) + free(m->rlimit[i]); + free(m); } @@ -595,7 +592,7 @@ static void manager_build_unit_path_cache(Manager *m) { if (ignore_file(de->d_name)) continue; - p = join(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL); + p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL); if (!p) { r = -ENOMEM; goto fail; @@ -630,6 +627,14 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { manager_run_generators(m); + r = lookup_paths_init( + &m->lookup_paths, m->running_as, true, + m->generator_unit_path, + m->generator_unit_path_early, + m->generator_unit_path_late); + if (r < 0) + return r; + manager_build_unit_path_cache(m); /* If we will deserialize make sure that during enumeration @@ -642,12 +647,15 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { r = manager_enumerate(m); /* Second, deserialize if there is something to deserialize */ - if (serialization) - if ((q = manager_deserialize(m, serialization, fds)) < 0) + if (serialization) { + q = manager_deserialize(m, serialization, fds); + if (q < 0) r = q; + } /* Third, fire things up! */ - if ((q = manager_coldplug(m)) < 0) + q = manager_coldplug(m); + if (q < 0) r = q; if (serialization) { @@ -790,7 +798,7 @@ int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DB t = unit_name_to_type(name); - if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid_no_type(name, false)) { + if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, false)) { dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name); return -EINVAL; } @@ -1487,9 +1495,10 @@ int manager_loop(Manager *m) { return m->exit_code; } -int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) { +int manager_load_unit_from_dbus_path(Manager *m, const char *s, DBusError *e, Unit **_u) { char *n; Unit *u; + int r; assert(m); assert(s); @@ -1498,14 +1507,15 @@ int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) { if (!startswith(s, "/org/freedesktop/systemd1/unit/")) return -EINVAL; - if (!(n = bus_path_unescape(s+31))) + n = bus_path_unescape(s+31); + if (!n) return -ENOMEM; - u = manager_get_unit(m, n); + r = manager_load_unit(m, n, NULL, e, &u); free(n); - if (!u) - return -ENOENT; + if (r < 0) + return r; *_u = u; @@ -1617,7 +1627,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { } if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) { - log_error("Out of memory"); + log_oom(); goto finish; } @@ -1714,7 +1724,7 @@ int manager_open_serialization(Manager *m, FILE **_f) { return 0; } -int manager_serialize(Manager *m, FILE *f, FDSet *fds) { +int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool serialize_jobs) { Iterator i; Unit *u; const char *t; @@ -1728,10 +1738,15 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) { fprintf(f, "current-job-id=%i\n", m->current_job_id); fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr)); + fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs); + fprintf(f, "n-failed-jobs=%u\n", m->n_failed_jobs); dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp); - dual_timestamp_serialize(f, "startup-timestamp", &m->startup_timestamp); - dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp); + + if (!in_initrd()) { + dual_timestamp_serialize(f, "startup-timestamp", &m->startup_timestamp); + dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp); + } fputc('\n', f); @@ -1746,7 +1761,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) { fputs(u->id, f); fputc('\n', f); - if ((r = unit_serialize(u, f, fds)) < 0) { + if ((r = unit_serialize(u, f, fds, serialize_jobs)) < 0) { m->n_reloading --; return r; } @@ -1800,6 +1815,20 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { log_debug("Failed to parse current job id value %s", l+15); else m->current_job_id = MAX(m->current_job_id, id); + } else if (startswith(l, "n-installed-jobs=")) { + uint32_t n; + + if (safe_atou32(l+17, &n) < 0) + log_debug("Failed to parse installed jobs counter %s", l+17); + else + m->n_installed_jobs += n; + } else if (startswith(l, "n-failed-jobs=")) { + uint32_t n; + + if (safe_atou32(l+14, &n) < 0) + log_debug("Failed to parse failed jobs counter %s", l+14); + else + m->n_failed_jobs += n; } else if (startswith(l, "taint-usr=")) { int b; @@ -1859,18 +1888,21 @@ int manager_reload(Manager *m) { assert(m); - if ((r = manager_open_serialization(m, &f)) < 0) + r = manager_open_serialization(m, &f); + if (r < 0) return r; m->n_reloading ++; - if (!(fds = fdset_new())) { + fds = fdset_new(); + if (!fds) { m->n_reloading --; r = -ENOMEM; goto finish; } - if ((r = manager_serialize(m, f, fds)) < 0) { + r = manager_serialize(m, f, fds, true); + if (r < 0) { m->n_reloading --; goto finish; } @@ -1884,29 +1916,37 @@ int manager_reload(Manager *m) { /* From here on there is no way back. */ manager_clear_jobs_and_units(m); manager_undo_generators(m); - - /* Find new unit paths */ lookup_paths_free(&m->lookup_paths); - if ((q = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0) - r = q; + /* Find new unit paths */ manager_run_generators(m); + q = lookup_paths_init( + &m->lookup_paths, m->running_as, true, + m->generator_unit_path, + m->generator_unit_path_early, + m->generator_unit_path_late); + if (q < 0) + r = q; + manager_build_unit_path_cache(m); /* First, enumerate what we can from all config files */ - if ((q = manager_enumerate(m)) < 0) + q = manager_enumerate(m); + if (q < 0) r = q; /* Second, deserialize our stored data */ - if ((q = manager_deserialize(m, f, fds)) < 0) + q = manager_deserialize(m, f, fds); + if (q < 0) r = q; fclose(f); f = NULL; /* Third, fire things up! */ - if ((q = manager_coldplug(m)) < 0) + q = manager_coldplug(m); + if (q < 0) r = q; assert(m->n_reloading > 0); @@ -1974,6 +2014,9 @@ void manager_check_finished(Manager *m) { /* Notify Type=idle units that we are done now */ close_pipe(m->idle_pipe); + /* Turn off confirm spawn now */ + m->confirm_spawn = false; + if (dual_timestamp_is_set(&m->finish_timestamp)) return; @@ -1989,26 +2032,41 @@ void manager_check_finished(Manager *m) { kernel_usec = m->initrd_timestamp.monotonic; initrd_usec = m->startup_timestamp.monotonic - m->initrd_timestamp.monotonic; - log_info("Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.", - format_timespan(kernel, sizeof(kernel), kernel_usec), - format_timespan(initrd, sizeof(initrd), initrd_usec), - format_timespan(userspace, sizeof(userspace), userspace_usec), - format_timespan(sum, sizeof(sum), total_usec)); + log_struct(LOG_INFO, + "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_STARTUP_FINISHED), + "KERNEL_USEC=%llu", (unsigned long long) kernel_usec, + "INITRD_USEC=%llu", (unsigned long long) initrd_usec, + "USERSPACE_USEC=%llu", (unsigned long long) userspace_usec, + "MESSAGE=Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.", + format_timespan(kernel, sizeof(kernel), kernel_usec), + format_timespan(initrd, sizeof(initrd), initrd_usec), + format_timespan(userspace, sizeof(userspace), userspace_usec), + format_timespan(sum, sizeof(sum), total_usec), + NULL); } else { kernel_usec = m->startup_timestamp.monotonic; initrd_usec = 0; - log_info("Startup finished in %s (kernel) + %s (userspace) = %s.", - format_timespan(kernel, sizeof(kernel), kernel_usec), - format_timespan(userspace, sizeof(userspace), userspace_usec), - format_timespan(sum, sizeof(sum), total_usec)); + log_struct(LOG_INFO, + "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_STARTUP_FINISHED), + "KERNEL_USEC=%llu", (unsigned long long) kernel_usec, + "USERSPACE_USEC=%llu", (unsigned long long) userspace_usec, + "MESSAGE=Startup finished in %s (kernel) + %s (userspace) = %s.", + format_timespan(kernel, sizeof(kernel), kernel_usec), + format_timespan(userspace, sizeof(userspace), userspace_usec), + format_timespan(sum, sizeof(sum), total_usec), + NULL); } } else { - userspace_usec = initrd_usec = kernel_usec = 0; - total_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic; - - log_debug("Startup finished in %s.", - format_timespan(sum, sizeof(sum), total_usec)); + initrd_usec = kernel_usec = 0; + total_usec = userspace_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic; + + log_struct(LOG_INFO, + "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(SD_MESSAGE_STARTUP_FINISHED), + "USERSPACE_USEC=%llu", (unsigned long long) userspace_usec, + "MESSAGE=Startup finished in %s.", + format_timespan(sum, sizeof(sum), total_usec), + NULL); } bus_broadcast_finished(m, kernel_usec, initrd_usec, userspace_usec, total_usec); @@ -2018,17 +2076,72 @@ void manager_check_finished(Manager *m) { format_timespan(sum, sizeof(sum), total_usec)); } +static int create_generator_dir(Manager *m, char **generator, const char *name) { + char *p; + int r; + + assert(m); + assert(generator); + assert(name); + + if (*generator) + return 0; + + if (m->running_as == MANAGER_SYSTEM && getpid() == 1) { + + p = strappend("/run/systemd/", name); + if (!p) + return log_oom(); + + r = mkdir_p_label(p, 0755); + if (r < 0) { + log_error("Failed to create generator directory: %s", strerror(-r)); + free(p); + return r; + } + } else { + p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL); + if (!p) + return log_oom(); + + if (!mkdtemp(p)) { + free(p); + log_error("Failed to create generator directory: %m"); + return -errno; + } + } + + *generator = p; + return 0; +} + +static void trim_generator_dir(Manager *m, char **generator) { + assert(m); + assert(generator); + + if (!*generator) + return; + + if (rmdir(*generator) >= 0) { + free(*generator); + *generator = NULL; + } + + return; +} + void manager_run_generators(Manager *m) { DIR *d = NULL; const char *generator_path; - const char *argv[3]; + const char *argv[5]; mode_t u; + int r; assert(m); generator_path = m->running_as == MANAGER_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH; - if (!(d = opendir(generator_path))) { - + d = opendir(generator_path); + if (!d) { if (errno == ENOENT) return; @@ -2036,79 +2149,57 @@ void manager_run_generators(Manager *m) { return; } - if (!m->generator_unit_path) { - const char *p; - char user_path[] = "/tmp/systemd-generator-XXXXXX"; - - if (m->running_as == MANAGER_SYSTEM && getpid() == 1) { - p = "/run/systemd/generator"; - - if (mkdir_p(p, 0755) < 0) { - log_error("Failed to create generator directory: %m"); - goto finish; - } + r = create_generator_dir(m, &m->generator_unit_path, "generator"); + if (r < 0) + goto finish; - } else { - if (!(p = mkdtemp(user_path))) { - log_error("Failed to create generator directory: %m"); - goto finish; - } - } + r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early"); + if (r < 0) + goto finish; - if (!(m->generator_unit_path = strdup(p))) { - log_error("Failed to allocate generator unit path."); - goto finish; - } - } + r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late"); + if (r < 0) + goto finish; argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */ argv[1] = m->generator_unit_path; - argv[2] = NULL; + argv[2] = m->generator_unit_path_early; + argv[3] = m->generator_unit_path_late; + argv[4] = NULL; u = umask(0022); execute_directory(generator_path, d, (char**) argv); umask(u); - if (rmdir(m->generator_unit_path) >= 0) { - /* Uh? we were able to remove this dir? I guess that - * means the directory was empty, hence let's shortcut - * this */ - - free(m->generator_unit_path); - m->generator_unit_path = NULL; - goto finish; - } - - if (!strv_find(m->lookup_paths.unit_path, m->generator_unit_path)) { - char **l; - - if (!(l = strv_append(m->lookup_paths.unit_path, m->generator_unit_path))) { - log_error("Failed to add generator directory to unit search path: %m"); - goto finish; - } - - strv_free(m->lookup_paths.unit_path); - m->lookup_paths.unit_path = l; - - log_debug("Added generator unit path %s to search path.", m->generator_unit_path); - } + trim_generator_dir(m, &m->generator_unit_path); + trim_generator_dir(m, &m->generator_unit_path_early); + trim_generator_dir(m, &m->generator_unit_path_late); finish: if (d) closedir(d); } -void manager_undo_generators(Manager *m) { +static void remove_generator_dir(Manager *m, char **generator) { assert(m); + assert(generator); - if (!m->generator_unit_path) + if (!*generator) return; - strv_remove(m->lookup_paths.unit_path, m->generator_unit_path); - rm_rf(m->generator_unit_path, false, true, false); + strv_remove(m->lookup_paths.unit_path, *generator); + rm_rf(*generator, false, true, false); + + free(*generator); + *generator = NULL; +} + +void manager_undo_generators(Manager *m) { + assert(m); - free(m->generator_unit_path); - m->generator_unit_path = NULL; + remove_generator_dir(m, &m->generator_unit_path); + remove_generator_dir(m, &m->generator_unit_path_early); + remove_generator_dir(m, &m->generator_unit_path_late); } int manager_set_default_controllers(Manager *m, char **controllers) { @@ -2128,6 +2219,23 @@ int manager_set_default_controllers(Manager *m, char **controllers) { return 0; } +int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) { + int i; + + assert(m); + + for (i = 0; i < RLIMIT_NLIMITS; i++) { + if (!default_rlimit[i]) + continue; + + m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1); + if (!m->rlimit[i]) + return -ENOMEM; + } + + return 0; +} + void manager_recheck_journal(Manager *m) { Unit *u;