machined.c revision d9e34bfda3d34dcde00a876cb052e7de0655e1cb
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen/***
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen This file is part of systemd.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen Copyright 2013 Lennart Poettering
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen systemd is free software; you can redistribute it and/or modify it
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen under the terms of the GNU Lesser General Public License as published by
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen (at your option) any later version.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen systemd is distributed in the hope that it will be useful, but
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen Lesser General Public License for more details.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen You should have received a copy of the GNU Lesser General Public License
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen***/
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <errno.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <pwd.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <fcntl.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <string.h>
0617ffabe86a6d366252477eafbe59a888b149d4Tom Gundersen#include <unistd.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include <sys/epoll.h>
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "sd-daemon.h"
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen#include "strv.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "conf-parser.h"
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen#include "cgroup-util.h"
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen#include "mkdir.h"
7c99d940c11e4da1863a218b6b70dd16e65b7518Tom Gundersen#include "bus-util.h"
7c99d940c11e4da1863a218b6b70dd16e65b7518Tom Gundersen#include "bus-error.h"
7c99d940c11e4da1863a218b6b70dd16e65b7518Tom Gundersen#include "machined.h"
7c99d940c11e4da1863a218b6b70dd16e65b7518Tom Gundersen
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom GundersenManager *manager_new(void) {
7c99d940c11e4da1863a218b6b70dd16e65b7518Tom Gundersen Manager *m;
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen int r;
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen m = new0(Manager, 1);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (!m)
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return NULL;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen m->machines = hashmap_new(string_hash_func, string_compare_func);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen m->machine_units = hashmap_new(string_hash_func, string_compare_func);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen m->machine_leaders = hashmap_new(trivial_hash_func, trivial_compare_func);
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen if (!m->machines || !m->machine_units || !m->machine_leaders) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen manager_free(m);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen return NULL;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen }
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen r = sd_event_default(&m->event);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen if (r < 0) {
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen manager_free(m);
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen return NULL;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen }
02b59d57e0c08231645120077f651151f5bb2babTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen sd_event_set_watchdog(m->event, true);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen return m;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen}
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersenvoid manager_free(Manager *m) {
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen Machine *machine;
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen assert(m);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen while ((machine = hashmap_first(m->machines)))
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen machine_free(machine);
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen hashmap_free(m->machines);
12e0f830f592ec4c6bb49ac7ae1e0e84f74105e3Tom Gundersen hashmap_free(m->machine_units);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen hashmap_free(m->machine_leaders);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen sd_bus_unref(m->bus);
f579559b3a14c1f1ef96c372e7626c4733e6ef7dTom Gundersen sd_event_unref(m->event);
free(m);
}
int manager_enumerate_machines(Manager *m) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r = 0;
assert(m);
/* Read in machine data stored on disk */
d = opendir("/run/systemd/machines");
if (!d) {
if (errno == ENOENT)
return 0;
log_error("Failed to open /run/systemd/machines: %m");
return -errno;
}
FOREACH_DIRENT(de, d, return -errno) {
struct Machine *machine;
int k;
if (!dirent_is_file(de))
continue;
k = manager_add_machine(m, de->d_name, &machine);
if (k < 0) {
log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
r = k;
continue;
}
machine_add_to_gc_queue(machine);
k = machine_load(machine);
if (k < 0)
r = k;
}
return r;
}
static int manager_connect_bus(Manager *m) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(m);
assert(!m->bus);
r = sd_bus_default_system(&m->bus);
if (r < 0) {
log_error("Failed to connect to system bus: %s", strerror(-r));
return r;
}
r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
if (r < 0) {
log_error("Failed to add manager object vtable: %s", strerror(-r));
return r;
}
r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
if (r < 0) {
log_error("Failed to add machine object vtable: %s", strerror(-r));
return r;
}
r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
if (r < 0) {
log_error("Failed to add machine enumerator: %s", strerror(-r));
return r;
}
r = sd_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='JobRemoved',"
"path='/org/freedesktop/systemd1'",
match_job_removed,
m);
if (r < 0) {
log_error("Failed to add match for JobRemoved: %s", strerror(-r));
return r;
}
r = sd_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='UnitRemoved',"
"path='/org/freedesktop/systemd1'",
match_unit_removed,
m);
if (r < 0) {
log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
return r;
}
r = sd_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.DBus.Properties',"
"member='PropertiesChanged'",
match_properties_changed,
m);
if (r < 0) {
log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
return r;
}
r = sd_bus_add_match(m->bus,
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='Reloading',"
"path='/org/freedesktop/systemd1'",
match_reloading,
m);
if (r < 0) {
log_error("Failed to add match for Reloading: %s", strerror(-r));
return r;
}
r = sd_bus_call_method(
m->bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"Subscribe",
&error,
NULL, NULL);
if (r < 0) {
log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
return r;
}
r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
if (r < 0) {
log_error("Failed to register name: %s", strerror(-r));
return r;
}
r = sd_bus_attach_event(m->bus, m->event, 0);
if (r < 0) {
log_error("Failed to attach bus to event loop: %s", strerror(-r));
return r;
}
return 0;
}
void manager_gc(Manager *m, bool drop_not_started) {
Machine *machine;
assert(m);
while ((machine = m->machine_gc_queue)) {
LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
machine->in_gc_queue = false;
if (!machine_check_gc(machine, drop_not_started)) {
machine_stop(machine);
machine_free(machine);
}
}
}
int manager_startup(Manager *m) {
Machine *machine;
Iterator i;
int r;
assert(m);
/* Connect to the bus */
r = manager_connect_bus(m);
if (r < 0)
return r;
/* Deserialize state */
manager_enumerate_machines(m);
/* Remove stale objects before we start them */
manager_gc(m, false);
/* And start everything */
HASHMAP_FOREACH(machine, m->machines, i)
machine_start(machine, NULL, NULL);
return 0;
}
static bool check_idle(void *userdata) {
Manager *m = userdata;
manager_gc(m, true);
return hashmap_isempty(m->machines);
}
int manager_run(Manager *m) {
assert(m);
return bus_event_loop_with_idle(
m->event,
m->bus,
"org.freedesktop.machine1",
DEFAULT_EXIT_USEC,
check_idle, m);
}
int main(int argc, char *argv[]) {
Manager *m = NULL;
int r;
log_set_target(LOG_TARGET_AUTO);
log_set_facility(LOG_AUTH);
log_parse_environment();
log_open();
umask(0022);
if (argc != 1) {
log_error("This program takes no arguments.");
r = -EINVAL;
goto finish;
}
/* Always create the directories people can create inotify
* watches in. Note that some applications might check for the
* existence of /run/systemd/machines/ to determine whether
* machined is available, so please always make sure this
* check stays in. */
mkdir_label("/run/systemd/machines", 0755);
m = manager_new();
if (!m) {
r = log_oom();
goto finish;
}
r = manager_startup(m);
if (r < 0) {
log_error("Failed to fully start up daemon: %s", strerror(-r));
goto finish;
}
log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
sd_notify(false,
"READY=1\n"
"STATUS=Processing requests...");
r = manager_run(m);
log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
finish:
sd_notify(false,
"STATUS=Shutting down...");
if (m)
manager_free(m);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}