LCOV - code coverage report
Current view: top level - basic - path-util.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 416 519 80.2 %
Date: 2019-08-23 13:36:53 Functions: 34 38 89.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 304 486 62.6 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <errno.h>
       4                 :            : #include <limits.h>
       5                 :            : #include <stdio.h>
       6                 :            : #include <stdlib.h>
       7                 :            : #include <string.h>
       8                 :            : #include <sys/stat.h>
       9                 :            : #include <unistd.h>
      10                 :            : 
      11                 :            : /* When we include libgen.h because we need dirname() we immediately
      12                 :            :  * undefine basename() since libgen.h defines it as a macro to the
      13                 :            :  * POSIX version which is really broken. We prefer GNU basename(). */
      14                 :            : #include <libgen.h>
      15                 :            : #undef basename
      16                 :            : 
      17                 :            : #include "alloc-util.h"
      18                 :            : #include "extract-word.h"
      19                 :            : #include "fs-util.h"
      20                 :            : #include "glob-util.h"
      21                 :            : #include "log.h"
      22                 :            : #include "macro.h"
      23                 :            : #include "missing.h"
      24                 :            : #include "nulstr-util.h"
      25                 :            : #include "parse-util.h"
      26                 :            : #include "path-util.h"
      27                 :            : #include "stat-util.h"
      28                 :            : #include "string-util.h"
      29                 :            : #include "strv.h"
      30                 :            : #include "time-util.h"
      31                 :            : #include "utf8.h"
      32                 :            : 
      33                 :    1666076 : bool path_is_absolute(const char *p) {
      34                 :    1666076 :         return p[0] == '/';
      35                 :            : }
      36                 :            : 
      37                 :       1040 : bool is_path(const char *p) {
      38                 :       1040 :         return !!strchr(p, '/');
      39                 :            : }
      40                 :            : 
      41                 :        284 : int path_split_and_make_absolute(const char *p, char ***ret) {
      42                 :            :         char **l;
      43                 :            :         int r;
      44                 :            : 
      45         [ -  + ]:        284 :         assert(p);
      46         [ -  + ]:        284 :         assert(ret);
      47                 :            : 
      48                 :        284 :         l = strv_split(p, ":");
      49         [ -  + ]:        284 :         if (!l)
      50                 :          0 :                 return -ENOMEM;
      51                 :            : 
      52                 :        284 :         r = path_strv_make_absolute_cwd(l);
      53         [ -  + ]:        284 :         if (r < 0) {
      54                 :          0 :                 strv_free(l);
      55                 :          0 :                 return r;
      56                 :            :         }
      57                 :            : 
      58                 :        284 :         *ret = l;
      59                 :        284 :         return r;
      60                 :            : }
      61                 :            : 
      62                 :     842956 : char *path_make_absolute(const char *p, const char *prefix) {
      63         [ -  + ]:     842956 :         assert(p);
      64                 :            : 
      65                 :            :         /* Makes every item in the list an absolute path by prepending
      66                 :            :          * the prefix, if specified and necessary */
      67                 :            : 
      68   [ +  -  -  + ]:     842956 :         if (path_is_absolute(p) || isempty(prefix))
      69                 :          0 :                 return strdup(p);
      70                 :            : 
      71                 :     842956 :         return path_join(prefix, p);
      72                 :            : }
      73                 :            : 
      74                 :          4 : int safe_getcwd(char **ret) {
      75                 :            :         char *cwd;
      76                 :            : 
      77                 :          4 :         cwd = get_current_dir_name();
      78         [ -  + ]:          4 :         if (!cwd)
      79                 :          0 :                 return negative_errno();
      80                 :            : 
      81                 :            :         /* Let's make sure the directory is really absolute, to protect us from the logic behind
      82                 :            :          * CVE-2018-1000001 */
      83         [ -  + ]:          4 :         if (cwd[0] != '/') {
      84                 :          0 :                 free(cwd);
      85                 :          0 :                 return -ENOMEDIUM;
      86                 :            :         }
      87                 :            : 
      88                 :          4 :         *ret = cwd;
      89                 :          4 :         return 0;
      90                 :            : }
      91                 :            : 
      92                 :      82876 : int path_make_absolute_cwd(const char *p, char **ret) {
      93                 :            :         char *c;
      94                 :            :         int r;
      95                 :            : 
      96         [ -  + ]:      82876 :         assert(p);
      97         [ -  + ]:      82876 :         assert(ret);
      98                 :            : 
      99                 :            :         /* Similar to path_make_absolute(), but prefixes with the
     100                 :            :          * current working directory. */
     101                 :            : 
     102         [ +  - ]:      82876 :         if (path_is_absolute(p))
     103                 :      82876 :                 c = strdup(p);
     104                 :            :         else {
     105         [ #  # ]:          0 :                 _cleanup_free_ char *cwd = NULL;
     106                 :            : 
     107                 :          0 :                 r = safe_getcwd(&cwd);
     108         [ #  # ]:          0 :                 if (r < 0)
     109                 :          0 :                         return r;
     110                 :            : 
     111                 :          0 :                 c = path_join(cwd, p);
     112                 :            :         }
     113         [ -  + ]:      82876 :         if (!c)
     114                 :          0 :                 return -ENOMEM;
     115                 :            : 
     116                 :      82876 :         *ret = c;
     117                 :      82876 :         return 0;
     118                 :            : }
     119                 :            : 
     120                 :         44 : int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
     121                 :            :         char *f, *t, *r, *p;
     122                 :         44 :         unsigned n_parents = 0;
     123                 :            : 
     124         [ -  + ]:         44 :         assert(from_dir);
     125         [ -  + ]:         44 :         assert(to_path);
     126         [ -  + ]:         44 :         assert(_r);
     127                 :            : 
     128                 :            :         /* Strips the common part, and adds ".." elements as necessary. */
     129                 :            : 
     130   [ +  +  +  + ]:         44 :         if (!path_is_absolute(from_dir) || !path_is_absolute(to_path))
     131                 :          8 :                 return -EINVAL;
     132                 :            : 
     133                 :         36 :         f = strdupa(from_dir);
     134                 :         36 :         t = strdupa(to_path);
     135                 :            : 
     136                 :         36 :         path_simplify(f, true);
     137                 :         36 :         path_simplify(t, true);
     138                 :            : 
     139                 :            :         /* Skip the common part. */
     140                 :         36 :         for (;;) {
     141                 :            :                 size_t a, b;
     142                 :            : 
     143                 :         72 :                 f += *f == '/';
     144                 :         72 :                 t += *t == '/';
     145                 :            : 
     146         [ +  + ]:         72 :                 if (!*f) {
     147         [ +  + ]:         16 :                         if (!*t)
     148                 :            :                                 /* from_dir equals to_path. */
     149                 :          8 :                                 r = strdup(".");
     150                 :            :                         else
     151                 :            :                                 /* from_dir is a parent directory of to_path. */
     152                 :          8 :                                 r = strdup(t);
     153         [ -  + ]:         16 :                         if (!r)
     154                 :          0 :                                 return -ENOMEM;
     155                 :            : 
     156                 :         16 :                         *_r = r;
     157                 :         16 :                         return 0;
     158                 :            :                 }
     159                 :            : 
     160         [ +  + ]:         56 :                 if (!*t)
     161                 :          4 :                         break;
     162                 :            : 
     163                 :         52 :                 a = strcspn(f, "/");
     164                 :         52 :                 b = strcspn(t, "/");
     165                 :            : 
     166   [ +  +  +  - ]:         52 :                 if (a != b || memcmp(f, t, a) != 0)
     167                 :            :                         break;
     168                 :            : 
     169                 :         36 :                 f += a;
     170                 :         36 :                 t += b;
     171                 :            :         }
     172                 :            : 
     173                 :            :         /* If we're here, then "from_dir" has one or more elements that need to
     174                 :            :          * be replaced with "..". */
     175                 :            : 
     176                 :            :         /* Count the number of necessary ".." elements. */
     177         [ +  + ]:         56 :         for (; *f;) {
     178                 :            :                 size_t w;
     179                 :            : 
     180                 :         40 :                 w = strcspn(f, "/");
     181                 :            : 
     182                 :            :                 /* If this includes ".." we can't do a simple series of "..", refuse */
     183   [ +  +  +  -  :         40 :                 if (w == 2 && f[0] == '.' && f[1] == '.')
                   +  - ]
     184                 :          4 :                         return -EINVAL;
     185                 :            : 
     186                 :            :                 /* Count number of elements */
     187                 :         36 :                 n_parents++;
     188                 :            : 
     189                 :         36 :                 f += w;
     190                 :         36 :                 f += *f == '/';
     191                 :            :         }
     192                 :            : 
     193                 :         16 :         r = new(char, n_parents * 3 + strlen(t) + 1);
     194         [ -  + ]:         16 :         if (!r)
     195                 :          0 :                 return -ENOMEM;
     196                 :            : 
     197         [ +  + ]:         48 :         for (p = r; n_parents > 0; n_parents--)
     198                 :         32 :                 p = mempcpy(p, "../", 3);
     199                 :            : 
     200         [ +  + ]:         16 :         if (*t)
     201                 :         12 :                 strcpy(p, t);
     202                 :            :         else
     203                 :            :                 /* Remove trailing slash */
     204                 :          4 :                 *(--p) = 0;
     205                 :            : 
     206                 :         16 :         *_r = r;
     207                 :         16 :         return 0;
     208                 :            : }
     209                 :            : 
     210                 :       4608 : char* path_startswith_strv(const char *p, char **set) {
     211                 :            :         char **s, *t;
     212                 :            : 
     213   [ +  -  +  + ]:      13316 :         STRV_FOREACH(s, set) {
     214                 :      10352 :                 t = path_startswith(p, *s);
     215         [ +  + ]:      10352 :                 if (t)
     216                 :       1644 :                         return t;
     217                 :            :         }
     218                 :            : 
     219                 :       2964 :         return NULL;
     220                 :            : }
     221                 :            : 
     222                 :        460 : int path_strv_make_absolute_cwd(char **l) {
     223                 :            :         char **s;
     224                 :            :         int r;
     225                 :            : 
     226                 :            :         /* Goes through every item in the string list and makes it
     227                 :            :          * absolute. This works in place and won't rollback any
     228                 :            :          * changes on failure. */
     229                 :            : 
     230   [ +  -  +  + ]:       2196 :         STRV_FOREACH(s, l) {
     231                 :            :                 char *t;
     232                 :            : 
     233                 :       1736 :                 r = path_make_absolute_cwd(*s, &t);
     234         [ -  + ]:       1736 :                 if (r < 0)
     235                 :          0 :                         return r;
     236                 :            : 
     237                 :       1736 :                 path_simplify(t, false);
     238                 :       1736 :                 free_and_replace(*s, t);
     239                 :            :         }
     240                 :            : 
     241                 :        460 :         return 0;
     242                 :            : }
     243                 :            : 
     244                 :       4004 : char **path_strv_resolve(char **l, const char *root) {
     245                 :            :         char **s;
     246                 :       4004 :         unsigned k = 0;
     247                 :       4004 :         bool enomem = false;
     248                 :            :         int r;
     249                 :            : 
     250         [ -  + ]:       4004 :         if (strv_isempty(l))
     251                 :          0 :                 return l;
     252                 :            : 
     253                 :            :         /* Goes through every item in the string list and canonicalize
     254                 :            :          * the path. This works in place and won't rollback any
     255                 :            :          * changes on failure. */
     256                 :            : 
     257   [ +  -  +  + ]:      52212 :         STRV_FOREACH(s, l) {
     258         [ +  - ]:      48208 :                 _cleanup_free_ char *orig = NULL;
     259                 :            :                 char *t, *u;
     260                 :            : 
     261         [ -  + ]:      48208 :                 if (!path_is_absolute(*s)) {
     262                 :          0 :                         free(*s);
     263                 :          0 :                         continue;
     264                 :            :                 }
     265                 :            : 
     266         [ +  + ]:      48208 :                 if (root) {
     267                 :        164 :                         orig = *s;
     268                 :        164 :                         t = path_join(root, orig);
     269         [ -  + ]:        164 :                         if (!t) {
     270                 :          0 :                                 enomem = true;
     271                 :          0 :                                 continue;
     272                 :            :                         }
     273                 :            :                 } else
     274                 :      48044 :                         t = *s;
     275                 :            : 
     276                 :      48208 :                 r = chase_symlinks(t, root, 0, &u);
     277         [ +  + ]:      48208 :                 if (r == -ENOENT) {
     278         [ +  + ]:      47744 :                         if (root) {
     279                 :        104 :                                 u = TAKE_PTR(orig);
     280                 :        104 :                                 free(t);
     281                 :            :                         } else
     282                 :      47640 :                                 u = t;
     283         [ -  + ]:        464 :                 } else if (r < 0) {
     284                 :          0 :                         free(t);
     285                 :            : 
     286         [ #  # ]:          0 :                         if (r == -ENOMEM)
     287                 :          0 :                                 enomem = true;
     288                 :            : 
     289                 :          0 :                         continue;
     290         [ +  + ]:        464 :                 } else if (root) {
     291                 :            :                         char *x;
     292                 :            : 
     293                 :         60 :                         free(t);
     294                 :         60 :                         x = path_startswith(u, root);
     295         [ +  - ]:         60 :                         if (x) {
     296                 :            :                                 /* restore the slash if it was lost */
     297         [ +  - ]:         60 :                                 if (!startswith(x, "/"))
     298                 :         60 :                                         *(--x) = '/';
     299                 :            : 
     300                 :         60 :                                 t = strdup(x);
     301                 :         60 :                                 free(u);
     302         [ -  + ]:         60 :                                 if (!t) {
     303                 :          0 :                                         enomem = true;
     304                 :          0 :                                         continue;
     305                 :            :                                 }
     306                 :         60 :                                 u = t;
     307                 :            :                         } else {
     308                 :            :                                 /* canonicalized path goes outside of
     309                 :            :                                  * prefix, keep the original path instead */
     310                 :          0 :                                 free_and_replace(u, orig);
     311                 :            :                         }
     312                 :            :                 } else
     313                 :        404 :                         free(t);
     314                 :            : 
     315                 :      48208 :                 l[k++] = u;
     316                 :            :         }
     317                 :            : 
     318                 :       4004 :         l[k] = NULL;
     319                 :            : 
     320         [ -  + ]:       4004 :         if (enomem)
     321                 :          0 :                 return NULL;
     322                 :            : 
     323                 :       4004 :         return l;
     324                 :            : }
     325                 :            : 
     326                 :       4004 : char **path_strv_resolve_uniq(char **l, const char *root) {
     327                 :            : 
     328         [ +  + ]:       4004 :         if (strv_isempty(l))
     329                 :          4 :                 return l;
     330                 :            : 
     331         [ -  + ]:       4000 :         if (!path_strv_resolve(l, root))
     332                 :          0 :                 return NULL;
     333                 :            : 
     334                 :       4000 :         return strv_uniq(l);
     335                 :            : }
     336                 :            : 
     337                 :      23316 : char *path_simplify(char *path, bool kill_dots) {
     338                 :            :         char *f, *t;
     339                 :      23316 :         bool slash = false, ignore_slash = false, absolute;
     340                 :            : 
     341         [ -  + ]:      23316 :         assert(path);
     342                 :            : 
     343                 :            :         /* Removes redundant inner and trailing slashes. Also removes unnecessary dots
     344                 :            :          * if kill_dots is true. Modifies the passed string in-place.
     345                 :            :          *
     346                 :            :          * ///foo//./bar/.   becomes /foo/./bar/.      (if kill_dots is false)
     347                 :            :          * ///foo//./bar/.   becomes /foo/bar          (if kill_dots is true)
     348                 :            :          * .//./foo//./bar/. becomes ././foo/./bar/.   (if kill_dots is false)
     349                 :            :          * .//./foo//./bar/. becomes foo/bar           (if kill_dots is true)
     350                 :            :          */
     351                 :            : 
     352         [ +  + ]:      23316 :         if (isempty(path))
     353                 :       1012 :                 return path;
     354                 :            : 
     355                 :      22304 :         absolute = path_is_absolute(path);
     356                 :            : 
     357                 :      22304 :         f = path;
     358   [ +  +  +  +  :      22304 :         if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/')) {
             +  +  +  + ]
     359                 :         20 :                 ignore_slash = true;
     360                 :         20 :                 f++;
     361                 :            :         }
     362                 :            : 
     363         [ +  + ]:     625182 :         for (t = path; *f; f++) {
     364                 :            : 
     365         [ +  + ]:     602878 :                 if (*f == '/') {
     366                 :      74368 :                         slash = true;
     367                 :      74368 :                         continue;
     368                 :            :                 }
     369                 :            : 
     370         [ +  + ]:     528510 :                 if (slash) {
     371   [ +  +  +  +  :      72532 :                         if (kill_dots && *f == '.' && IN_SET(f[1], 0, '/'))
             +  +  +  + ]
     372                 :        144 :                                 continue;
     373                 :            : 
     374                 :      72388 :                         slash = false;
     375         [ +  + ]:      72388 :                         if (ignore_slash)
     376                 :          4 :                                 ignore_slash = false;
     377                 :            :                         else
     378                 :      72384 :                                 *(t++) = '/';
     379                 :            :                 }
     380                 :            : 
     381                 :     528366 :                 *(t++) = *f;
     382                 :            :         }
     383                 :            : 
     384                 :            :         /* Special rule, if we stripped everything, we either need a "/" (for the root directory)
     385                 :            :          * or "." for the current directory */
     386         [ +  + ]:      22304 :         if (t == path) {
     387         [ +  + ]:        864 :                 if (absolute)
     388                 :        848 :                         *(t++) = '/';
     389                 :            :                 else
     390                 :         16 :                         *(t++) = '.';
     391                 :            :         }
     392                 :            : 
     393                 :      22304 :         *t = 0;
     394                 :      22304 :         return path;
     395                 :            : }
     396                 :            : 
     397                 :        144 : int path_simplify_and_warn(
     398                 :            :                 char *path,
     399                 :            :                 unsigned flag,
     400                 :            :                 const char *unit,
     401                 :            :                 const char *filename,
     402                 :            :                 unsigned line,
     403                 :            :                 const char *lvalue) {
     404                 :            : 
     405                 :        144 :         bool fatal = flag & PATH_CHECK_FATAL;
     406                 :            : 
     407         [ -  + ]:        144 :         assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
     408                 :            : 
     409         [ +  + ]:        144 :         if (!utf8_is_valid(path))
     410         [ +  - ]:          4 :                 return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
     411                 :            : 
     412         [ +  - ]:        140 :         if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
     413                 :            :                 bool absolute;
     414                 :            : 
     415                 :        140 :                 absolute = path_is_absolute(path);
     416                 :            : 
     417   [ +  +  +  - ]:        140 :                 if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
     418   [ +  -  -  + ]:          4 :                         return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
     419                 :            :                                           "%s= path is not absolute%s: %s",
     420                 :            :                                           lvalue, fatal ? "" : ", ignoring", path);
     421                 :            : 
     422   [ +  -  -  + ]:        136 :                 if (absolute && (flag & PATH_CHECK_RELATIVE))
     423   [ #  #  #  # ]:          0 :                         return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
     424                 :            :                                           "%s= path is absolute%s: %s",
     425                 :            :                                           lvalue, fatal ? "" : ", ignoring", path);
     426                 :            :         }
     427                 :            : 
     428                 :        136 :         path_simplify(path, true);
     429                 :            : 
     430         [ -  + ]:        136 :         if (!path_is_valid(path))
     431   [ #  #  #  # ]:          0 :                 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
     432                 :            :                                   "%s= path has invalid length (%zu bytes)%s.",
     433                 :            :                                   lvalue, strlen(path), fatal ? "" : ", ignoring");
     434                 :            : 
     435         [ -  + ]:        136 :         if (!path_is_normalized(path))
     436   [ #  #  #  # ]:          0 :                 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
     437                 :            :                                   "%s= path is not normalized%s: %s",
     438                 :            :                                   lvalue, fatal ? "" : ", ignoring", path);
     439                 :            : 
     440                 :        136 :         return 0;
     441                 :            : }
     442                 :            : 
     443                 :     325540 : char* path_startswith(const char *path, const char *prefix) {
     444         [ -  + ]:     325540 :         assert(path);
     445         [ -  + ]:     325540 :         assert(prefix);
     446                 :            : 
     447                 :            :         /* Returns a pointer to the start of the first component after the parts matched by
     448                 :            :          * the prefix, iff
     449                 :            :          * - both paths are absolute or both paths are relative,
     450                 :            :          * and
     451                 :            :          * - each component in prefix in turn matches a component in path at the same position.
     452                 :            :          * An empty string will be returned when the prefix and path are equivalent.
     453                 :            :          *
     454                 :            :          * Returns NULL otherwise.
     455                 :            :          */
     456                 :            : 
     457         [ +  + ]:     325540 :         if ((path[0] == '/') != (prefix[0] == '/'))
     458                 :       8572 :                 return NULL;
     459                 :            : 
     460                 :     289136 :         for (;;) {
     461                 :            :                 size_t a, b;
     462                 :            : 
     463                 :     606104 :                 path += strspn(path, "/");
     464                 :     606104 :                 prefix += strspn(prefix, "/");
     465                 :            : 
     466         [ +  + ]:     606104 :                 if (*prefix == 0)
     467                 :     211968 :                         return (char*) path;
     468                 :            : 
     469         [ +  + ]:     394136 :                 if (*path == 0)
     470                 :        224 :                         return NULL;
     471                 :            : 
     472                 :     393912 :                 a = strcspn(path, "/");
     473                 :     393912 :                 b = strcspn(prefix, "/");
     474                 :            : 
     475         [ +  + ]:     393912 :                 if (a != b)
     476                 :      15952 :                         return NULL;
     477                 :            : 
     478         [ +  + ]:     377960 :                 if (memcmp(path, prefix, a) != 0)
     479                 :      88824 :                         return NULL;
     480                 :            : 
     481                 :     289136 :                 path += a;
     482                 :     289136 :                 prefix += b;
     483                 :            :         }
     484                 :            : }
     485                 :            : 
     486                 :    1782688 : int path_compare(const char *a, const char *b) {
     487                 :            :         int d;
     488                 :            : 
     489         [ -  + ]:    1782688 :         assert(a);
     490         [ -  + ]:    1782688 :         assert(b);
     491                 :            : 
     492                 :            :         /* A relative path and an absolute path must not compare as equal.
     493                 :            :          * Which one is sorted before the other does not really matter.
     494                 :            :          * Here a relative path is ordered before an absolute path. */
     495                 :    1782688 :         d = (a[0] == '/') - (b[0] == '/');
     496         [ +  + ]:    1782688 :         if (d != 0)
     497                 :       1312 :                 return d;
     498                 :            : 
     499                 :     881557 :         for (;;) {
     500                 :            :                 size_t j, k;
     501                 :            : 
     502                 :    2662933 :                 a += strspn(a, "/");
     503                 :    2662933 :                 b += strspn(b, "/");
     504                 :            : 
     505   [ +  +  +  + ]:    2662933 :                 if (*a == 0 && *b == 0)
     506                 :      87026 :                         return 0;
     507                 :            : 
     508                 :            :                 /* Order prefixes first: "/foo" before "/foo/bar" */
     509         [ +  + ]:    2575907 :                 if (*a == 0)
     510                 :       2954 :                         return -1;
     511         [ +  + ]:    2572953 :                 if (*b == 0)
     512                 :     519855 :                         return 1;
     513                 :            : 
     514                 :    2053098 :                 j = strcspn(a, "/");
     515                 :    2053098 :                 k = strcspn(b, "/");
     516                 :            : 
     517                 :            :                 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
     518                 :    2053098 :                 d = memcmp(a, b, MIN(j, k));
     519         [ +  + ]:    2053098 :                 if (d != 0)
     520                 :    1119708 :                         return (d > 0) - (d < 0); /* sign of d */
     521                 :            : 
     522                 :            :                 /* Sort "/foo/a" before "/foo/aaa" */
     523                 :     933390 :                 d = (j > k) - (j < k);  /* sign of (j - k) */
     524         [ +  + ]:     933390 :                 if (d != 0)
     525                 :      51833 :                         return d;
     526                 :            : 
     527                 :     881557 :                 a += j;
     528                 :     881557 :                 b += k;
     529                 :            :         }
     530                 :            : }
     531                 :            : 
     532                 :    1631124 : bool path_equal(const char *a, const char *b) {
     533                 :    1631124 :         return path_compare(a, b) == 0;
     534                 :            : }
     535                 :            : 
     536                 :        696 : bool path_equal_or_files_same(const char *a, const char *b, int flags) {
     537   [ +  +  +  + ]:        696 :         return path_equal(a, b) || files_same(a, b, flags) > 0;
     538                 :            : }
     539                 :            : 
     540                 :    1472000 : char* path_join_internal(const char *first, ...) {
     541                 :            :         char *joined, *q;
     542                 :            :         const char *p;
     543                 :            :         va_list ap;
     544                 :            :         bool slash;
     545                 :            :         size_t sz;
     546                 :            : 
     547                 :            :         /* Joins all listed strings until the sentinel and places a "/" between them unless the strings end/begin
     548                 :            :          * already with one so that it is unnecessary. Note that slashes which are already duplicate won't be
     549                 :            :          * removed. The string returned is hence always equal to or longer than the sum of the lengths of each
     550                 :            :          * individual string.
     551                 :            :          *
     552                 :            :          * Note: any listed empty string is simply skipped. This can be useful for concatenating strings of which some
     553                 :            :          * are optional.
     554                 :            :          *
     555                 :            :          * Examples:
     556                 :            :          *
     557                 :            :          * path_join("foo", "bar") → "foo/bar"
     558                 :            :          * path_join("foo/", "bar") → "foo/bar"
     559                 :            :          * path_join("", "foo", "", "bar", "") → "foo/bar" */
     560                 :            : 
     561                 :    1472000 :         sz = strlen_ptr(first);
     562                 :    1472000 :         va_start(ap, first);
     563         [ +  + ]:    2965848 :         while ((p = va_arg(ap, char*)) != (const char*) -1)
     564         [ +  + ]:    1493848 :                 if (!isempty(p))
     565                 :    1472868 :                         sz += 1 + strlen(p);
     566                 :    1472000 :         va_end(ap);
     567                 :            : 
     568                 :    1472000 :         joined = new(char, sz + 1);
     569         [ -  + ]:    1472000 :         if (!joined)
     570                 :          0 :                 return NULL;
     571                 :            : 
     572         [ +  + ]:    1472000 :         if (!isempty(first)) {
     573                 :    1134736 :                 q = stpcpy(joined, first);
     574                 :    1134736 :                 slash = endswith(first, "/");
     575                 :            :         } else {
     576                 :            :                 /* Skip empty items */
     577                 :     337264 :                 joined[0] = 0;
     578                 :     337264 :                 q = joined;
     579                 :     337264 :                 slash = true; /* no need to generate a slash anymore */
     580                 :            :         }
     581                 :            : 
     582                 :    1472000 :         va_start(ap, first);
     583         [ +  + ]:    2965848 :         while ((p = va_arg(ap, char*)) != (const char*) -1) {
     584         [ +  + ]:    1493848 :                 if (isempty(p))
     585                 :      20980 :                         continue;
     586                 :            : 
     587   [ +  +  +  + ]:    1472868 :                 if (!slash && p[0] != '/')
     588                 :    1089224 :                         *(q++) = '/';
     589                 :            : 
     590                 :    1472868 :                 q = stpcpy(q, p);
     591                 :    1472868 :                 slash = endswith(p, "/");
     592                 :            :         }
     593                 :    1472000 :         va_end(ap);
     594                 :            : 
     595                 :    1472000 :         return joined;
     596                 :            : }
     597                 :            : 
     598                 :         40 : int find_binary(const char *name, char **ret) {
     599                 :            :         int last_error, r;
     600                 :            :         const char *p;
     601                 :            : 
     602         [ -  + ]:         40 :         assert(name);
     603                 :            : 
     604         [ +  + ]:         40 :         if (is_path(name)) {
     605         [ +  + ]:         16 :                 if (access(name, X_OK) < 0)
     606                 :          8 :                         return -errno;
     607                 :            : 
     608         [ +  - ]:          8 :                 if (ret) {
     609                 :          8 :                         r = path_make_absolute_cwd(name, ret);
     610         [ -  + ]:          8 :                         if (r < 0)
     611                 :          0 :                                 return r;
     612                 :            :                 }
     613                 :            : 
     614                 :          8 :                 return 0;
     615                 :            :         }
     616                 :            : 
     617                 :            :         /**
     618                 :            :          * Plain getenv, not secure_getenv, because we want
     619                 :            :          * to actually allow the user to pick the binary.
     620                 :            :          */
     621                 :         24 :         p = getenv("PATH");
     622         [ +  + ]:         24 :         if (!p)
     623                 :          8 :                 p = DEFAULT_PATH;
     624                 :            : 
     625                 :         24 :         last_error = -ENOENT;
     626                 :            : 
     627                 :        288 :         for (;;) {
     628   [ +  +  +  -  :        336 :                 _cleanup_free_ char *j = NULL, *element = NULL;
             +  +  +  - ]
     629                 :            : 
     630                 :        312 :                 r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
     631         [ -  + ]:        312 :                 if (r < 0)
     632                 :          0 :                         return r;
     633         [ +  + ]:        312 :                 if (r == 0)
     634                 :          8 :                         break;
     635                 :            : 
     636         [ -  + ]:        304 :                 if (!path_is_absolute(element))
     637                 :          0 :                         continue;
     638                 :            : 
     639                 :        304 :                 j = path_join(element, name);
     640         [ -  + ]:        304 :                 if (!j)
     641                 :          0 :                         return -ENOMEM;
     642                 :            : 
     643         [ +  + ]:        304 :                 if (access(j, X_OK) >= 0) {
     644                 :            :                         /* Found it! */
     645                 :            : 
     646         [ +  + ]:         16 :                         if (ret) {
     647                 :          8 :                                 *ret = path_simplify(j, false);
     648                 :          8 :                                 j = NULL;
     649                 :            :                         }
     650                 :            : 
     651                 :         16 :                         return 0;
     652                 :            :                 }
     653                 :            : 
     654                 :        288 :                 last_error = -errno;
     655                 :            :         }
     656                 :            : 
     657                 :          8 :         return last_error;
     658                 :            : }
     659                 :            : 
     660                 :          8 : bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
     661                 :          8 :         bool changed = false;
     662                 :            :         const char* const* i;
     663                 :            : 
     664         [ -  + ]:          8 :         assert(timestamp);
     665                 :            : 
     666         [ -  + ]:          8 :         if (!paths)
     667                 :          0 :                 return false;
     668                 :            : 
     669   [ +  -  +  + ]:         40 :         STRV_FOREACH(i, paths) {
     670                 :            :                 struct stat stats;
     671                 :            :                 usec_t u;
     672                 :            : 
     673         [ +  + ]:         32 :                 if (stat(*i, &stats) < 0)
     674                 :         24 :                         continue;
     675                 :            : 
     676                 :         16 :                 u = timespec_load(&stats.st_mtim);
     677                 :            : 
     678                 :            :                 /* first check */
     679         [ +  + ]:         16 :                 if (*timestamp >= u)
     680                 :          8 :                         continue;
     681                 :            : 
     682         [ -  + ]:          8 :                 log_debug("timestamp of '%s' changed", *i);
     683                 :            : 
     684                 :            :                 /* update timestamp */
     685         [ +  - ]:          8 :                 if (update) {
     686                 :          8 :                         *timestamp = u;
     687                 :          8 :                         changed = true;
     688                 :            :                 } else
     689                 :          0 :                         return true;
     690                 :            :         }
     691                 :            : 
     692                 :          8 :         return changed;
     693                 :            : }
     694                 :            : 
     695                 :         12 : static int binary_is_good(const char *binary) {
     696                 :         12 :         _cleanup_free_ char *p = NULL, *d = NULL;
     697                 :            :         int r;
     698                 :            : 
     699                 :         12 :         r = find_binary(binary, &p);
     700         [ +  + ]:         12 :         if (r == -ENOENT)
     701                 :          8 :                 return 0;
     702         [ -  + ]:          4 :         if (r < 0)
     703                 :          0 :                 return r;
     704                 :            : 
     705                 :            :         /* An fsck that is linked to /bin/true is a non-existent
     706                 :            :          * fsck */
     707                 :            : 
     708                 :          4 :         r = readlink_malloc(p, &d);
     709         [ +  - ]:          4 :         if (r == -EINVAL) /* not a symlink */
     710                 :          4 :                 return 1;
     711         [ #  # ]:          0 :         if (r < 0)
     712                 :          0 :                 return r;
     713                 :            : 
     714   [ #  #  #  #  :          0 :         return !PATH_IN_SET(d, "true"
                   #  # ]
     715                 :            :                                "/bin/true",
     716                 :            :                                "/usr/bin/true",
     717                 :            :                                "/dev/null");
     718                 :            : }
     719                 :            : 
     720                 :         12 : int fsck_exists(const char *fstype) {
     721                 :            :         const char *checker;
     722                 :            : 
     723         [ -  + ]:         12 :         assert(fstype);
     724                 :            : 
     725         [ -  + ]:         12 :         if (streq(fstype, "auto"))
     726                 :          0 :                 return -EINVAL;
     727                 :            : 
     728   [ +  +  +  -  :         60 :         checker = strjoina("fsck.", fstype);
          -  +  -  +  +  
                +  +  - ]
     729                 :         12 :         return binary_is_good(checker);
     730                 :            : }
     731                 :            : 
     732                 :          0 : int mkfs_exists(const char *fstype) {
     733                 :            :         const char *mkfs;
     734                 :            : 
     735         [ #  # ]:          0 :         assert(fstype);
     736                 :            : 
     737         [ #  # ]:          0 :         if (streq(fstype, "auto"))
     738                 :          0 :                 return -EINVAL;
     739                 :            : 
     740   [ #  #  #  #  :          0 :         mkfs = strjoina("mkfs.", fstype);
          #  #  #  #  #  
                #  #  # ]
     741                 :          0 :         return binary_is_good(mkfs);
     742                 :            : }
     743                 :            : 
     744                 :          0 : int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
     745                 :            :         char *p;
     746                 :            :         int r;
     747                 :            : 
     748                 :            :         /*
     749                 :            :          * This function is intended to be used in command line
     750                 :            :          * parsers, to handle paths that are passed in. It makes the
     751                 :            :          * path absolute, and reduces it to NULL if omitted or
     752                 :            :          * root (the latter optionally).
     753                 :            :          *
     754                 :            :          * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
     755                 :            :          * SUCCESS! Hence, do not pass in uninitialized pointers.
     756                 :            :          */
     757                 :            : 
     758         [ #  # ]:          0 :         if (isempty(path)) {
     759                 :          0 :                 *arg = mfree(*arg);
     760                 :          0 :                 return 0;
     761                 :            :         }
     762                 :            : 
     763                 :          0 :         r = path_make_absolute_cwd(path, &p);
     764         [ #  # ]:          0 :         if (r < 0)
     765         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
     766                 :            : 
     767                 :          0 :         path_simplify(p, false);
     768   [ #  #  #  # ]:          0 :         if (suppress_root && empty_or_root(p))
     769                 :          0 :                 p = mfree(p);
     770                 :            : 
     771                 :          0 :         free_and_replace(*arg, p);
     772                 :            : 
     773                 :          0 :         return 0;
     774                 :            : }
     775                 :            : 
     776                 :      57320 : char* dirname_malloc(const char *path) {
     777                 :            :         char *d, *dir, *dir2;
     778                 :            : 
     779         [ -  + ]:      57320 :         assert(path);
     780                 :            : 
     781                 :      57320 :         d = strdup(path);
     782         [ -  + ]:      57320 :         if (!d)
     783                 :          0 :                 return NULL;
     784                 :            : 
     785                 :      57320 :         dir = dirname(d);
     786         [ -  + ]:      57320 :         assert(dir);
     787                 :            : 
     788         [ +  - ]:      57320 :         if (dir == d)
     789                 :      57320 :                 return d;
     790                 :            : 
     791                 :          0 :         dir2 = strdup(dir);
     792                 :          0 :         free(d);
     793                 :            : 
     794                 :          0 :         return dir2;
     795                 :            : }
     796                 :            : 
     797                 :        280 : const char *last_path_component(const char *path) {
     798                 :            : 
     799                 :            :         /* Finds the last component of the path, preserving the optional trailing slash that signifies a directory.
     800                 :            :          *
     801                 :            :          *    a/b/c → c
     802                 :            :          *    a/b/c/ → c/
     803                 :            :          *    x → x
     804                 :            :          *    x/ → x/
     805                 :            :          *    /y → y
     806                 :            :          *    /y/ → y/
     807                 :            :          *    / → /
     808                 :            :          *    // → /
     809                 :            :          *    /foo/a → a
     810                 :            :          *    /foo/a/ → a/
     811                 :            :          *
     812                 :            :          *    Also, the empty string is mapped to itself.
     813                 :            :          *
     814                 :            :          * This is different than basename(), which returns "" when a trailing slash is present.
     815                 :            :          */
     816                 :            : 
     817                 :            :         unsigned l, k;
     818                 :            : 
     819         [ +  + ]:        280 :         if (!path)
     820                 :          4 :                 return NULL;
     821                 :            : 
     822                 :        276 :         l = k = strlen(path);
     823         [ +  + ]:        276 :         if (l == 0) /* special case — an empty string */
     824                 :          8 :                 return path;
     825                 :            : 
     826   [ +  +  +  + ]:        456 :         while (k > 0 && path[k-1] == '/')
     827                 :        188 :                 k--;
     828                 :            : 
     829         [ +  + ]:        268 :         if (k == 0) /* the root directory */
     830                 :         24 :                 return path + l - 1;
     831                 :            : 
     832   [ +  +  +  + ]:        828 :         while (k > 0 && path[k-1] != '/')
     833                 :        584 :                 k--;
     834                 :            : 
     835                 :        244 :         return path + k;
     836                 :            : }
     837                 :            : 
     838                 :        104 : int path_extract_filename(const char *p, char **ret) {
     839                 :        104 :         _cleanup_free_ char *a = NULL;
     840                 :        104 :         const char *c, *e = NULL, *q;
     841                 :            : 
     842                 :            :         /* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes
     843                 :            :          * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing slashes. */
     844                 :            : 
     845         [ +  + ]:        104 :         if (!p)
     846                 :          4 :                 return -EINVAL;
     847                 :            : 
     848                 :        100 :         c = last_path_component(p);
     849                 :            : 
     850         [ +  + ]:        300 :         for (q = c; *q != 0; q++)
     851         [ +  + ]:        200 :                 if (*q != '/')
     852                 :        100 :                         e = q + 1;
     853                 :            : 
     854         [ +  + ]:        100 :         if (!e) /* no valid character? */
     855                 :         16 :                 return -EINVAL;
     856                 :            : 
     857                 :         84 :         a = strndup(c, e - c);
     858         [ -  + ]:         84 :         if (!a)
     859                 :          0 :                 return -ENOMEM;
     860                 :            : 
     861         [ +  + ]:         84 :         if (!filename_is_valid(a))
     862                 :         48 :                 return -EINVAL;
     863                 :            : 
     864                 :         36 :         *ret = TAKE_PTR(a);
     865                 :            : 
     866                 :         36 :         return 0;
     867                 :            : }
     868                 :            : 
     869                 :       5816 : bool filename_is_valid(const char *p) {
     870                 :            :         const char *e;
     871                 :            : 
     872         [ +  + ]:       5816 :         if (isempty(p))
     873                 :          4 :                 return false;
     874                 :            : 
     875         [ +  + ]:       5812 :         if (dot_or_dot_dot(p))
     876                 :         56 :                 return false;
     877                 :            : 
     878                 :       5756 :         e = strchrnul(p, '/');
     879         [ +  + ]:       5756 :         if (*e != 0)
     880                 :         24 :                 return false;
     881                 :            : 
     882         [ +  + ]:       5732 :         if (e - p > FILENAME_MAX) /* FILENAME_MAX is counted *without* the trailing NUL byte */
     883                 :          4 :                 return false;
     884                 :            : 
     885                 :       5728 :         return true;
     886                 :            : }
     887                 :            : 
     888                 :      14156 : bool path_is_valid(const char *p) {
     889                 :            : 
     890         [ -  + ]:      14156 :         if (isempty(p))
     891                 :          0 :                 return false;
     892                 :            : 
     893         [ -  + ]:      14156 :         if (strlen(p) >= PATH_MAX) /* PATH_MAX is counted *with* the trailing NUL byte */
     894                 :          0 :                 return false;
     895                 :            : 
     896                 :      14156 :         return true;
     897                 :            : }
     898                 :            : 
     899                 :      12252 : bool path_is_normalized(const char *p) {
     900                 :            : 
     901         [ -  + ]:      12252 :         if (!path_is_valid(p))
     902                 :          0 :                 return false;
     903                 :            : 
     904         [ +  + ]:      12252 :         if (dot_or_dot_dot(p))
     905                 :          4 :                 return false;
     906                 :            : 
     907   [ +  -  +  +  :      12248 :         if (startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
                   +  + ]
     908                 :         24 :                 return false;
     909                 :            : 
     910   [ +  -  +  -  :      12224 :         if (startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
                   +  + ]
     911                 :          8 :                 return false;
     912                 :            : 
     913         [ +  + ]:      12216 :         if (strstr(p, "//"))
     914                 :          4 :                 return false;
     915                 :            : 
     916                 :      12212 :         return true;
     917                 :            : }
     918                 :            : 
     919                 :        476 : char *file_in_same_dir(const char *path, const char *filename) {
     920                 :            :         char *e, *ret;
     921                 :            :         size_t k;
     922                 :            : 
     923         [ -  + ]:        476 :         assert(path);
     924         [ -  + ]:        476 :         assert(filename);
     925                 :            : 
     926                 :            :         /* This removes the last component of path and appends
     927                 :            :          * filename, unless the latter is absolute anyway or the
     928                 :            :          * former isn't */
     929                 :            : 
     930         [ +  + ]:        476 :         if (path_is_absolute(filename))
     931                 :         44 :                 return strdup(filename);
     932                 :            : 
     933                 :        432 :         e = strrchr(path, '/');
     934         [ +  + ]:        432 :         if (!e)
     935                 :          4 :                 return strdup(filename);
     936                 :            : 
     937                 :        428 :         k = strlen(filename);
     938                 :        428 :         ret = new(char, (e + 1 - path) + k + 1);
     939         [ -  + ]:        428 :         if (!ret)
     940                 :          0 :                 return NULL;
     941                 :            : 
     942                 :        428 :         memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
     943                 :        428 :         return ret;
     944                 :            : }
     945                 :            : 
     946                 :    2777950 : bool hidden_or_backup_file(const char *filename) {
     947                 :            :         const char *p;
     948                 :            : 
     949         [ -  + ]:    2777950 :         assert(filename);
     950                 :            : 
     951         [ +  + ]:    2777950 :         if (filename[0] == '.' ||
     952         [ +  + ]:    2322022 :             streq(filename, "lost+found") ||
     953         [ +  + ]:    2322018 :             streq(filename, "aquota.user") ||
     954         [ +  + ]:    2322014 :             streq(filename, "aquota.group") ||
     955         [ +  + ]:    2322010 :             endswith(filename, "~"))
     956                 :     455944 :                 return true;
     957                 :            : 
     958                 :    2322006 :         p = strrchr(filename, '.');
     959         [ +  + ]:    2322006 :         if (!p)
     960                 :       5899 :                 return false;
     961                 :            : 
     962                 :            :         /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
     963                 :            :          * with always new suffixes and that everybody else should just adjust to that, then it really should be on
     964                 :            :          * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
     965                 :            :          * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
     966                 :            :          * string. Specifically: there's now:
     967                 :            :          *
     968                 :            :          *    The generic suffixes "~" and ".bak" for backup files
     969                 :            :          *    The generic prefix "." for hidden files
     970                 :            :          *
     971                 :            :          * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
     972                 :            :          * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
     973                 :            :          */
     974                 :            : 
     975                 :    2316107 :         return STR_IN_SET(p + 1,
     976                 :            :                           "rpmnew",
     977                 :            :                           "rpmsave",
     978                 :            :                           "rpmorig",
     979                 :            :                           "dpkg-old",
     980                 :            :                           "dpkg-new",
     981                 :            :                           "dpkg-tmp",
     982                 :            :                           "dpkg-dist",
     983                 :            :                           "dpkg-bak",
     984                 :            :                           "dpkg-backup",
     985                 :            :                           "dpkg-remove",
     986                 :            :                           "ucf-new",
     987                 :            :                           "ucf-old",
     988                 :            :                           "ucf-dist",
     989                 :            :                           "swp",
     990                 :            :                           "bak",
     991                 :            :                           "old",
     992                 :            :                           "new");
     993                 :            : }
     994                 :            : 
     995                 :       1240 : bool is_device_path(const char *path) {
     996                 :            : 
     997                 :            :         /* Returns true on paths that likely refer to a device, either by path in sysfs or to something in /dev */
     998                 :            : 
     999                 :       1240 :         return PATH_STARTSWITH_SET(path, "/dev/", "/sys/");
    1000                 :            : }
    1001                 :            : 
    1002                 :          0 : bool valid_device_node_path(const char *path) {
    1003                 :            : 
    1004                 :            :         /* Some superficial checks whether the specified path is a valid device node path, all without looking at the
    1005                 :            :          * actual device node. */
    1006                 :            : 
    1007         [ #  # ]:          0 :         if (!PATH_STARTSWITH_SET(path, "/dev/", "/run/systemd/inaccessible/"))
    1008                 :          0 :                 return false;
    1009                 :            : 
    1010         [ #  # ]:          0 :         if (endswith(path, "/")) /* can't be a device node if it ends in a slash */
    1011                 :          0 :                 return false;
    1012                 :            : 
    1013                 :          0 :         return path_is_normalized(path);
    1014                 :            : }
    1015                 :            : 
    1016                 :          0 : bool valid_device_allow_pattern(const char *path) {
    1017         [ #  # ]:          0 :         assert(path);
    1018                 :            : 
    1019                 :            :         /* Like valid_device_node_path(), but also allows full-subsystem expressions, like DeviceAllow= and DeviceDeny=
    1020                 :            :          * accept it */
    1021                 :            : 
    1022   [ #  #  #  #  :          0 :         if (STARTSWITH_SET(path, "block-", "char-"))
             #  #  #  # ]
    1023                 :          0 :                 return true;
    1024                 :            : 
    1025                 :          0 :         return valid_device_node_path(path);
    1026                 :            : }
    1027                 :            : 
    1028                 :         16 : int systemd_installation_has_version(const char *root, unsigned minimal_version) {
    1029                 :            :         const char *pattern;
    1030                 :            :         int r;
    1031                 :            : 
    1032                 :            :         /* Try to guess if systemd installation is later than the specified version. This
    1033                 :            :          * is hacky and likely to yield false negatives, particularly if the installation
    1034                 :            :          * is non-standard. False positives should be relatively rare.
    1035                 :            :          */
    1036                 :            : 
    1037   [ +  -  +  + ]:         80 :         NULSTR_FOREACH(pattern,
    1038                 :            :                        /* /lib works for systems without usr-merge, and for systems with a sane
    1039                 :            :                         * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
    1040                 :            :                         * for Gentoo which does a merge without making /lib a symlink.
    1041                 :            :                         */
    1042                 :            :                        "lib/systemd/libsystemd-shared-*.so\0"
    1043                 :            :                        "lib64/systemd/libsystemd-shared-*.so\0"
    1044                 :            :                        "usr/lib/systemd/libsystemd-shared-*.so\0"
    1045                 :            :                        "usr/lib64/systemd/libsystemd-shared-*.so\0") {
    1046                 :            : 
    1047      [ -  -  + ]:         64 :                 _cleanup_strv_free_ char **names = NULL;
    1048      [ -  -  + ]:         64 :                 _cleanup_free_ char *path = NULL;
    1049                 :            :                 char *c, **name;
    1050                 :            : 
    1051                 :         64 :                 path = path_join(root, pattern);
    1052         [ -  + ]:         64 :                 if (!path)
    1053                 :          0 :                         return -ENOMEM;
    1054                 :            : 
    1055                 :         64 :                 r = glob_extend(&names, path);
    1056         [ +  - ]:         64 :                 if (r == -ENOENT)
    1057                 :         64 :                         continue;
    1058         [ #  # ]:          0 :                 if (r < 0)
    1059                 :          0 :                         return r;
    1060                 :            : 
    1061         [ #  # ]:          0 :                 assert_se(c = endswith(path, "*.so"));
    1062                 :          0 :                 *c = '\0'; /* truncate the glob part */
    1063                 :            : 
    1064   [ #  #  #  # ]:          0 :                 STRV_FOREACH(name, names) {
    1065                 :            :                         /* This is most likely to run only once, hence let's not optimize anything. */
    1066                 :            :                         char *t, *t2;
    1067                 :            :                         unsigned version;
    1068                 :            : 
    1069                 :          0 :                         t = startswith(*name, path);
    1070         [ #  # ]:          0 :                         if (!t)
    1071                 :          0 :                                 continue;
    1072                 :            : 
    1073                 :          0 :                         t2 = endswith(t, ".so");
    1074         [ #  # ]:          0 :                         if (!t2)
    1075                 :          0 :                                 continue;
    1076                 :            : 
    1077                 :          0 :                         t2[0] = '\0'; /* truncate the suffix */
    1078                 :            : 
    1079                 :          0 :                         r = safe_atou(t, &version);
    1080         [ #  # ]:          0 :                         if (r < 0) {
    1081         [ #  # ]:          0 :                                 log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
    1082                 :          0 :                                 continue;
    1083                 :            :                         }
    1084                 :            : 
    1085   [ #  #  #  # ]:          0 :                         log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
    1086                 :            :                                   *name, version,
    1087                 :            :                                   version >= minimal_version ? "OK" : "too old");
    1088         [ #  # ]:          0 :                         if (version >= minimal_version)
    1089                 :          0 :                                 return true;
    1090                 :            :                 }
    1091                 :            :         }
    1092                 :            : 
    1093                 :         16 :         return false;
    1094                 :            : }
    1095                 :            : 
    1096                 :     194667 : bool dot_or_dot_dot(const char *path) {
    1097         [ +  + ]:     194667 :         if (!path)
    1098                 :          4 :                 return false;
    1099         [ +  + ]:     194663 :         if (path[0] != '.')
    1100                 :     193419 :                 return false;
    1101         [ +  + ]:       1244 :         if (path[1] == 0)
    1102                 :        588 :                 return true;
    1103         [ +  + ]:        656 :         if (path[1] != '.')
    1104                 :         76 :                 return false;
    1105                 :            : 
    1106                 :        580 :         return path[2] == 0;
    1107                 :            : }
    1108                 :            : 
    1109                 :     144712 : bool empty_or_root(const char *root) {
    1110                 :            : 
    1111                 :            :         /* For operations relative to some root directory, returns true if the specified root directory is redundant,
    1112                 :            :          * i.e. either / or NULL or the empty string or any equivalent. */
    1113                 :            : 
    1114         [ +  + ]:     144712 :         if (!root)
    1115                 :      81092 :                 return true;
    1116                 :            : 
    1117                 :      63620 :         return root[strspn(root, "/")] == 0;
    1118                 :            : }

Generated by: LCOV version 1.14