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 "-p", Profile, 1340 "WORKER", slotbuf, fdbuf, 1341 work->pkg->portdir, work->pkg->pkgfile, 1342 flagsbuf, 1343 NULL, envary); 1344 write(2, "EXECLE FAILURE\n", 15); 1345 _exit(1); 1346 } 1347 pthread_mutex_lock(&WorkerMutex); 1348 close(work->fds[1]); 1349 work->phase = PHASE_PENDING; 1350 work->lines = 0; 1351 work->memuse = 0; 1352 work->pid = pid; 1353 work->state = WORKER_RUNNING; 1354 /* fall through */ 1355 case WORKER_RUNNING: 1356 /* 1357 * Poll for status updates, if NULL is returned 1358 * and status is non-zero, the communications link 1359 * failed unexpectedly. 1360 */ 1361 pkg = work->pkg; 1362 pthread_mutex_unlock(&WorkerMutex); 1363 status = ipcreadmsg(work->fds[0], &wmsg); 1364 pthread_mutex_lock(&WorkerMutex); 1365 1366 if (status == 0) { 1367 /* 1368 * Normal message, can include normal 1369 * termination which changes us over 1370 * to another state. 1371 */ 1372 dowait = 0; 1373 switch(wmsg.cmd) { 1374 case WMSG_CMD_INSTALL_PKGS: 1375 wmsg.cmd = WMSG_RES_INSTALL_PKGS; 1376 wmsg.status = childInstallPkgDeps(work); 1377 pthread_mutex_unlock(&WorkerMutex); 1378 ipcwritemsg(work->fds[0], &wmsg); 1379 pthread_mutex_lock(&WorkerMutex); 1380 break; 1381 case WMSG_CMD_STATUS_UPDATE: 1382 work->phase = wmsg.phase; 1383 work->lines = wmsg.lines; 1384 if (work->memuse != wmsg.memuse) { 1385 RunningPkgDepSize += 1386 wmsg.memuse - work->memuse; 1387 work->memuse = wmsg.memuse; 1388 } 1389 break; 1390 case WMSG_CMD_SUCCESS: 1391 work->flags |= WORKERF_SUCCESS; 1392 break; 1393 case WMSG_CMD_FAILURE: 1394 work->flags |= WORKERF_FAILURE; 1395 break; 1396 case WMSG_CMD_FREEZEWORKER: 1397 work->flags |= WORKERF_FREEZE; 1398 break; 1399 default: 1400 break; 1401 } 1402 RunStatsUpdate(work, NULL); 1403 RunStatsSync(); 1404 } else { 1405 close(work->fds[0]); 1406 pthread_mutex_unlock(&WorkerMutex); 1407 while (waitpid(work->pid, &status, 0) < 0 && 1408 errno == EINTR) { 1409 ; 1410 } 1411 pthread_mutex_lock(&WorkerMutex); 1412 1413 if (work->flags & WORKERF_SUCCESS) { 1414 pkg->flags |= PKGF_SUCCESS; 1415 work->state = WORKER_DONE; 1416 } else if (work->flags & WORKERF_FAILURE) { 1417 pkg->flags |= PKGF_FAILURE; 1418 work->state = WORKER_DONE; 1419 } else { 1420 pkg->flags |= PKGF_FAILURE; 1421 work->state = WORKER_FAILED; 1422 } 1423 work->flags |= WORKERF_STATUS_UPDATE; 1424 pthread_cond_signal(&WorkerCond); 1425 } 1426 break; 1427 case WORKER_DONE: 1428 /* 1429 * pkg remains attached until frontend processes the 1430 * completion. The frontend will then set the state 1431 * back to idle. 1432 */ 1433 break; 1434 case WORKER_FAILED: 1435 /* 1436 * A worker failure means that the worker did not 1437 * send us a WMSG_CMD_SUCCESS or WMSG_CMD_FAILURE 1438 * ipc before terminating. 1439 * 1440 * We just sit in this state until the front-end 1441 * does something about it. 1442 */ 1443 break; 1444 case WORKER_FROZEN: 1445 /* 1446 * A worker getting frozen is debug-related. We 1447 * just sit in this state (likely forever). 1448 */ 1449 break; 1450 default: 1451 dfatal("worker: [%03d] Unexpected state %d " 1452 "for worker %d", 1453 work->index, work->state, work->index); 1454 /* NOT REACHED */ 1455 break; 1456 } 1457 1458 /* 1459 * The dsynth frontend will poll us approximately once 1460 * a second (its variable). 1461 */ 1462 if (dowait) 1463 pthread_cond_wait(&work->cond, &WorkerMutex); 1464 } 1465 1466 /* 1467 * Scrap the comm socket if running, this should cause the worker 1468 * process to kill its sub-programs and cleanup. 1469 */ 1470 if (work->state == WORKER_RUNNING) { 1471 pthread_mutex_unlock(&WorkerMutex); 1472 close(work->fds[0]); 1473 while (waitpid(work->pid, &status, 0) < 0 && 1474 errno == EINTR); 1475 pthread_mutex_lock(&WorkerMutex); 1476 } 1477 1478 /* 1479 * Final handshake 1480 */ 1481 work->state = WORKER_EXITING; 1482 pthread_cond_signal(&WorkerCond); 1483 pthread_mutex_unlock(&WorkerMutex); 1484 1485 return NULL; 1486 } 1487 1488 /* 1489 * Install all the binary packages (we have already built them) that 1490 * the current work package depends on, without duplicates, in a script 1491 * which will be run from within the specified work jail. 1492 * 1493 * Locked by WorkerMutex (global) 1494 */ 1495 static int 1496 childInstallPkgDeps(worker_t *work) 1497 { 1498 char *buf; 1499 FILE *fp; 1500 1501 if (PKGLIST_EMPTY(&work->pkg->idepon_list)) 1502 return 0; 1503 1504 asprintf(&buf, "%s/tmp/dsynth_install_pkgs", work->basedir); 1505 fp = fopen(buf, "w"); 1506 ddassert(fp != NULL); 1507 fprintf(fp, "#!/bin/sh\n"); 1508 fprintf(fp, "#\n"); 1509 fchmod(fileno(fp), 0755); 1510 1511 childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 0, 1, 0); 1512 childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 1, 1, 0); 1513 fprintf(fp, "\nexit 0\n"); 1514 fclose(fp); 1515 freestrp(&buf); 1516 1517 return 1; 1518 } 1519 1520 /* 1521 * Recursive child install dependencies. 1522 * 1523 * first_one_only is only specified if the pkg the list comes from 1524 * is a generic unflavored package that has flavors, telling us to 1525 * dive the first flavor only. 1526 * 1527 * However, in nearly all cases this flag will now be zero because 1528 * this code now dives the first flavor when encountering a dummy node 1529 * and clears nfirst on success. Hence if you are asking why 'nfirst' 1530 * is set to 1, and then zero, instead of just being removed entirely, 1531 * it is because there might still be an edge case here. 1532 */ 1533 static size_t 1534 childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list, int undoit, 1535 int depth, int first_one_only) 1536 { 1537 pkglink_t *link; 1538 pkg_t *pkg; 1539 size_t tot = 0; 1540 int ndepth; 1541 int nfirst; 1542 1543 PKGLIST_FOREACH(link, list) { 1544 pkg = link->pkg; 1545 1546 /* 1547 * We don't want to mess up our depth test just below if 1548 * a DUMMY node had to be inserted. The nodes under the 1549 * dummy node. 1550 * 1551 * The elements under a dummy node represent all the flabor, 1552 * a dependency that directly references a dummy node only 1553 * uses the first flavor (first_one_only / nfirst). 1554 */ 1555 ndepth = (pkg->flags & PKGF_DUMMY) ? depth : depth + 1; 1556 nfirst = (pkg->flags & PKGF_DUMMY) ? 1 : 0; 1557 1558 /* 1559 * We only need all packages for the top-level dependencies. 1560 * The deeper ones only need DEP_TYPE_LIB and DEP_TYPE_RUN 1561 * (types greater than DEP_TYPE_BUILD) since they are already 1562 * built. 1563 */ 1564 if (depth > 1 && link->dep_type <= DEP_TYPE_BUILD) { 1565 if (first_one_only) 1566 break; 1567 continue; 1568 } 1569 1570 /* 1571 * If this is a dummy node with no package, the originator 1572 * is requesting a flavored package. We select the default 1573 * flavor which we presume is the first one. 1574 */ 1575 if (pkg->pkgfile == NULL && (pkg->flags & PKGF_DUMMY)) { 1576 pkg_t *spkg = pkg->idepon_list.next->pkg; 1577 1578 if (spkg) { 1579 if (fp) { 1580 fprintf(fp, 1581 "echo 'UNFLAVORED %s -> use " 1582 "%s'\n", 1583 pkg->portdir, 1584 spkg->portdir); 1585 } 1586 pkg = spkg; 1587 nfirst = 0; 1588 } else { 1589 if (fp) { 1590 fprintf(fp, 1591 "echo 'CANNOT FIND DEFAULT " 1592 "FLAVOR FOR %s'\n", 1593 pkg->portdir); 1594 } 1595 } 1596 } 1597 1598 if (undoit) { 1599 if (pkg->dsynth_install_flg == 1) { 1600 pkg->dsynth_install_flg = 0; 1601 tot += childInstallPkgDeps_recurse(fp, 1602 &pkg->idepon_list, 1603 undoit, 1604 ndepth, nfirst); 1605 } 1606 if (first_one_only) 1607 break; 1608 continue; 1609 } 1610 1611 if (pkg->dsynth_install_flg) { 1612 if (DebugOpt >= 2 && pkg->pkgfile && fp) { 1613 fprintf(fp, "echo 'AlreadyHave %s'\n", 1614 pkg->pkgfile); 1615 } 1616 if (first_one_only) 1617 break; 1618 continue; 1619 } 1620 1621 tot += childInstallPkgDeps_recurse(fp, &pkg->idepon_list, 1622 undoit, ndepth, nfirst); 1623 if (pkg->dsynth_install_flg) { 1624 if (first_one_only) 1625 break; 1626 continue; 1627 } 1628 pkg->dsynth_install_flg = 1; 1629 1630 /* 1631 * Generate package installation command 1632 */ 1633 if (fp && pkg->pkgfile) { 1634 fprintf(fp, "echo 'Installing /packages/All/%s'\n", 1635 pkg->pkgfile); 1636 fprintf(fp, "pkg install -q -y /packages/All/%s " 1637 "|| exit 1\n", 1638 pkg->pkgfile); 1639 } else if (fp) { 1640 fprintf(fp, "echo 'CANNOT FIND PKG FOR %s'\n", 1641 pkg->portdir); 1642 } 1643 1644 if (pkg->pkgfile) { 1645 struct stat st; 1646 char *path; 1647 char *ptr; 1648 1649 asprintf(&path, "%s/%s", RepositoryPath, pkg->pkgfile); 1650 ptr = strrchr(pkg->pkgfile, '.'); 1651 if (stat(path, &st) == 0) { 1652 if (strcmp(ptr, ".tar") == 0) 1653 tot += st.st_size; 1654 else if (strcmp(ptr, ".tgz") == 0) 1655 tot += st.st_size * 3; 1656 else if (strcmp(ptr, ".txz") == 0) 1657 tot += st.st_size * 5; 1658 else if (strcmp(ptr, ".tbz") == 0) 1659 tot += st.st_size * 3; 1660 else 1661 tot += st.st_size * 2; 1662 } 1663 free(path); 1664 } 1665 if (first_one_only) 1666 break; 1667 } 1668 return tot; 1669 } 1670 1671 /* 1672 * Worker process interactions. 1673 * 1674 * The worker process is responsible for managing the build of a single 1675 * package. It is exec'd by the master dsynth and only loads the 1676 * configuration. 1677 * 1678 * This process does not run in the chroot. It will become the reaper for 1679 * all sub-processes and it will enter the chroot to execute various phases. 1680 * It catches SIGINTR, SIGHUP, and SIGPIPE and will iterate, terminate, and 1681 * reap all sub-process upon kill or exit. 1682 * 1683 * The command line forwarded to this function is: 1684 * 1685 * WORKER slot# socketfd portdir/subdir 1686 * 1687 * TERM=dumb 1688 * USER=root 1689 * HOME=/root 1690 * LANG=C 1691 * SSL_NO_VERIFY_PEER=1 1692 * USE_PACKAGE_DEPENDS_ONLY=1 1693 * PORTSDIR=/xports 1694 * PORT_DBDIR=/options For ports options 1695 * PACKAGE_BUILDING=yes Don't build packages that aren't legally 1696 * buildable for a binary repo. 1697 * PKG_DBDIR=/var/db/pkg 1698 * PKG_CACHEDIR=/var/cache/pkg 1699 * PKG_CREATE_VERBOSE=yes Ensure periodic output during packaging 1700 * (custom environment) 1701 * PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin 1702 * UNAME_s=DragonFly (example) 1703 * UNAME_v=DragonFly 5.7-SYNTH (example) 1704 * UNAME_p=x86_64 (example) 1705 * UNAME_m=x86_64 (example) 1706 * UNAME_r=5.7-SYNTH (example) 1707 * NO_DEPENDS=yes (conditional based on phase) 1708 * DISTDIR=/distfiles 1709 * WRKDIRPREFIX=/construction 1710 * BATCH=yes 1711 * MAKE_JOBS_NUMBER=n 1712 * 1713 * SETUP: 1714 * ldconfig -R 1715 * /usr/local/sbin/pkg-static install /packages/All/<the pkg pkg> 1716 * /usr/local/sbin/pkg-static install /packages/All/<pkg> 1717 * (for all dependencies) 1718 * 1719 * PHASES: make -C path FLAVOR=flavor <phase> 1720 * check-sanity 1721 * pkg-depends 1722 * fetch-depends 1723 * fetch 1724 * checksum 1725 * extract-depends 1726 * extract 1727 * patch-depends 1728 * patch 1729 * build-depends 1730 * lib-depends 1731 * configure 1732 * build 1733 * run-depends 1734 * stage 1735 * test (skipped) 1736 * check-plist ('dsynth test blahblah' or 'dsynth -D everything' only) 1737 * package e.g. /construction/lang/perl5.28/pkg/perl5-5.28.2.txz 1738 * install-mtree (skipped) 1739 * install (skipped) 1740 * deinstall (skipped) 1741 */ 1742 void 1743 WorkerProcess(int ac, char **av) 1744 { 1745 wmsg_t wmsg; 1746 int fd; 1747 int slot; 1748 int tmpfd; 1749 int pkgpkg = 0; 1750 int status; 1751 int len; 1752 int do_install_phase; 1753 char *portdir; 1754 char *pkgfile; 1755 char *flavor; 1756 char *buf; 1757 worker_t *work; 1758 bulk_t *bulk; 1759 pkg_t pkg; 1760 buildenv_t *benv; 1761 FILE *fp; 1762 1763 /* 1764 * Parse arguments 1765 */ 1766 if (ac != 6) { 1767 dlog(DLOG_ALL, "WORKER PROCESS %d- bad arguments\n", getpid()); 1768 exit(1); 1769 } 1770 slot = strtol(av[1], NULL, 0); 1771 fd = strtol(av[2], NULL, 0); /* master<->slave messaging */ 1772 portdir = av[3]; 1773 pkgfile = av[4]; 1774 flavor = strchr(portdir, '@'); 1775 if (flavor) { 1776 *flavor++ = 0; 1777 asprintf(&buf, "@%s", flavor); 1778 WorkerFlavorPrt = buf; 1779 buf = NULL; /* safety */ 1780 } 1781 WorkerProcFlags = strtol(av[5], NULL, 0); 1782 1783 bzero(&wmsg, sizeof(wmsg)); 1784 1785 setproctitle("[%02d] WORKER STARTUP %s%s", 1786 slot, portdir, WorkerFlavorPrt); 1787 1788 if (strcmp(portdir, "ports-mgmt/pkg") == 0) 1789 pkgpkg = 1; 1790 1791 signal(SIGTERM, phaseTerminateSignal); 1792 signal(SIGINT, phaseTerminateSignal); 1793 signal(SIGHUP, phaseTerminateSignal); 1794 1795 /* 1796 * Set up the environment 1797 */ 1798 setenv("TERM", "dumb", 1); 1799 setenv("USER", "root", 1); 1800 setenv("HOME", "/root", 1); 1801 setenv("LANG", "C", 1); 1802 setenv("SSL_NO_VERIFY_PEER", "1", 1); 1803 1804 addbuildenv("USE_PACKAGE_DEPENDS_ONLY", "yes", BENV_MAKECONF); 1805 addbuildenv("PORTSDIR", "/xports", BENV_MAKECONF); 1806 addbuildenv("PORT_DBDIR", "/options", BENV_MAKECONF); 1807 addbuildenv("PKG_DBDIR", "/var/db/pkg", BENV_MAKECONF); 1808 addbuildenv("PKG_CACHEDIR", "/var/cache/pkg", BENV_MAKECONF); 1809 addbuildenv("PKG_SUFX", UsePkgSufx, BENV_MAKECONF); 1810 if (WorkerProcFlags & WORKER_PROC_DEVELOPER) 1811 addbuildenv("DEVELOPER", "1", BENV_MAKECONF); 1812 1813 /* 1814 * CCache is a horrible unreliable hack but... leave the 1815 * mechanism in-place in case someone has a death wish. 1816 */ 1817 if (UseCCache) { 1818 addbuildenv("WITH_CCACHE_BUILD", "yes", BENV_MAKECONF); 1819 addbuildenv("CCACHE_DIR", "/ccache", BENV_MAKECONF); 1820 } 1821 1822 addbuildenv("UID", "0", BENV_MAKECONF); 1823 addbuildenv("ARCH", ArchitectureName, BENV_MAKECONF); 1824 1825 #ifdef __DragonFly__ 1826 addbuildenv("OPSYS", "DragonFly", BENV_MAKECONF); 1827 addbuildenv("DFLYVERSION", VersionFromParamHeader, BENV_MAKECONF); 1828 addbuildenv("OSVERSION", "9999999", BENV_MAKECONF); 1829 #else 1830 #error "Need OS-specific data to generate make.conf" 1831 #endif 1832 1833 addbuildenv("OSREL", ReleaseName, BENV_MAKECONF); 1834 addbuildenv("_OSRELEASE", VersionOnlyName, BENV_MAKECONF); 1835 1836 setenv("PATH", 1837 "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin", 1838 1); 1839 1840 setenv("UNAME_s", OperatingSystemName, 1); 1841 setenv("UNAME_v", VersionName, 1); 1842 setenv("UNAME_p", ArchitectureName, 1); 1843 setenv("UNAME_m", MachineName, 1); 1844 setenv("UNAME_r", ReleaseName, 1); 1845 1846 addbuildenv("DISTDIR", "/distfiles", BENV_MAKECONF); 1847 addbuildenv("WRKDIRPREFIX", "/construction", BENV_MAKECONF); 1848 addbuildenv("BATCH", "yes", BENV_MAKECONF); 1849 1850 /* 1851 * Special consideration 1852 * 1853 * PACKAGE_BUILDING - Disallow packaging ports which do not allow 1854 * for binary distribution. 1855 * 1856 * PKG_CREATE_VERBOSE - Ensure periodic output during the packaging 1857 * process to avoid a watchdog timeout. 1858 * 1859 */ 1860 addbuildenv("PACKAGE_BUILDING", "yes", BENV_MAKECONF); 1861 addbuildenv("PKG_CREATE_VERBOSE", "yes", BENV_MAKECONF); 1862 asprintf(&buf, "%d", MaxJobs); 1863 addbuildenv("MAKE_JOBS_NUMBER", buf, BENV_MAKECONF); 1864 freestrp(&buf); 1865 1866 if (flavor) 1867 setenv("FLAVOR", flavor, 1); 1868 1869 /* 1870 * Become the reaper 1871 */ 1872 if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) < 0) 1873 dfatal_errno("procctl() - Cannot become reaper"); 1874 1875 /* 1876 * Initialize a worker structure 1877 */ 1878 DoInitBuild(slot); 1879 1880 bzero(&pkg, sizeof(pkg)); 1881 pkg.portdir = portdir; /* sans flavor */ 1882 pkg.pkgfile = pkgfile; 1883 if (strchr(portdir, '/')) 1884 len = strchr(portdir, '/') - portdir; 1885 else 1886 len = 0; 1887 1888 /* 1889 * Setup the logfile 1890 */ 1891 asprintf(&pkg.logfile, 1892 "%s/%*.*s___%s%s%s.log", 1893 LogsPath, len, len, portdir, 1894 ((portdir[len] == '/') ? portdir + len + 1 : portdir + len), 1895 (flavor ? "@" : ""), 1896 (flavor ? flavor : "")); 1897 tmpfd = open(pkg.logfile, O_RDWR|O_CREAT|O_TRUNC, 0666); 1898 if (tmpfd >= 0) { 1899 if (DebugOpt >= 2) { 1900 dlog(DLOG_ALL, "[%03d] %s LOGFILE %s\n", 1901 slot, pkg.portdir, pkg.logfile); 1902 } 1903 close(tmpfd); 1904 } else { 1905 dlog(DLOG_ALL, "[%03d] LOGFILE %s (create failed)\n", 1906 slot, pkg.logfile); 1907 } 1908 1909 /* 1910 * Setup the work structure. Because this is an exec'd sub-process, 1911 * there is only one work structure. 1912 */ 1913 work = &WorkerAry[0]; 1914 work->flavor = flavor; 1915 work->fds[0] = fd; 1916 work->pkg = &pkg; 1917 work->start_time = time(NULL); 1918 1919 /* 1920 * Do mounts 1921 */ 1922 SigWork = work; 1923 setproctitle("[%02d] WORKER MOUNTS %s%s", 1924 slot, portdir, WorkerFlavorPrt); 1925 DoWorkerMounts(work); 1926 1927 /* 1928 * Generate an /etc/make.conf in the build base 1929 */ 1930 asprintf(&buf, "%s/etc/make.conf", work->basedir); 1931 fp = fopen(buf, "w"); 1932 dassert_errno(fp, "Unable to create %s\n", buf); 1933 for (benv = BuildEnv; benv; benv = benv->next) { 1934 if (benv->type & BENV_PKGLIST) 1935 continue; 1936 if ((benv->type & BENV_CMDMASK) == BENV_MAKECONF) { 1937 if (DebugOpt >= 2) { 1938 dlog(DLOG_ALL, "[%03d] ENV %s=%s\n", 1939 slot, benv->label, benv->data); 1940 } 1941 fprintf(fp, "%s=%s\n", benv->label, benv->data); 1942 } 1943 } 1944 fclose(fp); 1945 freestrp(&buf); 1946 1947 /* 1948 * Set up our hooks 1949 */ 1950 if (UsingHooks) 1951 initbulk(childHookRun, MaxBulk); 1952 1953 /* 1954 * Start phases 1955 */ 1956 wmsg.cmd = WMSG_CMD_INSTALL_PKGS; 1957 ipcwritemsg(fd, &wmsg); 1958 status = ipcreadmsg(fd, &wmsg); 1959 if (status < 0 || wmsg.cmd != WMSG_RES_INSTALL_PKGS) 1960 dfatal("pkg installation handshake failed"); 1961 do_install_phase = wmsg.status; 1962 1963 wmsg.cmd = WMSG_CMD_STATUS_UPDATE; 1964 wmsg.phase = PHASE_INSTALL_PKGS; 1965 wmsg.lines = 0; 1966 1967 status = ipcwritemsg(fd, &wmsg); 1968 1969 if (pkgpkg) { 1970 dophase(work, &wmsg, 1971 WDOG5, PHASE_PACKAGE, "package"); 1972 } else { 1973 if (do_install_phase) { 1974 dophase(work, &wmsg, 1975 WDOG4, PHASE_INSTALL_PKGS, "setup"); 1976 } 1977 dophase(work, &wmsg, 1978 WDOG2, PHASE_CHECK_SANITY, "check-sanity"); 1979 dophase(work, &wmsg, 1980 WDOG2, PHASE_PKG_DEPENDS, "pkg-depends"); 1981 dophase(work, &wmsg, 1982 WDOG7, PHASE_FETCH_DEPENDS, "fetch-depends"); 1983 dophase(work, &wmsg, 1984 WDOG7, PHASE_FETCH, "fetch"); 1985 dophase(work, &wmsg, 1986 WDOG2, PHASE_CHECKSUM, "checksum"); 1987 dophase(work, &wmsg, 1988 WDOG3, PHASE_EXTRACT_DEPENDS, "extract-depends"); 1989 dophase(work, &wmsg, 1990 WDOG3, PHASE_EXTRACT, "extract"); 1991 dophase(work, &wmsg, 1992 WDOG2, PHASE_PATCH_DEPENDS, "patch-depends"); 1993 dophase(work, &wmsg, 1994 WDOG2, PHASE_PATCH, "patch"); 1995 dophase(work, &wmsg, 1996 WDOG5, PHASE_BUILD_DEPENDS, "build-depends"); 1997 dophase(work, &wmsg, 1998 WDOG5, PHASE_LIB_DEPENDS, "lib-depends"); 1999 dophase(work, &wmsg, 2000 WDOG3, PHASE_CONFIGURE, "configure"); 2001 dophase(work, &wmsg, 2002 WDOG9, PHASE_BUILD, "build"); 2003 dophase(work, &wmsg, 2004 WDOG5, PHASE_RUN_DEPENDS, "run-depends"); 2005 dophase(work, &wmsg, 2006 WDOG5, PHASE_STAGE, "stage"); 2007 #if 0 2008 dophase(work, &wmsg, 2009 WDOG5, PHASE_TEST, "test"); 2010 #endif 2011 if (WorkerProcFlags & WORKER_PROC_CHECK_PLIST) { 2012 dophase(work, &wmsg, 2013 WDOG1, PHASE_CHECK_PLIST, "check-plist"); 2014 } 2015 dophase(work, &wmsg, 2016 WDOG5, PHASE_PACKAGE, "package"); 2017 #if 0 2018 dophase(work, &wmsg, 2019 WDOG5, PHASE_INSTALL_MTREE, "install-mtree"); 2020 dophase(work, &wmsg, 2021 WDOG5, PHASE_INSTALL, "install"); 2022 dophase(work, &wmsg, 2023 WDOG5, PHASE_DEINSTALL, "deinstall"); 2024 #endif 2025 } 2026 2027 if (MasterPtyFd >= 0) { 2028 close(MasterPtyFd); 2029 MasterPtyFd = -1; 2030 } 2031 2032 setproctitle("[%02d] WORKER CLEANUP %s%s", 2033 slot, portdir, WorkerFlavorPrt); 2034 2035 /* 2036 * Copy the package to the repo. 2037 */ 2038 if (work->accum_error == 0) { 2039 char *b1; 2040 char *b2; 2041 2042 asprintf(&b1, "%s/construction/%s/pkg/%s", 2043 work->basedir, pkg.portdir, pkg.pkgfile); 2044 asprintf(&b2, "%s/%s", RepositoryPath, pkg.pkgfile); 2045 if (copyfile(b1, b2)) { 2046 ++work->accum_error; 2047 dlog(DLOG_ALL, "[%03d] %s Unable to copy %s to %s\n", 2048 work->index, pkg.portdir, b1, b2); 2049 } 2050 free(b1); 2051 free(b2); 2052 } 2053 2054 /* 2055 * Unmount, unless we are in DebugStopMode. 2056 */ 2057 if ((WorkerProcFlags & WORKER_PROC_DEBUGSTOP) == 0) 2058 DoWorkerUnmounts(work); 2059 2060 /* 2061 * Send completion status to master dsynth worker thread. 2062 */ 2063 if (work->accum_error) { 2064 wmsg.cmd = WMSG_CMD_FAILURE; 2065 } else { 2066 wmsg.cmd = WMSG_CMD_SUCCESS; 2067 } 2068 ipcwritemsg(fd, &wmsg); 2069 if (WorkerProcFlags & WORKER_PROC_DEBUGSTOP) { 2070 wmsg.cmd = WMSG_CMD_FREEZEWORKER; 2071 ipcwritemsg(fd, &wmsg); 2072 } 2073 if (UsingHooks) { 2074 while ((bulk = getbulk()) != NULL) 2075 freebulk(bulk); 2076 donebulk(); 2077 } 2078 } 2079 2080 static void 2081 dophase(worker_t *work, wmsg_t *wmsg, int wdog, int phaseid, const char *phase) 2082 { 2083 pkg_t *pkg = work->pkg; 2084 char buf[1024]; 2085 pid_t pid; 2086 int status; 2087 int ms; 2088 pid_t wpid; 2089 int wpid_reaped; 2090 int fdlog; 2091 time_t start_time; 2092 time_t last_time; 2093 time_t next_time; 2094 time_t wdog_time; 2095 FILE *fp; 2096 2097 if (work->accum_error) 2098 return; 2099 setproctitle("[%02d] WORKER %-8.8s %s%s", 2100 work->index, phase, pkg->portdir, WorkerFlavorPrt); 2101 wmsg->phase = phaseid; 2102 if (ipcwritemsg(work->fds[0], wmsg) < 0) { 2103 dlog(DLOG_ALL, "[%03d] %s Lost Communication with dsynth, " 2104 "aborting worker\n", 2105 work->index, pkg->portdir); 2106 ++work->accum_error; 2107 return; 2108 } 2109 2110 /* 2111 * Execute the port make command in chroot on a pty. 2112 */ 2113 fflush(stdout); 2114 fflush(stderr); 2115 if (MasterPtyFd >= 0) { 2116 int slavefd; 2117 2118 /* 2119 * NOTE: We can't open the slave in the child because the 2120 * master may race a disconnection test. If we open 2121 * it in the parent our close() will flush any pending 2122 * output not read by the master (which is the same 2123 * parent process) and deadlock. 2124 * 2125 * Solve this by hand-shaking the slave tty to give 2126 * the master time to close its slavefd (after this 2127 * section). 2128 * 2129 * Leave the tty defaults intact, which also likely 2130 * means it will be in line-buffered mode, so handshake 2131 * with a full line. 2132 * 2133 * TODO: Our handshake probably echos back to the master pty 2134 * due to tty echo, and ends up in the log, so just 2135 * pass through a newline. 2136 */ 2137 slavefd = open(ptsname(MasterPtyFd), O_RDWR); 2138 dassert_errno(slavefd >= 0, "Cannot open slave pty"); 2139 2140 /* 2141 * Now do the fork. 2142 */ 2143 pid = fork(); 2144 if (pid == 0) { 2145 login_tty(slavefd); 2146 /* login_tty() closes slavefd */ 2147 } else { 2148 close(slavefd); 2149 } 2150 } else { 2151 /* 2152 * Initial MasterPtyFd for the slot, just use forkpty(). 2153 */ 2154 pid = forkpty(&MasterPtyFd, NULL, NULL, NULL); 2155 } 2156 2157 /* 2158 * The slave must make sure the master has time to close slavefd 2159 * in the re-use case before going its merry way. The master needs 2160 * to set terminal modes and the window as well. 2161 */ 2162 if (pid == 0) { 2163 /* 2164 * Slave waits for handshake 2165 */ 2166 char ttybuf[2]; 2167 2168 read(0, ttybuf, 1); 2169 } else { 2170 /* 2171 * We are going through a pty, so set the tty modes to 2172 * Set tty modes so we do not get ^M's in the log files. 2173 * 2174 * This isn't fatal if it doesn't work. Remember that 2175 * our output goes through the pty to the management 2176 * process which will log it. 2177 */ 2178 struct termios tio; 2179 struct winsize win; 2180 2181 if (tcgetattr(MasterPtyFd, &tio) == 0) { 2182 tio.c_oflag |= OPOST | ONOCR; 2183 tio.c_oflag &= ~(OCRNL | ONLCR); 2184 tio.c_iflag |= ICRNL; 2185 tio.c_iflag &= ~(INLCR | IGNCR); 2186 if (tcsetattr(MasterPtyFd, TCSANOW, &tio)) { 2187 printf("tcsetattr failed: %s\n", 2188 strerror(errno)); 2189 } 2190 2191 /* 2192 * Give the tty a non-zero columns field. 2193 * This fixes at least one port (textproc/po4a) 2194 */ 2195 if (ioctl(MasterPtyFd, TIOCGWINSZ, &win) == 0) { 2196 win.ws_col = 80; 2197 ioctl(MasterPtyFd, TIOCSWINSZ, &win); 2198 } else { 2199 printf("TIOCGWINSZ failed: %s\n", 2200 strerror(errno)); 2201 } 2202 2203 } else { 2204 printf("tcgetattr failed: %s\n", strerror(errno)); 2205 } 2206 2207 /* 2208 * Master issues handshake 2209 */ 2210 write(MasterPtyFd, "\n", 1); 2211 } 2212 2213 if (pid == 0) { 2214 /* 2215 * Additional phase-specific environment variables 2216 * 2217 * - Do not try to process missing depends outside of the 2218 * depends phases. Also relies on USE_PACKAGE_DEPENDS_ONLY 2219 * in the make.conf. 2220 */ 2221 switch(phaseid) { 2222 case PHASE_CHECK_SANITY: 2223 case PHASE_FETCH: 2224 case PHASE_CHECKSUM: 2225 case PHASE_EXTRACT: 2226 case PHASE_PATCH: 2227 case PHASE_CONFIGURE: 2228 case PHASE_STAGE: 2229 case PHASE_TEST: 2230 case PHASE_CHECK_PLIST: 2231 case PHASE_INSTALL_MTREE: 2232 case PHASE_INSTALL: 2233 case PHASE_DEINSTALL: 2234 break; 2235 case PHASE_PKG_DEPENDS: 2236 case PHASE_FETCH_DEPENDS: 2237 case PHASE_EXTRACT_DEPENDS: 2238 case PHASE_PATCH_DEPENDS: 2239 case PHASE_BUILD_DEPENDS: 2240 case PHASE_LIB_DEPENDS: 2241 case PHASE_RUN_DEPENDS: 2242 break; 2243 default: 2244 setenv("NO_DEPENDS", "1", 1); 2245 break; 2246 } 2247 2248 /* 2249 * Clean-up, chdir, and chroot. 2250 */ 2251 closefrom(3); 2252 if (chdir(work->basedir) < 0) 2253 dfatal_errno("chdir in phase initialization"); 2254 if (chroot(work->basedir) < 0) 2255 dfatal_errno("chroot in phase initialization"); 2256 2257 /* 2258 * We have a choice here on how to handle stdin (fd 0). 2259 * We can leave it connected to the pty in which case 2260 * the build will just block if it tries to ask a 2261 * question (and the watchdog will kill it, eventually), 2262 * or we can try to EOF the pty, or we can attach /dev/null 2263 * to descriptor 0. 2264 */ 2265 if (NullStdinOpt) { 2266 int fd; 2267 2268 fd = open("/dev/null", O_RDWR); 2269 dassert_errno(fd >= 0, "cannot open /dev/null"); 2270 if (fd != 0) { 2271 dup2(fd, 0); 2272 close(fd); 2273 } 2274 } 2275 2276 /* 2277 * Execute the appropriate command. 2278 */ 2279 switch(phaseid) { 2280 case PHASE_INSTALL_PKGS: 2281 snprintf(buf, sizeof(buf), "/tmp/dsynth_install_pkgs"); 2282 execl(buf, buf, NULL); 2283 break; 2284 default: 2285 snprintf(buf, sizeof(buf), "/xports/%s", pkg->portdir); 2286 execl(MAKE_BINARY, MAKE_BINARY, "-C", buf, phase, NULL); 2287 break; 2288 } 2289 _exit(1); 2290 } 2291 fcntl(MasterPtyFd, F_SETFL, O_NONBLOCK); 2292 2293 if (pid < 0) { 2294 dlog(DLOG_ALL, "[%03d] %s Fork Failed: %s\n", 2295 work->index, pkg->logfile, strerror(errno)); 2296 ++work->accum_error; 2297 return; 2298 } 2299 2300 SigPid = pid; 2301 2302 fdlog = open(pkg->logfile, O_RDWR|O_CREAT|O_APPEND, 0644); 2303 if (fdlog < 0) { 2304 dlog(DLOG_ALL, "[%03d] %s Cannot open logfile '%s': %s\n", 2305 work->index, pkg->portdir, 2306 pkg->logfile, strerror(errno)); 2307 } 2308 2309 snprintf(buf, sizeof(buf), 2310 "----------------------------------------" 2311 "---------------------------------------\n" 2312 "-- Phase: %s\n" 2313 "----------------------------------------" 2314 "---------------------------------------\n", 2315 phase); 2316 write(fdlog, buf, strlen(buf)); 2317 2318 start_time = time(NULL); 2319 last_time = start_time; 2320 wdog_time = start_time; 2321 wpid_reaped = 0; 2322 2323 status = 0; 2324 for (;;) { 2325 ms = mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time); 2326 if (ms == MPTY_FAILED) { 2327 dlog(DLOG_ALL, 2328 "[%03d] %s lost pty in phase %s, terminating\n", 2329 work->index, pkg->portdir, phase); 2330 break; 2331 } 2332 if (ms == MPTY_EOF) 2333 break; 2334 2335 /* 2336 * Generally speaking update status once a second. 2337 * This also allows us to detect if the management 2338 * dsynth process has gone away. 2339 */ 2340 next_time = time(NULL); 2341 if (next_time != last_time) { 2342 double dload[3]; 2343 double dv; 2344 int wdog_scaled; 2345 2346 /* 2347 * Send status update to the worker management thread 2348 * in the master dsynth process. Remember, *WE* are 2349 * the worker management process sub-fork. 2350 */ 2351 if (ipcwritemsg(work->fds[0], wmsg) < 0) 2352 break; 2353 last_time = next_time; 2354 2355 /* 2356 * Watchdog scaling 2357 */ 2358 getloadavg(dload, 3); 2359 dv = dload[2] / NumCores; 2360 if (dv < (double)NumCores) { 2361 wdog_scaled = wdog; 2362 } else { 2363 if (dv > 4.0 * NumCores) 2364 dv = 4.0 * NumCores; 2365 wdog_scaled = wdog * dv / NumCores; 2366 } 2367 2368 /* 2369 * Watchdog 2370 */ 2371 if (next_time - wdog_time >= wdog_scaled * 60) { 2372 snprintf(buf, sizeof(buf), 2373 "\n--------\n" 2374 "WATCHDOG TIMEOUT FOR %s in %s " 2375 "after %d minutes\n" 2376 "Killing pid %d\n" 2377 "--------\n", 2378 pkg->portdir, phase, wdog_scaled, pid); 2379 if (fdlog >= 0) 2380 write(fdlog, buf, strlen(buf)); 2381 dlog(DLOG_ALL, 2382 "[%03d] %s WATCHDOG TIMEOUT in %s " 2383 "after %d minutes (%d min scaled)\n", 2384 work->index, pkg->portdir, phase, 2385 wdog, wdog_scaled); 2386 kill(pid, SIGKILL); 2387 ++work->accum_error; 2388 break; 2389 } 2390 } 2391 2392 /* 2393 * Check process exit. Normally the pty will EOF 2394 * but if background processes remain we need to 2395 * check here to see if our primary exec is done, 2396 * so we can break out and reap those processes. 2397 * 2398 * Generally reap any other processes we have inherited 2399 * while we are here. 2400 */ 2401 do { 2402 wpid = wait3(&status, WNOHANG, NULL); 2403 } while (wpid > 0 && wpid != pid); 2404 if (wpid == pid && WIFEXITED(status)) { 2405 wpid_reaped = 1; 2406 break; 2407 } 2408 } 2409 2410 next_time = time(NULL); 2411 2412 setproctitle("[%02d] WORKER EXITREAP %s%s", 2413 work->index, pkg->portdir, WorkerFlavorPrt); 2414 2415 /* 2416 * We usually get here due to a mpty EOF, but not always as there 2417 * could be persistent processes still holding the slave. Finish 2418 * up getting the exit status for the main process we are waiting 2419 * on and clean out any data left on the MasterPtyFd (as it could 2420 * be blocking the exit). 2421 */ 2422 while (wpid_reaped == 0) { 2423 (void)mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time); 2424 wpid = waitpid(pid, &status, WNOHANG); 2425 if (wpid == pid && WIFEXITED(status)) { 2426 wpid_reaped = 1; 2427 break; 2428 } 2429 if (wpid < 0 && errno != EINTR) { 2430 break; 2431 } 2432 2433 /* 2434 * Safety. The normal phase waits until the fork/exec'd 2435 * pid finishes, causing a pty EOF on exit (the slave 2436 * descriptor is closed by the kernel on exit so the 2437 * process should already have exited). 2438 * 2439 * However, it is also possible to get here if the pty fails 2440 * for some reason. In this case, make sure that the process 2441 * is killed. 2442 */ 2443 kill(pid, SIGKILL); 2444 } 2445 2446 /* 2447 * Clean out anything left on the pty but don't wait around 2448 * because there could be background processes preventing the 2449 * slave side from closing. 2450 */ 2451 while (mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time) == MPTY_DATA) 2452 ; 2453 2454 /* 2455 * Report on the exit condition. If the pid was somehow lost 2456 * (probably due to someone gdb'ing the process), assume an error. 2457 */ 2458 if (wpid_reaped) { 2459 if (WEXITSTATUS(status)) { 2460 dlog(DLOG_ALL | DLOG_FILTER, 2461 "[%03d] %s Build phase '%s' failed exit %d\n", 2462 work->index, pkg->portdir, phase, 2463 WEXITSTATUS(status)); 2464 ++work->accum_error; 2465 } 2466 } else { 2467 dlog(DLOG_ALL, "[%03d] %s Build phase '%s' failed - lost pid\n", 2468 work->index, pkg->portdir, phase); 2469 ++work->accum_error; 2470 } 2471 2472 /* 2473 * Kill any processes still running (sometimes processes end up in 2474 * the background during a dports build), and clean up any other 2475 * children that we have inherited. 2476 */ 2477 phaseReapAll(); 2478 2479 /* 2480 * After the extraction phase add the space used by /construction 2481 * to the memory use. This helps us reduce the amount of paging 2482 * we do due to extremely large package extractions (languages, 2483 * chromium, etc). 2484 * 2485 * (dsynth already estimated the space used by the package deps 2486 * up front, but this will help us further). 2487 */ 2488 if (work->accum_error == 0 && phaseid == PHASE_EXTRACT) { 2489 struct statfs sfs; 2490 char *b1; 2491 2492 asprintf(&b1, "%s/construction", work->basedir); 2493 if (statfs(b1, &sfs) == 0) { 2494 wmsg->memuse = (sfs.f_blocks - sfs.f_bfree) * 2495 sfs.f_bsize; 2496 ipcwritemsg(work->fds[0], wmsg); 2497 } 2498 } 2499 2500 /* 2501 * Update log 2502 */ 2503 if (fdlog >= 0) { 2504 struct stat st; 2505 int h; 2506 int m; 2507 int s; 2508 2509 last_time = next_time - start_time; 2510 s = last_time % 60; 2511 m = last_time / 60 % 60; 2512 h = last_time / 3600; 2513 2514 fp = fdopen(fdlog, "a"); 2515 if (fp == NULL) { 2516 dlog(DLOG_ALL, "[%03d] %s Cannot fdopen fdlog: %s %d\n", 2517 work->index, pkg->portdir, 2518 strerror(errno), fstat(fdlog, &st)); 2519 close(fdlog); 2520 goto skip; 2521 } 2522 2523 fprintf(fp, "\n"); 2524 if (work->accum_error) { 2525 fprintf(fp, "FAILED %02d:%02d:%02d\n", h, m, s); 2526 } else { 2527 if (phaseid == PHASE_EXTRACT && wmsg->memuse) { 2528 fprintf(fp, "Extracted Memory Use: %6.2fM\n", 2529 wmsg->memuse / (1024.0 * 1024.0)); 2530 } 2531 fprintf(fp, "SUCCEEDED %02d:%02d:%02d\n", h, m, s); 2532 } 2533 last_time = next_time - work->start_time; 2534 s = last_time % 60; 2535 m = last_time / 60 % 60; 2536 h = last_time / 3600; 2537 if (phaseid == PHASE_PACKAGE) { 2538 fprintf(fp, "TOTAL TIME %02d:%02d:%02d\n", h, m, s); 2539 } 2540 fprintf(fp, "\n"); 2541 fclose(fp); 2542 skip: 2543 ; 2544 } 2545 2546 } 2547 2548 static void 2549 phaseReapAll(void) 2550 { 2551 struct reaper_status rs; 2552 int status; 2553 2554 while (procctl(P_PID, getpid(), PROC_REAP_STATUS, &rs) == 0) { 2555 if ((rs.flags & PROC_REAP_ACQUIRE) == 0) 2556 break; 2557 if (rs.pid_head < 0) 2558 break; 2559 if (kill(rs.pid_head, SIGKILL) == 0) { 2560 while (waitpid(rs.pid_head, &status, 0) < 0) 2561 ; 2562 } 2563 } 2564 while (wait3(&status, 0, NULL) > 0) 2565 ; 2566 } 2567 2568 static void 2569 phaseTerminateSignal(int sig __unused) 2570 { 2571 if (CopyFileFd >= 0) 2572 close(CopyFileFd); 2573 if (MasterPtyFd >= 0) 2574 close(MasterPtyFd); 2575 if (SigPid > 1) 2576 kill(SigPid, SIGKILL); 2577 phaseReapAll(); 2578 if (SigWork) 2579 DoWorkerUnmounts(SigWork); 2580 exit(1); 2581 } 2582 2583 static 2584 char * 2585 buildskipreason(pkglink_t *parent, pkg_t *pkg) 2586 { 2587 pkglink_t *link; 2588 pkg_t *scan; 2589 char *reason = NULL; 2590 char *ptr; 2591 size_t tot; 2592 size_t len; 2593 pkglink_t stack; 2594 2595 if ((pkg->flags & PKGF_NOBUILD_I) && pkg->ignore) 2596 asprintf(&reason, "%s ", pkg->ignore); 2597 2598 tot = 0; 2599 PKGLIST_FOREACH(link, &pkg->idepon_list) { 2600 #if 0 2601 if (link->dep_type > DEP_TYPE_BUILD) 2602 continue; 2603 #endif 2604 scan = link->pkg; 2605 if (scan == NULL) 2606 continue; 2607 if ((scan->flags & (PKGF_ERROR | PKGF_NOBUILD)) == 0) 2608 continue; 2609 if (scan->flags & PKGF_NOBUILD) { 2610 stack.pkg = scan; 2611 stack.next = parent; 2612 ptr = buildskipreason(&stack, scan); 2613 len = strlen(scan->portdir) + strlen(ptr) + 8; 2614 reason = realloc(reason, tot + len); 2615 snprintf(reason + tot, len, "%s->%s", 2616 scan->portdir, ptr); 2617 free(ptr); 2618 } else { 2619 len = strlen(scan->portdir) + 8; 2620 reason = realloc(reason, tot + len); 2621 snprintf(reason + tot, len, "%s", scan->portdir); 2622 } 2623 2624 /* 2625 * Don't try to print the entire graph 2626 */ 2627 if (parent) 2628 break; 2629 tot += strlen(reason + tot); 2630 reason[tot++] = ' '; 2631 reason[tot] = 0; 2632 } 2633 return (reason); 2634 } 2635 2636 /* 2637 * Count number of packages that would be skipped due to the 2638 * specified package having failed. 2639 * 2640 * Call with mode 1 to count, and mode 0 to clear the 2641 * cumulative rscan flag (used to de-duplicate the count). 2642 * 2643 * Must be serialized. 2644 */ 2645 static int 2646 buildskipcount_dueto(pkg_t *pkg, int mode) 2647 { 2648 pkglink_t *link; 2649 pkg_t *scan; 2650 int total; 2651 2652 total = 0; 2653 PKGLIST_FOREACH(link, &pkg->deponi_list) { 2654 scan = link->pkg; 2655 if (scan == NULL || scan->rscan == mode) 2656 continue; 2657 scan->rscan = mode; 2658 ++total; 2659 total += buildskipcount_dueto(scan, mode); 2660 } 2661 return total; 2662 } 2663 2664 /* 2665 * The master ptyfd is in non-blocking mode. Drain up to 1024 bytes 2666 * and update wmsg->lines and *wdog_timep as appropriate. 2667 * 2668 * This function will poll, stalling up to 1 second. 2669 */ 2670 static int 2671 mptylogpoll(int ptyfd, int fdlog, wmsg_t *wmsg, time_t *wdog_timep) 2672 { 2673 struct pollfd pfd; 2674 char buf[1024]; 2675 ssize_t r; 2676 2677 pfd.fd = ptyfd; 2678 pfd.events = POLLIN; 2679 pfd.revents = 0; 2680 2681 poll(&pfd, 1, 1000); 2682 if (pfd.revents) { 2683 r = read(ptyfd, buf, sizeof(buf)); 2684 if (r > 0) { 2685 *wdog_timep = time(NULL); 2686 if (r > 0 && fdlog >= 0) 2687 write(fdlog, buf, r); 2688 while (--r >= 0) { 2689 if (buf[r] == '\n') 2690 ++wmsg->lines; 2691 } 2692 return MPTY_DATA; 2693 } else if (r < 0) { 2694 if (errno != EINTR && errno != EAGAIN) 2695 return MPTY_FAILED; 2696 return MPTY_AGAIN; 2697 } else if (r == 0) { 2698 return MPTY_EOF; 2699 } 2700 } 2701 return MPTY_AGAIN; 2702 } 2703 2704 /* 2705 * Copy a (package) file from (src) to (dst), use an intermediate file and 2706 * rename to ensure that interruption does not leave us with a corrupt 2707 * package file. 2708 * 2709 * This is called by the WORKER process. 2710 * 2711 * (dsynth management thread -> WORKER process -> sub-processes) 2712 */ 2713 #define COPYBLKSIZE 32768 2714 2715 static int 2716 copyfile(char *src, char *dst) 2717 { 2718 char *tmp; 2719 char *buf; 2720 int fd1; 2721 int fd2; 2722 int error = 0; 2723 int mask; 2724 ssize_t r; 2725 2726 asprintf(&tmp, "%s.new", dst); 2727 buf = malloc(COPYBLKSIZE); 2728 2729 mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP)); 2730 fd1 = open(src, O_RDONLY|O_CLOEXEC); 2731 fd2 = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0644); 2732 CopyFileFd = fd1; 2733 sigsetmask(mask); 2734 while ((r = read(fd1, buf, COPYBLKSIZE)) > 0) { 2735 if (write(fd2, buf, r) != r) 2736 error = 1; 2737 } 2738 if (r < 0) 2739 error = 1; 2740 mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP)); 2741 CopyFileFd = -1; 2742 close(fd1); 2743 close(fd2); 2744 sigsetmask(mask); 2745 if (error) { 2746 remove(tmp); 2747 } else { 2748 if (rename(tmp, dst)) { 2749 error = 1; 2750 remove(tmp); 2751 } 2752 } 2753 2754 freestrp(&buf); 2755 freestrp(&tmp); 2756 2757 return error; 2758 } 2759 2760 /* 2761 * doHook() 2762 * 2763 * primary process (threaded) - run_start, run_end, pkg_ignored, pkg_skipped 2764 * worker process (threaded) - pkg_sucess, pkg_failure 2765 * 2766 * If waitfor is non-zero this hook will be serialized. 2767 */ 2768 static void 2769 doHook(pkg_t *pkg, const char *id, const char *path, int waitfor) 2770 { 2771 if (path == NULL) 2772 return; 2773 while (waitfor && getbulk() != NULL) 2774 ; 2775 if (pkg) 2776 queuebulk(pkg->portdir, id, path, pkg->pkgfile); 2777 else 2778 queuebulk(NULL, id, path, NULL); 2779 while (waitfor && getbulk() != NULL) 2780 ; 2781 } 2782 2783 /* 2784 * Execute hook (backend) 2785 * 2786 * s1 - portdir 2787 * s2 - id 2788 * s3 - script path 2789 * s4 - pkgfile (if applicable) 2790 */ 2791 static void 2792 childHookRun(bulk_t *bulk) 2793 { 2794 const char *cav[MAXCAC]; 2795 buildenv_t benv[MAXCAC]; 2796 char buf1[128]; 2797 char buf2[128]; 2798 char buf3[128]; 2799 char buf4[128]; 2800 FILE *fp; 2801 char *ptr; 2802 size_t len; 2803 pid_t pid; 2804 int cac; 2805 int bi; 2806 2807 cac = 0; 2808 bi = 0; 2809 bzero(benv, sizeof(benv)); 2810 2811 cav[cac++] = bulk->s3; 2812 2813 benv[bi].label = "PROFILE"; 2814 benv[bi].data = Profile; 2815 ++bi; 2816 2817 benv[bi].label = "DIR_PACKAGES"; 2818 benv[bi].data = PackagesPath; 2819 ++bi; 2820 2821 benv[bi].label = "DIR_REPOSITORY"; 2822 benv[bi].data = RepositoryPath; 2823 ++bi; 2824 2825 benv[bi].label = "DIR_PORTS"; 2826 benv[bi].data = DPortsPath; 2827 ++bi; 2828 2829 benv[bi].label = "DIR_OPTIONS"; 2830 benv[bi].data = OptionsPath; 2831 ++bi; 2832 2833 benv[bi].label = "DIR_DISTFILES"; 2834 benv[bi].data = DistFilesPath; 2835 ++bi; 2836 2837 benv[bi].label = "DIR_LOGS"; 2838 benv[bi].data = LogsPath; 2839 ++bi; 2840 2841 benv[bi].label = "DIR_BUILDBASE"; 2842 benv[bi].data = BuildBase; 2843 ++bi; 2844 2845 if (strcmp(bulk->s2, "hook_run_start") == 0) { 2846 snprintf(buf1, sizeof(buf1), "%d", BuildTotal); 2847 benv[bi].label = "PORTS_QUEUED"; 2848 benv[bi].data = buf1; 2849 ++bi; 2850 } else if (strcmp(bulk->s2, "hook_run_end") == 0) { 2851 snprintf(buf1, sizeof(buf1), "%d", BuildSuccessCount); 2852 benv[bi].label = "PORTS_BUILT"; 2853 benv[bi].data = buf1; 2854 ++bi; 2855 snprintf(buf2, sizeof(buf2), "%d", BuildFailCount); 2856 benv[bi].label = "PORTS_FAILED"; 2857 benv[bi].data = buf2; 2858 ++bi; 2859 snprintf(buf3, sizeof(buf3), "%d", BuildIgnoreCount); 2860 benv[bi].label = "PORTS_IGNORED"; 2861 benv[bi].data = buf3; 2862 ++bi; 2863 snprintf(buf4, sizeof(buf4), "%d", BuildSkipCount); 2864 benv[bi].label = "PORTS_SKIPPED"; 2865 benv[bi].data = buf4; 2866 ++bi; 2867 } else { 2868 /* 2869 * success, failure, ignored, skipped 2870 */ 2871 benv[bi].label = "RESULT"; 2872 if (strcmp(bulk->s2, "hook_pkg_success") == 0) { 2873 benv[bi].data = "success"; 2874 } else if (strcmp(bulk->s2, "hook_pkg_failure") == 0) { 2875 benv[bi].data = "failure"; 2876 } else if (strcmp(bulk->s2, "hook_pkg_ignored") == 0) { 2877 benv[bi].data = "ignored"; 2878 } else if (strcmp(bulk->s2, "hook_pkg_skipped") == 0) { 2879 benv[bi].data = "skipped"; 2880 } else { 2881 dfatal("Unknown hook id: %s", bulk->s2); 2882 /* NOT REACHED */ 2883 } 2884 ++bi; 2885 2886 /* 2887 * For compatibility with synth: 2888 * 2889 * ORIGIN does not include any @flavor, thus it is suitable 2890 * for finding the actual port directory/subdirectory. 2891 * 2892 * FLAVOR is set to ORIGIN if there is no flavor, otherwise 2893 * it is set to only the flavor sans the '@'. 2894 */ 2895 if ((ptr = strchr(bulk->s1, '@')) != NULL) { 2896 snprintf(buf1, sizeof(buf1), "%*.*s", 2897 (int)(ptr - bulk->s1), 2898 (int)(ptr - bulk->s1), 2899 bulk->s1); 2900 benv[bi].label = "ORIGIN"; 2901 benv[bi].data = buf1; 2902 ++bi; 2903 benv[bi].label = "FLAVOR"; 2904 benv[bi].data = ptr + 1; 2905 ++bi; 2906 } else { 2907 benv[bi].label = "ORIGIN"; 2908 benv[bi].data = bulk->s1; 2909 ++bi; 2910 benv[bi].label = "FLAVOR"; 2911 benv[bi].data = bulk->s1; 2912 ++bi; 2913 } 2914 benv[bi].label = "PKGNAME"; 2915 benv[bi].data = bulk->s4; 2916 ++bi; 2917 } 2918 2919 benv[bi].label = NULL; 2920 benv[bi].data = NULL; 2921 2922 fp = dexec_open(cav, cac, &pid, benv, 0, 0); 2923 while ((ptr = fgetln(fp, &len)) != NULL) 2924 ; 2925 2926 if (dexec_close(fp, pid)) { 2927 dlog(DLOG_ALL, 2928 "[XXX] %s SCRIPT %s (%s)\n", 2929 bulk->s1, bulk->s2, bulk->s3); 2930 } 2931 } 2932