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"
33 #include "formats-util.h"
35 #include "machine-dbus.h"
39 #include "terminal-util.h"
40 #include "unit-name.h"
43 Machine
* machine_new(Manager
*manager
, MachineClass
class, const char *name
) {
47 assert(class < _MACHINE_CLASS_MAX
);
50 /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
51 * means as much as "we don't know yet", and that we'll figure
52 * it out later when loading the state file. */
58 m
->name
= strdup(name
);
62 if (class != MACHINE_HOST
) {
63 m
->state_file
= strappend("/run/systemd/machines/", m
->name
);
70 if (hashmap_put(manager
->machines
, m
->name
, m
) < 0)
85 void machine_free(Machine
*m
) {
89 machine_operation_unref(m
->operations
);
92 LIST_REMOVE(gc_queue
, m
->manager
->machine_gc_queue
, m
);
94 machine_release_unit(m
);
98 (void) hashmap_remove(m
->manager
->machines
, m
->name
);
100 if (m
->manager
->host_machine
== m
)
101 m
->manager
->host_machine
= NULL
;
104 (void) hashmap_remove_value(m
->manager
->machine_leaders
, UINT_TO_PTR(m
->leader
), m
);
106 sd_bus_message_unref(m
->create_message
);
111 free(m
->root_directory
);
116 int machine_save(Machine
*m
) {
117 _cleanup_free_
char *temp_path
= NULL
;
118 _cleanup_fclose_
FILE *f
= NULL
;
129 r
= mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
133 r
= fopen_temporary(m
->state_file
, &f
, &temp_path
);
137 (void) fchmod(fileno(f
), 0644);
140 "# This is private data. Do not parse.\n"
145 _cleanup_free_
char *escaped
;
147 escaped
= cescape(m
->unit
);
153 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 */
157 fprintf(f
, "SCOPE_JOB=%s\n", m
->scope_job
);
160 _cleanup_free_
char *escaped
;
162 escaped
= cescape(m
->service
);
167 fprintf(f
, "SERVICE=%s\n", escaped
);
170 if (m
->root_directory
) {
171 _cleanup_free_
char *escaped
;
173 escaped
= cescape(m
->root_directory
);
178 fprintf(f
, "ROOT=%s\n", escaped
);
181 if (!sd_id128_equal(m
->id
, SD_ID128_NULL
))
182 fprintf(f
, "ID=" SD_ID128_FORMAT_STR
"\n", SD_ID128_FORMAT_VAL(m
->id
));
185 fprintf(f
, "LEADER="PID_FMT
"\n", m
->leader
);
187 if (m
->class != _MACHINE_CLASS_INVALID
)
188 fprintf(f
, "CLASS=%s\n", machine_class_to_string(m
->class));
190 if (dual_timestamp_is_set(&m
->timestamp
))
192 "REALTIME="USEC_FMT
"\n"
193 "MONOTONIC="USEC_FMT
"\n",
194 m
->timestamp
.realtime
,
195 m
->timestamp
.monotonic
);
197 if (m
->n_netif
> 0) {
202 for (i
= 0; i
< m
->n_netif
; i
++) {
206 fprintf(f
, "%i", m
->netif
[i
]);
212 r
= fflush_and_check(f
);
216 if (rename(temp_path
, m
->state_file
) < 0) {
224 /* Create a symlink from the unit name to the machine
225 * name, so that we can quickly find the machine for
226 * each given unit. Ignore error. */
227 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
228 (void) symlink(m
->name
, sl
);
234 (void) unlink(m
->state_file
);
237 (void) unlink(temp_path
);
239 return log_error_errno(r
, "Failed to save machine data %s: %m", m
->state_file
);
242 static void machine_unlink(Machine
*m
) {
249 sl
= strjoina("/run/systemd/machines/unit:", m
->unit
);
254 (void) unlink(m
->state_file
);
257 int machine_load(Machine
*m
) {
258 _cleanup_free_
char *realtime
= NULL
, *monotonic
= NULL
, *id
= NULL
, *leader
= NULL
, *class = NULL
, *netif
= NULL
;
266 r
= parse_env_file(m
->state_file
, NEWLINE
,
268 "SCOPE_JOB", &m
->scope_job
,
269 "SERVICE", &m
->service
,
270 "ROOT", &m
->root_directory
,
274 "REALTIME", &realtime
,
275 "MONOTONIC", &monotonic
,
282 return log_error_errno(r
, "Failed to read %s: %m", m
->state_file
);
286 sd_id128_from_string(id
, &m
->id
);
289 parse_pid(leader
, &m
->leader
);
294 c
= machine_class_from_string(class);
300 unsigned long long l
;
301 if (sscanf(realtime
, "%llu", &l
) > 0)
302 m
->timestamp
.realtime
= l
;
306 unsigned long long l
;
307 if (sscanf(monotonic
, "%llu", &l
) > 0)
308 m
->timestamp
.monotonic
= l
;
312 size_t l
, allocated
= 0, nr
= 0;
313 const char *word
, *state
;
316 FOREACH_WORD(word
, l
, netif
, state
) {
320 *(char*) (mempcpy(buf
, word
, l
)) = 0;
322 if (safe_atoi(buf
, &ifi
) < 0)
327 if (!GREEDY_REALLOC(ni
, allocated
, nr
+1)) {
343 static int machine_start_scope(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
347 assert(m
->class != MACHINE_HOST
);
350 _cleanup_free_
char *escaped
= NULL
;
351 char *scope
, *description
, *job
= NULL
;
353 escaped
= unit_name_escape(m
->name
);
357 scope
= strjoin("machine-", escaped
, ".scope", NULL
);
361 description
= strjoina(m
->class == MACHINE_VM
? "Virtual Machine " : "Container ", m
->name
);
363 r
= manager_start_scope(m
->manager
, scope
, m
->leader
, SPECIAL_MACHINE_SLICE
, description
, properties
, error
, &job
);
365 log_error("Failed to start machine scope: %s", bus_error_message(error
, r
));
377 hashmap_put(m
->manager
->machine_units
, m
->unit
, m
);
382 int machine_start(Machine
*m
, sd_bus_message
*properties
, sd_bus_error
*error
) {
387 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
393 r
= hashmap_put(m
->manager
->machine_leaders
, UINT_TO_PTR(m
->leader
), m
);
398 r
= machine_start_scope(m
, properties
, error
);
403 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START
),
405 "LEADER="PID_FMT
, m
->leader
,
406 LOG_MESSAGE("New machine %s.", m
->name
),
409 if (!dual_timestamp_is_set(&m
->timestamp
))
410 dual_timestamp_get(&m
->timestamp
);
414 /* Save new machine data */
417 machine_send_signal(m
, true);
422 static int machine_stop_scope(Machine
*m
) {
423 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
428 assert(m
->class != MACHINE_HOST
);
433 r
= manager_stop_unit(m
->manager
, m
->unit
, &error
, &job
);
435 log_error("Failed to stop machine scope: %s", bus_error_message(&error
, r
));
445 int machine_stop(Machine
*m
) {
449 if (!IN_SET(m
->class, MACHINE_CONTAINER
, MACHINE_VM
))
452 r
= machine_stop_scope(m
);
461 int machine_finalize(Machine
*m
) {
466 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP
),
468 "LEADER="PID_FMT
, m
->leader
,
469 LOG_MESSAGE("Machine %s terminated.", m
->name
),
473 machine_add_to_gc_queue(m
);
476 machine_send_signal(m
, false);
483 bool machine_check_gc(Machine
*m
, bool drop_not_started
) {
486 if (m
->class == MACHINE_HOST
)
489 if (drop_not_started
&& !m
->started
)
492 if (m
->scope_job
&& manager_job_is_active(m
->manager
, m
->scope_job
))
495 if (m
->unit
&& manager_unit_is_active(m
->manager
, m
->unit
))
501 void machine_add_to_gc_queue(Machine
*m
) {
507 LIST_PREPEND(gc_queue
, m
->manager
->machine_gc_queue
, m
);
508 m
->in_gc_queue
= true;
511 MachineState
machine_get_state(Machine
*s
) {
514 if (s
->class == MACHINE_HOST
)
515 return MACHINE_RUNNING
;
518 return MACHINE_CLOSING
;
521 return MACHINE_OPENING
;
523 return MACHINE_RUNNING
;
526 int machine_kill(Machine
*m
, KillWho who
, int signo
) {
529 if (!IN_SET(m
->class, MACHINE_VM
, MACHINE_CONTAINER
))
535 if (who
== KILL_LEADER
) {
536 /* If we shall simply kill the leader, do so directly */
538 if (kill(m
->leader
, signo
) < 0)
544 /* Otherwise make PID 1 do it for us, for the entire cgroup */
545 return manager_kill_unit(m
->manager
, m
->unit
, signo
, NULL
);
548 int machine_openpt(Machine
*m
, int flags
) {
556 fd
= posix_openpt(flags
);
560 if (unlockpt(fd
) < 0)
566 case MACHINE_CONTAINER
:
570 return openpt_in_namespace(m
->leader
, flags
);
577 int machine_open_terminal(Machine
*m
, const char *path
, int mode
) {
583 return open_terminal(path
, mode
);
585 case MACHINE_CONTAINER
:
589 return open_terminal_in_namespace(m
->leader
, path
, mode
);
596 MachineOperation
*machine_operation_unref(MachineOperation
*o
) {
600 sd_event_source_unref(o
->event_source
);
602 safe_close(o
->errno_fd
);
605 (void) kill(o
->pid
, SIGKILL
);
607 sd_bus_message_unref(o
->message
);
610 LIST_REMOVE(operations
, o
->machine
->operations
, o
);
611 o
->machine
->n_operations
--;
618 void machine_release_unit(Machine
*m
) {
624 (void) hashmap_remove(m
->manager
->machine_units
, m
->unit
);
625 m
->unit
= mfree(m
->unit
);
628 static const char* const machine_class_table
[_MACHINE_CLASS_MAX
] = {
629 [MACHINE_CONTAINER
] = "container",
631 [MACHINE_HOST
] = "host",
634 DEFINE_STRING_TABLE_LOOKUP(machine_class
, MachineClass
);
636 static const char* const machine_state_table
[_MACHINE_STATE_MAX
] = {
637 [MACHINE_OPENING
] = "opening",
638 [MACHINE_RUNNING
] = "running",
639 [MACHINE_CLOSING
] = "closing"
642 DEFINE_STRING_TABLE_LOOKUP(machine_state
, MachineState
);
644 static const char* const kill_who_table
[_KILL_WHO_MAX
] = {
645 [KILL_LEADER
] = "leader",
649 DEFINE_STRING_TABLE_LOOKUP(kill_who
, KillWho
);