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