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