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