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 int parsepkglist_file(const char *path, int debugstop); 44 static void childGetPackageInfo(bulk_t *bulk); 45 static void childGetBinaryDistInfo(bulk_t *bulk); 46 static void childOptimizeEnv(bulk_t *bulk); 47 static pkg_t *resolveDeps(pkg_t *dep_list, pkg_t ***list_tailp, int gentopo); 48 static void resolveFlavors(pkg_t *pkg, char *flavors, int gentopo); 49 static void resolveDepString(pkg_t *pkg, char *depstr, 50 int gentopo, int dep_type); 51 static pkg_t *processPackageListBulk(int total); 52 static int scan_and_queue_dir(const char *path, const char *level1, int level); 53 static int scan_binary_repo(const char *path); 54 #if 0 55 static void pkgfree(pkg_t *pkg); 56 #endif 57 58 static int PrepareSystemFlag; 59 60 static pkg_t *PkgHash1[PKG_HSIZE]; /* by portdir */ 61 static pkg_t *PkgHash2[PKG_HSIZE]; /* by pkgfile */ 62 63 /* 64 * Allocate a new pkg structure plus basic initialization. 65 */ 66 static __inline pkg_t * 67 allocpkg(void) 68 { 69 pkg_t *pkg; 70 71 pkg = calloc(1, sizeof(*pkg)); 72 pkg->idepon_list.next = &pkg->idepon_list; 73 pkg->idepon_list.prev = &pkg->idepon_list; 74 pkg->deponi_list.next = &pkg->deponi_list; 75 pkg->deponi_list.prev = &pkg->deponi_list; 76 77 return pkg; 78 } 79 80 /* 81 * Simple hash for lookups 82 */ 83 static __inline int 84 pkghash(const char *str) 85 { 86 int hv = 0xABC32923; 87 while (*str) { 88 hv = (hv << 5) ^ *str; 89 ++str; 90 } 91 hv = hv ^ (hv / PKG_HSIZE) ^ (hv / PKG_HSIZE / PKG_HSIZE); 92 return (hv & PKG_HMASK); 93 } 94 95 static void 96 pkg_enter(pkg_t *pkg) 97 { 98 pkg_t **pkgp; 99 pkg_t *scan; 100 101 if (pkg->portdir) { 102 pkgp = &PkgHash1[pkghash(pkg->portdir)]; 103 while ((scan = *pkgp) != NULL) { 104 if (strcmp(pkg->portdir, scan->portdir) == 0) 105 break; 106 pkgp = &scan->hnext1; 107 } 108 ddassert(scan == NULL || (scan->flags & PKGF_PLACEHOLD)); 109 if (scan && (scan->flags & PKGF_PLACEHOLD)) { 110 ddassert(scan->idepon_list.next == &scan->idepon_list); 111 ddassert(scan->deponi_list.next == &scan->deponi_list); 112 *pkgp = pkg; 113 pkg->hnext1 = scan->hnext1; 114 free(scan->portdir); 115 free(scan); 116 scan = NULL; 117 } 118 if (scan == NULL) 119 *pkgp = pkg; 120 } 121 122 if (pkg->pkgfile) { 123 pkgp = &PkgHash2[pkghash(pkg->pkgfile)]; 124 while ((scan = *pkgp) != NULL) { 125 if (strcmp(pkg->pkgfile, scan->pkgfile) == 0) 126 break; 127 pkgp = &scan->hnext2; 128 } 129 if (scan == NULL) 130 *pkgp = pkg; 131 } 132 } 133 134 static pkg_t * 135 pkg_find(const char *match) 136 { 137 pkg_t **pkgp; 138 pkg_t *pkg; 139 140 pkgp = &PkgHash1[pkghash(match)]; 141 for (pkg = *pkgp; pkg; pkg = pkg->hnext1) { 142 if (strcmp(pkg->portdir, match) == 0) 143 return pkg; 144 } 145 pkgp = &PkgHash2[pkghash(match)]; 146 for (pkg = *pkgp; pkg; pkg = pkg->hnext2) { 147 if (strcmp(pkg->pkgfile, match) == 0) 148 return pkg; 149 } 150 return NULL; 151 } 152 153 /* 154 * Parse a specific list of ports via origin name (portdir/subdir) 155 */ 156 pkg_t * 157 ParsePackageList(int n, char **ary, int debugstop) 158 { 159 pkg_t *list; 160 int total; 161 int fail; 162 int i; 163 164 total = 0; 165 fail = 0; 166 initbulk(childGetPackageInfo, MaxBulk); 167 168 /* 169 * Always include ports-mgmt/pkg. s4 is "x" meaning not a manual 170 * selection, "d" meaning DEBUGSTOP mode, or NULL. 171 */ 172 queuebulk("ports-mgmt", "pkg", NULL, "x"); 173 174 for (i = 0; i < n; ++i) { 175 char *l1; 176 char *l2; 177 char *l3; 178 struct stat st; 179 180 l1 = strdup(ary[i]); 181 if (stat(l1, &st) == 0 && S_ISREG(st.st_mode)) { 182 total += parsepkglist_file(l1, debugstop); 183 continue; 184 } 185 186 l2 = strchr(l1, '/'); 187 if (l2 == NULL) { 188 printf("Bad portdir specification: %s\n", l1); 189 free(l1); 190 fail = 1; 191 continue; 192 } 193 *l2++ = 0; 194 l3 = strchr(l2, '@'); 195 if (l3) 196 *l3++ = 0; 197 198 /* 199 * Silently ignore any manually specified ports-mgmt/pkg, 200 * which we already auto-added. 201 */ 202 if (strcmp(l1, "ports-mgmt") != 0 || 203 strcmp(l2, "pkg") != 0) 204 { 205 queuebulk(l1, l2, l3, (debugstop ? "d" : NULL)); 206 } 207 ++total; 208 free(l1); 209 } 210 printf("Processing %d ports\n", total); 211 212 list = processPackageListBulk(total); 213 if (fail) { 214 dfatal("Bad specifications, exiting"); 215 exit(1); 216 } 217 218 return list; 219 } 220 221 static 222 int 223 parsepkglist_file(const char *path, int debugstop) 224 { 225 FILE *fp; 226 char *base; 227 char *l1; 228 char *l2; 229 char *l3; 230 size_t len; 231 int total; 232 233 if ((fp = fopen(path, "r")) == NULL) { 234 dpanic_errno("Cannot read %s\n", path); 235 /* NOT REACHED */ 236 return 0; 237 } 238 239 total = 0; 240 241 while ((base = fgetln(fp, &len)) != NULL) { 242 if (len == 0 || base[len-1] != '\n') 243 continue; 244 base[--len] = 0; 245 l1 = strtok(base, " \t\r\n"); 246 if (l1 == NULL) { 247 printf("Badly formatted pkg info line: %s\n", base); 248 continue; 249 } 250 l2 = strchr(l1, '/'); 251 if (l2 == NULL) { 252 printf("Badly formatted specification: %s\n", l1); 253 continue; 254 } 255 *l2++ = 0; 256 l3 = strchr(l2, '@'); 257 if (l3) 258 *l3++ = 0; 259 queuebulk(l1, l2, l3, (debugstop ? "d" : NULL)); 260 ++total; 261 } 262 fclose(fp); 263 264 return total; 265 } 266 267 /* 268 * Parse packages from the list installed on the system. 269 */ 270 pkg_t * 271 GetLocalPackageList(void) 272 { 273 pkg_t *list; 274 FILE *fp; 275 char *base; 276 char *data; 277 char *l1; 278 char *l2; 279 char *l3; 280 int total; 281 int state; 282 size_t len; 283 284 PrepareSystemFlag = 1; 285 initbulk(childGetPackageInfo, MaxBulk); 286 total = 0; 287 state = 0; 288 l1 = NULL; 289 l2 = NULL; 290 l3 = NULL; 291 292 fp = popen("pkg info -a -o -A", "r"); 293 294 /* 295 * Always include ports-mgmt/pkg. s4 is "x" meaning not a manual 296 * selection, "d" meaning DEBUGSTOP mode, or NULL. 297 */ 298 queuebulk("ports-mgmt", "pkg", NULL, "x"); 299 300 while ((base = fgetln(fp, &len)) != NULL) { 301 if (len == 0 || base[len-1] != '\n') 302 continue; 303 base[--len] = 0; 304 305 data = strchr(base, ':'); 306 if (data == NULL) 307 continue; 308 *data++ = 0; 309 310 base = strtok(base, " \t\r"); 311 data = strtok(data, " \t\r"); 312 313 if (base == NULL || data == NULL) 314 continue; 315 316 if (strcmp(base, "Origin") == 0) { 317 if (state == 1) { 318 queuebulk(l1, l2, NULL, NULL); 319 state = 0; 320 ++total; 321 } 322 323 if (strchr(data, '/') == NULL) { 324 printf("Badly formatted origin: %s\n", l1); 325 } 326 if (l1) 327 free(l1); 328 if (l3) 329 free(l3); 330 l1 = strdup(data); 331 l2 = strchr(l1, '/'); 332 *l2++ = 0; 333 l3 = strchr(l2, '@'); /* typically NULL */ 334 if (l3) { 335 *l3++ = 0; 336 l3 = strdup(l3); 337 } 338 339 /* 340 * Don't queue ports-mgmt/pkg twice, we already 341 * queued it manually. 342 */ 343 if (strcmp(l1, "ports-mgmt") != 0 || 344 strcmp(l2, "pkg") != 0) { 345 state = 1; 346 } 347 continue; 348 } 349 if (state == 1 && strcmp(base, "flavor") == 0) { 350 queuebulk(l1, l2, data, NULL); 351 state = 0; 352 ++total; 353 } 354 } 355 if (state == 1) { 356 queuebulk(l1, l2, NULL, NULL); 357 /*state = 0; not needed */ 358 } 359 if (l1) 360 free(l1); 361 if (l3) 362 free(l3); 363 364 pclose(fp); 365 366 printf("Processing %d ports\n", total); 367 368 list = processPackageListBulk(total); 369 370 return list; 371 } 372 373 pkg_t * 374 GetFullPackageList(void) 375 { 376 int total; 377 378 initbulk(childGetPackageInfo, MaxBulk); 379 total = scan_and_queue_dir(DPortsPath, NULL, 1); 380 printf("Scanning %d ports\n", total); 381 382 return processPackageListBulk(total); 383 } 384 385 /* 386 * Caller has queued the process list for bulk operation. We retrieve 387 * the results and clean up the bulk operation (we may have to do a second 388 * bulk operation so we have to be the ones to clean it up). 389 */ 390 static pkg_t * 391 processPackageListBulk(int total) 392 { 393 bulk_t *bulk; 394 pkg_t *scan; 395 pkg_t *list; 396 pkg_t *dep_list; 397 pkg_t **list_tail; 398 int count; 399 int stop_fail; 400 int stop_base_list; 401 int remove_corrupt; 402 403 list = NULL; 404 list_tail = &list; 405 count = 0; 406 remove_corrupt = 0; 407 408 while ((bulk = getbulk()) != NULL) { 409 ++count; 410 if ((count & 255) == 0) { 411 printf("%6.2f%%\r", 412 (double)count * 100.0 / (double)total + 0.001); 413 fflush(stdout); 414 } 415 if (bulk->list) { 416 *list_tail = bulk->list; 417 bulk->list = NULL; 418 while ((scan = *list_tail) != NULL) { 419 if (bulk->s4 == NULL || bulk->s4[0] != 'x') 420 scan->flags |= PKGF_MANUALSEL; 421 pkg_enter(scan); 422 list_tail = &scan->bnext; 423 } 424 } 425 freebulk(bulk); 426 } 427 printf("100.00%%\n"); 428 printf("\nTotal %d\n", count); 429 fflush(stdout); 430 431 /* 432 * Resolve all dependencies for the related packages, potentially 433 * adding anything that could not be found to the list. This will 434 * continue to issue bulk operations and process the result until 435 * no dependencies are left. 436 */ 437 printf("Resolving dependencies..."); 438 fflush(stdout); 439 dep_list = list; 440 while (dep_list) { 441 dep_list = resolveDeps(dep_list, &list_tail, 0); 442 } 443 printf("done\n"); 444 445 donebulk(); 446 447 /* 448 * Generate the topology 449 */ 450 resolveDeps(list, NULL, 1); 451 452 /* 453 * Do a final count, ignore place holders. 454 * 455 * Also set stop_fail if appropriate. Check for direct specifications 456 * which fail to probe and any direct dependencies of those 457 * specifications, but don't recurse (for now)... don't check indirect 458 * dependencies (i.e. A -> B -> C where A is directly specified, B 459 * is adirect dependency, and C fails to probe). 460 */ 461 count = 0; 462 stop_fail = 0; 463 stop_base_list = 0; 464 for (scan = list; scan; scan = scan->bnext) { 465 if ((scan->flags & PKGF_ERROR) == 0) { 466 ++count; 467 } 468 if ((scan->flags & PKGF_MANUALSEL) && MaskProbeAbort == 0) { 469 pkglink_t *link; 470 471 /* 472 * Directly specified package failed to probe 473 */ 474 if (scan->flags & PKGF_CORRUPT) { 475 ++stop_fail; 476 ++stop_base_list; 477 } 478 479 /* 480 * Directly specified package had a direct dependency 481 * that failed to probe (don't go further). 482 */ 483 PKGLIST_FOREACH(link, &scan->idepon_list) { 484 if (link->pkg && 485 (link->pkg->flags & PKGF_CORRUPT)) { 486 ++stop_fail; 487 } 488 } 489 } 490 } 491 printf("Total Returned %d\n", count); 492 493 /* 494 * Check to see if any PKGF_MANUALSEL packages 495 */ 496 if (stop_fail) { 497 printf("%d packages failed to probe\n", stop_fail); 498 if (PrepareSystemFlag) { 499 if (stop_fail == stop_base_list) { 500 printf( 501 "prepare-system: Some of your installed packages no longer exist in\n" 502 "dports, do you wish to continue rebuilding what does exist?\n"); 503 if (askyn("Continue anyway? ")) 504 remove_corrupt = 1; 505 } else { 506 printf( 507 "prepare-system: Some of your installed packages have dependencies\n" 508 "which could not be found in dports, cannot continue, aborting\n"); 509 } 510 } else { 511 printf("unable to continue, aborting\n"); 512 } 513 if (remove_corrupt == 0) 514 exit(1); 515 } 516 517 /* 518 * Remove corrupt packages before continuing 519 */ 520 if (remove_corrupt) { 521 list_tail = &list; 522 while ((scan = *list_tail) != NULL) { 523 if (scan->flags & PKGF_CORRUPT) 524 *list_tail = scan->bnext; 525 else 526 list_tail = &scan->bnext; 527 } 528 } 529 530 /* 531 * Scan our binary distributions and related dependencies looking 532 * for any packages that have already been built. 533 */ 534 initbulk(childGetBinaryDistInfo, MaxBulk); 535 total = scan_binary_repo(RepositoryPath); 536 count = 0; 537 printf("Scanning %d packages\n", total); 538 539 while ((bulk = getbulk()) != NULL) { 540 ++count; 541 if ((count & 255) == 0) { 542 printf("%6.2f%%\r", 543 (double)count * 100.0 / (double)total + 0.001); 544 fflush(stdout); 545 } 546 freebulk(bulk); 547 } 548 printf("100.00%%\n"); 549 printf("\nTotal %d\n", count); 550 fflush(stdout); 551 donebulk(); 552 553 printf("all done\n"); 554 555 return list; 556 } 557 558 pkg_t * 559 GetPkgPkg(pkg_t **listp) 560 { 561 bulk_t *bulk; 562 pkg_t *scan; 563 pkg_t *s2; 564 565 for (scan = *listp; scan; scan = scan->bnext) { 566 if (strcmp(scan->portdir, "ports-mgmt/pkg") == 0) 567 return scan; 568 } 569 570 /* 571 * This will force pkg to be built, but generally this code 572 * is not reached because the package list processing code 573 * adds ports-mgmt/pkg unconditionally. 574 */ 575 initbulk(childGetPackageInfo, MaxBulk); 576 queuebulk("ports-mgmt", "pkg", NULL, "x"); 577 bulk = getbulk(); 578 dassert(bulk, "Cannot find ports-mgmt/pkg"); 579 scan = bulk->list; 580 bulk->list = NULL; 581 freebulk(bulk); 582 donebulk(); 583 584 585 /* 586 * Include added packages to the total and add the initial bulk 587 * built packages to the list so they get counted. 588 */ 589 for (s2 = scan; s2->bnext; s2 = s2->bnext) 590 ++BuildTotal; 591 for (s2 = scan; s2->bnext; s2 = s2->bnext) 592 ; 593 s2->bnext = *listp; 594 *listp = scan; 595 ++BuildTotal; 596 597 return scan; 598 } 599 600 /* 601 * Try to optimize the environment by supplying information that 602 * the ports system would generally have to run stuff to get on 603 * every package. 604 * 605 * See childOptimizeEnv() for the actual handling. We execute 606 * a single make -V... -V... for ports-mgmt/pkg from within the 607 * bulk system (which handles the environment and disables 608 * /etc/make.conf), and we then call addbuildenv() as appropriate. 609 * 610 * _PERL5_FROM_BIN 611 * add others... 612 */ 613 void 614 OptimizeEnv(void) 615 { 616 bulk_t *bulk; 617 618 initbulk(childOptimizeEnv, MaxBulk); 619 queuebulk("ports-mgmt", "pkg", NULL, NULL); 620 bulk = getbulk(); 621 freebulk(bulk); 622 donebulk(); 623 } 624 625 /* 626 * Run through the list resolving dependencies and constructing the topology 627 * linkages. This may append packages to the list. Dependencies to dummy 628 * nodes which do not specify a flavor do not need special handling, the 629 * search code in build.c will properly follow the first flavor. 630 */ 631 static pkg_t * 632 resolveDeps(pkg_t *list, pkg_t ***list_tailp, int gentopo) 633 { 634 pkg_t *ret_list = NULL; 635 pkg_t *scan; 636 pkg_t *use; 637 bulk_t *bulk; 638 639 for (scan = list; scan; scan = scan->bnext) { 640 use = pkg_find(scan->portdir); 641 resolveFlavors(use, scan->flavors, gentopo); 642 resolveDepString(use, scan->fetch_deps, 643 gentopo, DEP_TYPE_FETCH); 644 resolveDepString(use, scan->ext_deps, 645 gentopo, DEP_TYPE_EXT); 646 resolveDepString(use, scan->patch_deps, 647 gentopo, DEP_TYPE_PATCH); 648 resolveDepString(use, scan->build_deps, 649 gentopo, DEP_TYPE_BUILD); 650 resolveDepString(use, scan->lib_deps, 651 gentopo, DEP_TYPE_LIB); 652 resolveDepString(use, scan->run_deps, 653 gentopo, DEP_TYPE_RUN); 654 } 655 656 /* 657 * No bulk ops are queued when doing the final topology 658 * generation. 659 * 660 * Avoid entering duplicate results from the bulk ops. Duplicate 661 * results are mostly filtered out, but not always. A dummy node 662 * representing multiple flavors will parse-out the flavors 663 */ 664 if (gentopo) 665 return NULL; 666 while ((bulk = getbulk()) != NULL) { 667 if (bulk->list) { 668 if (ret_list == NULL) 669 ret_list = bulk->list; 670 **list_tailp = bulk->list; 671 bulk->list = NULL; 672 while ((scan = **list_tailp) != NULL) { 673 pkg_enter(scan); 674 *list_tailp = &scan->bnext; 675 } 676 } 677 freebulk(bulk); 678 } 679 return (ret_list); 680 } 681 682 /* 683 * Resolve a generic node that has flavors, queue to retrieve info for 684 * each flavor and setup linkages as appropriate. 685 */ 686 static void 687 resolveFlavors(pkg_t *pkg, char *flavors, int gentopo) 688 { 689 char *flavor_base; 690 char *flavor_scan; 691 char *flavor; 692 char *portdir; 693 char *s1; 694 char *s2; 695 pkg_t *dpkg; 696 pkglink_t *link; 697 698 if ((pkg->flags & PKGF_DUMMY) == 0) 699 return; 700 if (pkg->flavors == NULL || pkg->flavors[0] == 0) 701 return; 702 flavor_base = strdup(flavors); 703 flavor_scan = flavor_base; 704 705 for (;;) { 706 do { 707 flavor = strsep(&flavor_scan, " \t"); 708 } while (flavor && *flavor == 0); 709 if (flavor == NULL) 710 break; 711 712 /* 713 * Iterate each flavor generating "s1/s2@flavor". 714 * 715 * queuebulk() info for each flavor, and set-up the 716 * linkages in the topology generation pass. 717 */ 718 asprintf(&portdir, "%s@%s", pkg->portdir, flavor); 719 s1 = strdup(pkg->portdir); 720 s2 = strchr(s1, '/'); 721 *s2++ = 0; 722 723 dpkg = pkg_find(portdir); 724 if (dpkg && gentopo) { 725 /* 726 * Setup linkages 727 */ 728 free(portdir); 729 730 link = calloc(1, sizeof(*link)); 731 link->pkg = dpkg; 732 link->next = &pkg->idepon_list; 733 link->prev = pkg->idepon_list.prev; 734 link->next->prev = link; 735 link->prev->next = link; 736 link->dep_type = DEP_TYPE_BUILD; 737 738 link = calloc(1, sizeof(*link)); 739 link->pkg = pkg; 740 link->next = &dpkg->deponi_list; 741 link->prev = dpkg->deponi_list.prev; 742 link->next->prev = link; 743 link->prev->next = link; 744 link->dep_type = DEP_TYPE_BUILD; 745 ++dpkg->depi_count; 746 } else if (gentopo == 0 && dpkg == NULL) { 747 /* 748 * Use a place-holder to prevent duplicate 749 * dependencies from being processed. The placeholder 750 * will be replaced by the actual dependency. 751 */ 752 dpkg = allocpkg(); 753 dpkg->portdir = portdir; 754 dpkg->flags = PKGF_PLACEHOLD; 755 pkg_enter(dpkg); 756 queuebulk(s1, s2, flavor, NULL); 757 } 758 free(s1); 759 } 760 free(flavor_base); 761 } 762 763 static void 764 resolveDepString(pkg_t *pkg, char *depstr, int gentopo, int dep_type) 765 { 766 char *copy_base; 767 char *copy; 768 char *dep; 769 char *sep; 770 char *tag; 771 char *flavor; 772 pkg_t *dpkg; 773 774 if (depstr == NULL || depstr[0] == 0) 775 return; 776 777 copy_base = strdup(depstr); 778 copy = copy_base; 779 780 for (;;) { 781 do { 782 dep = strsep(©, " \t"); 783 } while (dep && *dep == 0); 784 if (dep == NULL) 785 break; 786 787 /* 788 * Ignore dependencies prefixed with ${NONEXISTENT} 789 */ 790 if (strncmp(dep, "/nonexistent:", 13) == 0) 791 continue; 792 793 dep = strchr(dep, ':'); 794 if (dep == NULL || *dep != ':') { 795 printf("Error parsing dependency for %s: %s\n", 796 pkg->portdir, copy_base); 797 continue; 798 } 799 ++dep; 800 801 /* 802 * Strip-off any DPortsPath prefix. EXTRACT_DEPENDS 803 * often (always?) generates this prefix. 804 */ 805 if (strncmp(dep, DPortsPath, strlen(DPortsPath)) == 0) { 806 dep += strlen(DPortsPath); 807 if (*dep == '/') 808 ++dep; 809 } 810 811 /* 812 * Strip-off any tag (such as :patch). We don't try to 813 * organize dependencies at this fine a grain (for now). 814 */ 815 tag = strchr(dep, ':'); 816 if (tag) 817 *tag++ = 0; 818 819 /* 820 * Locate the dependency 821 */ 822 if ((dpkg = pkg_find(dep)) != NULL) { 823 if (gentopo) { 824 pkglink_t *link; 825 826 /* 827 * NOTE: idep_count is calculated recursively 828 * at build-time 829 */ 830 ddprintf(0, "Add Dependency %s -> %s\n", 831 pkg->portdir, dpkg->portdir); 832 link = calloc(1, sizeof(*link)); 833 link->pkg = dpkg; 834 link->next = &pkg->idepon_list; 835 link->prev = pkg->idepon_list.prev; 836 link->next->prev = link; 837 link->prev->next = link; 838 link->dep_type = dep_type; 839 840 link = calloc(1, sizeof(*link)); 841 link->pkg = pkg; 842 link->next = &dpkg->deponi_list; 843 link->prev = dpkg->deponi_list.prev; 844 link->next->prev = link; 845 link->prev->next = link; 846 link->dep_type = dep_type; 847 ++dpkg->depi_count; 848 } 849 continue; 850 } 851 852 /* 853 * This shouldn't happen because we already took a first 854 * pass and should have generated the pkgs. 855 */ 856 if (gentopo) { 857 printf("Topology Generate failed for %s: %s\n", 858 pkg->portdir, copy_base); 859 continue; 860 } 861 862 /* 863 * Separate out the two dports directory components and 864 * extract the optional '@flavor' specification. 865 */ 866 sep = strchr(dep, '/'); 867 if (sep == NULL) { 868 printf("Error parsing dependency for %s: %s\n", 869 pkg->portdir, copy_base); 870 continue; 871 } 872 *sep++ = 0; 873 874 /* 875 * The flavor hangs off the separator, not the tag 876 */ 877 flavor = strrchr(sep, '@'); 878 #if 0 879 if (tag) 880 flavor = strrchr(tag, '@'); 881 else 882 flavor = strrchr(sep, '@'); 883 #endif 884 if (flavor) 885 *flavor++ = 0; 886 887 if (flavor) 888 ddprintf(0, "QUEUE DEPENDENCY FROM PKG %s: %s/%s@%s\n", 889 pkg->portdir, dep, sep, flavor); 890 else 891 ddprintf(0, "QUEUE DEPENDENCY FROM PKG %s: %s/%s\n", 892 pkg->portdir, dep, sep); 893 894 /* 895 * Use a place-holder to prevent duplicate dependencies from 896 * being processed. The placeholder will be replaced by 897 * the actual dependency. 898 */ 899 dpkg = allocpkg(); 900 if (flavor) 901 asprintf(&dpkg->portdir, "%s/%s@%s", dep, sep, flavor); 902 else 903 asprintf(&dpkg->portdir, "%s/%s", dep, sep); 904 dpkg->flags = PKGF_PLACEHOLD; 905 pkg_enter(dpkg); 906 907 queuebulk(dep, sep, flavor, NULL); 908 } 909 free(copy_base); 910 } 911 912 void 913 FreePackageList(pkg_t *pkgs __unused) 914 { 915 dfatal("not implemented"); 916 } 917 918 /* 919 * Scan some or all dports to allocate the related pkg structure. Dependencies 920 * are stored but not processed. 921 * 922 * Threaded function 923 */ 924 static void 925 childGetPackageInfo(bulk_t *bulk) 926 { 927 pkg_t *pkg; 928 char *flavor; 929 char *ptr; 930 FILE *fp; 931 int line; 932 size_t len; 933 char *portpath; 934 char *flavarg; 935 const char *cav[MAXCAC]; 936 pid_t pid; 937 int cac; 938 939 /* 940 * If the package has flavors we will loop on each one. If a flavor 941 * is not passed in s3 we will loop on all flavors, otherwise we will 942 * only process the passed-in flavor. 943 */ 944 flavor = bulk->s3; /* usually NULL */ 945 946 bulk->list = NULL; 947 948 asprintf(&portpath, "%s/%s/%s", DPortsPath, bulk->s1, bulk->s2); 949 if (flavor) 950 asprintf(&flavarg, "FLAVOR=%s", flavor); 951 else 952 flavarg = NULL; 953 954 cac = 0; 955 cav[cac++] = MAKE_BINARY; 956 cav[cac++] = "-C"; 957 cav[cac++] = portpath; 958 if (flavarg) 959 cav[cac++] = flavarg; 960 cav[cac++] = "-VPKGVERSION"; 961 cav[cac++] = "-VPKGFILE:T"; 962 cav[cac++] = "-VALLFILES"; 963 cav[cac++] = "-VDIST_SUBDIR"; 964 cav[cac++] = "-VMAKE_JOBS_NUMBER"; 965 cav[cac++] = "-VIGNORE"; 966 cav[cac++] = "-VFETCH_DEPENDS"; 967 cav[cac++] = "-VEXTRACT_DEPENDS"; 968 cav[cac++] = "-VPATCH_DEPENDS"; 969 cav[cac++] = "-VBUILD_DEPENDS"; 970 cav[cac++] = "-VLIB_DEPENDS"; 971 cav[cac++] = "-VRUN_DEPENDS"; 972 cav[cac++] = "-VSELECTED_OPTIONS"; 973 cav[cac++] = "-VDESELECTED_OPTIONS"; 974 cav[cac++] = "-VUSE_LINUX"; 975 cav[cac++] = "-VFLAVORS"; 976 cav[cac++] = "-VUSES"; 977 978 fp = dexec_open(portpath + strlen(DPortsPath) + 1, cav, cac, 979 &pid, NULL, 1, 1); 980 freestrp(&flavarg); 981 982 pkg = allocpkg(); 983 if (flavor) 984 asprintf(&pkg->portdir, "%s/%s@%s", bulk->s1, bulk->s2, flavor); 985 else 986 asprintf(&pkg->portdir, "%s/%s", bulk->s1, bulk->s2); 987 988 line = 1; 989 while ((ptr = fgetln(fp, &len)) != NULL) { 990 if (len == 0 || ptr[len-1] != '\n') { 991 dfatal("Bad package info for %s/%s response line %d", 992 bulk->s1, bulk->s2, line); 993 } 994 ptr[--len] = 0; 995 996 switch(line) { 997 case 1: /* PKGVERSION */ 998 asprintf(&pkg->version, "%s", ptr); 999 break; 1000 case 2: /* PKGFILE */ 1001 asprintf(&pkg->pkgfile, "%s", ptr); 1002 break; 1003 case 3: /* ALLFILES (aka DISTFILES + patch files) */ 1004 asprintf(&pkg->distfiles, "%s", ptr); 1005 break; 1006 case 4: /* DIST_SUBDIR */ 1007 pkg->distsubdir = strdup_or_null(ptr); 1008 break; 1009 case 5: /* MAKE_JOBS_NUMBER */ 1010 pkg->make_jobs_number = strtol(ptr, NULL, 0); 1011 break; 1012 case 6: /* IGNORE */ 1013 pkg->ignore = strdup_or_null(ptr); 1014 break; 1015 case 7: /* FETCH_DEPENDS */ 1016 pkg->fetch_deps = strdup_or_null(ptr); 1017 break; 1018 case 8: /* EXTRACT_DEPENDS */ 1019 pkg->ext_deps = strdup_or_null(ptr); 1020 break; 1021 case 9: /* PATCH_DEPENDS */ 1022 pkg->patch_deps = strdup_or_null(ptr); 1023 break; 1024 case 10: /* BUILD_DEPENDS */ 1025 pkg->build_deps = strdup_or_null(ptr); 1026 break; 1027 case 11: /* LIB_DEPENDS */ 1028 pkg->lib_deps = strdup_or_null(ptr); 1029 break; 1030 case 12: /* RUN_DEPENDS */ 1031 pkg->run_deps = strdup_or_null(ptr); 1032 break; 1033 case 13: /* SELECTED_OPTIONS */ 1034 pkg->pos_options = strdup_or_null(ptr); 1035 break; 1036 case 14: /* DESELECTED_OPTIONS */ 1037 pkg->neg_options = strdup_or_null(ptr); 1038 break; 1039 case 15: /* USE_LINUX */ 1040 if (ptr[0]) 1041 pkg->use_linux = 1; 1042 break; 1043 case 16: /* FLAVORS */ 1044 asprintf(&pkg->flavors, "%s", ptr); 1045 break; 1046 case 17: /* USES */ 1047 asprintf(&pkg->uses, "%s", ptr); 1048 if (strstr(pkg->uses, "metaport")) 1049 pkg->flags |= PKGF_META; 1050 break; 1051 default: 1052 printf("EXTRA LINE: %s\n", ptr); 1053 break; 1054 } 1055 ++line; 1056 } 1057 if (line == 1) { 1058 printf("DPort not found: %s/%s\n", bulk->s1, bulk->s2); 1059 pkg->flags |= PKGF_NOTFOUND; 1060 } else if (line != 17 + 1) { 1061 printf("DPort corrupt: %s/%s\n", bulk->s1, bulk->s2); 1062 pkg->flags |= PKGF_CORRUPT; 1063 } 1064 if (dexec_close(fp, pid)) { 1065 printf("make -V* command for %s/%s failed\n", 1066 bulk->s1, bulk->s2); 1067 pkg->flags |= PKGF_CORRUPT; 1068 } 1069 ddassert(bulk->s1); 1070 1071 /* 1072 * DEBUGSTOP mode 1073 */ 1074 if (bulk->s4 && bulk->s4[0] == 'd') 1075 pkg->flags |= PKGF_DEBUGSTOP; 1076 1077 /* 1078 * Mark as a dummy node, the front-end will iterate the flavors 1079 * and create sub-nodes for us. 1080 * 1081 * Get rid of elements returned that are for the first flavor. 1082 * We are creating a dummy node here, not the node for the first 1083 * flavor. 1084 */ 1085 if (flavor == NULL && pkg->flavors && pkg->flavors[0]) { 1086 pkg->flags |= PKGF_DUMMY; 1087 freestrp(&pkg->fetch_deps); 1088 freestrp(&pkg->ext_deps); 1089 freestrp(&pkg->patch_deps); 1090 freestrp(&pkg->build_deps); 1091 freestrp(&pkg->lib_deps); 1092 freestrp(&pkg->run_deps); 1093 freestrp(&pkg->pkgfile); 1094 } 1095 1096 /* 1097 * Checksum the port directory tree. This just rollsup crcs of the 1098 * path names and a few stat fields (mtime, size) in order to detect 1099 * if any modification has been made to the port. 1100 */ 1101 pkg->crc32 = crcDirTree(portpath); 1102 1103 /* 1104 * Only one pkg is put on the return list now. This code no 1105 * longer creates pseudo-nodes for flavors (the frontend requests 1106 * each flavor instead). 1107 */ 1108 bulk->list = pkg; 1109 free(portpath); 1110 } 1111 1112 /* 1113 * Query the package (at least to make sure it hasn't been truncated) 1114 * and mark it as PACKAGED if found. 1115 * 1116 * This is a pre-req prior to doing builds, so we cannot assume that 1117 * the template has its pkg-static binary yet. 1118 * 1119 * Threaded function 1120 */ 1121 static void 1122 childGetBinaryDistInfo(bulk_t *bulk) 1123 { 1124 char *ptr; 1125 FILE *fp; 1126 size_t len; 1127 pkg_t *pkg; 1128 const char *cav[MAXCAC]; 1129 char *repopath; 1130 char buf[1024]; 1131 pid_t pid; 1132 int cac; 1133 int deleteme; 1134 1135 asprintf(&repopath, "%s/%s", RepositoryPath, bulk->s1); 1136 1137 cac = 0; 1138 cav[cac++] = PKG_BINARY; 1139 cav[cac++] = "query"; 1140 cav[cac++] = "-F"; 1141 cav[cac++] = repopath; 1142 cav[cac++] = "%n-%v"; 1143 1144 fp = dexec_open(NULL, cav, cac, &pid, NULL, 1, 0); 1145 deleteme = DeleteObsoletePkgs; 1146 1147 while ((ptr = fgetln(fp, &len)) != NULL) { 1148 if (len == 0 || ptr[len-1] != '\n') 1149 continue; 1150 ptr[len-1] = 0; 1151 1152 /* 1153 * As of pkg 1.17 the binary dist files use a .pkg suffix 1154 * regardless of the compression format, so always check 1155 * those. 1156 */ 1157 snprintf(buf, sizeof(buf), "%s%s", ptr, ".pkg"); 1158 pkg = pkg_find(buf); 1159 if (pkg == NULL) { 1160 snprintf(buf, sizeof(buf), "%s%s", ptr, UsePkgSufx); 1161 pkg = pkg_find(buf); 1162 } 1163 if (pkg) { 1164 pkg->flags |= PKGF_PACKAGED; 1165 deleteme = 0; 1166 } else { 1167 ddprintf(0, "Note: package scan, not in list, " 1168 "skipping %s{.%s,.pkg}\n", ptr, UsePkgSufx); 1169 } 1170 } 1171 if (dexec_close(fp, pid)) { 1172 printf("pkg query command failed for %s\n", repopath); 1173 } 1174 if (deleteme) { 1175 dlog(DLOG_ALL | DLOG_STDOUT, 1176 "Deleting obsolete package %s\n", repopath); 1177 remove(repopath); 1178 } 1179 free(repopath); 1180 } 1181 1182 static void 1183 childOptimizeEnv(bulk_t *bulk) 1184 { 1185 char *portpath; 1186 char *ptr; 1187 FILE *fp; 1188 int line; 1189 size_t len; 1190 const char *cav[MAXCAC]; 1191 pid_t pid; 1192 int cac; 1193 1194 asprintf(&portpath, "%s/%s/%s", DPortsPath, bulk->s1, bulk->s2); 1195 1196 cac = 0; 1197 cav[cac++] = MAKE_BINARY; 1198 cav[cac++] = "-C"; 1199 cav[cac++] = portpath; 1200 cav[cac++] = "-V_PERL5_FROM_BIN"; 1201 1202 fp = dexec_open(portpath + strlen(DPortsPath) + 1, cav, cac, 1203 &pid, NULL, 1, 1); 1204 free(portpath); 1205 1206 line = 1; 1207 while ((ptr = fgetln(fp, &len)) != NULL) { 1208 if (len == 0 || ptr[len-1] != '\n') { 1209 dfatal("Bad package info for %s/%s response line %d", 1210 bulk->s1, bulk->s2, line); 1211 } 1212 ptr[--len] = 0; 1213 1214 switch(line) { 1215 case 1: /* _PERL5_FROM_BIN */ 1216 addbuildenv("_PERL5_FROM_BIN", ptr, BENV_ENVIRONMENT); 1217 break; 1218 default: 1219 printf("childOptimizeEnv: EXTRA LINE: %s\n", ptr); 1220 break; 1221 } 1222 ++line; 1223 } 1224 if (line == 1) { 1225 printf("DPort not found: %s/%s\n", bulk->s1, bulk->s2); 1226 } else if (line != 1 + 1) { 1227 printf("DPort corrupt: %s/%s\n", bulk->s1, bulk->s2); 1228 } 1229 if (dexec_close(fp, pid)) { 1230 printf("childOptimizeEnv() failed\n"); 1231 } 1232 } 1233 1234 static int 1235 scan_and_queue_dir(const char *path, const char *level1, int level) 1236 { 1237 DIR *dir; 1238 char *s1; 1239 char *s2; 1240 struct dirent *den; 1241 struct stat st; 1242 int count = 0; 1243 1244 dir = opendir(path); 1245 dassert(dir, "Cannot open dports path \"%s\"", path); 1246 1247 while ((den = readdir(dir)) != NULL) { 1248 if (den->d_namlen == 1 && den->d_name[0] == '.') 1249 continue; 1250 if (den->d_namlen == 2 && 1251 den->d_name[0] == '.' && den->d_name[1] == '.') 1252 continue; 1253 asprintf(&s1, "%s/%s", path, den->d_name); 1254 if (lstat(s1, &st) < 0 || !S_ISDIR(st.st_mode)) { 1255 free(s1); 1256 continue; 1257 } 1258 if (level == 1) { 1259 count += scan_and_queue_dir(s1, den->d_name, 2); 1260 free(s1); 1261 continue; 1262 } 1263 asprintf(&s2, "%s/Makefile", s1); 1264 if (lstat(s2, &st) == 0) { 1265 queuebulk(level1, den->d_name, NULL, NULL); 1266 ++count; 1267 } 1268 free(s1); 1269 free(s2); 1270 } 1271 closedir(dir); 1272 1273 return count; 1274 } 1275 1276 static int 1277 scan_binary_repo(const char *path) 1278 { 1279 DIR *dir; 1280 struct dirent *den; 1281 int count; 1282 1283 count = 0; 1284 dir = opendir(path); 1285 dassert(dir, "Cannot open repository path \"%s\"", path); 1286 1287 /* 1288 * NOTE: Test includes the '.' in the suffix. 1289 */ 1290 while ((den = readdir(dir)) != NULL) { 1291 const char *suffix; 1292 1293 suffix = strrchr(den->d_name, '.'); 1294 if (suffix && suffix != den->d_name && 1295 strcmp(suffix, UsePkgSufx) == 0) 1296 { 1297 queuebulk(den->d_name, NULL, NULL, NULL); 1298 ++count; 1299 } 1300 1301 /* 1302 * As of 1.17, pkg generates .pkg files. 1303 */ 1304 if (suffix && suffix != den->d_name && 1305 strcmp(suffix, ".pkg") == 0) 1306 { 1307 queuebulk(den->d_name, NULL, NULL, NULL); 1308 ++count; 1309 } 1310 } 1311 closedir(dir); 1312 1313 return count; 1314 } 1315 1316 #if 0 1317 static void 1318 pkgfree(pkg_t *pkg) 1319 { 1320 freestrp(&pkg->portdir); 1321 freestrp(&pkg->version); 1322 freestrp(&pkg->pkgfile); 1323 freestrp(&pkg->ignore); 1324 freestrp(&pkg->fetch_deps); 1325 freestrp(&pkg->ext_deps); 1326 freestrp(&pkg->patch_deps); 1327 freestrp(&pkg->build_deps); 1328 freestrp(&pkg->lib_deps); 1329 freestrp(&pkg->run_deps); 1330 freestrp(&pkg->pos_options); 1331 freestrp(&pkg->neg_options); 1332 freestrp(&pkg->flavors); 1333 free(pkg); 1334 } 1335 #endif 1336