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, DBusMessageIter *iter) {
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, iter, &error, &job);
246 log_error("Failed to start machine scope: %s", bus_error(&error, r));
247 dbus_error_free(&error);
260 hashmap_put(m->manager->machine_units, m->scope, m);
265 int machine_start(Machine *m, DBusMessageIter *iter) {
274 r = machine_start_scope(m, iter);
279 MESSAGE_ID(SD_MESSAGE_MACHINE_START),
281 "LEADER=%lu", (unsigned long) m->leader,
282 "MESSAGE=New machine %s.", m->name,
285 if (!dual_timestamp_is_set(&m->timestamp))
286 dual_timestamp_get(&m->timestamp);
290 /* Save new machine data */
293 machine_send_signal(m, true);
298 static int machine_stop_scope(Machine *m) {
305 dbus_error_init(&error);
310 r = manager_stop_unit(m->manager, m->scope, &error, &job);
312 log_error("Failed to stop machine scope: %s", bus_error(&error, r));
313 dbus_error_free(&error);
323 int machine_stop(Machine *m) {
329 MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
331 "LEADER=%lu", (unsigned long) m->leader,
332 "MESSAGE=Machine %s terminated.", m->name,
336 k = machine_stop_scope(m);
340 unlink(m->state_file);
341 machine_add_to_gc_queue(m);
344 machine_send_signal(m, false);
351 int machine_check_gc(Machine *m, bool drop_not_started) {
354 if (drop_not_started && !m->started)
361 return manager_unit_is_active(m->manager, m->scope) != 0;
366 void machine_add_to_gc_queue(Machine *m) {
372 LIST_PREPEND(Machine, gc_queue, m->manager->machine_gc_queue, m);
373 m->in_gc_queue = true;
376 MachineState machine_get_state(Machine *s) {
380 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
382 return MACHINE_RUNNING;
385 int machine_kill(Machine *m, KillWho who, int signo) {
391 return manager_kill_unit(m->manager, m->scope, who, signo, NULL);
394 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
395 [MACHINE_CONTAINER] = "container",
399 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
401 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
402 [MACHINE_OPENING] = "opening",
403 [MACHINE_RUNNING] = "running",
404 [MACHINE_CLOSING] = "closing"
407 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
409 static const char* const kill_who_table[_KILL_WHO_MAX] = {
410 [KILL_LEADER] = "leader",
414 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);