LCOV - code coverage report
Current view: top level - libpkg - utils.c (source / functions) Hit Total Coverage
Test: plop Lines: 359 565 63.5 %
Date: 2024-12-28 18:40:32 Functions: 27 36 75.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 114 200 57.0 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * Copyright (c) 2011-2020 Baptiste Daroussin <bapt@FreeBSD.org>
       3                 :            :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       4                 :            :  * Copyright (c) 2013 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       5                 :            :  * Copyright (c) 2023 Serenity Cyber Security, LLC
       6                 :            :  *                    Author: Gleb Popov <arrowd@FreeBSD.org>
       7                 :            :  * All rights reserved.
       8                 :            :  *
       9                 :            :  * Redistribution and use in source and binary forms, with or without
      10                 :            :  * modification, are permitted provided that the following conditions
      11                 :            :  * are met:
      12                 :            :  * 1. Redistributions of source code must retain the above copyright
      13                 :            :  *    notice, this list of conditions and the following disclaimer
      14                 :            :  *    in this position and unchanged.
      15                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      16                 :            :  *    notice, this list of conditions and the following disclaimer in the
      17                 :            :  *    documentation and/or other materials provided with the distribution.
      18                 :            :  *
      19                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      20                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      21                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      22                 :            :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      23                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      24                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      25                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      26                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      27                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      28                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29                 :            :  */
      30                 :            : 
      31                 :            : #include <pkg_config.h>
      32                 :            : 
      33                 :            : #include <sys/socket.h>
      34                 :            : #include <sys/stat.h>
      35                 :            : #include <sys/param.h>
      36                 :            : #include <stdio.h>
      37                 :            : 
      38                 :            : #include <assert.h>
      39                 :            : #include <errno.h>
      40                 :            : #include <fcntl.h>
      41                 :            : #include <stdlib.h>
      42                 :            : #include <unistd.h>
      43                 :            : #include <string.h>
      44                 :            : #include <ucl.h>
      45                 :            : #include <utlist.h>
      46                 :            : #include <ctype.h>
      47                 :            : #include <fnmatch.h>
      48                 :            : #include <paths.h>
      49                 :            : #include <float.h>
      50                 :            : #include <math.h>
      51                 :            : #include <regex.h>
      52                 :            : 
      53                 :            : #include <bsd_compat.h>
      54                 :            : 
      55                 :            : #include "pkg.h"
      56                 :            : #include "pkgvec.h"
      57                 :            : #include "private/event.h"
      58                 :            : #include "private/pkg_abi.h"
      59                 :            : #include "private/utils.h"
      60                 :            : #include "private/pkg.h"
      61                 :            : #include "xmalloc.h"
      62                 :            : #include "tllist.h"
      63                 :            : 
      64                 :            : extern struct pkg_ctx ctx;
      65                 :            : 
      66                 :            : bool
      67                 :       1192 : match_ucl_lists(const char *buf, const ucl_object_t *globs, const ucl_object_t *regexes)
      68                 :            : {
      69                 :            :         const ucl_object_t *cur;
      70                 :            :         ucl_object_iter_t it;
      71                 :            : 
      72                 :       1192 :         if (globs == NULL && regexes == NULL)
      73                 :        270 :                 return (false);
      74                 :            : 
      75                 :        922 :         if (globs != NULL) {
      76                 :        922 :                 it = NULL;
      77         [ +  + ]:        998 :                 while ((cur = ucl_iterate_object(globs, &it, true))) {
      78         [ +  + ]:         81 :                         if (fnmatch(ucl_object_tostring(cur), buf, 0) == 0)
      79                 :          5 :                                 return (true);
      80                 :            :                 }
      81                 :        917 :         }
      82                 :            : 
      83                 :        992 :         if (regexes != NULL) {
      84                 :        842 :                 it = NULL;
      85         [ +  + ]:        842 :                 while ((cur = ucl_iterate_object(regexes, &it, true))) {
      86                 :            :                         regex_t re;
      87                 :          1 :                         regcomp(&re, ucl_object_tostring(cur),
      88                 :            :                            REG_EXTENDED|REG_NOSUB);
      89         [ +  - ]:          1 :                         if (regexec(&re, buf, 0, NULL, 0) == 0) {
      90                 :          1 :                                 regfree(&re);
      91                 :          1 :                                 return (true);
      92                 :            :                         }
      93                 :          0 :                         regfree(&re);
      94                 :            :                 }
      95                 :        841 :         }
      96                 :            : 
      97                 :        917 :         return (false);
      98                 :       1193 : }
      99                 :            : 
     100                 :            : int
     101                 :        578 : pkg_mkdirs(const char *_path)
     102                 :            : {
     103                 :            :         char path[MAXPATHLEN];
     104                 :            :         char *p;
     105                 :            :         int dirfd;
     106                 :            : 
     107                 :        578 :         dirfd = open(_path, O_RDONLY|O_DIRECTORY);
     108         [ +  + ]:        578 :         if (dirfd >= 0) {
     109                 :        557 :                 close(dirfd);
     110                 :        557 :                 return EPKG_OK;
     111                 :            :         }
     112                 :            : 
     113                 :         21 :         strlcpy(path, _path, sizeof(path));
     114                 :         21 :         p = path;
     115         [ +  + ]:         38 :         while (*p == '/')
     116                 :         17 :                 p++;
     117                 :            : 
     118                 :        121 :         for (;;) {
     119                 :        121 :                 if ((p = strchr(p, '/')) != NULL)
     120                 :        100 :                         *p = '\0';
     121                 :            : 
     122                 :        116 :                 if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
     123                 :         84 :                         if (errno != EEXIST && errno != EISDIR) {
     124                 :          0 :                                 pkg_emit_errno("mkdir", path);
     125                 :          0 :                                 return (EPKG_FATAL);
     126                 :            :                         }
     127                 :            : 
     128                 :            :                 /* that was the last element of the path */
     129         [ +  + ]:        121 :                 if (p == NULL)
     130                 :         21 :                         break;
     131                 :            : 
     132                 :        100 :                 *p = '/';
     133                 :        100 :                 p++;
     134                 :            :         }
     135                 :            : 
     136                 :         21 :         return (EPKG_OK);
     137                 :        578 : }
     138                 :            : int
     139                 :        385 : file_to_bufferat(int dfd, const char *path, char **buffer, off_t *sz)
     140                 :            : {
     141                 :        385 :         int fd = -1;
     142                 :            :         struct stat st;
     143                 :        385 :         int retcode = EPKG_OK;
     144                 :            : 
     145                 :        385 :         assert(path != NULL && path[0] != '\0');
     146         [ +  - ]:        385 :         assert(buffer != NULL);
     147         [ +  - ]:        385 :         assert(sz != NULL);
     148                 :            : 
     149         [ -  + ]:        385 :         if ((fd = openat(dfd, path, O_RDONLY)) == -1) {
     150                 :          0 :                 pkg_emit_errno("openat", path);
     151                 :          0 :                 retcode = EPKG_FATAL;
     152                 :          0 :                 goto cleanup;
     153                 :            :         }
     154                 :            : 
     155         [ -  + ]:        385 :         if (fstat(fd, &st) == -1) {
     156                 :          0 :                 pkg_emit_errno("fstatat", path);
     157                 :          0 :                 retcode = EPKG_FATAL;
     158                 :          0 :                 goto cleanup;
     159                 :            :         }
     160                 :            : 
     161                 :        385 :         *buffer = xmalloc(st.st_size + 1);
     162                 :            : 
     163         [ -  + ]:        385 :         if (read(fd, *buffer, st.st_size) == -1) {
     164                 :          0 :                 pkg_emit_errno("read", path);
     165                 :          0 :                 retcode = EPKG_FATAL;
     166                 :          0 :                 goto cleanup;
     167                 :            :         }
     168                 :            : 
     169                 :            : cleanup:
     170                 :        385 :         if (fd >= 0)
     171                 :        385 :                 close(fd);
     172                 :            : 
     173         [ +  - ]:        385 :         if (retcode == EPKG_OK) {
     174                 :        385 :                 (*buffer)[st.st_size] = '\0';
     175                 :        385 :                 *sz = st.st_size;
     176                 :        385 :         } else {
     177                 :          0 :                 *buffer = NULL;
     178                 :          0 :                 *sz = -1;
     179                 :            :         }
     180                 :        385 :         return (retcode);
     181                 :            : }
     182                 :            : 
     183                 :            : int
     184                 :          4 : file_to_buffer(const char *path, char **buffer, off_t *sz)
     185                 :            : {
     186                 :          4 :         return file_to_bufferat(AT_FDCWD, path, buffer, sz);
     187                 :            : }
     188                 :            : 
     189                 :            : int
     190                 :          6 : format_exec_cmd(char **dest, const char *in, const char *prefix,
     191                 :            :     const char *plist_file, const char *line, int argc, char **argv, bool lua)
     192                 :            : {
     193                 :            :         xstring *buf;
     194                 :            :         char path[MAXPATHLEN];
     195                 :            :         char *cp;
     196                 :            :         const char *ptr;
     197                 :            :         size_t sz;
     198                 :            : 
     199                 :          6 :         buf = xstring_new();
     200                 :          6 :         cp = NULL;
     201                 :            : 
     202                 :          6 :         if (line != NULL && argv != NULL) {
     203         [ +  + ]:          6 :                 if (lua) {
     204                 :          2 :                         fprintf(buf->fp, "-- args: %s\n", line);
     205                 :          2 :                 } else {
     206                 :          4 :                         fprintf(buf->fp, "# args: %s\n", line);
     207                 :            :                 }
     208                 :          6 :         }
     209                 :            : 
     210         [ +  + ]:        185 :         while (in[0] != '\0') {
     211         [ +  + ]:        180 :                 if (in[0] != '%') {
     212                 :        172 :                         fputc(in[0], buf->fp);
     213                 :        172 :                         in++;
     214                 :        172 :                         continue;
     215                 :            :                 }
     216                 :          8 :                 in++;
     217   [ -  -  -  -  :          8 :                 switch(in[0]) {
             -  -  -  + ]
     218                 :            :                 case 'D':
     219                 :          0 :                         fprintf(buf->fp, "%s", prefix);
     220                 :          0 :                         break;
     221                 :            :                 case 'F':
     222                 :          0 :                         if (plist_file == NULL || plist_file[0] == '\0') {
     223                 :          0 :                                 pkg_emit_error("No files defined %%F couldn't "
     224                 :          0 :                                     "be expanded, ignoring %s", in);
     225                 :          0 :                                 xstring_free(buf);
     226                 :          0 :                                 return (EPKG_FATAL);
     227                 :            :                         }
     228                 :          0 :                         fprintf(buf->fp, "%s", plist_file);
     229                 :          0 :                         break;
     230                 :            :                 case 'f':
     231                 :          0 :                         if (plist_file == NULL || plist_file[0] == '\0') {
     232                 :          0 :                                 pkg_emit_error("No files defined %%f couldn't "
     233                 :          0 :                                     "be expanded, ignoring %s", in);
     234                 :          0 :                                 xstring_free(buf);
     235                 :          0 :                                 return (EPKG_FATAL);
     236                 :            :                         }
     237                 :          0 :                         ptr = strrchr(plist_file, '/');
     238         [ #  # ]:          0 :                         if (ptr != NULL)
     239                 :          0 :                                 ptr++;
     240                 :            :                         else
     241                 :          0 :                                 ptr = plist_file;
     242                 :          0 :                         fprintf(buf->fp, "%s", ptr);
     243                 :          0 :                         break;
     244                 :            :                 case 'B':
     245                 :          0 :                         if (plist_file == NULL || plist_file[0] == '\0') {
     246                 :          0 :                                 pkg_emit_error("No files defined %%B couldn't "
     247                 :          0 :                                     "be expanded, ignoring %s", in);
     248                 :          0 :                                 xstring_free(buf);
     249                 :          0 :                                 return (EPKG_FATAL);
     250                 :            :                         }
     251         [ #  # ]:          0 :                         if (prefix[strlen(prefix) - 1] == '/')
     252                 :          0 :                                 snprintf(path, sizeof(path), "%s%s", prefix,
     253                 :          0 :                                     plist_file);
     254                 :            :                         else
     255                 :          0 :                                 snprintf(path, sizeof(path), "%s/%s", prefix,
     256                 :          0 :                                     plist_file);
     257                 :          0 :                         cp = strrchr(path, '/');
     258                 :          0 :                         cp[0] = '\0';
     259                 :          0 :                         fprintf(buf->fp, "%s", path);
     260                 :          0 :                         break;
     261                 :            :                 case '%':
     262                 :          0 :                         fputc('%', buf->fp);
     263                 :          0 :                         break;
     264                 :            :                 case '@':
     265         [ #  # ]:          0 :                         if (line != NULL) {
     266                 :          0 :                                 fprintf(buf->fp, "%s", line);
     267                 :          0 :                                 break;
     268                 :            :                         }
     269                 :            : 
     270                 :            :                         /*
     271                 :            :                          * no break here because if line is not
     272                 :            :                          * given (default exec) %@ does not
     273                 :            :                          * exists
     274                 :            :                          */
     275                 :            :                         /* FALLTHRU */
     276                 :            :                 case '#':
     277                 :          0 :                         fprintf(buf->fp, "%d", argc);
     278                 :          0 :                         break;
     279                 :            :                 default:
     280         [ +  - ]:          8 :                         if ((sz = strspn(in, "0123456789")) > 0) {
     281                 :          8 :                                 int pos = strtol(in, NULL, 10);
     282         [ +  + ]:          8 :                                 if (pos > argc) {
     283                 :          1 :                                         pkg_emit_error("Requesting argument "
     284                 :            :                                             "%%%d while only %d arguments are"
     285                 :          1 :                                             " available", pos, argc);
     286                 :          1 :                                         xstring_free(buf);
     287                 :          1 :                                         return (EPKG_FATAL);
     288                 :            :                                 }
     289                 :          7 :                                 fprintf(buf->fp, "%s", argv[pos -1]);
     290                 :          7 :                                 in += sz -1;
     291                 :          7 :                                 break;
     292                 :            :                         }
     293                 :          0 :                         fprintf(buf->fp, "%c%c", '%', in[0]);
     294                 :          0 :                         break;
     295                 :            :                 }
     296                 :            : 
     297                 :          7 :                 in++;
     298                 :            :         }
     299                 :            : 
     300                 :          5 :         *dest = xstring_get(buf);
     301                 :            : 
     302                 :          5 :         return (EPKG_OK);
     303                 :          6 : }
     304                 :            : 
     305                 :            : int
     306                 :        150 : is_dir(const char *path)
     307                 :            : {
     308                 :            :         struct stat st;
     309                 :            : 
     310                 :        150 :         return (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
     311                 :            : }
     312                 :            : 
     313                 :            : int
     314                 :          0 : is_link(const char *path)
     315                 :            : {
     316                 :            :         struct stat st;
     317                 :            : 
     318                 :          0 :         return (lstat(path, &st) == 0 && S_ISLNK(st.st_mode));
     319                 :            : }
     320                 :            : 
     321                 :            : bool
     322                 :         20 : check_for_hardlink(hardlinks_t *hl, struct stat *st)
     323                 :            : {
     324                 :            :         struct hardlink *h;
     325                 :            : 
     326   [ +  +  +  +  :         20 :         tll_foreach(*hl, it) {
                   #  # ]
     327                 :         10 :                 if (it->item->ino == st->st_ino &&
     328                 :         10 :                     it->item->dev == st->st_dev)
     329                 :         10 :                         return (true);
     330                 :          0 :         }
     331                 :         10 :         h = xcalloc(1, sizeof(*h));
     332                 :         10 :         h->ino = st->st_ino;
     333                 :         10 :         h->dev = st->st_dev;
     334         [ -  + ]:         10 :         tll_push_back(*hl, h);
     335                 :            : 
     336                 :         10 :         return (false);
     337                 :         20 : }
     338                 :            : 
     339                 :            : /*
     340                 :            :  * ABI validation:
     341                 :            :  * - lowest match (case insensitive)
     342                 :            :  * - glob matching
     343                 :            :  *
     344                 :            :  * A package which is valid for installation on any FreeBSD now simply has
     345                 :            :  * to define itself as: abi: "FreeBSD" or "FreeBSD:*"
     346                 :            :  * A package which is valid for installation on any FreeBSD 15 regarless of
     347                 :            :  * the arch
     348                 :            :  * abi: "FreeBSD:15" or "FreeBSD:15:*"
     349                 :            :  *
     350                 :            :  */
     351                 :            : 
     352                 :            : bool
     353                 :        167 : is_valid_abi(const char *testabi, bool emit_error)
     354                 :            : {
     355                 :        167 :         const char *abi = pkg_object_string(pkg_config_get("ABI"));
     356                 :            : 
     357                 :        167 :         if (strncasecmp(testabi, abi, strlen(testabi)) != 0 &&
     358                 :         45 :             fnmatch(testabi, abi, FNM_CASEFOLD) == FNM_NOMATCH) {
     359                 :          0 :                 if (emit_error)
     360                 :          0 :                         pkg_emit_error("wrong architecture: %s instead of %s",
     361                 :          0 :                             testabi, abi);
     362                 :          0 :                 return (false);
     363                 :            :         }
     364                 :            : 
     365                 :        167 :         return (true);
     366                 :        167 : }
     367                 :            : 
     368                 :            : bool
     369                 :        167 : is_valid_os_version(struct pkg *pkg)
     370                 :            : {
     371         [ -  + ]:        167 :         if (ctx.abi.os != PKG_OS_FREEBSD)
     372                 :          0 :                 return (true);
     373                 :            :         const char *fbsd_version;
     374                 :        167 :         const char *errstr = NULL;
     375                 :            :         char query_buf[512];
     376                 :            :         /* -1: not checked, 0: not allowed, 1: allowed */
     377                 :            :         static int osver_mismatch_allowed = -1;
     378                 :            :         bool ret;
     379                 :            : 
     380         [ -  + ]:        167 :         if (pkg_object_bool(pkg_config_get("IGNORE_OSVERSION")))
     381                 :          0 :                 return (true);
     382                 :        167 :         if ((fbsd_version = pkg_kv_get(&pkg->annotations, "FreeBSD_version")) != NULL) {
     383                 :        122 :                 int pkg_osversion = strtonum(fbsd_version, 1, INT_MAX, &errstr);
     384         [ -  + ]:        122 :                 if (errstr != NULL) {
     385                 :          0 :                         pkg_emit_error("Invalid FreeBSD version %s for package %s",
     386                 :          0 :                             fbsd_version, pkg->name);
     387                 :          0 :                         return (false);
     388                 :            :                 }
     389                 :        122 :                 int abi_osversion = pkg_abi_get_freebsd_osversion(&ctx.abi);
     390         [ -  + ]:        122 :                 if (pkg_osversion > abi_osversion) {
     391         [ #  # ]:          0 :                         if (pkg_osversion - abi_osversion < 100000) {
     392                 :            :                                 /* Negligible difference, ask user to enforce */
     393                 :          0 :                                 if (osver_mismatch_allowed == -1) {
     394                 :          0 :                                         snprintf(query_buf, sizeof(query_buf),
     395                 :            :                                                         "Newer FreeBSD version for package %s:\n"
     396                 :            :                                                         "To ignore this error set IGNORE_OSVERSION=yes\n"
     397                 :            :                                                         "- package: %d\n"
     398                 :            :                                                         "- running userland: %d\n"
     399                 :          0 :                                                         "Ignore the mismatch and continue? ", pkg->name,
     400                 :          0 :                                                         pkg_osversion, abi_osversion);
     401                 :          0 :                                         ret = pkg_emit_query_yesno(false, query_buf);
     402                 :          0 :                                         osver_mismatch_allowed = ret;
     403                 :          0 :                                 }
     404                 :            : 
     405                 :          0 :                                 return (osver_mismatch_allowed);
     406                 :            :                         }
     407                 :            :                         else {
     408                 :          0 :                                 pkg_emit_error("Newer FreeBSD version for package %s:\n"
     409                 :            :                                         "To ignore this error set IGNORE_OSVERSION=yes\n"
     410                 :            :                                         "- package: %d\n"
     411                 :            :                                         "- running kernel: %d\n",
     412                 :          0 :                                         pkg->name,
     413                 :          0 :                                         pkg_osversion, abi_osversion);
     414                 :          0 :                                 return (false);
     415                 :            :                         }
     416                 :            :                 }
     417                 :        122 :         }
     418                 :        167 :         return (true);
     419                 :        167 : }
     420                 :            : 
     421                 :            : void
     422                 :          0 : set_nonblocking(int fd)
     423                 :            : {
     424                 :            :         int flags;
     425                 :            : 
     426         [ #  # ]:          0 :         if ((flags = fcntl(fd, F_GETFL)) == -1)
     427                 :          0 :                 return;
     428                 :          0 :         if (!(flags & O_NONBLOCK)) {
     429                 :          0 :                 flags |= O_NONBLOCK;
     430                 :          0 :                 fcntl(fd, F_SETFL, flags);
     431                 :          0 :         }
     432                 :          0 : }
     433                 :            : 
     434                 :            : void
     435                 :          0 : set_blocking(int fd)
     436                 :            : {
     437                 :            :         int flags;
     438                 :            : 
     439         [ #  # ]:          0 :         if ((flags = fcntl(fd, F_GETFL)) == -1)
     440                 :          0 :                 return;
     441                 :          0 :         if (flags & O_NONBLOCK) {
     442                 :          0 :                 flags &= ~O_NONBLOCK;
     443                 :          0 :                 fcntl(fd, F_SETFL, flags);
     444                 :          0 :         }
     445                 :          0 : }
     446                 :            : 
     447                 :            : /* Spawn a process from pfunc, returning it's pid. The fds array passed will
     448                 :            :  * be filled with two descriptors: fds[0] will read from the child process,
     449                 :            :  * and fds[1] will write to it.
     450                 :            :  * Similarly, the child process will receive a reading/writing fd set (in
     451                 :            :  * that same order) as arguments.
     452                 :            : */
     453                 :            : extern char **environ;
     454                 :            : pid_t
     455                 :          6 : process_spawn_pipe(FILE *inout[2], const char *command)
     456                 :            : {
     457                 :            :         pid_t pid;
     458                 :            :         int pipes[4];
     459                 :            :         char *argv[4];
     460                 :            : 
     461                 :            :         /* Parent read/child write pipe */
     462         [ -  + ]:          6 :         if (pipe(&pipes[0]) == -1)
     463                 :          0 :                 return (-1);
     464                 :            : 
     465                 :            :         /* Child read/parent write pipe */
     466         [ -  + ]:          6 :         if (pipe(&pipes[2]) == -1) {
     467                 :          0 :                 close(pipes[0]);
     468                 :          0 :                 close(pipes[1]);
     469                 :          0 :                 return (-1);
     470                 :            :         }
     471                 :            : 
     472                 :          6 :         argv[0] = __DECONST(char *, "sh");
     473                 :          6 :         argv[1] = __DECONST(char *, "-c");
     474                 :          6 :         argv[2] = __DECONST(char *, command);
     475                 :          6 :         argv[3] = NULL;
     476                 :            : 
     477                 :          6 :         pid = fork();
     478         [ +  + ]:          6 :         if (pid > 0) {
     479                 :            :                 /* Parent process */
     480                 :          6 :                 inout[0] = fdopen(pipes[0], "r");
     481                 :          6 :                 inout[1] = fdopen(pipes[3], "w");
     482                 :            : 
     483                 :          6 :                 close(pipes[1]);
     484                 :          6 :                 close(pipes[2]);
     485                 :            : 
     486                 :          6 :                 return (pid);
     487                 :            : 
     488         [ +  - ]:          6 :         } else if (pid == 0) {
     489                 :          6 :                 close(pipes[0]);
     490                 :          6 :                 close(pipes[3]);
     491                 :            : 
     492                 :          6 :                 if (pipes[1] != STDOUT_FILENO) {
     493                 :          6 :                         dup2(pipes[1], STDOUT_FILENO);
     494                 :          6 :                         close(pipes[1]);
     495                 :          6 :                 }
     496                 :          6 :                 if (pipes[2] != STDIN_FILENO) {
     497                 :          6 :                         dup2(pipes[2], STDIN_FILENO);
     498                 :          6 :                         close(pipes[2]);
     499                 :          6 :                 }
     500                 :         12 :                 closefrom(STDERR_FILENO + 1);
     501                 :            : 
     502                 :         12 :                 execve(_PATH_BSHELL, argv, environ);
     503                 :            : 
     504                 :          0 :                 _exit(127);
     505                 :            :         }
     506                 :            : 
     507                 :          0 :         return (-1); /* ? */
     508                 :          6 : }
     509                 :            : 
     510                 :            : static int
     511                 :          0 : ucl_buf_append_character(unsigned char c, size_t len, void *data)
     512                 :            : {
     513                 :          0 :         xstring *buf = data;
     514                 :            :         size_t i;
     515                 :            : 
     516         [ #  # ]:          0 :         for (i = 0; i < len; i++)
     517                 :          0 :                 fprintf(buf->fp, "%c", c);
     518                 :            : 
     519                 :          0 :         return (0);
     520                 :            : }
     521                 :            : 
     522                 :            : static int
     523                 :          0 : ucl_buf_append_len(const unsigned char *str, size_t len, void *data)
     524                 :            : {
     525                 :          0 :         xstring *buf = data;
     526                 :            : 
     527                 :          0 :         fprintf(buf->fp, "%.*s", (int)len, str);
     528                 :            : 
     529                 :          0 :         return (0);
     530                 :            : }
     531                 :            : 
     532                 :            : static int
     533                 :          0 : ucl_buf_append_int(int64_t val, void *data)
     534                 :            : {
     535                 :          0 :         xstring *buf = data;
     536                 :            : 
     537                 :          0 :         fprintf(buf->fp, "%"PRId64, val);
     538                 :            : 
     539                 :          0 :         return (0);
     540                 :            : }
     541                 :            : 
     542                 :            : static int
     543                 :          0 : ucl_buf_append_double(double val, void *data)
     544                 :            : {
     545                 :          0 :         xstring *buf = data;
     546                 :          0 :         const double delta = 0.0000001;
     547                 :            : 
     548         [ #  # ]:          0 :         if (val == (double)(int)val) {
     549                 :          0 :                 fprintf(buf->fp, "%.1lf", val);
     550         [ #  # ]:          0 :         } else if (fabs(val - (double)(int)val) < delta) {
     551                 :          0 :                 fprintf(buf->fp, "%.*lg", DBL_DIG, val);
     552                 :          0 :         } else {
     553                 :          0 :                 fprintf(buf->fp, "%lf", val);
     554                 :            :         }
     555                 :            : 
     556                 :          0 :         return (0);
     557                 :            : }
     558                 :            : 
     559                 :            : bool
     560                 :        258 : ucl_object_emit_file(const ucl_object_t *obj, enum ucl_emitter emit_type,
     561                 :            :     FILE *out)
     562                 :            : {
     563                 :        258 :         struct ucl_emitter_functions *f = ucl_object_emit_file_funcs(out);
     564                 :        258 :         bool ret = false;
     565                 :            : 
     566         [ -  + ]:        258 :         if (obj == NULL)
     567                 :          0 :                 return (false);
     568                 :            : 
     569                 :        258 :         ret = ucl_object_emit_full(obj, emit_type, f, NULL);
     570                 :        258 :         ucl_object_emit_funcs_free(f);
     571                 :            : 
     572                 :        258 :         return (ret);
     573                 :        258 : }
     574                 :            : 
     575                 :            : bool
     576                 :        294 : ucl_object_emit_fd(const ucl_object_t *obj, enum ucl_emitter emit_type, int fd)
     577                 :            : {
     578                 :        294 :         struct ucl_emitter_functions *f = ucl_object_emit_fd_funcs(fd);
     579                 :        294 :         bool ret = false;
     580                 :            : 
     581         [ -  + ]:        294 :         if (obj == NULL)
     582                 :          0 :                 return (false);
     583                 :        294 :         ret = ucl_object_emit_full(obj, emit_type, f, NULL);
     584                 :        294 :         ucl_object_emit_funcs_free(f);
     585                 :            : 
     586                 :        294 :         return (ret);
     587                 :        294 : }
     588                 :            : 
     589                 :            : 
     590                 :            : bool
     591                 :          0 : ucl_object_emit_buf(const ucl_object_t *obj, enum ucl_emitter emit_type,
     592                 :            :                      xstring **buf)
     593                 :            : {
     594                 :          0 :         bool ret = false;
     595                 :          0 :         struct ucl_emitter_functions func = {
     596                 :            :                 .ucl_emitter_append_character = ucl_buf_append_character,
     597                 :            :                 .ucl_emitter_append_len = ucl_buf_append_len,
     598                 :            :                 .ucl_emitter_append_int = ucl_buf_append_int,
     599                 :            :                 .ucl_emitter_append_double = ucl_buf_append_double
     600                 :            :         };
     601                 :            : 
     602         [ #  # ]:          0 :         xstring_renew(*buf);
     603                 :            : 
     604                 :          0 :         func.ud = *buf;
     605                 :            : 
     606                 :          0 :         ret = ucl_object_emit_full(obj, emit_type, &func, NULL);
     607                 :            : 
     608                 :          0 :         return (ret);
     609                 :            : }
     610                 :            : 
     611                 :            : /* A bit like strsep(), except it accounts for "double" and 'single'
     612                 :            :    quotes.  Unlike strsep(), returns the next arg string, trimmed of
     613                 :            :    whitespace or enclosing quotes, and updates **args to point at the
     614                 :            :    character after that.  Sets *args to NULL when it has been
     615                 :            :    completely consumed.  Quoted strings run from the first encountered
     616                 :            :    quotemark to the next one of the same type or the terminating NULL.
     617                 :            :    Quoted strings can contain the /other/ type of quote mark, which
     618                 :            :    loses any special significance.  There isn't an escape
     619                 :            :    character. */
     620                 :            : 
     621                 :            : enum parse_states {
     622                 :            :         START,
     623                 :            :         ORDINARY_TEXT,
     624                 :            :         OPEN_SINGLE_QUOTES,
     625                 :            :         IN_SINGLE_QUOTES,
     626                 :            :         OPEN_DOUBLE_QUOTES,
     627                 :            :         IN_DOUBLE_QUOTES,
     628                 :            : };
     629                 :            : 
     630                 :            : char *
     631                 :         41 : pkg_utils_tokenize(char **args)
     632                 :            : {
     633                 :            :         char                    *p, *p_start;
     634                 :         41 :         enum parse_states        parse_state = START;
     635                 :            : 
     636         [ +  - ]:         41 :         assert(*args != NULL);
     637                 :            : 
     638         [ +  + ]:        108 :         for (p = p_start = *args; *p != '\0'; p++) {
     639   [ +  +  -  -  :         91 :                 switch (parse_state) {
                   -  - ]
     640                 :            :                 case START:
     641         [ +  - ]:         41 :                         if (!isspace(*p)) {
     642         [ -  + ]:         41 :                                 if (*p == '"')
     643                 :          0 :                                         parse_state = OPEN_DOUBLE_QUOTES;
     644         [ -  + ]:         41 :                                 else if (*p == '\'')
     645                 :          0 :                                         parse_state = OPEN_SINGLE_QUOTES;
     646                 :            :                                 else {
     647                 :         41 :                                         parse_state = ORDINARY_TEXT;
     648                 :         41 :                                         p_start = p;
     649                 :            :                                 }
     650                 :         41 :                         } else
     651                 :          0 :                                 p_start = p;
     652                 :         41 :                         break;
     653                 :            :                 case ORDINARY_TEXT:
     654         [ +  + ]:         50 :                         if (isspace(*p))
     655                 :         24 :                                 goto finish;
     656                 :         26 :                         break;
     657                 :            :                 case OPEN_SINGLE_QUOTES:
     658                 :          0 :                         p_start = p;
     659         [ #  # ]:          0 :                         if (*p == '\'')
     660                 :          0 :                                 goto finish;
     661                 :            : 
     662                 :          0 :                         parse_state = IN_SINGLE_QUOTES;
     663                 :          0 :                         break;
     664                 :            :                 case IN_SINGLE_QUOTES:
     665         [ #  # ]:          0 :                         if (*p == '\'')
     666                 :          0 :                                 goto finish;
     667                 :          0 :                         break;
     668                 :            :                 case OPEN_DOUBLE_QUOTES:
     669                 :          0 :                         p_start = p;
     670         [ #  # ]:          0 :                         if (*p == '"')
     671                 :          0 :                                 goto finish;
     672                 :          0 :                         parse_state = IN_DOUBLE_QUOTES;
     673                 :          0 :                         break;
     674                 :            :                 case IN_DOUBLE_QUOTES:
     675         [ #  # ]:          0 :                         if (*p == '"')
     676                 :          0 :                                 goto finish;
     677                 :          0 :                         break;
     678                 :            :                 }
     679                 :         84 :         }
     680                 :            : 
     681                 :            : finish:
     682         [ +  + ]:         41 :         if (*p == '\0')
     683                 :         17 :                 *args = NULL;   /* All done */
     684                 :            :         else {
     685                 :         24 :                 *p = '\0';
     686                 :         24 :                 p++;
     687                 :         24 :                 if (*p == '\0' || parse_state == START)
     688                 :          0 :                         *args = NULL; /* whitespace or nothing left */
     689                 :            :                 else
     690                 :         24 :                         *args = p;
     691                 :            :         }
     692                 :         41 :         return (p_start);
     693                 :            : }
     694                 :            : 
     695                 :            : int
     696                 :         17 : pkg_utils_count_spaces(const char *args)
     697                 :            : {
     698                 :            :         int             spaces;
     699                 :            :         const char      *p;
     700                 :            : 
     701         [ +  + ]:        108 :         for (spaces = 0, p = args; *p != '\0'; p++)
     702                 :        115 :                 if (isspace(*p))
     703                 :         24 :                         spaces++;
     704                 :            : 
     705                 :         17 :         return (spaces);
     706                 :            : }
     707                 :            : 
     708                 :            : /* unlike realpath(3), this routine does not expand symbolic links */
     709                 :            : char *
     710                 :       1057 : pkg_absolutepath(const char *src, char *dest, size_t dest_size, bool fromroot) {
     711                 :            :         size_t dest_len, src_len, cur_len;
     712                 :            :         const char *cur, *next;
     713                 :            : 
     714                 :       1057 :         src_len = strlen(src);
     715                 :       1057 :         memset(dest, '\0', dest_size);
     716                 :            : 
     717                 :       1057 :         if (src_len != 0 && src[0] != '/') {
     718         [ #  # ]:          0 :                 if (fromroot)
     719                 :          0 :                         *dest = '/';
     720                 :            :                 /* relative path, we use cwd */
     721         [ #  # ]:          0 :                 else if (getcwd(dest, dest_size) == NULL)
     722                 :          0 :                         return (NULL);
     723                 :          0 :         }
     724                 :       1057 :         dest_len = strlen(dest);
     725                 :            : 
     726   [ +  +  +  + ]:       6867 :         for (cur = next = src; next != NULL; cur = (next == NULL) ? NULL : next + 1) {
     727                 :       5810 :                 next = strchr(cur, '/');
     728         [ +  + ]:       5810 :                 if (next != NULL)
     729                 :       4753 :                         cur_len = next - cur;
     730                 :            :                 else
     731                 :       1057 :                         cur_len = strlen(cur);
     732                 :            : 
     733                 :            :                 /* check for special cases "", "." and ".." */
     734         [ +  + ]:       5810 :                 if (cur_len == 0)
     735                 :       1087 :                         continue;
     736                 :       4723 :                 else if (cur_len == 1 && cur[0] == '.')
     737                 :          0 :                         continue;
     738                 :         24 :                 else if (cur_len == 2 && cur[0] == '.' && cur[1] == '.') {
     739                 :          0 :                         const char *slash = strrchr(dest, '/');
     740                 :          0 :                         if (slash != NULL) {
     741                 :          0 :                                 dest_len = slash - dest;
     742                 :          0 :                                 dest[dest_len] = '\0';
     743                 :          0 :                         }
     744                 :          0 :                         continue;
     745                 :            :                 }
     746                 :            : 
     747         [ -  + ]:       4723 :                 if (dest_len + 1 + cur_len >= dest_size)
     748                 :          0 :                         return (NULL);
     749                 :       4723 :                 dest[dest_len++] = '/';
     750                 :       4723 :                 (void)memcpy(dest + dest_len, cur, cur_len);
     751                 :       4723 :                 dest_len += cur_len;
     752                 :       4723 :                 dest[dest_len] = '\0';
     753                 :       4723 :         }
     754                 :            : 
     755                 :       1057 :         if (dest_len == 0) {
     756         [ #  # ]:          0 :                 if (strlcpy(dest, "/", dest_size) >= dest_size)
     757                 :          0 :                         return (NULL);
     758                 :          0 :         }
     759                 :            : 
     760                 :       1057 :         return (dest);
     761                 :       1057 : }
     762                 :            : 
     763                 :            : bool
     764                 :         35 : mkdirat_p(int fd, const char *path)
     765                 :            : {
     766                 :            :         const char *next;
     767                 :            :         char *walk, *walkorig, pathdone[MAXPATHLEN];
     768                 :            : 
     769                 :         35 :         walk = walkorig = xstrdup(path);
     770                 :         35 :         pathdone[0] = '\0';
     771                 :            : 
     772         [ +  + ]:        148 :         while ((next = strsep(&walk, "/")) != NULL) {
     773         [ +  + ]:        113 :                 if (*next == '\0')
     774                 :          1 :                         continue;
     775                 :        112 :                 strlcat(pathdone, next, sizeof(pathdone));
     776         [ +  + ]:        112 :                 if (mkdirat(fd, pathdone, 0755) == -1) {
     777         [ +  - ]:         19 :                         if (errno == EEXIST) {
     778                 :         19 :                                 strlcat(pathdone, "/", sizeof(pathdone));
     779                 :         19 :                                 continue;
     780                 :            :                         }
     781                 :          0 :                         pkg_errno("Fail to create /%s", pathdone);
     782                 :          0 :                         free(walkorig);
     783                 :          0 :                         return (false);
     784                 :            :                 }
     785                 :         93 :                 strlcat(pathdone, "/", sizeof(pathdone));
     786                 :            :         }
     787                 :         35 :         free(walkorig);
     788                 :         35 :         return (true);
     789                 :         35 : }
     790                 :            : 
     791                 :            : int
     792                 :         58 : pkg_namecmp(struct pkg *a, struct pkg *b)
     793                 :            : {
     794                 :            : 
     795                 :         58 :         return (strcmp(a->name, b->name));
     796                 :            : }
     797                 :            : 
     798                 :            : int
     799                 :         46 : get_socketpair(int *pipe)
     800                 :            : {
     801                 :            :         int r;
     802                 :            : 
     803                 :            : #ifdef HAVE_DECL_SOCK_SEQPACKET
     804                 :         46 :         r = socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, pipe);
     805                 :         46 :         if (r == -1) {
     806                 :          0 :                 r = socketpair(AF_LOCAL, SOCK_DGRAM, 0, pipe);
     807                 :          0 :         }
     808                 :            : #else
     809                 :            :         r = socketpair(AF_LOCAL, SOCK_DGRAM, 0, pipe);
     810                 :            : #endif
     811                 :            : 
     812                 :         46 :         return (r);
     813                 :            : }
     814                 :            : 
     815                 :            : /*
     816                 :            :  * Modify the passed C-String by stripping off the last component delimited by '/'.
     817                 :            :  * Return the string. Return a constant "." when passed NULL or the empty string.
     818                 :            :  * FIXME: This routine corrupts memory when passed the empty string.
     819                 :            :  * FIXME: This routine should propagate NULL.
     820                 :            :  * TODO: Refactor at call sites.
     821                 :            :  */
     822                 :            : char *
     823                 :         39 : get_dirname(char *d)
     824                 :            : {
     825                 :            :         char *walk;
     826                 :            : 
     827         [ -  + ]:         39 :         if (d == NULL)
     828                 :          0 :                 return (__DECONST(char *, "."));
     829                 :            : 
     830                 :         39 :         walk = strrchr(d, '/');
     831         [ -  + ]:         39 :         if (walk == NULL) {
     832                 :          0 :                 d[0] = '.';
     833                 :          0 :                 d[1] = '\0';
     834                 :          0 :         } else {
     835                 :         39 :                 *walk = '\0';
     836                 :            :         }
     837                 :            : 
     838                 :         39 :         return (d);
     839                 :         39 : }
     840                 :            : 
     841                 :            : char *
     842                 :         25 : rtrimspace(char *buf)
     843                 :            : {
     844                 :         25 :         char *cp = buf + strlen(buf) -1;
     845                 :            : 
     846         [ +  + ]:         26 :         while (cp > buf && isspace(*cp)) {
     847                 :          1 :                 *cp = 0;
     848                 :          1 :                 cp --;
     849                 :            :         }
     850                 :            : 
     851                 :         25 :         return (buf);
     852                 :            : }
     853                 :            : 
     854                 :            : static int
     855                 :          0 : _copy_file(int from, int to)
     856                 :            : {
     857                 :            :         char buf[BUFSIZ];
     858                 :          0 :         ssize_t r, wresid, w = 0;
     859                 :            :         char *bufp;
     860                 :          0 :         r = read(from, buf, BUFSIZ);
     861         [ #  # ]:          0 :         if (r < 0)
     862                 :          0 :                 return (r);
     863                 :          0 :         for (bufp = buf, wresid = r; ; bufp += w, wresid -= w) {
     864                 :          0 :                 w = write(to, bufp, wresid);
     865         [ #  # ]:          0 :                 if (w <= 0)
     866                 :          0 :                         break;
     867         [ #  # ]:          0 :                 if (w >= (ssize_t)wresid)
     868                 :          0 :                         break;
     869                 :          0 :         }
     870         [ #  # ]:          0 :         return (w < 0 ? w : r);
     871                 :          0 : }
     872                 :            : 
     873                 :            : bool
     874                 :          1 : pkg_copy_file(int from, int to)
     875                 :            : {
     876                 :            : #ifdef HAVE_COPY_FILE_RANGE
     877                 :          1 :         bool cfr = true;
     878                 :            : #endif
     879                 :            :         int r;
     880                 :            : 
     881                 :          2 :         do {
     882                 :            : #ifdef HAVE_COPY_FILE_RANGE
     883                 :          2 :                 if (cfr) {
     884                 :          2 :                         r = copy_file_range(from, NULL, to, NULL, SSIZE_MAX,
     885                 :            :                             0);
     886                 :          2 :                         if (r < 0 && (errno == EINVAL || errno == EXDEV)) {
     887                 :            :                                 /* probably a non seekable FD */
     888                 :          0 :                                 cfr = false;
     889                 :          0 :                         }
     890                 :          2 :                 }
     891                 :          4 :                 if (!cfr) {
     892                 :            : #endif
     893                 :          0 :                         r = _copy_file(from, to);
     894                 :            : #ifdef HAVE_COPY_FILE_RANGE
     895                 :          0 :                 }
     896                 :            : #endif
     897         [ +  + ]:          2 :         } while (r > 0);
     898                 :            : 
     899                 :          1 :         return (r >= 0);
     900                 :            : }
     901                 :            : 
     902                 :            : static const unsigned char litchar[] =
     903                 :            : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     904                 :            : 
     905                 :            : void
     906                 :        131 : append_random_suffix(char *buf, int buflen, int suflen)
     907                 :            : {
     908                 :        131 :         int nchars = strlen(buf);
     909                 :            :         char *pos;
     910                 :            :         int r;
     911                 :            : 
     912                 :            :         /* 2 being the "." and the \0 */
     913                 :        131 :         if (nchars + suflen > buflen - 2) {
     914                 :          2 :                 suflen = buflen - nchars - 2;
     915         [ -  + ]:          2 :                 if (suflen <= 0)
     916                 :          0 :                         return;
     917                 :          2 :         }
     918                 :            : 
     919                 :        131 :         buf[nchars++] = '.';
     920                 :        131 :         pos = buf + nchars;
     921                 :            : 
     922         [ +  + ]:       1692 :         while(suflen --) {
     923                 :            : #ifndef HAVE_ARC4RANDOM
     924                 :            :                 r = rand() % (sizeof(litchar) - 1);
     925                 :            : #else
     926                 :       1561 :                 r = arc4random_uniform(sizeof(litchar) - 1);
     927                 :            : #endif
     928                 :       1561 :                 *pos++ = litchar[r];
     929                 :            :         }
     930                 :            : 
     931                 :        131 :         *pos = '\0';
     932                 :        131 : }
     933                 :            : 
     934                 :            : void
     935                 :        129 : hidden_tempfile(char *buf, int buflen, const char *path)
     936                 :            : {
     937                 :            :         const char *fname;
     938                 :        129 :         int suffixlen = 12;
     939                 :            :         int nbuflen;
     940                 :        129 :         const char *prefix = ".pkgtemp.";
     941                 :            : 
     942                 :        129 :         fname = strrchr(path, '/');
     943                 :        129 :         if (fname != NULL)
     944                 :        127 :                 fname++;
     945                 :            : 
     946                 :            :         /*
     947                 :            :          * try to reduce the temporary name as much as possible to fit with very
     948                 :            :          * long file names if possible. by default
     949                 :            :          * .pkgtemp. fname . <suffix>
     950                 :            :          * otherwise
     951                 :            :          * . fname . <suffix>
     952                 :            :          * keep if suffix of at least 5 if possible
     953                 :            :          */
     954         [ +  + ]:        129 :         if (fname != NULL) {
     955                 :        127 :                 if (strlen(fname) >= (NAME_MAX - 15))
     956                 :          1 :                         prefix = ".";
     957                 :        127 :                 snprintf(buf, buflen, "%.*s%s%s", (int)(fname - path), path, prefix, fname);
     958                 :        127 :                 nbuflen = buflen;
     959                 :        127 :         } else {
     960                 :          2 :                 if (strlen(path) >= NAME_MAX - 15)
     961                 :          1 :                         prefix = ".";
     962                 :          2 :                 snprintf(buf, buflen, "%s%s", prefix, path);
     963                 :          2 :                 nbuflen = NAME_MAX;
     964                 :            :         }
     965                 :            : 
     966                 :            : 
     967                 :        129 :         append_random_suffix(buf, nbuflen, suffixlen);
     968                 :        129 : }
     969                 :            : 
     970                 :            : char *
     971                 :          1 : json_escape(const char *str)
     972                 :            : {
     973                 :          1 :         xstring *buf = xstring_new();
     974                 :            : 
     975         [ +  + ]:         11 :         while (str != NULL && *str != '\0') {
     976                 :         10 :                 if (*str == '"' || *str == '\\')
     977                 :          3 :                         fputc('\\', buf->fp);
     978                 :         10 :                 fputc(*str, buf->fp);
     979                 :         10 :                 str++;
     980                 :            :         }
     981                 :            : 
     982                 :          1 :         return (xstring_get(buf));
     983                 :            : }
     984                 :            : 
     985                 :            : struct tempdir *
     986                 :        131 : open_tempdir(int rootfd, const char *path, stringlist_t *symlinks_allowed)
     987                 :            : {
     988                 :            :         struct stat st;
     989                 :            :         char walk[MAXPATHLEN];
     990                 :            :         char *dir;
     991                 :        131 :         size_t cnt = 0, len;
     992                 :            :         struct tempdir *t;
     993                 :            : 
     994                 :        131 :         strlcpy(walk, path, sizeof(walk));
     995                 :        257 :         while ((dir = strrchr(walk, '/')) != NULL) {
     996                 :        257 :                 *dir = '\0';
     997                 :        257 :                 cnt++;
     998                 :            :                 /* accept symlinks pointing to directories only for prefix */
     999                 :        257 :                 len = strlen(walk);
    1000                 :        257 :                 if (len == 0 && cnt == 1)
    1001                 :         12 :                         break;
    1002                 :        215 :                 if (len > 0) {
    1003                 :        215 :                         int flag = AT_SYMLINK_NOFOLLOW;
    1004                 :        215 :                         if (symlinks_allowed != NULL) {
    1005   [ +  -  +  +  :        418 :                                 tll_foreach(*symlinks_allowed, t) {
                   -  + ]
    1006                 :        209 :                                         if (STREQ(RELATIVE_PATH(walk), RELATIVE_PATH(t->item)))
    1007                 :          8 :                                                 flag = 0;
    1008                 :        209 :                                 }
    1009                 :        209 :                         }
    1010         [ +  + ]:        215 :                         if (fstatat(rootfd, RELATIVE_PATH(walk), &st, flag) == -1)
    1011                 :        123 :                                 continue;
    1012                 :         92 :                         if (S_ISDIR(st.st_mode) && cnt == 1)
    1013                 :         84 :                                 break;
    1014         [ +  + ]:          8 :                         if (!S_ISDIR(st.st_mode))
    1015                 :          3 :                                 continue;
    1016                 :          5 :                 }
    1017                 :         35 :                 *dir = '/';
    1018                 :         35 :                 t = xcalloc(1, sizeof(*t));
    1019                 :         35 :                 hidden_tempfile(t->temp, sizeof(t->temp), walk);
    1020         [ -  + ]:         35 :                 if (mkdirat(rootfd, RELATIVE_PATH(t->temp), 0755) == -1) {
    1021                 :          0 :                         pkg_errno("Fail to create temporary directory: %s", t->temp);
    1022                 :          0 :                         free(t);
    1023                 :          0 :                         return (NULL);
    1024                 :            :                 }
    1025                 :            : 
    1026                 :         35 :                 strlcpy(t->name, walk, sizeof(t->name));
    1027                 :         35 :                 t->len = strlen(t->name);
    1028                 :         35 :                 t->fd = openat(rootfd, RELATIVE_PATH(t->temp), O_DIRECTORY);
    1029         [ -  + ]:         35 :                 if (t->fd == -1) {
    1030                 :          0 :                         pkg_errno("Fail to open directory %s", t->temp);
    1031                 :          0 :                         free(t);
    1032                 :          0 :                         return (NULL);
    1033                 :            :                 }
    1034                 :         35 :                 return (t);
    1035                 :            :         }
    1036                 :         96 :         errno = 0;
    1037                 :         96 :         return (NULL);
    1038                 :        131 : }
    1039                 :            : 
    1040                 :            : const char *
    1041                 :         16 : get_http_auth(void)
    1042                 :            : {
    1043                 :         16 :         const char *str = getenv("HTTP_AUTH");
    1044         [ +  + ]:         16 :         if (str == NULL)
    1045                 :         12 :                 return (NULL);
    1046         [ +  + ]:          4 :         if ((str = strchr(str, ':')) == NULL) {
    1047                 :          1 :                 pkg_emit_error("malformed HTTP_AUTH");
    1048                 :          1 :                 return (NULL);
    1049                 :            :         }
    1050         [ +  + ]:          3 :         if ((str = strchr(++str, ':')) == NULL) {
    1051                 :          1 :                 pkg_emit_error("malformed HTTP_AUTH");
    1052                 :          1 :                 return (NULL);
    1053                 :            :         }
    1054         [ +  + ]:          2 :         if (strchr(++str, ':') == NULL) {
    1055                 :          1 :                 pkg_emit_error("malformed HTTP_AUTH");
    1056                 :          1 :                 return (NULL);
    1057                 :            :         }
    1058                 :          1 :         return (str);
    1059                 :         16 : }
    1060                 :            : 
    1061                 :            : bool
    1062                 :         33 : c_charv_contains(c_charv_t *v, const char *el, bool casesensitive)
    1063                 :            : {
    1064         [ +  + ]:         43 :         for (size_t i = 0; i < v->len; i ++) {
    1065         [ +  + ]:         39 :                 if (casesensitive) {
    1066         [ +  + ]:         33 :                         if (STREQ(v->d[i], el))
    1067                 :         28 :                                 return (true);
    1068                 :          5 :                 } else {
    1069         [ +  + ]:          6 :                         if (STRIEQ(v->d[i], el)) {
    1070                 :          1 :                                 return (true);
    1071                 :            :                         }
    1072                 :            :                 }
    1073                 :         10 :         }
    1074                 :          4 :         return (false);
    1075                 :         33 : }

Generated by: LCOV version 1.15