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->unit);
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->unit); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
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="PID_FMT"\n", 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))
149 "REALTIME="USEC_FMT"\n"
150 "MONOTONIC="USEC_FMT"\n",
151 m->timestamp.realtime,
152 m->timestamp.monotonic);
156 if (ferror(f) || rename(temp_path, m->state_file) < 0) {
158 unlink(m->state_file);
165 /* Create a symlink from the unit name to the machine
166 * name, so that we can quickly find the machine for
168 sl = strappenda("/run/systemd/machines/unit:", m->unit);
169 symlink(m->name, sl);
174 log_error("Failed to save machine data %s: %s", m->state_file, strerror(-r));
179 static void machine_unlink(Machine *m) {
186 sl = strappenda("/run/systemd/machines/unit:", m->unit);
191 unlink(m->state_file);
194 int machine_load(Machine *m) {
195 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL;
200 r = parse_env_file(m->state_file, NEWLINE,
202 "SCOPE_JOB", &m->scope_job,
203 "SERVICE", &m->service,
204 "ROOT", &m->root_directory,
208 "REALTIME", &realtime,
209 "MONOTONIC", &monotonic,
215 log_error("Failed to read %s: %s", m->state_file, strerror(-r));
220 sd_id128_from_string(id, &m->id);
223 parse_pid(leader, &m->leader);
228 c = machine_class_from_string(class);
234 unsigned long long l;
235 if (sscanf(realtime, "%llu", &l) > 0)
236 m->timestamp.realtime = l;
240 unsigned long long l;
241 if (sscanf(monotonic, "%llu", &l) > 0)
242 m->timestamp.monotonic = l;
248 static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
254 _cleanup_free_ char *escaped = NULL;
255 char *scope, *description, *job = NULL;
257 escaped = unit_name_escape(m->name);
261 scope = strjoin("machine-", escaped, ".scope", NULL);
265 description = strappenda(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
267 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
269 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
281 hashmap_put(m->manager->machine_units, m->unit, m);
286 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
294 r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
299 r = machine_start_scope(m, properties, error);
304 MESSAGE_ID(SD_MESSAGE_MACHINE_START),
306 "LEADER=%lu", (unsigned long) m->leader,
307 "MESSAGE=New machine %s.", m->name,
310 if (!dual_timestamp_is_set(&m->timestamp))
311 dual_timestamp_get(&m->timestamp);
315 /* Save new machine data */
318 machine_send_signal(m, true);
323 static int machine_stop_scope(Machine *m) {
324 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
333 r = manager_stop_unit(m->manager, m->unit, &error, &job);
335 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
345 int machine_stop(Machine *m) {
351 MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
353 "LEADER=%lu", (unsigned long) m->leader,
354 "MESSAGE=Machine %s terminated.", m->name,
358 k = machine_stop_scope(m);
363 machine_add_to_gc_queue(m);
366 machine_send_signal(m, false);
373 bool machine_check_gc(Machine *m, bool drop_not_started) {
376 if (drop_not_started && !m->started)
379 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
382 if (m->unit && manager_unit_is_active(m->manager, m->unit))
388 void machine_add_to_gc_queue(Machine *m) {
394 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
395 m->in_gc_queue = true;
398 MachineState machine_get_state(Machine *s) {
402 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
404 return MACHINE_RUNNING;
407 int machine_kill(Machine *m, KillWho who, int signo) {
413 return manager_kill_unit(m->manager, m->unit, who, signo, NULL);
416 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
417 [MACHINE_CONTAINER] = "container",
421 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
423 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
424 [MACHINE_OPENING] = "opening",
425 [MACHINE_RUNNING] = "running",
426 [MACHINE_CLOSING] = "closing"
429 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
431 static const char* const kill_who_table[_KILL_WHO_MAX] = {
432 [KILL_LEADER] = "leader",
436 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);