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 #include "dsynth.h" 38 39 worker_t WorkerAry[MAXWORKERS]; 40 int BuildInitialized; 41 int RunningWorkers; 42 int DynamicMaxWorkers; 43 int FailedWorkers; 44 long RunningPkgDepSize; 45 pthread_mutex_t WorkerMutex; 46 pthread_cond_t WorkerCond; 47 48 static int build_find_leaves(pkg_t *parent, pkg_t *pkg, 49 pkg_t ***build_tailp, int *app, int *hasworkp, 50 int depth, int first, int first_one_only); 51 static int buildCalculateDepiDepth(pkg_t *pkg); 52 static void build_clear_trav(pkg_t *pkg); 53 static void startbuild(pkg_t **build_listp, pkg_t ***build_tailp); 54 static int qsort_depi(const void *pkg1, const void *pkg2); 55 static int qsort_idep(const void *pkg1, const void *pkg2); 56 static void startworker(pkg_t *pkg, worker_t *work); 57 static void cleanworker(worker_t *work); 58 static void waitbuild(int whilematch, int dynamicmax); 59 static void workercomplete(worker_t *work); 60 static void *childBuilderThread(void *arg); 61 static int childInstallPkgDeps(worker_t *work); 62 static size_t childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list, 63 int undoit, int depth, int first_one_only); 64 static void dophase(worker_t *work, wmsg_t *wmsg, 65 int wdog, int phaseid, const char *phase); 66 static void phaseReapAll(void); 67 static void phaseTerminateSignal(int sig); 68 static char *buildskipreason(pkglink_t *parent, pkg_t *pkg); 69 static int buildskipcount_dueto(pkg_t *pkg, int mode); 70 static int mptylogpoll(int ptyfd, int fdlog, wmsg_t *wmsg, 71 time_t *wdog_timep); 72 static int copyfile(char *src, char *dst); 73 static void doHook(pkg_t *pkg, const char *id, const char *path, int waitfor); 74 static void childHookRun(bulk_t *bulk); 75 76 static worker_t *SigWork; 77 static int MasterPtyFd = -1; 78 static int CopyFileFd = -1; 79 static pid_t SigPid; 80 static const char *WorkerFlavorPrt = ""; /* "" or "@flavor" */ 81 82 #define MPTY_FAILED -2 83 #define MPTY_AGAIN -1 84 #define MPTY_EOF 0 85 #define MPTY_DATA 1 86 87 int BuildTotal; 88 int BuildCount; 89 int BuildSkipCount; 90 int BuildIgnoreCount; 91 int BuildFailCount; 92 int BuildSuccessCount; 93 94 /* 95 * Initialize the WorkerAry[] 96 */ 97 void 98 DoInitBuild(int slot_override) 99 { 100 worker_t *work; 101 struct stat st; 102 int i; 103 104 ddassert(slot_override < 0 || MaxWorkers == 1); 105 106 bzero(WorkerAry, MaxWorkers * sizeof(worker_t)); 107 pthread_mutex_init(&WorkerMutex, NULL); 108 109 for (i = 0; i < MaxWorkers; ++i) { 110 work = &WorkerAry[i]; 111 work->index = (slot_override >= 0) ? slot_override : i; 112 work->state = WORKER_NONE; 113 asprintf(&work->basedir, "%s/SL%02d", BuildBase, work->index); 114 pthread_cond_init(&work->cond, NULL); 115 } 116 BuildCount = 0; 117 118 /* 119 * Create required sub-directories. The base directories must already 120 * exist as a dsynth configuration safety. 121 */ 122 if (stat(RepositoryPath, &st) < 0) { 123 if (mkdir(RepositoryPath, 0755) < 0) 124 dfatal("Cannot mkdir %s\n", RepositoryPath); 125 } 126 127 BuildInitialized = 1; 128 129 /* 130 * slow-start (increases at a rate of 1 per 5 seconds) 131 */ 132 if (SlowStartOpt > MaxWorkers) 133 DynamicMaxWorkers = MaxWorkers; 134 else if (SlowStartOpt > 0) 135 DynamicMaxWorkers = SlowStartOpt; 136 else 137 DynamicMaxWorkers = MaxWorkers; 138 } 139 140 /* 141 * Called by the frontend to clean-up any hanging mounts. 142 */ 143 void 144 DoCleanBuild(int resetlogs) 145 { 146 int i; 147 148 ddassert(BuildInitialized); 149 150 if (resetlogs) 151 dlogreset(); 152 for (i = 0; i < MaxWorkers; ++i) { 153 DoWorkerUnmounts(&WorkerAry[i]); 154 } 155 } 156 157 void 158 DoBuild(pkg_t *pkgs) 159 { 160 pkg_t *build_list = NULL; 161 pkg_t **build_tail = &build_list; 162 pkg_t *scan; 163 bulk_t *bulk; 164 int haswork = 1; 165 int first = 1; 166 int newtemplate; 167 time_t startTime; 168 time_t t; 169 int h, m, s; 170 171 /* 172 * We use our bulk system to run hooks. This will be for 173 * Skipped and Ignored. Success and Failure are handled by 174 * WorkerProcess() which is a separately-exec'd dsynth. 175 */ 176 if (UsingHooks) 177 initbulk(childHookRun, MaxBulk); 178 179 /* 180 * Count up the packages, not counting dummies 181 */ 182 for (scan = pkgs; scan; scan = scan->bnext) { 183 if ((scan->flags & PKGF_DUMMY) == 0) 184 ++BuildTotal; 185 } 186 187 doHook(NULL, "hook_run_start", HookRunStart, 1); 188 189 /* 190 * The pkg and pkg-static binaries are needed. If already present 191 * then assume that the template is also valid, otherwise build 192 * both. 193 */ 194 scan = GetPkgPkg(pkgs); 195 196 /* 197 * Create our template. The template will be missing pkg 198 * and pkg-static. 199 */ 200 if ((scan->flags & (PKGF_SUCCESS | PKGF_PACKAGED)) == 0) { 201 /* force a fresh template */ 202 newtemplate = DoCreateTemplate(1); 203 } else { 204 newtemplate = DoCreateTemplate(0); 205 } 206 207 /* 208 * This will clear the screen and set-up our gui, so sleep 209 * a little first in case the user wants to see what was 210 * printed before. 211 */ 212 sleep(2); 213 pthread_mutex_lock(&WorkerMutex); 214 startTime = time(NULL); 215 RunStatsInit(); 216 RunStatsReset(); 217 218 /* 219 * Build pkg/pkg-static. 220 */ 221 if ((scan->flags & (PKGF_SUCCESS | PKGF_PACKAGED)) == 0) { 222 build_list = scan; 223 build_tail = &scan->build_next; 224 startbuild(&build_list, &build_tail); 225 while (RunningWorkers == 1) 226 waitbuild(1, 0); 227 228 if (scan->flags & PKGF_NOBUILD) 229 dfatal("Unable to build 'pkg'"); 230 if (scan->flags & PKGF_ERROR) 231 dfatal("Error building 'pkg'"); 232 if ((scan->flags & PKGF_SUCCESS) == 0) 233 dfatal("Error building 'pkg'"); 234 newtemplate = 1; 235 } 236 237 /* 238 * Install pkg/pkg-static into the template 239 */ 240 if (newtemplate) { 241 char *buf; 242 int rc; 243 244 asprintf(&buf, 245 "cd %s/Template; " 246 "tar --exclude '+*' --exclude '*/man/*' " 247 "-xvzpf %s/%s > /dev/null 2>&1", 248 BuildBase, 249 RepositoryPath, 250 scan->pkgfile); 251 rc = system(buf); 252 if (rc) 253 dfatal("Command failed: %s\n", buf); 254 freestrp(&buf); 255 } 256 257 /* 258 * Calculate depi_depth, the longest chain of dependencies 259 * for who depends on me, weighted by powers of two. 260 */ 261 for (scan = pkgs; scan; scan = scan->bnext) { 262 buildCalculateDepiDepth(scan); 263 } 264 265 /* 266 * Nominal bulk build sequence 267 */ 268 while (haswork) { 269 haswork = 0; 270 fflush(stdout); 271 for (scan = pkgs; scan; scan = scan->bnext) { 272 ddprintf(0, "SCANLEAVES %08x %s\n", 273 scan->flags, scan->portdir); 274 scan->flags |= PKGF_BUILDLOOP; 275 /* 276 * NOTE: We must still find dependencies if PACKAGED 277 * to fill in the gaps, as some of them may 278 * need to be rebuilt. 279 */ 280 if (scan->flags & (PKGF_SUCCESS | PKGF_FAILURE | 281 PKGF_ERROR)) { 282 #if 0 283 ddprintf(0, "%s: already built\n", 284 scan->portdir); 285 #endif 286 } else { 287 int ap = 0; 288 build_find_leaves(NULL, scan, &build_tail, 289 &ap, &haswork, 0, first, 0); 290 ddprintf(0, "TOPLEVEL %s %08x\n", 291 scan->portdir, ap); 292 } 293 scan->flags &= ~PKGF_BUILDLOOP; 294 build_clear_trav(scan); 295 } 296 first = 0; 297 fflush(stdout); 298 startbuild(&build_list, &build_tail); 299 300 if (haswork == 0 && RunningWorkers) { 301 waitbuild(RunningWorkers, 1); 302 haswork = 1; 303 } 304 } 305 pthread_mutex_unlock(&WorkerMutex); 306 307 RunStatsUpdateTop(); 308 RunStatsUpdateLogs(); 309 RunStatsSync(); 310 RunStatsDone(); 311 312 doHook(NULL, "hook_run_end", HookRunEnd, 1); 313 if (UsingHooks) { 314 while ((bulk = getbulk()) != NULL) 315 freebulk(bulk); 316 donebulk(); 317 } 318 319 t = time(NULL) - startTime; 320 h = t / 3600; 321 m = t / 60 % 60; 322 s = t % 60; 323 324 dlog(DLOG_ALL|DLOG_STDOUT, 325 "\n" 326 "Initial queue size: %d\n" 327 " packages built: %d\n" 328 " ignored: %d\n" 329 " skipped: %d\n" 330 " failed: %d\n" 331 "\n" 332 "Duration: %02d:%02d:%02d\n" 333 "\n", 334 BuildTotal, 335 BuildSuccessCount, 336 BuildIgnoreCount, 337 BuildSkipCount, 338 BuildFailCount, 339 h, m, s); 340 } 341 342 /* 343 * Traverse the packages (pkg) depends on recursively until we find 344 * a leaf to build or report as unbuildable. Calculates and assigns a 345 * dependency count. Returns all parallel-buildable packages. 346 * 347 * (pkg) itself is only added to the list if it is immediately buildable. 348 */ 349 static 350 int 351 build_find_leaves(pkg_t *parent, pkg_t *pkg, pkg_t ***build_tailp, 352 int *app, int *hasworkp, int depth, int first, 353 int first_one_only) 354 { 355 pkglink_t *link; 356 pkg_t *scan; 357 int idep_count = 0; 358 int apsub; 359 int dfirst_one_only; 360 int ndepth; 361 char *buf; 362 363 ndepth = depth + 1; 364 365 /* 366 * Already on build list, possibly in-progress, tell caller that 367 * it is not ready. 368 */ 369 ddprintf(ndepth, "sbuild_find_leaves %d %s %08x {\n", 370 depth, pkg->portdir, pkg->flags); 371 if (pkg->flags & PKGF_BUILDLIST) { 372 ddprintf(ndepth, "} (already on build list)\n"); 373 *app |= PKGF_NOTREADY; 374 return (pkg->idep_count); 375 } 376 377 /* 378 * Check dependencies 379 */ 380 PKGLIST_FOREACH(link, &pkg->idepon_list) { 381 scan = link->pkg; 382 383 if (scan == NULL) { 384 if (first_one_only) 385 break; 386 continue; 387 } 388 ddprintf(ndepth, "check %s %08x\t", scan->portdir, scan->flags); 389 390 /* 391 * If this dependency is to a DUMMY node it is a dependency 392 * only on the default flavor which is only the first node 393 * under this one, not all of them. 394 * 395 * NOTE: The depth is not being for complex dependency type 396 * tests like it is in childInstallPkgDeps_recurse(), 397 * so we don't have to hicup it like we do in that 398 * procedure. 399 */ 400 dfirst_one_only = (scan->flags & PKGF_DUMMY) ? 1 : 0; 401 402 /* 403 * When accounting for a successful build, just bump 404 * idep_count by one. scan->idep_count will heavily 405 * overlap packages that we count down multiple branches. 406 * 407 * We must still recurse through PACKAGED packages as 408 * some of their dependencies might be missing. 409 */ 410 if (scan->flags & PKGF_SUCCESS) { 411 ddprintf(0, "SUCCESS - OK\n"); 412 ++idep_count; 413 if (first_one_only) 414 break; 415 continue; 416 } 417 418 /* 419 * ERROR includes FAILURE, which is set in numerous situations 420 * including when NOBUILD state is processed. So check for 421 * NOBUILD state first. 422 * 423 * An ERROR in a sub-package causes a NOBUILD in packages 424 * that depend on it. 425 */ 426 if (scan->flags & PKGF_NOBUILD) { 427 ddprintf(0, "NOBUILD - OK " 428 "(propagate failure upward)\n"); 429 *app |= PKGF_NOBUILD_S; 430 if (first_one_only) 431 break; 432 continue; 433 } 434 if (scan->flags & PKGF_ERROR) { 435 ddprintf(0, "ERROR - OK (propagate failure upward)\n"); 436 *app |= PKGF_NOBUILD_S; 437 if (first_one_only) 438 break; 439 continue; 440 } 441 442 /* 443 * If already on build-list this dependency is not ready. 444 */ 445 if (scan->flags & PKGF_BUILDLIST) { 446 ddprintf(0, " [BUILDLIST]"); 447 *app |= PKGF_NOTREADY; 448 } 449 450 /* 451 * If not packaged this dependency is not ready for 452 * the caller. 453 */ 454 if ((scan->flags & PKGF_PACKAGED) == 0) { 455 ddprintf(0, " [NOT_PACKAGED]"); 456 *app |= PKGF_NOTREADY; 457 } 458 459 /* 460 * Reduce search complexity, if we have already processed 461 * scan in the traversal it will either already be on the 462 * build list or it will not be buildable. Either way 463 * the parent is not buildable. 464 */ 465 if (scan->flags & PKGF_BUILDTRAV) { 466 ddprintf(0, " [BUILDTRAV]\n"); 467 *app |= PKGF_NOTREADY; 468 if (first_one_only) 469 break; 470 continue; 471 } 472 473 /* 474 * Assert on dependency loop 475 */ 476 ++idep_count; 477 if (scan->flags & PKGF_BUILDLOOP) { 478 dfatal("pkg dependency loop %s -> %s", 479 parent->portdir, scan->portdir); 480 } 481 482 /* 483 * NOTE: For debug tabbing purposes we use (ndepth + 1) 484 * here (i.e. depth + 2) in our iteration. 485 */ 486 scan->flags |= PKGF_BUILDLOOP; 487 apsub = 0; 488 ddprintf(0, " SUBRECURSION {\n"); 489 idep_count += build_find_leaves(pkg, scan, build_tailp, 490 &apsub, hasworkp, 491 ndepth + 1, first, 492 dfirst_one_only); 493 scan->flags &= ~PKGF_BUILDLOOP; 494 *app |= apsub; 495 if (apsub & PKGF_NOBUILD) { 496 ddprintf(ndepth, "} (sub-nobuild)\n"); 497 } else if (apsub & PKGF_ERROR) { 498 ddprintf(ndepth, "} (sub-error)\n"); 499 } else if (apsub & PKGF_NOTREADY) { 500 ddprintf(ndepth, "} (sub-notready)\n"); 501 } else { 502 ddprintf(ndepth, "} (sub-ok)\n"); 503 } 504 if (first_one_only) 505 break; 506 } 507 pkg->idep_count = idep_count; 508 pkg->flags |= PKGF_BUILDTRAV; 509 510 /* 511 * Incorporate scan results into pkg state. 512 */ 513 if ((pkg->flags & PKGF_NOBUILD) == 0 && (*app & PKGF_NOBUILD)) { 514 *hasworkp = 1; 515 } else if ((pkg->flags & PKGF_ERROR) == 0 && (*app & PKGF_ERROR)) { 516 *hasworkp = 1; 517 } 518 pkg->flags |= *app & ~PKGF_NOTREADY; 519 520 /* 521 * Clear PACKAGED bit if sub-dependencies aren't clean 522 */ 523 if ((pkg->flags & PKGF_PACKAGED) && 524 (pkg->flags & (PKGF_NOTREADY|PKGF_ERROR|PKGF_NOBUILD))) { 525 pkg->flags &= ~PKGF_PACKAGED; 526 ddassert(pkg->pkgfile); 527 asprintf(&buf, "%s/%s", RepositoryPath, pkg->pkgfile); 528 if (remove(buf) < 0) { 529 dlog(DLOG_ALL, 530 "[XXX] %s DELETE-PACKAGE %s (failed)\n", 531 pkg->portdir, buf); 532 } else { 533 dlog(DLOG_ALL, 534 "[XXX] %s DELETE-PACKAGE %s " 535 "(due to dependencies)\n", 536 pkg->portdir, buf); 537 } 538 freestrp(&buf); 539 *hasworkp = 1; 540 } 541 542 /* 543 * Set PKGF_NOBUILD_I if there is IGNORE data 544 */ 545 if (pkg->ignore) 546 pkg->flags |= PKGF_NOBUILD_I; 547 548 /* 549 * Handle propagated flags 550 */ 551 if (pkg->flags & PKGF_ERROR) { 552 /* 553 * This can only happen if the ERROR has already been 554 * processed and accounted for. 555 */ 556 ddprintf(depth, "} (ERROR - %s)\n", pkg->portdir); 557 } else if (*app & PKGF_NOTREADY) { 558 /* 559 * We don't set PKGF_NOTREADY in the pkg, it is strictly 560 * a transient flag propagated via build_find_leaves(). 561 * 562 * Just don't add the package to the list. 563 * 564 * NOTE: Even if NOBUILD is set (meaning we could list it 565 * and let startbuild() finish it up as a skip, we 566 * don't process it to the list because we want to 567 * process all the dependencies, so someone doing a 568 * manual build can get more complete information and 569 * does not have to iterate each failed dependency one 570 * at a time. 571 */ 572 ; 573 } else if (pkg->flags & PKGF_SUCCESS) { 574 ddprintf(depth, "} (SUCCESS - %s)\n", pkg->portdir); 575 } else if (pkg->flags & PKGF_DUMMY) { 576 /* 577 * Just mark dummy packages as successful when all of their 578 * sub-depends (flavors) complete successfully. Note that 579 * dummy packages are not counted in the total, so do not 580 * decrement BuildTotal. 581 */ 582 ddprintf(depth, "} (DUMMY/META - SUCCESS)\n"); 583 pkg->flags |= PKGF_SUCCESS; 584 *hasworkp = 1; 585 if (first) { 586 dlog(DLOG_ALL | DLOG_FILTER, 587 "[XXX] %s META-ALREADY-BUILT\n", 588 pkg->portdir); 589 } else { 590 dlog(DLOG_SUCC, "[XXX] %s meta-node complete\n", 591 pkg->portdir); 592 } 593 } else if (pkg->flags & PKGF_PACKAGED) { 594 /* 595 * We can just mark the pkg successful. If this is 596 * the first pass, we count this as an initial pruning 597 * pass and reduce BuildTotal. 598 */ 599 ddprintf(depth, "} (PACKAGED - SUCCESS)\n"); 600 pkg->flags |= PKGF_SUCCESS; 601 *hasworkp = 1; 602 if (first) { 603 dlog(DLOG_ALL | DLOG_FILTER, 604 "[XXX] %s ALREADY-BUILT\n", 605 pkg->portdir); 606 --BuildTotal; 607 } 608 } else { 609 /* 610 * All dependencies are successful, queue new work 611 * and indicate not-ready to the parent (since our 612 * package has to be built). 613 * 614 * NOTE: The NOBUILD case propagates to here as well 615 * and is ultimately handled by startbuild(). 616 */ 617 *hasworkp = 1; 618 if (pkg->flags & PKGF_NOBUILD_I) 619 ddprintf(depth, "} (ADDLIST(IGNORE/BROKEN) - %s)\n", 620 pkg->portdir); 621 else if (pkg->flags & PKGF_NOBUILD) 622 ddprintf(depth, "} (ADDLIST(NOBUILD) - %s)\n", 623 pkg->portdir); 624 else 625 ddprintf(depth, "} (ADDLIST - %s)\n", pkg->portdir); 626 pkg->flags |= PKGF_BUILDLIST; 627 **build_tailp = pkg; 628 *build_tailp = &pkg->build_next; 629 *app |= PKGF_NOTREADY; 630 } 631 632 return idep_count; 633 } 634 635 static 636 void 637 build_clear_trav(pkg_t *pkg) 638 { 639 pkglink_t *link; 640 pkg_t *scan; 641 642 pkg->flags &= ~PKGF_BUILDTRAV; 643 PKGLIST_FOREACH(link, &pkg->idepon_list) { 644 scan = link->pkg; 645 if (scan && (scan->flags & PKGF_BUILDTRAV)) 646 build_clear_trav(scan); 647 } 648 } 649 650 /* 651 * Calculate the longest chain of packages that depend on me. The 652 * long the chain, the more important my package is to build earlier 653 * rather than later. 654 */ 655 static int 656 buildCalculateDepiDepth(pkg_t *pkg) 657 { 658 pkglink_t *link; 659 pkg_t *scan; 660 int best_depth = 0; 661 int res; 662 663 if (pkg->depi_depth) 664 return(pkg->depi_depth + 1); 665 pkg->flags |= PKGF_BUILDLOOP; 666 PKGLIST_FOREACH(link, &pkg->deponi_list) { 667 scan = link->pkg; 668 if (scan && (scan->flags & PKGF_BUILDLOOP) == 0) { 669 res = buildCalculateDepiDepth(scan); 670 if (best_depth < res) 671 best_depth = res; 672 } 673 } 674 pkg->flags &= ~PKGF_BUILDLOOP; 675 pkg->depi_depth = best_depth; 676 677 return (best_depth + 1); 678 } 679 680 /* 681 * Take a list of pkg ready to go, sort it, and assign it to worker 682 * slots. This routine blocks in waitbuild() until it can dispose of 683 * the entire list. 684 * 685 * WorkerMutex is held by the caller. 686 */ 687 static 688 void 689 startbuild(pkg_t **build_listp, pkg_t ***build_tailp) 690 { 691 pkg_t *pkg; 692 pkg_t **idep_ary; 693 pkg_t **depi_ary; 694 int count; 695 int idep_index; 696 int depi_index; 697 int i; 698 int n; 699 worker_t *work; 700 static int IterateWorker; 701 702 /* 703 * Nothing to do 704 */ 705 if (*build_listp == NULL) 706 return; 707 708 /* 709 * Sort 710 */ 711 count = 0; 712 for (pkg = *build_listp; pkg; pkg = pkg->build_next) 713 ++count; 714 idep_ary = calloc(count, sizeof(pkg_t *)); 715 depi_ary = calloc(count, sizeof(pkg_t *)); 716 717 count = 0; 718 for (pkg = *build_listp; pkg; pkg = pkg->build_next) { 719 idep_ary[count] = pkg; 720 depi_ary[count] = pkg; 721 ++count; 722 } 723 724 /* 725 * idep_ary - sorted by #of dependencies this pkg has. 726 * depi_ary - sorted by #of other packages that depend on this pkg. 727 */ 728 qsort(idep_ary, count, sizeof(pkg_t *), qsort_idep); 729 qsort(depi_ary, count, sizeof(pkg_t *), qsort_depi); 730 731 idep_index = 0; 732 depi_index = 0; 733 734 /* 735 * Half the workers build based on the highest depi count, 736 * the other half build based on the highest idep count. 737 * 738 * This is an attempt to get projects which many other projects 739 * depend on built first, but to also try to build large projects 740 * (which tend to have a lot of dependencies) earlier rather than 741 * later so the end of the bulk run doesn't inefficiently build 742 * the last few huge projects. 743 * 744 * Loop until we manage to assign slots to everyone. We do not 745 * wait for build completion. 746 * 747 * This is the point where we handle DUMMY packages (these are 748 * dummy unflavored packages which 'cover' all the flavors for 749 * a package). These are not real packages are marked SUCCESS 750 * at this time because their dependencies (the flavors) have all 751 * been built. 752 */ 753 while (idep_index != count || depi_index != count) { 754 pkg_t *pkgi; 755 pkg_t *ipkg; 756 757 /* 758 * Find candidate to start sorted by depi or idep. 759 */ 760 ipkg = NULL; 761 while (idep_index < count) { 762 ipkg = idep_ary[idep_index]; 763 if ((ipkg->flags & 764 (PKGF_SUCCESS | PKGF_FAILURE | 765 PKGF_ERROR | PKGF_RUNNING)) == 0) { 766 break; 767 } 768 ipkg = NULL; 769 ++idep_index; 770 } 771 772 pkgi = NULL; 773 while (depi_index < count) { 774 pkgi = depi_ary[depi_index]; 775 if ((pkgi->flags & 776 (PKGF_SUCCESS | PKGF_FAILURE | 777 PKGF_ERROR | PKGF_RUNNING)) == 0) { 778 break; 779 } 780 pkgi = NULL; 781 ++depi_index; 782 } 783 784 /* 785 * ipkg and pkgi must either both be NULL, or both 786 * be non-NULL. 787 */ 788 if (ipkg == NULL && pkgi == NULL) 789 break; 790 ddassert(ipkg && pkgi); 791 792 /* 793 * Handle the NOBUILD case right here, there's no point 794 * queueing it anywhere. 795 */ 796 if (ipkg->flags & PKGF_NOBUILD) { 797 char *reason; 798 799 ipkg->flags |= PKGF_FAILURE; 800 ipkg->flags &= ~PKGF_BUILDLIST; 801 802 reason = buildskipreason(NULL, ipkg); 803 if (ipkg->flags & PKGF_NOBUILD_I) { 804 ++BuildIgnoreCount; 805 dlog(DLOG_IGN, "[XXX] %s ignored due to %s\n", 806 ipkg->portdir, reason); 807 doHook(ipkg, "hook_pkg_ignored", 808 HookPkgIgnored, 0); 809 } else { 810 ++BuildSkipCount; 811 dlog(DLOG_SKIP, "[XXX] %s skipped due to %s\n", 812 ipkg->portdir, reason); 813 doHook(ipkg, "hook_pkg_skipped", 814 HookPkgSkipped, 0); 815 } 816 free(reason); 817 ++BuildCount; 818 continue; 819 } 820 if (pkgi->flags & PKGF_NOBUILD) { 821 char *reason; 822 823 pkgi->flags |= PKGF_FAILURE; 824 pkgi->flags &= ~PKGF_BUILDLIST; 825 826 reason = buildskipreason(NULL, pkgi); 827 if (pkgi->flags & PKGF_NOBUILD_I) { 828 ++BuildIgnoreCount; 829 dlog(DLOG_IGN, "[XXX] %s ignored due to %s\n", 830 pkgi->portdir, reason); 831 doHook(pkgi, "hook_pkg_ignored", 832 HookPkgIgnored, 0); 833 } else { 834 ++BuildSkipCount; 835 dlog(DLOG_SKIP, "[XXX] %s skipped due to %s\n", 836 pkgi->portdir, reason); 837 doHook(pkgi, "hook_pkg_skipped", 838 HookPkgSkipped, 0); 839 } 840 free(reason); 841 ++BuildCount; 842 continue; 843 } 844 845 /* 846 * Block while no slots are available. waitbuild() 847 * will clean out any DONE states. 848 */ 849 while (RunningWorkers >= DynamicMaxWorkers || 850 RunningWorkers >= MaxWorkers - FailedWorkers) { 851 waitbuild(RunningWorkers, 1); 852 } 853 854 /* 855 * Find an available worker slot, there should be at 856 * least one. 857 */ 858 for (i = 0; i < MaxWorkers; ++i) { 859 n = IterateWorker % MaxWorkers; 860 work = &WorkerAry[n]; 861 862 if (work->state == WORKER_DONE || 863 work->state == WORKER_FAILED) { 864 workercomplete(work); 865 } 866 if (work->state == WORKER_NONE || 867 work->state == WORKER_IDLE) { 868 if (n <= MaxWorkers / 2) { 869 startworker(pkgi, work); 870 } else { 871 startworker(ipkg, work); 872 } 873 /*RunStatsUpdate(work);*/ 874 break; 875 } 876 ++IterateWorker; 877 } 878 ddassert(i != MaxWorkers); 879 } 880 RunStatsSync(); 881 882 /* 883 * We disposed of the whole list 884 */ 885 free(idep_ary); 886 free(depi_ary); 887 *build_listp = NULL; 888 *build_tailp = build_listp; 889 } 890 891 typedef const pkg_t *pkg_tt; 892 893 static int 894 qsort_idep(const void *pkg1_arg, const void *pkg2_arg) 895 { 896 const pkg_t *pkg1 = *(const pkg_tt *)pkg1_arg; 897 const pkg_t *pkg2 = *(const pkg_tt *)pkg2_arg; 898 899 return (pkg2->idep_count - pkg1->idep_count); 900 } 901 902 static int 903 qsort_depi(const void *pkg1_arg, const void *pkg2_arg) 904 { 905 const pkg_t *pkg1 = *(const pkg_tt *)pkg1_arg; 906 const pkg_t *pkg2 = *(const pkg_tt *)pkg2_arg; 907 908 return ((pkg2->depi_count * pkg2->depi_depth) - 909 (pkg1->depi_count * pkg1->depi_depth)); 910 } 911 912 /* 913 * Frontend starts a pkg up on a worker 914 * 915 * WorkerMutex must be held. 916 */ 917 static void 918 startworker(pkg_t *pkg, worker_t *work) 919 { 920 switch(work->state) { 921 case WORKER_NONE: 922 pthread_create(&work->td, NULL, childBuilderThread, work); 923 work->state = WORKER_IDLE; 924 /* fall through */ 925 case WORKER_IDLE: 926 work->pkg_dep_size = 927 childInstallPkgDeps_recurse(NULL, &pkg->idepon_list, 0, 1, 0); 928 childInstallPkgDeps_recurse(NULL, &pkg->idepon_list, 1, 1, 0); 929 RunningPkgDepSize += work->pkg_dep_size; 930 931 dlog(DLOG_ALL, "[%03d] START %s " 932 "##idep=%02d depi=%02d/%02d dep=%-4.2fG\n", 933 work->index, pkg->portdir, 934 pkg->idep_count, pkg->depi_count, pkg->depi_depth, 935 (double)work->pkg_dep_size / (double)ONEGB); 936 937 cleanworker(work); 938 pkg->flags |= PKGF_RUNNING; 939 work->pkg = pkg; 940 pthread_cond_signal(&work->cond); 941 ++RunningWorkers; 942 /*RunStatsUpdate(work);*/ 943 break; 944 case WORKER_PENDING: 945 case WORKER_RUNNING: 946 case WORKER_DONE: 947 case WORKER_FAILED: 948 case WORKER_FROZEN: 949 case WORKER_EXITING: 950 default: 951 dfatal("startworker: [%03d] Unexpected state %d for worker %d", 952 work->index, work->state, work->index); 953 break; 954 } 955 } 956 957 static void 958 cleanworker(worker_t *work) 959 { 960 work->state = WORKER_PENDING; 961 work->flags = 0; 962 work->accum_error = 0; 963 work->start_time = time(NULL); 964 } 965 966 /* 967 * Frontend finishes up a completed pkg on a worker. 968 * 969 * If the worker is in a FAILED state we clean the pkg out but (for now) 970 * leave it in its failed state so we can debug. At this point 971 * workercomplete() will be called every once in a while on the state 972 * and we have to deal with the NULL pkg. 973 * 974 * WorkerMutex must be held. 975 */ 976 static void 977 workercomplete(worker_t *work) 978 { 979 pkg_t *pkg; 980 time_t t; 981 int h; 982 int m; 983 int s; 984 985 /* 986 * Steady state FAILED case. 987 */ 988 if (work->state == WORKER_FAILED) { 989 if (work->pkg == NULL) 990 return; 991 } 992 993 t = time(NULL) - work->start_time; 994 h = t / 3600; 995 m = t / 60 % 60; 996 s = t % 60; 997 998 /* 999 * Reduce total dep size 1000 */ 1001 RunningPkgDepSize -= work->pkg_dep_size; 1002 RunningPkgDepSize -= work->memuse; 1003 work->pkg_dep_size = 0; 1004 work->memuse = 0; 1005 1006 /* 1007 * Process pkg out of the worker 1008 */ 1009 pkg = work->pkg; 1010 if (pkg->flags & (PKGF_ERROR|PKGF_NOBUILD)) { 1011 pkg->flags |= PKGF_FAILURE; 1012 1013 /* 1014 * This NOBUILD condition XXX can occur if the package is 1015 * not allowed to be built. 1016 */ 1017 if (pkg->flags & PKGF_NOBUILD) { 1018 char *reason; 1019 1020 reason = buildskipreason(NULL, pkg); 1021 if (pkg->flags & PKGF_NOBUILD_I) { 1022 ++BuildIgnoreCount; 1023 dlog(DLOG_SKIP, "[%03d] IGNORD %s - %s\n", 1024 work->index, pkg->portdir, reason); 1025 doHook(pkg, "hook_pkg_ignored", 1026 HookPkgIgnored, 0); 1027 } else { 1028 ++BuildSkipCount; 1029 dlog(DLOG_SKIP, "[%03d] SKIPPD %s - %s\n", 1030 work->index, pkg->portdir, reason); 1031 doHook(pkg, "hook_pkg_skipped", 1032 HookPkgSkipped, 0); 1033 } 1034 free(reason); 1035 } else { 1036 char skipbuf[16]; 1037 int scount; 1038 1039 scount = buildskipcount_dueto(pkg, 1); 1040 buildskipcount_dueto(pkg, 0); 1041 if (scount) 1042 snprintf(skipbuf, sizeof(skipbuf), " (%d)", scount); 1043 else 1044 skipbuf[0] = 0; 1045 1046 ++BuildFailCount; 1047 dlog(DLOG_FAIL | DLOG_RED, 1048 "[%03d] FAILURE %s%s ##%16.16s %02d:%02d:%02d\n", 1049 work->index, pkg->portdir, skipbuf, 1050 getphasestr(work->phase), 1051 h, m, s); 1052 doHook(pkg, "hook_pkg_failure", HookPkgFailure, 0); 1053 } 1054 } else { 1055 pkg->flags |= PKGF_SUCCESS; 1056 ++BuildSuccessCount; 1057 dlog(DLOG_SUCC | DLOG_GRN, 1058 "[%03d] SUCCESS %s ##%02d:%02d:%02d\n", 1059 work->index, pkg->portdir, h, m, s); 1060 doHook(pkg, "hook_pkg_success", HookPkgSuccess, 0); 1061 } 1062 ++BuildCount; 1063 pkg->flags &= ~PKGF_BUILDLIST; 1064 pkg->flags &= ~PKGF_RUNNING; 1065 work->pkg = NULL; 1066 --RunningWorkers; 1067 1068 if (work->state == WORKER_FAILED) { 1069 dlog(DLOG_ALL, "[%03d] XXX/XXX WORKER IS IN A FAILED STATE\n", 1070 work->index); 1071 ++FailedWorkers; 1072 } else if (work->flags & WORKERF_FREEZE) { 1073 dlog(DLOG_ALL, "[%03d] FROZEN(DEBUG) %s\n", 1074 work->index, pkg->portdir); 1075 work->state = WORKER_FROZEN; 1076 } else { 1077 work->state = WORKER_IDLE; 1078 } 1079 } 1080 1081 /* 1082 * Wait for one or more workers to complete. 1083 * 1084 * WorkerMutex must be held. 1085 */ 1086 static void 1087 waitbuild(int whilematch, int dynamicmax) 1088 { 1089 static time_t wblast_time; 1090 static time_t dmlast_time; 1091 struct timespec ts; 1092 worker_t *work; 1093 time_t t; 1094 int i; 1095 1096 if (whilematch == 0) 1097 whilematch = 1; 1098 1099 while (RunningWorkers == whilematch) { 1100 for (i = 0; i < MaxWorkers; ++i) { 1101 work = &WorkerAry[i]; 1102 if (work->state == WORKER_DONE || 1103 work->state == WORKER_FAILED) { 1104 workercomplete(work); 1105 } else { 1106 pthread_cond_signal(&work->cond); 1107 } 1108 RunStatsUpdate(work, NULL); 1109 } 1110 RunStatsUpdateTop(); 1111 RunStatsUpdateLogs(); 1112 RunStatsSync(); 1113 if (RunningWorkers == whilematch) { 1114 clock_gettime(CLOCK_REALTIME, &ts); 1115 ts.tv_sec += 1; 1116 ts.tv_nsec = 0; 1117 pthread_cond_timedwait(&WorkerCond, &WorkerMutex, &ts); 1118 } 1119 1120 /* 1121 * Dynamically reduce MaxWorkers based on the load. When 1122 * the load exceeds 2 x ncpus we reduce the number of workers 1123 * up to 75% of MaxWorkers @ (5 x ncpus) load. 1124 * 1125 * Dynamically reduce MaxWorkers based on swap use, starting 1126 * at 10% swap and up to 75% of MaxWorkers at 40% swap. 1127 * 1128 * NOTE! Generally speaking this allows more workers to be 1129 * configured which helps in two ways. First it allows 1130 * a higher build rate for smaller packages. Second 1131 * it allows dsynth to ratchet-down the number of slots 1132 * when large packages are forcing the load up. 1133 * 1134 * A high load doesn't hurt efficiency, but swap usage 1135 * due to loading the tmpfs in lots of worker slots up 1136 * with tons of pkg install's (pre-reqs for a build) 1137 * does. Reducing the number of worker slots has a 1138 * huge beneficial effect on reducing swap use / paging. 1139 */ 1140 t = time(NULL); 1141 if (dynamicmax && (wblast_time == 0 || 1142 (unsigned)(t - wblast_time) >= 5)) { 1143 double min_load = 1.5 * NumCores; 1144 double max_load = 5.0 * NumCores; 1145 double min_swap = 0.10; 1146 double max_swap = 0.40; 1147 double dload[3]; 1148 double dswap; 1149 int max1; 1150 int max2; 1151 int max3; 1152 int max_sel; 1153 int noswap; 1154 1155 wblast_time = t; 1156 1157 /* 1158 * Cap based on load. This is back-loaded. 1159 */ 1160 getloadavg(dload, 3); 1161 if (dload[0] < min_load) { 1162 max1 = MaxWorkers; 1163 } else if (dload[0] <= max_load) { 1164 max1 = MaxWorkers - 1165 MaxWorkers * 0.75 * 1166 (dload[0] - min_load) / 1167 (max_load - min_load); 1168 } else { 1169 max1 = MaxWorkers * 25 / 100; 1170 } 1171 1172 /* 1173 * Cap based on swap use. This is back-loaded. 1174 */ 1175 dswap = getswappct(&noswap); 1176 if (dswap < min_swap) { 1177 max2 = MaxWorkers; 1178 } else if (dswap <= max_swap) { 1179 max2 = MaxWorkers - 1180 MaxWorkers * 0.75 * 1181 (dswap - min_swap) / 1182 (max_swap - min_swap); 1183 } else { 1184 max2 = MaxWorkers * 25 / 100; 1185 } 1186 1187 /* 1188 * Cap based on aggregate pkg-dependency memory 1189 * use installed in worker slots. This is 1190 * front-loaded. 1191 * 1192 * Since it can take a while for workers to retire 1193 * (to reduce RunningPkgDepSize), just set our 1194 * target 1 below the current run count to allow 1195 * jobs to retire without being replaced with new 1196 * jobs. 1197 * 1198 * In addition, in order to avoid a paging 'shock', 1199 * We enforce a 30 second-per-increment slow-start 1200 * once RunningPkgDepSize exceeds 1/2 the target. 1201 */ 1202 if (RunningPkgDepSize > PkgDepMemoryTarget) { 1203 max3 = RunningWorkers - 1; 1204 } else if (RunningPkgDepSize > PkgDepMemoryTarget / 2) { 1205 if (dmlast_time == 0 || 1206 (unsigned)(t - dmlast_time) >= 30) { 1207 dmlast_time = t; 1208 max3 = RunningWorkers + 1; 1209 } else { 1210 max3 = RunningWorkers; 1211 } 1212 } else { 1213 max3 = MaxWorkers; 1214 } 1215 1216 /* 1217 * Priority reduction, convert to DynamicMaxWorkers 1218 */ 1219 max_sel = max1; 1220 if (max_sel > max2) 1221 max_sel = max2; 1222 if (max_sel > max3) 1223 max_sel = max3; 1224 1225 /* 1226 * Restrict to allowed range, and also handle 1227 * slow-start. 1228 */ 1229 if (max_sel < 1) 1230 max_sel = 1; 1231 if (max_sel > DynamicMaxWorkers + 1) 1232 max_sel = DynamicMaxWorkers + 1; 1233 if (max_sel > MaxWorkers) 1234 max_sel = MaxWorkers; 1235 1236 /* 1237 * Stop waiting if DynamicMaxWorkers is going to 1238 * increase. 1239 */ 1240 if (DynamicMaxWorkers < max1) 1241 whilematch = -1; 1242 1243 /* 1244 * And adjust 1245 */ 1246 if (DynamicMaxWorkers != max1) { 1247 dlog(DLOG_ALL | DLOG_FILTER, 1248 "[XXX] Load=%-6.2f(%2d) " 1249 "Swap=%-3.2f%%(%2d) " 1250 "Mem=%3.2fG(%2d) " 1251 "Adjust Workers %d->%d\n", 1252 dload[0], max1, 1253 dswap * 100.0, max2, 1254 RunningPkgDepSize / (double)ONEGB, max3, 1255 DynamicMaxWorkers, max_sel); 1256 DynamicMaxWorkers = max_sel; 1257 } 1258 } 1259 } 1260 } 1261 1262 1263 /* 1264 * Worker pthread (WorkerAry) 1265 * 1266 * This thread belongs to the dsynth master process and handled a worker slot. 1267 * (this_thread) -> WORKER fork/exec (WorkerPocess) -> (pty) -> sub-processes. 1268 */ 1269 static void * 1270 childBuilderThread(void *arg) 1271 { 1272 char *envary[1] = { NULL }; 1273 worker_t *work = arg; 1274 wmsg_t wmsg; 1275 pkg_t *pkg; 1276 pid_t pid; 1277 int status; 1278 int flags; 1279 volatile int dowait; 1280 char slotbuf[8]; 1281 char fdbuf[8]; 1282 char flagsbuf[16]; 1283 1284 pthread_mutex_lock(&WorkerMutex); 1285 while (work->terminate == 0) { 1286 dowait = 1; 1287 1288 switch(work->state) { 1289 case WORKER_IDLE: 1290 break; 1291 case WORKER_PENDING: 1292 /* 1293 * Fork the management process for the pkg operation 1294 * on this worker slot. 1295 * 1296 * This process will set up the environment, do the 1297 * mounts, will become the reaper, and will process 1298 * pipe commands and handle chroot operations. 1299 * 1300 * NOTE: If SOCK_CLOEXEC is not supported WorkerMutex 1301 * is sufficient to interlock F_SETFD FD_CLOEXEC 1302 * operations. 1303 */ 1304 ddassert(work->pkg); 1305 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 1306 PF_UNSPEC, work->fds)) { 1307 dfatal_errno("socketpair() during worker fork"); 1308 } 1309 snprintf(slotbuf, sizeof(slotbuf), "%d", work->index); 1310 snprintf(fdbuf, sizeof(fdbuf), "3"); 1311 1312 /* 1313 * Pass global flags and add-in the DEBUGSTOP if 1314 * the package is flagged for debugging. 1315 */ 1316 flags = WorkerProcFlags; 1317 if (work->pkg->flags & PKGF_DEBUGSTOP) { 1318 flags |= WORKER_PROC_DEBUGSTOP; 1319 } else { 1320 flags &= ~WORKER_PROC_DEBUGSTOP; 1321 } 1322 snprintf(flagsbuf, sizeof(flagsbuf), "%d", flags); 1323 1324 /* 1325 * fds[0] - master 1326 * fds[1] - slave 1327 * 1328 * We pass the salve descriptor in fd 3 and close all 1329 * other descriptors for security. 1330 */ 1331 pthread_mutex_unlock(&WorkerMutex); 1332 pid = vfork(); 1333 if (pid == 0) { 1334 close(work->fds[0]); 1335 dup2(work->fds[1], 3); 1336 closefrom(4); 1337 fcntl(3, F_SETFD, 0); 1338 execle(DSynthExecPath, DSynthExecPath, 1339 "WORKER", slotbuf, fdbuf, 1340 work->pkg->portdir, work->pkg->pkgfile, 1341 flagsbuf, 1342 NULL, envary); 1343 write(2, "EXECLE FAILURE\n", 15); 1344 _exit(1); 1345 } 1346 pthread_mutex_lock(&WorkerMutex); 1347 close(work->fds[1]); 1348 work->phase = PHASE_PENDING; 1349 work->lines = 0; 1350 work->memuse = 0; 1351 work->pid = pid; 1352 work->state = WORKER_RUNNING; 1353 /* fall through */ 1354 case WORKER_RUNNING: 1355 /* 1356 * Poll for status updates, if NULL is returned 1357 * and status is non-zero, the communications link 1358 * failed unexpectedly. 1359 */ 1360 pkg = work->pkg; 1361 pthread_mutex_unlock(&WorkerMutex); 1362 status = ipcreadmsg(work->fds[0], &wmsg); 1363 pthread_mutex_lock(&WorkerMutex); 1364 1365 if (status == 0) { 1366 /* 1367 * Normal message, can include normal 1368 * termination which changes us over 1369 * to another state. 1370 */ 1371 dowait = 0; 1372 switch(wmsg.cmd) { 1373 case WMSG_CMD_INSTALL_PKGS: 1374 wmsg.cmd = WMSG_RES_INSTALL_PKGS; 1375 wmsg.status = childInstallPkgDeps(work); 1376 pthread_mutex_unlock(&WorkerMutex); 1377 ipcwritemsg(work->fds[0], &wmsg); 1378 pthread_mutex_lock(&WorkerMutex); 1379 break; 1380 case WMSG_CMD_STATUS_UPDATE: 1381 work->phase = wmsg.phase; 1382 work->lines = wmsg.lines; 1383 if (work->memuse != wmsg.memuse) { 1384 RunningPkgDepSize += 1385 wmsg.memuse - work->memuse; 1386 work->memuse = wmsg.memuse; 1387 } 1388 break; 1389 case WMSG_CMD_SUCCESS: 1390 work->flags |= WORKERF_SUCCESS; 1391 break; 1392 case WMSG_CMD_FAILURE: 1393 work->flags |= WORKERF_FAILURE; 1394 break; 1395 case WMSG_CMD_FREEZEWORKER: 1396 work->flags |= WORKERF_FREEZE; 1397 break; 1398 default: 1399 break; 1400 } 1401 RunStatsUpdate(work, NULL); 1402 RunStatsSync(); 1403 } else { 1404 close(work->fds[0]); 1405 pthread_mutex_unlock(&WorkerMutex); 1406 while (waitpid(work->pid, &status, 0) < 0 && 1407 errno == EINTR) { 1408 ; 1409 } 1410 pthread_mutex_lock(&WorkerMutex); 1411 1412 if (work->flags & WORKERF_SUCCESS) { 1413 pkg->flags |= PKGF_SUCCESS; 1414 work->state = WORKER_DONE; 1415 } else if (work->flags & WORKERF_FAILURE) { 1416 pkg->flags |= PKGF_FAILURE; 1417 work->state = WORKER_DONE; 1418 } else { 1419 pkg->flags |= PKGF_FAILURE; 1420 work->state = WORKER_FAILED; 1421 } 1422 work->flags |= WORKERF_STATUS_UPDATE; 1423 pthread_cond_signal(&WorkerCond); 1424 } 1425 break; 1426 case WORKER_DONE: 1427 /* 1428 * pkg remains attached until frontend processes the 1429 * completion. The frontend will then set the state 1430 * back to idle. 1431 */ 1432 break; 1433 case WORKER_FAILED: 1434 /* 1435 * A worker failure means that the worker did not 1436 * send us a WMSG_CMD_SUCCESS or WMSG_CMD_FAILURE 1437 * ipc before terminating. 1438 * 1439 * We just sit in this state until the front-end 1440 * does something about it. 1441 */ 1442 break; 1443 case WORKER_FROZEN: 1444 /* 1445 * A worker getting frozen is debug-related. We 1446 * just sit in this state (likely forever). 1447 */ 1448 break; 1449 default: 1450 dfatal("worker: [%03d] Unexpected state %d " 1451 "for worker %d", 1452 work->index, work->state, work->index); 1453 /* NOT REACHED */ 1454 break; 1455 } 1456 1457 /* 1458 * The dsynth frontend will poll us approximately once 1459 * a second (its variable). 1460 */ 1461 if (dowait) 1462 pthread_cond_wait(&work->cond, &WorkerMutex); 1463 } 1464 1465 /* 1466 * Scrap the comm socket if running, this should cause the worker 1467 * process to kill its sub-programs and cleanup. 1468 */ 1469 if (work->state == WORKER_RUNNING) { 1470 pthread_mutex_unlock(&WorkerMutex); 1471 close(work->fds[0]); 1472 while (waitpid(work->pid, &status, 0) < 0 && 1473 errno == EINTR); 1474 pthread_mutex_lock(&WorkerMutex); 1475 } 1476 1477 /* 1478 * Final handshake 1479 */ 1480 work->state = WORKER_EXITING; 1481 pthread_cond_signal(&WorkerCond); 1482 pthread_mutex_unlock(&WorkerMutex); 1483 1484 return NULL; 1485 } 1486 1487 /* 1488 * Install all the binary packages (we have already built them) that 1489 * the current work package depends on, without duplicates, in a script 1490 * which will be run from within the specified work jail. 1491 * 1492 * Locked by WorkerMutex (global) 1493 */ 1494 static int 1495 childInstallPkgDeps(worker_t *work) 1496 { 1497 char *buf; 1498 FILE *fp; 1499 1500 if (PKGLIST_EMPTY(&work->pkg->idepon_list)) 1501 return 0; 1502 1503 asprintf(&buf, "%s/tmp/dsynth_install_pkgs", work->basedir); 1504 fp = fopen(buf, "w"); 1505 ddassert(fp != NULL); 1506 fprintf(fp, "#!/bin/sh\n"); 1507 fprintf(fp, "#\n"); 1508 fchmod(fileno(fp), 0755); 1509 1510 childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 0, 1, 0); 1511 childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 1, 1, 0); 1512 fprintf(fp, "\nexit 0\n"); 1513 fclose(fp); 1514 freestrp(&buf); 1515 1516 return 1; 1517 } 1518 1519 static size_t 1520 childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list, int undoit, 1521 int depth, int first_one_only) 1522 { 1523 pkglink_t *link; 1524 pkg_t *pkg; 1525 size_t tot = 0; 1526 int ndepth; 1527 int nfirst; 1528 1529 PKGLIST_FOREACH(link, list) { 1530 pkg = link->pkg; 1531 1532 /* 1533 * We don't want to mess up our depth test just below if 1534 * a DUMMY node had to be inserted. The nodes under the 1535 * dummy node. 1536 * 1537 * The elements under a dummy node represent all the flabor, 1538 * a dependency that directly references a dummy node only 1539 * uses the first flavor (first_one_only / nfirst). 1540 */ 1541 ndepth = (pkg->flags & PKGF_DUMMY) ? depth : depth + 1; 1542 nfirst = (pkg->flags & PKGF_DUMMY) ? 1 : 0; 1543 1544 /* 1545 * We only need all packages for the top-level dependencies. 1546 * The deeper ones only need DEP_TYPE_LIB and DEP_TYPE_RUN 1547 * (types greater than DEP_TYPE_BUILD) since they are already 1548 * built. 1549 */ 1550 if (depth > 1 && link->dep_type <= DEP_TYPE_BUILD) { 1551 if (first_one_only) 1552 break; 1553 continue; 1554 } 1555 1556 if (undoit) { 1557 if (pkg->dsynth_install_flg == 1) { 1558 pkg->dsynth_install_flg = 0; 1559 tot += childInstallPkgDeps_recurse(fp, 1560 &pkg->idepon_list, 1561 undoit, 1562 ndepth, nfirst); 1563 } 1564 if (first_one_only) 1565 break; 1566 continue; 1567 } 1568 if (pkg->dsynth_install_flg) { 1569 if (DebugOpt >= 2 && pkg->pkgfile && fp) { 1570 fprintf(fp, "echo 'AlreadyHave %s'\n", 1571 pkg->pkgfile); 1572 } 1573 if (first_one_only) 1574 break; 1575 continue; 1576 } 1577 1578 tot += childInstallPkgDeps_recurse(fp, &pkg->idepon_list, 1579 undoit, ndepth, nfirst); 1580 if (pkg->dsynth_install_flg) { 1581 if (first_one_only) 1582 break; 1583 continue; 1584 } 1585 pkg->dsynth_install_flg = 1; 1586 1587 /* 1588 * If this is a dummy node with no package, the originator 1589 * is requesting a flavored package. We select the default 1590 * flavor which we presume is the first one. 1591 */ 1592 if (pkg->pkgfile == NULL && (pkg->flags & PKGF_DUMMY)) { 1593 pkg_t *spkg = pkg->idepon_list.next->pkg; 1594 1595 if (spkg) { 1596 pkg = spkg; 1597 if (fp) { 1598 fprintf(fp, 1599 "echo 'DUMMY use %s (%p)'\n", 1600 pkg->portdir, pkg->pkgfile); 1601 } 1602 } else { 1603 if (fp) { 1604 fprintf(fp, 1605 "echo 'CANNOT FIND DEFAULT " 1606 "FLAVOR FOR %s'\n", 1607 pkg->portdir); 1608 } 1609 } 1610 } 1611 1612 /* 1613 * Generate package installation command 1614 */ 1615 if (fp && pkg->pkgfile) { 1616 fprintf(fp, "echo 'Installing /packages/All/%s'\n", 1617 pkg->pkgfile); 1618 fprintf(fp, "pkg install -q -y /packages/All/%s " 1619 "|| exit 1\n", 1620 pkg->pkgfile); 1621 } else if (fp) { 1622 fprintf(fp, "echo 'CANNOT FIND PKG FOR %s'\n", 1623 pkg->portdir); 1624 } 1625 1626 if (pkg->pkgfile) { 1627 struct stat st; 1628 char *path; 1629 char *ptr; 1630 1631 asprintf(&path, "%s/%s", RepositoryPath, pkg->pkgfile); 1632 ptr = strrchr(pkg->pkgfile, '.'); 1633 if (stat(path, &st) == 0) { 1634 if (strcmp(ptr, ".tar") == 0) 1635 tot += st.st_size; 1636 else if (strcmp(ptr, ".tgz") == 0) 1637 tot += st.st_size * 3; 1638 else if (strcmp(ptr, ".txz") == 0) 1639 tot += st.st_size * 5; 1640 else if (strcmp(ptr, ".tbz") == 0) 1641 tot += st.st_size * 3; 1642 else 1643 tot += st.st_size * 2; 1644 } 1645 free(path); 1646 } 1647 if (first_one_only) 1648 break; 1649 } 1650 return tot; 1651 } 1652 1653 /* 1654 * Worker process interactions. 1655 * 1656 * The worker process is responsible for managing the build of a single 1657 * package. It is exec'd by the master dsynth and only loads the 1658 * configuration. 1659 * 1660 * This process does not run in the chroot. It will become the reaper for 1661 * all sub-processes and it will enter the chroot to execute various phases. 1662 * It catches SIGINTR, SIGHUP, and SIGPIPE and will iterate, terminate, and 1663 * reap all sub-process upon kill or exit. 1664 * 1665 * The command line forwarded to this function is: 1666 * 1667 * WORKER slot# socketfd portdir/subdir 1668 * 1669 * TERM=dumb 1670 * USER=root 1671 * HOME=/root 1672 * LANG=C 1673 * SSL_NO_VERIFY_PEER=1 1674 * USE_PACKAGE_DEPENDS_ONLY=1 1675 * PORTSDIR=/xports 1676 * PORT_DBDIR=/options For ports options 1677 * PACKAGE_BUILDING=yes Don't build packages that aren't legally 1678 * buildable for a binary repo. 1679 * PKG_DBDIR=/var/db/pkg 1680 * PKG_CACHEDIR=/var/cache/pkg 1681 * PKG_CREATE_VERBOSE=yes Ensure periodic output during packaging 1682 * (custom environment) 1683 * PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin 1684 * UNAME_s=DragonFly (example) 1685 * UNAME_v=DragonFly 5.7-SYNTH (example) 1686 * UNAME_p=x86_64 (example) 1687 * UNAME_m=x86_64 (example) 1688 * UNAME_r=5.7-SYNTH (example) 1689 * NO_DEPENDS=yes (conditional based on phase) 1690 * DISTDIR=/distfiles 1691 * WRKDIRPREFIX=/construction 1692 * BATCH=yes 1693 * MAKE_JOBS_NUMBER=n 1694 * 1695 * SETUP: 1696 * ldconfig -R 1697 * /usr/local/sbin/pkg-static install /packages/All/<the pkg pkg> 1698 * /usr/local/sbin/pkg-static install /packages/All/<pkg> 1699 * (for all dependencies) 1700 * 1701 * PHASES: make -C path FLAVOR=flavor <phase> 1702 * check-sanity 1703 * pkg-depends 1704 * fetch-depends 1705 * fetch 1706 * checksum 1707 * extract-depends 1708 * extract 1709 * patch-depends 1710 * patch 1711 * build-depends 1712 * lib-depends 1713 * configure 1714 * build 1715 * run-depends 1716 * stage 1717 * test (skipped) 1718 * check-plist ('dsynth test blahblah' or 'dsynth -D everything' only) 1719 * package e.g. /construction/lang/perl5.28/pkg/perl5-5.28.2.txz 1720 * install-mtree (skipped) 1721 * install (skipped) 1722 * deinstall (skipped) 1723 */ 1724 void 1725 WorkerProcess(int ac, char **av) 1726 { 1727 wmsg_t wmsg; 1728 int fd; 1729 int slot; 1730 int tmpfd; 1731 int pkgpkg = 0; 1732 int status; 1733 int len; 1734 int do_install_phase; 1735 char *portdir; 1736 char *pkgfile; 1737 char *flavor; 1738 char *buf; 1739 worker_t *work; 1740 bulk_t *bulk; 1741 pkg_t pkg; 1742 buildenv_t *benv; 1743 FILE *fp; 1744 1745 /* 1746 * Parse arguments 1747 */ 1748 if (ac != 6) { 1749 dlog(DLOG_ALL, "WORKER PROCESS %d- bad arguments\n", getpid()); 1750 exit(1); 1751 } 1752 slot = strtol(av[1], NULL, 0); 1753 fd = strtol(av[2], NULL, 0); /* master<->slave messaging */ 1754 portdir = av[3]; 1755 pkgfile = av[4]; 1756 flavor = strchr(portdir, '@'); 1757 if (flavor) { 1758 *flavor++ = 0; 1759 asprintf(&buf, "@%s", flavor); 1760 WorkerFlavorPrt = buf; 1761 buf = NULL; /* safety */ 1762 } 1763 WorkerProcFlags = strtol(av[5], NULL, 0); 1764 1765 bzero(&wmsg, sizeof(wmsg)); 1766 1767 setproctitle("[%02d] WORKER STARTUP %s%s", 1768 slot, portdir, WorkerFlavorPrt); 1769 1770 if (strcmp(portdir, "ports-mgmt/pkg") == 0) 1771 pkgpkg = 1; 1772 1773 signal(SIGTERM, phaseTerminateSignal); 1774 signal(SIGINT, phaseTerminateSignal); 1775 signal(SIGHUP, phaseTerminateSignal); 1776 1777 /* 1778 * Set up the environment 1779 */ 1780 setenv("TERM", "dumb", 1); 1781 setenv("USER", "root", 1); 1782 setenv("HOME", "/root", 1); 1783 setenv("LANG", "C", 1); 1784 setenv("SSL_NO_VERIFY_PEER", "1", 1); 1785 1786 addbuildenv("USE_PACKAGE_DEPENDS_ONLY", "yes", BENV_MAKECONF); 1787 addbuildenv("PORTSDIR", "/xports", BENV_MAKECONF); 1788 addbuildenv("PORT_DBDIR", "/options", BENV_MAKECONF); 1789 addbuildenv("PKG_DBDIR", "/var/db/pkg", BENV_MAKECONF); 1790 addbuildenv("PKG_CACHEDIR", "/var/cache/pkg", BENV_MAKECONF); 1791 addbuildenv("PKG_SUFX", UsePkgSufx, BENV_MAKECONF); 1792 if (WorkerProcFlags & WORKER_PROC_DEVELOPER) 1793 addbuildenv("DEVELOPER", "1", BENV_MAKECONF); 1794 1795 /* 1796 * CCache is a horrible unreliable hack but... leave the 1797 * mechanism in-place in case someone has a death wish. 1798 */ 1799 if (UseCCache) { 1800 addbuildenv("WITH_CCACHE_BUILD", "yes", BENV_MAKECONF); 1801 addbuildenv("CCACHE_DIR", "/ccache", BENV_MAKECONF); 1802 } 1803 1804 addbuildenv("UID", "0", BENV_MAKECONF); 1805 addbuildenv("ARCH", ArchitectureName, BENV_MAKECONF); 1806 1807 #ifdef __DragonFly__ 1808 addbuildenv("OPSYS", "DragonFly", BENV_MAKECONF); 1809 addbuildenv("DFLYVERSION", VersionFromParamHeader, BENV_MAKECONF); 1810 addbuildenv("OSVERSION", "9999999", BENV_MAKECONF); 1811 #else 1812 #error "Need OS-specific data to generate make.conf" 1813 #endif 1814 1815 addbuildenv("OSREL", ReleaseName, BENV_MAKECONF); 1816 addbuildenv("_OSRELEASE", VersionOnlyName, BENV_MAKECONF); 1817 1818 setenv("PATH", 1819 "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin", 1820 1); 1821 1822 setenv("UNAME_s", OperatingSystemName, 1); 1823 setenv("UNAME_v", VersionName, 1); 1824 setenv("UNAME_p", ArchitectureName, 1); 1825 setenv("UNAME_m", MachineName, 1); 1826 setenv("UNAME_r", ReleaseName, 1); 1827 1828 addbuildenv("DISTDIR", "/distfiles", BENV_MAKECONF); 1829 addbuildenv("WRKDIRPREFIX", "/construction", BENV_MAKECONF); 1830 addbuildenv("BATCH", "yes", BENV_MAKECONF); 1831 1832 /* 1833 * Special consideration 1834 * 1835 * PACKAGE_BUILDING - Disallow packaging ports which do not allow 1836 * for binary distribution. 1837 * 1838 * PKG_CREATE_VERBOSE - Ensure periodic output during the packaging 1839 * process to avoid a watchdog timeout. 1840 * 1841 */ 1842 addbuildenv("PACKAGE_BUILDING", "yes", BENV_MAKECONF); 1843 addbuildenv("PKG_CREATE_VERBOSE", "yes", BENV_MAKECONF); 1844 asprintf(&buf, "%d", MaxJobs); 1845 addbuildenv("MAKE_JOBS_NUMBER", buf, BENV_MAKECONF); 1846 freestrp(&buf); 1847 1848 if (flavor) 1849 setenv("FLAVOR", flavor, 1); 1850 1851 /* 1852 * Become the reaper 1853 */ 1854 if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) < 0) 1855 dfatal_errno("procctl() - Cannot become reaper"); 1856 1857 /* 1858 * Initialize a worker structure 1859 */ 1860 DoInitBuild(slot); 1861 1862 bzero(&pkg, sizeof(pkg)); 1863 pkg.portdir = portdir; /* sans flavor */ 1864 pkg.pkgfile = pkgfile; 1865 if (strchr(portdir, '/')) 1866 len = strchr(portdir, '/') - portdir; 1867 else 1868 len = 0; 1869 1870 /* 1871 * Setup the logfile 1872 */ 1873 asprintf(&pkg.logfile, 1874 "%s/%*.*s___%s%s%s.log", 1875 LogsPath, len, len, portdir, 1876 ((portdir[len] == '/') ? portdir + len + 1 : portdir + len), 1877 (flavor ? "@" : ""), 1878 (flavor ? flavor : "")); 1879 tmpfd = open(pkg.logfile, O_RDWR|O_CREAT|O_TRUNC, 0666); 1880 if (tmpfd >= 0) { 1881 if (DebugOpt >= 2) { 1882 dlog(DLOG_ALL, "[%03d] %s LOGFILE %s\n", 1883 slot, pkg.portdir, pkg.logfile); 1884 } 1885 close(tmpfd); 1886 } else { 1887 dlog(DLOG_ALL, "[%03d] LOGFILE %s (create failed)\n", 1888 slot, pkg.logfile); 1889 } 1890 1891 /* 1892 * Setup the work structure. Because this is an exec'd sub-process, 1893 * there is only one work structure. 1894 */ 1895 work = &WorkerAry[0]; 1896 work->flavor = flavor; 1897 work->fds[0] = fd; 1898 work->pkg = &pkg; 1899 work->start_time = time(NULL); 1900 1901 /* 1902 * Do mounts 1903 */ 1904 SigWork = work; 1905 setproctitle("[%02d] WORKER MOUNTS %s%s", 1906 slot, portdir, WorkerFlavorPrt); 1907 DoWorkerMounts(work); 1908 1909 /* 1910 * Generate an /etc/make.conf in the build base 1911 */ 1912 asprintf(&buf, "%s/etc/make.conf", work->basedir); 1913 fp = fopen(buf, "w"); 1914 dassert_errno(fp, "Unable to create %s\n", buf); 1915 for (benv = BuildEnv; benv; benv = benv->next) { 1916 if (benv->type & BENV_PKGLIST) 1917 continue; 1918 if ((benv->type & BENV_CMDMASK) == BENV_MAKECONF) { 1919 if (DebugOpt >= 2) { 1920 dlog(DLOG_ALL, "[%03d] ENV %s=%s\n", 1921 slot, benv->label, benv->data); 1922 } 1923 fprintf(fp, "%s=%s\n", benv->label, benv->data); 1924 } 1925 } 1926 fclose(fp); 1927 freestrp(&buf); 1928 1929 /* 1930 * Set up our hooks 1931 */ 1932 if (UsingHooks) 1933 initbulk(childHookRun, MaxBulk); 1934 1935 /* 1936 * Start phases 1937 */ 1938 wmsg.cmd = WMSG_CMD_INSTALL_PKGS; 1939 ipcwritemsg(fd, &wmsg); 1940 status = ipcreadmsg(fd, &wmsg); 1941 if (status < 0 || wmsg.cmd != WMSG_RES_INSTALL_PKGS) 1942 dfatal("pkg installation handshake failed"); 1943 do_install_phase = wmsg.status; 1944 1945 wmsg.cmd = WMSG_CMD_STATUS_UPDATE; 1946 wmsg.phase = PHASE_INSTALL_PKGS; 1947 wmsg.lines = 0; 1948 1949 status = ipcwritemsg(fd, &wmsg); 1950 1951 if (pkgpkg) { 1952 dophase(work, &wmsg, 1953 WDOG5, PHASE_PACKAGE, "package"); 1954 } else { 1955 if (do_install_phase) { 1956 dophase(work, &wmsg, 1957 WDOG4, PHASE_INSTALL_PKGS, "setup"); 1958 } 1959 dophase(work, &wmsg, 1960 WDOG2, PHASE_CHECK_SANITY, "check-sanity"); 1961 dophase(work, &wmsg, 1962 WDOG2, PHASE_PKG_DEPENDS, "pkg-depends"); 1963 dophase(work, &wmsg, 1964 WDOG7, PHASE_FETCH_DEPENDS, "fetch-depends"); 1965 dophase(work, &wmsg, 1966 WDOG7, PHASE_FETCH, "fetch"); 1967 dophase(work, &wmsg, 1968 WDOG2, PHASE_CHECKSUM, "checksum"); 1969 dophase(work, &wmsg, 1970 WDOG3, PHASE_EXTRACT_DEPENDS, "extract-depends"); 1971 dophase(work, &wmsg, 1972 WDOG3, PHASE_EXTRACT, "extract"); 1973 dophase(work, &wmsg, 1974 WDOG2, PHASE_PATCH_DEPENDS, "patch-depends"); 1975 dophase(work, &wmsg, 1976 WDOG2, PHASE_PATCH, "patch"); 1977 dophase(work, &wmsg, 1978 WDOG5, PHASE_BUILD_DEPENDS, "build-depends"); 1979 dophase(work, &wmsg, 1980 WDOG5, PHASE_LIB_DEPENDS, "lib-depends"); 1981 dophase(work, &wmsg, 1982 WDOG3, PHASE_CONFIGURE, "configure"); 1983 dophase(work, &wmsg, 1984 WDOG9, PHASE_BUILD, "build"); 1985 dophase(work, &wmsg, 1986 WDOG5, PHASE_RUN_DEPENDS, "run-depends"); 1987 dophase(work, &wmsg, 1988 WDOG5, PHASE_STAGE, "stage"); 1989 #if 0 1990 dophase(work, &wmsg, 1991 WDOG5, PHASE_TEST, "test"); 1992 #endif 1993 if (WorkerProcFlags & WORKER_PROC_CHECK_PLIST) { 1994 dophase(work, &wmsg, 1995 WDOG1, PHASE_CHECK_PLIST, "check-plist"); 1996 } 1997 dophase(work, &wmsg, 1998 WDOG5, PHASE_PACKAGE, "package"); 1999 #if 0 2000 dophase(work, &wmsg, 2001 WDOG5, PHASE_INSTALL_MTREE, "install-mtree"); 2002 dophase(work, &wmsg, 2003 WDOG5, PHASE_INSTALL, "install"); 2004 dophase(work, &wmsg, 2005 WDOG5, PHASE_DEINSTALL, "deinstall"); 2006 #endif 2007 } 2008 2009 if (MasterPtyFd >= 0) { 2010 close(MasterPtyFd); 2011 MasterPtyFd = -1; 2012 } 2013 2014 setproctitle("[%02d] WORKER CLEANUP %s%s", 2015 slot, portdir, WorkerFlavorPrt); 2016 2017 /* 2018 * Copy the package to the repo. 2019 */ 2020 if (work->accum_error == 0) { 2021 char *b1; 2022 char *b2; 2023 2024 asprintf(&b1, "%s/construction/%s/pkg/%s", 2025 work->basedir, pkg.portdir, pkg.pkgfile); 2026 asprintf(&b2, "%s/%s", RepositoryPath, pkg.pkgfile); 2027 if (copyfile(b1, b2)) { 2028 ++work->accum_error; 2029 dlog(DLOG_ALL, "[%03d] %s Unable to copy %s to %s\n", 2030 work->index, pkg.portdir, b1, b2); 2031 } 2032 free(b1); 2033 free(b2); 2034 } 2035 2036 /* 2037 * Unmount, unless we are in DebugStopMode. 2038 */ 2039 if ((WorkerProcFlags & WORKER_PROC_DEBUGSTOP) == 0) 2040 DoWorkerUnmounts(work); 2041 2042 /* 2043 * Send completion status to master dsynth worker thread. 2044 */ 2045 if (work->accum_error) { 2046 wmsg.cmd = WMSG_CMD_FAILURE; 2047 } else { 2048 wmsg.cmd = WMSG_CMD_SUCCESS; 2049 } 2050 ipcwritemsg(fd, &wmsg); 2051 if (WorkerProcFlags & WORKER_PROC_DEBUGSTOP) { 2052 wmsg.cmd = WMSG_CMD_FREEZEWORKER; 2053 ipcwritemsg(fd, &wmsg); 2054 } 2055 if (UsingHooks) { 2056 while ((bulk = getbulk()) != NULL) 2057 freebulk(bulk); 2058 donebulk(); 2059 } 2060 } 2061 2062 static void 2063 dophase(worker_t *work, wmsg_t *wmsg, int wdog, int phaseid, const char *phase) 2064 { 2065 pkg_t *pkg = work->pkg; 2066 char buf[1024]; 2067 pid_t pid; 2068 int status; 2069 int ms; 2070 pid_t wpid; 2071 int wpid_reaped; 2072 int fdlog; 2073 time_t start_time; 2074 time_t last_time; 2075 time_t next_time; 2076 time_t wdog_time; 2077 FILE *fp; 2078 2079 if (work->accum_error) 2080 return; 2081 setproctitle("[%02d] WORKER %-8.8s %s%s", 2082 work->index, phase, pkg->portdir, WorkerFlavorPrt); 2083 wmsg->phase = phaseid; 2084 if (ipcwritemsg(work->fds[0], wmsg) < 0) { 2085 dlog(DLOG_ALL, "[%03d] %s Lost Communication with dsynth, " 2086 "aborting worker\n", 2087 work->index, pkg->portdir); 2088 ++work->accum_error; 2089 return; 2090 } 2091 2092 /* 2093 * Execute the port make command in chroot on a pty. 2094 */ 2095 fflush(stdout); 2096 fflush(stderr); 2097 if (MasterPtyFd >= 0) { 2098 int slavefd; 2099 2100 /* 2101 * NOTE: We can't open the slave in the child because the 2102 * master may race a disconnection test. If we open 2103 * it in the parent our close() will flush any pending 2104 * output not read by the master (which is the same 2105 * parent process) and deadlock. 2106 * 2107 * Solve this by hand-shaking the slave tty to give 2108 * the master time to close its slavefd (after this 2109 * section). 2110 * 2111 * Leave the tty defaults intact, which also likely 2112 * means it will be in line-buffered mode, so handshake 2113 * with a full line. 2114 * 2115 * TODO: Our handshake probably echos back to the master pty 2116 * due to tty echo, and ends up in the log, so just 2117 * pass through a newline. 2118 */ 2119 slavefd = open(ptsname(MasterPtyFd), O_RDWR); 2120 dassert_errno(slavefd >= 0, "Cannot open slave pty"); 2121 2122 /* 2123 * Now do the fork. 2124 */ 2125 pid = fork(); 2126 if (pid == 0) { 2127 login_tty(slavefd); 2128 /* login_tty() closes slavefd */ 2129 } else { 2130 close(slavefd); 2131 } 2132 } else { 2133 /* 2134 * Initial MasterPtyFd for the slot, just use forkpty(). 2135 */ 2136 pid = forkpty(&MasterPtyFd, NULL, NULL, NULL); 2137 } 2138 2139 /* 2140 * The slave must make sure the master has time to close slavefd 2141 * in the re-use case before going its merry way. The master needs 2142 * to set terminal modes and the window as well. 2143 */ 2144 if (pid == 0) { 2145 /* 2146 * Slave waits for handshake 2147 */ 2148 char ttybuf[2]; 2149 2150 read(0, ttybuf, 1); 2151 } else { 2152 /* 2153 * We are going through a pty, so set the tty modes to 2154 * Set tty modes so we do not get ^M's in the log files. 2155 * 2156 * This isn't fatal if it doesn't work. Remember that 2157 * our output goes through the pty to the management 2158 * process which will log it. 2159 */ 2160 struct termios tio; 2161 struct winsize win; 2162 2163 if (tcgetattr(MasterPtyFd, &tio) == 0) { 2164 tio.c_oflag |= OPOST | ONOCR; 2165 tio.c_oflag &= ~(OCRNL | ONLCR); 2166 tio.c_iflag |= ICRNL; 2167 tio.c_iflag &= ~(INLCR | IGNCR); 2168 if (tcsetattr(MasterPtyFd, TCSANOW, &tio)) { 2169 printf("tcsetattr failed: %s\n", 2170 strerror(errno)); 2171 } 2172 2173 /* 2174 * Give the tty a non-zero columns field. 2175 * This fixes at least one port (textproc/po4a) 2176 */ 2177 if (ioctl(MasterPtyFd, TIOCGWINSZ, &win) == 0) { 2178 win.ws_col = 80; 2179 ioctl(MasterPtyFd, TIOCSWINSZ, &win); 2180 } else { 2181 printf("TIOCGWINSZ failed: %s\n", 2182 strerror(errno)); 2183 } 2184 2185 } else { 2186 printf("tcgetattr failed: %s\n", strerror(errno)); 2187 } 2188 2189 /* 2190 * Master issues handshake 2191 */ 2192 write(MasterPtyFd, "\n", 1); 2193 } 2194 2195 if (pid == 0) { 2196 /* 2197 * Additional phase-specific environment variables 2198 * 2199 * - Do not try to process missing depends outside of the 2200 * depends phases. Also relies on USE_PACKAGE_DEPENDS_ONLY 2201 * in the make.conf. 2202 */ 2203 switch(phaseid) { 2204 case PHASE_CHECK_SANITY: 2205 case PHASE_FETCH: 2206 case PHASE_CHECKSUM: 2207 case PHASE_EXTRACT: 2208 case PHASE_PATCH: 2209 case PHASE_CONFIGURE: 2210 case PHASE_STAGE: 2211 case PHASE_TEST: 2212 case PHASE_CHECK_PLIST: 2213 case PHASE_INSTALL_MTREE: 2214 case PHASE_INSTALL: 2215 case PHASE_DEINSTALL: 2216 break; 2217 case PHASE_PKG_DEPENDS: 2218 case PHASE_FETCH_DEPENDS: 2219 case PHASE_EXTRACT_DEPENDS: 2220 case PHASE_PATCH_DEPENDS: 2221 case PHASE_BUILD_DEPENDS: 2222 case PHASE_LIB_DEPENDS: 2223 case PHASE_RUN_DEPENDS: 2224 break; 2225 default: 2226 setenv("NO_DEPENDS", "1", 1); 2227 break; 2228 } 2229 2230 /* 2231 * Clean-up, chdir, and chroot. 2232 */ 2233 closefrom(3); 2234 if (chdir(work->basedir) < 0) 2235 dfatal_errno("chdir in phase initialization"); 2236 if (chroot(work->basedir) < 0) 2237 dfatal_errno("chroot in phase initialization"); 2238 2239 /* 2240 * We have a choice here on how to handle stdin (fd 0). 2241 * We can leave it connected to the pty in which case 2242 * the build will just block if it tries to ask a 2243 * question (and the watchdog will kill it, eventually), 2244 * or we can try to EOF the pty, or we can attach /dev/null 2245 * to descriptor 0. 2246 */ 2247 if (NullStdinOpt) { 2248 int fd; 2249 2250 fd = open("/dev/null", O_RDWR); 2251 dassert_errno(fd >= 0, "cannot open /dev/null"); 2252 if (fd != 0) { 2253 dup2(fd, 0); 2254 close(fd); 2255 } 2256 } 2257 2258 /* 2259 * Execute the appropriate command. 2260 */ 2261 switch(phaseid) { 2262 case PHASE_INSTALL_PKGS: 2263 snprintf(buf, sizeof(buf), "/tmp/dsynth_install_pkgs"); 2264 execl(buf, buf, NULL); 2265 break; 2266 default: 2267 snprintf(buf, sizeof(buf), "/xports/%s", pkg->portdir); 2268 execl(MAKE_BINARY, MAKE_BINARY, "-C", buf, phase, NULL); 2269 break; 2270 } 2271 _exit(1); 2272 } 2273 fcntl(MasterPtyFd, F_SETFL, O_NONBLOCK); 2274 2275 if (pid < 0) { 2276 dlog(DLOG_ALL, "[%03d] %s Fork Failed: %s\n", 2277 work->index, pkg->logfile, strerror(errno)); 2278 ++work->accum_error; 2279 return; 2280 } 2281 2282 SigPid = pid; 2283 2284 fdlog = open(pkg->logfile, O_RDWR|O_CREAT|O_APPEND, 0644); 2285 if (fdlog < 0) { 2286 dlog(DLOG_ALL, "[%03d] %s Cannot open logfile '%s': %s\n", 2287 work->index, pkg->portdir, 2288 pkg->logfile, strerror(errno)); 2289 } 2290 2291 snprintf(buf, sizeof(buf), 2292 "----------------------------------------" 2293 "---------------------------------------\n" 2294 "-- Phase: %s\n" 2295 "----------------------------------------" 2296 "---------------------------------------\n", 2297 phase); 2298 write(fdlog, buf, strlen(buf)); 2299 2300 start_time = time(NULL); 2301 last_time = start_time; 2302 wdog_time = start_time; 2303 wpid_reaped = 0; 2304 2305 status = 0; 2306 for (;;) { 2307 ms = mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time); 2308 if (ms == MPTY_FAILED) { 2309 dlog(DLOG_ALL, 2310 "[%03d] %s lost pty in phase %s, terminating\n", 2311 work->index, pkg->portdir, phase); 2312 break; 2313 } 2314 if (ms == MPTY_EOF) 2315 break; 2316 2317 /* 2318 * Generally speaking update status once a second. 2319 * This also allows us to detect if the management 2320 * dsynth process has gone away. 2321 */ 2322 next_time = time(NULL); 2323 if (next_time != last_time) { 2324 double dload[3]; 2325 double dv; 2326 int wdog_scaled; 2327 2328 /* 2329 * Send status update to the worker management thread 2330 * in the master dsynth process. Remember, *WE* are 2331 * the worker management process sub-fork. 2332 */ 2333 if (ipcwritemsg(work->fds[0], wmsg) < 0) 2334 break; 2335 last_time = next_time; 2336 2337 /* 2338 * Watchdog scaling 2339 */ 2340 getloadavg(dload, 3); 2341 dv = dload[2] / NumCores; 2342 if (dv < (double)NumCores) { 2343 wdog_scaled = wdog; 2344 } else { 2345 if (dv > 4.0 * NumCores) 2346 dv = 4.0 * NumCores; 2347 wdog_scaled = wdog * dv / NumCores; 2348 } 2349 2350 /* 2351 * Watchdog 2352 */ 2353 if (next_time - wdog_time >= wdog_scaled * 60) { 2354 snprintf(buf, sizeof(buf), 2355 "\n--------\n" 2356 "WATCHDOG TIMEOUT FOR %s in %s " 2357 "after %d minutes\n" 2358 "Killing pid %d\n" 2359 "--------\n", 2360 pkg->portdir, phase, wdog_scaled, pid); 2361 if (fdlog >= 0) 2362 write(fdlog, buf, strlen(buf)); 2363 dlog(DLOG_ALL, 2364 "[%03d] %s WATCHDOG TIMEOUT in %s " 2365 "after %d minutes (%d min scaled)\n", 2366 work->index, pkg->portdir, phase, 2367 wdog, wdog_scaled); 2368 kill(pid, SIGKILL); 2369 ++work->accum_error; 2370 break; 2371 } 2372 } 2373 2374 /* 2375 * Check process exit. Normally the pty will EOF 2376 * but if background processes remain we need to 2377 * check here to see if our primary exec is done, 2378 * so we can break out and reap those processes. 2379 * 2380 * Generally reap any other processes we have inherited 2381 * while we are here. 2382 */ 2383 do { 2384 wpid = wait3(&status, WNOHANG, NULL); 2385 } while (wpid > 0 && wpid != pid); 2386 if (wpid == pid && WIFEXITED(status)) { 2387 wpid_reaped = 1; 2388 break; 2389 } 2390 } 2391 2392 next_time = time(NULL); 2393 2394 setproctitle("[%02d] WORKER EXITREAP %s%s", 2395 work->index, pkg->portdir, WorkerFlavorPrt); 2396 2397 /* 2398 * We usually get here due to a mpty EOF, but not always as there 2399 * could be persistent processes still holding the slave. Finish 2400 * up getting the exit status for the main process we are waiting 2401 * on and clean out any data left on the MasterPtyFd (as it could 2402 * be blocking the exit). 2403 */ 2404 while (wpid_reaped == 0) { 2405 (void)mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time); 2406 wpid = waitpid(pid, &status, WNOHANG); 2407 if (wpid == pid && WIFEXITED(status)) { 2408 wpid_reaped = 1; 2409 break; 2410 } 2411 if (wpid < 0 && errno != EINTR) { 2412 break; 2413 } 2414 2415 /* 2416 * Safety. The normal phase waits until the fork/exec'd 2417 * pid finishes, causing a pty EOF on exit (the slave 2418 * descriptor is closed by the kernel on exit so the 2419 * process should already have exited). 2420 * 2421 * However, it is also possible to get here if the pty fails 2422 * for some reason. In this case, make sure that the process 2423 * is killed. 2424 */ 2425 kill(pid, SIGKILL); 2426 } 2427 2428 /* 2429 * Clean out anything left on the pty but don't wait around 2430 * because there could be background processes preventing the 2431 * slave side from closing. 2432 */ 2433 while (mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time) == MPTY_DATA) 2434 ; 2435 2436 /* 2437 * Report on the exit condition. If the pid was somehow lost 2438 * (probably due to someone gdb'ing the process), assume an error. 2439 */ 2440 if (wpid_reaped) { 2441 if (WEXITSTATUS(status)) { 2442 dlog(DLOG_ALL | DLOG_FILTER, 2443 "[%03d] %s Build phase '%s' failed exit %d\n", 2444 work->index, pkg->portdir, phase, 2445 WEXITSTATUS(status)); 2446 ++work->accum_error; 2447 } 2448 } else { 2449 dlog(DLOG_ALL, "[%03d] %s Build phase '%s' failed - lost pid\n", 2450 work->index, pkg->portdir, phase); 2451 ++work->accum_error; 2452 } 2453 2454 /* 2455 * Kill any processes still running (sometimes processes end up in 2456 * the background during a dports build), and clean up any other 2457 * children that we have inherited. 2458 */ 2459 phaseReapAll(); 2460 2461 /* 2462 * After the extraction phase add the space used by /construction 2463 * to the memory use. This helps us reduce the amount of paging 2464 * we do due to extremely large package extractions (languages, 2465 * chromium, etc). 2466 * 2467 * (dsynth already estimated the space used by the package deps 2468 * up front, but this will help us further). 2469 */ 2470 if (work->accum_error == 0 && phaseid == PHASE_EXTRACT) { 2471 struct statfs sfs; 2472 char *b1; 2473 2474 asprintf(&b1, "%s/construction", work->basedir); 2475 if (statfs(b1, &sfs) == 0) { 2476 wmsg->memuse = (sfs.f_blocks - sfs.f_bfree) * 2477 sfs.f_bsize; 2478 ipcwritemsg(work->fds[0], wmsg); 2479 } 2480 } 2481 2482 /* 2483 * Update log 2484 */ 2485 if (fdlog >= 0) { 2486 struct stat st; 2487 int h; 2488 int m; 2489 int s; 2490 2491 last_time = next_time - start_time; 2492 s = last_time % 60; 2493 m = last_time / 60 % 60; 2494 h = last_time / 3600; 2495 2496 fp = fdopen(fdlog, "a"); 2497 if (fp == NULL) { 2498 dlog(DLOG_ALL, "[%03d] %s Cannot fdopen fdlog: %s %d\n", 2499 work->index, pkg->portdir, 2500 strerror(errno), fstat(fdlog, &st)); 2501 close(fdlog); 2502 goto skip; 2503 } 2504 2505 fprintf(fp, "\n"); 2506 if (work->accum_error) { 2507 fprintf(fp, "FAILED %02d:%02d:%02d\n", h, m, s); 2508 } else { 2509 if (phaseid == PHASE_EXTRACT && wmsg->memuse) { 2510 fprintf(fp, "Extracted Memory Use: %6.2fM\n", 2511 wmsg->memuse / (1024.0 * 1024.0)); 2512 } 2513 fprintf(fp, "SUCCEEDED %02d:%02d:%02d\n", h, m, s); 2514 } 2515 last_time = next_time - work->start_time; 2516 s = last_time % 60; 2517 m = last_time / 60 % 60; 2518 h = last_time / 3600; 2519 if (phaseid == PHASE_PACKAGE) { 2520 fprintf(fp, "TOTAL TIME %02d:%02d:%02d\n", h, m, s); 2521 } 2522 fprintf(fp, "\n"); 2523 fclose(fp); 2524 skip: 2525 ; 2526 } 2527 2528 } 2529 2530 static void 2531 phaseReapAll(void) 2532 { 2533 struct reaper_status rs; 2534 int status; 2535 2536 while (procctl(P_PID, getpid(), PROC_REAP_STATUS, &rs) == 0) { 2537 if ((rs.flags & PROC_REAP_ACQUIRE) == 0) 2538 break; 2539 if (rs.pid_head < 0) 2540 break; 2541 if (kill(rs.pid_head, SIGKILL) == 0) { 2542 while (waitpid(rs.pid_head, &status, 0) < 0) 2543 ; 2544 } 2545 } 2546 while (wait3(&status, 0, NULL) > 0) 2547 ; 2548 } 2549 2550 static void 2551 phaseTerminateSignal(int sig __unused) 2552 { 2553 if (CopyFileFd >= 0) 2554 close(CopyFileFd); 2555 if (MasterPtyFd >= 0) 2556 close(MasterPtyFd); 2557 if (SigPid > 1) 2558 kill(SigPid, SIGKILL); 2559 phaseReapAll(); 2560 if (SigWork) 2561 DoWorkerUnmounts(SigWork); 2562 exit(1); 2563 } 2564 2565 static 2566 char * 2567 buildskipreason(pkglink_t *parent, pkg_t *pkg) 2568 { 2569 pkglink_t *link; 2570 pkg_t *scan; 2571 char *reason = NULL; 2572 char *ptr; 2573 size_t tot; 2574 size_t len; 2575 pkglink_t stack; 2576 2577 if ((pkg->flags & PKGF_NOBUILD_I) && pkg->ignore) 2578 asprintf(&reason, "%s ", pkg->ignore); 2579 2580 tot = 0; 2581 PKGLIST_FOREACH(link, &pkg->idepon_list) { 2582 #if 0 2583 if (link->dep_type > DEP_TYPE_BUILD) 2584 continue; 2585 #endif 2586 scan = link->pkg; 2587 if (scan == NULL) 2588 continue; 2589 if ((scan->flags & (PKGF_ERROR | PKGF_NOBUILD)) == 0) 2590 continue; 2591 if (scan->flags & PKGF_NOBUILD) { 2592 stack.pkg = scan; 2593 stack.next = parent; 2594 ptr = buildskipreason(&stack, scan); 2595 len = strlen(scan->portdir) + strlen(ptr) + 8; 2596 reason = realloc(reason, tot + len); 2597 snprintf(reason + tot, len, "%s->%s", 2598 scan->portdir, ptr); 2599 free(ptr); 2600 } else { 2601 len = strlen(scan->portdir) + 8; 2602 reason = realloc(reason, tot + len); 2603 snprintf(reason + tot, len, "%s", scan->portdir); 2604 } 2605 2606 /* 2607 * Don't try to print the entire graph 2608 */ 2609 if (parent) 2610 break; 2611 tot += strlen(reason + tot); 2612 reason[tot++] = ' '; 2613 reason[tot] = 0; 2614 } 2615 return (reason); 2616 } 2617 2618 /* 2619 * Count number of packages that would be skipped due to the 2620 * specified package having failed. 2621 * 2622 * Call with mode 1 to count, and mode 0 to clear the 2623 * cumulative rscan flag (used to de-duplicate the count). 2624 * 2625 * Must be serialized. 2626 */ 2627 static int 2628 buildskipcount_dueto(pkg_t *pkg, int mode) 2629 { 2630 pkglink_t *link; 2631 pkg_t *scan; 2632 int total; 2633 2634 total = 0; 2635 PKGLIST_FOREACH(link, &pkg->deponi_list) { 2636 scan = link->pkg; 2637 if (scan == NULL || scan->rscan == mode) 2638 continue; 2639 scan->rscan = mode; 2640 ++total; 2641 total += buildskipcount_dueto(scan, mode); 2642 } 2643 return total; 2644 } 2645 2646 /* 2647 * The master ptyfd is in non-blocking mode. Drain up to 1024 bytes 2648 * and update wmsg->lines and *wdog_timep as appropriate. 2649 * 2650 * This function will poll, stalling up to 1 second. 2651 */ 2652 static int 2653 mptylogpoll(int ptyfd, int fdlog, wmsg_t *wmsg, time_t *wdog_timep) 2654 { 2655 struct pollfd pfd; 2656 char buf[1024]; 2657 ssize_t r; 2658 2659 pfd.fd = ptyfd; 2660 pfd.events = POLLIN; 2661 pfd.revents = 0; 2662 2663 poll(&pfd, 1, 1000); 2664 if (pfd.revents) { 2665 r = read(ptyfd, buf, sizeof(buf)); 2666 if (r > 0) { 2667 *wdog_timep = time(NULL); 2668 if (r > 0 && fdlog >= 0) 2669 write(fdlog, buf, r); 2670 while (--r >= 0) { 2671 if (buf[r] == '\n') 2672 ++wmsg->lines; 2673 } 2674 return MPTY_DATA; 2675 } else if (r < 0) { 2676 if (errno != EINTR && errno != EAGAIN) 2677 return MPTY_FAILED; 2678 return MPTY_AGAIN; 2679 } else if (r == 0) { 2680 return MPTY_EOF; 2681 } 2682 } 2683 return MPTY_AGAIN; 2684 } 2685 2686 /* 2687 * Copy a (package) file from (src) to (dst), use an intermediate file and 2688 * rename to ensure that interruption does not leave us with a corrupt 2689 * package file. 2690 * 2691 * This is called by the WORKER process. 2692 * 2693 * (dsynth management thread -> WORKER process -> sub-processes) 2694 */ 2695 #define COPYBLKSIZE 32768 2696 2697 static int 2698 copyfile(char *src, char *dst) 2699 { 2700 char *tmp; 2701 char *buf; 2702 int fd1; 2703 int fd2; 2704 int error = 0; 2705 int mask; 2706 ssize_t r; 2707 2708 asprintf(&tmp, "%s.new", dst); 2709 buf = malloc(COPYBLKSIZE); 2710 2711 mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP)); 2712 fd1 = open(src, O_RDONLY|O_CLOEXEC); 2713 fd2 = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0644); 2714 CopyFileFd = fd1; 2715 sigsetmask(mask); 2716 while ((r = read(fd1, buf, COPYBLKSIZE)) > 0) { 2717 if (write(fd2, buf, r) != r) 2718 error = 1; 2719 } 2720 if (r < 0) 2721 error = 1; 2722 mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP)); 2723 CopyFileFd = -1; 2724 close(fd1); 2725 close(fd2); 2726 sigsetmask(mask); 2727 if (error) { 2728 remove(tmp); 2729 } else { 2730 if (rename(tmp, dst)) { 2731 error = 1; 2732 remove(tmp); 2733 } 2734 } 2735 2736 freestrp(&buf); 2737 freestrp(&tmp); 2738 2739 return error; 2740 } 2741 2742 /* 2743 * doHook() 2744 * 2745 * primary process (threaded) - run_start, run_end, pkg_ignored, pkg_skipped 2746 * worker process (threaded) - pkg_sucess, pkg_failure 2747 * 2748 * If waitfor is non-zero this hook will be serialized. 2749 */ 2750 static void 2751 doHook(pkg_t *pkg, const char *id, const char *path, int waitfor) 2752 { 2753 if (path == NULL) 2754 return; 2755 while (waitfor && getbulk() != NULL) 2756 ; 2757 if (pkg) 2758 queuebulk(pkg->portdir, id, path, pkg->pkgfile); 2759 else 2760 queuebulk(NULL, id, path, NULL); 2761 while (waitfor && getbulk() != NULL) 2762 ; 2763 } 2764 2765 /* 2766 * Execute hook (backend) 2767 * 2768 * s1 - portdir 2769 * s2 - id 2770 * s3 - script path 2771 * s4 - pkgfile (if applicable) 2772 */ 2773 static void 2774 childHookRun(bulk_t *bulk) 2775 { 2776 const char *cav[MAXCAC]; 2777 buildenv_t benv[MAXCAC]; 2778 char buf1[128]; 2779 char buf2[128]; 2780 char buf3[128]; 2781 char buf4[128]; 2782 FILE *fp; 2783 char *ptr; 2784 size_t len; 2785 pid_t pid; 2786 int cac; 2787 int bi; 2788 2789 cac = 0; 2790 bi = 0; 2791 bzero(benv, sizeof(benv)); 2792 2793 cav[cac++] = bulk->s3; 2794 2795 benv[bi].label = "PROFILE"; 2796 benv[bi].data = Profile; 2797 ++bi; 2798 2799 benv[bi].label = "DIR_PACKAGES"; 2800 benv[bi].data = PackagesPath; 2801 ++bi; 2802 2803 benv[bi].label = "DIR_REPOSITORY"; 2804 benv[bi].data = RepositoryPath; 2805 ++bi; 2806 2807 benv[bi].label = "DIR_PORTS"; 2808 benv[bi].data = DPortsPath; 2809 ++bi; 2810 2811 benv[bi].label = "DIR_OPTIONS"; 2812 benv[bi].data = OptionsPath; 2813 ++bi; 2814 2815 benv[bi].label = "DIR_DISTFILES"; 2816 benv[bi].data = DistFilesPath; 2817 ++bi; 2818 2819 benv[bi].label = "DIR_LOGS"; 2820 benv[bi].data = LogsPath; 2821 ++bi; 2822 2823 benv[bi].label = "DIR_BUILDBASE"; 2824 benv[bi].data = BuildBase; 2825 ++bi; 2826 2827 if (strcmp(bulk->s2, "hook_run_start") == 0) { 2828 snprintf(buf1, sizeof(buf1), "%d", BuildTotal); 2829 benv[bi].label = "PORTS_QUEUED"; 2830 benv[bi].data = buf1; 2831 ++bi; 2832 } else if (strcmp(bulk->s2, "hook_run_end") == 0) { 2833 snprintf(buf1, sizeof(buf1), "%d", BuildSuccessCount); 2834 benv[bi].label = "PORTS_BUILT"; 2835 benv[bi].data = buf1; 2836 ++bi; 2837 snprintf(buf2, sizeof(buf2), "%d", BuildFailCount); 2838 benv[bi].label = "PORTS_FAILED"; 2839 benv[bi].data = buf2; 2840 ++bi; 2841 snprintf(buf3, sizeof(buf3), "%d", BuildIgnoreCount); 2842 benv[bi].label = "PORTS_IGNORED"; 2843 benv[bi].data = buf3; 2844 ++bi; 2845 snprintf(buf4, sizeof(buf4), "%d", BuildSkipCount); 2846 benv[bi].label = "PORTS_SKIPPED"; 2847 benv[bi].data = buf4; 2848 ++bi; 2849 } else { 2850 /* 2851 * success, failure, ignored, skipped 2852 */ 2853 benv[bi].label = "RESULT"; 2854 if (strcmp(bulk->s2, "hook_pkg_success") == 0) { 2855 benv[bi].data = "success"; 2856 } else if (strcmp(bulk->s2, "hook_pkg_failure") == 0) { 2857 benv[bi].data = "failure"; 2858 } else if (strcmp(bulk->s2, "hook_pkg_ignored") == 0) { 2859 benv[bi].data = "ignored"; 2860 } else if (strcmp(bulk->s2, "hook_pkg_skipped") == 0) { 2861 benv[bi].data = "skipped"; 2862 } else { 2863 dfatal("Unknown hook id: %s", bulk->s2); 2864 /* NOT REACHED */ 2865 } 2866 ++bi; 2867 2868 /* 2869 * For compatibility with synth: 2870 * 2871 * ORIGIN does not include any @flavor, thus it is suitable 2872 * for finding the actual port directory/subdirectory. 2873 * 2874 * FLAVOR is set to ORIGIN if there is no flavor, otherwise 2875 * it is set to only the flavor sans the '@'. 2876 */ 2877 if ((ptr = strchr(bulk->s1, '@')) != NULL) { 2878 snprintf(buf1, sizeof(buf1), "%*.*s", 2879 (int)(ptr - bulk->s1), 2880 (int)(ptr - bulk->s1), 2881 bulk->s1); 2882 benv[bi].label = "ORIGIN"; 2883 benv[bi].data = buf1; 2884 ++bi; 2885 benv[bi].label = "FLAVOR"; 2886 benv[bi].data = ptr + 1; 2887 ++bi; 2888 } else { 2889 benv[bi].label = "ORIGIN"; 2890 benv[bi].data = bulk->s1; 2891 ++bi; 2892 benv[bi].label = "FLAVOR"; 2893 benv[bi].data = bulk->s1; 2894 ++bi; 2895 } 2896 benv[bi].label = "PKGNAME"; 2897 benv[bi].data = bulk->s4; 2898 ++bi; 2899 } 2900 2901 benv[bi].label = NULL; 2902 benv[bi].data = NULL; 2903 2904 fp = dexec_open(cav, cac, &pid, benv, 0, 0); 2905 while ((ptr = fgetln(fp, &len)) != NULL) 2906 ; 2907 2908 if (dexec_close(fp, pid)) { 2909 dlog(DLOG_ALL, 2910 "[XXX] %s SCRIPT %s (%s)\n", 2911 bulk->s1, bulk->s2, bulk->s3); 2912 } 2913 } 2914