#include <libcgroup.h>
#include <termios.h>
#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include "manager.h"
#include "hashmap.h"
#include "mount-setup.h"
#include "utmp-wtmp.h"
#include "unit-name.h"
+#include "dbus-unit.h"
+#include "dbus-job.h"
static int enable_special_signals(Manager *m) {
char fd;
m->running_as = running_as;
m->confirm_spawn = confirm_spawn;
+ m->name_data_slot = -1;
+ m->exit_code = _MANAGER_EXIT_CODE_INVALID;
- m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = -1;
+ m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = -1;
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
goto fail;
+ if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
+ goto fail;
+
if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
goto fail;
return n;
}
-void manager_free(Manager *m) {
- UnitType c;
- Unit *u;
+static void manager_clear_jobs_and_units(Manager *m) {
Job *j;
+ Unit *u;
assert(m);
while ((u = hashmap_first(m->units)))
unit_free(u);
+}
- manager_dispatch_cleanup_queue(m);
+void manager_free(Manager *m) {
+ UnitType c;
+
+ assert(m);
+
+ manager_clear_jobs_and_units(m);
for (c = 0; c < _UNIT_TYPE_MAX; c++)
if (unit_vtable[c]->shutdown)
unit_vtable[c]->shutdown(m);
- manager_shutdown_cgroup(m);
+ /* If we reexecute ourselves, we keep the root cgroup
+ * around */
+ manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
bus_done_api(m);
bus_done_system(m);
hashmap_free(m->jobs);
hashmap_free(m->transaction_jobs);
hashmap_free(m->watch_pids);
+ hashmap_free(m->watch_bus);
if (m->epoll_fd >= 0)
- close_nointr(m->epoll_fd);
+ close_nointr_nofail(m->epoll_fd);
if (m->signal_watch.fd >= 0)
- close_nointr(m->signal_watch.fd);
+ close_nointr_nofail(m->signal_watch.fd);
strv_free(m->unit_path);
strv_free(m->sysvinit_path);
free(m->cgroup_controller);
free(m->cgroup_hierarchy);
- assert(hashmap_isempty(m->cgroup_bondings));
hashmap_free(m->cgroup_bondings);
free(m);
}
-int manager_coldplug(Manager *m) {
- int r;
+int manager_enumerate(Manager *m) {
+ int r = 0, q;
UnitType c;
- Iterator i;
- Unit *u;
- char *k;
assert(m);
- /* First, let's ask every type to load all units from
- * disk/kernel that it might know */
+ /* 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)
- if ((r = unit_vtable[c]->enumerate(m)) < 0)
- return r;
+ if ((q = unit_vtable[c]->enumerate(m)) < 0)
+ r = q;
manager_dispatch_load_queue(m);
+ return r;
+}
+
+int manager_coldplug(Manager *m) {
+ int r = 0, q;
+ Iterator i;
+ Unit *u;
+ char *k;
+
+ assert(m);
/* Then, let's set up their initial state. */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
continue;
if (UNIT_VTABLE(u)->coldplug)
- if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
- return r;
+ if ((q = UNIT_VTABLE(u)->coldplug(u)) < 0)
+ r = q;
}
+ return r;
+}
+
+int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
+ int r, q;
+
+ assert(m);
+
+ /* First, enumerate what we can from all config files */
+ r = manager_enumerate(m);
+
+ /* Second, deserialize if there is something to deserialize */
+ if (serialization)
+ if ((q = manager_deserialize(m, serialization, fds)) < 0)
+ r = q;
+
+ /* Third, fire things up! */
+ if ((q = manager_coldplug(m)) < 0)
+ r = q;
+
/* Now that the initial devices are available, let's see if we
* can write the utmp file */
manager_write_utmp_reboot(m);
- return 0;
+ return r;
}
static void transaction_delete_job(Manager *m, Job *j, bool delete_dependencies) {
log_error("Failed to enqueue %s job: %s", name, strerror(-r));
}
-static int manager_process_signal_fd(Manager *m, bool *quit) {
+static int manager_process_signal_fd(Manager *m) {
ssize_t n;
struct signalfd_siginfo sfsi;
bool sigchld = false;
break;
}
- *quit = true;
+ m->exit_code = MANAGER_EXIT;
return 0;
case SIGWINCH:
break;
}
+ case SIGHUP:
+ m->exit_code = MANAGER_RELOAD;
+ break;
+
default:
log_info("Got unhandled signal <%s>.", strsignal(sfsi.ssi_signo));
}
return 0;
}
-static int process_event(Manager *m, struct epoll_event *ev, bool *quit) {
+static int process_event(Manager *m, struct epoll_event *ev) {
int r;
Watch *w;
if (ev->events != EPOLLIN)
return -EINVAL;
- if ((r = manager_process_signal_fd(m, quit)) < 0)
+ if ((r = manager_process_signal_fd(m)) < 0)
return r;
break;
int manager_loop(Manager *m) {
int r;
- bool quit = false;
RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 1000);
assert(m);
+ m->exit_code = MANAGER_RUNNING;
- do {
+ while (m->exit_code == MANAGER_RUNNING) {
struct epoll_event event;
int n;
assert(n == 1);
- if ((r = process_event(m, &event, &quit)) < 0)
+ if ((r = process_event(m, &event)) < 0)
return r;
- } while (!quit);
+ }
- return 0;
+ return m->exit_code;
}
int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u) {
}
}
+void manager_dispatch_bus_name_owner_changed(
+ Manager *m,
+ const char *name,
+ const char* old_owner,
+ const char *new_owner) {
+
+ Unit *u;
+
+ assert(m);
+ assert(name);
+
+ if (!(u = hashmap_get(m->watch_bus, name)))
+ return;
+
+ UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
+}
+
+void manager_dispatch_bus_query_pid_done(
+ Manager *m,
+ const char *name,
+ pid_t pid) {
+
+ Unit *u;
+
+ assert(m);
+ assert(name);
+ assert(pid >= 1);
+
+ if (!(u = hashmap_get(m->watch_bus, name)))
+ return;
+
+ UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid);
+}
+
+int manager_open_serialization(FILE **_f) {
+ char *path;
+ mode_t saved_umask;
+ int fd;
+ FILE *f;
+
+ assert(_f);
+
+ if (asprintf(&path, "/dev/shm/systemd-%u.dump-XXXXXX", (unsigned) getpid()) < 0)
+ return -ENOMEM;
+
+ saved_umask = umask(0077);
+ fd = mkostemp(path, O_RDWR|O_CLOEXEC);
+ umask(saved_umask);
+
+ if (fd < 0) {
+ free(path);
+ return -errno;
+ }
+
+ unlink(path);
+
+ log_debug("Serializing state to %s", path);
+ free(path);
+
+ if (!(f = fdopen(fd, "w+")) < 0)
+ return -errno;
+
+ *_f = f;
+
+ return 0;
+}
+
+int manager_serialize(Manager *m, FILE *f, FDSet *fds) {
+ Iterator i;
+ Unit *u;
+ const char *t;
+ int r;
+
+ assert(m);
+ assert(f);
+ assert(fds);
+
+ HASHMAP_FOREACH_KEY(u, t, m->units, i) {
+ if (u->meta.id != t)
+ continue;
+
+ if (!unit_can_serialize(u))
+ continue;
+
+ /* Start marker */
+ fputs(u->meta.id, f);
+ fputc('\n', f);
+
+ if ((r = unit_serialize(u, f, fds)) < 0)
+ return r;
+ }
+
+ if (ferror(f))
+ return -EIO;
+
+ return 0;
+}
+
+int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
+ int r = 0;
+
+ assert(m);
+ assert(f);
+
+ log_debug("Deserializing state...");
+
+ for (;;) {
+ Unit *u;
+ char name[UNIT_NAME_MAX+2];
+
+ /* Start marker */
+ if (!fgets(name, sizeof(name), f)) {
+ if (feof(f))
+ break;
+
+ return -errno;
+ }
+
+ char_array_0(name);
+
+ if ((r = manager_load_unit(m, strstrip(name), NULL, &u)) < 0)
+ return r;
+
+ if ((r = unit_deserialize(u, f, fds)) < 0)
+ return r;
+ }
+
+ if (ferror(f))
+ return -EIO;
+
+ return 0;
+}
+
+int manager_reload(Manager *m) {
+ int r, q;
+ FILE *f;
+ FDSet *fds;
+
+ assert(m);
+
+ if ((r = manager_open_serialization(&f)) < 0)
+ return r;
+
+ if (!(fds = fdset_new())) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if ((r = manager_serialize(m, f, fds)) < 0)
+ goto finish;
+
+ if (fseeko(f, 0, SEEK_SET) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ /* From here on there is no way back. */
+ manager_clear_jobs_and_units(m);
+
+ /* First, enumerate what we can from all config files */
+ if ((q = manager_enumerate(m)) < 0)
+ r = q;
+
+ /* Second, deserialize our stored data */
+ if ((q = manager_deserialize(m, f, fds)) < 0)
+ r = q;
+
+ fclose(f);
+ f = NULL;
+
+ /* Third, fire things up! */
+ if ((q = manager_coldplug(m)) < 0)
+ r = q;
+
+finish:
+ if (f)
+ fclose(f);
+
+ if (fds)
+ fdset_free(fds);
+
+ return r;
+}
+
static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
[MANAGER_INIT] = "init",
[MANAGER_SYSTEM] = "system",