dsynth - Add manual page, change configuration directory, more
authorMatthew Dillon <dillon@apollo.backplane.com>
Thu, 22 Aug 2019 01:41:33 +0000 (18:41 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Thu, 22 Aug 2019 01:49:13 +0000 (18:49 -0700)
* Change the configuration location from /usr/local/etc/synth.ini
  to /etc/dsynth/dsynth.ini and (as an alternate)
  /usr/local/etc/dsynth/dsynth.ini

* Add 'dsynth debug <port>' directive.  This will build all
  dependencies and then build the specified port and freeze
  its worker slot with mounts still intact.

* Add the 'dsynth init' directive.  This will initialize the
  /etc/dsynth directory and default configuration files.
  This directive will refuse to do anything if /etc/dsynth
  or /usr/local/etc/dsynth already exists.

* Allow 'Number_of_builders' and/or 'Max_jobs_per_builder' to
  be specified as 0.  If 0, these parameters will be
  auto-configured.

* Add the dsynth(1) manual page.

* Include a procfs (/proc) mount in the worker chroot.

* Change a 'cpdup' to a 'cp' to improve portability.  Also change
  how the Template is generated a bit.

usr.bin/dsynth/Makefile
usr.bin/dsynth/build.c
usr.bin/dsynth/config.c
usr.bin/dsynth/dsynth.1 [new file with mode: 0644]
usr.bin/dsynth/dsynth.c
usr.bin/dsynth/dsynth.h
usr.bin/dsynth/gui.c
usr.bin/dsynth/mktemplate.sh
usr.bin/dsynth/mount.c

index 7b9e733..0533df4 100644 (file)
@@ -4,7 +4,6 @@
 PROG=  dsynth
 SRCS=  dsynth.c subs.c pkglist.c config.c bulk.c build.c repo.c mount.c
 SRCS+= status.c gui.c
-NOMAN=true
 
 SCRIPTS=mktemplate.sh
 SCRIPTSDIR= ${SHAREDIR}/dsynth
index 03ae332..f5a97cd 100644 (file)
@@ -752,6 +752,7 @@ startworker(pkg_t *pkg, worker_t *work)
        case WORKER_RUNNING:
        case WORKER_DONE:
        case WORKER_FAILED:
+       case WORKER_FROZEN:
        case WORKER_EXITING:
        default:
                dfatal("startworker: Unexpected state %d for worker %d",
@@ -846,6 +847,10 @@ workercomplete(worker_t *work)
        if (work->state == WORKER_FAILED) {
                dlog(DLOG_ALL, "[%03d] XXX/XXX WORKER IS IN A FAILED STATE\n",
                     work->index);
+       } else if (work->flags & WORKERF_FREEZE) {
+               dlog(DLOG_ALL, "[%03d] XXX/XXX WORKER FROZEN BY REQUEST\n",
+                    work->index);
+               work->state = WORKER_FROZEN;
        } else {
                work->state = WORKER_IDLE;
        }
@@ -1009,6 +1014,7 @@ childBuilderThread(void *arg)
        volatile int dowait;
        char slotbuf[8];
        char fdbuf[8];
+       char flagsbuf[16];
 
        pthread_mutex_lock(&WorkerMutex);
        while (work->terminate == 0) {
@@ -1035,8 +1041,12 @@ childBuilderThread(void *arg)
                                       PF_UNSPEC, work->fds)) {
                                dfatal_errno("socketpair() during worker fork");
                        }
-                       snprintf(slotbuf, sizeof(slotbuf), "%d", work->index);
-                       snprintf(fdbuf, sizeof(fdbuf), "3");
+                       snprintf(slotbuf, sizeof(slotbuf),
+                                "%d", work->index);
+                       snprintf(fdbuf, sizeof(fdbuf),
+                                "3");
+                       snprintf(flagsbuf, sizeof(flagsbuf),
+                                "%d", DebugStopMode);
 
                        /*
                         * fds[0] - master
@@ -1055,6 +1065,7 @@ childBuilderThread(void *arg)
                                execle(DSynthExecPath, DSynthExecPath,
                                       "WORKER", slotbuf, fdbuf,
                                       work->pkg->portdir, work->pkg->pkgfile,
+                                      flagsbuf,
                                       NULL, envary);
                                write(2, "EXECLE FAILURE\n", 15);
                                _exit(1);
@@ -1102,6 +1113,9 @@ childBuilderThread(void *arg)
                                case WMSG_CMD_FAILURE:
                                        work->flags |= WORKERF_FAILURE;
                                        break;
+                               case WMSG_CMD_FREEZEWORKER:
+                                       work->flags |= WORKERF_FREEZE;
+                                       break;
                                default:
                                        break;
                                }
@@ -1363,7 +1377,7 @@ WorkerProcess(int ac, char **av)
        int slot;
        int tmpfd;
        int pkgpkg = 0;
-       int status __unused;
+       int status;
        int len;
        int do_install_phase;
        char *portdir;
@@ -1377,7 +1391,7 @@ WorkerProcess(int ac, char **av)
        /*
         * Parse arguments
         */
-       if (ac != 5) {
+       if (ac != 6) {
                dlog(DLOG_ALL, "WORKER PROCESS %d- bad arguments\n", getpid());
                exit(1);
        }
@@ -1388,6 +1402,8 @@ WorkerProcess(int ac, char **av)
        flavor = strchr(portdir, '@');
        if (flavor)
                *flavor++ = 0;
+       DebugStopMode = strtol(av[5], NULL, 0);
+
        bzero(&wmsg, sizeof(wmsg));
 
        setproctitle("WORKER [%02d] STARTUP  %s", slot, portdir);
@@ -1413,6 +1429,15 @@ WorkerProcess(int ac, char **av)
        setenv("PKG_DBDIR", "/var/db/pkg", 1);
        setenv("PKG_CACHEDIR", "/var/cache/pkg", 1);
 
+#if 0
+       setenv("_PERL5_FROM_BIN", "5.28.2", 1);
+       setenv("OPSYS", OperatingSystemName, 1);
+#endif
+#if 0
+       setenv("DFLYVERSION", "5.7.0", 1);
+       setenv("OSVERSION", "9999999", 1);
+#endif
+
        setenv("PATH",
               "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
               1);
@@ -1609,15 +1634,25 @@ WorkerProcess(int ac, char **av)
                free(b2);
        }
 
-       DoWorkerUnmounts(work);
+       /*
+        * Unmount, unless we are in DebugStopMode.
+        */
+       if (DebugStopMode == 0)
+               DoWorkerUnmounts(work);
 
+       /*
+        * Send completion status to master dsynth worker thread.
+        */
        if (work->accum_error) {
                wmsg.cmd = WMSG_CMD_FAILURE;
        } else {
                wmsg.cmd = WMSG_CMD_SUCCESS;
        }
-
-       status = ipcwritemsg(fd, &wmsg);
+       ipcwritemsg(fd, &wmsg);
+       if (DebugStopMode) {
+               wmsg.cmd = WMSG_CMD_FREEZEWORKER;
+               ipcwritemsg(fd, &wmsg);
+       }
 }
 
 static void
