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"
33 #include "unit-name.h"
35 #include "bus-error.h"
37 #include "machine-dbus.h"
38 #include "formats-util.h"
40 Machine
* machine_new(Manager
*manager
, MachineClass
class, const char *name
) {
44 assert(class < _MACHINE_CLASS_MAX
);
47 /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
48 * means as much as "we don't know yet", and that we'll figure
49 * it out later when loading the state file. */
55 m
->name
= strdup(name
);
59 if (class != MACHINE_HOST
) {
60 m
->state_file
= strappend("/run/systemd/machines/", m
->name
);
67 if (hashmap_put(manager
->machines
, m
->name
, m
) < 0)
82 void machine_free(Machine
*m
) {
86 machine_operation_unref(m
->operations
);
89 LIST_REMOVE(gc_queue
, m
->manager
->machine_gc_queue
, m
);
91 machine_release_unit(m
);
95 (void) hashmap_remove(m
->manager
->machines
, m
->name
);
97 if (m
->manager
->host_machine
== m
)
98 m
->manager
->host_machine
= NULL
;
101 (void) hashmap_remove_value(m
->manager
->machine_leaders
, UINT_TO_PTR(m
->leader
), m
);
103 sd_bus_message_unref(m
->create_message
);
108 free(m
->root_directory
);
113 int machine_save(Machine
*m
) {
114 _cleanup_free_
char *temp_path
= NULL
;
115 _cleanup_fclose_
FILE *f
= NULL
;
126 r
= mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
130 r
= fopen_temporary(m
->state_file
, &f
, &temp_path
);
134 (void) fchmod(fileno(f
), 0644);
137 "# This is private data. Do not parse.\n"
142 _cleanup_free_
char *escaped
;
144 escaped
= cescape(m
->unit
);
150 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 */
154 fprintf(f
, "SCOPE_JOB=%s\n", m
->scope_job
);
157 _cleanup_free_
char *escaped
;
159 escaped
= cescape(m
->service
);
164 fprintf(f
, "SERVICE=%s\n", escaped
);
167 if (m
->root_directory
) {
168 _cleanup_free_
char *escaped
;
170 escaped
= cescape(m
->root_directory
);
175 fprintf(f
, "ROOT=%s\n", escaped
);
178 if (!sd_id128_equal(m
->id
, SD_ID128_NULL
))
179 fprintf(f
, "ID=" SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(m
->id
));
182 fprintf(f
, "LEADER="PID_FMT
"\n", m
->leader
);
184 if (m
->class != _MACHINE_CLASS_INVALID
)
185 fprintf(f
, "CLASS=%s\n", machine_class_to_string(m
->class));
187 if (dual_timestamp_is_set(&m
->timestamp
))
189 "REALTIME="USEC_FMT
"\n"
190 "MONOTONIC="USEC_FMT
"\n",
191 m
->timestamp
.realtime
,
192 m
->timestamp
.monotonic
);
194 if (m
->n_netif
> 0) {
199 for (i
= 0; i
< m
->n_netif
; i
++) {
203 fprintf(f
, "%i", m
->netif
[i
]);
209 r
= fflush_and_check(f
);
213 if (rename(temp_path
, m
->state_file
) < 0) {
221 /* Create a symlink from the unit name to the machine
222 * name, so that we can quickly find the machine for
223 * each given unit. Ignore error. */
224 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
225 (void) symlink(m
->name
, sl
);
231 (void) unlink(m
->state_file
);
234 (void) unlink(temp_path
);
236 return log_error_errno(r
, "Failed to save machine data %s: %m", m
->state_file
);
239 static void machine_unlink(Machine
*m
) {
246 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
251 (void) unlink(m
->state_file
);
254 int machine_load(Machine
*m
) {
255 _cleanup_free_
char *realtime
= NULL
, *monotonic
= NULL
, *id
= NULL
, *leader
= NULL
, *class = NULL
, *netif
= NULL
;
263 r
= parse_env_file(m
->state_file
, NEWLINE
,
265 "SCOPE_JOB", &m
->scope_job
,
266 "SERVICE", &m
->service
,
267 "ROOT", &m
->root_directory
,
271 "REALTIME", &realtime
,
272 "MONOTONIC", &monotonic
,
279 return log_error_errno(r
, "Failed to read %s: %m", m
->state_file
);
283 sd_id128_from_string(id
, &m
->id
);
286 parse_pid(leader
, &m
->leader
);
291 c
= machine_class_from_string(class);
297 unsigned long long l
;
298 if (sscanf(realtime
, "%llu", &l
) > 0)
299 m
->timestamp
.realtime
= l
;
303 unsigned long long l
;
304 if (sscanf(monotonic
, "%llu", &l
) > 0)
305 m
->timestamp
.monotonic
= l
;
309 size_t l
, allocated
= 0, nr
= 0;
310 const char *word
, *state
;
313 FOREACH_WORD(word
, l
, netif
, state
) {
317 *(char*) (mempcpy(buf
, word
, l
)) = 0;
319 if (safe_atoi(buf
, &ifi
) < 0)
324 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
340 static int machine_start_scope(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
344 assert(m
->class != MACHINE_HOST
);
347 _cleanup_free_
char *escaped
= NULL
;
348 char *scope
, *description
, *job
= NULL
;
350 escaped
= unit_name_escape(m
->name
);
354 scope
= strjoin("machine-", escaped
, ".scope", NULL
);
358 description
= strjoina(m
->class == MACHINE_VM
? "Virtual Machine " : "Container ", m
->name
);
360 r
= manager_start_scope(m
->manager
, scope
, m
->leader
, SPECIAL_MACHINE_SLICE
, description
, properties
, error
, &job
);
362 log_error("Failed to start machine scope: %s", bus_error_message(error
, r
));
374 hashmap_put(m
->manager
->machine_units
, m
->unit
, m
);
379 int machine_start(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
384 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
390 r
= hashmap_put(m
->manager
->machine_leaders
, UINT_TO_PTR(m
->leader
), m
);
395 r
= machine_start_scope(m
, properties
, error
);
400 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START
),
402 "LEADER="PID_FMT
, m
->leader
,
403 LOG_MESSAGE("New machine %s.", m
->name
),
406 if (!dual_timestamp_is_set(&m
->timestamp
))
407 dual_timestamp_get(&m
->timestamp
);
411 /* Save new machine data */
414 machine_send_signal(m
, true);
419 static int machine_stop_scope(Machine
*m
) {
420 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
425 assert(m
->class != MACHINE_HOST
);
430 r
= manager_stop_unit(m
->manager
, m
->unit
, &error
, &job
);
432 log_error("Failed to stop machine scope: %s", bus_error_message(&error
, r
));
442 int machine_stop(Machine
*m
) {
446 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
449 r
= machine_stop_scope(m
);
458 int machine_finalize(Machine
*m
) {
463 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP
),
465 "LEADER="PID_FMT
, m
->leader
,
466 LOG_MESSAGE("Machine %s terminated.", m
->name
),
470 machine_add_to_gc_queue(m
);
473 machine_send_signal(m
, false);
480 bool machine_check_gc(Machine
*m
, bool drop_not_started
) {
483 if (m
->class == MACHINE_HOST
)
486 if (drop_not_started
&& !m
->started
)
489 if (m
->scope_job
&& manager_job_is_active(m
->manager
, m
->scope_job
))
492 if (m
->unit
&& manager_unit_is_active(m
->manager
, m
->unit
))
498 void machine_add_to_gc_queue(Machine
*m
) {
504 LIST_PREPEND(gc_queue
, m
->manager
->machine_gc_queue
, m
);
505 m
->in_gc_queue
= true;
508 MachineState
machine_get_state(Machine
*s
) {
511 if (s
->class == MACHINE_HOST
)
512 return MACHINE_RUNNING
;
515 return MACHINE_CLOSING
;
518 return MACHINE_OPENING
;
520 return MACHINE_RUNNING
;
523 int machine_kill(Machine
*m
, KillWho who
, int signo
) {
526 if (!IN_SET(m
->class, MACHINE_VM
, MACHINE_CONTAINER
))
532 if (who
== KILL_LEADER
) {
533 /* If we shall simply kill the leader, do so directly */
535 if (kill(m
->leader
, signo
) < 0)
541 /* Otherwise make PID 1 do it for us, for the entire cgroup */
542 return manager_kill_unit(m
->manager
, m
->unit
, signo
, NULL
);
545 int machine_openpt(Machine
*m
, int flags
) {
553 fd
= posix_openpt(flags
);
557 if (unlockpt(fd
) < 0)
563 case MACHINE_CONTAINER
:
567 return openpt_in_namespace(m
->leader
, flags
);
574 MachineOperation
*machine_operation_unref(MachineOperation
*o
) {
578 sd_event_source_unref(o
->event_source
);
580 safe_close(o
->errno_fd
);
583 (void) kill(o
->pid
, SIGKILL
);
585 sd_bus_message_unref(o
->message
);
588 LIST_REMOVE(operations
, o
->machine
->operations
, o
);
589 o
->machine
->n_operations
--;
596 void machine_release_unit(Machine
*m
) {
602 (void) hashmap_remove(m
->manager
->machine_units
, m
->unit
);
603 m
->unit
= mfree(m
->unit
);
606 static const char* const machine_class_table
[_MACHINE_CLASS_MAX
] = {
607 [MACHINE_CONTAINER
] = "container",
609 [MACHINE_HOST
] = "host",
612 DEFINE_STRING_TABLE_LOOKUP(machine_class
, MachineClass
);
614 static const char* const machine_state_table
[_MACHINE_STATE_MAX
] = {
615 [MACHINE_OPENING
] = "opening",
616 [MACHINE_RUNNING
] = "running",
617 [MACHINE_CLOSING
] = "closing"
620 DEFINE_STRING_TABLE_LOOKUP(machine_state
, MachineState
);
622 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
623 [KILL_LEADER
] = "leader",
627 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);