machined.c revision d3e84ddb885e9d5f0ae9930eb905910e3a81f157
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering/***
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering This file is part of systemd.
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering Copyright 2013 Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering systemd is free software; you can redistribute it and/or modify it
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering under the terms of the GNU Lesser General Public License as published by
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering (at your option) any later version.
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering systemd is distributed in the hope that it will be useful, but
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering Lesser General Public License for more details.
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering You should have received a copy of the GNU Lesser General Public License
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering***/
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering#include <errno.h>
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering#include <pwd.h>
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering#include <fcntl.h>
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen#include <string.h>
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering#include <unistd.h>
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering#include <sys/epoll.h>
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering#include "sd-daemon.h"
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering#include "strv.h"
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering#include "conf-parser.h"
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering#include "cgroup-util.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "mkdir.h"
7778dffff3d8bd7438fe19a248c16203668324c9Daniel Mack#include "bus-util.h"
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen#include "bus-error.h"
71d35b6b5563817dfbe757ab9e3b9f018b2db491Thomas Hindoe Paaboel Andersen#include "machined.h"
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart PoetteringManager *manager_new(void) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering Manager *m;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering int r;
931851e8e492a4d2715e22dcde50a5e7ccef4b49Lennart Poettering
931851e8e492a4d2715e22dcde50a5e7ccef4b49Lennart Poettering m = new0(Manager, 1);
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering if (!m)
a407657425a3e47fd2b559cd3bc800f791303f63Lennart Poettering return NULL;
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering m->machines = hashmap_new(string_hash_func, string_compare_func);
4d506d6bb757af3b99e0876234c465e6898c5ea4Lennart Poettering m->machine_units = hashmap_new(string_hash_func, string_compare_func);
7778dffff3d8bd7438fe19a248c16203668324c9Daniel Mack m->machine_leaders = hashmap_new(trivial_hash_func, trivial_compare_func);
7778dffff3d8bd7438fe19a248c16203668324c9Daniel Mack
if (!m->machines || !m->machine_units || !m->machine_leaders) {
manager_free(m);
return NULL;
}
r = sd_event_new(&m->event);
if (r < 0) {
manager_free(m);
return NULL;
}
return m;
}
void manager_free(Manager *m) {
Machine *machine;
assert(m);
while ((machine = hashmap_first(m->machines)))
machine_free(machine);
hashmap_free(m->machines);
hashmap_free(m->machine_units);
hashmap_free(m->machine_leaders);
sd_bus_unref(m->bus);
sd_event_unref(m->event);
free(m);
}
int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
Machine *machine;
assert(m);
assert(name);
machine = hashmap_get(m->machines, name);
if (!machine) {
machine = machine_new(m, name);
if (!machine)
return -ENOMEM;
}
if (_machine)
*_machine = machine;
return 0;
}
int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
_cleanup_free_ char *unit = NULL;
Machine *mm;
int r;
assert(m);
assert(pid >= 1);
assert(machine);
r = cg_pid_get_unit(pid, &unit);
if (r < 0)
mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
else
mm = hashmap_get(m->machine_units, unit);
if (!mm)
return 0;
*machine = mm;
return 1;
}
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_open_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", SD_BUS_NAME_DO_NOT_QUEUE);
if (r < 0) {
log_error("Failed to register name: %s", strerror(-r));
return r;
}
if (r != SD_BUS_NAME_PRIMARY_OWNER) {
log_error("Failed to acquire name.");
return -EEXIST;
}
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;
}
int manager_run(Manager *m) {
int r;
assert(m);
for (;;) {
r = sd_event_get_state(m->event);
if (r < 0)
return r;
if (r == SD_EVENT_FINISHED)
return 0;
manager_gc(m, true);
r = sd_event_run(m->event, (uint64_t) -1);
if (r < 0)
return r;
}
return 0;
}
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;
}