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>
30 #include "cgroup-util.h"
35 #include "unit-name.h"
36 #include "dbus-common.h"
37 #include "logind-machine.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(Machine, 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 if (m->create_message)
89 dbus_message_unref(m->create_message);
94 free(m->root_directory);
98 int machine_save(Machine *m) {
99 _cleanup_free_ char *temp_path = NULL;
100 _cleanup_fclose_ FILE *f = NULL;
104 assert(m->state_file);
109 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
113 r = fopen_temporary(m->state_file, &f, &temp_path);
117 fchmod(fileno(f), 0644);
120 "# This is private data. Do not parse.\n"
125 fprintf(f, "SCOPE=%s\n", m->scope);
128 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
131 fprintf(f, "SERVICE=%s\n", m->service);
133 if (m->root_directory)
134 fprintf(f, "ROOT=%s\n", m->root_directory);
136 if (!sd_id128_equal(m->id, SD_ID128_NULL))
137 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
140 fprintf(f, "LEADER=%lu\n", (unsigned long) m->leader);
142 if (m->class != _MACHINE_CLASS_INVALID)
143 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
145 if (dual_timestamp_is_set(&m->timestamp))
149 (unsigned long long) m->timestamp.realtime,
150 (unsigned long long) m->timestamp.monotonic);
154 if (ferror(f) || rename(temp_path, m->state_file) < 0) {
156 unlink(m->state_file);
162 log_error("Failed to save machine data for %s: %s", m->name, strerror(-r));
167 int machine_load(Machine *m) {
168 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL;
173 r = parse_env_file(m->state_file, NEWLINE,
175 "SCOPE_JOB", &m->scope_job,
176 "SERVICE", &m->service,
177 "ROOT", &m->root_directory,
181 "REALTIME", &realtime,
182 "MONOTONIC", &monotonic,
188 log_error("Failed to read %s: %s", m->state_file, strerror(-r));
193 sd_id128_from_string(id, &m->id);
196 parse_pid(leader, &m->leader);
201 c = machine_class_from_string(class);
207 unsigned long long l;
208 if (sscanf(realtime, "%llu", &l) > 0)
209 m->timestamp.realtime = l;
213 unsigned long long l;
214 if (sscanf(monotonic, "%llu", &l) > 0)
215 m->timestamp.monotonic = l;
221 static int machine_start_scope(Machine *m) {
222 _cleanup_free_ char *description = NULL;
229 dbus_error_init(&error);
232 _cleanup_free_ char *escaped = NULL;
234 escaped = unit_name_escape(m->name);
238 m->scope = strjoin("machine-", m->name, ".scope", NULL);
242 r = hashmap_put(m->manager->machine_units, m->scope, m);
244 log_warning("Failed to create mapping between unit and machine");
247 description = strappend(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
249 r = manager_start_scope(m->manager, m->scope, m->leader, SPECIAL_MACHINE_SLICE, description, &error, &job);
251 log_error("Failed to start machine scope: %s", bus_error(&error, r));
252 dbus_error_free(&error);
261 int machine_start(Machine *m) {
270 r = machine_start_scope(m);
275 MESSAGE_ID(SD_MESSAGE_MACHINE_START),
277 "LEADER=%lu", (unsigned long) m->leader,
278 "MESSAGE=New machine %s.", m->name,
281 if (!dual_timestamp_is_set(&m->timestamp))
282 dual_timestamp_get(&m->timestamp);
286 /* Save new machine data */
289 machine_send_signal(m, true);
294 static int machine_stop_scope(Machine *m) {
301 dbus_error_init(&error);
306 r = manager_stop_unit(m->manager, m->scope, &error, &job);
308 log_error("Failed to stop machine scope: %s", bus_error(&error, r));
309 dbus_error_free(&error);
319 int machine_stop(Machine *m) {
325 MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
327 "LEADER=%lu", (unsigned long) m->leader,
328 "MESSAGE=Machine %s terminated.", m->name,
332 k = machine_stop_scope(m);
336 unlink(m->state_file);
337 machine_add_to_gc_queue(m);
340 machine_send_signal(m, false);
347 int machine_check_gc(Machine *m, bool drop_not_started) {
350 if (drop_not_started && !m->started)
357 return manager_unit_is_active(m->manager, m->scope) != 0;
362 void machine_add_to_gc_queue(Machine *m) {
368 LIST_PREPEND(Machine, gc_queue, m->manager->machine_gc_queue, m);
369 m->in_gc_queue = true;
372 MachineState machine_get_state(Machine *s) {
376 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
378 return MACHINE_RUNNING;
381 int machine_kill(Machine *m, KillWho who, int signo) {
387 return manager_kill_unit(m->manager, m->scope, who, signo, NULL);
390 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
391 [MACHINE_CONTAINER] = "container",
395 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
397 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
398 [MACHINE_OPENING] = "opening",
399 [MACHINE_RUNNING] = "running",
400 [MACHINE_CLOSING] = "closing"
403 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);