LCOV - code coverage report
Current view: top level - libpkg - pkg_repo_create.c (source / functions) Hit Total Coverage
Test: rapport Lines: 405 719 56.3 %
Date: 2021-12-10 16:22:55 Functions: 11 13 84.6 %
Branches: 120 257 46.7 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * Copyright (c) 2011-2021 Baptiste Daroussin <bapt@FreeBSD.org>
       3                 :            :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       4                 :            :  * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
       5                 :            :  * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
       6                 :            :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       7                 :            :  *
       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                 :            : #include "pkg_config.h"
      32                 :            : 
      33                 :            : #include <sys/types.h>
      34                 :            : #include <sys/stat.h>
      35                 :            : #include <sys/wait.h>
      36                 :            : #include <sys/socket.h>
      37                 :            : #include <sys/file.h>
      38                 :            : #include <sys/time.h>
      39                 :            : 
      40                 :            : #include <archive_entry.h>
      41                 :            : #include <assert.h>
      42                 :            : #include <fts.h>
      43                 :            : #include <libgen.h>
      44                 :            : #include <sqlite3.h>
      45                 :            : #include <string.h>
      46                 :            : #include <stdio.h>
      47                 :            : #include <stdbool.h>
      48                 :            : #include <unistd.h>
      49                 :            : #include <errno.h>
      50                 :            : #include <fcntl.h>
      51                 :            : #include <math.h>
      52                 :            : #include <poll.h>
      53                 :            : #include <sys/uio.h>
      54                 :            : #include <msgpuck.h>
      55                 :            : 
      56                 :            : #include "pkg.h"
      57                 :            : #include "private/event.h"
      58                 :            : #include "private/utils.h"
      59                 :            : #include "private/pkg.h"
      60                 :            : #include "private/pkgdb.h"
      61                 :            : 
      62                 :            : enum {
      63                 :            :         MSG_PKG_DONE=0,
      64                 :            :         MSG_PKG_READY,
      65                 :            :         MSG_DIGEST,
      66                 :            : };
      67                 :            : 
      68                 :            : struct digest_list_entry {
      69                 :            :         char *origin;
      70                 :            :         char *digest;
      71                 :            :         long manifest_pos;
      72                 :            :         long files_pos;
      73                 :            :         long manifest_length;
      74                 :            :         char *checksum;
      75                 :            :         struct digest_list_entry *prev, *next;
      76                 :            : };
      77                 :            : 
      78                 :            : struct pkg_conflict_bulk {
      79                 :            :         struct pkg_conflict *conflicts;
      80                 :            :         pkghash *conflictshash;
      81                 :            :         char *file;
      82                 :            : };
      83                 :            : 
      84                 :            : static int
      85                 :          0 : hash_file(struct pkg_repo_meta *meta, struct pkg *pkg, char *path)
      86                 :            : {
      87                 :          0 :         char tmp_repo[MAXPATHLEN] = { 0 };
      88                 :          0 :         char tmp_name[MAXPATHLEN] = { 0 };
      89                 :          0 :         char repo_name[MAXPATHLEN] = { 0 };
      90                 :          0 :         char hash_name[MAXPATHLEN] = { 0 };
      91                 :          0 :         char link_name[MAXPATHLEN] = { 0 };
      92                 :          0 :         char *rel_repo = NULL;
      93                 :          0 :         char *rel_dir = NULL;
      94                 :          0 :         char *rel_link = NULL;
      95                 :          0 :         char *ext = NULL;
      96                 :            : 
      97                 :            :         /* Don't rename symlinks */
      98         [ #  # ]:          0 :         if (is_link(path))
      99                 :          0 :                 return (EPKG_OK);
     100                 :            : 
     101                 :          0 :         ext = strrchr(path, '.');
     102                 :            : 
     103                 :          0 :         strlcpy(tmp_name, path, sizeof(tmp_name));
     104                 :          0 :         rel_dir = get_dirname(tmp_name);
     105         [ #  # ]:          0 :         while (strstr(rel_dir, "/Hashed") != NULL) {
     106                 :          0 :                 rel_dir = get_dirname(rel_dir);
     107                 :            :         }
     108                 :          0 :         strlcpy(tmp_name, rel_dir, sizeof(tmp_name));
     109                 :          0 :         rel_dir = (char *)&tmp_name;
     110                 :            : 
     111                 :          0 :         rel_repo = path;
     112                 :          0 :         if (strncmp(rel_repo, meta->repopath, strlen(meta->repopath)) == 0) {
     113                 :          0 :                 rel_repo += strlen(meta->repopath);
     114         [ #  # ]:          0 :                 while (rel_repo[0] == '/')
     115                 :          0 :                         rel_repo++;
     116                 :          0 :         }
     117                 :          0 :         strlcpy(tmp_repo, rel_repo, sizeof(tmp_repo));
     118                 :          0 :         rel_repo = get_dirname(tmp_repo);
     119         [ #  # ]:          0 :         while (strstr(rel_repo, "/Hashed") != NULL) {
     120                 :          0 :                 rel_repo = get_dirname(rel_repo);
     121                 :            :         }
     122                 :          0 :         strlcpy(tmp_repo, rel_repo, sizeof(tmp_repo));
     123                 :          0 :         rel_repo = (char *)&tmp_repo;
     124                 :            : 
     125                 :          0 :         pkg_snprintf(repo_name, sizeof(repo_name), "%S/%S/%n-%v%S%z%S",
     126                 :          0 :             rel_repo, PKG_HASH_DIR, pkg, pkg, PKG_HASH_SEPSTR, pkg, ext);
     127                 :          0 :         pkg_snprintf(link_name, sizeof(repo_name), "%S/%n-%v%S",
     128                 :          0 :             rel_dir, pkg, pkg, ext);
     129                 :          0 :         pkg_snprintf(hash_name, sizeof(hash_name), "%S/%S/%n-%v%S%z%S",
     130                 :          0 :             rel_dir, PKG_HASH_DIR, pkg, pkg, PKG_HASH_SEPSTR, pkg, ext);
     131                 :          0 :         rel_link = (char *)&hash_name;
     132                 :          0 :         rel_link += strlen(rel_dir);
     133         [ #  # ]:          0 :         while (rel_link[0] == '/')
     134                 :          0 :                 rel_link++;
     135                 :            : 
     136                 :          0 :         snprintf(tmp_name, sizeof(tmp_name), "%s/%s", rel_dir, PKG_HASH_DIR);
     137                 :          0 :         rel_dir = (char *)&tmp_name;
     138                 :          0 :         if (!is_dir(rel_dir)) {
     139                 :          0 :                 pkg_debug(1, "Making directory: %s", rel_dir);
     140                 :          0 :                 (void)mkdirs(rel_dir);
     141                 :          0 :         }
     142                 :            : 
     143                 :          0 :         if (strcmp(path, hash_name) != 0) {
     144                 :          0 :                 pkg_debug(1, "Rename the pkg from: %s to: %s", path, hash_name);
     145         [ #  # ]:          0 :                 if (rename(path, hash_name) == -1) {
     146                 :          0 :                         pkg_emit_errno("rename", hash_name);
     147                 :          0 :                         return (EPKG_FATAL);
     148                 :            :                 }
     149                 :          0 :         }
     150                 :          0 :         if (meta->hash_symlink) {
     151                 :          0 :                 pkg_debug(1, "Symlinking pkg file from: %s to: %s", rel_link,
     152                 :          0 :                     link_name);
     153                 :          0 :                 (void)unlink(link_name);
     154         [ #  # ]:          0 :                 if (symlink(rel_link, link_name) == -1) {
     155                 :          0 :                         pkg_emit_errno("symlink", link_name);
     156                 :          0 :                         return (EPKG_FATAL);
     157                 :            :                 }
     158                 :          0 :         }
     159                 :          0 :         free(pkg->repopath);
     160                 :          0 :         pkg->repopath = xstrdup(repo_name);
     161                 :            : 
     162                 :          0 :         return (EPKG_OK);
     163                 :          0 : }
     164                 :            : 
     165                 :            : static int
     166                 :          4 : pkg_digest_sort_compare_func(struct digest_list_entry *d1,
     167                 :            :                 struct digest_list_entry *d2)
     168                 :            : {
     169                 :          4 :         return strcmp(d1->origin, d2->origin);
     170                 :            : }
     171                 :            : 
     172                 :            : struct pkg_fts_item {
     173                 :            :         char *fts_accpath;
     174                 :            :         char *pkg_path;
     175                 :            :         char *fts_name;
     176                 :            :         off_t fts_size;
     177                 :            :         int fts_info;
     178                 :            :         struct pkg_fts_item *next;
     179                 :            : };
     180                 :            : 
     181                 :            : static struct pkg_fts_item*
     182                 :        534 : pkg_create_repo_fts_new(FTSENT *fts, const char *root_path)
     183                 :            : {
     184                 :            :         struct pkg_fts_item *item;
     185                 :            :         char *pkg_path;
     186                 :            : 
     187                 :        534 :         item = xmalloc(sizeof(*item));
     188                 :        534 :         item->fts_accpath = xstrdup(fts->fts_accpath);
     189                 :        534 :         item->fts_name = xstrdup(fts->fts_name);
     190                 :        534 :         item->fts_size = fts->fts_statp->st_size;
     191                 :        534 :         item->fts_info = fts->fts_info;
     192                 :            : 
     193                 :        534 :         pkg_path = fts->fts_path;
     194                 :        534 :         pkg_path += strlen(root_path);
     195         [ +  + ]:       1068 :         while (pkg_path[0] == '/')
     196                 :        534 :                 pkg_path++;
     197                 :            : 
     198                 :        534 :         item->pkg_path = xstrdup(pkg_path);
     199                 :            : 
     200                 :        534 :         return (item);
     201                 :            : }
     202                 :            : 
     203                 :            : static void
     204                 :          0 : pkg_create_repo_fts_free(struct pkg_fts_item *item)
     205                 :            : {
     206                 :          0 :         free(item->fts_accpath);
     207                 :          0 :         free(item->pkg_path);
     208                 :          0 :         free(item->fts_name);
     209                 :          0 :         free(item);
     210                 :          0 : }
     211                 :            : 
     212                 :            : static int
     213                 :        277 : pkg_create_repo_read_fts(struct pkg_fts_item **items, FTS *fts,
     214                 :            :         const char *repopath, size_t *plen, struct pkg_repo_meta *meta)
     215                 :            : {
     216                 :            :         FTSENT *fts_ent;
     217                 :            :         struct pkg_fts_item *fts_cur;
     218                 :            :         char *ext;
     219                 :        277 :         int linklen = 0;
     220                 :        277 :         char tmp_name[MAXPATHLEN] = { 0 };
     221                 :            :         char repo_path[MAXPATHLEN];
     222                 :            :         size_t repo_path_len;
     223                 :            : 
     224         [ -  + ]:        277 :         if (realpath(repopath, repo_path) == NULL) {
     225                 :          0 :                 pkg_emit_errno("invalid repo path", repopath);
     226                 :          0 :                 return (EPKG_FATAL);
     227                 :            :         }
     228                 :        277 :         repo_path_len = strlen(repo_path);
     229                 :        277 :         errno = 0;
     230                 :            : 
     231         [ +  + ]:       4027 :         while ((fts_ent = fts_read(fts)) != NULL) {
     232                 :            :                 /*
     233                 :            :                  * Skip directories starting with '.' to avoid Poudriere
     234                 :            :                  * symlinks.
     235                 :            :                  */
     236                 :       4826 :                 if ((fts_ent->fts_info == FTS_D ||
     237                 :       2994 :                     fts_ent->fts_info == FTS_DP) &&
     238                 :       1076 :                     fts_ent->fts_namelen > 2 &&
     239                 :       1076 :                     fts_ent->fts_name[0] == '.') {
     240                 :          0 :                         fts_set(fts, fts_ent, FTS_SKIP);
     241                 :          0 :                         continue;
     242                 :            :                 }
     243                 :            :                 /*
     244                 :            :                  * Ignore 'Latest' directory as it is just symlinks back to
     245                 :            :                  * already-processed packages.
     246                 :            :                  */
     247                 :       2994 :                 if ((fts_ent->fts_info == FTS_D ||
     248                 :       2994 :                     fts_ent->fts_info == FTS_DP ||
     249                 :       2238 :                     fts_ent->fts_info == FTS_SL) &&
     250                 :         16 :                     strcmp(fts_ent->fts_name, "Latest") == 0) {
     251                 :         16 :                         fts_set(fts, fts_ent, FTS_SKIP);
     252                 :         16 :                         continue;
     253                 :            :                 }
     254                 :            :                 /* Follow symlinks. */
     255         [ +  + ]:       3734 :                 if (fts_ent->fts_info == FTS_SL) {
     256                 :            :                         /*
     257                 :            :                          * Skip symlinks pointing inside the repo
     258                 :            :                          * and dead symlinks
     259                 :            :                          */
     260         [ +  + ]:         82 :                         if (realpath(fts_ent->fts_path, tmp_name) == NULL)
     261                 :         14 :                                 continue;
     262         [ +  + ]:         68 :                         if (strncmp(repo_path, tmp_name, repo_path_len) == 0)
     263                 :         64 :                                 continue;
     264                 :            :                         /* Skip symlinks to hashed packages */
     265                 :          4 :                         if (meta->hash) {
     266                 :          0 :                                 linklen = readlink(fts_ent->fts_path,
     267                 :          0 :                                     (char *)&tmp_name, MAXPATHLEN);
     268         [ #  # ]:          0 :                                 if (linklen < 0)
     269                 :          0 :                                         continue;
     270                 :          0 :                                 tmp_name[linklen] = '\0';
     271         [ #  # ]:          0 :                                 if (strstr(tmp_name, PKG_HASH_DIR) != NULL)
     272                 :          0 :                                         continue;
     273                 :          0 :                         }
     274                 :          4 :                         fts_set(fts, fts_ent, FTS_FOLLOW);
     275                 :            :                         /* Restart. Next entry will be the resolved file. */
     276                 :          4 :                         continue;
     277                 :            :                 }
     278                 :            :                 /* Skip everything that is not a file */
     279         [ +  + ]:       3652 :                 if (fts_ent->fts_info != FTS_F)
     280                 :       1496 :                         continue;
     281                 :            : 
     282                 :       2156 :                 ext = strrchr(fts_ent->fts_name, '.');
     283                 :            : 
     284         [ +  + ]:       2156 :                 if (ext == NULL)
     285                 :        530 :                         continue;
     286                 :            : 
     287         [ +  + ]:       1626 :                 if (!packing_is_valid_format(ext + 1))
     288                 :       1044 :                         continue;
     289                 :            : 
     290                 :            :                 /* skip all files which are not .pkg */
     291                 :        582 :                 if (!ctx.repo_accept_legacy_pkg && strcmp(ext + 1, "pkg") != 0)
     292                 :          0 :                         continue;
     293                 :            : 
     294                 :            : 
     295                 :        582 :                 *ext = '\0';
     296                 :            : 
     297         [ +  + ]:        582 :                 if (pkg_repo_meta_is_old_file(fts_ent->fts_name, meta)) {
     298                 :          4 :                         unlink(fts_ent->fts_path);
     299                 :          4 :                         continue;
     300                 :            :                 }
     301                 :        578 :                 if (strcmp(fts_ent->fts_name, "meta") == 0 ||
     302                 :        558 :                                 pkg_repo_meta_is_special_file(fts_ent->fts_name, meta)) {
     303                 :         44 :                         *ext = '.';
     304                 :         44 :                         continue;
     305                 :            :                 }
     306                 :            : 
     307                 :        534 :                 *ext = '.';
     308                 :        534 :                 fts_cur = pkg_create_repo_fts_new(fts_ent, repopath);
     309         [ -  + ]:        534 :                 if (fts_cur == NULL)
     310                 :          0 :                         return (EPKG_FATAL);
     311                 :            : 
     312                 :        534 :                 LL_PREPEND(*items, fts_cur);
     313                 :        534 :                 (*plen) ++;
     314                 :            :         }
     315                 :            : 
     316         [ -  + ]:        277 :         if (errno != 0) {
     317                 :          0 :                 pkg_emit_errno("fts_read", "pkg_create_repo_read_fts");
     318                 :          0 :                 return (EPKG_FATAL);
     319                 :            :         }
     320                 :            : 
     321                 :        277 :         return (EPKG_OK);
     322                 :        277 : }
     323                 :            : 
     324                 :            : static void
     325                 :       1068 : tell_parent(int fd, char *buf, size_t len)
     326                 :            : {
     327                 :            :         struct iovec iov[2];
     328                 :            :         struct msghdr msg;
     329                 :            : 
     330                 :       1068 :         iov[0].iov_base = buf;
     331                 :       1068 :         iov[0].iov_len = len;
     332                 :       1068 :         memset(&msg, 0, sizeof(msg));
     333                 :       1068 :         msg.msg_iov = iov;
     334                 :       1068 :         msg.msg_iovlen = 1;
     335                 :       1068 :         sendmsg(fd, &msg, MSG_EOR);
     336                 :       1068 : }
     337                 :            : 
     338                 :            : static int
     339                 :        534 : pkg_create_repo_worker(int mfd, int ffd, int pip,
     340                 :            :         struct pkg_repo_meta *meta)
     341                 :            : {
     342                 :            :         pid_t pid;
     343                 :        534 :         struct pollfd *pfd = NULL;
     344                 :        534 :         int flags, ret = EPKG_OK;
     345                 :            :         size_t sz;
     346                 :        534 :         struct pkg *pkg = NULL;
     347                 :        534 :         struct pkg_manifest_key *keys = NULL;
     348                 :        534 :         char *mdigest = NULL;
     349                 :            :         char digestbuf[1024];
     350                 :            :         xstring *b;
     351                 :            :         struct iovec iov[2];
     352                 :            :         uint32_t len;
     353                 :            :         char buf[1024];
     354                 :            :         char *w, *path;
     355                 :            :         const char *rbuf, *c, *repopath;
     356                 :            : 
     357                 :        534 :         b = xstring_new();
     358                 :            : 
     359                 :        534 :         pid = fork();
     360      [ -  -  + ]:        534 :         switch(pid) {
     361                 :            :         case -1:
     362                 :          0 :                 pkg_emit_errno("pkg_create_repo_worker", "fork");
     363                 :          0 :                 xstring_free(b);
     364                 :          0 :                 return (EPKG_FATAL);
     365                 :            :                 break;
     366                 :            :         case 0:
     367                 :          0 :                 break;
     368                 :            :         default:
     369                 :            :                 /* Parent */
     370                 :        534 :                 xstring_free(b);
     371                 :        534 :                 return (EPKG_OK);
     372                 :            :                 break;
     373                 :            :         }
     374                 :            : 
     375                 :          0 :         pkg_manifest_keys_new(&keys);
     376                 :          0 :         pkg_debug(1, "start worker to parse packages");
     377                 :            : 
     378         [ #  # ]:          0 :         if (ffd != -1)
     379                 :          0 :                 flags = PKG_OPEN_MANIFEST_ONLY;
     380                 :            :         else
     381                 :          0 :                 flags = PKG_OPEN_MANIFEST_ONLY | PKG_OPEN_MANIFEST_COMPACT;
     382                 :            : 
     383                 :            :         /* We are reading to digest buf but it's only to check the socketpair */
     384         [ #  # ]:          0 :         if (read(pip, digestbuf, 1) == -1) {
     385                 :          0 :                 pkg_emit_errno("pkg_create_repo_worker", "read");
     386                 :          0 :                 goto cleanup;
     387                 :            :         }
     388                 :            : 
     389                 :          0 :         pfd = xcalloc(1, sizeof(struct pollfd));
     390                 :          0 :         pfd[0].fd = pip;
     391                 :          0 :         pfd[0].events = POLLIN;
     392                 :            : 
     393                 :          0 :         for (;;) {
     394                 :          0 :                 w = buf;
     395                 :          0 :                 w = mp_encode_array(w, 1);
     396                 :          0 :                 w = mp_encode_uint(w, MSG_PKG_READY);
     397                 :          0 :                 tell_parent(pip, buf, w - buf);
     398         [ #  # ]:          0 :                 if (poll(pfd, 1, -1) == -1) {
     399         [ #  # ]:          0 :                         if (errno == EINTR)
     400                 :          0 :                                 continue;
     401                 :            :                         else
     402                 :          0 :                                 goto cleanup;
     403                 :            :                 }
     404         [ #  # ]:          0 :                 if (pfd[0].revents & (POLLIN|POLLHUP|POLLERR)) {
     405                 :          0 :                         for (;;) {
     406                 :            :                                 ssize_t r;
     407                 :          0 :                                 r = read(pfd[0].fd, buf, sizeof(buf));
     408         [ #  # ]:          0 :                                 if (r == -1) {
     409         [ #  # ]:          0 :                                         if (errno == EINTR)
     410                 :          0 :                                                 continue;
     411                 :          0 :                                         else if (errno == EAGAIN || errno == EWOULDBLOCK) {
     412                 :          0 :                                                 return (EPKG_OK);
     413                 :            :                                         }
     414                 :          0 :                                         pkg_emit_errno("pkg_repo_worker", "read");
     415                 :          0 :                                         return (EPKG_FATAL);
     416         [ #  # ]:          0 :                                 } else if (r == 0)
     417                 :          0 :                                         return (EPKG_END);
     418                 :            :                                 else
     419                 :          0 :                                         break;
     420                 :            :                         }
     421                 :          0 :                 } else {
     422                 :          0 :                         continue;
     423                 :            :                 }
     424                 :          0 :                 rbuf = buf;
     425                 :          0 :                 sz = mp_decode_array(&rbuf);
     426         [ #  # ]:          0 :                 if (sz < 1)
     427                 :          0 :                         continue;
     428                 :          0 :                 c = mp_decode_str(&rbuf, &len);
     429         [ #  # ]:          0 :                 if (len == 0) /* empty package name means ends of repo */
     430                 :          0 :                         break;
     431                 :          0 :                 path = xstrndup(c, len);
     432                 :          0 :                 repopath = mp_decode_str(&rbuf, &len);
     433         [ #  # ]:          0 :                 if (len == 0) /* empty package name means ends of repo */
     434                 :          0 :                         break;
     435                 :          0 :                 if (pkg_open(&pkg, path, keys, flags) == EPKG_OK) {
     436                 :          0 :                         off_t mpos, fpos = 0;
     437                 :            :                         size_t mlen;
     438                 :            :                         struct stat st;
     439                 :            : 
     440                 :          0 :                         pkg->sum = pkg_checksum_file(path, PKG_HASH_TYPE_SHA256_HEX);
     441                 :          0 :                         stat(path, &st);
     442                 :          0 :                         pkg->pkgsize = st.st_size;
     443         [ #  # ]:          0 :                         if (meta->hash) {
     444                 :          0 :                                 ret = hash_file(meta, pkg, path);
     445         [ #  # ]:          0 :                                 if (ret != EPKG_OK)
     446                 :          0 :                                         goto cleanup;
     447                 :          0 :                         } else {
     448                 :          0 :                                 pkg->repopath = xstrdup(repopath);
     449                 :            :                         }
     450                 :            : 
     451                 :            :                         /*
     452                 :            :                          * TODO: use pkg_checksum for new manifests
     453                 :            :                          */
     454                 :          0 :                         xstring_reset(b);
     455                 :          0 :                         mdigest = xmalloc(pkg_checksum_type_size(meta->digest_format));
     456                 :            : 
     457                 :          0 :                         pkg_emit_manifest_buf(pkg, b, PKG_MANIFEST_EMIT_COMPACT, NULL);
     458                 :            :                         /* Only version 1 needs the digest */
     459                 :          0 :                         if (meta->version == 1) {
     460   [ #  #  #  #  :          0 :                                 if (pkg_checksum_generate(pkg, mdigest,
                   #  # ]
     461                 :          0 :                                     pkg_checksum_type_size(meta->digest_format),
     462                 :          0 :                                     meta->digest_format, false, true, false) != EPKG_OK) {
     463                 :          0 :                                         pkg_emit_error("Cannot generate digest for a package");
     464                 :          0 :                                         ret = EPKG_FATAL;
     465                 :            : 
     466                 :          0 :                                         goto cleanup;
     467                 :            :                                 }
     468                 :          0 :                         }
     469                 :          0 :                         fflush(b->fp);
     470                 :          0 :                         mlen = strlen(b->buf);
     471                 :            : 
     472         [ #  # ]:          0 :                         if (flock(mfd, LOCK_EX) == -1) {
     473                 :          0 :                                 pkg_emit_errno("pkg_create_repo_worker", "flock");
     474                 :          0 :                                 ret = EPKG_FATAL;
     475                 :          0 :                                 goto cleanup;
     476                 :            :                         }
     477                 :            : 
     478                 :          0 :                         mpos = lseek(mfd, 0, SEEK_END);
     479                 :            : 
     480                 :          0 :                         iov[0].iov_base = b->buf;
     481                 :          0 :                         iov[0].iov_len = mlen;
     482                 :          0 :                         iov[1].iov_base = (void *)"\n";
     483                 :          0 :                         iov[1].iov_len = 1;
     484                 :            : 
     485         [ #  # ]:          0 :                         if (writev(mfd, iov, 2) == -1) {
     486                 :          0 :                                 pkg_emit_errno("pkg_create_repo_worker", "write");
     487                 :          0 :                                 ret = EPKG_FATAL;
     488                 :          0 :                                 flock(mfd, LOCK_UN);
     489                 :          0 :                                 goto cleanup;
     490                 :            :                         }
     491                 :            : 
     492                 :          0 :                         flock(mfd, LOCK_UN);
     493                 :            : 
     494                 :          0 :                         if (ffd != -1) {
     495                 :            :                                 FILE *fl;
     496                 :            : 
     497         [ #  # ]:          0 :                                 if (flock(ffd, LOCK_EX) == -1) {
     498                 :          0 :                                         pkg_emit_errno("pkg_create_repo_worker", "flock");
     499                 :          0 :                                         ret = EPKG_FATAL;
     500                 :          0 :                                         goto cleanup;
     501                 :            :                                 }
     502                 :          0 :                                 fpos = lseek(ffd, 0, SEEK_END);
     503                 :          0 :                                 fl = fdopen(dup(ffd), "a");
     504                 :          0 :                                 pkg_emit_filelist(pkg, fl);
     505                 :          0 :                                 fclose(fl);
     506                 :            : 
     507                 :          0 :                                 flock(ffd, LOCK_UN);
     508                 :          0 :                         }
     509                 :            : 
     510                 :          0 :                         if (meta->version == 1) {
     511                 :          0 :                                 w = buf;
     512                 :          0 :                                 w = mp_encode_array(w, 7);
     513                 :          0 :                                 w = mp_encode_uint(w, MSG_DIGEST);
     514                 :          0 :                                 w = mp_encode_str(w, pkg->origin, strlen(pkg->origin));
     515                 :          0 :                                 w = mp_encode_str(w, mdigest, strlen(mdigest));
     516                 :          0 :                                 w = mp_encode_uint(w, mpos);
     517                 :          0 :                                 w = mp_encode_uint(w, fpos);
     518                 :          0 :                                 w = mp_encode_uint(w, mlen);
     519                 :          0 :                                 w = mp_encode_str(w, pkg->sum, strlen(pkg->sum));
     520                 :          0 :                                 tell_parent(pip, buf, w - buf);
     521                 :          0 :                         }
     522                 :            :                         /* send a tick */
     523                 :          0 :                         w = buf;
     524                 :          0 :                         w = mp_encode_array(w, 1);
     525                 :          0 :                         w = mp_encode_uint(w, MSG_PKG_DONE);
     526                 :          0 :                         tell_parent(pip, buf, w - buf);
     527                 :          0 :                 }
     528                 :          0 :                 free(path);
     529                 :          0 :         }
     530                 :            : 
     531                 :            : cleanup:
     532                 :          0 :         pkg_manifest_keys_free(keys);
     533                 :          0 :         xstring_free(b);
     534                 :          0 :         close(pip);
     535                 :          0 :         free(mdigest);
     536                 :            : 
     537                 :          0 :         pkg_debug(1, "worker done");
     538                 :          0 :         _exit(ret);
     539                 :        534 : }
     540                 :            : 
     541                 :            : static int
     542                 :       1859 : pkg_create_repo_read_pipe(int fd, struct digest_list_entry **dlist, struct pkg_fts_item **items)
     543                 :            : {
     544                 :       1859 :         struct digest_list_entry *dig = NULL;
     545                 :            :         char buf[1024];
     546                 :            :         int r;
     547                 :            :         size_t sz;
     548                 :            :         uint32_t len;
     549                 :            :         uint64_t msgtype;
     550                 :            :         const char *rbuf;
     551                 :            : 
     552                 :       2939 :         for (;;) {
     553                 :       2939 :                 dig = NULL;
     554                 :       2939 :                 r = read(fd, buf, sizeof(buf));
     555         [ +  + ]:       2939 :                 if (r == -1) {
     556         [ -  + ]:        791 :                         if (errno == EINTR)
     557                 :          0 :                                 continue;
     558         [ -  + ]:        791 :                         else if (errno == ECONNRESET) {
     559                 :            :                                 /* Treat it as the end of a connection */
     560                 :          0 :                                 return (EPKG_END);
     561                 :            :                         }
     562                 :        791 :                         else if (errno == EAGAIN || errno == EWOULDBLOCK) {
     563                 :        791 :                                 return (EPKG_OK);
     564                 :            :                         }
     565                 :            : 
     566                 :          0 :                         pkg_emit_errno("pkg_create_repo_read_pipe", "read");
     567                 :          0 :                         return (EPKG_FATAL);
     568                 :            :                 }
     569         [ +  + ]:       2148 :                 else if (r == 0)
     570                 :        534 :                         return (EPKG_END);
     571                 :            : 
     572                 :       1614 :                 rbuf = buf;
     573                 :       1614 :                 sz = mp_decode_array(&rbuf);
     574         [ -  + ]:       1614 :                 if (sz < 1)
     575                 :          0 :                         continue;
     576                 :       1614 :                 msgtype = mp_decode_uint(&rbuf);
     577                 :            : 
     578         [ +  + ]:       1614 :                 if (msgtype == MSG_PKG_DONE) {
     579                 :        534 :                         return (EPKG_OK);
     580                 :            :                 }
     581                 :            : 
     582                 :       1080 :                 if (msgtype == MSG_DIGEST) {
     583                 :            :                         const char *c;
     584                 :         12 :                         dig = xcalloc(1, sizeof(*dig));
     585                 :         12 :                         c = mp_decode_str(&rbuf, &len);
     586                 :         12 :                         dig->origin = xstrndup(c, len);
     587                 :         12 :                         c = mp_decode_str(&rbuf, &len);
     588                 :         12 :                         dig->digest = xstrndup(c, len);
     589                 :         12 :                         dig->manifest_pos = mp_decode_uint(&rbuf);
     590                 :         12 :                         dig->files_pos = mp_decode_uint(&rbuf);
     591                 :         12 :                         dig->manifest_length = mp_decode_uint(&rbuf);
     592                 :         12 :                         c = mp_decode_str(&rbuf, &len);
     593                 :         12 :                         dig->checksum = xstrndup(c, len);
     594         [ +  + ]:         12 :                         DL_APPEND(*dlist, dig);
     595                 :         12 :                 }
     596                 :            : 
     597                 :       1068 :                 if (msgtype == MSG_PKG_READY) {
     598                 :            :                         char *w;
     599         [ +  + ]:       1068 :                         const char *str = (*items) != NULL ? (*items)->fts_accpath : "";
     600         [ +  + ]:       1068 :                         const char *str2 = (*items) != NULL ? (*items)->pkg_path : "";
     601                 :       1068 :                         w = buf;
     602                 :       1068 :                         w = mp_encode_array(w, 2);
     603                 :       1068 :                         w = mp_encode_str(w, str, strlen(str));
     604                 :       1068 :                         w = mp_encode_str(w, str2, strlen(str2) + 1);
     605                 :       1068 :                         if (*items != NULL)
     606   [ +  -  #  # ]:        534 :                                 LL_DELETE((*items), (*items));
     607                 :       1068 :                         tell_parent(fd, buf, w - buf);
     608                 :       1068 :                 }
     609                 :            :         }
     610                 :            : 
     611                 :            :         /*
     612                 :            :          * Never reached
     613                 :            :          */
     614                 :            :         return (EPKG_OK);
     615                 :       1859 : }
     616                 :            : 
     617                 :            : #ifdef __linux__
     618                 :            : typedef const FTSENT *FTSENTP;
     619                 :            : #else
     620                 :            : typedef const FTSENT *const FTSENTP;
     621                 :            : #endif
     622                 :            : 
     623                 :            : static int
     624                 :       5501 : fts_compare(FTSENTP *a, FTSENTP *b)
     625                 :            : {
     626                 :            :         /* Sort files before directories, then alpha order */
     627                 :       5501 :         if ((*a)->fts_info != FTS_D && (*b)->fts_info == FTS_D)
     628                 :        251 :                 return -1;
     629                 :        888 :         if ((*a)->fts_info == FTS_D && (*b)->fts_info != FTS_D)
     630                 :        758 :                 return 1;
     631                 :       4492 :         return (strcmp((*a)->fts_name, (*b)->fts_name));
     632                 :       5501 : }
     633                 :            : 
     634                 :            : int
     635                 :        277 : pkg_create_repo(char *path, const char *output_dir, bool filelist,
     636                 :            :         const char *metafile, bool hash, bool hash_symlink)
     637                 :            : {
     638                 :        277 :         FTS *fts = NULL;
     639                 :        277 :         struct pkg_fts_item *fts_items = NULL;
     640                 :        277 :         pkghash *conflicts = NULL;
     641                 :            :         struct pkg_conflict_bulk *curcb;
     642                 :            :         int num_workers, i, remaining_workers;
     643                 :            :         size_t len, ntask;
     644                 :        277 :         struct digest_list_entry *dlist = NULL, *cur_dig, *dtmp;
     645                 :        277 :         struct pollfd *pfd = NULL;
     646                 :            :         int cur_pipe[2], fd, outputdir_fd, mfd, ffd;
     647                 :        277 :         struct pkg_repo_meta *meta = NULL;
     648                 :        277 :         int retcode = EPKG_FATAL;
     649                 :            :         ucl_object_t *meta_dump;
     650                 :            :         FILE *mfile;
     651                 :            :         pkghash_it it;
     652                 :            : 
     653                 :            :         char *repopath[2];
     654                 :            :         char repodb[MAXPATHLEN];
     655                 :        277 :         FILE *mandigests = NULL;
     656                 :            : 
     657                 :        277 :         mfd = ffd = -1;
     658                 :            : 
     659         [ -  + ]:        277 :         if (!is_dir(path)) {
     660                 :          0 :                 pkg_emit_error("%s is not a directory", path);
     661                 :          0 :                 return (EPKG_FATAL);
     662                 :            :         }
     663                 :            : 
     664                 :        277 :         errno = 0;
     665                 :        277 :         if (!is_dir(output_dir)) {
     666                 :            :                 /* Try to create dir */
     667         [ #  # ]:          0 :                 if (errno == ENOENT) {
     668                 :          0 :                         if (mkdir(output_dir, 00755) == -1) {
     669                 :          0 :                                 pkg_fatal_errno("cannot create output directory %s",
     670                 :            :                                         output_dir);
     671                 :          0 :                         }
     672                 :          0 :                 }
     673                 :            :                 else {
     674                 :          0 :                         pkg_emit_error("%s is not a directory", output_dir);
     675                 :          0 :                         return (EPKG_FATAL);
     676                 :            :                 }
     677                 :          0 :         }
     678         [ -  + ]:        277 :         if ((outputdir_fd = open(output_dir, O_DIRECTORY)) == -1) {
     679                 :          0 :                 pkg_emit_error("Cannot open %s", output_dir);
     680                 :          0 :                 return (EPKG_FATAL);
     681                 :            :         }
     682                 :            : 
     683         [ +  + ]:        277 :         if (metafile != NULL) {
     684                 :         16 :                 fd = open(metafile, O_RDONLY);
     685         [ -  + ]:         16 :                 if (fd == -1) {
     686                 :          0 :                         pkg_emit_error("meta loading error while trying %s", metafile);
     687                 :          0 :                         return (EPKG_FATAL);
     688                 :            :                 }
     689         [ -  + ]:         16 :                 if (pkg_repo_meta_load(fd, &meta) != EPKG_OK) {
     690                 :          0 :                         pkg_emit_error("meta loading error while trying %s", metafile);
     691                 :          0 :                         close(fd);
     692                 :          0 :                         return (EPKG_FATAL);
     693                 :            :                 }
     694                 :         16 :                 close(fd);
     695                 :         16 :         } else {
     696                 :        261 :                 meta = pkg_repo_meta_default();
     697                 :            :         }
     698                 :        277 :         meta->repopath = path;
     699                 :        277 :         meta->hash = hash;
     700                 :        277 :         meta->hash_symlink = hash_symlink;
     701                 :            : 
     702                 :        277 :         repopath[0] = path;
     703                 :        277 :         repopath[1] = NULL;
     704                 :            : 
     705                 :        277 :         num_workers = pkg_object_int(pkg_config_get("WORKERS_COUNT"));
     706                 :        277 :         if (num_workers <= 0) {
     707                 :        277 :                 num_workers = (int)sysconf(_SC_NPROCESSORS_ONLN);
     708                 :        277 :                 if (num_workers == -1)
     709                 :          0 :                         num_workers = 6;
     710                 :        277 :         }
     711                 :            : 
     712         [ -  + ]:        277 :         if ((fts = fts_open(repopath, FTS_PHYSICAL|FTS_NOCHDIR, fts_compare)) == NULL) {
     713                 :          0 :                 pkg_emit_errno("fts_open", path);
     714                 :          0 :                 goto cleanup;
     715                 :            :         }
     716                 :            : 
     717   [ -  +  -  + ]:        554 :         if ((mfd = openat(outputdir_fd, meta->manifests,
     718                 :        277 :              O_CREAT|O_TRUNC|O_WRONLY, 00644)) == -1) {
     719                 :          0 :                 goto cleanup;
     720                 :            :         }
     721                 :        277 :         if (filelist) {
     722   [ #  #  #  # ]:          0 :                 if ((ffd = openat(outputdir_fd, meta->filesite,
     723                 :          0 :                         O_CREAT|O_TRUNC|O_WRONLY, 00644)) == -1) {
     724                 :          0 :                         goto cleanup;
     725                 :            :                 }
     726                 :          0 :         }
     727                 :          8 :         if (meta->version == 1) {
     728         [ -  + ]:          8 :                 if ((fd = openat(outputdir_fd, meta->digests, O_CREAT|O_TRUNC|O_RDWR, 00644)) == -1) {
     729                 :          0 :                         goto cleanup;
     730                 :            :                 }
     731         [ -  + ]:          8 :                 if ((mandigests = fdopen(fd, "w")) == NULL) {
     732                 :          0 :                         goto cleanup;
     733                 :            :                 }
     734                 :          8 :         }
     735                 :            : 
     736                 :        277 :         len = 0;
     737                 :            : 
     738                 :        277 :         pkg_create_repo_read_fts(&fts_items, fts, path, &len, meta);
     739                 :            : 
     740         [ -  + ]:        277 :         if (len == 0) {
     741                 :            :                 /* Nothing to do */
     742                 :          0 :                 pkg_emit_error("No package files have been found");
     743                 :          0 :                 goto cleanup;
     744                 :            :         }
     745                 :            : 
     746                 :            :         /* Split items over all workers */
     747         [ -  + ]:        277 :         num_workers = MIN(num_workers, len);
     748                 :            : 
     749                 :            :         /* Launch workers */
     750                 :        277 :         pkg_emit_progress_start("Creating repository in %s", output_dir);
     751                 :            : 
     752                 :        277 :         pfd = xcalloc(num_workers, sizeof(struct pollfd));
     753                 :        277 :         ntask = 0;
     754                 :            : 
     755         [ +  + ]:        811 :         for (int i = 0; i < num_workers; i++) {
     756                 :            :                 /* Create new worker */
     757                 :            :                 int ofl;
     758                 :            : 
     759         [ -  + ]:        534 :                 if (get_socketpair(cur_pipe) == -1) {
     760                 :          0 :                         pkg_emit_errno("pkg_create_repo", "pipe");
     761                 :          0 :                         goto cleanup;
     762                 :            :                 }
     763                 :            : 
     764   [ -  +  -  +  :       1602 :                 if (pkg_create_repo_worker(mfd,
                   -  + ]
     765                 :       1068 :                     ffd, cur_pipe[1], meta) == EPKG_FATAL) {
     766                 :          0 :                         close(cur_pipe[0]);
     767                 :          0 :                         close(cur_pipe[1]);
     768                 :          0 :                         goto cleanup;
     769                 :            :                 }
     770                 :            : 
     771                 :        534 :                 pfd[i].fd = cur_pipe[0];
     772                 :        534 :                 pfd[i].events = POLLIN;
     773                 :        534 :                 close(cur_pipe[1]);
     774                 :            :                 /* Make our end of the pipe non-blocking */
     775                 :        534 :                 ofl = fcntl(cur_pipe[0], F_GETFL, 0);
     776                 :        534 :                 fcntl(cur_pipe[0], F_SETFL, ofl | O_NONBLOCK);
     777                 :        534 :         }
     778                 :            : 
     779                 :            :         /* Send start marker to all workers */
     780         [ +  + ]:        811 :         for (i = 0; i < num_workers; i ++) {
     781                 :        534 :                 if (write(pfd[i].fd, ".", 1) == -1)
     782                 :          0 :                         pkg_emit_errno("pkg_create_repo", "write");
     783                 :        534 :         }
     784                 :            : 
     785                 :        277 :         ntask = 0;
     786                 :        277 :         remaining_workers = num_workers;
     787         [ +  + ]:       1964 :         while(remaining_workers > 0) {
     788                 :            :                 int st;
     789                 :            : 
     790                 :       1687 :                 pkg_debug(1, "checking for %d workers", remaining_workers);
     791                 :       1687 :                 retcode = poll(pfd, num_workers, -1);
     792         [ -  + ]:       1687 :                 if (retcode == -1) {
     793         [ #  # ]:          0 :                         if (errno == EINTR) {
     794                 :          0 :                                 continue;
     795                 :            :                         }
     796                 :            :                         else {
     797                 :          0 :                                 goto cleanup;
     798                 :            :                         }
     799                 :            :                 }
     800                 :       1687 :                 else if (retcode > 0) {
     801         [ +  + ]:       5610 :                         for (i = 0; i < num_workers; i ++) {
     802                 :       3923 :                                 if (pfd[i].fd != -1 &&
     803                 :       3365 :                                                                 (pfd[i].revents & (POLLIN|POLLHUP|POLLERR))) {
     804         [ +  + ]:       1859 :                                         if (pkg_create_repo_read_pipe(pfd[i].fd, &dlist, &fts_items) != EPKG_OK) {
     805                 :            :                                                 /*
     806                 :            :                                                  * Wait for the worker finished
     807                 :            :                                                  */
     808                 :        534 :                                                 while (wait(&st) == -1) {
     809         [ #  # ]:          0 :                                                         if (errno == EINTR)
     810                 :          0 :                                                                 continue;
     811                 :            : 
     812                 :          0 :                                                         pkg_emit_errno("pkg_create_repo", "wait");
     813                 :          0 :                                                         break;
     814                 :            :                                                 }
     815                 :            : 
     816                 :        534 :                                                 remaining_workers --;
     817                 :        534 :                                                 pkg_debug(1, "finished worker, %d remaining",
     818                 :        534 :                                                         remaining_workers);
     819                 :        534 :                                                 pfd[i].events = 0;
     820                 :        534 :                                                 pfd[i].revents = 0;
     821                 :        534 :                                                 close(pfd[i].fd);
     822                 :        534 :                                                 pfd[i].fd = -1;
     823                 :        534 :                                         } else {
     824                 :       1325 :                                                 if (errno == EAGAIN || errno == EWOULDBLOCK) {
     825                 :        791 :                                                         errno = 0;
     826                 :        791 :                                                         continue;
     827                 :            :                                                 }
     828                 :        534 :                                                 pkg_emit_progress_tick(ntask++, len);
     829                 :            :                                         }
     830                 :       1068 :                                 }
     831                 :       3132 :                         }
     832                 :       1687 :                 }
     833                 :            :         }
     834                 :            : 
     835                 :        277 :         pkg_emit_progress_tick(len, len);
     836                 :            : 
     837                 :            :         /* Now sort all digests */
     838                 :        277 :         if (meta->version == 1)
     839   [ +  +  +  +  :         36 :                 DL_SORT(dlist, pkg_digest_sort_compare_func);
          +  +  +  +  +  
             +  +  -  +  
                      + ]
     840                 :            : 
     841                 :            :         /* Write metafile */
     842                 :        277 :         snprintf(repodb, sizeof(repodb), "%s/%s", output_dir,
     843                 :            :                 "meta");
     844         [ +  - ]:        277 :         if ((mfile = fopen(repodb, "we")) != NULL) {
     845                 :        277 :                 meta_dump = pkg_repo_meta_to_ucl(meta);
     846                 :        277 :                 ucl_object_emit_file(meta_dump, UCL_EMIT_CONFIG, mfile);
     847                 :        277 :                 fclose(mfile);
     848                 :        277 :                 strlcat(repodb, ".conf", sizeof(repodb));
     849         [ +  - ]:        277 :                 if ((mfile = fopen(repodb, "we")) != NULL) {
     850                 :        277 :                         ucl_object_emit_file(meta_dump, UCL_EMIT_CONFIG, mfile);
     851                 :        277 :                         fclose(mfile);
     852                 :        277 :                 } else {
     853                 :          0 :                         pkg_emit_notice("cannot create metafile at %s", repodb);
     854                 :            :                 }
     855                 :        277 :                 ucl_object_unref(meta_dump);
     856                 :        277 :         }
     857                 :            :         else {
     858                 :          0 :                 pkg_emit_notice("cannot create metafile at %s", repodb);
     859                 :            :         }
     860                 :        277 :         retcode = EPKG_OK;
     861                 :            : cleanup:
     862                 :        277 :         if (outputdir_fd != -1)
     863                 :        277 :                 close(outputdir_fd);
     864                 :        277 :         if (mfd != -1)
     865                 :        277 :                 close(mfd);
     866                 :        554 :         if (ffd != -1)
     867                 :          0 :                 close(ffd);
     868                 :        277 :         it = pkghash_iterator(conflicts);
     869         [ -  + ]:        277 :         while (pkghash_next(&it)) {
     870                 :          0 :                 curcb = (struct pkg_conflict_bulk *)it.value;
     871   [ #  #  #  #  :          0 :                 LL_FREE(curcb->conflicts, pkg_conflict_free);
                   #  # ]
     872                 :          0 :                 pkghash_destroy(curcb->conflictshash);
     873                 :          0 :                 curcb->conflictshash = NULL;
     874                 :          0 :                 free(curcb);
     875                 :            :         }
     876                 :        277 :         pkghash_destroy(conflicts);
     877                 :            : 
     878                 :        277 :         if (pfd != NULL)
     879                 :        277 :                 free(pfd);
     880                 :        277 :         if (fts != NULL)
     881                 :        277 :                 fts_close(fts);
     882                 :            : 
     883   [ -  +  #  #  :        277 :         LL_FREE(fts_items, pkg_create_repo_fts_free);
                   #  # ]
     884                 :            : 
     885                 :        277 :         if (meta->version == 1) {
     886         [ +  + ]:         20 :                 LL_FOREACH_SAFE(dlist, cur_dig, dtmp) {
     887         [ +  - ]:         12 :                         if (cur_dig->checksum != NULL)
     888                 :         24 :                                 fprintf(mandigests, "%s:%s:%ld:%ld:%ld:%s\n", cur_dig->origin,
     889                 :         12 :                                     cur_dig->digest, cur_dig->manifest_pos, cur_dig->files_pos,
     890                 :         12 :                                     cur_dig->manifest_length, cur_dig->checksum);
     891                 :            :                         else
     892                 :          0 :                                 fprintf(mandigests, "%s:%s:%ld:%ld:%ld\n", cur_dig->origin,
     893                 :          0 :                                     cur_dig->digest, cur_dig->manifest_pos, cur_dig->files_pos,
     894                 :          0 :                                     cur_dig->manifest_length);
     895                 :            : 
     896                 :         12 :                         free(cur_dig->digest);
     897                 :         12 :                         free(cur_dig->origin);
     898                 :         12 :                         free(cur_dig);
     899                 :         12 :                 }
     900                 :          8 :         }
     901                 :            : 
     902                 :          8 :         if (meta->version == 1 && mandigests != NULL)
     903                 :          8 :                 fclose(mandigests);
     904                 :        277 :         pkg_repo_meta_free(meta);
     905                 :            : 
     906                 :        277 :         return (retcode);
     907                 :        277 : }
     908                 :            : 
     909                 :            : static int
     910                 :         16 : pkg_repo_sign(char *path, char **argv, int argc, char **sig, size_t *siglen,
     911                 :            :     char **cert)
     912                 :            : {
     913                 :            :         FILE *fp;
     914                 :            :         char *sha256;
     915                 :         16 :         xstring *cmd = NULL;
     916                 :         16 :         xstring *buf = NULL;
     917                 :         16 :         xstring *sigstr = NULL;
     918                 :         16 :         xstring *certstr = NULL;
     919                 :         16 :         char *line = NULL;
     920                 :         16 :         size_t linecap = 0;
     921                 :            :         ssize_t linelen;
     922                 :         16 :         int i, ret = EPKG_OK;
     923                 :            : 
     924                 :         16 :         sha256 = pkg_checksum_file(path, PKG_HASH_TYPE_SHA256_HEX);
     925         [ -  + ]:         16 :         if (!sha256)
     926                 :          0 :                 return (EPKG_FATAL);
     927                 :            : 
     928                 :         16 :         cmd = xstring_new();
     929                 :            : 
     930         [ +  + ]:         48 :         for (i = 0; i < argc; i++) {
     931         [ -  + ]:         32 :                 if (strspn(argv[i], " \t\n") > 0)
     932                 :          0 :                         fprintf(cmd->fp, " \"%s\" ", argv[i]);
     933                 :            :                 else
     934                 :         32 :                         fprintf(cmd->fp, " %s ", argv[i]);
     935                 :         32 :         }
     936                 :            : 
     937                 :         16 :         fflush(cmd->fp);
     938         [ -  + ]:         16 :         if ((fp = popen(cmd->buf, "r+")) == NULL) {
     939                 :          0 :                 ret = EPKG_FATAL;
     940                 :          0 :                 goto done;
     941                 :            :         }
     942                 :            : 
     943                 :         16 :         fprintf(fp, "%s\n", sha256);
     944                 :            : 
     945                 :         16 :         sigstr = xstring_new();
     946                 :         16 :         certstr = xstring_new();
     947                 :            : 
     948                 :        224 :         while ((linelen = getline(&line, &linecap, fp)) > 0 ) {
     949         [ +  + ]:        224 :                 if (strcmp(line, "SIGNATURE\n") == 0) {
     950                 :         16 :                         buf = sigstr;
     951                 :         16 :                         continue;
     952         [ +  + ]:        208 :                 } else if (strcmp(line, "CERT\n") == 0) {
     953                 :         16 :                         buf = certstr;
     954                 :         16 :                         continue;
     955         [ +  + ]:        192 :                 } else if (strcmp(line, "END\n") == 0) {
     956                 :         16 :                         break;
     957                 :            :                 }
     958                 :        176 :                 if (buf != NULL) {
     959                 :        176 :                         fwrite(line, linelen, 1, buf->fp);
     960                 :        176 :                 }
     961                 :            :         }
     962                 :            : 
     963                 :         16 :         *cert = xstring_get(certstr);
     964                 :         16 :         fclose(sigstr->fp);
     965                 :         16 :         sigstr->size--;
     966                 :         16 :         *siglen = sigstr->size;
     967                 :         16 :         *sig = sigstr->buf;
     968                 :         16 :         free(sigstr);
     969                 :            : 
     970                 :            :         /* remove the latest \n */
     971                 :            : 
     972         [ -  + ]:         16 :         if (pclose(fp) != 0) {
     973                 :          0 :                 ret = EPKG_FATAL;
     974                 :          0 :                 goto done;
     975                 :            :         }
     976                 :            : 
     977                 :            : done:
     978                 :         16 :         free(sha256);
     979                 :         16 :         xstring_free(cmd);
     980                 :            : 
     981                 :         16 :         return (ret);
     982                 :         16 : }
     983                 :            : 
     984                 :            : static int
     985                 :        562 : pkg_repo_pack_db(const char *name, const char *archive, char *path,
     986                 :            :                 struct pkg_key *keyinfo, struct pkg_repo_meta *meta,
     987                 :            :                 char **argv, int argc)
     988                 :            : {
     989                 :            :         struct packing *pack;
     990                 :        562 :         unsigned char *sigret = NULL;
     991                 :        562 :         unsigned int siglen = 0;
     992                 :        562 :         size_t signature_len = 0;
     993                 :            :         char fname[MAXPATHLEN];
     994                 :            :         char *sig, *pub;
     995                 :        562 :         int ret = EPKG_OK;
     996                 :            : 
     997                 :        562 :         sig = NULL;
     998                 :        562 :         pub = NULL;
     999                 :            : 
    1000         [ -  + ]:        562 :         if (packing_init(&pack, archive, meta->packing_format, 0, (time_t)-1, true, true) != EPKG_OK)
    1001                 :          0 :                 return (EPKG_FATAL);
    1002                 :            : 
    1003         [ +  + ]:        562 :         if (keyinfo != NULL) {
    1004         [ -  + ]:         16 :                 if (rsa_sign(path, keyinfo, &sigret, &siglen) != EPKG_OK) {
    1005                 :          0 :                         ret = EPKG_FATAL;
    1006                 :          0 :                         goto out;
    1007                 :            :                 }
    1008                 :            : 
    1009         [ -  + ]:         16 :                 if (packing_append_buffer(pack, sigret, "signature", siglen + 1) != EPKG_OK) {
    1010                 :          0 :                         ret = EPKG_FATAL;
    1011                 :          0 :                         goto out;
    1012                 :            :                 }
    1013                 :        562 :         } else if (argc >= 1) {
    1014         [ -  + ]:         16 :                 if (pkg_repo_sign(path, argv, argc, &sig, &signature_len, &pub) != EPKG_OK) {
    1015                 :          0 :                         ret = EPKG_FATAL;
    1016                 :          0 :                         goto out;
    1017                 :            :                 }
    1018                 :            : 
    1019                 :         16 :                 snprintf(fname, sizeof(fname), "%s.sig", name);
    1020         [ -  + ]:         16 :                 if (packing_append_buffer(pack, sig, fname, signature_len) != EPKG_OK) {
    1021                 :          0 :                         ret = EPKG_FATAL;
    1022                 :          0 :                         goto out;
    1023                 :            :                 }
    1024                 :            : 
    1025                 :         16 :                 snprintf(fname, sizeof(fname), "%s.pub", name);
    1026         [ -  + ]:         16 :                 if (packing_append_buffer(pack, pub, fname, strlen(pub)) != EPKG_OK) {
    1027                 :          0 :                         ret = EPKG_FATAL;
    1028                 :          0 :                         goto out;
    1029                 :            :                 }
    1030                 :            : 
    1031                 :         16 :         }
    1032                 :        562 :         packing_append_file_attr(pack, path, name, "root", "wheel", 0644, 0);
    1033                 :            : 
    1034                 :            : out:
    1035                 :        562 :         packing_finish(pack);
    1036                 :        562 :         unlink(path);
    1037                 :        562 :         free(sigret);
    1038                 :        562 :         free(sig);
    1039                 :        562 :         free(pub);
    1040                 :            : 
    1041                 :        562 :         return (ret);
    1042                 :        562 : }
    1043                 :            : 
    1044                 :            : int
    1045                 :        277 : pkg_finish_repo(const char *output_dir, pkg_password_cb *password_cb,
    1046                 :            :     char **argv, int argc, bool filelist)
    1047                 :            : {
    1048                 :            :         char repo_path[MAXPATHLEN];
    1049                 :            :         char repo_archive[MAXPATHLEN];
    1050                 :            :         char *key_file;
    1051                 :            :         const char *key_type;
    1052                 :        277 :         struct pkg_key *keyinfo = NULL;
    1053                 :            :         struct pkg_repo_meta *meta;
    1054                 :            :         struct stat st;
    1055                 :        277 :         int ret = EPKG_OK, nfile = 0, fd;
    1056                 :        277 :         const int files_to_pack = 4;
    1057                 :            : 
    1058         [ -  + ]:        277 :         if (!is_dir(output_dir)) {
    1059                 :          0 :                 pkg_emit_error("%s is not a directory", output_dir);
    1060                 :          0 :                 return (EPKG_FATAL);
    1061                 :            :         }
    1062                 :            : 
    1063                 :        277 :         if (argc == 1) {
    1064                 :          8 :                 key_type = key_file = argv[0];
    1065         [ +  + ]:          8 :                 if (strncmp(key_file, "rsa:", 4) == 0) {
    1066                 :          4 :                         key_file += 4;
    1067                 :          4 :                         *(key_file - 1) = '\0';
    1068                 :          4 :                 } else {
    1069                 :          4 :                         key_type = "rsa";
    1070                 :            :                 }
    1071                 :            : 
    1072                 :          8 :                 pkg_debug(1, "Loading %s key from '%s' for signing", key_type, key_file);
    1073                 :          8 :                 rsa_new(&keyinfo, password_cb, key_file);
    1074                 :          8 :         }
    1075                 :            : 
    1076                 :          8 :         if (argc > 1 && strcmp(argv[0], "signing_command:") != 0)
    1077                 :          0 :                 return (EPKG_FATAL);
    1078                 :            : 
    1079                 :          8 :         if (argc > 1) {
    1080                 :          8 :                 argc--;
    1081                 :          8 :                 argv++;
    1082                 :          8 :         }
    1083                 :            : 
    1084                 :        277 :         pkg_emit_progress_start("Packing files for repository");
    1085                 :        277 :         pkg_emit_progress_tick(nfile++, files_to_pack);
    1086                 :            : 
    1087                 :        277 :         snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir,
    1088                 :            :                 repo_meta_file);
    1089         [ +  - ]:        277 :         if ((fd = open(repo_path, O_RDONLY)) != -1) {
    1090         [ -  + ]:        277 :                 if (pkg_repo_meta_load(fd, &meta) != EPKG_OK) {
    1091                 :          0 :                         pkg_emit_error("meta loading error while trying %s", repo_path);
    1092                 :          0 :                         rsa_free(keyinfo);
    1093                 :          0 :                         close(fd);
    1094                 :          0 :                         return (EPKG_FATAL);
    1095                 :            :                 }
    1096   [ -  +  -  +  :        831 :                 if (pkg_repo_pack_db(repo_meta_file, repo_path, repo_path, keyinfo,
                   -  + ]
    1097                 :        554 :                     meta, argv, argc) != EPKG_OK) {
    1098                 :          0 :                         ret = EPKG_FATAL;
    1099                 :          0 :                         goto cleanup;
    1100                 :            :                 }
    1101                 :        277 :         }
    1102                 :            :         else {
    1103                 :          0 :                 meta = pkg_repo_meta_default();
    1104                 :            :         }
    1105                 :            : 
    1106                 :        554 :         snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir,
    1107                 :        277 :             meta->manifests);
    1108                 :        554 :         snprintf(repo_archive, sizeof(repo_archive), "%s/%s", output_dir,
    1109                 :        277 :                 meta->manifests_archive);
    1110   [ -  +  -  +  :        831 :         if (pkg_repo_pack_db(meta->manifests, repo_archive, repo_path, keyinfo,
                   -  + ]
    1111                 :        554 :             meta, argv, argc) != EPKG_OK) {
    1112                 :          0 :                 ret = EPKG_FATAL;
    1113                 :          0 :                 goto cleanup;
    1114                 :            :         }
    1115                 :            : 
    1116                 :        277 :         pkg_emit_progress_tick(nfile++, files_to_pack);
    1117                 :            : 
    1118                 :        277 :         if (filelist) {
    1119                 :          0 :                 snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir,
    1120                 :          0 :                     meta->filesite);
    1121                 :          0 :                 snprintf(repo_archive, sizeof(repo_archive), "%s/%s",
    1122                 :          0 :                     output_dir, meta->filesite_archive);
    1123   [ #  #  #  #  :          0 :                 if (pkg_repo_pack_db(meta->filesite, repo_archive, repo_path, keyinfo,
                   #  # ]
    1124                 :          0 :                     meta, argv, argc) != EPKG_OK) {
    1125                 :          0 :                         ret = EPKG_FATAL;
    1126                 :          0 :                         goto cleanup;
    1127                 :            :                 }
    1128                 :          0 :         }
    1129                 :            : 
    1130                 :          8 :         pkg_emit_progress_tick(nfile++, files_to_pack);
    1131                 :            : 
    1132                 :          8 :         if (meta->version == 1) {
    1133                 :         16 :                 snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir,
    1134                 :          8 :                     meta->digests);
    1135                 :         16 :                 snprintf(repo_archive, sizeof(repo_archive), "%s/%s", output_dir,
    1136                 :          8 :                     meta->digests_archive);
    1137   [ -  +  -  +  :         24 :                 if (pkg_repo_pack_db(meta->digests, repo_archive, repo_path, keyinfo,
                   -  + ]
    1138                 :         16 :                     meta, argv, argc) != EPKG_OK) {
    1139                 :          0 :                         ret = EPKG_FATAL;
    1140                 :          0 :                         goto cleanup;
    1141                 :            :                 }
    1142                 :          8 :         }
    1143                 :            : 
    1144                 :        277 :         pkg_emit_progress_tick(nfile++, files_to_pack);
    1145                 :            : 
    1146                 :            : #if 0
    1147                 :            :         snprintf(repo_path, sizeof(repo_path), "%s/%s", output_dir,
    1148                 :            :                 meta->conflicts);
    1149                 :            :         snprintf(repo_archive, sizeof(repo_archive), "%s/%s", output_dir,
    1150                 :            :                 meta->conflicts_archive);
    1151                 :            :         if (pkg_repo_pack_db(meta->conflicts, repo_archive, repo_path, keyinfo,
    1152                 :            :             meta, argv, argc) != EPKG_OK) {
    1153                 :            :                 ret = EPKG_FATAL;
    1154                 :            :                 goto cleanup;
    1155                 :            :         }
    1156                 :            : #endif
    1157                 :            : 
    1158                 :            :         /* Now we need to set the equal mtime for all archives in the repo */
    1159                 :        554 :         snprintf(repo_archive, sizeof(repo_archive), "%s/%s.pkg",
    1160                 :        277 :             output_dir, repo_meta_file);
    1161                 :        554 :         if (stat(repo_archive, &st) == 0) {
    1162                 :        554 :                 struct timeval ftimes[2] = {
    1163                 :        554 :                         {
    1164                 :        277 :                         .tv_sec = st.st_mtime,
    1165                 :            :                         .tv_usec = 0
    1166                 :            :                         },
    1167                 :        554 :                         {
    1168                 :        277 :                         .tv_sec = st.st_mtime,
    1169                 :            :                         .tv_usec = 0
    1170                 :            :                         }
    1171                 :            :                 };
    1172                 :        554 :                 snprintf(repo_archive, sizeof(repo_archive), "%s/%s.pkg",
    1173                 :        277 :                     output_dir, meta->manifests_archive);
    1174                 :        277 :                 utimes(repo_archive, ftimes);
    1175                 :        277 :                 if (meta->version == 1) {
    1176                 :         16 :                         snprintf(repo_archive, sizeof(repo_archive), "%s/%s.pkg",
    1177                 :          8 :                             output_dir, meta->digests_archive);
    1178                 :          8 :                         utimes(repo_archive, ftimes);
    1179                 :          8 :                 }
    1180                 :         16 :                 if (filelist) {
    1181                 :          0 :                         snprintf(repo_archive, sizeof(repo_archive),
    1182                 :          0 :                             "%s/%s.pkg", output_dir, meta->filesite_archive);
    1183                 :          0 :                         utimes(repo_archive, ftimes);
    1184                 :          0 :                 }
    1185                 :        554 :                 snprintf(repo_archive, sizeof(repo_archive),
    1186                 :        277 :                         "%s/%s.pkg", output_dir, repo_meta_file);
    1187                 :        277 :                 utimes(repo_archive, ftimes);
    1188                 :        277 :         }
    1189                 :            : 
    1190                 :            : cleanup:
    1191                 :        277 :         pkg_emit_progress_tick(files_to_pack, files_to_pack);
    1192                 :        277 :         pkg_repo_meta_free(meta);
    1193                 :            : 
    1194                 :        277 :         rsa_free(keyinfo);
    1195                 :            : 
    1196                 :        277 :         return (ret);
    1197                 :        277 : }

Generated by: LCOV version 1.15