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 machine_operation_unref(m->operations);
81 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
84 hashmap_remove(m->manager->machine_units, m->unit);
90 hashmap_remove(m->manager->machines, m->name);
93 hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
95 sd_bus_message_unref(m->create_message);
100 free(m->root_directory);
105 int machine_save(Machine *m) {
106 _cleanup_free_ char *temp_path = NULL;
107 _cleanup_fclose_ FILE *f = NULL;
111 assert(m->state_file);
116 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
120 r = fopen_temporary(m->state_file, &f, &temp_path);
124 fchmod(fileno(f), 0644);
127 "# This is private data. Do not parse.\n"
132 _cleanup_free_ char *escaped;
134 escaped = cescape(m->unit);
140 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 */
144 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
147 _cleanup_free_ char *escaped;
149 escaped = cescape(m->service);
154 fprintf(f, "SERVICE=%s\n", escaped);
157 if (m->root_directory) {
158 _cleanup_free_ char *escaped;
160 escaped = cescape(m->root_directory);
165 fprintf(f, "ROOT=%s\n", escaped);
168 if (!sd_id128_equal(m->id, SD_ID128_NULL))
169 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
172 fprintf(f, "LEADER="PID_FMT"\n", m->leader);
174 if (m->class != _MACHINE_CLASS_INVALID)
175 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
177 if (dual_timestamp_is_set(&m->timestamp))
179 "REALTIME="USEC_FMT"\n"
180 "MONOTONIC="USEC_FMT"\n",
181 m->timestamp.realtime,
182 m->timestamp.monotonic);
184 if (m->n_netif > 0) {
189 for (i = 0; i < m->n_netif; i++) {
193 fprintf(f, "%i", m->netif[i]);
199 r = fflush_and_check(f);
203 if (rename(temp_path, m->state_file) < 0) {
214 /* Create a symlink from the unit name to the machine
215 * name, so that we can quickly find the machine for
217 sl = strjoina("/run/systemd/machines/unit:", m->unit);
218 symlink(m->name, sl);
226 log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
231 static void machine_unlink(Machine *m) {
238 sl = strjoina("/run/systemd/machines/unit:", m->unit);
243 unlink(m->state_file);
246 int machine_load(Machine *m) {
247 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
252 r = parse_env_file(m->state_file, NEWLINE,
254 "SCOPE_JOB", &m->scope_job,
255 "SERVICE", &m->service,
256 "ROOT", &m->root_directory,
260 "REALTIME", &realtime,
261 "MONOTONIC", &monotonic,
268 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
272 sd_id128_from_string(id, &m->id);
275 parse_pid(leader, &m->leader);
280 c = machine_class_from_string(class);
286 unsigned long long l;
287 if (sscanf(realtime, "%llu", &l) > 0)
288 m->timestamp.realtime = l;
292 unsigned long long l;
293 if (sscanf(monotonic, "%llu", &l) > 0)
294 m->timestamp.monotonic = l;
298 size_t l, allocated = 0, nr = 0;
299 const char *word, *state;
302 FOREACH_WORD(word, l, netif, state) {
306 *(char*) (mempcpy(buf, word, l)) = 0;
308 if (safe_atoi(buf, &ifi) < 0)
313 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
329 static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
335 _cleanup_free_ char *escaped = NULL;
336 char *scope, *description, *job = NULL;
338 escaped = unit_name_escape(m->name);
342 scope = strjoin("machine-", escaped, ".scope", NULL);
346 description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
348 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
350 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
362 hashmap_put(m->manager->machine_units, m->unit, m);
367 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
375 r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
380 r = machine_start_scope(m, properties, error);
385 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START),
387 "LEADER="PID_FMT, m->leader,
388 LOG_MESSAGE("New machine %s.", m->name),
391 if (!dual_timestamp_is_set(&m->timestamp))
392 dual_timestamp_get(&m->timestamp);
396 /* Save new machine data */
399 machine_send_signal(m, true);
404 static int machine_stop_scope(Machine *m) {
405 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
414 r = manager_stop_unit(m->manager, m->unit, &error, &job);
416 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
426 int machine_stop(Machine *m) {
432 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
434 "LEADER="PID_FMT, m->leader,
435 LOG_MESSAGE("Machine %s terminated.", m->name),
439 k = machine_stop_scope(m);
444 machine_add_to_gc_queue(m);
447 machine_send_signal(m, false);
454 bool machine_check_gc(Machine *m, bool drop_not_started) {
457 if (drop_not_started && !m->started)
460 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
463 if (m->unit && manager_unit_is_active(m->manager, m->unit))
469 void machine_add_to_gc_queue(Machine *m) {
475 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
476 m->in_gc_queue = true;
479 MachineState machine_get_state(Machine *s) {
483 return s->started ? MACHINE_OPENING : MACHINE_CLOSING;
485 return MACHINE_RUNNING;
488 int machine_kill(Machine *m, KillWho who, int signo) {
494 if (who == KILL_LEADER) {
495 /* If we shall simply kill the leader, do so directly */
497 if (kill(m->leader, signo) < 0)
503 /* Otherwise make PID 1 do it for us, for the entire cgroup */
504 return manager_kill_unit(m->manager, m->unit, signo, NULL);
507 MachineOperation *machine_operation_unref(MachineOperation *o) {
511 sd_event_source_unref(o->event_source);
513 safe_close(o->errno_fd);
516 (void) kill(o->pid, SIGKILL);
518 sd_bus_message_unref(o->message);
521 LIST_REMOVE(operations, o->machine->operations, o);
522 o->machine->n_operations--;
529 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
530 [MACHINE_CONTAINER] = "container",
534 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
536 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
537 [MACHINE_OPENING] = "opening",
538 [MACHINE_RUNNING] = "running",
539 [MACHINE_CLOSING] = "closing"
542 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
544 static const char* const kill_who_table[_KILL_WHO_MAX] = {
545 [KILL_LEADER] = "leader",
549 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);