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