else
strncpy(sa.un.sun_path+1, NOTIFY_SOCKET, sizeof(sa.un.sun_path)-1);
- if (bind(m->notify_watch.fd, &sa.sa, sizeof(sa_family_t) + 1 + strlen(sa.un.sun_path+1)) < 0) {
+ if (bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
log_error("bind() failed: %m");
return -errno;
}
j->unit->meta.job = j;
j->installed = true;
+ m->n_installed_jobs ++;
/* We're fully installed. Now let's free data we don't
* need anymore. */
assert(type < _JOB_TYPE_MAX);
assert(unit);
- if (unit->meta.load_state != UNIT_LOADED && unit->meta.load_state != UNIT_ERROR) {
+ if (unit->meta.load_state != UNIT_LOADED &&
+ unit->meta.load_state != UNIT_ERROR &&
+ unit->meta.load_state != UNIT_MASKED) {
dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->meta.id);
return -EINVAL;
}
if (type != JOB_STOP && unit->meta.load_state == UNIT_ERROR) {
- dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s failed to load: %s. You might find more information in the system logs.",
+ dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
+ "Unit %s failed to load: %s. "
+ "You might find more information in the system logs.",
unit->meta.id,
strerror(-unit->meta.load_error));
return -EINVAL;
}
+ if (type != JOB_STOP && unit->meta.load_state == UNIT_MASKED) {
+ dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->meta.id);
+ return -EINVAL;
+ }
+
if (!unit_job_is_applicable(unit, type)) {
dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->meta.id);
return -EBADR;
return -EPERM;
}
- log_debug("Trying to enqueue job %s/%s", unit->meta.id, job_type_to_string(type));
+ 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, e, &ret)) < 0) {
transaction_abort(m);
if (!name)
name = file_name_from_path(path);
- if (!unit_name_is_valid(name)) {
+ if (!unit_name_is_valid(name, false)) {
dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
return -EINVAL;
}
set_free_free(m->unit_path_cache);
m->unit_path_cache = NULL;
+ manager_check_finished(m);
+
/* There might still be some zombies hanging around from
* before we were exec()'ed. Leat's reap them */
if ((r = manager_dispatch_sigchld(m)) < 0)
if (manager_dispatch_dbus_queue(m) > 0)
continue;
+ if (swap_dispatch_reload(m) > 0)
+ continue;
+
if ((n = epoll_wait(m->epoll_fd, &event, 1, -1)) < 0) {
if (errno == EINTR)
}
+void manager_send_unit_plymouth(Manager *m, Unit *u) {
+ int fd = -1;
+ union sockaddr_union sa;
+ int n = 0;
+ char *message = NULL;
+ ssize_t r;
+
+ /* Don't generate plymouth events if the service was already
+ * started and we're just deserializing */
+ if (m->n_deserializing > 0)
+ return;
+
+ if (m->running_as != MANAGER_SYSTEM)
+ return;
+
+ if (u->meta.type != UNIT_SERVICE &&
+ u->meta.type != UNIT_MOUNT &&
+ u->meta.type != UNIT_SWAP)
+ return;
+
+ /* We set SOCK_NONBLOCK here so that we rather drop the
+ * message then wait for plymouth */
+ if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
+ log_error("socket() failed: %m");
+ return;
+ }
+
+ zero(sa);
+ sa.sa.sa_family = AF_UNIX;
+ strncpy(sa.un.sun_path+1, "/ply-boot-protocol", sizeof(sa.un.sun_path)-1);
+ if (connect(fd, &sa.sa, sizeof(sa.un)) < 0) {
+
+ if (errno != EPIPE &&
+ errno != EAGAIN &&
+ errno != ENOENT &&
+ errno != ECONNREFUSED &&
+ errno != ECONNRESET &&
+ errno != ECONNABORTED)
+ log_error("connect() failed: %m");
+
+ goto finish;
+ }
+
+ if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->meta.id) + 1), u->meta.id, &n) < 0) {
+ log_error("Out of memory");
+ goto finish;
+ }
+
+ errno = 0;
+ if ((r = write(fd, message, n + 1)) != n + 1) {
+
+ if (errno != EPIPE &&
+ errno != EAGAIN &&
+ errno != ENOENT &&
+ errno != ECONNREFUSED &&
+ errno != ECONNRESET &&
+ errno != 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(
Manager *m,
const char *name,
return unit_pending_inactive(u);
}
+void manager_check_finished(Manager *m) {
+ char userspace[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
+
+ assert(m);
+
+ if (dual_timestamp_is_set(&m->finish_timestamp))
+ return;
+
+ if (hashmap_size(m->jobs) > 0)
+ return;
+
+ dual_timestamp_get(&m->finish_timestamp);
+
+ if (m->running_as == MANAGER_SYSTEM)
+ 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
+ log_debug("Startup finished in %s.",
+ format_timespan(userspace, sizeof(userspace),
+ m->finish_timestamp.monotonic - m->startup_timestamp.monotonic));
+
+}
+
static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
[MANAGER_SYSTEM] = "system",
[MANAGER_SESSION] = "session"