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"
36 #include "bus-error.h"
38 #include "machine-dbus.h"
40 Machine* machine_new(Manager *manager, const char *name) {
50 m->name = strdup(name);
54 m->state_file = strappend("/run/systemd/machines/", m->name);
58 if (hashmap_put(manager->machines, m->name, m) < 0)
61 m->class = _MACHINE_CLASS_INVALID;
74 void machine_free(Machine *m) {
78 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
81 hashmap_remove(m->manager->machine_units, m->unit);
87 hashmap_remove(m->manager->machines, m->name);
90 hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
92 sd_bus_message_unref(m->create_message);
97 free(m->root_directory);
102 int machine_save(Machine *m) {
103 _cleanup_free_ char *temp_path = NULL;
104 _cleanup_fclose_ FILE *f = NULL;
108 assert(m->state_file);
113 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
117 r = fopen_temporary(m->state_file, &f, &temp_path);
121 fchmod(fileno(f), 0644);
124 "# This is private data. Do not parse.\n"
129 _cleanup_free_ char *escaped;
131 escaped = cescape(m->unit);
137 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 */
141 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
144 _cleanup_free_ char *escaped;
146 escaped = cescape(m->service);
151 fprintf(f, "SERVICE=%s\n", escaped);
154 if (m->root_directory) {
155 _cleanup_free_ char *escaped;
157 escaped = cescape(m->root_directory);
162 fprintf(f, "ROOT=%s\n", escaped);
165 if (!sd_id128_equal(m->id, SD_ID128_NULL))
166 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
169 fprintf(f, "LEADER="PID_FMT"\n", m->leader);
171 if (m->class != _MACHINE_CLASS_INVALID)
172 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
174 if (dual_timestamp_is_set(&m->timestamp))
176 "REALTIME="USEC_FMT"\n"
177 "MONOTONIC="USEC_FMT"\n",
178 m->timestamp.realtime,
179 m->timestamp.monotonic);
181 if (m->n_netif > 0) {
186 for (i = 0; i < m->n_netif; i++) {
190 fprintf(f, "%i", m->netif[i]);
196 r = fflush_and_check(f);
200 if (rename(temp_path, m->state_file) < 0) {
208 /* Create a symlink from the unit name to the machine
209 * name, so that we can quickly find the machine for
211 sl = strappenda("/run/systemd/machines/unit:", m->unit);
212 symlink(m->name, sl);
220 log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
226 static void machine_unlink(Machine *m) {
233 sl = strappenda("/run/systemd/machines/unit:", m->unit);
238 unlink(m->state_file);
241 int machine_load(Machine *m) {
242 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
247 r = parse_env_file(m->state_file, NEWLINE,
249 "SCOPE_JOB", &m->scope_job,
250 "SERVICE", &m->service,
251 "ROOT", &m->root_directory,
255 "REALTIME", &realtime,
256 "MONOTONIC", &monotonic,
263 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
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 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START),
382 "LEADER="PID_FMT, m->leader,
383 LOG_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 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
431 "LEADER="PID_FMT, m->leader,
432 LOG_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);