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