#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
/* Where clients shall send notification messages to */
-#define NOTIFY_SOCKET_SYSTEM "/run/systemd/notify"
-#define NOTIFY_SOCKET_USER "@/org/freedesktop/systemd1/notify"
+#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
static int manager_setup_notify(Manager *m) {
union {
struct sockaddr_un un;
} sa;
struct epoll_event ev;
- int one = 1, r;
- mode_t u;
+ int one = 1;
assert(m);
m->notify_watch.type = WATCH_NOTIFY;
- if ((m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
+ m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (m->notify_watch.fd < 0) {
log_error("Failed to allocate notification socket: %m");
return -errno;
}
sa.sa.sa_family = AF_UNIX;
if (getpid() != 1)
- snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET_USER "/%llu", random_ull());
- else {
- unlink(NOTIFY_SOCKET_SYSTEM);
- strncpy(sa.un.sun_path, NOTIFY_SOCKET_SYSTEM, sizeof(sa.un.sun_path));
- }
-
- if (sa.un.sun_path[0] == '@')
- sa.un.sun_path[0] = 0;
+ snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%llu", random_ull());
+ else
+ strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path));
- u = umask(0111);
- r = bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
- umask(u);
+ sa.un.sun_path[0] = 0;
- if (r < 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;
}
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0)
return -errno;
- if (sa.un.sun_path[0] == 0)
- sa.un.sun_path[0] = '@';
-
- if (!(m->notify_socket = strdup(sa.un.sun_path)))
+ sa.un.sun_path[0] = '@';
+ m->notify_socket = strdup(sa.un.sun_path);
+ if (!m->notify_socket)
return -ENOMEM;
log_debug("Using notification socket %s", m->notify_socket);
if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
goto fail;
- if ((r = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0)
- goto fail;
-
if ((r = manager_setup_signals(m)) < 0)
goto fail;
void manager_free(Manager *m) {
UnitType c;
+ int i;
assert(m);
free(m->switch_root);
free(m->switch_root_init);
+ for (i = 0; i < RLIMIT_NLIMITS; i++)
+ free(m->rlimit[i]);
+
free(m);
}
if (ignore_file(de->d_name))
continue;
- p = join(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
+ p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
if (!p) {
r = -ENOMEM;
goto fail;
manager_run_generators(m);
+ r = lookup_paths_init(
+ &m->lookup_paths, m->running_as, true,
+ m->generator_unit_path,
+ m->generator_unit_path_early,
+ m->generator_unit_path_late);
+ if (r < 0)
+ return r;
+
manager_build_unit_path_cache(m);
/* If we will deserialize make sure that during enumeration
r = manager_enumerate(m);
/* Second, deserialize if there is something to deserialize */
- if (serialization)
- if ((q = manager_deserialize(m, serialization, fds)) < 0)
+ if (serialization) {
+ q = manager_deserialize(m, serialization, fds);
+ if (q < 0)
r = q;
+ }
/* Third, fire things up! */
- if ((q = manager_coldplug(m)) < 0)
+ q = manager_coldplug(m);
+ if (q < 0)
r = q;
if (serialization) {
t = unit_name_to_type(name);
- if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid_no_type(name, false)) {
+ if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, false)) {
dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
return -EINVAL;
}
return m->exit_code;
}
-int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) {
+int manager_load_unit_from_dbus_path(Manager *m, const char *s, DBusError *e, Unit **_u) {
char *n;
Unit *u;
+ int r;
assert(m);
assert(s);
if (!startswith(s, "/org/freedesktop/systemd1/unit/"))
return -EINVAL;
- if (!(n = bus_path_unescape(s+31)))
+ n = bus_path_unescape(s+31);
+ if (!n)
return -ENOMEM;
- u = manager_get_unit(m, n);
+ r = manager_load_unit(m, n, NULL, e, &u);
free(n);
- if (!u)
- return -ENOENT;
+ if (r < 0)
+ return r;
*_u = u;
fprintf(f, "current-job-id=%i\n", m->current_job_id);
fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
+ fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs);
+ fprintf(f, "n-failed-jobs=%u\n", m->n_failed_jobs);
dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp);
- dual_timestamp_serialize(f, "startup-timestamp", &m->startup_timestamp);
- dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
+
+ if (!in_initrd()) {
+ dual_timestamp_serialize(f, "startup-timestamp", &m->startup_timestamp);
+ dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
+ }
fputc('\n', f);
log_debug("Failed to parse current job id value %s", l+15);
else
m->current_job_id = MAX(m->current_job_id, id);
+ } else if (startswith(l, "n-installed-jobs=")) {
+ uint32_t n;
+
+ if (safe_atou32(l+17, &n) < 0)
+ log_debug("Failed to parse installed jobs counter %s", l+17);
+ else
+ m->n_installed_jobs += n;
+ } else if (startswith(l, "n-failed-jobs=")) {
+ uint32_t n;
+
+ if (safe_atou32(l+14, &n) < 0)
+ log_debug("Failed to parse failed jobs counter %s", l+14);
+ else
+ m->n_failed_jobs += n;
} else if (startswith(l, "taint-usr=")) {
int b;
assert(m);
- if ((r = manager_open_serialization(m, &f)) < 0)
+ r = manager_open_serialization(m, &f);
+ if (r < 0)
return r;
m->n_reloading ++;
- if (!(fds = fdset_new())) {
+ fds = fdset_new();
+ if (!fds) {
m->n_reloading --;
r = -ENOMEM;
goto finish;
}
- if ((r = manager_serialize(m, f, fds)) < 0) {
+ r = manager_serialize(m, f, fds);
+ if (r < 0) {
m->n_reloading --;
goto finish;
}
/* From here on there is no way back. */
manager_clear_jobs_and_units(m);
manager_undo_generators(m);
-
- /* Find new unit paths */
lookup_paths_free(&m->lookup_paths);
- if ((q = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0)
- r = q;
+ /* Find new unit paths */
manager_run_generators(m);
+ q = lookup_paths_init(
+ &m->lookup_paths, m->running_as, true,
+ m->generator_unit_path,
+ m->generator_unit_path_early,
+ m->generator_unit_path_late);
+ if (q < 0)
+ r = q;
+
manager_build_unit_path_cache(m);
/* First, enumerate what we can from all config files */
- if ((q = manager_enumerate(m)) < 0)
+ q = manager_enumerate(m);
+ if (q < 0)
r = q;
/* Second, deserialize our stored data */
- if ((q = manager_deserialize(m, f, fds)) < 0)
+ q = manager_deserialize(m, f, fds);
+ if (q < 0)
r = q;
fclose(f);
f = NULL;
/* Third, fire things up! */
- if ((q = manager_coldplug(m)) < 0)
+ q = manager_coldplug(m);
+ if (q < 0)
r = q;
assert(m->n_reloading > 0);
/* Notify Type=idle units that we are done now */
close_pipe(m->idle_pipe);
+ /* Turn off confirm spawn now */
+ m->confirm_spawn = false;
+
if (dual_timestamp_is_set(&m->finish_timestamp))
return;
format_timespan(sum, sizeof(sum), total_usec));
}
+static int create_generator_dir(Manager *m, char **generator, const char *name) {
+ char *p;
+ int r;
+
+ assert(m);
+ assert(generator);
+ assert(name);
+
+ if (*generator)
+ return 0;
+
+ if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
+
+ p = strappend("/run/systemd/", name);
+ if (!p) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+
+ r = mkdir_p_label(p, 0755);
+ if (r < 0) {
+ log_error("Failed to create generator directory: %s", strerror(-r));
+ free(p);
+ return r;
+ }
+ } else {
+ p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL);
+ if (!p) {
+ log_error("Out of memory");
+ return -ENOMEM;
+ }
+
+ if (!mkdtemp(p)) {
+ free(p);
+ log_error("Failed to create generator directory: %m");
+ return -errno;
+ }
+ }
+
+ *generator = p;
+ return 0;
+}
+
+static void trim_generator_dir(Manager *m, char **generator) {
+ assert(m);
+ assert(generator);
+
+ if (!*generator)
+ return;
+
+ if (rmdir(*generator) >= 0) {
+ free(*generator);
+ *generator = NULL;
+ }
+
+ return;
+}
+
void manager_run_generators(Manager *m) {
DIR *d = NULL;
const char *generator_path;
- const char *argv[3];
+ const char *argv[5];
mode_t u;
+ int r;
assert(m);
generator_path = m->running_as == MANAGER_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
- if (!(d = opendir(generator_path))) {
-
+ d = opendir(generator_path);
+ if (!d) {
if (errno == ENOENT)
return;
return;
}
- if (!m->generator_unit_path) {
- const char *p;
- char user_path[] = "/tmp/systemd-generator-XXXXXX";
-
- if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
- p = "/run/systemd/generator";
-
- if (mkdir_p(p, 0755) < 0) {
- log_error("Failed to create generator directory: %m");
- goto finish;
- }
+ r = create_generator_dir(m, &m->generator_unit_path, "generator");
+ if (r < 0)
+ goto finish;
- } else {
- if (!(p = mkdtemp(user_path))) {
- log_error("Failed to create generator directory: %m");
- goto finish;
- }
- }
+ r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early");
+ if (r < 0)
+ goto finish;
- if (!(m->generator_unit_path = strdup(p))) {
- log_error("Failed to allocate generator unit path.");
- goto finish;
- }
- }
+ r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late");
+ if (r < 0)
+ goto finish;
argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
argv[1] = m->generator_unit_path;
- argv[2] = NULL;
+ argv[2] = m->generator_unit_path_early;
+ argv[3] = m->generator_unit_path_late;
+ argv[4] = NULL;
u = umask(0022);
execute_directory(generator_path, d, (char**) argv);
umask(u);
- if (rmdir(m->generator_unit_path) >= 0) {
- /* Uh? we were able to remove this dir? I guess that
- * means the directory was empty, hence let's shortcut
- * this */
-
- free(m->generator_unit_path);
- m->generator_unit_path = NULL;
- goto finish;
- }
-
- if (!strv_find(m->lookup_paths.unit_path, m->generator_unit_path)) {
- char **l;
-
- if (!(l = strv_append(m->lookup_paths.unit_path, m->generator_unit_path))) {
- log_error("Failed to add generator directory to unit search path: %m");
- goto finish;
- }
-
- strv_free(m->lookup_paths.unit_path);
- m->lookup_paths.unit_path = l;
-
- log_debug("Added generator unit path %s to search path.", m->generator_unit_path);
- }
+ trim_generator_dir(m, &m->generator_unit_path);
+ trim_generator_dir(m, &m->generator_unit_path_early);
+ trim_generator_dir(m, &m->generator_unit_path_late);
finish:
if (d)
closedir(d);
}
-void manager_undo_generators(Manager *m) {
+static void remove_generator_dir(Manager *m, char **generator) {
assert(m);
+ assert(generator);
- if (!m->generator_unit_path)
+ if (!*generator)
return;
- strv_remove(m->lookup_paths.unit_path, m->generator_unit_path);
- rm_rf(m->generator_unit_path, false, true, false);
+ strv_remove(m->lookup_paths.unit_path, *generator);
+ rm_rf(*generator, false, true, false);
+
+ free(*generator);
+ *generator = NULL;
+}
+
+void manager_undo_generators(Manager *m) {
+ assert(m);
- free(m->generator_unit_path);
- m->generator_unit_path = NULL;
+ remove_generator_dir(m, &m->generator_unit_path);
+ remove_generator_dir(m, &m->generator_unit_path_early);
+ remove_generator_dir(m, &m->generator_unit_path_late);
}
int manager_set_default_controllers(Manager *m, char **controllers) {
return 0;
}
+int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
+ int i;
+
+ assert(m);
+
+ for (i = 0; i < RLIMIT_NLIMITS; i++) {
+ if (!default_rlimit[i])
+ continue;
+
+ m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1);
+ if (!m->rlimit[i])
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
void manager_recheck_journal(Manager *m) {
Unit *u;