chiark / gitweb /
manager: fix initialization of plymouth socket
[elogind.git] / src / core / manager.c
index b181aa0453eb9a7b593d20d10f5cfa428bc8316a..f7e5cbdcf3c85608ecf7429ee0787991d1da3588 100644 (file)
@@ -105,7 +105,6 @@ static int manager_watch_jobs_in_progress(Manager *m) {
                 return 0;
 
         next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
-        log_debug("queuing for "USEC_FMT, next);
         return sd_event_add_monotonic(m->event, next, 0, manager_dispatch_jobs_in_progress, m, &m->jobs_in_progress_event_source);
 }
 
@@ -448,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;
@@ -599,7 +594,7 @@ static int manager_setup_kdbus(Manager *m) {
          * necessary to ensure that users cannot get access to busses
          * of virtualized users when no UID namespacing is used. */
         if (m->running_as == SYSTEMD_SYSTEM)
-                mkdir_p_label("/dev/kdbus/ns", 0700);
+                mkdir_p_label("/dev/kdbus/domain", 0700);
 #endif
 
         return 0;
@@ -779,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);
@@ -1320,6 +1316,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;
@@ -1338,6 +1354,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;
@@ -1352,7 +1369,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) {
@@ -1375,36 +1391,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
@@ -1425,15 +1455,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) {
@@ -1442,26 +1487,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);
-
-                hashmap_remove(m->watch_pids, LONG_TO_PTR(si.si_pid));
-                UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
         }
 
         return 0;
@@ -1766,7 +1791,6 @@ static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t use
         manager_print_jobs_in_progress(m);
 
         next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_PERIOD_USEC;
-        log_debug("requeuing for "USEC_FMT, next);
         r = sd_event_source_set_time(source, next);
         if (r < 0)
                 return r;
@@ -1892,7 +1916,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();
@@ -1925,17 +1949,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 */
@@ -1961,46 +1987,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(
@@ -2468,7 +2470,6 @@ void manager_check_finished(Manager *m) {
         if (hashmap_size(m->jobs) > 0) {
                 if (m->jobs_in_progress_event_source) {
                         uint64_t next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
-                        log_debug("requeuing for "USEC_FMT, next);
                         sd_event_source_set_time(m->jobs_in_progress_event_source, next);
                 }
                 return;