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"
32 "abcdefghijklmnopqrstuvwxyz" \
33 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
36 static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
37 [UNIT_SERVICE] = "service",
38 [UNIT_SOCKET] = "socket",
39 [UNIT_TARGET] = "target",
40 [UNIT_DEVICE] = "device",
41 [UNIT_MOUNT] = "mount",
42 [UNIT_AUTOMOUNT] = "automount",
43 [UNIT_SNAPSHOT] = "snapshot",
44 [UNIT_TIMER] = "timer",
47 [UNIT_SLICE] = "slice"
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_ERROR] = "error",
56 [UNIT_MERGED] = "merged",
57 [UNIT_MASKED] = "masked"
60 DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
62 bool unit_name_is_valid(const char *n, bool template_ok) {
63 const char *e, *i, *at;
67 * string@instance.suffix
73 if (strlen(n) >= UNIT_NAME_MAX)
80 if (unit_type_from_string(e + 1) < 0)
83 for (i = n, at = NULL; i < e; i++) {
88 if (!strchr("@" VALID_CHARS, *i))
96 if (!template_ok && at+1 == e)
103 bool unit_instance_is_valid(const char *i) {
106 /* The max length depends on the length of the string, so we
107 * don't really check this here. */
112 /* We allow additional @ in the instance string, we do not
113 * allow them in the prefix! */
116 if (!strchr("@" VALID_CHARS, *i))
122 bool unit_prefix_is_valid(const char *p) {
124 /* We don't allow additional @ in the instance string */
130 if (!strchr(VALID_CHARS, *p))
136 int unit_name_to_instance(const char *n, char **instance) {
143 /* Everything past the first @ and before the last . is the instance */
150 assert_se(d = strrchr(n, '.'));
153 i = strndup(p+1, d-p-1);
161 char *unit_name_to_prefix_and_instance(const char *n) {
166 assert_se(d = strrchr(n, '.'));
168 return strndup(n, d - n);
171 char *unit_name_to_prefix(const char *n) {
176 return strndup(n, p - n);
178 return unit_name_to_prefix_and_instance(n);
181 char *unit_name_change_suffix(const char *n, const char *suffix) {
186 assert(unit_name_is_valid(n, true));
188 assert(suffix[0] == '.');
190 assert_se(e = strrchr(n, '.'));
194 r = new(char, a + b + 1);
199 memcpy(r+a, suffix, b+1);
204 char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
206 assert(unit_prefix_is_valid(prefix));
207 assert(!instance || unit_instance_is_valid(instance));
211 return strappend(prefix, suffix);
213 return strjoin(prefix, "@", instance, suffix, NULL);
216 static char *do_escape_char(char c, char *t) {
219 *(t++) = hexchar(c >> 4);
224 static char *do_escape(const char *f, char *t) {
228 /* do not create units with a leading '.', like for "/.dotdir" mount points */
230 t = do_escape_char(*f, t);
237 else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f))
238 t = do_escape_char(*f, t);
246 char *unit_name_escape(const char *f) {
249 r = new(char, strlen(f)*4+1);
259 char *unit_name_unescape(const char *f) {
268 for (t = r; *f; f++) {
271 else if (*f == '\\') {
275 (a = unhexchar(f[2])) < 0 ||
276 (b = unhexchar(f[3])) < 0) {
277 /* Invalid escape code, let's take it literal then */
280 *(t++) = (char) ((a << 4) | b);
292 char *unit_name_path_escape(const char *f) {
301 path_kill_slashes(p);
308 e = unit_name_escape(p[0] == '/' ? p + 1 : p);
314 char *unit_name_path_unescape(const char *f) {
319 e = unit_name_unescape(f);
326 w = strappend("/", e);
335 bool unit_name_is_template(const char *n) {
347 bool unit_name_is_instance(const char *n) {
359 char *unit_name_replace_instance(const char *f, const char *i) {
372 assert_se(e = strchr(f, 0));
377 r = new(char, a + 1 + b + strlen(e) + 1);
381 k = mempcpy(r, f, a + 1);
382 k = mempcpy(k, i, b);
388 char *unit_name_template(const char *f) {
397 assert_se(e = strrchr(f, '.'));
400 r = new(char, a + strlen(e) + 1);
404 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 char *unit_name_mangle(const char *name) {
475 /* Try to turn a string that might not be a unit name into a
476 * sensible unit name. */
478 if (is_device_path(name))
479 return unit_name_from_path(name, ".device");
481 if (path_is_absolute(name))
482 return unit_name_from_path(name, ".mount");
484 /* We'll only escape the obvious characters here, to play
487 r = new(char, strlen(name) * 4 + 1 + sizeof(".service")-1);
491 for (f = name, t = r; *f; f++) {
494 else if (!strchr("@" VALID_CHARS, *f))
495 t = do_escape_char(*f, t);
500 if (unit_name_to_type(name) < 0)
501 strcpy(t, ".service");
508 char *unit_name_mangle_with_suffix(const char *name, const char *suffix) {
514 assert(suffix[0] == '.');
516 /* Similar to unit_name_mangle(), but is called when we know
517 * that this is about snapshot units. */
519 r = new(char, strlen(name) * 4 + strlen(suffix) + 1);
523 for (f = name, t = r; *f; f++) {
526 else if (!strchr(VALID_CHARS, *f))
527 t = do_escape_char(*f, t);
532 if (!endswith(name, suffix))
540 UnitType unit_name_to_type(const char *n) {
547 return _UNIT_TYPE_INVALID;
549 return unit_type_from_string(e + 1);