LCOV - code coverage report
Current view: top level - libpkg - pkg_manifest.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 444 737 60.2 %
Date: 2015-08-15 Functions: 24 30 80.0 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2015 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       4             :  * Copyright (c) 2013-2014 Vsevolod Stakhov <vsevolod@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/types.h>
      30             : #include <sys/sbuf.h>
      31             : 
      32             : #include <assert.h>
      33             : #include <ctype.h>
      34             : #include <errno.h>
      35             : #include <stdbool.h>
      36             : #include <stdlib.h>
      37             : #include <string.h>
      38             : #include <ucl.h>
      39             : 
      40             : #include "pkg.h"
      41             : #include "private/event.h"
      42             : #include "private/pkg.h"
      43             : #include "private/utils.h"
      44             : 
      45             : #define PKG_UNKNOWN             -1
      46             : #define PKG_DEPS                -2
      47             : #define PKG_FILES               -3
      48             : #define PKG_DIRS                -4
      49             : #define PKG_SCRIPTS             -5
      50             : #define PKG_OPTIONS             -8
      51             : #define PKG_OPTION_DEFAULTS     -9
      52             : #define PKG_OPTION_DESCRIPTIONS -10
      53             : #define PKG_USERS               -11
      54             : #define PKG_GROUPS              -12
      55             : #define PKG_DIRECTORIES         -13
      56             : #define PKG_SHLIBS_REQUIRED     -14
      57             : #define PKG_SHLIBS_PROVIDED     -15
      58             : #define PKG_CONFLICTS           -17
      59             : #define PKG_PROVIDES            -18
      60             : #define PKG_REQUIRES            -19
      61             : 
      62             : static int pkg_string(struct pkg *, const ucl_object_t *, int);
      63             : static int pkg_obj(struct pkg *, const ucl_object_t *, int);
      64             : static int pkg_array(struct pkg *, const ucl_object_t *, int);
      65             : static int pkg_int(struct pkg *, const ucl_object_t *, int);
      66             : static int pkg_set_deps_from_object(struct pkg *, const ucl_object_t *);
      67             : static int pkg_set_files_from_object(struct pkg *, const ucl_object_t *);
      68             : static int pkg_set_dirs_from_object(struct pkg *, const ucl_object_t *);
      69             : 
      70             : /*
      71             :  * Keep sorted
      72             :  */
      73             : static struct manifest_key {
      74             :         const char *key;
      75             :         int type;
      76             :         uint16_t valid_type;
      77             :         int (*parse_data)(struct pkg *, const ucl_object_t *, int);
      78             : } manifest_keys[] = {
      79             :         { "annotations",         PKG_ANNOTATIONS,         UCL_OBJECT, pkg_obj},
      80             :         { "abi",                 PKG_ABI,                 UCL_STRING, pkg_string},
      81             :         { "arch",                PKG_ARCH,                UCL_STRING, pkg_string},
      82             :         { "categories",          PKG_CATEGORIES,          UCL_ARRAY,  pkg_array},
      83             :         { "comment",             PKG_COMMENT,             UCL_STRING, pkg_string},
      84             :         { "conflicts",           PKG_CONFLICTS,           UCL_ARRAY,  pkg_array},
      85             :         { "config",              PKG_CONFIG_FILES,        UCL_ARRAY,  pkg_array},
      86             :         { "dep_formula",         PKG_DEP_FORMULA,         UCL_STRING, pkg_string},
      87             :         { "deps",                PKG_DEPS,                UCL_OBJECT, pkg_obj},
      88             :         { "desc",                PKG_DESC,                UCL_STRING, pkg_string},
      89             :         { "directories",         PKG_DIRECTORIES,         UCL_OBJECT, pkg_obj},
      90             :         { "dirs",                PKG_DIRS,                UCL_ARRAY,  pkg_array},
      91             :         { "files",               PKG_FILES,               UCL_OBJECT, pkg_obj},
      92             :         { "flatsize",            PKG_FLATSIZE,            UCL_INT,    pkg_int},
      93             :         { "groups",              PKG_GROUPS,              UCL_ARRAY,  pkg_array},
      94             :         { "licenselogic",        PKG_LICENSE_LOGIC,       UCL_STRING, pkg_string},
      95             :         { "licenses",            PKG_LICENSES,            UCL_ARRAY,  pkg_array},
      96             :         { "maintainer",          PKG_MAINTAINER,          UCL_STRING, pkg_string},
      97             :         { "message",             PKG_MESSAGE,             UCL_STRING, pkg_string},
      98             :         { "name",                PKG_NAME,                UCL_STRING, pkg_string},
      99             :         { "name",                PKG_NAME,                UCL_INT,    pkg_string},
     100             :         { "options",             PKG_OPTIONS,             UCL_OBJECT, pkg_obj},
     101             :         { "option_defaults",     PKG_OPTION_DEFAULTS,     UCL_OBJECT, pkg_obj},
     102             :         { "option_descriptions", PKG_OPTION_DESCRIPTIONS, UCL_OBJECT, pkg_obj},
     103             :         { "origin",              PKG_ORIGIN,              UCL_STRING, pkg_string},
     104             :         { "path",                PKG_REPOPATH,            UCL_STRING, pkg_string},
     105             :         { "repopath",            PKG_REPOPATH,            UCL_STRING, pkg_string},
     106             :         { "pkgsize",             PKG_PKGSIZE,             UCL_INT,    pkg_int},
     107             :         { "prefix",              PKG_PREFIX,              UCL_STRING, pkg_string},
     108             :         { "provides",            PKG_PROVIDES,            UCL_ARRAY,  pkg_array},
     109             :         { "requires",            PKG_REQUIRES,            UCL_ARRAY,  pkg_array},
     110             :         { "scripts",             PKG_SCRIPTS,             UCL_OBJECT, pkg_obj},
     111             :         { "shlibs",              PKG_SHLIBS_REQUIRED,     UCL_ARRAY,  pkg_array}, /* Backwards compat with 1.0.x packages */
     112             :         { "shlibs_provided",     PKG_SHLIBS_PROVIDED,     UCL_ARRAY,  pkg_array},
     113             :         { "shlibs_required",     PKG_SHLIBS_REQUIRED,     UCL_ARRAY,  pkg_array},
     114             :         { "sum",                 PKG_CKSUM,               UCL_STRING, pkg_string},
     115             :         { "users",               PKG_USERS,               UCL_ARRAY,  pkg_array},
     116             :         { "version",             PKG_VERSION,             UCL_STRING, pkg_string},
     117             :         { "version",             PKG_VERSION,             UCL_INT,    pkg_string},
     118             :         { "www",                 PKG_WWW,                 UCL_STRING, pkg_string},
     119             :         { NULL, -99, -99, NULL}
     120             : };
     121             : 
     122             : typedef int (*parse_data)(struct pkg *, const ucl_object_t *, int);
     123       27360 : KHASH_MAP_INIT_INT(dataparser, parse_data);
     124             : typedef khash_t(dataparser) dataparser_t;
     125             : 
     126             : struct pkg_manifest_key {
     127             :         const char *key;
     128             :         int type;
     129             :         dataparser_t *parser;
     130             :         UT_hash_handle hh;
     131             : };
     132             : 
     133             : int
     134         173 : pkg_manifest_keys_new(struct pkg_manifest_key **key)
     135             : {
     136             :         int i, absent;
     137             :         struct pkg_manifest_key *k;
     138             :         khint_t h;
     139             : 
     140         173 :         if (*key != NULL)
     141          17 :                 return (EPKG_OK);
     142             : 
     143        6396 :         for (i = 0; manifest_keys[i].key != NULL; i++) {
     144        6240 :                 HASH_FIND_STR(*key, manifest_keys[i].key, k);
     145        6240 :                 if (k == NULL) {
     146        5928 :                         k = calloc(1, sizeof(struct pkg_manifest_key));
     147        5928 :                         k->key = manifest_keys[i].key;
     148        5928 :                         k->type = manifest_keys[i].type;
     149        5928 :                         k->parser = kh_init(dataparser);
     150        5928 :                         HASH_ADD_KEYPTR(hh, *key, k->key, strlen(k->key), k);
     151             :                 }
     152        6240 :                 h = kh_put_dataparser(k->parser, manifest_keys[i].valid_type, &absent);
     153        6240 :                 if (absent == 0)
     154           0 :                         continue;
     155        6240 :                 kh_value(k->parser, h) = manifest_keys[i].parse_data;
     156             :         }
     157             : 
     158         156 :         return (EPKG_OK);
     159             : }
     160             : 
     161             : static void
     162        4674 : pmk_free(struct pkg_manifest_key *key) {
     163        4674 :         kh_destroy_dataparser(key->parser);
     164        4674 :         free(key);
     165        4674 : }
     166             : 
     167             : void
     168         123 : pkg_manifest_keys_free(struct pkg_manifest_key *key)
     169             : {
     170         123 :         if (key == NULL)
     171         123 :                 return;
     172             : 
     173         123 :         HASH_FREE(key, pmk_free);
     174             : }
     175             : 
     176             : static int
     177         225 : urlencode(const char *src, struct sbuf **dest)
     178             : {
     179             :         size_t len;
     180             :         size_t i;
     181             : 
     182         225 :         sbuf_init(dest);
     183             : 
     184         225 :         len = strlen(src);
     185        4290 :         for (i = 0; i < len; i++) {
     186        4065 :                 if (!isascii(src[i]) || src[i] == '%')
     187           0 :                         sbuf_printf(*dest, "%%%.2x", (unsigned char)src[i]);
     188             :                 else
     189        4065 :                         sbuf_putc(*dest, src[i]);
     190             :         }
     191         225 :         sbuf_finish(*dest);
     192             : 
     193         225 :         return (EPKG_OK);
     194             : }
     195             : 
     196             : 
     197             : static int
     198         409 : urldecode(const char *src, struct sbuf **dest)
     199             : {
     200             :         size_t len;
     201             :         size_t i;
     202             :         char c;
     203         409 :         char hex[] = {'\0', '\0', '\0'};
     204             : 
     205         409 :         sbuf_init(dest);
     206             : 
     207         409 :         len = strlen(src);
     208       12326 :         for (i = 0; i < len; i++) {
     209       11917 :                 if (src[i] != '%') {
     210       11917 :                         sbuf_putc(*dest, src[i]);
     211             :                 } else {
     212           0 :                         if (i + 2 > len) {
     213           0 :                                 pkg_emit_error("unexpected end of string");
     214           0 :                                 return (EPKG_FATAL);
     215             :                         }
     216             : 
     217           0 :                         hex[0] = src[++i];
     218           0 :                         hex[1] = src[++i];
     219           0 :                         errno = 0;
     220           0 :                         c = strtol(hex, NULL, 16);
     221           0 :                         if (errno != 0) {
     222             :                                 /*
     223             :                                  * if it fails consider this is not a urlencoded
     224             :                                  * information
     225             :                                  */
     226           0 :                                 sbuf_printf(*dest, "%%%s", hex);
     227             :                         } else {
     228           0 :                                 sbuf_putc(*dest, c);
     229             :                         }
     230             :                 }
     231             :         }
     232         409 :         sbuf_finish(*dest);
     233             : 
     234         409 :         return (EPKG_OK);
     235             : }
     236             : 
     237             : static int
     238          44 : script_type_str(const char *str)
     239             : {
     240          44 :         if (strcmp(str, "pre-install") == 0)
     241          17 :                 return (PKG_SCRIPT_PRE_INSTALL);
     242          27 :         if (strcmp(str, "install") == 0)
     243           0 :                 return (PKG_SCRIPT_INSTALL);
     244          27 :         if (strcmp(str, "post-install") == 0)
     245          21 :                 return (PKG_SCRIPT_POST_INSTALL);
     246           6 :         if (strcmp(str, "pre-upgrade") == 0)
     247           0 :                 return (PKG_SCRIPT_PRE_UPGRADE);
     248           6 :         if (strcmp(str, "upgrade") == 0)
     249           0 :                 return (PKG_SCRIPT_UPGRADE);
     250           6 :         if (strcmp(str, "post-upgrade") == 0)
     251           0 :                 return (PKG_SCRIPT_POST_UPGRADE);
     252           6 :         if (strcmp(str, "pre-deinstall") == 0)
     253           2 :                 return (PKG_SCRIPT_PRE_DEINSTALL);
     254           4 :         if (strcmp(str, "deinstall") == 0)
     255           0 :                 return (PKG_SCRIPT_DEINSTALL);
     256           4 :         if (strcmp(str, "post-deinstall") == 0)
     257           4 :                 return (PKG_SCRIPT_POST_DEINSTALL);
     258           0 :         return (PKG_SCRIPT_UNKNOWN);
     259             : }
     260             : 
     261             : static int
     262        1851 : pkg_string(struct pkg *pkg, const ucl_object_t *obj, int attr)
     263             : {
     264        1851 :         int ret = EPKG_OK;
     265             :         const char *str;
     266        1851 :         struct sbuf *buf = NULL;
     267             : 
     268        1851 :         str = ucl_object_tostring_forced(obj);
     269             : 
     270        1851 :         switch (attr)
     271             :         {
     272             :         case PKG_LICENSE_LOGIC:
     273           4 :                 if (!strcmp(str, "single"))
     274           4 :                         pkg->licenselogic = LICENSE_SINGLE;
     275           0 :                 else if (!strcmp(str, "or") ||
     276           0 :                          !strcmp(str, "dual"))
     277           0 :                         pkg->licenselogic = LICENSE_OR;
     278           0 :                 else if (!strcmp(str, "and") ||
     279           0 :                          !strcmp(str, "multi"))
     280           0 :                         pkg->licenselogic = LICENSE_AND;
     281             :                 else {
     282           0 :                         pkg_emit_error("Unknown license logic: %s", str);
     283           0 :                         ret = EPKG_FATAL;
     284             :                 }
     285           4 :                 break;
     286             :         case PKG_ABI:
     287         151 :                 pkg->abi = strdup(str);
     288         151 :                 break;
     289             :         case PKG_ARCH:
     290         112 :                 pkg->arch = strdup(str);
     291         112 :                 break;
     292             :         case PKG_COMMENT:
     293         189 :                 pkg->comment = strdup(str);
     294         189 :                 break;
     295             :         case PKG_DESC:
     296         189 :                 urldecode(str, &buf);
     297         189 :                 sbuf_finish(buf);
     298         189 :                 pkg->desc = strdup(sbuf_data(buf));
     299         189 :                 sbuf_delete(buf);
     300         189 :                 break;
     301             :         case PKG_MAINTAINER:
     302         189 :                 pkg->maintainer = strdup(str);
     303         189 :                 break;
     304             :         case PKG_MESSAGE:
     305           0 :                 pkg->message = strdup(str);
     306           0 :                 break;
     307             :         case PKG_NAME:
     308         189 :                 pkg->name = strdup(str);
     309         189 :                 break;
     310             :         case PKG_ORIGIN:
     311         189 :                 pkg->origin = strdup(str);
     312         189 :                 break;
     313             :         case PKG_PREFIX:
     314         189 :                 pkg->prefix = strdup(str);
     315         189 :                 break;
     316             :         case PKG_REPOPATH:
     317          48 :                 pkg->repopath = strdup(str);
     318          48 :                 break;
     319             :         case PKG_CKSUM:
     320          24 :                 pkg->sum = strdup(str);
     321          24 :                 break;
     322             :         case PKG_VERSION:
     323         189 :                 pkg->version = strdup(str);
     324         189 :                 break;
     325             :         case PKG_WWW:
     326         189 :                 pkg->www = strdup(str);
     327         189 :                 break;
     328             :         case PKG_DEP_FORMULA:
     329           0 :                 pkg->dep_formula = strdup(str);
     330           0 :                 break;
     331             :         }
     332             : 
     333        1851 :         return (ret);
     334             : }
     335             : 
     336             : static int
     337         132 : pkg_int(struct pkg *pkg, const ucl_object_t *obj, int attr)
     338             : {
     339         132 :         switch (attr) {
     340             :         case PKG_FLATSIZE:
     341         108 :                 pkg->flatsize = ucl_object_toint(obj);
     342         108 :                 break;
     343             :         case PKG_PKGSIZE:
     344          24 :                 pkg->pkgsize = ucl_object_toint(obj);
     345          24 :                 break;
     346             :         }
     347         132 :         return (EPKG_OK);
     348             : }
     349             : 
     350             : static int
     351         230 : pkg_array(struct pkg *pkg, const ucl_object_t *obj, int attr)
     352             : {
     353             :         const ucl_object_t *cur;
     354         230 :         ucl_object_iter_t it = NULL;
     355             : 
     356         230 :         pkg_debug(3, "%s", "Manifest: parsing array");
     357         690 :         while ((cur = ucl_iterate_object(obj, &it, true))) {
     358         230 :                 switch (attr) {
     359             :                 case PKG_CATEGORIES:
     360         180 :                         if (cur->type != UCL_STRING)
     361           0 :                                 pkg_emit_error("Skipping malformed category");
     362             :                         else
     363         180 :                                 pkg_strel_add(&pkg->categories,
     364             :                                     ucl_object_tostring(cur), "category");
     365         180 :                         break;
     366             :                 case PKG_LICENSES:
     367           2 :                         if (cur->type != UCL_STRING)
     368           0 :                                 pkg_emit_error("Skipping malformed license");
     369             :                         else
     370           2 :                                 pkg_strel_add(&pkg->licenses,
     371             :                                     ucl_object_tostring(cur), "license");
     372           2 :                         break;
     373             :                 case PKG_USERS:
     374           0 :                         if (cur->type == UCL_STRING)
     375           0 :                                 pkg_adduser(pkg, ucl_object_tostring(cur));
     376           0 :                         else if (cur->type == UCL_OBJECT)
     377           0 :                                 pkg_obj(pkg, cur, attr);
     378             :                         else
     379           0 :                                 pkg_emit_error("Skipping malformed license");
     380           0 :                         break;
     381             :                 case PKG_GROUPS:
     382           0 :                         if (cur->type == UCL_STRING)
     383           0 :                                 pkg_addgroup(pkg, ucl_object_tostring(cur));
     384           0 :                         else if (cur->type == UCL_OBJECT)
     385           0 :                                 pkg_obj(pkg, cur, attr);
     386             :                         else
     387           0 :                                 pkg_emit_error("Skipping malformed license");
     388           0 :                         break;
     389             :                 case PKG_DIRS:
     390           0 :                         if (cur->type == UCL_STRING)
     391           0 :                                 pkg_adddir(pkg, ucl_object_tostring(cur), false);
     392           0 :                         else if (cur->type == UCL_OBJECT)
     393           0 :                                 pkg_obj(pkg, cur, attr);
     394             :                         else
     395           0 :                                 pkg_emit_error("Skipping malformed dirs");
     396           0 :                         break;
     397             :                 case PKG_SHLIBS_REQUIRED:
     398           0 :                         if (cur->type != UCL_STRING)
     399           0 :                                 pkg_emit_error("Skipping malformed required shared library");
     400             :                         else
     401           0 :                                 pkg_addshlib_required(pkg, ucl_object_tostring(cur));
     402           0 :                         break;
     403             :                 case PKG_SHLIBS_PROVIDED:
     404           6 :                         if (cur->type != UCL_STRING)
     405           0 :                                 pkg_emit_error("Skipping malformed provided shared library");
     406             :                         else
     407           6 :                                 pkg_addshlib_provided(pkg, ucl_object_tostring(cur));
     408           6 :                         break;
     409             :                 case PKG_CONFLICTS:
     410           0 :                         if (cur->type != UCL_STRING)
     411           0 :                                 pkg_emit_error("Skipping malformed conflict name");
     412             :                         else
     413           0 :                                 pkg_addconflict(pkg, ucl_object_tostring(cur));
     414           0 :                         break;
     415             :                 case PKG_PROVIDES:
     416          14 :                         if (cur->type != UCL_STRING)
     417           0 :                                 pkg_emit_error("Skipping malformed provide name");
     418             :                         else
     419          14 :                                 pkg_addprovide(pkg, ucl_object_tostring(cur));
     420          14 :                         break;
     421             :                 case PKG_CONFIG_FILES:
     422           0 :                         if (cur->type != UCL_STRING)
     423           0 :                                 pkg_emit_error("Skipping malformed config file name");
     424             :                         else
     425           0 :                                 pkg_addconfig_file(pkg, ucl_object_tostring(cur), NULL);
     426           0 :                         break;
     427             :                 case PKG_REQUIRES:
     428          28 :                         if (cur->type != UCL_STRING)
     429           0 :                                 pkg_emit_error("Skipping malformed require name");
     430             :                         else
     431          28 :                                 pkg_addrequire(pkg, ucl_object_tostring(cur));
     432          28 :                         break;
     433             :                 }
     434             :         }
     435             : 
     436         230 :         return (EPKG_OK);
     437             : }
     438             : 
     439             : static int
     440         206 : pkg_obj(struct pkg *pkg, const ucl_object_t *obj, int attr)
     441             : {
     442         206 :         struct sbuf *tmp = NULL;
     443             :         const ucl_object_t *cur;
     444         206 :         ucl_object_iter_t it = NULL;
     445             :         pkg_script script_type;
     446             :         const char *key, *buf;
     447             :         size_t len;
     448             : 
     449         206 :         pkg_debug(3, "%s", "Manifest: parsing object");
     450         814 :         while ((cur = ucl_iterate_object(obj, &it, true))) {
     451         402 :                 key = ucl_object_key(cur);
     452         402 :                 if (key == NULL)
     453           0 :                         continue;
     454         402 :                 switch (attr) {
     455             :                 case PKG_DEPS:
     456         118 :                         if (cur->type != UCL_OBJECT && cur->type != UCL_ARRAY)
     457           0 :                                 pkg_emit_error("Skipping malformed dependency %s",
     458             :                                     key);
     459             :                         else
     460         118 :                                 pkg_set_deps_from_object(pkg, cur);
     461         118 :                         break;
     462             :                 case PKG_DIRS:
     463           0 :                         if (cur->type != UCL_OBJECT)
     464           0 :                                 pkg_emit_error("Skipping malformed dirs %s",
     465             :                                     key);
     466             :                         else
     467           0 :                                 pkg_set_dirs_from_object(pkg, cur);
     468           0 :                         break;
     469             :                 case PKG_DIRECTORIES:
     470           9 :                         if (cur->type == UCL_BOOLEAN) {
     471           0 :                                 urldecode(key, &tmp);
     472           0 :                                 pkg_adddir(pkg, sbuf_data(tmp), false);
     473           9 :                         } else if (cur->type == UCL_OBJECT) {
     474           0 :                                 pkg_set_dirs_from_object(pkg, cur);
     475           9 :                         } else if (cur->type == UCL_STRING) {
     476           9 :                                 urldecode(key, &tmp);
     477           9 :                                 pkg_adddir(pkg, sbuf_data(tmp), false);
     478             :                         } else {
     479           0 :                                 pkg_emit_error("Skipping malformed directories %s",
     480             :                                     key);
     481             :                         }
     482           9 :                         break;
     483             :                 case PKG_FILES:
     484         167 :                         if (cur->type == UCL_STRING) {
     485         167 :                                 buf = ucl_object_tolstring(cur, &len);
     486         167 :                                 urldecode(key, &tmp);
     487         167 :                                 pkg_addfile(pkg, sbuf_data(tmp), len >= 2 ? buf : NULL, false);
     488           0 :                         } else if (cur->type == UCL_OBJECT)
     489           0 :                                 pkg_set_files_from_object(pkg, cur);
     490             :                         else
     491           0 :                                 pkg_emit_error("Skipping malformed files %s",
     492             :                                    key);
     493         167 :                         break;
     494             :                 case PKG_OPTIONS:
     495          62 :                         if (cur->type != UCL_STRING && cur->type != UCL_BOOLEAN)
     496           0 :                                 pkg_emit_error("Skipping malformed option %s",
     497             :                                     key);
     498          62 :                         else if (cur->type == UCL_STRING) {
     499          62 :                                 pkg_addoption(pkg, key, ucl_object_tostring(cur));
     500             :                         } else {
     501           0 :                                 pkg_addoption(pkg, key, ucl_object_toboolean(cur) ? "on" : "off");
     502             :                         }
     503          62 :                         break;
     504             :                 case PKG_OPTION_DEFAULTS:
     505           0 :                         if (cur->type != UCL_STRING)
     506           0 :                                 pkg_emit_error("Skipping malformed option default %s",
     507             :                                     key);
     508             :                         else
     509           0 :                                 pkg_addoption_default(pkg, key,
     510             :                                     ucl_object_tostring(cur));
     511           0 :                         break;
     512             :                 case PKG_OPTION_DESCRIPTIONS:
     513           0 :                         if (cur->type != UCL_STRING)
     514           0 :                                 pkg_emit_error("Skipping malformed option description %s",
     515             :                                     key);
     516             :                         else
     517           0 :                                 pkg_addoption_description(pkg, key,
     518             :                                     ucl_object_tostring(cur));
     519           0 :                         break;
     520             :                 case PKG_SCRIPTS:
     521          44 :                         if (cur->type != UCL_STRING)
     522           0 :                                 pkg_emit_error("Skipping malformed scripts %s",
     523             :                                     key);
     524             :                         else {
     525          44 :                                 script_type = script_type_str(key);
     526          44 :                                 if (script_type == PKG_SCRIPT_UNKNOWN) {
     527           0 :                                         pkg_emit_error("Skipping unknown script "
     528             :                                             "type: %s", key);
     529           0 :                                         break;
     530             :                                 }
     531             : 
     532          44 :                                 urldecode(ucl_object_tostring(cur), &tmp);
     533          44 :                                 pkg_addscript(pkg, sbuf_data(tmp), script_type);
     534             :                         }
     535          44 :                         break;
     536             :                 case PKG_ANNOTATIONS:
     537           2 :                         if (cur->type != UCL_STRING)
     538           0 :                                 pkg_emit_error("Skipping malformed annotation %s",
     539             :                                     key);
     540             :                         else
     541           2 :                                 pkg_kv_add(&pkg->annotations, key, ucl_object_tostring(cur), "annotation");
     542           2 :                         break;
     543             :                 }
     544             :         }
     545             : 
     546         206 :         sbuf_free(tmp);
     547             : 
     548         206 :         return (EPKG_OK);
     549             : }
     550             : 
     551             : static int
     552           0 : pkg_set_files_from_object(struct pkg *pkg, const ucl_object_t *obj)
     553             : {
     554             :         const ucl_object_t *cur;
     555           0 :         ucl_object_iter_t it = NULL;
     556           0 :         const char *sum = NULL;
     557           0 :         const char *uname = NULL;
     558           0 :         const char *gname = NULL;
     559           0 :         void *set = NULL;
     560           0 :         mode_t perm = 0;
     561           0 :         struct sbuf *fname = NULL;
     562             :         const char *key, *okey;
     563             : 
     564           0 :         okey = ucl_object_key(obj);
     565           0 :         if (okey == NULL)
     566           0 :                 return (EPKG_FATAL);
     567           0 :         urldecode(okey, &fname);
     568           0 :         while ((cur = ucl_iterate_object(obj, &it, true))) {
     569           0 :                 key = ucl_object_key(cur);
     570           0 :                 if (key == NULL)
     571           0 :                         continue;
     572           0 :                 if (!strcasecmp(key, "uname") && cur->type == UCL_STRING)
     573           0 :                         uname = ucl_object_tostring(cur);
     574           0 :                 else if (!strcasecmp(key, "gname") && cur->type == UCL_STRING)
     575           0 :                         gname = ucl_object_tostring(cur);
     576           0 :                 else if (!strcasecmp(key, "sum") && cur->type == UCL_STRING &&
     577           0 :                     strlen(ucl_object_tostring(cur)) == 64)
     578           0 :                         sum = ucl_object_tostring(cur);
     579           0 :                 else if (!strcasecmp(key, "perm") &&
     580           0 :                     (cur->type == UCL_STRING || cur->type == UCL_INT)) {
     581           0 :                         if ((set = setmode(ucl_object_tostring_forced(cur))) == NULL)
     582           0 :                                 pkg_emit_error("Not a valid mode: %s",
     583             :                                     ucl_object_tostring(cur));
     584             :                         else
     585           0 :                                 perm = getmode(set, 0);
     586             :                 } else {
     587           0 :                         pkg_emit_error("Skipping unknown key for file(%s): %s",
     588             :                             sbuf_data(fname), key);
     589             :                 }
     590             :         }
     591             : 
     592           0 :         pkg_addfile_attr(pkg, sbuf_data(fname), sum, uname, gname, perm, 0,
     593             :             false);
     594           0 :         sbuf_delete(fname);
     595             : 
     596           0 :         return (EPKG_OK);
     597             : }
     598             : 
     599             : static int
     600           0 : pkg_set_dirs_from_object(struct pkg *pkg, const ucl_object_t *obj)
     601             : {
     602             :         const ucl_object_t *cur;
     603           0 :         ucl_object_iter_t it = NULL;
     604           0 :         const char *uname = NULL;
     605           0 :         const char *gname = NULL;
     606             :         void *set;
     607           0 :         mode_t perm = 0;
     608           0 :         struct sbuf *dirname = NULL;
     609             :         const char *key, *okey;
     610             : 
     611           0 :         okey = ucl_object_key(obj);
     612           0 :         if (okey == NULL)
     613           0 :                 return (EPKG_FATAL);
     614           0 :         urldecode(okey, &dirname);
     615           0 :         while ((cur = ucl_iterate_object(obj, &it, true))) {
     616           0 :                 key = ucl_object_key(cur);
     617           0 :                 if (key == NULL)
     618           0 :                         continue;
     619           0 :                 if (!strcasecmp(key, "uname") && cur->type == UCL_STRING)
     620           0 :                         uname = ucl_object_tostring(cur);
     621           0 :                 else if (!strcasecmp(key, "gname") && cur->type == UCL_STRING)
     622           0 :                         gname = ucl_object_tostring(cur);
     623           0 :                 else if (!strcasecmp(key, "perm") &&
     624           0 :                     (cur->type == UCL_STRING || cur->type == UCL_INT)) {
     625           0 :                         if ((set = setmode(ucl_object_tostring_forced(cur))) == NULL)
     626           0 :                                 pkg_emit_error("Not a valid mode: %s",
     627             :                                     ucl_object_tostring(cur));
     628             :                         else
     629           0 :                                 perm = getmode(set, 0);
     630           0 :                 } else if (!strcasecmp(key, "try") && cur->type == UCL_BOOLEAN) {
     631             :                         /* ignore on purpose : compatibility*/
     632             :                 } else {
     633           0 :                         pkg_emit_error("Skipping unknown key for dir(%s): %s",
     634             :                             sbuf_data(dirname), key);
     635             :                 }
     636             :         }
     637             : 
     638           0 :         pkg_adddir_attr(pkg, sbuf_data(dirname), uname, gname, perm, 0, false);
     639           0 :         sbuf_delete(dirname);
     640             : 
     641           0 :         return (EPKG_OK);
     642             : }
     643             : 
     644             : static int
     645         118 : pkg_set_deps_from_object(struct pkg *pkg, const ucl_object_t *obj)
     646             : {
     647             :         const ucl_object_t *cur, *self;
     648         118 :         ucl_object_iter_t it = NULL, it2;
     649         118 :         const char *origin = NULL;
     650         118 :         const char *version = NULL;
     651             :         const char *key, *okey;
     652             : 
     653         118 :         okey = ucl_object_key(obj);
     654         118 :         if (okey == NULL)
     655           0 :                 return (EPKG_FATAL);
     656         118 :         pkg_debug(2, "Found %s", okey);
     657         354 :         while ((self = ucl_iterate_object(obj, &it, (obj->type == UCL_ARRAY)))) {
     658         118 :                 it2 = NULL;
     659         470 :                 while ((cur = ucl_iterate_object(self, &it2, true))) {
     660         234 :                         key = ucl_object_key(cur);
     661         234 :                         if (key == NULL)
     662           0 :                                 continue;
     663         234 :                         if (cur->type != UCL_STRING) {
     664             :                                 /* accept version to be an integer */
     665           4 :                                 if (cur->type == UCL_INT && strcasecmp(key, "version") == 0) {
     666           4 :                                         version = ucl_object_tostring_forced(cur);
     667           4 :                                         continue;
     668             :                                 }
     669             : 
     670           0 :                                 pkg_emit_error("Skipping malformed dependency entry "
     671             :                                                 "for %s", okey);
     672           0 :                                 continue;
     673             :                         }
     674         230 :                         if (strcasecmp(key, "origin") == 0)
     675         118 :                                 origin = ucl_object_tostring(cur);
     676         230 :                         if (strcasecmp(key, "version") == 0)
     677         112 :                                 version = ucl_object_tostring(cur);
     678             :                 }
     679         118 :                 if (origin != NULL)
     680         118 :                         pkg_adddep(pkg, okey, origin, version, false);
     681             :                 else
     682           0 :                         pkg_emit_error("Skipping malformed dependency %s", okey);
     683             :         }
     684             : 
     685         118 :         return (EPKG_OK);
     686             : }
     687             : 
     688             : static int
     689         189 : parse_manifest(struct pkg *pkg, struct pkg_manifest_key *keys, ucl_object_t *obj)
     690             : {
     691             :         const ucl_object_t *cur;
     692         189 :         ucl_object_iter_t it = NULL;
     693             :         struct pkg_manifest_key *selected_key;
     694             :         parse_data dp;
     695             :         const char *key;
     696             :         khint_t k;
     697             : 
     698        2798 :         while ((cur = ucl_iterate_object(obj, &it, true))) {
     699        2420 :                 key = ucl_object_key(cur);
     700        2420 :                 if (key == NULL)
     701           0 :                         continue;
     702        2420 :                 pkg_debug(3, "Manifest: found key: '%s'", key);
     703        2420 :                 HASH_FIND_STR(keys, key, selected_key);
     704        2420 :                 if (selected_key != NULL) {
     705        2420 :                         k = kh_get_dataparser(selected_key->parser, cur->type);
     706        2420 :                         if (k != kh_end(selected_key->parser)) {
     707        2419 :                                 pkg_debug(3, "Manifest: key is valid");
     708        2419 :                                 dp = kh_value(selected_key->parser, k);
     709        2419 :                                 dp(pkg, cur, selected_key->type);
     710             :                         } else {
     711           1 :                                 pkg_emit_error("Skipping malformed key '%s'", key);
     712             :                         }
     713             :                 } else {
     714           0 :                         pkg_emit_error("Skipping unknown key '%s'", key);
     715             :                 }
     716             :         }
     717             : 
     718         189 :         return (EPKG_OK);
     719             : }
     720             : 
     721             : int
     722         104 : pkg_parse_manifest(struct pkg *pkg, char *buf, size_t len, struct pkg_manifest_key *keys)
     723             : {
     724         104 :         struct ucl_parser *p = NULL;
     725             :         const ucl_object_t *cur;
     726         104 :         ucl_object_t *obj = NULL;
     727         104 :         ucl_object_iter_t it = NULL;
     728             :         int rc;
     729             :         struct pkg_manifest_key *sk;
     730             :         const char *key;
     731             :         khint_t k;
     732             : 
     733         104 :         assert(pkg != NULL);
     734         104 :         assert(buf != NULL);
     735             : 
     736         104 :         pkg_debug(2, "%s", "Parsing manifest from buffer");
     737             : 
     738         104 :         p = ucl_parser_new(0);
     739         104 :         if (!ucl_parser_add_chunk(p, buf, len)) {
     740           0 :                 pkg_emit_error("Error parsing manifest: %s",
     741             :                     ucl_parser_get_error(p));
     742           0 :                 ucl_parser_free(p);
     743             : 
     744           0 :                 return (EPKG_FATAL);
     745             :         }
     746             : 
     747         104 :         if ((obj = ucl_parser_get_object(p)) == NULL) {
     748           0 :                 ucl_parser_free(p);
     749           0 :                 return (EPKG_FATAL);
     750             :         }
     751             : 
     752         104 :         ucl_parser_free(p);
     753             : 
     754             :         /* do a minimal validation */
     755         104 :         while ((cur = ucl_iterate_object(obj, &it, true))) {
     756        1487 :                 key = ucl_object_key(cur);
     757        1487 :                 if (key == NULL)
     758           0 :                         continue;
     759        1487 :                 HASH_FIND_STR(keys, key, sk);
     760        1487 :                 if (sk != NULL) {
     761        1487 :                         k = kh_get_dataparser(sk->parser, cur->type);
     762        1487 :                         if (k == kh_end(sk->parser)) {
     763           0 :                                 pkg_emit_error("Bad format in manifest for key:"
     764             :                                     " %s", key);
     765           0 :                                 ucl_object_unref(obj);
     766           0 :                                 return (EPKG_FATAL);
     767             :                         }
     768             :                 }
     769             :         }
     770             : 
     771         104 :         rc = parse_manifest(pkg, keys, obj);
     772             : 
     773         104 :         ucl_object_unref(obj);
     774             : 
     775         104 :         return (rc);
     776             : }
     777             : 
     778             : int
     779          25 : pkg_parse_manifest_fileat(int dfd, struct pkg *pkg, const char *file,
     780             :     struct pkg_manifest_key *keys)
     781             : {
     782          25 :         struct ucl_parser *p = NULL;
     783          25 :         ucl_object_t *obj = NULL;
     784             :         int rc;
     785             :         char *data;
     786          25 :         off_t sz = 0;
     787             : 
     788          25 :         assert(pkg != NULL);
     789          25 :         assert(file != NULL);
     790             : 
     791          25 :         pkg_debug(1, "Parsing manifest from '%s'", file);
     792             : 
     793          25 :         errno = 0;
     794             : 
     795          25 :         if ((rc = file_to_bufferat(dfd, file, &data, &sz)) != EPKG_OK)
     796           0 :                 return (EPKG_FATAL);
     797             : 
     798          25 :         p = ucl_parser_new(0);
     799          25 :         if (!ucl_parser_add_string(p, data, sz)) {
     800           0 :                 pkg_emit_error("manifest parsing error: %s", ucl_parser_get_error(p));
     801           0 :                 ucl_parser_free(p);
     802           0 :                 return (EPKG_FATAL);
     803             :         }
     804             : 
     805          25 :         obj = ucl_parser_get_object(p);
     806          25 :         rc = parse_manifest(pkg, keys, obj);
     807             : 
     808          25 :         ucl_parser_free(p);
     809          25 :         ucl_object_unref(obj);
     810          25 :         free(data);
     811             : 
     812          25 :         return (rc);
     813             : }
     814             : 
     815             : int
     816          60 : pkg_parse_manifest_file(struct pkg *pkg, const char *file, struct pkg_manifest_key *keys)
     817             : {
     818          60 :         struct ucl_parser *p = NULL;
     819             :         const ucl_object_t *cur;
     820          60 :         ucl_object_t *obj = NULL;
     821          60 :         ucl_object_iter_t it = NULL;
     822             :         int rc;
     823             :         struct pkg_manifest_key *sk;
     824             :         const char *key;
     825             :         khint_t k;
     826             : 
     827          60 :         assert(pkg != NULL);
     828          60 :         assert(file != NULL);
     829             : 
     830          60 :         pkg_debug(1, "Parsing manifest from '%s'", file);
     831             : 
     832          60 :         errno = 0;
     833          60 :         p = ucl_parser_new(0);
     834          60 :         if (!ucl_parser_add_file(p, file)) {
     835           0 :                 pkg_emit_error("Error parsing manifest: %s",
     836             :                     ucl_parser_get_error(p));
     837           0 :                 ucl_parser_free(p);
     838           0 :                 return (EPKG_FATAL);
     839             :         }
     840             : 
     841          60 :         if ((obj = ucl_parser_get_object(p)) == NULL) {
     842           0 :                 ucl_parser_free(p);
     843           0 :                 return (EPKG_FATAL);
     844             :         }
     845             : 
     846          60 :         ucl_parser_free(p);
     847             : 
     848             :         /* do a minimal validation */
     849          60 :         while ((cur = ucl_iterate_object(obj, &it, true))) {
     850         683 :                 key = ucl_object_key(cur);
     851         683 :                 if (key == NULL)
     852           0 :                         continue;
     853         683 :                 HASH_FIND_STR(keys, key, sk);
     854         683 :                 if (sk != NULL) {
     855         683 :                         k = kh_get_dataparser(sk->parser, cur->type);
     856         683 :                         if (k == kh_end(sk->parser)) {
     857           0 :                                 pkg_emit_error("Bad format in manifest for key:"
     858             :                                     " %s", key);
     859           0 :                                 ucl_object_unref(obj);
     860           0 :                                 return (EPKG_FATAL);
     861             :                         }
     862             :                 }
     863             :         }
     864             : 
     865          60 :         rc = parse_manifest(pkg, keys, obj);
     866             : 
     867          60 :         ucl_object_unref(obj);
     868             : 
     869          60 :         return (rc);
     870             : }
     871             : 
     872             : int
     873           0 : pkg_emit_filelist(struct pkg *pkg, FILE *f)
     874             : {
     875           0 :         ucl_object_t *obj = NULL, *seq;
     876           0 :         struct pkg_file *file = NULL;
     877           0 :         struct sbuf *b = NULL;
     878             : 
     879           0 :         obj = ucl_object_typed_new(UCL_OBJECT);
     880           0 :         ucl_object_insert_key(obj, ucl_object_fromstring(pkg->origin), "origin", 6, false);
     881           0 :         ucl_object_insert_key(obj, ucl_object_fromstring(pkg->name), "name", 4, false);
     882           0 :         ucl_object_insert_key(obj, ucl_object_fromstring(pkg->version), "version", 7, false);
     883             : 
     884           0 :         seq = NULL;
     885           0 :         while (pkg_files(pkg, &file) == EPKG_OK) {
     886           0 :                 urlencode(file->path, &b);
     887           0 :                 if (seq == NULL)
     888           0 :                         seq = ucl_object_typed_new(UCL_ARRAY);
     889           0 :                 ucl_array_append(seq, ucl_object_fromlstring(sbuf_data(b), sbuf_len(b)));
     890             :         }
     891           0 :         if (seq != NULL)
     892           0 :                 ucl_object_insert_key(obj, seq, "files", 5, false);
     893             : 
     894           0 :         ucl_object_emit_file(obj, UCL_EMIT_JSON_COMPACT, f);
     895             : 
     896           0 :         if (b != NULL)
     897           0 :                 sbuf_delete(b);
     898             : 
     899           0 :         ucl_object_unref(obj);
     900             : 
     901           0 :         return (EPKG_OK);
     902             : }
     903             : 
     904             : pkg_object*
     905         149 : pkg_emit_object(struct pkg *pkg, short flags)
     906             : {
     907             :         struct pkg_strel        *el;
     908             :         struct pkg_kv           *kv;
     909         149 :         struct pkg_dep          *dep      = NULL;
     910         149 :         struct pkg_option       *option   = NULL;
     911         149 :         struct pkg_file         *file     = NULL;
     912         149 :         struct pkg_dir          *dir      = NULL;
     913         149 :         struct pkg_conflict     *conflict = NULL;
     914         149 :         struct pkg_config_file  *cf       = NULL;
     915         149 :         struct sbuf             *tmpsbuf  = NULL;
     916             :         char                    *buf;
     917             :         int i;
     918         149 :         const char *script_types = NULL;
     919             :         char legacyarch[BUFSIZ];
     920             :         ucl_object_t *map, *seq, *submap;
     921         149 :         ucl_object_t *top = ucl_object_typed_new(UCL_OBJECT);
     922             : 
     923         149 :         if (pkg->abi == NULL && pkg->arch != NULL)
     924           0 :                 pkg->abi = strdup(pkg->arch);
     925         149 :         pkg_arch_to_legacy(pkg->abi, legacyarch, BUFSIZ);
     926         149 :         pkg->arch = strdup(legacyarch);
     927         149 :         pkg_debug(4, "Emitting basic metadata");
     928         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->name, 0,
     929             :             UCL_STRING_TRIM), "name", 4, false);
     930         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->origin, 0,
     931             :             UCL_STRING_TRIM), "origin", 6, false);
     932         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->version, 0,
     933             :             UCL_STRING_TRIM), "version", 7, false);
     934         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->comment, 0,
     935             :             UCL_STRING_TRIM), "comment", 7, false);
     936         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->maintainer, 0,
     937             :             UCL_STRING_TRIM), "maintainer", 10, false);
     938         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->www, 0,
     939             :             UCL_STRING_TRIM), "www", 3, false);
     940         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->abi, 0,
     941             :             UCL_STRING_TRIM), "abi", 3, false);
     942         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->arch, 0,
     943             :             UCL_STRING_TRIM), "arch", 4, false);
     944         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->prefix, 0,
     945             :             UCL_STRING_TRIM), "prefix", 6, false);
     946         149 :         ucl_object_insert_key(top, ucl_object_fromstring_common(pkg->sum, 0,
     947             :             UCL_STRING_TRIM), "sum", 3, false);
     948         149 :         ucl_object_insert_key(top, ucl_object_fromint(pkg->flatsize), "flatsize", 8, false);
     949             :         /*
     950             :          * XXX: dirty hack to be compatible with pkg 1.2
     951             :          */
     952         149 :         if (pkg->repopath) {
     953          31 :                 ucl_object_insert_key(top,
     954          31 :                         ucl_object_fromstring(pkg->repopath), "path", 4, false);
     955          31 :                 ucl_object_insert_key(top,
     956          31 :                         ucl_object_fromstring(pkg->repopath), "repopath", 8, false);
     957             :         }
     958             : 
     959         149 :         switch (pkg->licenselogic) {
     960             :         case LICENSE_SINGLE:
     961           0 :                 ucl_object_insert_key(top, ucl_object_fromlstring("single", 6), "licenselogic", 12, false);
     962           0 :                 break;
     963             :         case LICENSE_AND:
     964           0 :                 ucl_object_insert_key(top, ucl_object_fromlstring("and", 3), "licenselogic", 12, false);
     965           0 :                 break;
     966             :         case LICENSE_OR:
     967           0 :                 ucl_object_insert_key(top, ucl_object_fromlstring("or", 2), "licenselogic", 12, false);
     968           0 :                 break;
     969             :         }
     970             : 
     971         149 :         pkg_debug(4, "Emitting licenses");
     972         149 :         seq = NULL;
     973         149 :         el = NULL;
     974         149 :         LL_FOREACH(pkg->licenses, el) {
     975           0 :                 if (seq == NULL)
     976           0 :                         seq = ucl_object_typed_new(UCL_ARRAY);
     977           0 :                 ucl_array_append(seq, ucl_object_fromstring(el->value));
     978             :         }
     979         149 :         if (seq)
     980           0 :                 ucl_object_insert_key(top, seq, "licenses", 8, false);
     981             : 
     982         149 :         if (pkg->pkgsize > 0)
     983          31 :                 ucl_object_insert_key(top, ucl_object_fromint(pkg->pkgsize), "pkgsize", 7, false);
     984             : 
     985         149 :         if (pkg->desc != NULL) {
     986         149 :                 urlencode(pkg->desc, &tmpsbuf);
     987         298 :                 ucl_object_insert_key(top,
     988         298 :                         ucl_object_fromstring_common(sbuf_data(tmpsbuf), sbuf_len(tmpsbuf), UCL_STRING_TRIM),
     989             :                         "desc", 4, false);
     990             :         }
     991             : 
     992         149 :         pkg_debug(4, "Emitting deps");
     993         149 :         map = NULL;
     994         376 :         while (pkg_deps(pkg, &dep) == EPKG_OK) {
     995          78 :                 submap = ucl_object_typed_new(UCL_OBJECT);
     996          78 :                 ucl_object_insert_key(submap, ucl_object_fromstring(dep->origin), "origin", 6, false);
     997          78 :                 ucl_object_insert_key(submap, ucl_object_fromstring(dep->version), "version", 7, false);
     998          78 :                 if (map == NULL)
     999          51 :                         map = ucl_object_typed_new(UCL_OBJECT);
    1000          78 :                 ucl_object_insert_key(map, submap, dep->name, 0, false);
    1001             :         }
    1002         149 :         if (map)
    1003          51 :                 ucl_object_insert_key(top, map, "deps", 4, false);
    1004             : 
    1005         149 :         pkg_debug(4, "Emitting categories");
    1006         149 :         seq = NULL;
    1007         149 :         el = NULL;
    1008         291 :         LL_FOREACH(pkg->categories, el) {
    1009         142 :                 if (seq == NULL)
    1010         142 :                         seq = ucl_object_typed_new(UCL_ARRAY);
    1011         142 :                 ucl_array_append(seq, ucl_object_fromstring(el->value));
    1012             :         }
    1013         149 :         if (seq)
    1014         142 :                 ucl_object_insert_key(top, seq, "categories", 10, false);
    1015             : 
    1016         149 :         pkg_debug(4, "Emitting users");
    1017         149 :         seq = NULL;
    1018         149 :         buf = NULL;
    1019         298 :         while (pkg_users(pkg, &buf) == EPKG_OK) {
    1020           0 :                 if (seq == NULL)
    1021           0 :                         seq = ucl_object_typed_new(UCL_ARRAY);
    1022           0 :                 ucl_array_append(seq, ucl_object_fromstring(buf));
    1023             :         }
    1024         149 :         if (seq)
    1025           0 :                 ucl_object_insert_key(top, seq, "users", 5, false);
    1026             : 
    1027         149 :         pkg_debug(4, "Emitting groups");
    1028         149 :         seq = NULL;
    1029         149 :         buf = NULL;
    1030         298 :         while (pkg_groups(pkg, &buf) == EPKG_OK) {
    1031           0 :                 if (seq == NULL)
    1032           0 :                         seq = ucl_object_typed_new(UCL_ARRAY);
    1033           0 :                 ucl_array_append(seq, ucl_object_fromstring(buf));
    1034             :         }
    1035         149 :         if (seq)
    1036           0 :                 ucl_object_insert_key(top, seq, "groups", 6, false);
    1037             : 
    1038         149 :         pkg_debug(4, "Emitting required");
    1039         149 :         seq = NULL;
    1040         149 :         buf = NULL;
    1041         298 :         while (pkg_shlibs_required(pkg, &buf) == EPKG_OK) {
    1042           0 :                 if (seq == NULL)
    1043           0 :                         seq = ucl_object_typed_new(UCL_ARRAY);
    1044           0 :                 ucl_array_append(seq, ucl_object_fromstring(buf));
    1045             :         }
    1046         149 :         if (seq)
    1047           0 :                 ucl_object_insert_key(top, seq, "shlibs_required", 15, false);
    1048             : 
    1049         149 :         pkg_debug(4, "Emitting shlibs_provided");
    1050         149 :         seq = NULL;
    1051         149 :         buf = NULL;
    1052         298 :         while (pkg_shlibs_provided(pkg, &buf) == EPKG_OK) {
    1053           0 :                 if (seq == NULL)
    1054           0 :                         seq = ucl_object_typed_new(UCL_ARRAY);
    1055           0 :                 ucl_array_append(seq, ucl_object_fromstring(buf));
    1056             :         }
    1057         149 :         if (seq)
    1058           0 :                 ucl_object_insert_key(top, seq, "shlibs_provided", 15, false);
    1059             : 
    1060         149 :         pkg_debug(4, "Emitting conflicts");
    1061         149 :         seq = NULL;
    1062         298 :         while (pkg_conflicts(pkg, &conflict) == EPKG_OK) {
    1063           0 :                 if (seq == NULL)
    1064           0 :                         seq = ucl_object_typed_new(UCL_ARRAY);
    1065           0 :                 ucl_array_append(seq, ucl_object_fromstring(conflict->uid));
    1066             :         }
    1067         149 :         if (seq)
    1068           0 :                 ucl_object_insert_key(top, seq, "conflicts", 9, false);
    1069             : 
    1070         149 :         pkg_debug(4, "Emitting provides");
    1071         149 :         seq = NULL;
    1072         149 :         buf = NULL;
    1073         307 :         while (pkg_provides(pkg, &buf) == EPKG_OK) {
    1074           9 :                 if (seq == NULL)
    1075           9 :                         seq = ucl_object_typed_new(UCL_ARRAY);
    1076           9 :                 ucl_array_append(seq, ucl_object_fromstring(buf));
    1077             :         }
    1078         149 :         if (seq)
    1079           9 :                 ucl_object_insert_key(top, seq, "provides", 8, false);
    1080             : 
    1081         149 :         pkg_debug(4, "Emitting requires");
    1082         149 :         seq = NULL;
    1083         149 :         buf = NULL;
    1084         316 :         while (pkg_requires(pkg, &buf) == EPKG_OK) {
    1085          18 :                 if (seq == NULL)
    1086          18 :                         seq = ucl_object_typed_new(UCL_ARRAY);
    1087          18 :                 ucl_array_append(seq, ucl_object_fromstring(buf));
    1088             :         }
    1089         149 :         if (seq)
    1090          18 :                 ucl_object_insert_key(top, seq, "requires", 8, false);
    1091             : 
    1092         149 :         pkg_debug(4, "Emitting options");
    1093         149 :         map = NULL;
    1094         312 :         while (pkg_options(pkg, &option) == EPKG_OK) {
    1095          14 :                 pkg_debug(2, "Emiting option: %s", option->value);
    1096          14 :                 if (map == NULL)
    1097           7 :                         map = ucl_object_typed_new(UCL_OBJECT);
    1098          14 :                 ucl_object_insert_key(map,
    1099          14 :                     ucl_object_fromstring(option->value),
    1100          14 :                     option->key, 0, false);
    1101             :         }
    1102         149 :         if (map)
    1103           7 :                 ucl_object_insert_key(top, map, "options", 7, false);
    1104             : 
    1105         149 :         map = NULL;
    1106         149 :         kv = NULL;
    1107         149 :         LL_FOREACH(pkg->annotations, kv) {
    1108           0 :                 if (map == NULL)
    1109           0 :                         map = ucl_object_typed_new(UCL_OBJECT);
    1110             :                 /* Add annotations except for internal ones. */
    1111           0 :                 if (strcmp(kv->key, "repository") == 0 ||
    1112           0 :                     strcmp(kv->key, "relocated") == 0)
    1113           0 :                         continue;
    1114           0 :                 ucl_object_insert_key(map, ucl_object_fromstring(kv->value),
    1115           0 :                     kv->key, strlen(kv->key), true);
    1116             :         }
    1117         149 :         if (map)
    1118           0 :                 ucl_object_insert_key(top, map, "annotations", 11, false);
    1119             : 
    1120         149 :         if ((flags & PKG_MANIFEST_EMIT_COMPACT) == 0) {
    1121          59 :                 if ((flags & PKG_MANIFEST_EMIT_NOFILES) == 0) {
    1122          59 :                         pkg_debug(4, "Emitting files");
    1123          59 :                         map = NULL;
    1124         166 :                         while (pkg_files(pkg, &file) == EPKG_OK) {
    1125          48 :                                 if (file->sum == NULL)
    1126           0 :                                         file->sum = strdup("-");
    1127             : 
    1128          48 :                                 urlencode(file->path, &tmpsbuf);
    1129          48 :                                 if (map == NULL)
    1130          45 :                                         map = ucl_object_typed_new(UCL_OBJECT);
    1131          96 :                                 ucl_object_insert_key(map,
    1132          48 :                                     ucl_object_fromstring(file->sum),
    1133          96 :                                     sbuf_data(tmpsbuf), sbuf_len(tmpsbuf), true);
    1134             :                         }
    1135          59 :                         if (map)
    1136          45 :                                 ucl_object_insert_key(top, map, "files", 5, false);
    1137             : 
    1138          59 :                         pkg_debug(3, "Emitting config files");
    1139          59 :                         seq = NULL;
    1140         118 :                         while (pkg_config_files(pkg, &cf) == EPKG_OK) {
    1141           0 :                                 urlencode(cf->path, &tmpsbuf);
    1142           0 :                                 if (seq == NULL)
    1143           0 :                                         seq = ucl_object_typed_new(UCL_ARRAY);
    1144           0 :                                 ucl_array_append(seq, ucl_object_fromstring(sbuf_data(tmpsbuf)));
    1145             :                         }
    1146          59 :                         if (seq)
    1147           0 :                                 ucl_object_insert_key(top, seq, "config", 6, false);
    1148             : 
    1149          59 :                         pkg_debug(4, "Emitting directories");
    1150          59 :                         map = NULL;
    1151         126 :                         while (pkg_dirs(pkg, &dir) == EPKG_OK) {
    1152           8 :                                 urlencode(dir->path, &tmpsbuf);
    1153           8 :                                 if (map == NULL)
    1154           8 :                                         map = ucl_object_typed_new(UCL_OBJECT);
    1155          16 :                                 ucl_object_insert_key(map,
    1156             :                                     ucl_object_fromstring("y"),
    1157          16 :                                     sbuf_data(tmpsbuf), sbuf_len(tmpsbuf), true);
    1158             :                         }
    1159          59 :                         if (map)
    1160           8 :                                 ucl_object_insert_key(top, map, "directories", 11, false);
    1161             :                 }
    1162             : 
    1163          59 :                 pkg_debug(4, "Emitting scripts");
    1164          59 :                 map = NULL;
    1165         590 :                 for (i = 0; i < PKG_NUM_SCRIPTS; i++) {
    1166         531 :                         if (pkg_script_get(pkg, i) == NULL)
    1167         511 :                                 continue;
    1168             : 
    1169          20 :                         switch (i) {
    1170             :                         case PKG_SCRIPT_PRE_INSTALL:
    1171           8 :                                 script_types = "pre-install";
    1172           8 :                                 break;
    1173             :                         case PKG_SCRIPT_INSTALL:
    1174           0 :                                 script_types = "install";
    1175           0 :                                 break;
    1176             :                         case PKG_SCRIPT_POST_INSTALL:
    1177          12 :                                 script_types = "post-install";
    1178          12 :                                 break;
    1179             :                         case PKG_SCRIPT_PRE_UPGRADE:
    1180           0 :                                 script_types = "pre-upgrade";
    1181           0 :                                 break;
    1182             :                         case PKG_SCRIPT_UPGRADE:
    1183           0 :                                 script_types = "upgrade";
    1184           0 :                                 break;
    1185             :                         case PKG_SCRIPT_POST_UPGRADE:
    1186           0 :                                 script_types = "post-upgrade";
    1187           0 :                                 break;
    1188             :                         case PKG_SCRIPT_PRE_DEINSTALL:
    1189           0 :                                 script_types = "pre-deinstall";
    1190           0 :                                 break;
    1191             :                         case PKG_SCRIPT_DEINSTALL:
    1192           0 :                                 script_types = "deinstall";
    1193           0 :                                 break;
    1194             :                         case PKG_SCRIPT_POST_DEINSTALL:
    1195           0 :                                 script_types = "post-deinstall";
    1196           0 :                                 break;
    1197             :                         }
    1198          20 :                         urlencode(pkg_script_get(pkg, i), &tmpsbuf);
    1199          20 :                         if (map == NULL)
    1200          12 :                                 map = ucl_object_typed_new(UCL_OBJECT);
    1201          40 :                         ucl_object_insert_key(map,
    1202          20 :                             ucl_object_fromstring_common(sbuf_data(tmpsbuf),
    1203          20 :                                 sbuf_len(tmpsbuf), UCL_STRING_TRIM),
    1204             :                             script_types, 0, true);
    1205             :                 }
    1206          59 :                 if (map)
    1207          12 :                         ucl_object_insert_key(top, map, "scripts", 7, false);
    1208             :         }
    1209             : 
    1210         149 :         pkg_debug(4, "Emitting message");
    1211         149 :         if (pkg->message != NULL) {
    1212           0 :                 urlencode(pkg->message, &tmpsbuf);
    1213           0 :                 ucl_object_insert_key(top,
    1214           0 :                     ucl_object_fromstring_common(sbuf_data(tmpsbuf), sbuf_len(tmpsbuf), UCL_STRING_TRIM),
    1215             :                     "message", 7, false);
    1216             :         }
    1217             : 
    1218         149 :         return (top);
    1219             : }
    1220             : 
    1221             : 
    1222             : static int
    1223         149 : emit_manifest(struct pkg *pkg, struct sbuf **out, short flags)
    1224             : {
    1225             :         ucl_object_t *top;
    1226             : 
    1227         149 :         top = pkg_emit_object(pkg, flags);
    1228             : 
    1229         149 :         if ((flags & PKG_MANIFEST_EMIT_PRETTY) == PKG_MANIFEST_EMIT_PRETTY)
    1230           0 :                 ucl_object_emit_sbuf(top, UCL_EMIT_YAML, out);
    1231         149 :         else if ((flags & PKG_MANIFEST_EMIT_UCL) == PKG_MANIFEST_EMIT_UCL)
    1232           0 :                 ucl_object_emit_sbuf(top, UCL_EMIT_CONFIG, out);
    1233         149 :         else if ((flags & PKG_MANIFEST_EMIT_JSON) == PKG_MANIFEST_EMIT_JSON)
    1234           0 :                 ucl_object_emit_sbuf(top, UCL_EMIT_JSON, out);
    1235             :         else
    1236         149 :                 ucl_object_emit_sbuf(top, UCL_EMIT_JSON_COMPACT, out);
    1237             : 
    1238         149 :         ucl_object_unref(top);
    1239             : 
    1240         149 :         return (EPKG_OK);
    1241             : }
    1242             : 
    1243             : static void
    1244           0 : pkg_emit_manifest_digest(const unsigned char *digest, size_t len, char *hexdigest)
    1245             : {
    1246             :         unsigned int i;
    1247             : 
    1248           0 :         for (i = 0; i < len; i ++)
    1249           0 :                 sprintf(hexdigest + (i * 2), "%02x", digest[i]);
    1250             : 
    1251           0 :         hexdigest[len * 2] = '\0';
    1252           0 : }
    1253             : 
    1254             : /*
    1255             :  * This routine is able to output to either a (FILE *) or a (struct sbuf *). It
    1256             :  * exist only to avoid code duplication and should not be called except from
    1257             :  * pkg_emit_manifest_file() and pkg_emit_manifest_sbuf().
    1258             :  */
    1259             : static int
    1260         149 : pkg_emit_manifest_generic(struct pkg *pkg, void *out, short flags,
    1261             :             char **pdigest, bool out_is_a_sbuf)
    1262             : {
    1263         149 :         struct sbuf *output = NULL;
    1264             :         unsigned char digest[SHA256_DIGEST_LENGTH];
    1265         149 :         SHA256_CTX *sign_ctx = NULL;
    1266             :         int rc;
    1267             : 
    1268         149 :         if (pdigest != NULL) {
    1269           0 :                 *pdigest = malloc(sizeof(digest) * 2 + 1);
    1270           0 :                 sign_ctx = malloc(sizeof(SHA256_CTX));
    1271           0 :                 SHA256_Init(sign_ctx);
    1272             :         }
    1273             : 
    1274         149 :         if (out_is_a_sbuf)
    1275         149 :                 output = out;
    1276             : 
    1277         149 :         rc = emit_manifest(pkg, &output, flags);
    1278             : 
    1279         149 :         if (sign_ctx != NULL)
    1280           0 :                 SHA256_Update(sign_ctx, sbuf_data(output), sbuf_len(output));
    1281             : 
    1282         149 :         if (!out_is_a_sbuf)
    1283           0 :                 fprintf(out, "%s\n", sbuf_data(output));
    1284             : 
    1285         149 :         if (pdigest != NULL) {
    1286           0 :                 SHA256_Final(digest, sign_ctx);
    1287           0 :                 pkg_emit_manifest_digest(digest, sizeof(digest), *pdigest);
    1288           0 :                 free(sign_ctx);
    1289             :         }
    1290             : 
    1291         149 :         if (!out_is_a_sbuf)
    1292           0 :                 sbuf_free(output);
    1293             : 
    1294         149 :         return (rc);
    1295             : }
    1296             : 
    1297             : int
    1298           0 : pkg_emit_manifest_file(struct pkg *pkg, FILE *f, short flags, char **pdigest)
    1299             : {
    1300             : 
    1301           0 :         return (pkg_emit_manifest_generic(pkg, f, flags, pdigest, false));
    1302             : }
    1303             : 
    1304             : int
    1305         149 : pkg_emit_manifest_sbuf(struct pkg *pkg, struct sbuf *b, short flags, char **pdigest)
    1306             : {
    1307             : 
    1308         149 :         return (pkg_emit_manifest_generic(pkg, b, flags, pdigest, true));
    1309             : }
    1310             : 
    1311             : int
    1312           0 : pkg_emit_manifest(struct pkg *pkg, char **dest, short flags, char **pdigest)
    1313             : {
    1314           0 :         struct sbuf *b = sbuf_new_auto();
    1315             :         int rc;
    1316             : 
    1317           0 :         rc = pkg_emit_manifest_sbuf(pkg, b, flags, pdigest);
    1318             : 
    1319           0 :         if (rc != EPKG_OK) {
    1320           0 :                 sbuf_delete(b);
    1321           0 :                 return (rc);
    1322             :         }
    1323             : 
    1324           0 :         sbuf_finish(b);
    1325           0 :         *dest = strdup(sbuf_data(b));
    1326           0 :         sbuf_delete(b);
    1327             : 
    1328           0 :         return (rc);
    1329             : }
    1330             : 

Generated by: LCOV version 1.10