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