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