1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "sd-messages.h"
27 #include "alloc-util.h"
28 #include "bus-error.h"
31 #include "extract-word.h"
34 #include "format-util.h"
36 #include "machine-dbus.h"
39 #include "parse-util.h"
40 #include "process-util.h"
42 #include "stdio-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)
88 void machine_free(Machine
*m
) {
92 operation_free(m
->operations
);
95 LIST_REMOVE(gc_queue
, m
->manager
->machine_gc_queue
, m
);
97 machine_release_unit(m
);
101 (void) hashmap_remove(m
->manager
->machines
, m
->name
);
103 if (m
->manager
->host_machine
== m
)
104 m
->manager
->host_machine
= NULL
;
107 (void) hashmap_remove_value(m
->manager
->machine_leaders
, PID_TO_PTR(m
->leader
), m
);
109 sd_bus_message_unref(m
->create_message
);
114 free(m
->root_directory
);
119 int machine_save(Machine
*m
) {
120 _cleanup_free_
char *temp_path
= NULL
;
121 _cleanup_fclose_
FILE *f
= NULL
;
132 r
= mkdir_safe_label("/run/systemd/machines", 0755, 0, 0, false);
136 r
= fopen_temporary(m
->state_file
, &f
, &temp_path
);
140 (void) fchmod(fileno(f
), 0644);
143 "# This is private data. Do not parse.\n"
148 _cleanup_free_
char *escaped
;
150 escaped
= cescape(m
->unit
);
156 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 */
160 fprintf(f
, "SCOPE_JOB=%s\n", m
->scope_job
);
163 _cleanup_free_
char *escaped
;
165 escaped
= cescape(m
->service
);
170 fprintf(f
, "SERVICE=%s\n", escaped
);
173 if (m
->root_directory
) {
174 _cleanup_free_
char *escaped
;
176 escaped
= cescape(m
->root_directory
);
181 fprintf(f
, "ROOT=%s\n", escaped
);
184 if (!sd_id128_is_null(m
->id
))
185 fprintf(f
, "ID=" SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(m
->id
));
188 fprintf(f
, "LEADER="PID_FMT
"\n", m
->leader
);
190 if (m
->class != _MACHINE_CLASS_INVALID
)
191 fprintf(f
, "CLASS=%s\n", machine_class_to_string(m
->class));
193 if (dual_timestamp_is_set(&m
->timestamp
))
195 "REALTIME="USEC_FMT
"\n"
196 "MONOTONIC="USEC_FMT
"\n",
197 m
->timestamp
.realtime
,
198 m
->timestamp
.monotonic
);
200 if (m
->n_netif
> 0) {
203 fputs_unlocked("NETIF=", f
);
205 for (i
= 0; i
< m
->n_netif
; i
++) {
207 fputc_unlocked(' ', f
);
209 fprintf(f
, "%i", m
->netif
[i
]);
212 fputc_unlocked('\n', f
);
215 r
= fflush_and_check(f
);
219 if (rename(temp_path
, m
->state_file
) < 0) {
227 /* Create a symlink from the unit name to the machine
228 * name, so that we can quickly find the machine for
229 * each given unit. Ignore error. */
230 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
231 (void) symlink(m
->name
, sl
);
237 (void) unlink(m
->state_file
);
240 (void) unlink(temp_path
);
242 return log_error_errno(r
, "Failed to save machine data %s: %m", m
->state_file
);
245 static void machine_unlink(Machine
*m
) {
252 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
257 (void) unlink(m
->state_file
);
260 int machine_load(Machine
*m
) {
261 _cleanup_free_
char *realtime
= NULL
, *monotonic
= NULL
, *id
= NULL
, *leader
= NULL
, *class = NULL
, *netif
= NULL
;
269 r
= parse_env_file(m
->state_file
, NEWLINE
,
271 "SCOPE_JOB", &m
->scope_job
,
272 "SERVICE", &m
->service
,
273 "ROOT", &m
->root_directory
,
277 "REALTIME", &realtime
,
278 "MONOTONIC", &monotonic
,
285 return log_error_errno(r
, "Failed to read %s: %m", m
->state_file
);
289 sd_id128_from_string(id
, &m
->id
);
292 parse_pid(leader
, &m
->leader
);
297 c
= machine_class_from_string(class);
303 timestamp_deserialize(realtime
, &m
->timestamp
.realtime
);
305 timestamp_deserialize(monotonic
, &m
->timestamp
.monotonic
);
308 size_t allocated
= 0, nr
= 0;
314 _cleanup_free_
char *word
= NULL
;
317 r
= extract_first_word(&p
, &word
, NULL
, 0);
323 log_warning_errno(r
, "Failed to parse NETIF: %s", netif
);
327 if (parse_ifindex(word
, &ifi
) < 0)
330 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
346 static int machine_start_scope(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
350 assert(m
->class != MACHINE_HOST
);
353 _cleanup_free_
char *escaped
= NULL
;
354 char *scope
, *description
, *job
= NULL
;
356 escaped
= unit_name_escape(m
->name
);
360 scope
= strjoin("machine-", escaped
, ".scope");
364 description
= strjoina(m
->class == MACHINE_VM
? "Virtual Machine " : "Container ", m
->name
);
366 r
= manager_start_scope(m
->manager
, scope
, m
->leader
, SPECIAL_MACHINE_SLICE
, description
, properties
, error
, &job
);
368 log_error("Failed to start machine scope: %s", bus_error_message(error
, r
));
380 hashmap_put(m
->manager
->machine_units
, m
->unit
, m
);
385 int machine_start(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
390 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
396 r
= hashmap_put(m
->manager
->machine_leaders
, PID_TO_PTR(m
->leader
), m
);
401 r
= machine_start_scope(m
, properties
, error
);
406 "MESSAGE_ID=" SD_MESSAGE_MACHINE_START_STR
,
408 "LEADER="PID_FMT
, m
->leader
,
409 LOG_MESSAGE("New machine %s.", m
->name
),
412 if (!dual_timestamp_is_set(&m
->timestamp
))
413 dual_timestamp_get(&m
->timestamp
);
417 /* Save new machine data */
420 machine_send_signal(m
, true);
425 static int machine_stop_scope(Machine
*m
) {
426 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
431 assert(m
->class != MACHINE_HOST
);
436 r
= manager_stop_unit(m
->manager
, m
->unit
, &error
, &job
);
438 log_error("Failed to stop machine scope: %s", bus_error_message(&error
, r
));
448 int machine_stop(Machine
*m
) {
452 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
455 r
= machine_stop_scope(m
);
464 int machine_finalize(Machine
*m
) {
469 "MESSAGE_ID=" SD_MESSAGE_MACHINE_STOP_STR
,
471 "LEADER="PID_FMT
, m
->leader
,
472 LOG_MESSAGE("Machine %s terminated.", m
->name
),
476 machine_add_to_gc_queue(m
);
479 machine_send_signal(m
, false);
486 bool machine_check_gc(Machine
*m
, bool drop_not_started
) {
489 if (m
->class == MACHINE_HOST
)
492 if (drop_not_started
&& !m
->started
)
495 if (m
->scope_job
&& manager_job_is_active(m
->manager
, m
->scope_job
))
498 if (m
->unit
&& manager_unit_is_active(m
->manager
, m
->unit
))
504 void machine_add_to_gc_queue(Machine
*m
) {
510 LIST_PREPEND(gc_queue
, m
->manager
->machine_gc_queue
, m
);
511 m
->in_gc_queue
= true;
514 MachineState
machine_get_state(Machine
*s
) {
517 if (s
->class == MACHINE_HOST
)
518 return MACHINE_RUNNING
;
521 return MACHINE_CLOSING
;
524 return MACHINE_OPENING
;
526 return MACHINE_RUNNING
;
529 int machine_kill(Machine
*m
, KillWho who
, int signo
) {
532 if (!IN_SET(m
->class, MACHINE_VM
, MACHINE_CONTAINER
))
538 if (who
== KILL_LEADER
) {
539 /* If we shall simply kill the leader, do so directly */
541 if (kill(m
->leader
, signo
) < 0)
547 /* Otherwise, make PID 1 do it for us, for the entire cgroup */
548 return manager_kill_unit(m
->manager
, m
->unit
, signo
, NULL
);
551 int machine_openpt(Machine
*m
, int flags
) {
559 fd
= posix_openpt(flags
);
563 if (unlockpt(fd
) < 0)
569 case MACHINE_CONTAINER
:
573 return openpt_in_namespace(m
->leader
, flags
);
580 int machine_open_terminal(Machine
*m
, const char *path
, int mode
) {
586 return open_terminal(path
, mode
);
588 case MACHINE_CONTAINER
:
592 return open_terminal_in_namespace(m
->leader
, path
, mode
);
599 void machine_release_unit(Machine
*m
) {
605 (void) hashmap_remove(m
->manager
->machine_units
, m
->unit
);
606 m
->unit
= mfree(m
->unit
);
609 int machine_get_uid_shift(Machine
*m
, uid_t
*ret
) {
610 char p
[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t
) + 1];
611 uid_t uid_base
, uid_shift
, uid_range
;
612 gid_t gid_base
, gid_shift
, gid_range
;
613 _cleanup_fclose_
FILE *f
= NULL
;
619 /* Return the base UID/GID of the specified machine. Note that this only works for containers with simple
620 * mappings. In most cases setups should be simple like this, and administrators should only care about the
621 * basic offset a container has relative to the host. This is what this function exposes.
623 * If we encounter any more complex mappings we politely refuse this with ENXIO. */
625 if (m
->class == MACHINE_HOST
) {
630 if (m
->class != MACHINE_CONTAINER
)
633 xsprintf(p
, "/proc/" PID_FMT
"/uid_map", m
->leader
);
636 if (errno
== ENOENT
) {
637 /* If the file doesn't exist, user namespacing is off in the kernel, return a zero mapping hence. */
645 /* Read the first line. There's at least one. */
647 k
= fscanf(f
, UID_FMT
" " UID_FMT
" " UID_FMT
"\n", &uid_base
, &uid_shift
, &uid_range
);
655 /* Not a mapping starting at 0? Then it's a complex mapping we can't expose here. */
658 /* Insist that at least the nobody user is mapped, everything else is weird, and hence complex, and we don't support it */
659 if (uid_range
< (uid_t
) 65534U)
662 /* If there's more than one line, then we don't support this mapping. */
668 xsprintf(p
, "/proc/" PID_FMT
"/gid_map", m
->leader
);
673 /* Read the first line. There's at least one. */
675 k
= fscanf(f
, GID_FMT
" " GID_FMT
" " GID_FMT
"\n", &gid_base
, &gid_shift
, &gid_range
);
683 /* If there's more than one line, then we don't support this file. */
687 /* If the UID and GID mapping doesn't match, we don't support this mapping. */
688 if (uid_base
!= (uid_t
) gid_base
)
690 if (uid_shift
!= (uid_t
) gid_shift
)
692 if (uid_range
!= (uid_t
) gid_range
)
699 static const char* const machine_class_table
[_MACHINE_CLASS_MAX
] = {
700 [MACHINE_CONTAINER
] = "container",
702 [MACHINE_HOST
] = "host",
705 DEFINE_STRING_TABLE_LOOKUP(machine_class
, MachineClass
);
707 static const char* const machine_state_table
[_MACHINE_STATE_MAX
] = {
708 [MACHINE_OPENING
] = "opening",
709 [MACHINE_RUNNING
] = "running",
710 [MACHINE_CLOSING
] = "closing"
713 DEFINE_STRING_TABLE_LOOKUP(machine_state
, MachineState
);
715 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
716 [KILL_LEADER
] = "leader",
720 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);