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