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