]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/unit-name.c
Merge branch 'pr/980'
[thirdparty/systemd.git] / src / basic / unit-name.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <stddef.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "alloc-util.h"
29 #include "bus-label.h"
30 #include "glob-util.h"
31 #include "hexdecoct.h"
32 #include "macro.h"
33 #include "path-util.h"
34 #include "string-table.h"
35 #include "string-util.h"
36 #include "strv.h"
37 #include "unit-name.h"
38
39 /* Characters valid in a unit name. */
40 #define VALID_CHARS \
41 DIGITS \
42 LETTERS \
43 ":-_.\\"
44
45 /* The same, but also permits the single @ character that may appear */
46 #define VALID_CHARS_WITH_AT \
47 "@" \
48 VALID_CHARS
49
50 /* All chars valid in a unit name glob */
51 #define VALID_CHARS_GLOB \
52 VALID_CHARS_WITH_AT \
53 "[]!-*?"
54
55 bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
56 const char *e, *i, *at;
57
58 assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0);
59
60 if (_unlikely_(flags == 0))
61 return false;
62
63 if (isempty(n))
64 return false;
65
66 if (strlen(n) >= UNIT_NAME_MAX)
67 return false;
68
69 e = strrchr(n, '.');
70 if (!e || e == n)
71 return false;
72
73 if (unit_type_from_string(e + 1) < 0)
74 return false;
75
76 for (i = n, at = NULL; i < e; i++) {
77
78 if (*i == '@' && !at)
79 at = i;
80
81 if (!strchr("@" VALID_CHARS, *i))
82 return false;
83 }
84
85 if (at == n)
86 return false;
87
88 if (flags & UNIT_NAME_PLAIN)
89 if (!at)
90 return true;
91
92 if (flags & UNIT_NAME_INSTANCE)
93 if (at && e > at + 1)
94 return true;
95
96 if (flags & UNIT_NAME_TEMPLATE)
97 if (at && e == at + 1)
98 return true;
99
100 return false;
101 }
102
103 bool unit_prefix_is_valid(const char *p) {
104
105 /* We don't allow additional @ in the prefix string */
106
107 if (isempty(p))
108 return false;
109
110 return in_charset(p, VALID_CHARS);
111 }
112
113 bool unit_instance_is_valid(const char *i) {
114
115 /* The max length depends on the length of the string, so we
116 * don't really check this here. */
117
118 if (isempty(i))
119 return false;
120
121 /* We allow additional @ in the instance string, we do not
122 * allow them in the prefix! */
123
124 return in_charset(i, "@" VALID_CHARS);
125 }
126
127 bool unit_suffix_is_valid(const char *s) {
128 if (isempty(s))
129 return false;
130
131 if (s[0] != '.')
132 return false;
133
134 if (unit_type_from_string(s + 1) < 0)
135 return false;
136
137 return true;
138 }
139
140 int unit_name_to_prefix(const char *n, char **ret) {
141 const char *p;
142 char *s;
143
144 assert(n);
145 assert(ret);
146
147 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
148 return -EINVAL;
149
150 p = strchr(n, '@');
151 if (!p)
152 p = strrchr(n, '.');
153
154 assert_se(p);
155
156 s = strndup(n, p - n);
157 if (!s)
158 return -ENOMEM;
159
160 *ret = s;
161 return 0;
162 }
163
164 int unit_name_to_instance(const char *n, char **instance) {
165 const char *p, *d;
166 char *i;
167
168 assert(n);
169 assert(instance);
170
171 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
172 return -EINVAL;
173
174 /* Everything past the first @ and before the last . is the instance */
175 p = strchr(n, '@');
176 if (!p) {
177 *instance = NULL;
178 return 0;
179 }
180
181 p++;
182
183 d = strrchr(p, '.');
184 if (!d)
185 return -EINVAL;
186
187 i = strndup(p, d-p);
188 if (!i)
189 return -ENOMEM;
190
191 *instance = i;
192 return 1;
193 }
194
195 int unit_name_to_prefix_and_instance(const char *n, char **ret) {
196 const char *d;
197 char *s;
198
199 assert(n);
200 assert(ret);
201
202 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
203 return -EINVAL;
204
205 d = strrchr(n, '.');
206 if (!d)
207 return -EINVAL;
208
209 s = strndup(n, d - n);
210 if (!s)
211 return -ENOMEM;
212
213 *ret = s;
214 return 0;
215 }
216
217 UnitType unit_name_to_type(const char *n) {
218 const char *e;
219
220 assert(n);
221
222 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
223 return _UNIT_TYPE_INVALID;
224
225 assert_se(e = strrchr(n, '.'));
226
227 return unit_type_from_string(e + 1);
228 }
229
230 int unit_name_change_suffix(const char *n, const char *suffix, char **ret) {
231 char *e, *s;
232 size_t a, b;
233
234 assert(n);
235 assert(suffix);
236 assert(ret);
237
238 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
239 return -EINVAL;
240
241 if (!unit_suffix_is_valid(suffix))
242 return -EINVAL;
243
244 assert_se(e = strrchr(n, '.'));
245
246 a = e - n;
247 b = strlen(suffix);
248
249 s = new(char, a + b + 1);
250 if (!s)
251 return -ENOMEM;
252
253 strcpy(mempcpy(s, n, a), suffix);
254 *ret = s;
255
256 return 0;
257 }
258
259 int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret) {
260 char *s;
261
262 assert(prefix);
263 assert(suffix);
264 assert(ret);
265
266 if (!unit_prefix_is_valid(prefix))
267 return -EINVAL;
268
269 if (instance && !unit_instance_is_valid(instance))
270 return -EINVAL;
271
272 if (!unit_suffix_is_valid(suffix))
273 return -EINVAL;
274
275 if (!instance)
276 s = strappend(prefix, suffix);
277 else
278 s = strjoin(prefix, "@", instance, suffix, NULL);
279 if (!s)
280 return -ENOMEM;
281
282 *ret = s;
283 return 0;
284 }
285
286 static char *do_escape_char(char c, char *t) {
287 assert(t);
288
289 *(t++) = '\\';
290 *(t++) = 'x';
291 *(t++) = hexchar(c >> 4);
292 *(t++) = hexchar(c);
293
294 return t;
295 }
296
297 static char *do_escape(const char *f, char *t) {
298 assert(f);
299 assert(t);
300
301 /* do not create units with a leading '.', like for "/.dotdir" mount points */
302 if (*f == '.') {
303 t = do_escape_char(*f, t);
304 f++;
305 }
306
307 for (; *f; f++) {
308 if (*f == '/')
309 *(t++) = '-';
310 else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f))
311 t = do_escape_char(*f, t);
312 else
313 *(t++) = *f;
314 }
315
316 return t;
317 }
318
319 char *unit_name_escape(const char *f) {
320 char *r, *t;
321
322 assert(f);
323
324 r = new(char, strlen(f)*4+1);
325 if (!r)
326 return NULL;
327
328 t = do_escape(f, r);
329 *t = 0;
330
331 return r;
332 }
333
334 int unit_name_unescape(const char *f, char **ret) {
335 _cleanup_free_ char *r = NULL;
336 char *t;
337
338 assert(f);
339
340 r = strdup(f);
341 if (!r)
342 return -ENOMEM;
343
344 for (t = r; *f; f++) {
345 if (*f == '-')
346 *(t++) = '/';
347 else if (*f == '\\') {
348 int a, b;
349
350 if (f[1] != 'x')
351 return -EINVAL;
352
353 a = unhexchar(f[2]);
354 if (a < 0)
355 return -EINVAL;
356
357 b = unhexchar(f[3]);
358 if (b < 0)
359 return -EINVAL;
360
361 *(t++) = (char) (((uint8_t) a << 4U) | (uint8_t) b);
362 f += 3;
363 } else
364 *(t++) = *f;
365 }
366
367 *t = 0;
368
369 *ret = r;
370 r = NULL;
371
372 return 0;
373 }
374
375 int unit_name_path_escape(const char *f, char **ret) {
376 char *p, *s;
377
378 assert(f);
379 assert(ret);
380
381 p = strdupa(f);
382 if (!p)
383 return -ENOMEM;
384
385 path_kill_slashes(p);
386
387 if (STR_IN_SET(p, "/", ""))
388 s = strdup("-");
389 else {
390 char *e;
391
392 if (!path_is_safe(p))
393 return -EINVAL;
394
395 /* Truncate trailing slashes */
396 e = endswith(p, "/");
397 if (e)
398 *e = 0;
399
400 /* Truncate leading slashes */
401 if (p[0] == '/')
402 p++;
403
404 s = unit_name_escape(p);
405 }
406 if (!s)
407 return -ENOMEM;
408
409 *ret = s;
410 return 0;
411 }
412
413 int unit_name_path_unescape(const char *f, char **ret) {
414 char *s;
415 int r;
416
417 assert(f);
418
419 if (isempty(f))
420 return -EINVAL;
421
422 if (streq(f, "-")) {
423 s = strdup("/");
424 if (!s)
425 return -ENOMEM;
426 } else {
427 char *w;
428
429 r = unit_name_unescape(f, &w);
430 if (r < 0)
431 return r;
432
433 /* Don't accept trailing or leading slashes */
434 if (startswith(w, "/") || endswith(w, "/")) {
435 free(w);
436 return -EINVAL;
437 }
438
439 /* Prefix a slash again */
440 s = strappend("/", w);
441 free(w);
442 if (!s)
443 return -ENOMEM;
444
445 if (!path_is_safe(s)) {
446 free(s);
447 return -EINVAL;
448 }
449 }
450
451 if (ret)
452 *ret = s;
453 else
454 free(s);
455
456 return 0;
457 }
458
459 int unit_name_replace_instance(const char *f, const char *i, char **ret) {
460 const char *p, *e;
461 char *s;
462 size_t a, b;
463
464 assert(f);
465 assert(i);
466 assert(ret);
467
468 if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
469 return -EINVAL;
470 if (!unit_instance_is_valid(i))
471 return -EINVAL;
472
473 assert_se(p = strchr(f, '@'));
474 assert_se(e = strrchr(f, '.'));
475
476 a = p - f;
477 b = strlen(i);
478
479 s = new(char, a + 1 + b + strlen(e) + 1);
480 if (!s)
481 return -ENOMEM;
482
483 strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e);
484
485 *ret = s;
486 return 0;
487 }
488
489 int unit_name_template(const char *f, char **ret) {
490 const char *p, *e;
491 char *s;
492 size_t a;
493
494 assert(f);
495 assert(ret);
496
497 if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
498 return -EINVAL;
499
500 assert_se(p = strchr(f, '@'));
501 assert_se(e = strrchr(f, '.'));
502
503 a = p - f;
504
505 s = new(char, a + 1 + strlen(e) + 1);
506 if (!s)
507 return -ENOMEM;
508
509 strcpy(mempcpy(s, f, a + 1), e);
510
511 *ret = s;
512 return 0;
513 }
514
515 int unit_name_from_path(const char *path, const char *suffix, char **ret) {
516 _cleanup_free_ char *p = NULL;
517 char *s = NULL;
518 int r;
519
520 assert(path);
521 assert(suffix);
522 assert(ret);
523
524 if (!unit_suffix_is_valid(suffix))
525 return -EINVAL;
526
527 r = unit_name_path_escape(path, &p);
528 if (r < 0)
529 return r;
530
531 s = strappend(p, suffix);
532 if (!s)
533 return -ENOMEM;
534
535 *ret = s;
536 return 0;
537 }
538
539 int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret) {
540 _cleanup_free_ char *p = NULL;
541 char *s;
542 int r;
543
544 assert(prefix);
545 assert(path);
546 assert(suffix);
547 assert(ret);
548
549 if (!unit_prefix_is_valid(prefix))
550 return -EINVAL;
551
552 if (!unit_suffix_is_valid(suffix))
553 return -EINVAL;
554
555 r = unit_name_path_escape(path, &p);
556 if (r < 0)
557 return r;
558
559 s = strjoin(prefix, "@", p, suffix, NULL);
560 if (!s)
561 return -ENOMEM;
562
563 *ret = s;
564 return 0;
565 }
566
567 int unit_name_to_path(const char *name, char **ret) {
568 _cleanup_free_ char *prefix = NULL;
569 int r;
570
571 assert(name);
572
573 r = unit_name_to_prefix(name, &prefix);
574 if (r < 0)
575 return r;
576
577 return unit_name_path_unescape(prefix, ret);
578 }
579
580 char *unit_dbus_path_from_name(const char *name) {
581 _cleanup_free_ char *e = NULL;
582
583 assert(name);
584
585 e = bus_label_escape(name);
586 if (!e)
587 return NULL;
588
589 return strappend("/org/freedesktop/systemd1/unit/", e);
590 }
591
592 int unit_name_from_dbus_path(const char *path, char **name) {
593 const char *e;
594 char *n;
595
596 e = startswith(path, "/org/freedesktop/systemd1/unit/");
597 if (!e)
598 return -EINVAL;
599
600 n = bus_label_unescape(e);
601 if (!n)
602 return -ENOMEM;
603
604 *name = n;
605 return 0;
606 }
607
608 const char* unit_dbus_interface_from_type(UnitType t) {
609
610 static const char *const table[_UNIT_TYPE_MAX] = {
611 [UNIT_SERVICE] = "org.freedesktop.systemd1.Service",
612 [UNIT_SOCKET] = "org.freedesktop.systemd1.Socket",
613 [UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName",
614 [UNIT_TARGET] = "org.freedesktop.systemd1.Target",
615 [UNIT_DEVICE] = "org.freedesktop.systemd1.Device",
616 [UNIT_MOUNT] = "org.freedesktop.systemd1.Mount",
617 [UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount",
618 [UNIT_SWAP] = "org.freedesktop.systemd1.Swap",
619 [UNIT_TIMER] = "org.freedesktop.systemd1.Timer",
620 [UNIT_PATH] = "org.freedesktop.systemd1.Path",
621 [UNIT_SLICE] = "org.freedesktop.systemd1.Slice",
622 [UNIT_SCOPE] = "org.freedesktop.systemd1.Scope",
623 };
624
625 if (t < 0)
626 return NULL;
627 if (t >= _UNIT_TYPE_MAX)
628 return NULL;
629
630 return table[t];
631 }
632
633 const char *unit_dbus_interface_from_name(const char *name) {
634 UnitType t;
635
636 t = unit_name_to_type(name);
637 if (t < 0)
638 return NULL;
639
640 return unit_dbus_interface_from_type(t);
641 }
642
643 static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) {
644 const char *valid_chars;
645
646 assert(f);
647 assert(IN_SET(allow_globs, UNIT_NAME_GLOB, UNIT_NAME_NOGLOB));
648 assert(t);
649
650 /* We'll only escape the obvious characters here, to play
651 * safe. */
652
653 valid_chars = allow_globs == UNIT_NAME_GLOB ? VALID_CHARS_GLOB : VALID_CHARS_WITH_AT;
654
655 for (; *f; f++) {
656 if (*f == '/')
657 *(t++) = '-';
658 else if (!strchr(valid_chars, *f))
659 t = do_escape_char(*f, t);
660 else
661 *(t++) = *f;
662 }
663
664 return t;
665 }
666
667 /**
668 * Convert a string to a unit name. /dev/blah is converted to dev-blah.device,
669 * /blah/blah is converted to blah-blah.mount, anything else is left alone,
670 * except that @suffix is appended if a valid unit suffix is not present.
671 *
672 * If @allow_globs, globs characters are preserved. Otherwise, they are escaped.
673 */
674 int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) {
675 char *s, *t;
676 int r;
677
678 assert(name);
679 assert(suffix);
680 assert(ret);
681
682 if (isempty(name)) /* We cannot mangle empty unit names to become valid, sorry. */
683 return -EINVAL;
684
685 if (!unit_suffix_is_valid(suffix))
686 return -EINVAL;
687
688 /* Already a fully valid unit name? If so, no mangling is necessary... */
689 if (unit_name_is_valid(name, UNIT_NAME_ANY))
690 goto good;
691
692 /* Already a fully valid globbing expression? If so, no mangling is necessary either... */
693 if (allow_globs == UNIT_NAME_GLOB &&
694 string_is_glob(name) &&
695 in_charset(name, VALID_CHARS_GLOB))
696 goto good;
697
698 if (is_device_path(name)) {
699 r = unit_name_from_path(name, ".device", ret);
700 if (r >= 0)
701 return 1;
702 if (r != -EINVAL)
703 return r;
704 }
705
706 if (path_is_absolute(name)) {
707 r = unit_name_from_path(name, ".mount", ret);
708 if (r >= 0)
709 return 1;
710 if (r != -EINVAL)
711 return r;
712 }
713
714 s = new(char, strlen(name) * 4 + strlen(suffix) + 1);
715 if (!s)
716 return -ENOMEM;
717
718 t = do_escape_mangle(name, allow_globs, s);
719 *t = 0;
720
721 /* Append a suffix if it doesn't have any, but only if this is not a glob, so that we can allow "foo.*" as a
722 * valid glob. */
723 if ((allow_globs != UNIT_NAME_GLOB || !string_is_glob(s)) && unit_name_to_type(s) < 0)
724 strcpy(t, suffix);
725
726 *ret = s;
727 return 1;
728
729 good:
730 s = strdup(name);
731 if (!s)
732 return -ENOMEM;
733
734 *ret = s;
735 return 0;
736 }
737
738 int slice_build_parent_slice(const char *slice, char **ret) {
739 char *s, *dash;
740 int r;
741
742 assert(slice);
743 assert(ret);
744
745 if (!slice_name_is_valid(slice))
746 return -EINVAL;
747
748 if (streq(slice, "-.slice")) {
749 *ret = NULL;
750 return 0;
751 }
752
753 s = strdup(slice);
754 if (!s)
755 return -ENOMEM;
756
757 dash = strrchr(s, '-');
758 if (dash)
759 strcpy(dash, ".slice");
760 else {
761 r = free_and_strdup(&s, "-.slice");
762 if (r < 0) {
763 free(s);
764 return r;
765 }
766 }
767
768 *ret = s;
769 return 1;
770 }
771
772 int slice_build_subslice(const char *slice, const char*name, char **ret) {
773 char *subslice;
774
775 assert(slice);
776 assert(name);
777 assert(ret);
778
779 if (!slice_name_is_valid(slice))
780 return -EINVAL;
781
782 if (!unit_prefix_is_valid(name))
783 return -EINVAL;
784
785 if (streq(slice, "-.slice"))
786 subslice = strappend(name, ".slice");
787 else {
788 char *e;
789
790 assert_se(e = endswith(slice, ".slice"));
791
792 subslice = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
793 if (!subslice)
794 return -ENOMEM;
795
796 stpcpy(stpcpy(stpcpy(mempcpy(subslice, slice, e - slice), "-"), name), ".slice");
797 }
798
799 *ret = subslice;
800 return 0;
801 }
802
803 bool slice_name_is_valid(const char *name) {
804 const char *p, *e;
805 bool dash = false;
806
807 if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
808 return false;
809
810 if (streq(name, "-.slice"))
811 return true;
812
813 e = endswith(name, ".slice");
814 if (!e)
815 return false;
816
817 for (p = name; p < e; p++) {
818
819 if (*p == '-') {
820
821 /* Don't allow initial dash */
822 if (p == name)
823 return false;
824
825 /* Don't allow multiple dashes */
826 if (dash)
827 return false;
828
829 dash = true;
830 } else
831 dash = false;
832 }
833
834 /* Don't allow trailing hash */
835 if (dash)
836 return false;
837
838 return true;
839 }
840
841 static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
842 [UNIT_SERVICE] = "service",
843 [UNIT_SOCKET] = "socket",
844 [UNIT_BUSNAME] = "busname",
845 [UNIT_TARGET] = "target",
846 [UNIT_DEVICE] = "device",
847 [UNIT_MOUNT] = "mount",
848 [UNIT_AUTOMOUNT] = "automount",
849 [UNIT_SWAP] = "swap",
850 [UNIT_TIMER] = "timer",
851 [UNIT_PATH] = "path",
852 [UNIT_SLICE] = "slice",
853 [UNIT_SCOPE] = "scope",
854 };
855
856 DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
857
858 static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
859 [UNIT_STUB] = "stub",
860 [UNIT_LOADED] = "loaded",
861 [UNIT_NOT_FOUND] = "not-found",
862 [UNIT_ERROR] = "error",
863 [UNIT_MERGED] = "merged",
864 [UNIT_MASKED] = "masked"
865 };
866
867 DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
868
869 static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
870 [UNIT_ACTIVE] = "active",
871 [UNIT_RELOADING] = "reloading",
872 [UNIT_INACTIVE] = "inactive",
873 [UNIT_FAILED] = "failed",
874 [UNIT_ACTIVATING] = "activating",
875 [UNIT_DEACTIVATING] = "deactivating"
876 };
877
878 DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
879
880 static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
881 [AUTOMOUNT_DEAD] = "dead",
882 [AUTOMOUNT_WAITING] = "waiting",
883 [AUTOMOUNT_RUNNING] = "running",
884 [AUTOMOUNT_FAILED] = "failed"
885 };
886
887 DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
888
889 static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
890 [BUSNAME_DEAD] = "dead",
891 [BUSNAME_MAKING] = "making",
892 [BUSNAME_REGISTERED] = "registered",
893 [BUSNAME_LISTENING] = "listening",
894 [BUSNAME_RUNNING] = "running",
895 [BUSNAME_SIGTERM] = "sigterm",
896 [BUSNAME_SIGKILL] = "sigkill",
897 [BUSNAME_FAILED] = "failed",
898 };
899
900 DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
901
902 static const char* const device_state_table[_DEVICE_STATE_MAX] = {
903 [DEVICE_DEAD] = "dead",
904 [DEVICE_TENTATIVE] = "tentative",
905 [DEVICE_PLUGGED] = "plugged",
906 };
907
908 DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
909
910 static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
911 [MOUNT_DEAD] = "dead",
912 [MOUNT_MOUNTING] = "mounting",
913 [MOUNT_MOUNTING_DONE] = "mounting-done",
914 [MOUNT_MOUNTED] = "mounted",
915 [MOUNT_REMOUNTING] = "remounting",
916 [MOUNT_UNMOUNTING] = "unmounting",
917 [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
918 [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
919 [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
920 [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
921 [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
922 [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
923 [MOUNT_FAILED] = "failed"
924 };
925
926 DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
927
928 static const char* const path_state_table[_PATH_STATE_MAX] = {
929 [PATH_DEAD] = "dead",
930 [PATH_WAITING] = "waiting",
931 [PATH_RUNNING] = "running",
932 [PATH_FAILED] = "failed"
933 };
934
935 DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
936
937 static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
938 [SCOPE_DEAD] = "dead",
939 [SCOPE_RUNNING] = "running",
940 [SCOPE_ABANDONED] = "abandoned",
941 [SCOPE_STOP_SIGTERM] = "stop-sigterm",
942 [SCOPE_STOP_SIGKILL] = "stop-sigkill",
943 [SCOPE_FAILED] = "failed",
944 };
945
946 DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
947
948 static const char* const service_state_table[_SERVICE_STATE_MAX] = {
949 [SERVICE_DEAD] = "dead",
950 [SERVICE_START_PRE] = "start-pre",
951 [SERVICE_START] = "start",
952 [SERVICE_START_POST] = "start-post",
953 [SERVICE_RUNNING] = "running",
954 [SERVICE_EXITED] = "exited",
955 [SERVICE_RELOAD] = "reload",
956 [SERVICE_STOP] = "stop",
957 [SERVICE_STOP_SIGABRT] = "stop-sigabrt",
958 [SERVICE_STOP_SIGTERM] = "stop-sigterm",
959 [SERVICE_STOP_SIGKILL] = "stop-sigkill",
960 [SERVICE_STOP_POST] = "stop-post",
961 [SERVICE_FINAL_SIGTERM] = "final-sigterm",
962 [SERVICE_FINAL_SIGKILL] = "final-sigkill",
963 [SERVICE_FAILED] = "failed",
964 [SERVICE_AUTO_RESTART] = "auto-restart",
965 };
966
967 DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
968
969 static const char* const slice_state_table[_SLICE_STATE_MAX] = {
970 [SLICE_DEAD] = "dead",
971 [SLICE_ACTIVE] = "active"
972 };
973
974 DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
975
976 static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
977 [SOCKET_DEAD] = "dead",
978 [SOCKET_START_PRE] = "start-pre",
979 [SOCKET_START_CHOWN] = "start-chown",
980 [SOCKET_START_POST] = "start-post",
981 [SOCKET_LISTENING] = "listening",
982 [SOCKET_RUNNING] = "running",
983 [SOCKET_STOP_PRE] = "stop-pre",
984 [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
985 [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
986 [SOCKET_STOP_POST] = "stop-post",
987 [SOCKET_FINAL_SIGTERM] = "final-sigterm",
988 [SOCKET_FINAL_SIGKILL] = "final-sigkill",
989 [SOCKET_FAILED] = "failed"
990 };
991
992 DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
993
994 static const char* const swap_state_table[_SWAP_STATE_MAX] = {
995 [SWAP_DEAD] = "dead",
996 [SWAP_ACTIVATING] = "activating",
997 [SWAP_ACTIVATING_DONE] = "activating-done",
998 [SWAP_ACTIVE] = "active",
999 [SWAP_DEACTIVATING] = "deactivating",
1000 [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
1001 [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
1002 [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
1003 [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
1004 [SWAP_FAILED] = "failed"
1005 };
1006
1007 DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
1008
1009 static const char* const target_state_table[_TARGET_STATE_MAX] = {
1010 [TARGET_DEAD] = "dead",
1011 [TARGET_ACTIVE] = "active"
1012 };
1013
1014 DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
1015
1016 static const char* const timer_state_table[_TIMER_STATE_MAX] = {
1017 [TIMER_DEAD] = "dead",
1018 [TIMER_WAITING] = "waiting",
1019 [TIMER_RUNNING] = "running",
1020 [TIMER_ELAPSED] = "elapsed",
1021 [TIMER_FAILED] = "failed"
1022 };
1023
1024 DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
1025
1026 static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
1027 [UNIT_REQUIRES] = "Requires",
1028 [UNIT_REQUISITE] = "Requisite",
1029 [UNIT_WANTS] = "Wants",
1030 [UNIT_BINDS_TO] = "BindsTo",
1031 [UNIT_PART_OF] = "PartOf",
1032 [UNIT_REQUIRED_BY] = "RequiredBy",
1033 [UNIT_REQUISITE_OF] = "RequisiteOf",
1034 [UNIT_WANTED_BY] = "WantedBy",
1035 [UNIT_BOUND_BY] = "BoundBy",
1036 [UNIT_CONSISTS_OF] = "ConsistsOf",
1037 [UNIT_CONFLICTS] = "Conflicts",
1038 [UNIT_CONFLICTED_BY] = "ConflictedBy",
1039 [UNIT_BEFORE] = "Before",
1040 [UNIT_AFTER] = "After",
1041 [UNIT_ON_FAILURE] = "OnFailure",
1042 [UNIT_TRIGGERS] = "Triggers",
1043 [UNIT_TRIGGERED_BY] = "TriggeredBy",
1044 [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo",
1045 [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom",
1046 [UNIT_JOINS_NAMESPACE_OF] = "JoinsNamespaceOf",
1047 [UNIT_REFERENCES] = "References",
1048 [UNIT_REFERENCED_BY] = "ReferencedBy",
1049 };
1050
1051 DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);