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("Failed to save machine data %s: %s", m->state_file, strerror(-r));
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 log_error("Failed to read %s: %s", m->state_file, strerror(-r));
267 sd_id128_from_string(id, &m->id);
270 parse_pid(leader, &m->leader);
275 c = machine_class_from_string(class);
281 unsigned long long l;
282 if (sscanf(realtime, "%llu", &l) > 0)
283 m->timestamp.realtime = l;
287 unsigned long long l;
288 if (sscanf(monotonic, "%llu", &l) > 0)
289 m->timestamp.monotonic = l;
293 size_t l, allocated = 0, nr = 0;
294 const char *word, *state;
297 FOREACH_WORD(word, l, netif, state) {
301 *(char*) (mempcpy(buf, word, l)) = 0;
303 if (safe_atoi(buf, &ifi) < 0)
308 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
324 static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
330 _cleanup_free_ char *escaped = NULL;
331 char *scope, *description, *job = NULL;
333 escaped = unit_name_escape(m->name);
337 scope = strjoin("machine-", escaped, ".scope", NULL);
341 description = strappenda(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
343 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
345 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
357 hashmap_put(m->manager->machine_units, m->unit, m);
362 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
370 r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
375 r = machine_start_scope(m, properties, error);
380 MESSAGE_ID(SD_MESSAGE_MACHINE_START),
382 "LEADER="PID_FMT, m->leader,
383 "MESSAGE=New machine %s.", m->name,
386 if (!dual_timestamp_is_set(&m->timestamp))
387 dual_timestamp_get(&m->timestamp);
391 /* Save new machine data */
394 machine_send_signal(m, true);
399 static int machine_stop_scope(Machine *m) {
400 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
409 if (!m->registered) {
410 r = manager_stop_unit(m->manager, m->unit, &error, &job);
412 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
423 int machine_stop(Machine *m) {
429 MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
431 "LEADER="PID_FMT, m->leader,
432 "MESSAGE=Machine %s terminated.", m->name,
436 k = machine_stop_scope(m);
441 machine_add_to_gc_queue(m);
444 machine_send_signal(m, false);
451 bool machine_check_gc(Machine *m, bool drop_not_started) {
454 if (drop_not_started && !m->started)
457 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
460 if (m->unit && manager_unit_is_active(m->manager, m->unit))
466 void machine_add_to_gc_queue(Machine *m) {
472 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
473 m->in_gc_queue = true;
476 MachineState machine_get_state(Machine *s) {
480 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
482 return MACHINE_RUNNING;
485 int machine_kill(Machine *m, KillWho who, int signo) {
491 if (who == KILL_LEADER) {
492 /* If we shall simply kill the leader, do so directly */
494 if (kill(m->leader, signo) < 0)
500 /* Otherwise make PID 1 do it for us, for the entire cgroup */
501 return manager_kill_unit(m->manager, m->unit, signo, NULL);
504 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
505 [MACHINE_CONTAINER] = "container",
509 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
511 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
512 [MACHINE_OPENING] = "opening",
513 [MACHINE_RUNNING] = "running",
514 [MACHINE_CLOSING] = "closing"
517 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
519 static const char* const kill_who_table[_KILL_WHO_MAX] = {
520 [KILL_LEADER] = "leader",
524 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);