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"
28 #include "alloc-util.h"
29 #include "bus-error.h"
32 #include "extract-word.h"
35 #include "formats-util.h"
37 #include "machine-dbus.h"
40 #include "parse-util.h"
41 #include "process-util.h"
43 #include "string-table.h"
44 #include "terminal-util.h"
45 #include "unit-name.h"
48 Machine
* machine_new(Manager
*manager
, MachineClass
class, const char *name
) {
52 assert(class < _MACHINE_CLASS_MAX
);
55 /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
56 * means as much as "we don't know yet", and that we'll figure
57 * it out later when loading the state file. */
63 m
->name
= strdup(name
);
67 if (class != MACHINE_HOST
) {
68 m
->state_file
= strappend("/run/systemd/machines/", m
->name
);
75 if (hashmap_put(manager
->machines
, m
->name
, m
) < 0)
90 void machine_free(Machine
*m
) {
94 machine_operation_unref(m
->operations
);
97 LIST_REMOVE(gc_queue
, m
->manager
->machine_gc_queue
, m
);
99 machine_release_unit(m
);
103 (void) hashmap_remove(m
->manager
->machines
, m
->name
);
105 if (m
->manager
->host_machine
== m
)
106 m
->manager
->host_machine
= NULL
;
109 (void) hashmap_remove_value(m
->manager
->machine_leaders
, PID_TO_PTR(m
->leader
), m
);
111 sd_bus_message_unref(m
->create_message
);
116 free(m
->root_directory
);
121 int machine_save(Machine
*m
) {
122 _cleanup_free_
char *temp_path
= NULL
;
123 _cleanup_fclose_
FILE *f
= NULL
;
134 r
= mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
138 r
= fopen_temporary(m
->state_file
, &f
, &temp_path
);
142 (void) fchmod(fileno(f
), 0644);
145 "# This is private data. Do not parse.\n"
150 _cleanup_free_
char *escaped
;
152 escaped
= cescape(m
->unit
);
158 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 */
162 fprintf(f
, "SCOPE_JOB=%s\n", m
->scope_job
);
165 _cleanup_free_
char *escaped
;
167 escaped
= cescape(m
->service
);
172 fprintf(f
, "SERVICE=%s\n", escaped
);
175 if (m
->root_directory
) {
176 _cleanup_free_
char *escaped
;
178 escaped
= cescape(m
->root_directory
);
183 fprintf(f
, "ROOT=%s\n", escaped
);
186 if (!sd_id128_equal(m
->id
, SD_ID128_NULL
))
187 fprintf(f
, "ID=" SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(m
->id
));
190 fprintf(f
, "LEADER="PID_FMT
"\n", m
->leader
);
192 if (m
->class != _MACHINE_CLASS_INVALID
)
193 fprintf(f
, "CLASS=%s\n", machine_class_to_string(m
->class));
195 if (dual_timestamp_is_set(&m
->timestamp
))
197 "REALTIME="USEC_FMT
"\n"
198 "MONOTONIC="USEC_FMT
"\n",
199 m
->timestamp
.realtime
,
200 m
->timestamp
.monotonic
);
202 if (m
->n_netif
> 0) {
207 for (i
= 0; i
< m
->n_netif
; i
++) {
211 fprintf(f
, "%i", m
->netif
[i
]);
217 r
= fflush_and_check(f
);
221 if (rename(temp_path
, m
->state_file
) < 0) {
229 /* Create a symlink from the unit name to the machine
230 * name, so that we can quickly find the machine for
231 * each given unit. Ignore error. */
232 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
233 (void) symlink(m
->name
, sl
);
239 (void) unlink(m
->state_file
);
242 (void) unlink(temp_path
);
244 return log_error_errno(r
, "Failed to save machine data %s: %m", m
->state_file
);
247 static void machine_unlink(Machine
*m
) {
254 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
259 (void) unlink(m
->state_file
);
262 int machine_load(Machine
*m
) {
263 _cleanup_free_
char *realtime
= NULL
, *monotonic
= NULL
, *id
= NULL
, *leader
= NULL
, *class = NULL
, *netif
= NULL
;
271 r
= parse_env_file(m
->state_file
, NEWLINE
,
273 "SCOPE_JOB", &m
->scope_job
,
274 "SERVICE", &m
->service
,
275 "ROOT", &m
->root_directory
,
279 "REALTIME", &realtime
,
280 "MONOTONIC", &monotonic
,
287 return log_error_errno(r
, "Failed to read %s: %m", m
->state_file
);
291 sd_id128_from_string(id
, &m
->id
);
294 parse_pid(leader
, &m
->leader
);
299 c
= machine_class_from_string(class);
305 unsigned long long l
;
306 if (sscanf(realtime
, "%llu", &l
) > 0)
307 m
->timestamp
.realtime
= l
;
311 unsigned long long l
;
312 if (sscanf(monotonic
, "%llu", &l
) > 0)
313 m
->timestamp
.monotonic
= l
;
317 size_t allocated
= 0, nr
= 0;
323 _cleanup_free_
char *word
= NULL
;
326 r
= extract_first_word(&p
, &word
, NULL
, 0);
332 log_warning_errno(r
, "Failed to parse NETIF: %s", netif
);
336 if (parse_ifindex(word
, &ifi
) < 0)
339 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
355 static int machine_start_scope(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
359 assert(m
->class != MACHINE_HOST
);
362 _cleanup_free_
char *escaped
= NULL
;
363 char *scope
, *description
, *job
= NULL
;
365 escaped
= unit_name_escape(m
->name
);
369 scope
= strjoin("machine-", escaped
, ".scope", NULL
);
373 description
= strjoina(m
->class == MACHINE_VM
? "Virtual Machine " : "Container ", m
->name
);
375 r
= manager_start_scope(m
->manager
, scope
, m
->leader
, SPECIAL_MACHINE_SLICE
, description
, properties
, error
, &job
);
377 log_error("Failed to start machine scope: %s", bus_error_message(error
, r
));
389 hashmap_put(m
->manager
->machine_units
, m
->unit
, m
);
394 int machine_start(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
399 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
405 r
= hashmap_put(m
->manager
->machine_leaders
, PID_TO_PTR(m
->leader
), m
);
410 r
= machine_start_scope(m
, properties
, error
);
415 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START
),
417 "LEADER="PID_FMT
, m
->leader
,
418 LOG_MESSAGE("New machine %s.", m
->name
),
421 if (!dual_timestamp_is_set(&m
->timestamp
))
422 dual_timestamp_get(&m
->timestamp
);
426 /* Save new machine data */
429 machine_send_signal(m
, true);
434 static int machine_stop_scope(Machine
*m
) {
435 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
440 assert(m
->class != MACHINE_HOST
);
445 r
= manager_stop_unit(m
->manager
, m
->unit
, &error
, &job
);
447 log_error("Failed to stop machine scope: %s", bus_error_message(&error
, r
));
457 int machine_stop(Machine
*m
) {
461 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
464 r
= machine_stop_scope(m
);
473 int machine_finalize(Machine
*m
) {
478 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP
),
480 "LEADER="PID_FMT
, m
->leader
,
481 LOG_MESSAGE("Machine %s terminated.", m
->name
),
485 machine_add_to_gc_queue(m
);
488 machine_send_signal(m
, false);
495 bool machine_check_gc(Machine
*m
, bool drop_not_started
) {
498 if (m
->class == MACHINE_HOST
)
501 if (drop_not_started
&& !m
->started
)
504 if (m
->scope_job
&& manager_job_is_active(m
->manager
, m
->scope_job
))
507 if (m
->unit
&& manager_unit_is_active(m
->manager
, m
->unit
))
513 void machine_add_to_gc_queue(Machine
*m
) {
519 LIST_PREPEND(gc_queue
, m
->manager
->machine_gc_queue
, m
);
520 m
->in_gc_queue
= true;
523 MachineState
machine_get_state(Machine
*s
) {
526 if (s
->class == MACHINE_HOST
)
527 return MACHINE_RUNNING
;
530 return MACHINE_CLOSING
;
533 return MACHINE_OPENING
;
535 return MACHINE_RUNNING
;
538 int machine_kill(Machine
*m
, KillWho who
, int signo
) {
541 if (!IN_SET(m
->class, MACHINE_VM
, MACHINE_CONTAINER
))
547 if (who
== KILL_LEADER
) {
548 /* If we shall simply kill the leader, do so directly */
550 if (kill(m
->leader
, signo
) < 0)
556 /* Otherwise, make PID 1 do it for us, for the entire cgroup */
557 return manager_kill_unit(m
->manager
, m
->unit
, signo
, NULL
);
560 int machine_openpt(Machine
*m
, int flags
) {
568 fd
= posix_openpt(flags
);
572 if (unlockpt(fd
) < 0)
578 case MACHINE_CONTAINER
:
582 return openpt_in_namespace(m
->leader
, flags
);
589 int machine_open_terminal(Machine
*m
, const char *path
, int mode
) {
595 return open_terminal(path
, mode
);
597 case MACHINE_CONTAINER
:
601 return open_terminal_in_namespace(m
->leader
, path
, mode
);
608 MachineOperation
*machine_operation_unref(MachineOperation
*o
) {
612 sd_event_source_unref(o
->event_source
);
614 safe_close(o
->errno_fd
);
617 (void) kill(o
->pid
, SIGKILL
);
619 sd_bus_message_unref(o
->message
);
622 LIST_REMOVE(operations
, o
->machine
->operations
, o
);
623 o
->machine
->n_operations
--;
630 void machine_release_unit(Machine
*m
) {
636 (void) hashmap_remove(m
->manager
->machine_units
, m
->unit
);
637 m
->unit
= mfree(m
->unit
);
640 static const char* const machine_class_table
[_MACHINE_CLASS_MAX
] = {
641 [MACHINE_CONTAINER
] = "container",
643 [MACHINE_HOST
] = "host",
646 DEFINE_STRING_TABLE_LOOKUP(machine_class
, MachineClass
);
648 static const char* const machine_state_table
[_MACHINE_STATE_MAX
] = {
649 [MACHINE_OPENING
] = "opening",
650 [MACHINE_RUNNING
] = "running",
651 [MACHINE_CLOSING
] = "closing"
654 DEFINE_STRING_TABLE_LOOKUP(machine_state
, MachineState
);
656 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
657 [KILL_LEADER
] = "leader",
661 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);