LCOV - code coverage report
Current view: top level - libpkg - pkg_ports.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 388 644 60.2 %
Date: 2015-08-15 Functions: 27 41 65.9 %

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

Generated by: LCOV version 1.10