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 char *escaped = NULL;
233 escaped = unit_name_escape(m->name);
237 m->scope = strjoin("machine-", escaped, ".scope", NULL);
243 r = hashmap_put(m->manager->machine_units, m->scope, m);
245 log_warning("Failed to create mapping between unit and machine");
248 description = strappend(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
250 r = manager_start_scope(m->manager, m->scope, m->leader, SPECIAL_MACHINE_SLICE, description, &error, &job);
252 log_error("Failed to start machine scope: %s", bus_error(&error, r));
253 dbus_error_free(&error);
262 int machine_start(Machine *m) {
271 r = machine_start_scope(m);
276 MESSAGE_ID(SD_MESSAGE_MACHINE_START),
278 "LEADER=%lu", (unsigned long) m->leader,
279 "MESSAGE=New machine %s.", m->name,
282 if (!dual_timestamp_is_set(&m->timestamp))
283 dual_timestamp_get(&m->timestamp);
287 /* Save new machine data */
290 machine_send_signal(m, true);
295 static int machine_stop_scope(Machine *m) {
302 dbus_error_init(&error);
307 r = manager_stop_unit(m->manager, m->scope, &error, &job);
309 log_error("Failed to stop machine scope: %s", bus_error(&error, r));
310 dbus_error_free(&error);
320 int machine_stop(Machine *m) {
326 MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
328 "LEADER=%lu", (unsigned long) m->leader,
329 "MESSAGE=Machine %s terminated.", m->name,
333 k = machine_stop_scope(m);
337 unlink(m->state_file);
338 machine_add_to_gc_queue(m);
341 machine_send_signal(m, false);
348 int machine_check_gc(Machine *m, bool drop_not_started) {
351 if (drop_not_started && !m->started)
358 return manager_unit_is_active(m->manager, m->scope) != 0;
363 void machine_add_to_gc_queue(Machine *m) {
369 LIST_PREPEND(Machine, gc_queue, m->manager->machine_gc_queue, m);
370 m->in_gc_queue = true;
373 MachineState machine_get_state(Machine *s) {
377 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
379 return MACHINE_RUNNING;
382 int machine_kill(Machine *m, KillWho who, int signo) {
388 return manager_kill_unit(m->manager, m->scope, who, signo, NULL);
391 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
392 [MACHINE_CONTAINER] = "container",
396 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
398 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
399 [MACHINE_OPENING] = "opening",
400 [MACHINE_RUNNING] = "running",
401 [MACHINE_CLOSING] = "closing"
404 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
406 static const char* const kill_who_table[_KILL_WHO_MAX] = {
407 [KILL_LEADER] = "leader",
411 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);