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