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