]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine.c
2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "sd-messages.h"
26 #include "alloc-util.h"
27 #include "bus-error.h"
30 #include "extract-word.h"
33 #include "formats-util.h"
35 #include "machine-dbus.h"
38 #include "parse-util.h"
39 #include "process-util.h"
41 #include "string-table.h"
42 #include "terminal-util.h"
43 #include "unit-name.h"
46 Machine
* machine_new(Manager
*manager
, MachineClass
class, const char *name
) {
50 assert(class < _MACHINE_CLASS_MAX
);
53 /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
54 * means as much as "we don't know yet", and that we'll figure
55 * it out later when loading the state file. */
61 m
->name
= strdup(name
);
65 if (class != MACHINE_HOST
) {
66 m
->state_file
= strappend("/run/systemd/machines/", m
->name
);
73 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);
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_equal(m
->id
, SD_ID128_NULL
))
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) {
205 for (i
= 0; i
< m
->n_netif
; i
++) {
209 fprintf(f
, "%i", m
->netif
[i
]);
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", NULL
);
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 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START
),
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 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP
),
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 static const char* const machine_class_table
[_MACHINE_CLASS_MAX
] = {
610 [MACHINE_CONTAINER
] = "container",
612 [MACHINE_HOST
] = "host",
615 DEFINE_STRING_TABLE_LOOKUP(machine_class
, MachineClass
);
617 static const char* const machine_state_table
[_MACHINE_STATE_MAX
] = {
618 [MACHINE_OPENING
] = "opening",
619 [MACHINE_RUNNING
] = "running",
620 [MACHINE_CLOSING
] = "closing"
623 DEFINE_STRING_TABLE_LOOKUP(machine_state
, MachineState
);
625 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
626 [KILL_LEADER
] = "leader",
630 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);