]>
git.proxmox.com Git - systemd.git/blob - src/shared/unit-name.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
26 #include "path-util.h"
28 #include "unit-name.h"
35 static const char* const unit_type_table
[_UNIT_TYPE_MAX
] = {
36 [UNIT_SERVICE
] = "service",
37 [UNIT_SOCKET
] = "socket",
38 [UNIT_TARGET
] = "target",
39 [UNIT_DEVICE
] = "device",
40 [UNIT_MOUNT
] = "mount",
41 [UNIT_AUTOMOUNT
] = "automount",
42 [UNIT_SNAPSHOT
] = "snapshot",
43 [UNIT_TIMER
] = "timer",
46 [UNIT_SLICE
] = "slice",
47 [UNIT_SCOPE
] = "scope"
50 DEFINE_STRING_TABLE_LOOKUP(unit_type
, UnitType
);
52 static const char* const unit_load_state_table
[_UNIT_LOAD_STATE_MAX
] = {
54 [UNIT_LOADED
] = "loaded",
55 [UNIT_NOT_FOUND
] = "not-found",
56 [UNIT_ERROR
] = "error",
57 [UNIT_MERGED
] = "merged",
58 [UNIT_MASKED
] = "masked"
61 DEFINE_STRING_TABLE_LOOKUP(unit_load_state
, UnitLoadState
);
63 bool unit_name_is_valid(const char *n
, bool template_ok
) {
64 const char *e
, *i
, *at
;
68 * string@instance.suffix
74 if (strlen(n
) >= UNIT_NAME_MAX
)
81 if (unit_type_from_string(e
+ 1) < 0)
84 for (i
= n
, at
= NULL
; i
< e
; i
++) {
89 if (!strchr("@" VALID_CHARS
, *i
))
97 if (!template_ok
&& at
+1 == e
)
104 bool unit_instance_is_valid(const char *i
) {
107 /* The max length depends on the length of the string, so we
108 * don't really check this here. */
113 /* We allow additional @ in the instance string, we do not
114 * allow them in the prefix! */
117 if (!strchr("@" VALID_CHARS
, *i
))
123 bool unit_prefix_is_valid(const char *p
) {
125 /* We don't allow additional @ in the instance string */
131 if (!strchr(VALID_CHARS
, *p
))
137 int unit_name_to_instance(const char *n
, char **instance
) {
144 /* Everything past the first @ and before the last . is the instance */
151 assert_se(d
= strrchr(n
, '.'));
154 i
= strndup(p
+1, d
-p
-1);
162 char *unit_name_to_prefix_and_instance(const char *n
) {
167 assert_se(d
= strrchr(n
, '.'));
169 return strndup(n
, d
- n
);
172 char *unit_name_to_prefix(const char *n
) {
177 return strndup(n
, p
- n
);
179 return unit_name_to_prefix_and_instance(n
);
182 char *unit_name_change_suffix(const char *n
, const char *suffix
) {
187 assert(unit_name_is_valid(n
, true));
189 assert(suffix
[0] == '.');
191 assert_se(e
= strrchr(n
, '.'));
195 r
= new(char, a
+ b
+ 1);
200 memcpy(r
+a
, suffix
, b
+1);
205 char *unit_name_build(const char *prefix
, const char *instance
, const char *suffix
) {
207 assert(unit_prefix_is_valid(prefix
));
208 assert(!instance
|| unit_instance_is_valid(instance
));
212 return strappend(prefix
, suffix
);
214 return strjoin(prefix
, "@", instance
, suffix
, NULL
);
217 static char *do_escape_char(char c
, char *t
) {
220 *(t
++) = hexchar(c
>> 4);
225 static char *do_escape(const char *f
, char *t
) {
229 /* do not create units with a leading '.', like for "/.dotdir" mount points */
231 t
= do_escape_char(*f
, t
);
238 else if (*f
== '-' || *f
== '\\' || !strchr(VALID_CHARS
, *f
))
239 t
= do_escape_char(*f
, t
);
247 char *unit_name_escape(const char *f
) {
250 r
= new(char, strlen(f
)*4+1);
260 char *unit_name_unescape(const char *f
) {
269 for (t
= r
; *f
; f
++) {
272 else if (*f
== '\\') {
276 (a
= unhexchar(f
[2])) < 0 ||
277 (b
= unhexchar(f
[3])) < 0) {
278 /* Invalid escape code, let's take it literal then */
281 *(t
++) = (char) ((a
<< 4) | b
);
293 char *unit_name_path_escape(const char *f
) {
302 path_kill_slashes(p
);
304 if (streq(p
, "/") || streq(p
, "")) {
309 e
= unit_name_escape(p
[0] == '/' ? p
+ 1 : p
);
315 char *unit_name_path_unescape(const char *f
) {
320 e
= unit_name_unescape(f
);
327 w
= strappend("/", e
);
336 bool unit_name_is_template(const char *n
) {
348 bool unit_name_is_instance(const char *n
) {
360 char *unit_name_replace_instance(const char *f
, const char *i
) {
373 assert_se(e
= strchr(f
, 0));
378 r
= new(char, a
+ 1 + b
+ strlen(e
) + 1);
382 k
= mempcpy(r
, f
, a
+ 1);
383 k
= mempcpy(k
, i
, b
);
389 char *unit_name_template(const char *f
) {
398 assert_se(e
= strrchr(f
, '.'));
401 r
= new(char, a
+ strlen(e
) + 1);
405 strcpy(mempcpy(r
, f
, a
), e
);
409 char *unit_name_from_path(const char *path
, const char *suffix
) {
415 p
= unit_name_path_escape(path
);
419 r
= strappend(p
, suffix
);
425 char *unit_name_from_path_instance(const char *prefix
, const char *path
, const char *suffix
) {
432 p
= unit_name_path_escape(path
);
436 r
= strjoin(prefix
, "@", p
, suffix
, NULL
);
442 char *unit_name_to_path(const char *name
) {
447 w
= unit_name_to_prefix(name
);
451 e
= unit_name_path_unescape(w
);
457 char *unit_dbus_path_from_name(const char *name
) {
458 _cleanup_free_
char *e
= NULL
;
462 e
= bus_path_escape(name
);
466 return strappend("/org/freedesktop/systemd1/unit/", e
);
469 int unit_name_from_dbus_path(const char *path
, char **name
) {
473 e
= startswith(path
, "/org/freedesktop/systemd1/unit/");
477 n
= bus_path_unescape(e
);
485 char *unit_name_mangle(const char *name
) {
491 /* Try to turn a string that might not be a unit name into a
492 * sensible unit name. */
494 if (is_device_path(name
))
495 return unit_name_from_path(name
, ".device");
497 if (path_is_absolute(name
))
498 return unit_name_from_path(name
, ".mount");
500 /* We'll only escape the obvious characters here, to play
503 r
= new(char, strlen(name
) * 4 + 1 + sizeof(".service")-1);
507 for (f
= name
, t
= r
; *f
; f
++) {
510 else if (!strchr("@" VALID_CHARS
, *f
))
511 t
= do_escape_char(*f
, t
);
516 if (unit_name_to_type(name
) < 0)
517 strcpy(t
, ".service");
524 char *unit_name_mangle_with_suffix(const char *name
, const char *suffix
) {
530 assert(suffix
[0] == '.');
532 /* Similar to unit_name_mangle(), but is called when we know
533 * that this is about snapshot units. */
535 r
= new(char, strlen(name
) * 4 + strlen(suffix
) + 1);
539 for (f
= name
, t
= r
; *f
; f
++) {
542 else if (!strchr(VALID_CHARS
, *f
))
543 t
= do_escape_char(*f
, t
);
548 if (!endswith(name
, suffix
))
556 UnitType
unit_name_to_type(const char *n
) {
563 return _UNIT_TYPE_INVALID
;
565 return unit_type_from_string(e
+ 1);
568 int build_subslice(const char *slice
, const char*name
, char **subslice
) {
575 if (streq(slice
, "-.slice"))
576 ret
= strappend(name
, ".slice");
580 e
= endswith(slice
, ".slice");
584 ret
= new(char, (e
- slice
) + 1 + strlen(name
) + 6 + 1);
588 stpcpy(stpcpy(stpcpy(mempcpy(ret
, slice
, e
- slice
), "-"), name
), ".slice");