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=7653850cd4273296470398cea5775c8490b5c096;hpb=ee33e53a70c0d3f9d8aeafe4b8fd84a0d5e1d8d9;p=elogind.git diff --git a/src/core/manager.c b/src/core/manager.c index 7653850cd..491809112 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -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) { @@ -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; @@ -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);