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 bool unit_name_is_valid_no_type(const char *n, bool template_ok) {
37 const char *e, *i, *at;
41 * string@instance.suffix
47 if (strlen(n) >= UNIT_NAME_MAX)
54 for (i = n, at = NULL; i < e; i++) {
59 if (!strchr("@" VALID_CHARS, *i))
67 if (!template_ok && at+1 == e)
74 bool unit_instance_is_valid(const char *i) {
77 /* The max length depends on the length of the string, so we
78 * don't really check this here. */
83 /* We allow additional @ in the instance string, we do not
84 * allow them in the prefix! */
87 if (!strchr("@" VALID_CHARS, *i))
93 bool unit_prefix_is_valid(const char *p) {
95 /* We don't allow additional @ in the instance string */
101 if (!strchr(VALID_CHARS, *p))
107 int unit_name_to_instance(const char *n, char **instance) {
114 /* Everything past the first @ and before the last . is the instance */
121 assert_se(d = strrchr(n, '.'));
124 i = strndup(p+1, d-p-1);
132 char *unit_name_to_prefix_and_instance(const char *n) {
137 assert_se(d = strrchr(n, '.'));
139 return strndup(n, d - n);
142 char *unit_name_to_prefix(const char *n) {
147 return strndup(n, p - n);
149 return unit_name_to_prefix_and_instance(n);
152 char *unit_name_change_suffix(const char *n, const char *suffix) {
157 assert(unit_name_is_valid_no_type(n, true));
160 assert_se(e = strrchr(n, '.'));
164 r = new(char, a + b + 1);
169 memcpy(r+a, suffix, b+1);
174 char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
176 assert(unit_prefix_is_valid(prefix));
177 assert(!instance || unit_instance_is_valid(instance));
181 return strappend(prefix, suffix);
183 return join(prefix, "@", instance, suffix, NULL);
186 static char *do_escape_char(char c, char *t) {
189 *(t++) = hexchar(c >> 4);
194 static char *do_escape(const char *f, char *t) {
198 /* do not create units with a leading '.', like for "/.dotdir" mount points */
200 t = do_escape_char(*f, t);
207 else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f))
208 t = do_escape_char(*f, t);
216 char *unit_name_escape(const char *f) {
219 r = new(char, strlen(f)*4+1);
229 char *unit_name_unescape(const char *f) {
238 for (t = r; *f; f++) {
241 else if (*f == '\\') {
245 (a = unhexchar(f[2])) < 0 ||
246 (b = unhexchar(f[3])) < 0) {
247 /* Invalid escape code, let's take it literal then */
250 *(t++) = (char) ((a << 4) | b);
262 char *unit_name_path_escape(const char *f) {
271 path_kill_slashes(p);
278 e = unit_name_escape(p[0] == '/' ? p + 1 : p);
284 char *unit_name_path_unescape(const char *f) {
289 e = unit_name_unescape(f);
296 w = strappend("/", e);
305 bool unit_name_is_template(const char *n) {
310 if (!(p = strchr(n, '@')))
316 char *unit_name_replace_instance(const char *f, const char *i) {
324 assert_se(e = strrchr(f, '.'));
333 r = new(char, a + 1 + b + strlen(e) + 1);
337 k = mempcpy(r, f, a + 1);
338 k = mempcpy(k, i, b);
341 r = new(char, a + strlen(e) + 1);
345 k = mempcpy(r, f, a);
352 char *unit_name_template(const char *f) {
361 assert_se(e = strrchr(f, '.'));
364 r = new(char, a + strlen(e) + 1);
368 strcpy(mempcpy(r, f, a), e);
373 char *unit_name_from_path(const char *path, const char *suffix) {
379 p = unit_name_path_escape(path);
383 r = strappend(p, suffix);
389 char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) {
396 p = unit_name_path_escape(path);
400 r = join(prefix, "@", p, suffix, NULL);
406 char *unit_name_to_path(const char *name) {
411 w = unit_name_to_prefix(name);
415 e = unit_name_path_unescape(w);
421 char *unit_dbus_path_from_name(const char *name) {
426 e = bus_path_escape(name);
430 p = strappend("/org/freedesktop/systemd1/unit/", e);
436 char *unit_name_mangle(const char *name) {
442 /* Try to turn a string that might not be a unit name into a
443 * sensible unit name. */
445 if (path_startswith(name, "/dev/") ||
446 path_startswith(name, "/sys/"))
447 return unit_name_from_path(name, ".device");
449 if (path_is_absolute(name))
450 return unit_name_from_path(name, ".mount");
452 /* We'll only escape the obvious characters here, to play
455 r = new(char, strlen(name) * 4 + 1);
459 for (f = name, t = r; *f; f++) {
463 else if (!strchr("@" VALID_CHARS, *f))
464 t = do_escape_char(*f, t);