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