dsynth - Misc/stabilization
[dragonfly.git] / usr.bin / dsynth / build.c
1 /*
2  * Copyright (c) 2019 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * This code uses concepts and configuration based on 'synth', by
8  * John R. Marino <draco@marino.st>, which was written in ada.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  * 3. Neither the name of The DragonFly Project nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific, prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
28  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 #include "dsynth.h"
38
39 worker_t WorkerAry[MAXWORKERS];
40 int BuildInitialized;
41 int RunningWorkers;
42 pthread_mutex_t WorkerMutex;
43 pthread_cond_t WorkerCond;
44
45 static int build_find_leaves(pkg_t *parent, pkg_t *pkg, pkg_t ***build_tailp,
46                         int *app, int *hasworkp, int level, int first);
47 static void build_clear_trav(pkg_t *pkg);
48 static void startbuild(pkg_t **build_listp, pkg_t ***build_tailp);
49 static int qsort_depi(const void *pkg1, const void *pkg2);
50 static int qsort_idep(const void *pkg1, const void *pkg2);
51 static void startworker(pkg_t *pkg, worker_t *work);
52 static void cleanworker(worker_t *work);
53 static void waitbuild(int whilematch);
54 static void workercomplete(worker_t *work);
55 static void *childBuilderThread(void *arg);
56 static int childInstallPkgDeps(worker_t *work);
57 static void childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list, int undoit);
58 static void dophase(worker_t *work, wmsg_t *wmsg,
59                         int wdog, int phaseid, const char *phase);
60 static void phaseReapAll(void);
61 static void phaseTerminateSignal(int sig);
62 static char *buildskipreason(pkg_t *pkg);
63 static int copyfile(char *src, char *dst);
64
65 static worker_t *SigWork;
66 static int FDMaster = -1;
67 static pid_t SigPid;
68 static int DynamicMaxWorkers;
69
70 int BuildTotal;
71 int BuildCount;
72 int BuildSkipCount;
73 int BuildFailCount;
74 int BuildSuccessCount;
75
76 /*
77  * Initialize the WorkerAry[]
78  */
79 void
80 DoInitBuild(int slot_override)
81 {
82         worker_t *work;
83         struct stat st;
84         int i;
85
86         ddassert(slot_override < 0 || MaxWorkers == 1);
87
88         bzero(WorkerAry, MaxWorkers * sizeof(worker_t));
89         pthread_mutex_init(&WorkerMutex, NULL);
90
91         for (i = 0; i < MaxWorkers; ++i) {
92                 work = &WorkerAry[i];
93                 work->index = (slot_override >= 0) ? slot_override : i;
94                 work->state = WORKER_NONE;
95                 asprintf(&work->basedir, "%s/SL%02d", BuildBase, work->index);
96                 pthread_cond_init(&work->cond, NULL);
97         }
98         BuildCount = 0;
99
100         /*
101          * Create required sub-directories. The base directories must already
102          * exist as a dsynth configuration safety.
103          */
104         if (stat(RepositoryPath, &st) < 0) {
105                 if (mkdir(RepositoryPath, 0755) < 0)
106                         dfatal("Cannot mkdir %s\n", RepositoryPath);
107         }
108
109         BuildInitialized = 1;
110         DynamicMaxWorkers = MaxWorkers;
111 }
112
113 /*
114  * Called by the frontend to clean-up any hanging mounts.
115  */
116 void
117 DoCleanBuild(void)
118 {
119         int i;
120
121         ddassert(BuildInitialized);
122
123         for (i = 0; i < MaxWorkers; ++i) {
124                 DoWorkerUnmounts(&WorkerAry[i]);
125         }
126         dlogreset();
127 }
128
129 void
130 DoBuild(pkg_t *pkgs)
131 {
132         pkg_t *build_list = NULL;
133         pkg_t **build_tail = &build_list;
134         pkg_t *scan;
135         int haswork = 1;
136         int first = 1;
137
138         for (scan = pkgs; scan; scan = scan->bnext)
139                 ++BuildTotal;
140
141         /*
142          * The pkg and pkg-static binaries are needed.  If already present
143          * then assume that the template is also valid, otherwise build
144          * both.
145          */
146         scan = GetPkgPkg(pkgs);
147
148         /*
149          * Create our template.  The template will be missing pkg
150          * and pkg-static.
151          */
152         if ((scan->flags & (PKGF_SUCCESS | PKGF_PACKAGED)) == 0) {
153                 DoCreateTemplate();
154         }
155
156         /*
157          * This will clear the screen and set-up our gui, so sleep
158          * a little first in case the user wants to see what was
159          * printed before.
160          */
161         sleep(2);
162         pthread_mutex_lock(&WorkerMutex);
163         GuiInit();
164         GuiReset();
165
166         if ((scan->flags & (PKGF_SUCCESS | PKGF_PACKAGED)) == 0) {
167                 char *buf;
168                 int rc;
169
170                 /*
171                  * Build pkg/pkg-static.
172                  */
173                 build_list = scan;
174                 build_tail = &scan->build_next;
175                 startbuild(&build_list, &build_tail);
176                 waitbuild(1);
177
178                 if (scan->flags & PKGF_NOBUILD)
179                         dfatal("Unable to build 'pkg'");
180                 if (scan->flags & PKGF_ERROR)
181                         dfatal("Error building 'pkg'");
182                 if ((scan->flags & PKGF_SUCCESS) == 0)
183                         dfatal("Error building 'pkg'");
184
185                 /*
186                  * Install pkg/pkg-static into the template
187                  */
188                 asprintf(&buf,
189                          "cd %s/Template; "
190                          "tar --exclude '+*' --exclude '*/man/*' "
191                          "-xvzpf %s/%s > /dev/null 2>&1",
192                          BuildBase,
193                          RepositoryPath,
194                          scan->pkgfile);
195                 rc = system(buf);
196                 if (rc)
197                         dfatal("Command failed: %s\n", buf);
198                 free(buf);
199         }
200
201         /*
202          * Nominal bulk build sequence
203          */
204         while (haswork) {
205                 haswork = 0;
206                 fflush(stdout);
207                 for (scan = pkgs; scan; scan = scan->bnext) {
208                         ddprintf(0, "SCANLEAVES %08x %s\n",
209                                  scan->flags, scan->portdir);
210                         scan->flags |= PKGF_BUILDLOOP;
211                         /*
212                          * NOTE: We must still find dependencies if PACKAGED
213                          *       to fill in the gaps, as some of them may
214                          *       need to be rebuilt.
215                          */
216                         if (scan->flags & (PKGF_SUCCESS | PKGF_FAILURE |
217                                            PKGF_ERROR | PKGF_NOBUILD)) {
218 #if 0
219                                 ddprintf(0, "%s: already built\n",
220                                          scan->portdir);
221 #endif
222                         } else {
223                                 int ap = 0;
224                                 build_find_leaves(NULL, scan, &build_tail,
225                                                   &ap, &haswork, 0, first);
226                                 ddprintf(0, "TOPLEVEL %s %08x\n",
227                                          scan->portdir, ap);
228                         }
229                         scan->flags &= ~PKGF_BUILDLOOP;
230                         build_clear_trav(scan);
231                 }
232                 first = 0;
233                 fflush(stdout);
234                 startbuild(&build_list, &build_tail);
235
236                 if (haswork == 0 && RunningWorkers) {
237                         waitbuild(RunningWorkers);
238                         haswork = 1;
239                 }
240         }
241         pthread_mutex_unlock(&WorkerMutex);
242
243         ddprintf(0, "BuildCount %d\n", BuildCount);
244 }
245
246 /*
247  * Traverse the packages (pkg) depends on recursively until we find
248  * a leaf to build or report as unbuildable.  Calculates and assigns a
249  * dependency count.  Returns all parallel-buildable packages.
250  *
251  * (pkg) itself is only added to the list if it is immediately buildable.
252  */
253 static
254 int
255 build_find_leaves(pkg_t *parent, pkg_t *pkg, pkg_t ***build_tailp,
256                   int *app, int *hasworkp, int level, int first)
257 {
258         pkglink_t *link;
259         pkg_t *scan;
260         int idep_count = 0;
261         int apsub;
262         char *buf;
263
264         /*
265          * Already on build list, possibly in-progress, tell caller that
266          * it is not ready.
267          */
268         ddprintf(level, "sbuild_find_leaves %d %s %08x {\n",
269                  level, pkg->portdir, pkg->flags);
270         if (pkg->flags & PKGF_BUILDLIST) {
271                 ddprintf(level, "} (already on build list)\n");
272                 *app |= PKGF_NOTREADY;
273                 return (pkg->idep_count);
274         }
275
276         /*
277          * Check dependencies
278          */
279         ++level;
280         PKGLIST_FOREACH(link, &pkg->idepon_list) {
281                 scan = link->pkg;
282
283                 if (scan == NULL)
284                         continue;
285                 ddprintf(level, "check %s %08x\t", scan->portdir, scan->flags);
286
287                 /*
288                  * When accounting for a successful build, just bump
289                  * idep_count by one.  scan->idep_count will heavily
290                  * overlap packages that we count down multiple branches.
291                  *
292                  * We must still recurse through PACKAGED packages as
293                  * some of their dependencies might be missing.
294                  */
295                 if (scan->flags & PKGF_SUCCESS) {
296                         ddprintf(0, "SUCCESS - OK\n");
297                         ++idep_count;
298                         continue;
299                 }
300                 if (scan->flags & PKGF_ERROR) {
301                         ddprintf(0, "ERROR - OK (propogate failure upward)\n");
302                         *app |= PKGF_NOBUILD_S;
303                         continue;
304                 }
305                 if (scan->flags & PKGF_NOBUILD) {
306                         ddprintf(0, "NOBUILD - OK "
307                                     "(propogate failure upward)\n");
308                         *app |= PKGF_NOBUILD_S;
309                         continue;
310                 }
311
312                 /*
313                  * If already on build-list this dependency is not ready.
314                  */
315                 if (scan->flags & PKGF_BUILDLIST) {
316                         ddprintf(0, " [BUILDLIST]");
317                         *app |= PKGF_NOTREADY;
318                 }
319
320                 /*
321                  * If not packaged this dependency is not ready for
322                  * the caller.
323                  */
324                 if ((scan->flags & PKGF_PACKAGED) == 0) {
325                         ddprintf(0, " [NOT_PACKAGED]");
326                         *app |= PKGF_NOTREADY;
327                 }
328
329                 /*
330                  * Reduce search complexity, if we have already processed
331                  * scan in the traversal it will either already be on the
332                  * build list or it will not be buildable.  Either way
333                  * the parent is not buildable.
334                  */
335                 if (scan->flags & PKGF_BUILDTRAV) {
336                         ddprintf(0, " [BUILDTRAV]\n");
337                         *app |= PKGF_NOTREADY;
338                         continue;
339                 }
340
341                 /*
342                  * Assert on dependency loop
343                  */
344                 ++idep_count;
345                 if (scan->flags & PKGF_BUILDLOOP) {
346                         dfatal("pkg dependency loop %s -> %s",
347                                 parent->portdir, scan->portdir);
348                 }
349                 scan->flags |= PKGF_BUILDLOOP;
350                 apsub = 0;
351                 ddprintf(0, " SUBRECURSION {\n");
352                 idep_count += build_find_leaves(pkg, scan, build_tailp,
353                                                 &apsub, hasworkp,
354                                                 level + 1, first);
355                 scan->flags &= ~PKGF_BUILDLOOP;
356                 *app |= apsub;
357                 if (apsub & PKGF_NOBUILD) {
358                         ddprintf(level, "} (sub-nobuild)\n");
359                 } else if (apsub & PKGF_ERROR) {
360                         ddprintf(level, "} (sub-error)\n");
361                 } else if (apsub & PKGF_NOTREADY) {
362                         ddprintf(level, "} (sub-notready)\n");
363                 } else {
364                         ddprintf(level, "} (sub-ok)\n");
365                 }
366         }
367         --level;
368         pkg->idep_count = idep_count;
369         pkg->flags |= PKGF_BUILDTRAV;
370
371         /*
372          * Incorporate scan results into pkg state.
373          */
374         if ((pkg->flags & PKGF_NOBUILD) == 0 && (*app & PKGF_NOBUILD)) {
375                 *hasworkp = 1;
376         } else if ((pkg->flags & PKGF_ERROR) == 0 && (*app & PKGF_ERROR)) {
377                 *hasworkp = 1;
378         }
379         pkg->flags |= *app & ~PKGF_NOTREADY;
380
381         /*
382          * Clear PACKAGED bit if sub-dependencies aren't clean
383          */
384         if ((pkg->flags & PKGF_PACKAGED) &&
385             (pkg->flags & (PKGF_NOTREADY|PKGF_ERROR|PKGF_NOBUILD))) {
386                 pkg->flags &= ~PKGF_PACKAGED;
387                 ddassert(pkg->pkgfile);
388                 asprintf(&buf, "%s/%s", RepositoryPath, pkg->pkgfile);
389                 if (remove(buf) < 0) {
390                         dlog(DLOG_ALL,
391                              "[XXX] %s DELETE-PACKAGE %s (failed)\n",
392                              pkg->portdir, buf);
393                 } else {
394                         dlog(DLOG_ALL,
395                              "[XXX] %s DELETE-PACKAGE %s "
396                              "(due to dependencies)\n",
397                              pkg->portdir, buf);
398                 }
399                 free(buf);
400                 buf = NULL;
401                 *hasworkp = 1;
402         }
403
404         /*
405          * Handle propagated flags
406          */
407         if (pkg->flags & PKGF_ERROR) {
408                 ddprintf(level, "} (ERROR - %s)\n", pkg->portdir);
409         } else if (pkg->flags & PKGF_NOBUILD) {
410                 ddprintf(level, "} (SKIPPED - %s)\n", pkg->portdir);
411         } else if (*app & PKGF_NOTREADY) {
412                 /*
413                  * We don't set PKGF_NOTREADY in the pkg, it is strictly
414                  * a transient flag propagated via build_find_leaves().
415                  *
416                  * Just don't add the package to the list.
417                  */
418                 ;
419         } else if (pkg->flags & PKGF_SUCCESS) {
420                 ddprintf(level, "} (SUCCESS - %s)\n", pkg->portdir);
421         } else if (pkg->flags & PKGF_DUMMY) {
422                 ddprintf(level, "} (DUMMY/META - SUCCESS)\n");
423                 pkg->flags |= PKGF_SUCCESS;
424                 *hasworkp = 1;
425                 if (first) {
426                         dlog(DLOG_ALL, "[XXX] %s META-ALREADY-BUILT\n",
427                              pkg->portdir);
428                         --BuildTotal;
429                 } else {
430                         dlog(DLOG_SUCC, "[XXX] %s meta-node complete\n",
431                              pkg->portdir);
432                 }
433         } else if (pkg->flags & PKGF_PACKAGED) {
434                 /*
435                  * We can just mark the pkg successful.  If this is
436                  * the first pass, we count this as an initial pruning
437                  * pass and reduce BuildTotal.
438                  */
439                 ddprintf(level, "} (PACKAGED - SUCCESS)\n");
440                 pkg->flags |= PKGF_SUCCESS;
441                 *hasworkp = 1;
442                 if (first) {
443                         dlog(DLOG_ALL, "[XXX] %s ALREADY-BUILT\n",
444                              pkg->portdir);
445                         --BuildTotal;
446                 }
447         } else {
448                 /*
449                  * All dependencies are successful, queue new work
450                  * and indicate not-ready to the parent (since our
451                  * package has to be built).
452                  */
453                 *hasworkp = 1;
454                 ddprintf(level, "} (ADDLIST - %s)\n", pkg->portdir);
455                 pkg->flags |= PKGF_BUILDLIST;
456                 **build_tailp = pkg;
457                 *build_tailp = &pkg->build_next;
458                 *app |= PKGF_NOTREADY;
459         }
460
461         return idep_count;
462 }
463
464 static
465 void
466 build_clear_trav(pkg_t *pkg)
467 {
468         pkglink_t *link;
469         pkg_t *scan;
470
471         pkg->flags &= ~PKGF_BUILDTRAV;
472         PKGLIST_FOREACH(link, &pkg->idepon_list) {
473                 scan = link->pkg;
474                 if (scan && (scan->flags & PKGF_BUILDTRAV))
475                         build_clear_trav(scan);
476         }
477 }
478
479 /*
480  * Take a list of pkg ready to go, sort it, and assign it to worker
481  * slots.  This routine blocks in waitbuild() until it can dispose of
482  * the entire list.
483  *
484  * WorkerMutex is held by the caller.
485  */
486 static
487 void
488 startbuild(pkg_t **build_listp, pkg_t ***build_tailp)
489 {
490         pkg_t *pkg;
491         pkg_t **idep_ary;
492         pkg_t **depi_ary;
493         int count;
494         int idep_index;
495         int depi_index;
496         int i;
497         int n;
498         worker_t *work;
499         static int IterateWorker;
500
501         /*
502          * Nothing to do
503          */
504         if (*build_listp == NULL)
505                 return;
506
507         /*
508          * Sort
509          */
510         count = 0;
511         for (pkg = *build_listp; pkg; pkg = pkg->build_next)
512                 ++count;
513         idep_ary = calloc(count, sizeof(pkg_t *));
514         depi_ary = calloc(count, sizeof(pkg_t *));
515
516         count = 0;
517         for (pkg = *build_listp; pkg; pkg = pkg->build_next) {
518                 idep_ary[count] = pkg;
519                 depi_ary[count] = pkg;
520                 ++count;
521         }
522
523         /*
524          * idep_ary - sorted by #of dependencies this pkg has.
525          * depi_ary - sorted by #of other packages that depend on this pkg.
526          */
527         qsort(idep_ary, count, sizeof(pkg_t *), qsort_idep);
528         qsort(depi_ary, count, sizeof(pkg_t *), qsort_depi);
529
530         idep_index = 0;
531         depi_index = 0;
532
533         /*
534          * Half the workers build based on the highest depi count,
535          * the other half build based on the highest idep count.
536          *
537          * This is an attempt to get projects which many other projects
538          * depend on built first, but to also try to build large projects
539          * (which tend to have a lot of dependencies) earlier rather than
540          * later so the end of the bulk run doesn't inefficiently build
541          * the last few huge projects.
542          *
543          * Loop until we manage to assign slots to everyone.  We do not
544          * wait for build completion.
545          *
546          * This is the point where we handle DUMMY packages (these are
547          * dummy unflavored packages which 'cover' all the flavors for
548          * a package).  These are not real packages are marked SUCCESS
549          * at this time because their dependencies (the flavors) have all
550          * been built.
551          */
552         while (idep_index != count || depi_index != count) {
553                 pkg_t *pkgi;
554                 pkg_t *ipkg;
555
556                 /*
557                  * Find candidate to start sorted by depi or idep.
558                  */
559                 ipkg = NULL;
560                 while (idep_index < count) {
561                         ipkg = idep_ary[idep_index];
562                         if ((ipkg->flags &
563                              (PKGF_SUCCESS |
564                               PKGF_FAILURE |
565                               PKGF_ERROR | PKGF_NOBUILD |
566                               PKGF_RUNNING)) == 0) {
567                                 break;
568                         }
569                         ipkg = NULL;
570                         ++idep_index;
571                 }
572
573                 pkgi = NULL;
574                 while (depi_index < count) {
575                         pkgi = depi_ary[depi_index];
576                         if ((pkgi->flags &
577                              (PKGF_SUCCESS |
578                               PKGF_FAILURE |
579                               PKGF_ERROR | PKGF_NOBUILD |
580                               PKGF_RUNNING)) == 0) {
581                                 break;
582                         }
583                         pkgi = NULL;
584                         ++depi_index;
585                 }
586
587                 if (ipkg == NULL && pkgi == NULL)
588                         break;
589                 ddassert(ipkg && pkgi);
590
591                 /*
592                  * Block while no slots are available.  waitbuild()
593                  * will clean out any DONE states.
594                  */
595                 while (RunningWorkers >= DynamicMaxWorkers) {
596                         waitbuild(RunningWorkers);
597                 }
598
599                 /*
600                  * Find an available worker slot, there should be at
601                  * least one.
602                  */
603                 for (i = 0; i < MaxWorkers; ++i) {
604                         n = IterateWorker % MaxWorkers;
605                         work = &WorkerAry[n];
606
607                         if (work->state == WORKER_DONE ||
608                             work->state == WORKER_FAILED) {
609                                 workercomplete(work);
610                         }
611                         if (work->state == WORKER_NONE ||
612                             work->state == WORKER_IDLE) {
613                                 if (n <= MaxWorkers / 2) {
614                                         startworker(pkgi, work);
615                                 } else {
616                                         startworker(ipkg, work);
617                                 }
618                                 /*GuiUpdate(work);*/
619                                 break;
620                         }
621                         ++IterateWorker;
622                 }
623                 ddassert(i != MaxWorkers);
624         }
625         GuiSync();
626
627         /*
628          * We disposed of the whole list
629          */
630         free(idep_ary);
631         free(depi_ary);
632         *build_listp = NULL;
633         *build_tailp = build_listp;
634 }
635
636 typedef const pkg_t *pkg_tt;
637
638 static int
639 qsort_idep(const void *pkg1_arg, const void *pkg2_arg)
640 {
641         const pkg_t *pkg1 = *(const pkg_tt *)pkg1_arg;
642         const pkg_t *pkg2 = *(const pkg_tt *)pkg2_arg;
643
644         return (pkg2->idep_count - pkg1->idep_count);
645 }
646
647 static int
648 qsort_depi(const void *pkg1_arg, const void *pkg2_arg)
649 {
650         const pkg_t *pkg1 = *(const pkg_tt *)pkg1_arg;
651         const pkg_t *pkg2 = *(const pkg_tt *)pkg2_arg;
652
653         return (pkg2->depi_count - pkg1->depi_count);
654 }
655
656 /*
657  * Frontend starts a pkg up on a worker
658  *
659  * WorkerMutex must be held.
660  */
661 static void
662 startworker(pkg_t *pkg, worker_t *work)
663 {
664         switch(work->state) {
665         case WORKER_NONE:
666                 pthread_create(&work->td, NULL, childBuilderThread, work);
667                 work->state = WORKER_IDLE;
668                 /* fall through */
669         case WORKER_IDLE:
670                 dlog(DLOG_ALL, "[%03d] %s START\n", work->index, pkg->portdir);
671                 cleanworker(work);
672                 pkg->flags |= PKGF_RUNNING;
673                 work->pkg = pkg;
674                 pthread_cond_signal(&work->cond);
675                 ++RunningWorkers;
676                 /*GuiUpdate(work);*/
677                 break;
678         case WORKER_PENDING:
679         case WORKER_RUNNING:
680         case WORKER_DONE:
681         case WORKER_FAILED:
682         case WORKER_EXITING:
683         default:
684                 dfatal("startworker: Unexpected state %d for worker %d",
685                        work->state, work->index);
686                 break;
687         }
688 }
689
690 static void
691 cleanworker(worker_t *work)
692 {
693         work->state = WORKER_PENDING;
694         work->flags = 0;
695         work->accum_error = 0;
696         work->start_time = time(NULL);
697 }
698
699 /*
700  * Frontend finishes up a completed pkg on a worker.
701  *
702  * If the worker is in a FAILED state we clean the pkg out but (for now)
703  * leave it in its failed state so we can debug.  At this point
704  * workercomplete() will be called every once in a while on the state
705  * and we have to deal with the NULL pkg.
706  *
707  * WorkerMutex must be held.
708  */
709 static void
710 workercomplete(worker_t *work)
711 {
712         pkg_t *pkg;
713
714         /*
715          * Steady state FAILED case.
716          */
717         if (work->state == WORKER_FAILED) {
718                 if (work->pkg == NULL)
719                         return;
720         }
721
722         /*
723          * Process pkg out of the worker
724          */
725         pkg = work->pkg;
726         if (pkg->flags & (PKGF_ERROR|PKGF_NOBUILD)) {
727                 pkg->flags |= PKGF_FAILURE;
728                 if (pkg->flags & PKGF_NOBUILD) {
729                         char *reason;
730
731                         ++BuildSkipCount;
732                         reason = buildskipreason(pkg);
733                         dlog(DLOG_SKIP, "[%03d] %s skipped due to%s\n",
734                              work->index, pkg->portdir, reason);
735                         free(reason);
736                 } else {
737                         ++BuildFailCount;
738                         dlog(DLOG_FAIL, "[%03d] %s build-failed\n",
739                              work->index, pkg->portdir);
740                 }
741         } else {
742                 time_t t;
743                 int h;
744                 int m;
745                 int s;
746
747                 t = time(NULL) - work->start_time;
748                 s = t % 60;
749                 m = t / 60 % 60;
750                 h = t / 3600;
751
752                 dlog(DLOG_SUCC,
753                      "[%03d] %s\tbuild-succeded in %02d:%02d:%02d\n",
754                      work->index, pkg->portdir, h, m, s);
755                 pkg->flags |= PKGF_SUCCESS;
756                 ++BuildSuccessCount;
757         }
758         ++BuildCount;
759         pkg->flags &= ~PKGF_BUILDLIST;
760         dlog(DLOG_ALL, "[%03d] %s FINISHED (%s)\n",
761              work->index,
762              pkg->portdir,
763              ((pkg->flags & PKGF_SUCCESS) ? "success" : "failure"));
764         pkg->flags &= ~PKGF_RUNNING;
765         work->pkg = NULL;
766         --RunningWorkers;
767
768         if (work->state == WORKER_FAILED) {
769                 dlog(DLOG_ALL, "[%03d] XXX/XXX WORKER IS IN A FAILED STATE\n",
770                      work->index);
771         } else {
772                 work->state = WORKER_IDLE;
773         }
774 }
775
776 /*
777  * Wait for one or more workers to complete.
778  *
779  * WorkerMutex must be held.
780  */
781 static void
782 waitbuild(int whilematch)
783 {
784         static time_t wblast_time;
785         struct timespec ts;
786         worker_t *work;
787         time_t t;
788         int i;
789
790         if (whilematch == 0)
791                 whilematch = 1;
792
793         while (RunningWorkers == whilematch) {
794                 for (i = 0; i < MaxWorkers; ++i) {
795                         work = &WorkerAry[i];
796                         if (work->state == WORKER_DONE ||
797                             work->state == WORKER_FAILED) {
798                                 workercomplete(work);
799                         } else {
800                                 pthread_cond_signal(&work->cond);
801                         }
802                         GuiUpdate(work);
803                 }
804                 GuiUpdateTop();
805                 GuiSync();
806                 if (RunningWorkers == whilematch) {
807                         clock_gettime(CLOCK_REALTIME, &ts);
808                         ts.tv_sec += 1;
809                         ts.tv_nsec = 0;
810                         pthread_cond_timedwait(&WorkerCond, &WorkerMutex, &ts);
811                 }
812
813                 /*
814                  * Dynamically reduce MaxWorkers based on the load.  When
815                  * the load exceeds 2 x ncpus we reduce the number of workers
816                  * by (2 * load / ncpus), but go no lower than 4.
817                  */
818                 t = time(NULL);
819                 if (wblast_time == 0 || wblast_time != t) {
820                         double dload[3];
821
822                         wblast_time = t;
823                         getloadavg(dload, 3);
824                         if (dload[0] > NumCores * 2) {
825                                 int reduce = dload[0] * 2.0 / NumCores;
826
827                                 reduce = MaxWorkers - reduce;
828                                 if (reduce < 4)
829                                         reduce = 4;
830                                 if (reduce > MaxWorkers)
831                                         reduce = MaxWorkers;
832                                 if (DynamicMaxWorkers != reduce) {
833                                         dlog(DLOG_ALL,
834                                              "[XXX] Load %6.2f "
835                                              "Adjust MaxWorkers "
836                                              "%d->%d\n",
837                                              dload[0],
838                                              DynamicMaxWorkers,
839                                              reduce);
840                                         DynamicMaxWorkers = reduce;
841                                 }
842                         } else if (DynamicMaxWorkers != MaxWorkers) {
843                                 dlog(DLOG_ALL,
844                                      "[XXX] Load %6.2f Adjust MaxWorkers "
845                                      "%d->%d\n",
846                                      dload[0], DynamicMaxWorkers, MaxWorkers);
847                                 DynamicMaxWorkers = MaxWorkers;
848                         }
849                 }
850         }
851 }
852
853
854 /*
855  * Worker pthread (WorkerAry)
856  *
857  * This thread belongs to the dsynth master process and handled a worker slot.
858  * (this_thread) -> WORKER fork/exec (WorkerPocess) -> (pty) -> sub-processes.
859  */
860 static void *
861 childBuilderThread(void *arg)
862 {
863         char *envary[1] = { NULL };
864         worker_t *work = arg;
865         wmsg_t wmsg;
866         pkg_t *pkg;
867         pid_t pid;
868         int status;
869         volatile int dowait;
870         char slotbuf[8];
871         char fdbuf[8];
872
873         pthread_mutex_lock(&WorkerMutex);
874         while (work->terminate == 0) {
875                 dowait = 1;
876
877                 switch(work->state) {
878                 case WORKER_IDLE:
879                         break;
880                 case WORKER_PENDING:
881                         /*
882                          * Fork the management process for the pkg operation
883                          * on this worker slot.
884                          *
885                          * This process will set up the environment, do the
886                          * mounts, will become the reaper, and will process
887                          * pipe commands and handle chroot operations.
888                          *
889                          * NOTE: If SOCK_CLOEXEC is not supported WorkerMutex
890                          *       is sufficient to interlock F_SETFD FD_CLOEXEC
891                          *       operations.
892                          */
893                         ddassert(work->pkg);
894                         if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC,
895                                        PF_UNSPEC, work->fds)) {
896                                 dfatal_errno("socketpair() during worker fork");
897                         }
898                         snprintf(slotbuf, sizeof(slotbuf), "%d", work->index);
899                         snprintf(fdbuf, sizeof(fdbuf), "3");
900
901                         /*
902                          * fds[0] - master
903                          * fds[1] - slave
904                          *
905                          * We pass the salve descriptor in fd 3 and close all
906                          * other descriptors for security.
907                          */
908                         pthread_mutex_unlock(&WorkerMutex);
909                         pid = vfork();
910                         if (pid == 0) {
911                                 close(work->fds[0]);
912                                 dup2(work->fds[1], 3);
913                                 closefrom(4);
914                                 fcntl(3, F_SETFD, 0);
915                                 execle(DSynthExecPath, DSynthExecPath,
916                                        "WORKER", slotbuf, fdbuf,
917                                        work->pkg->portdir, work->pkg->pkgfile,
918                                        NULL, envary);
919                                 write(2, "EXECLE FAILURE\n", 15);
920                                 _exit(1);
921                         }
922                         pthread_mutex_lock(&WorkerMutex);
923                         close(work->fds[1]);
924                         work->phase = PHASE_PENDING;
925                         work->lines = 0;
926                         work->pid = pid;
927                         work->state = WORKER_RUNNING;
928                         /* fall through */
929                 case WORKER_RUNNING:
930                         /*
931                          * Poll for status updates, if NULL is returned
932                          * and status is non-zero, the communications link
933                          * failed unexpectedly.
934                          */
935                         pkg = work->pkg;
936                         pthread_mutex_unlock(&WorkerMutex);
937                         status = ipcreadmsg(work->fds[0], &wmsg);
938                         pthread_mutex_lock(&WorkerMutex);
939
940                         if (status == 0) {
941                                 /*
942                                  * Normal message, can include normal
943                                  * termination which changes us over
944                                  * to another state.
945                                  */
946                                 dowait = 0;
947                                 switch(wmsg.cmd) {
948                                 case WMSG_CMD_INSTALL_PKGS:
949                                         wmsg.cmd = WMSG_RES_INSTALL_PKGS;
950                                         wmsg.status = childInstallPkgDeps(work);
951                                         pthread_mutex_unlock(&WorkerMutex);
952                                         ipcwritemsg(work->fds[0], &wmsg);
953                                         pthread_mutex_lock(&WorkerMutex);
954                                         break;
955                                 case WMSG_CMD_STATUS_UPDATE:
956                                         work->phase = wmsg.phase;
957                                         work->lines = wmsg.lines;
958                                         break;
959                                 case WMSG_CMD_SUCCESS:
960                                         work->flags |= WORKERF_SUCCESS;
961                                         break;
962                                 case WMSG_CMD_FAILURE:
963                                         work->flags |= WORKERF_FAILURE;
964                                         break;
965                                 default:
966                                         break;
967                                 }
968                                 GuiUpdate(work);
969                                 GuiSync();
970                         } else {
971                                 close(work->fds[0]);
972                                 pthread_mutex_unlock(&WorkerMutex);
973                                 while (waitpid(work->pid, &status, 0) < 0 &&
974                                        errno == EINTR) {
975                                         ;
976                                 }
977                                 pthread_mutex_lock(&WorkerMutex);
978
979                                 if (work->flags & WORKERF_SUCCESS) {
980                                         pkg->flags |= PKGF_SUCCESS;
981                                         work->state = WORKER_DONE;
982                                 } else if (work->flags & WORKERF_FAILURE) {
983                                         pkg->flags |= PKGF_FAILURE;
984                                         work->state = WORKER_DONE;
985                                 } else {
986                                         pkg->flags |= PKGF_FAILURE;
987                                         work->state = WORKER_FAILED;
988                                 }
989                                 work->flags |= WORKERF_STATUS_UPDATE;
990                                 pthread_cond_signal(&WorkerCond);
991                         }
992                         break;
993                 case WORKER_DONE:
994                         /*
995                          * pkg remains attached until frontend processes the
996                          * completion.  The frontend will then set the state
997                          * back to idle.
998                          */
999                         break;
1000                 case WORKER_FAILED:
1001                         /*
1002                          * A worker failure means that the worker did not
1003                          * send us a WMSG_CMD_SUCCESS or WMSG_CMD_FAILURE
1004                          * ipc before terminating.
1005                          *
1006                          * We just sit in this state until the front-end
1007                          * does something about it.
1008                          */
1009                         break;
1010                 default:
1011                         dfatal("worker: Unexpected state %d for worker %d",
1012                                work->state, work->index);
1013                         /* NOT REACHED */
1014                         break;
1015                 }
1016
1017                 /*
1018                  * The dsynth frontend will poll us approximately once
1019                  * a second (its variable).
1020                  */
1021                 if (dowait)
1022                         pthread_cond_wait(&work->cond, &WorkerMutex);
1023         }
1024
1025         /*
1026          * Scrap the comm socket if running, this should cause the worker
1027          * process to kill its sub-programs and cleanup.
1028          */
1029         if (work->state == WORKER_RUNNING) {
1030                 pthread_mutex_unlock(&WorkerMutex);
1031                 close(work->fds[0]);
1032                 while (waitpid(work->pid, &status, 0) < 0 &&
1033                        errno == EINTR);
1034                 pthread_mutex_lock(&WorkerMutex);
1035         }
1036
1037         /*
1038          * Final handshake
1039          */
1040         work->state = WORKER_EXITING;
1041         pthread_cond_signal(&WorkerCond);
1042         pthread_mutex_unlock(&WorkerMutex);
1043
1044         return NULL;
1045 }
1046
1047 /*
1048  * Install all the binary packages (we have already built them) that
1049  * the current work package depends on, without duplicates, in a script
1050  * which will be run from within the specified work jail.
1051  *
1052  * Locked by WorkerMutex (global)
1053  */
1054 static int
1055 childInstallPkgDeps(worker_t *work)
1056 {
1057         char *buf;
1058         FILE *fp;
1059
1060         if (PKGLIST_EMPTY(&work->pkg->idepon_list))
1061                 return 0;
1062
1063         asprintf(&buf, "%s/tmp/dsynth_install_pkgs", work->basedir);
1064         fp = fopen(buf, "w");
1065         ddassert(fp != NULL);
1066         fprintf(fp, "#!/bin/sh\n");
1067         fprintf(fp, "#\n");
1068         fchmod(fileno(fp), 0755);
1069
1070         childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 0);
1071         childInstallPkgDeps_recurse(fp, &work->pkg->idepon_list, 1);
1072         fprintf(fp, "\nexit 0\n");
1073         fclose(fp);
1074
1075         return 1;
1076 }
1077
1078 static void
1079 childInstallPkgDeps_recurse(FILE *fp, pkglink_t *list, int undoit)
1080 {
1081         pkglink_t *link;
1082         pkg_t *pkg;
1083
1084         PKGLIST_FOREACH(link, list) {
1085                 pkg = link->pkg;
1086
1087                 if (undoit) {
1088                         if (pkg->dsynth_install_flg == 1) {
1089                                 pkg->dsynth_install_flg = 0;
1090                                 childInstallPkgDeps_recurse(fp,
1091                                                             &pkg->idepon_list,
1092                                                             undoit);
1093                         }
1094                         continue;
1095                 }
1096                 if (pkg->dsynth_install_flg) {
1097                         if (DebugOpt && pkg->pkgfile) {
1098                                 fprintf(fp, "echo 'AlreadyHave %s'\n",
1099                                         pkg->pkgfile);
1100                         }
1101                         continue;
1102                 }
1103
1104                 childInstallPkgDeps_recurse(fp, &pkg->idepon_list, undoit);
1105                 if (pkg->dsynth_install_flg)
1106                         continue;
1107                 pkg->dsynth_install_flg = 1;
1108
1109                 /*
1110                  * If this is a dummy node with no package, the originator
1111                  * is requesting a flavored package.  We select the default
1112                  * flavor which we presume is the first one.
1113                  */
1114                 if (pkg->pkgfile == NULL && (pkg->flags & PKGF_DUMMY)) {
1115                         pkg_t *spkg = pkg->idepon_list.next->pkg;
1116
1117                         if (spkg) {
1118                                 pkg = spkg;
1119                                 fprintf(fp,
1120                                         "echo 'DUMMY use %s (%p)'\n",
1121                                         pkg->portdir, pkg->pkgfile);
1122                         } else {
1123                                 fprintf(fp,
1124                                         "echo 'CANNOT FIND DEFAULT FLAVOR "
1125                                         "FOR %s'\n",
1126                                         pkg->portdir);
1127                         }
1128                 }
1129
1130                 /*
1131                  * Generate package installation command
1132                  */
1133                 if (pkg->pkgfile) {
1134                         fprintf(fp, "echo 'Installing /packages/All/%s'\n",
1135                                 pkg->pkgfile);
1136                         fprintf(fp, "pkg install -q -y /packages/All/%s "
1137                                 "|| exit 1\n",
1138                                 pkg->pkgfile);
1139                 } else {
1140                         fprintf(fp, "echo 'CANNOT FIND PKG FOR %s'\n",
1141                                 pkg->portdir);
1142                 }
1143         }
1144 }
1145
1146 /*
1147  * Worker process interactions.
1148  *
1149  * The worker process is responsible for managing the build of a single
1150  * package.  It is exec'd by the master dsynth and only loads the
1151  * configuration.
1152  *
1153  * This process does not run in the chroot.  It will become the reaper for
1154  * all sub-processes and it will enter the chroot to execute various phases.
1155  * It catches SIGINTR, SIGHUP, and SIGPIPE and will iterate, terminate, and
1156  * reap all sub-process upon kill or exit.
1157  *
1158  * The command line forwarded to this function is:
1159  *
1160  *      WORKER slot# socketfd portdir/subdir
1161  *
1162  * TERM=dumb
1163  * USER=root
1164  * HOME=/root
1165  * LANG=C
1166  * SSL_NO_VERIFY_PEER=1
1167  * USE_PACKAGE_DEPENDS_ONLY=1   (exec_phase_depends)
1168  * PORTSDIR=/xports
1169  * PORT_DBDIR=/options          For ports options
1170  * PACKAGE_BUILDING=yes         Don't build packages that aren't legally
1171  *                              buildable for a binary repo.
1172  * PKG_DBDIR=/var/db/pkg
1173  * PKG_CACHEDIR=/var/cache/pkg
1174  * PKG_CREATE_VERBOSE=yes       Ensure periodic output during packaging
1175  * (custom environment)
1176  * PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
1177  * UNAME_s=DragonFly            (example)
1178  * UNAME_v=DragonFly 5.7-SYNTH  (example)
1179  * UNAME_p=x86_64               (example)
1180  * UNAME_m=x86_64               (example)
1181  * UNAME_r=5.7-SYNTH            (example)
1182  * NO_DEPENDS=yes               (exec_phase)
1183  * DISTDIR=/distfiles
1184  * WRKDIRPREFIX=/construction
1185  * BATCH=yes
1186  * MAKE_JOBS_NUMBER=n
1187  *
1188  * SETUP:
1189  *      ldconfig -R
1190  *      /usr/local/sbin/pkg-static install /packages/All/<the pkg pkg>
1191  *      /usr/local/sbin/pkg-static install /packages/All/<pkg>
1192  *                      (for all dependencies)
1193  *
1194  * PHASES:              make -C path FLAVOR=flavor <phase>
1195  *      check-sanity
1196  *      pkg-depends
1197  *      fetch-depends
1198  *      fetch
1199  *      checksum
1200  *      extract-depends
1201  *      extract
1202  *      patch-depends
1203  *      patch
1204  *      build-depends
1205  *      lib-depends
1206  *      configure
1207  *      build
1208  *      run-depends
1209  *      stage
1210  *      test
1211  *      check-plist
1212  *      package          e.g. /construction/lang/perl5.28/pkg/perl5-5.28.2.txz
1213  *      install-mtree
1214  *      install
1215  *      deinstall
1216  */
1217 void
1218 WorkerProcess(int ac, char **av)
1219 {
1220         wmsg_t wmsg;
1221         int fd;
1222         int slot;
1223         int tmpfd;
1224         int pkgpkg = 0;
1225         int status __unused;
1226         int len;
1227         int do_install_phase;
1228         char *portdir;
1229         char *pkgfile;
1230         char *flavor;
1231         char *buf;
1232         worker_t *work;
1233         pkg_t pkg;
1234         buildenv_t *benv;
1235
1236         /*
1237          * Parse arguments
1238          */
1239         if (ac != 5) {
1240                 dlog(DLOG_ALL, "WORKER PROCESS %d- bad arguments\n", getpid());
1241                 exit(1);
1242         }
1243         slot = strtol(av[1], NULL, 0);
1244         fd = strtol(av[2], NULL, 0);    /* master<->slave messaging */
1245         portdir = av[3];
1246         pkgfile = av[4];
1247         flavor = strchr(portdir, '@');
1248         if (flavor)
1249                 *flavor++ = 0;
1250         bzero(&wmsg, sizeof(wmsg));
1251
1252         setproctitle("WORKER [%02d] STARTUP  %s", slot, portdir);
1253
1254         if (strcmp(portdir, "ports-mgmt/pkg") == 0)
1255                 pkgpkg = 1;
1256
1257         signal(SIGTERM, phaseTerminateSignal);
1258         signal(SIGINT, phaseTerminateSignal);
1259         signal(SIGHUP, phaseTerminateSignal);
1260
1261         /*
1262          * Set up the environment
1263          */
1264         setenv("TERM", "dumb", 1);
1265         setenv("USER", "root", 1);
1266         setenv("HOME", "/root", 1);
1267         setenv("LANG", "C", 1);
1268         setenv("SSL_NO_VERIFY_PEER", "1", 1);
1269         setenv("USE_PACKAGE_DEPENDS_ONLY", "1", 1);
1270         setenv("PORTSDIR", "/xports", 1);
1271         setenv("PORT_DBDIR", "/options", 1);
1272         setenv("PKG_DBDIR", "/var/db/pkg", 1);
1273         setenv("PKG_CACHEDIR", "/var/cache/pkg", 1);
1274
1275         setenv("PATH",
1276                "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
1277                1);
1278
1279         setenv("UNAME_s", OperatingSystemName, 1);
1280         setenv("UNAME_v", VersionName, 1);
1281         setenv("UNAME_p", ArchitectureName, 1);
1282         setenv("UNAME_m", MachineName, 1);
1283         setenv("UNAME_r", ReleaseName, 1);
1284
1285         setenv("NO_DEPENDS", "yes", 1);
1286         setenv("DISTDIR", "/distfiles", 1);
1287         setenv("WRKDIRPREFIX", "/construction", 1);
1288         setenv("BATCH", "yes", 1);
1289
1290         /*
1291          * Special consideration
1292          *
1293          * PACKAGE_BUILDING     - Disallow packaging ports which do not allow
1294          *                        for binary distribution.
1295          *
1296          * PKG_CREATE_VERBOSE   - Ensure periodic output during the packaging
1297          *                        process to avoid a watchdog timeout.
1298          *
1299          */
1300         setenv("PACKAGE_BUILDING", "yes", 1);
1301         setenv("PKG_CREATE_VERBOSE", "yes", 1);
1302
1303         asprintf(&buf, "%d", MaxJobs);
1304         setenv("MAKE_JOBS_NUMBER", buf, 1);
1305         free(buf);
1306
1307         if (flavor)
1308                 setenv("FLAVOR", flavor, 1);
1309
1310         /*
1311          * Load environment from profile
1312          */
1313         for (benv = BuildEnv; benv; benv = benv->next) {
1314                 if (DebugOpt >= 2) {
1315                         dlog(DLOG_ALL, "[%03d] ENV %s=%s\n",
1316                              slot, benv->label, benv->data);
1317                 }
1318                 setenv(benv->label, benv->data, 1);
1319         }
1320
1321         /*
1322          * Become the reaper
1323          */
1324         if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) < 0)
1325                 dfatal_errno("procctl() - Cannot become reaper");
1326
1327         /*
1328          * Initialize a worker structure
1329          */
1330         DoInitBuild(slot);
1331
1332         bzero(&pkg, sizeof(pkg));
1333         pkg.portdir = portdir;          /* sans flavor */
1334         pkg.pkgfile = pkgfile;
1335         if (strchr(portdir, '/'))
1336                 len = strchr(portdir, '/') - portdir;
1337         else
1338                 len = 0;
1339
1340         /*
1341          * Setup the logfile
1342          */
1343         asprintf(&pkg.logfile,
1344                  "%s/%*.*s___%s%s%s.log",
1345                  LogsPath, len, len, portdir,
1346                  ((portdir[len] == '/') ? portdir + len + 1 : portdir + len),
1347                  (flavor ? "@" : ""),
1348                  (flavor ? flavor : ""));
1349         tmpfd = open(pkg.logfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
1350         if (tmpfd >= 0) {
1351                 dlog(DLOG_ALL, "[%03d] %s LOGFILE %s\n",
1352                      slot, pkg.portdir, pkg.logfile);
1353                 close(tmpfd);
1354         } else {
1355                 dlog(DLOG_ALL, "[%03d] LOGFILE %s (create failed)\n",
1356                      slot, pkg.logfile);
1357         }
1358
1359         /*
1360          * Setup the work structure.  Because this is an exec'd sub-process,
1361          * there is only one work structure.
1362          */
1363         work = &WorkerAry[0];
1364         work->flavor = flavor;
1365         work->fds[0] = fd;
1366         work->pkg = &pkg;
1367         work->start_time = time(NULL);
1368
1369         /*
1370          * Do mounts and start the phases
1371          */
1372         SigWork = work;
1373         setproctitle("WORKER [%02d] MOUNTS   %s", slot, portdir);
1374         DoWorkerMounts(work);
1375
1376         wmsg.cmd = WMSG_CMD_INSTALL_PKGS;
1377         ipcwritemsg(fd, &wmsg);
1378         status = ipcreadmsg(fd, &wmsg);
1379         if (status < 0 || wmsg.cmd != WMSG_RES_INSTALL_PKGS)
1380                 dfatal("pkg installation handshake failed");
1381         do_install_phase = wmsg.status;
1382
1383         wmsg.cmd = WMSG_CMD_STATUS_UPDATE;
1384         wmsg.phase = PHASE_INSTALL_PKGS;
1385         wmsg.lines = 0;
1386
1387         status = ipcwritemsg(fd, &wmsg);
1388
1389         if (pkgpkg) {
1390                 dophase(work, &wmsg,
1391                         WDOG5, PHASE_PACKAGE, "package");
1392         } else {
1393                 if (do_install_phase) {
1394                         dophase(work, &wmsg,
1395                                 WDOG4, PHASE_INSTALL_PKGS, "setup");
1396                 }
1397                 dophase(work, &wmsg,
1398                         WDOG2, PHASE_CHECK_SANITY, "check-sanity");
1399                 dophase(work, &wmsg,
1400                         WDOG2, PHASE_PKG_DEPENDS, "pkg-depends");
1401                 dophase(work, &wmsg,
1402                         WDOG7, PHASE_FETCH_DEPENDS, "fetch-depends");
1403                 dophase(work, &wmsg,
1404                         WDOG7, PHASE_FETCH, "fetch");
1405                 dophase(work, &wmsg,
1406                         WDOG2, PHASE_CHECKSUM, "checksum");
1407                 dophase(work, &wmsg,
1408                         WDOG3, PHASE_EXTRACT_DEPENDS, "extract-depends");
1409                 dophase(work, &wmsg,
1410                         WDOG3, PHASE_EXTRACT, "extract");
1411                 dophase(work, &wmsg,
1412                         WDOG2, PHASE_PATCH_DEPENDS, "patch-depends");
1413                 dophase(work, &wmsg,
1414                         WDOG2, PHASE_PATCH, "patch");
1415                 dophase(work, &wmsg,
1416                         WDOG5, PHASE_BUILD_DEPENDS, "build-depends");
1417                 dophase(work, &wmsg,
1418                         WDOG5, PHASE_LIB_DEPENDS, "lib-depends");
1419                 dophase(work, &wmsg,
1420                         WDOG3, PHASE_CONFIGURE, "configure");
1421                 dophase(work, &wmsg,
1422                         WDOG9, PHASE_BUILD, "build");
1423                 dophase(work, &wmsg,
1424                         WDOG5, PHASE_RUN_DEPENDS, "run-depends");
1425                 dophase(work, &wmsg,
1426                         WDOG5, PHASE_STAGE, "stage");
1427 #if 0
1428                 dophase(work, &wmsg,
1429                         WDOG5, PHASE_TEST, "test");
1430 #endif
1431                 dophase(work, &wmsg,
1432                         WDOG1, PHASE_CHECK_PLIST, "check-plist");
1433                 dophase(work, &wmsg,
1434                         WDOG5, PHASE_PACKAGE, "package");
1435 #if 0
1436                 dophase(work, &wmsg,
1437                         WDOG5, PHASE_INSTALL_MTREE, "install-mtree");
1438                 dophase(work, &wmsg,
1439                         WDOG5, PHASE_INSTALL, "install");
1440                 dophase(work, &wmsg,
1441                         WDOG5, PHASE_DEINSTALL, "deinstall");
1442 #endif
1443         }
1444
1445         setproctitle("WORKER [%02d] CLEANUP  %s", slot, portdir);
1446
1447         /*
1448          * Copy the package to the repo.
1449          */
1450         if (work->accum_error == 0) {
1451                 char *b1;
1452                 char *b2;
1453
1454                 asprintf(&b1, "%s/construction/%s/pkg/%s",
1455                          work->basedir, pkg.portdir, pkg.pkgfile);
1456                 asprintf(&b2, "%s/%s", RepositoryPath, pkg.pkgfile);
1457                 if (copyfile(b1, b2)) {
1458                         ++work->accum_error;
1459                         dlog(DLOG_ALL, "[%03d] %s Unable to copy %s to %s\n",
1460                              work->index, pkg.portdir, b1, b2);
1461                 }
1462                 free(b1);
1463                 free(b2);
1464         }
1465
1466         DoWorkerUnmounts(work);
1467
1468         if (work->accum_error) {
1469                 wmsg.cmd = WMSG_CMD_FAILURE;
1470         } else {
1471                 wmsg.cmd = WMSG_CMD_SUCCESS;
1472         }
1473
1474         status = ipcwritemsg(fd, &wmsg);
1475 }
1476
1477 static void
1478 dophase(worker_t *work, wmsg_t *wmsg, int wdog, int phaseid, const char *phase)
1479 {
1480         pkg_t *pkg = work->pkg;
1481         char buf[1024];
1482         pid_t pid;
1483         ssize_t r;
1484         int status;
1485         int fdmaster;
1486         int fdlog;
1487         time_t start_time;
1488         time_t last_time;
1489         time_t next_time;
1490         time_t wdog_time;
1491         FILE *fp;
1492
1493         if (work->accum_error)
1494                 return;
1495         setproctitle("WORKER [%02d] %8.8s %s",
1496                      work->index, phase, pkg->portdir);
1497         wmsg->phase = phaseid;
1498         if (ipcwritemsg(work->fds[0], wmsg) < 0) {
1499                 dlog(DLOG_ALL, "[%03d] %s Lost Communication with dsynth, "
1500                      "aborting worker\n",
1501                      work->index, pkg->portdir);
1502                 ++work->accum_error;
1503                 return;
1504         }
1505
1506         /*
1507          * Execute the port make command in chroot on a pty
1508          */
1509         fflush(stdout);
1510         fflush(stderr);
1511         if ((pid = forkpty(&fdmaster, NULL, NULL, NULL)) == 0) {
1512                 closefrom(3);
1513                 if (chdir(work->basedir) < 0)
1514                         dfatal_errno("chdir in phase initialization");
1515                 if (chroot(work->basedir) < 0)
1516                         dfatal_errno("chroot in phase initialization");
1517
1518                 /*
1519                  * Execute the appropriate command.
1520                  */
1521                 switch(phaseid) {
1522                 case PHASE_INSTALL_PKGS:
1523                         snprintf(buf, sizeof(buf), "/tmp/dsynth_install_pkgs");
1524                         execl(buf, buf, NULL);
1525                         break;
1526                 default:
1527                         snprintf(buf, sizeof(buf), "/xports/%s", pkg->portdir);
1528                         execl(MAKE_BINARY, MAKE_BINARY, "-C", buf, phase, NULL);
1529                         break;
1530                 }
1531                 _exit(1);
1532         }
1533
1534         FDMaster = fdmaster;    /* for signal handler */
1535         SigPid = pid;
1536
1537         fdlog = open(pkg->logfile, O_RDWR|O_CREAT|O_APPEND, 0644);
1538         if (fdlog < 0) {
1539                 dlog(DLOG_ALL, "[%03d] %s Cannot open logfile '%s': %s\n",
1540                      work->index, pkg->portdir,
1541                      pkg->logfile, strerror(errno));
1542         }
1543         start_time = time(NULL);
1544         last_time = start_time;
1545         wdog_time = start_time;
1546
1547         status = 0;
1548         for (;;) {
1549                 struct pollfd pfd;
1550
1551                 pfd.fd = fdmaster;
1552                 pfd.events = POLLIN;
1553                 pfd.revents = 0;
1554
1555                 poll(&pfd, 1, 1000);
1556                 if (pfd.revents) {
1557                         r = read(fdmaster, buf, sizeof(buf));
1558                         if (r <= 0) {
1559                                 if (r < 0 && errno == EINTR)
1560                                         continue;
1561                                 break;
1562                         }
1563                         wdog_time = time(NULL);
1564                         if (r > 0 && fdlog >= 0)
1565                                 write(fdlog, buf, r);
1566                         while (--r >= 0) {
1567                                 if (buf[r] == '\n')
1568                                         ++wmsg->lines;
1569                         }
1570                 }
1571
1572                 /*
1573                  * Generally speaking update status once a second.
1574                  * This also allows us to detect if the management
1575                  * dsynth process has gone away.
1576                  */
1577                 next_time = time(NULL);
1578                 if (next_time != last_time) {
1579                         double dload[3];
1580                         double dv;
1581                         int wdog_scaled;
1582
1583                         /*
1584                          * Send status update to the worker management thread
1585                          * in the master dsynth process.  Remember, *WE* are
1586                          * the worker management process sub-fork.
1587                          */
1588                         if (ipcwritemsg(work->fds[0], wmsg) < 0)
1589                                 break;
1590                         last_time = next_time;
1591
1592                         /*
1593                          * Watchdog scaling
1594                          */
1595                         getloadavg(dload, 3);
1596                         dv = dload[2] / NumCores;
1597                         if (dv < (double)NumCores) {
1598                                 wdog_scaled = wdog;
1599                         } else {
1600                                 if (dv > 4.0 * NumCores)
1601                                         dv = 4.0 * NumCores;
1602                                 wdog_scaled = wdog * dv / NumCores;
1603                         }
1604
1605                         /*
1606                          * Watchdog
1607                          */
1608                         if (next_time - wdog_time >= wdog_scaled * 60) {
1609                                 snprintf(buf, sizeof(buf),
1610                                          "\n--------\n"
1611                                          "WATCHDOG TIMEOUT FOR %s in %s "
1612                                          "after %d minutes\n"
1613                                          "Killing pid %d\n"
1614                                          "--------\n",
1615                                          pkg->portdir, phase, wdog_scaled, pid);
1616                                 if (fdlog >= 0)
1617                                         write(fdlog, buf, strlen(buf));
1618                                 dlog(DLOG_ALL,
1619                                      "[%03d] WATCHDOG TIMEOUT FOR %s in %s "
1620                                      "after %d minutes (%d min scaled)\n",
1621                                      work->index, pkg->portdir, phase,
1622                                      wdog, wdog_scaled);
1623                                 kill(pid, SIGKILL);
1624                                 ++work->accum_error;
1625                                 break;
1626                         }
1627                 }
1628
1629                 /*
1630                  * Check process exit.  Normally the pty will EOF
1631                  * but if background processes remain we need to
1632                  * check here to see if our primary exec is done,
1633                  * so we can break out and reap those processes.
1634                  */
1635                 if (waitpid(pid, &status, WNOHANG) == pid &&
1636                     WIFEXITED(status)) {
1637                         break;
1638                 }
1639         }
1640         close(fdmaster);
1641
1642         next_time = time(NULL);
1643
1644         setproctitle("WORKER [%02d] EXITREAP %s",
1645                      work->index, pkg->portdir);
1646         kill(pid, SIGKILL);
1647         while (WIFEXITED(status) == 0) {
1648                 if (waitpid(pid, &status, 0) < 0) {
1649                         if (errno != EINTR)
1650                                 break;
1651                 }
1652
1653         }
1654
1655         if (WEXITSTATUS(status)) {
1656                 dlog(DLOG_ALL, "[%03d] %s Build phase '%s' failed\n",
1657                      work->index, pkg->portdir, phase);
1658                 ++work->accum_error;
1659         }
1660
1661         /*
1662          * Kill any processes still running (sometimes processes end up in
1663          * the background during a dports build), and clean up any other
1664          * children that we have inherited.
1665          */
1666         phaseReapAll();
1667
1668         /*
1669          * Update log
1670          */
1671         if (fdlog >= 0) {
1672                 struct stat st;
1673                 int h;
1674                 int m;
1675                 int s;
1676
1677                 last_time = next_time - start_time;
1678                 s = last_time % 60;
1679                 m = last_time / 60 % 60;
1680                 h = last_time / 3600;
1681
1682                 fp = fdopen(fdlog, "a");
1683                 if (fp == NULL) {
1684                         dlog(DLOG_ALL, "[%03d] %s Cannot fdopen fdlog: %s %d\n",
1685                              work->index, pkg->portdir,
1686                              strerror(errno), fstat(fdlog, &st));
1687                         close(fdlog);
1688                         goto skip;
1689                 }
1690
1691                 fprintf(fp, "--------\n");
1692                 if (work->accum_error) {
1693                         fprintf(fp, "PHASE %s FAILED %02d:%02d:%02d\n",
1694                                 phase, h, m, s);
1695                 } else {
1696                         fprintf(fp, "PHASE %s SUCCEEDED %02d:%02d:%02d\n",
1697                                 phase, h, m, s);
1698                 }
1699                 last_time = next_time - work->start_time;
1700                 s = last_time % 60;
1701                 m = last_time / 60 % 60;
1702                 h = last_time / 3600;
1703                 if (phaseid == PHASE_PACKAGE) {
1704                         fprintf(fp, "TOTAL TIME %02d:%02d:%02d\n", h, m, s);
1705                 }
1706                 fprintf(fp, "--------\n");
1707                 fclose(fp);
1708 skip:
1709                 ;
1710         }
1711
1712 }
1713
1714 static void
1715 phaseReapAll(void)
1716 {
1717         struct reaper_status rs;
1718         int status;
1719
1720         while (procctl(P_PID, getpid(), PROC_REAP_STATUS, &rs) == 0) {
1721                 if ((rs.flags & PROC_REAP_ACQUIRE) == 0)
1722                         break;
1723                 if (rs.pid_head < 0)
1724                         break;
1725                 if (kill(rs.pid_head, SIGKILL) == 0) {
1726                         while (waitpid(rs.pid_head, &status, 0) < 0)
1727                                 ;
1728                 }
1729         }
1730         while (wait3(&status, 0, NULL) > 0)
1731                 ;
1732 }
1733
1734 static void
1735 phaseTerminateSignal(int sig __unused)
1736 {
1737         if (FDMaster >= 0)
1738                 close(FDMaster);
1739         if (SigPid > 1)
1740                 kill(SigPid, SIGKILL);
1741         phaseReapAll();
1742         if (SigWork)
1743                 DoWorkerUnmounts(SigWork);
1744         exit(1);
1745 }
1746
1747 static
1748 char *
1749 buildskipreason(pkg_t *pkg)
1750 {
1751         pkglink_t *link;
1752         pkg_t *scan;
1753         char *reason = NULL;
1754         size_t tot;
1755         size_t len;
1756
1757         tot = 0;
1758         PKGLIST_FOREACH(link, &pkg->idepon_list) {
1759                 scan = link->pkg;
1760                 if (scan == NULL)
1761                         continue;
1762                 if ((scan->flags & (PKGF_ERROR | PKGF_NOBUILD)) == 0)
1763                         continue;
1764                 len = strlen(scan->portdir);
1765                 reason = realloc(reason, tot + len + 8);
1766                 snprintf(reason + tot, len + 8, " %s", scan->portdir);
1767                 tot += strlen(reason + tot);
1768         }
1769         return (reason);
1770 }
1771
1772 /*
1773  * Copy a (package) file from (src) to (dst), use an intermediate file and
1774  * rename to ensure that interruption does not leave us with a corrupt
1775  * package file.
1776  *
1777  * This is called by the WORKER process.
1778  *
1779  * (dsynth management thread -> WORKER process -> sub-processes)
1780  */
1781 #define COPYBLKSIZE     32768
1782
1783 static int
1784 copyfile(char *src, char *dst)
1785 {
1786         char *tmp;
1787         char *buf;
1788         int fd1;
1789         int fd2;
1790         int error = 0;
1791         ssize_t r;
1792
1793         asprintf(&tmp, "%s.new", dst);
1794         buf = malloc(COPYBLKSIZE);
1795
1796         fd1 = open(src, O_RDONLY|O_CLOEXEC);
1797         fd2 = open(tmp, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
1798         while ((r = read(fd1, buf, COPYBLKSIZE)) > 0) {
1799                 if (write(fd2, buf, r) != r)
1800                         error = 1;
1801         }
1802         close(fd1);
1803         close(fd2);
1804         if (error) {
1805                 remove(tmp);
1806         } else {
1807                 if (rename(tmp, dst)) {
1808                         error = 1;
1809                         remove(tmp);
1810                 }
1811         }
1812
1813         free(buf);
1814         free(tmp);
1815
1816         return error;
1817 }