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 }