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);
88 sd_bus_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, sd_bus_message *properties, sd_bus_error *error) {
226 _cleanup_free_ char *escaped = NULL;
227 char *scope, *description, *job;
229 escaped = unit_name_escape(m->name);
233 scope = strjoin("machine-", escaped, ".scope", NULL);
237 description = strappenda(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
239 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
241 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
253 hashmap_put(m->manager->machine_units, m->scope, m);
258 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
267 r = machine_start_scope(m, properties, error);
272 MESSAGE_ID(SD_MESSAGE_MACHINE_START),
274 "LEADER=%lu", (unsigned long) m->leader,
275 "MESSAGE=New machine %s.", m->name,
278 if (!dual_timestamp_is_set(&m->timestamp))
279 dual_timestamp_get(&m->timestamp);
283 /* Save new machine data */
286 machine_send_signal(m, true);
291 static int machine_stop_scope(Machine *m) {
292 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
301 r = manager_stop_unit(m->manager, m->scope, &error, &job);
303 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
313 int machine_stop(Machine *m) {
319 MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
321 "LEADER=%lu", (unsigned long) m->leader,
322 "MESSAGE=Machine %s terminated.", m->name,
326 k = machine_stop_scope(m);
330 unlink(m->state_file);
331 machine_add_to_gc_queue(m);
334 machine_send_signal(m, false);
341 bool machine_check_gc(Machine *m, bool drop_not_started) {
344 if (drop_not_started && !m->started)
347 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
350 if (m->scope && manager_unit_is_active(m->manager, m->scope))
356 void machine_add_to_gc_queue(Machine *m) {
362 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
363 m->in_gc_queue = true;
366 MachineState machine_get_state(Machine *s) {
370 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
372 return MACHINE_RUNNING;
375 int machine_kill(Machine *m, KillWho who, int signo) {
381 return manager_kill_unit(m->manager, m->scope, who, signo, NULL);
384 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
385 [MACHINE_CONTAINER] = "container",
389 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
391 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
392 [MACHINE_OPENING] = "opening",
393 [MACHINE_RUNNING] = "running",
394 [MACHINE_CLOSING] = "closing"
397 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
399 static const char* const kill_who_table[_KILL_WHO_MAX] = {
400 [KILL_LEADER] = "leader",
404 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);