index 3ba0088..127513e 100644 (file)
@@ -54,7 +54,6 @@ const char *VersionName = "unknown";
 const char *ReleaseName = "unknown";
 const char *DPortsPath = "/usr/dports";
 const char *CCachePath = "/build/ccache";
-const char *SynthConfig = "/usr/local/etc/synth/synth.ini";
 const char *PackagesPath = "/build/synth/live_packages";
 const char *RepositoryPath = "/build/synth/live_packages/All";
 const char *OptionsPath = "/build/synth/options";
@@ -64,6 +63,9 @@ const char *LogsPath = "/build/synth/logs";
 const char *SystemPath = "/";
 const char *ProfileLabel = "[LiveSystem]";
 
+const char *ConfigBase = "/etc/dsynth";
+const char *AltConfigBase = "/usr/local/etc/dsynth";
+
 static void parseConfigFile(const char *path);
 static void parseProfile(const char *cpath, const char *path);
 static char *stripwhite(char *str);
@@ -75,6 +77,14 @@ ParseConfiguration(int isworker)
 {
        struct stat st;
        size_t len;
+       char *synth_config;
+
+       /*
+        *
+        */
+       asprintf(&synth_config, "%s/dsynth.ini", ConfigBase);
+       if (stat(synth_config, &st) < 0)
+               asprintf(&synth_config, "%s/dsynth.ini", AltConfigBase);
 
        /*
         * OperatingSystemName, ArchitectureName, ReleaseName
@@ -104,14 +114,18 @@ ParseConfiguration(int isworker)
        /*
         * Configuration file must exist
         */
-       if (stat(SynthConfig, &st) < 0)
-               dfatal("Configuration file missing: %s", SynthConfig);
+       if (stat(synth_config, &st) < 0) {
+               dfatal("Configuration file missing, "
+                      "could not find %s/dsynth.ini or %s/dsynth.ini\n",
+                      ConfigBase,
+                      AltConfigBase);
+       }
 
        /*
         * Parse the configuration file(s)
         */
-       parseConfigFile(SynthConfig);
-       parseProfile(SynthConfig, ProfileLabel);
+       parseConfigFile(synth_config);
+       parseProfile(synth_config, ProfileLabel);
 
        /*
         * If this is a dsynth WORKER exec it handles a single slot,
@@ -259,17 +273,23 @@ parseConfigFile(const char *path)
                                SystemPath = l2;
                        } else if (strcmp(l1, "Number_of_builders") == 0) {
                                MaxWorkers = strtol(l2, NULL, 0);
-                               if (MaxWorkers < 1 || MaxWorkers > MAXWORKERS) {
+                               if (MaxWorkers == 0)
+                                       MaxWorkers = NumCores / 2 + 1;
+                               else
+                               if (MaxWorkers < 0 || MaxWorkers > MAXWORKERS) {
                                        dfatal("Config: Number_of_builders "
-                                              "must range 1..%d",
+                                              "must range %d..%d",
                                               1, MAXWORKERS);
                                }
                                free(l2);
                        } else if (strcmp(l1, "Max_jobs_per_builder") == 0) {
                                MaxJobs = strtol(l2, NULL, 0);
-                               if (MaxJobs < 1 || MaxJobs > MAXJOBS) {
+                               if (MaxJobs == 0) {
+                                       MaxJobs = NumCores;
+                               } else
+                               if (MaxJobs < 0 || MaxJobs > MAXJOBS) {
                                        dfatal("Config: Max_jobs_per_builder "
-                                              "must range 1..%d",
+                                              "must range %d..%d",
                                               1, MAXJOBS);
                                }
                                free(l2);
diff --git a/usr.bin/dsynth/dsynth.1 b/usr.bin/dsynth/dsynth.1
new file mode 100644 (file)
index 0000000..ef592ab
--- /dev/null
@@ -0,0 +1,331 @@
+.\" Copyright (c) 2019 The DragonFly Project.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to The DragonFly Project
+.\" by Matthew Dillon <dillon@backplane.com>
+.\" This code is based on a concept originally developed by John R. Marino.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in
+.\"    the documentation and/or other materials provided with the
+.\"    distribution.
+.\" 3. Neither the name of The DragonFly Project nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific, prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd August 21, 2019
+.Dt DSYNC 8
+.Os
+.Sh NAME
+.Nm dsynth
+.Nd dsynth bulk dports builder utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl dhvy
+.Op Fl s Ar n
+.Ar directive
+.Op origins
+.Nm
+.Ar help
+.Sh DESCRIPTION
+The
+.Nm
+utility allows a user to build and maintain part or all of dports
+locally.
+.Nm
+figures out the dependency topology of the dport(s) you
+is capable of building any number of ports concurrently based
+on the configuration parameters you supply.
+.Pp
+.Nm
+is based on an application called
+.Xr synth 1
+which was written by John Marino in ADA and served as the conceptual base
+for this program.
+.Nm
+is written in C and designed to be as portable as possible given a
+ports-style infrastructure.
+.Pp
+Our recommended build topology is with a configuration as follows:
+.Bd -literal
+[Global Configuration]
+profile_selected= LiveSystem
+
+[LiveSystem]
+Operating_system= DragonFly
+Directory_packages= /build/synth/live_packages
+Directory_repository= /build/synth/live_packages/All
+Directory_portsdir= /build/synth/dports
+Directory_options= /build/synth/options
+Directory_distfiles= /build/synth/distfiles
+Directory_buildbase= /build/synth/build
+Directory_logs= /build/synth/logs
+Directory_ccache= disabled
+Directory_system= /
+Number_of_builders= 8
+Max_jobs_per_builder= 8
+Display_with_ncurses= true
+.Ed
+.Pp
+This places all major directories under
+.Pa /build/synth .
+If you want to use the same dports and the same distfiles as your base
+system, you can null-mount /usr/distfiles onto /build/synth/distfiles
+and /usr/dports onto /build/synth/dports with
+.Pa /etc/fstab
+entries as follows:
+.Bd -literal
+# Device              Mountpoint               FStype  Options DumpPass#
+/usr/distfiles        /build/synth/distfiles   null    rw      4 4
+/usr/dports           /build/synth/dports      null    rw      4 4
+.Ed
+.Pp
+Please set the number of builders and the maximum number of jobs per
+builder according to available system resources.  Remember that the total
+load on the system can be as high as (builders x jobs), and at least 4x
+that value in processes.  Systems are typically restricted by memory and
+cpu horsepower.  Start conservative and ramp up according to what your
+system can handle.
+A good rule of thumb is to set workers to the number of cpu threads your
+machine has or to 1/2 the number of gigabytes of memory your system has,
+whichever is lower.  Then set the jobs per worker to no more than the
+number of cpu threads your machine has.
+.Pp
+.Nm
+has numerous feature to manage machine load and swap usage to
+prevent a machine from being overloaded, allowing more workers
+to be configured than you might otherwise think is reasonable
+(which helps a lot when building the smaller ports).
+However, users running this program should be aware that very high loads
+and modest swap use are still likely to develop when building a large
+number of ports or when building very large ports like chromium.
+If the system is not dedicated to building packages you can reduce the
+impact to the rest of the system by running
+.Nm
+at nice +20 and also by reducing the number of workers and number of
+jobs per worker somewhat.
+.Pp
+We recommend that a minimum of 64GB of SSD-based swap be configured,
+or twice as much swap as main memory, whichever is the higher value.
+.Pp
+We recommend a minimum of 500GB of storage be configured in
+.Pa /build
+or wherever you have configured various directories.
+A full set of distfiles requires at least 120GB, a full dports including
+the git repo requires at least 1.5GB, and a full set of built packages
+requires at least 75GB.  If using a filesystem such as HAMMER or HAMMER2
+which frees space overnight, double all of those numbers.
+.Pp
+The actual build infrastructure uses tmpfs... memory and swap, and does
+not use regular filesystem space.
+.Pp
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl d
+Run in debug mode.  This automatically turns off ncurses and outputs
+the primary log (00_last_results.log) to the standard output.
+.It Fl h
+Quickly output a synopsis of options and directives and exit.
+.It Fl v
+Quickly output the version and exit.
+.It Fl y
+Automatically answer 'y'es to any questions.
+.It Fl s Ar n
+.Nm
+usually slow-starts the worker slots, beginning with one slot and increasing
+by one every 5 seconds until the maximum configured number of workers is
+reached.
+This gives
+.Nm
+a slower ramp that it can load manage against.
+Specifying 0 disables the slow-start feature and the maximum number of
+worker slots (limited by the dependency graph) will be loaded immediately.
+.El
+.Sh DIRECTIVES
+.Pp
+Generally
+.Nm
+is run with a directive and some directives allow a list of ports to be
+specified.  This list should be space-delimited in DIR/SUBDIR format,
+for example:
+.Ar www/chromium .
+For directives with an optional ports list, your current installed set
+of ports will be used if you do not specify a list.
+.Pp
+.Bl -tag -width indent
+.It Cm status
+This will do a dry-run of
+.Cm upgrade-system
+but not actually build anything.
+.It Cm cleanup
+This will clean up any left-over mounts from prior builds.
+.Nm
+attempts to clean up all processes and mounts when you interrupt
+a build but doesn't always succeed.
+.It Cm init
+Creates and initializes the
+.Pa /etc/dsynth
+directory if it does not exst.
+This directive will complain and exit if either
+.Pa /etc/dsynth
+or
+.Pa /usr/local/etc/dsynth
+exists.  It will not create
+.Pa /etc/dsynth
+in this situation.
+.It Cm configure
+NOT CURRENTLY IMPLEMENTED
+.It Cm upgrade-system
+NOT CURRENTLY IMPLEMENTED.  Incrementally build and upgrade your locally
+installed packages, then upgrade your local system with them.
+.It Cm prepare-system
+Incrementally build and upgrade your locally installed packages, but
+do not upgrade your system with them.
+.It Cm rebuild-repository
+Build or rebuild the database files for the configured repository.
+.It Cm purge-distfiles
+Delete any obsolete source distribution files.
+.It Cm status-everything
+This will do a dry-run of a full bulk build of everything,
+but not actually build anything.
+.It Cm everything
+This will build the entire dports tree and then rebuild the repository
+when it finishes.
+.It Cm version
+This is for synth compatibility.  The version of
+.Nm
+will be printed and the program will exit.
+.It Cm help
+Output a synopsis of options and directives and exit.
+.It Cm status Op Ar ports
+Do a dry-run with 'build' of the given list.
+.It Cm build Op Ar ports
+Incrementally build dports based on the given list.  When
+done, ask whether the repository should be rebuilt or not.
+.It Cm just-build Op Ar ports
+Incrementally build dports based on the given list, then
+exits.  No post-build steps will be taken.
+.It Cm install Op Ar ports
+NOT CURRENTLY IMPLEMENTED.  'build' based on the supplied
+list (or using currently installed packages), then rebuild
+the repository and uprgade the system without asking any further
+questions.
+.It Cm force Op Ar ports
+This is the same as 'build' but will delete existing packages
+first.  Dependencies are not deleted unless they are out of date.
+.It Cm test Op Ar ports
+This is the same as 'build' but sets the environment variable
+.La DEVELOPER=yes
+and pre-deletes specified packages.  Dependencies are not deleted
+unless they are out of date.
+.El
+
+.Sh FILES
+.Bl -tag -width ".It Pa <fs>/abc/defghi/<name>" -compact
+.It Pa /etc/dsynth/synth.ini
+The primary configuration file.  If not found,
+.Nm
+will also look in
+.Pa /usr/local/etc/dsynth/synth.ini .
+.Pp
+.It Pa /etc/dsynth/LiveSystem-make.conf
+Typically contains the environment variables that will be set in
+the workers.
+.Nm
+firewalls the environment it is run under from the environment it
+provides to the workers.
+.Pp
+.It Pa /build/synth/build
+Recommended setting for
+.La Directory_buildbase ,
+contains the build infrastructure... typically a template, mirrored
+system directories, and mount points for all the worker slots.
+The template will be [re]generated if 'pkg' needs to be built or
+if the
+.Pa .template.good
+file in this directory is deleted.
+.Pp
+.It Pa /build/synth/distfiles
+Recommended setting for
+.La Directory_distfiles ,
+ports to a directory into which
+.Nm
+will download any source distribution files required for building.
+.Pp
+.It Pa /build/synth/dports
+Recommended setting for
+.La Directory_portsdir ,
+points to a checked out dports repo.
+Note that
+.Nm
+does not automatically 'git pull' or otherwise synchronize the dports repo,
+you must do that yourself prior to starting a build.
+.Pp
+.It Pa /build/synth/live_packages
+Recommended setting for
+.La Directory_packages ,
+points to a directory which will contain the completed application
+packages.
+.Pp
+.It Pa /build/synth/logs
+Recommended setting for
+.La Directory_logs ,
+all log files will be placed in this directory.
+Special management logfiles begin with the numeral '0' for easily
+location.
+The logfiles for ports while and after building are stored in the
+form subdir____portname.log, with three underscores.
+.Pp
+.It Pa /build/synth/options
+Recommended setting for
+.La Directory_options ,
+where options overrides for specific ports may be located.
+.Pp
+.It Pa /
+Recommended setting for
+.La Directory_system ,
+which
+.Nm
+uses as a basis for creating the jails or chroots in each worker slot
+during building.
+No part of the system root is ever NULL-mounted read-write... it is always
+NULL-mounted read-only.
+Some elements from the system base will be mirrored in the build-base
+as an optimization.
+.Pp
+Note that the packages directory and the distfiles directory is mounted
+read-write in jails or chroots.  All other r/w filesystems in the workers
+are
+.Xr tmpfs 5
+based filesystems and will be created and torn-down for each port.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr synth 1
+.Xr dports 7
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Dx 5.7 .
+.Sh AUTHORS
+.An Matthew Dillon Aq Mt dillon@backplane.com
index 83bb072..c6c390b 100644 (file)
 
 #include "dsynth.h"
 
+static void DoInit(void);
 static void usage(int ecode) __dead2;
 
 int YesOpt;
 int DebugOpt;
 int NullStdinOpt = 1;
 int SlowStartOpt = 1;
+int DebugStopMode;
 char *DSynthExecPath;
 
 int
@@ -107,6 +109,11 @@ main(int ac, char **av)
                /* NOT REACHED */
        }
 
