]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machine.c
Merge pull request #7625 from thom311/th/const-strlen
[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>
9444b1f2 24
c3350683 25#include "sd-messages.h"
fb6becb4 26
b5efdb8a 27#include "alloc-util.h"
66cb2fde
LP
28#include "bus-error.h"
29#include "bus-util.h"
4f5dd394 30#include "escape.h"
cf0fbc49 31#include "extract-word.h"
3ffd4af2 32#include "fd-util.h"
9444b1f2 33#include "fileio.h"
f97b34a6 34#include "format-util.h"
66cb2fde 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"
4a0b58c4 40#include "process-util.h"
9444b1f2 41#include "special.h"
3401419b 42#include "stdio-util.h"
8b43440b 43#include "string-table.h"
66cb2fde 44#include "terminal-util.h"
fb6becb4 45#include "unit-name.h"
3a664727 46#include "user-util.h"
66cb2fde 47#include "util.h"
9444b1f2 48
fbe55073 49Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
9444b1f2
LP
50 Machine *m;
51
52 assert(manager);
fbe55073 53 assert(class < _MACHINE_CLASS_MAX);
9444b1f2
LP
54 assert(name);
55
fbe55073
LP
56 /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
57 * means as much as "we don't know yet", and that we'll figure
58 * it out later when loading the state file. */
59
9444b1f2
LP
60 m = new0(Machine, 1);
61 if (!m)
62 return NULL;
63
64 m->name = strdup(name);
65 if (!m->name)
66 goto fail;
67
fbe55073
LP
68 if (class != MACHINE_HOST) {
69 m->state_file = strappend("/run/systemd/machines/", m->name);
70 if (!m->state_file)
71 goto fail;
72 }
73
74 m->class = class;
9444b1f2
LP
75
76 if (hashmap_put(manager->machines, m->name, m) < 0)
77 goto fail;
78
9444b1f2
LP
79 m->manager = manager;
80
81 return m;
82
83fail:
84 free(m->state_file);
85 free(m->name);
6b430fdb 86 return mfree(m);
9444b1f2
LP
87}
88
89void machine_free(Machine *m) {
90 assert(m);
91
0370612e 92 while (m->operations)
795c5d31 93 operation_free(m->operations);
0370612e 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)
4a0b58c4 108 (void) hashmap_remove_value(m->manager->machine_leaders, PID_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
c31ad024 133 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0, false);
9444b1f2 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 184
3bbaff3e 185 if (!sd_id128_is_null(m->id))
9444b1f2
LP
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
4b61c875 204 fputs_unlocked("NETIF=", f);
9b5ed6fe
LP
205
206 for (i = 0; i < m->n_netif; i++) {
207 if (i != 0)
4b61c875 208 fputc_unlocked(' ', f);
9b5ed6fe
LP
209
210 fprintf(f, "%i", m->netif[i]);
211 }
212
4b61c875 213 fputc_unlocked('\n', f);
9b5ed6fe
LP
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
b895a735
BR
303 if (realtime)
304 timestamp_deserialize(realtime, &m->timestamp.realtime);
305 if (monotonic)
306 timestamp_deserialize(monotonic, &m->timestamp.monotonic);
9444b1f2 307
9b5ed6fe 308 if (netif) {
75a8fd6a
SS
309 size_t allocated = 0, nr = 0;
310 const char *p;
9b5ed6fe
LP
311 int *ni = NULL;
312
75a8fd6a 313 p = netif;
9ed794a3 314 for (;;) {
75a8fd6a 315 _cleanup_free_ char *word = NULL;
9b5ed6fe
LP
316 int ifi;
317
75a8fd6a 318 r = extract_first_word(&p, &word, NULL, 0);
75a8fd6a
SS
319 if (r == 0)
320 break;
6a37c684 321 if (r == -ENOMEM)
52278ad3 322 return log_oom();
6a37c684 323 if (r < 0) {
52278ad3 324 log_warning_errno(r, "Failed to parse NETIF: %s", netif);
6a37c684 325 break;
52278ad3 326 }
75a8fd6a 327
6ad623a3 328 if (parse_ifindex(word, &ifi) < 0)
9b5ed6fe
LP
329 continue;
330
331 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
332 free(ni);
333 return log_oom();
334 }
335
336 ni[nr++] = ifi;
337 }
338
339 free(m->netif);
340 m->netif = ni;
341 m->n_netif = nr;
342 }
343
9444b1f2
LP
344 return r;
345}
346
c3350683 347static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
2c4c73b3 348 int r = 0;
9444b1f2
LP
349
350 assert(m);
fbe55073 351 assert(m->class != MACHINE_HOST);
9444b1f2 352
89f7c846 353 if (!m->unit) {
d0af76e6 354 _cleanup_free_ char *escaped = NULL;
39883f62 355 char *scope, *description, *job = NULL;
9444b1f2 356
fb6becb4 357 escaped = unit_name_escape(m->name);
9444b1f2
LP
358 if (!escaped)
359 return log_oom();
360
605405c6 361 scope = strjoin("machine-", escaped, ".scope");
f526ab7e 362 if (!scope)
9444b1f2 363 return log_oom();
9444b1f2 364
63c372cb 365 description = strjoina(m->class == MACHINE_VM ? "Virtual Machine " : "Container ", m->name);
9444b1f2 366
c3350683 367 r = manager_start_scope(m->manager, scope, m->leader, SPECIAL_MACHINE_SLICE, description, properties, error, &job);
d0af76e6 368 if (r < 0) {
c3350683 369 log_error("Failed to start machine scope: %s", bus_error_message(error, r));
d0af76e6 370 free(scope);
f2d4f98d 371 return r;
d0af76e6 372 } else {
89f7c846 373 m->unit = scope;
d0af76e6
LP
374
375 free(m->scope_job);
376 m->scope_job = job;
377 }
9444b1f2
LP
378 }
379
89f7c846
LP
380 if (m->unit)
381 hashmap_put(m->manager->machine_units, m->unit, m);
d0af76e6 382
fb6becb4 383 return r;
9444b1f2
LP
384}
385
c3350683 386int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
9444b1f2
LP
387 int r;
388
389 assert(m);
390
fbe55073
LP
391 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
392 return -EOPNOTSUPP;
393
9444b1f2
LP
394 if (m->started)
395 return 0;
396
4a0b58c4 397 r = hashmap_put(m->manager->machine_leaders, PID_TO_PTR(m->leader), m);
d3e84ddb
LP
398 if (r < 0)
399 return r;
400
fb6becb4 401 /* Create cgroup */
c3350683 402 r = machine_start_scope(m, properties, error);
fb6becb4
LP
403 if (r < 0)
404 return r;
405
9444b1f2 406 log_struct(LOG_INFO,
2b044526 407 "MESSAGE_ID=" SD_MESSAGE_MACHINE_START_STR,
9444b1f2 408 "NAME=%s", m->name,
de0671ee 409 "LEADER="PID_FMT, m->leader,
e2cc6eca 410 LOG_MESSAGE("New machine %s.", m->name),
9444b1f2
LP
411 NULL);
412
9444b1f2
LP
413 if (!dual_timestamp_is_set(&m->timestamp))
414 dual_timestamp_get(&m->timestamp);
415
416 m->started = true;
417
418 /* Save new machine data */
419 machine_save(m);
420
421 machine_send_signal(m, true);
422
423 return 0;
424}
425
fb6becb4 426static int machine_stop_scope(Machine *m) {
4afd3348 427 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
39883f62 428 char *job = NULL;
9444b1f2 429 int r;
9444b1f2
LP
430
431 assert(m);
fbe55073 432 assert(m->class != MACHINE_HOST);
9444b1f2 433
89f7c846 434 if (!m->unit)
fb6becb4 435 return 0;
9444b1f2 436
c00a4c8f
LP
437 r = manager_stop_unit(m->manager, m->unit, &error, &job);
438 if (r < 0) {
439 log_error("Failed to stop machine scope: %s", bus_error_message(&error, r));
440 return r;
fb6becb4 441 }
9444b1f2 442
fb6becb4
LP
443 free(m->scope_job);
444 m->scope_job = job;
9444b1f2 445
f14aa1f1 446 return 0;
9444b1f2
LP
447}
448
449int machine_stop(Machine *m) {
49f3fffd
LP
450 int r;
451 assert(m);
452
fbe55073
LP
453 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
454 return -EOPNOTSUPP;
455
49f3fffd
LP
456 r = machine_stop_scope(m);
457
458 m->stopping = true;
459
460 machine_save(m);
461
462 return r;
463}
464
465int machine_finalize(Machine *m) {
9444b1f2
LP
466 assert(m);
467
468 if (m->started)
469 log_struct(LOG_INFO,
2b044526 470 "MESSAGE_ID=" SD_MESSAGE_MACHINE_STOP_STR,
9444b1f2 471 "NAME=%s", m->name,
de0671ee 472 "LEADER="PID_FMT, m->leader,
e2cc6eca 473 LOG_MESSAGE("Machine %s terminated.", m->name),
9444b1f2
LP
474 NULL);
475
89f7c846 476 machine_unlink(m);
9444b1f2
LP
477 machine_add_to_gc_queue(m);
478
49f3fffd 479 if (m->started) {
9444b1f2 480 machine_send_signal(m, false);
49f3fffd
LP
481 m->started = false;
482 }
9444b1f2 483
49f3fffd 484 return 0;
9444b1f2
LP
485}
486
a658cafa 487bool machine_check_gc(Machine *m, bool drop_not_started) {
9444b1f2
LP
488 assert(m);
489
fbe55073
LP
490 if (m->class == MACHINE_HOST)
491 return true;
492
9444b1f2 493 if (drop_not_started && !m->started)
c3350683 494 return false;
9444b1f2 495
c3350683
LP
496 if (m->scope_job && manager_job_is_active(m->manager, m->scope_job))
497 return true;
9444b1f2 498
89f7c846 499 if (m->unit && manager_unit_is_active(m->manager, m->unit))
c3350683 500 return true;
9444b1f2 501
c3350683 502 return false;
9444b1f2
LP
503}
504
505void machine_add_to_gc_queue(Machine *m) {
506 assert(m);
507
508 if (m->in_gc_queue)
509 return;
510
71fda00f 511 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
9444b1f2
LP
512 m->in_gc_queue = true;
513}
514
fb6becb4
LP
515MachineState machine_get_state(Machine *s) {
516 assert(s);
9444b1f2 517
fbe55073
LP
518 if (s->class == MACHINE_HOST)
519 return MACHINE_RUNNING;
520
49f3fffd
LP
521 if (s->stopping)
522 return MACHINE_CLOSING;
523
fb6becb4 524 if (s->scope_job)
49f3fffd 525 return MACHINE_OPENING;
9444b1f2 526
fb6becb4
LP
527 return MACHINE_RUNNING;
528}
9444b1f2 529
fb6becb4
LP
530int machine_kill(Machine *m, KillWho who, int signo) {
531 assert(m);
9444b1f2 532
fbe55073
LP
533 if (!IN_SET(m->class, MACHINE_VM, MACHINE_CONTAINER))
534 return -EOPNOTSUPP;
535
89f7c846 536 if (!m->unit)
fb6becb4 537 return -ESRCH;
9444b1f2 538
de58a50e
LP
539 if (who == KILL_LEADER) {
540 /* If we shall simply kill the leader, do so directly */
541
542 if (kill(m->leader, signo) < 0)
543 return -errno;
9d685ca8
ED
544
545 return 0;
de58a50e
LP
546 }
547
b938cb90 548 /* Otherwise, make PID 1 do it for us, for the entire cgroup */
de58a50e 549 return manager_kill_unit(m->manager, m->unit, signo, NULL);
9444b1f2
LP
550}
551
fbe55073
LP
552int machine_openpt(Machine *m, int flags) {
553 assert(m);
554
555 switch (m->class) {
556
5f430ff7
LP
557 case MACHINE_HOST: {
558 int fd;
559
560 fd = posix_openpt(flags);
561 if (fd < 0)
562 return -errno;
563
564 if (unlockpt(fd) < 0)
565 return -errno;
566
567 return fd;
568 }
fbe55073
LP
569
570 case MACHINE_CONTAINER:
571 if (m->leader <= 0)
572 return -EINVAL;
573
574 return openpt_in_namespace(m->leader, flags);
575
576 default:
577 return -EOPNOTSUPP;
578 }
579}
580
40e1f4ea
LP
581int machine_open_terminal(Machine *m, const char *path, int mode) {
582 assert(m);
583
584 switch (m->class) {
585
586 case MACHINE_HOST:
587 return open_terminal(path, mode);
588
589 case MACHINE_CONTAINER:
590 if (m->leader <= 0)
591 return -EINVAL;
592
593 return open_terminal_in_namespace(m->leader, path, mode);
594
595 default:
596 return -EOPNOTSUPP;
597 }
598}
599
9b420b3c
LP
600void machine_release_unit(Machine *m) {
601 assert(m);
602
603 if (!m->unit)
604 return;
605
606 (void) hashmap_remove(m->manager->machine_units, m->unit);
a1e58e8e 607 m->unit = mfree(m->unit);
9b420b3c
LP
608}
609
3401419b
LP
610int machine_get_uid_shift(Machine *m, uid_t *ret) {
611 char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
612 uid_t uid_base, uid_shift, uid_range;
613 gid_t gid_base, gid_shift, gid_range;
614 _cleanup_fclose_ FILE *f = NULL;
615 int k;
616
617 assert(m);
618 assert(ret);
619
620 /* Return the base UID/GID of the specified machine. Note that this only works for containers with simple
621 * mappings. In most cases setups should be simple like this, and administrators should only care about the
622 * basic offset a container has relative to the host. This is what this function exposes.
623 *
624 * If we encounter any more complex mappings we politely refuse this with ENXIO. */
625
626 if (m->class == MACHINE_HOST) {
627 *ret = 0;
628 return 0;
629 }
630
631 if (m->class != MACHINE_CONTAINER)
632 return -EOPNOTSUPP;
633
634 xsprintf(p, "/proc/" PID_FMT "/uid_map", m->leader);
635 f = fopen(p, "re");
636 if (!f) {
637 if (errno == ENOENT) {
638 /* If the file doesn't exist, user namespacing is off in the kernel, return a zero mapping hence. */
639 *ret = 0;
640 return 0;
641 }
642
643 return -errno;
644 }
645
646 /* Read the first line. There's at least one. */
647 errno = 0;
648 k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
649 if (k != 3) {
650 if (ferror(f))
651 return -errno;
652
653 return -EBADMSG;
654 }
655
656 /* Not a mapping starting at 0? Then it's a complex mapping we can't expose here. */
657 if (uid_base != 0)
658 return -ENXIO;
659 /* Insist that at least the nobody user is mapped, everything else is weird, and hence complex, and we don't support it */
3a664727 660 if (uid_range < UID_NOBODY)
3401419b
LP
661 return -ENXIO;
662
663 /* If there's more than one line, then we don't support this mapping. */
664 if (fgetc(f) != EOF)
665 return -ENXIO;
666
667 fclose(f);
668
669 xsprintf(p, "/proc/" PID_FMT "/gid_map", m->leader);
670 f = fopen(p, "re");
671 if (!f)
672 return -errno;
673
674 /* Read the first line. There's at least one. */
675 errno = 0;
676 k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT "\n", &gid_base, &gid_shift, &gid_range);
677 if (k != 3) {
678 if (ferror(f))
679 return -errno;
680
681 return -EBADMSG;
682 }
683
684 /* If there's more than one line, then we don't support this file. */
685 if (fgetc(f) != EOF)
686 return -ENXIO;
687
688 /* If the UID and GID mapping doesn't match, we don't support this mapping. */
689 if (uid_base != (uid_t) gid_base)
690 return -ENXIO;
691 if (uid_shift != (uid_t) gid_shift)
692 return -ENXIO;
693 if (uid_range != (uid_t) gid_range)
694 return -ENXIO;
695
696 *ret = uid_shift;
697 return 0;
698}
699
9444b1f2
LP
700static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
701 [MACHINE_CONTAINER] = "container",
fbe55073
LP
702 [MACHINE_VM] = "vm",
703 [MACHINE_HOST] = "host",
9444b1f2
LP
704};
705
706DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
fb6becb4
LP
707
708static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
709 [MACHINE_OPENING] = "opening",
710 [MACHINE_RUNNING] = "running",
711 [MACHINE_CLOSING] = "closing"
712};
713
714DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
1ee306e1
LP
715
716static const char* const kill_who_table[_KILL_WHO_MAX] = {
717 [KILL_LEADER] = "leader",
718 [KILL_ALL] = "all"
719};
720
721DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);