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 "logind-machine.h"
29 #include "cgroup-util.h"
34 #include <systemd/sd-messages.h>
36 Machine* machine_new(Manager *manager, const char *name) {
46 m->name = strdup(name);
50 m->state_file = strappend("/run/systemd/machines/", m->name);
54 if (hashmap_put(manager->machines, m->name, m) < 0)
57 m->class = _MACHINE_CLASS_INVALID;
70 void machine_free(Machine *m) {
74 LIST_REMOVE(Machine, gc_queue, m->manager->machine_gc_queue, m);
77 hashmap_remove(m->manager->machine_cgroups, m->cgroup_path);
81 hashmap_remove(m->manager->machines, m->name);
87 free(m->root_directory);
91 int machine_save(Machine *m) {
92 _cleanup_free_ char *temp_path = NULL;
93 _cleanup_fclose_ FILE *f = NULL;
97 assert(m->state_file);
102 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
106 r = fopen_temporary(m->state_file, &f, &temp_path);
110 fchmod(fileno(f), 0644);
113 "# This is private data. Do not parse.\n"
118 fprintf(f, "CGROUP=%s\n", m->cgroup_path);
121 fprintf(f, "SERVICE=%s\n", m->service);
124 fprintf(f, "SLICE=%s\n", m->slice);
126 if (m->root_directory)
127 fprintf(f, "ROOT=%s\n", m->root_directory);
129 if (!sd_id128_equal(m->id, SD_ID128_NULL))
130 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
133 fprintf(f, "LEADER=%lu\n", (unsigned long) m->leader);
135 if (m->class != _MACHINE_CLASS_INVALID)
136 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
138 if (dual_timestamp_is_set(&m->timestamp))
142 (unsigned long long) m->timestamp.realtime,
143 (unsigned long long) m->timestamp.monotonic);
147 if (ferror(f) || rename(temp_path, m->state_file) < 0) {
149 unlink(m->state_file);
155 log_error("Failed to save machine data for %s: %s", m->name, strerror(-r));
160 int machine_load(Machine *m) {
161 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL;
166 r = parse_env_file(m->state_file, NEWLINE,
167 "CGROUP", &m->cgroup_path,
168 "SERVICE", &m->service,
170 "ROOT", &m->root_directory,
174 "REALTIME", &realtime,
175 "MONOTONIC", &monotonic,
181 log_error("Failed to read %s: %s", m->state_file, strerror(-r));
186 sd_id128_from_string(id, &m->id);
189 parse_pid(leader, &m->leader);
194 c = machine_class_from_string(class);
200 unsigned long long l;
201 if (sscanf(realtime, "%llu", &l) > 0)
202 m->timestamp.realtime = l;
206 unsigned long long l;
207 if (sscanf(monotonic, "%llu", &l) > 0)
208 m->timestamp.monotonic = l;
214 static int machine_create_one_group(Machine *m, const char *controller, const char *path) {
221 r = cg_create_and_attach(controller, path, m->leader);
226 r = cg_create(controller, path);
234 static int machine_create_cgroup(Machine *m) {
241 m->slice = strdup(SPECIAL_MACHINE_SLICE);
246 if (!m->cgroup_path) {
247 _cleanup_free_ char *escaped = NULL, *slice = NULL;
250 name = strappenda(m->name, ".machine");
252 escaped = cg_escape(name);
256 r = cg_slice_to_path(m->slice, &slice);
260 m->cgroup_path = strjoin(m->manager->cgroup_root, "/", slice, "/", escaped, NULL);
265 r = machine_create_one_group(m, SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path);
267 log_error("Failed to create cgroup "SYSTEMD_CGROUP_CONTROLLER":%s: %s", m->cgroup_path, strerror(-r));
271 STRV_FOREACH(k, m->manager->controllers) {
273 if (strv_contains(m->manager->reset_controllers, *k))
276 r = machine_create_one_group(m, *k, m->cgroup_path);
278 log_warning("Failed to create cgroup %s:%s: %s", *k, m->cgroup_path, strerror(-r));
282 STRV_FOREACH(k, m->manager->reset_controllers) {
283 r = cg_attach(*k, "/", m->leader);
285 log_warning("Failed to reset controller %s: %s", *k, strerror(-r));
289 r = hashmap_put(m->manager->machine_cgroups, m->cgroup_path, m);
291 log_warning("Failed to create mapping between cgroup and machine");
296 int machine_start(Machine *m) {
305 MESSAGE_ID(SD_MESSAGE_MACHINE_START),
307 "LEADER=%lu", (unsigned long) m->leader,
308 "MESSAGE=New machine %s.", m->name,
312 r = machine_create_cgroup(m);
316 if (!dual_timestamp_is_set(&m->timestamp))
317 dual_timestamp_get(&m->timestamp);
321 /* Save new machine data */
324 machine_send_signal(m, true);
329 static int machine_terminate_cgroup(Machine *m) {
338 cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, false);
340 r = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, true);
342 log_error("Failed to kill machine cgroup: %s", strerror(-r));
344 STRV_FOREACH(k, m->manager->controllers)
345 cg_trim(*k, m->cgroup_path, true);
347 hashmap_remove(m->manager->machine_cgroups, m->cgroup_path);
349 free(m->cgroup_path);
350 m->cgroup_path = NULL;
355 int machine_stop(Machine *m) {
361 MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
363 "LEADER=%lu", (unsigned long) m->leader,
364 "MESSAGE=Machine %s terminated.", m->name,
368 k = machine_terminate_cgroup(m);
372 unlink(m->state_file);
373 machine_add_to_gc_queue(m);
376 machine_send_signal(m, false);
383 int machine_check_gc(Machine *m, bool drop_not_started) {
388 if (drop_not_started && !m->started)
391 if (m->cgroup_path) {
392 r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, false);
403 void machine_add_to_gc_queue(Machine *m) {
409 LIST_PREPEND(Machine, gc_queue, m->manager->machine_gc_queue, m);
410 m->in_gc_queue = true;
413 int machine_kill(Machine *m, KillWho who, int signo) {
414 _cleanup_set_free_ Set *pid_set = NULL;
422 if (m->leader <= 0 && who == KILL_LEADER)
426 if (kill(m->leader, signo) < 0)
429 if (who == KILL_ALL) {
432 pid_set = set_new(trivial_hash_func, trivial_compare_func);
437 q = set_put(pid_set, LONG_TO_PTR(m->leader));
442 q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, signo, false, true, false, pid_set);
443 if (q < 0 && (q != -EAGAIN && q != -ESRCH && q != -ENOENT))
450 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
451 [MACHINE_CONTAINER] = "container",
455 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);