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 "sd-messages.h"
34 #include "unit-name.h"
37 #include "bus-error.h"
39 Machine* machine_new(Manager *manager, const char *name) {
49 m->name = strdup(name);
53 m->state_file = strappend("/run/systemd/machines/", m->name);
57 if (hashmap_put(manager->machines, m->name, m) < 0)
60 m->class = _MACHINE_CLASS_INVALID;
73 void machine_free(Machine *m) {
77 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
80 hashmap_remove(m->manager->machine_units, m->scope);
86 hashmap_remove(m->manager->machines, m->name);
89 hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
91 sd_bus_message_unref(m->create_message);
96 free(m->root_directory);
100 int machine_save(Machine *m) {
101 _cleanup_free_ char *temp_path = NULL;
102 _cleanup_fclose_ FILE *f = NULL;
106 assert(m->state_file);
111 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
115 r = fopen_temporary(m->state_file, &f, &temp_path);
119 fchmod(fileno(f), 0644);
122 "# This is private data. Do not parse.\n"
127 fprintf(f, "SCOPE=%s\n", m->scope);
130 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
133 fprintf(f, "SERVICE=%s\n", m->service);
135 if (m->root_directory)
136 fprintf(f, "ROOT=%s\n", m->root_directory);
138 if (!sd_id128_equal(m->id, SD_ID128_NULL))
139 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
142 fprintf(f, "LEADER=%lu\n", (unsigned long) m->leader);
144 if (m->class != _MACHINE_CLASS_INVALID)
145 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
147 if (dual_timestamp_is_set(&m->timestamp))
151 (unsigned long long) m->timestamp.realtime,
152 (unsigned long long) m->timestamp.monotonic);
156 if (ferror(f) || rename(temp_path, m->state_file) < 0) {
158 unlink(m->state_file);
164 log_error("Failed to save machine data for %s: %s", m->name, strerror(-r));
169 int machine_load(Machine *m) {
170 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL;
175 r = parse_env_file(m->state_file, NEWLINE,
177 "SCOPE_JOB", &m->scope_job,
178 "SERVICE", &m->service,
179 "ROOT", &m->root_directory,
183 "REALTIME", &realtime,
184 "MONOTONIC", &monotonic,
190 log_error("Failed to read %s: %s", m->state_file, strerror(-r));
195 sd_id128_from_string(id, &m->id);
198 parse_pid(leader, &m->leader);
203 c = machine_class_from_string(class);
209 unsigned long long l;
210 if (sscanf(realtime, "%llu", &l) > 0)
211 m->timestamp.realtime = l;
215 unsigned long long l;
216 if (sscanf(monotonic, "%llu", &l) > 0)
217 m->timestamp.monotonic = l;
223 static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
229 _cleanup_free_ char *escaped = NULL;
230 char *scope, *description, *job;
232 escaped = unit_name_escape(m->name);
236 scope = strjoin("machine-", escaped, ".scope", NULL);
240 description = strappenda(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
242 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
244 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
256 hashmap_put(m->manager->machine_units, m->scope, m);
261 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
269 r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
274 r = machine_start_scope(m, properties, error);
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) {
299 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
308 r = manager_stop_unit(m->manager, m->scope, &error, &job);
310 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
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 bool machine_check_gc(Machine *m, bool drop_not_started) {
351 if (drop_not_started && !m->started)
354 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
357 if (m->scope && manager_unit_is_active(m->manager, m->scope))
363 void machine_add_to_gc_queue(Machine *m) {
369 LIST_PREPEND(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);