LCOV - code coverage report
Current view: top level - libpkg - pkg_ports.c (source / functions) Hit Total Coverage
Test: rapport Lines: 575 710 81.0 %
Date: 2021-12-10 16:22:55 Functions: 31 36 86.1 %
Branches: 307 438 70.1 %

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

Generated by: LCOV version 1.15