X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fmanager.c;h=c0cc1b3f37d1889f30162d02ff6d1f4a1dfd8873;hp=f070295d881274b2ee29aeecf3970148a593d028;hb=33c5fae93976505df343b842727f93910ad510c6;hpb=75778e21dfeee51036d24501e39ea7398fabe502 diff --git a/src/core/manager.c b/src/core/manager.c index f070295d8..c0cc1b3f3 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -65,6 +65,7 @@ #include "virt.h" #include "watchdog.h" #include "cgroup-util.h" +#include "path-util.h" /* As soon as 16 units are in our GC queue, make sure to run a gc sweep */ #define GC_QUEUE_ENTRIES_MAX 16 @@ -259,6 +260,7 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) { m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1; m->exit_code = _MANAGER_EXIT_CODE_INVALID; m->pin_cgroupfs_fd = -1; + m->idle_pipe[0] = m->idle_pipe[1] = -1; #ifdef HAVE_AUDIT m->audit_fd = -1; @@ -297,9 +299,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; @@ -474,6 +473,7 @@ static void manager_clear_jobs_and_units(Manager *m) { void manager_free(Manager *m) { UnitType c; + int i; assert(m); @@ -518,6 +518,14 @@ void manager_free(Manager *m) { hashmap_free(m->cgroup_bondings); set_free_free(m->unit_path_cache); + 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); } @@ -626,6 +634,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 @@ -638,12 +654,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) { @@ -656,7 +675,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) { int r; - Job *ret; Transaction *tr; assert(m); @@ -676,13 +694,15 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove log_debug("Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode)); + job_type_collapse(&type, unit); + tr = transaction_new(); if (!tr) return -ENOMEM; r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false, mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS, - mode == JOB_IGNORE_DEPENDENCIES, e, &ret); + mode == JOB_IGNORE_DEPENDENCIES, e); if (r < 0) goto tr_abort; @@ -696,10 +716,10 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove if (r < 0) goto tr_abort; - log_debug("Enqueued job %s/%s as %u", unit->id, job_type_to_string(type), (unsigned) ret->id); + log_debug("Enqueued job %s/%s as %u", unit->id, job_type_to_string(type), (unsigned) tr->anchor_job->id); if (_ret) - *_ret = ret; + *_ret = tr->anchor_job; transaction_free(tr); return 0; @@ -781,7 +801,7 @@ int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DB } if (!name) - name = file_name_from_path(path); + name = path_get_file_name(path); t = unit_name_to_type(name); @@ -872,7 +892,8 @@ void manager_clear_jobs(Manager *m) { assert(m); while ((j = hashmap_first(m->jobs))) - job_finish_and_invalidate(j, JOB_CANCELED); + /* No need to recurse. We're cancelling all jobs. */ + job_finish_and_invalidate(j, JOB_CANCELED, false); } unsigned manager_dispatch_run_queue(Manager *m) { @@ -1481,9 +1502,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); @@ -1492,14 +1514,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; @@ -1722,10 +1745,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); @@ -1794,6 +1822,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; @@ -1853,18 +1895,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); + if (r < 0) { m->n_reloading --; goto finish; } @@ -1878,29 +1923,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); @@ -1962,10 +2015,16 @@ void manager_check_finished(Manager *m) { assert(m); - if (dual_timestamp_is_set(&m->finish_timestamp)) + if (hashmap_size(m->jobs) > 0) return; - if (hashmap_size(m->jobs) > 0) + /* 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; dual_timestamp_get(&m->finish_timestamp); @@ -2009,17 +2068,76 @@ 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) { + log_error("Out of memory"); + return -ENOMEM; + } + + 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 = join("/tmp/systemd-", name, ".XXXXXX", NULL); + if (!p) { + log_error("Out of memory"); + return -ENOMEM; + } + + 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; @@ -2027,79 +2145,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(m->generator_unit_path); - m->generator_unit_path = NULL; + free(*generator); + *generator = NULL; +} + +void manager_undo_generators(Manager *m) { + assert(m); + + 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) { @@ -2119,6 +2215,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;