LCOV - code coverage report
Current view: top level - basic - unit-name.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 373 422 88.4 %
Date: 2019-08-23 13:36:53 Functions: 27 27 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 263 372 70.7 %

           Branch data     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                 :    1123120 : bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
      35                 :            :         const char *e, *i, *at;
      36                 :            : 
      37         [ -  + ]:    1123120 :         assert((flags & ~(UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) == 0);
      38                 :            : 
      39         [ -  + ]:    1123120 :         if (_unlikely_(flags == 0))
      40                 :          0 :                 return false;
      41                 :            : 
      42         [ +  + ]:    1123120 :         if (isempty(n))
      43                 :         20 :                 return false;
      44                 :            : 
      45         [ -  + ]:    1123100 :         if (strlen(n) >= UNIT_NAME_MAX)
      46                 :          0 :                 return false;
      47                 :            : 
      48                 :    1123100 :         e = strrchr(n, '.');
      49   [ +  +  +  + ]:    1123100 :         if (!e || e == n)
      50                 :       1584 :                 return false;
      51                 :            : 
      52         [ +  + ]:    1121516 :         if (unit_type_from_string(e + 1) < 0)
      53                 :        892 :                 return false;
      54                 :            : 
      55         [ +  + ]:   19126392 :         for (i = n, at = NULL; i < e; i++) {
      56                 :            : 
      57   [ +  +  +  + ]:   18005796 :                 if (*i == '@' && !at)
      58                 :      90316 :                         at = i;
      59                 :            : 
      60         [ +  + ]:   18005796 :                 if (!strchr("@" VALID_CHARS, *i))
      61                 :         28 :                         return false;
      62                 :            :         }
      63                 :            : 
      64         [ +  + ]:    1120596 :         if (at == n)
      65                 :         20 :                 return false;
      66                 :            : 
      67         [ +  + ]:    1120576 :         if (flags & UNIT_NAME_PLAIN)
      68         [ +  + ]:     936476 :                 if (!at)
      69                 :     859708 :                         return true;
      70                 :            : 
      71         [ +  + ]:     260868 :         if (flags & UNIT_NAME_INSTANCE)
      72   [ +  +  +  + ]:     228628 :                 if (at && e > at + 1)
      73                 :      20716 :                         return true;
      74                 :            : 
      75         [ +  + ]:     240152 :         if (flags & UNIT_NAME_TEMPLATE)
      76   [ +  +  +  + ]:     134208 :                 if (at && e == at + 1)
      77                 :      68552 :                         return true;
      78                 :            : 
      79                 :     171600 :         return false;
      80                 :            : }
      81                 :            : 
      82                 :     148512 : bool unit_prefix_is_valid(const char *p) {
      83                 :            : 
      84                 :            :         /* We don't allow additional @ in the prefix string */
      85                 :            : 
      86         [ +  + ]:     148512 :         if (isempty(p))
      87                 :          4 :                 return false;
      88                 :            : 
      89                 :     148508 :         return in_charset(p, VALID_CHARS);
      90                 :            : }
      91                 :            : 
      92                 :        320 : 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         [ +  + ]:        320 :         if (isempty(i))
      98                 :          4 :                 return false;
      99                 :            : 
     100                 :            :         /* We allow additional @ in the instance string, we do not
     101                 :            :          * allow them in the prefix! */
     102                 :            : 
     103                 :        316 :         return in_charset(i, "@" VALID_CHARS);
     104                 :            : }
     105                 :            : 
     106                 :      12096 : bool unit_suffix_is_valid(const char *s) {
     107         [ -  + ]:      12096 :         if (isempty(s))
     108                 :          0 :                 return false;
     109                 :            : 
     110         [ -  + ]:      12096 :         if (s[0] != '.')
     111                 :          0 :                 return false;
     112                 :            : 
     113         [ +  + ]:      12096 :         if (unit_type_from_string(s + 1) < 0)
     114                 :          4 :                 return false;
     115                 :            : 
     116                 :      12092 :         return true;
     117                 :            : }
     118                 :            : 
     119                 :     100680 : int unit_name_to_prefix(const char *n, char **ret) {
     120                 :            :         const char *p;
     121                 :            :         char *s;
     122                 :            : 
     123         [ -  + ]:     100680 :         assert(n);
     124         [ -  + ]:     100680 :         assert(ret);
     125                 :            : 
     126         [ +  + ]:     100680 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     127                 :         28 :                 return -EINVAL;
     128                 :            : 
     129                 :     100652 :         p = strchr(n, '@');
     130         [ +  + ]:     100652 :         if (!p)
     131                 :     100620 :                 p = strrchr(n, '.');
     132                 :            : 
     133         [ -  + ]:     100652 :         assert_se(p);
     134                 :            : 
     135                 :     100652 :         s = strndup(n, p - n);
     136         [ -  + ]:     100652 :         if (!s)
     137                 :          0 :                 return -ENOMEM;
     138                 :            : 
     139                 :     100652 :         *ret = s;
     140                 :     100652 :         return 0;
     141                 :            : }
     142                 :            : 
     143                 :      27080 : int unit_name_to_instance(const char *n, char **ret) {
     144                 :            :         const char *p, *d;
     145                 :            : 
     146         [ -  + ]:      27080 :         assert(n);
     147                 :            : 
     148         [ +  + ]:      27080 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     149                 :         12 :                 return -EINVAL;
     150                 :            : 
     151                 :            :         /* Everything past the first @ and before the last . is the instance */
     152                 :      27068 :         p = strchr(n, '@');
     153         [ +  + ]:      27068 :         if (!p) {
     154         [ +  - ]:      26876 :                 if (ret)
     155                 :      26876 :                         *ret = NULL;
     156                 :      26876 :                 return UNIT_NAME_PLAIN;
     157                 :            :         }
     158                 :            : 
     159                 :        192 :         p++;
     160                 :            : 
     161                 :        192 :         d = strrchr(p, '.');
     162         [ -  + ]:        192 :         if (!d)
     163                 :          0 :                 return -EINVAL;
     164                 :            : 
     165         [ +  - ]:        192 :         if (ret) {
     166                 :        192 :                 char *i = strndup(p, d-p);
     167         [ -  + ]:        192 :                 if (!i)
     168                 :          0 :                         return -ENOMEM;
     169                 :            : 
     170                 :        192 :                 *ret = i;
     171                 :            :         }
     172         [ +  + ]:        192 :         return d > p ? UNIT_NAME_INSTANCE : UNIT_NAME_TEMPLATE;
     173                 :            : }
     174                 :            : 
     175                 :         20 : int unit_name_to_prefix_and_instance(const char *n, char **ret) {
     176                 :            :         const char *d;
     177                 :            :         char *s;
     178                 :            : 
     179         [ -  + ]:         20 :         assert(n);
     180         [ -  + ]:         20 :         assert(ret);
     181                 :            : 
     182         [ -  + ]:         20 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     183                 :          0 :                 return -EINVAL;
     184                 :            : 
     185                 :         20 :         d = strrchr(n, '.');
     186         [ -  + ]:         20 :         if (!d)
     187                 :          0 :                 return -EINVAL;
     188                 :            : 
     189                 :         20 :         s = strndup(n, d - n);
     190         [ -  + ]:         20 :         if (!s)
     191                 :          0 :                 return -ENOMEM;
     192                 :            : 
     193                 :         20 :         *ret = s;
     194                 :         20 :         return 0;
     195                 :            : }
     196                 :            : 
     197                 :     134784 : UnitType unit_name_to_type(const char *n) {
     198                 :            :         const char *e;
     199                 :            : 
     200         [ -  + ]:     134784 :         assert(n);
     201                 :            : 
     202         [ +  + ]:     134784 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     203                 :        376 :                 return _UNIT_TYPE_INVALID;
     204                 :            : 
     205         [ -  + ]:     134408 :         assert_se(e = strrchr(n, '.'));
     206                 :            : 
     207                 :     134408 :         return unit_type_from_string(e + 1);
     208                 :            : }
     209                 :            : 
     210                 :         32 : int unit_name_change_suffix(const char *n, const char *suffix, char **ret) {
     211                 :            :         char *e, *s;
     212                 :            :         size_t a, b;
     213                 :            : 
     214         [ -  + ]:         32 :         assert(n);
     215         [ -  + ]:         32 :         assert(suffix);
     216         [ -  + ]:         32 :         assert(ret);
     217                 :            : 
     218         [ -  + ]:         32 :         if (!unit_name_is_valid(n, UNIT_NAME_ANY))
     219                 :          0 :                 return -EINVAL;
     220                 :            : 
     221         [ -  + ]:         32 :         if (!unit_suffix_is_valid(suffix))
     222                 :          0 :                 return -EINVAL;
     223                 :            : 
     224         [ -  + ]:         32 :         assert_se(e = strrchr(n, '.'));
     225                 :            : 
     226                 :         32 :         a = e - n;
     227                 :         32 :         b = strlen(suffix);
     228                 :            : 
     229                 :         32 :         s = new(char, a + b + 1);
     230         [ -  + ]:         32 :         if (!s)
     231                 :          0 :                 return -ENOMEM;
     232                 :            : 
     233                 :         32 :         strcpy(mempcpy(s, n, a), suffix);
     234                 :         32 :         *ret = s;
     235                 :            : 
     236                 :         32 :         return 0;
     237                 :            : }
     238                 :            : 
     239                 :         24 : int unit_name_build(const char *prefix, const char *instance, const char *suffix, char **ret) {
     240                 :            :         UnitType type;
     241                 :            : 
     242         [ -  + ]:         24 :         assert(prefix);
     243         [ -  + ]:         24 :         assert(suffix);
     244         [ -  + ]:         24 :         assert(ret);
     245                 :            : 
     246         [ -  + ]:         24 :         if (suffix[0] != '.')
     247                 :          0 :                 return -EINVAL;
     248                 :            : 
     249                 :         24 :         type = unit_type_from_string(suffix + 1);
     250         [ -  + ]:         24 :         if (type < 0)
     251                 :          0 :                 return -EINVAL;
     252                 :            : 
     253                 :         24 :         return unit_name_build_from_type(prefix, instance, type, ret);
     254                 :            : }
     255                 :            : 
     256                 :      74224 : 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         [ -  + ]:      74224 :         assert(prefix);
     261         [ -  + ]:      74224 :         assert(type >= 0);
     262         [ -  + ]:      74224 :         assert(type < _UNIT_TYPE_MAX);
     263         [ -  + ]:      74224 :         assert(ret);
     264                 :            : 
     265         [ -  + ]:      74224 :         if (!unit_prefix_is_valid(prefix))
     266                 :          0 :                 return -EINVAL;
     267                 :            : 
     268   [ +  +  -  + ]:      74224 :         if (instance && !unit_instance_is_valid(instance))
     269                 :          0 :                 return -EINVAL;
     270                 :            : 
     271                 :      74224 :         ut = unit_type_to_string(type);
     272                 :            : 
     273         [ +  + ]:      74224 :         if (!instance)
     274                 :      74204 :                 s = strjoin(prefix, ".", ut);
     275                 :            :         else
     276                 :         20 :                 s = strjoin(prefix, "@", instance, ".", ut);
     277         [ -  + ]:      74224 :         if (!s)
     278                 :          0 :                 return -ENOMEM;
     279                 :            : 
     280                 :      74224 :         *ret = s;
     281                 :      74224 :         return 0;
     282                 :            : }
     283                 :            : 
     284                 :      12196 : static char *do_escape_char(char c, char *t) {
     285         [ -  + ]:      12196 :         assert(t);
     286                 :            : 
     287                 :      12196 :         *(t++) = '\\';
     288                 :      12196 :         *(t++) = 'x';
     289                 :      12196 :         *(t++) = hexchar(c >> 4);
     290                 :      12196 :         *(t++) = hexchar(c);
     291                 :            : 
     292                 :      12196 :         return t;
     293                 :            : }
     294                 :            : 
     295                 :      10476 : static char *do_escape(const char *f, char *t) {
     296         [ -  + ]:      10476 :         assert(f);
     297         [ -  + ]:      10476 :         assert(t);
     298                 :            : 
     299                 :            :         /* do not create units with a leading '.', like for "/.dotdir" mount points */
     300         [ -  + ]:      10476 :         if (*f == '.') {
     301                 :          0 :                 t = do_escape_char(*f, t);
     302                 :          0 :                 f++;
     303                 :            :         }
     304                 :            : 
     305         [ +  + ]:     292864 :         for (; *f; f++) {
     306         [ +  + ]:     282388 :                 if (*f == '/')
     307                 :      25480 :                         *(t++) = '-';
     308   [ +  +  +  +  :     256908 :                 else if (IN_SET(*f, '-', '\\') || !strchr(VALID_CHARS, *f))
                   +  + ]
     309                 :      12108 :                         t = do_escape_char(*f, t);
     310                 :            :                 else
     311                 :     244800 :                         *(t++) = *f;
     312                 :            :         }
     313                 :            : 
     314                 :      10476 :         return t;
     315                 :            : }
     316                 :            : 
     317                 :      10476 : char *unit_name_escape(const char *f) {
     318                 :            :         char *r, *t;
     319                 :            : 
     320         [ -  + ]:      10476 :         assert(f);
     321                 :            : 
     322                 :      10476 :         r = new(char, strlen(f)*4+1);
     323         [ -  + ]:      10476 :         if (!r)
     324                 :          0 :                 return NULL;
     325                 :            : 
     326                 :      10476 :         t = do_escape(f, r);
     327                 :      10476 :         *t = 0;
     328                 :            : 
     329                 :      10476 :         return r;
     330                 :            : }
     331                 :            : 
     332                 :        136 : int unit_name_unescape(const char *f, char **ret) {
     333                 :        136 :         _cleanup_free_ char *r = NULL;
     334                 :            :         char *t;
     335                 :            : 
     336         [ -  + ]:        136 :         assert(f);
     337                 :            : 
     338                 :        136 :         r = strdup(f);
     339         [ -  + ]:        136 :         if (!r)
     340                 :          0 :                 return -ENOMEM;
     341                 :            : 
     342         [ +  + ]:       1100 :         for (t = r; *f; f++) {
     343         [ +  + ]:        964 :                 if (*f == '-')
     344                 :        124 :                         *(t++) = '/';
     345         [ +  + ]:        840 :                 else if (*f == '\\') {
     346                 :            :                         int a, b;
     347                 :            : 
     348         [ -  + ]:         20 :                         if (f[1] != 'x')
     349                 :          0 :                                 return -EINVAL;
     350                 :            : 
     351                 :         20 :                         a = unhexchar(f[2]);
     352         [ -  + ]:         20 :                         if (a < 0)
     353                 :          0 :                                 return -EINVAL;
     354                 :            : 
     355                 :         20 :                         b = unhexchar(f[3]);
     356         [ -  + ]:         20 :                         if (b < 0)
     357                 :          0 :                                 return -EINVAL;
     358                 :            : 
     359                 :         20 :                         *(t++) = (char) (((uint8_t) a << 4U) | (uint8_t) b);
     360                 :         20 :                         f += 3;
     361                 :            :                 } else
     362                 :        820 :                         *(t++) = *f;
     363                 :            :         }
     364                 :            : 
     365                 :        136 :         *t = 0;
     366                 :            : 
     367                 :        136 :         *ret = TAKE_PTR(r);
     368                 :            : 
     369                 :        136 :         return 0;
     370                 :            : }
     371                 :            : 
     372                 :      11592 : int unit_name_path_escape(const char *f, char **ret) {
     373                 :            :         char *p, *s;
     374                 :            : 
     375         [ -  + ]:      11592 :         assert(f);
     376         [ -  + ]:      11592 :         assert(ret);
     377                 :            : 
     378                 :      11592 :         p = strdupa(f);
     379         [ -  + ]:      11592 :         if (!p)
     380                 :          0 :                 return -ENOMEM;
     381                 :            : 
     382                 :      11592 :         path_simplify(p, false);
     383                 :            : 
     384         [ +  + ]:      11592 :         if (empty_or_root(p))
     385                 :       1108 :                 s = strdup("-");
     386                 :            :         else {
     387         [ +  + ]:      10484 :                 if (!path_is_normalized(p))
     388                 :         12 :                         return -EINVAL;
     389                 :            : 
     390                 :            :                 /* Truncate trailing slashes */
     391                 :      10472 :                 delete_trailing_chars(p, "/");
     392                 :            : 
     393                 :            :                 /* Truncate leading slashes */
     394                 :      10472 :                 p = skip_leading_chars(p, "/");
     395                 :            : 
     396                 :      10472 :                 s = unit_name_escape(p);
     397                 :            :         }
     398         [ -  + ]:      11580 :         if (!s)
     399                 :          0 :                 return -ENOMEM;
     400                 :            : 
     401                 :      11580 :         *ret = s;
     402                 :      11580 :         return 0;
     403                 :            : }
     404                 :            : 
     405                 :        132 : int unit_name_path_unescape(const char *f, char **ret) {
     406                 :        132 :         _cleanup_free_ char *s = NULL;
     407                 :            :         int r;
     408                 :            : 
     409         [ -  + ]:        132 :         assert(f);
     410                 :            : 
     411         [ +  + ]:        132 :         if (isempty(f))
     412                 :          4 :                 return -EINVAL;
     413                 :            : 
     414         [ +  + ]:        128 :         if (streq(f, "-")) {
     415                 :         28 :                 s = strdup("/");
     416         [ -  + ]:         28 :                 if (!s)
     417                 :          0 :                         return -ENOMEM;
     418                 :            :         } else {
     419         [ +  + ]:        100 :                 _cleanup_free_ char *w = NULL;
     420                 :            : 
     421                 :        100 :                 r = unit_name_unescape(f, &w);
     422         [ -  + ]:        100 :                 if (r < 0)
     423                 :          0 :                         return r;
     424                 :            : 
     425                 :            :                 /* Don't accept trailing or leading slashes */
     426   [ +  +  +  + ]:        100 :                 if (startswith(w, "/") || endswith(w, "/"))
     427                 :         24 :                         return -EINVAL;
     428                 :            : 
     429                 :            :                 /* Prefix a slash again */
     430                 :         76 :                 s = strjoin("/", w);
     431         [ -  + ]:         76 :                 if (!s)
     432                 :          0 :                         return -ENOMEM;
     433                 :            : 
     434         [ +  + ]:         76 :                 if (!path_is_normalized(s))
     435                 :         16 :                         return -EINVAL;
     436                 :            :         }
     437                 :            : 
     438         [ +  - ]:         88 :         if (ret)
     439                 :         88 :                 *ret = TAKE_PTR(s);
     440                 :            : 
     441                 :         88 :         return 0;
     442                 :            : }
     443                 :            : 
     444                 :        192 : 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         [ -  + ]:        192 :         assert(f);
     450         [ -  + ]:        192 :         assert(i);
     451         [ -  + ]:        192 :         assert(ret);
     452                 :            : 
     453         [ +  + ]:        192 :         if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
     454                 :         24 :                 return -EINVAL;
     455         [ -  + ]:        168 :         if (!unit_instance_is_valid(i))
     456                 :          0 :                 return -EINVAL;
     457                 :            : 
     458         [ -  + ]:        168 :         assert_se(p = strchr(f, '@'));
     459         [ -  + ]:        168 :         assert_se(e = strrchr(f, '.'));
     460                 :            : 
     461                 :        168 :         a = p - f;
     462                 :        168 :         b = strlen(i);
     463                 :            : 
     464                 :        168 :         s = new(char, a + 1 + b + strlen(e) + 1);
     465         [ -  + ]:        168 :         if (!s)
     466                 :          0 :                 return -ENOMEM;
     467                 :            : 
     468                 :        168 :         strcpy(mempcpy(mempcpy(s, f, a + 1), i, b), e);
     469                 :            : 
     470                 :        168 :         *ret = s;
     471                 :        168 :         return 0;
     472                 :            : }
     473                 :            : 
     474                 :        384 : int unit_name_template(const char *f, char **ret) {
     475                 :            :         const char *p, *e;
     476                 :            :         char *s;
     477                 :            :         size_t a;
     478                 :            : 
     479         [ -  + ]:        384 :         assert(f);
     480         [ -  + ]:        384 :         assert(ret);
     481                 :            : 
     482         [ +  + ]:        384 :         if (!unit_name_is_valid(f, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE))
     483                 :         48 :                 return -EINVAL;
     484                 :            : 
     485         [ -  + ]:        336 :         assert_se(p = strchr(f, '@'));
     486         [ -  + ]:        336 :         assert_se(e = strrchr(f, '.'));
     487                 :            : 
     488                 :        336 :         a = p - f;
     489                 :            : 
     490                 :        336 :         s = new(char, a + 1 + strlen(e) + 1);
     491         [ -  + ]:        336 :         if (!s)
     492                 :          0 :                 return -ENOMEM;
     493                 :            : 
     494                 :        336 :         strcpy(mempcpy(s, f, a + 1), e);
     495                 :            : 
     496                 :        336 :         *ret = s;
     497                 :        336 :         return 0;
     498                 :            : }
     499                 :            : 
     500                 :      11564 : int unit_name_from_path(const char *path, const char *suffix, char **ret) {
     501                 :      11564 :         _cleanup_free_ char *p = NULL;
     502                 :      11564 :         char *s = NULL;
     503                 :            :         int r;
     504                 :            : 
     505         [ -  + ]:      11564 :         assert(path);
     506         [ -  + ]:      11564 :         assert(suffix);
     507         [ -  + ]:      11564 :         assert(ret);
     508                 :            : 
     509         [ -  + ]:      11564 :         if (!unit_suffix_is_valid(suffix))
     510                 :          0 :                 return -EINVAL;
     511                 :            : 
     512                 :      11564 :         r = unit_name_path_escape(path, &p);
     513         [ +  + ]:      11564 :         if (r < 0)
     514                 :          8 :                 return r;
     515                 :            : 
     516                 :      11556 :         s = strjoin(p, suffix);
     517         [ -  + ]:      11556 :         if (!s)
     518                 :          0 :                 return -ENOMEM;
     519                 :            : 
     520                 :      11556 :         *ret = s;
     521                 :      11556 :         return 0;
     522                 :            : }
     523                 :            : 
     524                 :         32 : int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret) {
     525                 :         32 :         _cleanup_free_ char *p = NULL;
     526                 :            :         char *s;
     527                 :            :         int r;
     528                 :            : 
     529         [ -  + ]:         32 :         assert(prefix);
     530         [ -  + ]:         32 :         assert(path);
     531         [ -  + ]:         32 :         assert(suffix);
     532         [ -  + ]:         32 :         assert(ret);
     533                 :            : 
     534         [ -  + ]:         32 :         if (!unit_prefix_is_valid(prefix))
     535                 :          0 :                 return -EINVAL;
     536                 :            : 
     537         [ +  + ]:         32 :         if (!unit_suffix_is_valid(suffix))
     538                 :          4 :                 return -EINVAL;
     539                 :            : 
     540                 :         28 :         r = unit_name_path_escape(path, &p);
     541         [ +  + ]:         28 :         if (r < 0)
     542                 :          4 :                 return r;
     543                 :            : 
     544                 :         24 :         s = strjoin(prefix, "@", p, suffix);
     545         [ -  + ]:         24 :         if (!s)
     546                 :          0 :                 return -ENOMEM;
     547                 :            : 
     548                 :         24 :         *ret = s;
     549                 :         24 :         return 0;
     550                 :            : }
     551                 :            : 
     552                 :         64 : int unit_name_to_path(const char *name, char **ret) {
     553                 :         64 :         _cleanup_free_ char *prefix = NULL;
     554                 :            :         int r;
     555                 :            : 
     556         [ -  + ]:         64 :         assert(name);
     557                 :            : 
     558                 :         64 :         r = unit_name_to_prefix(name, &prefix);
     559         [ +  + ]:         64 :         if (r < 0)
     560                 :          8 :                 return r;
     561                 :            : 
     562                 :         56 :         return unit_name_path_unescape(prefix, ret);
     563                 :            : }
     564                 :            : 
     565                 :        396 : static bool do_escape_mangle(const char *f, bool allow_globs, char *t) {
     566                 :            :         const char *valid_chars;
     567                 :        396 :         bool mangled = false;
     568                 :            : 
     569         [ -  + ]:        396 :         assert(f);
     570         [ -  + ]:        396 :         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         [ +  + ]:        396 :         valid_chars = allow_globs ? VALID_CHARS_GLOB : VALID_CHARS_WITH_AT;
     578                 :            : 
     579         [ +  + ]:       2232 :         for (; *f; f++)
     580         [ +  + ]:       1836 :                 if (*f == '/') {
     581                 :         20 :                         *(t++) = '-';
     582                 :         20 :                         mangled = true;
     583         [ +  + ]:       1816 :                 } else if (!strchr(valid_chars, *f)) {
     584                 :         88 :                         t = do_escape_char(*f, t);
     585                 :         88 :                         mangled = true;
     586                 :            :                 } else
     587                 :       1728 :                         *(t++) = *f;
     588                 :        396 :         *t = 0;
     589                 :            : 
     590                 :        396 :         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                 :        472 : 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         [ -  + ]:        472 :         assert(name);
     606         [ -  + ]:        472 :         assert(suffix);
     607         [ -  + ]:        472 :         assert(ret);
     608                 :            : 
     609         [ +  + ]:        472 :         if (isempty(name)) /* We cannot mangle empty unit names to become valid, sorry. */
     610                 :          4 :                 return -EINVAL;
     611                 :            : 
     612         [ -  + ]:        468 :         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         [ +  + ]:        468 :         if (unit_name_is_valid(name, UNIT_NAME_ANY))
     617                 :         52 :                 goto good;
     618                 :            : 
     619                 :            :         /* Already a fully valid globbing expression? If so, no mangling is necessary either... */
     620         [ +  + ]:        416 :         if ((flags & UNIT_NAME_MANGLE_GLOB) &&
     621         [ +  + ]:         20 :             string_is_glob(name) &&
     622         [ +  + ]:         16 :             in_charset(name, VALID_CHARS_GLOB))
     623                 :         12 :                 goto good;
     624                 :            : 
     625         [ +  + ]:        404 :         if (is_device_path(name)) {
     626                 :          4 :                 r = unit_name_from_path(name, ".device", ret);
     627         [ +  - ]:          4 :                 if (r >= 0)
     628                 :          4 :                         return 1;
     629         [ #  # ]:          0 :                 if (r != -EINVAL)
     630                 :          0 :                         return r;
     631                 :            :         }
     632                 :            : 
     633         [ +  + ]:        400 :         if (path_is_absolute(name)) {
     634                 :          4 :                 r = unit_name_from_path(name, ".mount", ret);
     635         [ +  - ]:          4 :                 if (r >= 0)
     636                 :          4 :                         return 1;
     637         [ #  # ]:          0 :                 if (r != -EINVAL)
     638                 :          0 :                         return r;
     639                 :            :         }
     640                 :            : 
     641                 :        396 :         s = new(char, strlen(name) * 4 + strlen(suffix) + 1);
     642         [ -  + ]:        396 :         if (!s)
     643                 :          0 :                 return -ENOMEM;
     644                 :            : 
     645                 :        396 :         mangled = do_escape_mangle(name, flags & UNIT_NAME_MANGLE_GLOB, s);
     646         [ +  + ]:        396 :         if (mangled)
     647   [ +  +  +  - ]:         28 :                 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   [ +  +  +  +  :        396 :         if ((!(flags & UNIT_NAME_MANGLE_GLOB) || !string_is_glob(s)) && unit_name_to_type(s) < 0)
                   +  + ]
     654                 :        376 :                 strcat(s, suffix);
     655                 :            : 
     656                 :        396 :         *ret = s;
     657                 :        396 :         return 1;
     658                 :            : 
     659                 :         64 : good:
     660                 :         64 :         s = strdup(name);
     661         [ -  + ]:         64 :         if (!s)
     662                 :          0 :                 return -ENOMEM;
     663                 :            : 
     664                 :         64 :         *ret = s;
     665                 :         64 :         return 0;
     666                 :            : }
     667                 :            : 
     668                 :        208 : int slice_build_parent_slice(const char *slice, char **ret) {
     669                 :            :         char *s, *dash;
     670                 :            :         int r;
     671                 :            : 
     672         [ -  + ]:        208 :         assert(slice);
     673         [ -  + ]:        208 :         assert(ret);
     674                 :            : 
     675         [ +  + ]:        208 :         if (!slice_name_is_valid(slice))
     676                 :         48 :                 return -EINVAL;
     677                 :            : 
     678         [ +  + ]:        160 :         if (streq(slice, SPECIAL_ROOT_SLICE)) {
     679                 :         92 :                 *ret = NULL;
     680                 :         92 :                 return 0;
     681                 :            :         }
     682                 :            : 
     683                 :         68 :         s = strdup(slice);
     684         [ -  + ]:         68 :         if (!s)
     685                 :          0 :                 return -ENOMEM;
     686                 :            : 
     687                 :         68 :         dash = strrchr(s, '-');
     688         [ +  + ]:         68 :         if (dash)
     689                 :         40 :                 strcpy(dash, ".slice");
     690                 :            :         else {
     691                 :         28 :                 r = free_and_strdup(&s, SPECIAL_ROOT_SLICE);
     692         [ -  + ]:         28 :                 if (r < 0) {
     693                 :          0 :                         free(s);
     694                 :          0 :                         return r;
     695                 :            :                 }
     696                 :            :         }
     697                 :            : 
     698                 :         68 :         *ret = s;
     699                 :         68 :         return 1;
     700                 :            : }
     701                 :            : 
     702                 :         24 : int slice_build_subslice(const char *slice, const char *name, char **ret) {
     703                 :            :         char *subslice;
     704                 :            : 
     705         [ -  + ]:         24 :         assert(slice);
     706         [ -  + ]:         24 :         assert(name);
     707         [ -  + ]:         24 :         assert(ret);
     708                 :            : 
     709         [ +  + ]:         24 :         if (!slice_name_is_valid(slice))
     710                 :          8 :                 return -EINVAL;
     711                 :            : 
     712         [ -  + ]:         16 :         if (!unit_prefix_is_valid(name))
     713                 :          0 :                 return -EINVAL;
     714                 :            : 
     715         [ +  + ]:         16 :         if (streq(slice, SPECIAL_ROOT_SLICE))
     716                 :          4 :                 subslice = strjoin(name, ".slice");
     717                 :            :         else {
     718                 :            :                 char *e;
     719                 :            : 
     720         [ -  + ]:         12 :                 assert_se(e = endswith(slice, ".slice"));
     721                 :            : 
     722                 :         12 :                 subslice = new(char, (e - slice) + 1 + strlen(name) + 6 + 1);
     723         [ -  + ]:         12 :                 if (!subslice)
     724                 :          0 :                         return -ENOMEM;
     725                 :            : 
     726                 :         12 :                 stpcpy(stpcpy(stpcpy(mempcpy(subslice, slice, e - slice), "-"), name), ".slice");
     727                 :            :         }
     728                 :            : 
     729                 :         16 :         *ret = subslice;
     730                 :         16 :         return 0;
     731                 :            : }
     732                 :            : 
     733                 :        404 : bool slice_name_is_valid(const char *name) {
     734                 :            :         const char *p, *e;
     735                 :        404 :         bool dash = false;
     736                 :            : 
     737         [ +  + ]:        404 :         if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
     738                 :         96 :                 return false;
     739                 :            : 
     740         [ +  + ]:        308 :         if (streq(name, SPECIAL_ROOT_SLICE))
     741                 :        144 :                 return true;
     742                 :            : 
     743                 :        164 :         e = endswith(name, ".slice");
     744         [ +  + ]:        164 :         if (!e)
     745                 :         12 :                 return false;
     746                 :            : 
     747         [ +  + ]:       1332 :         for (p = name; p < e; p++) {
     748                 :            : 
     749         [ +  + ]:       1204 :                 if (*p == '-') {
     750                 :            : 
     751                 :            :                         /* Don't allow initial dash */
     752         [ +  + ]:        148 :                         if (p == name)
     753                 :         12 :                                 return false;
     754                 :            : 
     755                 :            :                         /* Don't allow multiple dashes */
     756         [ +  + ]:        136 :                         if (dash)
     757                 :         12 :                                 return false;
     758                 :            : 
     759                 :        124 :                         dash = true;
     760                 :            :                 } else
     761                 :       1056 :                         dash = false;
     762                 :            :         }
     763                 :            : 
     764                 :            :         /* Don't allow trailing hash */
     765         [ +  + ]:        128 :         if (dash)
     766                 :          8 :                 return false;
     767                 :            : 
     768                 :        120 :         return true;
     769                 :            : }

Generated by: LCOV version 1.14