LCOV - code coverage report
Current view: top level - libpkg - pkg_create.c (source / functions) Hit Total Coverage
Test: plop Lines: 250 324 77.2 %
Date: 2024-12-30 07:09:03 Functions: 21 24 87.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 111 176 63.1 %

           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) 2014-2015 Matthew Seaman <matthew@FreeBSD.org>
       5                 :            :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       6                 :            :  * Copyright (c) 2023 Serenity Cyber Security, LLC
       7                 :            :  *                    Author: Gleb Popov <arrowd@FreeBSD.org>
       8                 :            :  * All rights reserved.
       9                 :            :  *
      10                 :            :  * Redistribution and use in source and binary forms, with or without
      11                 :            :  * modification, are permitted provided that the following conditions
      12                 :            :  * are met:
      13                 :            :  * 1. Redistributions of source code must retain the above copyright
      14                 :            :  *    notice, this list of conditions and the following disclaimer
      15                 :            :  *    in this position and unchanged.
      16                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      17                 :            :  *    notice, this list of conditions and the following disclaimer in the
      18                 :            :  *    documentation and/or other materials provided with the distribution.
      19                 :            :  *
      20                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      21                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      22                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      23                 :            :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      24                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      25                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      26                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      27                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      28                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      29                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      30                 :            :  */
      31                 :            : 
      32                 :            : #include <sys/stat.h>
      33                 :            : 
      34                 :            : #include <errno.h>
      35                 :            : #include <regex.h>
      36                 :            : #include <fcntl.h>
      37                 :            : 
      38                 :            : #include <bsd_compat.h>
      39                 :            : 
      40                 :            : #include "pkg.h"
      41                 :            : #include "private/event.h"
      42                 :            : #include "private/pkg.h"
      43                 :            : #include "private/pkg_abi.h"
      44                 :            : #include "xmalloc.h"
      45                 :            : 
      46                 :            : #define TICK    100
      47                 :            : 
      48                 :            : static int load_metadata(struct pkg *pkg, const char *metadata, const char *plist,
      49                 :            :     const char *rootdir);
      50                 :            : static void fixup_abi(struct pkg *pkg, const char *rootdir, bool testing);
      51                 :            : static void counter_init(const char *what, int64_t max);
      52                 :            : static void counter_count(void);
      53                 :            : static void counter_end(void);
      54                 :            : 
      55                 :            : extern struct pkg_ctx ctx;
      56                 :            : 
      57                 :            : static int
      58                 :        264 : pkg_create_from_dir(struct pkg *pkg, const char *root,
      59                 :            :     struct pkg_create *pc, struct packing *pkg_archive)
      60                 :            : {
      61                 :            :         char             fpath[MAXPATHLEN];
      62                 :        264 :         struct pkg_file *file = NULL;
      63                 :        264 :         struct pkg_dir  *dir = NULL;
      64                 :            :         int              ret;
      65                 :            :         struct stat      st;
      66                 :        264 :         int64_t          flatsize = 0;
      67                 :            :         int64_t          nfiles;
      68                 :            :         const char      *relocation;
      69                 :            :         char            *manifest;
      70                 :            :         ucl_object_t    *obj;
      71                 :            :         hardlinks_t      hardlinks;
      72                 :            : 
      73                 :        264 :         pkgvec_init(&hardlinks);
      74         [ -  + ]:        264 :         if (pkg_is_valid(pkg) != EPKG_OK) {
      75                 :          0 :                 pkg_emit_error("the package is not valid");
      76                 :          0 :                 return (EPKG_FATAL);
      77                 :            :         }
      78                 :            : 
      79                 :        264 :         relocation = pkg_kv_get(&pkg->annotations, "relocated");
      80         [ -  + ]:        264 :         if (relocation == NULL)
      81                 :        264 :                 relocation = "";
      82         [ +  - ]:        264 :         if (ctx.pkg_rootdir != NULL)
      83                 :          0 :                 relocation = ctx.pkg_rootdir;
      84                 :            : 
      85                 :            :         /*
      86                 :            :          * Get / compute size / checksum if not provided in the manifest
      87                 :            :          */
      88                 :            : 
      89                 :        264 :         nfiles = pkghash_count(pkg->filehash);
      90                 :        264 :         counter_init("file sizes/checksums", nfiles);
      91                 :            : 
      92         [ +  + ]:        477 :         while (pkg_files(pkg, &file) == EPKG_OK) {
      93                 :            : 
      94         [ +  + ]:        214 :                 snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "",
      95                 :        214 :                     relocation, file->path);
      96                 :            : 
      97         [ -  + ]:        214 :                 if (lstat(fpath, &st) == -1) {
      98                 :          0 :                         pkg_emit_error("file '%s' is missing", fpath);
      99         [ #  # ]:          0 :                         pkgvec_free_and_free(&hardlinks, free);
     100                 :          0 :                         return (EPKG_FATAL);
     101                 :            :                 }
     102                 :            : 
     103   [ +  +  +  + ]:        214 :                 if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) {
     104                 :          1 :                         pkg_emit_error("file '%s' is not a regular file or symlink", fpath);
     105         [ -  + ]:          1 :                         pkgvec_free_and_free(&hardlinks, free);
     106                 :          1 :                         return (EPKG_FATAL);
     107                 :            :                 }
     108                 :            : 
     109         [ -  + ]:        213 :                 if (file->size == 0)
     110                 :        213 :                         file->size = (int64_t)st.st_size;
     111                 :            : 
     112   [ +  +  +  + ]:        213 :                 if (st.st_nlink == 1 || !check_for_hardlink(&hardlinks, &st)) {
     113                 :        208 :                         flatsize += file->size;
     114                 :        208 :                 }
     115                 :            : 
     116                 :        213 :                 free(file->sum);
     117                 :        213 :                 file->sum = pkg_checksum_generate_file(fpath,
     118                 :            :                     PKG_HASH_TYPE_SHA256_HEX);
     119         [ +  - ]:        213 :                 if (file->sum == NULL) {
     120         [ #  # ]:          0 :                         pkgvec_free_and_free(&hardlinks, free);
     121                 :          0 :                         return (EPKG_FATAL);
     122                 :            :                 }
     123                 :            : 
     124                 :        213 :                 counter_count();
     125                 :            :         }
     126         [ +  + ]:        268 :         pkgvec_free_and_free(&hardlinks, free);
     127                 :            : 
     128                 :        263 :         counter_end();
     129                 :            : 
     130                 :        263 :         pkg->flatsize = flatsize;
     131                 :            : 
     132         [ -  + ]:        263 :         if (pkg->type == PKG_OLD_FILE) {
     133                 :          0 :                 pkg_emit_error("Cannot create an old format package");
     134                 :          0 :                 return (EPKG_FATAL);
     135                 :            :         }
     136                 :            : 
     137                 :        263 :         obj = pkg_emit_object(pkg, PKG_MANIFEST_EMIT_COMPACT);
     138                 :        263 :         manifest = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT);
     139                 :        263 :         ucl_object_unref(obj);
     140                 :        263 :         packing_append_buffer(pkg_archive, manifest, "+COMPACT_MANIFEST", strlen(manifest));
     141                 :        263 :         free(manifest);
     142                 :        263 :         obj = pkg_emit_object(pkg, 0);
     143         [ -  + ]:        263 :         if (pc->expand_manifest) {
     144                 :          0 :                 manifest = ucl_object_emit(obj, UCL_EMIT_CONFIG);
     145                 :          0 :         } else {
     146                 :        263 :                 manifest = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT);
     147                 :            :         }
     148                 :        263 :         ucl_object_unref(obj);
     149                 :        263 :         packing_append_buffer(pkg_archive, manifest, "+MANIFEST", strlen(manifest));
     150                 :        263 :         free(manifest);
     151                 :            : 
     152                 :        263 :         counter_init("packing files", nfiles);
     153                 :            : 
     154         [ +  + ]:        475 :         while (pkg_files(pkg, &file) == EPKG_OK) {
     155                 :            :                 char dpath[MAXPATHLEN];
     156                 :        212 :                 const char *dp = file->path;
     157                 :            : 
     158         [ +  + ]:        212 :                 if (pkg->oprefix != NULL) {
     159                 :          2 :                         size_t l = strlen(pkg->prefix);
     160   [ -  +  +  - ]:          4 :                         if (strncmp(file->path, pkg->prefix, l) == 0 &&
     161         [ +  - ]:          2 :                             (file->path[l] == '/' || l == 1)) {
     162                 :          4 :                                 snprintf(dpath, sizeof(dpath), "%s%s%s",
     163                 :          2 :                                     pkg->oprefix, l == 1 ? "/" : "", file->path + l);
     164                 :          2 :                                 dp = dpath;
     165                 :          2 :                         }
     166                 :          2 :                 }
     167                 :            : 
     168         [ +  + ]:        212 :                 snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "",
     169                 :        212 :                     relocation, file->path);
     170                 :            : 
     171                 :        424 :                 ret = packing_append_file_attr(pkg_archive, fpath, dp,
     172                 :        212 :                     file->uname, file->gname, file->perm, file->fflags);
     173   [ -  +  #  # ]:        212 :                 if (ctx.developer_mode && ret != EPKG_OK)
     174                 :          0 :                         return (ret);
     175                 :        212 :                 counter_count();
     176                 :            :         }
     177                 :            : 
     178                 :        263 :         counter_end();
     179                 :            : 
     180                 :        263 :         nfiles = pkghash_count(pkg->dirhash);
     181                 :        263 :         counter_init("packing directories", nfiles);
     182                 :            : 
     183         [ +  + ]:        271 :         while (pkg_dirs(pkg, &dir) == EPKG_OK) {
     184         [ +  + ]:          8 :                 snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "",
     185                 :          8 :                     relocation, dir->path);
     186                 :            : 
     187                 :         16 :                 ret = packing_append_file_attr(pkg_archive, fpath, dir->path,
     188                 :          8 :                     dir->uname, dir->gname, dir->perm, dir->fflags);
     189   [ -  +  #  # ]:          8 :                 if (ctx.developer_mode && ret != EPKG_OK)
     190                 :          0 :                         return (ret);
     191                 :          8 :                 counter_count();
     192                 :            :         }
     193                 :            : 
     194                 :        263 :         counter_end();
     195                 :            : 
     196                 :        263 :         return (EPKG_OK);
     197                 :        264 : }
     198                 :            : 
     199                 :            : static struct packing *
     200                 :        265 : pkg_create_archive(struct pkg *pkg, struct pkg_create *pc, unsigned required_flags)
     201                 :            : {
     202                 :        265 :         char            *pkg_path = NULL;
     203                 :        265 :         struct packing  *pkg_archive = NULL;
     204                 :            : 
     205                 :            :         /*
     206                 :            :          * Ensure that we have all the information we need
     207                 :            :          */
     208         [ -  + ]:        265 :         if (pkg->type != PKG_OLD_FILE)
     209         [ +  - ]:        265 :                 assert((pkg->flags & required_flags) == required_flags);
     210                 :            : 
     211         [ -  + ]:        265 :         if (pkg_mkdirs(pc->outdir) != EPKG_OK)
     212                 :          0 :                 return NULL;
     213                 :            : 
     214         [ +  - ]:        265 :         if (pkg_asprintf(&pkg_path, "%S/%n-%v", pc->outdir, pkg, pkg) == -1) {
     215                 :          0 :                 pkg_emit_errno("pkg_asprintf", "");
     216                 :          0 :                 return (NULL);
     217                 :            :         }
     218                 :            : 
     219   [ +  +  +  +  :        795 :         if (packing_init(&pkg_archive, pkg_path, pc->format,
                   +  + ]
     220                 :        530 :             pc->compression_level, pc->compression_threads, pc->timestamp, pc->overwrite, false) != EPKG_OK) {
     221                 :          1 :                 pkg_archive = NULL;
     222                 :          1 :         }
     223                 :            : 
     224                 :        265 :         free(pkg_path);
     225                 :            : 
     226                 :        265 :         return pkg_archive;
     227                 :        265 : }
     228                 :            : 
     229                 :            : static const char * const scripts[] = {
     230                 :            :         "+INSTALL",
     231                 :            :         "+PRE_INSTALL",
     232                 :            :         "+POST_INSTALL",
     233                 :            :         "+POST_INSTALL",
     234                 :            :         "+DEINSTALL",
     235                 :            :         "+PRE_DEINSTALL",
     236                 :            :         "+POST_DEINSTALL",
     237                 :            :         "pkg-install",
     238                 :            :         "pkg-pre-install",
     239                 :            :         "pkg-post-install",
     240                 :            :         "pkg-deinstall",
     241                 :            :         "pkg-pre-deinstall",
     242                 :            :         "pkg-post-deinstall",
     243                 :            :         NULL
     244                 :            : };
     245                 :            : 
     246                 :            : static const char * const lua_scripts[] = {
     247                 :            :         "pkg-pre-install.lua",
     248                 :            :         "pkg-post-install.lua",
     249                 :            :         "pkg-pre-deinstall.lua",
     250                 :            :         "pkg-post-deinstall.lua",
     251                 :            :         NULL
     252                 :            : };
     253                 :            : 
     254                 :            : struct pkg_create *
     255                 :        281 : pkg_create_new(void)
     256                 :            : {
     257                 :            :         struct pkg_create *pc;
     258                 :            : 
     259                 :        281 :         pc = xcalloc(1, sizeof(*pc));
     260                 :        281 :         pc->format = packing_format_from_string(ctx.compression_format);
     261                 :        281 :         pc->compression_level = ctx.compression_level;
     262                 :        281 :         pc->compression_threads = ctx.compression_threads;
     263                 :        281 :         pc->timestamp = (time_t) -1;
     264                 :        281 :         pc->overwrite = true;
     265                 :        281 :         pc->expand_manifest = false;
     266                 :            : 
     267                 :        281 :         return (pc);
     268                 :            : }
     269                 :            : 
     270                 :            : void
     271                 :        281 : pkg_create_free(struct pkg_create *pc)
     272                 :            : {
     273                 :        281 :         free(pc);
     274                 :        281 : }
     275                 :            : 
     276                 :            : bool
     277                 :          3 : pkg_create_set_format(struct pkg_create *pc, const char *format)
     278                 :            : {
     279         [ +  - ]:          3 :         if (STREQ(format, "tzst"))
     280                 :          0 :                 pc->format = TZS;
     281         [ +  + ]:          3 :         else if (STREQ(format, "txz"))
     282                 :          2 :                 pc->format = TXZ;
     283         [ +  - ]:          1 :         else if (STREQ(format, "tbz"))
     284                 :          0 :                 pc->format = TBZ;
     285         [ +  - ]:          1 :         else if (STREQ(format, "tgz"))
     286                 :          0 :                 pc->format = TGZ;
     287         [ -  + ]:          1 :         else if (STREQ(format, "tar"))
     288                 :          1 :                 pc->format = TAR;
     289                 :            :         else
     290                 :          0 :                 return (false);
     291                 :          3 :         return (true);
     292                 :          3 : }
     293                 :            : 
     294                 :            : void
     295                 :          0 : pkg_create_set_compression_level(struct pkg_create *pc, int clevel)
     296                 :            : {
     297                 :          0 :         pc->compression_level = clevel;
     298                 :          0 : }
     299                 :            : 
     300                 :            : void
     301                 :          0 : pkg_create_set_compression_threads(struct pkg_create *pc, int threads)
     302                 :            : {
     303                 :          0 :         pc->compression_threads = threads;
     304                 :          0 : }
     305                 :            : 
     306                 :            : void
     307                 :        281 : pkg_create_set_expand_manifest(struct pkg_create *pc, bool expand)
     308                 :            : {
     309                 :        281 :         pc->expand_manifest = expand;
     310                 :        281 : }
     311                 :            : 
     312                 :            : void
     313                 :        281 : pkg_create_set_rootdir(struct pkg_create *pc, const char *rootdir)
     314                 :            : {
     315                 :        281 :         pc->rootdir = rootdir;
     316                 :        281 : }
     317                 :            : 
     318                 :            : void
     319                 :        281 : pkg_create_set_output_dir(struct pkg_create *pc, const char *outdir)
     320                 :            : {
     321                 :        281 :         pc->outdir = outdir;
     322                 :        281 : }
     323                 :            : 
     324                 :            : void
     325                 :          2 : pkg_create_set_timestamp(struct pkg_create *pc, time_t timestamp)
     326                 :            : {
     327                 :          2 :         pc->timestamp = timestamp;
     328                 :          2 : }
     329                 :            : 
     330                 :            : void
     331                 :        281 : pkg_create_set_overwrite(struct pkg_create *pc, bool overwrite)
     332                 :            : {
     333                 :        281 :         pc->overwrite = overwrite;
     334                 :        281 : }
     335                 :            : 
     336                 :            : static int
     337                 :          1 : hash_file(struct pkg *pkg)
     338                 :            : {
     339                 :            :         char hash_dest[MAXPATHLEN];
     340                 :            :         char filename[MAXPATHLEN];
     341                 :            : 
     342                 :            :         /* Find the hash and rename the file and create a symlink */
     343                 :          2 :         pkg_snprintf(filename, sizeof(filename), "%n-%v.pkg",
     344                 :          1 :                         pkg, pkg);
     345                 :          1 :         pkg->sum = pkg_checksum_file(filename,
     346                 :            :                         PKG_HASH_TYPE_SHA256_HEX);
     347                 :          2 :         pkg_snprintf(hash_dest, sizeof(hash_dest), "%n-%v-%z.pkg",
     348                 :          1 :                         pkg, pkg, pkg);
     349                 :            : 
     350                 :          1 :         pkg_debug(1, "Rename the pkg file from: %s to: %s",
     351                 :          1 :                         filename, hash_dest);
     352         [ +  - ]:          1 :         if (rename(filename, hash_dest) == -1) {
     353                 :          0 :                 pkg_emit_errno("rename", hash_dest);
     354                 :          0 :                 unlink(hash_dest);
     355                 :          0 :                 return (EPKG_FATAL);
     356                 :            :         }
     357         [ +  - ]:          1 :         if (symlink(hash_dest, filename) == -1) {
     358                 :          0 :                 pkg_emit_errno("symlink", hash_dest);
     359                 :          0 :                 return (EPKG_FATAL);
     360                 :            :         }
     361                 :          1 :         return (EPKG_OK);
     362                 :          1 : }
     363                 :            : 
     364                 :            : int
     365                 :          0 : pkg_create_i(struct pkg_create *pc, struct pkg *pkg, bool hash)
     366                 :            : {
     367                 :          0 :         struct packing *pkg_archive = NULL;
     368                 :            :         int ret;
     369                 :            : 
     370                 :          0 :         unsigned required_flags = PKG_LOAD_DEPS | PKG_LOAD_FILES |
     371                 :            :                 PKG_LOAD_CATEGORIES | PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS |
     372                 :            :                 PKG_LOAD_OPTIONS | PKG_LOAD_LICENSES | PKG_LOAD_LUA_SCRIPTS;
     373                 :            : 
     374   [ #  #  #  # ]:          0 :         assert(pkg->type == PKG_INSTALLED || pkg->type == PKG_OLD_FILE);
     375                 :            : 
     376                 :          0 :         pkg_archive = pkg_create_archive(pkg, pc, required_flags);
     377         [ #  # ]:          0 :         if (pkg_archive == NULL) {
     378         [ #  # ]:          0 :                 if (errno == EEXIST)
     379                 :          0 :                         return (EPKG_EXIST);
     380                 :          0 :                 pkg_emit_error("unable to create archive");
     381                 :          0 :                 return (EPKG_FATAL);
     382                 :            :         }
     383                 :            : 
     384         [ #  # ]:          0 :         if ((ret = pkg_create_from_dir(pkg, NULL, pc, pkg_archive)) != EPKG_OK) {
     385                 :          0 :                 pkg_emit_error("package creation failed");
     386                 :          0 :         }
     387                 :          0 :         packing_finish(pkg_archive);
     388                 :            : 
     389   [ #  #  #  # ]:          0 :         if (hash && ret == EPKG_OK)
     390                 :          0 :                 ret = hash_file(pkg);
     391                 :            : 
     392                 :          0 :         return (ret);
     393                 :          0 : }
     394                 :            : 
     395                 :            : int
     396                 :        281 : pkg_create(struct pkg_create *pc, const char *metadata, const char *plist,
     397                 :            :     bool hash)
     398                 :            : {
     399                 :        281 :         struct pkg *pkg = NULL;
     400                 :        281 :         struct packing *pkg_archive = NULL;
     401                 :        281 :         int ret = ENOMEM;
     402                 :            : 
     403                 :        281 :         pkg_debug(1, "Creating package");
     404         [ -  + ]:        281 :         if (pkg_new(&pkg, PKG_FILE) != EPKG_OK) {
     405                 :          0 :                 return (EPKG_FATAL);
     406                 :            :         }
     407                 :            : 
     408         [ +  + ]:        281 :         if (load_metadata(pkg, metadata, plist, pc->rootdir) != EPKG_OK) {
     409                 :         16 :                 pkg_free(pkg);
     410                 :         16 :                 return (EPKG_FATAL);
     411                 :            :         }
     412                 :        265 :         fixup_abi(pkg, pc->rootdir, false);
     413                 :            : 
     414                 :        265 :         pkg_archive = pkg_create_archive(pkg, pc, 0);
     415         [ +  + ]:        265 :         if (pkg_archive == NULL) {
     416         [ +  - ]:          1 :                 if (errno == EEXIST) {
     417                 :          1 :                         pkg_emit_notice("%s-%s already packaged, skipping...\n",
     418                 :          1 :                             pkg->name, pkg->version);
     419                 :          1 :                         pkg_free(pkg);
     420                 :          1 :                         return (EPKG_EXIST);
     421                 :            :                 }
     422                 :          0 :                 pkg_free(pkg);
     423                 :          0 :                 return (EPKG_FATAL);
     424                 :            :         }
     425                 :            : 
     426         [ +  + ]:        264 :         if ((ret = pkg_create_from_dir(pkg, pc->rootdir, pc, pkg_archive)) != EPKG_OK)
     427                 :          1 :                 pkg_emit_error("package creation failed");
     428                 :            : 
     429                 :        264 :         packing_finish(pkg_archive);
     430   [ +  +  -  + ]:        264 :         if (hash && ret == EPKG_OK)
     431                 :          1 :                 ret = hash_file(pkg);
     432                 :            : 
     433                 :        264 :         pkg_free(pkg);
     434                 :        264 :         return (ret);
     435                 :        281 : }
     436                 :            : 
     437                 :            : static int
     438                 :         36 : pkg_load_message_from_file(int fd, struct pkg *pkg, const char *path)
     439                 :            : {
     440                 :         36 :         char *buf = NULL;
     441                 :         36 :         off_t size = 0;
     442                 :            :         int ret;
     443                 :            :         ucl_object_t *obj;
     444                 :            : 
     445         [ +  - ]:         36 :         assert(pkg != NULL);
     446         [ +  - ]:         36 :         assert(path != NULL);
     447                 :            : 
     448         [ +  + ]:         36 :         if (faccessat(fd, path, F_OK, 0) == -1) {
     449                 :         31 :                 return (EPKG_FATAL);
     450                 :            :         }
     451                 :            : 
     452                 :          5 :         pkg_debug(1, "Reading message: '%s'", path);
     453         [ -  + ]:          5 :         if ((ret = file_to_bufferat(fd, path, &buf, &size)) != EPKG_OK) {
     454                 :          0 :                 return (ret);
     455                 :            :         }
     456                 :            : 
     457         [ +  + ]:          5 :         if (*buf == '[') {
     458                 :          2 :                 ret = pkg_message_from_str(pkg, buf, size);
     459                 :          2 :                 free(buf);
     460                 :          2 :                 return (ret);
     461                 :            :         }
     462                 :          3 :         obj = ucl_object_fromstring_common(buf, size,
     463                 :            :             UCL_STRING_RAW|UCL_STRING_TRIM);
     464                 :          3 :         ret = pkg_message_from_ucl(pkg, obj);
     465                 :          3 :         ucl_object_unref(obj);
     466                 :          3 :         free(buf);
     467                 :            : 
     468                 :          3 :         return (ret);
     469                 :         36 : }
     470                 :            : 
     471                 :            : /* TODO use file descriptor for rootdir */
     472                 :            : static int
     473                 :        322 : load_manifest(struct pkg *pkg, const char *metadata, const char *plist,
     474                 :            :     const char *rootdir)
     475                 :            : {
     476                 :            :         int ret;
     477                 :            : 
     478                 :        322 :         ret = pkg_parse_manifest_file(pkg, metadata);
     479                 :            : 
     480   [ +  +  +  + ]:        322 :         if (ret == EPKG_OK && plist != NULL)
     481                 :         44 :                 ret = ports_parse_plist(pkg, plist, rootdir);
     482                 :        322 :         return (ret);
     483                 :            : }
     484                 :            : 
     485                 :            : /* TODO use file descriptor for rootdir */
     486                 :            : static int
     487                 :        359 : load_metadata(struct pkg *pkg, const char *metadata, const char *plist,
     488                 :            :     const char *rootdir)
     489                 :            : {
     490                 :            :         regex_t preg;
     491                 :            :         regmatch_t pmatch[2];
     492                 :            :         size_t size;
     493                 :            :         int fd, i;
     494                 :            : 
     495                 :            :         /* Let's see if we have a directory or a manifest */
     496         [ +  + ]:        359 :         if ((fd = open(metadata, O_DIRECTORY|O_CLOEXEC)) == -1) {
     497         [ +  - ]:        322 :                 if (errno == ENOTDIR)
     498                 :        322 :                         return (load_manifest(pkg, metadata, plist, rootdir));
     499                 :          0 :                 pkg_emit_errno("open", metadata);
     500                 :          0 :                 return (EPKG_FATAL);
     501                 :            :         }
     502                 :            : 
     503         [ +  + ]:         37 :         if ((pkg_parse_manifest_fileat(fd, pkg, "+MANIFEST")) != EPKG_OK) {
     504                 :          1 :                 close(fd);
     505                 :          1 :                 return (EPKG_FATAL);
     506                 :            :         }
     507                 :            : 
     508                 :         36 :         pkg_load_message_from_file(fd, pkg, "+DISPLAY");
     509         [ +  - ]:         36 :         if (pkg->desc == NULL)
     510                 :          0 :                 pkg_set_from_fileat(fd, pkg, PKG_ATTR_DESC, "+DESC", false);
     511                 :            : 
     512         [ +  + ]:        504 :         for (i = 0; scripts[i] != NULL; i++) {
     513         [ +  - ]:        468 :                 if (faccessat(fd, scripts[i], F_OK, 0) == 0)
     514                 :          0 :                         pkg_addscript_fileat(fd, pkg, scripts[i]);
     515                 :        468 :         }
     516                 :            : 
     517         [ +  + ]:        180 :         for (i = 0; lua_scripts[i] != NULL; i++) {
     518         [ +  - ]:        144 :                 if (faccessat(fd, lua_scripts[i], F_OK, 0) == 0)
     519                 :          0 :                         pkg_addluascript_fileat(fd, pkg, lua_scripts[i]);
     520                 :        144 :         }
     521                 :            : 
     522   [ +  +  +  + ]:         36 :         if (plist != NULL && ports_parse_plist(pkg, plist, rootdir) != EPKG_OK) {
     523                 :         13 :                 return (EPKG_FATAL);
     524                 :            :         }
     525                 :         23 :         close(fd);
     526                 :            : 
     527         [ +  - ]:         23 :         if (pkg->www == NULL) {
     528         [ #  # ]:          0 :                 if (pkg->desc == NULL) {
     529                 :          0 :                         pkg_emit_error("No www or desc defined in manifest");
     530                 :          0 :                         return (EPKG_FATAL);
     531                 :            :                 }
     532                 :          0 :                 regcomp(&preg, "^WWW:[[:space:]]*(.*)$",
     533                 :            :                     REG_EXTENDED|REG_ICASE|REG_NEWLINE);
     534         [ #  # ]:          0 :                 if (regexec(&preg, pkg->desc, 2, pmatch, 0) == 0) {
     535                 :          0 :                         size = pmatch[1].rm_eo - pmatch[1].rm_so;
     536                 :          0 :                         pkg->www = xstrndup(&pkg->desc[pmatch[1].rm_so], size);
     537                 :          0 :                 } else {
     538                 :          0 :                         pkg->www = xstrdup("UNKNOWN");
     539                 :            :                 }
     540                 :          0 :                 regfree(&preg);
     541                 :          0 :         }
     542                 :            : 
     543                 :         23 :         return (EPKG_OK);
     544                 :        359 : }
     545                 :            : 
     546                 :            : static void
     547                 :        342 : fixup_abi(struct pkg *pkg, const char *rootdir, bool testing)
     548                 :            : {
     549                 :        342 :         bool defaultarch = false;
     550                 :            : 
     551                 :            :         /* if no arch autodetermine it */
     552         [ +  + ]:        342 :         if (pkg->abi == NULL) {
     553         [ +  + ]:        222 :                 if (ctx.abi.os == PKG_OS_FREEBSD) {
     554                 :            :                         char *str_osversion;
     555                 :        211 :                         xasprintf(&str_osversion, "%d", pkg_abi_get_freebsd_osversion(&ctx.abi));
     556                 :        211 :                         pkg_kv_add(&pkg->annotations, "FreeBSD_version", str_osversion, "annotation");
     557                 :        211 :                 }
     558                 :        222 :                 pkg->abi = pkg_abi_to_string(&ctx.abi);
     559                 :        222 :                 defaultarch = true;
     560                 :        222 :         }
     561                 :            : 
     562         [ +  + ]:        342 :         if (!testing)
     563                 :        330 :                 pkg_analyse_files(NULL, pkg, rootdir);
     564                 :            : 
     565         [ +  - ]:        342 :         if (ctx.developer_mode)
     566                 :          0 :                 suggest_arch(pkg, defaultarch);
     567                 :        342 : }
     568                 :            : 
     569                 :            : int
     570                 :         78 : pkg_load_metadata(struct pkg *pkg, const char *mfile, const char *md_dir,
     571                 :            :     const char *plist, const char *rootdir, bool testing)
     572                 :            : {
     573                 :            :         int ret;
     574                 :            : 
     575         [ +  + ]:         78 :         ret = load_metadata(pkg, md_dir != NULL ? md_dir: mfile, plist, rootdir);
     576         [ +  + ]:         78 :         if (ret != EPKG_OK)
     577                 :          1 :                 return (ret);
     578                 :            : 
     579                 :         77 :         fixup_abi(pkg, rootdir, testing);
     580                 :         77 :         return (ret);
     581                 :         78 : }
     582                 :            : 
     583                 :            : static int64_t  count;
     584                 :            : static int64_t  maxcount;
     585                 :            : static const char *what;
     586                 :            : 
     587                 :        790 : static int magnitude(int64_t num)
     588                 :            : {
     589                 :            :         int oom;
     590                 :            : 
     591         [ +  + ]:        790 :         if (num == 0)
     592                 :        436 :                 return (1);
     593         [ +  - ]:        354 :         if (num < 0)
     594                 :          0 :                 num = -num;
     595                 :            : 
     596         [ -  + ]:        354 :         for (oom = 1; num >= 10; oom++)
     597                 :          0 :                 num /= 10;
     598                 :            : 
     599                 :        354 :         return (oom);
     600                 :        790 : }
     601                 :            : 
     602                 :            : static void
     603                 :        790 : counter_init(const char *count_what, int64_t max)
     604                 :            : {
     605                 :        790 :         count = 0;
     606                 :        790 :         what = count_what;
     607                 :        790 :         maxcount = max;
     608                 :       1580 :         pkg_emit_progress_start("%-20s%*s[%jd]", what,
     609                 :        790 :             6 - magnitude(maxcount), " ", (intmax_t)maxcount);
     610                 :            : 
     611                 :        790 :         return;
     612                 :            : }
     613                 :            : 
     614                 :            : static void
     615                 :        433 : counter_count(void)
     616                 :            : {
     617                 :        433 :         count++;
     618                 :            : 
     619         [ +  - ]:        433 :         if (count % TICK == 0)
     620                 :          0 :                 pkg_emit_progress_tick(count, maxcount);
     621                 :            : 
     622                 :        433 :         return;
     623                 :            : }
     624                 :            : 
     625                 :            : static void
     626                 :        789 : counter_end(void)
     627                 :            : {
     628                 :        789 :         pkg_emit_progress_tick(count, maxcount);
     629                 :        789 :         return;
     630                 :            : }

Generated by: LCOV version 1.15