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) {
211 /* Create a symlink from the unit name to the machine
212 * name, so that we can quickly find the machine for
214 sl = strjoina("/run/systemd/machines/unit:", m->unit);
215 symlink(m->name, sl);
223 log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
228 static void machine_unlink(Machine *m) {
235 sl = strjoina("/run/systemd/machines/unit:", m->unit);
240 unlink(m->state_file);
243 int machine_load(Machine *m) {
244 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
249 r = parse_env_file(m->state_file, NEWLINE,
251 "SCOPE_JOB", &m->scope_job,
252 "SERVICE", &m->service,
253 "ROOT", &m->root_directory,
257 "REALTIME", &realtime,
258 "MONOTONIC", &monotonic,
265 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
269 sd_id128_from_string(id, &m->id);
272 parse_pid(leader, &m->leader);
277 c = machine_class_from_string(class);
283 unsigned long long l;
284 if (sscanf(realtime, "%llu", &l) > 0)
285 m->timestamp.realtime = l;
289 unsigned long long l;
290 if (sscanf(monotonic, "%llu", &l) > 0)
291 m->timestamp.monotonic = l;
295 size_t l, allocated = 0, nr = 0;
296 const char *word, *state;
299 FOREACH_WORD(word, l, netif, state) {
303 *(char*) (mempcpy(buf, word, l)) = 0;
305 if (safe_atoi(buf, &ifi) < 0)
310 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
326 static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
332 _cleanup_free_ char *escaped = NULL;
333 char *scope, *description, *job = NULL;
335 escaped = unit_name_escape(m->name);
339 scope = strjoin("machine-", escaped, ".scope", NULL);
343 description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
345 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
347 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
359 hashmap_put(m->manager->machine_units, m->unit, m);
364 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
372 r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
377 r = machine_start_scope(m, properties, error);
382 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START),
384 "LEADER="PID_FMT, m->leader,
385 LOG_MESSAGE("New machine %s.", m->name),
388 if (!dual_timestamp_is_set(&m->timestamp))
389 dual_timestamp_get(&m->timestamp);
393 /* Save new machine data */
396 machine_send_signal(m, true);
401 static int machine_stop_scope(Machine *m) {
402 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
411 r = manager_stop_unit(m->manager, m->unit, &error, &job);
413 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);