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