1 /* 2 * Copyright (c) 2019 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * This code uses concepts and configuration based on 'synth', by 8 * John R. Marino <draco@marino.st>, which was written in ada. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 3. Neither the name of The DragonFly Project nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific, prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 34 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #include "dsynth.h" 39 40 #define PKG_HSIZE 32768 41 #define PKG_HMASK 32767 42 43 static void childGetPackageInfo(bulk_t *bulk); 44 static void childGetBinaryDistInfo(bulk_t *bulk); 45 static void childOptimizeEnv(bulk_t *bulk); 46 static pkg_t *resolveDeps(pkg_t *dep_list, pkg_t ***list_tailp, int gentopo); 47 static void resolveDepString(pkg_t *pkg, char *depstr, 48 int gentopo, int dep_type); 49 static pkg_t *processPackageListBulk(int total); 50 static int scan_and_queue_dir(const char *path, const char *level1, int level); 51 static int scan_binary_repo(const char *path); 52 #if 0 53 static void pkgfree(pkg_t *pkg); 54 #endif 55 56 pkg_t *PkgHash1[PKG_HSIZE]; /* by portdir */ 57 pkg_t *PkgHash2[PKG_HSIZE]; /* by pkgfile */ 58 59 /* 60 * Allocate a new pkg structure plus basic initialization. 61 */ 62 static __inline pkg_t * 63 allocpkg(void) 64 { 65 pkg_t *pkg; 66 67 pkg = calloc(1, sizeof(*pkg)); 68 pkg->idepon_list.next = &pkg->idepon_list; 69 pkg->idepon_list.prev = &pkg->idepon_list; 70 pkg->deponi_list.next = &pkg->deponi_list; 71 pkg->deponi_list.prev = &pkg->deponi_list; 72 73 return pkg; 74 } 75 76 /* 77 * Simple hash for lookups 78 */ 79 static __inline int 80 pkghash(const char *str) 81 { 82 int hv = 0xABC32923; 83 while (*str) { 84 hv = (hv << 5) ^ *str; 85 ++str; 86 } 87 hv = hv ^ (hv / PKG_HSIZE) ^ (hv / PKG_HSIZE / PKG_HSIZE); 88 return (hv & PKG_HMASK); 89 } 90 91 static void 92 pkg_enter(pkg_t *pkg) 93 { 94 pkg_t **pkgp; 95 pkg_t *scan; 96 97 if (pkg->portdir) { 98 pkgp = &PkgHash1[pkghash(pkg->portdir)]; 99 while ((scan = *pkgp) != NULL) { 100 if (strcmp(pkg->portdir, scan->portdir) == 0) 101 break; 102 pkgp = &scan->hnext1; 103 } 104 if (scan && (scan->flags & PKGF_PLACEHOLD)) { 105 *pkgp = pkg; 106 pkg->hnext1 = scan->hnext1; 107 free(scan->portdir); 108 free(scan); 109 scan = NULL; 110 } 111 if (scan == NULL) 112 *pkgp = pkg; 113 } 114 115 if (pkg->pkgfile) { 116 pkgp = &PkgHash2[pkghash(pkg->pkgfile)]; 117 while ((scan = *pkgp) != NULL) { 118 if (strcmp(pkg->pkgfile, scan->pkgfile) == 0) 119 break; 120 pkgp = &scan->hnext2; 121 } 122 if (scan == NULL) 123 *pkgp = pkg; 124 } 125 } 126 127 static pkg_t * 128 pkg_find(const char *match) 129 { 130 pkg_t **pkgp; 131 pkg_t *pkg; 132 133 pkgp = &PkgHash1[pkghash(match)]; 134 for (pkg = *pkgp; pkg; pkg = pkg->hnext1) { 135 if (strcmp(pkg->portdir, match) == 0) 136 return pkg; 137 } 138 pkgp = &PkgHash2[pkghash(match)]; 139 for (pkg = *pkgp; pkg; pkg = pkg->hnext2) { 140 if (strcmp(pkg->pkgfile, match) == 0) 141 return pkg; 142 } 143 return NULL; 144 } 145 146 /* 147 * Parse a specific list of ports via origin name (portdir/subdir) 148 */ 149 pkg_t * 150 ParsePackageList(int n, char **ary) 151 { 152 pkg_t *list; 153 int i; 154 int total; 155 156 total = 0; 157 initbulk(childGetPackageInfo, MaxBulk); 158 159 /* 160 * Always include ports-mgmt/pkg. A non-null s4 field just tells 161 * the processing code that this isn't a manual selection. 162 */ 163 queuebulk("ports-mgmt", "pkg", NULL, "x"); 164 165 for (i = 0; i < n; ++i) { 166 char *l1; 167 char *l2; 168 169 l1 = strdup(ary[i]); 170 l2 = strchr(l1, '/'); 171 if (l2) { 172 *l2++ = 0; 173 queuebulk(l1, l2, NULL, NULL); 174 ++total; 175 } else { 176 printf("Bad portdir specification: %s\n", l1); 177 } 178 free(l1); 179 } 180 printf("Processing %d ports\n", total); 181 182 list = processPackageListBulk(total); 183 184 return list; 185 } 186 187 /* 188 * Parse packages from the list installed on the system. 189 */ 190 pkg_t * 191 GetLocalPackageList(void) 192 { 193 pkg_t *list; 194 FILE *fp; 195 char *base; 196 char *l1; 197 char *l2; 198 int total; 199 size_t len; 200 201 initbulk(childGetPackageInfo, MaxBulk); 202 total = 0; 203 204 fp = popen("pkg info -a -o", "r"); 205 206 /* 207 * Always include ports-mgmt/pkg. A non-null s4 field just tells 208 * the processing code that this isn't a manual selection. 209 */ 210 queuebulk("ports-mgmt", "pkg", NULL, "x"); 211 212 while ((base = fgetln(fp, &len)) != NULL) { 213 if (len == 0 || base[len-1] != '\n') 214 continue; 215 base[--len] = 0; 216 if (strtok(base, " \t") == NULL) { 217 printf("Badly formatted pkg info line: %s\n", base); 218 continue; 219 } 220 l1 = strtok(NULL, " \t"); 221 if (l1 == NULL) { 222 printf("Badly formatted pkg info line: %s\n", base); 223 continue; 224 } 225 226 l2 = strchr(l1, '/'); 227 if (l2) { 228 *l2++ = 0; 229 queuebulk(l1, l2, NULL, NULL); 230 ++total; 231 } else { 232 printf("Badly formatted specification: %s\n", l1); 233 } 234 } 235 pclose(fp); 236 237 printf("Processing %d ports\n", total); 238 239 list = processPackageListBulk(total); 240 241 return list; 242 } 243 244 pkg_t * 245 GetFullPackageList(void) 246 { 247 int total; 248 249 initbulk(childGetPackageInfo, MaxBulk); 250 251 total = scan_and_queue_dir(DPortsPath, NULL, 1); 252 printf("Scanning %d ports\n", total); 253 254 return processPackageListBulk(total); 255 } 256 257 /* 258 * Caller has queued the process list for bulk operation. We retrieve 259 * the results and clean up the bulk operation (we may have to do a second 260 * bulk operation so we have to be the ones to clean it up). 261 */ 262 static pkg_t * 263 processPackageListBulk(int total) 264 { 265 bulk_t *bulk; 266 pkg_t *scan; 267 pkg_t *list; 268 pkg_t *dep_list; 269 pkg_t **list_tail; 270 int count; 271 272 list = NULL; 273 list_tail = &list; 274 count = 0; 275 276 while ((bulk = getbulk()) != NULL) { 277 ++count; 278 if ((count & 255) == 0) { 279 printf("%6.2f%%\r", 280 (double)count * 100.0 / (double)total + 0.001); 281 fflush(stdout); 282 } 283 if (bulk->list) { 284 *list_tail = bulk->list; 285 bulk->list = NULL; 286 while ((scan = *list_tail) != NULL) { 287 if (bulk->s4 == NULL) 288 scan->flags |= PKGF_MANUALSEL; 289 pkg_enter(scan); 290 list_tail = &scan->bnext; 291 } 292 } 293 freebulk(bulk); 294 } 295 printf("100.00%%\n"); 296 printf("\nTotal %d\n", count); 297 fflush(stdout); 298 299 /* 300 * Resolve all dependencies for the related packages, potentially 301 * adding anything that could not be found to the list. This will 302 * continue to issue bulk operations and process the result until 303 * no dependencies are left. 304 */ 305 printf("Resolving dependencies..."); 306 fflush(stdout); 307 dep_list = list; 308 while (dep_list) { 309 dep_list = resolveDeps(dep_list, &list_tail, 0); 310 } 311 printf("done\n"); 312 313 donebulk(); 314 315 /* 316 * Generate the topology 317 */ 318 resolveDeps(list, NULL, 1); 319 320 /* 321 * Do a final count, ignore place holders. 322 */ 323 count = 0; 324 for (scan = list; scan; scan = scan->bnext) { 325 if ((scan->flags & PKGF_ERROR) == 0) { 326 ++count; 327 } 328 } 329 printf("Total Returned %d\n", count); 330 331 /* 332 * Scan our binary distributions and related dependencies looking 333 * for any packages that have already been built. 334 */ 335 initbulk(childGetBinaryDistInfo, MaxBulk); 336 total = scan_binary_repo(RepositoryPath); 337 count = 0; 338 printf("Scanning %d packages\n", total); 339 340 while ((bulk = getbulk()) != NULL) { 341 ++count; 342 if ((count & 255) == 0) { 343 printf("%6.2f%%\r", 344 (double)count * 100.0 / (double)total + 0.001); 345 fflush(stdout); 346 } 347 freebulk(bulk); 348 } 349 printf("100.00%%\n"); 350 printf("\nTotal %d\n", count); 351 fflush(stdout); 352 donebulk(); 353 354 printf("all done\n"); 355 356 return list; 357 } 358 359 pkg_t * 360 GetPkgPkg(pkg_t *list) 361 { 362 bulk_t *bulk; 363 pkg_t *scan; 364 365 for (scan = list; scan; scan = scan->bnext) { 366 if (strcmp(scan->portdir, "ports-mgmt/pkg") == 0) 367 return scan; 368 } 369 370 /* 371 * This will force pkg to be built, but generally this code 372 * is not reached because the package list processing code 373 * adds ports-mgmt/pkg unconditionally. 374 */ 375 initbulk(childGetPackageInfo, MaxBulk); 376 queuebulk("ports-mgmt", "pkg", NULL, "x"); 377 bulk = getbulk(); 378 dassert(bulk, "Cannot find ports-mgmt/pkg"); 379 scan = bulk->list; 380 bulk->list = NULL; 381 freebulk(bulk); 382 donebulk(); 383 384 return scan; 385 } 386 387 /* 388 * Try to optimize the environment by supplying information that 389 * the ports system would generally have to run stuff to get on 390 * every package. 391 * 392 * See childOptimizeEnv() for the actual handling. We execute 393 * a single make -V... -V... for ports-mgmt/pkg from within the 394 * bulk system (which handles the environment and disables 395 * /etc/make.conf), and we then call addbuildenv() as appropriate. 396 * 397 * _PERL5_FROM_BIN 398 * add others... 399 */ 400 void 401 OptimizeEnv(void) 402 { 403 bulk_t *bulk; 404 405 initbulk(childOptimizeEnv, MaxBulk); 406 queuebulk("ports-mgmt", "pkg", NULL, NULL); 407 bulk = getbulk(); 408 freebulk(bulk); 409 donebulk(); 410 } 411 412 /* 413 * Run through the list resolving dependencies and constructing the topology 414 * linkages. This may append packages to the list. 415 */ 416 static pkg_t * 417 resolveDeps(pkg_t *list, pkg_t ***list_tailp, int gentopo) 418 { 419 pkg_t *scan; 420 pkg_t *ret_list = NULL; 421 bulk_t *bulk; 422 423 for (scan = list; scan; scan = scan->bnext) { 424 resolveDepString(scan, scan->fetch_deps, 425 gentopo, DEP_TYPE_FETCH); 426 resolveDepString(scan, scan->ext_deps, 427 gentopo, DEP_TYPE_EXT); 428 resolveDepString(scan, scan->patch_deps, 429 gentopo, DEP_TYPE_PATCH); 430 resolveDepString(scan, scan->build_deps, 431 gentopo, DEP_TYPE_BUILD); 432 resolveDepString(scan, scan->lib_deps, 433 gentopo, DEP_TYPE_LIB); 434 resolveDepString(scan, scan->run_deps, 435 gentopo, DEP_TYPE_RUN); 436 } 437 438 /* 439 * No bulk ops are queued when doing the final topology 440 * generation. 441 */ 442 if (gentopo) 443 return NULL; 444 while ((bulk = getbulk()) != NULL) { 445 if (bulk->list) { 446 if (ret_list == NULL) 447 ret_list = bulk->list; 448 **list_tailp = bulk->list; 449 bulk->list = NULL; 450 while (**list_tailp) { 451 pkg_enter(**list_tailp); 452 *list_tailp = &(**list_tailp)->bnext; 453 } 454 } 455 freebulk(bulk); 456 } 457 return (ret_list); 458 } 459 460 static void 461 resolveDepString(pkg_t *pkg, char *depstr, int gentopo, int dep_type) 462 { 463 char *copy_base; 464 char *copy; 465 char *dep; 466 char *sep; 467 char *tag; 468 char *flavor; 469 pkg_t *dpkg; 470 471 if (depstr == NULL || depstr[0] == 0) 472 return; 473 474 copy_base = strdup(depstr); 475 copy = copy_base; 476 477 for (;;) { 478 do { 479 dep = strsep(©, " \t"); 480 } while (dep && *dep == 0); 481 if (dep == NULL) 482 break; 483 484 /* 485 * Ignore dependencies prefixed with ${NONEXISTENT} 486 */ 487 if (strncmp(dep, "/nonexistent:", 13) == 0) 488 continue; 489 490 dep = strchr(dep, ':'); 491 if (dep == NULL || *dep != ':') { 492 printf("Error parsing dependency for %s: %s\n", 493 pkg->portdir, copy_base); 494 continue; 495 } 496 ++dep; 497 498 /* 499 * Strip-off any DPortsPath prefix. EXTRACT_DEPENDS 500 * often (always?) generates this prefix. 501 */ 502 if (strncmp(dep, DPortsPath, strlen(DPortsPath)) == 0) { 503 dep += strlen(DPortsPath); 504 if (*dep == '/') 505 ++dep; 506 } 507 508 /* 509 * Strip-off any tag (such as :patch). We don't try to 510 * organize dependencies at this fine a grain (for now). 511 */ 512 tag = strchr(dep, ':'); 513 if (tag) 514 *tag++ = 0; 515 516 /* 517 * Locate the dependency 518 */ 519 if ((dpkg = pkg_find(dep)) != NULL) { 520 if (gentopo) { 521 pkglink_t *link; 522 523 /* 524 * NOTE: idep_count is calculated recursively 525 * at build-time 526 */ 527 ddprintf(0, "Add Dependency %s -> %s\n", 528 pkg->portdir, dpkg->portdir); 529 link = calloc(1, sizeof(*link)); 530 link->pkg = dpkg; 531 link->next = &pkg->idepon_list; 532 link->prev = pkg->idepon_list.prev; 533 link->next->prev = link; 534 link->prev->next = link; 535 link->dep_type = dep_type; 536 537 link = calloc(1, sizeof(*link)); 538 link->pkg = pkg; 539 link->next = &dpkg->deponi_list; 540 link->prev = dpkg->deponi_list.prev; 541 link->next->prev = link; 542 link->prev->next = link; 543 link->dep_type = dep_type; 544 ++dpkg->depi_count; 545 } 546 continue; 547 } 548 549 /* 550 * This shouldn't happen because we already took a first 551 * pass and should have generated the pkgs. 552 */ 553 if (gentopo) { 554 printf("Topology Generate failed for %s: %s\n", 555 pkg->portdir, copy_base); 556 continue; 557 } 558 559 /* 560 * Separate out the two dports directory components and 561 * extract the optional '@flavor' specification. 562 */ 563 sep = strchr(dep, '/'); 564 if (sep == NULL) { 565 printf("Error parsing dependency for %s: %s\n", 566 pkg->portdir, copy_base); 567 continue; 568 } 569 *sep++ = 0; 570 571 if (tag) 572 flavor = strrchr(tag, '@'); 573 else 574 flavor = strrchr(sep, '@'); 575 576 if (flavor) 577 *flavor++ = 0; 578 579 if (flavor) 580 ddprintf(0, "QUEUE DEPENDENCY FROM PKG %s: %s/%s@%s\n", 581 pkg->portdir, dep, sep, flavor); 582 else 583 ddprintf(0, "QUEUE DEPENDENCY FROM PKG %s: %s/%s\n", 584 pkg->portdir, dep, sep); 585 586 /* 587 * Use a place-holder to prevent duplicate dependencies from 588 * being processed. The placeholder will be replaced by 589 * the actual dependency. 590 */ 591 dpkg = allocpkg(); 592 if (flavor) 593 asprintf(&dpkg->portdir, "%s/%s@%s", dep, sep, flavor); 594 else 595 asprintf(&dpkg->portdir, "%s/%s", dep, sep); 596 dpkg->flags = PKGF_PLACEHOLD; 597 pkg_enter(dpkg); 598 599 queuebulk(dep, sep, flavor, NULL); 600 } 601 free(copy_base); 602 } 603 604 void 605 FreePackageList(pkg_t *pkgs __unused) 606 { 607 dfatal("not implemented"); 608 } 609 610 /* 611 * Scan some or all dports to allocate the related pkg structure. Dependencies 612 * are stored but not processed. 613 * 614 * Threaded function 615 */ 616 static void 617 childGetPackageInfo(bulk_t *bulk) 618 { 619 pkg_t *pkg; 620 pkg_t *dummy_node; 621 pkg_t **list_tail; 622 char *flavors_save; 623 char *flavors; 624 char *flavor; 625 char *ptr; 626 FILE *fp; 627 int line; 628 size_t len; 629 char *portpath; 630 char *flavarg; 631 const char *cav[MAXCAC]; 632 pid_t pid; 633 int cac; 634 635 /* 636 * If the package has flavors we will loop on each one. If a flavor 637 * is not passed in s3 we will loop on all flavors, otherwise we will 638 * only process the passed-in flavor. 639 */ 640 flavor = bulk->s3; /* usually NULL */ 641 flavors = NULL; 642 flavors_save = NULL; 643 dummy_node = NULL; 644 645 bulk->list = NULL; 646 list_tail = &bulk->list; 647 again: 648 asprintf(&portpath, "%s/%s/%s", DPortsPath, bulk->s1, bulk->s2); 649 if (flavor) 650 asprintf(&flavarg, "FLAVOR=%s", flavor); 651 else 652 flavarg = NULL; 653 654 cac = 0; 655 cav[cac++] = MAKE_BINARY; 656 cav[cac++] = "-C"; 657 cav[cac++] = portpath; 658 if (flavarg) 659 cav[cac++] = flavarg; 660 cav[cac++] = "-VPKGVERSION"; 661 cav[cac++] = "-VPKGFILE:T"; 662 cav[cac++] = "-VDISTFILES"; 663 cav[cac++] = "-VDIST_SUBDIR"; 664 cav[cac++] = "-VMAKE_JOBS_NUMBER"; 665 cav[cac++] = "-VIGNORE"; 666 cav[cac++] = "-VFETCH_DEPENDS"; 667 cav[cac++] = "-VEXTRACT_DEPENDS"; 668 cav[cac++] = "-VPATCH_DEPENDS"; 669 cav[cac++] = "-VBUILD_DEPENDS"; 670 cav[cac++] = "-VLIB_DEPENDS"; 671 cav[cac++] = "-VRUN_DEPENDS"; 672 cav[cac++] = "-VSELECTED_OPTIONS"; 673 cav[cac++] = "-VDESELECTED_OPTIONS"; 674 cav[cac++] = "-VUSE_LINUX"; 675 cav[cac++] = "-VFLAVORS"; 676 cav[cac++] = "-VUSES"; 677 678 fp = dexec_open(cav, cac, &pid, NULL, 1, 1); 679 free(portpath); 680 freestrp(&flavarg); 681 682 pkg = allocpkg(); 683 if (flavor) 684 asprintf(&pkg->portdir, "%s/%s@%s", bulk->s1, bulk->s2, flavor); 685 else 686 asprintf(&pkg->portdir, "%s/%s", bulk->s1, bulk->s2); 687 688 line = 1; 689 while ((ptr = fgetln(fp, &len)) != NULL) { 690 if (len == 0 || ptr[len-1] != '\n') { 691 dfatal("Bad package info for %s/%s response line %d", 692 bulk->s1, bulk->s2, line); 693 } 694 ptr[--len] = 0; 695 696 switch(line) { 697 case 1: /* PKGVERSION */ 698 asprintf(&pkg->version, "%s", ptr); 699 break; 700 case 2: /* PKGFILE */ 701 asprintf(&pkg->pkgfile, "%s", ptr); 702 break; 703 case 3: /* DISTFILES */ 704 asprintf(&pkg->distfiles, "%s", ptr); 705 break; 706 case 4: /* DIST_SUBDIR */ 707 pkg->distsubdir = strdup_or_null(ptr); 708 break; 709 case 5: /* MAKE_JOBS_NUMBER */ 710 pkg->make_jobs_number = strtol(ptr, NULL, 0); 711 break; 712 case 6: /* IGNORE */ 713 pkg->ignore = strdup_or_null(ptr); 714 break; 715 case 7: /* FETCH_DEPENDS */ 716 pkg->fetch_deps = strdup_or_null(ptr); 717 break; 718 case 8: /* EXTRACT_DEPENDS */ 719 pkg->ext_deps = strdup_or_null(ptr); 720 break; 721 case 9: /* PATCH_DEPENDS */ 722 pkg->patch_deps = strdup_or_null(ptr); 723 break; 724 case 10: /* BUILD_DEPENDS */ 725 pkg->build_deps = strdup_or_null(ptr); 726 break; 727 case 11: /* LIB_DEPENDS */ 728 pkg->lib_deps = strdup_or_null(ptr); 729 break; 730 case 12: /* RUN_DEPENDS */ 731 pkg->run_deps = strdup_or_null(ptr); 732 break; 733 case 13: /* SELECTED_OPTIONS */ 734 pkg->pos_options = strdup_or_null(ptr); 735 break; 736 case 14: /* DESELECTED_OPTIONS */ 737 pkg->neg_options = strdup_or_null(ptr); 738 break; 739 case 15: /* USE_LINUX */ 740 if (ptr[0]) 741 pkg->use_linux = 1; 742 break; 743 case 16: /* FLAVORS */ 744 asprintf(&pkg->flavors, "%s", ptr); 745 break; 746 case 17: /* USES */ 747 asprintf(&pkg->uses, "%s", ptr); 748 if (strstr(pkg->uses, "metaport")) 749 pkg->flags |= PKGF_META; 750 break; 751 default: 752 printf("EXTRA LINE: %s\n", ptr); 753 break; 754 } 755 ++line; 756 } 757 if (line == 1) { 758 printf("DPort not found: %s/%s\n", bulk->s1, bulk->s2); 759 pkg->flags |= PKGF_NOTFOUND; 760 } else if (line != 17 + 1) { 761 printf("DPort corrupt: %s/%s\n", bulk->s1, bulk->s2); 762 pkg->flags |= PKGF_CORRUPT; 763 } 764 if (dexec_close(fp, pid)) { 765 printf("make -V* command for %s/%s failed\n", 766 bulk->s1, bulk->s2); 767 pkg->flags |= PKGF_CORRUPT; 768 } 769 ddassert(bulk->s1); 770 771 /* 772 * Generate flavors 773 */ 774 if (flavor == NULL) { 775 /* 776 * If there are flavors add the current unflavored pkg 777 * as a dummy node so dependencies can attach to it, 778 * then iterate the first flavor and loop. 779 * 780 * We must NULL out pkgfile because it will have the 781 * default flavor and conflict with the actual flavored 782 * pkg. 783 */ 784 if (pkg->flavors && pkg->flavors[0]) { 785 dummy_node = pkg; 786 787 pkg->flags |= PKGF_DUMMY; 788 789 freestrp(&pkg->fetch_deps); 790 freestrp(&pkg->ext_deps); 791 freestrp(&pkg->patch_deps); 792 freestrp(&pkg->build_deps); 793 freestrp(&pkg->lib_deps); 794 freestrp(&pkg->run_deps); 795 796 freestrp(&pkg->pkgfile); 797 *list_tail = pkg; 798 while (*list_tail) 799 list_tail = &(*list_tail)->bnext; 800 801 flavors_save = strdup(pkg->flavors); 802 flavors = flavors_save; 803 do { 804 flavor = strsep(&flavors, " \t"); 805 } while (flavor && *flavor == 0); 806 goto again; 807 } 808 809 /* 810 * No flavors, add the current unflavored pkg as a real 811 * node. 812 */ 813 *list_tail = pkg; 814 while (*list_tail) 815 list_tail = &(*list_tail)->bnext; 816 } else { 817 /* 818 * Add flavored package and iterate. 819 */ 820 *list_tail = pkg; 821 while (*list_tail) 822 list_tail = &(*list_tail)->bnext; 823 824 /* 825 * Flavor iteration under dummy node, add dependency 826 */ 827 if (dummy_node) { 828 pkglink_t *link; 829 830 ddprintf(0, "Add Dependency %s -> %s (flavor rollup)\n", 831 dummy_node->portdir, pkg->portdir); 832 link = calloc(1, sizeof(*link)); 833 link->pkg = pkg; 834 link->next = &dummy_node->idepon_list; 835 link->prev = dummy_node->idepon_list.prev; 836 link->next->prev = link; 837 link->prev->next = link; 838 link->dep_type = DEP_TYPE_BUILD; 839 840 link = calloc(1, sizeof(*link)); 841 link->pkg = dummy_node; 842 link->next = &pkg->deponi_list; 843 link->prev = pkg->deponi_list.prev; 844 link->next->prev = link; 845 link->prev->next = link; 846 link->dep_type = DEP_TYPE_BUILD; 847 ++pkg->depi_count; 848 } 849 850 if (flavors) { 851 do { 852 flavor = strsep(&flavors, " \t"); 853 } while (flavor && *flavor == 0); 854 if (flavor) 855 goto again; 856 free(flavors); 857 } 858 } 859 } 860 861 /* 862 * Query the package (at least to make sure it hasn't been truncated) 863 * and mark it as PACKAGED if found. 864 * 865 * Threaded function 866 */ 867 static void 868 childGetBinaryDistInfo(bulk_t *bulk) 869 { 870 char *ptr; 871 FILE *fp; 872 size_t len; 873 pkg_t *pkg; 874 const char *cav[MAXCAC]; 875 char *repopath; 876 char buf[1024]; 877 pid_t pid; 878 int cac; 879 880 asprintf(&repopath, "%s/%s", RepositoryPath, bulk->s1); 881 882 cac = 0; 883 cav[cac++] = PKG_BINARY; 884 cav[cac++] = "query"; 885 cav[cac++] = "-F"; 886 cav[cac++] = repopath; 887 cav[cac++] = "%n-%v"; 888 889 fp = dexec_open(cav, cac, &pid, NULL, 1, 0); 890 891 while ((ptr = fgetln(fp, &len)) != NULL) { 892 if (len == 0 || ptr[len-1] != '\n') 893 continue; 894 ptr[len-1] = 0; 895 snprintf(buf, sizeof(buf), "%s%s", ptr, USE_PKG_SUFX); 896 897 pkg = pkg_find(buf); 898 if (pkg) { 899 pkg->flags |= PKGF_PACKAGED; 900 } else { 901 ddprintf(0, "Note: package scan, not in list, " 902 "skipping %s\n", buf); 903 } 904 } 905 if (dexec_close(fp, pid)) { 906 printf("pkg query command failed for %s\n", repopath); 907 } 908 free(repopath); 909 } 910 911 static void 912 childOptimizeEnv(bulk_t *bulk) 913 { 914 char *portpath; 915 char *ptr; 916 FILE *fp; 917 int line; 918 size_t len; 919 const char *cav[MAXCAC]; 920 pid_t pid; 921 int cac; 922 923 asprintf(&portpath, "%s/%s/%s", DPortsPath, bulk->s1, bulk->s2); 924 925 cac = 0; 926 cav[cac++] = MAKE_BINARY; 927 cav[cac++] = "-C"; 928 cav[cac++] = portpath; 929 cav[cac++] = "-V_PERL5_FROM_BIN"; 930 931 fp = dexec_open(cav, cac, &pid, NULL, 1, 1); 932 free(portpath); 933 934 line = 1; 935 while ((ptr = fgetln(fp, &len)) != NULL) { 936 if (len == 0 || ptr[len-1] != '\n') { 937 dfatal("Bad package info for %s/%s response line %d", 938 bulk->s1, bulk->s2, line); 939 } 940 ptr[--len] = 0; 941 942 switch(line) { 943 case 1: /* _PERL5_FROM_BIN */ 944 addbuildenv("_PERL5_FROM_BIN", ptr, BENV_ENVIRONMENT); 945 break; 946 default: 947 printf("childOptimizeEnv: EXTRA LINE: %s\n", ptr); 948 break; 949 } 950 ++line; 951 } 952 if (line == 1) { 953 printf("DPort not found: %s/%s\n", bulk->s1, bulk->s2); 954 } else if (line != 1 + 1) { 955 printf("DPort corrupt: %s/%s\n", bulk->s1, bulk->s2); 956 } 957 if (dexec_close(fp, pid)) { 958 printf("childOptimizeEnv() failed\n"); 959 } 960 } 961 962 static int 963 scan_and_queue_dir(const char *path, const char *level1, int level) 964 { 965 DIR *dir; 966 char *s1; 967 char *s2; 968 struct dirent *den; 969 struct stat st; 970 int count = 0; 971 972 dir = opendir(path); 973 dassert(dir, "Cannot open dports path \"%s\"", path); 974 975 while ((den = readdir(dir)) != NULL) { 976 if (den->d_namlen == 1 && den->d_name[0] == '.') 977 continue; 978 if (den->d_namlen == 2 && 979 den->d_name[0] == '.' && den->d_name[1] == '.') 980 continue; 981 asprintf(&s1, "%s/%s", path, den->d_name); 982 if (lstat(s1, &st) < 0 || !S_ISDIR(st.st_mode)) { 983 free(s1); 984 continue; 985 } 986 if (level == 1) { 987 count += scan_and_queue_dir(s1, den->d_name, 2); 988 free(s1); 989 continue; 990 } 991 asprintf(&s2, "%s/Makefile", s1); 992 if (lstat(s2, &st) == 0) { 993 queuebulk(level1, den->d_name, NULL, NULL); 994 ++count; 995 } 996 free(s1); 997 free(s2); 998 } 999 closedir(dir); 1000 1001 return count; 1002 } 1003 1004 static int 1005 scan_binary_repo(const char *path) 1006 { 1007 DIR *dir; 1008 struct dirent *den; 1009 size_t len; 1010 int count; 1011 1012 count = 0; 1013 dir = opendir(path); 1014 dassert(dir, "Cannot open repository path \"%s\"", path); 1015 1016 /* 1017 * NOTE: Test includes the '.' in the suffix. 1018 */ 1019 while ((den = readdir(dir)) != NULL) { 1020 len = strlen(den->d_name); 1021 if (len > 4 && 1022 strcmp(den->d_name + len - 4, USE_PKG_SUFX) == 0) { 1023 queuebulk(den->d_name, NULL, NULL, NULL); 1024 ++count; 1025 } 1026 } 1027 closedir(dir); 1028 1029 return count; 1030 } 1031 1032 #if 0 1033 static void 1034 pkgfree(pkg_t *pkg) 1035 { 1036 freestrp(&pkg->portdir); 1037 freestrp(&pkg->version); 1038 freestrp(&pkg->pkgfile); 1039 freestrp(&pkg->ignore); 1040 freestrp(&pkg->fetch_deps); 1041 freestrp(&pkg->ext_deps); 1042 freestrp(&pkg->patch_deps); 1043 freestrp(&pkg->build_deps); 1044 freestrp(&pkg->lib_deps); 1045 freestrp(&pkg->run_deps); 1046 freestrp(&pkg->pos_options); 1047 freestrp(&pkg->neg_options); 1048 freestrp(&pkg->flavors); 1049 free(pkg); 1050 } 1051 #endif 1052