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