X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Fmanager.c;h=491809112611af2a495e3a20b4a8e3314321a3db;hb=4968105790c65af58d4ab42bffa2a4bedc0be8ee;hp=5fbb375cd4e96d3e08a755d2c1d887fcdd96591d;hpb=230314d718cb68b328961c9723976e54c17d06f7;p=elogind.git diff --git a/src/core/manager.c b/src/core/manager.c index 5fbb375cd..491809112 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -69,7 +69,7 @@ #include "audit-fd.h" #include "boot-timestamps.h" #include "env-util.h" -#include "bus-errors.h" +#include "bus-common-errors.h" #include "bus-error.h" #include "bus-util.h" #include "dbus.h" @@ -84,6 +84,9 @@ #define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3) #define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3 +#define NOTIFY_FD_MAX 768 +#define NOTIFY_BUFFER_MAX PIPE_BUF + static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata); @@ -162,6 +165,7 @@ static void manager_print_jobs_in_progress(Manager *m) { uint64_t x; assert(m); + assert(m->n_running_jobs > 0); manager_flip_auto_status(m, true); @@ -184,8 +188,7 @@ static void manager_print_jobs_in_progress(Manager *m) { m->jobs_in_progress_iteration++; if (m->n_running_jobs > 1) - if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0) - job_of_n = NULL; + asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs); format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC); if (job_get_timeout(j, &x) > 0) @@ -197,7 +200,6 @@ static void manager_print_jobs_in_progress(Manager *m) { job_type_to_string(j->type), unit_description(j->unit), time, limit); - } static int have_ask_password(void) { @@ -440,7 +442,7 @@ static int manager_setup_signals(Manager *m) { SIGRTMIN+26, /* systemd: set log target to journal-or-kmsg */ 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 (obsolete)*/ + SIGRTMIN+29, /* systemd: set log target to syslog-or-kmsg (obsolete) */ /* ... one free signal here SIGRTMIN+30 ... */ #endif @@ -946,20 +948,29 @@ Manager* manager_free(Manager *m) { } int manager_enumerate(Manager *m) { - int r = 0, q; + int r = 0; UnitType c; assert(m); /* Let's ask every type to load all units from disk/kernel * that it might know */ - for (c = 0; c < _UNIT_TYPE_MAX; c++) - if (unit_vtable[c]->enumerate) { - q = unit_vtable[c]->enumerate(m); - if (q < 0) - r = q; + for (c = 0; c < _UNIT_TYPE_MAX; c++) { + int q; + + if (unit_vtable[c]->supported && !unit_vtable[c]->supported(m)) { + log_info("Unit type .%s is not supported on this system.", unit_type_to_string(c)); + continue; } + if (!unit_vtable[c]->enumerate) + continue; + + q = unit_vtable[c]->enumerate(m); + if (q < 0) + r = q; + } + manager_dispatch_load_queue(m); return r; } @@ -1019,7 +1030,7 @@ static void manager_build_unit_path_cache(Manager *m) { while ((de = readdir(d))) { char *p; - if (ignore_file(de->d_name)) + if (hidden_file(de->d_name)) continue; p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL); @@ -1441,7 +1452,7 @@ 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) { +static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) { _cleanup_strv_free_ char **tags = NULL; assert(m); @@ -1458,12 +1469,13 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char * log_unit_debug(u->id, "Got notification message for unit %s", u->id); if (UNIT_VTABLE(u)->notify_message) - UNIT_VTABLE(u)->notify_message(u, pid, tags); + UNIT_VTABLE(u)->notify_message(u, pid, tags, fds); } static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { Manager *m = userdata; ssize_t n; + int r; assert(m); assert(m->notify_fd == fd); @@ -1474,73 +1486,101 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t } for (;;) { - char buf[4096]; + _cleanup_fdset_free_ FDSet *fds = NULL; + char buf[NOTIFY_BUFFER_MAX+1]; struct iovec iovec = { .iov_base = buf, .iov_len = sizeof(buf)-1, }; - bool found = false; - union { struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; } control = {}; - struct msghdr msghdr = { .msg_iov = &iovec, .msg_iovlen = 1, .msg_control = &control, .msg_controllen = sizeof(control), }; - struct ucred *ucred; + struct cmsghdr *cmsg; + struct ucred *ucred = NULL; + bool found = false; Unit *u1, *u2, *u3; + int *fd_array = NULL; + unsigned n_fds = 0; - n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT); - if (n <= 0) { - if (n == 0) - return -EIO; - + n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (n < 0) { if (errno == EAGAIN || errno == EINTR) break; return -errno; } + if (n == 0) + return -ECONNRESET; + + for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + + fd_array = (int*) CMSG_DATA(cmsg); + n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + + ucred = (struct ucred*) CMSG_DATA(cmsg); + } + } + + if (n_fds > 0) { + assert(fd_array); + + r = fdset_new_array(&fds, fd_array, n_fds); + if (r < 0) { + close_many(fd_array, n_fds); + return log_oom(); + } + } - if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || - control.cmsghdr.cmsg_level != SOL_SOCKET || - control.cmsghdr.cmsg_type != SCM_CREDENTIALS || - control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { - log_warning("Received notify message without credentials. Ignoring."); + if (!ucred || ucred->pid <= 0) { + log_warning("Received notify message without valid credentials. Ignoring."); continue; } - ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); + if ((size_t) n >= sizeof(buf)) { + log_warning("Received notify message exceeded maximum size. Ignoring."); + continue; + } - assert((size_t) n < sizeof(buf)); buf[n] = 0; /* Notify every unit that might be interested, but try * to avoid notifying the same one multiple times. */ u1 = manager_get_unit_by_pid(m, ucred->pid); if (u1) { - manager_invoke_notify_message(m, u1, ucred->pid, buf, n); + manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); found = true; } u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid)); if (u2 && u2 != u1) { - manager_invoke_notify_message(m, u2, ucred->pid, buf, n); + manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); found = true; } u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid)); if (u3 && u3 != u2 && u3 != u1) { - manager_invoke_notify_message(m, u3, ucred->pid, buf, n); + manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); found = true; } if (!found) log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); + + if (fdset_size(fds) > 0) + log_warning("Got auxiliary fds with notification message, closing all."); } return 0; @@ -2289,7 +2329,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { uint32_t id; if (safe_atou32(l+15, &id) < 0) - log_warning("Failed to parse current job id value %s", l+15); + log_debug("Failed to parse current job id value %s", l+15); else m->current_job_id = MAX(m->current_job_id, id); @@ -2297,7 +2337,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { uint32_t n; if (safe_atou32(l+17, &n) < 0) - log_warning("Failed to parse installed jobs counter %s", l+17); + log_debug("Failed to parse installed jobs counter %s", l+17); else m->n_installed_jobs += n; @@ -2305,7 +2345,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { uint32_t n; if (safe_atou32(l+14, &n) < 0) - log_warning("Failed to parse failed jobs counter %s", l+14); + log_debug("Failed to parse failed jobs counter %s", l+14); else m->n_failed_jobs += n; @@ -2314,7 +2354,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { b = parse_boolean(l+10); if (b < 0) - log_warning("Failed to parse taint /usr flag %s", l+10); + log_debug("Failed to parse taint /usr flag %s", l+10); else m->taint_usr = m->taint_usr || b; @@ -2365,7 +2405,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { int fd; if (safe_atoi(l + 10, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) - log_warning("Failed to parse notify fd: %s", l + 10); + log_debug("Failed to parse notify fd: %s", l + 10); else { m->notify_event_source = sd_event_source_unref(m->notify_event_source); safe_close(m->notify_fd); @@ -2388,7 +2428,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { int fd; if (safe_atoi(l + 9, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) - log_warning("Failed to parse kdbus fd: %s", l + 9); + log_debug("Failed to parse kdbus fd: %s", l + 9); else { safe_close(m->kdbus_fd); m->kdbus_fd = fdset_remove(fds, fd); @@ -2626,9 +2666,6 @@ void manager_check_finished(Manager *m) { assert(m); - if (m->n_running_jobs == 0) - m->jobs_in_progress_event_source = sd_event_source_unref(m->jobs_in_progress_event_source); - if (hashmap_size(m->jobs) > 0) { if (m->jobs_in_progress_event_source) @@ -2739,7 +2776,6 @@ static void trim_generator_dir(Manager *m, char **generator) { } void manager_run_generators(Manager *m) { - _cleanup_closedir_ DIR *d = NULL; const char *generator_path; const char *argv[5]; int r; @@ -2750,13 +2786,13 @@ void manager_run_generators(Manager *m) { return; generator_path = m->running_as == SYSTEMD_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH; - d = opendir(generator_path); - if (!d) { - if (errno == ENOENT) - return; - log_error_errno(errno, "Failed to enumerate generator directory %s: %m", - generator_path); + /* Optimize by skipping the whole process by not creating output directories + * if no generators are found. */ + if (access(generator_path, F_OK) != 0) { + if (errno != ENOENT) + log_error_errno(errno, "Failed to open generator directory %s: %m", + generator_path); return; } @@ -2779,7 +2815,7 @@ void manager_run_generators(Manager *m) { argv[4] = NULL; RUN_WITH_UMASK(0022) - execute_directory(generator_path, d, DEFAULT_TIMEOUT_USEC, (char**) argv); + execute_directory(generator_path, DEFAULT_TIMEOUT_USEC, (char**) argv); finish: trim_generator_dir(m, &m->generator_unit_path);