1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <systemd/sd-messages.h>
34 #include "unit-name.h"
35 #include "dbus-common.h"
38 Machine* machine_new(Manager *manager, const char *name) {
48 m->name = strdup(name);
52 m->state_file = strappend("/run/systemd/machines/", m->name);
56 if (hashmap_put(manager->machines, m->name, m) < 0)
59 m->class = _MACHINE_CLASS_INVALID;
72 void machine_free(Machine *m) {
76 LIST_REMOVE(Machine, gc_queue, m->manager->machine_gc_queue, m);
79 hashmap_remove(m->manager->machine_units, m->scope);
85 hashmap_remove(m->manager->machines, m->name);
87 if (m->create_message)
88 dbus_message_unref(m->create_message);
93 free(m->root_directory);
97 int machine_save(Machine *m) {
98 _cleanup_free_ char *temp_path = NULL;
99 _cleanup_fclose_ FILE *f = NULL;
103 assert(m->state_file);
108 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
112 r = fopen_temporary(m->state_file, &f, &temp_path);
116 fchmod(fileno(f), 0644);
119 "# This is private data. Do not parse.\n"
124 fprintf(f, "SCOPE=%s\n", m->scope);
127 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
130 fprintf(f, "SERVICE=%s\n", m->service);
132 if (m->root_directory)
133 fprintf(f, "ROOT=%s\n", m->root_directory);
135 if (!sd_id128_equal(m->id, SD_ID128_NULL))
136 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
139 fprintf(f, "LEADER=%lu\n", (unsigned long) m->leader);
141 if (m->class != _MACHINE_CLASS_INVALID)
142 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
144 if (dual_timestamp_is_set(&m->timestamp))
148 (unsigned long long) m->timestamp.realtime,
149 (unsigned long long) m->timestamp.monotonic);
153 if (ferror(f) || rename(temp_path, m->state_file) < 0) {
155 unlink(m->state_file);
161 log_error("Failed to save machine data for %s: %s", m->name, strerror(-r));
166 int machine_load(Machine *m) {
167 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL;
172 r = parse_env_file(m->state_file, NEWLINE,
174 "SCOPE_JOB", &m->scope_job,
175 "SERVICE", &m->service,
176 "ROOT", &m->root_directory,
180 "REALTIME", &realtime,
181 "MONOTONIC", &monotonic,
187 log_error("Failed to read %s: %s", m->state_file, strerror(-r));
192 sd_id128_from_string(id, &m->id);
195 parse_pid(leader, &m->leader);
200 c = machine_class_from_string(class);
206 unsigned long long l;
207 if (sscanf(realtime, "%llu", &l) > 0)
208 m->timestamp.realtime = l;
212 unsigned long long l;
213 if (sscanf(monotonic, "%llu", &l) > 0)
214 m->timestamp.monotonic = l;
220 static int machine_start_scope(Machine *m) {
221 _cleanup_free_ char *description = NULL;
228 dbus_error_init(&error);
231 _cleanup_free_ char *escaped = NULL;
234 escaped = unit_name_escape(m->name);
238 scope = strjoin("machine-", escaped, ".scope", NULL);
242 description = strappend(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
244 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, &error, &job);
246 log_error("Failed to start machine scope: %s", bus_error(&error, r));
247 dbus_error_free(&error);
259 hashmap_put(m->manager->machine_units, m->scope, m);
264 int machine_start(Machine *m) {
273 r = machine_start_scope(m);
278 MESSAGE_ID(SD_MESSAGE_MACHINE_START),
280 "LEADER=%lu", (unsigned long) m->leader,
281 "MESSAGE=New machine %s.", m->name,
284 if (!dual_timestamp_is_set(&m->timestamp))
285 dual_timestamp_get(&m->timestamp);
289 /* Save new machine data */
292 machine_send_signal(m, true);
297 static int machine_stop_scope(Machine *m) {
304 dbus_error_init(&error);
309 r = manager_stop_unit(m->manager, m->scope, &error, &job);
311 log_error("Failed to stop machine scope: %s", bus_error(&error, r));
312 dbus_error_free(&error);
322 int machine_stop(Machine *m) {
328 MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
330 "LEADER=%lu", (unsigned long) m->leader,
331 "MESSAGE=Machine %s terminated.", m->name,
335 k = machine_stop_scope(m);
339 unlink(m->state_file);
340 machine_add_to_gc_queue(m);
343 machine_send_signal(m, false);
350 int machine_check_gc(Machine *m, bool drop_not_started) {
353 if (drop_not_started && !m->started)
360 return manager_unit_is_active(m->manager, m->scope) != 0;
365 void machine_add_to_gc_queue(Machine *m) {
371 LIST_PREPEND(Machine, gc_queue, m->manager->machine_gc_queue, m);
372 m->in_gc_queue = true;
375 MachineState machine_get_state(Machine *s) {
379 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
381 return MACHINE_RUNNING;
384 int machine_kill(Machine *m, KillWho who, int signo) {
390 return manager_kill_unit(m->manager, m->scope, who, signo, NULL);
393 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
394 [MACHINE_CONTAINER] = "container",
398 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
400 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
401 [MACHINE_OPENING] = "opening",
402 [MACHINE_RUNNING] = "running",
403 [MACHINE_CLOSING] = "closing"
406 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
408 static const char* const kill_who_table[_KILL_WHO_MAX] = {
409 [KILL_LEADER] = "leader",
413 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);