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 "bus-error.h"
31 #include "formats-util.h"
35 #include "terminal-util.h"
36 #include "unit-name.h"
38 #include "machine-dbus.h"
41 Machine
* machine_new(Manager
*manager
, MachineClass
class, const char *name
) {
45 assert(class < _MACHINE_CLASS_MAX
);
48 /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
49 * means as much as "we don't know yet", and that we'll figure
50 * it out later when loading the state file. */
56 m
->name
= strdup(name
);
60 if (class != MACHINE_HOST
) {
61 m
->state_file
= strappend("/run/systemd/machines/", m
->name
);
68 if (hashmap_put(manager
->machines
, m
->name
, m
) < 0)
83 void machine_free(Machine
*m
) {
87 machine_operation_unref(m
->operations
);
90 LIST_REMOVE(gc_queue
, m
->manager
->machine_gc_queue
, m
);
92 machine_release_unit(m
);
96 (void) hashmap_remove(m
->manager
->machines
, m
->name
);
98 if (m
->manager
->host_machine
== m
)
99 m
->manager
->host_machine
= NULL
;
102 (void) hashmap_remove_value(m
->manager
->machine_leaders
, UINT_TO_PTR(m
->leader
), m
);
104 sd_bus_message_unref(m
->create_message
);
109 free(m
->root_directory
);
114 int machine_save(Machine
*m
) {
115 _cleanup_free_
char *temp_path
= NULL
;
116 _cleanup_fclose_
FILE *f
= NULL
;
127 r
= mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
131 r
= fopen_temporary(m
->state_file
, &f
, &temp_path
);
135 (void) fchmod(fileno(f
), 0644);
138 "# This is private data. Do not parse.\n"
143 _cleanup_free_
char *escaped
;
145 escaped
= cescape(m
->unit
);
151 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 */
155 fprintf(f
, "SCOPE_JOB=%s\n", m
->scope_job
);
158 _cleanup_free_
char *escaped
;
160 escaped
= cescape(m
->service
);
165 fprintf(f
, "SERVICE=%s\n", escaped
);
168 if (m
->root_directory
) {
169 _cleanup_free_
char *escaped
;
171 escaped
= cescape(m
->root_directory
);
176 fprintf(f
, "ROOT=%s\n", escaped
);
179 if (!sd_id128_equal(m
->id
, SD_ID128_NULL
))
180 fprintf(f
, "ID=" SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(m
->id
));
183 fprintf(f
, "LEADER="PID_FMT
"\n", m
->leader
);
185 if (m
->class != _MACHINE_CLASS_INVALID
)
186 fprintf(f
, "CLASS=%s\n", machine_class_to_string(m
->class));
188 if (dual_timestamp_is_set(&m
->timestamp
))
190 "REALTIME="USEC_FMT
"\n"
191 "MONOTONIC="USEC_FMT
"\n",
192 m
->timestamp
.realtime
,
193 m
->timestamp
.monotonic
);
195 if (m
->n_netif
> 0) {
200 for (i
= 0; i
< m
->n_netif
; i
++) {
204 fprintf(f
, "%i", m
->netif
[i
]);
210 r
= fflush_and_check(f
);
214 if (rename(temp_path
, m
->state_file
) < 0) {
222 /* Create a symlink from the unit name to the machine
223 * name, so that we can quickly find the machine for
224 * each given unit. Ignore error. */
225 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
226 (void) symlink(m
->name
, sl
);
232 (void) unlink(m
->state_file
);
235 (void) unlink(temp_path
);
237 return log_error_errno(r
, "Failed to save machine data %s: %m", m
->state_file
);
240 static void machine_unlink(Machine
*m
) {
247 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
252 (void) unlink(m
->state_file
);
255 int machine_load(Machine
*m
) {
256 _cleanup_free_
char *realtime
= NULL
, *monotonic
= NULL
, *id
= NULL
, *leader
= NULL
, *class = NULL
, *netif
= NULL
;
264 r
= parse_env_file(m
->state_file
, NEWLINE
,
266 "SCOPE_JOB", &m
->scope_job
,
267 "SERVICE", &m
->service
,
268 "ROOT", &m
->root_directory
,
272 "REALTIME", &realtime
,
273 "MONOTONIC", &monotonic
,
280 return log_error_errno(r
, "Failed to read %s: %m", m
->state_file
);
284 sd_id128_from_string(id
, &m
->id
);
287 parse_pid(leader
, &m
->leader
);
292 c
= machine_class_from_string(class);
298 unsigned long long l
;
299 if (sscanf(realtime
, "%llu", &l
) > 0)
300 m
->timestamp
.realtime
= l
;
304 unsigned long long l
;
305 if (sscanf(monotonic
, "%llu", &l
) > 0)
306 m
->timestamp
.monotonic
= l
;
310 size_t l
, allocated
= 0, nr
= 0;
311 const char *word
, *state
;
314 FOREACH_WORD(word
, l
, netif
, state
) {
318 *(char*) (mempcpy(buf
, word
, l
)) = 0;
320 if (safe_atoi(buf
, &ifi
) < 0)
325 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
341 static int machine_start_scope(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
345 assert(m
->class != MACHINE_HOST
);
348 _cleanup_free_
char *escaped
= NULL
;
349 char *scope
, *description
, *job
= NULL
;
351 escaped
= unit_name_escape(m
->name
);
355 scope
= strjoin("machine-", escaped
, ".scope", NULL
);
359 description
= strjoina(m
->class == MACHINE_VM
? "Virtual Machine " : "Container ", m
->name
);
361 r
= manager_start_scope(m
->manager
, scope
, m
->leader
, SPECIAL_MACHINE_SLICE
, description
, properties
, error
, &job
);
363 log_error("Failed to start machine scope: %s", bus_error_message(error
, r
));
375 hashmap_put(m
->manager
->machine_units
, m
->unit
, m
);
380 int machine_start(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
385 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
391 r
= hashmap_put(m
->manager
->machine_leaders
, UINT_TO_PTR(m
->leader
), m
);
396 r
= machine_start_scope(m
, properties
, error
);
401 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START
),
403 "LEADER="PID_FMT
, m
->leader
,
404 LOG_MESSAGE("New machine %s.", m
->name
),
407 if (!dual_timestamp_is_set(&m
->timestamp
))
408 dual_timestamp_get(&m
->timestamp
);
412 /* Save new machine data */
415 machine_send_signal(m
, true);
420 static int machine_stop_scope(Machine
*m
) {
421 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
426 assert(m
->class != MACHINE_HOST
);
431 r
= manager_stop_unit(m
->manager
, m
->unit
, &error
, &job
);
433 log_error("Failed to stop machine scope: %s", bus_error_message(&error
, r
));
443 int machine_stop(Machine
*m
) {
447 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
450 r
= machine_stop_scope(m
);
459 int machine_finalize(Machine
*m
) {
464 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP
),
466 "LEADER="PID_FMT
, m
->leader
,
467 LOG_MESSAGE("Machine %s terminated.", m
->name
),
471 machine_add_to_gc_queue(m
);
474 machine_send_signal(m
, false);
481 bool machine_check_gc(Machine
*m
, bool drop_not_started
) {
484 if (m
->class == MACHINE_HOST
)
487 if (drop_not_started
&& !m
->started
)
490 if (m
->scope_job
&& manager_job_is_active(m
->manager
, m
->scope_job
))
493 if (m
->unit
&& manager_unit_is_active(m
->manager
, m
->unit
))
499 void machine_add_to_gc_queue(Machine
*m
) {
505 LIST_PREPEND(gc_queue
, m
->manager
->machine_gc_queue
, m
);
506 m
->in_gc_queue
= true;
509 MachineState
machine_get_state(Machine
*s
) {
512 if (s
->class == MACHINE_HOST
)
513 return MACHINE_RUNNING
;
516 return MACHINE_CLOSING
;
519 return MACHINE_OPENING
;
521 return MACHINE_RUNNING
;
524 int machine_kill(Machine
*m
, KillWho who
, int signo
) {
527 if (!IN_SET(m
->class, MACHINE_VM
, MACHINE_CONTAINER
))
533 if (who
== KILL_LEADER
) {
534 /* If we shall simply kill the leader, do so directly */
536 if (kill(m
->leader
, signo
) < 0)
542 /* Otherwise make PID 1 do it for us, for the entire cgroup */
543 return manager_kill_unit(m
->manager
, m
->unit
, signo
, NULL
);
546 int machine_openpt(Machine
*m
, int flags
) {
554 fd
= posix_openpt(flags
);
558 if (unlockpt(fd
) < 0)
564 case MACHINE_CONTAINER
:
568 return openpt_in_namespace(m
->leader
, flags
);
575 int machine_open_terminal(Machine
*m
, const char *path
, int mode
) {
581 return open_terminal(path
, mode
);
583 case MACHINE_CONTAINER
:
587 return open_terminal_in_namespace(m
->leader
, path
, mode
);
594 MachineOperation
*machine_operation_unref(MachineOperation
*o
) {
598 sd_event_source_unref(o
->event_source
);
600 safe_close(o
->errno_fd
);
603 (void) kill(o
->pid
, SIGKILL
);
605 sd_bus_message_unref(o
->message
);
608 LIST_REMOVE(operations
, o
->machine
->operations
, o
);
609 o
->machine
->n_operations
--;
616 void machine_release_unit(Machine
*m
) {
622 (void) hashmap_remove(m
->manager
->machine_units
, m
->unit
);
623 m
->unit
= mfree(m
->unit
);
626 static const char* const machine_class_table
[_MACHINE_CLASS_MAX
] = {
627 [MACHINE_CONTAINER
] = "container",
629 [MACHINE_HOST
] = "host",
632 DEFINE_STRING_TABLE_LOOKUP(machine_class
, MachineClass
);
634 static const char* const machine_state_table
[_MACHINE_STATE_MAX
] = {
635 [MACHINE_OPENING
] = "opening",
636 [MACHINE_RUNNING
] = "running",
637 [MACHINE_CLOSING
] = "closing"
640 DEFINE_STRING_TABLE_LOOKUP(machine_state
, MachineState
);
642 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
643 [KILL_LEADER
] = "leader",
647 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);