xref: /dragonfly/usr.bin/dsynth/dsynth.c (revision 2b3f93ea)
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 int CheckAddReExec(int lkfd);
41 static void DoAddReExec(int lkfd, int ac, char **oldav);
42 static void DoInit(void);
43 static void usage(int ecode) __dead2;
44 
45 int ForceOpt;
46 int OverridePkgDeleteOpt;
47 int FetchOnlyOpt;
48 int YesOpt;
49 int DebugOpt;
50 int MaskProbeAbort;
51 int ColorOpt = 1;
52 int NullStdinOpt = 1;
53 int SlowStartOpt = -1;
54 int CapabilityRestrictions;
55 long PkgDepMemoryTarget;
56 long PkgDepScaleTarget = 100;	/* 1.00 */
57 char *DSynthExecPath;
58 char *ProfileOverrideOpt;
59 int NiceOpt = 10;
60 
61 int
62 main(int ac, char **av)
63 {
64 	char *lkpath;
65 	pkg_t *pkgs;
66 	int lkfd;
67 	int isworker;
68 	int c;
69 	int sopt;
70 	int doadds;
71 
72 #if defined(__DragonFly__)
73 	/*
74 	 * The system is expected to have capabilities
75 	 */
76 	{
77 		size_t len = sizeof(CapabilityRestrictions);
78 		sysctlbyname("kern.caps_available",
79 			     &CapabilityRestrictions, &len, NULL, 0);
80 		if (CapabilityRestrictions == 0)
81 			fprintf(stderr, "caps restrictions unavailable\n");
82 	}
83 #endif
84 
85 	/*
86 	 * Get our exec path so we can self-exec clean WORKER
87 	 * processes.
88 	 */
89 	{
90 		size_t len;
91 		const int name[] = {
92 			CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1,
93 		};
94 		if (sysctl(name, 4, NULL, &len, NULL, 0) < 0)
95 			dfatal_errno("Cannot get binary path");
96 		DSynthExecPath = malloc(len + 1);
97 		if (sysctl(name, 4, DSynthExecPath, &len, NULL, 0) < 0)
98 			dfatal_errno("Cannot get binary path");
99 		DSynthExecPath[len] = 0;
100 	}
101 
102 	/*
103 	 * Override profile in dsynth.ini (can be further overridden
104 	 * with the -p profile option).
105 	 */
106 	ProfileOverrideOpt = getenv("DSYNTH_PROFILE");
107 
108 	/*
109 	 * Process options and make sure the directive is present
110 	 */
111 	sopt = 0;
112 	while ((c = getopt(ac, av, "dfhm:p:vxys:DPM:NS")) != -1) {
113 		switch(c) {
114 		case 'f':
115 			++ForceOpt;
116 			break;
117 		case 'x':
118 			++OverridePkgDeleteOpt;
119 			break;
120 		case 'y':
121 			++YesOpt;
122 			break;
123 		case 'D':
124 			WorkerProcFlags |= WORKER_PROC_DEVELOPER;
125 			break;
126 		case 'P':
127 			WorkerProcFlags |= WORKER_PROC_CHECK_PLIST;
128 			break;
129 		case 'S':
130 			UseNCurses = 0;
131 			if (++sopt == 2)
132 				ColorOpt = 0;
133 			break;
134 		case 'N':
135 			NiceOpt = 0;
136 			break;
137 		case 'd':
138 			++DebugOpt;
139 			if (DebugOpt >= 2)
140 				UseNCurses = 0;
141 			break;
142 		case 'h':
143 			usage(0);
144 			/* NOT REACHED */
145 			exit(0);
146 		case 'v':
147 			printf("dsynth %s\n", DSYNTH_VERSION);
148 			exit(0);
149 		case 's':
150 			/*
151 			 * Start with N jobs, increasing to the configured
152 			 * maximum slowly.  0 to disable (starts with the
153 			 * full count).
154 			 */
155 			SlowStartOpt = strtol(optarg, NULL, 0);
156 			break;
157 		case 'm':
158 			PkgDepMemoryTarget = strtoul(optarg, NULL, 0);
159 			PkgDepMemoryTarget *= ONEGB;
160 			break;
161 		case 'M':
162 			PkgDepScaleTarget = strtod(optarg, NULL) * 100;
163 			if (PkgDepScaleTarget < 1)
164 				PkgDepScaleTarget = 1;
165 			if (PkgDepScaleTarget > 9900)
166 				PkgDepScaleTarget = 9900;
167 			break;
168 		case 'p':
169 			ProfileOverrideOpt = optarg;
170 			break;
171 		default:
172 			fprintf(stderr, "Unknown option: %c\n", c);
173 			usage(2);
174 			/* NOT REACHED */
175 			break;
176 		}
177 	}
178 	ac -= optind;
179 	av += optind;
180 	pkgs = NULL;
181 	if (ac < 1) {
182 		fprintf(stderr, "Missing directive\n");
183 		usage(2);
184 		/* NOT REACHED */
185 	}
186 
187 	/*
188 	 * Directives which do not require a working configuration
189 	 */
190 	if (strcmp(av[0], "init") == 0) {
191 		DoInit();
192 		exit(0);
193 		/* NOT REACHED */
194 	}
195 	if (strcmp(av[0], "help") == 0) {
196 		usage(0);
197 		exit(0);
198 		/* NOT REACHED */
199 	}
200 	if (strcmp(av[0], "version") == 0) {
201 		printf("dsynth %s\n", DSYNTH_VERSION);
202 		exit(0);
203 		/* NOT REACHED */
204 	}
205 
206 	/*
207 	 * Preconfiguration.
208 	 */
209 	if (strcmp(av[0], "WORKER") == 0) {
210 		isworker = 1;
211 	} else {
212 		isworker = 0;
213 	}
214 
215 	signal(SIGPIPE, SIG_IGN);
216 	ParseConfiguration(isworker);
217 
218 	/*
219 	 * Lock file path (also contains any 'add' directives thrown in
220 	 * during a build).
221 	 */
222 	asprintf(&lkpath, "%s/.lock", BuildBase);
223 
224 	/*
225 	 * Setup some environment for bulk operations (pkglist scan).
226 	 * These are not used by the builder (the builder will replicate
227 	 * all of these).
228 	 *
229 	 * NOTE: PKG_SUFX - pkg versions older than 1.17
230 	 *	 PKG_COMPRESSION_FORMAT - pkg versions >= 1.17
231 	 */
232 	addbuildenv("PORTSDIR", DPortsPath,
233 		    BENV_ENVIRONMENT | BENV_PKGLIST);
234 	addbuildenv("BATCH", "yes",
235 		    BENV_ENVIRONMENT | BENV_PKGLIST);
236 	addbuildenv("PKG_COMPRESSION_FORMAT", UsePkgSufx,
237 		    BENV_ENVIRONMENT | BENV_PKGLIST);
238 	addbuildenv("PKG_SUFX", UsePkgSufx,
239 		    BENV_ENVIRONMENT | BENV_PKGLIST);
240 	addbuildenv("PACKAGE_BUILDING", "yes",
241 		    BENV_ENVIRONMENT | BENV_PKGLIST);
242 	addbuildenv("ARCH", ArchitectureName,
243 		    BENV_ENVIRONMENT | BENV_PKGLIST);
244 
245 #if 0
246 	/*
247 	 *
248 	 */
249 	addbuildenv("OSTYPE", OperatingSystemName,
250 		    BENV_ENVIRONMENT | BENV_PKGLIST);
251 	addbuildenv("MACHTYPE", MachineName,
252 		    BENV_ENVIRONMENT | BENV_PKGLIST);
253 #endif
254 	/*
255 	 * SlowStart auto adjust.  We nominally start with 1 job and increase
256 	 * it to the maximum every 5 seconds to give various dynamic management
257 	 * parameters time to stabilize.
258 	 *
259 	 * This can take a while on a many-core box with a high jobs setting,
260 	 * so increase the initial jobs in such cases.
261 	 */
262 	if (SlowStartOpt > MaxWorkers)
263 		SlowStartOpt = MaxWorkers;
264 	if (SlowStartOpt < 0) {
265 		if (MaxWorkers < 16)
266 			SlowStartOpt = 1;
267 		else
268 			SlowStartOpt = MaxWorkers / 4;
269 	}
270 
271 	/*
272 	 * Special directive for when dsynth execs itself to manage
273 	 * a worker chroot.
274 	 */
275 	if (isworker) {
276 		WorkerProcess(ac, av);
277 		exit(0);
278 	}
279 
280 	/*
281 	 * Build initialization and directive handling
282 	 */
283 	DoInitBuild(-1);
284 
285 	/*
286 	 * Directives that use the configuration but are not interlocked
287 	 * against a running dsynth.
288 	 */
289 	if (strcmp(av[0], "monitor") == 0) {
290 		char *spath;
291 		char *lpath;
292 
293 		if (ac == 1) {
294 			asprintf(&spath, "%s/%s", StatsBase, STATS_FILE);
295 			asprintf(&lpath, "%s/%s", StatsBase, STATS_LOCKFILE);
296 			MonitorDirective(spath, lpath);
297 			free(spath);
298 			free(lpath);
299 		} else {
300 			MonitorDirective(av[1], NULL);
301 		}
302 		exit(0);
303 		/* NOT REACHED */
304 	} else if (strcmp(av[0], "add") == 0) {
305 		char *buf;
306 		int fd;
307 		int i;
308 
309 		/*
310 		 * The lock check is a bit racey XXX
311 		 */
312 		fd = open(lkpath, O_RDWR | O_CREAT | O_APPEND, 0644);
313 		if (flock(fd, LOCK_EX | LOCK_NB) == 0) {
314 			dfatal("No dsynth running to add ports to");
315 			flock(fd, LOCK_UN);
316 		}
317 		for (i = 1; i < ac; ++i) {
318 			asprintf(&buf, "%s\n", av[i]);
319 			write(fd, buf, strlen(buf));
320 			printf("added to run: %s\n", av[i]);
321 		}
322 		close(fd);
323 		exit(0);
324 	}
325 
326 	/*
327 	 * Front-end exec (not a WORKER exec), normal startup.  We have
328 	 * the configuration so the first thing we need to do is check
329 	 * the lock file.
330 	 */
331 	lkfd = open(lkpath, O_RDWR | O_CREAT | O_CLOEXEC, 0644);
332 	if (lkfd < 0)
333 		dfatal_errno("Unable to create %s", lkpath);
334 	if (flock(lkfd, LOCK_EX | LOCK_NB) < 0) {
335 		dfatal("Another dsynth is using %s, exiting",
336 		       BuildBase);
337 	}
338 
339 	/*
340 	 * Starting a new run cleans out any prior add directives
341 	 * that may have been pending.
342 	 */
343 	ftruncate(lkfd, 0);
344 	/* leave descriptor open */
345 
346 	doadds = 0;
347 
348 	if (strcmp(av[0], "debug") == 0) {
349 		DoCleanBuild(1);
350 		OptimizeEnv();
351 		pkgs = ParsePackageList(ac - 1, av + 1, 1);
352 		RemovePackages(pkgs);
353 		DoBuild(pkgs);
354 		doadds = 1;
355 	} else if (strcmp(av[0], "status") == 0) {
356 		OptimizeEnv();
357 		if (ac - 1)
358 			pkgs = ParsePackageList(ac - 1, av + 1, 0);
359 		else
360 			pkgs = GetLocalPackageList();
361 		DoStatus(pkgs);
362 	} else if (strcmp(av[0], "cleanup") == 0) {
363 		DoCleanBuild(0);
364 	} else if (strcmp(av[0], "configure") == 0) {
365 		DoCleanBuild(0);
366 		DoConfigure();
367 	} else if (strcmp(av[0], "fetch-only") == 0) {
368 		if (SlowStartOpt == -1)
369 			SlowStartOpt = 999;
370 		if (PkgDepScaleTarget == 100)
371 			PkgDepScaleTarget = 999;
372 		++FetchOnlyOpt;
373 		++YesOpt;
374 		WorkerProcFlags |= WORKER_PROC_FETCHONLY;
375 		DoCleanBuild(1);
376 		OptimizeEnv();
377 		if (ac == 2 && strcmp(av[1], "everything") == 0) {
378 			MaskProbeAbort = 1;
379 			pkgs = GetFullPackageList();
380 		} else {
381 			pkgs = ParsePackageList(ac - 1, av + 1, 0);
382 		}
383 		DoBuild(pkgs);
384 		doadds = 1;
385 	} else if (strcmp(av[0], "list-system") == 0) {
386 		FILE *fp;
387 
388 		DoCleanBuild(1);
389 		OptimizeEnv();
390 		pkgs = GetLocalPackageList();
391 		if ((fp = fopen("build.txt", "w")) != NULL) {
392 			while (pkgs) {
393 				fprintf(fp, "%s\n", pkgs->portdir);
394 				pkgs = pkgs->bnext;
395 			}
396 			fclose(fp);
397 			printf("list written to build.txt\n");
398 		} else {
399 			fprintf(stderr, "Cannot create 'build.txt'\n");
400 			exit(1);
401 		}
402 	} else if (strcmp(av[0], "upgrade-system") == 0) {
403 		DoCleanBuild(1);
404 		OptimizeEnv();
405 		pkgs = GetLocalPackageList();
406 		DoBuild(pkgs);
407 		DoRebuildRepo(0);
408 		DoUpgradePkgs(pkgs, 0);
409 		dfatal("NOTE: you have to pkg upgrade manually");
410 	} else if (strcmp(av[0], "prepare-system") == 0) {
411 		DeleteObsoletePkgs = 1;
412 		DoCleanBuild(1);
413 		OptimizeEnv();
414 		pkgs = GetLocalPackageList();
415 		DoBuild(pkgs);
416 		DoRebuildRepo(0);
417 	} else if (strcmp(av[0], "rebuild-repository") == 0) {
418 		OptimizeEnv();
419 		DoRebuildRepo(0);
420 	} else if (strcmp(av[0], "purge-distfiles") == 0) {
421 		OptimizeEnv();
422 		pkgs = GetFullPackageList();
423 		PurgeDistfiles(pkgs);
424 	} else if (strcmp(av[0], "reset-db") == 0) {
425 		char *dbmpath;
426 
427 		asprintf(&dbmpath, "%s/ports_crc.db", BuildBase);
428 		remove(dbmpath);
429 		printf("%s reset, will be regenerated on next build\n",
430 		       dbmpath);
431 		free(dbmpath);
432 	} else if (strcmp(av[0], "status-everything") == 0) {
433 		OptimizeEnv();
434 		pkgs = GetFullPackageList();
435 		DoStatus(pkgs);
436 	} else if (strcmp(av[0], "everything") == 0) {
437 		if (WorkerProcFlags & WORKER_PROC_DEVELOPER)
438 			WorkerProcFlags |= WORKER_PROC_CHECK_PLIST;
439 		MaskProbeAbort = 1;
440 		DeleteObsoletePkgs = 1;
441 		DoCleanBuild(1);
442 		OptimizeEnv();
443 		pkgs = GetFullPackageList();
444 		DoBuild(pkgs);
445 		DoRebuildRepo(!CheckAddReExec(lkfd));
446 	} else if (strcmp(av[0], "build") == 0) {
447 		DoCleanBuild(1);
448 		OptimizeEnv();
449 		pkgs = ParsePackageList(ac - 1, av + 1, 0);
450 		DoBuild(pkgs);
451 		DoRebuildRepo(!CheckAddReExec(lkfd));
452 		DoUpgradePkgs(pkgs, 1);
453 		doadds = 1;
454 	} else if (strcmp(av[0], "just-build") == 0) {
455 		DoCleanBuild(1);
456 		OptimizeEnv();
457 		pkgs = ParsePackageList(ac - 1, av + 1, 0);
458 		DoBuild(pkgs);
459 		doadds = 1;
460 	} else if (strcmp(av[0], "install") == 0) {
461 		DoCleanBuild(1);
462 		OptimizeEnv();
463 		pkgs = ParsePackageList(ac - 1, av + 1, 0);
464 		DoBuild(pkgs);
465 		DoRebuildRepo(0);
466 		DoUpgradePkgs(pkgs, 0);
467 		doadds = 1;
468 	} else if (strcmp(av[0], "force") == 0) {
469 		DoCleanBuild(1);
470 		OptimizeEnv();
471 		pkgs = ParsePackageList(ac - 1, av + 1, 0);
472 		RemovePackages(pkgs);
473 		DoBuild(pkgs);
474 		DoRebuildRepo(!CheckAddReExec(lkfd));
475 		DoUpgradePkgs(pkgs, 1);
476 		doadds = 1;
477 	} else if (strcmp(av[0], "test") == 0) {
478 		WorkerProcFlags |= WORKER_PROC_CHECK_PLIST |
479 				   WORKER_PROC_INSTALL |
480 				   WORKER_PROC_DEINSTALL;
481 		DoCleanBuild(1);
482 		OptimizeEnv();
483 		pkgs = ParsePackageList(ac - 1, av + 1, 0);
484 		RemovePackages(pkgs);
485 		WorkerProcFlags |= WORKER_PROC_DEVELOPER;
486 		DoBuild(pkgs);
487 		doadds = 1;
488 	} else {
489 		fprintf(stderr, "Unknown directive '%s'\n", av[0]);
490 		usage(2);
491 	}
492 
493 	/*
494 	 * For directives that support the 'add' directive, check for
495 	 * additions and re-exec.
496 	 *
497 	 * Note that the lockfile is O_CLOEXEC and will be remade on exec.
498 	 *
499 	 * XXX a bit racey vs adds done just as we are finishing
500 	 */
501 	if (doadds && CheckAddReExec(lkfd))
502 		DoAddReExec(lkfd, optind + 1, av - optind);
503 
504 	return 0;
505 }
506 
507 /*
508  * If the 'add' directive was issued while a dsynth build was in
509  * progress, we re-exec dsynth with its original options and
510  * directive along with the added ports.
511  */
512 static int
513 CheckAddReExec(int lkfd)
514 {
515 	struct stat st;
516 
517 	if (fstat(lkfd, &st) < 0 || st.st_size == 0)
518 		return 0;
519 	return 1;
520 }
521 
522 static void
523 DoAddReExec(int lkfd, int ac, char **oldav)
524 {
525 	struct stat st;
526 	char *buf;
527 	char **av;
528 	size_t bi;
529 	size_t i;
530 	int nadd;
531 	int n;
532 
533 	if (fstat(lkfd, &st) < 0 || st.st_size == 0)
534 		return;
535 	buf = malloc(st.st_size + 1);
536 	if (read(lkfd, buf, st.st_size) != st.st_size) {
537 		free(buf);
538 		return;
539 	}
540 	buf[st.st_size] = 0;
541 
542 	nadd = 0;
543 	for (i = 0; i < (size_t)st.st_size; ++i) {
544 		if (buf[i] == '\n' || buf[i] == 0) {
545 			buf[i] = 0;
546 			++nadd;
547 		}
548 	}
549 
550 	av = calloc(ac + nadd + 1, sizeof(char *));
551 
552 	for (n = 0; n < ac; ++n)
553 		av[n] = oldav[n];
554 
555 	nadd = 0;
556 	bi = 0;
557 	for (i = 0; i < (size_t)st.st_size; ++i) {
558 		if (buf[i] == 0) {
559 			av[ac + nadd] = buf + bi;
560 			bi = i + 1;
561 			++nadd;
562 		}
563 	}
564 
565 	printf("dsynth re-exec'ing additionally added packages\n");
566 	for (n = 0; n < ac + nadd; ++n)
567 		printf(" %s", av[n]);
568 	printf("\n");
569 	fflush(stdout);
570 	sleep(2);
571 	execv(DSynthExecPath, av);
572 }
573 
574 static void
575 DoInit(void)
576 {
577 	struct stat st;
578 	char *path;
579 	FILE *fp;
580 
581 	if (stat(ConfigBase1, &st) == 0) {
582 		dfatal("init will not overwrite %s", ConfigBase1);
583 	}
584 	if (stat(ConfigBase2, &st) == 0) {
585 		dfatal("init will not create %s if %s exists",
586 		       ConfigBase2, ConfigBase1);
587 	}
588 	if (mkdir(ConfigBase1, 0755) < 0)
589 		dfatal_errno("Unable to mkdir %s", ConfigBase1);
590 
591 	asprintf(&path, "%s/dsynth.ini", ConfigBase1);
592 	fp = fopen(path, "w");
593 	dassert_errno(fp, "Unable to create %s", path);
594 	fprintf(fp, "%s",
595 	    "; This Synth configuration file is automatically generated\n"
596 	    "; Take care when hand editing!\n"
597 	    "\n"
598 	    "[Global Configuration]\n"
599 	    "profile_selected= LiveSystem\n"
600 	    "\n"
601 	    "[LiveSystem]\n"
602 	    "Operating_system= DragonFly\n"
603 	    "Directory_packages= /build/synth/live_packages\n"
604 	    "Directory_repository= /build/synth/live_packages/All\n"
605 	    "Directory_portsdir= /build/synth/dports\n"
606 	    "Directory_options= /build/synth/options\n"
607 	    "Directory_distfiles= /build/synth/distfiles\n"
608 	    "Directory_buildbase= /build/synth/build\n"
609 	    "Directory_logs= /build/synth/logs\n"
610 	    "Directory_ccache= disabled\n"
611 	    "Directory_system= /\n"
612 	    "Package_suffix= .txz\n"
613 	    "Number_of_builders= 0\n"
614 	    "Max_jobs_per_builder= 0\n"
615 	    "Tmpfs_workdir= true\n"
616 	    "Tmpfs_localbase= true\n"
617 	    "Display_with_ncurses= true\n"
618 	    "leverage_prebuilt= false\n"
619 	    "; Meta_version= 2\n"
620 	    "; Check_plist= false\n"
621 	    "; Numa_setsize= 2\n"
622 	    "\n");
623 	if (fclose(fp))
624 		dfatal_errno("Unable to write to %s\n", ConfigBase1);
625 	free(path);
626 
627 	asprintf(&path, "%s/LiveSystem-make.conf", ConfigBase1);
628 	fp = fopen(path, "w");
629 	dassert_errno(fp, "Unable to create %s", path);
630 	fprintf(fp, "%s",
631 	    "#\n"
632 	    "# Various dports options that might be of interest\n"
633 	    "#\n"
634 	    "#LICENSES_ACCEPTED=      NONE\n"
635 	    "#DISABLE_LICENSES=       yes\n"
636 	    "#DEFAULT_VERSIONS=       ssl=openssl\n"
637 	    "#FORCE_PACKAGE=          yes\n"
638 	    "#DPORTS_BUILDER=         yes\n"
639 	    "#\n"
640 	    "# Turn these on to generate debug binaries.  However, these\n"
641 	    "# options will seriously bloat memory use and storage use,\n"
642 	    "# do not use lightly\n"
643 	    "#\n"
644 	    "#STRIP=\n"
645 	    "#WITH_DEBUG=yes\n"
646 	);
647 	if (fclose(fp))
648 		dfatal_errno("Unable to write to %s\n", ConfigBase1);
649 	free(path);
650 }
651 
652 __dead2 static void
653 usage(int ecode)
654 {
655 	if (ecode == 2) {
656 		fprintf(stderr, "Run 'dsynth help' for usage\n");
657 		exit(1);
658 	}
659 
660 	fprintf(stderr,
661     "dsynth [options] directive\n"
662     "    -d                   - Debug verbosity (-dd disables ncurses)\n"
663     "    -f                   - Force (for purge-distfiles)\n"
664     "    -h                   - Display this screen and exit\n"
665     "    -m gb                - Load management based on pkgdep memory\n"
666     "    -p profile           - Override profile selected in dsynth.ini\n"
667     "    -s n                 - Set initial DynamicMaxWorkers\n"
668     "    -v                   - Print version info and exit\n"
669     "    -x                   - Do not rebuild packages with dependencies\n"
670     "                           which require rebuilding\n"
671     "    -xx                  - Do not rebuild packages whos dports trees\n"
672     "                           change\n"
673     "    -y                   - Automatically answer yes to dsynth questions\n"
674     "    -D                   - Enable DEVELOPER mode\n"
675     "    -P                   - Include the check-plist stage\n"
676     "    -S                   - Disable ncurses\n"
677     "    -N                   - Do not nice-up sub-processes (else nice +10)\n"
678     "\n"
679     "    init                 - Initialize /etc/dsynth\n"
680     "    status               - Dry-run of 'upgrade-system'\n"
681     "    cleanup              - Clean-up mounts\n"
682     "    configure            - Bring up configuration menu\n"
683     "    list-system          - Just generate the build list to build.txt\n"
684     "    upgrade-system       - Incremental build and upgrade using pkg list\n"
685     "                           from local system, then upgrade the local\n"
686     "                           system.\n"
687     "    prepare-system       - 'upgrade-system' but stops after building\n"
688     "    rebuild-repository   - Rebuild database files for current repository\n"
689     "    purge-distfiles      - Delete obsolete source distribution files\n"
690     "    reset-db             - Delete ports_crc.db, regenerate next build\n"
691     "    status-everything    - Dry-run of 'everything'\n"
692     "    everything           - Build entire dports tree and repo database\n"
693     "				(-D everything infers -P)\n"
694     "    version              - Print version info and exit\n"
695     "    help                 - Display this screen and exit\n"
696     "    status     [ports]   - Dry-run of 'build' with given list\n"
697     "    build      [ports]   - Incrementally build dports based on the given\n"
698     "                           list, but asks before updating the repo\n"
699     "                           database and system\n"
700     "    just-build [ports]   - 'build' but skips post-build steps\n"
701     "    install    [ports]   - 'build' but upgrades system without asking\n"
702     "    force      [ports]   - 'build' but deletes existing packages first\n"
703     "    test       [ports]   - 'build' w/DEVELOPER=yes and pre-deletes pkgs\n"
704     "				(also infers -P)\n"
705     "    debug      [ports]   - like 'test' but leaves mounts intact\n"
706     "    fetch-only [ports]   - Fetch src dists only ('everything' ok)\n"
707     "    monitor    [datfile] - Monitor a running dsynth\n"
708     "\n"
709     "    [ports] is a space-delimited list of origins, e.g. editors/joe.  It\n"
710     "            may also be a path to a file containing one origin per line.\n"
711 	);
712 
713 	exit(ecode);
714 }
715