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);
101 int machine_save(Machine *m) {
102 _cleanup_free_ char *temp_path = NULL;
103 _cleanup_fclose_ FILE *f = NULL;
107 assert(m->state_file);
112 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
116 r = fopen_temporary(m->state_file, &f, &temp_path);
120 fchmod(fileno(f), 0644);
123 "# This is private data. Do not parse.\n"
128 _cleanup_free_ char *escaped;
130 escaped = cescape(m->unit);
136 fprintf(f, "SCOPE=%s\n", escaped); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
140 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
143 _cleanup_free_ char *escaped;
145 escaped = cescape(m->service);
150 fprintf(f, "SERVICE=%s\n", escaped);
153 if (m->root_directory) {
154 _cleanup_free_ char *escaped;
156 escaped = cescape(m->root_directory);
161 fprintf(f, "ROOT=%s\n", escaped);
164 if (!sd_id128_equal(m->id, SD_ID128_NULL))
165 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
168 fprintf(f, "LEADER="PID_FMT"\n", m->leader);
170 if (m->class != _MACHINE_CLASS_INVALID)
171 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
173 if (dual_timestamp_is_set(&m->timestamp))
175 "REALTIME="USEC_FMT"\n"
176 "MONOTONIC="USEC_FMT"\n",
177 m->timestamp.realtime,
178 m->timestamp.monotonic);
180 if (m->n_netif > 0) {
185 for (i = 0; i < m->n_netif; i++) {
189 fprintf(f, "%i", m->netif[i]);
195 r = fflush_and_check(f);
199 if (rename(temp_path, m->state_file) < 0) {
207 /* Create a symlink from the unit name to the machine
208 * name, so that we can quickly find the machine for
210 sl = strappenda("/run/systemd/machines/unit:", m->unit);
211 symlink(m->name, sl);
219 log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
225 static void machine_unlink(Machine *m) {
232 sl = strappenda("/run/systemd/machines/unit:", m->unit);
237 unlink(m->state_file);
240 int machine_load(Machine *m) {
241 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
246 r = parse_env_file(m->state_file, NEWLINE,
248 "SCOPE_JOB", &m->scope_job,
249 "SERVICE", &m->service,
250 "ROOT", &m->root_directory,
254 "REALTIME", &realtime,
255 "MONOTONIC", &monotonic,
262 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
266 sd_id128_from_string(id, &m->id);
269 parse_pid(leader, &m->leader);
274 c = machine_class_from_string(class);
280 unsigned long long l;
281 if (sscanf(realtime, "%llu", &l) > 0)
282 m->timestamp.realtime = l;
286 unsigned long long l;
287 if (sscanf(monotonic, "%llu", &l) > 0)
288 m->timestamp.monotonic = l;
292 size_t l, allocated = 0, nr = 0;
293 const char *word, *state;
296 FOREACH_WORD(word, l, netif, state) {
300 *(char*) (mempcpy(buf, word, l)) = 0;
302 if (safe_atoi(buf, &ifi) < 0)
307 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
323 static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
329 _cleanup_free_ char *escaped = NULL;
330 char *scope, *description, *job = NULL;
332 escaped = unit_name_escape(m->name);
336 scope = strjoin("machine-", escaped, ".scope", NULL);
340 description = strappenda(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
342 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
344 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
356 hashmap_put(m->manager->machine_units, m->unit, m);
361 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
369 r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
374 r = machine_start_scope(m, properties, error);
379 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START),
381 "LEADER="PID_FMT, m->leader,
382 LOG_MESSAGE("New machine %s.", m->name),
385 if (!dual_timestamp_is_set(&m->timestamp))
386 dual_timestamp_get(&m->timestamp);
390 /* Save new machine data */
393 machine_send_signal(m, true);
398 static int machine_stop_scope(Machine *m) {
399 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
408 if (!m->registered) {
409 r = manager_stop_unit(m->manager, m->unit, &error, &job);
411 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
422 int machine_stop(Machine *m) {
428 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
430 "LEADER="PID_FMT, m->leader,
431 LOG_MESSAGE("Machine %s terminated.", m->name),
435 k = machine_stop_scope(m);
440 machine_add_to_gc_queue(m);
443 machine_send_signal(m, false);
450 bool machine_check_gc(Machine *m, bool drop_not_started) {
453 if (drop_not_started && !m->started)
456 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
459 if (m->unit && manager_unit_is_active(m->manager, m->unit))
465 void machine_add_to_gc_queue(Machine *m) {
471 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
472 m->in_gc_queue = true;
475 MachineState machine_get_state(Machine *s) {
479 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
481 return MACHINE_RUNNING;
484 int machine_kill(Machine *m, KillWho who, int signo) {
490 if (who == KILL_LEADER) {
491 /* If we shall simply kill the leader, do so directly */
493 if (kill(m->leader, signo) < 0)
499 /* Otherwise make PID 1 do it for us, for the entire cgroup */
500 return manager_kill_unit(m->manager, m->unit, signo, NULL);
503 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
504 [MACHINE_CONTAINER] = "container",
508 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
510 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
511 [MACHINE_OPENING] = "opening",
512 [MACHINE_RUNNING] = "running",
513 [MACHINE_CLOSING] = "closing"
516 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
518 static const char* const kill_who_table[_KILL_WHO_MAX] = {
519 [KILL_LEADER] = "leader",
523 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);