dsynth - Add #define for compression algo, default to .tgz
[dragonfly.git] / usr.bin / dsynth / dsynth.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
38 #include "dsynth.h"
39
40 static void DoInit(void);
41 static void usage(int ecode) __dead2;
42
43 int YesOpt;
44 int DebugOpt;
45 int NullStdinOpt = 1;
46 int SlowStartOpt = 1;
47 int DebugStopMode;
48 char *DSynthExecPath;
49
50 int
51 main(int ac, char **av)
52 {
53         pkg_t *pkgs;
54         int isworker;
55         int c;
56
57         /*
58          * Get our exec path so we can self-exec clean WORKER
59          * processes.
60          */
61         {
62                 size_t len;
63                 const int name[] = {
64                         CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1,
65                 };
66                 if (sysctl(name, 4, NULL, &len, NULL, 0) < 0)
67                         dfatal_errno("Cannot get binary path");
68                 DSynthExecPath = malloc(len + 1);
69                 if (sysctl(name, 4, DSynthExecPath, &len, NULL, 0) < 0)
70                         dfatal_errno("Cannot get binary path");
71                 DSynthExecPath[len] = 0;
72         }
73
74         /*
75          * Process options and make sure the directive is present
76          */
77         while ((c = getopt(ac, av, "dhvys:")) != -1) {
78                 switch(c) {
79                 case 'y':
80                         ++YesOpt;
81                         break;
82                 case 'd':
83                         ++DebugOpt;
84                         UseNCurses = 0;
85                         break;
86                 case 'h':
87                         usage(0);
88                         /* NOT REACHED */
89                         exit(0);
90                 case 'v':
91                         printf("dsynth %s\n", DSYNTH_VERSION);
92                         exit(0);
93                 case 's':
94                         SlowStartOpt = strtol(optarg, NULL, 0);
95                         break;
96                 default:
97                         fprintf(stderr, "Unknown option: %c\n", c);
98                         usage(2);
99                         /* NOT REACHED */
100                         break;
101                 }
102         }
103         ac -= optind;
104         av += optind;
105         pkgs = NULL;
106         if (ac < 1) {
107                 fprintf(stderr, "Missing directive\n");
108                 usage(2);
109                 /* NOT REACHED */
110         }
111
112         if (strcmp(av[0], "init") == 0) {
113                 DoInit();
114                 exit(0);
115         }
116
117         if (strcmp(av[0], "WORKER") == 0) {
118                 isworker = 1;
119         } else {
120                 isworker = 0;
121         }
122
123         /*
124          * Preconfiguration.
125          */
126         signal(SIGPIPE, SIG_IGN);
127         ParseConfiguration(isworker);
128
129         /*
130          * Setup some environment for bulk operations (pkglist scan).
131          * These will be overridden by the builder for the chrooted
132          * builds.
133          */
134         setenv("PORTSDIR", DPortsPath, 1);
135         setenv("BATCH", "yes", 1);
136         setenv("PKG_SUFX", USE_PKG_SUFX, 1);
137
138         /*
139          * Special directive for when dsynth execs itself to manage
140          * a worker chroot.
141          */
142         if (isworker) {
143                 WorkerProcess(ac, av);
144                 exit(0);
145         }
146
147         DoInitBuild(-1);
148
149         if (strcmp(av[0], "debug") == 0) {
150                 DebugStopMode = 1;
151 #if 0
152                 DoCleanBuild();
153                 pkgs = ParsePackageList(ac - 1, av + 1);
154                 RemovePackages(pkgs);
155                 addbuildenv("DEVELOPER", "yes");
156                 DoBuild(pkgs);
157 #endif
158                 DebugStopMode = 1;
159                 DoCleanBuild();
160                 pkgs = ParsePackageList(ac - 1, av + 1);
161                 DoBuild(pkgs);
162         } else if (strcmp(av[0], "status") == 0) {
163                 if (ac - 1)
164                         pkgs = ParsePackageList(ac - 1, av + 1);
165                 else
166                         pkgs = GetLocalPackageList();
167                 DoStatus(pkgs);
168         } else if (strcmp(av[0], "cleanup") == 0) {
169                 DoCleanBuild();
170         } else if (strcmp(av[0], "configure") == 0) {
171                 DoCleanBuild();
172                 DoConfigure();
173         } else if (strcmp(av[0], "upgrade-system") == 0) {
174                 DoCleanBuild();
175                 pkgs = GetLocalPackageList();
176                 DoBuild(pkgs);
177                 DoRebuildRepo(0);
178                 DoUpgradePkgs(pkgs, 0);
179         } else if (strcmp(av[0], "prepare-system") == 0) {
180                 DoCleanBuild();
181                 pkgs = GetLocalPackageList();
182                 DoBuild(pkgs);
183                 DoRebuildRepo(0);
184         } else if (strcmp(av[0], "rebuild-repository") == 0) {
185                 DoRebuildRepo(0);
186         } else if (strcmp(av[0], "purge-distfiles") == 0) {
187                 pkgs = GetFullPackageList();
188                 PurgeDistfiles(pkgs);
189         } else if (strcmp(av[0], "status-everything") == 0) {
190                 pkgs = GetFullPackageList();
191                 DoStatus(pkgs);
192         } else if (strcmp(av[0], "everything") == 0) {
193                 DoCleanBuild();
194                 pkgs = GetFullPackageList();
195                 DoBuild(pkgs);
196                 DoRebuildRepo(1);
197         } else if (strcmp(av[0], "version") == 0) {
198                 printf("dsynth %s\n", DSYNTH_VERSION);
199                 exit(0);
200         } else if (strcmp(av[0], "help") == 0) {
201                 usage(0);
202                 /* NOT REACHED */
203                 exit(0);
204         } else if (strcmp(av[0], "build") == 0) {
205                 DoCleanBuild();
206                 pkgs = ParsePackageList(ac - 1, av + 1);
207                 DoBuild(pkgs);
208                 DoRebuildRepo(1);
209                 DoUpgradePkgs(pkgs, 1);
210         } else if (strcmp(av[0], "just-build") == 0) {
211                 DoCleanBuild();
212                 pkgs = ParsePackageList(ac - 1, av + 1);
213                 DoBuild(pkgs);
214         } else if (strcmp(av[0], "install") == 0) {
215                 DoCleanBuild();
216                 pkgs = ParsePackageList(ac - 1, av + 1);
217                 DoBuild(pkgs);
218                 DoRebuildRepo(0);
219                 DoUpgradePkgs(pkgs, 0);
220         } else if (strcmp(av[0], "force") == 0) {
221                 DoCleanBuild();
222                 pkgs = ParsePackageList(ac - 1, av + 1);
223                 RemovePackages(pkgs);
224                 DoBuild(pkgs);
225                 DoRebuildRepo(1);
226                 DoUpgradePkgs(pkgs, 1);
227         } else if (strcmp(av[0], "test") == 0) {
228                 DoCleanBuild();
229                 pkgs = ParsePackageList(ac - 1, av + 1);
230                 RemovePackages(pkgs);
231                 addbuildenv("DEVELOPER", "yes");
232                 DoBuild(pkgs);
233         } else {
234                 fprintf(stderr, "Unknown directive '%s'\n", av[0]);
235                 usage(2);
236         }
237
238         return 0;
239 }
240
241 static void
242 DoInit(void)
243 {
244         struct stat st;
245         char *path;
246         FILE *fp;
247
248         if (stat(ConfigBase, &st) == 0) {
249                 dfatal("init will not overwrite %s", ConfigBase);
250         }
251         if (stat(AltConfigBase, &st) == 0) {
252                 dfatal("init will not create %s if %s exists",
253                        ConfigBase, AltConfigBase);
254         }
255         if (mkdir(ConfigBase, 0755) < 0)
256                 dfatal_errno("Unable to mkdir %s", ConfigBase);
257
258         asprintf(&path, "%s/dsynth.ini", ConfigBase);
259         fp = fopen(path, "w");
260         dassert_errno(fp, "Unable to create %s", path);
261         fprintf(fp, "%s",
262             "; This Synth configuration file is automatically generated\n"
263             "; Take care when hand editing!\n"
264             "\n"
265             "[Global Configuration]\n"
266             "profile_selected= LiveSystem\n"
267             "\n"
268             "[LiveSystem]\n"
269             "Operating_system= DragonFly\n"
270             "Directory_packages= /build/synth/live_packages\n"
271             "Directory_repository= /build/synth/live_packages/All\n"
272             "Directory_portsdir= /build/synth/dports\n"
273             "Directory_options= /build/synth/options\n"
274             "Directory_distfiles= /build/synth/distfiles\n"
275             "Directory_buildbase= /build/synth/build\n"
276             "Directory_logs= /build/synth/logs\n"
277             "Directory_ccache= disabled\n"
278             "Directory_system= /\n"
279             "Number_of_builders= 0\n"
280             "Max_jobs_per_builder= 0\n"
281             "Tmpfs_workdir= true\n"
282             "Tmpfs_localbase= true\n"
283             "Display_with_ncurses= true\n"
284             "leverage_prebuilt= false\n"
285             "\n");
286         if (fclose(fp))
287                 dfatal_errno("Unable to write to %s\n", ConfigBase);
288         free(path);
289
290         asprintf(&path, "%s/LiveSystem-make.conf", ConfigBase);
291         fp = fopen(path, "w");
292         dassert_errno(fp, "Unable to create %s", path);
293         fprintf(fp, "%s",
294             "#\n"
295             "# Various dports options that might be of interest\n"
296             "#\n"
297             "#LICENSES_ACCEPTED=      NONE\n"
298             "#DISABLE_LICENSES=       yes\n"
299             "#DEFAULT_VERSIONS=       ssl=openssl\n"
300             "#FORCE_PACKAGE=          yes\n"
301             "#DPORTS_BUILDER=         yes\n"
302             "#\n"
303             "# Turn these on to generate debug binaries.  However, these\n"
304             "# options will seriously bloat memory use and storage use,\n"
305             "# do not use lightly\n"
306             "#\n"
307             "#STRIP=\n"
308             "#WITH_DEBUG=yes\n"
309         );
310         if (fclose(fp))
311                 dfatal_errno("Unable to write to %s\n", ConfigBase);
312         free(path);
313 }
314
315 __dead2 static void
316 usage(int ecode)
317 {
318         if (ecode == 2) {
319                 fprintf(stderr, "Run 'dsynth help' for usage\n");
320                 exit(1);
321         }
322
323         fprintf(stderr,
324     "dsynth [options] directive\n"
325     "    init                 - Initialize /etc/dsynth\n"
326     "    status               - Dry-run of 'upgrade-system'\n"
327     "    cleanup              - Clean-up mounts\n"
328     "    configure            - Bring up configuration menu\n"
329     "    upgrade-system       - Incremental build and upgrade using pkg list\n"
330     "                           from local system, then upgrade the local\n"
331     "                           system.\n"
332     "    prepare-system       - 'upgrade-system' but stops after building\n"
333     "    rebuild-repository   - Rebuild database files for current repository\n"
334     "    purge-distfiles      - Delete obsolete source distribution files\n"
335     "    status-everything    - Dry-run of 'everything'\n"
336     "    everything           - Build entire dports tree and repo database\n"
337     "    version              - Display version info and exit\n"
338     "    help                 - Displays this screen\n"
339     "    status     [ports]   - Dry-run of 'build' with given list\n"
340     "    build      [ports]   - Incrementally build dports based on the given\n"
341     "                           list, but asks before updating the repo\n"
342     "                           database and system\n"
343     "    just-build [ports]   - 'build' but skips post-build steps\n"
344     "    install    [ports]   - 'build' but upgrades system without asking\n"
345     "    force      [ports]   - 'build' but deletes existing packages first\n"
346     "    test       [ports]   - 'build' w/DEVELOPER=yes and pre-deletes pkgs\n"
347     "\n"
348     "    [ports] is a space-delimited list of origins, e.g. editors/joe.  It\n"
349     "            may also be a path to a file containing one origin per line.\n"
350         );
351
352         exit(ecode);
353 }