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"
34 #include "formats-util.h"
36 #include "machine-dbus.h"
39 #include "parse-util.h"
41 #include "string-table.h"
42 #include "terminal-util.h"
43 #include "unit-name.h"
45 #include "extract-word.h"
47 Machine
* machine_new(Manager
*manager
, MachineClass
class, const char *name
) {
51 assert(class < _MACHINE_CLASS_MAX
);
54 /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
55 * means as much as "we don't know yet", and that we'll figure
56 * it out later when loading the state file. */
62 m
->name
= strdup(name
);
66 if (class != MACHINE_HOST
) {
67 m
->state_file
= strappend("/run/systemd/machines/", m
->name
);
74 if (hashmap_put(manager
->machines
, m
->name
, m
) < 0)
89 void machine_free(Machine
*m
) {
93 machine_operation_unref(m
->operations
);
96 LIST_REMOVE(gc_queue
, m
->manager
->machine_gc_queue
, m
);
98 machine_release_unit(m
);
102 (void) hashmap_remove(m
->manager
->machines
, m
->name
);
104 if (m
->manager
->host_machine
== m
)
105 m
->manager
->host_machine
= NULL
;
108 (void) hashmap_remove_value(m
->manager
->machine_leaders
, UINT_TO_PTR(m
->leader
), m
);
110 sd_bus_message_unref(m
->create_message
);
115 free(m
->root_directory
);
120 int machine_save(Machine
*m
) {
121 _cleanup_free_
char *temp_path
= NULL
;
122 _cleanup_fclose_
FILE *f
= NULL
;
133 r
= mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
137 r
= fopen_temporary(m
->state_file
, &f
, &temp_path
);
141 (void) fchmod(fileno(f
), 0644);
144 "# This is private data. Do not parse.\n"
149 _cleanup_free_
char *escaped
;
151 escaped
= cescape(m
->unit
);
157 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 */
161 fprintf(f
, "SCOPE_JOB=%s\n", m
->scope_job
);
164 _cleanup_free_
char *escaped
;
166 escaped
= cescape(m
->service
);
171 fprintf(f
, "SERVICE=%s\n", escaped
);
174 if (m
->root_directory
) {
175 _cleanup_free_
char *escaped
;
177 escaped
= cescape(m
->root_directory
);
182 fprintf(f
, "ROOT=%s\n", escaped
);
185 if (!sd_id128_equal(m
->id
, SD_ID128_NULL
))
186 fprintf(f
, "ID=" SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(m
->id
));
189 fprintf(f
, "LEADER="PID_FMT
"\n", m
->leader
);
191 if (m
->class != _MACHINE_CLASS_INVALID
)
192 fprintf(f
, "CLASS=%s\n", machine_class_to_string(m
->class));
194 if (dual_timestamp_is_set(&m
->timestamp
))
196 "REALTIME="USEC_FMT
"\n"
197 "MONOTONIC="USEC_FMT
"\n",
198 m
->timestamp
.realtime
,
199 m
->timestamp
.monotonic
);
201 if (m
->n_netif
> 0) {
206 for (i
= 0; i
< m
->n_netif
; i
++) {
210 fprintf(f
, "%i", m
->netif
[i
]);
216 r
= fflush_and_check(f
);
220 if (rename(temp_path
, m
->state_file
) < 0) {
228 /* Create a symlink from the unit name to the machine
229 * name, so that we can quickly find the machine for
230 * each given unit. Ignore error. */
231 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
232 (void) symlink(m
->name
, sl
);
238 (void) unlink(m
->state_file
);
241 (void) unlink(temp_path
);
243 return log_error_errno(r
, "Failed to save machine data %s: %m", m
->state_file
);
246 static void machine_unlink(Machine
*m
) {
253 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
258 (void) unlink(m
->state_file
);
261 int machine_load(Machine
*m
) {
262 _cleanup_free_
char *realtime
= NULL
, *monotonic
= NULL
, *id
= NULL
, *leader
= NULL
, *class = NULL
, *netif
= NULL
;
270 r
= parse_env_file(m
->state_file
, NEWLINE
,
272 "SCOPE_JOB", &m
->scope_job
,
273 "SERVICE", &m
->service
,
274 "ROOT", &m
->root_directory
,
278 "REALTIME", &realtime
,
279 "MONOTONIC", &monotonic
,
286 return log_error_errno(r
, "Failed to read %s: %m", m
->state_file
);
290 sd_id128_from_string(id
, &m
->id
);
293 parse_pid(leader
, &m
->leader
);
298 c
= machine_class_from_string(class);
304 unsigned long long l
;
305 if (sscanf(realtime
, "%llu", &l
) > 0)
306 m
->timestamp
.realtime
= l
;
310 unsigned long long l
;
311 if (sscanf(monotonic
, "%llu", &l
) > 0)
312 m
->timestamp
.monotonic
= l
;
316 size_t allocated
= 0, nr
= 0;
322 _cleanup_free_
char *word
= NULL
;
325 r
= extract_first_word(&p
, &word
, NULL
, 0);
331 log_warning_errno(r
, "Failed to parse NETIF: %s", netif
);
335 if (parse_ifindex(word
, &ifi
) < 0)
338 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
354 static int machine_start_scope(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
358 assert(m
->class != MACHINE_HOST
);
361 _cleanup_free_
char *escaped
= NULL
;
362 char *scope
, *description
, *job
= NULL
;
364 escaped
= unit_name_escape(m
->name
);
368 scope
= strjoin("machine-", escaped
, ".scope", NULL
);
372 description
= strjoina(m
->class == MACHINE_VM
? "Virtual Machine " : "Container ", m
->name
);
374 r
= manager_start_scope(m
->manager
, scope
, m
->leader
, SPECIAL_MACHINE_SLICE
, description
, properties
, error
, &job
);
376 log_error("Failed to start machine scope: %s", bus_error_message(error
, r
));
388 hashmap_put(m
->manager
->machine_units
, m
->unit
, m
);
393 int machine_start(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
398 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
404 r
= hashmap_put(m
->manager
->machine_leaders
, UINT_TO_PTR(m
->leader
), m
);
409 r
= machine_start_scope(m
, properties
, error
);
414 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START
),
416 "LEADER="PID_FMT
, m
->leader
,
417 LOG_MESSAGE("New machine %s.", m
->name
),
420 if (!dual_timestamp_is_set(&m
->timestamp
))
421 dual_timestamp_get(&m
->timestamp
);
425 /* Save new machine data */
428 machine_send_signal(m
, true);
433 static int machine_stop_scope(Machine
*m
) {
434 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
439 assert(m
->class != MACHINE_HOST
);
444 r
= manager_stop_unit(m
->manager
, m
->unit
, &error
, &job
);
446 log_error("Failed to stop machine scope: %s", bus_error_message(&error
, r
));
456 int machine_stop(Machine
*m
) {
460 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
463 r
= machine_stop_scope(m
);
472 int machine_finalize(Machine
*m
) {
477 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP
),
479 "LEADER="PID_FMT
, m
->leader
,
480 LOG_MESSAGE("Machine %s terminated.", m
->name
),
484 machine_add_to_gc_queue(m
);
487 machine_send_signal(m
, false);
494 bool machine_check_gc(Machine
*m
, bool drop_not_started
) {
497 if (m
->class == MACHINE_HOST
)
500 if (drop_not_started
&& !m
->started
)
503 if (m
->scope_job
&& manager_job_is_active(m
->manager
, m
->scope_job
))
506 if (m
->unit
&& manager_unit_is_active(m
->manager
, m
->unit
))
512 void machine_add_to_gc_queue(Machine
*m
) {
518 LIST_PREPEND(gc_queue
, m
->manager
->machine_gc_queue
, m
);
519 m
->in_gc_queue
= true;
522 MachineState
machine_get_state(Machine
*s
) {
525 if (s
->class == MACHINE_HOST
)
526 return MACHINE_RUNNING
;
529 return MACHINE_CLOSING
;
532 return MACHINE_OPENING
;
534 return MACHINE_RUNNING
;
537 int machine_kill(Machine
*m
, KillWho who
, int signo
) {
540 if (!IN_SET(m
->class, MACHINE_VM
, MACHINE_CONTAINER
))
546 if (who
== KILL_LEADER
) {
547 /* If we shall simply kill the leader, do so directly */
549 if (kill(m
->leader
, signo
) < 0)
555 /* Otherwise make PID 1 do it for us, for the entire cgroup */
556 return manager_kill_unit(m
->manager
, m
->unit
, signo
, NULL
);
559 int machine_openpt(Machine
*m
, int flags
) {
567 fd
= posix_openpt(flags
);
571 if (unlockpt(fd
) < 0)
577 case MACHINE_CONTAINER
:
581 return openpt_in_namespace(m
->leader
, flags
);
588 int machine_open_terminal(Machine
*m
, const char *path
, int mode
) {
594 return open_terminal(path
, mode
);
596 case MACHINE_CONTAINER
:
600 return open_terminal_in_namespace(m
->leader
, path
, mode
);
607 MachineOperation
*machine_operation_unref(MachineOperation
*o
) {
611 sd_event_source_unref(o
->event_source
);
613 safe_close(o
->errno_fd
);
616 (void) kill(o
->pid
, SIGKILL
);
618 sd_bus_message_unref(o
->message
);
621 LIST_REMOVE(operations
, o
->machine
->operations
, o
);
622 o
->machine
->n_operations
--;
629 void machine_release_unit(Machine
*m
) {
635 (void) hashmap_remove(m
->manager
->machine_units
, m
->unit
);
636 m
->unit
= mfree(m
->unit
);
639 static const char* const machine_class_table
[_MACHINE_CLASS_MAX
] = {
640 [MACHINE_CONTAINER
] = "container",
642 [MACHINE_HOST
] = "host",
645 DEFINE_STRING_TABLE_LOOKUP(machine_class
, MachineClass
);
647 static const char* const machine_state_table
[_MACHINE_STATE_MAX
] = {
648 [MACHINE_OPENING
] = "opening",
649 [MACHINE_RUNNING
] = "running",
650 [MACHINE_CLOSING
] = "closing"
653 DEFINE_STRING_TABLE_LOOKUP(machine_state
, MachineState
);
655 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
656 [KILL_LEADER
] = "leader",
660 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);