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 r = manager_stop_unit(m->manager, m->unit, &error, &job);
411 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
421 int machine_stop(Machine *m) {
427 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
429 "LEADER="PID_FMT, m->leader,
430 LOG_MESSAGE("Machine %s terminated.", m->name),
434 k = machine_stop_scope(m);
439 machine_add_to_gc_queue(m);
442 machine_send_signal(m, false);
449 bool machine_check_gc(Machine *m, bool drop_not_started) {
452 if (drop_not_started && !m->started)
455 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
458 if (m->unit && manager_unit_is_active(m->manager, m->unit))
464 void machine_add_to_gc_queue(Machine *m) {
470 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
471 m->in_gc_queue = true;
474 MachineState machine_get_state(Machine *s) {
478 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
480 return MACHINE_RUNNING;
483 int machine_kill(Machine *m, KillWho who, int signo) {
489 if (who == KILL_LEADER) {
490 /* If we shall simply kill the leader, do so directly */
492 if (kill(m->leader, signo) < 0)
498 /* Otherwise make PID 1 do it for us, for the entire cgroup */
499 return manager_kill_unit(m->manager, m->unit, signo, NULL);
502 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
503 [MACHINE_CONTAINER] = "container",
507 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
509 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
510 [MACHINE_OPENING] = "opening",
511 [MACHINE_RUNNING] = "running",
512 [MACHINE_CLOSING] = "closing"
515 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
517 static const char* const kill_who_table[_KILL_WHO_MAX] = {
518 [KILL_LEADER] = "leader",
522 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);