LCOV - code coverage report
Current view: top level - basic - unit-name.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 373 422 88.4 %
Date: 2019-08-22 15:41:25 Functions: 27 27 100.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <stddef.h>
       5             : #include <stdint.h>
       6             : #include <stdlib.h>
       7             : #include <string.h>
       8             : 
       9             : #include "alloc-util.h"
      10             : #include "glob-util.h"
      11             : #include "hexdecoct.h"
      12             : #include "path-util.h"
      13             : #include "special.h"
      14             : #include "string-util.h"
      15             : #include "strv.h"
      16             : #include "unit-name.h"
      17             : 
      18             : /* Characters valid in a unit name. */
      19             : #define VALID_CHARS                             \
      20             :         DIGITS                                  \
      21             :         LETTERS                                 \
      22             :         ":-_.\\"
      23             : 
      24             : /* The same, but also permits the single @ character that may appear */
      25             : #define VALID_CHARS_WITH_AT                     \
      26             :         "@"                                     \
      27             :         VALID_CHARS
      28             : 
      29             : /* All chars valid in a unit name glob */
      30             : #define VALID_CHARS_GLOB                        \
      31             :         VALID_CHARS_WITH_AT                     \
      32             :         "[]!-*?"
      33             : 
      34      279439 : bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
      35             :         const char *e, *i, *at;
      36             : 
      37      279439 :         assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0);
      38             : 
      39      279439 :         if (_unlikely_(flags == 0))
      40           0 :                 return false;
      41             : 
      42      279439 :         if (isempty(n))
      43           5 :                 return false;
      44             : 
      45      279434 :         if (strlen(n) >= UNIT_NAME_MAX)
      46           0 :                 return false;
      47             : 
      48      279434 :         e = strrchr(n, '.');
      49      279434 :         if (!e || e == n)
      50         396 :                 return false;
      51             : 
      52      279038 :         if (unit_type_from_string(e + 1) < 0)
      53         223 :                 return false;
      54             : 
      55     4753856 :         for (i = n, at = NULL; i < e; i++) {
      56             : 
      57     4475048 :                 if (*i == '@' && !at)
      58       22579 :                         at = i;
      59             : 
      60     4475048 :                 if (!strchr("@" VALID_CHARS, *i))
      61           7 :                         return false;
      62             :         }
      63             : 
      64      278808 :         if (at == n)
      65           5 :                 return false;
      66             : 
      67      278803 :         if (flags & UNIT_NAME_PLAIN)
      68      233234 :                 if (!at)
      69      214042 :                         return true;
      70             : 
      71       64761 :         if (flags & UNIT_NAME_INSTANCE)
      72       56767 :                 if (at && e > at + 1)
      73        5179 :                         return true;
      74             : 
      75       59582 :         if (flags & UNIT_NAME_TEMPLATE)
      76       33486 :                 if (at && e == at + 1)
      77       17138 :                         return true;
      78             : 
      79       42444 :         return false;
      80             : }
      81             : 
      82       36504 : bool unit_prefix_is_valid(const char *p) {
      83             : 
      84             :         /* We don't allow additional @ in the prefix string */
      85             : 
      86       36504 :         if (isempty(p))
      87           1 :                 return false;
      88             : 
      89       36503 :         return in_charset(p, VALID_CHARS);
      90             : }
      91             : 
      92          80 : bool unit_instance_is_valid(const char *i) {
      93             : 
      94             :         /* The max length depends on the length of the string, so we
      95             :          * don't really check this here. */
      96             : 
      97          80 :         if (isempty(i))
      98           1 :                 return false;
      99             : 
     100             :         /* We allow additional @ in the instance string, we do not
     101             :          * allow them in the prefix! */
     102             : 
     103          79 :         return in_charset(i, "@" VALID_CHARS);
     104             : }
     105             : 
     106        3002 : bool unit_suffix_is_valid(const char *s) {
     107        3002 :         if (isempty(s))
     108           0 :                 return false;
     109             : 
     110        3002 :         if (s[0] != '.')
     111           0 :                 return false;
     112             : 
     113        3002 :         if (unit_type_from_string(s + 1) < 0)
     114           1 :                 return false;
     115             : 
     116        3001 :         return true;
     117             : }
     118             : 
     119       24780 : int unit_name_to_prefix(const char *n, char **ret) {
     120             :         const char *p;
     121             :         char *s;
     122             : 
     123       24780 :         assert(n);
     124       24780 :         assert(ret);
     125             : 
     126       24780 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     127           7 :                 return -EINVAL;
     128             : 
     129       24773 :         p = strchr(n, '@');
     130       24773 :         if (!p)
     131       24765 :                 p = strrchr(n, '.');
     132             : 
     133       24773 :         assert_se(p);
     134             : 
     135       24773 :         s = strndup(n, p - n);
     136       24773 :         if (!s)
     137           0 :                 return -ENOMEM;
     138             : 
     139       24773 :         *ret = s;
     140       24773 :         return 0;
     141             : }
     142             : 
     143        6704 : int unit_name_to_instance(const char *n, char **ret) {
     144             :         const char *p, *d;
     145             : 
     146        6704 :         assert(n);
     147             : 
     148        6704 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     149           3 :                 return -EINVAL;
     150             : 
     151             :         /* Everything past the first @ and before the last . is the instance */
     152        6701 :         p = strchr(n, '@');
     153        6701 :         if (!p) {
     154        6653 :                 if (ret)
     155        6653 :                         *ret = NULL;
     156        6653 :                 return UNIT_NAME_PLAIN;
     157             :         }
     158             : 
     159          48 :         p++;
     160             : 
     161          48 :         d = strrchr(p, '.');
     162          48 :         if (!d)
     163           0 :                 return -EINVAL;
     164             : 
     165          48 :         if (ret) {
     166          48 :                 char *i = strndup(p, d-p);
     167          48 :                 if (!i)
     168           0 :                         return -ENOMEM;
     169             : 
     170          48 :                 *ret = i;
     171             :         }
     172          48 :         return d > p ? UNIT_NAME_INSTANCE : UNIT_NAME_TEMPLATE;
     173             : }
     174             : 
     175           5 : int unit_name_to_prefix_and_instance(const char *n, char **ret) {
     176             :         const char *d;
     177             :         char *s;
     178             : 
     179           5 :         assert(n);
     180           5 :         assert(ret);
     181             : 
     182           5 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     183           0 :                 return -EINVAL;
     184             : 
     185           5 :         d = strrchr(n, '.');
     186           5 :         if (!d)
     187           0 :                 return -EINVAL;
     188             : 
     189           5 :         s = strndup(n, d - n);
     190           5 :         if (!s)
     191           0 :                 return -ENOMEM;
     192             : 
     193           5 :         *ret = s;
     194           5 :         return 0;
     195             : }
     196             : 
     197       33362 : UnitType unit_name_to_type(const char *n) {
     198             :         const char *e;
     199             : 
     200       33362 :         assert(n);
     201             : 
     202       33362 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     203          94 :                 return _UNIT_TYPE_INVALID;
     204             : 
     205       33268 :         assert_se(e = strrchr(n, '.'));
     206             : 
     207       33268 :         return unit_type_from_string(e + 1);
     208             : }
     209             : 
     210           8 : int unit_name_change_suffix(const char *n, const char *suffix, char **ret) {
     211             :         char *e, *s;
     212             :         size_t a, b;
     213             : 
     214           8 :         assert(n);
     215           8 :         assert(suffix);
     216           8 :         assert(ret);
     217             : 
     218           8 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     219           0 :                 return -EINVAL;
     220             : 
     221           8 :         if (!unit_suffix_is_valid(suffix))
     222           0 :                 return -EINVAL;
     223             : 
     224           8 :         assert_se(e = strrchr(n, '.'));
     225             : 
     226           8 :         a = e - n;
     227           8 :         b = strlen(suffix);
     228             : 
     229           8 :         s = new(char, a + b + 1);
     230           8 :         if (!s)
     231           0 :                 return -ENOMEM;
     232             : 
     233           8 :         strcpy(mempcpy(s, n, a), suffix);
     234           8 :         *ret = s;
     235             : 
     236           8 :         return 0;
     237             : }
     238             : 
     239           6 : int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret) {
     240             :         UnitType type;
     241             : 
     242           6 :         assert(prefix);
     243           6 :         assert(suffix);
     244           6 :         assert(ret);
     245             : 
     246           6 :         if (suffix[0] != '.')
     247           0 :                 return -EINVAL;
     248             : 
     249           6 :         type = unit_type_from_string(suffix + 1);
     250           6 :         if (type < 0)
     251           0 :                 return -EINVAL;
     252             : 
     253           6 :         return unit_name_build_from_type(prefix, instance, type, ret);
     254             : }
     255             : 
     256       18244 : int unit_name_build_from_type(const char *prefix, const char *instance, UnitType type, char **ret) {
     257             :         const char *ut;
     258             :         char *s;
     259             : 
     260       18244 :         assert(prefix);
     261       18244 :         assert(type >= 0);
     262       18244 :         assert(type < _UNIT_TYPE_MAX);
     263       18244 :         assert(ret);
     264             : 
     265       18244 :         if (!unit_prefix_is_valid(prefix))
     266           0 :                 return -EINVAL;
     267             : 
     268       18244 :         if (instance && !unit_instance_is_valid(instance))
     269           0 :                 return -EINVAL;
     270             : 
     271       18244 :         ut = unit_type_to_string(type);
     272             : 
     273       18244 :         if (!instance)
     274       18239 :                 s = strjoin(prefix, ".", ut);
     275             :         else
     276           5 :                 s = strjoin(prefix, "@", instance, ".", ut);
     277       18244 :         if (!s)
     278           0 :                 return -ENOMEM;
     279             : 
     280       18244 :         *ret = s;
     281       18244 :         return 0;
     282             : }
     283             : 
     284        3049 : static char *do_escape_char(char c, char *t) {
     285        3049 :         assert(t);
     286             : 
     287        3049 :         *(t++) = '\\';
     288        3049 :         *(t++) = 'x';
     289        3049 :         *(t++) = hexchar(c >> 4);
     290        3049 :         *(t++) = hexchar(c);
     291             : 
     292        3049 :         return t;
     293             : }
     294             : 
     295        2597 : static char *do_escape(const char *f, char *t) {
     296        2597 :         assert(f);
     297        2597 :         assert(t);
     298             : 
     299             :         /* do not create units with a leading '.', like for "/.dotdir" mount points */
     300        2597 :         if (*f == '.') {
     301           0 :                 t = do_escape_char(*f, t);
     302           0 :                 f++;
     303             :         }
     304             : 
     305       72556 :         for (; *f; f++) {
     306       69959 :                 if (*f == '/')
     307        6282 :                         *(t++) = '-';
     308       63677 :                 else if (IN_SET(*f, '-', '\\') || !strchr(VALID_CHARS, *f))
     309        3027 :                         t = do_escape_char(*f, t);
     310             :                 else
     311       60650 :                         *(t++) = *f;
     312             :         }
     313             : 
     314        2597 :         return t;
     315             : }
     316             : 
     317        2597 : char *unit_name_escape(const char *f) {
     318             :         char *r, *t;
     319             : 
     320        2597 :         assert(f);
     321             : 
     322        2597 :         r = new(char, strlen(f)*4+1);
     323        2597 :         if (!r)
     324           0 :                 return NULL;
     325             : 
     326        2597 :         t = do_escape(f, r);
     327        2597 :         *t = 0;
     328             : 
     329        2597 :         return r;
     330             : }
     331             : 
     332          34 : int unit_name_unescape(const char *f, char **ret) {
     333          34 :         _cleanup_free_ char *r = NULL;
     334             :         char *t;
     335             : 
     336          34 :         assert(f);
     337             : 
     338          34 :         r = strdup(f);
     339          34 :         if (!r)
     340           0 :                 return -ENOMEM;
     341             : 
     342         275 :         for (t = r; *f; f++) {
     343         241 :                 if (*f == '-')
     344          31 :                         *(t++) = '/';
     345         210 :                 else if (*f == '\\') {
     346             :                         int a, b;
     347             : 
     348           5 :                         if (f[1] != 'x')
     349           0 :                                 return -EINVAL;
     350             : 
     351           5 :                         a = unhexchar(f[2]);
     352           5 :                         if (a < 0)
     353           0 :                                 return -EINVAL;
     354             : 
     355           5 :                         b = unhexchar(f[3]);
     356           5 :                         if (b < 0)
     357           0 :                                 return -EINVAL;
     358             : 
     359           5 :                         *(t++) = (char) (((uint8_t) a << 4U) | (uint8_t) b);
     360           5 :                         f += 3;
     361             :                 } else
     362         205 :                         *(t++) = *f;
     363             :         }
     364             : 
     365          34 :         *t = 0;
     366             : 
     367          34 :         *ret = TAKE_PTR(r);
     368             : 
     369          34 :         return 0;
     370             : }
     371             : 
     372        2876 : int unit_name_path_escape(const char *f, char **ret) {
     373             :         char *p, *s;
     374             : 
     375        2876 :         assert(f);
     376        2876 :         assert(ret);
     377             : 
     378        2876 :         p = strdupa(f);
     379        2876 :         if (!p)
     380           0 :                 return -ENOMEM;
     381             : 
     382        2876 :         path_simplify(p, false);
     383             : 
     384        2876 :         if (empty_or_root(p))
     385         277 :                 s = strdup("-");
     386             :         else {
     387        2599 :                 if (!path_is_normalized(p))
     388           3 :                         return -EINVAL;
     389             : 
     390             :                 /* Truncate trailing slashes */
     391        2596 :                 delete_trailing_chars(p, "/");
     392             : 
     393             :                 /* Truncate leading slashes */
     394        2596 :                 p = skip_leading_chars(p, "/");
     395             : 
     396        2596 :                 s = unit_name_escape(p);
     397             :         }
     398        2873 :         if (!s)
     399           0 :                 return -ENOMEM;
     400             : 
     401        2873 :         *ret = s;
     402        2873 :         return 0;
     403             : }
     404             : 
     405          33 : int unit_name_path_unescape(const char *f, char **ret) {
     406          33 :         _cleanup_free_ char *s = NULL;
     407             :         int r;
     408             : 
     409          33 :         assert(f);
     410             : 
     411          33 :         if (isempty(f))
     412           1 :                 return -EINVAL;
     413             : 
     414          32 :         if (streq(f, "-")) {
     415           7 :                 s = strdup("/");
     416           7 :                 if (!s)
     417           0 :                         return -ENOMEM;
     418             :         } else {
     419          25 :                 _cleanup_free_ char *w = NULL;
     420             : 
     421          25 :                 r = unit_name_unescape(f, &w);
     422          25 :                 if (r < 0)
     423           0 :                         return r;
     424             : 
     425             :                 /* Don't accept trailing or leading slashes */
     426          25 :                 if (startswith(w, "/") || endswith(w, "/"))
     427           6 :                         return -EINVAL;
     428             : 
     429             :                 /* Prefix a slash again */
     430          19 :                 s = strjoin("/", w);
     431          19 :                 if (!s)
     432           0 :                         return -ENOMEM;
     433             : 
     434          19 :                 if (!path_is_normalized(s))
     435           4 :                         return -EINVAL;
     436             :         }
     437             : 
     438          22 :         if (ret)
     439          22 :                 *ret = TAKE_PTR(s);
     440             : 
     441          22 :         return 0;
     442             : }
     443             : 
     444          48 : int unit_name_replace_instance(const char *f, const char *i, char **ret) {
     445             :         const char *p, *e;
     446             :         char *s;
     447             :         size_t a, b;
     448             : 
     449          48 :         assert(f);
     450          48 :         assert(i);
     451          48 :         assert(ret);
     452             : 
     453          48 :         if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
     454           6 :                 return -EINVAL;
     455          42 :         if (!unit_instance_is_valid(i))
     456           0 :                 return -EINVAL;
     457             : 
     458          42 :         assert_se(p = strchr(f, '@'));
     459          42 :         assert_se(e = strrchr(f, '.'));
     460             : 
     461          42 :         a = p - f;
     462          42 :         b = strlen(i);
     463             : 
     464          42 :         s = new(char, a + 1 + b + strlen(e) + 1);
     465          42 :         if (!s)
     466           0 :                 return -ENOMEM;
     467             : 
     468          42 :         strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e);
     469             : 
     470          42 :         *ret = s;
     471          42 :         return 0;
     472             : }
     473             : 
     474          96 : int unit_name_template(const char *f, char **ret) {
     475             :         const char *p, *e;
     476             :         char *s;
     477             :         size_t a;
     478             : 
     479          96 :         assert(f);
     480          96 :         assert(ret);
     481             : 
     482          96 :         if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
     483          12 :                 return -EINVAL;
     484             : 
     485          84 :         assert_se(p = strchr(f, '@'));
     486          84 :         assert_se(e = strrchr(f, '.'));
     487             : 
     488          84 :         a = p - f;
     489             : 
     490          84 :         s = new(char, a + 1 + strlen(e) + 1);
     491          84 :         if (!s)
     492           0 :                 return -ENOMEM;
     493             : 
     494          84 :         strcpy(mempcpy(s, f, a + 1), e);
     495             : 
     496          84 :         *ret = s;
     497          84 :         return 0;
     498             : }
     499             : 
     500        2869 : int unit_name_from_path(const char *path, const char *suffix, char **ret) {
     501        2869 :         _cleanup_free_ char *p = NULL;
     502        2869 :         char *s = NULL;
     503             :         int r;
     504             : 
     505        2869 :         assert(path);
     506        2869 :         assert(suffix);
     507        2869 :         assert(ret);
     508             : 
     509        2869 :         if (!unit_suffix_is_valid(suffix))
     510           0 :                 return -EINVAL;
     511             : 
     512        2869 :         r = unit_name_path_escape(path, &p);
     513        2869 :         if (r < 0)
     514           2 :                 return r;
     515             : 
     516        2867 :         s = strjoin(p, suffix);
     517        2867 :         if (!s)
     518           0 :                 return -ENOMEM;
     519             : 
     520        2867 :         *ret = s;
     521        2867 :         return 0;
     522             : }
     523             : 
     524           8 : int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret) {
     525           8 :         _cleanup_free_ char *p = NULL;
     526             :         char *s;
     527             :         int r;
     528             : 
     529           8 :         assert(prefix);
     530           8 :         assert(path);
     531           8 :         assert(suffix);
     532           8 :         assert(ret);
     533             : 
     534           8 :         if (!unit_prefix_is_valid(prefix))
     535           0 :                 return -EINVAL;
     536             : 
     537           8 :         if (!unit_suffix_is_valid(suffix))
     538           1 :                 return -EINVAL;
     539             : 
     540           7 :         r = unit_name_path_escape(path, &p);
     541           7 :         if (r < 0)
     542           1 :                 return r;
     543             : 
     544           6 :         s = strjoin(prefix, "@", p, suffix);
     545           6 :         if (!s)
     546           0 :                 return -ENOMEM;
     547             : 
     548           6 :         *ret = s;
     549           6 :         return 0;
     550             : }
     551             : 
     552          16 : int unit_name_to_path(const char *name, char **ret) {
     553          16 :         _cleanup_free_ char *prefix = NULL;
     554             :         int r;
     555             : 
     556          16 :         assert(name);
     557             : 
     558          16 :         r = unit_name_to_prefix(name, &prefix);
     559          16 :         if (r < 0)
     560           2 :                 return r;
     561             : 
     562          14 :         return unit_name_path_unescape(prefix, ret);
     563             : }
     564             : 
     565          99 : static bool do_escape_mangle(const char *f, bool allow_globs, char *t) {
     566             :         const char *valid_chars;
     567          99 :         bool mangled = false;
     568             : 
     569          99 :         assert(f);
     570          99 :         assert(t);
     571             : 
     572             :         /* We'll only escape the obvious characters here, to play safe.
     573             :          *
     574             :          * Returns true if any characters were mangled, false otherwise.
     575             :          */
     576             : 
     577          99 :         valid_chars = allow_globs ? VALID_CHARS_GLOB : VALID_CHARS_WITH_AT;
     578             : 
     579         558 :         for (; *f; f++)
     580         459 :                 if (*f == '/') {
     581           5 :                         *(t++) = '-';
     582           5 :                         mangled = true;
     583         454 :                 } else if (!strchr(valid_chars, *f)) {
     584          22 :                         t = do_escape_char(*f, t);
     585          22 :                         mangled = true;
     586             :                 } else
     587         432 :                         *(t++) = *f;
     588          99 :         *t = 0;
     589             : 
     590          99 :         return mangled;
     591             : }
     592             : 
     593             : /**
     594             :  *  Convert a string to a unit name. /dev/blah is converted to dev-blah.device,
     595             :  *  /blah/blah is converted to blah-blah.mount, anything else is left alone,
     596             :  *  except that @suffix is appended if a valid unit suffix is not present.
     597             :  *
     598             :  *  If @allow_globs, globs characters are preserved. Otherwise, they are escaped.
     599             :  */
     600         118 : int unit_name_mangle_with_suffix(const char *name, UnitNameMangle flags, const char *suffix, char **ret) {
     601             :         char *s;
     602             :         int r;
     603             :         bool mangled;
     604             : 
     605         118 :         assert(name);
     606         118 :         assert(suffix);
     607         118 :         assert(ret);
     608             : 
     609         118 :         if (isempty(name)) /* We cannot mangle empty unit names to become valid, sorry. */
     610           1 :                 return -EINVAL;
     611             : 
     612         117 :         if (!unit_suffix_is_valid(suffix))
     613           0 :                 return -EINVAL;
     614             : 
     615             :         /* Already a fully valid unit name? If so, no mangling is necessary... */
     616         117 :         if (unit_name_is_valid(name, UNIT_NAME_ANY))
     617          13 :                 goto good;
     618             : 
     619             :         /* Already a fully valid globbing expression? If so, no mangling is necessary either... */
     620         104 :         if ((flags & UNIT_NAME_MANGLE_GLOB) &&
     621           5 :             string_is_glob(name) &&
     622           4 :             in_charset(name, VALID_CHARS_GLOB))
     623           3 :                 goto good;
     624             : 
     625         101 :         if (is_device_path(name)) {
     626           1 :                 r = unit_name_from_path(name, ".device", ret);
     627           1 :                 if (r >= 0)
     628           1 :                         return 1;
     629           0 :                 if (r != -EINVAL)
     630           0 :                         return r;
     631             :         }
     632             : 
     633         100 :         if (path_is_absolute(name)) {
     634           1 :                 r = unit_name_from_path(name, ".mount", ret);
     635           1 :                 if (r >= 0)
     636           1 :                         return 1;
     637           0 :                 if (r != -EINVAL)
     638           0 :                         return r;
     639             :         }
     640             : 
     641          99 :         s = new(char, strlen(name) * 4 + strlen(suffix) + 1);
     642          99 :         if (!s)
     643           0 :                 return -ENOMEM;
     644             : 
     645          99 :         mangled = do_escape_mangle(name, flags & UNIT_NAME_MANGLE_GLOB, s);
     646          99 :         if (mangled)
     647           7 :                 log_full(flags & UNIT_NAME_MANGLE_WARN ? LOG_NOTICE : LOG_DEBUG,
     648             :                          "Invalid unit name \"%s\" was escaped as \"%s\" (maybe you should use systemd-escape?)",
     649             :                          name, s);
     650             : 
     651             :         /* Append a suffix if it doesn't have any, but only if this is not a glob, so that we can allow "foo.*" as a
     652             :          * valid glob. */
     653          99 :         if ((!(flags & UNIT_NAME_MANGLE_GLOB) || !string_is_glob(s)) && unit_name_to_type(s) < 0)
     654          94 :                 strcat(s, suffix);
     655             : 
     656          99 :         *ret = s;
     657          99 :         return 1;
     658             : 
     659          16 : good:
     660          16 :         s = strdup(name);
     661          16 :         if (!s)
     662           0 :                 return -ENOMEM;
     663             : 
     664          16 :         *ret = s;
     665          16 :         return 0;
     666             : }
     667             : 
     668          52 : int slice_build_parent_slice(const char *slice, char **ret) {
     669             :         char *s, *dash;
     670             :         int r;
     671             : 
     672          52 :         assert(slice);
     673          52 :         assert(ret);
     674             : 
     675          52 :         if (!slice_name_is_valid(slice))
     676          12 :                 return -EINVAL;
     677             : 
     678          40 :         if (streq(slice, SPECIAL_ROOT_SLICE)) {
     679          23 :                 *ret = NULL;
     680          23 :                 return 0;
     681             :         }
     682             : 
     683          17 :         s = strdup(slice);
     684          17 :         if (!s)
     685           0 :                 return -ENOMEM;
     686             : 
     687          17 :         dash = strrchr(s, '-');
     688          17 :         if (dash)
     689          10 :                 strcpy(dash, ".slice");
     690             :         else {
     691           7 :                 r = free_and_strdup(&s, SPECIAL_ROOT_SLICE);
     692           7 :                 if (r < 0) {
     693           0 :                         free(s);
     694           0 :                         return r;
     695             :                 }
     696             :         }
     697             : 
     698          17 :         *ret = s;
     699          17 :         return 1;
     700             : }
     701             : 
     702           6 : int slice_build_subslice(const char *slice, const char *name, char **ret) {
     703             :         char *subslice;
     704             : 
     705           6 :         assert(slice);
     706           6 :         assert(name);
     707           6 :         assert(ret);
     708             : 
     709           6 :         if (!slice_name_is_valid(slice))
     710           2 :                 return -EINVAL;
     711             : 
     712           4 :         if (!unit_prefix_is_valid(name))
     713           0 :                 return -EINVAL;
     714             : 
     715           4 :         if (streq(slice, SPECIAL_ROOT_SLICE))
     716           1 :                 subslice = strjoin(name, ".slice");
     717             :         else {
     718             :                 char *e;
     719             : 
     720           3 :                 assert_se(e = endswith(slice, ".slice"));
     721             : 
     722           3 :                 subslice = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
     723           3 :                 if (!subslice)
     724           0 :                         return -ENOMEM;
     725             : 
     726           3 :                 stpcpy(stpcpy(stpcpy(mempcpy(subslice, slice, e - slice), "-"), name), ".slice");
     727             :         }
     728             : 
     729           4 :         *ret = subslice;
     730           4 :         return 0;
     731             : }
     732             : 
     733         101 : bool slice_name_is_valid(const char *name) {
     734             :         const char *p, *e;
     735         101 :         bool dash = false;
     736             : 
     737         101 :         if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
     738          24 :                 return false;
     739             : 
     740          77 :         if (streq(name, SPECIAL_ROOT_SLICE))
     741          36 :                 return true;
     742             : 
     743          41 :         e = endswith(name, ".slice");
     744          41 :         if (!e)
     745           3 :                 return false;
     746             : 
     747         333 :         for (p = name; p < e; p++) {
     748             : 
     749         301 :                 if (*p == '-') {
     750             : 
     751             :                         /* Don't allow initial dash */
     752          37 :                         if (p == name)
     753           3 :                                 return false;
     754             : 
     755             :                         /* Don't allow multiple dashes */
     756          34 :                         if (dash)
     757           3 :                                 return false;
     758             : 
     759          31 :                         dash = true;
     760             :                 } else
     761         264 :                         dash = false;
     762             :         }
     763             : 
     764             :         /* Don't allow trailing hash */
     765          32 :         if (dash)
     766           2 :                 return false;
     767             : 
     768          30 :         return true;
     769             : }

Generated by: LCOV version 1.14