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 */
115 if (!(p = strchr(n, '@'))) {
120 assert_se(d = strrchr(n, '.'));
123 if (!(i = strndup(p+1, d-p-1)))
130 char *unit_name_to_prefix_and_instance(const char *n) {
135 assert_se(d = strrchr(n, '.'));
137 return strndup(n, d - n);
140 char *unit_name_to_prefix(const char *n) {
143 if ((p = strchr(n, '@')))
144 return strndup(n, p - n);
146 return unit_name_to_prefix_and_instance(n);
149 char *unit_name_change_suffix(const char *n, const char *suffix) {
154 assert(unit_name_is_valid_no_type(n, true));
157 assert_se(e = strrchr(n, '.'));
161 if (!(r = new(char, a + b + 1)))
165 memcpy(r+a, suffix, b+1);
170 char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
172 assert(unit_prefix_is_valid(prefix));
173 assert(!instance || unit_instance_is_valid(instance));
177 return strappend(prefix, suffix);
179 return join(prefix, "@", instance, suffix, NULL);
182 static char *do_escape_char(char c, char *t) {
185 *(t++) = hexchar(c >> 4);
190 static char *do_escape(const char *f, char *t) {
194 /* do not create units with a leading '.', like for "/.dotdir" mount points */
196 t = do_escape_char(*f, t);
203 else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f))
204 t = do_escape_char(*f, t);
212 char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) {
219 /* Takes a arbitrary string for prefix and instance plus a
220 * suffix and makes a nice string suitable as unit name of it,
221 * escaping all weird chars on the way.
223 * / becomes -, and all chars not allowed in a unit name get
224 * escaped as \xFF, including \ and -, of course. This
225 * escaping is hence reversible.
227 * This is primarily useful to make nice unit names from
228 * strings, but is actually useful for any kind of string.
235 b = strlen(instance);
237 if (!(r = new(char, a*4 + 1 + b*4 + c + 1)))
240 t = do_escape(prefix, r);
242 t = do_escape(instance, t);
245 if (!(r = new(char, a*4 + c + 1)))
248 t = do_escape(prefix, r);
255 char *unit_name_escape(const char *f) {
258 if (!(r = new(char, strlen(f)*4+1)))
268 char *unit_name_unescape(const char *f) {
273 if (!(r = strdup(f)))
276 for (t = r; *f; f++) {
279 else if (*f == '\\') {
283 (a = unhexchar(f[2])) < 0 ||
284 (b = unhexchar(f[3])) < 0) {
285 /* Invalid escape code, let's take it literal then */
288 *(t++) = (char) ((a << 4) | b);
300 bool unit_name_is_template(const char *n) {
305 if (!(p = strchr(n, '@')))
311 char *unit_name_replace_instance(const char *f, const char *i) {
319 assert_se(e = strrchr(f, '.'));
328 if (!(r = new(char, a + 1 + b + strlen(e) + 1)))
331 k = mempcpy(r, f, a + 1);
332 k = mempcpy(k, i, b);
335 if (!(r = new(char, a + strlen(e) + 1)))
338 k = mempcpy(r, f, a);
345 char *unit_name_template(const char *f) {
350 if (!(p = strchr(f, '@')))
353 assert_se(e = strrchr(f, '.'));
356 if (!(r = new(char, a + strlen(e) + 1)))
359 strcpy(mempcpy(r, f, a), e);
364 char *unit_name_from_path(const char *path, const char *suffix) {
370 if (!(p = strdup(path)))
373 path_kill_slashes(p);
375 path = p[0] == '/' ? p + 1 : p;
379 return strappend("-", suffix);
382 r = unit_name_build_escape(path, NULL, suffix);
388 char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) {
394 if (!(p = strdup(path)))
397 path_kill_slashes(p);
399 path = p[0] == '/' ? p + 1 : p;
403 return unit_name_build_escape(prefix, "-", suffix);
406 r = unit_name_build_escape(prefix, path, suffix);
412 char *unit_name_to_path(const char *name) {
417 if (!(w = unit_name_to_prefix(name)))
420 e = unit_name_unescape(w);
427 w = strappend("/", e);
439 char *unit_name_path_unescape(const char *f) {
444 if (!(e = unit_name_unescape(f)))
450 w = strappend("/", e);
462 char *unit_dbus_path_from_name(const char *name) {
465 e = bus_path_escape(name);
469 p = strappend("/org/freedesktop/systemd1/unit/", e);