]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/unit-name.c
systemctl: add --state=help
[thirdparty/systemd.git] / src / basic / unit-name.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
9e2f7c11
LP
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
5430f7f2
LP
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
9e2f7c11
LP
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
5430f7f2 16 Lesser General Public License for more details.
9e2f7c11 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
9e2f7c11
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <string.h>
24
9eb977db 25#include "path-util.h"
f01de965 26#include "bus-label.h"
71fad675 27#include "util.h"
9e2f7c11 28#include "unit-name.h"
4b549144 29#include "def.h"
b9a33026 30#include "strv.h"
9e2f7c11
LP
31
32#define VALID_CHARS \
4b549144 33 DIGITS LETTERS \
4f2d528d 34 ":-_.\\"
9e2f7c11 35
7410616c 36bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
9e2f7c11
LP
37 const char *e, *i, *at;
38
7410616c 39 assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0);
9e2f7c11 40
7410616c
LP
41 if (_unlikely_(flags == 0))
42 return false;
9e2f7c11 43
b9a33026
LP
44 if (isempty(n))
45 return false;
46
9e2f7c11
LP
47 if (strlen(n) >= UNIT_NAME_MAX)
48 return false;
49
71fad675
LP
50 e = strrchr(n, '.');
51 if (!e || e == n)
9e2f7c11
LP
52 return false;
53
5f739699
LP
54 if (unit_type_from_string(e + 1) < 0)
55 return false;
56
9e2f7c11
LP
57 for (i = n, at = NULL; i < e; i++) {
58
59 if (*i == '@' && !at)
60 at = i;
61
62 if (!strchr("@" VALID_CHARS, *i))
63 return false;
64 }
65
7410616c
LP
66 if (at == n)
67 return false;
9e2f7c11 68
7410616c
LP
69 if (flags & UNIT_NAME_PLAIN)
70 if (!at)
71 return true;
9e2f7c11 72
7410616c
LP
73 if (flags & UNIT_NAME_INSTANCE)
74 if (at && e > at + 1)
75 return true;
76
77 if (flags & UNIT_NAME_TEMPLATE)
78 if (at && e == at + 1)
79 return true;
80
81 return false;
82}
83
84bool unit_prefix_is_valid(const char *p) {
85
86 /* We don't allow additional @ in the prefix string */
87
88 if (isempty(p))
89 return false;
90
91 return in_charset(p, VALID_CHARS);
9e2f7c11
LP
92}
93
94bool unit_instance_is_valid(const char *i) {
9e2f7c11
LP
95
96 /* The max length depends on the length of the string, so we
97 * don't really check this here. */
98
b9a33026 99 if (isempty(i))
9e2f7c11
LP
100 return false;
101
102 /* We allow additional @ in the instance string, we do not
103 * allow them in the prefix! */
104
b9a33026 105 return in_charset(i, "@" VALID_CHARS);
9e2f7c11
LP
106}
107
7410616c
LP
108bool unit_suffix_is_valid(const char *s) {
109 if (isempty(s))
110 return false;
9e2f7c11 111
7410616c
LP
112 if (s[0] != '.')
113 return false;
9e2f7c11 114
7410616c 115 if (unit_type_from_string(s + 1) < 0)
9e2f7c11
LP
116 return false;
117
7410616c
LP
118 return true;
119}
120
121int unit_name_to_prefix(const char *n, char **ret) {
122 const char *p;
123 char *s;
124
125 assert(n);
126 assert(ret);
127
128 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
129 return -EINVAL;
130
131 p = strchr(n, '@');
132 if (!p)
133 p = strrchr(n, '.');
134
135 assert_se(p);
136
137 s = strndup(n, p - n);
138 if (!s)
139 return -ENOMEM;
140
141 *ret = s;
142 return 0;
9e2f7c11
LP
143}
144
145int unit_name_to_instance(const char *n, char **instance) {
146 const char *p, *d;
147 char *i;
148
149 assert(n);
150 assert(instance);
151
7410616c
LP
152 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
153 return -EINVAL;
154
9e2f7c11 155 /* Everything past the first @ and before the last . is the instance */
35eb6b12
LP
156 p = strchr(n, '@');
157 if (!p) {
9e2f7c11
LP
158 *instance = NULL;
159 return 0;
160 }
161
7410616c
LP
162 p++;
163
164 d = strrchr(p, '.');
b9a33026
LP
165 if (!d)
166 return -EINVAL;
9e2f7c11 167
7410616c 168 i = strndup(p, d-p);
35eb6b12 169 if (!i)
9e2f7c11
LP
170 return -ENOMEM;
171
172 *instance = i;
b9a33026 173 return 1;
9e2f7c11
LP
174}
175
7410616c 176int unit_name_to_prefix_and_instance(const char *n, char **ret) {
9e2f7c11 177 const char *d;
7410616c 178 char *s;
9e2f7c11
LP
179
180 assert(n);
7410616c
LP
181 assert(ret);
182
183 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
184 return -EINVAL;
9e2f7c11 185
7410616c
LP
186 d = strrchr(n, '.');
187 if (!d)
188 return -EINVAL;
189
190 s = strndup(n, d - n);
191 if (!s)
192 return -ENOMEM;
193
194 *ret = s;
195 return 0;
9e2f7c11
LP
196}
197
7410616c
LP
198UnitType unit_name_to_type(const char *n) {
199 const char *e;
9e2f7c11 200
b9a33026
LP
201 assert(n);
202
7410616c
LP
203 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
204 return _UNIT_TYPE_INVALID;
9e2f7c11 205
7410616c
LP
206 assert_se(e = strrchr(n, '.'));
207
208 return unit_type_from_string(e + 1);
9e2f7c11
LP
209}
210
7410616c
LP
211int unit_name_change_suffix(const char *n, const char *suffix, char **ret) {
212 char *e, *s;
9e2f7c11
LP
213 size_t a, b;
214
215 assert(n);
9e2f7c11 216 assert(suffix);
7410616c
LP
217 assert(ret);
218
219 if (!unit_name_is_valid(n, UNIT_NAME_ANY))
220 return -EINVAL;
221
222 if (!unit_suffix_is_valid(suffix))
223 return -EINVAL;
9e2f7c11
LP
224
225 assert_se(e = strrchr(n, '.'));
7410616c 226
9e2f7c11
LP
227 a = e - n;
228 b = strlen(suffix);
229
7410616c
LP
230 s = new(char, a + b + 1);
231 if (!s)
232 return -ENOMEM;
9e2f7c11 233
7410616c
LP
234 strcpy(mempcpy(s, n, a), suffix);
235 *ret = s;
236
237 return 0;
9e2f7c11
LP
238}
239
7410616c
LP
240int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret) {
241 char *s;
242
9e2f7c11 243 assert(prefix);
9e2f7c11 244 assert(suffix);
7410616c
LP
245 assert(ret);
246
247 if (!unit_prefix_is_valid(prefix))
248 return -EINVAL;
249
250 if (instance && !unit_instance_is_valid(instance))
251 return -EINVAL;
252
253 if (!unit_suffix_is_valid(suffix))
254 return -EINVAL;
9e2f7c11
LP
255
256 if (!instance)
7410616c
LP
257 s = strappend(prefix, suffix);
258 else
259 s = strjoin(prefix, "@", instance, suffix, NULL);
260 if (!s)
261 return -ENOMEM;
9e2f7c11 262
7410616c
LP
263 *ret = s;
264 return 0;
9e2f7c11
LP
265}
266
4b712653 267static char *do_escape_char(char c, char *t) {
b9a33026
LP
268 assert(t);
269
4b712653
KS
270 *(t++) = '\\';
271 *(t++) = 'x';
272 *(t++) = hexchar(c >> 4);
273 *(t++) = hexchar(c);
b9a33026 274
4b712653
KS
275 return t;
276}
277
278static char *do_escape(const char *f, char *t) {
9e2f7c11
LP
279 assert(f);
280 assert(t);
281
4b712653
KS
282 /* do not create units with a leading '.', like for "/.dotdir" mount points */
283 if (*f == '.') {
284 t = do_escape_char(*f, t);
285 f++;
286 }
287
9e2f7c11
LP
288 for (; *f; f++) {
289 if (*f == '/')
8d567588 290 *(t++) = '-';
4b712653
KS
291 else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f))
292 t = do_escape_char(*f, t);
293 else
9e2f7c11
LP
294 *(t++) = *f;
295 }
296
297 return t;
298}
299
9e2f7c11
LP
300char *unit_name_escape(const char *f) {
301 char *r, *t;
302
b9a33026
LP
303 assert(f);
304
b0193f1c
LP
305 r = new(char, strlen(f)*4+1);
306 if (!r)
9e2f7c11
LP
307 return NULL;
308
309 t = do_escape(f, r);
310 *t = 0;
311
312 return r;
9e2f7c11
LP
313}
314
7410616c
LP
315int unit_name_unescape(const char *f, char **ret) {
316 _cleanup_free_ char *r = NULL;
317 char *t;
9e2f7c11
LP
318
319 assert(f);
320
b0193f1c
LP
321 r = strdup(f);
322 if (!r)
7410616c 323 return -ENOMEM;
9e2f7c11
LP
324
325 for (t = r; *f; f++) {
8d567588 326 if (*f == '-')
9e2f7c11
LP
327 *(t++) = '/';
328 else if (*f == '\\') {
329 int a, b;
330
7410616c
LP
331 if (f[1] != 'x')
332 return -EINVAL;
333
334 a = unhexchar(f[2]);
335 if (a < 0)
336 return -EINVAL;
337
338 b = unhexchar(f[3]);
339 if (b < 0)
340 return -EINVAL;
341
93c47472 342 *(t++) = (char) (((uint8_t) a << 4U) | (uint8_t) b);
7410616c 343 f += 3;
9e2f7c11
LP
344 } else
345 *(t++) = *f;
346 }
347
348 *t = 0;
349
7410616c
LP
350 *ret = r;
351 r = NULL;
352
353 return 0;
9e2f7c11
LP
354}
355
7410616c
LP
356int unit_name_path_escape(const char *f, char **ret) {
357 char *p, *s;
35eb6b12
LP
358
359 assert(f);
7410616c 360 assert(ret);
35eb6b12 361
7410616c 362 p = strdupa(f);
35eb6b12 363 if (!p)
7410616c 364 return -ENOMEM;
35eb6b12
LP
365
366 path_kill_slashes(p);
367
b9a33026 368 if (STR_IN_SET(p, "/", ""))
7410616c
LP
369 s = strdup("-");
370 else {
371 char *e;
35eb6b12 372
7410616c
LP
373 if (!path_is_safe(p))
374 return -EINVAL;
35eb6b12 375
7410616c
LP
376 /* Truncate trailing slashes */
377 e = endswith(p, "/");
378 if (e)
379 *e = 0;
35eb6b12 380
7410616c
LP
381 /* Truncate leading slashes */
382 if (p[0] == '/')
383 p++;
35eb6b12 384
7410616c 385 s = unit_name_escape(p);
35eb6b12 386 }
7410616c
LP
387 if (!s)
388 return -ENOMEM;
35eb6b12 389
7410616c
LP
390 *ret = s;
391 return 0;
35eb6b12
LP
392}
393
7410616c 394int unit_name_path_unescape(const char *f, char **ret) {
93c47472 395 char *s;
7410616c 396 int r;
9e2f7c11 397
7410616c 398 assert(f);
9e2f7c11 399
93c47472
LP
400 if (isempty(f))
401 return -EINVAL;
402
7410616c
LP
403 if (streq(f, "-")) {
404 s = strdup("/");
405 if (!s)
406 return -ENOMEM;
93c47472
LP
407 } else {
408 char *w;
6ef9eeed 409
93c47472
LP
410 r = unit_name_unescape(f, &w);
411 if (r < 0)
412 return r;
29283ea4 413
93c47472
LP
414 /* Don't accept trailing or leading slashes */
415 if (startswith(w, "/") || endswith(w, "/")) {
416 free(w);
417 return -EINVAL;
418 }
29283ea4 419
93c47472
LP
420 /* Prefix a slash again */
421 s = strappend("/", w);
7410616c 422 free(w);
93c47472
LP
423 if (!s)
424 return -ENOMEM;
425
426 if (!path_is_safe(s)) {
427 free(s);
428 return -EINVAL;
429 }
7410616c 430 }
6ef9eeed 431
93c47472
LP
432 if (ret)
433 *ret = s;
434 else
435 free(s);
436
7410616c 437 return 0;
29283ea4
MS
438}
439
7410616c 440int unit_name_replace_instance(const char *f, const char *i, char **ret) {
9e2f7c11 441 const char *p, *e;
7410616c 442 char *s;
8556879e 443 size_t a, b;
9e2f7c11
LP
444
445 assert(f);
b9a33026 446 assert(i);
7410616c 447 assert(ret);
9e2f7c11 448
7410616c
LP
449 if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
450 return -EINVAL;
451 if (!unit_instance_is_valid(i))
452 return -EINVAL;
9e2f7c11 453
7410616c
LP
454 assert_se(p = strchr(f, '@'));
455 assert_se(e = strrchr(f, '.'));
9e2f7c11 456
8556879e
LP
457 a = p - f;
458 b = strlen(i);
9e2f7c11 459
7410616c
LP
460 s = new(char, a + 1 + b + strlen(e) + 1);
461 if (!s)
462 return -ENOMEM;
9e2f7c11 463
7410616c
LP
464 strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e);
465
466 *ret = s;
467 return 0;
9e2f7c11
LP
468}
469
7410616c 470int unit_name_template(const char *f, char **ret) {
9e2f7c11 471 const char *p, *e;
7410616c 472 char *s;
9e2f7c11
LP
473 size_t a;
474
b9a33026 475 assert(f);
7410616c 476 assert(ret);
b9a33026 477
7410616c
LP
478 if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
479 return -EINVAL;
9e2f7c11 480
7410616c
LP
481 assert_se(p = strchr(f, '@'));
482 assert_se(e = strrchr(f, '.'));
b9a33026
LP
483
484 a = p - f;
9e2f7c11 485
7410616c
LP
486 s = new(char, a + 1 + strlen(e) + 1);
487 if (!s)
488 return -ENOMEM;
9e2f7c11 489
7410616c
LP
490 strcpy(mempcpy(s, f, a + 1), e);
491
492 *ret = s;
493 return 0;
9e2f7c11 494}
a16e1123 495
7410616c 496int unit_name_from_path(const char *path, const char *suffix, char **ret) {
58d08142 497 _cleanup_free_ char *p = NULL;
7410616c
LP
498 char *s = NULL;
499 int r;
5ffceb2f 500
a16e1123
LP
501 assert(path);
502 assert(suffix);
7410616c 503 assert(ret);
a16e1123 504
7410616c
LP
505 if (!unit_suffix_is_valid(suffix))
506 return -EINVAL;
5ffceb2f 507
7410616c
LP
508 r = unit_name_path_escape(path, &p);
509 if (r < 0)
510 return r;
511
512 s = strappend(p, suffix);
513 if (!s)
514 return -ENOMEM;
515
516 *ret = s;
517 return 0;
a16e1123
LP
518}
519
7410616c 520int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret) {
58d08142 521 _cleanup_free_ char *p = NULL;
7410616c
LP
522 char *s;
523 int r;
9fff8a1f 524
35eb6b12 525 assert(prefix);
9fff8a1f
LP
526 assert(path);
527 assert(suffix);
7410616c 528 assert(ret);
9fff8a1f 529
7410616c
LP
530 if (!unit_prefix_is_valid(prefix))
531 return -EINVAL;
532
533 if (!unit_suffix_is_valid(suffix))
534 return -EINVAL;
535
536 r = unit_name_path_escape(path, &p);
537 if (r < 0)
538 return r;
539
540 s = strjoin(prefix, "@", p, suffix, NULL);
541 if (!s)
542 return -ENOMEM;
9fff8a1f 543
7410616c
LP
544 *ret = s;
545 return 0;
9fff8a1f
LP
546}
547
7410616c
LP
548int unit_name_to_path(const char *name, char **ret) {
549 _cleanup_free_ char *prefix = NULL;
550 int r;
a16e1123
LP
551
552 assert(name);
553
7410616c
LP
554 r = unit_name_to_prefix(name, &prefix);
555 if (r < 0)
556 return r;
a16e1123 557
7410616c 558 return unit_name_path_unescape(prefix, ret);
9fc50704 559}
48899192
MS
560
561char *unit_dbus_path_from_name(const char *name) {
9444b1f2 562 _cleanup_free_ char *e = NULL;
48899192 563
35eb6b12
LP
564 assert(name);
565
f01de965 566 e = bus_label_escape(name);
48899192
MS
567 if (!e)
568 return NULL;
569
9444b1f2 570 return strappend("/org/freedesktop/systemd1/unit/", e);
48899192 571}
b0193f1c 572
ede3a796
LP
573int unit_name_from_dbus_path(const char *path, char **name) {
574 const char *e;
575 char *n;
576
577 e = startswith(path, "/org/freedesktop/systemd1/unit/");
578 if (!e)
579 return -EINVAL;
580
f01de965 581 n = bus_label_unescape(e);
ede3a796
LP
582 if (!n)
583 return -ENOMEM;
584
585 *name = n;
586 return 0;
587}
588
21b735e7
LP
589const char* unit_dbus_interface_from_type(UnitType t) {
590
591 static const char *const table[_UNIT_TYPE_MAX] = {
592 [UNIT_SERVICE] = "org.freedesktop.systemd1.Service",
593 [UNIT_SOCKET] = "org.freedesktop.systemd1.Socket",
594 [UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName",
595 [UNIT_TARGET] = "org.freedesktop.systemd1.Target",
596 [UNIT_SNAPSHOT] = "org.freedesktop.systemd1.Snapshot",
597 [UNIT_DEVICE] = "org.freedesktop.systemd1.Device",
598 [UNIT_MOUNT] = "org.freedesktop.systemd1.Mount",
599 [UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount",
600 [UNIT_SWAP] = "org.freedesktop.systemd1.Swap",
601 [UNIT_TIMER] = "org.freedesktop.systemd1.Timer",
602 [UNIT_PATH] = "org.freedesktop.systemd1.Path",
603 [UNIT_SLICE] = "org.freedesktop.systemd1.Slice",
604 [UNIT_SCOPE] = "org.freedesktop.systemd1.Scope",
605 };
606
607 if (t < 0)
608 return NULL;
609 if (t >= _UNIT_TYPE_MAX)
610 return NULL;
611
612 return table[t];
613}
614
615const char *unit_dbus_interface_from_name(const char *name) {
616 UnitType t;
617
618 t = unit_name_to_type(name);
619 if (t < 0)
620 return NULL;
621
622 return unit_dbus_interface_from_type(t);
623}
624
7410616c
LP
625static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) {
626 const char *valid_chars;
627
628 assert(f);
629 assert(IN_SET(allow_globs, UNIT_NAME_GLOB, UNIT_NAME_NOGLOB));
630 assert(t);
631
632 /* We'll only escape the obvious characters here, to play
633 * safe. */
634
635 valid_chars = allow_globs == UNIT_NAME_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
636
637 for (; *f; f++) {
638 if (*f == '/')
639 *(t++) = '-';
640 else if (!strchr(valid_chars, *f))
641 t = do_escape_char(*f, t);
642 else
643 *(t++) = *f;
644 }
645
646 return t;
647}
648
e3e0314b 649/**
5e03c6e3
ZJS
650 * Convert a string to a unit name. /dev/blah is converted to dev-blah.device,
651 * /blah/blah is converted to blah-blah.mount, anything else is left alone,
652 * except that @suffix is appended if a valid unit suffix is not present.
653 *
654 * If @allow_globs, globs characters are preserved. Otherwise they are escaped.
e3e0314b 655 */
7410616c
LP
656int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) {
657 char *s, *t;
658 int r;
b0193f1c
LP
659
660 assert(name);
5e03c6e3 661 assert(suffix);
7410616c 662 assert(ret);
b0193f1c 663
7410616c
LP
664 if (isempty(name)) /* We cannot mangle empty unit names to become valid, sorry. */
665 return -EINVAL;
b0193f1c 666
7410616c
LP
667 if (!unit_suffix_is_valid(suffix))
668 return -EINVAL;
b0193f1c 669
7410616c
LP
670 if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
671 /* No mangling necessary... */
672 s = strdup(name);
673 if (!s)
674 return -ENOMEM;
1dcf6065 675
7410616c
LP
676 *ret = s;
677 return 0;
678 }
1dcf6065 679
7410616c
LP
680 if (is_device_path(name)) {
681 r = unit_name_from_path(name, ".device", ret);
682 if (r >= 0)
683 return 1;
684 if (r != -EINVAL)
685 return r;
686 }
1dcf6065 687
7410616c
LP
688 if (path_is_absolute(name)) {
689 r = unit_name_from_path(name, ".mount", ret);
690 if (r >= 0)
691 return 1;
692 if (r != -EINVAL)
693 return r;
694 }
1dcf6065 695
7410616c
LP
696 s = new(char, strlen(name) * 4 + strlen(suffix) + 1);
697 if (!s)
698 return -ENOMEM;
5f739699 699
7410616c
LP
700 t = do_escape_mangle(name, allow_globs, s);
701 *t = 0;
5f739699 702
7410616c
LP
703 if (unit_name_to_type(s) < 0)
704 strcpy(t, suffix);
5f739699 705
7410616c
LP
706 *ret = s;
707 return 1;
5f739699 708}
fb6becb4 709
93c47472
LP
710int slice_build_parent_slice(const char *slice, char **ret) {
711 char *s, *dash;
2fc09a9c 712 int r;
93c47472
LP
713
714 assert(slice);
715 assert(ret);
716
717 if (!slice_name_is_valid(slice))
718 return -EINVAL;
719
720 if (streq(slice, "-.slice")) {
721 *ret = NULL;
722 return 0;
723 }
724
725 s = strdup(slice);
726 if (!s)
727 return -ENOMEM;
728
729 dash = strrchr(s, '-');
730 if (dash)
731 strcpy(dash, ".slice");
732 else {
2fc09a9c 733 r = free_and_strdup(&s, "-.slice");
8e542fcd
DM
734 if (r < 0) {
735 free(s);
2fc09a9c 736 return r;
8e542fcd 737 }
93c47472
LP
738 }
739
740 *ret = s;
741 return 1;
742}
743
7410616c
LP
744int slice_build_subslice(const char *slice, const char*name, char **ret) {
745 char *subslice;
fb6becb4
LP
746
747 assert(slice);
748 assert(name);
7410616c
LP
749 assert(ret);
750
93c47472 751 if (!slice_name_is_valid(slice))
7410616c
LP
752 return -EINVAL;
753
754 if (!unit_prefix_is_valid(name))
755 return -EINVAL;
fb6becb4
LP
756
757 if (streq(slice, "-.slice"))
7410616c 758 subslice = strappend(name, ".slice");
fb6becb4
LP
759 else {
760 char *e;
761
93c47472 762 assert_se(e = endswith(slice, ".slice"));
fb6becb4 763
7410616c
LP
764 subslice = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
765 if (!subslice)
fb6becb4
LP
766 return -ENOMEM;
767
7410616c 768 stpcpy(stpcpy(stpcpy(mempcpy(subslice, slice, e - slice), "-"), name), ".slice");
fb6becb4
LP
769 }
770
7410616c 771 *ret = subslice;
fb6becb4
LP
772 return 0;
773}
cb87a73b 774
93c47472
LP
775bool slice_name_is_valid(const char *name) {
776 const char *p, *e;
777 bool dash = false;
778
779 if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
780 return false;
781
782 if (streq(name, "-.slice"))
783 return true;
784
785 e = endswith(name, ".slice");
786 if (!e)
787 return false;
788
789 for (p = name; p < e; p++) {
790
791 if (*p == '-') {
792
793 /* Don't allow initial dash */
794 if (p == name)
795 return false;
796
797 /* Don't allow multiple dashes */
798 if (dash)
799 return false;
800
801 dash = true;
802 } else
803 dash = false;
804 }
805
806 /* Don't allow trailing hash */
807 if (dash)
808 return false;
809
810 return true;
811}
812
7410616c
LP
813static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
814 [UNIT_SERVICE] = "service",
815 [UNIT_SOCKET] = "socket",
816 [UNIT_BUSNAME] = "busname",
817 [UNIT_TARGET] = "target",
818 [UNIT_SNAPSHOT] = "snapshot",
819 [UNIT_DEVICE] = "device",
820 [UNIT_MOUNT] = "mount",
821 [UNIT_AUTOMOUNT] = "automount",
822 [UNIT_SWAP] = "swap",
823 [UNIT_TIMER] = "timer",
824 [UNIT_PATH] = "path",
825 [UNIT_SLICE] = "slice",
21b735e7 826 [UNIT_SCOPE] = "scope",
7410616c
LP
827};
828
829DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
830
831static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
832 [UNIT_STUB] = "stub",
833 [UNIT_LOADED] = "loaded",
834 [UNIT_NOT_FOUND] = "not-found",
835 [UNIT_ERROR] = "error",
836 [UNIT_MERGED] = "merged",
837 [UNIT_MASKED] = "masked"
838};
839
840DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
841
978c8b63
ZJS
842static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
843 [UNIT_ACTIVE] = "active",
844 [UNIT_RELOADING] = "reloading",
845 [UNIT_INACTIVE] = "inactive",
846 [UNIT_FAILED] = "failed",
847 [UNIT_ACTIVATING] = "activating",
848 [UNIT_DEACTIVATING] = "deactivating"
849};
850
851DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
852
cb87a73b
LN
853static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
854 [UNIT_REQUIRES] = "Requires",
855 [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
856 [UNIT_REQUISITE] = "Requisite",
857 [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable",
858 [UNIT_WANTS] = "Wants",
859 [UNIT_BINDS_TO] = "BindsTo",
860 [UNIT_PART_OF] = "PartOf",
861 [UNIT_REQUIRED_BY] = "RequiredBy",
862 [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
be7d9ff7
LP
863 [UNIT_REQUISITE_OF] = "RequisiteOf",
864 [UNIT_REQUISITE_OF_OVERRIDABLE] = "RequisiteOfOverridable",
cb87a73b
LN
865 [UNIT_WANTED_BY] = "WantedBy",
866 [UNIT_BOUND_BY] = "BoundBy",
867 [UNIT_CONSISTS_OF] = "ConsistsOf",
868 [UNIT_CONFLICTS] = "Conflicts",
869 [UNIT_CONFLICTED_BY] = "ConflictedBy",
870 [UNIT_BEFORE] = "Before",
871 [UNIT_AFTER] = "After",
872 [UNIT_ON_FAILURE] = "OnFailure",
873 [UNIT_TRIGGERS] = "Triggers",
874 [UNIT_TRIGGERED_BY] = "TriggeredBy",
875 [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo",
876 [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom",
877 [UNIT_JOINS_NAMESPACE_OF] = "JoinsNamespaceOf",
878 [UNIT_REFERENCES] = "References",
879 [UNIT_REFERENCED_BY] = "ReferencedBy",
880};
881
882DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);