]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine.c
Merge pull request #7059 from yuwata/dynamic-user-7013
[thirdparty/systemd.git] / src / machine / machine.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
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.
10
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.
15
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/>.
18 ***/
19
20 #include <errno.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include "sd-messages.h"
25
26 #include "alloc-util.h"
27 #include "bus-error.h"
28 #include "bus-util.h"
29 #include "escape.h"
30 #include "extract-word.h"
31 #include "fd-util.h"
32 #include "fileio.h"
33 #include "format-util.h"
34 #include "hashmap.h"
35 #include "machine-dbus.h"
36 #include "machine.h"
37 #include "mkdir.h"
38 #include "parse-util.h"
39 #include "process-util.h"
40 #include "special.h"
41 #include "stdio-util.h"
42 #include "string-table.h"
43 #include "terminal-util.h"
44 #include "unit-name.h"
45 #include "util.h"
46
47 Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
48 Machine *m;
49
50 assert(manager);
51 assert(class < _MACHINE_CLASS_MAX);
52 assert(name);
53
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
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
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;
73
74 if (hashmap_put(manager->machines, m->name, m) < 0)
75 goto fail;
76
77 m->manager = manager;
78
79 return m;
80
81 fail:
82 free(m->state_file);
83 free(m->name);
84 return mfree(m);
85 }
86
87 void machine_free(Machine *m) {
88 assert(m);
89
90 while (m->operations)
91 operation_free(m->operations);
92
93 if (m->in_gc_queue)
94 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
95
96 machine_release_unit(m);
97
98 free(m->scope_job);
99
100 (void) hashmap_remove(m->manager->machines, m->name);
101
102 if (m->manager->host_machine == m)
103 m->manager->host_machine = NULL;
104
105 if (m->leader > 0)
106 (void) hashmap_remove_value(m->manager->machine_leaders, PID_TO_PTR(m->leader), m);
107
108 sd_bus_message_unref(m->create_message);
109
110 free(m->name);
111 free(m->state_file);
112 free(m->service);
113 free(m->root_directory);
114 free(m->netif);
115 free(m);
116 }
117
118 int machine_save(Machine *m) {
119 _cleanup_free_ char *temp_path = NULL;
120 _cleanup_fclose_ FILE *f = NULL;
121 int r;
122
123 assert(m);
124
125 if (!m->state_file)
126 return 0;
127
128 if (!m->started)
129 return 0;
130
131 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0, false);
132 if (r < 0)
133 goto fail;
134
135 r = fopen_temporary(m->state_file, &f, &temp_path);
136 if (r < 0)
137 goto fail;
138
139 (void) fchmod(fileno(f), 0644);
140
141 fprintf(f,
142 "# This is private data. Do not parse.\n"
143 "NAME=%s\n",
144 m->name);
145
146 if (m->unit) {
147 _cleanup_free_ char *escaped;
148
149 escaped = cescape(m->unit);
150 if (!escaped) {
151 r = -ENOMEM;
152 goto fail;
153 }
154
155 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 */
156 }
157
158 if (m->scope_job)
159 fprintf(f, "SCOPE_JOB=%s\n", m->scope_job);
160
161 if (m->service) {
162 _cleanup_free_ char *escaped;
163
164 escaped = cescape(m->service);
165 if (!escaped) {
166 r = -ENOMEM;
167 goto fail;
168 }
169 fprintf(f, "SERVICE=%s\n", escaped);
170 }
171
172 if (m->root_directory) {
173 _cleanup_free_ char *escaped;
174
175 escaped = cescape(m->root_directory);
176 if (!escaped) {
177 r = -ENOMEM;
178 goto fail;
179 }
180 fprintf(f, "ROOT=%s\n", escaped);
181 }
182
183 if (!sd_id128_is_null(m->id))
184 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
185
186 if (m->leader != 0)
187 fprintf(f, "LEADER="PID_FMT"\n", m->leader);
188
189 if (m->class != _MACHINE_CLASS_INVALID)
190 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
191
192 if (dual_timestamp_is_set(&m->timestamp))
193 fprintf(f,
194 "REALTIME="USEC_FMT"\n"
195 "MONOTONIC="USEC_FMT"\n",
196 m->timestamp.realtime,
197 m->timestamp.monotonic);
198
199 if (m->n_netif > 0) {
200 unsigned i;
201
202 fputs_unlocked("NETIF=", f);
203
204 for (i = 0; i < m->n_netif; i++) {
205 if (i != 0)
206 fputc_unlocked(' ', f);
207
208 fprintf(f, "%i", m->netif[i]);
209 }
210
211 fputc_unlocked('\n', f);
212 }
213
214 r = fflush_and_check(f);
215 if (r < 0)
216 goto fail;
217
218 if (rename(temp_path, m->state_file) < 0) {
219 r = -errno;
220 goto fail;
221 }
222
223 if (m->unit) {
224 char *sl;
225
226 /* Create a symlink from the unit name to the machine
227 * name, so that we can quickly find the machine for
228 * each given unit. Ignore error. */
229 sl = strjoina("/run/systemd/machines/unit:", m->unit);
230 (void) symlink(m->name, sl);
231 }
232
233 return 0;
234
235 fail:
236 (void) unlink(m->state_file);
237
238 if (temp_path)
239 (void) unlink(temp_path);
240
241 return log_error_errno(r, "Failed to save machine data %s: %m", m->state_file);
242 }
243
244 static void machine_unlink(Machine *m) {
245 assert(m);
246
247 if (m->unit) {
248
249 char *sl;
250
251 sl = strjoina("/run/systemd/machines/unit:", m->unit);
252 (void) unlink(sl);
253 }
254
255 if (m->state_file)
256 (void) unlink(m->state_file);
257 }
258
259 int machine_load(Machine *m) {
260 _cleanup_free_ char *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *class = NULL, *netif = NULL;
261 int r;
262
263 assert(m);
264
265 if (!m->state_file)
266 return 0;
267
268 r = parse_env_file(m->state_file, NEWLINE,
269 "SCOPE", &m->unit,
270 "SCOPE_JOB", &m->scope_job,
271 "SERVICE", &m->service,
272 "ROOT", &m->root_directory,
273 "ID", &id,
274 "LEADER", &leader,
275 "CLASS", &class,
276 "REALTIME", &realtime,
277 "MONOTONIC", &monotonic,
278 "NETIF", &netif,
279 NULL);
280 if (r < 0) {
281 if (r == -ENOENT)
282 return 0;
283
284 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
285 }
286
287 if (id)
288 sd_id128_from_string(id, &m->id);
289
290 if (leader)
291 parse_pid(leader, &m->leader);
292
293 if (class) {
294 MachineClass c;
295
296 c = machine_class_from_string(class);
297 if (c >= 0)
298 m->class = c;
299 }
300
301 if (realtime)
302 timestamp_deserialize(realtime, &m->timestamp.realtime);
303 if (monotonic)
304 timestamp_deserialize(monotonic, &m->timestamp.monotonic);
305
306 if (netif) {
307 size_t allocated = 0, nr = 0;
308 const char *p;
309 int *ni = NULL;
310
311 p = netif;
312 for (;;) {
313 _cleanup_free_ char *word = NULL;
314 int ifi;
315
316 r = extract_first_word(&p, &word, NULL, 0);
317 if (r == 0)
318 break;
319 if (r == -ENOMEM)
320 return log_oom();
321 if (r < 0) {
322 log_warning_errno(r, "Failed to parse NETIF: %s", netif);
323 break;
324 }
325
326 if (parse_ifindex(word, &ifi) < 0)
327 continue;
328
329 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
330 free(ni);
331 return log_oom();
332 }
333
334 ni[nr++] = ifi;
335 }
336
337 free(m->netif);
338 m->netif = ni;
339 m->n_netif = nr;
340 }
341
342 return r;
343 }
344
345 static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
346 int r = 0;
347
348 assert(m);
349 assert(m->class != MACHINE_HOST);
350
351 if (!m->unit) {
352 _cleanup_free_ char *escaped = NULL;
353 char *scope, *description, *job = NULL;
354
355 escaped = unit_name_escape(m->name);
356 if (!escaped)
357 return log_oom();
358
359 scope = strjoin("machine-", escaped, ".scope");
360 if (!scope)
361 return log_oom();
362
363 description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
364
365 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
366 if (r < 0) {
367 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
368 free(scope);
369 return r;
370 } else {
371 m->unit = scope;
372
373 free(m->scope_job);
374 m->scope_job = job;
375 }
376 }
377
378 if (m->unit)
379 hashmap_put(m->manager->machine_units, m->unit, m);
380
381 return r;
382 }
383
384 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
385 int r;
386
387 assert(m);
388
389 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
390 return -EOPNOTSUPP;
391
392 if (m->started)
393 return 0;
394
395 r = hashmap_put(m->manager->machine_leaders, PID_TO_PTR(m->leader), m);
396 if (r < 0)
397 return r;
398
399 /* Create cgroup */
400 r = machine_start_scope(m, properties, error);
401 if (r < 0)
402 return r;
403
404 log_struct(LOG_INFO,
405 "MESSAGE_ID=" SD_MESSAGE_MACHINE_START_STR,
406 "NAME=%s", m->name,
407 "LEADER="PID_FMT, m->leader,
408 LOG_MESSAGE("New machine %s.", m->name),
409 NULL);
410
411 if (!dual_timestamp_is_set(&m->timestamp))
412 dual_timestamp_get(&m->timestamp);
413
414 m->started = true;
415
416 /* Save new machine data */
417 machine_save(m);
418
419 machine_send_signal(m, true);
420
421 return 0;
422 }
423
424 static int machine_stop_scope(Machine *m) {
425 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
426 char *job = NULL;
427 int r;
428
429 assert(m);
430 assert(m->class != MACHINE_HOST);
431
432 if (!m->unit)
433 return 0;
434
435 r = manager_stop_unit(m->manager, m->unit, &error, &job);
436 if (r < 0) {
437 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
438 return r;
439 }
440
441 free(m->scope_job);
442 m->scope_job = job;
443
444 return 0;
445 }
446
447 int machine_stop(Machine *m) {
448 int r;
449 assert(m);
450
451 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
452 return -EOPNOTSUPP;
453
454 r = machine_stop_scope(m);
455
456 m->stopping = true;
457
458 machine_save(m);
459
460 return r;
461 }
462
463 int machine_finalize(Machine *m) {
464 assert(m);
465
466 if (m->started)
467 log_struct(LOG_INFO,
468 "MESSAGE_ID=" SD_MESSAGE_MACHINE_STOP_STR,
469 "NAME=%s", m->name,
470 "LEADER="PID_FMT, m->leader,
471 LOG_MESSAGE("Machine %s terminated.", m->name),
472 NULL);
473
474 machine_unlink(m);
475 machine_add_to_gc_queue(m);
476
477 if (m->started) {
478 machine_send_signal(m, false);
479 m->started = false;
480 }
481
482 return 0;
483 }
484
485 bool machine_check_gc(Machine *m, bool drop_not_started) {
486 assert(m);
487
488 if (m->class == MACHINE_HOST)
489 return true;
490
491 if (drop_not_started && !m->started)
492 return false;
493
494 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
495 return true;
496
497 if (m->unit && manager_unit_is_active(m->manager, m->unit))
498 return true;
499
500 return false;
501 }
502
503 void machine_add_to_gc_queue(Machine *m) {
504 assert(m);
505
506 if (m->in_gc_queue)
507 return;
508
509 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
510 m->in_gc_queue = true;
511 }
512
513 MachineState machine_get_state(Machine *s) {
514 assert(s);
515
516 if (s->class == MACHINE_HOST)
517 return MACHINE_RUNNING;
518
519 if (s->stopping)
520 return MACHINE_CLOSING;
521
522 if (s->scope_job)
523 return MACHINE_OPENING;
524
525 return MACHINE_RUNNING;
526 }
527
528 int machine_kill(Machine *m, KillWho who, int signo) {
529 assert(m);
530
531 if (!IN_SET(m->class, MACHINE_VM, MACHINE_CONTAINER))
532 return -EOPNOTSUPP;
533
534 if (!m->unit)
535 return -ESRCH;
536
537 if (who == KILL_LEADER) {
538 /* If we shall simply kill the leader, do so directly */
539
540 if (kill(m->leader, signo) < 0)
541 return -errno;
542
543 return 0;
544 }
545
546 /* Otherwise, make PID 1 do it for us, for the entire cgroup */
547 return manager_kill_unit(m->manager, m->unit, signo, NULL);
548 }
549
550 int machine_openpt(Machine *m, int flags) {
551 assert(m);
552
553 switch (m->class) {
554
555 case MACHINE_HOST: {
556 int fd;
557
558 fd = posix_openpt(flags);
559 if (fd < 0)
560 return -errno;
561
562 if (unlockpt(fd) < 0)
563 return -errno;
564
565 return fd;
566 }
567
568 case MACHINE_CONTAINER:
569 if (m->leader <= 0)
570 return -EINVAL;
571
572 return openpt_in_namespace(m->leader, flags);
573
574 default:
575 return -EOPNOTSUPP;
576 }
577 }
578
579 int machine_open_terminal(Machine *m, const char *path, int mode) {
580 assert(m);
581
582 switch (m->class) {
583
584 case MACHINE_HOST:
585 return open_terminal(path, mode);
586
587 case MACHINE_CONTAINER:
588 if (m->leader <= 0)
589 return -EINVAL;
590
591 return open_terminal_in_namespace(m->leader, path, mode);
592
593 default:
594 return -EOPNOTSUPP;
595 }
596 }
597
598 void machine_release_unit(Machine *m) {
599 assert(m);
600
601 if (!m->unit)
602 return;
603
604 (void) hashmap_remove(m->manager->machine_units, m->unit);
605 m->unit = mfree(m->unit);
606 }
607
608 int machine_get_uid_shift(Machine *m, uid_t *ret) {
609 char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
610 uid_t uid_base, uid_shift, uid_range;
611 gid_t gid_base, gid_shift, gid_range;
612 _cleanup_fclose_ FILE *f = NULL;
613 int k;
614
615 assert(m);
616 assert(ret);
617
618 /* Return the base UID/GID of the specified machine. Note that this only works for containers with simple
619 * mappings. In most cases setups should be simple like this, and administrators should only care about the
620 * basic offset a container has relative to the host. This is what this function exposes.
621 *
622 * If we encounter any more complex mappings we politely refuse this with ENXIO. */
623
624 if (m->class == MACHINE_HOST) {
625 *ret = 0;
626 return 0;
627 }
628
629 if (m->class != MACHINE_CONTAINER)
630 return -EOPNOTSUPP;
631
632 xsprintf(p, "/proc/" PID_FMT "/uid_map", m->leader);
633 f = fopen(p, "re");
634 if (!f) {
635 if (errno == ENOENT) {
636 /* If the file doesn't exist, user namespacing is off in the kernel, return a zero mapping hence. */
637 *ret = 0;
638 return 0;
639 }
640
641 return -errno;
642 }
643
644 /* Read the first line. There's at least one. */
645 errno = 0;
646 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
647 if (k != 3) {
648 if (ferror(f))
649 return -errno;
650
651 return -EBADMSG;
652 }
653
654 /* Not a mapping starting at 0? Then it's a complex mapping we can't expose here. */
655 if (uid_base != 0)
656 return -ENXIO;
657 /* Insist that at least the nobody user is mapped, everything else is weird, and hence complex, and we don't support it */
658 if (uid_range < (uid_t) 65534U)
659 return -ENXIO;
660
661 /* If there's more than one line, then we don't support this mapping. */
662 if (fgetc(f) != EOF)
663 return -ENXIO;
664
665 fclose(f);
666
667 xsprintf(p, "/proc/" PID_FMT "/gid_map", m->leader);
668 f = fopen(p, "re");
669 if (!f)
670 return -errno;
671
672 /* Read the first line. There's at least one. */
673 errno = 0;
674 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT "\n", &gid_base, &gid_shift, &gid_range);
675 if (k != 3) {
676 if (ferror(f))
677 return -errno;
678
679 return -EBADMSG;
680 }
681
682 /* If there's more than one line, then we don't support this file. */
683 if (fgetc(f) != EOF)
684 return -ENXIO;
685
686 /* If the UID and GID mapping doesn't match, we don't support this mapping. */
687 if (uid_base != (uid_t) gid_base)
688 return -ENXIO;
689 if (uid_shift != (uid_t) gid_shift)
690 return -ENXIO;
691 if (uid_range != (uid_t) gid_range)
692 return -ENXIO;
693
694 *ret = uid_shift;
695 return 0;
696 }
697
698 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
699 [MACHINE_CONTAINER] = "container",
700 [MACHINE_VM] = "vm",
701 [MACHINE_HOST] = "host",
702 };
703
704 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
705
706 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
707 [MACHINE_OPENING] = "opening",
708 [MACHINE_RUNNING] = "running",
709 [MACHINE_CLOSING] = "closing"
710 };
711
712 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
713
714 static const char* const kill_who_table[_KILL_WHO_MAX] = {
715 [KILL_LEADER] = "leader",
716 [KILL_ALL] = "all"
717 };
718
719 DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);