LCOV - code coverage report
Current view: top level - basic - unit-name.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 362 426 85.0 %
Date: 2015-07-29 18:47:03 Functions: 32 34 94.1 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       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
       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.
      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
      16             :   Lesser General Public License for more details.
      17             : 
      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/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <string.h>
      24             : 
      25             : #include "path-util.h"
      26             : #include "bus-label.h"
      27             : #include "util.h"
      28             : #include "unit-name.h"
      29             : #include "def.h"
      30             : #include "strv.h"
      31             : 
      32             : #define VALID_CHARS                             \
      33             :         DIGITS LETTERS                          \
      34             :         ":-_.\\"
      35             : 
      36       10199 : bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
      37             :         const char *e, *i, *at;
      38             : 
      39       10199 :         assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0);
      40             : 
      41       10199 :         if (_unlikely_(flags == 0))
      42           0 :                 return false;
      43             : 
      44       10199 :         if (isempty(n))
      45           4 :                 return false;
      46             : 
      47       10195 :         if (strlen(n) >= UNIT_NAME_MAX)
      48           0 :                 return false;
      49             : 
      50       10195 :         e = strrchr(n, '.');
      51       10195 :         if (!e || e == n)
      52         288 :                 return false;
      53             : 
      54        9907 :         if (unit_type_from_string(e + 1) < 0)
      55          20 :                 return false;
      56             : 
      57      256380 :         for (i = n, at = NULL; i < e; i++) {
      58             : 
      59      246499 :                 if (*i == '@' && !at)
      60         156 :                         at = i;
      61             : 
      62      246499 :                 if (!strchr("@" VALID_CHARS, *i))
      63           6 :                         return false;
      64             :         }
      65             : 
      66        9881 :         if (at == n)
      67           2 :                 return false;
      68             : 
      69        9879 :         if (flags & UNIT_NAME_PLAIN)
      70        6014 :                 if (!at)
      71        5872 :                         return true;
      72             : 
      73        4007 :         if (flags & UNIT_NAME_INSTANCE)
      74        2715 :                 if (at && e > at + 1)
      75          58 :                         return true;
      76             : 
      77        3949 :         if (flags & UNIT_NAME_TEMPLATE)
      78        1378 :                 if (at && e == at + 1)
      79          86 :                         return true;
      80             : 
      81        3863 :         return false;
      82             : }
      83             : 
      84          25 : bool unit_prefix_is_valid(const char *p) {
      85             : 
      86             :         /* We don't allow additional @ in the prefix string */
      87             : 
      88          25 :         if (isempty(p))
      89           1 :                 return false;
      90             : 
      91          24 :         return in_charset(p, VALID_CHARS);
      92             : }
      93             : 
      94          16 : bool unit_instance_is_valid(const char *i) {
      95             : 
      96             :         /* The max length depends on the length of the string, so we
      97             :          * don't really check this here. */
      98             : 
      99          16 :         if (isempty(i))
     100           1 :                 return false;
     101             : 
     102             :         /* We allow additional @ in the instance string, we do not
     103             :          * allow them in the prefix! */
     104             : 
     105          15 :         return in_charset(i, "@" VALID_CHARS);
     106             : }
     107             : 
     108        1512 : bool unit_suffix_is_valid(const char *s) {
     109        1512 :         if (isempty(s))
     110           0 :                 return false;
     111             : 
     112        1512 :         if (s[0] != '.')
     113           0 :                 return false;
     114             : 
     115        1512 :         if (unit_type_from_string(s + 1) < 0)
     116           1 :                 return false;
     117             : 
     118        1511 :         return true;
     119             : }
     120             : 
     121          30 : int unit_name_to_prefix(const char *n, char **ret) {
     122             :         const char *p;
     123             :         char *s;
     124             : 
     125          30 :         assert(n);
     126          30 :         assert(ret);
     127             : 
     128          30 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     129           2 :                 return -EINVAL;
     130             : 
     131          28 :         p = strchr(n, '@');
     132          28 :         if (!p)
     133          25 :                 p = strrchr(n, '.');
     134             : 
     135          28 :         assert_se(p);
     136             : 
     137          28 :         s = strndup(n, p - n);
     138          28 :         if (!s)
     139           0 :                 return -ENOMEM;
     140             : 
     141          28 :         *ret = s;
     142          28 :         return 0;
     143             : }
     144             : 
     145         895 : int unit_name_to_instance(const char *n, char **instance) {
     146             :         const char *p, *d;
     147             :         char *i;
     148             : 
     149         895 :         assert(n);
     150         895 :         assert(instance);
     151             : 
     152         895 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     153           2 :                 return -EINVAL;
     154             : 
     155             :         /* Everything past the first @ and before the last . is the instance */
     156         893 :         p = strchr(n, '@');
     157         893 :         if (!p) {
     158         883 :                 *instance = NULL;
     159         883 :                 return 0;
     160             :         }
     161             : 
     162          10 :         p++;
     163             : 
     164          10 :         d = strrchr(p, '.');
     165          10 :         if (!d)
     166           0 :                 return -EINVAL;
     167             : 
     168          10 :         i = strndup(p, d-p);
     169          10 :         if (!i)
     170           0 :                 return -ENOMEM;
     171             : 
     172          10 :         *instance = i;
     173          10 :         return 1;
     174             : }
     175             : 
     176           4 : int unit_name_to_prefix_and_instance(const char *n, char **ret) {
     177             :         const char *d;
     178             :         char *s;
     179             : 
     180           4 :         assert(n);
     181           4 :         assert(ret);
     182             : 
     183           4 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     184           0 :                 return -EINVAL;
     185             : 
     186           4 :         d = strrchr(n, '.');
     187           4 :         if (!d)
     188           0 :                 return -EINVAL;
     189             : 
     190           4 :         s = strndup(n, d - n);
     191           4 :         if (!s)
     192           0 :                 return -ENOMEM;
     193             : 
     194           4 :         *ret = s;
     195           4 :         return 0;
     196             : }
     197             : 
     198        1381 : UnitType unit_name_to_type(const char *n) {
     199             :         const char *e;
     200             : 
     201        1381 :         assert(n);
     202             : 
     203        1381 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     204         137 :                 return _UNIT_TYPE_INVALID;
     205             : 
     206        1244 :         assert_se(e = strrchr(n, '.'));
     207             : 
     208        1244 :         return unit_type_from_string(e + 1);
     209             : }
     210             : 
     211           8 : int unit_name_change_suffix(const char *n, const char *suffix, char **ret) {
     212             :         char *e, *s;
     213             :         size_t a, b;
     214             : 
     215           8 :         assert(n);
     216           8 :         assert(suffix);
     217           8 :         assert(ret);
     218             : 
     219           8 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     220           0 :                 return -EINVAL;
     221             : 
     222           8 :         if (!unit_suffix_is_valid(suffix))
     223           0 :                 return -EINVAL;
     224             : 
     225           8 :         assert_se(e = strrchr(n, '.'));
     226             : 
     227           8 :         a = e - n;
     228           8 :         b = strlen(suffix);
     229             : 
     230           8 :         s = new(char, a + b + 1);
     231           8 :         if (!s)
     232           0 :                 return -ENOMEM;
     233             : 
     234           8 :         strcpy(mempcpy(s, n, a), suffix);
     235           8 :         *ret = s;
     236             : 
     237           8 :         return 0;
     238             : }
     239             : 
     240           3 : int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret) {
     241             :         char *s;
     242             : 
     243           3 :         assert(prefix);
     244           3 :         assert(suffix);
     245           3 :         assert(ret);
     246             : 
     247           3 :         if (!unit_prefix_is_valid(prefix))
     248           0 :                 return -EINVAL;
     249             : 
     250           3 :         if (instance && !unit_instance_is_valid(instance))
     251           0 :                 return -EINVAL;
     252             : 
     253           3 :         if (!unit_suffix_is_valid(suffix))
     254           0 :                 return -EINVAL;
     255             : 
     256           3 :         if (!instance)
     257           1 :                 s = strappend(prefix, suffix);
     258             :         else
     259           2 :                 s = strjoin(prefix, "@", instance, suffix, NULL);
     260           3 :         if (!s)
     261           0 :                 return -ENOMEM;
     262             : 
     263           3 :         *ret = s;
     264           3 :         return 0;
     265             : }
     266             : 
     267         783 : static char *do_escape_char(char c, char *t) {
     268         783 :         assert(t);
     269             : 
     270         783 :         *(t++) = '\\';
     271         783 :         *(t++) = 'x';
     272         783 :         *(t++) = hexchar(c >> 4);
     273         783 :         *(t++) = hexchar(c);
     274             : 
     275         783 :         return t;
     276             : }
     277             : 
     278        1109 : static char *do_escape(const char *f, char *t) {
     279        1109 :         assert(f);
     280        1109 :         assert(t);
     281             : 
     282             :         /* do not create units with a leading '.', like for "/.dotdir" mount points */
     283        1109 :         if (*f == '.') {
     284           0 :                 t = do_escape_char(*f, t);
     285           0 :                 f++;
     286             :         }
     287             : 
     288       30984 :         for (; *f; f++) {
     289       29875 :                 if (*f == '/')
     290        2745 :                         *(t++) = '-';
     291       27130 :                 else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f))
     292         763 :                         t = do_escape_char(*f, t);
     293             :                 else
     294       26367 :                         *(t++) = *f;
     295             :         }
     296             : 
     297        1109 :         return t;
     298             : }
     299             : 
     300        1109 : char *unit_name_escape(const char *f) {
     301             :         char *r, *t;
     302             : 
     303        1109 :         assert(f);
     304             : 
     305        1109 :         r = new(char, strlen(f)*4+1);
     306        1109 :         if (!r)
     307           0 :                 return NULL;
     308             : 
     309        1109 :         t = do_escape(f, r);
     310        1109 :         *t = 0;
     311             : 
     312        1109 :         return r;
     313             : }
     314             : 
     315          27 : int unit_name_unescape(const char *f, char **ret) {
     316          54 :         _cleanup_free_ char *r = NULL;
     317             :         char *t;
     318             : 
     319          27 :         assert(f);
     320             : 
     321          27 :         r = strdup(f);
     322          27 :         if (!r)
     323           0 :                 return -ENOMEM;
     324             : 
     325         235 :         for (t = r; *f; f++) {
     326         208 :                 if (*f == '-')
     327          29 :                         *(t++) = '/';
     328         179 :                 else if (*f == '\\') {
     329             :                         int a, b;
     330             : 
     331           2 :                         if (f[1] != 'x')
     332           0 :                                 return -EINVAL;
     333             : 
     334           2 :                         a = unhexchar(f[2]);
     335           2 :                         if (a < 0)
     336           0 :                                 return -EINVAL;
     337             : 
     338           2 :                         b = unhexchar(f[3]);
     339           2 :                         if (b < 0)
     340           0 :                                 return -EINVAL;
     341             : 
     342           2 :                         *(t++) = (char) (((uint8_t) a << 4U) | (uint8_t) b);
     343           2 :                         f += 3;
     344             :                 } else
     345         177 :                         *(t++) = *f;
     346             :         }
     347             : 
     348          27 :         *t = 0;
     349             : 
     350          27 :         *ret = r;
     351          27 :         r = NULL;
     352             : 
     353          27 :         return 0;
     354             : }
     355             : 
     356        1347 : int unit_name_path_escape(const char *f, char **ret) {
     357             :         char *p, *s;
     358             : 
     359        1347 :         assert(f);
     360        1347 :         assert(ret);
     361             : 
     362        1347 :         p = strdupa(f);
     363        1347 :         if (!p)
     364           0 :                 return -ENOMEM;
     365             : 
     366        1347 :         path_kill_slashes(p);
     367             : 
     368        1347 :         if (STR_IN_SET(p, "/", ""))
     369         236 :                 s = strdup("-");
     370             :         else {
     371             :                 char *e;
     372             : 
     373        1111 :                 if (!path_is_safe(p))
     374           3 :                         return -EINVAL;
     375             : 
     376             :                 /* Truncate trailing slashes */
     377        1108 :                 e = endswith(p, "/");
     378        1108 :                 if (e)
     379           0 :                         *e = 0;
     380             : 
     381             :                 /* Truncate leading slashes */
     382        1108 :                 if (p[0] == '/')
     383        1108 :                         p++;
     384             : 
     385        1108 :                 s = unit_name_escape(p);
     386             :         }
     387        1344 :         if (!s)
     388           0 :                 return -ENOMEM;
     389             : 
     390        1344 :         *ret = s;
     391        1344 :         return 0;
     392             : }
     393             : 
     394          32 : int unit_name_path_unescape(const char *f, char **ret) {
     395             :         char *s;
     396             :         int r;
     397             : 
     398          32 :         assert(f);
     399             : 
     400          32 :         if (isempty(f))
     401           1 :                 return -EINVAL;
     402             : 
     403          31 :         if (streq(f, "-")) {
     404           7 :                 s = strdup("/");
     405           7 :                 if (!s)
     406           0 :                         return -ENOMEM;
     407             :         } else {
     408             :                 char *w;
     409             : 
     410          24 :                 r = unit_name_unescape(f, &w);
     411          24 :                 if (r < 0)
     412          10 :                         return r;
     413             : 
     414             :                 /* Don't accept trailing or leading slashes */
     415          24 :                 if (startswith(w, "/") || endswith(w, "/")) {
     416           6 :                         free(w);
     417           6 :                         return -EINVAL;
     418             :                 }
     419             : 
     420             :                 /* Prefix a slash again */
     421          18 :                 s = strappend("/", w);
     422          18 :                 free(w);
     423          18 :                 if (!s)
     424           0 :                         return -ENOMEM;
     425             : 
     426          18 :                 if (!path_is_safe(s)) {
     427           4 :                         free(s);
     428           4 :                         return -EINVAL;
     429             :                 }
     430             :         }
     431             : 
     432          21 :         if (ret)
     433          21 :                 *ret = s;
     434             :         else
     435           0 :                 free(s);
     436             : 
     437          21 :         return 0;
     438             : }
     439             : 
     440           8 : int unit_name_replace_instance(const char *f, const char *i, char **ret) {
     441             :         const char *p, *e;
     442             :         char *s;
     443             :         size_t a, b;
     444             : 
     445           8 :         assert(f);
     446           8 :         assert(i);
     447           8 :         assert(ret);
     448             : 
     449           8 :         if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
     450           6 :                 return -EINVAL;
     451           2 :         if (!unit_instance_is_valid(i))
     452           0 :                 return -EINVAL;
     453             : 
     454           2 :         assert_se(p = strchr(f, '@'));
     455           2 :         assert_se(e = strrchr(f, '.'));
     456             : 
     457           2 :         a = p - f;
     458           2 :         b = strlen(i);
     459             : 
     460           2 :         s = new(char, a + 1 + b + strlen(e) + 1);
     461           2 :         if (!s)
     462           0 :                 return -ENOMEM;
     463             : 
     464           2 :         strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e);
     465             : 
     466           2 :         *ret = s;
     467           2 :         return 0;
     468             : }
     469             : 
     470           2 : int unit_name_template(const char *f, char **ret) {
     471             :         const char *p, *e;
     472             :         char *s;
     473             :         size_t a;
     474             : 
     475           2 :         assert(f);
     476           2 :         assert(ret);
     477             : 
     478           2 :         if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
     479           1 :                 return -EINVAL;
     480             : 
     481           1 :         assert_se(p = strchr(f, '@'));
     482           1 :         assert_se(e = strrchr(f, '.'));
     483             : 
     484           1 :         a = p - f;
     485             : 
     486           1 :         s = new(char, a + 1 + strlen(e) + 1);
     487           1 :         if (!s)
     488           0 :                 return -ENOMEM;
     489             : 
     490           1 :         strcpy(mempcpy(s, f, a + 1), e);
     491             : 
     492           1 :         *ret = s;
     493           1 :         return 0;
     494             : }
     495             : 
     496        1340 : int unit_name_from_path(const char *path, const char *suffix, char **ret) {
     497        2680 :         _cleanup_free_ char *p = NULL;
     498        1340 :         char *s = NULL;
     499             :         int r;
     500             : 
     501        1340 :         assert(path);
     502        1340 :         assert(suffix);
     503        1340 :         assert(ret);
     504             : 
     505        1340 :         if (!unit_suffix_is_valid(suffix))
     506           0 :                 return -EINVAL;
     507             : 
     508        1340 :         r = unit_name_path_escape(path, &p);
     509        1340 :         if (r < 0)
     510           2 :                 return r;
     511             : 
     512        1338 :         s = strappend(p, suffix);
     513        1338 :         if (!s)
     514           0 :                 return -ENOMEM;
     515             : 
     516        1338 :         *ret = s;
     517        1338 :         return 0;
     518             : }
     519             : 
     520           8 : int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret) {
     521          16 :         _cleanup_free_ char *p = NULL;
     522             :         char *s;
     523             :         int r;
     524             : 
     525           8 :         assert(prefix);
     526           8 :         assert(path);
     527           8 :         assert(suffix);
     528           8 :         assert(ret);
     529             : 
     530           8 :         if (!unit_prefix_is_valid(prefix))
     531           0 :                 return -EINVAL;
     532             : 
     533           8 :         if (!unit_suffix_is_valid(suffix))
     534           1 :                 return -EINVAL;
     535             : 
     536           7 :         r = unit_name_path_escape(path, &p);
     537           7 :         if (r < 0)
     538           1 :                 return r;
     539             : 
     540           6 :         s = strjoin(prefix, "@", p, suffix, NULL);
     541           6 :         if (!s)
     542           0 :                 return -ENOMEM;
     543             : 
     544           6 :         *ret = s;
     545           6 :         return 0;
     546             : }
     547             : 
     548          15 : int unit_name_to_path(const char *name, char **ret) {
     549          30 :         _cleanup_free_ char *prefix = NULL;
     550             :         int r;
     551             : 
     552          15 :         assert(name);
     553             : 
     554          15 :         r = unit_name_to_prefix(name, &prefix);
     555          15 :         if (r < 0)
     556           2 :                 return r;
     557             : 
     558          13 :         return unit_name_path_unescape(prefix, ret);
     559             : }
     560             : 
     561           0 : char *unit_dbus_path_from_name(const char *name) {
     562           0 :         _cleanup_free_ char *e = NULL;
     563             : 
     564           0 :         assert(name);
     565             : 
     566           0 :         e = bus_label_escape(name);
     567           0 :         if (!e)
     568           0 :                 return NULL;
     569             : 
     570           0 :         return strappend("/org/freedesktop/systemd1/unit/", e);
     571             : }
     572             : 
     573           0 : int unit_name_from_dbus_path(const char *path, char **name) {
     574             :         const char *e;
     575             :         char *n;
     576             : 
     577           0 :         e = startswith(path, "/org/freedesktop/systemd1/unit/");
     578           0 :         if (!e)
     579           0 :                 return -EINVAL;
     580             : 
     581           0 :         n = bus_label_unescape(e);
     582           0 :         if (!n)
     583           0 :                 return -ENOMEM;
     584             : 
     585           0 :         *name = n;
     586           0 :         return 0;
     587             : }
     588             : 
     589         141 : static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) {
     590             :         const char *valid_chars;
     591             : 
     592         141 :         assert(f);
     593         141 :         assert(IN_SET(allow_globs, UNIT_NAME_GLOB, UNIT_NAME_NOGLOB));
     594         141 :         assert(t);
     595             : 
     596             :         /* We'll only escape the obvious characters here, to play
     597             :          * safe. */
     598             : 
     599         141 :         valid_chars = allow_globs == UNIT_NAME_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
     600             : 
     601         745 :         for (; *f; f++) {
     602         604 :                 if (*f == '/')
     603           5 :                         *(t++) = '-';
     604         599 :                 else if (!strchr(valid_chars, *f))
     605          20 :                         t = do_escape_char(*f, t);
     606             :                 else
     607         579 :                         *(t++) = *f;
     608             :         }
     609             : 
     610         141 :         return t;
     611             : }
     612             : 
     613             : /**
     614             :  *  Convert a string to a unit name. /dev/blah is converted to dev-blah.device,
     615             :  *  /blah/blah is converted to blah-blah.mount, anything else is left alone,
     616             :  *  except that @suffix is appended if a valid unit suffix is not present.
     617             :  *
     618             :  *  If @allow_globs, globs characters are preserved. Otherwise they are escaped.
     619             :  */
     620         154 : int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) {
     621             :         char *s, *t;
     622             :         int r;
     623             : 
     624         154 :         assert(name);
     625         154 :         assert(suffix);
     626         154 :         assert(ret);
     627             : 
     628         154 :         if (isempty(name)) /* We cannot mangle empty unit names to become valid, sorry. */
     629           1 :                 return -EINVAL;
     630             : 
     631         153 :         if (!unit_suffix_is_valid(suffix))
     632           0 :                 return -EINVAL;
     633             : 
     634         153 :         if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
     635             :                 /* No mangling necessary... */
     636          10 :                 s = strdup(name);
     637          10 :                 if (!s)
     638           0 :                         return -ENOMEM;
     639             : 
     640          10 :                 *ret = s;
     641          10 :                 return 0;
     642             :         }
     643             : 
     644         143 :         if (is_device_path(name)) {
     645           1 :                 r = unit_name_from_path(name, ".device", ret);
     646           1 :                 if (r >= 0)
     647           1 :                         return 1;
     648           0 :                 if (r != -EINVAL)
     649           0 :                         return r;
     650             :         }
     651             : 
     652         142 :         if (path_is_absolute(name)) {
     653           1 :                 r = unit_name_from_path(name, ".mount", ret);
     654           1 :                 if (r >= 0)
     655           1 :                         return 1;
     656           0 :                 if (r != -EINVAL)
     657           0 :                         return r;
     658             :         }
     659             : 
     660         141 :         s = new(char, strlen(name) * 4 + strlen(suffix) + 1);
     661         141 :         if (!s)
     662           0 :                 return -ENOMEM;
     663             : 
     664         141 :         t = do_escape_mangle(name, allow_globs, s);
     665         141 :         *t = 0;
     666             : 
     667         141 :         if (unit_name_to_type(s) < 0)
     668         137 :                 strcpy(t, suffix);
     669             : 
     670         141 :         *ret = s;
     671         141 :         return 1;
     672             : }
     673             : 
     674          21 : int slice_build_parent_slice(const char *slice, char **ret) {
     675             :         char *s, *dash;
     676             : 
     677          21 :         assert(slice);
     678          21 :         assert(ret);
     679             : 
     680          21 :         if (!slice_name_is_valid(slice))
     681           5 :                 return -EINVAL;
     682             : 
     683          16 :         if (streq(slice, "-.slice")) {
     684          11 :                 *ret = NULL;
     685          11 :                 return 0;
     686             :         }
     687             : 
     688           5 :         s = strdup(slice);
     689           5 :         if (!s)
     690           0 :                 return -ENOMEM;
     691             : 
     692           5 :         dash = strrchr(s, '-');
     693           5 :         if (dash)
     694           3 :                 strcpy(dash, ".slice");
     695             :         else {
     696           2 :                 free(s);
     697             : 
     698           2 :                 s = strdup("-.slice");
     699           2 :                 if (!s)
     700           0 :                         return -ENOMEM;
     701             :         }
     702             : 
     703           5 :         *ret = s;
     704           5 :         return 1;
     705             : }
     706             : 
     707           6 : int slice_build_subslice(const char *slice, const char*name, char **ret) {
     708             :         char *subslice;
     709             : 
     710           6 :         assert(slice);
     711           6 :         assert(name);
     712           6 :         assert(ret);
     713             : 
     714           6 :         if (!slice_name_is_valid(slice))
     715           2 :                 return -EINVAL;
     716             : 
     717           4 :         if (!unit_prefix_is_valid(name))
     718           0 :                 return -EINVAL;
     719             : 
     720           4 :         if (streq(slice, "-.slice"))
     721           1 :                 subslice = strappend(name, ".slice");
     722             :         else {
     723             :                 char *e;
     724             : 
     725           3 :                 assert_se(e = endswith(slice, ".slice"));
     726             : 
     727           3 :                 subslice = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
     728           3 :                 if (!subslice)
     729           0 :                         return -ENOMEM;
     730             : 
     731           3 :                 stpcpy(stpcpy(stpcpy(mempcpy(subslice, slice, e - slice), "-"), name), ".slice");
     732             :         }
     733             : 
     734           4 :         *ret = subslice;
     735           4 :         return 0;
     736             : }
     737             : 
     738          51 : bool slice_name_is_valid(const char *name) {
     739             :         const char *p, *e;
     740          51 :         bool dash = false;
     741             : 
     742          51 :         if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
     743           4 :                 return false;
     744             : 
     745          47 :         if (streq(name, "-.slice"))
     746          23 :                 return true;
     747             : 
     748          24 :         e = endswith(name, ".slice");
     749          24 :         if (!e)
     750           3 :                 return false;
     751             : 
     752         161 :         for (p = name; p < e; p++) {
     753             : 
     754         146 :                 if (*p == '-') {
     755             : 
     756             :                         /* Don't allow initial dash */
     757          27 :                         if (p == name)
     758           3 :                                 return false;
     759             : 
     760             :                         /* Don't allow multiple dashes */
     761          24 :                         if (dash)
     762           3 :                                 return false;
     763             : 
     764          21 :                         dash = true;
     765             :                 } else
     766         119 :                         dash = false;
     767             :         }
     768             : 
     769             :         /* Don't allow trailing hash */
     770          15 :         if (dash)
     771           2 :                 return false;
     772             : 
     773          13 :         return true;
     774             : }
     775             : 
     776             : static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
     777             :         [UNIT_SERVICE] = "service",
     778             :         [UNIT_SOCKET] = "socket",
     779             :         [UNIT_BUSNAME] = "busname",
     780             :         [UNIT_TARGET] = "target",
     781             :         [UNIT_SNAPSHOT] = "snapshot",
     782             :         [UNIT_DEVICE] = "device",
     783             :         [UNIT_MOUNT] = "mount",
     784             :         [UNIT_AUTOMOUNT] = "automount",
     785             :         [UNIT_SWAP] = "swap",
     786             :         [UNIT_TIMER] = "timer",
     787             :         [UNIT_PATH] = "path",
     788             :         [UNIT_SLICE] = "slice",
     789             :         [UNIT_SCOPE] = "scope"
     790             : };
     791             : 
     792       12693 : DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType);
     793             : 
     794             : static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
     795             :         [UNIT_STUB] = "stub",
     796             :         [UNIT_LOADED] = "loaded",
     797             :         [UNIT_NOT_FOUND] = "not-found",
     798             :         [UNIT_ERROR] = "error",
     799             :         [UNIT_MERGED] = "merged",
     800             :         [UNIT_MASKED] = "masked"
     801             : };
     802             : 
     803         341 : DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
     804             : 
     805             : static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
     806             :         [UNIT_REQUIRES] = "Requires",
     807             :         [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
     808             :         [UNIT_REQUISITE] = "Requisite",
     809             :         [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable",
     810             :         [UNIT_WANTS] = "Wants",
     811             :         [UNIT_BINDS_TO] = "BindsTo",
     812             :         [UNIT_PART_OF] = "PartOf",
     813             :         [UNIT_REQUIRED_BY] = "RequiredBy",
     814             :         [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
     815             :         [UNIT_REQUISITE_OF] = "RequisiteOf",
     816             :         [UNIT_REQUISITE_OF_OVERRIDABLE] = "RequisiteOfOverridable",
     817             :         [UNIT_WANTED_BY] = "WantedBy",
     818             :         [UNIT_BOUND_BY] = "BoundBy",
     819             :         [UNIT_CONSISTS_OF] = "ConsistsOf",
     820             :         [UNIT_CONFLICTS] = "Conflicts",
     821             :         [UNIT_CONFLICTED_BY] = "ConflictedBy",
     822             :         [UNIT_BEFORE] = "Before",
     823             :         [UNIT_AFTER] = "After",
     824             :         [UNIT_ON_FAILURE] = "OnFailure",
     825             :         [UNIT_TRIGGERS] = "Triggers",
     826             :         [UNIT_TRIGGERED_BY] = "TriggeredBy",
     827             :         [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo",
     828             :         [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom",
     829             :         [UNIT_JOINS_NAMESPACE_OF] = "JoinsNamespaceOf",
     830             :         [UNIT_REFERENCES] = "References",
     831             :         [UNIT_REFERENCED_BY] = "ReferencedBy",
     832             : };
     833             : 
     834        1398 : DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);

Generated by: LCOV version 1.11