LCOV - code coverage report
Current view: top level - libpkg - pkg_ports.c (source / functions) Hit Total Coverage
Test: plop Lines: 668 780 85.6 %
Date: 2024-12-30 07:09:03 Functions: 36 39 92.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 390 522 74.7 %

           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) 2012-2013 Bryan Drewery <bdrewery@FreeBSD.org>
       5                 :            :  * All rights reserved.
       6                 :            :  *
       7                 :            :  * Redistribution and use in source and binary forms, with or without
       8                 :            :  * modification, are permitted provided that the following conditions
       9                 :            :  * are met:
      10                 :            :  * 1. Redistributions of source code must retain the above copyright
      11                 :            :  *    notice, this list of conditions and the following disclaimer
      12                 :            :  *    in this position and unchanged.
      13                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      14                 :            :  *    notice, this list of conditions and the following disclaimer in the
      15                 :            :  *    documentation and/or other materials provided with the distribution.
      16                 :            :  *
      17                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      18                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      19                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      20                 :            :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      21                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      22                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      26                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27                 :            :  */
      28                 :            : 
      29                 :            : #include "pkg_config.h"
      30                 :            : 
      31                 :            : #ifdef HAVE_CAPSICUM
      32                 :            : #include <sys/capsicum.h>
      33                 :            : #endif
      34                 :            : 
      35                 :            : #include <sys/stat.h>
      36                 :            : #include <sys/types.h>
      37                 :            : #include <sys/wait.h>
      38                 :            : 
      39                 :            : #include <assert.h>
      40                 :            : #include <ctype.h>
      41                 :            : #include <errno.h>
      42                 :            : #include <regex.h>
      43                 :            : #include <stdio.h>
      44                 :            : #include <stdlib.h>
      45                 :            : #include <stdbool.h>
      46                 :            : #include <string.h>
      47                 :            : #include <fcntl.h>
      48                 :            : #include <unistd.h>
      49                 :            : #include <err.h>
      50                 :            : 
      51                 :            : #include "pkg.h"
      52                 :            : #include "private/utils.h"
      53                 :            : #include "private/event.h"
      54                 :            : #include "private/pkg.h"
      55                 :            : #include "private/lua.h"
      56                 :            : 
      57                 :            : static ucl_object_t *keyword_schema = NULL;
      58                 :            : 
      59                 :            : static int override_prefix(struct plist *, char *, struct file_attr *);
      60                 :            : static int setprefix(struct plist *, char *, struct file_attr *);
      61                 :            : static int dir(struct plist *, char *, struct file_attr *);
      62                 :            : static int file(struct plist *, char *, struct file_attr *);
      63                 :            : static int setmod(struct plist *, char *, struct file_attr *);
      64                 :            : static int setowner(struct plist *, char *, struct file_attr *);
      65                 :            : static int setgroup(struct plist *, char *, struct file_attr *);
      66                 :            : static int comment_key(struct plist *, char *, struct file_attr *);
      67                 :            : static int config(struct plist *, char *, struct file_attr *);
      68                 :            : /* compat with old packages */
      69                 :            : static int name_key(struct plist *, char *, struct file_attr *);
      70                 :            : static int include_plist(struct plist *, char *, struct file_attr *);
      71                 :            : static int add_variable(struct plist *, char *, struct file_attr *);
      72                 :            : 
      73                 :            : static struct action_cmd {
      74                 :            :         const char *name;
      75                 :            :         int (*perform)(struct plist *, char *, struct file_attr *);
      76                 :            :         size_t namelen;
      77                 :            : } list_actions[] = {
      78                 :            :         { "setprefix", setprefix, 9},
      79                 :            :         { "dir", dir, 3 },
      80                 :            :         { "file", file, 4 },
      81                 :            :         { "setmode", setmod, 6 },
      82                 :            :         { "setowner", setowner, 8 },
      83                 :            :         { "setgroup", setgroup, 8 },
      84                 :            :         { "comment", comment_key, 7 },
      85                 :            :         { "config", config, 6 },
      86                 :            :         { "override_prefix", override_prefix, 15 },
      87                 :            :         /* compat with old packages */
      88                 :            :         { "name", name_key, 4 },
      89                 :            :         { NULL, NULL, 0 }
      90                 :            : };
      91                 :            : 
      92                 :            : static ucl_object_t *
      93                 :         19 : keyword_open_schema(void)
      94                 :            : {
      95                 :            :         struct ucl_parser *parser;
      96                 :            :         static const char keyword_schema_str[] = ""
      97                 :            :                 "{"
      98                 :            :                 "  type = object;"
      99                 :            :                 "  properties {"
     100                 :            :                 "    actions = { "
     101                 :            :                 "      type = array; "
     102                 :            :                 "      items = { type = string }; "
     103                 :            :                 "      uniqueItems: true "
     104                 :            :                 "    }; "
     105                 :            :                 "    actions_script = { type = string }; "
     106                 :            :                 "    arguments = { type = boolean }; "
     107                 :            :                 "    preformat_arguments { type = boolean }; "
     108                 :            :                 "    prepackaging = { type = string }; "
     109                 :            :                 "    deprecated = { type = boolean }; "
     110                 :            :                 "    deprecation_message = { type = string }; "
     111                 :            :                 "    attributes = { "
     112                 :            :                 "      type = object; "
     113                 :            :                 "      properties { "
     114                 :            :                 "        owner = { type = string }; "
     115                 :            :                 "        group = { type = string }; "
     116                 :            :                 "        mode = { oneOf: [ { type = integer }, { type = string } ] }; "
     117                 :            :                 "      }"
     118                 :            :                 "    }; "
     119                 :            :                 "    pre-install = { type = string }; "
     120                 :            :                 "    post-install = { type = string }; "
     121                 :            :                 "    pre-deinstall = { type = string }; "
     122                 :            :                 "    post-deinstall = { type = string }; "
     123                 :            :                 "    pre-install-lua = { type = string }; "
     124                 :            :                 "    post-install-lua = { type = string }; "
     125                 :            :                 "    pre-deinstall-lua = { type = string }; "
     126                 :            :                 "    post-deinstall-lua = { type = string }; "
     127                 :            :                 "    messages: {"
     128                 :            :                 "        type = array; "
     129                 :            :                 "        items = {"
     130                 :            :                 "            type = object;"
     131                 :            :                 "            properties {"
     132                 :            :                 "                message = { type = string };"
     133                 :            :                 "                type = { enum = [ upgrade, remove, install ] };"
     134                 :            :                 "            };"
     135                 :            :                 "            required [ message ];"
     136                 :            :                 "        };"
     137                 :            :                 "    };"
     138                 :            :                 "  }"
     139                 :            :                 "}";
     140                 :            : 
     141         [ +  + ]:         19 :         if (keyword_schema != NULL)
     142                 :          4 :                 return (keyword_schema);
     143                 :            : 
     144                 :         15 :         parser = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
     145         [ +  - ]:         15 :         if (!ucl_parser_add_chunk(parser, keyword_schema_str,
     146                 :            :             sizeof(keyword_schema_str) -1)) {
     147                 :          0 :                 pkg_emit_error("Cannot parse schema for keywords: %s",
     148                 :          0 :                     ucl_parser_get_error(parser));
     149                 :          0 :                 ucl_parser_free(parser);
     150                 :          0 :                 return (NULL);
     151                 :            :         }
     152                 :            : 
     153                 :         15 :         keyword_schema = ucl_parser_get_object(parser);
     154                 :         15 :         ucl_parser_free(parser);
     155                 :            : 
     156                 :         15 :         return (keyword_schema);
     157                 :         19 : }
     158                 :            : 
     159                 :            : void *
     160                 :         12 : parse_mode(const char *str)
     161                 :            : {
     162   [ +  -  -  + ]:         12 :         if (str == NULL || *str == '\0')
     163                 :          0 :                 return (NULL);
     164                 :            : 
     165   [ +  +  -  +  :         23 :         if (strstr(str, "u+") || strstr(str, "o+") || strstr(str, "g+") ||
             -  +  -  + ]
     166   [ -  +  -  +  :         11 :             strstr(str, "u-") || strstr(str, "o-") || strstr(str, "g-") ||
                   -  + ]
     167         [ -  + ]:         11 :             strstr(str, "a+") || strstr(str, "a-"))
     168                 :          1 :                 return (NULL);
     169                 :            : 
     170                 :         11 :         return (setmode(str));
     171                 :         12 : }
     172                 :            : 
     173                 :            : void
     174                 :         83 : free_file_attr(struct file_attr *a)
     175                 :            : {
     176         [ +  + ]:         83 :         if (a == NULL)
     177                 :         67 :                 return;
     178                 :         16 :         free(a->owner);
     179                 :         16 :         free(a->group);
     180                 :         16 :         free(a);
     181                 :         83 : }
     182                 :            : 
     183                 :            : static int
     184                 :          2 : override_prefix(struct plist *p, char *line, struct file_attr *a __unused)
     185                 :            : {
     186                 :          2 :         char *np = NULL;
     187                 :            : 
     188         [ -  + ]:          2 :         if (line[0] != '\0')
     189                 :          2 :                 np = xstrdup(line);
     190                 :          2 :         free(p->pkg->oprefix);
     191                 :          2 :         p->pkg->oprefix = np;
     192                 :          2 :         return (EPKG_OK);
     193                 :            : }
     194                 :            : 
     195                 :            : static int
     196                 :          4 : setprefix(struct plist *p, char *line, struct file_attr *a __unused)
     197                 :            : {
     198                 :            :         /* if no arguments then set default prefix */
     199         [ +  + ]:          4 :         if (line[0] == '\0') {
     200                 :          1 :                 strlcpy(p->prefix, p->pkg->prefix, sizeof(p->prefix));
     201                 :          1 :         }
     202                 :            :         else
     203                 :          3 :                 strlcpy(p->prefix, line, sizeof(p->prefix));
     204                 :            : 
     205         [ +  + ]:          4 :         if (p->pkg->prefix == NULL)
     206                 :          1 :                 p->pkg->prefix = xstrdup(line);
     207                 :            : 
     208                 :          4 :         p->slash = p->prefix[strlen(p->prefix) -1] == '/' ? "" : "/";
     209                 :            : 
     210                 :          4 :         fprintf(p->post_install_buf->fp, "cd %s\n", p->prefix);
     211                 :          4 :         fprintf(p->pre_deinstall_buf->fp, "cd %s\n", p->prefix);
     212                 :          4 :         fprintf(p->post_deinstall_buf->fp, "cd %s\n", p->prefix);
     213                 :            : 
     214                 :          4 :         return (EPKG_OK);
     215                 :            : }
     216                 :            : 
     217                 :            : static int
     218                 :          3 : name_key(struct plist *p, char *line, struct file_attr *a __unused)
     219                 :            : {
     220                 :            :         char *tmp;
     221                 :            : 
     222         [ +  + ]:          3 :         if (p->pkg->name != NULL) {
     223                 :          1 :                 return (EPKG_OK);
     224                 :            :         }
     225                 :          2 :         tmp = strrchr(line, '-');
     226         [ +  + ]:          2 :         if (tmp == NULL) {
     227                 :          1 :                 pkg_emit_error("Invalid @name key: '%s' expecting <name>-<version>", line);
     228                 :          1 :                 return (EPKG_FATAL);
     229                 :            :         }
     230                 :          1 :         tmp[0] = '\0';
     231                 :          1 :         tmp++;
     232                 :          1 :         p->pkg->name = xstrdup(line);
     233                 :          1 :         p->pkg->version = xstrdup(tmp);
     234                 :            : 
     235                 :          1 :         return (EPKG_OK);
     236                 :          3 : }
     237                 :            : 
     238                 :            : static int
     239                 :          8 : lua_meta(lua_State *L,
     240                 :            :     int (*perform)(struct plist *, char *, struct file_attr *))
     241                 :            : {
     242                 :          8 :         int n = lua_gettop(L);
     243                 :            :         int ret;
     244   [ +  -  #  #  :          8 :         luaL_argcheck(L, n == 1, n > 1 ? 2 : n,
                   #  # ]
     245                 :            :             "takes exactly one argument");
     246                 :          8 :         char *str = strdup(luaL_checkstring(L, 1));
     247                 :          8 :         lua_getglobal(L, "plist");
     248                 :          8 :         struct plist *p = lua_touserdata(L, -1);
     249                 :          8 :         lua_getglobal(L, "attrs");
     250                 :          8 :         struct file_attr *a = lua_touserdata(L, -1);
     251                 :            : 
     252                 :          8 :         ret = perform(p, str, a);
     253                 :          8 :         free(str);
     254                 :          8 :         lua_pushboolean(L, ret == EPKG_OK);
     255                 :          8 :         return (1);
     256                 :            : }
     257                 :            : 
     258                 :            : static int
     259                 :          0 : lua_dir(lua_State *L)
     260                 :            : {
     261                 :          0 :         return (lua_meta(L, dir));
     262                 :            : }
     263                 :            : 
     264                 :            : static int
     265                 :          0 : lua_config(lua_State *L) {
     266                 :          0 :         return (lua_meta(L, config));
     267                 :            : }
     268                 :            : 
     269                 :            : static int
     270                 :          8 : lua_file(lua_State *L) {
     271                 :          8 :         return (lua_meta(L, file));
     272                 :            : }
     273                 :            : 
     274                 :            : 
     275                 :            : static int
     276                 :          6 : dir(struct plist *p, char *line, struct file_attr *a)
     277                 :            : {
     278                 :            :         char path[MAXPATHLEN+1];
     279                 :            :         char *cp;
     280                 :            :         struct stat st;
     281                 :          6 :         int ret = EPKG_OK;
     282                 :            : 
     283                 :          6 :         cp = line + strlen(line) -1;
     284   [ +  +  +  -  :          6 :         while (cp > line && isspace(*cp)) {
                   -  + ]
     285                 :          0 :                 *cp = 0;
     286                 :          0 :                 cp--;
     287                 :            :         }
     288                 :            : 
     289         [ +  + ]:          6 :         if (line[0] == '/')
     290                 :          1 :                 snprintf(path, sizeof(path), "%s/", line);
     291                 :            :         else
     292                 :         10 :                 snprintf(path, sizeof(path), "%s%s%s/", p->prefix, p->slash,
     293                 :          5 :                     line);
     294                 :            : 
     295   [ +  +  +  + ]:         12 :         if (fstatat(p->stagefd, RELATIVE_PATH(path), &st, AT_SYMLINK_NOFOLLOW)
     296                 :          6 :             == -1) {
     297         [ +  - ]:          1 :                 pkg_errno("Unable to access file %s%s",
     298                 :            :                     p->stage ? p->stage: "", path);
     299         [ -  + ]:          1 :                 if (p->stage != NULL)
     300                 :          1 :                         ret = EPKG_FATAL;
     301         [ +  - ]:          1 :                 if (ctx.developer_mode) {
     302                 :          0 :                         pkg_emit_developer_mode("Plist error: @dir %s", line);
     303                 :          0 :                         ret = EPKG_FATAL;
     304                 :          0 :                 }
     305                 :          1 :         } else {
     306         [ +  + ]:          5 :                 if (a != NULL)
     307                 :          2 :                         ret = pkg_adddir_attr(p->pkg, path,
     308         [ +  - ]:          1 :                             a->owner ? a->owner : p->uname,
     309         [ -  + ]:          1 :                             a->group ? a->group : p->gname,
     310         [ -  + ]:          1 :                             a->mode ? a->mode : p->perm,
     311                 :          1 :                             a->fflags, true);
     312                 :            :                 else
     313                 :          8 :                         ret = pkg_adddir_attr(p->pkg, path, p->uname, p->gname,
     314                 :          4 :                             p->perm, 0, true);
     315                 :            :         }
     316                 :            : 
     317                 :          6 :         return (ret);
     318                 :            : }
     319                 :            : 
     320                 :            : static int
     321                 :         93 : meta_file(struct plist *p, char *line, struct file_attr *a, bool is_config)
     322                 :            : {
     323                 :            :         size_t len;
     324                 :            :         char path[MAXPATHLEN];
     325                 :            :         struct stat st;
     326                 :         93 :         char *buf = NULL;
     327                 :         93 :         bool regular = false;
     328                 :         93 :         int ret = EPKG_OK;
     329                 :            : 
     330                 :         93 :         len = strlen(line);
     331                 :            : 
     332         [ -  + ]:         93 :         while (isspace(line[len - 1]))
     333                 :          0 :                 line[--len] = '\0';
     334                 :            : 
     335         [ +  + ]:         93 :         if (line[0] == '/')
     336                 :         46 :                 snprintf(path, sizeof(path), "%s", line);
     337                 :            :         else
     338                 :         94 :                 snprintf(path, sizeof(path), "%s%s%s", p->prefix,
     339                 :         47 :                     p->slash, line);
     340                 :            : 
     341   [ +  +  +  + ]:        186 :         if (fstatat(p->stagefd, RELATIVE_PATH(path), &st, AT_SYMLINK_NOFOLLOW)
     342                 :         93 :             == -1) {
     343         [ +  - ]:          6 :                 pkg_errno("Unable to access file %s%s",
     344                 :            :                     p->stage ? p->stage : "", path);
     345         [ -  + ]:          6 :                 if (p->stage != NULL)
     346                 :          6 :                         ret = EPKG_FATAL;
     347         [ +  - ]:          6 :                 if (ctx.developer_mode) {
     348                 :          0 :                         pkg_emit_developer_mode("Plist error, missing file: %s",
     349                 :          0 :                             line);
     350                 :          0 :                         ret = EPKG_FATAL;
     351                 :          0 :                 }
     352                 :          6 :                 return (ret);
     353                 :            :         }
     354                 :         87 :         buf = NULL;
     355                 :         87 :         regular = false;
     356                 :            : 
     357         [ +  + ]:         87 :         if (S_ISREG(st.st_mode)) {
     358         [ +  + ]:         82 :                 if (st.st_nlink > 1)
     359                 :         10 :                         regular = !check_for_hardlink(&p->hardlinks, &st);
     360                 :            :                 else
     361                 :         72 :                         regular = true;
     362         [ -  + ]:         87 :         } else if (S_ISLNK(st.st_mode))
     363                 :          5 :                 regular = false;
     364                 :            : 
     365                 :         87 :         buf = pkg_checksum_generate_fileat(p->stagefd, RELATIVE_PATH(path),
     366                 :            :             PKG_HASH_TYPE_SHA256_HEX);
     367         [ +  - ]:         87 :         if (buf == NULL) {
     368                 :          0 :                 return (EPKG_FATAL);
     369                 :            :         }
     370                 :            : 
     371         [ +  + ]:         87 :         if (regular) {
     372                 :         77 :                 p->flatsize += st.st_size;
     373         [ +  + ]:         77 :                 if (is_config) {
     374                 :            :                         off_t sz;
     375                 :            :                         char *content;
     376                 :         13 :                         file_to_bufferat(p->stagefd, RELATIVE_PATH(path),
     377                 :            :                             &content, &sz);
     378                 :         13 :                         ret = pkg_addconfig_file(p->pkg, path, content);
     379         [ +  + ]:         13 :                         if (ret != EPKG_OK) {
     380                 :          1 :                                 return (ret);
     381                 :            :                         }
     382                 :         12 :                         free(content);
     383                 :         12 :                 }
     384                 :         76 :         }
     385                 :            : 
     386         [ -  + ]:         86 :         if (S_ISDIR(st.st_mode)) {
     387                 :          0 :                 pkg_emit_error("Plist error, directory listed as a file: %s",
     388                 :          0 :                     line);
     389                 :          0 :                 free(buf);
     390                 :          0 :                 return (EPKG_FATAL);
     391                 :            :         }
     392                 :            : 
     393         [ +  + ]:         86 :         if (a != NULL) {
     394                 :         32 :                 ret = pkg_addfile_attr(p->pkg, path, buf,
     395         [ +  + ]:         16 :                     a->owner ? a->owner : p->uname,
     396         [ +  + ]:         16 :                     a->group ? a->group : p->gname,
     397         [ +  + ]:         16 :                     a->mode ? a->mode : p->perm,
     398                 :         16 :                     a->fflags, true);
     399                 :         16 :         } else {
     400                 :        140 :                 ret = pkg_addfile_attr(p->pkg, path, buf, p->uname,
     401                 :         70 :                     p->gname, p->perm, 0, true);
     402                 :            :         }
     403                 :            : 
     404                 :         86 :         free(buf);
     405                 :            : 
     406                 :         86 :         return (ret);
     407                 :         93 : }
     408                 :            : 
     409                 :            : static int
     410                 :         14 : config(struct plist *p, char *line, struct file_attr *a)
     411                 :            : {
     412                 :         14 :         return (meta_file(p, line, a, true));
     413                 :            : }
     414                 :            : 
     415                 :            : static int
     416                 :         79 : file(struct plist *p, char *line, struct file_attr *a)
     417                 :            : {
     418                 :         79 :         return (meta_file(p, line, a, false));
     419                 :            : }
     420                 :            : 
     421                 :            : static int
     422                 :          2 : setmod(struct plist *p, char *line, struct file_attr *a __unused)
     423                 :            : {
     424                 :            :         void *set;
     425                 :            : 
     426                 :          2 :         p->perm = 0;
     427                 :            : 
     428         [ +  + ]:          2 :         if (line[0] == '\0')
     429                 :          1 :                 return (EPKG_OK);
     430                 :            : 
     431         [ +  - ]:          1 :         if ((set = parse_mode(line)) == NULL) {
     432                 :          0 :                 pkg_emit_error("%s wrong mode value", line);
     433                 :          0 :                 return (EPKG_FATAL);
     434                 :            :         }
     435                 :          1 :         p->perm = getmode(set, 0);
     436                 :          1 :         return (EPKG_OK);
     437                 :          2 : }
     438                 :            : 
     439                 :            : static int
     440                 :          2 : setowner(struct plist *p, char *line, struct file_attr *a __unused)
     441                 :            : {
     442                 :          2 :         free(p->uname);
     443         [ +  + ]:          2 :         if (line[0] == '\0')
     444                 :          1 :                 p->uname = xstrdup("root");
     445                 :            :         else
     446                 :          1 :                 p->uname = xstrdup(line);
     447                 :          2 :         return (EPKG_OK);
     448                 :            : }
     449                 :            : 
     450                 :            : static int
     451                 :          2 : setgroup(struct plist *p, char *line, struct file_attr *a __unused)
     452                 :            : {
     453                 :          2 :         free(p->gname);
     454         [ +  + ]:          2 :         if (line[0] == '\0')
     455                 :          1 :                 p->gname = xstrdup("wheel");
     456                 :            :         else
     457                 :          1 :                 p->gname = xstrdup(line);
     458                 :          2 :         return (EPKG_OK);
     459                 :            : }
     460                 :            : 
     461                 :            : static int
     462                 :          2 : comment_key(struct plist *p __unused, char *line __unused , struct file_attr *a __unused)
     463                 :            : {
     464                 :            :         /* ignore md5 will be recomputed anyway */
     465                 :          2 :         return (EPKG_OK);
     466                 :            : }
     467                 :            : 
     468                 :            : static struct keyact {
     469                 :            :         const char *key;
     470                 :            :         int (*action)(struct plist *, char *, struct file_attr *);
     471                 :            : } keyacts[] = {
     472                 :            :         { "cwd", setprefix },
     473                 :            :         { "comment", comment_key },
     474                 :            :         { "config", config },
     475                 :            :         { "dir", dir },
     476                 :            :         { "include", include_plist },
     477                 :            :         { "mode", setmod },
     478                 :            :         { "owner", setowner },
     479                 :            :         { "group", setgroup },
     480                 :            :         { "override_prefix", override_prefix },
     481                 :            :         { "var", add_variable },
     482                 :            :         /* old pkg compat */
     483                 :            :         { "name", name_key },
     484                 :            :         { NULL, NULL },
     485                 :            : };
     486                 :            : 
     487                 :            : static struct lua_map {
     488                 :            :         const char *key;
     489                 :            :         pkg_lua_script type;
     490                 :            : } lua_mapping[] = {
     491                 :            :         { "pre-install-lua", PKG_LUA_PRE_INSTALL },
     492                 :            :         { "post-install-lua", PKG_LUA_POST_INSTALL },
     493                 :            :         { "pre-deinstall-lua", PKG_LUA_PRE_DEINSTALL },
     494                 :            :         { "post-deinstall-lua", PKG_LUA_POST_DEINSTALL },
     495                 :            : };
     496                 :            : 
     497                 :            : static struct script_map {
     498                 :            :         const char *key;
     499                 :            :         pkg_script type;
     500                 :            : } script_mapping[] = {
     501                 :            :         { "pre-install", PKG_SCRIPT_PRE_INSTALL },
     502                 :            :         { "post-install", PKG_SCRIPT_POST_INSTALL },
     503                 :            :         { "pre-deinstall", PKG_SCRIPT_PRE_DEINSTALL },
     504                 :            :         { "post-deinstall", PKG_SCRIPT_POST_DEINSTALL },
     505                 :            : };
     506                 :            : 
     507                 :            : static void
     508                 :         78 : populate_keywords(struct plist *p)
     509                 :            : {
     510                 :            :         struct keyword *k;
     511                 :            :         struct action *a;
     512                 :            :         int i;
     513                 :            : 
     514         [ +  + ]:        936 :         for (i = 0; keyacts[i].key != NULL; i++) {
     515                 :        858 :                 k = xcalloc(1, sizeof(struct keyword));
     516                 :        858 :                 a = xmalloc(sizeof(struct action));
     517                 :        858 :                 k->keyword = xstrdup(keyacts[i].key);
     518                 :        858 :                 a->perform = keyacts[i].action;
     519   [ -  +  +  -  :        858 :                 tll_push_back(k->actions, a);
          #  #  -  +  -  
                      + ]
     520   [ +  +  -  + ]:       1638 :                 pkghash_safe_add(p->keywords, k->keyword, k, NULL);
     521                 :        858 :         }
     522                 :         78 : }
     523                 :            : 
     524                 :            : static void
     525                 :        858 : keyword_free(struct keyword *k)
     526                 :            : {
     527                 :        858 :         free(k->keyword);
     528   [ +  -  +  +  :       1716 :         tll_free_and_free(k->actions, free);
                   -  + ]
     529                 :        858 :         free(k);
     530                 :        858 : }
     531                 :            : 
     532                 :            : static int
     533                 :         14 : parse_actions(const ucl_object_t *o, struct plist *p,
     534                 :            :     char *line, struct file_attr *a, int argc, char **argv)
     535                 :            : {
     536                 :            :         const ucl_object_t *cur;
     537                 :            :         const char *actname;
     538                 :         14 :         ucl_object_iter_t it = NULL;
     539                 :         14 :         int i, j = 0;
     540                 :         14 :         int r, rc = EPKG_OK;
     541                 :            : 
     542         [ +  + ]:         18 :         while ((cur = ucl_iterate_object(o, &it, true))) {
     543                 :          5 :                 actname = ucl_object_tostring(cur);
     544         [ -  + ]:         13 :                 for (i = 0; list_actions[i].name != NULL; i++) {
     545         [ +  - ]:         31 :                         if (!strncasecmp(actname, list_actions[i].name,
     546   [ +  +  +  + ]:         26 :                             list_actions[i].namelen) &&
     547         [ +  - ]:          5 :                             (actname[list_actions[i].namelen ] == '\0' ||
     548                 :          5 :                              actname[list_actions[i].namelen ] == '(' )) {
     549                 :          5 :                                 actname += list_actions[i].namelen;
     550         [ -  + ]:          5 :                                 if (*actname == '(') {
     551   [ +  +  +  + ]:         10 :                                         if (strspn(actname + 1, "1234567890")
     552                 :          5 :                                             != strlen(actname + 1) - 1) {
     553                 :          1 :                                                 pkg_emit_error(
     554                 :            :                                                     "Invalid argument: "
     555                 :            :                                                     "expecting a number "
     556                 :          1 :                                                     "got %s", actname);
     557                 :          1 :                                                 return (EPKG_FATAL);
     558                 :            :                                         }
     559                 :          4 :                                         j = strtol(actname+1, NULL, 10);
     560         [ +  - ]:          4 :                                         if (j > argc) {
     561                 :          0 :                                                 pkg_emit_error(
     562                 :            :                                                     "Invalid argument requested %d"
     563                 :          0 :                                                     " available: %d", j, argc);
     564                 :          0 :                                                 return (EPKG_FATAL);
     565                 :            :                                         }
     566                 :          4 :                                 }
     567         [ +  - ]:          4 :                                 r = list_actions[i].perform(p, j > 0 ? argv[j - 1] : line, a);
     568   [ -  +  #  # ]:          4 :                                 if (r != EPKG_OK && rc == EPKG_OK)
     569                 :          0 :                                         rc = r;
     570                 :          4 :                                 break;
     571                 :            :                         }
     572                 :          8 :                 }
     573                 :            :         }
     574                 :            : 
     575                 :         13 :         return (rc);
     576                 :         14 : }
     577                 :            : 
     578                 :            : static void
     579                 :          0 : parse_attributes(const ucl_object_t *o, struct file_attr **a)
     580                 :            : {
     581                 :            :         const ucl_object_t *cur;
     582                 :          0 :         ucl_object_iter_t it = NULL;
     583                 :            :         const char *key;
     584                 :            : 
     585         [ #  # ]:          0 :         if (*a == NULL)
     586                 :          0 :                 *a = xcalloc(1, sizeof(struct file_attr));
     587                 :            : 
     588         [ #  # ]:          0 :         while ((cur = ucl_iterate_object(o, &it, true))) {
     589                 :          0 :                 key = ucl_object_key(cur);
     590         [ #  # ]:          0 :                 if (key == NULL)
     591                 :          0 :                         continue;
     592   [ #  #  #  # ]:          0 :                 if (STRIEQ(key, "owner") && cur->type == UCL_STRING) {
     593                 :          0 :                         free((*a)->owner);
     594                 :          0 :                         (*a)->owner = xstrdup(ucl_object_tostring(cur));
     595                 :          0 :                         continue;
     596                 :            :                 }
     597   [ #  #  #  # ]:          0 :                 if (STRIEQ(key, "group") && cur->type == UCL_STRING) {
     598                 :          0 :                         free((*a)->group);
     599                 :          0 :                         (*a)->group = xstrdup(ucl_object_tostring(cur));
     600                 :          0 :                         continue;
     601                 :            :                 }
     602         [ #  # ]:          0 :                 if (STRIEQ(key, "mode")) {
     603         [ #  # ]:          0 :                         if (cur->type == UCL_STRING) {
     604                 :            :                                 void *set;
     605         [ #  # ]:          0 :                                 if ((set = parse_mode(ucl_object_tostring(cur))) == NULL) {
     606                 :          0 :                                         pkg_emit_error("Bad format for the mode attribute: %s", ucl_object_tostring(cur));
     607                 :          0 :                                         return;
     608                 :            :                                 }
     609                 :          0 :                                 (*a)->mode = getmode(set, 0);
     610                 :          0 :                                 free(set);
     611                 :          0 :                         } else {
     612                 :          0 :                                 pkg_emit_error("Expecting a string for the mode attribute, ignored");
     613                 :            :                         }
     614                 :          0 :                 }
     615                 :            :         }
     616                 :          0 : }
     617                 :            : 
     618                 :            : static void
     619                 :          3 : append_script(struct plist *p, pkg_script t, const char *cmd)
     620                 :            : {
     621   [ -  -  +  -  :          3 :         switch (t) {
                      - ]
     622                 :            :         case PKG_SCRIPT_PRE_INSTALL:
     623                 :          0 :                 fprintf(p->pre_install_buf->fp, "%s\n", cmd);
     624                 :          0 :                 break;
     625                 :            :         case PKG_SCRIPT_POST_INSTALL:
     626                 :          3 :                 fprintf(p->post_install_buf->fp, "%s\n", cmd);
     627                 :          3 :                 break;
     628                 :            :         case PKG_SCRIPT_PRE_DEINSTALL:
     629                 :          0 :                 fprintf(p->pre_deinstall_buf->fp, "%s\n", cmd);
     630                 :          0 :                 break;
     631                 :            :         case PKG_SCRIPT_POST_DEINSTALL:
     632                 :          0 :                 fprintf(p->post_deinstall_buf->fp, "%s\n", cmd);
     633                 :          0 :                 break;
     634                 :            :         }
     635                 :          3 : }
     636                 :            : 
     637                 :            : static int
     638                 :         19 : apply_keyword_file(ucl_object_t *obj, struct plist *p, char *line, struct file_attr *attr)
     639                 :            : {
     640                 :            :         const ucl_object_t *o, *cur, *elt;
     641                 :         19 :         ucl_object_iter_t it = NULL;
     642                 :            :         struct pkg_message *msg;
     643                 :            :         char *cmd;
     644                 :         19 :         const char *l = line;
     645                 :         19 :         char *formated_line = NULL;
     646                 :         19 :         char **args = NULL;
     647                 :         19 :         char *buf, *tofree = NULL;
     648                 :         19 :         struct file_attr *freeattr = NULL;
     649                 :         19 :         int spaces, argc = 0;
     650                 :         19 :         int ret = EPKG_FATAL;
     651                 :            : 
     652   [ +  +  -  + ]:         19 :         if ((o = ucl_object_find_key(obj,  "arguments")) && ucl_object_toboolean(o)) {
     653                 :         15 :                 spaces = pkg_utils_count_spaces(line);
     654                 :         15 :                 args = xmalloc((spaces + 1)* sizeof(char *));
     655                 :         15 :                 tofree = buf = xstrdup(line);
     656         [ +  + ]:         52 :                 while (buf != NULL) {
     657                 :         37 :                         args[argc++] = pkg_utils_tokenize(&buf);
     658                 :            :                 }
     659                 :         15 :         }
     660                 :            : 
     661         [ +  - ]:         19 :         if ((o = ucl_object_find_key(obj,  "attributes")))
     662         [ #  # ]:          0 :                 parse_attributes(o, attr != NULL ? &attr : &freeattr);
     663                 :            : 
     664   [ -  +  #  # ]:         19 :         if ((o = ucl_object_find_key(obj,  "preformat_arguments")) &&
     665                 :          0 :             ucl_object_toboolean(o)) {
     666                 :          0 :                 format_exec_cmd(&formated_line, line, p->prefix, p->last_file, NULL, 0,
     667                 :            :                                 NULL, false);
     668                 :          0 :                 l = formated_line;
     669                 :          0 :         }
     670                 :            :         /* add all shell scripts */
     671         [ +  + ]:         92 :         for (int i = 0; i < NELEM(script_mapping); i++) {
     672         [ +  + ]:         74 :                 if ((o = ucl_object_find_key(obj, script_mapping[i].key))) {
     673   [ +  +  +  +  :         12 :                         if (format_exec_cmd(&cmd, ucl_object_tostring(o), p->prefix,
                   +  + ]
     674                 :          8 :                             p->last_file, l, argc, args, false) != EPKG_OK)
     675                 :          1 :                                 goto keywords_cleanup;
     676                 :          3 :                         append_script(p, script_mapping[i].type, cmd);
     677                 :          3 :                         free(cmd);
     678                 :          3 :                 }
     679                 :         73 :         }
     680                 :            : 
     681                 :            :         /* add all lua scripts */
     682         [ +  + ]:         90 :         for (int i = 0; i < NELEM(lua_mapping); i++) {
     683         [ +  + ]:         72 :                 if ((o = ucl_object_find_key(obj, lua_mapping[i].key))) {
     684   [ +  -  +  -  :          6 :                         if (format_exec_cmd(&cmd, ucl_object_tostring(o), p->prefix,
                   +  - ]
     685                 :          4 :                             p->last_file, l, argc, args, true) != EPKG_OK)
     686                 :          0 :                                 goto keywords_cleanup;
     687                 :          2 :                         pkg_add_lua_script(p->pkg, cmd, lua_mapping[i].type);
     688                 :          2 :                         free(cmd);
     689                 :          2 :                 }
     690                 :         72 :         }
     691                 :         18 :         free(formated_line);
     692                 :            : 
     693         [ +  + ]:         18 :         if ((o = ucl_object_find_key(obj, "messages"))) {
     694         [ +  + ]:          4 :                 while ((cur = ucl_iterate_object(o, &it, true))) {
     695                 :          3 :                         elt = ucl_object_find_key(cur, "message");
     696                 :          3 :                         msg = xcalloc(1, sizeof(*msg));
     697                 :          3 :                         msg->str = xstrdup(ucl_object_tostring(elt));
     698                 :          3 :                         msg->type = PKG_MESSAGE_ALWAYS;
     699                 :          3 :                         elt = ucl_object_find_key(cur, "type");
     700         [ +  + ]:          3 :                         if (elt != NULL) {
     701         [ +  + ]:          2 :                                 if (STRIEQ(ucl_object_tostring(elt), "install"))
     702                 :          1 :                                         msg->type = PKG_MESSAGE_INSTALL;
     703         [ -  + ]:          1 :                                 else if (STRIEQ(ucl_object_tostring(elt), "remove"))
     704                 :          0 :                                         msg->type = PKG_MESSAGE_REMOVE;
     705         [ -  + ]:          1 :                                 else if (STRIEQ(ucl_object_tostring(elt), "upgrade"))
     706                 :          1 :                                         msg->type = PKG_MESSAGE_UPGRADE;
     707                 :          2 :                         }
     708   [ -  +  -  +  :          3 :                         tll_push_back(p->pkg->message, msg);
          +  -  +  -  -  
                      + ]
     709                 :            :                 }
     710                 :          1 :         }
     711                 :            : 
     712                 :         18 :         ret = EPKG_OK;
     713         [ +  + ]:         18 :         if ((o = ucl_object_find_key(obj,  "actions")))
     714                 :         14 :                 ret = parse_actions(o, p, line, attr, argc, args);
     715                 :            : 
     716   [ +  +  +  + ]:         28 :         if (ret == EPKG_OK && (o = ucl_object_find_key(obj, "prepackaging"))) {
     717                 :         10 :                 lua_State *L = luaL_newstate();
     718                 :            :                 static const luaL_Reg plist_lib[] = {
     719                 :            :                         { "config", lua_config },
     720                 :            :                         { "dir", lua_dir },
     721                 :            :                         { "file", lua_file },
     722                 :            :                         { NULL, NULL },
     723                 :            :                 };
     724                 :         10 :                 luaL_openlibs(L);
     725                 :         10 :                 lua_pushlightuserdata(L, p);
     726                 :         10 :                 lua_setglobal(L, "plist");
     727                 :         10 :                 lua_pushlightuserdata(L, attr);
     728                 :         10 :                 lua_setglobal(L, "attrs");
     729                 :         10 :                 lua_pushstring(L, line);
     730                 :         10 :                 lua_setglobal(L, "line");
     731                 :         10 :                 lua_args_table(L, args, argc);
     732                 :         10 :                 luaL_newlib(L, plist_lib);
     733                 :         10 :                 lua_setglobal(L, "pkg");
     734                 :         10 :                 lua_override_ios(L, false);
     735                 :         10 :                 pkg_debug(3, "Scripts: executing lua\n--- BEGIN ---"
     736                 :         10 :                     "\n%s\nScripts: --- END ---", ucl_object_tostring(o));
     737   [ +  -  -  + ]:         10 :                 if (luaL_dostring(L, ucl_object_tostring(o))) {
     738                 :          0 :                         pkg_emit_error("Failed to execute lua script: "
     739                 :          0 :                             "%s", lua_tostring(L, -1));
     740                 :          0 :                         ret = EPKG_FATAL;
     741                 :          0 :                 }
     742         [ +  + ]:         10 :                 if (lua_tonumber(L, -1) != 0) {
     743                 :          8 :                         ret = EPKG_FATAL;
     744                 :          8 :                 }
     745                 :         10 :                 lua_close(L);
     746                 :         10 :         }
     747                 :            : 
     748                 :            : keywords_cleanup:
     749                 :         19 :         free(args);
     750                 :         19 :         free(tofree);
     751                 :         19 :         return (ret);
     752                 :            : }
     753                 :            : 
     754                 :            : static int
     755                 :         22 : external_keyword(struct plist *plist, char *keyword, char *line, struct file_attr *attr)
     756                 :            : {
     757                 :            :         struct ucl_parser *parser;
     758                 :         22 :         const char *keyword_dir = NULL;
     759                 :            :         char keyfile_path[MAXPATHLEN];
     760                 :         22 :         int ret = EPKG_UNKNOWN, fd;
     761                 :            :         ucl_object_t *o, *schema;
     762                 :            :         const ucl_object_t *obj;
     763                 :            :         struct ucl_schema_error err;
     764                 :            : 
     765                 :         22 :         keyword_dir = pkg_object_string(pkg_config_get("PLIST_KEYWORDS_DIR"));
     766         [ +  + ]:         22 :         if (keyword_dir == NULL) {
     767                 :          2 :                 keyword_dir = pkg_object_string(pkg_config_get("PORTSDIR"));
     768                 :          4 :                 snprintf(keyfile_path, sizeof(keyfile_path),
     769                 :          2 :                     "%s/Keywords/%s.ucl", keyword_dir, keyword);
     770                 :          2 :         } else {
     771                 :         40 :                 snprintf(keyfile_path, sizeof(keyfile_path),
     772                 :         20 :                     "%s/%s.ucl", keyword_dir, keyword);
     773                 :            :         }
     774                 :            : 
     775                 :         22 :         fd = open(keyfile_path, O_RDONLY);
     776         [ +  + ]:         22 :         if (fd == -1) {
     777                 :          3 :                 pkg_emit_error("cannot load keyword from %s: %s",
     778                 :          3 :                                 keyfile_path, strerror(errno));
     779                 :          3 :                 return (EPKG_UNKNOWN);
     780                 :            :         }
     781                 :            : 
     782                 :         19 :         parser = ucl_parser_new(UCL_PARSER_NO_FILEVARS);
     783         [ +  - ]:         19 :         if (!ucl_parser_add_fd(parser, fd)) {
     784                 :          0 :                 pkg_emit_error("cannot parse keyword: %s",
     785                 :          0 :                                 ucl_parser_get_error(parser));
     786                 :          0 :                 ucl_parser_free(parser);
     787                 :          0 :                 close(fd);
     788                 :          0 :                 return (EPKG_UNKNOWN);
     789                 :            :         }
     790                 :            : 
     791                 :         19 :         close(fd);
     792                 :         19 :         o = ucl_parser_get_object(parser);
     793                 :         19 :         ucl_parser_free(parser);
     794                 :            : 
     795                 :         19 :         schema = keyword_open_schema();
     796                 :            : 
     797         [ -  + ]:         19 :         if (schema != NULL) {
     798         [ +  - ]:         19 :                 if (!ucl_object_validate(schema, o, &err)) {
     799                 :          0 :                         pkg_emit_error("Keyword definition %s cannot be validated: %s", keyfile_path, err.msg);
     800                 :          0 :                         ucl_object_unref(o);
     801                 :          0 :                         return (EPKG_FATAL);
     802                 :            :                 }
     803                 :         19 :         }
     804                 :            : 
     805   [ +  +  -  + ]:         19 :         if ((obj = ucl_object_find_key(o, "deprecated")) &&
     806                 :          2 :             ucl_object_toboolean(obj)) {
     807                 :          2 :                 obj = ucl_object_find_key(o, "deprecation_message");
     808                 :          4 :                 pkg_emit_error("Use of '@%s' is deprecated%s%s", keyword,
     809                 :          2 :                    obj != NULL ? ": " : "",
     810         [ +  + ]:          2 :                    obj != NULL ? ucl_object_tostring(obj) : "");
     811         [ -  + ]:          2 :                 if (ctx.developer_mode) {
     812                 :          0 :                         ucl_object_unref(o);
     813                 :          0 :                         return (EPKG_FATAL);
     814                 :            :                 }
     815                 :          2 :         }
     816                 :         19 :         ret = apply_keyword_file(o, plist, line, attr);
     817         [ +  + ]:         19 :         if (ret != EPKG_OK) {
     818                 :         10 :                 pkg_emit_error("Fail to apply keyword '%s'", keyword);
     819                 :         10 :         }
     820                 :            : 
     821                 :         19 :         return (ret);
     822                 :         22 : }
     823                 :            : 
     824                 :            :  struct file_attr *
     825                 :         23 : parse_keyword_args(char *args, char *keyword)
     826                 :            : {
     827                 :            :         struct file_attr *attr;
     828                 :            :         char *owner, *group, *permstr, *fflags;
     829                 :         23 :         void *set = NULL;
     830                 :         23 :         u_long fset = 0;
     831                 :            : 
     832                 :         23 :         owner = group = permstr = fflags = NULL;
     833                 :            : 
     834                 :            :         /* remove last ')' */
     835                 :         23 :         args[strlen(args) -1] = '\0';
     836                 :            : 
     837                 :         66 :         do {
     838                 :         66 :                 args[0] = '\0';
     839                 :         66 :                 args++;
     840         [ +  + ]:         75 :                 while (isspace(*args))
     841                 :          9 :                         args++;
     842         [ +  + ]:         66 :                 if (*args == '\0')
     843                 :         14 :                         break;
     844         [ +  + ]:         52 :                 if (owner == NULL) {
     845                 :         21 :                         owner = args;
     846         [ +  + ]:         52 :                 } else if (group == NULL) {
     847                 :         18 :                         group = args;
     848         [ +  + ]:         31 :                 } else if (permstr == NULL) {
     849                 :         10 :                         permstr = args;
     850         [ -  + ]:         13 :                 } else if (fflags == NULL) {
     851                 :          3 :                         fflags = args;
     852                 :          3 :                         break;
     853                 :            :                 } else {
     854                 :          0 :                         return (NULL);
     855                 :            :                 }
     856         [ +  + ]:         49 :         } while ((args = strchr(args, ',')) != NULL);
     857                 :            : 
     858   [ +  +  -  + ]:         23 :         if (fflags != NULL && *fflags != '\0') {
     859                 :            : #ifdef HAVE_STRTOFFLAGS
     860         [ +  + ]:          3 :                 if (strtofflags(&fflags, &fset, NULL) != 0) {
     861                 :          2 :                         pkg_emit_error("Malformed keyword '%s', wrong fflags",
     862                 :          2 :                             keyword);
     863                 :          2 :                         return (NULL);
     864                 :            :                 }
     865                 :            : #else
     866                 :            :                 pkg_emit_error("Malformed keyword '%s', maximum 3 arguments "
     867                 :            :                     "are accepted", keyword);
     868                 :            : #endif
     869                 :          1 :         }
     870                 :            : 
     871   [ +  +  +  + ]:         21 :         if (permstr != NULL && *permstr != '\0') {
     872         [ +  - ]:          7 :                 if ((set = parse_mode(permstr)) == NULL) {
     873                 :          0 :                         pkg_emit_error("Malformed keyword '%s', wrong mode "
     874                 :          0 :                             "section", keyword);
     875                 :          0 :                         return (NULL);
     876                 :            :                 }
     877                 :          7 :         }
     878   [ +  +  -  +  :         21 :         if (owner == NULL && group == NULL && set == NULL)
                   -  + ]
     879                 :          2 :                 return (NULL);
     880                 :            : 
     881                 :         19 :         attr = xcalloc(1, sizeof(struct file_attr));
     882   [ +  -  +  + ]:         19 :         if (owner != NULL && *owner != '\0')
     883                 :         14 :                 attr->owner = xstrdup(rtrimspace(owner));
     884   [ +  +  +  + ]:         19 :         if (group != NULL && *group != '\0')
     885                 :         11 :                 attr->group = xstrdup(rtrimspace(group));
     886         [ +  + ]:         19 :         if (set != NULL) {
     887                 :          7 :                 attr->mode = getmode(set, 0);
     888                 :          7 :                 free(set);
     889                 :          7 :         }
     890                 :         19 :         attr->fflags = fset;
     891                 :            : 
     892                 :         19 :         return (attr);
     893                 :         23 : }
     894                 :            : 
     895                 :            : static int
     896                 :         79 : parse_keywords(struct plist *plist, char *keyword,
     897                 :            :     char *line, struct file_attr *attr)
     898                 :            : {
     899                 :         79 :         struct keyword *k = NULL;
     900                 :         79 :         int ret = EPKG_FATAL;
     901                 :            : 
     902                 :            :         /* if keyword is empty consider it as a file */
     903         [ +  + ]:         79 :         if (*keyword == '\0')
     904                 :         11 :                 return (file(plist, line, attr));
     905                 :            : 
     906                 :         68 :         k = pkghash_get_value(plist->keywords, keyword);
     907         [ +  + ]:         68 :         if (k != NULL) {
     908   [ +  -  +  +  :         87 :                 tll_foreach(k->actions, a) {
                   -  + ]
     909                 :         46 :                         ret = a->item->perform(plist, line, attr);
     910         [ +  + ]:         46 :                         if (ret != EPKG_OK)
     911                 :          5 :                                 break;
     912                 :         41 :                 }
     913                 :         46 :                 return (ret);
     914                 :            :         }
     915                 :            : 
     916                 :            :         /*
     917                 :            :          * if we are here it means the keyword has not been found
     918                 :            :          * maybe it is defined externally
     919                 :            :          * let's try to find it
     920                 :            :          */
     921                 :         22 :         return (external_keyword(plist, keyword, line, attr));
     922                 :         79 : }
     923                 :            : 
     924                 :            : char *
     925                 :         87 : extract_keywords(char *line, char **keyword, struct file_attr **attr)
     926                 :            : {
     927                 :            :         char *k, *buf, *tmp;
     928                 :         87 :         struct file_attr *a = NULL;
     929                 :            : 
     930                 :         87 :         buf = k = line;
     931   [ +  +  +  +  :        480 :         while (!(isspace(buf[0]) || buf[0] == '\0')) {
                   +  + ]
     932   [ +  +  +  + ]:        394 :                 if (buf[0] == '(' && (buf = strchr(buf, ')')) == NULL)
     933                 :          1 :                         return (NULL);
     934                 :        393 :                 buf++;
     935                 :            :         }
     936         [ +  + ]:         86 :         if (buf[0] != '\0') {
     937                 :         78 :                 buf[0] = '\0';
     938                 :         78 :                 buf++;
     939                 :         78 :         }
     940                 :            : 
     941                 :            :         /* trim spaces after the keyword */
     942         [ +  + ]:         88 :         while (isspace(buf[0]))
     943                 :          2 :                 buf++;
     944                 :            : 
     945                 :         86 :         pkg_debug(1, "Parsing plist, found keyword: '%s", k);
     946                 :            : 
     947   [ +  +  +  - ]:         86 :         if ((tmp = strchr(k, '(')) != NULL && k[strlen(k) -1] != ')')
     948                 :          0 :                 return (NULL);
     949                 :            : 
     950         [ +  + ]:         86 :         if (tmp != NULL) {
     951                 :         18 :                 a = parse_keyword_args(tmp, k);
     952         [ +  + ]:         18 :                 if (a == NULL)
     953                 :          2 :                         return (NULL);
     954                 :         16 :         }
     955                 :            : 
     956                 :         84 :         *attr = a;
     957                 :         84 :         *keyword = k;
     958                 :            : 
     959                 :         84 :         return (buf);
     960                 :         87 : }
     961                 :            : 
     962                 :            : static void
     963                 :        304 : flush_script_buffer(xstring *buf, struct pkg *p, int type)
     964                 :            : {
     965                 :        304 :         fflush(buf->fp);
     966         [ +  + ]:        304 :         if (buf->buf[0] != '\0') {
     967                 :          3 :                 pkg_appendscript(p, buf->buf, type);
     968                 :          3 :         }
     969                 :        304 : }
     970                 :            : 
     971                 :            : int
     972                 :        142 : plist_parse_line(struct plist *plist, char *line)
     973                 :            : {
     974                 :            :         char *buf, *bkpline;
     975                 :            : 
     976         [ +  + ]:        142 :         if (line[0] == '\0')
     977                 :          4 :                 return (EPKG_OK);
     978                 :            : 
     979                 :        138 :         pkg_debug(1, "Parsing plist line: '%s'", line);
     980                 :        138 :         bkpline = xstrdup(line);
     981                 :            : 
     982         [ +  + ]:        138 :         if (line[0] == '@') {
     983                 :         80 :                 char *keyword = 0;
     984                 :         80 :                 struct file_attr *a = 0;
     985                 :         80 :                 buf = extract_keywords(line + 1, &keyword, &a);
     986         [ +  + ]:         80 :                 if (buf == NULL) {
     987                 :          1 :                         pkg_emit_error("Malformed keyword %s, expecting @keyword "
     988                 :          1 :                             "or @keyword(owner,group,mode)", bkpline);
     989                 :          1 :                         free_file_attr(a);
     990                 :          1 :                         free(bkpline);
     991                 :          1 :                         return (EPKG_FATAL);
     992                 :            :                 }
     993                 :            : 
     994      [ +  +  + ]:         79 :                 switch (parse_keywords(plist, keyword, buf, a)) {
     995                 :            :                 case EPKG_UNKNOWN:
     996                 :         18 :                         pkg_emit_error("unknown keyword %s: %s",
     997                 :          3 :                             keyword, line);
     998                 :            :                         /* FALLTHRU */
     999                 :            :                 case EPKG_FATAL:
    1000                 :         18 :                         free_file_attr(a);
    1001                 :         18 :                         free(bkpline);
    1002                 :         18 :                         return (EPKG_FATAL);
    1003                 :            :                 }
    1004                 :         61 :                 free_file_attr(a);
    1005                 :         61 :         } else {
    1006                 :         58 :                 buf = line;
    1007                 :         58 :                 strlcpy(plist->last_file, buf, sizeof(plist->last_file));
    1008                 :            : 
    1009                 :            :                 /* remove spaces at the begining and at the end */
    1010         [ +  + ]:         60 :                 while (isspace(buf[0]))
    1011                 :          2 :                         buf++;
    1012                 :            : 
    1013         [ +  + ]:         58 :                 if (file(plist, buf, NULL) != EPKG_OK) {
    1014                 :          4 :                         free(bkpline);
    1015                 :          4 :                         return (EPKG_FATAL);
    1016                 :            :                 }
    1017                 :            :         }
    1018                 :            : 
    1019                 :        115 :         free(bkpline);
    1020                 :        115 :         return (EPKG_OK);
    1021                 :        142 : }
    1022                 :            : 
    1023                 :            : struct plist *
    1024                 :         79 : plist_new(struct pkg *pkg, const char *stage)
    1025                 :            : {
    1026                 :            :         struct plist *p;
    1027                 :            : 
    1028                 :         79 :         p = xcalloc(1, sizeof(struct plist));
    1029                 :         79 :         p->plistdirfd = -1;
    1030         [ +  + ]:         79 :         p->stagefd = open(stage ? stage : "/", O_DIRECTORY | O_CLOEXEC);
    1031         [ +  + ]:         79 :         if (p->stagefd == -1) {
    1032                 :          1 :                 free(p);
    1033                 :          1 :                 return (NULL);
    1034                 :            :         }
    1035                 :            : 
    1036                 :         78 :         p->pkg = pkg;
    1037         [ +  + ]:         78 :         if (pkg->prefix != NULL)
    1038                 :         76 :                 strlcpy(p->prefix, pkg->prefix, sizeof(p->prefix));
    1039   [ +  +  +  + ]:         78 :         p->slash = *p->prefix != '\0' && p->prefix[strlen(p->prefix) - 1] == '/' ? "" : "/";
    1040                 :         78 :         p->stage = stage;
    1041                 :            : 
    1042                 :         78 :         p->uname = xstrdup("root");
    1043                 :         78 :         p->gname = xstrdup("wheel");
    1044                 :            : 
    1045                 :         78 :         p->pre_install_buf = xstring_new();
    1046                 :         78 :         p->post_install_buf = xstring_new();
    1047                 :         78 :         p->pre_deinstall_buf = xstring_new();
    1048                 :         78 :         p->post_deinstall_buf = xstring_new();
    1049                 :         78 :         pkgvec_init(&p->hardlinks);
    1050                 :            : 
    1051                 :         78 :         populate_keywords(p);
    1052                 :            : 
    1053                 :         78 :         return (p);
    1054                 :         79 : }
    1055                 :            : 
    1056                 :            : void
    1057                 :         78 : plist_free(struct plist *p)
    1058                 :            : {
    1059         [ +  - ]:         78 :         if (p == NULL)
    1060                 :          0 :                 return;
    1061                 :            : 
    1062         [ -  + ]:         78 :         if (p->stagefd != -1)
    1063                 :         78 :                 close(p->stagefd);
    1064         [ +  + ]:         78 :         if (p->plistdirfd != -1)
    1065                 :         76 :                 close(p->plistdirfd);
    1066                 :            : 
    1067                 :         78 :         pkghash_it it = pkghash_iterator(p->keywords);
    1068         [ +  + ]:        936 :         while (pkghash_next(&it))
    1069                 :        858 :                 keyword_free((struct keyword *)it.value);
    1070                 :         78 :         pkghash_destroy(p->keywords);
    1071                 :         78 :         p->keywords = NULL;
    1072                 :            : 
    1073                 :         78 :         free(p->uname);
    1074                 :         78 :         free(p->gname);
    1075         [ +  + ]:         83 :         pkgvec_free_and_free(&p->hardlinks, free);
    1076                 :            : 
    1077                 :         78 :         xstring_free(p->post_deinstall_buf);
    1078                 :         78 :         xstring_free(p->post_install_buf);
    1079                 :         78 :         xstring_free(p->pre_deinstall_buf);
    1080                 :         78 :         xstring_free(p->pre_install_buf);
    1081                 :            : 
    1082                 :         78 :         free(p);
    1083                 :         78 : }
    1084                 :            : 
    1085                 :            : char *
    1086                 :        134 : expand_plist_variables(const char *in, kvlist_t *vars)
    1087                 :            : {
    1088                 :            :         xstring *buf;
    1089                 :            :         const char *cp;
    1090                 :            :         size_t len;
    1091                 :            : 
    1092         [ +  + ]:        134 :         if (tll_length(*vars) == 0)
    1093                 :        109 :                 return (xstrdup(in));
    1094                 :            : 
    1095                 :         25 :         buf = xstring_new();
    1096                 :         25 :         cp = NULL;
    1097         [ +  + ]:        271 :         while (in[0] != '\0') {
    1098         [ +  + ]:        247 :                 if (in[0] != '%') {
    1099                 :        214 :                         fputc(in[0], buf->fp);
    1100                 :        214 :                         in++;
    1101                 :        214 :                         continue;
    1102                 :            :                 }
    1103                 :         33 :                 in++;
    1104         [ +  + ]:         33 :                 if (in[0] == '\0') {
    1105                 :          1 :                         fputc('%', buf->fp);
    1106                 :          1 :                         break;
    1107                 :            :                 }
    1108         [ +  + ]:         32 :                 if (in[0] != '%') {
    1109                 :          7 :                         fputc('%', buf->fp);
    1110                 :          7 :                         fputc(in[0], buf->fp);
    1111                 :          7 :                         in++;
    1112                 :          7 :                         continue;
    1113                 :            :                 }
    1114                 :         25 :                 in++;
    1115                 :         25 :                 cp = in;
    1116   [ +  -  +  +  :        113 :                 while (in[0] != '\0' && !isspace(in[0])) {
                   +  + ]
    1117   [ +  +  +  - ]:        109 :                         if (in[0] == '%' && in[1] == '%') {
    1118                 :         21 :                                 in++;
    1119                 :         21 :                                 break;
    1120                 :            :                         }
    1121                 :         88 :                         in++;
    1122                 :            :                 }
    1123         [ +  + ]:         25 :                 if (in[0] != '%') {
    1124                 :          4 :                         fprintf(buf->fp, "%%%%%.*s", (int)(in - cp), cp);
    1125                 :          4 :                         continue;
    1126                 :            :                 }
    1127                 :         21 :                 len = in - cp -1;
    1128                 :            :                 /* we have a variable */
    1129                 :         21 :                 bool found = false;
    1130   [ +  -  +  +  :         40 :                 tll_foreach(*vars, i) {
                   +  + ]
    1131         [ +  + ]:         38 :                         if (strncmp(cp, i->item->key, len) != 0)
    1132                 :         19 :                                 continue;
    1133                 :         19 :                         fputs(i->item->value, buf->fp);
    1134                 :         19 :                         found = true;
    1135                 :         19 :                         in++;
    1136                 :         19 :                         break;
    1137                 :            :                 }
    1138         [ +  + ]:         21 :                 if (found)
    1139                 :         19 :                         continue;
    1140                 :          2 :                 fprintf(buf->fp, "%%%%%.*s%%", (int)(in - cp), cp);
    1141                 :          2 :                 in++;
    1142                 :            :         }
    1143                 :         25 :         return (xstring_get(buf));
    1144                 :        134 : }
    1145                 :            : 
    1146                 :            : static int
    1147                 :         78 : plist_parse(struct plist *pplist, FILE *f)
    1148                 :            : {
    1149                 :         78 :         int ret, rc = EPKG_OK;
    1150                 :         78 :         size_t linecap = 0;
    1151                 :            :         ssize_t linelen;
    1152                 :         78 :         char *line = NULL;
    1153                 :            :         char *l;
    1154                 :            : 
    1155         [ +  + ]:        203 :         while ((linelen = getline(&line, &linecap, f)) > 0) {
    1156         [ -  + ]:        125 :                 if (line[linelen - 1] == '\n')
    1157                 :        125 :                         line[linelen - 1] = '\0';
    1158                 :        125 :                 l = expand_plist_variables(line, &pplist->variables);
    1159                 :        125 :                 ret = plist_parse_line(pplist, l);
    1160                 :        125 :                 free(l);
    1161   [ +  +  +  + ]:        125 :                 if (ret != EPKG_OK && rc == EPKG_OK)
    1162                 :         16 :                         rc = ret;
    1163                 :            :         }
    1164                 :         78 :         free(line);
    1165                 :            : 
    1166                 :         78 :         return (rc);
    1167                 :            : }
    1168                 :            : 
    1169                 :            : static int
    1170                 :         76 : open_directory_of(const char *file)
    1171                 :            : {
    1172                 :            :         char path[MAXPATHLEN];
    1173                 :            :         char *walk;
    1174                 :            : 
    1175         [ +  + ]:         76 :         if (strchr(file, '/') == NULL) {
    1176         [ +  - ]:         73 :                 if (getcwd(path, MAXPATHLEN) == NULL) {
    1177                 :          0 :                         pkg_emit_error("Unable to determine current location");
    1178                 :          0 :                         return (-1);
    1179                 :            :                 }
    1180                 :         73 :                 return (open(path, O_DIRECTORY));
    1181                 :            :         }
    1182                 :          3 :         strlcpy(path, file, sizeof(path));
    1183                 :          3 :         walk = strrchr(path, '/');
    1184                 :          3 :         *walk = '\0';
    1185                 :          3 :         return (open(path, O_DIRECTORY));
    1186                 :         76 : }
    1187                 :            : 
    1188                 :            : int
    1189                 :          8 : add_variable(struct plist *p, char *line, struct file_attr *a __unused)
    1190                 :            : {
    1191                 :            :         const char *key;
    1192                 :            :         char *val;
    1193                 :            : 
    1194                 :          8 :         key = val = line;
    1195   [ +  +  +  +  :         40 :         while (*val != '\0' && !isspace(*val))
                   +  + ]
    1196                 :         32 :                 val++;
    1197         [ +  + ]:          8 :         if (*val != '\0') {
    1198                 :          6 :                 *val = '\0';
    1199                 :          6 :                 val++;
    1200                 :          6 :         }
    1201                 :            : 
    1202         [ +  - ]:          8 :         if (*key == '\0') {
    1203                 :          0 :                 pkg_emit_error("Inside in @include it is not allowed to reuse @include");
    1204                 :          0 :                 return (EPKG_FATAL);
    1205                 :            :         }
    1206                 :            : 
    1207   [ +  +  +  -  :          8 :         while (*val != '\0' && isspace(*val))
                   -  + ]
    1208                 :          0 :                 val++;
    1209                 :            : 
    1210   [ +  +  +  +  :         18 :         tll_foreach(p->variables, v) {
                   +  + ]
    1211         [ +  + ]:         12 :                 if (STREQ(v->item->key, key)) {
    1212                 :          2 :                         free(v->item->value);
    1213                 :          2 :                         v->item->value = xstrdup(val);
    1214                 :          2 :                         return (EPKG_OK);
    1215                 :            :                 }
    1216                 :         10 :         }
    1217                 :          6 :         struct pkg_kv *kv = pkg_kv_new(key, val);
    1218   [ +  +  +  +  :          6 :         tll_push_back(p->variables, kv);
          +  -  -  +  +  
                      + ]
    1219                 :          6 :         return (EPKG_OK);
    1220                 :          8 : }
    1221                 :            : 
    1222                 :            : int
    1223                 :          3 : include_plist(struct plist *p, char *name, struct file_attr *a __unused)
    1224                 :            : {
    1225                 :            :         FILE *f;
    1226                 :            :         int fd;
    1227                 :            :         int rc;
    1228                 :            : 
    1229         [ +  + ]:          3 :         if (p->in_include) {
    1230                 :          1 :                 pkg_emit_error("Inside in @include it is not allowed to reuse @include");
    1231                 :          1 :                 return (EPKG_FATAL);
    1232                 :            :         }
    1233                 :          2 :         p->in_include = true;
    1234                 :            : 
    1235                 :          2 :         fd = openat(p->plistdirfd, name, O_RDONLY);
    1236         [ +  - ]:          2 :         if (fd == -1) {
    1237                 :          0 :                 pkg_emit_errno("Inpossible to include", name);
    1238                 :          0 :                 return (EPKG_FATAL);
    1239                 :            :         }
    1240                 :          2 :         f = fdopen(fd, "r");
    1241         [ +  - ]:          2 :         if (f == NULL) {
    1242                 :          0 :                 pkg_emit_errno("Inpossible to include", name);
    1243                 :          0 :                 close(fd);
    1244                 :          0 :                 return (EPKG_FATAL);
    1245                 :            :         }
    1246                 :            : 
    1247                 :          2 :         rc = plist_parse(p, f);
    1248                 :            : 
    1249                 :          2 :         fclose(f);
    1250                 :          2 :         return (rc);
    1251                 :          3 : }
    1252                 :            : 
    1253                 :            : int
    1254                 :         76 : ports_parse_plist(struct pkg *pkg, const char *plist, const char *stage)
    1255                 :            : {
    1256                 :         76 :         int rc = EPKG_OK;
    1257                 :            :         struct plist *pplist;
    1258                 :            :         FILE *plist_f;
    1259                 :            : 
    1260         [ +  - ]:         76 :         assert(pkg != NULL);
    1261         [ +  - ]:         76 :         assert(plist != NULL);
    1262                 :            : 
    1263         [ +  - ]:         76 :         if ((pplist = plist_new(pkg, stage)) == NULL)
    1264                 :          0 :                 return (EPKG_FATAL);
    1265                 :            : 
    1266                 :         76 :         pplist->plistdirfd = open_directory_of(plist);
    1267         [ +  - ]:         76 :         if (pplist->plistdirfd == -1) {
    1268                 :          0 :                 pkg_emit_error("impossible to open the directory where the plist is: %s", plist);
    1269                 :          0 :                 plist_free(pplist);
    1270                 :          0 :                 return (EPKG_FATAL);
    1271                 :            :         }
    1272         [ +  - ]:         76 :         if ((plist_f = fopen(plist, "re")) == NULL) {
    1273                 :          0 :                 pkg_emit_error("Unable to open plist file: %s", plist);
    1274                 :          0 :                 plist_free(pplist);
    1275                 :          0 :                 return (EPKG_FATAL);
    1276                 :            :         }
    1277                 :            : 
    1278                 :         76 :         rc = plist_parse(pplist, plist_f);
    1279                 :            : 
    1280                 :         76 :         pkg->flatsize = pplist->flatsize;
    1281                 :            : 
    1282                 :         76 :         flush_script_buffer(pplist->pre_install_buf, pkg,
    1283                 :            :             PKG_SCRIPT_PRE_INSTALL);
    1284                 :         76 :         flush_script_buffer(pplist->post_install_buf, pkg,
    1285                 :            :             PKG_SCRIPT_POST_INSTALL);
    1286                 :         76 :         flush_script_buffer(pplist->pre_deinstall_buf, pkg,
    1287                 :            :             PKG_SCRIPT_PRE_DEINSTALL);
    1288                 :         76 :         flush_script_buffer(pplist->post_deinstall_buf, pkg,
    1289                 :            :             PKG_SCRIPT_POST_DEINSTALL);
    1290                 :            : 
    1291                 :         76 :         fclose(plist_f);
    1292                 :            : 
    1293                 :         76 :         plist_free(pplist);
    1294                 :            : 
    1295                 :         76 :         return (rc);
    1296                 :         76 : }
    1297                 :            : 
    1298                 :            : /*
    1299                 :            :  * if the provided database is NULL then we don't want to register the package
    1300                 :            :  * in the database aka NO_PKG_REGISTER
    1301                 :            :  */
    1302                 :            : int
    1303                 :         77 : pkg_add_port(struct pkgdb *db, struct pkg *pkg, const char *input_path,
    1304                 :            :     const char *reloc, bool testing)
    1305                 :            : {
    1306                 :            :         const char *location;
    1307                 :         77 :         int rc = EPKG_OK;
    1308                 :            :         xstring *message;
    1309                 :            : 
    1310   [ +  +  +  + ]:         77 :         if (db != NULL && pkg_is_installed(db, pkg->name) != EPKG_END) {
    1311                 :          1 :                 return(EPKG_INSTALLED);
    1312                 :            :         }
    1313                 :            : 
    1314                 :         76 :         location = reloc;
    1315         [ +  + ]:         76 :         if (ctx.pkg_rootdir != NULL)
    1316                 :          2 :                 location = ctx.pkg_rootdir;
    1317                 :            : 
    1318   [ +  +  -  + ]:         76 :         if (ctx.pkg_rootdir == NULL && location != NULL)
    1319                 :          0 :                 pkg_kv_add(&pkg->annotations, "relocated", location, "annotation");
    1320                 :            : 
    1321                 :         76 :         pkg_emit_install_begin(pkg);
    1322                 :            : 
    1323         [ +  + ]:         76 :         if (db != NULL) {
    1324                 :         75 :                 rc = pkgdb_register_pkg(db, pkg, 0, NULL);
    1325         [ +  + ]:         75 :                 if (rc != EPKG_OK) {
    1326                 :          1 :                         db = NULL;
    1327                 :          1 :                         goto cleanup;
    1328                 :            :                 }
    1329                 :         74 :         }
    1330                 :            : 
    1331         [ +  + ]:         75 :         if (!testing) {
    1332                 :            :                 /* Execute pre-install scripts */
    1333                 :         63 :                 pkg_lua_script_run(pkg, PKG_LUA_PRE_INSTALL, false);
    1334                 :         63 :                 pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL, false);
    1335                 :            : 
    1336         [ +  + ]:         63 :                 if (input_path != NULL) {
    1337                 :          3 :                         pkg_register_cleanup_callback(pkg_rollback_cb, pkg);
    1338                 :          3 :                         rc = pkg_add_fromdir(pkg, input_path);
    1339                 :          3 :                         pkg_unregister_cleanup_callback(pkg_rollback_cb, pkg);
    1340         [ +  - ]:          3 :                         if (rc != EPKG_OK) {
    1341                 :          0 :                                 pkg_rollback_pkg(pkg);
    1342         [ #  # ]:          0 :                                 if (db != NULL)
    1343                 :          0 :                                         pkg_delete_dirs(db, pkg, NULL);
    1344                 :          0 :                         }
    1345                 :          3 :                 }
    1346                 :            : 
    1347                 :            :                 /* Execute post-install scripts */
    1348                 :         63 :                 pkg_lua_script_run(pkg, PKG_LUA_POST_INSTALL, false);
    1349                 :         63 :                 pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL, false);
    1350                 :         63 :         }
    1351                 :            : 
    1352         [ -  + ]:         75 :         if (rc == EPKG_OK) {
    1353                 :         75 :                 pkg_emit_install_finished(pkg, NULL);
    1354         [ +  + ]:         75 :                 if (pkg_has_message(pkg))
    1355                 :         11 :                         message = xstring_new();
    1356   [ +  +  +  +  :         94 :                 tll_foreach(pkg->message, m) {
                   +  + ]
    1357   [ +  +  +  + ]:         19 :                         if (m->item->type == PKG_MESSAGE_ALWAYS ||
    1358                 :          8 :                             m->item->type == PKG_MESSAGE_INSTALL) {
    1359                 :         13 :                                 fprintf(message->fp, "%s\n", m->item->str);
    1360                 :         13 :                         }
    1361                 :         19 :                 }
    1362         [ +  + ]:         75 :                 if (pkg_has_message(pkg)) {
    1363                 :         11 :                         fflush(message->fp);
    1364         [ -  + ]:         11 :                         if (message->buf[0] != '\0') {
    1365                 :         11 :                                 pkg_emit_message(message->buf);
    1366                 :         11 :                         }
    1367                 :         11 :                         xstring_free(message);
    1368                 :         11 :                 }
    1369                 :         75 :         }
    1370                 :            :         /* it is impossible at this point to get any cleanup triggers to run */
    1371                 :         75 :         triggers_execute(NULL);
    1372                 :            : 
    1373                 :            : cleanup:
    1374         [ +  + ]:         76 :         if (db != NULL)
    1375                 :         74 :                 pkgdb_register_finale(db, rc, NULL);
    1376                 :            : 
    1377                 :         76 :         return (rc);
    1378                 :         77 : }

Generated by: LCOV version 1.15