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