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