X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fmanager.c;h=f8cbcfcc98ff8fa7faf1f25dadf1ec7fa908e5f5;hp=df75eca8c48d6167bcc468b33d3662c7309d93d1;hb=1e2579fdeb7608719cb28da0b5061f48ba0efc34;hpb=e03ae6615a1fe9a2aee854d00c3fc7397a06983d diff --git a/src/manager.c b/src/manager.c index df75eca8c..f8cbcfcc9 100644 --- a/src/manager.c +++ b/src/manager.c @@ -58,6 +58,8 @@ #include "special.h" #include "bus-errors.h" #include "exit-status.h" +#include "sd-daemon.h" +#include "virt.h" /* As soon as 16 units are in our GC queue, make sure to run a gc sweep */ #define GC_QUEUE_ENTRIES_MAX 16 @@ -66,7 +68,7 @@ #define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC) /* Where clients shall send notification messages to */ -#define NOTIFY_SOCKET_SYSTEM "/dev/.run/systemd/notify" +#define NOTIFY_SOCKET_SYSTEM "/run/systemd/notify" #define NOTIFY_SOCKET_USER "@/org/freedesktop/systemd1/notify" static int manager_setup_notify(Manager *m) { @@ -75,7 +77,8 @@ static int manager_setup_notify(Manager *m) { struct sockaddr_un un; } sa; struct epoll_event ev; - int one = 1; + int one = 1, r; + mode_t u; assert(m); @@ -98,7 +101,11 @@ static int manager_setup_notify(Manager *m) { if (sa.un.sun_path[0] == '@') sa.un.sun_path[0] = 0; - if (bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { + 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); + + if (r < 0) { log_error("bind() failed: %m"); return -errno; } @@ -127,7 +134,7 @@ static int manager_setup_notify(Manager *m) { } static int enable_special_signals(Manager *m) { - char fd; + int fd; assert(m); @@ -135,7 +142,7 @@ static int enable_special_signals(Manager *m) { if (reboot(RB_DISABLE_CAD) < 0) log_warning("Failed to enable ctrl-alt-del handling: %m"); - if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY)) < 0) + if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) log_warning("Failed to open /dev/tty0: %m"); else { /* Enable that we get SIGWINCH on kbrequest */ @@ -185,6 +192,11 @@ static int manager_setup_signals(Manager *m) { SIGRTMIN+16, /* systemd: Immediate kexec */ SIGRTMIN+20, /* systemd: enable status messages */ SIGRTMIN+21, /* systemd: disable status messages */ + SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */ + SIGRTMIN+23, /* systemd: set log level to LOG_INFO */ + SIGRTMIN+27, /* systemd: set log target to console */ + SIGRTMIN+28, /* systemd: set log target to kmsg */ + SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg */ -1); assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); @@ -257,7 +269,7 @@ 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)) < 0) + if ((r = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0) goto fail; if ((r = manager_setup_signals(m)) < 0) @@ -274,10 +286,15 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) { goto fail; #ifdef HAVE_AUDIT - if ((m->audit_fd = audit_open()) < 0) + if ((m->audit_fd = audit_open()) < 0 && + /* If the kernel lacks netlink or audit support, + * don't worry about it. */ + errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT) log_error("Failed to connect to audit log: %m"); #endif + m->taint_usr = dir_is_empty("/usr") > 0; + *_m = m; return 0; @@ -552,7 +569,8 @@ static void manager_build_unit_path_cache(Manager *m) { if (ignore_file(de->d_name)) continue; - if (asprintf(&p, "%s/%s", streq(*i, "/") ? "" : *i, de->d_name) < 0) { + p = join(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL); + if (!p) { r = -ENOMEM; goto fail; } @@ -592,7 +610,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { * this is already known, so we increase the counter here * already */ if (serialization) - m->n_deserializing ++; + m->n_reloading ++; /* First, enumerate what we can from all config files */ r = manager_enumerate(m); @@ -607,8 +625,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { r = q; if (serialization) { - assert(m->n_deserializing > 0); - m->n_deserializing --; + assert(m->n_reloading > 0); + m->n_reloading --; } return r; @@ -894,6 +912,9 @@ static int transaction_merge_jobs(Manager *m, DBusError *e) { transaction_merge_and_delete_job(m, j, k, t); } + if (j->unit->meta.job && !j->installed) + transaction_merge_and_delete_job(m, j, j->unit->meta.job, t); + assert(!j->transaction_next); assert(!j->transaction_prev); } @@ -1165,13 +1186,13 @@ static void transaction_minimize_impact(Manager *m) { continue; if (stops_running_service) - log_info("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type)); + log_debug("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type)); if (changes_existing_job) - log_info("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type)); + log_debug("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type)); /* Ok, let's get rid of this */ - log_info("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type)); + log_debug("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type)); transaction_delete_job(m, j, true); again = true; @@ -1185,13 +1206,32 @@ static void transaction_minimize_impact(Manager *m) { } while (again); } -static int transaction_apply(Manager *m) { +static int transaction_apply(Manager *m, JobMode mode) { Iterator i; Job *j; int r; /* Moves the transaction jobs to the set of active jobs */ + if (mode == JOB_ISOLATE) { + + /* When isolating first kill all installed jobs which + * aren't part of the new transaction */ + rescan: + HASHMAP_FOREACH(j, m->jobs, i) { + assert(j->installed); + + if (hashmap_get(m->transaction_jobs, j->unit)) + continue; + + /* 'j' itself is safe to remove, but if other jobs + are invalidated recursively, our iterator may become + invalid and we need to start over. */ + if (job_finish_and_invalidate(j, JOB_CANCELED) > 0) + goto rescan; + } + } + HASHMAP_FOREACH(j, m->transaction_jobs, i) { /* Assume merged */ assert(!j->transaction_prev); @@ -1271,7 +1311,8 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) { for (;;) { /* Fourth step: Let's remove unneeded jobs that might * be lurking. */ - transaction_collect_garbage(m); + if (mode != JOB_ISOLATE) + transaction_collect_garbage(m); /* Fifth step: verify order makes sense and correct * cycles if necessary and possible */ @@ -1301,7 +1342,8 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) { /* Seventh step: an entry got dropped, let's garbage * collect its dependencies. */ - transaction_collect_garbage(m); + if (mode != JOB_ISOLATE) + transaction_collect_garbage(m); /* Let's see if the resulting transaction still has * unmergeable entries ... */ @@ -1318,7 +1360,7 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) { } /* Tenth step: apply changes */ - if ((r = transaction_apply(m)) < 0) { + if ((r = transaction_apply(m, mode)) < 0) { log_warning("Failed to apply transaction: %s", strerror(-r)); goto rollback; } @@ -1421,7 +1463,8 @@ static int transaction_add_job_and_dependencies( bool matters, bool override, bool conflicts, - bool ignore_deps, + bool ignore_requirements, + bool ignore_order, DBusError *e, Job **_ret) { Job *ret; @@ -1449,9 +1492,10 @@ static int transaction_add_job_and_dependencies( if (type != JOB_STOP && unit->meta.load_state == UNIT_ERROR) { dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s failed to load: %s. " - "See system logs and 'systemctl status' for details.", + "See system logs and 'systemctl status %s' for details.", unit->meta.id, - strerror(-unit->meta.load_error)); + strerror(-unit->meta.load_error), + unit->meta.id); return -EINVAL; } @@ -1469,20 +1513,20 @@ static int transaction_add_job_and_dependencies( if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new))) return -ENOMEM; - ret->ignore_deps = ret->ignore_deps || ignore_deps; + ret->ignore_order = ret->ignore_order || ignore_order; /* Then, add a link to the job. */ if (!job_dependency_new(by, ret, matters, conflicts)) return -ENOMEM; - if (is_new && !ignore_deps) { + if (is_new && !ignore_requirements) { Set *following; /* If we are following some other unit, make sure we * add all dependencies of everybody following. */ if (unit_following_set(ret->unit, &following) > 0) { SET_FOREACH(dep, following, i) - if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) { log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); if (e) @@ -1495,7 +1539,7 @@ static int transaction_add_job_and_dependencies( /* Finally, recursively add in all dependencies. */ if (type == JOB_START || type == JOB_RELOAD_OR_START) { SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { if (r != -EBADR) goto fail; @@ -1504,7 +1548,7 @@ static int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BIND_TO], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { if (r != -EBADR) goto fail; @@ -1514,7 +1558,7 @@ static int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) { log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); if (e) @@ -1522,7 +1566,7 @@ static int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL)) < 0) { log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); if (e) @@ -1530,7 +1574,7 @@ static int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { if (r != -EBADR) goto fail; @@ -1540,7 +1584,7 @@ static int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) { log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); if (e) @@ -1548,7 +1592,7 @@ static int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL)) < 0) { if (r != -EBADR) goto fail; @@ -1558,7 +1602,7 @@ static int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTED_BY], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) { log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); if (e) @@ -1568,7 +1612,7 @@ static int transaction_add_job_and_dependencies( } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) { SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i) - if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { if (r != -EBADR) goto fail; @@ -1578,7 +1622,7 @@ static int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BOUND_BY], i) - if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) { if (r != -EBADR) goto fail; @@ -1614,7 +1658,7 @@ static int transaction_add_isolate_jobs(Manager *m) { if (u->meta.id != k) continue; - if (UNIT_VTABLE(u)->no_isolate) + if (u->meta.ignore_on_isolate) continue; /* No need to stop inactive jobs */ @@ -1625,7 +1669,7 @@ static int transaction_add_isolate_jobs(Manager *m) { if (hashmap_get(m->transaction_jobs, u)) continue; - if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, false, false, NULL, NULL)) < 0) + if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, false, false, false, NULL, NULL)) < 0) log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->meta.id, strerror(-r)); } @@ -1653,7 +1697,9 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove log_debug("Trying to enqueue job %s/%s/%s", unit->meta.id, job_type_to_string(type), job_mode_to_string(mode)); - if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false, mode == JOB_IGNORE_DEPENDENCIES, e, &ret)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false, + mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS, + mode == JOB_IGNORE_DEPENDENCIES, e, &ret)) < 0) { transaction_abort(m); return r; } @@ -1986,7 +2032,7 @@ static int manager_dispatch_sigchld(Manager *m) { if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) { char *name = NULL; - get_process_name(si.si_pid, &name); + get_process_comm(si.si_pid, &name); log_debug("Got SIGCHLD for process %lu (%s)", (unsigned long) si.si_pid, strna(name)); free(name); } @@ -2057,8 +2103,6 @@ static int manager_process_signal_fd(Manager *m) { assert(m); for (;;) { - char *p = NULL; - if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) { if (n >= 0) @@ -2070,11 +2114,17 @@ static int manager_process_signal_fd(Manager *m) { return -errno; } - get_process_name(sfsi.ssi_pid, &p); - log_debug("Received SIG%s from PID %lu (%s)", - strna(signal_to_string(sfsi.ssi_signo)), - (unsigned long) sfsi.ssi_pid, strna(p)); - free(p); + if (sfsi.ssi_pid > 0) { + char *p = NULL; + + get_process_comm(sfsi.ssi_pid, &p); + + log_debug("Received SIG%s from PID %lu (%s).", + signal_to_string(sfsi.ssi_signo), + (unsigned long) sfsi.ssi_pid, strna(p)); + free(p); + } else + log_debug("Received SIG%s.", signal_to_string(sfsi.ssi_signo)); switch (sfsi.ssi_signo) { @@ -2170,6 +2220,7 @@ static int manager_process_signal_fd(Manager *m) { break; default: { + /* Starting SIGRTMIN+0 */ static const char * const target_table[] = { [0] = SPECIAL_DEFAULT_TARGET, @@ -2191,8 +2242,9 @@ static int manager_process_signal_fd(Manager *m) { if ((int) sfsi.ssi_signo >= SIGRTMIN+0 && (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) { - manager_start_target(m, target_table[sfsi.ssi_signo - SIGRTMIN], - (sfsi.ssi_signo == 1 || sfsi.ssi_signo == 2) ? JOB_ISOLATE : JOB_REPLACE); + int idx = (int) sfsi.ssi_signo - SIGRTMIN; + manager_start_target(m, target_table[idx], + (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE); break; } @@ -2206,16 +2258,41 @@ static int manager_process_signal_fd(Manager *m) { case 20: log_debug("Enabling showing of status."); - m->show_status = true; + manager_set_show_status(m, true); break; case 21: log_debug("Disabling showing of status."); - m->show_status = false; + manager_set_show_status(m, false); + break; + + case 22: + log_set_max_level(LOG_DEBUG); + log_notice("Setting log level to debug."); + break; + + case 23: + log_set_max_level(LOG_INFO); + log_notice("Setting log level to info."); + break; + + case 27: + log_set_target(LOG_TARGET_CONSOLE); + log_notice("Setting log target to console."); + break; + + case 28: + log_set_target(LOG_TARGET_KMSG); + log_notice("Setting log target to kmsg."); + break; + + case 29: + log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); + log_notice("Setting log target to syslog-or-kmsg."); break; default: - log_warning("Got unhandled signal <%s>.", strna(signal_to_string(sfsi.ssi_signo))); + log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo)); } } } @@ -2234,7 +2311,7 @@ static int process_event(Manager *m, struct epoll_event *ev) { assert(m); assert(ev); - assert(w = ev->data.ptr); + assert_se(w = ev->data.ptr); if (w->type == WATCH_INVALID) return 0; @@ -2324,7 +2401,7 @@ static int process_event(Manager *m, struct epoll_event *ev) { int manager_loop(Manager *m) { int r; - RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 1000); + RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000); assert(m); m->exit_code = MANAGER_RUNNING; @@ -2446,7 +2523,13 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { /* Don't generate audit events if the service was already * started and we're just deserializing */ - if (m->n_deserializing > 0) + if (m->n_reloading > 0) + return; + + if (m->running_as != MANAGER_SYSTEM) + return; + + if (u->meta.type != UNIT_SERVICE) return; if (!(p = unit_name_to_prefix_and_instance(u->meta.id))) { @@ -2481,7 +2564,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { /* Don't generate plymouth events if the service was already * started and we're just deserializing */ - if (m->n_deserializing > 0) + if (m->n_reloading > 0) return; if (m->running_as != MANAGER_SYSTEM) @@ -2584,7 +2667,7 @@ int manager_open_serialization(Manager *m, FILE **_f) { assert(_f); if (m->running_as == MANAGER_SYSTEM) - asprintf(&path, "/dev/.run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid()); + asprintf(&path, "/run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid()); else asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid()); @@ -2605,7 +2688,7 @@ int manager_open_serialization(Manager *m, FILE **_f) { log_debug("Serializing state to %s", path); free(path); - if (!(f = fdopen(fd, "w+")) < 0) + if (!(f = fdopen(fd, "w+"))) return -errno; *_f = f; @@ -2623,6 +2706,11 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) { assert(f); assert(fds); + m->n_reloading ++; + + fprintf(f, "current-job-id=%i\n", m->current_job_id); + fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr)); + 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); @@ -2640,13 +2728,22 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) { fputs(u->meta.id, f); fputc('\n', f); - if ((r = unit_serialize(u, f, fds)) < 0) + if ((r = unit_serialize(u, f, fds)) < 0) { + m->n_reloading --; return r; + } } + assert(m->n_reloading > 0); + m->n_reloading --; + if (ferror(f)) return -EIO; + r = bus_fdset_add_all(m, fds); + if (r < 0) + return r; + return 0; } @@ -2658,10 +2755,10 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { log_debug("Deserializing state..."); - m->n_deserializing ++; + m->n_reloading ++; for (;;) { - char line[1024], *l; + char line[LINE_MAX], *l; if (!fgets(line, sizeof(line), f)) { if (feof(f)) @@ -2678,7 +2775,21 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { if (l[0] == 0) break; - if (startswith(l, "initrd-timestamp=")) + if (startswith(l, "current-job-id=")) { + uint32_t id; + + if (safe_atou32(l+15, &id) < 0) + 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, "taint-usr=")) { + int b; + + if ((b = parse_boolean(l+10)) < 0) + log_debug("Failed to parse taint /usr flag %s", l+10); + else + m->taint_usr = m->taint_usr || b; + } else if (startswith(l, "initrd-timestamp=")) dual_timestamp_deserialize(l+17, &m->initrd_timestamp); else if (startswith(l, "startup-timestamp=")) dual_timestamp_deserialize(l+18, &m->startup_timestamp); @@ -2717,8 +2828,8 @@ finish: goto finish; } - assert(m->n_deserializing > 0); - m->n_deserializing --; + assert(m->n_reloading > 0); + m->n_reloading --; return r; } @@ -2733,15 +2844,21 @@ int manager_reload(Manager *m) { if ((r = manager_open_serialization(m, &f)) < 0) return r; + m->n_reloading ++; + if (!(fds = fdset_new())) { + m->n_reloading --; r = -ENOMEM; goto finish; } - if ((r = manager_serialize(m, f, fds)) < 0) + if ((r = manager_serialize(m, f, fds)) < 0) { + m->n_reloading --; goto finish; + } if (fseeko(f, 0, SEEK_SET) < 0) { + m->n_reloading --; r = -errno; goto finish; } @@ -2752,15 +2869,13 @@ int manager_reload(Manager *m) { /* Find new unit paths */ lookup_paths_free(&m->lookup_paths); - if ((q = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0) + if ((q = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0) r = q; manager_run_generators(m); manager_build_unit_path_cache(m); - m->n_deserializing ++; - /* First, enumerate what we can from all config files */ if ((q = manager_enumerate(m)) < 0) r = q; @@ -2776,8 +2891,8 @@ int manager_reload(Manager *m) { if ((q = manager_coldplug(m)) < 0) r = q; - assert(m->n_deserializing > 0); - m->n_deserializing ++; + assert(m->n_reloading > 0); + m->n_reloading--; finish: if (f) @@ -2799,7 +2914,8 @@ bool manager_is_booting_or_shutting_down(Manager *m) { return true; /* Is there a job for the shutdown target? */ - if (((u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET)))) + u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET); + if (u) return !!u->meta.job; return false; @@ -2830,6 +2946,7 @@ bool manager_unit_pending_inactive(Manager *m, const char *name) { void manager_check_finished(Manager *m) { char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX]; + usec_t kernel_usec = 0, initrd_usec = 0, userspace_usec = 0, total_usec = 0; assert(m); @@ -2843,35 +2960,48 @@ void manager_check_finished(Manager *m) { if (m->running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0) { + userspace_usec = m->finish_timestamp.monotonic - m->startup_timestamp.monotonic; + total_usec = m->finish_timestamp.monotonic; + if (dual_timestamp_is_set(&m->initrd_timestamp)) { + + 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), - m->initrd_timestamp.monotonic), - format_timespan(initrd, sizeof(initrd), - m->startup_timestamp.monotonic - m->initrd_timestamp.monotonic), - format_timespan(userspace, sizeof(userspace), - m->finish_timestamp.monotonic - m->startup_timestamp.monotonic), - format_timespan(sum, sizeof(sum), - m->finish_timestamp.monotonic)); - } else + 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)); + } 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), - m->startup_timestamp.monotonic), - format_timespan(userspace, sizeof(userspace), - m->finish_timestamp.monotonic - m->startup_timestamp.monotonic), - format_timespan(sum, sizeof(sum), - m->finish_timestamp.monotonic)); - } else + format_timespan(kernel, sizeof(kernel), kernel_usec), + format_timespan(userspace, sizeof(userspace), userspace_usec), + format_timespan(sum, sizeof(sum), total_usec)); + } + } 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(userspace, sizeof(userspace), - m->finish_timestamp.monotonic - m->startup_timestamp.monotonic)); + format_timespan(sum, sizeof(sum), total_usec)); + } + + bus_broadcast_finished(m, kernel_usec, initrd_usec, userspace_usec, total_usec); + sd_notifyf(false, + "READY=1\nSTATUS=Startup finished in %s.", + format_timespan(sum, sizeof(sum), total_usec)); } void manager_run_generators(Manager *m) { DIR *d = NULL; const char *generator_path; const char *argv[3]; + mode_t u; assert(m); @@ -2886,13 +3016,22 @@ void manager_run_generators(Manager *m) { } if (!m->generator_unit_path) { - char *p; - char system_path[] = "/dev/.run/systemd/generator-XXXXXX", - user_path[] = "/tmp/systemd-generator-XXXXXX"; + const char *p; + char user_path[] = "/tmp/systemd-generator-XXXXXX"; - if (!(p = mkdtemp(m->running_as == MANAGER_SYSTEM ? system_path : user_path))) { - log_error("Failed to generate generator directory: %m"); - goto finish; + 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; + } + + } else { + if (!(p = mkdtemp(user_path))) { + log_error("Failed to create generator directory: %m"); + goto finish; + } } if (!(m->generator_unit_path = strdup(p))) { @@ -2905,7 +3044,9 @@ void manager_run_generators(Manager *m) { argv[1] = m->generator_unit_path; argv[2] = 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 @@ -2943,7 +3084,7 @@ void manager_undo_generators(Manager *m) { return; strv_remove(m->lookup_paths.unit_path, m->generator_unit_path); - rm_rf(m->generator_unit_path, false, true); + rm_rf(m->generator_unit_path, false, true, false); free(m->generator_unit_path); m->generator_unit_path = NULL; @@ -2963,6 +3104,76 @@ int manager_set_default_controllers(Manager *m, char **controllers) { return 0; } +void manager_recheck_syslog(Manager *m) { + Unit *u; + + assert(m); + + if (m->running_as != MANAGER_SYSTEM) + return; + + if ((u = manager_get_unit(m, SPECIAL_SYSLOG_SOCKET))) { + SocketState state; + + state = SOCKET(u)->state; + + if (state != SOCKET_DEAD && + state != SOCKET_FAILED && + state != SOCKET_RUNNING) { + + /* Hmm, the socket is not set up, or is still + * listening, let's better not try to use + * it. Note that we have no problem if the + * socket is completely down, since there + * might be a foreign /dev/log socket around + * and we want to make use of that. + */ + + log_close_syslog(); + return; + } + } + + if ((u = manager_get_unit(m, SPECIAL_SYSLOG_TARGET))) + if (TARGET(u)->state != TARGET_ACTIVE) { + log_close_syslog(); + return; + } + + /* Hmm, OK, so the socket is either fully up, or fully down, + * and the target is up, then let's make use of the socket */ + log_open(); +} + +void manager_set_show_status(Manager *m, bool b) { + assert(m); + + if (m->running_as != MANAGER_SYSTEM) + return; + + m->show_status = b; + + if (b) + touch("/run/systemd/show-status"); + else + unlink("/run/systemd/show-status"); +} + +bool manager_get_show_status(Manager *m) { + assert(m); + + if (m->running_as != MANAGER_SYSTEM) + return false; + + if (m->show_status) + return true; + + /* If Plymouth is running make sure we show the status, so + * that there's something nice to see when people press Esc */ + + return plymouth_running(); +} + static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = { [MANAGER_SYSTEM] = "system", [MANAGER_USER] = "user"