+       if (strcmp(av[0], "init") == 0) {
+               DoInit();
+               exit(0);
+       }
+
        if (strcmp(av[0], "WORKER") == 0) {
                isworker = 1;
        } else {
@@ -138,17 +145,20 @@ main(int ac, char **av)
 
        DoInitBuild(-1);
 
-#if 1
        if (strcmp(av[0], "debug") == 0) {
+               DebugStopMode = 1;
+#if 0
                DoCleanBuild();
-               pkgs = GetFullPackageList();
-               printf("DoBuild: %p\n", pkgs);
-               MaxWorkers = 8; /* XXX */
+               pkgs = ParsePackageList(ac - 1, av + 1);
+               RemovePackages(pkgs);
+               addbuildenv("DEVELOPER", "yes");
                DoBuild(pkgs);
-               printf("DoBuild - done: %p\n", pkgs);
-       } else
 #endif
-       if (strcmp(av[0], "status") == 0) {
+               DebugStopMode = 1;
+               DoCleanBuild();
+               pkgs = ParsePackageList(ac - 1, av + 1);
+               DoBuild(pkgs);
+       } else if (strcmp(av[0], "status") == 0) {
                if (ac - 1)
                        pkgs = ParsePackageList(ac - 1, av + 1);
                else
@@ -227,6 +237,80 @@ main(int ac, char **av)
        return 0;
 }
 
+static void
+DoInit(void)
+{
+       struct stat st;
+       char *path;
+       FILE *fp;
+
+       if (stat(ConfigBase, &st) == 0) {
+               dfatal("init will not overwrite %s", ConfigBase);
+       }
+       if (stat(AltConfigBase, &st) == 0) {
+               dfatal("init will not create %s if %s exists",
+                      ConfigBase, AltConfigBase);
+       }
+       if (mkdir(ConfigBase, 0755) < 0)
+               dfatal_errno("Unable to mkdir %s", ConfigBase);
+
+       asprintf(&path, "%s/dsynth.ini", ConfigBase);
+       fp = fopen(path, "w");
+       dassert_errno(fp, "Unable to create %s", path);
+       fprintf(fp, "%s",
+           "; This Synth configuration file is automatically generated\n"
+           "; Take care when hand editing!\n"
+           "\n"
+           "[Global Configuration]\n"
+           "profile_selected= LiveSystem\n"
+           "\n"
+           "[LiveSystem]\n"
+           "Operating_system= DragonFly\n"
+           "Directory_packages= /build/synth/live_packages\n"
+           "Directory_repository= /build/synth/live_packages/All\n"
+           "Directory_portsdir= /build/synth/dports\n"
+           "Directory_options= /build/synth/options\n"
+           "Directory_distfiles= /build/synth/distfiles\n"
+           "Directory_buildbase= /build/synth/build\n"
+           "Directory_logs= /build/synth/logs\n"
+           "Directory_ccache= disabled\n"
+           "Directory_system= /\n"
+           "Number_of_builders= 0\n"
+           "Max_jobs_per_builder= 0\n"
+           "Tmpfs_workdir= true\n"
+           "Tmpfs_localbase= true\n"
+           "Display_with_ncurses= true\n"
+           "leverage_prebuilt= false\n"
+           "\n");
+       if (fclose(fp))
+               dfatal_errno("Unable to write to %s\n", ConfigBase);
+       free(path);
+
+       asprintf(&path, "%s/LiveSystem-make.conf", ConfigBase);
+       fp = fopen(path, "w");
+       dassert_errno(fp, "Unable to create %s", path);
+       fprintf(fp, "%s",
+           "#\n"
+           "# Various dports options that might be of interest\n"
+           "#\n"
+           "#LICENSES_ACCEPTED=      NONE\n"
+           "#DISABLE_LICENSES=       yes\n"
+           "#DEFAULT_VERSIONS=       ssl=openssl\n"
+           "#FORCE_PACKAGE=          yes\n"
+           "#DPORTS_BUILDER=         yes\n"
+           "#\n"
+           "# Turn these on to generate debug binaries.  However, these\n"
+           "# options will seriously bloat memory use and storage use,\n"
+           "# do not use lightly\n"
+           "#\n"
+           "#STRIP=\n"
+           "#WITH_DEBUG=yes\n"
+       );
+       if (fclose(fp))
+               dfatal_errno("Unable to write to %s\n", ConfigBase);
+       free(path);
+}
+
 __dead2 static void
 usage(int ecode)
 {
@@ -237,6 +321,7 @@ usage(int ecode)
 
        fprintf(stderr,
     "dsynth [options] directive\n"
+    "    init                - Initialize /etc/dsynth\n"
     "    status               - Dry-run of 'upgrade-system'\n"
     "    cleanup              - Clean-up mounts\n"
     "    configure            - Bring up configuration menu\n"
index 1564092..22d252a 100644 (file)
@@ -72,6 +72,7 @@ struct pkglink;
 #define MOUNT_NULLFS_BINARY    "/sbin/mount_null"
 #define MOUNT_TMPFS_BINARY     "/sbin/mount_tmpfs"
 #define MOUNT_DEVFS_BINARY     "/sbin/mount_devfs"
+#define MOUNT_PROCFS_BINARY    "/sbin/mount_procfs"
 #define UMOUNT_BINARY          "/sbin/umount"
 
 /*
@@ -189,7 +190,7 @@ typedef struct bulk {
  */
 enum worker_state { WORKER_NONE, WORKER_IDLE, WORKER_PENDING,
                    WORKER_RUNNING, WORKER_DONE, WORKER_FAILED,
-                   WORKER_EXITING };
+                   WORKER_FROZEN, WORKER_EXITING };
 typedef enum worker_state worker_state_t;
 
 enum worker_phase { PHASE_PENDING,
@@ -256,17 +257,20 @@ typedef struct worker {
 #define WORKERF_STATUS_UPDATE  0x0001  /* display update */
 #define WORKERF_SUCCESS                0x0002  /* completion flag */
 #define WORKERF_FAILURE                0x0004  /* completion flag */
+#define WORKERF_FREEZE         0x0008  /* freeze the worker */
 
 #define MOUNT_TYPE_MASK                0x000F
 #define MOUNT_TYPE_TMPFS       0x0001
 #define MOUNT_TYPE_NULLFS      0x0002
 #define MOUNT_TYPE_DEVFS       0x0003
+#define MOUNT_TYPE_PROCFS      0x0004
 #define MOUNT_TYPE_RW          0x0010
 #define MOUNT_TYPE_BIG         0x0020
 #define MOUNT_TYPE_TMP         0x0040
 
 #define NULLFS_RO              (MOUNT_TYPE_NULLFS)
 #define NULLFS_RW              (MOUNT_TYPE_NULLFS | MOUNT_TYPE_RW)
+#define PROCFS_RO              (MOUNT_TYPE_PROCFS)
 #define TMPFS_RW               (MOUNT_TYPE_TMPFS | MOUNT_TYPE_RW)
 #define TMPFS_RW_BIG           (MOUNT_TYPE_TMPFS | MOUNT_TYPE_RW |     \
                                 MOUNT_TYPE_BIG)
@@ -287,6 +291,7 @@ typedef struct wmsg {
 #define WMSG_CMD_FAILURE       0x0003
 #define WMSG_CMD_INSTALL_PKGS  0x0004
 #define WMSG_RES_INSTALL_PKGS  0x0005
+#define WMSG_CMD_FREEZEWORKER  0x0006
 
 /*
  * Make variables and build environment
@@ -357,6 +362,7 @@ extern int DynamicMaxWorkers;
 
 extern buildenv_t *BuildEnv;
 extern int DebugOpt;
+extern int DebugStopMode;
 extern int SlowStartOpt;
 extern int YesOpt;
 extern int NullStdinOpt;
@@ -378,6 +384,8 @@ extern const char *MachineName;
 extern const char *ReleaseName;
 extern const char *VersionName;
 
+extern const char *ConfigBase;
+extern const char *AltConfigBase;
 extern const char *DPortsPath;
 extern const char *CCachePath;
 extern const char *SynthConfig;
index 9ce5f9e..6ee5292 100644 (file)
@@ -256,6 +256,9 @@ GuiUpdate(worker_t *work)
        case WORKER_DONE:
                phase = "Done";
                break;
+       case WORKER_FROZEN:
+               phase = "FROZEN";
+               break;
        default:
                break;
        }
index 5ce9b19..d70ccd4 100755 (executable)
@@ -50,6 +50,7 @@ mkdir -p $template/usr/local/etc
 mkdir -p $template/usr/local/etc/pkg
 mkdir -p $template/usr/local/bin
 mkdir -p $template/usr/local/sbin
+mkdir -p $template/usr/local/lib
 mkdir -p $template/var/run
 
 cp /var/run/ld-elf.so.hints $template/var/run
index fe8c89f..a53d0d5 100644 (file)
@@ -52,10 +52,13 @@ int
 DoCreateTemplate(int force)
 {
        struct stat st;
+       char *goodbuf;
        char *buf;
        int rc;
+       int fd;
 
        rc = 0;
+       asprintf(&goodbuf, "%s/.template.good", BuildBase);
 
        /*
         * Conditionally create the template and discrete copies of certain
@@ -67,8 +70,7 @@ DoCreateTemplate(int force)
                        force = 1;
                free(buf);
 
-               asprintf(&buf, "%s/usr.bin.%03d", BuildBase, MaxWorkers - 1);
-               if (stat(buf, &st) < 0)
+               if (stat(goodbuf, &st) < 0)
                        force = 1;
                free(buf);
        }
@@ -77,6 +79,11 @@ DoCreateTemplate(int force)
         * Create the template
         */
        if (force) {
+               printf("Creating Template for workers...");
+               fflush(stdout);
+
+               remove(goodbuf);        /* ignore exit code */
+
                rc = 0;
                asprintf(&buf, "%s/mktemplate %s %s/Template",
                         SCRIPTPATH(SCRIPTDIR), SystemPath, BuildBase);
@@ -84,18 +91,31 @@ DoCreateTemplate(int force)
                if (rc)
                        dfatal("Command failed: %s\n", buf);
                free(buf);
-       }
 
-       /*
-        * Make discrete copies of certain extremely heavily used
-        * but small directories.
-        */
-       if (force) {
-               makeDiscreteCopies("$/bin", "/bin.%03d");
-               makeDiscreteCopies("$/lib", "/lib.%03d");
-               makeDiscreteCopies("$/libexec", "/libexec.%03d");
-               makeDiscreteCopies("$/usr/bin", "/usr.bin.%03d");
+               /*
+                * Make discrete copies of certain extremely heavily used
+                * but small directories.
+                */
+               if (force) {
+                       makeDiscreteCopies("$/bin", "/bin.%03d");
+                       makeDiscreteCopies("$/lib", "/lib.%03d");
+                       makeDiscreteCopies("$/libexec", "/libexec.%03d");
+                       makeDiscreteCopies("$/usr/bin", "/usr.bin.%03d");
+               }
+
+               /*
+                * Mark the template good... ah, do a sync() to really
+                * be sure that it can't get corrupted.
+                */
+               sync();
+               fd = open(goodbuf, O_RDWR|O_CREAT|O_TRUNC, 0644);
+               dassert_errno(fd >= 0, "could not create %s", goodbuf);
+               close(fd);
+
+               printf("done\n");
+               fflush(stdout);
        }
+       free(goodbuf);
 
        return rc;
 }
@@ -148,6 +168,7 @@ DoWorkerMounts(worker_t *work)
        domount(work, NULLFS_RO, "$/boot", "/boot", NULL);
        domount(work, TMPFS_RW,  "dummy", "/boot/modules.local", NULL);
        domount(work, DEVFS_RW,  "dummy", "/dev", NULL);
+       domount(work, PROCFS_RO, "dummy", "/proc", NULL);
        domount(work, NULLFS_RO, "$/bin", "/bin", "/bin.%03d");
        domount(work, NULLFS_RO, "$/sbin", "/sbin", NULL);
        domount(work, NULLFS_RO, "$/lib", "/lib", "/lib.%03d");
@@ -194,6 +215,7 @@ DoWorkerUnmounts(worker_t *work)
 
        work->mount_error = 0;
        for (retries = 0; retries < 10; ++retries) {
+               dounmount(work, "/proc");
                dounmount(work, "/dev");
                dounmount(work, "/usr/src");
                dounmount(work, "/usr/games");
@@ -277,6 +299,9 @@ domount(worker_t *work, int type, const char *spath, const char *dpath,
        case MOUNT_TYPE_DEVFS:
                prog = MOUNT_DEVFS_BINARY;
                break;
+       case MOUNT_TYPE_PROCFS:
+               prog = MOUNT_PROCFS_BINARY;
+               break;
        default:
                dfatal("Illegal mount type: %08x", type);
                /* NOT REACHED */
@@ -366,7 +391,10 @@ makeDiscreteCopies(const char *spath, const char *discretefmt)
                        if (mkdir(dst, 0555) < 0)
                                dfatal_errno("Cannot mkdir %s", dst);
                }
-               asprintf(&buf, "cpdup %s %s", src, dst);
+               asprintf(&buf, "chflags -R noschg %s; "
+                              "rm -rf %s; "
+                              "cp -Rp %s/. %s",
+                              dst, dst, src, dst);
                rc = system(buf);
                if (rc)
                        dfatal("Command failed: %s", buf);