LCOV - code coverage report
Current view: top level - libpkg - utils.c (source / functions) Hit Total Coverage
Test: rapport Lines: 250 459 54.5 %
Date: 2021-12-10 16:22:55 Functions: 25 31 80.6 %
Branches: 79 155 51.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                 :            :  * All rights reserved.
       6                 :            :  * 
       7                 :            :  * Redistribution and use in source and binary forms, with or without
       8                 :            :  * modification, are permitted provided that the following conditions
       9                 :            :  * are met:
      10                 :            :  * 1. Redistributions of source code must retain the above copyright
      11                 :            :  *    notice, this list of conditions and the following disclaimer
      12                 :            :  *    in this position and unchanged.
      13                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      14                 :            :  *    notice, this list of conditions and the following disclaimer in the
      15                 :            :  *    documentation and/or other materials provided with the distribution.
      16                 :            :  * 
      17                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      18                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      19                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      20                 :            :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      21                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      22                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      26                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27                 :            :  */
      28                 :            : 
      29                 :            : #include <pkg_config.h>
      30                 :            : 
      31                 :            : #include <sys/socket.h>
      32                 :            : #include <sys/stat.h>
      33                 :            : #include <sys/param.h>
      34                 :            : #include <stdio.h>
      35                 :            : 
      36                 :            : #include <assert.h>
      37                 :            : #include <errno.h>
      38                 :            : #include <fcntl.h>
      39                 :            : #include <stdlib.h>
      40                 :            : #include <unistd.h>
      41                 :            : #include <string.h>
      42                 :            : #include <ucl.h>
      43                 :            : #include <utlist.h>
      44                 :            : #include <ctype.h>
      45                 :            : #include <fnmatch.h>
      46                 :            : #include <paths.h>
      47                 :            : #include <float.h>
      48                 :            : #include <math.h>
      49                 :            : #include <regex.h>
      50                 :            : 
      51                 :            : #include <bsd_compat.h>
      52                 :            : 
      53                 :            : #include "pkg.h"
      54                 :            : #include "private/event.h"
      55                 :            : #include "private/utils.h"
      56                 :            : #include "private/pkg.h"
      57                 :            : #include "xmalloc.h"
      58                 :            : 
      59                 :            : extern struct pkg_ctx ctx;
      60                 :            : 
      61                 :            : bool
      62                 :       3976 : match_ucl_lists(const char *buf, const ucl_object_t *globs, const ucl_object_t *regexes)
      63                 :            : {
      64                 :            :         const ucl_object_t *cur;
      65                 :            :         ucl_object_iter_t it;
      66                 :            : 
      67                 :       3976 :         if (globs == NULL && regexes == NULL)
      68                 :        428 :                 return (false);
      69                 :            : 
      70                 :       3544 :         if (globs != NULL) {
      71                 :       3544 :                 it = NULL;
      72         [ +  + ]:       7492 :                 while ((cur = ucl_iterate_object(globs, &it, true))) {
      73         [ +  + ]:       3968 :                         if (fnmatch(ucl_object_tostring(cur), buf, 0) == 0)
      74                 :         20 :                                 return (true);
      75                 :            :                 }
      76                 :       3524 :         }
      77                 :            : 
      78                 :       3944 :         if (regexes != NULL) {
      79                 :       3104 :                 it = NULL;
      80         [ +  + ]:       6204 :                 while ((cur = ucl_iterate_object(regexes, &it, true))) {
      81                 :            :                         regex_t re;
      82                 :       3104 :                         regcomp(&re, ucl_object_tostring(cur),
      83                 :            :                            REG_EXTENDED|REG_NOSUB);
      84         [ +  + ]:       3104 :                         if (regexec(&re, buf, 0, NULL, 0) == 0) {
      85                 :          4 :                                 regfree(&re);
      86                 :          4 :                                 return (true);
      87                 :            :                         }
      88                 :       3100 :                         regfree(&re);
      89                 :            :                 }
      90                 :       3100 :         }
      91                 :            : 
      92                 :       3524 :         return (false);
      93                 :       3976 : }
      94                 :            : 
      95                 :            : int
      96                 :       2044 : mkdirs(const char *_path)
      97                 :            : {
      98                 :            :         char path[MAXPATHLEN];
      99                 :            :         char *p;
     100                 :            : 
     101                 :       2044 :         strlcpy(path, _path, sizeof(path));
     102                 :       2044 :         p = path;
     103                 :       2044 :         if (*p == '/')
     104                 :       1208 :                 p++;
     105                 :            : 
     106                 :       6743 :         for (;;) {
     107                 :       6743 :                 if ((p = strchr(p, '/')) != NULL)
     108                 :       4699 :                         *p = '\0';
     109                 :            : 
     110                 :       6594 :                 if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
     111                 :       6594 :                         if (errno != EEXIST && errno != EISDIR) {
     112                 :          0 :                                 pkg_emit_errno("mkdir", path);
     113                 :          0 :                                 return (EPKG_FATAL);
     114                 :            :                         }
     115                 :            : 
     116                 :            :                 /* that was the last element of the path */
     117         [ +  + ]:       6743 :                 if (p == NULL)
     118                 :       2044 :                         break;
     119                 :            : 
     120                 :       4699 :                 *p = '/';
     121                 :       4699 :                 p++;
     122                 :            :         }
     123                 :            : 
     124                 :       2044 :         return (EPKG_OK);
     125                 :       2044 : }
     126                 :            : int
     127                 :        239 : file_to_bufferat(int dfd, const char *path, char **buffer, off_t *sz)
     128                 :            : {
     129                 :        239 :         int fd = -1;
     130                 :            :         struct stat st;
     131                 :        239 :         int retcode = EPKG_OK;
     132                 :            : 
     133                 :        239 :         assert(path != NULL && path[0] != '\0');
     134         [ +  - ]:        239 :         assert(buffer != NULL);
     135         [ +  - ]:        239 :         assert(sz != NULL);
     136                 :            : 
     137         [ -  + ]:        239 :         if ((fd = openat(dfd, path, O_RDONLY)) == -1) {
     138                 :          0 :                 pkg_emit_errno("openat", path);
     139                 :          0 :                 retcode = EPKG_FATAL;
     140                 :          0 :                 goto cleanup;
     141                 :            :         }
     142                 :            : 
     143         [ -  + ]:        239 :         if (fstatat(dfd, path, &st, 0) == -1) {
     144                 :          0 :                 pkg_emit_errno("fstatat", path);
     145                 :          0 :                 retcode = EPKG_FATAL;
     146                 :          0 :                 goto cleanup;
     147                 :            :         }
     148                 :            : 
     149                 :        239 :         *buffer = xmalloc(st.st_size + 1);
     150                 :            : 
     151         [ -  + ]:        239 :         if (read(fd, *buffer, st.st_size) == -1) {
     152                 :          0 :                 pkg_emit_errno("read", path);
     153                 :          0 :                 retcode = EPKG_FATAL;
     154                 :          0 :                 goto cleanup;
     155                 :            :         }
     156                 :            : 
     157                 :            :         cleanup:
     158                 :        239 :         if (fd >= 0)
     159                 :        239 :                 close(fd);
     160                 :            : 
     161         [ +  - ]:        239 :         if (retcode == EPKG_OK) {
     162                 :        239 :                 (*buffer)[st.st_size] = '\0';
     163                 :        239 :                 *sz = st.st_size;
     164                 :        239 :         } else {
     165                 :          0 :                 *buffer = NULL;
     166                 :          0 :                 *sz = -1;
     167                 :            :         }
     168                 :        239 :         return (retcode);
     169                 :            : }
     170                 :            : 
     171                 :            : int
     172                 :          8 : file_to_buffer(const char *path, char **buffer, off_t *sz)
     173                 :            : {
     174                 :          8 :         int fd = -1;
     175                 :            :         struct stat st;
     176                 :          8 :         int retcode = EPKG_OK;
     177                 :            : 
     178                 :          8 :         assert(path != NULL && path[0] != '\0');
     179         [ +  - ]:          8 :         assert(buffer != NULL);
     180         [ +  - ]:          8 :         assert(sz != NULL);
     181                 :            : 
     182         [ -  + ]:          8 :         if ((fd = open(path, O_RDONLY)) == -1) {
     183                 :          0 :                 pkg_emit_errno("open", path);
     184                 :          0 :                 retcode = EPKG_FATAL;
     185                 :          0 :                 goto cleanup;
     186                 :            :         }
     187                 :            : 
     188         [ -  + ]:          8 :         if (fstat(fd, &st) == -1) {
     189                 :          0 :                 pkg_emit_errno("fstat", path);
     190                 :          0 :                 retcode = EPKG_FATAL;
     191                 :          0 :                 goto cleanup;
     192                 :            :         }
     193                 :            : 
     194                 :          8 :         *buffer = xmalloc(st.st_size + 1);
     195                 :            : 
     196         [ -  + ]:          8 :         if (read(fd, *buffer, st.st_size) == -1) {
     197                 :          0 :                 pkg_emit_errno("read", path);
     198                 :          0 :                 retcode = EPKG_FATAL;
     199                 :          0 :                 goto cleanup;
     200                 :            :         }
     201                 :            : 
     202                 :            :         cleanup:
     203                 :          8 :         if (fd >= 0)
     204                 :          8 :                 close(fd);
     205                 :            : 
     206         [ +  - ]:          8 :         if (retcode == EPKG_OK) {
     207                 :          8 :                 (*buffer)[st.st_size] = '\0';
     208                 :          8 :                 *sz = st.st_size;
     209                 :          8 :         } else {
     210                 :          0 :                 *buffer = NULL;
     211                 :          0 :                 *sz = -1;
     212                 :            :         }
     213                 :          8 :         return (retcode);
     214                 :            : }
     215                 :            : 
     216                 :            : int
     217                 :         24 : format_exec_cmd(char **dest, const char *in, const char *prefix,
     218                 :            :     const char *plist_file, const char *line, int argc, char **argv, bool lua)
     219                 :            : {
     220                 :            :         xstring *buf;
     221                 :            :         char path[MAXPATHLEN];
     222                 :            :         char *cp;
     223                 :            :         size_t sz;
     224                 :            : 
     225                 :         24 :         buf = xstring_new();
     226                 :            : 
     227                 :         24 :         if (line != NULL && argv != NULL) {
     228         [ +  + ]:         24 :                 if (lua) {
     229                 :          8 :                         fprintf(buf->fp, "-- args: %s\n", line);
     230                 :          8 :                 } else {
     231                 :         16 :                         fprintf(buf->fp, "# args: %s\n", line);
     232                 :            :                 }
     233                 :         24 :         }
     234                 :            : 
     235         [ +  + ]:        740 :         while (in[0] != '\0') {
     236         [ +  + ]:        720 :                 if (in[0] != '%') {
     237                 :        688 :                         fputc(in[0], buf->fp);
     238                 :        688 :                         in++;
     239                 :        688 :                         continue;
     240                 :            :                 }
     241                 :         32 :                 in++;
     242   [ -  -  -  -  :         32 :                 switch(in[0]) {
                -  -  + ]
     243                 :            :                 case 'D':
     244                 :          0 :                         fprintf(buf->fp, "%s", prefix);
     245                 :          0 :                         break;
     246                 :            :                 case 'F':
     247                 :          0 :                         if (plist_file == NULL || plist_file[0] == '\0') {
     248                 :          0 :                                 pkg_emit_error("No files defined %%F couldn't "
     249                 :          0 :                                     "be expanded, ignoring %s", in);
     250                 :          0 :                                 xstring_free(buf);
     251                 :          0 :                                 return (EPKG_FATAL);
     252                 :            :                         }
     253                 :          0 :                         fprintf(buf->fp, "%s", plist_file);
     254                 :          0 :                         break;
     255                 :            :                 case 'f':
     256                 :          0 :                         if (plist_file == NULL || plist_file[0] == '\0') {
     257                 :          0 :                                 pkg_emit_error("No files defined %%f couldn't "
     258                 :          0 :                                     "be expanded, ignoring %s", in);
     259                 :          0 :                                 xstring_free(buf);
     260                 :          0 :                                 return (EPKG_FATAL);
     261                 :            :                         }
     262         [ #  # ]:          0 :                         if (prefix[strlen(prefix) - 1] == '/')
     263                 :          0 :                                 snprintf(path, sizeof(path), "%s%s",
     264                 :          0 :                                     prefix, plist_file);
     265                 :            :                         else
     266                 :          0 :                                 snprintf(path, sizeof(path), "%s/%s",
     267                 :          0 :                                     prefix, plist_file);
     268                 :          0 :                         cp = strrchr(path, '/');
     269                 :          0 :                         cp ++;
     270                 :          0 :                         fprintf(buf->fp, "%s", cp);
     271                 :          0 :                         break;
     272                 :            :                 case 'B':
     273                 :          0 :                         if (plist_file == NULL || plist_file[0] == '\0') {
     274                 :          0 :                                 pkg_emit_error("No files defined %%B couldn't "
     275                 :          0 :                                     "be expanded, ignoring %s", in);
     276                 :          0 :                                 xstring_free(buf);
     277                 :          0 :                                 return (EPKG_FATAL);
     278                 :            :                         }
     279         [ #  # ]:          0 :                         if (prefix[strlen(prefix) - 1] == '/')
     280                 :          0 :                                 snprintf(path, sizeof(path), "%s%s", prefix,
     281                 :          0 :                                     plist_file);
     282                 :            :                         else
     283                 :          0 :                                 snprintf(path, sizeof(path), "%s/%s", prefix,
     284                 :          0 :                                     plist_file);
     285                 :          0 :                         cp = strrchr(path, '/');
     286                 :          0 :                         cp[0] = '\0';
     287                 :          0 :                         fprintf(buf->fp, "%s", path);
     288                 :          0 :                         break;
     289                 :            :                 case '%':
     290                 :          0 :                         fputc('%', buf->fp);
     291                 :          0 :                         break;
     292                 :            :                 case '@':
     293         [ #  # ]:          0 :                         if (line != NULL) {
     294                 :          0 :                                 fprintf(buf->fp, "%s", line);
     295                 :          0 :                                 break;
     296                 :            :                         }
     297                 :            : 
     298                 :            :                         /*
     299                 :            :                          * no break here because if line is not
     300                 :            :                          * given (default exec) %@ does not
     301                 :            :                          * exists
     302                 :            :                          */
     303                 :            :                         /* FALLTHRU */
     304                 :            :                 case '#':
     305                 :          0 :                         fprintf(buf->fp, "%d", argc);
     306                 :          0 :                         break;
     307                 :            :                 default:
     308         [ +  - ]:         32 :                         if ((sz = strspn(in, "0123456789")) > 0) {
     309                 :         32 :                                 int pos = strtol(in, NULL, 10);
     310         [ +  + ]:         32 :                                 if (pos > argc) {
     311                 :          4 :                                         pkg_emit_error("Requesting argument "
     312                 :            :                                             "%%%d while only %d arguments are"
     313                 :          4 :                                             " available", pos, argc);
     314                 :          4 :                                         xstring_free(buf);
     315                 :          4 :                                         return (EPKG_FATAL);
     316                 :            :                                 }
     317                 :         28 :                                 fprintf(buf->fp, "%s", argv[pos -1]);
     318                 :         28 :                                 in += sz -1;
     319                 :         28 :                                 break;
     320                 :            :                         }
     321                 :          0 :                         fprintf(buf->fp, "%c%c", '%', in[0]);
     322                 :          0 :                         break;
     323                 :            :                 }
     324                 :            : 
     325                 :         28 :                 in++;
     326                 :            :         }
     327                 :            : 
     328                 :         20 :         *dest = xstring_get(buf);
     329                 :            : 
     330                 :         20 :         return (EPKG_OK);
     331                 :         24 : }
     332                 :            : 
     333                 :            : int
     334                 :        831 : is_dir(const char *path)
     335                 :            : {
     336                 :            :         struct stat st;
     337                 :            : 
     338                 :        831 :         return (stat(path, &st) == 0 && S_ISDIR(st.st_mode));
     339                 :            : }
     340                 :            : 
     341                 :            : int
     342                 :          0 : is_link(const char *path)
     343                 :            : {
     344                 :            :         struct stat st;
     345                 :            : 
     346                 :          0 :         return (lstat(path, &st) == 0 && S_ISLNK(st.st_mode));
     347                 :            : }
     348                 :            : 
     349                 :            : bool
     350                 :         92 : check_for_hardlink(hardlinks_t *hl, struct stat *st)
     351                 :            : {
     352                 :            :         int absent;
     353                 :            : 
     354                 :         92 :         kh_put_hardlinks(hl, st->st_ino, &absent);
     355         [ +  + ]:         92 :         if (absent == 0)
     356                 :         46 :                 return (true);
     357                 :            : 
     358                 :         46 :         return (false);
     359                 :         92 : }
     360                 :            : 
     361                 :            : bool
     362                 :        694 : is_valid_abi(const char *arch, bool emit_error) {
     363                 :            :         const char *myarch, *myarch_legacy;
     364                 :            : 
     365                 :        694 :         myarch = pkg_object_string(pkg_config_get("ABI"));
     366                 :        694 :         myarch_legacy = pkg_object_string(pkg_config_get("ALTABI"));
     367                 :            : 
     368                 :        694 :         if (fnmatch(arch, myarch, FNM_CASEFOLD) == FNM_NOMATCH &&
     369                 :          0 :             fnmatch(arch, myarch_legacy, FNM_CASEFOLD) == FNM_NOMATCH &&
     370                 :          0 :             strncasecmp(arch, myarch, strlen(myarch)) != 0 &&
     371                 :          0 :             strncasecmp(arch, myarch_legacy, strlen(myarch_legacy)) != 0) {
     372                 :          0 :                 if (emit_error)
     373                 :          0 :                         pkg_emit_error("wrong architecture: %s instead of %s",
     374                 :          0 :                             arch, myarch);
     375                 :          0 :                 return (false);
     376                 :            :         }
     377                 :            : 
     378                 :        694 :         return (true);
     379                 :        694 : }
     380                 :            : 
     381                 :            : bool
     382                 :        694 : is_valid_os_version(struct pkg *pkg)
     383                 :            : {
     384                 :            : #ifdef __FreeBSD__
     385                 :            :         const char *fbsd_version;
     386                 :        694 :         const char *errstr = NULL;
     387                 :            :         int fbsdver;
     388                 :            :         char query_buf[512];
     389                 :            :         /* -1: not checked, 0: not allowed, 1: allowed */
     390                 :            :         static int osver_mismatch_allowed = -1;
     391                 :            :         bool ret;
     392                 :            : 
     393         [ -  + ]:        694 :         if (pkg_object_bool(pkg_config_get("IGNORE_OSVERSION")))
     394                 :          0 :                 return (true);
     395                 :        694 :         if ((fbsd_version = pkg_kv_get(&pkg->annotations, "FreeBSD_version")) != NULL) {
     396                 :        570 :                 fbsdver = strtonum(fbsd_version, 1, INT_MAX, &errstr);
     397         [ -  + ]:        570 :                 if (errstr != NULL) {
     398                 :          0 :                         pkg_emit_error("Invalid FreeBSD version %s for package %s",
     399                 :          0 :                             fbsd_version, pkg->name);
     400                 :          0 :                         return (false);
     401                 :            :                 }
     402         [ -  + ]:        570 :                 if (fbsdver > ctx.osversion) {
     403         [ #  # ]:          0 :                         if (fbsdver - ctx.osversion < 100000) {
     404                 :            :                                 /* Negligible difference, ask user to enforce */
     405                 :          0 :                                 if (osver_mismatch_allowed == -1) {
     406                 :          0 :                                         snprintf(query_buf, sizeof(query_buf),
     407                 :            :                                                         "Newer FreeBSD version for package %s:\n"
     408                 :            :                                                         "To ignore this error set IGNORE_OSVERSION=yes\n"
     409                 :            :                                                         "- package: %d\n"
     410                 :            :                                                         "- running kernel: %d\n"
     411                 :          0 :                                                         "Ignore the mismatch and continue? ", pkg->name,
     412                 :          0 :                                                         fbsdver, ctx.osversion);
     413                 :          0 :                                         ret = pkg_emit_query_yesno(false, query_buf);
     414                 :          0 :                                         osver_mismatch_allowed = ret;
     415                 :          0 :                                 }
     416                 :            : 
     417                 :          0 :                                 return (osver_mismatch_allowed);
     418                 :            :                         }
     419                 :            :                         else {
     420                 :          0 :                                 pkg_emit_error("Newer FreeBSD version for package %s:\n"
     421                 :            :                                         "To ignore this error set IGNORE_OSVERSION=yes\n"
     422                 :            :                                         "- package: %d\n"
     423                 :            :                                         "- running kernel: %d\n",
     424                 :          0 :                                         pkg->name,
     425                 :          0 :                                         fbsdver, ctx.osversion);
     426                 :          0 :                                 return (false);
     427                 :            :                         }
     428                 :            :                 }
     429                 :        570 :         }
     430                 :        694 :         return (true);
     431                 :            : #else
     432                 :            :         return (true);
     433                 :            : #endif
     434                 :            : 
     435                 :        694 : }
     436                 :            : 
     437                 :            : void
     438                 :          0 : set_nonblocking(int fd)
     439                 :            : {
     440                 :            :         int flags;
     441                 :            : 
     442         [ #  # ]:          0 :         if ((flags = fcntl(fd, F_GETFL)) == -1)
     443                 :          0 :                 return;
     444                 :          0 :         if (!(flags & O_NONBLOCK)) {
     445                 :          0 :                 flags |= O_NONBLOCK;
     446                 :          0 :                 fcntl(fd, F_SETFL, flags);
     447                 :          0 :         }
     448                 :          0 : }
     449                 :            : 
     450                 :            : void
     451                 :          0 : set_blocking(int fd)
     452                 :            : {
     453                 :            :         int flags;
     454                 :            : 
     455         [ #  # ]:          0 :         if ((flags = fcntl(fd, F_GETFL)) == -1)
     456                 :          0 :                 return;
     457                 :          0 :         if (flags & O_NONBLOCK) {
     458                 :          0 :                 flags &= ~O_NONBLOCK;
     459                 :          0 :                 fcntl(fd, F_SETFL, flags);
     460                 :          0 :         }
     461                 :          0 : }
     462                 :            : 
     463                 :            : /* Spawn a process from pfunc, returning it's pid. The fds array passed will
     464                 :            :  * be filled with two descriptors: fds[0] will read from the child process,
     465                 :            :  * and fds[1] will write to it.
     466                 :            :  * Similarly, the child process will receive a reading/writing fd set (in
     467                 :            :  * that same order) as arguments.
     468                 :            : */
     469                 :            : extern char **environ;
     470                 :            : pid_t
     471                 :          0 : process_spawn_pipe(FILE *inout[2], const char *command)
     472                 :            : {
     473                 :            :         pid_t pid;
     474                 :            :         int pipes[4];
     475                 :            :         char *argv[4];
     476                 :            : 
     477                 :            :         /* Parent read/child write pipe */
     478         [ #  # ]:          0 :         if (pipe(&pipes[0]) == -1)
     479                 :          0 :                 return (-1);
     480                 :            : 
     481                 :            :         /* Child read/parent write pipe */
     482         [ #  # ]:          0 :         if (pipe(&pipes[2]) == -1) {
     483                 :          0 :                 close(pipes[0]);
     484                 :          0 :                 close(pipes[1]);
     485                 :          0 :                 return (-1);
     486                 :            :         }
     487                 :            : 
     488                 :          0 :         argv[0] = __DECONST(char *, "sh");
     489                 :          0 :         argv[1] = __DECONST(char *, "-c");
     490                 :          0 :         argv[2] = __DECONST(char *, command);
     491                 :          0 :         argv[3] = NULL;
     492                 :            : 
     493                 :          0 :         pid = fork();
     494         [ #  # ]:          0 :         if (pid > 0) {
     495                 :            :                 /* Parent process */
     496                 :          0 :                 inout[0] = fdopen(pipes[0], "r");
     497                 :          0 :                 inout[1] = fdopen(pipes[3], "w");
     498                 :            : 
     499                 :          0 :                 close(pipes[1]);
     500                 :          0 :                 close(pipes[2]);
     501                 :            : 
     502                 :          0 :                 return (pid);
     503                 :            : 
     504         [ #  # ]:          0 :         } else if (pid == 0) {
     505                 :          0 :                 close(pipes[0]);
     506                 :          0 :                 close(pipes[3]);
     507                 :            : 
     508                 :          0 :                 if (pipes[1] != STDOUT_FILENO) {
     509                 :          0 :                         dup2(pipes[1], STDOUT_FILENO);
     510                 :          0 :                         close(pipes[1]);
     511                 :          0 :                 }
     512                 :          0 :                 if (pipes[2] != STDIN_FILENO) {
     513                 :          0 :                         dup2(pipes[2], STDIN_FILENO);
     514                 :          0 :                         close(pipes[2]);
     515                 :          0 :                 }
     516                 :          0 :                 closefrom(STDERR_FILENO + 1);
     517                 :            : 
     518                 :          0 :                 execve(_PATH_BSHELL, argv, environ);
     519                 :            : 
     520                 :          0 :                 exit(127);
     521                 :            :         }
     522                 :            : 
     523                 :          0 :         return (-1); /* ? */
     524                 :          0 : }
     525                 :            : 
     526                 :            : static int
     527                 :      14141 : ucl_file_append_character(unsigned char c, size_t len, void *data)
     528                 :            : {
     529                 :            :         size_t i;
     530                 :      14141 :         FILE *out = data;
     531                 :            : 
     532         [ +  + ]:      28282 :         for (i = 0; i < len; i++)
     533                 :      14141 :                 fprintf(out, "%c", c);
     534                 :            : 
     535                 :      14141 :         return (0);
     536                 :            : }
     537                 :            : 
     538                 :            : static int
     539                 :      15607 : ucl_file_append_len(const unsigned char *str, size_t len, void *data)
     540                 :            : {
     541                 :      15607 :         FILE *out = data;
     542                 :            : 
     543                 :      15607 :         fprintf(out, "%.*s", (int)len, str);
     544                 :            : 
     545                 :      15607 :         return (0);
     546                 :            : }
     547                 :            : 
     548                 :            : static int
     549                 :        797 : ucl_file_append_int(int64_t val, void *data)
     550                 :            : {
     551                 :        797 :         FILE *out = data;
     552                 :            : 
     553                 :        797 :         fprintf(out, "%"PRId64, val);
     554                 :            : 
     555                 :        797 :         return (0);
     556                 :            : }
     557                 :            : 
     558                 :            : static int
     559                 :          0 : ucl_file_append_double(double val, void *data)
     560                 :            : {
     561                 :          0 :         FILE *out = data;
     562                 :          0 :         const double delta = 0.0000001;
     563                 :            : 
     564         [ #  # ]:          0 :         if (val == (double)(int)val) {
     565                 :          0 :                 fprintf(out, "%.1lf", val);
     566         [ #  # ]:          0 :         } else if (fabs(val - (double)(int)val) < delta) {
     567                 :          0 :                 fprintf(out, "%.*lg", DBL_DIG, val);
     568                 :          0 :         } else {
     569                 :          0 :                 fprintf(out, "%lf", val);
     570                 :            :         }
     571                 :            : 
     572                 :          0 :         return (0);
     573                 :            : }
     574                 :            : 
     575                 :            : static int
     576                 :     198321 : ucl_buf_append_character(unsigned char c, size_t len, void *data)
     577                 :            : {
     578                 :     198321 :         xstring *buf = data;
     579                 :            :         size_t i;
     580                 :            : 
     581         [ +  + ]:     396954 :         for (i = 0; i < len; i++)
     582                 :     198633 :                 fprintf(buf->fp, "%c", c);
     583                 :            : 
     584                 :     198321 :         return (0);
     585                 :            : }
     586                 :            : 
     587                 :            : static int
     588                 :      72976 : ucl_buf_append_len(const unsigned char *str, size_t len, void *data)
     589                 :            : {
     590                 :      72976 :         xstring *buf = data;
     591                 :            : 
     592                 :      72976 :         fprintf(buf->fp, "%.*s", (int)len, str);
     593                 :            : 
     594                 :      72976 :         return (0);
     595                 :            : }
     596                 :            : 
     597                 :            : static int
     598                 :       2017 : ucl_buf_append_int(int64_t val, void *data)
     599                 :            : {
     600                 :       2017 :         xstring *buf = data;
     601                 :            : 
     602                 :       2017 :         fprintf(buf->fp, "%"PRId64, val);
     603                 :            : 
     604                 :       2017 :         return (0);
     605                 :            : }
     606                 :            : 
     607                 :            : static int
     608                 :          0 : ucl_buf_append_double(double val, void *data)
     609                 :            : {
     610                 :          0 :         xstring *buf = data;
     611                 :          0 :         const double delta = 0.0000001;
     612                 :            : 
     613         [ #  # ]:          0 :         if (val == (double)(int)val) {
     614                 :          0 :                 fprintf(buf->fp, "%.1lf", val);
     615         [ #  # ]:          0 :         } else if (fabs(val - (double)(int)val) < delta) {
     616                 :          0 :                 fprintf(buf->fp, "%.*lg", DBL_DIG, val);
     617                 :          0 :         } else {
     618                 :          0 :                 fprintf(buf->fp, "%lf", val);
     619                 :            :         }
     620                 :            : 
     621                 :          0 :         return (0);
     622                 :            : }
     623                 :            : 
     624                 :            : bool
     625                 :        797 : ucl_object_emit_file(const ucl_object_t *obj, enum ucl_emitter emit_type,
     626                 :            :     FILE *out)
     627                 :            : {
     628                 :        797 :         struct ucl_emitter_functions func = {
     629                 :            :                 .ucl_emitter_append_character = ucl_file_append_character,
     630                 :            :                 .ucl_emitter_append_len = ucl_file_append_len,
     631                 :            :                 .ucl_emitter_append_int = ucl_file_append_int,
     632                 :            :                 .ucl_emitter_append_double = ucl_file_append_double
     633                 :            :         };
     634                 :            : 
     635         [ -  + ]:        797 :         if (obj == NULL)
     636                 :          0 :                 return (false);
     637                 :            : 
     638                 :        797 :         func.ud = out;
     639                 :            : 
     640                 :        797 :         return (ucl_object_emit_full(obj, emit_type, &func, NULL));
     641                 :        797 : }
     642                 :            : 
     643                 :            : bool
     644                 :       2017 : ucl_object_emit_buf(const ucl_object_t *obj, enum ucl_emitter emit_type,
     645                 :            :                      xstring **buf)
     646                 :            : {
     647                 :       2017 :         bool ret = false;
     648                 :       2017 :         struct ucl_emitter_functions func = {
     649                 :            :                 .ucl_emitter_append_character = ucl_buf_append_character,
     650                 :            :                 .ucl_emitter_append_len = ucl_buf_append_len,
     651                 :            :                 .ucl_emitter_append_int = ucl_buf_append_int,
     652                 :            :                 .ucl_emitter_append_double = ucl_buf_append_double
     653                 :            :         };
     654                 :            : 
     655         [ +  + ]:       2017 :         xstring_renew(*buf);
     656                 :            : 
     657                 :       2017 :         func.ud = *buf;
     658                 :            : 
     659                 :       2017 :         ret = ucl_object_emit_full(obj, emit_type, &func, NULL);
     660                 :            : 
     661                 :       2017 :         return (ret);
     662                 :            : }
     663                 :            : 
     664                 :            : /* A bit like strsep(), except it accounts for "double" and 'single'
     665                 :            :    quotes.  Unlike strsep(), returns the next arg string, trimmed of
     666                 :            :    whitespace or enclosing quotes, and updates **args to point at the
     667                 :            :    character after that.  Sets *args to NULL when it has been
     668                 :            :    completely consumed.  Quoted strings run from the first encountered
     669                 :            :    quotemark to the next one of the same type or the terminating NULL.
     670                 :            :    Quoted strings can contain the /other/ type of quote mark, which
     671                 :            :    loses any special significance.  There isn't an escape
     672                 :            :    character. */
     673                 :            : 
     674                 :            : enum parse_states {
     675                 :            :         START,
     676                 :            :         ORDINARY_TEXT,
     677                 :            :         OPEN_SINGLE_QUOTES,
     678                 :            :         IN_SINGLE_QUOTES,
     679                 :            :         OPEN_DOUBLE_QUOTES,
     680                 :            :         IN_DOUBLE_QUOTES,
     681                 :            : };
     682                 :            : 
     683                 :            : char *
     684                 :        200 : pkg_utils_tokenize(char **args)
     685                 :            : {
     686                 :            :         char                    *p, *p_start;
     687                 :        200 :         enum parse_states        parse_state = START;
     688                 :            : 
     689         [ +  - ]:        200 :         assert(*args != NULL);
     690                 :            : 
     691         [ +  + ]:        594 :         for (p = p_start = *args; *p != '\0'; p++) {
     692   [ +  +  -  -  :        508 :                 switch (parse_state) {
                   -  - ]
     693                 :            :                 case START:
     694         [ +  - ]:        200 :                         if (!isspace(*p)) {
     695         [ -  + ]:        200 :                                 if (*p == '"')
     696                 :          0 :                                         parse_state = OPEN_DOUBLE_QUOTES;
     697         [ -  + ]:        200 :                                 else if (*p == '\'')
     698                 :          0 :                                         parse_state = OPEN_SINGLE_QUOTES;
     699                 :            :                                 else {
     700                 :        200 :                                         parse_state = ORDINARY_TEXT;
     701                 :        200 :                                         p_start = p;
     702                 :            :                                 }                               
     703                 :        200 :                         } else
     704                 :          0 :                                 p_start = p;
     705                 :        200 :                         break;
     706                 :            :                 case ORDINARY_TEXT:
     707         [ +  + ]:        308 :                         if (isspace(*p))
     708                 :        114 :                                 goto finish;
     709                 :        194 :                         break;
     710                 :            :                 case OPEN_SINGLE_QUOTES:
     711                 :          0 :                         p_start = p;
     712         [ #  # ]:          0 :                         if (*p == '\'')
     713                 :          0 :                                 goto finish;
     714                 :            : 
     715                 :          0 :                         parse_state = IN_SINGLE_QUOTES;
     716                 :          0 :                         break;
     717                 :            :                 case IN_SINGLE_QUOTES:
     718         [ #  # ]:          0 :                         if (*p == '\'')
     719                 :          0 :                                 goto finish;
     720                 :          0 :                         break;
     721                 :            :                 case OPEN_DOUBLE_QUOTES:
     722                 :          0 :                         p_start = p;
     723         [ #  # ]:          0 :                         if (*p == '"')
     724                 :          0 :                                 goto finish;
     725                 :          0 :                         parse_state = IN_DOUBLE_QUOTES;
     726                 :          0 :                         break;
     727                 :            :                 case IN_DOUBLE_QUOTES:
     728         [ #  # ]:          0 :                         if (*p == '"')
     729                 :          0 :                                 goto finish;
     730                 :          0 :                         break;
     731                 :            :                 }
     732                 :        480 :         }
     733                 :            : 
     734                 :            : finish:
     735         [ +  + ]:        200 :         if (*p == '\0')
     736                 :         86 :                 *args = NULL;   /* All done */
     737                 :            :         else {
     738                 :        114 :                 *p = '\0';
     739                 :        114 :                 p++;
     740                 :        114 :                 if (*p == '\0' || parse_state == START)
     741                 :          0 :                         *args = NULL; /* whitespace or nothing left */
     742                 :            :                 else
     743                 :        114 :                         *args = p;
     744                 :            :         }
     745                 :        200 :         return (p_start);
     746                 :            : }
     747                 :            : 
     748                 :            : int
     749                 :         86 : pkg_utils_count_spaces(const char *args)
     750                 :            : {
     751                 :            :         int             spaces;
     752                 :            :         const char      *p;
     753                 :            : 
     754         [ +  + ]:        594 :         for (spaces = 0, p = args; *p != '\0'; p++)
     755                 :        622 :                 if (isspace(*p))
     756                 :        114 :                         spaces++;
     757                 :            : 
     758                 :         86 :         return (spaces);
     759                 :            : }
     760                 :            : 
     761                 :            : /* unlike realpath(3), this routine does not expand symbolic links */
     762                 :            : char *
     763                 :       4046 : pkg_absolutepath(const char *src, char *dest, size_t dest_size, bool fromroot) {
     764                 :            :         size_t dest_len, src_len, cur_len;
     765                 :            :         const char *cur, *next;
     766                 :            : 
     767                 :       4046 :         src_len = strlen(src);
     768                 :       4046 :         bzero(dest, dest_size);
     769                 :       4046 :         if (src_len != 0 && src[0] != '/') {
     770         [ #  # ]:          0 :                 if (fromroot)
     771                 :          0 :                         *dest = '/';
     772                 :            :                 /* relative path, we use cwd */
     773         [ #  # ]:          0 :                 else if (getcwd(dest, dest_size) == NULL)
     774                 :          0 :                         return (NULL);
     775                 :          0 :         }
     776                 :       4046 :         dest_len = strlen(dest);
     777                 :            : 
     778   [ +  +  +  + ]:      26801 :         for (cur = next = src; next != NULL; cur = (next == NULL) ? NULL : next + 1) {
     779                 :      22755 :                 next = strchr(cur, '/');
     780         [ +  + ]:      22755 :                 if (next != NULL)
     781                 :      18709 :                         cur_len = next - cur;
     782                 :            :                 else
     783                 :       4046 :                         cur_len = strlen(cur);
     784                 :            : 
     785                 :            :                 /* check for special cases "", "." and ".." */
     786         [ +  + ]:      22755 :                 if (cur_len == 0)
     787                 :       4186 :                         continue;
     788                 :      18569 :                 else if (cur_len == 1 && cur[0] == '.')
     789                 :          0 :                         continue;
     790                 :       1099 :                 else if (cur_len == 2 && cur[0] == '.' && cur[1] == '.') {
     791                 :          0 :                         const char *slash = strrchr(dest, '/');
     792                 :          0 :                         if (slash != NULL) {
     793                 :          0 :                                 dest_len = slash - dest;
     794                 :          0 :                                 dest[dest_len] = '\0';
     795                 :          0 :                         }
     796                 :          0 :                         continue;
     797                 :            :                 }
     798                 :            : 
     799         [ -  + ]:      18569 :                 if (dest_len + 1 + cur_len >= dest_size)
     800                 :          0 :                         return (NULL);
     801                 :      18569 :                 dest[dest_len++] = '/';
     802                 :      18569 :                 (void)memcpy(dest + dest_len, cur, cur_len);
     803                 :      18569 :                 dest_len += cur_len;
     804                 :      18569 :                 dest[dest_len] = '\0';
     805                 :      18569 :         }
     806                 :            : 
     807                 :       4046 :         if (dest_len == 0) {
     808         [ #  # ]:          0 :                 if (strlcpy(dest, "/", dest_size) >= dest_size)
     809                 :          0 :                         return (NULL);
     810                 :          0 :         }
     811                 :            : 
     812                 :       4046 :         return (dest);
     813                 :       4046 : }
     814                 :            : 
     815                 :            : bool
     816                 :        120 : mkdirat_p(int fd, const char *path)
     817                 :            : {
     818                 :            :         const char *next;
     819                 :            :         char *walk, *walkorig, pathdone[MAXPATHLEN];
     820                 :            : 
     821                 :        120 :         walk = walkorig = xstrdup(path);
     822                 :        120 :         pathdone[0] = '\0';
     823                 :            : 
     824         [ +  + ]:        596 :         while ((next = strsep(&walk, "/")) != NULL) {
     825         [ +  + ]:        476 :                 if (*next == '\0')
     826                 :          4 :                         continue;
     827                 :        472 :                 strlcat(pathdone, next, sizeof(pathdone));
     828         [ +  + ]:        472 :                 if (mkdirat(fd, pathdone, 0755) == -1) {
     829         [ +  - ]:         80 :                         if (errno == EEXIST) {
     830                 :         80 :                                 strlcat(pathdone, "/", sizeof(pathdone));
     831                 :         80 :                                 continue;
     832                 :            :                         }
     833                 :          0 :                         pkg_errno("Fail to create /%s", pathdone);
     834                 :          0 :                         free(walkorig);
     835                 :          0 :                         return (false);
     836                 :            :                 }
     837                 :        392 :                 strlcat(pathdone, "/", sizeof(pathdone));
     838                 :            :         }
     839                 :        120 :         free(walkorig);
     840                 :        120 :         return (true);
     841                 :        120 : }
     842                 :            : 
     843                 :            : int
     844                 :        180 : pkg_namecmp(struct pkg *a, struct pkg *b)
     845                 :            : {
     846                 :            : 
     847                 :        180 :         return (strcmp(a->name, b->name));
     848                 :            : }
     849                 :            : 
     850                 :            : int
     851                 :        835 : get_socketpair(int *pipe)
     852                 :            : {
     853                 :            :         int r;
     854                 :            : 
     855                 :            : #ifdef HAVE_DECL_SOCK_SEQPACKET
     856                 :        835 :         r = socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, pipe);
     857                 :        835 :         if (r == -1) {
     858                 :          0 :                 r = socketpair(AF_LOCAL, SOCK_DGRAM, 0, pipe);
     859                 :          0 :         }
     860                 :            : #else
     861                 :            :         r = socketpair(AF_LOCAL, SOCK_DGRAM, 0, pipe);
     862                 :            : #endif
     863                 :            : 
     864                 :        835 :         return (r);
     865                 :            : }
     866                 :            : 
     867                 :            : char *
     868                 :        280 : get_dirname(char *d)
     869                 :            : {
     870                 :            :         char *walk;
     871                 :            : 
     872         [ -  + ]:        280 :         if (d == NULL)
     873                 :          0 :                 return (__DECONST(char *, "."));
     874                 :            : 
     875                 :        280 :         walk = strrchr(d, '/');
     876         [ +  + ]:        280 :         if (walk == NULL) {
     877                 :        108 :                 d[0] = '.';
     878                 :        108 :                 d[1] = '\0';
     879                 :        108 :         } else {
     880                 :        172 :                 *walk = '\0';
     881                 :            :         }
     882                 :            : 
     883                 :        280 :         return (d);
     884                 :        280 : }
     885                 :            : 
     886                 :            : char *
     887                 :        181 : rtrimspace(char *buf)
     888                 :            : {
     889                 :        181 :         char *cp = buf + strlen(buf) -1;
     890                 :            : 
     891         [ +  + ]:        194 :         while (cp > buf && isspace(*cp)) {
     892                 :         13 :                 *cp = 0;
     893                 :         13 :                 cp --;
     894                 :            :         }
     895                 :            : 
     896                 :        181 :         return (buf);
     897                 :            : }

Generated by: LCOV version 1.15