]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machine.c
Merge pull request #1750 from systemd/revert-1740-master
[thirdparty/systemd.git] / src / machine / machine.c
CommitLineData
9444b1f2
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
66cb2fde 22#include <errno.h>
9444b1f2
LP
23#include <string.h>
24#include <unistd.h>
9444b1f2 25
c3350683 26#include "sd-messages.h"
fb6becb4 27
b5efdb8a 28#include "alloc-util.h"
66cb2fde
LP
29#include "bus-error.h"
30#include "bus-util.h"
4f5dd394 31#include "escape.h"
3ffd4af2 32#include "fd-util.h"
9444b1f2 33#include "fileio.h"
66cb2fde
LP
34#include "formats-util.h"
35#include "hashmap.h"
4f5dd394 36#include "machine-dbus.h"
3ffd4af2 37#include "machine.h"
66cb2fde 38#include "mkdir.h"
6bedfcbb 39#include "parse-util.h"
9444b1f2 40#include "special.h"
8b43440b 41#include "string-table.h"
66cb2fde 42#include "terminal-util.h"
fb6becb4 43#include "unit-name.h"
66cb2fde 44#include "util.h"
75a8fd6a 45#include "extract-word.h"
9444b1f2 46
fbe55073 47Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
9444b1f2
LP
48 Machine *m;
49
50 assert(manager);
fbe55073 51 assert(class < _MACHINE_CLASS_MAX);
9444b1f2
LP
52 assert(name);
53
fbe55073
LP
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. */
57
9444b1f2
LP
58 m = new0(Machine, 1);
59 if (!m)
60 return NULL;
61
62 m->name = strdup(name);
63 if (!m->name)
64 goto fail;
65
fbe55073
LP
66 if (class != MACHINE_HOST) {
67 m->state_file = strappend("/run/systemd/machines/", m->name);
68 if (!m->state_file)
69 goto fail;
70 }
71
72 m->class = class;
9444b1f2
LP
73
74 if (hashmap_put(manager->machines, m->name, m) < 0)
75 goto fail;
76
9444b1f2
LP
77 m->manager = manager;
78
79 return m;
80
81fail:
82 free(m->state_file);
83 free(m->name);
84 free(m);
85
86 return NULL;
87}
88
89void machine_free(Machine *m) {
90 assert(m);
91
0370612e
LP
92 while (m->operations)
93 machine_operation_unref(m->operations);
94
9444b1f2 95 if (m->in_gc_queue)
71fda00f 96 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
9444b1f2 97
9b420b3c 98 machine_release_unit(m);
9444b1f2 99
fb6becb4
LP
100 free(m->scope_job);
101
9b420b3c 102 (void) hashmap_remove(m->manager->machines, m->name);
9444b1f2 103
fbe55073
LP
104 if (m->manager->host_machine == m)
105 m->manager->host_machine = NULL;
106
d3e84ddb 107 if (m->leader > 0)
9b420b3c 108 (void) hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
d3e84ddb 109
c3350683 110 sd_bus_message_unref(m->create_message);
fb6becb4 111
9444b1f2
LP
112 free(m->name);
113 free(m->state_file);
114 free(m->service);
9444b1f2 115 free(m->root_directory);
9b5ed6fe 116 free(m->netif);
9444b1f2
LP
117 free(m);
118}
119
120int machine_save(Machine *m) {
121 _cleanup_free_ char *temp_path = NULL;
122 _cleanup_fclose_ FILE *f = NULL;
123 int r;
124
125 assert(m);
fbe55073
LP
126
127 if (!m->state_file)
128 return 0;
9444b1f2
LP
129
130 if (!m->started)
131 return 0;
132
133 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0);
134 if (r < 0)
dacd6cee 135 goto fail;
9444b1f2
LP
136
137 r = fopen_temporary(m->state_file, &f, &temp_path);
138 if (r < 0)
dacd6cee 139 goto fail;
9444b1f2 140
dacd6cee 141 (void) fchmod(fileno(f), 0644);
9444b1f2
LP
142
143 fprintf(f,
144 "# This is private data. Do not parse.\n"
145 "NAME=%s\n",
146 m->name);
147
ca5405bb
LP
148 if (m->unit) {
149 _cleanup_free_ char *escaped;
150
151 escaped = cescape(m->unit);
152 if (!escaped) {
153 r = -ENOMEM;
dacd6cee 154 goto fail;
ca5405bb
LP
155 }
156
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 */
158 }
fb6becb4
LP
159
160 if (m->scope_job)
161 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
9444b1f2 162
ca5405bb
LP
163 if (m->service) {
164 _cleanup_free_ char *escaped;
9444b1f2 165
ca5405bb
LP
166 escaped = cescape(m->service);
167 if (!escaped) {
168 r = -ENOMEM;
dacd6cee 169 goto fail;
ca5405bb
LP
170 }
171 fprintf(f, "SERVICE=%s\n", escaped);
172 }
173
174 if (m->root_directory) {
175 _cleanup_free_ char *escaped;
176
177 escaped = cescape(m->root_directory);
178 if (!escaped) {
179 r = -ENOMEM;
dacd6cee 180 goto fail;
ca5405bb
LP
181 }
182 fprintf(f, "ROOT=%s\n", escaped);
183 }
9444b1f2
LP
184
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));
187
188 if (m->leader != 0)
90b2de37 189 fprintf(f, "LEADER="PID_FMT"\n", m->leader);
9444b1f2
LP
190
191 if (m->class != _MACHINE_CLASS_INVALID)
192 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
193
194 if (dual_timestamp_is_set(&m->timestamp))
195 fprintf(f,
90b2de37
ZJS
196 "REALTIME="USEC_FMT"\n"
197 "MONOTONIC="USEC_FMT"\n",
198 m->timestamp.realtime,
199 m->timestamp.monotonic);
9444b1f2 200
9b5ed6fe
LP
201 if (m->n_netif > 0) {
202 unsigned i;
203
204 fputs("NETIF=", f);
205
206 for (i = 0; i < m->n_netif; i++) {
207 if (i != 0)
208 fputc(' ', f);
209
210 fprintf(f, "%i", m->netif[i]);
211 }
212
213 fputc('\n', f);
214 }
215
034753ac
LP
216 r = fflush_and_check(f);
217 if (r < 0)
dacd6cee 218 goto fail;
9444b1f2 219
034753ac 220 if (rename(temp_path, m->state_file) < 0) {
9444b1f2 221 r = -errno;
dacd6cee 222 goto fail;
9444b1f2
LP
223 }
224
89f7c846
LP
225 if (m->unit) {
226 char *sl;
227
228 /* Create a symlink from the unit name to the machine
229 * name, so that we can quickly find the machine for
e62d9b81 230 * each given unit. Ignore error. */
63c372cb 231 sl = strjoina("/run/systemd/machines/unit:", m->unit);
e62d9b81 232 (void) symlink(m->name, sl);
89f7c846
LP
233 }
234
dacd6cee 235 return 0;
034753ac 236
dacd6cee
LP
237fail:
238 (void) unlink(m->state_file);
239
240 if (temp_path)
241 (void) unlink(temp_path);
9444b1f2 242
dacd6cee 243 return log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
9444b1f2
LP
244}
245
89f7c846
LP
246static void machine_unlink(Machine *m) {
247 assert(m);
248
249 if (m->unit) {
250
251 char *sl;
252
63c372cb 253 sl = strjoina("/run/systemd/machines/unit:", m->unit);
491ac9f2 254 (void) unlink(sl);
89f7c846
LP
255 }
256
257 if (m->state_file)
491ac9f2 258 (void) unlink(m->state_file);
89f7c846
LP
259}
260
9444b1f2 261int machine_load(Machine *m) {
9b5ed6fe 262 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
9444b1f2
LP
263 int r;
264
265 assert(m);
266
fbe55073
LP
267 if (!m->state_file)
268 return 0;
269
9444b1f2 270 r = parse_env_file(m->state_file, NEWLINE,
89f7c846 271 "SCOPE", &m->unit,
fb6becb4 272 "SCOPE_JOB", &m->scope_job,
9444b1f2 273 "SERVICE", &m->service,
9444b1f2
LP
274 "ROOT", &m->root_directory,
275 "ID", &id,
276 "LEADER", &leader,
277 "CLASS", &class,
278 "REALTIME", &realtime,
279 "MONOTONIC", &monotonic,
9b5ed6fe 280 "NETIF", &netif,
9444b1f2
LP
281 NULL);
282 if (r < 0) {
283 if (r == -ENOENT)
284 return 0;
285
8d3d7072 286 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
9444b1f2
LP
287 }
288
289 if (id)
290 sd_id128_from_string(id, &m->id);
291
292 if (leader)
293 parse_pid(leader, &m->leader);
294
295 if (class) {
296 MachineClass c;
297
298 c = machine_class_from_string(class);
299 if (c >= 0)
300 m->class = c;
301 }
302
303 if (realtime) {
304 unsigned long long l;
305 if (sscanf(realtime, "%llu", &l) > 0)
306 m->timestamp.realtime = l;
307 }
308
309 if (monotonic) {
310 unsigned long long l;
311 if (sscanf(monotonic, "%llu", &l) > 0)
312 m->timestamp.monotonic = l;
313 }
314
9b5ed6fe 315 if (netif) {
75a8fd6a
SS
316 size_t allocated = 0, nr = 0;
317 const char *p;
9b5ed6fe
LP
318 int *ni = NULL;
319
75a8fd6a
SS
320 p = netif;
321 for(;;) {
322 _cleanup_free_ char *word = NULL;
9b5ed6fe
LP
323 int ifi;
324
75a8fd6a
SS
325 r = extract_first_word(&p, &word, NULL, 0);
326 if (r < 0)
327 return log_error_errno(r, "Failed to parse NETIF: %s", netif);
9b5ed6fe 328
75a8fd6a
SS
329 if (r == 0)
330 break;
331
332 if (safe_atoi(word, &ifi) < 0)
9b5ed6fe
LP
333 continue;
334 if (ifi <= 0)
335 continue;
336
337 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
338 free(ni);
339 return log_oom();
340 }
341
342 ni[nr++] = ifi;
343 }
344
345 free(m->netif);
346 m->netif = ni;
347 m->n_netif = nr;
348 }
349
9444b1f2
LP
350 return r;
351}
352
c3350683 353static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
2c4c73b3 354 int r = 0;
9444b1f2
LP
355
356 assert(m);
fbe55073 357 assert(m->class != MACHINE_HOST);
9444b1f2 358
89f7c846 359 if (!m->unit) {
d0af76e6 360 _cleanup_free_ char *escaped = NULL;
39883f62 361 char *scope, *description, *job = NULL;
9444b1f2 362
fb6becb4 363 escaped = unit_name_escape(m->name);
9444b1f2
LP
364 if (!escaped)
365 return log_oom();
366
d0af76e6 367 scope = strjoin("machine-", escaped, ".scope", NULL);
f526ab7e 368 if (!scope)
9444b1f2 369 return log_oom();
9444b1f2 370
63c372cb 371 description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
9444b1f2 372
c3350683 373 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
d0af76e6 374 if (r < 0) {
c3350683 375 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
d0af76e6 376 free(scope);
f2d4f98d 377 return r;
d0af76e6 378 } else {
89f7c846 379 m->unit = scope;
d0af76e6
LP
380
381 free(m->scope_job);
382 m->scope_job = job;
383 }
9444b1f2
LP
384 }
385
89f7c846
LP
386 if (m->unit)
387 hashmap_put(m->manager->machine_units, m->unit, m);
d0af76e6 388
fb6becb4 389 return r;
9444b1f2
LP
390}
391
c3350683 392int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
9444b1f2
LP
393 int r;
394
395 assert(m);
396
fbe55073
LP
397 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
398 return -EOPNOTSUPP;
399
9444b1f2
LP
400 if (m->started)
401 return 0;
402
d3e84ddb
LP
403 r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m);
404 if (r < 0)
405 return r;
406
fb6becb4 407 /* Create cgroup */
c3350683 408 r = machine_start_scope(m, properties, error);
fb6becb4
LP
409 if (r < 0)
410 return r;
411
9444b1f2 412 log_struct(LOG_INFO,
e2cc6eca 413 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START),
9444b1f2 414 "NAME=%s", m->name,
de0671ee 415 "LEADER="PID_FMT, m->leader,
e2cc6eca 416 LOG_MESSAGE("New machine %s.", m->name),
9444b1f2
LP
417 NULL);
418
9444b1f2
LP
419 if (!dual_timestamp_is_set(&m->timestamp))
420 dual_timestamp_get(&m->timestamp);
421
422 m->started = true;
423
424 /* Save new machine data */
425 machine_save(m);
426
427 machine_send_signal(m, true);
428
429 return 0;
430}
431
fb6becb4 432static int machine_stop_scope(Machine *m) {
c3350683 433 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
39883f62 434 char *job = NULL;
9444b1f2 435 int r;
9444b1f2
LP
436
437 assert(m);
fbe55073 438 assert(m->class != MACHINE_HOST);
9444b1f2 439
89f7c846 440 if (!m->unit)
fb6becb4 441 return 0;
9444b1f2 442
c00a4c8f
LP
443 r = manager_stop_unit(m->manager, m->unit, &error, &job);
444 if (r < 0) {
445 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
446 return r;
fb6becb4 447 }
9444b1f2 448
fb6becb4
LP
449 free(m->scope_job);
450 m->scope_job = job;
9444b1f2 451
f14aa1f1 452 return 0;
9444b1f2
LP
453}
454
455int machine_stop(Machine *m) {
49f3fffd
LP
456 int r;
457 assert(m);
458
fbe55073
LP
459 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
460 return -EOPNOTSUPP;
461
49f3fffd
LP
462 r = machine_stop_scope(m);
463
464 m->stopping = true;
465
466 machine_save(m);
467
468 return r;
469}
470
471int machine_finalize(Machine *m) {
9444b1f2
LP
472 assert(m);
473
474 if (m->started)
475 log_struct(LOG_INFO,
e2cc6eca 476 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP),
9444b1f2 477 "NAME=%s", m->name,
de0671ee 478 "LEADER="PID_FMT, m->leader,
e2cc6eca 479 LOG_MESSAGE("Machine %s terminated.", m->name),
9444b1f2
LP
480 NULL);
481
89f7c846 482 machine_unlink(m);
9444b1f2
LP
483 machine_add_to_gc_queue(m);
484
49f3fffd 485 if (m->started) {
9444b1f2 486 machine_send_signal(m, false);
49f3fffd
LP
487 m->started = false;
488 }
9444b1f2 489
49f3fffd 490 return 0;
9444b1f2
LP
491}
492
a658cafa 493bool machine_check_gc(Machine *m, bool drop_not_started) {
9444b1f2
LP
494 assert(m);
495
fbe55073
LP
496 if (m->class == MACHINE_HOST)
497 return true;
498
9444b1f2 499 if (drop_not_started && !m->started)
c3350683 500 return false;
9444b1f2 501
c3350683
LP
502 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
503 return true;
9444b1f2 504
89f7c846 505 if (m->unit && manager_unit_is_active(m->manager, m->unit))
c3350683 506 return true;
9444b1f2 507
c3350683 508 return false;
9444b1f2
LP
509}
510
511void machine_add_to_gc_queue(Machine *m) {
512 assert(m);
513
514 if (m->in_gc_queue)
515 return;
516
71fda00f 517 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
9444b1f2
LP
518 m->in_gc_queue = true;
519}
520
fb6becb4
LP
521MachineState machine_get_state(Machine *s) {
522 assert(s);
9444b1f2 523
fbe55073
LP
524 if (s->class == MACHINE_HOST)
525 return MACHINE_RUNNING;
526
49f3fffd
LP
527 if (s->stopping)
528 return MACHINE_CLOSING;
529
fb6becb4 530 if (s->scope_job)
49f3fffd 531 return MACHINE_OPENING;
9444b1f2 532
fb6becb4
LP
533 return MACHINE_RUNNING;
534}
9444b1f2 535
fb6becb4
LP
536int machine_kill(Machine *m, KillWho who, int signo) {
537 assert(m);
9444b1f2 538
fbe55073
LP
539 if (!IN_SET(m->class, MACHINE_VM, MACHINE_CONTAINER))
540 return -EOPNOTSUPP;
541
89f7c846 542 if (!m->unit)
fb6becb4 543 return -ESRCH;
9444b1f2 544
de58a50e
LP
545 if (who == KILL_LEADER) {
546 /* If we shall simply kill the leader, do so directly */
547
548 if (kill(m->leader, signo) < 0)
549 return -errno;
9d685ca8
ED
550
551 return 0;
de58a50e
LP
552 }
553
554 /* Otherwise make PID 1 do it for us, for the entire cgroup */
555 return manager_kill_unit(m->manager, m->unit, signo, NULL);
9444b1f2
LP
556}
557
fbe55073
LP
558int machine_openpt(Machine *m, int flags) {
559 assert(m);
560
561 switch (m->class) {
562
5f430ff7
LP
563 case MACHINE_HOST: {
564 int fd;
565
566 fd = posix_openpt(flags);
567 if (fd < 0)
568 return -errno;
569
570 if (unlockpt(fd) < 0)
571 return -errno;
572
573 return fd;
574 }
fbe55073
LP
575
576 case MACHINE_CONTAINER:
577 if (m->leader <= 0)
578 return -EINVAL;
579
580 return openpt_in_namespace(m->leader, flags);
581
582 default:
583 return -EOPNOTSUPP;
584 }
585}
586
40e1f4ea
LP
587int machine_open_terminal(Machine *m, const char *path, int mode) {
588 assert(m);
589
590 switch (m->class) {
591
592 case MACHINE_HOST:
593 return open_terminal(path, mode);
594
595 case MACHINE_CONTAINER:
596 if (m->leader <= 0)
597 return -EINVAL;
598
599 return open_terminal_in_namespace(m->leader, path, mode);
600
601 default:
602 return -EOPNOTSUPP;
603 }
604}
605
0370612e
LP
606MachineOperation *machine_operation_unref(MachineOperation *o) {
607 if (!o)
608 return NULL;
609
610 sd_event_source_unref(o->event_source);
611
612 safe_close(o->errno_fd);
613
614 if (o->pid > 1)
615 (void) kill(o->pid, SIGKILL);
616
617 sd_bus_message_unref(o->message);
618
619 if (o->machine) {
620 LIST_REMOVE(operations, o->machine->operations, o);
621 o->machine->n_operations--;
622 }
623
624 free(o);
625 return NULL;
626}
627
9b420b3c
LP
628void machine_release_unit(Machine *m) {
629 assert(m);
630
631 if (!m->unit)
632 return;
633
634 (void) hashmap_remove(m->manager->machine_units, m->unit);
a1e58e8e 635 m->unit = mfree(m->unit);
9b420b3c
LP
636}
637
9444b1f2
LP
638static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
639 [MACHINE_CONTAINER] = "container",
fbe55073
LP
640 [MACHINE_VM] = "vm",
641 [MACHINE_HOST] = "host",
9444b1f2
LP
642};
643
644DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
fb6becb4
LP
645
646static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
647 [MACHINE_OPENING] = "opening",
648 [MACHINE_RUNNING] = "running",
649 [MACHINE_CLOSING] = "closing"
650};
651
652DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
1ee306e1
LP
653
654static const char* const kill_who_table[_KILL_WHO_MAX] = {
655 [KILL_LEADER] = "leader",
656 [KILL_ALL] = "all"
657};
658
659DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);