xref: /dflybsd-src/usr.bin/dsynth/build.c (revision a361ab312536a661d74caf5630c7ae20bcd8e3e4)
18e25f19bSMatthew Dillon /*
23bd7e0a7SMatthew Dillon  * Copyright (c) 2019-2022 The DragonFly Project.  All rights reserved.
38e25f19bSMatthew Dillon  *
48e25f19bSMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
58e25f19bSMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
68e25f19bSMatthew Dillon  *
78e25f19bSMatthew Dillon  * This code uses concepts and configuration based on 'synth', by
88e25f19bSMatthew Dillon  * John R. Marino <draco@marino.st>, which was written in ada.
98e25f19bSMatthew Dillon  *
108e25f19bSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
118e25f19bSMatthew Dillon  * modification, are permitted provided that the following conditions
128e25f19bSMatthew Dillon  * are met:
138e25f19bSMatthew Dillon  *
148e25f19bSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
158e25f19bSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
168e25f19bSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
178e25f19bSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
188e25f19bSMatthew Dillon  *    the documentation and/or other materials provided with the
198e25f19bSMatthew Dillon  *    distribution.
208e25f19bSMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
218e25f19bSMatthew Dillon  *    contributors may be used to endorse or promote products derived
228e25f19bSMatthew Dillon  *    from this software without specific, prior written permission.
238e25f19bSMatthew Dillon  *
248e25f19bSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
258e25f19bSMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
268e25f19bSMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
278e25f19bSMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
288e25f19bSMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
298e25f19bSMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
308e25f19bSMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
318e25f19bSMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
328e25f19bSMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
338e25f19bSMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
348e25f19bSMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
358e25f19bSMatthew Dillon  * SUCH DAMAGE.
368e25f19bSMatthew Dillon  */
3777d66d4eSAntonio Huete Jimenez 
3877d66d4eSAntonio Huete Jimenez #include <netdb.h>
3977d66d4eSAntonio Huete Jimenez 
408e25f19bSMatthew Dillon #include "dsynth.h"
418e25f19bSMatthew Dillon 
42d50f9ae3SSascha Wildner static worker_t WorkerAry[MAXWORKERS];
43d50f9ae3SSascha Wildner static int BuildInitialized;
44d50f9ae3SSascha Wildner static int RunningWorkers;
45f7f25838SMatthew Dillon int DynamicMaxWorkers;
46d50f9ae3SSascha Wildner static int FailedWorkers;
47d50f9ae3SSascha Wildner static long RunningPkgDepSize;
487b5ce327SMatthew Dillon static pthread_mutex_t DbmMutex;
49d50f9ae3SSascha Wildner static pthread_mutex_t WorkerMutex;
50d50f9ae3SSascha Wildner static pthread_cond_t WorkerCond;
518e25f19bSMatthew Dillon 
521fa9d809SMatthew Dillon static int build_find_leaves(pkg_t *parent, pkg_t *pkg,
531fa9d809SMatthew Dillon 			pkg_t ***build_tailp, int *app, int *hasworkp,
541fa9d809SMatthew Dillon 			int depth, int first, int first_one_only);
5588c24d72SMatthew Dillon static int buildCalculateDepiDepth(pkg_t *pkg);
568e25f19bSMatthew Dillon static void build_clear_trav(pkg_t *pkg);
578e25f19bSMatthew Dillon static void startbuild(pkg_t **build_listp, pkg_t ***build_tailp);
588e25f19bSMatthew Dillon static int qsort_depi(const void *pkg1, const void *pkg2);
598e25f19bSMatthew Dillon static int qsort_idep(const void *pkg1, const void *pkg2);
608e25f19bSMatthew Dillon static void startworker(pkg_t *pkg, worker_t *work);
618e25f19bSMatthew Dillon static void cleanworker(worker_t *work);
623699ee09SMatthew Dillon static void waitbuild(int whilematch, int dynamicmax);
638e25f19bSMatthew Dillon static void workercomplete(worker_t *work);
648e25f19bSMatthew Dillon static void *childBuilderThread(void *arg);
658e25f19bSMatthew Dillon static int childInstallPkgDeps(worker_t *work);
6663fcce5bSMatthew Dillon static size_t childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list,
671fa9d809SMatthew Dillon 			int undoit, int depth, int first_one_only);
688e25f19bSMatthew Dillon static void dophase(worker_t *work, wmsg_t *wmsg,
698e25f19bSMatthew Dillon 			int wdog, int phaseid, const char *phase);
708e25f19bSMatthew Dillon static void phaseReapAll(void);
718e25f19bSMatthew Dillon static void phaseTerminateSignal(int sig);
723699ee09SMatthew Dillon static char *buildskipreason(pkglink_t *parent, pkg_t *pkg);
733dd48cfaSMatthew Dillon static int buildskipcount_dueto(pkg_t *pkg, int mode);
747880dcf7SMatthew Dillon static int mptylogpoll(int ptyfd, int fdlog, wmsg_t *wmsg,
757880dcf7SMatthew Dillon 			time_t *wdog_timep);
7668dc2eeaSMatthew Dillon static void doHook(pkg_t *pkg, const char *id, const char *path, int waitfor);
7768dc2eeaSMatthew Dillon static void childHookRun(bulk_t *bulk);
7832fc5bbfSMatthew Dillon static void adjloadavg(double *dload);
79b6bd007bSMatthew Dillon static void check_packaged(const char *dbmpath, pkg_t *pkgs);
808e25f19bSMatthew Dillon 
818e25f19bSMatthew Dillon static worker_t *SigWork;
821d6e00cdSMatthew Dillon static int MasterPtyFd = -1;
83fef2fc63SMatthew Dillon static int CopyFileFd = -1;
848e25f19bSMatthew Dillon static pid_t SigPid;
85ffc851f6SMatthew Dillon static const char *WorkerFlavorPrt = "";	/* "" or "@flavor" */
86b6bd007bSMatthew Dillon static DBM *CheckDBM;
878e25f19bSMatthew Dillon 
887880dcf7SMatthew Dillon #define MPTY_FAILED	-2
897880dcf7SMatthew Dillon #define MPTY_AGAIN	-1
907880dcf7SMatthew Dillon #define MPTY_EOF	0
917880dcf7SMatthew Dillon #define MPTY_DATA	1
927880dcf7SMatthew Dillon 
938e25f19bSMatthew Dillon int BuildTotal;
948e25f19bSMatthew Dillon int BuildCount;
958e25f19bSMatthew Dillon int BuildSkipCount;
9687017ac4SMatthew Dillon int BuildIgnoreCount;
978e25f19bSMatthew Dillon int BuildFailCount;
988e25f19bSMatthew Dillon int BuildSuccessCount;
99549987f1SMatthew Dillon int BuildMissingCount;
10051705b28SAntonio Huete Jimenez int BuildMetaCount;
101dca89e44SMatthew Dillon int PkgVersionPkgSuffix;
1028e25f19bSMatthew Dillon 
1038e25f19bSMatthew Dillon /*
1048e25f19bSMatthew Dillon  * Initialize the WorkerAry[]
1058e25f19bSMatthew Dillon  */
1068e25f19bSMatthew Dillon void
DoInitBuild(int slot_override)1078e25f19bSMatthew Dillon DoInitBuild(int slot_override)
1088e25f19bSMatthew Dillon {
1098e25f19bSMatthew Dillon 	worker_t *work;
1108e25f19bSMatthew Dillon 	struct stat st;
1115d0718a8SMatthew Dillon 	char *path;
1128e25f19bSMatthew Dillon 	int i;
1138e25f19bSMatthew Dillon 
1148e25f19bSMatthew Dillon 	ddassert(slot_override < 0 || MaxWorkers == 1);
1158e25f19bSMatthew Dillon 
1168e25f19bSMatthew Dillon 	bzero(WorkerAry, MaxWorkers * sizeof(worker_t));
1178e25f19bSMatthew Dillon 	pthread_mutex_init(&WorkerMutex, NULL);
1187b5ce327SMatthew Dillon 	pthread_mutex_init(&DbmMutex, NULL);
1198e25f19bSMatthew Dillon 
1208e25f19bSMatthew Dillon 	for (i = 0; i < MaxWorkers; ++i) {
1218e25f19bSMatthew Dillon 		work = &WorkerAry[i];
1228e25f19bSMatthew Dillon 		work->index = (slot_override >= 0) ? slot_override : i;
1238e25f19bSMatthew Dillon 		work->state = WORKER_NONE;
1248e25f19bSMatthew Dillon 		asprintf(&work->basedir, "%s/SL%02d", BuildBase, work->index);
1258e25f19bSMatthew Dillon 		pthread_cond_init(&work->cond, NULL);
1268e25f19bSMatthew Dillon 	}
1278e25f19bSMatthew Dillon 	BuildCount = 0;
1288e25f19bSMatthew Dillon 
1298e25f19bSMatthew Dillon 	/*
1308e25f19bSMatthew Dillon 	 * Create required sub-directories. The base directories must already
1318e25f19bSMatthew Dillon 	 * exist as a dsynth configuration safety.
1328e25f19bSMatthew Dillon 	 */
1338e25f19bSMatthew Dillon 	if (stat(RepositoryPath, &st) < 0) {
1348e25f19bSMatthew Dillon 		if (mkdir(RepositoryPath, 0755) < 0)
1358e25f19bSMatthew Dillon 			dfatal("Cannot mkdir %s\n", RepositoryPath);
1368e25f19bSMatthew Dillon 	}
1378e25f19bSMatthew Dillon 
1385d0718a8SMatthew Dillon 	/*
1395d0718a8SMatthew Dillon 	 * An empty directory for LOCALBASE= in the pkg scan.
1405d0718a8SMatthew Dillon 	 */
1415d0718a8SMatthew Dillon 	asprintf(&path, "%s/empty", BuildBase);
1425d0718a8SMatthew Dillon 	if (stat(path, &st) < 0) {
1435d0718a8SMatthew Dillon 		if (mkdir(path, 0755) < 0)
1445d0718a8SMatthew Dillon 			dfatal("Cannot mkdir %s\n", path);
1455d0718a8SMatthew Dillon 	}
1465d0718a8SMatthew Dillon 	free(path);
1475d0718a8SMatthew Dillon 
1488e25f19bSMatthew Dillon 	BuildInitialized = 1;
149f7f25838SMatthew Dillon 
150f7f25838SMatthew Dillon 	/*
151f7f25838SMatthew Dillon 	 * slow-start (increases at a rate of 1 per 5 seconds)
152f7f25838SMatthew Dillon 	 */
153f7f25838SMatthew Dillon 	if (SlowStartOpt > MaxWorkers)
154f7f25838SMatthew Dillon 		DynamicMaxWorkers = MaxWorkers;
155f7f25838SMatthew Dillon 	else if (SlowStartOpt > 0)
156f7f25838SMatthew Dillon 		DynamicMaxWorkers = SlowStartOpt;
157f7f25838SMatthew Dillon 	else
158f7f25838SMatthew Dillon 		DynamicMaxWorkers = MaxWorkers;
1598e25f19bSMatthew Dillon }
1608e25f19bSMatthew Dillon 
1618e25f19bSMatthew Dillon /*
1628e25f19bSMatthew Dillon  * Called by the frontend to clean-up any hanging mounts.
1638e25f19bSMatthew Dillon  */
1648e25f19bSMatthew Dillon void
DoCleanBuild(int resetlogs)16587017ac4SMatthew Dillon DoCleanBuild(int resetlogs)
1668e25f19bSMatthew Dillon {
1678e25f19bSMatthew Dillon 	int i;
1688e25f19bSMatthew Dillon 
1698e25f19bSMatthew Dillon 	ddassert(BuildInitialized);
1708e25f19bSMatthew Dillon 
17187017ac4SMatthew Dillon 	if (resetlogs)
17287017ac4SMatthew Dillon 		dlogreset();
1738e25f19bSMatthew Dillon 	for (i = 0; i < MaxWorkers; ++i) {
1748e25f19bSMatthew Dillon 		DoWorkerUnmounts(&WorkerAry[i]);
1758e25f19bSMatthew Dillon 	}
1768e25f19bSMatthew Dillon }
1778e25f19bSMatthew Dillon 
1788e25f19bSMatthew Dillon void
DoBuild(pkg_t * pkgs)1798e25f19bSMatthew Dillon DoBuild(pkg_t *pkgs)
1808e25f19bSMatthew Dillon {
1818e25f19bSMatthew Dillon 	pkg_t *build_list = NULL;
1828e25f19bSMatthew Dillon 	pkg_t **build_tail = &build_list;
1838e25f19bSMatthew Dillon 	pkg_t *scan;
18468dc2eeaSMatthew Dillon 	bulk_t *bulk;
1858e25f19bSMatthew Dillon 	int haswork = 1;
1868e25f19bSMatthew Dillon 	int first = 1;
1876fd67931SMatthew Dillon 	int newtemplate;
188f4094b20SMatthew Dillon 	time_t startTime;
189f4094b20SMatthew Dillon 	time_t t;
190f4094b20SMatthew Dillon 	int h, m, s;
191b6bd007bSMatthew Dillon 	char *dbmpath;
1928e25f19bSMatthew Dillon 
1937b609b0aSMatthew Dillon 	/*
19468dc2eeaSMatthew Dillon 	 * We use our bulk system to run hooks.  This will be for
19568dc2eeaSMatthew Dillon 	 * Skipped and Ignored.  Success and Failure are handled by
19668dc2eeaSMatthew Dillon 	 * WorkerProcess() which is a separately-exec'd dsynth.
19768dc2eeaSMatthew Dillon 	 */
19868dc2eeaSMatthew Dillon 	if (UsingHooks)
19968dc2eeaSMatthew Dillon 		initbulk(childHookRun, MaxBulk);
20068dc2eeaSMatthew Dillon 
20168dc2eeaSMatthew Dillon 	/*
2027b609b0aSMatthew Dillon 	 * Count up the packages, not counting dummies
2037b609b0aSMatthew Dillon 	 */
2047b609b0aSMatthew Dillon 	for (scan = pkgs; scan; scan = scan->bnext) {
2057b609b0aSMatthew Dillon 		if ((scan->flags & PKGF_DUMMY) == 0)
2068e25f19bSMatthew Dillon 			++BuildTotal;
2077b609b0aSMatthew Dillon 	}
2088e25f19bSMatthew Dillon 
209b6bd007bSMatthew Dillon 	/*
210b6bd007bSMatthew Dillon 	 * Remove binary package files for dports whos directory
211b6bd007bSMatthew Dillon 	 * has changed.
212b6bd007bSMatthew Dillon 	 */
213b6bd007bSMatthew Dillon 	asprintf(&dbmpath, "%s/ports_crc", BuildBase);
214b6bd007bSMatthew Dillon 	CheckDBM = dbm_open(dbmpath, O_CREAT|O_RDWR, 0644);
215b6bd007bSMatthew Dillon 	check_packaged(dbmpath, pkgs);
216b6bd007bSMatthew Dillon 
21768dc2eeaSMatthew Dillon 	doHook(NULL, "hook_run_start", HookRunStart, 1);
21868dc2eeaSMatthew Dillon 
2198e25f19bSMatthew Dillon 	/*
2208e25f19bSMatthew Dillon 	 * The pkg and pkg-static binaries are needed.  If already present
221549987f1SMatthew Dillon 	 * then assume that the template is also valid, otherwise add to
222549987f1SMatthew Dillon 	 * the list and build both.
2238e25f19bSMatthew Dillon 	 */
224549987f1SMatthew Dillon 	scan = GetPkgPkg(&pkgs);
2258e25f19bSMatthew Dillon 
2268e25f19bSMatthew Dillon 	/*
2271645cafeSMatthew Dillon 	 * Create our template.  The template will be missing pkg
2281645cafeSMatthew Dillon 	 * and pkg-static.
2298e25f19bSMatthew Dillon 	 */
230325ef124SMatthew Dillon 	if (FetchOnlyOpt) {
231325ef124SMatthew Dillon 		newtemplate = DoCreateTemplate(0);
232325ef124SMatthew Dillon 	} else if ((scan->flags & (PKGF_SUCCESS | PKGF_PACKAGED)) == 0) {
2336fd67931SMatthew Dillon 		/* force a fresh template */
2346fd67931SMatthew Dillon 		newtemplate = DoCreateTemplate(1);
2351d6e00cdSMatthew Dillon 	} else {
2366fd67931SMatthew Dillon 		newtemplate = DoCreateTemplate(0);
2371645cafeSMatthew Dillon 	}
2381645cafeSMatthew Dillon 
2391645cafeSMatthew Dillon 	/*
2401645cafeSMatthew Dillon 	 * This will clear the screen and set-up our gui, so sleep
2411645cafeSMatthew Dillon 	 * a little first in case the user wants to see what was
2421645cafeSMatthew Dillon 	 * printed before.
2431645cafeSMatthew Dillon 	 */
2441645cafeSMatthew Dillon 	sleep(2);
2458e25f19bSMatthew Dillon 	pthread_mutex_lock(&WorkerMutex);
246f4094b20SMatthew Dillon 	startTime = time(NULL);
247ea37671dSMatthew Dillon 	RunStatsInit();
248ea37671dSMatthew Dillon 	RunStatsReset();
2498e25f19bSMatthew Dillon 
2508e25f19bSMatthew Dillon 	/*
251dca89e44SMatthew Dillon 	 * Build pkg/pkg-static
2528e25f19bSMatthew Dillon 	 */
253325ef124SMatthew Dillon 	if ((scan->flags & (PKGF_SUCCESS | PKGF_PACKAGED)) == 0 && FetchOnlyOpt == 0) {
2548e25f19bSMatthew Dillon 		build_list = scan;
2558e25f19bSMatthew Dillon 		build_tail = &scan->build_next;
2568e25f19bSMatthew Dillon 		startbuild(&build_list, &build_tail);
2573699ee09SMatthew Dillon 		while (RunningWorkers == 1)
2583699ee09SMatthew Dillon 			waitbuild(1, 0);
2598e25f19bSMatthew Dillon 
2608e25f19bSMatthew Dillon 		if (scan->flags & PKGF_NOBUILD)
2618e25f19bSMatthew Dillon 			dfatal("Unable to build 'pkg'");
2628e25f19bSMatthew Dillon 		if (scan->flags & PKGF_ERROR)
2638e25f19bSMatthew Dillon 			dfatal("Error building 'pkg'");
2648e25f19bSMatthew Dillon 		if ((scan->flags & PKGF_SUCCESS) == 0)
2658e25f19bSMatthew Dillon 			dfatal("Error building 'pkg'");
2666fd67931SMatthew Dillon 		newtemplate = 1;
2676fd67931SMatthew Dillon 	}
2688e25f19bSMatthew Dillon 
2698e25f19bSMatthew Dillon 	/*
2708e25f19bSMatthew Dillon 	 * Install pkg/pkg-static into the template
2718e25f19bSMatthew Dillon 	 */
272325ef124SMatthew Dillon 	if (newtemplate && FetchOnlyOpt == 0) {
2736fd67931SMatthew Dillon 		char *buf;
2746fd67931SMatthew Dillon 		int rc;
2756fd67931SMatthew Dillon 
2768e25f19bSMatthew Dillon 		asprintf(&buf,
2778e25f19bSMatthew Dillon 			 "cd %s/Template; "
2788e25f19bSMatthew Dillon 			 "tar --exclude '+*' --exclude '*/man/*' "
2791645cafeSMatthew Dillon 			 "-xvzpf %s/%s > /dev/null 2>&1",
2808e25f19bSMatthew Dillon 			 BuildBase,
2818e25f19bSMatthew Dillon 			 RepositoryPath,
2828e25f19bSMatthew Dillon 			 scan->pkgfile);
2838e25f19bSMatthew Dillon 		rc = system(buf);
2848e25f19bSMatthew Dillon 		if (rc)
2858e25f19bSMatthew Dillon 			dfatal("Command failed: %s\n", buf);
286ffc851f6SMatthew Dillon 		freestrp(&buf);
2878e25f19bSMatthew Dillon 	}
2888e25f19bSMatthew Dillon 
2898e25f19bSMatthew Dillon 	/*
290dca89e44SMatthew Dillon 	 * Figure out pkg version
291dca89e44SMatthew Dillon 	 */
292dca89e44SMatthew Dillon 	if (scan->version) {
293dca89e44SMatthew Dillon 		int v1;
294dca89e44SMatthew Dillon 		int v2;
295dca89e44SMatthew Dillon 
296dca89e44SMatthew Dillon 		dlog(DLOG_ALL, "[XXX] pkg version %s\n", scan->version);
297dca89e44SMatthew Dillon 		if (sscanf(scan->version, "%d.%d", &v1, &v2) == 2) {
298dca89e44SMatthew Dillon 			if ((v1 == 1 && v2 >= 17) || v1 > 1)
299dca89e44SMatthew Dillon 			    PkgVersionPkgSuffix = 1;
300dca89e44SMatthew Dillon 		}
301dca89e44SMatthew Dillon 	}
302dca89e44SMatthew Dillon 
303dca89e44SMatthew Dillon 	/*
30488c24d72SMatthew Dillon 	 * Calculate depi_depth, the longest chain of dependencies
30588c24d72SMatthew Dillon 	 * for who depends on me, weighted by powers of two.
30688c24d72SMatthew Dillon 	 */
30788c24d72SMatthew Dillon 	for (scan = pkgs; scan; scan = scan->bnext) {
30888c24d72SMatthew Dillon 		buildCalculateDepiDepth(scan);
30988c24d72SMatthew Dillon 	}
31088c24d72SMatthew Dillon 
31188c24d72SMatthew Dillon 	/*
3128e25f19bSMatthew Dillon 	 * Nominal bulk build sequence
3138e25f19bSMatthew Dillon 	 */
3148e25f19bSMatthew Dillon 	while (haswork) {
3158e25f19bSMatthew Dillon 		haswork = 0;
3168e25f19bSMatthew Dillon 		fflush(stdout);
3178e25f19bSMatthew Dillon 		for (scan = pkgs; scan; scan = scan->bnext) {
3188e25f19bSMatthew Dillon 			ddprintf(0, "SCANLEAVES %08x %s\n",
3198e25f19bSMatthew Dillon 				 scan->flags, scan->portdir);
3208e25f19bSMatthew Dillon 			scan->flags |= PKGF_BUILDLOOP;
3218e25f19bSMatthew Dillon 			/*
3228e25f19bSMatthew Dillon 			 * NOTE: We must still find dependencies if PACKAGED
3238e25f19bSMatthew Dillon 			 *	 to fill in the gaps, as some of them may
3248e25f19bSMatthew Dillon 			 *	 need to be rebuilt.
3258e25f19bSMatthew Dillon 			 */
3268e25f19bSMatthew Dillon 			if (scan->flags & (PKGF_SUCCESS | PKGF_FAILURE |
3273699ee09SMatthew Dillon 					   PKGF_ERROR)) {
3288e25f19bSMatthew Dillon #if 0
3298e25f19bSMatthew Dillon 				ddprintf(0, "%s: already built\n",
3308e25f19bSMatthew Dillon 					 scan->portdir);
3318e25f19bSMatthew Dillon #endif
3328e25f19bSMatthew Dillon 			} else {
3338e25f19bSMatthew Dillon 				int ap = 0;
3348e25f19bSMatthew Dillon 				build_find_leaves(NULL, scan, &build_tail,
3351fa9d809SMatthew Dillon 						  &ap, &haswork, 0, first, 0);
3368e25f19bSMatthew Dillon 				ddprintf(0, "TOPLEVEL %s %08x\n",
3378e25f19bSMatthew Dillon 					 scan->portdir, ap);
3388e25f19bSMatthew Dillon 			}
3398e25f19bSMatthew Dillon 			scan->flags &= ~PKGF_BUILDLOOP;
3408e25f19bSMatthew Dillon 			build_clear_trav(scan);
3418e25f19bSMatthew Dillon 		}
3428e25f19bSMatthew Dillon 		first = 0;
3438e25f19bSMatthew Dillon 		fflush(stdout);
3448e25f19bSMatthew Dillon 		startbuild(&build_list, &build_tail);
3458e25f19bSMatthew Dillon 
3468e25f19bSMatthew Dillon 		if (haswork == 0 && RunningWorkers) {
3473699ee09SMatthew Dillon 			waitbuild(RunningWorkers, 1);
3488e25f19bSMatthew Dillon 			haswork = 1;
3498e25f19bSMatthew Dillon 		}
3508e25f19bSMatthew Dillon 	}
3518e25f19bSMatthew Dillon 	pthread_mutex_unlock(&WorkerMutex);
3528e25f19bSMatthew Dillon 
353549987f1SMatthew Dillon 	/*
354549987f1SMatthew Dillon 	 * What is left that cannot be built?  The list really ought to be
355549987f1SMatthew Dillon 	 * empty at this point, report anything that remains.
356549987f1SMatthew Dillon 	 */
357549987f1SMatthew Dillon 	for (scan = pkgs; scan; scan = scan->bnext) {
358549987f1SMatthew Dillon 		if (scan->flags & (PKGF_SUCCESS | PKGF_FAILURE))
359549987f1SMatthew Dillon 			continue;
360549987f1SMatthew Dillon 		dlog(DLOG_ABN, "[XXX] %s lost in the ether [flags=%08x]\n",
361549987f1SMatthew Dillon 		     scan->portdir, scan->flags);
362549987f1SMatthew Dillon 		++BuildMissingCount;
363549987f1SMatthew Dillon 	}
364549987f1SMatthew Dillon 
365549987f1SMatthew Dillon 	/*
366549987f1SMatthew Dillon 	 * Final updates
367549987f1SMatthew Dillon 	 */
3688b485838SMatthew Dillon 	RunStatsUpdateTop(0);
369ea37671dSMatthew Dillon 	RunStatsUpdateLogs();
370ea37671dSMatthew Dillon 	RunStatsSync();
371ea37671dSMatthew Dillon 	RunStatsDone();
3723699ee09SMatthew Dillon 
37368dc2eeaSMatthew Dillon 	doHook(NULL, "hook_run_end", HookRunEnd, 1);
37468dc2eeaSMatthew Dillon 	if (UsingHooks) {
37568dc2eeaSMatthew Dillon 		while ((bulk = getbulk()) != NULL)
37668dc2eeaSMatthew Dillon 			freebulk(bulk);
37768dc2eeaSMatthew Dillon 		donebulk();
37868dc2eeaSMatthew Dillon 	}
37968dc2eeaSMatthew Dillon 
380f4094b20SMatthew Dillon 	t = time(NULL) - startTime;
381f4094b20SMatthew Dillon 	h = t / 3600;
382f4094b20SMatthew Dillon 	m = t / 60 % 60;
383f4094b20SMatthew Dillon 	s = t % 60;
384f4094b20SMatthew Dillon 
385b6bd007bSMatthew Dillon 	if (CheckDBM) {
386b6bd007bSMatthew Dillon 		dbm_close(CheckDBM);
387b6bd007bSMatthew Dillon 		CheckDBM = NULL;
388b6bd007bSMatthew Dillon 	}
389b6bd007bSMatthew Dillon 
39033170e2dSMatthew Dillon 	dlog(DLOG_ALL|DLOG_STDOUT,
39133170e2dSMatthew Dillon 		"\n"
39233170e2dSMatthew Dillon 		"Initial queue size: %d\n"
39333170e2dSMatthew Dillon 		"    packages built: %d\n"
39433170e2dSMatthew Dillon 		"           ignored: %d\n"
39533170e2dSMatthew Dillon 		"           skipped: %d\n"
39633170e2dSMatthew Dillon 		"            failed: %d\n"
397549987f1SMatthew Dillon 		"           missing: %d\n"
39851705b28SAntonio Huete Jimenez 		"        meta-nodes: %d\n"
39933170e2dSMatthew Dillon 		"\n"
40033170e2dSMatthew Dillon 		"Duration: %02d:%02d:%02d\n"
40133170e2dSMatthew Dillon 		"\n",
40233170e2dSMatthew Dillon 		BuildTotal,
40333170e2dSMatthew Dillon 		BuildSuccessCount,
40433170e2dSMatthew Dillon 		BuildIgnoreCount,
40533170e2dSMatthew Dillon 		BuildSkipCount,
40633170e2dSMatthew Dillon 		BuildFailCount,
407549987f1SMatthew Dillon 		BuildMissingCount,
40851705b28SAntonio Huete Jimenez 		BuildMetaCount,
40933170e2dSMatthew Dillon 		h, m, s);
4108e25f19bSMatthew Dillon }
4118e25f19bSMatthew Dillon 
4128e25f19bSMatthew Dillon /*
4138e25f19bSMatthew Dillon  * Traverse the packages (pkg) depends on recursively until we find
4148e25f19bSMatthew Dillon  * a leaf to build or report as unbuildable.  Calculates and assigns a
4158e25f19bSMatthew Dillon  * dependency count.  Returns all parallel-buildable packages.
4168e25f19bSMatthew Dillon  *
4178e25f19bSMatthew Dillon  * (pkg) itself is only added to the list if it is immediately buildable.
4188e25f19bSMatthew Dillon  */
4198e25f19bSMatthew Dillon static
4208e25f19bSMatthew Dillon int
build_find_leaves(pkg_t * parent,pkg_t * pkg,pkg_t *** build_tailp,int * app,int * hasworkp,int depth,int first,int first_one_only)4218e25f19bSMatthew Dillon build_find_leaves(pkg_t *parent, pkg_t *pkg, pkg_t ***build_tailp,
4221fa9d809SMatthew Dillon 		  int *app, int *hasworkp, int depth, int first,
4231fa9d809SMatthew Dillon 		  int first_one_only)
4248e25f19bSMatthew Dillon {
4258e25f19bSMatthew Dillon 	pkglink_t *link;
4268e25f19bSMatthew Dillon 	pkg_t *scan;
4278e25f19bSMatthew Dillon 	int idep_count = 0;
4288e25f19bSMatthew Dillon 	int apsub;
4291fa9d809SMatthew Dillon 	int dfirst_one_only;
4301fa9d809SMatthew Dillon 	int ndepth;
4318e25f19bSMatthew Dillon 	char *buf;
4328e25f19bSMatthew Dillon 
4331fa9d809SMatthew Dillon 	ndepth = depth + 1;
4341fa9d809SMatthew Dillon 
4358e25f19bSMatthew Dillon 	/*
4368e25f19bSMatthew Dillon 	 * Already on build list, possibly in-progress, tell caller that
4378e25f19bSMatthew Dillon 	 * it is not ready.
4388e25f19bSMatthew Dillon 	 */
4391fa9d809SMatthew Dillon 	ddprintf(ndepth, "sbuild_find_leaves %d %s %08x {\n",
4401fa9d809SMatthew Dillon 		 depth, pkg->portdir, pkg->flags);
4418e25f19bSMatthew Dillon 	if (pkg->flags & PKGF_BUILDLIST) {
4421fa9d809SMatthew Dillon 		ddprintf(ndepth, "} (already on build list)\n");
4438e25f19bSMatthew Dillon 		*app |= PKGF_NOTREADY;
4448e25f19bSMatthew Dillon 		return (pkg->idep_count);
4458e25f19bSMatthew Dillon 	}
4468e25f19bSMatthew Dillon 
4478e25f19bSMatthew Dillon 	/*
4488e25f19bSMatthew Dillon 	 * Check dependencies
4498e25f19bSMatthew Dillon 	 */
4508e25f19bSMatthew Dillon 	PKGLIST_FOREACH(link, &pkg->idepon_list) {
4518e25f19bSMatthew Dillon 		scan = link->pkg;
4528e25f19bSMatthew Dillon 
4531fa9d809SMatthew Dillon 		if (scan == NULL) {
4541fa9d809SMatthew Dillon 			if (first_one_only)
4551fa9d809SMatthew Dillon 				break;
4568e25f19bSMatthew Dillon 			continue;
4571fa9d809SMatthew Dillon 		}
4581fa9d809SMatthew Dillon 		ddprintf(ndepth, "check %s %08x\t", scan->portdir, scan->flags);
4591fa9d809SMatthew Dillon 
4601fa9d809SMatthew Dillon 		/*
4611fa9d809SMatthew Dillon 		 * If this dependency is to a DUMMY node it is a dependency
4621fa9d809SMatthew Dillon 		 * only on the default flavor which is only the first node
4631fa9d809SMatthew Dillon 		 * under this one, not all of them.
4641fa9d809SMatthew Dillon 		 *
465349e3a76SMatthew Dillon 		 * DUMMY nodes can be marked SUCCESS so the build skips past
466349e3a76SMatthew Dillon 		 * them, but this doesn't mean that their sub-nodes succeeded.
467349e3a76SMatthew Dillon 		 * We have to check, so recurse even if it is marked
468349e3a76SMatthew Dillon 		 * successful.
469349e3a76SMatthew Dillon 		 *
4701fa9d809SMatthew Dillon 		 * NOTE: The depth is not being for complex dependency type
4711fa9d809SMatthew Dillon 		 *	 tests like it is in childInstallPkgDeps_recurse(),
4721fa9d809SMatthew Dillon 		 *	 so we don't have to hicup it like we do in that
4731fa9d809SMatthew Dillon 		 *	 procedure.
4741fa9d809SMatthew Dillon 		 */
4751fa9d809SMatthew Dillon 		dfirst_one_only = (scan->flags & PKGF_DUMMY) ? 1 : 0;
476349e3a76SMatthew Dillon 		if (dfirst_one_only)
477349e3a76SMatthew Dillon 			goto skip_to_flavor;
4788e25f19bSMatthew Dillon 
4798e25f19bSMatthew Dillon 		/*
4808e25f19bSMatthew Dillon 		 * When accounting for a successful build, just bump
4818e25f19bSMatthew Dillon 		 * idep_count by one.  scan->idep_count will heavily
4828e25f19bSMatthew Dillon 		 * overlap packages that we count down multiple branches.
4838e25f19bSMatthew Dillon 		 *
4848e25f19bSMatthew Dillon 		 * We must still recurse through PACKAGED packages as
4858e25f19bSMatthew Dillon 		 * some of their dependencies might be missing.
4868e25f19bSMatthew Dillon 		 */
4878e25f19bSMatthew Dillon 		if (scan->flags & PKGF_SUCCESS) {
4888e25f19bSMatthew Dillon 			ddprintf(0, "SUCCESS - OK\n");
4898e25f19bSMatthew Dillon 			++idep_count;
4901fa9d809SMatthew Dillon 			if (first_one_only)
4911fa9d809SMatthew Dillon 				break;
4928e25f19bSMatthew Dillon 			continue;
4938e25f19bSMatthew Dillon 		}
4949c4c701fSMatthew Dillon 
4959c4c701fSMatthew Dillon 		/*
4969c4c701fSMatthew Dillon 		 * ERROR includes FAILURE, which is set in numerous situations
497549987f1SMatthew Dillon 		 * including when NOBUILD state is finally processed.  So
498549987f1SMatthew Dillon 		 * check for NOBUILD state first.
4999c4c701fSMatthew Dillon 		 *
5009c4c701fSMatthew Dillon 		 * An ERROR in a sub-package causes a NOBUILD in packages
5019c4c701fSMatthew Dillon 		 * that depend on it.
5029c4c701fSMatthew Dillon 		 */
5038e25f19bSMatthew Dillon 		if (scan->flags & PKGF_NOBUILD) {
5048e25f19bSMatthew Dillon 			ddprintf(0, "NOBUILD - OK "
50521265a85SSascha Wildner 				    "(propagate failure upward)\n");
5068e25f19bSMatthew Dillon 			*app |= PKGF_NOBUILD_S;
5071fa9d809SMatthew Dillon 			if (first_one_only)
5081fa9d809SMatthew Dillon 				break;
5098e25f19bSMatthew Dillon 			continue;
5108e25f19bSMatthew Dillon 		}
5119c4c701fSMatthew Dillon 		if (scan->flags & PKGF_ERROR) {
51221265a85SSascha Wildner 			ddprintf(0, "ERROR - OK (propagate failure upward)\n");
5139c4c701fSMatthew Dillon 			*app |= PKGF_NOBUILD_S;
5141fa9d809SMatthew Dillon 			if (first_one_only)
5151fa9d809SMatthew Dillon 				break;
5169c4c701fSMatthew Dillon 			continue;
5179c4c701fSMatthew Dillon 		}
5188e25f19bSMatthew Dillon 
5198e25f19bSMatthew Dillon 		/*
5208e25f19bSMatthew Dillon 		 * If already on build-list this dependency is not ready.
5218e25f19bSMatthew Dillon 		 */
5228e25f19bSMatthew Dillon 		if (scan->flags & PKGF_BUILDLIST) {
5238e25f19bSMatthew Dillon 			ddprintf(0, " [BUILDLIST]");
5248e25f19bSMatthew Dillon 			*app |= PKGF_NOTREADY;
5258e25f19bSMatthew Dillon 		}
5268e25f19bSMatthew Dillon 
5278e25f19bSMatthew Dillon 		/*
5288e25f19bSMatthew Dillon 		 * If not packaged this dependency is not ready for
5298e25f19bSMatthew Dillon 		 * the caller.
5308e25f19bSMatthew Dillon 		 */
5318e25f19bSMatthew Dillon 		if ((scan->flags & PKGF_PACKAGED) == 0) {
5328e25f19bSMatthew Dillon 			ddprintf(0, " [NOT_PACKAGED]");
5338e25f19bSMatthew Dillon 			*app |= PKGF_NOTREADY;
5348e25f19bSMatthew Dillon 		}
5358e25f19bSMatthew Dillon 
5368e25f19bSMatthew Dillon 		/*
5378e25f19bSMatthew Dillon 		 * Reduce search complexity, if we have already processed
5388e25f19bSMatthew Dillon 		 * scan in the traversal it will either already be on the
5398e25f19bSMatthew Dillon 		 * build list or it will not be buildable.  Either way
5408e25f19bSMatthew Dillon 		 * the parent is not buildable.
5418e25f19bSMatthew Dillon 		 */
5428e25f19bSMatthew Dillon 		if (scan->flags & PKGF_BUILDTRAV) {
5438e25f19bSMatthew Dillon 			ddprintf(0, " [BUILDTRAV]\n");
5448e25f19bSMatthew Dillon 			*app |= PKGF_NOTREADY;
5451fa9d809SMatthew Dillon 			if (first_one_only)
5461fa9d809SMatthew Dillon 				break;
5478e25f19bSMatthew Dillon 			continue;
5488e25f19bSMatthew Dillon 		}
54950cde9e9SMatthew Dillon skip_to_flavor:
5508e25f19bSMatthew Dillon 
5518e25f19bSMatthew Dillon 		/*
5528e25f19bSMatthew Dillon 		 * Assert on dependency loop
5538e25f19bSMatthew Dillon 		 */
5548e25f19bSMatthew Dillon 		++idep_count;
5558e25f19bSMatthew Dillon 		if (scan->flags & PKGF_BUILDLOOP) {
5568e25f19bSMatthew Dillon 			dfatal("pkg dependency loop %s -> %s",
5578e25f19bSMatthew Dillon 				parent->portdir, scan->portdir);
5588e25f19bSMatthew Dillon 		}
5591fa9d809SMatthew Dillon 
5601fa9d809SMatthew Dillon 		/*
5611fa9d809SMatthew Dillon 		 * NOTE: For debug tabbing purposes we use (ndepth + 1)
5621fa9d809SMatthew Dillon 		 *	 here (i.e. depth + 2) in our iteration.
5631fa9d809SMatthew Dillon 		 */
5648e25f19bSMatthew Dillon 		scan->flags |= PKGF_BUILDLOOP;
5658e25f19bSMatthew Dillon 		apsub = 0;
5668e25f19bSMatthew Dillon 		ddprintf(0, " SUBRECURSION {\n");
5678e25f19bSMatthew Dillon 		idep_count += build_find_leaves(pkg, scan, build_tailp,
5688e25f19bSMatthew Dillon 						&apsub, hasworkp,
5691fa9d809SMatthew Dillon 						ndepth + 1, first,
5701fa9d809SMatthew Dillon 						dfirst_one_only);
5718e25f19bSMatthew Dillon 		scan->flags &= ~PKGF_BUILDLOOP;
5728e25f19bSMatthew Dillon 		*app |= apsub;
5738e25f19bSMatthew Dillon 		if (apsub & PKGF_NOBUILD) {
5741fa9d809SMatthew Dillon 			ddprintf(ndepth, "} (sub-nobuild)\n");
5758e25f19bSMatthew Dillon 		} else if (apsub & PKGF_ERROR) {
5761fa9d809SMatthew Dillon 			ddprintf(ndepth, "} (sub-error)\n");
5778e25f19bSMatthew Dillon 		} else if (apsub & PKGF_NOTREADY) {
5781fa9d809SMatthew Dillon 			ddprintf(ndepth, "} (sub-notready)\n");
5798e25f19bSMatthew Dillon 		} else {
5801fa9d809SMatthew Dillon 			ddprintf(ndepth, "} (sub-ok)\n");
5818e25f19bSMatthew Dillon 		}
5821fa9d809SMatthew Dillon 		if (first_one_only)
5831fa9d809SMatthew Dillon 			break;
5848e25f19bSMatthew Dillon 	}
5858e25f19bSMatthew Dillon 	pkg->idep_count = idep_count;
5868e25f19bSMatthew Dillon 	pkg->flags |= PKGF_BUILDTRAV;
5878e25f19bSMatthew Dillon 
5888e25f19bSMatthew Dillon 	/*
5898e25f19bSMatthew Dillon 	 * Incorporate scan results into pkg state.
5908e25f19bSMatthew Dillon 	 */
5918e25f19bSMatthew Dillon 	if ((pkg->flags & PKGF_NOBUILD) == 0 && (*app & PKGF_NOBUILD)) {
5928e25f19bSMatthew Dillon 		*hasworkp = 1;
5938e25f19bSMatthew Dillon 	} else if ((pkg->flags & PKGF_ERROR) == 0 && (*app & PKGF_ERROR)) {
5948e25f19bSMatthew Dillon 		*hasworkp = 1;
5958e25f19bSMatthew Dillon 	}
5968e25f19bSMatthew Dillon 	pkg->flags |= *app & ~PKGF_NOTREADY;
5978e25f19bSMatthew Dillon 
5988e25f19bSMatthew Dillon 	/*
599bd0c9b9eSMatthew Dillon 	 * Clear the PACKAGED bit if sub-dependencies aren't clean.
600bd0c9b9eSMatthew Dillon 	 *
601bd0c9b9eSMatthew Dillon 	 * NOTE: PKGF_NOTREADY is not stored in pkg->flags, only in *app,
602bd0c9b9eSMatthew Dillon 	 *	 so incorporate *app to test for it.
6038e25f19bSMatthew Dillon 	 */
6048e25f19bSMatthew Dillon 	if ((pkg->flags & PKGF_PACKAGED) &&
605bd0c9b9eSMatthew Dillon 	    ((pkg->flags | *app) & (PKGF_NOTREADY|PKGF_ERROR|PKGF_NOBUILD))) {
6068e25f19bSMatthew Dillon 		pkg->flags &= ~PKGF_PACKAGED;
6078e25f19bSMatthew Dillon 		ddassert(pkg->pkgfile);
6088e25f19bSMatthew Dillon 		asprintf(&buf, "%s/%s", RepositoryPath, pkg->pkgfile);
609b6bd007bSMatthew Dillon 		if (OverridePkgDeleteOpt >= 1) {
610b6bd007bSMatthew Dillon 			pkg->flags |= PKGF_PACKAGED;
611b6bd007bSMatthew Dillon 			dlog(DLOG_ALL,
612b6bd007bSMatthew Dillon 			     "[XXX] %s DELETE-PACKAGE %s "
613b6bd007bSMatthew Dillon 			     "(OVERRIDE, NOT DELETED)\n",
614b6bd007bSMatthew Dillon 			     pkg->portdir, buf);
615b6bd007bSMatthew Dillon 		} else if (remove(buf) < 0) {
6168e25f19bSMatthew Dillon 			dlog(DLOG_ALL,
6178e25f19bSMatthew Dillon 			     "[XXX] %s DELETE-PACKAGE %s (failed)\n",
6188e25f19bSMatthew Dillon 			     pkg->portdir, buf);
6198e25f19bSMatthew Dillon 		} else {
6208e25f19bSMatthew Dillon 			dlog(DLOG_ALL,
6218e25f19bSMatthew Dillon 			     "[XXX] %s DELETE-PACKAGE %s "
6228e25f19bSMatthew Dillon 			     "(due to dependencies)\n",
6238e25f19bSMatthew Dillon 			     pkg->portdir, buf);
6248e25f19bSMatthew Dillon 		}
625ffc851f6SMatthew Dillon 		freestrp(&buf);
6268e25f19bSMatthew Dillon 		*hasworkp = 1;
6278e25f19bSMatthew Dillon 	}
6288e25f19bSMatthew Dillon 
6298e25f19bSMatthew Dillon 	/*
63087017ac4SMatthew Dillon 	 * Set PKGF_NOBUILD_I if there is IGNORE data
63187017ac4SMatthew Dillon 	 */
632549987f1SMatthew Dillon 	if (pkg->ignore) {
63387017ac4SMatthew Dillon 		pkg->flags |= PKGF_NOBUILD_I;
634549987f1SMatthew Dillon 	}
63587017ac4SMatthew Dillon 
63687017ac4SMatthew Dillon 	/*
6378e25f19bSMatthew Dillon 	 * Handle propagated flags
6388e25f19bSMatthew Dillon 	 */
6398e25f19bSMatthew Dillon 	if (pkg->flags & PKGF_ERROR) {
6409c4c701fSMatthew Dillon 		/*
6419c4c701fSMatthew Dillon 		 * This can only happen if the ERROR has already been
6429c4c701fSMatthew Dillon 		 * processed and accounted for.
6439c4c701fSMatthew Dillon 		 */
6441fa9d809SMatthew Dillon 		ddprintf(depth, "} (ERROR - %s)\n", pkg->portdir);
6458e25f19bSMatthew Dillon 	} else if (*app & PKGF_NOTREADY) {
6468e25f19bSMatthew Dillon 		/*
6478e25f19bSMatthew Dillon 		 * We don't set PKGF_NOTREADY in the pkg, it is strictly
6488e25f19bSMatthew Dillon 		 * a transient flag propagated via build_find_leaves().
6498e25f19bSMatthew Dillon 		 *
6508e25f19bSMatthew Dillon 		 * Just don't add the package to the list.
6519c4c701fSMatthew Dillon 		 *
6529c4c701fSMatthew Dillon 		 * NOTE: Even if NOBUILD is set (meaning we could list it
6539c4c701fSMatthew Dillon 		 *	 and let startbuild() finish it up as a skip, we
6549c4c701fSMatthew Dillon 		 *	 don't process it to the list because we want to
6559c4c701fSMatthew Dillon 		 *	 process all the dependencies, so someone doing a
6569c4c701fSMatthew Dillon 		 *	 manual build can get more complete information and
6579c4c701fSMatthew Dillon 		 *	 does not have to iterate each failed dependency one
6589c4c701fSMatthew Dillon 		 *	 at a time.
6598e25f19bSMatthew Dillon 		 */
6608e25f19bSMatthew Dillon 		;
6618e25f19bSMatthew Dillon 	} else if (pkg->flags & PKGF_SUCCESS) {
6621fa9d809SMatthew Dillon 		ddprintf(depth, "} (SUCCESS - %s)\n", pkg->portdir);
6638e25f19bSMatthew Dillon 	} else if (pkg->flags & PKGF_DUMMY) {
6647b609b0aSMatthew Dillon 		/*
6657b609b0aSMatthew Dillon 		 * Just mark dummy packages as successful when all of their
6667b609b0aSMatthew Dillon 		 * sub-depends (flavors) complete successfully.  Note that
6677b609b0aSMatthew Dillon 		 * dummy packages are not counted in the total, so do not
6687b609b0aSMatthew Dillon 		 * decrement BuildTotal.
66950cde9e9SMatthew Dillon 		 *
670549987f1SMatthew Dillon 		 * Do not propagate *app up for the dummy node or add it to
671549987f1SMatthew Dillon 		 * the build list.  The dummy node itself is not an actual
672549987f1SMatthew Dillon 		 * dependency.  Packages which depend on the default flavor
673549987f1SMatthew Dillon 		 * (aka this dummy node) actually depend on the first flavor
674549987f1SMatthew Dillon 		 * under this node.
675549987f1SMatthew Dillon 		 *
676549987f1SMatthew Dillon 		 * So if there is a generic dependency (i.e. no flavor
677549987f1SMatthew Dillon 		 * specified), the upper recursion detects PKGF_DUMMY and
678549987f1SMatthew Dillon 		 * traverses through the dummy node to the default flavor
679549987f1SMatthew Dillon 		 * without checking the error/nobuild flags on this dummy
680549987f1SMatthew Dillon 		 * node.
6817b609b0aSMatthew Dillon 		 */
682349e3a76SMatthew Dillon 		if (pkg->flags & PKGF_NOBUILD) {
683549987f1SMatthew Dillon 			ddprintf(depth, "} (DUMMY/META - IGNORED "
684549987f1SMatthew Dillon 				 "- MARK SUCCESS ANYWAY)\n");
685349e3a76SMatthew Dillon 		} else {
6861fa9d809SMatthew Dillon 			ddprintf(depth, "} (DUMMY/META - SUCCESS)\n");
687549987f1SMatthew Dillon 		}
6888e25f19bSMatthew Dillon 		pkg->flags |= PKGF_SUCCESS;
6898e25f19bSMatthew Dillon 		*hasworkp = 1;
6908e25f19bSMatthew Dillon 		if (first) {
691a574cbf0SMatthew Dillon 			dlog(DLOG_ALL | DLOG_FILTER,
692a574cbf0SMatthew Dillon 			     "[XXX] %s META-ALREADY-BUILT\n",
6938e25f19bSMatthew Dillon 			     pkg->portdir);
6948e25f19bSMatthew Dillon 		} else {
6958e25f19bSMatthew Dillon 			dlog(DLOG_SUCC, "[XXX] %s meta-node complete\n",
6968e25f19bSMatthew Dillon 			     pkg->portdir);
697549987f1SMatthew Dillon 			RunStatsUpdateCompletion(NULL, DLOG_SUCC, pkg, "", "");
69851705b28SAntonio Huete Jimenez 			++BuildMetaCount;   /* Only for not built meta nodes */
699349e3a76SMatthew Dillon 		}
7008e25f19bSMatthew Dillon 	} else if (pkg->flags & PKGF_PACKAGED) {
7018e25f19bSMatthew Dillon 		/*
7028e25f19bSMatthew Dillon 		 * We can just mark the pkg successful.  If this is
7038e25f19bSMatthew Dillon 		 * the first pass, we count this as an initial pruning
7048e25f19bSMatthew Dillon 		 * pass and reduce BuildTotal.
7058e25f19bSMatthew Dillon 		 */
7061fa9d809SMatthew Dillon 		ddprintf(depth, "} (PACKAGED - SUCCESS)\n");
7078e25f19bSMatthew Dillon 		pkg->flags |= PKGF_SUCCESS;
7088e25f19bSMatthew Dillon 		*hasworkp = 1;
7098e25f19bSMatthew Dillon 		if (first) {
710a574cbf0SMatthew Dillon 			dlog(DLOG_ALL | DLOG_FILTER,
711bd0c9b9eSMatthew Dillon 			     "[XXX] %s Already-Built\n",
7128e25f19bSMatthew Dillon 			     pkg->portdir);
7138e25f19bSMatthew Dillon 			--BuildTotal;
714549987f1SMatthew Dillon 		} else {
715549987f1SMatthew Dillon 			dlog(DLOG_ABN | DLOG_FILTER,
716bd0c9b9eSMatthew Dillon 			     "[XXX] %s flags=%08x Packaged Unexpectedly\n",
717bd0c9b9eSMatthew Dillon 			     pkg->portdir, pkg->flags);
718549987f1SMatthew Dillon 			/* ++BuildSuccessTotal; XXX not sure */
719549987f1SMatthew Dillon 			goto addlist;
7208e25f19bSMatthew Dillon 		}
7218e25f19bSMatthew Dillon 	} else {
7228e25f19bSMatthew Dillon 		/*
7238e25f19bSMatthew Dillon 		 * All dependencies are successful, queue new work
7248e25f19bSMatthew Dillon 		 * and indicate not-ready to the parent (since our
7258e25f19bSMatthew Dillon 		 * package has to be built).
7269c4c701fSMatthew Dillon 		 *
7279c4c701fSMatthew Dillon 		 * NOTE: The NOBUILD case propagates to here as well
7289c4c701fSMatthew Dillon 		 *	 and is ultimately handled by startbuild().
7298e25f19bSMatthew Dillon 		 */
730549987f1SMatthew Dillon addlist:
7318e25f19bSMatthew Dillon 		*hasworkp = 1;
73287017ac4SMatthew Dillon 		if (pkg->flags & PKGF_NOBUILD_I)
7331fa9d809SMatthew Dillon 			ddprintf(depth, "} (ADDLIST(IGNORE/BROKEN) - %s)\n",
73487017ac4SMatthew Dillon 				 pkg->portdir);
73587017ac4SMatthew Dillon 		else if (pkg->flags & PKGF_NOBUILD)
7361fa9d809SMatthew Dillon 			ddprintf(depth, "} (ADDLIST(NOBUILD) - %s)\n",
7379c4c701fSMatthew Dillon 				 pkg->portdir);
7389c4c701fSMatthew Dillon 		else
7391fa9d809SMatthew Dillon 			ddprintf(depth, "} (ADDLIST - %s)\n", pkg->portdir);
7408e25f19bSMatthew Dillon 		pkg->flags |= PKGF_BUILDLIST;
7418e25f19bSMatthew Dillon 		**build_tailp = pkg;
7428e25f19bSMatthew Dillon 		*build_tailp = &pkg->build_next;
743549987f1SMatthew Dillon 		pkg->build_next = NULL;
7448e25f19bSMatthew Dillon 		*app |= PKGF_NOTREADY;
7458e25f19bSMatthew Dillon 	}
7468e25f19bSMatthew Dillon 
7478e25f19bSMatthew Dillon 	return idep_count;
7488e25f19bSMatthew Dillon }
7498e25f19bSMatthew Dillon 
7508e25f19bSMatthew Dillon static
7518e25f19bSMatthew Dillon void
build_clear_trav(pkg_t * pkg)7528e25f19bSMatthew Dillon build_clear_trav(pkg_t *pkg)
7538e25f19bSMatthew Dillon {
7548e25f19bSMatthew Dillon 	pkglink_t *link;
7558e25f19bSMatthew Dillon 	pkg_t *scan;
7568e25f19bSMatthew Dillon 
7578e25f19bSMatthew Dillon 	pkg->flags &= ~PKGF_BUILDTRAV;
7588e25f19bSMatthew Dillon 	PKGLIST_FOREACH(link, &pkg->idepon_list) {
7598e25f19bSMatthew Dillon 		scan = link->pkg;
7608e25f19bSMatthew Dillon 		if (scan && (scan->flags & PKGF_BUILDTRAV))
7618e25f19bSMatthew Dillon 			build_clear_trav(scan);
7628e25f19bSMatthew Dillon 	}
7638e25f19bSMatthew Dillon }
7648e25f19bSMatthew Dillon 
7658e25f19bSMatthew Dillon /*
76688c24d72SMatthew Dillon  * Calculate the longest chain of packages that depend on me.  The
76788c24d72SMatthew Dillon  * long the chain, the more important my package is to build earlier
76888c24d72SMatthew Dillon  * rather than later.
76988c24d72SMatthew Dillon  */
77088c24d72SMatthew Dillon static int
buildCalculateDepiDepth(pkg_t * pkg)77188c24d72SMatthew Dillon buildCalculateDepiDepth(pkg_t *pkg)
77288c24d72SMatthew Dillon {
77388c24d72SMatthew Dillon 	pkglink_t *link;
77488c24d72SMatthew Dillon 	pkg_t *scan;
77588c24d72SMatthew Dillon 	int best_depth = 0;
77688c24d72SMatthew Dillon 	int res;
77788c24d72SMatthew Dillon 
77888c24d72SMatthew Dillon 	if (pkg->depi_depth)
77988c24d72SMatthew Dillon 		return(pkg->depi_depth + 1);
78088c24d72SMatthew Dillon 	pkg->flags |= PKGF_BUILDLOOP;
78188c24d72SMatthew Dillon 	PKGLIST_FOREACH(link, &pkg->deponi_list) {
78288c24d72SMatthew Dillon 		scan = link->pkg;
78388c24d72SMatthew Dillon 		if (scan && (scan->flags & PKGF_BUILDLOOP) == 0) {
78488c24d72SMatthew Dillon 			res = buildCalculateDepiDepth(scan);
78588c24d72SMatthew Dillon 			if (best_depth < res)
78688c24d72SMatthew Dillon 				best_depth = res;
78788c24d72SMatthew Dillon 		}
78888c24d72SMatthew Dillon 	}
78988c24d72SMatthew Dillon 	pkg->flags &= ~PKGF_BUILDLOOP;
79088c24d72SMatthew Dillon 	pkg->depi_depth = best_depth;
79188c24d72SMatthew Dillon 
79288c24d72SMatthew Dillon 	return (best_depth + 1);
79388c24d72SMatthew Dillon }
79488c24d72SMatthew Dillon 
79588c24d72SMatthew Dillon /*
7968e25f19bSMatthew Dillon  * Take a list of pkg ready to go, sort it, and assign it to worker
7978e25f19bSMatthew Dillon  * slots.  This routine blocks in waitbuild() until it can dispose of
7988e25f19bSMatthew Dillon  * the entire list.
7998e25f19bSMatthew Dillon  *
8008e25f19bSMatthew Dillon  * WorkerMutex is held by the caller.
8018e25f19bSMatthew Dillon  */
8028e25f19bSMatthew Dillon static
8038e25f19bSMatthew Dillon void
startbuild(pkg_t ** build_listp,pkg_t *** build_tailp)8048e25f19bSMatthew Dillon startbuild(pkg_t **build_listp, pkg_t ***build_tailp)
8058e25f19bSMatthew Dillon {
8068e25f19bSMatthew Dillon 	pkg_t *pkg;
8078e25f19bSMatthew Dillon 	pkg_t **idep_ary;
8088e25f19bSMatthew Dillon 	pkg_t **depi_ary;
8098e25f19bSMatthew Dillon 	int count;
8108e25f19bSMatthew Dillon 	int idep_index;
8118e25f19bSMatthew Dillon 	int depi_index;
8128e25f19bSMatthew Dillon 	int i;
8138e25f19bSMatthew Dillon 	int n;
8148e25f19bSMatthew Dillon 	worker_t *work;
8158e25f19bSMatthew Dillon 	static int IterateWorker;
8168e25f19bSMatthew Dillon 
8178e25f19bSMatthew Dillon 	/*
8188e25f19bSMatthew Dillon 	 * Nothing to do
8198e25f19bSMatthew Dillon 	 */
8208e25f19bSMatthew Dillon 	if (*build_listp == NULL)
8218e25f19bSMatthew Dillon 		return;
8228e25f19bSMatthew Dillon 
8238e25f19bSMatthew Dillon 	/*
8248e25f19bSMatthew Dillon 	 * Sort
8258e25f19bSMatthew Dillon 	 */
8268e25f19bSMatthew Dillon 	count = 0;
8278e25f19bSMatthew Dillon 	for (pkg = *build_listp; pkg; pkg = pkg->build_next)
8288e25f19bSMatthew Dillon 		++count;
8298e25f19bSMatthew Dillon 	idep_ary = calloc(count, sizeof(pkg_t *));
8308e25f19bSMatthew Dillon 	depi_ary = calloc(count, sizeof(pkg_t *));
8318e25f19bSMatthew Dillon 
8328e25f19bSMatthew Dillon 	count = 0;
8338e25f19bSMatthew Dillon 	for (pkg = *build_listp; pkg; pkg = pkg->build_next) {
8348e25f19bSMatthew Dillon 		idep_ary[count] = pkg;
8358e25f19bSMatthew Dillon 		depi_ary[count] = pkg;
8368e25f19bSMatthew Dillon 		++count;
8378e25f19bSMatthew Dillon 	}
8388e25f19bSMatthew Dillon 
8398e25f19bSMatthew Dillon 	/*
8408e25f19bSMatthew Dillon 	 * idep_ary - sorted by #of dependencies this pkg has.
8418e25f19bSMatthew Dillon 	 * depi_ary - sorted by #of other packages that depend on this pkg.
8428e25f19bSMatthew Dillon 	 */
8438e25f19bSMatthew Dillon 	qsort(idep_ary, count, sizeof(pkg_t *), qsort_idep);
8448e25f19bSMatthew Dillon 	qsort(depi_ary, count, sizeof(pkg_t *), qsort_depi);
8458e25f19bSMatthew Dillon 
8468e25f19bSMatthew Dillon 	idep_index = 0;
8478e25f19bSMatthew Dillon 	depi_index = 0;
8488e25f19bSMatthew Dillon 
8498e25f19bSMatthew Dillon 	/*
8508e25f19bSMatthew Dillon 	 * Half the workers build based on the highest depi count,
8518e25f19bSMatthew Dillon 	 * the other half build based on the highest idep count.
8528e25f19bSMatthew Dillon 	 *
8538e25f19bSMatthew Dillon 	 * This is an attempt to get projects which many other projects
8548e25f19bSMatthew Dillon 	 * depend on built first, but to also try to build large projects
8558e25f19bSMatthew Dillon 	 * (which tend to have a lot of dependencies) earlier rather than
8568e25f19bSMatthew Dillon 	 * later so the end of the bulk run doesn't inefficiently build
8578e25f19bSMatthew Dillon 	 * the last few huge projects.
8588e25f19bSMatthew Dillon 	 *
8598e25f19bSMatthew Dillon 	 * Loop until we manage to assign slots to everyone.  We do not
8608e25f19bSMatthew Dillon 	 * wait for build completion.
8618e25f19bSMatthew Dillon 	 *
8628e25f19bSMatthew Dillon 	 * This is the point where we handle DUMMY packages (these are
8638e25f19bSMatthew Dillon 	 * dummy unflavored packages which 'cover' all the flavors for
8648e25f19bSMatthew Dillon 	 * a package).  These are not real packages are marked SUCCESS
8658e25f19bSMatthew Dillon 	 * at this time because their dependencies (the flavors) have all
8668e25f19bSMatthew Dillon 	 * been built.
8678e25f19bSMatthew Dillon 	 */
8688e25f19bSMatthew Dillon 	while (idep_index != count || depi_index != count) {
8698e25f19bSMatthew Dillon 		pkg_t *pkgi;
8708e25f19bSMatthew Dillon 		pkg_t *ipkg;
8718e25f19bSMatthew Dillon 
8728e25f19bSMatthew Dillon 		/*
8738e25f19bSMatthew Dillon 		 * Find candidate to start sorted by depi or idep.
8748e25f19bSMatthew Dillon 		 */
8758e25f19bSMatthew Dillon 		ipkg = NULL;
8768e25f19bSMatthew Dillon 		while (idep_index < count) {
8778e25f19bSMatthew Dillon 			ipkg = idep_ary[idep_index];
8788e25f19bSMatthew Dillon 			if ((ipkg->flags &
8793699ee09SMatthew Dillon 			     (PKGF_SUCCESS | PKGF_FAILURE |
8803699ee09SMatthew Dillon 			      PKGF_ERROR | PKGF_RUNNING)) == 0) {
8818e25f19bSMatthew Dillon 				break;
8828e25f19bSMatthew Dillon 			}
8838e25f19bSMatthew Dillon 			ipkg = NULL;
8848e25f19bSMatthew Dillon 			++idep_index;
8858e25f19bSMatthew Dillon 		}
8868e25f19bSMatthew Dillon 
8878e25f19bSMatthew Dillon 		pkgi = NULL;
8888e25f19bSMatthew Dillon 		while (depi_index < count) {
8898e25f19bSMatthew Dillon 			pkgi = depi_ary[depi_index];
8908e25f19bSMatthew Dillon 			if ((pkgi->flags &
8913699ee09SMatthew Dillon 			     (PKGF_SUCCESS | PKGF_FAILURE |
8923699ee09SMatthew Dillon 			      PKGF_ERROR | PKGF_RUNNING)) == 0) {
8938e25f19bSMatthew Dillon 				break;
8948e25f19bSMatthew Dillon 			}
8958e25f19bSMatthew Dillon 			pkgi = NULL;
8968e25f19bSMatthew Dillon 			++depi_index;
8978e25f19bSMatthew Dillon 		}
8988e25f19bSMatthew Dillon 
899f7f25838SMatthew Dillon 		/*
900f7f25838SMatthew Dillon 		 * ipkg and pkgi must either both be NULL, or both
901f7f25838SMatthew Dillon 		 * be non-NULL.
902f7f25838SMatthew Dillon 		 */
9038e25f19bSMatthew Dillon 		if (ipkg == NULL && pkgi == NULL)
9048e25f19bSMatthew Dillon 			break;
9058e25f19bSMatthew Dillon 		ddassert(ipkg && pkgi);
9068e25f19bSMatthew Dillon 
9078e25f19bSMatthew Dillon 		/*
9089c4c701fSMatthew Dillon 		 * Handle the NOBUILD case right here, there's no point
9099c4c701fSMatthew Dillon 		 * queueing it anywhere.
9109c4c701fSMatthew Dillon 		 */
9119c4c701fSMatthew Dillon 		if (ipkg->flags & PKGF_NOBUILD) {
9129c4c701fSMatthew Dillon 			char *reason;
91364b61b2eSMatthew Dillon 			char skipbuf[16];
91464b61b2eSMatthew Dillon 			int scount;
91564b61b2eSMatthew Dillon 
91664b61b2eSMatthew Dillon 			scount = buildskipcount_dueto(ipkg, 1);
91764b61b2eSMatthew Dillon 			buildskipcount_dueto(ipkg, 0);
91864b61b2eSMatthew Dillon 			if (scount) {
91964b61b2eSMatthew Dillon 				snprintf(skipbuf, sizeof(skipbuf), " %d",
92064b61b2eSMatthew Dillon 					 scount);
92164b61b2eSMatthew Dillon 			} else {
92264b61b2eSMatthew Dillon 				skipbuf[0] = 0;
92364b61b2eSMatthew Dillon 			}
9249c4c701fSMatthew Dillon 
9259c4c701fSMatthew Dillon 			ipkg->flags |= PKGF_FAILURE;
9269c4c701fSMatthew Dillon 			ipkg->flags &= ~PKGF_BUILDLIST;
9279c4c701fSMatthew Dillon 
9283699ee09SMatthew Dillon 			reason = buildskipreason(NULL, ipkg);
9294ea2ee4dSMatthew Dillon 			if (ipkg->flags & PKGF_NOBUILD_I) {
9304ea2ee4dSMatthew Dillon 				++BuildIgnoreCount;
93164b61b2eSMatthew Dillon 				dlog(DLOG_IGN,
93264b61b2eSMatthew Dillon 				     "[XXX] %s%s ignored due to %s\n",
93364b61b2eSMatthew Dillon 				     ipkg->portdir, skipbuf, reason);
93464b61b2eSMatthew Dillon 				RunStatsUpdateCompletion(NULL, DLOG_IGN, ipkg,
93564b61b2eSMatthew Dillon 							 reason, skipbuf);
936a69ec4d6SMatthew Dillon 				doHook(ipkg, "hook_pkg_ignored",
93768dc2eeaSMatthew Dillon 				       HookPkgIgnored, 0);
9384ea2ee4dSMatthew Dillon 			} else {
9394ea2ee4dSMatthew Dillon 				++BuildSkipCount;
94064b61b2eSMatthew Dillon 				dlog(DLOG_SKIP,
94164b61b2eSMatthew Dillon 				     "[XXX] %s%s skipped due to %s\n",
94264b61b2eSMatthew Dillon 				     ipkg->portdir, skipbuf, reason);
94364b61b2eSMatthew Dillon 				RunStatsUpdateCompletion(NULL, DLOG_SKIP, ipkg,
94464b61b2eSMatthew Dillon 							 reason, skipbuf);
945a69ec4d6SMatthew Dillon 				doHook(ipkg, "hook_pkg_skipped",
94668dc2eeaSMatthew Dillon 				       HookPkgSkipped, 0);
9474ea2ee4dSMatthew Dillon 			}
9489c4c701fSMatthew Dillon 			free(reason);
949ffc851f6SMatthew Dillon 			++BuildCount;
9509c4c701fSMatthew Dillon 			continue;
9519c4c701fSMatthew Dillon 		}
9529c4c701fSMatthew Dillon 		if (pkgi->flags & PKGF_NOBUILD) {
9539c4c701fSMatthew Dillon 			char *reason;
95464b61b2eSMatthew Dillon 			char skipbuf[16];
95564b61b2eSMatthew Dillon 			int scount;
95664b61b2eSMatthew Dillon 
95764b61b2eSMatthew Dillon 			scount = buildskipcount_dueto(pkgi, 1);
95864b61b2eSMatthew Dillon 			buildskipcount_dueto(pkgi, 0);
95964b61b2eSMatthew Dillon 			if (scount) {
96064b61b2eSMatthew Dillon 				snprintf(skipbuf, sizeof(skipbuf), " %d",
96164b61b2eSMatthew Dillon 					 scount);
96264b61b2eSMatthew Dillon 			} else {
96364b61b2eSMatthew Dillon 				skipbuf[0] = 0;
96464b61b2eSMatthew Dillon 			}
9659c4c701fSMatthew Dillon 
9669c4c701fSMatthew Dillon 			pkgi->flags |= PKGF_FAILURE;
9679c4c701fSMatthew Dillon 			pkgi->flags &= ~PKGF_BUILDLIST;
9689c4c701fSMatthew Dillon 
9693699ee09SMatthew Dillon 			reason = buildskipreason(NULL, pkgi);
970ffc851f6SMatthew Dillon 			if (pkgi->flags & PKGF_NOBUILD_I) {
971ffc851f6SMatthew Dillon 				++BuildIgnoreCount;
97264b61b2eSMatthew Dillon 				dlog(DLOG_IGN, "[XXX] %s%s ignored due to %s\n",
97364b61b2eSMatthew Dillon 				     pkgi->portdir, skipbuf, reason);
97464b61b2eSMatthew Dillon 				RunStatsUpdateCompletion(NULL, DLOG_IGN, pkgi,
97564b61b2eSMatthew Dillon 							 reason, skipbuf);
976a69ec4d6SMatthew Dillon 				doHook(pkgi, "hook_pkg_ignored",
97768dc2eeaSMatthew Dillon 				       HookPkgIgnored, 0);
978ffc851f6SMatthew Dillon 			} else {
979ffc851f6SMatthew Dillon 				++BuildSkipCount;
98064b61b2eSMatthew Dillon 				dlog(DLOG_SKIP,
98164b61b2eSMatthew Dillon 				     "[XXX] %s%s skipped due to %s\n",
98264b61b2eSMatthew Dillon 				     pkgi->portdir, skipbuf, reason);
98364b61b2eSMatthew Dillon 				RunStatsUpdateCompletion(NULL, DLOG_SKIP, pkgi,
98464b61b2eSMatthew Dillon 							 reason, skipbuf);
985a69ec4d6SMatthew Dillon 				doHook(pkgi, "hook_pkg_skipped",
98668dc2eeaSMatthew Dillon 				       HookPkgSkipped, 0);
987ffc851f6SMatthew Dillon 			}
9889c4c701fSMatthew Dillon 			free(reason);
989ffc851f6SMatthew Dillon 			++BuildCount;
9909c4c701fSMatthew Dillon 			continue;
9919c4c701fSMatthew Dillon 		}
9929c4c701fSMatthew Dillon 
9939c4c701fSMatthew Dillon 		/*
9948e25f19bSMatthew Dillon 		 * Block while no slots are available.  waitbuild()
9958e25f19bSMatthew Dillon 		 * will clean out any DONE states.
9968e25f19bSMatthew Dillon 		 */
9978d9409b8SMatthew Dillon 		while (RunningWorkers >= DynamicMaxWorkers ||
9988d9409b8SMatthew Dillon 		       RunningWorkers >= MaxWorkers - FailedWorkers) {
9993699ee09SMatthew Dillon 			waitbuild(RunningWorkers, 1);
10008e25f19bSMatthew Dillon 		}
10018e25f19bSMatthew Dillon 
10028e25f19bSMatthew Dillon 		/*
10038e25f19bSMatthew Dillon 		 * Find an available worker slot, there should be at
10048e25f19bSMatthew Dillon 		 * least one.
10058e25f19bSMatthew Dillon 		 */
10068e25f19bSMatthew Dillon 		for (i = 0; i < MaxWorkers; ++i) {
10078e25f19bSMatthew Dillon 			n = IterateWorker % MaxWorkers;
10088e25f19bSMatthew Dillon 			work = &WorkerAry[n];
10098e25f19bSMatthew Dillon 
10108e25f19bSMatthew Dillon 			if (work->state == WORKER_DONE ||
10118e25f19bSMatthew Dillon 			    work->state == WORKER_FAILED) {
10128e25f19bSMatthew Dillon 				workercomplete(work);
10138e25f19bSMatthew Dillon 			}
10148e25f19bSMatthew Dillon 			if (work->state == WORKER_NONE ||
10158e25f19bSMatthew Dillon 			    work->state == WORKER_IDLE) {
10168e25f19bSMatthew Dillon 				if (n <= MaxWorkers / 2) {
10178e25f19bSMatthew Dillon 					startworker(pkgi, work);
10188e25f19bSMatthew Dillon 				} else {
10198e25f19bSMatthew Dillon 					startworker(ipkg, work);
10208e25f19bSMatthew Dillon 				}
1021ea37671dSMatthew Dillon 				/*RunStatsUpdate(work);*/
10228e25f19bSMatthew Dillon 				break;
10238e25f19bSMatthew Dillon 			}
10248e25f19bSMatthew Dillon 			++IterateWorker;
10258e25f19bSMatthew Dillon 		}
10268e25f19bSMatthew Dillon 		ddassert(i != MaxWorkers);
10278e25f19bSMatthew Dillon 	}
1028ea37671dSMatthew Dillon 	RunStatsSync();
10298e25f19bSMatthew Dillon 
10308e25f19bSMatthew Dillon 	/*
10318e25f19bSMatthew Dillon 	 * We disposed of the whole list
10328e25f19bSMatthew Dillon 	 */
10338e25f19bSMatthew Dillon 	free(idep_ary);
10348e25f19bSMatthew Dillon 	free(depi_ary);
10358e25f19bSMatthew Dillon 	*build_listp = NULL;
10368e25f19bSMatthew Dillon 	*build_tailp = build_listp;
10378e25f19bSMatthew Dillon }
10388e25f19bSMatthew Dillon 
10398e25f19bSMatthew Dillon typedef const pkg_t *pkg_tt;
10408e25f19bSMatthew Dillon 
10418e25f19bSMatthew Dillon static int
qsort_idep(const void * pkg1_arg,const void * pkg2_arg)10428e25f19bSMatthew Dillon qsort_idep(const void *pkg1_arg, const void *pkg2_arg)
10438e25f19bSMatthew Dillon {
10448e25f19bSMatthew Dillon 	const pkg_t *pkg1 = *(const pkg_tt *)pkg1_arg;
10458e25f19bSMatthew Dillon 	const pkg_t *pkg2 = *(const pkg_tt *)pkg2_arg;
10468e25f19bSMatthew Dillon 
10478e25f19bSMatthew Dillon 	return (pkg2->idep_count - pkg1->idep_count);
10488e25f19bSMatthew Dillon }
10498e25f19bSMatthew Dillon 
10508e25f19bSMatthew Dillon static int
qsort_depi(const void * pkg1_arg,const void * pkg2_arg)10518e25f19bSMatthew Dillon qsort_depi(const void *pkg1_arg, const void *pkg2_arg)
10528e25f19bSMatthew Dillon {
10538e25f19bSMatthew Dillon 	const pkg_t *pkg1 = *(const pkg_tt *)pkg1_arg;
10548e25f19bSMatthew Dillon 	const pkg_t *pkg2 = *(const pkg_tt *)pkg2_arg;
10558e25f19bSMatthew Dillon 
105688c24d72SMatthew Dillon 	return ((pkg2->depi_count * pkg2->depi_depth) -
105788c24d72SMatthew Dillon 		(pkg1->depi_count * pkg1->depi_depth));
10588e25f19bSMatthew Dillon }
10598e25f19bSMatthew Dillon 
10608e25f19bSMatthew Dillon /*
10618e25f19bSMatthew Dillon  * Frontend starts a pkg up on a worker
10628e25f19bSMatthew Dillon  *
10638e25f19bSMatthew Dillon  * WorkerMutex must be held.
10648e25f19bSMatthew Dillon  */
10658e25f19bSMatthew Dillon static void
startworker(pkg_t * pkg,worker_t * work)10668e25f19bSMatthew Dillon startworker(pkg_t *pkg, worker_t *work)
10678e25f19bSMatthew Dillon {
10688e25f19bSMatthew Dillon 	switch(work->state) {
10698e25f19bSMatthew Dillon 	case WORKER_NONE:
10708e25f19bSMatthew Dillon 		pthread_create(&work->td, NULL, childBuilderThread, work);
10718e25f19bSMatthew Dillon 		work->state = WORKER_IDLE;
10728e25f19bSMatthew Dillon 		/* fall through */
10738e25f19bSMatthew Dillon 	case WORKER_IDLE:
1074fef2fc63SMatthew Dillon 		work->pkg_dep_size =
10751fa9d809SMatthew Dillon 		childInstallPkgDeps_recurse(NULL, &pkg->idepon_list, 0, 1, 0);
10761fa9d809SMatthew Dillon 		childInstallPkgDeps_recurse(NULL, &pkg->idepon_list, 1, 1, 0);
1077fef2fc63SMatthew Dillon 		RunningPkgDepSize += work->pkg_dep_size;
1078fef2fc63SMatthew Dillon 
1079a574cbf0SMatthew Dillon 		dlog(DLOG_ALL, "[%03d] START   %s "
1080a574cbf0SMatthew Dillon 			       "##idep=%02d depi=%02d/%02d dep=%-4.2fG\n",
108188c24d72SMatthew Dillon 		     work->index, pkg->portdir,
108288c24d72SMatthew Dillon 		     pkg->idep_count, pkg->depi_count, pkg->depi_depth,
1083a574cbf0SMatthew Dillon 		     (double)work->pkg_dep_size / (double)ONEGB);
1084fef2fc63SMatthew Dillon 
10858e25f19bSMatthew Dillon 		cleanworker(work);
10868e25f19bSMatthew Dillon 		pkg->flags |= PKGF_RUNNING;
10878e25f19bSMatthew Dillon 		work->pkg = pkg;
10888e25f19bSMatthew Dillon 		pthread_cond_signal(&work->cond);
10898e25f19bSMatthew Dillon 		++RunningWorkers;
1090ea37671dSMatthew Dillon 		/*RunStatsUpdate(work);*/
10918e25f19bSMatthew Dillon 		break;
10928e25f19bSMatthew Dillon 	case WORKER_PENDING:
10938e25f19bSMatthew Dillon 	case WORKER_RUNNING:
10948e25f19bSMatthew Dillon 	case WORKER_DONE:
10958e25f19bSMatthew Dillon 	case WORKER_FAILED:
10968ec23ca1SMatthew Dillon 	case WORKER_FROZEN:
10978e25f19bSMatthew Dillon 	case WORKER_EXITING:
10988e25f19bSMatthew Dillon 	default:
10996fd67931SMatthew Dillon 		dfatal("startworker: [%03d] Unexpected state %d for worker %d",
11006fd67931SMatthew Dillon 		       work->index, work->state, work->index);
11018e25f19bSMatthew Dillon 		break;
11028e25f19bSMatthew Dillon 	}
11038e25f19bSMatthew Dillon }
11048e25f19bSMatthew Dillon 
11058e25f19bSMatthew Dillon static void
cleanworker(worker_t * work)11068e25f19bSMatthew Dillon cleanworker(worker_t *work)
11078e25f19bSMatthew Dillon {
11088e25f19bSMatthew Dillon 	work->state = WORKER_PENDING;
11098e25f19bSMatthew Dillon 	work->flags = 0;
11108e25f19bSMatthew Dillon 	work->accum_error = 0;
11118e25f19bSMatthew Dillon 	work->start_time = time(NULL);
11128e25f19bSMatthew Dillon }
11138e25f19bSMatthew Dillon 
11148e25f19bSMatthew Dillon /*
11158e25f19bSMatthew Dillon  * Frontend finishes up a completed pkg on a worker.
11168e25f19bSMatthew Dillon  *
11178e25f19bSMatthew Dillon  * If the worker is in a FAILED state we clean the pkg out but (for now)
11188e25f19bSMatthew Dillon  * leave it in its failed state so we can debug.  At this point
11198e25f19bSMatthew Dillon  * workercomplete() will be called every once in a while on the state
11208e25f19bSMatthew Dillon  * and we have to deal with the NULL pkg.
11218e25f19bSMatthew Dillon  *
11228e25f19bSMatthew Dillon  * WorkerMutex must be held.
11238e25f19bSMatthew Dillon  */
11248e25f19bSMatthew Dillon static void
workercomplete(worker_t * work)11258e25f19bSMatthew Dillon workercomplete(worker_t *work)
11268e25f19bSMatthew Dillon {
11278e25f19bSMatthew Dillon 	pkg_t *pkg;
11283232b774SMatthew Dillon 	time_t t;
11293232b774SMatthew Dillon 	int h;
11303232b774SMatthew Dillon 	int m;
11313232b774SMatthew Dillon 	int s;
11328e25f19bSMatthew Dillon 
11338e25f19bSMatthew Dillon 	/*
11348e25f19bSMatthew Dillon 	 * Steady state FAILED case.
11358e25f19bSMatthew Dillon 	 */
11368e25f19bSMatthew Dillon 	if (work->state == WORKER_FAILED) {
11378e25f19bSMatthew Dillon 		if (work->pkg == NULL)
11388e25f19bSMatthew Dillon 			return;
11398e25f19bSMatthew Dillon 	}
11408e25f19bSMatthew Dillon 
11413232b774SMatthew Dillon 	t = time(NULL) - work->start_time;
11423232b774SMatthew Dillon 	h = t / 3600;
1143a574cbf0SMatthew Dillon 	m = t / 60 % 60;
1144a574cbf0SMatthew Dillon 	s = t % 60;
11453232b774SMatthew Dillon 
11468e25f19bSMatthew Dillon 	/*
1147fef2fc63SMatthew Dillon 	 * Reduce total dep size
1148fef2fc63SMatthew Dillon 	 */
1149fef2fc63SMatthew Dillon 	RunningPkgDepSize -= work->pkg_dep_size;
1150516819d9SMatthew Dillon 	RunningPkgDepSize -= work->memuse;
1151516819d9SMatthew Dillon 	work->pkg_dep_size = 0;
1152516819d9SMatthew Dillon 	work->memuse = 0;
1153fef2fc63SMatthew Dillon 
1154fef2fc63SMatthew Dillon 	/*
11558e25f19bSMatthew Dillon 	 * Process pkg out of the worker
11568e25f19bSMatthew Dillon 	 */
11578e25f19bSMatthew Dillon 	pkg = work->pkg;
11588e25f19bSMatthew Dillon 	if (pkg->flags & (PKGF_ERROR|PKGF_NOBUILD)) {
115964b61b2eSMatthew Dillon 		char skipbuf[16];
116064b61b2eSMatthew Dillon 		int scount;
116164b61b2eSMatthew Dillon 
1162d1e52415SMatthew Dillon 		/*
1163d1e52415SMatthew Dillon 		 * Normally mark the package as failed, but if we are doing
1164d1e52415SMatthew Dillon 		 * a fetch-only, mark it as successful so dependant ports
1165d1e52415SMatthew Dillon 		 * still get fetched.
1166d1e52415SMatthew Dillon 		 */
1167d1e52415SMatthew Dillon 		if (FetchOnlyOpt)
1168d1e52415SMatthew Dillon 			pkg->flags |= PKGF_SUCCESS;
1169d1e52415SMatthew Dillon 		else
11708e25f19bSMatthew Dillon 			pkg->flags |= PKGF_FAILURE;
11719c4c701fSMatthew Dillon 
117264b61b2eSMatthew Dillon 		scount = buildskipcount_dueto(pkg, 1);
117364b61b2eSMatthew Dillon 		buildskipcount_dueto(pkg, 0);
117464b61b2eSMatthew Dillon 		if (scount) {
117564b61b2eSMatthew Dillon 			snprintf(skipbuf, sizeof(skipbuf), " %d",
117664b61b2eSMatthew Dillon 				 scount);
117764b61b2eSMatthew Dillon 		} else {
117864b61b2eSMatthew Dillon 			skipbuf[0] = 0;
117964b61b2eSMatthew Dillon 		}
118064b61b2eSMatthew Dillon 
11819c4c701fSMatthew Dillon 		/*
11829c4c701fSMatthew Dillon 		 * This NOBUILD condition XXX can occur if the package is
11839c4c701fSMatthew Dillon 		 * not allowed to be built.
11849c4c701fSMatthew Dillon 		 */
11858e25f19bSMatthew Dillon 		if (pkg->flags & PKGF_NOBUILD) {
11868e25f19bSMatthew Dillon 			char *reason;
11878e25f19bSMatthew Dillon 
11883699ee09SMatthew Dillon 			reason = buildskipreason(NULL, pkg);
11893232b774SMatthew Dillon 			if (pkg->flags & PKGF_NOBUILD_I) {
11903232b774SMatthew Dillon 				++BuildIgnoreCount;
119164b61b2eSMatthew Dillon 				dlog(DLOG_SKIP, "[%03d] IGNORD %s%s - %s\n",
119264b61b2eSMatthew Dillon 				     work->index, pkg->portdir,
119364b61b2eSMatthew Dillon 				     skipbuf, reason);
119464b61b2eSMatthew Dillon 				RunStatsUpdateCompletion(work, DLOG_SKIP, pkg,
119564b61b2eSMatthew Dillon 							 reason, skipbuf);
119668dc2eeaSMatthew Dillon 				doHook(pkg, "hook_pkg_ignored",
119768dc2eeaSMatthew Dillon 				       HookPkgIgnored, 0);
11983232b774SMatthew Dillon 			} else {
11993232b774SMatthew Dillon 				++BuildSkipCount;
120064b61b2eSMatthew Dillon 				dlog(DLOG_SKIP, "[%03d] SKIPPD %s%s - %s\n",
120164b61b2eSMatthew Dillon 				     work->index, pkg->portdir,
120264b61b2eSMatthew Dillon 				     skipbuf, reason);
120364b61b2eSMatthew Dillon 				RunStatsUpdateCompletion(work, DLOG_SKIP, pkg,
120464b61b2eSMatthew Dillon 							 reason, skipbuf);
120568dc2eeaSMatthew Dillon 				doHook(pkg, "hook_pkg_skipped",
120668dc2eeaSMatthew Dillon 				       HookPkgSkipped, 0);
12073232b774SMatthew Dillon 			}
12088e25f19bSMatthew Dillon 			free(reason);
12098e25f19bSMatthew Dillon 		} else {
12108e25f19bSMatthew Dillon 			++BuildFailCount;
1211a574cbf0SMatthew Dillon 			dlog(DLOG_FAIL | DLOG_RED,
12123dd48cfaSMatthew Dillon 			     "[%03d] FAILURE %s%s ##%16.16s %02d:%02d:%02d\n",
12133dd48cfaSMatthew Dillon 			     work->index, pkg->portdir, skipbuf,
12143cebe4a8SMatthew Dillon 			     getphasestr(work->phase),
12153cebe4a8SMatthew Dillon 			     h, m, s);
121664b61b2eSMatthew Dillon 			RunStatsUpdateCompletion(work, DLOG_FAIL, pkg,
121764b61b2eSMatthew Dillon 						 skipbuf, "");
121868dc2eeaSMatthew Dillon 			doHook(pkg, "hook_pkg_failure", HookPkgFailure, 0);
12198e25f19bSMatthew Dillon 		}
12208e25f19bSMatthew Dillon 	} else {
1221b6bd007bSMatthew Dillon 		if (CheckDBM) {
1222b6bd007bSMatthew Dillon 			datum key;
1223b6bd007bSMatthew Dillon 			datum data;
1224b6bd007bSMatthew Dillon 
1225b6bd007bSMatthew Dillon 			key.dptr = pkg->portdir;
1226b6bd007bSMatthew Dillon 			key.dsize = strlen(pkg->portdir);
1227b6bd007bSMatthew Dillon 			data.dptr = &pkg->crc32;
1228b6bd007bSMatthew Dillon 			data.dsize = sizeof(pkg->crc32);
12297b5ce327SMatthew Dillon #ifndef __DB_IS_THREADSAFE
12307b5ce327SMatthew Dillon 			pthread_mutex_lock(&DbmMutex);
12317b5ce327SMatthew Dillon #endif
1232b6bd007bSMatthew Dillon 			dbm_store(CheckDBM, key, data, DBM_REPLACE);
12337b5ce327SMatthew Dillon #ifndef __DB_IS_THREADSAFE
12347b5ce327SMatthew Dillon 			pthread_mutex_unlock(&DbmMutex);
12357b5ce327SMatthew Dillon #endif
1236b6bd007bSMatthew Dillon 		}
123768dc2eeaSMatthew Dillon 		pkg->flags |= PKGF_SUCCESS;
123868dc2eeaSMatthew Dillon 		++BuildSuccessCount;
1239a574cbf0SMatthew Dillon 		dlog(DLOG_SUCC | DLOG_GRN,
1240a574cbf0SMatthew Dillon 		     "[%03d] SUCCESS %s ##%02d:%02d:%02d\n",
12418e25f19bSMatthew Dillon 		     work->index, pkg->portdir, h, m, s);
124264b61b2eSMatthew Dillon 		RunStatsUpdateCompletion(work, DLOG_SUCC, pkg, "", "");
124368dc2eeaSMatthew Dillon 		doHook(pkg, "hook_pkg_success", HookPkgSuccess, 0);
12448e25f19bSMatthew Dillon 	}
12458e25f19bSMatthew Dillon 	++BuildCount;
12468e25f19bSMatthew Dillon 	pkg->flags &= ~PKGF_BUILDLIST;
12478e25f19bSMatthew Dillon 	pkg->flags &= ~PKGF_RUNNING;
12488e25f19bSMatthew Dillon 	work->pkg = NULL;
12498e25f19bSMatthew Dillon 	--RunningWorkers;
12508e25f19bSMatthew Dillon 
12518e25f19bSMatthew Dillon 	if (work->state == WORKER_FAILED) {
12528e25f19bSMatthew Dillon 		dlog(DLOG_ALL, "[%03d] XXX/XXX WORKER IS IN A FAILED STATE\n",
12538e25f19bSMatthew Dillon 		     work->index);
12548d9409b8SMatthew Dillon 		++FailedWorkers;
12558ec23ca1SMatthew Dillon 	} else if (work->flags & WORKERF_FREEZE) {
1256a574cbf0SMatthew Dillon 		dlog(DLOG_ALL, "[%03d] FROZEN(DEBUG) %s\n",
1257a574cbf0SMatthew Dillon 		     work->index, pkg->portdir);
12588ec23ca1SMatthew Dillon 		work->state = WORKER_FROZEN;
12598e25f19bSMatthew Dillon 	} else {
12608e25f19bSMatthew Dillon 		work->state = WORKER_IDLE;
12618e25f19bSMatthew Dillon 	}
12628e25f19bSMatthew Dillon }
12638e25f19bSMatthew Dillon 
12648e25f19bSMatthew Dillon /*
12658e25f19bSMatthew Dillon  * Wait for one or more workers to complete.
12668e25f19bSMatthew Dillon  *
12678e25f19bSMatthew Dillon  * WorkerMutex must be held.
12688e25f19bSMatthew Dillon  */
12698e25f19bSMatthew Dillon static void
waitbuild(int whilematch,int dynamicmax)12703699ee09SMatthew Dillon waitbuild(int whilematch, int dynamicmax)
12718e25f19bSMatthew Dillon {
12721645cafeSMatthew Dillon 	static time_t wblast_time;
12737f0eca56SMatthew Dillon 	static time_t dmlast_time;
12748e25f19bSMatthew Dillon 	struct timespec ts;
12758e25f19bSMatthew Dillon 	worker_t *work;
12761645cafeSMatthew Dillon 	time_t t;
12778e25f19bSMatthew Dillon 	int i;
12788e25f19bSMatthew Dillon 
12798e25f19bSMatthew Dillon 	if (whilematch == 0)
12808e25f19bSMatthew Dillon 		whilematch = 1;
12818e25f19bSMatthew Dillon 
12828e25f19bSMatthew Dillon 	while (RunningWorkers == whilematch) {
12838e25f19bSMatthew Dillon 		for (i = 0; i < MaxWorkers; ++i) {
12848e25f19bSMatthew Dillon 			work = &WorkerAry[i];
12858e25f19bSMatthew Dillon 			if (work->state == WORKER_DONE ||
12868e25f19bSMatthew Dillon 			    work->state == WORKER_FAILED) {
12878e25f19bSMatthew Dillon 				workercomplete(work);
12888e25f19bSMatthew Dillon 			} else {
12898e25f19bSMatthew Dillon 				pthread_cond_signal(&work->cond);
12908e25f19bSMatthew Dillon 			}
1291aac7a6d9SMatthew Dillon 			RunStatsUpdate(work, NULL);
12928e25f19bSMatthew Dillon 		}
12938b485838SMatthew Dillon 		RunStatsUpdateTop(1);
1294ea37671dSMatthew Dillon 		RunStatsUpdateLogs();
1295ea37671dSMatthew Dillon 		RunStatsSync();
12968e25f19bSMatthew Dillon 		if (RunningWorkers == whilematch) {
12978e25f19bSMatthew Dillon 			clock_gettime(CLOCK_REALTIME, &ts);
12988e25f19bSMatthew Dillon 			ts.tv_sec += 1;
12998e25f19bSMatthew Dillon 			ts.tv_nsec = 0;
13008e25f19bSMatthew Dillon 			pthread_cond_timedwait(&WorkerCond, &WorkerMutex, &ts);
13018e25f19bSMatthew Dillon 		}
13021645cafeSMatthew Dillon 
13031645cafeSMatthew Dillon 		/*
13041645cafeSMatthew Dillon 		 * Dynamically reduce MaxWorkers based on the load.  When
13051645cafeSMatthew Dillon 		 * the load exceeds 2 x ncpus we reduce the number of workers
13069c4c701fSMatthew Dillon 		 * up to 75% of MaxWorkers @ (5 x ncpus) load.
1307f7f25838SMatthew Dillon 		 *
1308f7f25838SMatthew Dillon 		 * Dynamically reduce MaxWorkers based on swap use, starting
1309f7f25838SMatthew Dillon 		 * at 10% swap and up to 75% of MaxWorkers at 40% swap.
1310f7f25838SMatthew Dillon 		 *
1311f7f25838SMatthew Dillon 		 * NOTE! Generally speaking this allows more workers to be
1312f7f25838SMatthew Dillon 		 *	 configured which helps in two ways.  First it allows
1313f7f25838SMatthew Dillon 		 *	 a higher build rate for smaller packages.  Second
1314f7f25838SMatthew Dillon 		 *	 it allows dsynth to ratchet-down the number of slots
1315f7f25838SMatthew Dillon 		 *	 when large packages are forcing the load up.
1316f7f25838SMatthew Dillon 		 *
1317f7f25838SMatthew Dillon 		 *	 A high load doesn't hurt efficiency, but swap usage
1318f7f25838SMatthew Dillon 		 *	 due to loading the tmpfs in lots of worker slots up
1319f7f25838SMatthew Dillon 		 *	 with tons of pkg install's (pre-reqs for a build)
1320f7f25838SMatthew Dillon 		 *	 does.  Reducing the number of worker slots has a
1321f7f25838SMatthew Dillon 		 *	 huge beneficial effect on reducing swap use / paging.
13221645cafeSMatthew Dillon 		 */
13231645cafeSMatthew Dillon 		t = time(NULL);
13243699ee09SMatthew Dillon 		if (dynamicmax && (wblast_time == 0 ||
13253699ee09SMatthew Dillon 				   (unsigned)(t - wblast_time) >= 5)) {
13263699ee09SMatthew Dillon 			double min_load = 1.5 * NumCores;
1327f5fc9cfaSMatthew Dillon 			double max_load = 5.0 * NumCores;
13283699ee09SMatthew Dillon 			double min_swap = 0.10;
13293699ee09SMatthew Dillon 			double max_swap = 0.40;
13301645cafeSMatthew Dillon 			double dload[3];
13313699ee09SMatthew Dillon 			double dswap;
13327f0eca56SMatthew Dillon 			int max1;
13337f0eca56SMatthew Dillon 			int max2;
13347f0eca56SMatthew Dillon 			int max3;
13357f0eca56SMatthew Dillon 			int max_sel;
13363699ee09SMatthew Dillon 			int noswap;
13371645cafeSMatthew Dillon 
13381645cafeSMatthew Dillon 			wblast_time = t;
13391645cafeSMatthew Dillon 
1340fef2fc63SMatthew Dillon 			/*
13417f0eca56SMatthew Dillon 			 * Cap based on load.  This is back-loaded.
1342fef2fc63SMatthew Dillon 			 */
1343fef2fc63SMatthew Dillon 			getloadavg(dload, 3);
134432fc5bbfSMatthew Dillon 			adjloadavg(dload);
13453699ee09SMatthew Dillon 			if (dload[0] < min_load) {
13467f0eca56SMatthew Dillon 				max1 = MaxWorkers;
13473699ee09SMatthew Dillon 			} else if (dload[0] <= max_load) {
13487f0eca56SMatthew Dillon 				max1 = MaxWorkers -
13497f0eca56SMatthew Dillon 				       MaxWorkers * 0.75 *
13507f0eca56SMatthew Dillon 				       (dload[0] - min_load) /
13513699ee09SMatthew Dillon 				       (max_load - min_load);
13529c4c701fSMatthew Dillon 			} else {
13537f0eca56SMatthew Dillon 				max1 = MaxWorkers * 25 / 100;
13549c4c701fSMatthew Dillon 			}
13553699ee09SMatthew Dillon 
1356fef2fc63SMatthew Dillon 			/*
13577f0eca56SMatthew Dillon 			 * Cap based on swap use.  This is back-loaded.
1358fef2fc63SMatthew Dillon 			 */
1359fef2fc63SMatthew Dillon 			dswap = getswappct(&noswap);
13603699ee09SMatthew Dillon 			if (dswap < min_swap) {
13617f0eca56SMatthew Dillon 				max2 = MaxWorkers;
13623699ee09SMatthew Dillon 			} else if (dswap <= max_swap) {
13637f0eca56SMatthew Dillon 				max2 = MaxWorkers -
13647f0eca56SMatthew Dillon 				       MaxWorkers * 0.75 *
13657f0eca56SMatthew Dillon 				       (dswap - min_swap) /
13663699ee09SMatthew Dillon 				       (max_swap - min_swap);
13673699ee09SMatthew Dillon 			} else {
13687f0eca56SMatthew Dillon 				max2 = MaxWorkers * 25 / 100;
13693699ee09SMatthew Dillon 			}
13703699ee09SMatthew Dillon 
13713699ee09SMatthew Dillon 			/*
13727f0eca56SMatthew Dillon 			 * Cap based on aggregate pkg-dependency memory
13737f0eca56SMatthew Dillon 			 * use installed in worker slots.  This is
13747f0eca56SMatthew Dillon 			 * front-loaded.
13757f0eca56SMatthew Dillon 			 *
13767f0eca56SMatthew Dillon 			 * Since it can take a while for workers to retire
13777f0eca56SMatthew Dillon 			 * (to reduce RunningPkgDepSize), just set our
13787f0eca56SMatthew Dillon 			 * target 1 below the current run count to allow
13797f0eca56SMatthew Dillon 			 * jobs to retire without being replaced with new
13807f0eca56SMatthew Dillon 			 * jobs.
13817f0eca56SMatthew Dillon 			 *
13827f0eca56SMatthew Dillon 			 * In addition, in order to avoid a paging 'shock',
13837f0eca56SMatthew Dillon 			 * We enforce a 30 second-per-increment slow-start
13847f0eca56SMatthew Dillon 			 * once RunningPkgDepSize exceeds 1/2 the target.
1385fef2fc63SMatthew Dillon 			 */
13867f0eca56SMatthew Dillon 			if (RunningPkgDepSize > PkgDepMemoryTarget) {
13877f0eca56SMatthew Dillon 				max3 = RunningWorkers - 1;
13887f0eca56SMatthew Dillon 			} else if (RunningPkgDepSize > PkgDepMemoryTarget / 2) {
13897f0eca56SMatthew Dillon 				if (dmlast_time == 0 ||
13907f0eca56SMatthew Dillon 				    (unsigned)(t - dmlast_time) >= 30) {
13917f0eca56SMatthew Dillon 					dmlast_time = t;
13927f0eca56SMatthew Dillon 					max3 = RunningWorkers + 1;
13937f0eca56SMatthew Dillon 				} else {
13947f0eca56SMatthew Dillon 					max3 = RunningWorkers;
13957f0eca56SMatthew Dillon 				}
13967f0eca56SMatthew Dillon 			} else {
13977f0eca56SMatthew Dillon 				max3 = MaxWorkers;
13987f0eca56SMatthew Dillon 			}
1399fef2fc63SMatthew Dillon 
1400fef2fc63SMatthew Dillon 			/*
14014ad2f7b8SMatthew Dillon 			 * Dynamic scale adjustment
14024ad2f7b8SMatthew Dillon 			 */
14034ad2f7b8SMatthew Dillon 
14044ad2f7b8SMatthew Dillon 			if (PkgDepScaleTarget != 100) {
14054ad2f7b8SMatthew Dillon 				max1 = max1 * (PkgDepScaleTarget + 50) / 100;
14064ad2f7b8SMatthew Dillon 				max2 = max2 * (PkgDepScaleTarget + 50) / 100;
14074ad2f7b8SMatthew Dillon 				max3 = max3 * (PkgDepScaleTarget + 50) / 100;
14084ad2f7b8SMatthew Dillon 			}
14094ad2f7b8SMatthew Dillon 
14104ad2f7b8SMatthew Dillon 			/*
14113699ee09SMatthew Dillon 			 * Priority reduction, convert to DynamicMaxWorkers
14123699ee09SMatthew Dillon 			 */
14137f0eca56SMatthew Dillon 			max_sel = max1;
14147f0eca56SMatthew Dillon 			if (max_sel > max2)
14157f0eca56SMatthew Dillon 				max_sel = max2;
14167f0eca56SMatthew Dillon 			if (max_sel > max3)
14177f0eca56SMatthew Dillon 				max_sel = max3;
14183699ee09SMatthew Dillon 
14193699ee09SMatthew Dillon 			/*
14207f0eca56SMatthew Dillon 			 * Restrict to allowed range, and also handle
14217f0eca56SMatthew Dillon 			 * slow-start.
14223699ee09SMatthew Dillon 			 */
14237f0eca56SMatthew Dillon 			if (max_sel < 1)
14247f0eca56SMatthew Dillon 				max_sel = 1;
14257f0eca56SMatthew Dillon 			if (max_sel > DynamicMaxWorkers + 1)
14267f0eca56SMatthew Dillon 				max_sel = DynamicMaxWorkers + 1;
14277f0eca56SMatthew Dillon 			if (max_sel > MaxWorkers)
14287f0eca56SMatthew Dillon 				max_sel = MaxWorkers;
14293699ee09SMatthew Dillon 
14303699ee09SMatthew Dillon 			/*
14317f0eca56SMatthew Dillon 			 * Stop waiting if DynamicMaxWorkers is going to
14327f0eca56SMatthew Dillon 			 * increase.
14333699ee09SMatthew Dillon 			 */
14347f0eca56SMatthew Dillon 			if (DynamicMaxWorkers < max1)
14353699ee09SMatthew Dillon 				whilematch = -1;
14363699ee09SMatthew Dillon 
14373699ee09SMatthew Dillon 			/*
14383699ee09SMatthew Dillon 			 * And adjust
14393699ee09SMatthew Dillon 			 */
14407f0eca56SMatthew Dillon 			if (DynamicMaxWorkers != max1) {
1441a574cbf0SMatthew Dillon 				dlog(DLOG_ALL | DLOG_FILTER,
14427f0eca56SMatthew Dillon 				     "[XXX] Load=%-6.2f(%2d) "
14436fd67931SMatthew Dillon 				     "Swap=%-3.2f%%(%2d) "
14447f0eca56SMatthew Dillon 				     "Mem=%3.2fG(%2d) "
1445fef2fc63SMatthew Dillon 				     "Adjust Workers %d->%d\n",
14467f0eca56SMatthew Dillon 				     dload[0], max1,
14477f0eca56SMatthew Dillon 				     dswap * 100.0, max2,
14487f0eca56SMatthew Dillon 				     RunningPkgDepSize / (double)ONEGB, max3,
14497f0eca56SMatthew Dillon 				     DynamicMaxWorkers, max_sel);
14507f0eca56SMatthew Dillon 				DynamicMaxWorkers = max_sel;
14511645cafeSMatthew Dillon 			}
14521645cafeSMatthew Dillon 		}
14538e25f19bSMatthew Dillon 	}
14548e25f19bSMatthew Dillon }
14558e25f19bSMatthew Dillon 
14568e25f19bSMatthew Dillon 
14578e25f19bSMatthew Dillon /*
14588e25f19bSMatthew Dillon  * Worker pthread (WorkerAry)
14598e25f19bSMatthew Dillon  *
14603bd7e0a7SMatthew Dillon  * This thread belongs to the dsynth master process and handles a worker slot.
14618e25f19bSMatthew Dillon  * (this_thread) -> WORKER fork/exec (WorkerPocess) -> (pty) -> sub-processes.
14628e25f19bSMatthew Dillon  */
14638e25f19bSMatthew Dillon static void *
childBuilderThread(void * arg)14648e25f19bSMatthew Dillon childBuilderThread(void *arg)
14658e25f19bSMatthew Dillon {
14668e25f19bSMatthew Dillon 	char *envary[1] = { NULL };
14678e25f19bSMatthew Dillon 	worker_t *work = arg;
14688e25f19bSMatthew Dillon 	wmsg_t wmsg;
14698e25f19bSMatthew Dillon 	pkg_t *pkg;
14708e25f19bSMatthew Dillon 	pid_t pid;
14718e25f19bSMatthew Dillon 	int status;
1472710838f7SMatthew Dillon 	int flags;
14738e25f19bSMatthew Dillon 	volatile int dowait;
14748e25f19bSMatthew Dillon 	char slotbuf[8];
14758e25f19bSMatthew Dillon 	char fdbuf[8];
14768ec23ca1SMatthew Dillon 	char flagsbuf[16];
14778e25f19bSMatthew Dillon 
14783bd7e0a7SMatthew Dillon 	setNumaDomain(work->index);
14798e25f19bSMatthew Dillon 	pthread_mutex_lock(&WorkerMutex);
14803bd7e0a7SMatthew Dillon 
14818e25f19bSMatthew Dillon 	while (work->terminate == 0) {
14828e25f19bSMatthew Dillon 		dowait = 1;
14838e25f19bSMatthew Dillon 
14848e25f19bSMatthew Dillon 		switch(work->state) {
14858e25f19bSMatthew Dillon 		case WORKER_IDLE:
14868e25f19bSMatthew Dillon 			break;
14878e25f19bSMatthew Dillon 		case WORKER_PENDING:
14888e25f19bSMatthew Dillon 			/*
14898e25f19bSMatthew Dillon 			 * Fork the management process for the pkg operation
14908e25f19bSMatthew Dillon 			 * on this worker slot.
14918e25f19bSMatthew Dillon 			 *
14928e25f19bSMatthew Dillon 			 * This process will set up the environment, do the
14938e25f19bSMatthew Dillon 			 * mounts, will become the reaper, and will process
14948e25f19bSMatthew Dillon 			 * pipe commands and handle chroot operations.
14958e25f19bSMatthew Dillon 			 *
14968e25f19bSMatthew Dillon 			 * NOTE: If SOCK_CLOEXEC is not supported WorkerMutex
14978e25f19bSMatthew Dillon 			 *	 is sufficient to interlock F_SETFD FD_CLOEXEC
14988e25f19bSMatthew Dillon 			 *	 operations.
14998e25f19bSMatthew Dillon 			 */
15008e25f19bSMatthew Dillon 			ddassert(work->pkg);
15018e25f19bSMatthew Dillon 			if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC,
15028e25f19bSMatthew Dillon 				       PF_UNSPEC, work->fds)) {
15038e25f19bSMatthew Dillon 				dfatal_errno("socketpair() during worker fork");
15048e25f19bSMatthew Dillon 			}
1505710838f7SMatthew Dillon 			snprintf(slotbuf, sizeof(slotbuf), "%d", work->index);
1506710838f7SMatthew Dillon 			snprintf(fdbuf, sizeof(fdbuf), "3");
1507710838f7SMatthew Dillon 
1508710838f7SMatthew Dillon 			/*
1509710838f7SMatthew Dillon 			 * Pass global flags and add-in the DEBUGSTOP if
1510710838f7SMatthew Dillon 			 * the package is flagged for debugging.
1511710838f7SMatthew Dillon 			 */
1512710838f7SMatthew Dillon 			flags = WorkerProcFlags;
1513dca89e44SMatthew Dillon 
1514dca89e44SMatthew Dillon 			if (work->pkg->flags & PKGF_DEBUGSTOP)
1515710838f7SMatthew Dillon 				flags |= WORKER_PROC_DEBUGSTOP;
1516dca89e44SMatthew Dillon 			else
1517710838f7SMatthew Dillon 				flags &= ~WORKER_PROC_DEBUGSTOP;
1518dca89e44SMatthew Dillon 
1519dca89e44SMatthew Dillon 			if (PkgVersionPkgSuffix)
1520dca89e44SMatthew Dillon 				flags |= WORKER_PROC_PKGV17;
1521dca89e44SMatthew Dillon 			else
1522dca89e44SMatthew Dillon 				flags &= ~WORKER_PROC_PKGV17;
1523dca89e44SMatthew Dillon 
1524710838f7SMatthew Dillon 			snprintf(flagsbuf, sizeof(flagsbuf), "%d", flags);
15258e25f19bSMatthew Dillon 
15268e25f19bSMatthew Dillon 			/*
15278e25f19bSMatthew Dillon 			 * fds[0] - master
15288e25f19bSMatthew Dillon 			 * fds[1] - slave
15298e25f19bSMatthew Dillon 			 *
15308e25f19bSMatthew Dillon 			 * We pass the salve descriptor in fd 3 and close all
15318e25f19bSMatthew Dillon 			 * other descriptors for security.
15328e25f19bSMatthew Dillon 			 */
15338e25f19bSMatthew Dillon 			pthread_mutex_unlock(&WorkerMutex);
15348e25f19bSMatthew Dillon 			pid = vfork();
15358e25f19bSMatthew Dillon 			if (pid == 0) {
15368e25f19bSMatthew Dillon 				close(work->fds[0]);
15378e25f19bSMatthew Dillon 				dup2(work->fds[1], 3);
15388e25f19bSMatthew Dillon 				closefrom(4);
15398e25f19bSMatthew Dillon 				fcntl(3, F_SETFD, 0);
15408e25f19bSMatthew Dillon 				execle(DSynthExecPath, DSynthExecPath,
1541*a361ab31SMatthew Dillon 				       "-C", ConfigBase,
15429e1d0b12SMatthew Dillon 				       "-p", Profile,
15438e25f19bSMatthew Dillon 				       "WORKER", slotbuf, fdbuf,
15448e25f19bSMatthew Dillon 				       work->pkg->portdir, work->pkg->pkgfile,
15458ec23ca1SMatthew Dillon 				       flagsbuf,
15468e25f19bSMatthew Dillon 				       NULL, envary);
15478e25f19bSMatthew Dillon 				write(2, "EXECLE FAILURE\n", 15);
15488e25f19bSMatthew Dillon 				_exit(1);
15498e25f19bSMatthew Dillon 			}
15508e25f19bSMatthew Dillon 			pthread_mutex_lock(&WorkerMutex);
15518e25f19bSMatthew Dillon 			close(work->fds[1]);
15528e25f19bSMatthew Dillon 			work->phase = PHASE_PENDING;
15538e25f19bSMatthew Dillon 			work->lines = 0;
1554516819d9SMatthew Dillon 			work->memuse = 0;
15558e25f19bSMatthew Dillon 			work->pid = pid;
15568e25f19bSMatthew Dillon 			work->state = WORKER_RUNNING;
15578e25f19bSMatthew Dillon 			/* fall through */
15588e25f19bSMatthew Dillon 		case WORKER_RUNNING:
15598e25f19bSMatthew Dillon 			/*
15608e25f19bSMatthew Dillon 			 * Poll for status updates, if NULL is returned
15618e25f19bSMatthew Dillon 			 * and status is non-zero, the communications link
15628e25f19bSMatthew Dillon 			 * failed unexpectedly.
15638e25f19bSMatthew Dillon 			 */
15648e25f19bSMatthew Dillon 			pkg = work->pkg;
15658e25f19bSMatthew Dillon 			pthread_mutex_unlock(&WorkerMutex);
15668e25f19bSMatthew Dillon 			status = ipcreadmsg(work->fds[0], &wmsg);
15678e25f19bSMatthew Dillon 			pthread_mutex_lock(&WorkerMutex);
15688e25f19bSMatthew Dillon 
15698e25f19bSMatthew Dillon 			if (status == 0) {
15708e25f19bSMatthew Dillon 				/*
15718e25f19bSMatthew Dillon 				 * Normal message, can include normal
15728e25f19bSMatthew Dillon 				 * termination which changes us over
15738e25f19bSMatthew Dillon 				 * to another state.
15748e25f19bSMatthew Dillon 				 */
15758e25f19bSMatthew Dillon 				dowait = 0;
15768e25f19bSMatthew Dillon 				switch(wmsg.cmd) {
15778e25f19bSMatthew Dillon 				case WMSG_CMD_INSTALL_PKGS:
15788e25f19bSMatthew Dillon 					wmsg.cmd = WMSG_RES_INSTALL_PKGS;
15798e25f19bSMatthew Dillon 					wmsg.status = childInstallPkgDeps(work);
15808e25f19bSMatthew Dillon 					pthread_mutex_unlock(&WorkerMutex);
15818e25f19bSMatthew Dillon 					ipcwritemsg(work->fds[0], &wmsg);
15828e25f19bSMatthew Dillon 					pthread_mutex_lock(&WorkerMutex);
15838e25f19bSMatthew Dillon 					break;
15848e25f19bSMatthew Dillon 				case WMSG_CMD_STATUS_UPDATE:
15858e25f19bSMatthew Dillon 					work->phase = wmsg.phase;
15868e25f19bSMatthew Dillon 					work->lines = wmsg.lines;
1587516819d9SMatthew Dillon 					if (work->memuse != wmsg.memuse) {
1588516819d9SMatthew Dillon 						RunningPkgDepSize +=
1589516819d9SMatthew Dillon 						wmsg.memuse - work->memuse;
1590516819d9SMatthew Dillon 						work->memuse = wmsg.memuse;
1591516819d9SMatthew Dillon 					}
15928e25f19bSMatthew Dillon 					break;
15938e25f19bSMatthew Dillon 				case WMSG_CMD_SUCCESS:
15948e25f19bSMatthew Dillon 					work->flags |= WORKERF_SUCCESS;
15958e25f19bSMatthew Dillon 					break;
15968e25f19bSMatthew Dillon 				case WMSG_CMD_FAILURE:
15978e25f19bSMatthew Dillon 					work->flags |= WORKERF_FAILURE;
15988e25f19bSMatthew Dillon 					break;
15998ec23ca1SMatthew Dillon 				case WMSG_CMD_FREEZEWORKER:
16008ec23ca1SMatthew Dillon 					work->flags |= WORKERF_FREEZE;
16018ec23ca1SMatthew Dillon 					break;
16028e25f19bSMatthew Dillon 				default:
16038e25f19bSMatthew Dillon 					break;
16048e25f19bSMatthew Dillon 				}
1605aac7a6d9SMatthew Dillon 				RunStatsUpdate(work, NULL);
1606ea37671dSMatthew Dillon 				RunStatsSync();
16078e25f19bSMatthew Dillon 			} else {
16088e25f19bSMatthew Dillon 				close(work->fds[0]);
16098e25f19bSMatthew Dillon 				pthread_mutex_unlock(&WorkerMutex);
16108e25f19bSMatthew Dillon 				while (waitpid(work->pid, &status, 0) < 0 &&
16118e25f19bSMatthew Dillon 				       errno == EINTR) {
16128e25f19bSMatthew Dillon 					;
16138e25f19bSMatthew Dillon 				}
16148e25f19bSMatthew Dillon 				pthread_mutex_lock(&WorkerMutex);
16158e25f19bSMatthew Dillon 
16168e25f19bSMatthew Dillon 				if (work->flags & WORKERF_SUCCESS) {
16178e25f19bSMatthew Dillon 					pkg->flags |= PKGF_SUCCESS;
16188e25f19bSMatthew Dillon 					work->state = WORKER_DONE;
16198e25f19bSMatthew Dillon 				} else if (work->flags & WORKERF_FAILURE) {
16208e25f19bSMatthew Dillon 					pkg->flags |= PKGF_FAILURE;
16218e25f19bSMatthew Dillon 					work->state = WORKER_DONE;
16228e25f19bSMatthew Dillon 				} else {
16238e25f19bSMatthew Dillon 					pkg->flags |= PKGF_FAILURE;
16248e25f19bSMatthew Dillon 					work->state = WORKER_FAILED;
16258e25f19bSMatthew Dillon 				}
16268e25f19bSMatthew Dillon 				work->flags |= WORKERF_STATUS_UPDATE;
16278e25f19bSMatthew Dillon 				pthread_cond_signal(&WorkerCond);
16288e25f19bSMatthew Dillon 			}
16298e25f19bSMatthew Dillon 			break;
16308e25f19bSMatthew Dillon 		case WORKER_DONE:
16318e25f19bSMatthew Dillon 			/*
16328e25f19bSMatthew Dillon 			 * pkg remains attached until frontend processes the
16338e25f19bSMatthew Dillon 			 * completion.  The frontend will then set the state
16348e25f19bSMatthew Dillon 			 * back to idle.
16358e25f19bSMatthew Dillon 			 */
16368e25f19bSMatthew Dillon 			break;
16378e25f19bSMatthew Dillon 		case WORKER_FAILED:
16388e25f19bSMatthew Dillon 			/*
16398e25f19bSMatthew Dillon 			 * A worker failure means that the worker did not
16408e25f19bSMatthew Dillon 			 * send us a WMSG_CMD_SUCCESS or WMSG_CMD_FAILURE
16418e25f19bSMatthew Dillon 			 * ipc before terminating.
16428e25f19bSMatthew Dillon 			 *
16438e25f19bSMatthew Dillon 			 * We just sit in this state until the front-end
16448e25f19bSMatthew Dillon 			 * does something about it.
16458e25f19bSMatthew Dillon 			 */
16468e25f19bSMatthew Dillon 			break;
1647710838f7SMatthew Dillon 		case WORKER_FROZEN:
1648710838f7SMatthew Dillon 			/*
1649710838f7SMatthew Dillon 			 * A worker getting frozen is debug-related.  We
1650710838f7SMatthew Dillon 			 * just sit in this state (likely forever).
1651710838f7SMatthew Dillon 			 */
1652710838f7SMatthew Dillon 			break;
16538e25f19bSMatthew Dillon 		default:
1654710838f7SMatthew Dillon 			dfatal("worker: [%03d] Unexpected state %d "
1655710838f7SMatthew Dillon 			       "for worker %d",
16566fd67931SMatthew Dillon 			       work->index, work->state, work->index);
16578e25f19bSMatthew Dillon 			/* NOT REACHED */
16588e25f19bSMatthew Dillon 			break;
16598e25f19bSMatthew Dillon 		}
16608e25f19bSMatthew Dillon 
16618e25f19bSMatthew Dillon 		/*
16628e25f19bSMatthew Dillon 		 * The dsynth frontend will poll us approximately once
16638e25f19bSMatthew Dillon 		 * a second (its variable).
16648e25f19bSMatthew Dillon 		 */
16658e25f19bSMatthew Dillon 		if (dowait)
16668e25f19bSMatthew Dillon 			pthread_cond_wait(&work->cond, &WorkerMutex);
16678e25f19bSMatthew Dillon 	}
16688e25f19bSMatthew Dillon 
16698e25f19bSMatthew Dillon 	/*
16708e25f19bSMatthew Dillon 	 * Scrap the comm socket if running, this should cause the worker
16718e25f19bSMatthew Dillon 	 * process to kill its sub-programs and cleanup.
16728e25f19bSMatthew Dillon 	 */
16738e25f19bSMatthew Dillon 	if (work->state == WORKER_RUNNING) {
16748e25f19bSMatthew Dillon 		pthread_mutex_unlock(&WorkerMutex);
16758e25f19bSMatthew Dillon 		close(work->fds[0]);
16768e25f19bSMatthew Dillon 		while (waitpid(work->pid, &status, 0) < 0 &&
16778e25f19bSMatthew Dillon 		       errno == EINTR);
16788e25f19bSMatthew Dillon 		pthread_mutex_lock(&WorkerMutex);
16798e25f19bSMatthew Dillon 	}
16808e25f19bSMatthew Dillon 
16818e25f19bSMatthew Dillon 	/*
16828e25f19bSMatthew Dillon 	 * Final handshake
16838e25f19bSMatthew Dillon 	 */
16848e25f19bSMatthew Dillon 	work->state = WORKER_EXITING;
16858e25f19bSMatthew Dillon 	pthread_cond_signal(&WorkerCond);
16868e25f19bSMatthew Dillon 	pthread_mutex_unlock(&WorkerMutex);
16878e25f19bSMatthew Dillon 
16888e25f19bSMatthew Dillon 	return NULL;
16898e25f19bSMatthew Dillon }
16908e25f19bSMatthew Dillon 
16918e25f19bSMatthew Dillon /*
16928e25f19bSMatthew Dillon  * Install all the binary packages (we have already built them) that
16938e25f19bSMatthew Dillon  * the current work package depends on, without duplicates, in a script
16948e25f19bSMatthew Dillon  * which will be run from within the specified work jail.
16958e25f19bSMatthew Dillon  *
16968e25f19bSMatthew Dillon  * Locked by WorkerMutex (global)
16978e25f19bSMatthew Dillon  */
16988e25f19bSMatthew Dillon static int
childInstallPkgDeps(worker_t * work)16998e25f19bSMatthew Dillon childInstallPkgDeps(worker_t *work)
17008e25f19bSMatthew Dillon {
17018e25f19bSMatthew Dillon 	char *buf;
17028e25f19bSMatthew Dillon 	FILE *fp;
17038e25f19bSMatthew Dillon 
17048e25f19bSMatthew Dillon 	if (PKGLIST_EMPTY(&work->pkg->idepon_list))
17058e25f19bSMatthew Dillon 		return 0;
17068e25f19bSMatthew Dillon 
17078e25f19bSMatthew Dillon 	asprintf(&buf, "%s/tmp/dsynth_install_pkgs", work->basedir);
17088e25f19bSMatthew Dillon 	fp = fopen(buf, "w");
17098e25f19bSMatthew Dillon 	ddassert(fp != NULL);
17108e25f19bSMatthew Dillon 	fprintf(fp, "#!/bin/sh\n");
17118e25f19bSMatthew Dillon 	fprintf(fp, "#\n");
17128e25f19bSMatthew Dillon 	fchmod(fileno(fp), 0755);
17138e25f19bSMatthew Dillon 
17141fa9d809SMatthew Dillon 	childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 0, 1, 0);
17151fa9d809SMatthew Dillon 	childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 1, 1, 0);
17168e25f19bSMatthew Dillon 	fprintf(fp, "\nexit 0\n");
17178e25f19bSMatthew Dillon 	fclose(fp);
1718ffc851f6SMatthew Dillon 	freestrp(&buf);
17198e25f19bSMatthew Dillon 
17208e25f19bSMatthew Dillon 	return 1;
17218e25f19bSMatthew Dillon }
17228e25f19bSMatthew Dillon 
17239e1d0b12SMatthew Dillon /*
17249e1d0b12SMatthew Dillon  * Recursive child install dependencies.
17259e1d0b12SMatthew Dillon  *
17269e1d0b12SMatthew Dillon  * first_one_only is only specified if the pkg the list comes from
17279e1d0b12SMatthew Dillon  * is a generic unflavored package that has flavors, telling us to
17289e1d0b12SMatthew Dillon  * dive the first flavor only.
17299e1d0b12SMatthew Dillon  *
17309e1d0b12SMatthew Dillon  * However, in nearly all cases this flag will now be zero because
17319e1d0b12SMatthew Dillon  * this code now dives the first flavor when encountering a dummy node
17329e1d0b12SMatthew Dillon  * and clears nfirst on success.  Hence if you are asking why 'nfirst'
17339e1d0b12SMatthew Dillon  * is set to 1, and then zero, instead of just being removed entirely,
17349e1d0b12SMatthew Dillon  * it is because there might still be an edge case here.
17359e1d0b12SMatthew Dillon  */
1736fef2fc63SMatthew Dillon static size_t
childInstallPkgDeps_recurse(FILE * fp,pkglink_t * list,int undoit,int depth,int first_one_only)17371fa9d809SMatthew Dillon childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list, int undoit,
17381fa9d809SMatthew Dillon 			    int depth, int first_one_only)
17398e25f19bSMatthew Dillon {
17408e25f19bSMatthew Dillon 	pkglink_t *link;
17418e25f19bSMatthew Dillon 	pkg_t *pkg;
1742fef2fc63SMatthew Dillon 	size_t tot = 0;
17431fa9d809SMatthew Dillon 	int ndepth;
17441fa9d809SMatthew Dillon 	int nfirst;
17458e25f19bSMatthew Dillon 
17468e25f19bSMatthew Dillon 	PKGLIST_FOREACH(link, list) {
17478e25f19bSMatthew Dillon 		pkg = link->pkg;
17488e25f19bSMatthew Dillon 
174963fcce5bSMatthew Dillon 		/*
17501fa9d809SMatthew Dillon 		 * We don't want to mess up our depth test just below if
17511fa9d809SMatthew Dillon 		 * a DUMMY node had to be inserted.  The nodes under the
17521fa9d809SMatthew Dillon 		 * dummy node.
17531fa9d809SMatthew Dillon 		 *
17541fa9d809SMatthew Dillon 		 * The elements under a dummy node represent all the flabor,
17551fa9d809SMatthew Dillon 		 * a dependency that directly references a dummy node only
17561fa9d809SMatthew Dillon 		 * uses the first flavor (first_one_only / nfirst).
17571fa9d809SMatthew Dillon 		 */
17581fa9d809SMatthew Dillon 		ndepth = (pkg->flags & PKGF_DUMMY) ? depth : depth + 1;
17591fa9d809SMatthew Dillon 		nfirst = (pkg->flags & PKGF_DUMMY) ? 1 : 0;
17601fa9d809SMatthew Dillon 
17611fa9d809SMatthew Dillon 		/*
176263fcce5bSMatthew Dillon 		 * We only need all packages for the top-level dependencies.
176363fcce5bSMatthew Dillon 		 * The deeper ones only need DEP_TYPE_LIB and DEP_TYPE_RUN
176463fcce5bSMatthew Dillon 		 * (types greater than DEP_TYPE_BUILD) since they are already
176563fcce5bSMatthew Dillon 		 * built.
176663fcce5bSMatthew Dillon 		 */
17671fa9d809SMatthew Dillon 		if (depth > 1 && link->dep_type <= DEP_TYPE_BUILD) {
17681fa9d809SMatthew Dillon 			if (first_one_only)
17691fa9d809SMatthew Dillon 				break;
177063fcce5bSMatthew Dillon 			continue;
17711fa9d809SMatthew Dillon 		}
177263fcce5bSMatthew Dillon 
17739e1d0b12SMatthew Dillon 		/*
17749e1d0b12SMatthew Dillon 		 * If this is a dummy node with no package, the originator
17759e1d0b12SMatthew Dillon 		 * is requesting a flavored package.  We select the default
17769e1d0b12SMatthew Dillon 		 * flavor which we presume is the first one.
17779e1d0b12SMatthew Dillon 		 */
17789e1d0b12SMatthew Dillon 		if (pkg->pkgfile == NULL && (pkg->flags & PKGF_DUMMY)) {
17799e1d0b12SMatthew Dillon 			pkg_t *spkg = pkg->idepon_list.next->pkg;
17809e1d0b12SMatthew Dillon 
17819e1d0b12SMatthew Dillon 			if (spkg) {
17829e1d0b12SMatthew Dillon 				if (fp) {
17839e1d0b12SMatthew Dillon 					fprintf(fp,
17849e1d0b12SMatthew Dillon 						"echo 'UNFLAVORED %s -> use "
17859e1d0b12SMatthew Dillon 						"%s'\n",
17869e1d0b12SMatthew Dillon 						pkg->portdir,
17879e1d0b12SMatthew Dillon 						spkg->portdir);
17889e1d0b12SMatthew Dillon 				}
17899e1d0b12SMatthew Dillon 				pkg = spkg;
17909e1d0b12SMatthew Dillon 				nfirst = 0;
17919e1d0b12SMatthew Dillon 			} else {
17929e1d0b12SMatthew Dillon 				if (fp) {
17939e1d0b12SMatthew Dillon 					fprintf(fp,
17949e1d0b12SMatthew Dillon 						"echo 'CANNOT FIND DEFAULT "
17959e1d0b12SMatthew Dillon 						"FLAVOR FOR %s'\n",
17969e1d0b12SMatthew Dillon 						pkg->portdir);
17979e1d0b12SMatthew Dillon 				}
17989e1d0b12SMatthew Dillon 			}
17999e1d0b12SMatthew Dillon 		}
18009e1d0b12SMatthew Dillon 
18018e25f19bSMatthew Dillon 		if (undoit) {
18028e25f19bSMatthew Dillon 			if (pkg->dsynth_install_flg == 1) {
18038e25f19bSMatthew Dillon 				pkg->dsynth_install_flg = 0;
1804fef2fc63SMatthew Dillon 				tot += childInstallPkgDeps_recurse(fp,
18058e25f19bSMatthew Dillon 							    &pkg->idepon_list,
18061fa9d809SMatthew Dillon 							    undoit,
18071fa9d809SMatthew Dillon 							    ndepth, nfirst);
18088e25f19bSMatthew Dillon 			}
18091fa9d809SMatthew Dillon 			if (first_one_only)
18101fa9d809SMatthew Dillon 				break;
18118e25f19bSMatthew Dillon 			continue;
18128e25f19bSMatthew Dillon 		}
18139e1d0b12SMatthew Dillon 
18148e25f19bSMatthew Dillon 		if (pkg->dsynth_install_flg) {
1815fef2fc63SMatthew Dillon 			if (DebugOpt >= 2 && pkg->pkgfile && fp) {
18168e25f19bSMatthew Dillon 				fprintf(fp, "echo 'AlreadyHave %s'\n",
18178e25f19bSMatthew Dillon 					pkg->pkgfile);
18188e25f19bSMatthew Dillon 			}
18191fa9d809SMatthew Dillon 			if (first_one_only)
18201fa9d809SMatthew Dillon 				break;
18218e25f19bSMatthew Dillon 			continue;
18228e25f19bSMatthew Dillon 		}
18238e25f19bSMatthew Dillon 
182463fcce5bSMatthew Dillon 		tot += childInstallPkgDeps_recurse(fp, &pkg->idepon_list,
18251fa9d809SMatthew Dillon 						   undoit, ndepth, nfirst);
18261fa9d809SMatthew Dillon 		if (pkg->dsynth_install_flg) {
18271fa9d809SMatthew Dillon 			if (first_one_only)
18281fa9d809SMatthew Dillon 				break;
18298e25f19bSMatthew Dillon 			continue;
18301fa9d809SMatthew Dillon 		}
18318e25f19bSMatthew Dillon 		pkg->dsynth_install_flg = 1;
18328e25f19bSMatthew Dillon 
18338e25f19bSMatthew Dillon 		/*
18348e25f19bSMatthew Dillon 		 * Generate package installation command
18358e25f19bSMatthew Dillon 		 */
1836fef2fc63SMatthew Dillon 		if (fp && pkg->pkgfile) {
18378e25f19bSMatthew Dillon 			fprintf(fp, "echo 'Installing /packages/All/%s'\n",
18388e25f19bSMatthew Dillon 				pkg->pkgfile);
1839349e3a76SMatthew Dillon 			fprintf(fp, "pkg install -q -U -y /packages/All/%s "
18408e25f19bSMatthew Dillon 				"|| exit 1\n",
18418e25f19bSMatthew Dillon 				pkg->pkgfile);
1842fef2fc63SMatthew Dillon 		} else if (fp) {
18438e25f19bSMatthew Dillon 			fprintf(fp, "echo 'CANNOT FIND PKG FOR %s'\n",
18448e25f19bSMatthew Dillon 				pkg->portdir);
18458e25f19bSMatthew Dillon 		}
1846fef2fc63SMatthew Dillon 
1847fef2fc63SMatthew Dillon 		if (pkg->pkgfile) {
1848fef2fc63SMatthew Dillon 			struct stat st;
1849fef2fc63SMatthew Dillon 			char *path;
1850fef2fc63SMatthew Dillon 			char *ptr;
1851fef2fc63SMatthew Dillon 
1852fef2fc63SMatthew Dillon 			asprintf(&path, "%s/%s", RepositoryPath, pkg->pkgfile);
1853fef2fc63SMatthew Dillon 			ptr = strrchr(pkg->pkgfile, '.');
1854fef2fc63SMatthew Dillon 			if (stat(path, &st) == 0) {
1855fef2fc63SMatthew Dillon 				if (strcmp(ptr, ".tar") == 0)
1856fef2fc63SMatthew Dillon 					tot += st.st_size;
1857fef2fc63SMatthew Dillon 				else if (strcmp(ptr, ".tgz") == 0)
1858fef2fc63SMatthew Dillon 					tot += st.st_size * 3;
1859fef2fc63SMatthew Dillon 				else if (strcmp(ptr, ".txz") == 0)
1860fef2fc63SMatthew Dillon 					tot += st.st_size * 5;
1861ef0c0bf5SKrzysztof Piecuch 				else if (strcmp(ptr, ".tzst") == 0)
1862ef0c0bf5SKrzysztof Piecuch 					tot += st.st_size * 5;
1863fef2fc63SMatthew Dillon 				else if (strcmp(ptr, ".tbz") == 0)
1864fef2fc63SMatthew Dillon 					tot += st.st_size * 3;
1865fef2fc63SMatthew Dillon 				else
1866fef2fc63SMatthew Dillon 					tot += st.st_size * 2;
18678e25f19bSMatthew Dillon 			}
1868fef2fc63SMatthew Dillon 			free(path);
1869fef2fc63SMatthew Dillon 		}
18701fa9d809SMatthew Dillon 		if (first_one_only)
18711fa9d809SMatthew Dillon 			break;
1872fef2fc63SMatthew Dillon 	}
1873fef2fc63SMatthew Dillon 	return tot;
18748e25f19bSMatthew Dillon }
18758e25f19bSMatthew Dillon 
18768e25f19bSMatthew Dillon /*
18778e25f19bSMatthew Dillon  * Worker process interactions.
18788e25f19bSMatthew Dillon  *
18798e25f19bSMatthew Dillon  * The worker process is responsible for managing the build of a single
18808e25f19bSMatthew Dillon  * package.  It is exec'd by the master dsynth and only loads the
18818e25f19bSMatthew Dillon  * configuration.
18828e25f19bSMatthew Dillon  *
18838e25f19bSMatthew Dillon  * This process does not run in the chroot.  It will become the reaper for
18848e25f19bSMatthew Dillon  * all sub-processes and it will enter the chroot to execute various phases.
18858e25f19bSMatthew Dillon  * It catches SIGINTR, SIGHUP, and SIGPIPE and will iterate, terminate, and
18868e25f19bSMatthew Dillon  * reap all sub-process upon kill or exit.
18878e25f19bSMatthew Dillon  *
18888e25f19bSMatthew Dillon  * The command line forwarded to this function is:
18898e25f19bSMatthew Dillon  *
18908e25f19bSMatthew Dillon  *	WORKER slot# socketfd portdir/subdir
18918e25f19bSMatthew Dillon  *
18928e25f19bSMatthew Dillon  * TERM=dumb
18938e25f19bSMatthew Dillon  * USER=root
18948e25f19bSMatthew Dillon  * HOME=/root
18958e25f19bSMatthew Dillon  * LANG=C
18968e25f19bSMatthew Dillon  * SSL_NO_VERIFY_PEER=1
189778f42860SMatthew Dillon  * USE_PACKAGE_DEPENDS_ONLY=1
18988e25f19bSMatthew Dillon  * PORTSDIR=/xports
189964824e6cSMatthew Dillon  * PORT_DBDIR=/options		For ports options
190064824e6cSMatthew Dillon  * PACKAGE_BUILDING=yes		Don't build packages that aren't legally
190164824e6cSMatthew Dillon  *				buildable for a binary repo.
19028e25f19bSMatthew Dillon  * PKG_DBDIR=/var/db/pkg
19038e25f19bSMatthew Dillon  * PKG_CACHEDIR=/var/cache/pkg
190464824e6cSMatthew Dillon  * PKG_CREATE_VERBOSE=yes	Ensure periodic output during packaging
19058e25f19bSMatthew Dillon  * (custom environment)
19068e25f19bSMatthew Dillon  * PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
19078e25f19bSMatthew Dillon  * UNAME_s=DragonFly		(example)
19088e25f19bSMatthew Dillon  * UNAME_v=DragonFly 5.7-SYNTH	(example)
19098e25f19bSMatthew Dillon  * UNAME_p=x86_64		(example)
19108e25f19bSMatthew Dillon  * UNAME_m=x86_64		(example)
19118e25f19bSMatthew Dillon  * UNAME_r=5.7-SYNTH		(example)
191278f42860SMatthew Dillon  * NO_DEPENDS=yes		(conditional based on phase)
19138e25f19bSMatthew Dillon  * DISTDIR=/distfiles
19148e25f19bSMatthew Dillon  * WRKDIRPREFIX=/construction
19158e25f19bSMatthew Dillon  * BATCH=yes
19168e25f19bSMatthew Dillon  * MAKE_JOBS_NUMBER=n
19178e25f19bSMatthew Dillon  *
19188e25f19bSMatthew Dillon  * SETUP:
19198e25f19bSMatthew Dillon  *	ldconfig -R
19208e25f19bSMatthew Dillon  *	/usr/local/sbin/pkg-static install /packages/All/<the pkg pkg>
19218e25f19bSMatthew Dillon  *	/usr/local/sbin/pkg-static install /packages/All/<pkg>
19228e25f19bSMatthew Dillon  *			(for all dependencies)
19238e25f19bSMatthew Dillon  *
19248e25f19bSMatthew Dillon  * PHASES: 		make -C path FLAVOR=flavor <phase>
19258e25f19bSMatthew Dillon  *	check-sanity
19268e25f19bSMatthew Dillon  *	pkg-depends
19278e25f19bSMatthew Dillon  *	fetch-depends
19288e25f19bSMatthew Dillon  *	fetch
19298e25f19bSMatthew Dillon  *	checksum
19308e25f19bSMatthew Dillon  *	extract-depends
19318e25f19bSMatthew Dillon  *	extract
19328e25f19bSMatthew Dillon  *	patch-depends
19338e25f19bSMatthew Dillon  *	patch
19348e25f19bSMatthew Dillon  *	build-depends
19358e25f19bSMatthew Dillon  *	lib-depends
19368e25f19bSMatthew Dillon  *	configure
19378e25f19bSMatthew Dillon  *	build
19388e25f19bSMatthew Dillon  *	run-depends
19398e25f19bSMatthew Dillon  *	stage
1940f7f25838SMatthew Dillon  *	test		(skipped)
194132f62172SMatthew Dillon  *	check-plist	('dsynth test blahblah' or 'dsynth -D everything' only)
19428e25f19bSMatthew Dillon  *	package		 e.g. /construction/lang/perl5.28/pkg/perl5-5.28.2.txz
1943f7f25838SMatthew Dillon  *	install		(skipped)
1944f7f25838SMatthew Dillon  *	deinstall	(skipped)
19458e25f19bSMatthew Dillon  */
19468e25f19bSMatthew Dillon void
WorkerProcess(int ac,char ** av)19478e25f19bSMatthew Dillon WorkerProcess(int ac, char **av)
19488e25f19bSMatthew Dillon {
19498e25f19bSMatthew Dillon 	wmsg_t wmsg;
19508e25f19bSMatthew Dillon 	int fd;
19518e25f19bSMatthew Dillon 	int slot;
19528e25f19bSMatthew Dillon 	int tmpfd;
19538e25f19bSMatthew Dillon 	int pkgpkg = 0;
19548ec23ca1SMatthew Dillon 	int status;
19558e25f19bSMatthew Dillon 	int len;
19568e25f19bSMatthew Dillon 	int do_install_phase;
19578e25f19bSMatthew Dillon 	char *portdir;
19588e25f19bSMatthew Dillon 	char *pkgfile;
19598e25f19bSMatthew Dillon 	char *flavor;
19608e25f19bSMatthew Dillon 	char *buf;
19618e25f19bSMatthew Dillon 	worker_t *work;
196268dc2eeaSMatthew Dillon 	bulk_t *bulk;
19638e25f19bSMatthew Dillon 	pkg_t pkg;
19648e25f19bSMatthew Dillon 	buildenv_t *benv;
19656fd67931SMatthew Dillon 	FILE *fp;
19668e25f19bSMatthew Dillon 
19678e25f19bSMatthew Dillon 	/*
19688e25f19bSMatthew Dillon 	 * Parse arguments
19698e25f19bSMatthew Dillon 	 */
19708ec23ca1SMatthew Dillon 	if (ac != 6) {
19711645cafeSMatthew Dillon 		dlog(DLOG_ALL, "WORKER PROCESS %d- bad arguments\n", getpid());
19728e25f19bSMatthew Dillon 		exit(1);
19738e25f19bSMatthew Dillon 	}
19748e25f19bSMatthew Dillon 	slot = strtol(av[1], NULL, 0);
19753bd7e0a7SMatthew Dillon 	setNumaDomain(slot);
19763bd7e0a7SMatthew Dillon 
19778e25f19bSMatthew Dillon 	fd = strtol(av[2], NULL, 0);	/* master<->slave messaging */
19788e25f19bSMatthew Dillon 	portdir = av[3];
19798e25f19bSMatthew Dillon 	pkgfile = av[4];
19803bd7e0a7SMatthew Dillon 
19818e25f19bSMatthew Dillon 	flavor = strchr(portdir, '@');
1982ffc851f6SMatthew Dillon 	if (flavor) {
19838e25f19bSMatthew Dillon 		*flavor++ = 0;
1984ffc851f6SMatthew Dillon 		asprintf(&buf, "@%s", flavor);
1985ffc851f6SMatthew Dillon 		WorkerFlavorPrt = buf;
1986ffc851f6SMatthew Dillon 		buf = NULL;	/* safety */
1987ffc851f6SMatthew Dillon 	}
19886fd67931SMatthew Dillon 	WorkerProcFlags = strtol(av[5], NULL, 0);
19898ec23ca1SMatthew Dillon 
1990325ef124SMatthew Dillon 	if (WorkerProcFlags & WORKER_PROC_FETCHONLY)
1991325ef124SMatthew Dillon 		FetchOnlyOpt = 1;
1992dca89e44SMatthew Dillon 	if (WorkerProcFlags & WORKER_PROC_PKGV17)
1993dca89e44SMatthew Dillon 		PkgVersionPkgSuffix = 1;
1994dca89e44SMatthew Dillon 
19958e25f19bSMatthew Dillon 	bzero(&wmsg, sizeof(wmsg));
19968e25f19bSMatthew Dillon 
1997ffc851f6SMatthew Dillon 	setproctitle("[%02d] WORKER STARTUP  %s%s",
1998ffc851f6SMatthew Dillon 		     slot, portdir, WorkerFlavorPrt);
19998e25f19bSMatthew Dillon 
20008e25f19bSMatthew Dillon 	if (strcmp(portdir, "ports-mgmt/pkg") == 0)
20018e25f19bSMatthew Dillon 		pkgpkg = 1;
20028e25f19bSMatthew Dillon 
20038e25f19bSMatthew Dillon 	signal(SIGTERM, phaseTerminateSignal);
20048e25f19bSMatthew Dillon 	signal(SIGINT, phaseTerminateSignal);
20058e25f19bSMatthew Dillon 	signal(SIGHUP, phaseTerminateSignal);
20068e25f19bSMatthew Dillon 
20078e25f19bSMatthew Dillon 	/*
20088e25f19bSMatthew Dillon 	 * Set up the environment
20098e25f19bSMatthew Dillon 	 */
20108e25f19bSMatthew Dillon 	setenv("TERM", "dumb", 1);
20118e25f19bSMatthew Dillon 	setenv("USER", "root", 1);
20128e25f19bSMatthew Dillon 	setenv("HOME", "/root", 1);
20138e25f19bSMatthew Dillon 	setenv("LANG", "C", 1);
20148e25f19bSMatthew Dillon 	setenv("SSL_NO_VERIFY_PEER", "1", 1);
20156fd67931SMatthew Dillon 
2016bd73b895SMatthew Dillon 	/*
2017bd73b895SMatthew Dillon 	 * NOTE: PKG_SUFX - pkg versions older than 1.17
2018bd73b895SMatthew Dillon 	 *	 PKG_COMPRESSION_FORMAT - pkg versions >= 1.17
2019dca89e44SMatthew Dillon 	 *
2020dca89e44SMatthew Dillon 	 *	 Avoid WARNING messages in the logs by omitting
2021dca89e44SMatthew Dillon 	 *	 PKG_SUFX when we know the pkg version is >= 1.17.
2022bd73b895SMatthew Dillon 	 */
20236fd67931SMatthew Dillon 	addbuildenv("USE_PACKAGE_DEPENDS_ONLY", "yes", BENV_MAKECONF);
20246fd67931SMatthew Dillon 	addbuildenv("PORTSDIR", "/xports", BENV_MAKECONF);
20256fd67931SMatthew Dillon 	addbuildenv("PORT_DBDIR", "/options", BENV_MAKECONF);
20266fd67931SMatthew Dillon 	addbuildenv("PKG_DBDIR", "/var/db/pkg", BENV_MAKECONF);
20276fd67931SMatthew Dillon 	addbuildenv("PKG_CACHEDIR", "/var/cache/pkg", BENV_MAKECONF);
2028bd73b895SMatthew Dillon 	addbuildenv("PKG_COMPRESSION_FORMAT", UsePkgSufx, BENV_MAKECONF);
2029dca89e44SMatthew Dillon 	if (PkgVersionPkgSuffix == 0)
2030483dbac9SMatthew Dillon 		addbuildenv("PKG_SUFX", UsePkgSufx, BENV_MAKECONF);
2031dca89e44SMatthew Dillon 
2032dca89e44SMatthew Dillon 	/*
2033dca89e44SMatthew Dillon 	 * We are exec'ing the worker process so various bits of global
2034dca89e44SMatthew Dillon 	 * state that we want to inherit have to be passed in.
2035dca89e44SMatthew Dillon 	 */
20366fd67931SMatthew Dillon 	if (WorkerProcFlags & WORKER_PROC_DEVELOPER)
20376fd67931SMatthew Dillon 		addbuildenv("DEVELOPER", "1", BENV_MAKECONF);
20386fd67931SMatthew Dillon 
20396fd67931SMatthew Dillon 	/*
2040f4094b20SMatthew Dillon 	 * CCache is a horrible unreliable hack but... leave the
2041f4094b20SMatthew Dillon 	 * mechanism in-place in case someone has a death wish.
20426fd67931SMatthew Dillon 	 */
20436fd67931SMatthew Dillon 	if (UseCCache) {
20446fd67931SMatthew Dillon 		addbuildenv("WITH_CCACHE_BUILD", "yes", BENV_MAKECONF);
20456fd67931SMatthew Dillon 		addbuildenv("CCACHE_DIR", "/ccache", BENV_MAKECONF);
20466fd67931SMatthew Dillon 	}
2047667fb2cbSMatthew Dillon 
20480df5ec4eSMatthew Dillon 	addbuildenv("UID", "0", BENV_MAKECONF);
20490df5ec4eSMatthew Dillon 	addbuildenv("ARCH", ArchitectureName, BENV_MAKECONF);
20500df5ec4eSMatthew Dillon 
20515ea034f4SAntonio Huete Jimenez 	/*
20525ea034f4SAntonio Huete Jimenez 	 * Always honor either the operating system detection or the
20535ea034f4SAntonio Huete Jimenez 	 * operating system selection in the config file.
20545ea034f4SAntonio Huete Jimenez 	 */
20555ea034f4SAntonio Huete Jimenez 	addbuildenv("OPSYS", OperatingSystemName, BENV_MAKECONF);
20565ea034f4SAntonio Huete Jimenez 
20570df5ec4eSMatthew Dillon #ifdef __DragonFly__
20580df5ec4eSMatthew Dillon 	addbuildenv("DFLYVERSION", VersionFromParamHeader, BENV_MAKECONF);
20590df5ec4eSMatthew Dillon 	addbuildenv("OSVERSION", "9999999", BENV_MAKECONF);
20600df5ec4eSMatthew Dillon #else
20610df5ec4eSMatthew Dillon #error "Need OS-specific data to generate make.conf"
20628ec23ca1SMatthew Dillon #endif
20630df5ec4eSMatthew Dillon 
20640df5ec4eSMatthew Dillon 	addbuildenv("OSREL", ReleaseName, BENV_MAKECONF);
20650df5ec4eSMatthew Dillon 	addbuildenv("_OSRELEASE", VersionOnlyName, BENV_MAKECONF);
20668ec23ca1SMatthew Dillon 
20678e25f19bSMatthew Dillon 	setenv("PATH",
20688e25f19bSMatthew Dillon 	       "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
20698e25f19bSMatthew Dillon 	       1);
20708e25f19bSMatthew Dillon 
20718e25f19bSMatthew Dillon 	setenv("UNAME_s", OperatingSystemName, 1);
20728e25f19bSMatthew Dillon 	setenv("UNAME_v", VersionName, 1);
20738e25f19bSMatthew Dillon 	setenv("UNAME_p", ArchitectureName, 1);
20748e25f19bSMatthew Dillon 	setenv("UNAME_m", MachineName, 1);
20758e25f19bSMatthew Dillon 	setenv("UNAME_r", ReleaseName, 1);
20768e25f19bSMatthew Dillon 
20776fd67931SMatthew Dillon 	addbuildenv("DISTDIR", "/distfiles", BENV_MAKECONF);
20786fd67931SMatthew Dillon 	addbuildenv("WRKDIRPREFIX", "/construction", BENV_MAKECONF);
20796fd67931SMatthew Dillon 	addbuildenv("BATCH", "yes", BENV_MAKECONF);
20808e25f19bSMatthew Dillon 
208164824e6cSMatthew Dillon 	/*
208264824e6cSMatthew Dillon 	 * Special consideration
208364824e6cSMatthew Dillon 	 *
208464824e6cSMatthew Dillon 	 * PACKAGE_BUILDING	- Disallow packaging ports which do not allow
208564824e6cSMatthew Dillon 	 *			  for binary distribution.
208664824e6cSMatthew Dillon 	 *
208764824e6cSMatthew Dillon 	 * PKG_CREATE_VERBOSE	- Ensure periodic output during the packaging
208864824e6cSMatthew Dillon 	 *			  process to avoid a watchdog timeout.
208964824e6cSMatthew Dillon 	 *
209064824e6cSMatthew Dillon 	 */
20916fd67931SMatthew Dillon 	addbuildenv("PACKAGE_BUILDING", "yes", BENV_MAKECONF);
20926fd67931SMatthew Dillon 	addbuildenv("PKG_CREATE_VERBOSE", "yes", BENV_MAKECONF);
20938e25f19bSMatthew Dillon 	asprintf(&buf, "%d", MaxJobs);
20946fd67931SMatthew Dillon 	addbuildenv("MAKE_JOBS_NUMBER", buf, BENV_MAKECONF);
2095ffc851f6SMatthew Dillon 	freestrp(&buf);
20968e25f19bSMatthew Dillon 
20978e25f19bSMatthew Dillon 	if (flavor)
20988e25f19bSMatthew Dillon 		setenv("FLAVOR", flavor, 1);
20998e25f19bSMatthew Dillon 
21008e25f19bSMatthew Dillon 	/*
21018e25f19bSMatthew Dillon 	 * Become the reaper
21028e25f19bSMatthew Dillon 	 */
21038e25f19bSMatthew Dillon 	if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) < 0)
21048e25f19bSMatthew Dillon 		dfatal_errno("procctl() - Cannot become reaper");
21058e25f19bSMatthew Dillon 
21068e25f19bSMatthew Dillon 	/*
21078e25f19bSMatthew Dillon 	 * Initialize a worker structure
21088e25f19bSMatthew Dillon 	 */
21098e25f19bSMatthew Dillon 	DoInitBuild(slot);
21108e25f19bSMatthew Dillon 
21118e25f19bSMatthew Dillon 	bzero(&pkg, sizeof(pkg));
21128e25f19bSMatthew Dillon 	pkg.portdir = portdir;		/* sans flavor */
21138e25f19bSMatthew Dillon 	pkg.pkgfile = pkgfile;
21148e25f19bSMatthew Dillon 	if (strchr(portdir, '/'))
21158e25f19bSMatthew Dillon 		len = strchr(portdir, '/') - portdir;
21168e25f19bSMatthew Dillon 	else
21178e25f19bSMatthew Dillon 		len = 0;
21188e25f19bSMatthew Dillon 
21198e25f19bSMatthew Dillon 	/*
21208e25f19bSMatthew Dillon 	 * Setup the logfile
21218e25f19bSMatthew Dillon 	 */
21228e25f19bSMatthew Dillon 	asprintf(&pkg.logfile,
21238e25f19bSMatthew Dillon 		 "%s/%*.*s___%s%s%s.log",
21248e25f19bSMatthew Dillon 		 LogsPath, len, len, portdir,
21258e25f19bSMatthew Dillon 		 ((portdir[len] == '/') ? portdir + len + 1 : portdir + len),
21268e25f19bSMatthew Dillon 		 (flavor ? "@" : ""),
21278e25f19bSMatthew Dillon 		 (flavor ? flavor : ""));
21288e25f19bSMatthew Dillon 	tmpfd = open(pkg.logfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
21298e25f19bSMatthew Dillon 	if (tmpfd >= 0) {
213054f2fefcSMatthew Dillon 		if (DebugOpt >= 2) {
21318e25f19bSMatthew Dillon 			dlog(DLOG_ALL, "[%03d] %s LOGFILE %s\n",
21328e25f19bSMatthew Dillon 			     slot, pkg.portdir, pkg.logfile);
213354f2fefcSMatthew Dillon 		}
21348e25f19bSMatthew Dillon 		close(tmpfd);
21358e25f19bSMatthew Dillon 	} else {
21368e25f19bSMatthew Dillon 		dlog(DLOG_ALL, "[%03d] LOGFILE %s (create failed)\n",
21378e25f19bSMatthew Dillon 		     slot, pkg.logfile);
21388e25f19bSMatthew Dillon 	}
21398e25f19bSMatthew Dillon 
21408e25f19bSMatthew Dillon 	/*
21418e25f19bSMatthew Dillon 	 * Setup the work structure.  Because this is an exec'd sub-process,
21428e25f19bSMatthew Dillon 	 * there is only one work structure.
21438e25f19bSMatthew Dillon 	 */
21448e25f19bSMatthew Dillon 	work = &WorkerAry[0];
21458e25f19bSMatthew Dillon 	work->flavor = flavor;
21468e25f19bSMatthew Dillon 	work->fds[0] = fd;
21478e25f19bSMatthew Dillon 	work->pkg = &pkg;
21488e25f19bSMatthew Dillon 	work->start_time = time(NULL);
21498e25f19bSMatthew Dillon 
21508e25f19bSMatthew Dillon 	/*
21516fd67931SMatthew Dillon 	 * Do mounts
21528e25f19bSMatthew Dillon 	 */
21538e25f19bSMatthew Dillon 	SigWork = work;
2154ffc851f6SMatthew Dillon 	setproctitle("[%02d] WORKER MOUNTS   %s%s",
2155ffc851f6SMatthew Dillon 		     slot, portdir, WorkerFlavorPrt);
21568e25f19bSMatthew Dillon 	DoWorkerMounts(work);
21578e25f19bSMatthew Dillon 
21586fd67931SMatthew Dillon 	/*
21596fd67931SMatthew Dillon 	 * Generate an /etc/make.conf in the build base
21606fd67931SMatthew Dillon 	 */
21616fd67931SMatthew Dillon 	asprintf(&buf, "%s/etc/make.conf", work->basedir);
21626fd67931SMatthew Dillon 	fp = fopen(buf, "w");
21636fd67931SMatthew Dillon 	dassert_errno(fp, "Unable to create %s\n", buf);
21646fd67931SMatthew Dillon 	for (benv = BuildEnv; benv; benv = benv->next) {
216531f2ea22SMatthew Dillon 		if (benv->type & BENV_PKGLIST)
216631f2ea22SMatthew Dillon 			continue;
216731f2ea22SMatthew Dillon 		if ((benv->type & BENV_CMDMASK) == BENV_MAKECONF) {
21686fd67931SMatthew Dillon 			if (DebugOpt >= 2) {
21696fd67931SMatthew Dillon 				dlog(DLOG_ALL, "[%03d] ENV %s=%s\n",
21706fd67931SMatthew Dillon 				     slot, benv->label, benv->data);
21716fd67931SMatthew Dillon 			}
21726fd67931SMatthew Dillon 			fprintf(fp, "%s=%s\n", benv->label, benv->data);
21736fd67931SMatthew Dillon 		}
217431f2ea22SMatthew Dillon 	}
21756fd67931SMatthew Dillon 	fclose(fp);
2176ffc851f6SMatthew Dillon 	freestrp(&buf);
21776fd67931SMatthew Dillon 
21786fd67931SMatthew Dillon 	/*
217968dc2eeaSMatthew Dillon 	 * Set up our hooks
218068dc2eeaSMatthew Dillon 	 */
218168dc2eeaSMatthew Dillon 	if (UsingHooks)
218268dc2eeaSMatthew Dillon 		initbulk(childHookRun, MaxBulk);
218368dc2eeaSMatthew Dillon 
218468dc2eeaSMatthew Dillon 	/*
21856fd67931SMatthew Dillon 	 * Start phases
21866fd67931SMatthew Dillon 	 */
21878e25f19bSMatthew Dillon 	wmsg.cmd = WMSG_CMD_INSTALL_PKGS;
21888e25f19bSMatthew Dillon 	ipcwritemsg(fd, &wmsg);
21898e25f19bSMatthew Dillon 	status = ipcreadmsg(fd, &wmsg);
21908e25f19bSMatthew Dillon 	if (status < 0 || wmsg.cmd != WMSG_RES_INSTALL_PKGS)
21918e25f19bSMatthew Dillon 		dfatal("pkg installation handshake failed");
21928e25f19bSMatthew Dillon 	do_install_phase = wmsg.status;
2193325ef124SMatthew Dillon 	if (FetchOnlyOpt)
2194325ef124SMatthew Dillon 		do_install_phase = 0;
21958e25f19bSMatthew Dillon 
21968e25f19bSMatthew Dillon 	wmsg.cmd = WMSG_CMD_STATUS_UPDATE;
21978e25f19bSMatthew Dillon 	wmsg.phase = PHASE_INSTALL_PKGS;
21988e25f19bSMatthew Dillon 	wmsg.lines = 0;
21998e25f19bSMatthew Dillon 
22008e25f19bSMatthew Dillon 	status = ipcwritemsg(fd, &wmsg);
22018e25f19bSMatthew Dillon 
2202325ef124SMatthew Dillon 	if (pkgpkg && FetchOnlyOpt == 0) {
22038e25f19bSMatthew Dillon 		dophase(work, &wmsg,
22048e25f19bSMatthew Dillon 			WDOG5, PHASE_PACKAGE, "package");
22058e25f19bSMatthew Dillon 	} else {
22069fdb3f28SAntonio Huete Jimenez 		/*
22079fdb3f28SAntonio Huete Jimenez 		 * Dump as much information of the build process as possible.
22089fdb3f28SAntonio Huete Jimenez 		 * Will help troubleshooting port build breakages.
22099fdb3f28SAntonio Huete Jimenez 		 * Only enabled when DEVELOPER is set.
22109fdb3f28SAntonio Huete Jimenez 		 *
22119fdb3f28SAntonio Huete Jimenez 		 * This sort of mimics what synth did.
22129fdb3f28SAntonio Huete Jimenez 		 */
22139fdb3f28SAntonio Huete Jimenez 		if (WorkerProcFlags & WORKER_PROC_DEVELOPER) {
22149fdb3f28SAntonio Huete Jimenez 			dophase(work, &wmsg,
22159fdb3f28SAntonio Huete Jimenez 			    WDOG2, PHASE_DUMP_ENV, "Environment");
22169fdb3f28SAntonio Huete Jimenez 			dophase(work, &wmsg,
22179fdb3f28SAntonio Huete Jimenez 			    WDOG2, PHASE_SHOW_CONFIG, "showconfig");
22189fdb3f28SAntonio Huete Jimenez 			dophase(work, &wmsg,
22199fdb3f28SAntonio Huete Jimenez 			    WDOG2, PHASE_DUMP_VAR, "CONFIGURE_ENV");
22209fdb3f28SAntonio Huete Jimenez 			dophase(work, &wmsg,
22219fdb3f28SAntonio Huete Jimenez 			    WDOG2, PHASE_DUMP_VAR, "CONFIGURE_ARGS");
22229fdb3f28SAntonio Huete Jimenez 			dophase(work, &wmsg,
22239fdb3f28SAntonio Huete Jimenez 			    WDOG2, PHASE_DUMP_VAR, "MAKE_ENV");
22249fdb3f28SAntonio Huete Jimenez 			dophase(work, &wmsg,
22259fdb3f28SAntonio Huete Jimenez 			    WDOG2, PHASE_DUMP_VAR, "MAKE_ARGS");
22269fdb3f28SAntonio Huete Jimenez 			dophase(work, &wmsg,
22279fdb3f28SAntonio Huete Jimenez 			    WDOG2, PHASE_DUMP_VAR, "PLIST_SUB");
22289fdb3f28SAntonio Huete Jimenez 			dophase(work, &wmsg,
22299fdb3f28SAntonio Huete Jimenez 			    WDOG2, PHASE_DUMP_VAR, "SUB_LIST");
22309fdb3f28SAntonio Huete Jimenez 			dophase(work, &wmsg,
22319fdb3f28SAntonio Huete Jimenez 			    WDOG2, PHASE_DUMP_MAKECONF, "/etc/make.conf");
22329fdb3f28SAntonio Huete Jimenez 		}
22339fdb3f28SAntonio Huete Jimenez 
22348e25f19bSMatthew Dillon 		if (do_install_phase) {
22358e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22368e25f19bSMatthew Dillon 				WDOG4, PHASE_INSTALL_PKGS, "setup");
22378e25f19bSMatthew Dillon 		}
22388e25f19bSMatthew Dillon 		dophase(work, &wmsg,
22398e25f19bSMatthew Dillon 			WDOG2, PHASE_CHECK_SANITY, "check-sanity");
2240325ef124SMatthew Dillon 		if (FetchOnlyOpt == 0) {
22418e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22428e25f19bSMatthew Dillon 				WDOG2, PHASE_PKG_DEPENDS, "pkg-depends");
2243325ef124SMatthew Dillon 		}
22448e25f19bSMatthew Dillon 		dophase(work, &wmsg,
22458e25f19bSMatthew Dillon 			WDOG7, PHASE_FETCH_DEPENDS, "fetch-depends");
22468e25f19bSMatthew Dillon 		dophase(work, &wmsg,
22478e25f19bSMatthew Dillon 			WDOG7, PHASE_FETCH, "fetch");
22488e25f19bSMatthew Dillon 		dophase(work, &wmsg,
22498e25f19bSMatthew Dillon 			WDOG2, PHASE_CHECKSUM, "checksum");
2250325ef124SMatthew Dillon 		if (FetchOnlyOpt == 0) {
22518e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22528e25f19bSMatthew Dillon 				WDOG3, PHASE_EXTRACT_DEPENDS, "extract-depends");
22538e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22548e25f19bSMatthew Dillon 				WDOG3, PHASE_EXTRACT, "extract");
22558e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22568e25f19bSMatthew Dillon 				WDOG2, PHASE_PATCH_DEPENDS, "patch-depends");
22578e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22588e25f19bSMatthew Dillon 				WDOG2, PHASE_PATCH, "patch");
22598e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22608e25f19bSMatthew Dillon 				WDOG5, PHASE_BUILD_DEPENDS, "build-depends");
22618e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22628e25f19bSMatthew Dillon 				WDOG5, PHASE_LIB_DEPENDS, "lib-depends");
22638e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22648e25f19bSMatthew Dillon 				WDOG3, PHASE_CONFIGURE, "configure");
22658e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22668e25f19bSMatthew Dillon 				WDOG9, PHASE_BUILD, "build");
22678e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22688e25f19bSMatthew Dillon 				WDOG5, PHASE_RUN_DEPENDS, "run-depends");
22698e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22708e25f19bSMatthew Dillon 				WDOG5, PHASE_STAGE, "stage");
22718e25f19bSMatthew Dillon #if 0
22728e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22738e25f19bSMatthew Dillon 				WDOG5, PHASE_TEST, "test");
22748e25f19bSMatthew Dillon #endif
227532f62172SMatthew Dillon 			if (WorkerProcFlags & WORKER_PROC_CHECK_PLIST) {
22768e25f19bSMatthew Dillon 				dophase(work, &wmsg,
22778e25f19bSMatthew Dillon 					WDOG1, PHASE_CHECK_PLIST, "check-plist");
227832f62172SMatthew Dillon 			}
22798e25f19bSMatthew Dillon 			dophase(work, &wmsg,
22808e25f19bSMatthew Dillon 				WDOG5, PHASE_PACKAGE, "package");
228129d8adfcSAntonio Huete Jimenez 
228229d8adfcSAntonio Huete Jimenez 			if (WorkerProcFlags & WORKER_PROC_INSTALL) {
22838e25f19bSMatthew Dillon 				dophase(work, &wmsg,
22848e25f19bSMatthew Dillon 				    WDOG5, PHASE_INSTALL, "install");
228529d8adfcSAntonio Huete Jimenez 			}
228629d8adfcSAntonio Huete Jimenez 
228729d8adfcSAntonio Huete Jimenez 			if (WorkerProcFlags & WORKER_PROC_DEINSTALL) {
22888e25f19bSMatthew Dillon 				dophase(work, &wmsg,
22898e25f19bSMatthew Dillon 				    WDOG5, PHASE_DEINSTALL, "deinstall");
229029d8adfcSAntonio Huete Jimenez 			}
22918e25f19bSMatthew Dillon 		}
2292325ef124SMatthew Dillon 	}
22938e25f19bSMatthew Dillon 
22941d6e00cdSMatthew Dillon 	if (MasterPtyFd >= 0) {
22951d6e00cdSMatthew Dillon 		close(MasterPtyFd);
22961d6e00cdSMatthew Dillon 		MasterPtyFd = -1;
22971d6e00cdSMatthew Dillon 	}
22981d6e00cdSMatthew Dillon 
2299ffc851f6SMatthew Dillon 	setproctitle("[%02d] WORKER CLEANUP  %s%s",
2300ffc851f6SMatthew Dillon 		     slot, portdir, WorkerFlavorPrt);
23018e25f19bSMatthew Dillon 
23028e25f19bSMatthew Dillon 	/*
23038e25f19bSMatthew Dillon 	 * Copy the package to the repo.
23048e25f19bSMatthew Dillon 	 */
2305325ef124SMatthew Dillon 	if (work->accum_error == 0 && FetchOnlyOpt == 0) {
23068e25f19bSMatthew Dillon 		char *b1;
23078e25f19bSMatthew Dillon 		char *b2;
23088e25f19bSMatthew Dillon 
23098e25f19bSMatthew Dillon 		asprintf(&b1, "%s/construction/%s/pkg/%s",
23108e25f19bSMatthew Dillon 			 work->basedir, pkg.portdir, pkg.pkgfile);
23118e25f19bSMatthew Dillon 		asprintf(&b2, "%s/%s", RepositoryPath, pkg.pkgfile);
23128e25f19bSMatthew Dillon 		if (copyfile(b1, b2)) {
23138e25f19bSMatthew Dillon 			++work->accum_error;
23148e25f19bSMatthew Dillon 			dlog(DLOG_ALL, "[%03d] %s Unable to copy %s to %s\n",
23158e25f19bSMatthew Dillon 			     work->index, pkg.portdir, b1, b2);
23168e25f19bSMatthew Dillon 		}
23178e25f19bSMatthew Dillon 		free(b1);
23188e25f19bSMatthew Dillon 		free(b2);
23198e25f19bSMatthew Dillon 	}
23208e25f19bSMatthew Dillon 
23218ec23ca1SMatthew Dillon 	/*
23228ec23ca1SMatthew Dillon 	 * Unmount, unless we are in DebugStopMode.
23238ec23ca1SMatthew Dillon 	 */
23246fd67931SMatthew Dillon 	if ((WorkerProcFlags & WORKER_PROC_DEBUGSTOP) == 0)
23258e25f19bSMatthew Dillon 		DoWorkerUnmounts(work);
23268e25f19bSMatthew Dillon 
23278ec23ca1SMatthew Dillon 	/*
23288ec23ca1SMatthew Dillon 	 * Send completion status to master dsynth worker thread.
23298ec23ca1SMatthew Dillon 	 */
23308e25f19bSMatthew Dillon 	if (work->accum_error) {
23318e25f19bSMatthew Dillon 		wmsg.cmd = WMSG_CMD_FAILURE;
23328e25f19bSMatthew Dillon 	} else {
23338e25f19bSMatthew Dillon 		wmsg.cmd = WMSG_CMD_SUCCESS;
23348e25f19bSMatthew Dillon 	}
23358ec23ca1SMatthew Dillon 	ipcwritemsg(fd, &wmsg);
23366fd67931SMatthew Dillon 	if (WorkerProcFlags & WORKER_PROC_DEBUGSTOP) {
23378ec23ca1SMatthew Dillon 		wmsg.cmd = WMSG_CMD_FREEZEWORKER;
23388ec23ca1SMatthew Dillon 		ipcwritemsg(fd, &wmsg);
23398ec23ca1SMatthew Dillon 	}
234068dc2eeaSMatthew Dillon 	if (UsingHooks) {
234168dc2eeaSMatthew Dillon 		while ((bulk = getbulk()) != NULL)
234268dc2eeaSMatthew Dillon 			freebulk(bulk);
234368dc2eeaSMatthew Dillon 		donebulk();
234468dc2eeaSMatthew Dillon 	}
23458e25f19bSMatthew Dillon }
23468e25f19bSMatthew Dillon 
234777d66d4eSAntonio Huete Jimenez static int
check_dns(void)234877d66d4eSAntonio Huete Jimenez check_dns(void)
234977d66d4eSAntonio Huete Jimenez {
235077d66d4eSAntonio Huete Jimenez 	char check_domains[4][24] = {
235177d66d4eSAntonio Huete Jimenez 		"www.dragonflybsd.org",
235277d66d4eSAntonio Huete Jimenez 		"www.freebsd.org",
235377d66d4eSAntonio Huete Jimenez 		"www.openbsd.org",
235477d66d4eSAntonio Huete Jimenez 		"www.netbsd.org",
235577d66d4eSAntonio Huete Jimenez 	};
235677d66d4eSAntonio Huete Jimenez 	int failures = 0;
235777d66d4eSAntonio Huete Jimenez 
235877d66d4eSAntonio Huete Jimenez 	for (int i = 0; i < 4; i++)
235977d66d4eSAntonio Huete Jimenez 		if (gethostbyname (check_domains[i]) == NULL)
236077d66d4eSAntonio Huete Jimenez 			failures++;
236177d66d4eSAntonio Huete Jimenez 	if (failures > 1)
236277d66d4eSAntonio Huete Jimenez 		return -1;
236377d66d4eSAntonio Huete Jimenez 
236477d66d4eSAntonio Huete Jimenez 	return 0;
236577d66d4eSAntonio Huete Jimenez }
236677d66d4eSAntonio Huete Jimenez 
23678e25f19bSMatthew Dillon static void
dophase(worker_t * work,wmsg_t * wmsg,int wdog,int phaseid,const char * phase)23688e25f19bSMatthew Dillon dophase(worker_t *work, wmsg_t *wmsg, int wdog, int phaseid, const char *phase)
23698e25f19bSMatthew Dillon {
23708e25f19bSMatthew Dillon 	pkg_t *pkg = work->pkg;
23718e25f19bSMatthew Dillon 	char buf[1024];
23728e25f19bSMatthew Dillon 	pid_t pid;
23738e25f19bSMatthew Dillon 	int status;
23747880dcf7SMatthew Dillon 	int ms;
23757880dcf7SMatthew Dillon 	pid_t wpid;
23767880dcf7SMatthew Dillon 	int wpid_reaped;
23778e25f19bSMatthew Dillon 	int fdlog;
23788e25f19bSMatthew Dillon 	time_t start_time;
23798e25f19bSMatthew Dillon 	time_t last_time;
23808e25f19bSMatthew Dillon 	time_t next_time;
23818e25f19bSMatthew Dillon 	time_t wdog_time;
23828e25f19bSMatthew Dillon 	FILE *fp;
23838e25f19bSMatthew Dillon 
23848e25f19bSMatthew Dillon 	if (work->accum_error)
23858e25f19bSMatthew Dillon 		return;
2386ffc851f6SMatthew Dillon 	setproctitle("[%02d] WORKER %-8.8s %s%s",
2387ffc851f6SMatthew Dillon 		     work->index, phase, pkg->portdir, WorkerFlavorPrt);
23888e25f19bSMatthew Dillon 	wmsg->phase = phaseid;
23898e25f19bSMatthew Dillon 	if (ipcwritemsg(work->fds[0], wmsg) < 0) {
23908e25f19bSMatthew Dillon 		dlog(DLOG_ALL, "[%03d] %s Lost Communication with dsynth, "
23918e25f19bSMatthew Dillon 		     "aborting worker\n",
23928e25f19bSMatthew Dillon 		     work->index, pkg->portdir);
23938e25f19bSMatthew Dillon 		++work->accum_error;
23948e25f19bSMatthew Dillon 		return;
23958e25f19bSMatthew Dillon 	}
23968e25f19bSMatthew Dillon 
23978e25f19bSMatthew Dillon 	/*
2398168bca18SMatthew Dillon 	 * Execute the port make command in chroot on a pty.
23998e25f19bSMatthew Dillon 	 */
24008e25f19bSMatthew Dillon 	fflush(stdout);
24018e25f19bSMatthew Dillon 	fflush(stderr);
24021d6e00cdSMatthew Dillon 	if (MasterPtyFd >= 0) {
24031d6e00cdSMatthew Dillon 		int slavefd;
24041d6e00cdSMatthew Dillon 
2405168bca18SMatthew Dillon 		/*
2406168bca18SMatthew Dillon 		 * NOTE: We can't open the slave in the child because the
2407168bca18SMatthew Dillon 		 *	 master may race a disconnection test.  If we open
2408168bca18SMatthew Dillon 		 *	 it in the parent our close() will flush any pending
2409168bca18SMatthew Dillon 		 *	 output not read by the master (which is the same
2410168bca18SMatthew Dillon 		 *	 parent process) and deadlock.
2411168bca18SMatthew Dillon 		 *
2412168bca18SMatthew Dillon 		 *	 Solve this by hand-shaking the slave tty to give
2413f51d778eSMatthew Dillon 		 *	 the master time to close its slavefd (after this
2414f51d778eSMatthew Dillon 		 *	 section).
2415a9300d32SMatthew Dillon 		 *
2416a9300d32SMatthew Dillon 		 *	 Leave the tty defaults intact, which also likely
2417a9300d32SMatthew Dillon 		 *	 means it will be in line-buffered mode, so handshake
2418a9300d32SMatthew Dillon 		 *	 with a full line.
24192074bc97SMatthew Dillon 		 *
24202074bc97SMatthew Dillon 		 * TODO: Our handshake probably echos back to the master pty
24219bb2c592SMatthew Dillon 		 *	 due to tty echo, and ends up in the log, so just
24229bb2c592SMatthew Dillon 		 *	 pass through a newline.
2423168bca18SMatthew Dillon 		 */
24241d6e00cdSMatthew Dillon 		slavefd = open(ptsname(MasterPtyFd), O_RDWR);
24251d6e00cdSMatthew Dillon 		dassert_errno(slavefd >= 0, "Cannot open slave pty");
2426f51d778eSMatthew Dillon 
2427f51d778eSMatthew Dillon 		/*
2428f51d778eSMatthew Dillon 		 * Now do the fork.
2429f51d778eSMatthew Dillon 		 */
24301d6e00cdSMatthew Dillon 		pid = fork();
24311d6e00cdSMatthew Dillon 		if (pid == 0) {
24321d6e00cdSMatthew Dillon 			login_tty(slavefd);
2433a9300d32SMatthew Dillon 			/* login_tty() closes slavefd */
24341d6e00cdSMatthew Dillon 		} else {
24351d6e00cdSMatthew Dillon 			close(slavefd);
24361d6e00cdSMatthew Dillon 		}
24371d6e00cdSMatthew Dillon 	} else {
2438f51d778eSMatthew Dillon 		/*
2439f51d778eSMatthew Dillon 		 * Initial MasterPtyFd for the slot, just use forkpty().
2440f51d778eSMatthew Dillon 		 */
24411d6e00cdSMatthew Dillon 		pid = forkpty(&MasterPtyFd, NULL, NULL, NULL);
24421d6e00cdSMatthew Dillon 	}
24431d6e00cdSMatthew Dillon 
2444f51d778eSMatthew Dillon 	/*
2445f51d778eSMatthew Dillon 	 * The slave must make sure the master has time to close slavefd
2446f51d778eSMatthew Dillon 	 * in the re-use case before going its merry way.  The master needs
2447f51d778eSMatthew Dillon 	 * to set terminal modes and the window as well.
2448f51d778eSMatthew Dillon 	 */
24491d6e00cdSMatthew Dillon 	if (pid == 0) {
2450f51d778eSMatthew Dillon 		/*
24516d1478d9SMatthew Dillon 		 * Slave nices itself and waits for handshake
2452f51d778eSMatthew Dillon 		 */
2453f51d778eSMatthew Dillon 		char ttybuf[2];
2454a574cbf0SMatthew Dillon 
24556d1478d9SMatthew Dillon 		/*
24566d1478d9SMatthew Dillon 		 * Self-nice to be nice (ignore any error)
24576d1478d9SMatthew Dillon 		 */
24586d1478d9SMatthew Dillon 		if (NiceOpt)
24596d1478d9SMatthew Dillon 			setpriority(PRIO_PROCESS, 0, NiceOpt);
24606d1478d9SMatthew Dillon 
2461f51d778eSMatthew Dillon 		read(0, ttybuf, 1);
2462f51d778eSMatthew Dillon 	} else {
2463a574cbf0SMatthew Dillon 		/*
2464a574cbf0SMatthew Dillon 		 * We are going through a pty, so set the tty modes to
2465a574cbf0SMatthew Dillon 		 * Set tty modes so we do not get ^M's in the log files.
2466a574cbf0SMatthew Dillon 		 *
2467a574cbf0SMatthew Dillon 		 * This isn't fatal if it doesn't work.  Remember that
2468a574cbf0SMatthew Dillon 		 * our output goes through the pty to the management
2469a574cbf0SMatthew Dillon 		 * process which will log it.
2470a574cbf0SMatthew Dillon 		 */
2471f51d778eSMatthew Dillon 		struct termios tio;
2472f51d778eSMatthew Dillon 		struct winsize win;
2473f51d778eSMatthew Dillon 
2474f51d778eSMatthew Dillon 		if (tcgetattr(MasterPtyFd, &tio) == 0) {
2475a574cbf0SMatthew Dillon 			tio.c_oflag |= OPOST | ONOCR;
2476a574cbf0SMatthew Dillon 			tio.c_oflag &= ~(OCRNL | ONLCR);
2477a574cbf0SMatthew Dillon 			tio.c_iflag |= ICRNL;
2478a574cbf0SMatthew Dillon 			tio.c_iflag &= ~(INLCR | IGNCR);
2479f51d778eSMatthew Dillon 			if (tcsetattr(MasterPtyFd, TCSANOW, &tio)) {
2480a574cbf0SMatthew Dillon 				printf("tcsetattr failed: %s\n",
2481a574cbf0SMatthew Dillon 				       strerror(errno));
2482a574cbf0SMatthew Dillon 			}
2483f51d778eSMatthew Dillon 
2484f51d778eSMatthew Dillon 			/*
2485f51d778eSMatthew Dillon 			 * Give the tty a non-zero columns field.
2486f51d778eSMatthew Dillon 			 * This fixes at least one port (textproc/po4a)
2487f51d778eSMatthew Dillon 			 */
2488f51d778eSMatthew Dillon 			if (ioctl(MasterPtyFd, TIOCGWINSZ, &win) == 0) {
2489f51d778eSMatthew Dillon 				win.ws_col = 80;
2490f51d778eSMatthew Dillon 				ioctl(MasterPtyFd, TIOCSWINSZ, &win);
2491f51d778eSMatthew Dillon 			} else {
2492f51d778eSMatthew Dillon 				printf("TIOCGWINSZ failed: %s\n",
2493f51d778eSMatthew Dillon 				       strerror(errno));
2494f51d778eSMatthew Dillon 			}
2495f51d778eSMatthew Dillon 
2496a574cbf0SMatthew Dillon 		} else {
2497a574cbf0SMatthew Dillon 			printf("tcgetattr failed: %s\n", strerror(errno));
2498a574cbf0SMatthew Dillon 		}
2499a574cbf0SMatthew Dillon 
2500a574cbf0SMatthew Dillon 		/*
2501f51d778eSMatthew Dillon 		 * Master issues handshake
2502f51d778eSMatthew Dillon 		 */
2503f51d778eSMatthew Dillon 		write(MasterPtyFd, "\n", 1);
2504f51d778eSMatthew Dillon 	}
2505f51d778eSMatthew Dillon 
2506f51d778eSMatthew Dillon 	if (pid == 0) {
2507f51d778eSMatthew Dillon 		/*
250878f42860SMatthew Dillon 		 * Additional phase-specific environment variables
250978f42860SMatthew Dillon 		 *
251078f42860SMatthew Dillon 		 * - Do not try to process missing depends outside of the
251178f42860SMatthew Dillon 		 *   depends phases.  Also relies on USE_PACKAGE_DEPENDS_ONLY
251278f42860SMatthew Dillon 		 *   in the make.conf.
251378f42860SMatthew Dillon 		 */
251478f42860SMatthew Dillon 		switch(phaseid) {
251578f42860SMatthew Dillon 		case PHASE_CHECK_SANITY:
251678f42860SMatthew Dillon 		case PHASE_FETCH:
251778f42860SMatthew Dillon 		case PHASE_CHECKSUM:
251878f42860SMatthew Dillon 		case PHASE_EXTRACT:
251978f42860SMatthew Dillon 		case PHASE_PATCH:
252078f42860SMatthew Dillon 		case PHASE_CONFIGURE:
252178f42860SMatthew Dillon 		case PHASE_STAGE:
252278f42860SMatthew Dillon 		case PHASE_TEST:
252378f42860SMatthew Dillon 		case PHASE_CHECK_PLIST:
252478f42860SMatthew Dillon 		case PHASE_INSTALL:
252578f42860SMatthew Dillon 		case PHASE_DEINSTALL:
252678f42860SMatthew Dillon 			break;
252778f42860SMatthew Dillon 		case PHASE_PKG_DEPENDS:
252878f42860SMatthew Dillon 		case PHASE_FETCH_DEPENDS:
252978f42860SMatthew Dillon 		case PHASE_EXTRACT_DEPENDS:
253078f42860SMatthew Dillon 		case PHASE_PATCH_DEPENDS:
253178f42860SMatthew Dillon 		case PHASE_BUILD_DEPENDS:
253278f42860SMatthew Dillon 		case PHASE_LIB_DEPENDS:
253378f42860SMatthew Dillon 		case PHASE_RUN_DEPENDS:
253478f42860SMatthew Dillon 			break;
253578f42860SMatthew Dillon 		default:
253678f42860SMatthew Dillon 			setenv("NO_DEPENDS", "1", 1);
253778f42860SMatthew Dillon 			break;
253878f42860SMatthew Dillon 		}
253978f42860SMatthew Dillon 
254078f42860SMatthew Dillon 		/*
2541a574cbf0SMatthew Dillon 		 * Clean-up, chdir, and chroot.
2542a574cbf0SMatthew Dillon 		 */
25438e25f19bSMatthew Dillon 		closefrom(3);
25448e25f19bSMatthew Dillon 		if (chdir(work->basedir) < 0)
25458e25f19bSMatthew Dillon 			dfatal_errno("chdir in phase initialization");
25468e25f19bSMatthew Dillon 		if (chroot(work->basedir) < 0)
25478e25f19bSMatthew Dillon 			dfatal_errno("chroot in phase initialization");
25488e25f19bSMatthew Dillon 
254977d66d4eSAntonio Huete Jimenez 		/* Explicitly fail when DNS is not working */
255077d66d4eSAntonio Huete Jimenez 		if (check_dns() != 0)
255177d66d4eSAntonio Huete Jimenez 			dfatal("DNS resolution not working");
255277d66d4eSAntonio Huete Jimenez 
25538e25f19bSMatthew Dillon 		/*
25549c4c701fSMatthew Dillon 		 * We have a choice here on how to handle stdin (fd 0).
25559c4c701fSMatthew Dillon 		 * We can leave it connected to the pty in which case
25569c4c701fSMatthew Dillon 		 * the build will just block if it tries to ask a
25579c4c701fSMatthew Dillon 		 * question (and the watchdog will kill it, eventually),
25589c4c701fSMatthew Dillon 		 * or we can try to EOF the pty, or we can attach /dev/null
25599c4c701fSMatthew Dillon 		 * to descriptor 0.
25609c4c701fSMatthew Dillon 		 */
25619c4c701fSMatthew Dillon 		if (NullStdinOpt) {
25629c4c701fSMatthew Dillon 			int fd;
25639c4c701fSMatthew Dillon 
25649c4c701fSMatthew Dillon 			fd = open("/dev/null", O_RDWR);
25659c4c701fSMatthew Dillon 			dassert_errno(fd >= 0, "cannot open /dev/null");
25669c4c701fSMatthew Dillon 			if (fd != 0) {
25679c4c701fSMatthew Dillon 				dup2(fd, 0);
25689c4c701fSMatthew Dillon 				close(fd);
25699c4c701fSMatthew Dillon 			}
25709c4c701fSMatthew Dillon 		}
25719c4c701fSMatthew Dillon 
25729c4c701fSMatthew Dillon 		/*
25732b3f93eaSMatthew Dillon 		 * Capability restrictions to make root safer.
25742b3f93eaSMatthew Dillon 		 */
25752b3f93eaSMatthew Dillon 		set_capability_restrictions();
25762b3f93eaSMatthew Dillon 
25772b3f93eaSMatthew Dillon 		/*
25788e25f19bSMatthew Dillon 		 * Execute the appropriate command.
25798e25f19bSMatthew Dillon 		 */
25808e25f19bSMatthew Dillon 		switch(phaseid) {
25818e25f19bSMatthew Dillon 		case PHASE_INSTALL_PKGS:
25828e25f19bSMatthew Dillon 			snprintf(buf, sizeof(buf), "/tmp/dsynth_install_pkgs");
25838e25f19bSMatthew Dillon 			execl(buf, buf, NULL);
25848e25f19bSMatthew Dillon 			break;
25859fdb3f28SAntonio Huete Jimenez 		case PHASE_DUMP_ENV:
25869fdb3f28SAntonio Huete Jimenez 			snprintf(buf, sizeof(buf), "/usr/bin/env");
25879fdb3f28SAntonio Huete Jimenez 			execl(buf, buf, NULL);
25889fdb3f28SAntonio Huete Jimenez 			break;
25899fdb3f28SAntonio Huete Jimenez 		case PHASE_DUMP_VAR:
25909fdb3f28SAntonio Huete Jimenez 			snprintf(buf, sizeof(buf), "/xports/%s", pkg->portdir);
25919fdb3f28SAntonio Huete Jimenez 			execl(MAKE_BINARY, MAKE_BINARY, "-C", buf, "-V", phase,
25929fdb3f28SAntonio Huete Jimenez 			    NULL);
25939fdb3f28SAntonio Huete Jimenez 			break;
25949fdb3f28SAntonio Huete Jimenez 		case PHASE_DUMP_MAKECONF:
25959fdb3f28SAntonio Huete Jimenez 			snprintf(buf, sizeof(buf), "/bin/cat");
25969fdb3f28SAntonio Huete Jimenez 			execl(buf, buf, "/etc/make.conf", NULL);
25979fdb3f28SAntonio Huete Jimenez 			break;
25989fdb3f28SAntonio Huete Jimenez 		case PHASE_SHOW_CONFIG:
25999fdb3f28SAntonio Huete Jimenez 			/* fall-through */
26008e25f19bSMatthew Dillon 		default:
26018e25f19bSMatthew Dillon 			snprintf(buf, sizeof(buf), "/xports/%s", pkg->portdir);
26028e25f19bSMatthew Dillon 			execl(MAKE_BINARY, MAKE_BINARY, "-C", buf, phase, NULL);
26038e25f19bSMatthew Dillon 			break;
26048e25f19bSMatthew Dillon 		}
26058e25f19bSMatthew Dillon 		_exit(1);
26068e25f19bSMatthew Dillon 	}
26077880dcf7SMatthew Dillon 	fcntl(MasterPtyFd, F_SETFL, O_NONBLOCK);
26088e25f19bSMatthew Dillon 
26091d6e00cdSMatthew Dillon 	if (pid < 0) {
26106a3a20b1SMatthew Dillon 		dlog(DLOG_ALL, "[%03d] %s Fork Failed: %s\n",
26116a3a20b1SMatthew Dillon 		     work->index, pkg->logfile, strerror(errno));
26121d6e00cdSMatthew Dillon 		++work->accum_error;
26131d6e00cdSMatthew Dillon 		return;
26141d6e00cdSMatthew Dillon 	}
26151d6e00cdSMatthew Dillon 
26168e25f19bSMatthew Dillon 	SigPid = pid;
26178e25f19bSMatthew Dillon 
26188e25f19bSMatthew Dillon 	fdlog = open(pkg->logfile, O_RDWR|O_CREAT|O_APPEND, 0644);
26198e25f19bSMatthew Dillon 	if (fdlog < 0) {
26208e25f19bSMatthew Dillon 		dlog(DLOG_ALL, "[%03d] %s Cannot open logfile '%s': %s\n",
26218e25f19bSMatthew Dillon 		     work->index, pkg->portdir,
26228e25f19bSMatthew Dillon 		     pkg->logfile, strerror(errno));
26238e25f19bSMatthew Dillon 	}
26246fd67931SMatthew Dillon 
26256fd67931SMatthew Dillon 	snprintf(buf, sizeof(buf),
26263cebe4a8SMatthew Dillon 		 "----------------------------------------"
26273cebe4a8SMatthew Dillon 		 "---------------------------------------\n"
26286fd67931SMatthew Dillon 		 "-- Phase: %s\n"
26293cebe4a8SMatthew Dillon 		 "----------------------------------------"
26303cebe4a8SMatthew Dillon 		 "---------------------------------------\n",
26316fd67931SMatthew Dillon 		 phase);
26326fd67931SMatthew Dillon 	write(fdlog, buf, strlen(buf));
26336fd67931SMatthew Dillon 
26348e25f19bSMatthew Dillon 	start_time = time(NULL);
26358e25f19bSMatthew Dillon 	last_time = start_time;
26368e25f19bSMatthew Dillon 	wdog_time = start_time;
26377880dcf7SMatthew Dillon 	wpid_reaped = 0;
26388e25f19bSMatthew Dillon 
26398e25f19bSMatthew Dillon 	status = 0;
26408e25f19bSMatthew Dillon 	for (;;) {
26417880dcf7SMatthew Dillon 		ms = mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time);
26427880dcf7SMatthew Dillon 		if (ms == MPTY_FAILED) {
26437880dcf7SMatthew Dillon 			dlog(DLOG_ALL,
26447880dcf7SMatthew Dillon 			     "[%03d] %s lost pty in phase %s, terminating\n",
26457880dcf7SMatthew Dillon 			     work->index, pkg->portdir, phase);
26468e25f19bSMatthew Dillon 			break;
26478e25f19bSMatthew Dillon 		}
26487880dcf7SMatthew Dillon 		if (ms == MPTY_EOF)
26497880dcf7SMatthew Dillon 			break;
26508e25f19bSMatthew Dillon 
26518e25f19bSMatthew Dillon 		/*
26528e25f19bSMatthew Dillon 		 * Generally speaking update status once a second.
26538e25f19bSMatthew Dillon 		 * This also allows us to detect if the management
26548e25f19bSMatthew Dillon 		 * dsynth process has gone away.
26558e25f19bSMatthew Dillon 		 */
26568e25f19bSMatthew Dillon 		next_time = time(NULL);
26578e25f19bSMatthew Dillon 		if (next_time != last_time) {
26588e25f19bSMatthew Dillon 			double dload[3];
26598e25f19bSMatthew Dillon 			double dv;
26608e25f19bSMatthew Dillon 			int wdog_scaled;
26618e25f19bSMatthew Dillon 
26628e25f19bSMatthew Dillon 			/*
26638e25f19bSMatthew Dillon 			 * Send status update to the worker management thread
26648e25f19bSMatthew Dillon 			 * in the master dsynth process.  Remember, *WE* are
26658e25f19bSMatthew Dillon 			 * the worker management process sub-fork.
26668e25f19bSMatthew Dillon 			 */
26678e25f19bSMatthew Dillon 			if (ipcwritemsg(work->fds[0], wmsg) < 0)
26688e25f19bSMatthew Dillon 				break;
26698e25f19bSMatthew Dillon 			last_time = next_time;
26708e25f19bSMatthew Dillon 
26718e25f19bSMatthew Dillon 			/*
26728e25f19bSMatthew Dillon 			 * Watchdog scaling
26738e25f19bSMatthew Dillon 			 */
26748e25f19bSMatthew Dillon 			getloadavg(dload, 3);
267532fc5bbfSMatthew Dillon 			adjloadavg(dload);
26768e25f19bSMatthew Dillon 			dv = dload[2] / NumCores;
26778e25f19bSMatthew Dillon 			if (dv < (double)NumCores) {
26788e25f19bSMatthew Dillon 				wdog_scaled = wdog;
26798e25f19bSMatthew Dillon 			} else {
26808e25f19bSMatthew Dillon 				if (dv > 4.0 * NumCores)
26818e25f19bSMatthew Dillon 					dv = 4.0 * NumCores;
26828e25f19bSMatthew Dillon 				wdog_scaled = wdog * dv / NumCores;
26838e25f19bSMatthew Dillon 			}
26848e25f19bSMatthew Dillon 
26858e25f19bSMatthew Dillon 			/*
26868e25f19bSMatthew Dillon 			 * Watchdog
26878e25f19bSMatthew Dillon 			 */
26888e25f19bSMatthew Dillon 			if (next_time - wdog_time >= wdog_scaled * 60) {
26898e25f19bSMatthew Dillon 				snprintf(buf, sizeof(buf),
26908e25f19bSMatthew Dillon 					 "\n--------\n"
26918e25f19bSMatthew Dillon 					 "WATCHDOG TIMEOUT FOR %s in %s "
26928e25f19bSMatthew Dillon 					 "after %d minutes\n"
26938e25f19bSMatthew Dillon 					 "Killing pid %d\n"
26948e25f19bSMatthew Dillon 					 "--------\n",
26958e25f19bSMatthew Dillon 					 pkg->portdir, phase, wdog_scaled, pid);
26968e25f19bSMatthew Dillon 				if (fdlog >= 0)
26978e25f19bSMatthew Dillon 					write(fdlog, buf, strlen(buf));
26988e25f19bSMatthew Dillon 				dlog(DLOG_ALL,
2699a574cbf0SMatthew Dillon 				     "[%03d] %s WATCHDOG TIMEOUT in %s "
27008e25f19bSMatthew Dillon 				     "after %d minutes (%d min scaled)\n",
27018e25f19bSMatthew Dillon 				     work->index, pkg->portdir, phase,
27028e25f19bSMatthew Dillon 				     wdog, wdog_scaled);
27038e25f19bSMatthew Dillon 				kill(pid, SIGKILL);
27048e25f19bSMatthew Dillon 				++work->accum_error;
27058e25f19bSMatthew Dillon 				break;
27068e25f19bSMatthew Dillon 			}
27078e25f19bSMatthew Dillon 		}
27088e25f19bSMatthew Dillon 
27098e25f19bSMatthew Dillon 		/*
27108e25f19bSMatthew Dillon 		 * Check process exit.  Normally the pty will EOF
27118e25f19bSMatthew Dillon 		 * but if background processes remain we need to
27128e25f19bSMatthew Dillon 		 * check here to see if our primary exec is done,
27138e25f19bSMatthew Dillon 		 * so we can break out and reap those processes.
2714e86766eeSMatthew Dillon 		 *
2715e86766eeSMatthew Dillon 		 * Generally reap any other processes we have inherited
2716e86766eeSMatthew Dillon 		 * while we are here.
27178e25f19bSMatthew Dillon 		 */
2718e86766eeSMatthew Dillon 		do {
2719e86766eeSMatthew Dillon 			wpid = wait3(&status, WNOHANG, NULL);
2720e86766eeSMatthew Dillon 		} while (wpid > 0 && wpid != pid);
27217880dcf7SMatthew Dillon 		if (wpid == pid && WIFEXITED(status)) {
27227880dcf7SMatthew Dillon 			wpid_reaped = 1;
27238e25f19bSMatthew Dillon 			break;
27248e25f19bSMatthew Dillon 		}
27257880dcf7SMatthew Dillon 	}
27268e25f19bSMatthew Dillon 
27278e25f19bSMatthew Dillon 	next_time = time(NULL);
27288e25f19bSMatthew Dillon 
2729ffc851f6SMatthew Dillon 	setproctitle("[%02d] WORKER EXITREAP %s%s",
2730ffc851f6SMatthew Dillon 		     work->index, pkg->portdir, WorkerFlavorPrt);
27317880dcf7SMatthew Dillon 
27327880dcf7SMatthew Dillon 	/*
27337880dcf7SMatthew Dillon 	 * We usually get here due to a mpty EOF, but not always as there
27347880dcf7SMatthew Dillon 	 * could be persistent processes still holding the slave.  Finish
27357880dcf7SMatthew Dillon 	 * up getting the exit status for the main process we are waiting
27367880dcf7SMatthew Dillon 	 * on and clean out any data left on the MasterPtyFd (as it could
27377880dcf7SMatthew Dillon 	 * be blocking the exit).
27387880dcf7SMatthew Dillon 	 */
27397880dcf7SMatthew Dillon 	while (wpid_reaped == 0) {
27407880dcf7SMatthew Dillon 		(void)mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time);
27417880dcf7SMatthew Dillon 		wpid = waitpid(pid, &status, WNOHANG);
27427880dcf7SMatthew Dillon 		if (wpid == pid && WIFEXITED(status)) {
27437880dcf7SMatthew Dillon 			wpid_reaped = 1;
27447880dcf7SMatthew Dillon 			break;
27457880dcf7SMatthew Dillon 		}
27467880dcf7SMatthew Dillon 		if (wpid < 0 && errno != EINTR) {
27478e25f19bSMatthew Dillon 			break;
27488e25f19bSMatthew Dillon 		}
27498e25f19bSMatthew Dillon 
27507880dcf7SMatthew Dillon 		/*
27517880dcf7SMatthew Dillon 		 * Safety.  The normal phase waits until the fork/exec'd
27527880dcf7SMatthew Dillon 		 * pid finishes, causing a pty EOF on exit (the slave
27537880dcf7SMatthew Dillon 		 * descriptor is closed by the kernel on exit so the
27547880dcf7SMatthew Dillon 		 * process should already have exited).
27557880dcf7SMatthew Dillon 		 *
27567880dcf7SMatthew Dillon 		 * However, it is also possible to get here if the pty fails
27577880dcf7SMatthew Dillon 		 * for some reason.  In this case, make sure that the process
27587880dcf7SMatthew Dillon 		 * is killed.
27597880dcf7SMatthew Dillon 		 */
27607880dcf7SMatthew Dillon 		kill(pid, SIGKILL);
27618e25f19bSMatthew Dillon 	}
27628e25f19bSMatthew Dillon 
27637880dcf7SMatthew Dillon 	/*
27647880dcf7SMatthew Dillon 	 * Clean out anything left on the pty but don't wait around
27657880dcf7SMatthew Dillon 	 * because there could be background processes preventing the
27667880dcf7SMatthew Dillon 	 * slave side from closing.
27677880dcf7SMatthew Dillon 	 */
27687880dcf7SMatthew Dillon 	while (mptylogpoll(MasterPtyFd, fdlog, wmsg, &wdog_time) == MPTY_DATA)
27697880dcf7SMatthew Dillon 		;
27707880dcf7SMatthew Dillon 
27717880dcf7SMatthew Dillon 	/*
27727880dcf7SMatthew Dillon 	 * Report on the exit condition.  If the pid was somehow lost
27737880dcf7SMatthew Dillon 	 * (probably due to someone gdb'ing the process), assume an error.
27747880dcf7SMatthew Dillon 	 */
27757880dcf7SMatthew Dillon 	if (wpid_reaped) {
27768e25f19bSMatthew Dillon 		if (WEXITSTATUS(status)) {
2777a574cbf0SMatthew Dillon 			dlog(DLOG_ALL | DLOG_FILTER,
2778a574cbf0SMatthew Dillon 			     "[%03d] %s Build phase '%s' failed exit %d\n",
27797880dcf7SMatthew Dillon 			     work->index, pkg->portdir, phase,
27807880dcf7SMatthew Dillon 			     WEXITSTATUS(status));
27817880dcf7SMatthew Dillon 			++work->accum_error;
27827880dcf7SMatthew Dillon 		}
27837880dcf7SMatthew Dillon 	} else {
27847880dcf7SMatthew Dillon 		dlog(DLOG_ALL, "[%03d] %s Build phase '%s' failed - lost pid\n",
27858e25f19bSMatthew Dillon 		     work->index, pkg->portdir, phase);
27868e25f19bSMatthew Dillon 		++work->accum_error;
27878e25f19bSMatthew Dillon 	}
27888e25f19bSMatthew Dillon 
27898e25f19bSMatthew Dillon 	/*
27908e25f19bSMatthew Dillon 	 * Kill any processes still running (sometimes processes end up in
27918e25f19bSMatthew Dillon 	 * the background during a dports build), and clean up any other
27928e25f19bSMatthew Dillon 	 * children that we have inherited.
27938e25f19bSMatthew Dillon 	 */
27948e25f19bSMatthew Dillon 	phaseReapAll();
27958e25f19bSMatthew Dillon 
27968e25f19bSMatthew Dillon 	/*
2797516819d9SMatthew Dillon 	 * After the extraction phase add the space used by /construction
2798516819d9SMatthew Dillon 	 * to the memory use.  This helps us reduce the amount of paging
2799516819d9SMatthew Dillon 	 * we do due to extremely large package extractions (languages,
2800516819d9SMatthew Dillon 	 * chromium, etc).
2801516819d9SMatthew Dillon 	 *
2802516819d9SMatthew Dillon 	 * (dsynth already estimated the space used by the package deps
2803516819d9SMatthew Dillon 	 * up front, but this will help us further).
2804516819d9SMatthew Dillon 	 */
2805516819d9SMatthew Dillon 	if (work->accum_error == 0 && phaseid == PHASE_EXTRACT) {
2806516819d9SMatthew Dillon 		struct statfs sfs;
2807516819d9SMatthew Dillon 		char *b1;
2808516819d9SMatthew Dillon 
2809516819d9SMatthew Dillon 		asprintf(&b1, "%s/construction", work->basedir);
2810516819d9SMatthew Dillon 		if (statfs(b1, &sfs) == 0) {
2811516819d9SMatthew Dillon 			wmsg->memuse = (sfs.f_blocks - sfs.f_bfree) *
2812516819d9SMatthew Dillon 				       sfs.f_bsize;
2813516819d9SMatthew Dillon 			ipcwritemsg(work->fds[0], wmsg);
2814516819d9SMatthew Dillon 		}
2815516819d9SMatthew Dillon 	}
2816516819d9SMatthew Dillon 
2817516819d9SMatthew Dillon 	/*
28188e25f19bSMatthew Dillon 	 * Update log
28198e25f19bSMatthew Dillon 	 */
28208e25f19bSMatthew Dillon 	if (fdlog >= 0) {
28218e25f19bSMatthew Dillon 		struct stat st;
28228e25f19bSMatthew Dillon 		int h;
28238e25f19bSMatthew Dillon 		int m;
28248e25f19bSMatthew Dillon 		int s;
28258e25f19bSMatthew Dillon 
28268e25f19bSMatthew Dillon 		last_time = next_time - start_time;
28278e25f19bSMatthew Dillon 		s = last_time % 60;
28288e25f19bSMatthew Dillon 		m = last_time / 60 % 60;
28298e25f19bSMatthew Dillon 		h = last_time / 3600;
28308e25f19bSMatthew Dillon 
28318e25f19bSMatthew Dillon 		fp = fdopen(fdlog, "a");
28328e25f19bSMatthew Dillon 		if (fp == NULL) {
28338e25f19bSMatthew Dillon 			dlog(DLOG_ALL, "[%03d] %s Cannot fdopen fdlog: %s %d\n",
28348e25f19bSMatthew Dillon 			     work->index, pkg->portdir,
28358e25f19bSMatthew Dillon 			     strerror(errno), fstat(fdlog, &st));
28368e25f19bSMatthew Dillon 			close(fdlog);
28378e25f19bSMatthew Dillon 			goto skip;
28388e25f19bSMatthew Dillon 		}
28398e25f19bSMatthew Dillon 
28406fd67931SMatthew Dillon 		fprintf(fp, "\n");
28418e25f19bSMatthew Dillon 		if (work->accum_error) {
28426fd67931SMatthew Dillon 			fprintf(fp, "FAILED %02d:%02d:%02d\n", h, m, s);
28438e25f19bSMatthew Dillon 		} else {
2844516819d9SMatthew Dillon 			if (phaseid == PHASE_EXTRACT && wmsg->memuse) {
2845516819d9SMatthew Dillon 				fprintf(fp, "Extracted Memory Use: %6.2fM\n",
2846516819d9SMatthew Dillon 					wmsg->memuse / (1024.0 * 1024.0));
2847516819d9SMatthew Dillon 			}
28486fd67931SMatthew Dillon 			fprintf(fp, "SUCCEEDED %02d:%02d:%02d\n", h, m, s);
28498e25f19bSMatthew Dillon 		}
28508e25f19bSMatthew Dillon 		last_time = next_time - work->start_time;
28518e25f19bSMatthew Dillon 		s = last_time % 60;
28528e25f19bSMatthew Dillon 		m = last_time / 60 % 60;
28538e25f19bSMatthew Dillon 		h = last_time / 3600;
28548e25f19bSMatthew Dillon 		if (phaseid == PHASE_PACKAGE) {
28558e25f19bSMatthew Dillon 			fprintf(fp, "TOTAL TIME %02d:%02d:%02d\n", h, m, s);
28568e25f19bSMatthew Dillon 		}
28576fd67931SMatthew Dillon 		fprintf(fp, "\n");
28588e25f19bSMatthew Dillon 		fclose(fp);
28598e25f19bSMatthew Dillon skip:
28608e25f19bSMatthew Dillon 		;
28618e25f19bSMatthew Dillon 	}
28628e25f19bSMatthew Dillon 
28638e25f19bSMatthew Dillon }
28648e25f19bSMatthew Dillon 
28658e25f19bSMatthew Dillon static void
phaseReapAll(void)28668e25f19bSMatthew Dillon phaseReapAll(void)
28678e25f19bSMatthew Dillon {
28688e25f19bSMatthew Dillon 	struct reaper_status rs;
28698e25f19bSMatthew Dillon 	int status;
28708e25f19bSMatthew Dillon 
28718e25f19bSMatthew Dillon 	while (procctl(P_PID, getpid(), PROC_REAP_STATUS, &rs) == 0) {
28728e25f19bSMatthew Dillon 		if ((rs.flags & PROC_REAP_ACQUIRE) == 0)
28738e25f19bSMatthew Dillon 			break;
28748e25f19bSMatthew Dillon 		if (rs.pid_head < 0)
28758e25f19bSMatthew Dillon 			break;
28768e25f19bSMatthew Dillon 		if (kill(rs.pid_head, SIGKILL) == 0) {
28778e25f19bSMatthew Dillon 			while (waitpid(rs.pid_head, &status, 0) < 0)
28788e25f19bSMatthew Dillon 				;
28798e25f19bSMatthew Dillon 		}
28808e25f19bSMatthew Dillon 	}
28818e25f19bSMatthew Dillon 	while (wait3(&status, 0, NULL) > 0)
28828e25f19bSMatthew Dillon 		;
28838e25f19bSMatthew Dillon }
28848e25f19bSMatthew Dillon 
28858e25f19bSMatthew Dillon static void
phaseTerminateSignal(int sig __unused)28868e25f19bSMatthew Dillon phaseTerminateSignal(int sig __unused)
28878e25f19bSMatthew Dillon {
2888fef2fc63SMatthew Dillon 	if (CopyFileFd >= 0)
2889fef2fc63SMatthew Dillon 		close(CopyFileFd);
28901d6e00cdSMatthew Dillon 	if (MasterPtyFd >= 0)
28911d6e00cdSMatthew Dillon 		close(MasterPtyFd);
28928e25f19bSMatthew Dillon 	if (SigPid > 1)
28938e25f19bSMatthew Dillon 		kill(SigPid, SIGKILL);
28948e25f19bSMatthew Dillon 	phaseReapAll();
28958e25f19bSMatthew Dillon 	if (SigWork)
28968e25f19bSMatthew Dillon 		DoWorkerUnmounts(SigWork);
28978e25f19bSMatthew Dillon 	exit(1);
28988e25f19bSMatthew Dillon }
28998e25f19bSMatthew Dillon 
29008e25f19bSMatthew Dillon static
29018e25f19bSMatthew Dillon char *
buildskipreason(pkglink_t * parent,pkg_t * pkg)29023699ee09SMatthew Dillon buildskipreason(pkglink_t *parent, pkg_t *pkg)
29038e25f19bSMatthew Dillon {
29048e25f19bSMatthew Dillon 	pkglink_t *link;
29058e25f19bSMatthew Dillon 	pkg_t *scan;
29068e25f19bSMatthew Dillon 	char *reason = NULL;
29073699ee09SMatthew Dillon 	char *ptr;
29088e25f19bSMatthew Dillon 	size_t tot;
29098e25f19bSMatthew Dillon 	size_t len;
29103699ee09SMatthew Dillon 	pkglink_t stack;
29118e25f19bSMatthew Dillon 
29124ea2ee4dSMatthew Dillon 	if ((pkg->flags & PKGF_NOBUILD_I) && pkg->ignore)
29134ea2ee4dSMatthew Dillon 		asprintf(&reason, "%s ", pkg->ignore);
29144ea2ee4dSMatthew Dillon 
29158e25f19bSMatthew Dillon 	tot = 0;
29168e25f19bSMatthew Dillon 	PKGLIST_FOREACH(link, &pkg->idepon_list) {
291763fcce5bSMatthew Dillon #if 0
291863fcce5bSMatthew Dillon 		if (link->dep_type > DEP_TYPE_BUILD)
291963fcce5bSMatthew Dillon 			continue;
292063fcce5bSMatthew Dillon #endif
29218e25f19bSMatthew Dillon 		scan = link->pkg;
29228e25f19bSMatthew Dillon 		if (scan == NULL)
29238e25f19bSMatthew Dillon 			continue;
29248e25f19bSMatthew Dillon 		if ((scan->flags & (PKGF_ERROR | PKGF_NOBUILD)) == 0)
29258e25f19bSMatthew Dillon 			continue;
29263699ee09SMatthew Dillon 		if (scan->flags & PKGF_NOBUILD) {
29273699ee09SMatthew Dillon 			stack.pkg = scan;
29283699ee09SMatthew Dillon 			stack.next = parent;
29293699ee09SMatthew Dillon 			ptr = buildskipreason(&stack, scan);
29303699ee09SMatthew Dillon 			len = strlen(scan->portdir) + strlen(ptr) + 8;
29313699ee09SMatthew Dillon 			reason = realloc(reason, tot + len);
29323699ee09SMatthew Dillon 			snprintf(reason + tot, len, "%s->%s",
29333699ee09SMatthew Dillon 				 scan->portdir, ptr);
29343699ee09SMatthew Dillon 			free(ptr);
29353699ee09SMatthew Dillon 		} else {
29363699ee09SMatthew Dillon 			len = strlen(scan->portdir) + 8;
29373699ee09SMatthew Dillon 			reason = realloc(reason, tot + len);
29383699ee09SMatthew Dillon 			snprintf(reason + tot, len, "%s", scan->portdir);
29393699ee09SMatthew Dillon 		}
29403699ee09SMatthew Dillon 
29413699ee09SMatthew Dillon 		/*
29423699ee09SMatthew Dillon 		 * Don't try to print the entire graph
29433699ee09SMatthew Dillon 		 */
29443699ee09SMatthew Dillon 		if (parent)
29453699ee09SMatthew Dillon 			break;
29468e25f19bSMatthew Dillon 		tot += strlen(reason + tot);
29473699ee09SMatthew Dillon 		reason[tot++] = ' ';
29483699ee09SMatthew Dillon 		reason[tot] = 0;
29498e25f19bSMatthew Dillon 	}
29508e25f19bSMatthew Dillon 	return (reason);
29518e25f19bSMatthew Dillon }
29528e25f19bSMatthew Dillon 
29538e25f19bSMatthew Dillon /*
29543dd48cfaSMatthew Dillon  * Count number of packages that would be skipped due to the
29553dd48cfaSMatthew Dillon  * specified package having failed.
29563dd48cfaSMatthew Dillon  *
29573dd48cfaSMatthew Dillon  * Call with mode 1 to count, and mode 0 to clear the
29583dd48cfaSMatthew Dillon  * cumulative rscan flag (used to de-duplicate the count).
29593dd48cfaSMatthew Dillon  *
29603dd48cfaSMatthew Dillon  * Must be serialized.
29613dd48cfaSMatthew Dillon  */
29623dd48cfaSMatthew Dillon static int
buildskipcount_dueto(pkg_t * pkg,int mode)29633dd48cfaSMatthew Dillon buildskipcount_dueto(pkg_t *pkg, int mode)
29643dd48cfaSMatthew Dillon {
29653dd48cfaSMatthew Dillon 	pkglink_t *link;
29663dd48cfaSMatthew Dillon 	pkg_t *scan;
29673dd48cfaSMatthew Dillon 	int total;
29683dd48cfaSMatthew Dillon 
29693dd48cfaSMatthew Dillon 	total = 0;
29703dd48cfaSMatthew Dillon 	PKGLIST_FOREACH(link, &pkg->deponi_list) {
29713dd48cfaSMatthew Dillon 		scan = link->pkg;
29723dd48cfaSMatthew Dillon 		if (scan == NULL || scan->rscan == mode)
29733dd48cfaSMatthew Dillon 			continue;
29743dd48cfaSMatthew Dillon 		scan->rscan = mode;
29753dd48cfaSMatthew Dillon 		++total;
29763dd48cfaSMatthew Dillon 		total += buildskipcount_dueto(scan, mode);
29773dd48cfaSMatthew Dillon 	}
29783dd48cfaSMatthew Dillon 	return total;
29793dd48cfaSMatthew Dillon }
29803dd48cfaSMatthew Dillon 
29813dd48cfaSMatthew Dillon /*
29827880dcf7SMatthew Dillon  * The master ptyfd is in non-blocking mode.  Drain up to 1024 bytes
29837880dcf7SMatthew Dillon  * and update wmsg->lines and *wdog_timep as appropriate.
29847880dcf7SMatthew Dillon  *
29857880dcf7SMatthew Dillon  * This function will poll, stalling up to 1 second.
29867880dcf7SMatthew Dillon  */
29877880dcf7SMatthew Dillon static int
mptylogpoll(int ptyfd,int fdlog,wmsg_t * wmsg,time_t * wdog_timep)29887880dcf7SMatthew Dillon mptylogpoll(int ptyfd, int fdlog, wmsg_t *wmsg, time_t *wdog_timep)
29897880dcf7SMatthew Dillon {
29907880dcf7SMatthew Dillon 	struct pollfd pfd;
29917880dcf7SMatthew Dillon 	char buf[1024];
29927880dcf7SMatthew Dillon 	ssize_t r;
29937880dcf7SMatthew Dillon 
29947880dcf7SMatthew Dillon 	pfd.fd = ptyfd;
29957880dcf7SMatthew Dillon 	pfd.events = POLLIN;
29967880dcf7SMatthew Dillon 	pfd.revents = 0;
29977880dcf7SMatthew Dillon 
29987880dcf7SMatthew Dillon 	poll(&pfd, 1, 1000);
29997880dcf7SMatthew Dillon 	if (pfd.revents) {
30007880dcf7SMatthew Dillon 		r = read(ptyfd, buf, sizeof(buf));
30017880dcf7SMatthew Dillon 		if (r > 0) {
30027880dcf7SMatthew Dillon 			*wdog_timep = time(NULL);
30037880dcf7SMatthew Dillon 			if (r > 0 && fdlog >= 0)
30047880dcf7SMatthew Dillon 				write(fdlog, buf, r);
30057880dcf7SMatthew Dillon 			while (--r >= 0) {
30067880dcf7SMatthew Dillon 				if (buf[r] == '\n')
30077880dcf7SMatthew Dillon 					++wmsg->lines;
30087880dcf7SMatthew Dillon 			}
30097880dcf7SMatthew Dillon 			return MPTY_DATA;
30107880dcf7SMatthew Dillon 		} else if (r < 0) {
30117880dcf7SMatthew Dillon 			if (errno != EINTR && errno != EAGAIN)
30127880dcf7SMatthew Dillon 				return MPTY_FAILED;
30137880dcf7SMatthew Dillon 			return MPTY_AGAIN;
30147880dcf7SMatthew Dillon 		} else if (r == 0) {
30157880dcf7SMatthew Dillon 			return MPTY_EOF;
30167880dcf7SMatthew Dillon 		}
30177880dcf7SMatthew Dillon 	}
30187880dcf7SMatthew Dillon 	return MPTY_AGAIN;
30197880dcf7SMatthew Dillon }
30207880dcf7SMatthew Dillon 
30217880dcf7SMatthew Dillon /*
30228e25f19bSMatthew Dillon  * Copy a (package) file from (src) to (dst), use an intermediate file and
30238e25f19bSMatthew Dillon  * rename to ensure that interruption does not leave us with a corrupt
30248e25f19bSMatthew Dillon  * package file.
30258e25f19bSMatthew Dillon  *
30268e25f19bSMatthew Dillon  * This is called by the WORKER process.
30278e25f19bSMatthew Dillon  *
30288e25f19bSMatthew Dillon  * (dsynth management thread -> WORKER process -> sub-processes)
30298e25f19bSMatthew Dillon  */
30308e25f19bSMatthew Dillon #define COPYBLKSIZE	32768
30318e25f19bSMatthew Dillon 
30328b485838SMatthew Dillon int
copyfile(char * src,char * dst)30338e25f19bSMatthew Dillon copyfile(char *src, char *dst)
30348e25f19bSMatthew Dillon {
30358e25f19bSMatthew Dillon 	char *tmp;
30368e25f19bSMatthew Dillon 	char *buf;
30378e25f19bSMatthew Dillon 	int fd1;
30388e25f19bSMatthew Dillon 	int fd2;
30398e25f19bSMatthew Dillon 	int error = 0;
3040fef2fc63SMatthew Dillon 	int mask;
30418e25f19bSMatthew Dillon 	ssize_t r;
30428e25f19bSMatthew Dillon 
30438e25f19bSMatthew Dillon 	asprintf(&tmp, "%s.new", dst);
30448e25f19bSMatthew Dillon 	buf = malloc(COPYBLKSIZE);
30458e25f19bSMatthew Dillon 
3046fef2fc63SMatthew Dillon 	mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP));
30478e25f19bSMatthew Dillon 	fd1 = open(src, O_RDONLY|O_CLOEXEC);
30488e25f19bSMatthew Dillon 	fd2 = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
3049fef2fc63SMatthew Dillon 	CopyFileFd = fd1;
3050fef2fc63SMatthew Dillon 	sigsetmask(mask);
30518e25f19bSMatthew Dillon 	while ((r = read(fd1, buf, COPYBLKSIZE)) > 0) {
30528e25f19bSMatthew Dillon 		if (write(fd2, buf, r) != r)
30538e25f19bSMatthew Dillon 			error = 1;
30548e25f19bSMatthew Dillon 	}
3055f7f25838SMatthew Dillon 	if (r < 0)
3056f7f25838SMatthew Dillon 		error = 1;
3057fef2fc63SMatthew Dillon 	mask = sigsetmask(sigmask(SIGTERM)|sigmask(SIGINT)|sigmask(SIGHUP));
3058fef2fc63SMatthew Dillon 	CopyFileFd = -1;
30598e25f19bSMatthew Dillon 	close(fd1);
30608e25f19bSMatthew Dillon 	close(fd2);
3061fef2fc63SMatthew Dillon 	sigsetmask(mask);
30628e25f19bSMatthew Dillon 	if (error) {
30638e25f19bSMatthew Dillon 		remove(tmp);
30648e25f19bSMatthew Dillon 	} else {
30658e25f19bSMatthew Dillon 		if (rename(tmp, dst)) {
30668e25f19bSMatthew Dillon 			error = 1;
30678e25f19bSMatthew Dillon 			remove(tmp);
30688e25f19bSMatthew Dillon 		}
30698e25f19bSMatthew Dillon 	}
30708e25f19bSMatthew Dillon 
3071ffc851f6SMatthew Dillon 	freestrp(&buf);
3072ffc851f6SMatthew Dillon 	freestrp(&tmp);
30738e25f19bSMatthew Dillon 
30748e25f19bSMatthew Dillon 	return error;
30758e25f19bSMatthew Dillon }
307668dc2eeaSMatthew Dillon 
307768dc2eeaSMatthew Dillon /*
307868dc2eeaSMatthew Dillon  * doHook()
307968dc2eeaSMatthew Dillon  *
308068dc2eeaSMatthew Dillon  * primary process (threaded) - run_start, run_end, pkg_ignored, pkg_skipped
308168dc2eeaSMatthew Dillon  * worker process  (threaded) - pkg_sucess, pkg_failure
308268dc2eeaSMatthew Dillon  *
308368dc2eeaSMatthew Dillon  * If waitfor is non-zero this hook will be serialized.
308468dc2eeaSMatthew Dillon  */
308568dc2eeaSMatthew Dillon static void
doHook(pkg_t * pkg,const char * id,const char * path,int waitfor)308668dc2eeaSMatthew Dillon doHook(pkg_t *pkg, const char *id, const char *path, int waitfor)
308768dc2eeaSMatthew Dillon {
308868dc2eeaSMatthew Dillon 	if (path == NULL)
308968dc2eeaSMatthew Dillon 		return;
309068dc2eeaSMatthew Dillon 	while (waitfor && getbulk() != NULL)
309168dc2eeaSMatthew Dillon 		;
309268dc2eeaSMatthew Dillon 	if (pkg)
309368dc2eeaSMatthew Dillon 		queuebulk(pkg->portdir, id, path, pkg->pkgfile);
309468dc2eeaSMatthew Dillon 	else
309568dc2eeaSMatthew Dillon 		queuebulk(NULL, id, path, NULL);
309668dc2eeaSMatthew Dillon 	while (waitfor && getbulk() != NULL)
309768dc2eeaSMatthew Dillon 		;
309868dc2eeaSMatthew Dillon }
309968dc2eeaSMatthew Dillon 
310068dc2eeaSMatthew Dillon /*
310168dc2eeaSMatthew Dillon  * Execute hook (backend)
310268dc2eeaSMatthew Dillon  *
310368dc2eeaSMatthew Dillon  * s1 - portdir
310468dc2eeaSMatthew Dillon  * s2 - id
310568dc2eeaSMatthew Dillon  * s3 - script path
310668dc2eeaSMatthew Dillon  * s4 - pkgfile		(if applicable)
310768dc2eeaSMatthew Dillon  */
310868dc2eeaSMatthew Dillon static void
childHookRun(bulk_t * bulk)310968dc2eeaSMatthew Dillon childHookRun(bulk_t *bulk)
311068dc2eeaSMatthew Dillon {
311168dc2eeaSMatthew Dillon 	const char *cav[MAXCAC];
311268dc2eeaSMatthew Dillon 	buildenv_t benv[MAXCAC];
311368dc2eeaSMatthew Dillon 	char buf1[128];
311468dc2eeaSMatthew Dillon 	char buf2[128];
311568dc2eeaSMatthew Dillon 	char buf3[128];
311668dc2eeaSMatthew Dillon 	char buf4[128];
311768dc2eeaSMatthew Dillon 	FILE *fp;
311868dc2eeaSMatthew Dillon 	char *ptr;
311968dc2eeaSMatthew Dillon 	size_t len;
312068dc2eeaSMatthew Dillon 	pid_t pid;
312168dc2eeaSMatthew Dillon 	int cac;
312268dc2eeaSMatthew Dillon 	int bi;
312368dc2eeaSMatthew Dillon 
312468dc2eeaSMatthew Dillon 	cac = 0;
312568dc2eeaSMatthew Dillon 	bi = 0;
312668dc2eeaSMatthew Dillon 	bzero(benv, sizeof(benv));
312768dc2eeaSMatthew Dillon 
312868dc2eeaSMatthew Dillon 	cav[cac++] = bulk->s3;
312968dc2eeaSMatthew Dillon 
313068dc2eeaSMatthew Dillon 	benv[bi].label = "PROFILE";
313168dc2eeaSMatthew Dillon 	benv[bi].data = Profile;
313268dc2eeaSMatthew Dillon 	++bi;
313368dc2eeaSMatthew Dillon 
313468dc2eeaSMatthew Dillon 	benv[bi].label = "DIR_PACKAGES";
313568dc2eeaSMatthew Dillon 	benv[bi].data = PackagesPath;
313668dc2eeaSMatthew Dillon 	++bi;
313768dc2eeaSMatthew Dillon 
313868dc2eeaSMatthew Dillon 	benv[bi].label = "DIR_REPOSITORY";
313968dc2eeaSMatthew Dillon 	benv[bi].data = RepositoryPath;
314068dc2eeaSMatthew Dillon 	++bi;
314168dc2eeaSMatthew Dillon 
314268dc2eeaSMatthew Dillon 	benv[bi].label = "DIR_PORTS";
314368dc2eeaSMatthew Dillon 	benv[bi].data = DPortsPath;
314468dc2eeaSMatthew Dillon 	++bi;
314568dc2eeaSMatthew Dillon 
314668dc2eeaSMatthew Dillon 	benv[bi].label = "DIR_OPTIONS";
314768dc2eeaSMatthew Dillon 	benv[bi].data = OptionsPath;
314868dc2eeaSMatthew Dillon 	++bi;
314968dc2eeaSMatthew Dillon 
315068dc2eeaSMatthew Dillon 	benv[bi].label = "DIR_DISTFILES";
315168dc2eeaSMatthew Dillon 	benv[bi].data = DistFilesPath;
315268dc2eeaSMatthew Dillon 	++bi;
315368dc2eeaSMatthew Dillon 
315468dc2eeaSMatthew Dillon 	benv[bi].label = "DIR_LOGS";
315568dc2eeaSMatthew Dillon 	benv[bi].data = LogsPath;
315668dc2eeaSMatthew Dillon 	++bi;
315768dc2eeaSMatthew Dillon 
315868dc2eeaSMatthew Dillon 	benv[bi].label = "DIR_BUILDBASE";
315968dc2eeaSMatthew Dillon 	benv[bi].data = BuildBase;
316068dc2eeaSMatthew Dillon 	++bi;
316168dc2eeaSMatthew Dillon 
316268dc2eeaSMatthew Dillon 	if (strcmp(bulk->s2, "hook_run_start") == 0) {
316368dc2eeaSMatthew Dillon 		snprintf(buf1, sizeof(buf1), "%d", BuildTotal);
316468dc2eeaSMatthew Dillon 		benv[bi].label = "PORTS_QUEUED";
316568dc2eeaSMatthew Dillon 		benv[bi].data = buf1;
316668dc2eeaSMatthew Dillon 		++bi;
316768dc2eeaSMatthew Dillon 	} else if (strcmp(bulk->s2, "hook_run_end") == 0) {
316868dc2eeaSMatthew Dillon 		snprintf(buf1, sizeof(buf1), "%d", BuildSuccessCount);
316968dc2eeaSMatthew Dillon 		benv[bi].label = "PORTS_BUILT";
317068dc2eeaSMatthew Dillon 		benv[bi].data = buf1;
317168dc2eeaSMatthew Dillon 		++bi;
317268dc2eeaSMatthew Dillon 		snprintf(buf2, sizeof(buf2), "%d", BuildFailCount);
317368dc2eeaSMatthew Dillon 		benv[bi].label = "PORTS_FAILED";
317468dc2eeaSMatthew Dillon 		benv[bi].data = buf2;
317568dc2eeaSMatthew Dillon 		++bi;
317668dc2eeaSMatthew Dillon 		snprintf(buf3, sizeof(buf3), "%d", BuildIgnoreCount);
317768dc2eeaSMatthew Dillon 		benv[bi].label = "PORTS_IGNORED";
317868dc2eeaSMatthew Dillon 		benv[bi].data = buf3;
317968dc2eeaSMatthew Dillon 		++bi;
318068dc2eeaSMatthew Dillon 		snprintf(buf4, sizeof(buf4), "%d", BuildSkipCount);
318168dc2eeaSMatthew Dillon 		benv[bi].label = "PORTS_SKIPPED";
318268dc2eeaSMatthew Dillon 		benv[bi].data = buf4;
318368dc2eeaSMatthew Dillon 		++bi;
318468dc2eeaSMatthew Dillon 	} else {
318568dc2eeaSMatthew Dillon 		/*
318668dc2eeaSMatthew Dillon 		 * success, failure, ignored, skipped
318768dc2eeaSMatthew Dillon 		 */
318868dc2eeaSMatthew Dillon 		benv[bi].label = "RESULT";
318968dc2eeaSMatthew Dillon 		if (strcmp(bulk->s2, "hook_pkg_success") == 0) {
319068dc2eeaSMatthew Dillon 			benv[bi].data = "success";
319168dc2eeaSMatthew Dillon 		} else if (strcmp(bulk->s2, "hook_pkg_failure") == 0) {
319268dc2eeaSMatthew Dillon 			benv[bi].data = "failure";
319368dc2eeaSMatthew Dillon 		} else if (strcmp(bulk->s2, "hook_pkg_ignored") == 0) {
319468dc2eeaSMatthew Dillon 			benv[bi].data = "ignored";
319568dc2eeaSMatthew Dillon 		} else if (strcmp(bulk->s2, "hook_pkg_skipped") == 0) {
319668dc2eeaSMatthew Dillon 			benv[bi].data = "skipped";
319768dc2eeaSMatthew Dillon 		} else {
319868dc2eeaSMatthew Dillon 			dfatal("Unknown hook id: %s", bulk->s2);
319968dc2eeaSMatthew Dillon 			/* NOT REACHED */
320068dc2eeaSMatthew Dillon 		}
320168dc2eeaSMatthew Dillon 		++bi;
320268dc2eeaSMatthew Dillon 
320368dc2eeaSMatthew Dillon 		/*
320468dc2eeaSMatthew Dillon 		 * For compatibility with synth:
320568dc2eeaSMatthew Dillon 		 *
320668dc2eeaSMatthew Dillon 		 * ORIGIN does not include any @flavor, thus it is suitable
320768dc2eeaSMatthew Dillon 		 * for finding the actual port directory/subdirectory.
320868dc2eeaSMatthew Dillon 		 *
320968dc2eeaSMatthew Dillon 		 * FLAVOR is set to ORIGIN if there is no flavor, otherwise
321068dc2eeaSMatthew Dillon 		 * it is set to only the flavor sans the '@'.
321168dc2eeaSMatthew Dillon 		 */
321268dc2eeaSMatthew Dillon 		if ((ptr = strchr(bulk->s1, '@')) != NULL) {
321368dc2eeaSMatthew Dillon 			snprintf(buf1, sizeof(buf1), "%*.*s",
321468dc2eeaSMatthew Dillon 				 (int)(ptr - bulk->s1),
321568dc2eeaSMatthew Dillon 				 (int)(ptr - bulk->s1),
321668dc2eeaSMatthew Dillon 				 bulk->s1);
321768dc2eeaSMatthew Dillon 			benv[bi].label = "ORIGIN";
321868dc2eeaSMatthew Dillon 			benv[bi].data = buf1;
321968dc2eeaSMatthew Dillon 			++bi;
322068dc2eeaSMatthew Dillon 			benv[bi].label = "FLAVOR";
322168dc2eeaSMatthew Dillon 			benv[bi].data = ptr + 1;
322268dc2eeaSMatthew Dillon 			++bi;
322368dc2eeaSMatthew Dillon 		} else {
322468dc2eeaSMatthew Dillon 			benv[bi].label = "ORIGIN";
322568dc2eeaSMatthew Dillon 			benv[bi].data = bulk->s1;
322668dc2eeaSMatthew Dillon 			++bi;
322768dc2eeaSMatthew Dillon 			benv[bi].label = "FLAVOR";
322868dc2eeaSMatthew Dillon 			benv[bi].data = bulk->s1;
322968dc2eeaSMatthew Dillon 			++bi;
323068dc2eeaSMatthew Dillon 		}
323168dc2eeaSMatthew Dillon 		benv[bi].label = "PKGNAME";
323268dc2eeaSMatthew Dillon 		benv[bi].data = bulk->s4;
323368dc2eeaSMatthew Dillon 		++bi;
323468dc2eeaSMatthew Dillon 	}
323568dc2eeaSMatthew Dillon 
323668dc2eeaSMatthew Dillon 	benv[bi].label = NULL;
323768dc2eeaSMatthew Dillon 	benv[bi].data = NULL;
323868dc2eeaSMatthew Dillon 
3239f9d29536SMatthew Dillon 	fp = dexec_open(bulk->s1, cav, cac, &pid, benv, 0, 0);
324068dc2eeaSMatthew Dillon 	while ((ptr = fgetln(fp, &len)) != NULL)
324168dc2eeaSMatthew Dillon 		;
324268dc2eeaSMatthew Dillon 
324368dc2eeaSMatthew Dillon 	if (dexec_close(fp, pid)) {
324468dc2eeaSMatthew Dillon 		dlog(DLOG_ALL,
324568dc2eeaSMatthew Dillon 		     "[XXX] %s SCRIPT %s (%s)\n",
324668dc2eeaSMatthew Dillon 		     bulk->s1, bulk->s2, bulk->s3);
324768dc2eeaSMatthew Dillon 	}
324868dc2eeaSMatthew Dillon }
324932fc5bbfSMatthew Dillon 
325032fc5bbfSMatthew Dillon /*
325132fc5bbfSMatthew Dillon  * Adjusts dload[0] by adding in t_pw (processes waiting on page-fault).
325232fc5bbfSMatthew Dillon  * We don't want load reductions due to e.g. thrashing to cause dsynth
325332fc5bbfSMatthew Dillon  * to increase the dynamic limit because it thinks the load is low.
3254f5fc9cfaSMatthew Dillon  *
3255f5fc9cfaSMatthew Dillon  * This has a desirable property.  If the system pager cannot keep up
3256f5fc9cfaSMatthew Dillon  * with process demand t_pw will spike while loadavg will only drop
3257f5fc9cfaSMatthew Dillon  * slowly, resulting in a high adjusted load calculation that causes
3258f5fc9cfaSMatthew Dillon  * dsynth to quickly clamp-down the limit.  If the condition alleviates,
3259f5fc9cfaSMatthew Dillon  * the limit will then rise slowly again, possibly even before existing
3260f5fc9cfaSMatthew Dillon  * jobs are retired to meet the clamp-down from the original spike.
326132fc5bbfSMatthew Dillon  */
326232fc5bbfSMatthew Dillon static void
adjloadavg(double * dload)326332fc5bbfSMatthew Dillon adjloadavg(double *dload)
326432fc5bbfSMatthew Dillon {
326532fc5bbfSMatthew Dillon #if defined(__DragonFly__)
326632fc5bbfSMatthew Dillon 	struct vmtotal total;
326732fc5bbfSMatthew Dillon 	size_t size;
326832fc5bbfSMatthew Dillon 
326932fc5bbfSMatthew Dillon 	size = sizeof(total);
327032fc5bbfSMatthew Dillon 	if (sysctlbyname("vm.vmtotal", &total, &size, NULL, 0) == 0) {
327132fc5bbfSMatthew Dillon 		dload[0] += (double)total.t_pw;
327232fc5bbfSMatthew Dillon 	}
327332fc5bbfSMatthew Dillon #else
327432fc5bbfSMatthew Dillon 	dload[0] += 0.0;	/* just avoid compiler 'unused' warnings */
327532fc5bbfSMatthew Dillon #endif
327632fc5bbfSMatthew Dillon }
3277b6bd007bSMatthew Dillon 
3278b6bd007bSMatthew Dillon /*
32798d6cd058SMatthew Dillon  * The list of pkgs has already been flagged PKGF_PACKAGED if a pkg
32808d6cd058SMatthew Dillon  * file exists.  Check if the ports directory contents for such packages
32818d6cd058SMatthew Dillon  * has changed by comparing against a small DBM database that we maintain.
32828d6cd058SMatthew Dillon  *
32838d6cd058SMatthew Dillon  * Force-clear PKGF_PACKAGED if the ports directory content has changed.
32848d6cd058SMatthew Dillon  *
32858d6cd058SMatthew Dillon  * If no DBM database entry is present, update the entry and assume that
32868d6cd058SMatthew Dillon  * the package does not need to be rebuilt (allows the .dbm file to be
32878d6cd058SMatthew Dillon  * manually deleted without forcing a complete rebuild).
3288b6bd007bSMatthew Dillon  */
3289b6bd007bSMatthew Dillon static
3290b6bd007bSMatthew Dillon void
check_packaged(const char * dbmpath,pkg_t * pkgs)3291b6bd007bSMatthew Dillon check_packaged(const char *dbmpath, pkg_t *pkgs)
3292b6bd007bSMatthew Dillon {
3293b6bd007bSMatthew Dillon 	pkg_t *scan;
3294b6bd007bSMatthew Dillon 	datum key;
3295b6bd007bSMatthew Dillon 	datum data;
3296b6bd007bSMatthew Dillon 	char *buf;
3297b6bd007bSMatthew Dillon 
3298b6bd007bSMatthew Dillon 	if (CheckDBM == NULL) {
3299b6bd007bSMatthew Dillon 		dlog(DLOG_ABN, "[XXX] Unable to open/create dbm %s\n", dbmpath);
3300b6bd007bSMatthew Dillon 		return;
3301b6bd007bSMatthew Dillon 	}
3302b6bd007bSMatthew Dillon 	for (scan = pkgs; scan; scan = scan->bnext) {
3303b6bd007bSMatthew Dillon 		if ((scan->flags & PKGF_PACKAGED) == 0)
3304b6bd007bSMatthew Dillon 			continue;
3305b6bd007bSMatthew Dillon 		key.dptr = scan->portdir;
3306b6bd007bSMatthew Dillon 		key.dsize = strlen(scan->portdir);
3307b6bd007bSMatthew Dillon 		data = dbm_fetch(CheckDBM, key);
3308b6bd007bSMatthew Dillon 		if (data.dptr && data.dsize == sizeof(uint32_t) &&
3309b6bd007bSMatthew Dillon 		    *(uint32_t *)data.dptr != scan->crc32) {
3310b6bd007bSMatthew Dillon 			scan->flags &= ~PKGF_PACKAGED;
3311b6bd007bSMatthew Dillon 			asprintf(&buf, "%s/%s", RepositoryPath, scan->pkgfile);
3312b6bd007bSMatthew Dillon 			if (OverridePkgDeleteOpt >= 2) {
3313b6bd007bSMatthew Dillon 				scan->flags |= PKGF_PACKAGED;
3314b6bd007bSMatthew Dillon 				dlog(DLOG_ALL,
3315b6bd007bSMatthew Dillon 				     "[XXX] %s DELETE-PACKAGE %s "
3316b6bd007bSMatthew Dillon 				     "(port content changed CRC %08x/%08x "
3317b6bd007bSMatthew Dillon 				     "OVERRIDE, NOT DELETED)\n",
3318b6bd007bSMatthew Dillon 				     scan->portdir, buf,
3319b6bd007bSMatthew Dillon 				     *(uint32_t *)data.dptr, scan->crc32);
3320b6bd007bSMatthew Dillon 			} else if (remove(buf) < 0) {
3321b6bd007bSMatthew Dillon 				dlog(DLOG_ALL,
3322b6bd007bSMatthew Dillon 				     "[XXX] %s DELETE-PACKAGE %s (failed)\n",
3323b6bd007bSMatthew Dillon 				     scan->portdir, buf);
3324b6bd007bSMatthew Dillon 			} else {
3325b6bd007bSMatthew Dillon 				dlog(DLOG_ALL,
3326b6bd007bSMatthew Dillon 				     "[XXX] %s DELETE-PACKAGE %s "
3327b6bd007bSMatthew Dillon 				     "(port content changed CRC %08x/%08x)\n",
3328b6bd007bSMatthew Dillon 				     scan->portdir, buf,
3329b6bd007bSMatthew Dillon 				     *(uint32_t *)data.dptr, scan->crc32);
3330b6bd007bSMatthew Dillon 			}
3331b6bd007bSMatthew Dillon 			freestrp(&buf);
3332b6bd007bSMatthew Dillon 		} else if (data.dptr == NULL) {
3333b6bd007bSMatthew Dillon 			data.dptr = &scan->crc32;
3334b6bd007bSMatthew Dillon 			data.dsize = sizeof(scan->crc32);
3335b6bd007bSMatthew Dillon 			dbm_store(CheckDBM, key, data, DBM_REPLACE);
3336b6bd007bSMatthew Dillon 		}
3337b6bd007bSMatthew Dillon 	}
3338b6bd007bSMatthew Dillon }
3339