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