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