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