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