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