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