X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fmanager.c;h=e4d03681ab089a06a0d278c90ae8c7aef5927ac4;hp=c0bcc79f00a72c6962d4ba1044fcb0da245390a7;hb=517d56b1d0f67dcf76710bc1e17b05518b8cabe6;hpb=a911bb9ab27ac0eb3bbf4e8b4109e5da9b88eee3 diff --git a/src/core/manager.c b/src/core/manager.c index c0bcc79f0..e4d03681a 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -105,7 +105,7 @@ static int manager_watch_jobs_in_progress(Manager *m) { return 0; next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC; - return sd_event_add_monotonic(m->event, next, 0, manager_dispatch_jobs_in_progress, m, &m->jobs_in_progress_event_source); + return sd_event_add_monotonic(m->event, &m->jobs_in_progress_event_source, next, 0, manager_dispatch_jobs_in_progress, m); } #define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1)) @@ -209,7 +209,7 @@ static int manager_watch_idle_pipe(Manager *m) { if (m->idle_pipe[2] < 0) return 0; - r = sd_event_add_io(m->event, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m, &m->idle_pipe_event_source); + r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m); if (r < 0) { log_error("Failed to watch idle pipe: %s", strerror(-r)); return r; @@ -253,7 +253,7 @@ static int manager_setup_time_change(Manager *m) { return 0; } - r = sd_event_add_io(m->event, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m, &m->time_change_event_source); + r = sd_event_add_io(m->event, &m->time_change_event_source, m->time_change_fd, EPOLLIN, manager_dispatch_time_change_fd, m); if (r < 0) { log_error("Failed to create time change event source: %s", strerror(-r)); return r; @@ -340,7 +340,7 @@ static int manager_setup_signals(Manager *m) { if (m->signal_fd < 0) return -errno; - r = sd_event_add_io(m->event, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m, &m->signal_event_source); + r = sd_event_add_io(m->event, &m->signal_event_source, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m); if (r < 0) return r; @@ -447,10 +447,6 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) { if (r < 0) goto fail; - r = hashmap_ensure_allocated(&m->watch_pids, trivial_hash_func, trivial_compare_func); - if (r < 0) - goto fail; - r = hashmap_ensure_allocated(&m->watch_bus, string_hash_func, string_compare_func); if (r < 0) goto fail; @@ -459,7 +455,7 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) { if (r < 0) goto fail; - r = sd_event_add_defer(m->event, manager_dispatch_run_queue, m, &m->run_queue_event_source); + r = sd_event_add_defer(m->event, &m->run_queue_event_source, manager_dispatch_run_queue, m); if (r < 0) goto fail; @@ -556,7 +552,7 @@ static int manager_setup_notify(Manager *m) { } if (!m->notify_event_source) { - r = sd_event_add_io(m->event, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m, &m->notify_event_source); + r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m); if (r < 0) { log_error("Failed to allocate notify event source: %s", strerror(-r)); return -errno; @@ -778,7 +774,8 @@ void manager_free(Manager *m) { hashmap_free(m->units); hashmap_free(m->jobs); - hashmap_free(m->watch_pids); + hashmap_free(m->watch_pids1); + hashmap_free(m->watch_pids2); hashmap_free(m->watch_bus); sd_event_source_unref(m->signal_event_source); @@ -813,7 +810,7 @@ void manager_free(Manager *m) { free(m->switch_root); free(m->switch_root_init); - for (i = 0; i < RLIMIT_NLIMITS; i++) + for (i = 0; i < _RLIMIT_MAX; i++) free(m->rlimit[i]); assert(hashmap_isempty(m->units_requiring_mounts_for)); @@ -842,7 +839,7 @@ int manager_enumerate(Manager *m) { } static int manager_coldplug(Manager *m) { - int r = 0, q; + int r = 0; Iterator i; Unit *u; char *k; @@ -851,12 +848,14 @@ static int manager_coldplug(Manager *m) { /* Then, let's set up their initial state. */ HASHMAP_FOREACH_KEY(u, k, m->units, i) { + int q; /* ignore aliases */ if (u->id != k) continue; - if ((q = unit_coldplug(u)) < 0) + q = unit_coldplug(u); + if (q < 0) r = q; } @@ -999,6 +998,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { * didn't, then let's create the bus now. */ manager_setup_kdbus(m); manager_connect_bus(m, !!serialization); + bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed); /* Third, fire things up! */ q = manager_coldplug(m); @@ -1319,6 +1319,26 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { return n; } +static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n) { + _cleanup_strv_free_ char **tags = NULL; + + assert(m); + assert(u); + assert(buf); + assert(n > 0); + + tags = strv_split(buf, "\n\r"); + if (!tags) { + log_oom(); + return; + } + + log_debug_unit(u->id, "Got notification message for unit %s", u->id); + + if (UNIT_VTABLE(u)->notify_message) + UNIT_VTABLE(u)->notify_message(u, pid, tags); +} + static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { Manager *m = userdata; ssize_t n; @@ -1337,6 +1357,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t .iov_base = buf, .iov_len = sizeof(buf)-1, }; + bool found = false; union { struct cmsghdr cmsghdr; @@ -1351,7 +1372,6 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t }; struct ucred *ucred; Unit *u; - _cleanup_strv_free_ char **tags = NULL; n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT); if (n <= 0) { @@ -1374,36 +1394,50 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); - u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid)); - if (!u) { - u = manager_get_unit_by_pid(m, ucred->pid); - if (!u) { - log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); - continue; - } - } - assert((size_t) n < sizeof(buf)); buf[n] = 0; - tags = strv_split(buf, "\n\r"); - if (!tags) - return log_oom(); - log_debug_unit(u->id, "Got notification message for unit %s", u->id); + u = manager_get_unit_by_pid(m, ucred->pid); + if (u) { + manager_invoke_notify_message(m, u, ucred->pid, buf, n); + found = true; + } + + u = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid)); + if (u) { + manager_invoke_notify_message(m, u, ucred->pid, buf, n); + found = true; + } + + u = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid)); + if (u) { + manager_invoke_notify_message(m, u, ucred->pid, buf, n); + found = true; + } - if (UNIT_VTABLE(u)->notify_message) - UNIT_VTABLE(u)->notify_message(u, ucred->pid, tags); + if (!found) + log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); } return 0; } +static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { + assert(m); + assert(u); + assert(si); + + log_debug_unit(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id); + + unit_unwatch_pid(u, si->si_pid); + UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status); +} + static int manager_dispatch_sigchld(Manager *m) { assert(m); for (;;) { siginfo_t si = {}; - Unit *u; /* First we call waitd() for a PID and do not reap the * zombie. That way we can still access /proc/$PID for @@ -1424,15 +1458,30 @@ static int manager_dispatch_sigchld(Manager *m) { if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) { _cleanup_free_ char *name = NULL; + Unit *u; get_process_comm(si.si_pid, &name); - log_debug("Got SIGCHLD for process "PID_FMT" (%s)", si.si_pid, strna(name)); - } - /* And now figure out the unit this belongs to */ - u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid)); - if (!u) + log_debug("Child "PID_FMT" (%s) died (code=%s, status=%i/%s)", + si.si_pid, strna(name), + sigchld_code_to_string(si.si_code), + si.si_status, + strna(si.si_code == CLD_EXITED + ? exit_status_to_string(si.si_status, EXIT_STATUS_FULL) + : signal_to_string(si.si_status))); + + /* And now figure out the unit this belongs + * to, it might be multiple... */ u = manager_get_unit_by_pid(m, si.si_pid); + if (u) + invoke_sigchld_event(m, u, &si); + u = hashmap_get(m->watch_pids1, LONG_TO_PTR(si.si_pid)); + if (u) + invoke_sigchld_event(m, u, &si); + u = hashmap_get(m->watch_pids2, LONG_TO_PTR(si.si_pid)); + if (u) + invoke_sigchld_event(m, u, &si); + } /* And now, we actually reap the zombie. */ if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) { @@ -1441,26 +1490,6 @@ static int manager_dispatch_sigchld(Manager *m) { return -errno; } - - if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED) - continue; - - log_debug("Child %lu died (code=%s, status=%i/%s)", - (long unsigned) si.si_pid, - sigchld_code_to_string(si.si_code), - si.si_status, - strna(si.si_code == CLD_EXITED - ? exit_status_to_string(si.si_status, EXIT_STATUS_FULL) - : signal_to_string(si.si_status))); - - if (!u) - continue; - - log_debug_unit(u->id, - "Child %lu belongs to %s", (long unsigned) si.si_pid, u->id); - - unit_unwatch_pid(u, si.si_pid); - UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status); } return 0; @@ -1506,23 +1535,10 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t return -errno; } - if (sfsi.ssi_pid > 0) { - _cleanup_free_ char *p = NULL; - - get_process_comm(sfsi.ssi_pid, &p); - - log_full(sfsi.ssi_signo == SIGCHLD || - (sfsi.ssi_signo == SIGTERM && m->running_as == SYSTEMD_USER) - ? LOG_DEBUG : LOG_INFO, - "Received SIG%s from PID "PID_FMT" (%s).", - signal_to_string(sfsi.ssi_signo), - sfsi.ssi_pid, strna(p)); - } else - log_full(sfsi.ssi_signo == SIGCHLD || - (sfsi.ssi_signo == SIGTERM && m->running_as == SYSTEMD_USER) - ? LOG_DEBUG : LOG_INFO, - "Received SIG%s.", - signal_to_string(sfsi.ssi_signo)); + log_received_signal(sfsi.ssi_signo == SIGCHLD || + (sfsi.ssi_signo == SIGTERM && m->running_as == SYSTEMD_USER) + ? LOG_DEBUG : LOG_INFO, + &sfsi); switch (sfsi.ssi_signo) { @@ -1890,7 +1906,7 @@ int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) { void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { #ifdef HAVE_AUDIT - char *p; + _cleanup_free_ char *p = NULL; int audit_fd; audit_fd = get_audit_fd(); @@ -1923,17 +1939,19 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { } else log_warning("Failed to send audit message: %m"); } - - free(p); #endif } void manager_send_unit_plymouth(Manager *m, Unit *u) { - int fd = -1; - union sockaddr_union sa; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "\0/org/freedesktop/plymouthd", + }; + int n = 0; - char *message = NULL; + _cleanup_free_ char *message = NULL; + _cleanup_close_ int fd = -1; /* Don't generate plymouth events if the service was already * started and we're just deserializing */ @@ -1959,46 +1977,22 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { return; } - zero(sa); - sa.sa.sa_family = AF_UNIX; - strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1); if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) { - if (errno != EPIPE && - errno != EAGAIN && - errno != ENOENT && - errno != ECONNREFUSED && - errno != ECONNRESET && - errno != ECONNABORTED) + if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED)) log_error("connect() failed: %m"); - - goto finish; + return; } if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) { log_oom(); - goto finish; + return; } errno = 0; - if (write(fd, message, n + 1) != n + 1) { - - if (errno != EPIPE && - errno != EAGAIN && - errno != ENOENT && - errno != ECONNREFUSED && - errno != ECONNRESET && - errno != ECONNABORTED) + if (write(fd, message, n + 1) != n + 1) + if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED)) log_error("Failed to write Plymouth message: %m"); - - goto finish; - } - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - free(message); } void manager_dispatch_bus_name_owner_changed( @@ -2111,7 +2105,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) { fprintf(f, "kdbus-fd=%i\n", copy); } - bus_serialize(m, f); + bus_track_serialize(m->subscribed, f); fputc('\n', f); @@ -2288,7 +2282,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { m->kdbus_fd = fdset_remove(fds, fd); } - } else if (bus_deserialize_item(m, l) == 0) + } else if (bus_track_deserialize_item(&m->deserialized_subscribed, l) == 0) log_debug("Unknown serialization item '%s'", l); } @@ -2734,7 +2728,7 @@ int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) { assert(m); - for (i = 0; i < RLIMIT_NLIMITS; i++) { + for (i = 0; i < _RLIMIT_MAX; i++) { if (!default_rlimit[i]) continue; @@ -2857,3 +2851,10 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) { return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p); } + +const char *manager_get_runtime_prefix(Manager *m) { + + return m->running_as == SYSTEMD_SYSTEM ? + "/run" : + getenv("XDG_RUNTIME_DIR"); +}