1 /* $NetBSD: main.c,v 1.111 2005/06/24 02:53:27 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 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 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 1989 by Berkeley Softworks 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Adam de Boor. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71 #ifndef MAKE_NATIVE 72 static char rcsid[] = "$NetBSD: main.c,v 1.111 2005/06/24 02:53:27 lukem Exp $"; 73 #else 74 #include <sys/cdefs.h> 75 #ifndef lint 76 __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993\n\ 77 The Regents of the University of California. All rights reserved.\n"); 78 #endif /* not lint */ 79 80 #ifndef lint 81 #if 0 82 static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; 83 #else 84 __RCSID("$NetBSD: main.c,v 1.111 2005/06/24 02:53:27 lukem Exp $"); 85 #endif 86 #endif /* not lint */ 87 #endif 88 89 /*- 90 * main.c -- 91 * The main file for this entire program. Exit routines etc 92 * reside here. 93 * 94 * Utility functions defined in this file: 95 * Main_ParseArgLine Takes a line of arguments, breaks them and 96 * treats them as if they were given when first 97 * invoked. Used by the parse module to implement 98 * the .MFLAGS target. 99 * 100 * Error Print a tagged error message. The global 101 * MAKE variable must have been defined. This 102 * takes a format string and two optional 103 * arguments for it. 104 * 105 * Fatal Print an error message and exit. Also takes 106 * a format string and two arguments. 107 * 108 * Punt Aborts all jobs and exits with a message. Also 109 * takes a format string and two arguments. 110 * 111 * Finish Finish things up by printing the number of 112 * errors which occurred, as passed to it, and 113 * exiting. 114 */ 115 116 #include <sys/types.h> 117 #include <sys/time.h> 118 #include <sys/param.h> 119 #include <sys/resource.h> 120 #include <sys/signal.h> 121 #include <sys/stat.h> 122 #ifdef MAKE_NATIVE 123 #include <sys/utsname.h> 124 #endif 125 #include <sys/wait.h> 126 127 #include <errno.h> 128 #include <fcntl.h> 129 #include <stdarg.h> 130 #include <stdio.h> 131 #include <stdlib.h> 132 #include <time.h> 133 134 #include "make.h" 135 #include "hash.h" 136 #include "dir.h" 137 #include "job.h" 138 #include "pathnames.h" 139 #include "trace.h" 140 141 #ifdef USE_IOVEC 142 #include <sys/uio.h> 143 #endif 144 145 #ifndef DEFMAXLOCAL 146 #define DEFMAXLOCAL DEFMAXJOBS 147 #endif /* DEFMAXLOCAL */ 148 149 Lst create; /* Targets to be made */ 150 time_t now; /* Time at start of make */ 151 GNode *DEFAULT; /* .DEFAULT node */ 152 Boolean allPrecious; /* .PRECIOUS given on line by itself */ 153 154 static Boolean noBuiltins; /* -r flag */ 155 static Lst makefiles; /* ordered list of makefiles to read */ 156 static Boolean printVars; /* print value of one or more vars */ 157 static Lst variables; /* list of variables to print */ 158 int maxJobs; /* -j argument */ 159 static int maxLocal; /* -L argument */ 160 Boolean compatMake; /* -B argument */ 161 Boolean debug; /* -d flag */ 162 Boolean noExecute; /* -n flag */ 163 Boolean noRecursiveExecute; /* -N flag */ 164 Boolean keepgoing; /* -k flag */ 165 Boolean queryFlag; /* -q flag */ 166 Boolean touchFlag; /* -t flag */ 167 Boolean usePipes; /* !-P flag */ 168 Boolean ignoreErrors; /* -i flag */ 169 Boolean beSilent; /* -s flag */ 170 Boolean oldVars; /* variable substitution style */ 171 Boolean checkEnvFirst; /* -e flag */ 172 Boolean parseWarnFatal; /* -W flag */ 173 Boolean jobServer; /* -J flag */ 174 Boolean varNoExportEnv; /* -X flag */ 175 static Boolean jobsRunning; /* TRUE if the jobs might be running */ 176 static const char * tracefile; 177 static char * Check_Cwd_av(int, char **, int); 178 static void MainParseArgs(int, char **); 179 static int ReadMakefile(ClientData, ClientData); 180 static void usage(void); 181 182 static char curdir[MAXPATHLEN + 1]; /* startup directory */ 183 static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ 184 char *progname; /* the program name */ 185 186 Boolean forceJobs = FALSE; 187 188 extern Lst parseIncPath; 189 190 /*- 191 * MainParseArgs -- 192 * Parse a given argument vector. Called from main() and from 193 * Main_ParseArgLine() when the .MAKEFLAGS target is used. 194 * 195 * XXX: Deal with command line overriding .MAKEFLAGS in makefile 196 * 197 * Results: 198 * None 199 * 200 * Side Effects: 201 * Various global and local flags will be set depending on the flags 202 * given 203 */ 204 static void 205 MainParseArgs(int argc, char **argv) 206 { 207 char *p; 208 int c; 209 int arginc; 210 char *argvalue; 211 const char *getopt_def; 212 char *optscan; 213 Boolean inOption, dashDash = FALSE; 214 char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 215 216 #ifdef REMOTE 217 # define OPTFLAGS "BD:I:J:L:NPST:V:WXd:ef:ij:km:nqrst" 218 #else 219 # define OPTFLAGS "BD:I:J:NPST:V:WXd:ef:ij:km:nqrst" 220 #endif 221 #undef optarg 222 #define optarg argvalue 223 /* Can't actually use getopt(3) because rescanning is not portable */ 224 225 getopt_def = OPTFLAGS; 226 rearg: 227 inOption = FALSE; 228 optscan = NULL; 229 while(argc > 1) { 230 char *getopt_spec; 231 if(!inOption) 232 optscan = argv[1]; 233 c = *optscan++; 234 arginc = 0; 235 if(inOption) { 236 if(c == '\0') { 237 ++argv; 238 --argc; 239 inOption = FALSE; 240 continue; 241 } 242 } else { 243 if (c != '-' || dashDash) 244 break; 245 inOption = TRUE; 246 c = *optscan++; 247 } 248 /* '-' found at some earlier point */ 249 getopt_spec = strchr(getopt_def, c); 250 if(c != '\0' && getopt_spec != NULL && getopt_spec[1] == ':') { 251 /* -<something> found, and <something> should have an arg */ 252 inOption = FALSE; 253 arginc = 1; 254 argvalue = optscan; 255 if(*argvalue == '\0') { 256 if (argc < 3) { 257 (void)fprintf(stderr, 258 "%s: option requires " 259 "an argument -- %c\n", 260 progname, c); 261 usage(); 262 } 263 argvalue = argv[2]; 264 arginc = 2; 265 } 266 } else { 267 argvalue = NULL; 268 } 269 switch(c) { 270 case '\0': 271 arginc = 1; 272 inOption = FALSE; 273 break; 274 case 'B': 275 compatMake = TRUE; 276 Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 277 break; 278 case 'D': 279 Var_Set(optarg, "1", VAR_GLOBAL, 0); 280 Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 281 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 282 break; 283 case 'I': 284 Parse_AddIncludeDir(optarg); 285 Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 286 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 287 break; 288 case 'J': 289 if (sscanf(optarg, "%d,%d", &job_pipe[0], &job_pipe[1]) != 2) { 290 /* backslash to avoid trigraph ??) */ 291 (void)fprintf(stderr, 292 "%s: internal error -- J option malformed (%s?\?)\n", 293 progname, optarg); 294 usage(); 295 } 296 if ((fcntl(job_pipe[0], F_GETFD, 0) < 0) || 297 (fcntl(job_pipe[1], F_GETFD, 0) < 0)) { 298 #if 0 299 (void)fprintf(stderr, 300 "%s: warning -- J descriptors were closed!\n", 301 progname); 302 #endif 303 job_pipe[0] = -1; 304 job_pipe[1] = -1; 305 compatMake = TRUE; 306 } else { 307 Var_Append(MAKEFLAGS, "-J", VAR_GLOBAL); 308 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 309 jobServer = TRUE; 310 } 311 break; 312 #ifdef REMOTE 313 case 'L': 314 maxLocal = strtol(optarg, &p, 0); 315 if (*p != '\0' || maxLocal < 1) { 316 (void) fprintf(stderr, "%s: illegal argument to -L -- must be positive integer!\n", 317 progname); 318 exit(1); 319 } 320 Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL); 321 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 322 break; 323 #endif 324 case 'N': 325 noExecute = TRUE; 326 noRecursiveExecute = TRUE; 327 Var_Append(MAKEFLAGS, "-N", VAR_GLOBAL); 328 break; 329 case 'P': 330 usePipes = FALSE; 331 Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL); 332 break; 333 case 'S': 334 keepgoing = FALSE; 335 Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 336 break; 337 case 'T': 338 tracefile = estrdup(optarg); 339 Var_Append(MAKEFLAGS, "-T", VAR_GLOBAL); 340 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 341 break; 342 case 'V': 343 printVars = TRUE; 344 (void)Lst_AtEnd(variables, (ClientData)optarg); 345 Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 346 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 347 break; 348 case 'W': 349 parseWarnFatal = TRUE; 350 break; 351 case 'X': 352 varNoExportEnv = TRUE; 353 Var_Append(MAKEFLAGS, "-X", VAR_GLOBAL); 354 break; 355 case 'd': { 356 char *modules = optarg; 357 358 for (; *modules; ++modules) 359 switch (*modules) { 360 case 'A': 361 debug = ~0; 362 break; 363 case 'a': 364 debug |= DEBUG_ARCH; 365 break; 366 case 'c': 367 debug |= DEBUG_COND; 368 break; 369 case 'd': 370 debug |= DEBUG_DIR; 371 break; 372 case 'e': 373 debug |= DEBUG_ERROR; 374 break; 375 case 'f': 376 debug |= DEBUG_FOR; 377 break; 378 case 'g': 379 if (modules[1] == '1') { 380 debug |= DEBUG_GRAPH1; 381 ++modules; 382 } 383 else if (modules[1] == '2') { 384 debug |= DEBUG_GRAPH2; 385 ++modules; 386 } 387 else if (modules[1] == '3') { 388 debug |= DEBUG_GRAPH3; 389 ++modules; 390 } 391 break; 392 case 'j': 393 debug |= DEBUG_JOB; 394 break; 395 case 'm': 396 debug |= DEBUG_MAKE; 397 break; 398 case 'n': 399 debug |= DEBUG_SCRIPT; 400 break; 401 case 's': 402 debug |= DEBUG_SUFF; 403 break; 404 case 't': 405 debug |= DEBUG_TARG; 406 break; 407 case 'v': 408 debug |= DEBUG_VAR; 409 break; 410 case 'x': 411 debug |= DEBUG_SHELL; 412 break; 413 default: 414 (void)fprintf(stderr, 415 "%s: illegal argument to d option -- %c\n", 416 progname, *modules); 417 usage(); 418 } 419 Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 420 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 421 break; 422 } 423 case 'e': 424 checkEnvFirst = TRUE; 425 Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 426 break; 427 case 'f': 428 (void)Lst_AtEnd(makefiles, (ClientData)optarg); 429 break; 430 case 'i': 431 ignoreErrors = TRUE; 432 Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 433 break; 434 case 'j': 435 forceJobs = TRUE; 436 maxJobs = strtol(optarg, &p, 0); 437 if (*p != '\0' || maxJobs < 1) { 438 (void) fprintf(stderr, "%s: illegal argument to -j -- must be positive integer!\n", 439 progname); 440 exit(1); 441 } 442 #ifndef REMOTE 443 maxLocal = maxJobs; 444 #endif 445 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 446 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 447 break; 448 case 'k': 449 keepgoing = TRUE; 450 Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 451 break; 452 case 'm': 453 /* look for magic parent directory search string */ 454 if (strncmp(".../", optarg, 4) == 0) { 455 if (!Dir_FindHereOrAbove(curdir, optarg+4, 456 found_path, sizeof(found_path))) 457 break; /* nothing doing */ 458 (void) Dir_AddDir(sysIncPath, found_path); 459 460 } else { 461 (void) Dir_AddDir(sysIncPath, optarg); 462 } 463 Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 464 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 465 break; 466 case 'n': 467 noExecute = TRUE; 468 Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 469 break; 470 case 'q': 471 queryFlag = TRUE; 472 /* Kind of nonsensical, wot? */ 473 Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 474 break; 475 case 'r': 476 noBuiltins = TRUE; 477 Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 478 break; 479 case 's': 480 beSilent = TRUE; 481 Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 482 break; 483 case 't': 484 touchFlag = TRUE; 485 Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 486 break; 487 case '-': 488 dashDash = TRUE; 489 break; 490 default: 491 case '?': 492 usage(); 493 } 494 argv += arginc; 495 argc -= arginc; 496 } 497 498 oldVars = TRUE; 499 500 /* 501 * See if the rest of the arguments are variable assignments and 502 * perform them if so. Else take them to be targets and stuff them 503 * on the end of the "create" list. 504 */ 505 for (; argc > 1; ++argv, --argc) 506 if (Parse_IsVar(argv[1])) { 507 Parse_DoVar(argv[1], VAR_CMD); 508 } else { 509 if (!*argv[1]) 510 Punt("illegal (null) argument."); 511 if (*argv[1] == '-' && !dashDash) 512 goto rearg; 513 (void)Lst_AtEnd(create, (ClientData)estrdup(argv[1])); 514 } 515 } 516 517 /*- 518 * Main_ParseArgLine -- 519 * Used by the parse module when a .MFLAGS or .MAKEFLAGS target 520 * is encountered and by main() when reading the .MAKEFLAGS envariable. 521 * Takes a line of arguments and breaks it into its 522 * component words and passes those words and the number of them to the 523 * MainParseArgs function. 524 * The line should have all its leading whitespace removed. 525 * 526 * Input: 527 * line Line to fracture 528 * 529 * Results: 530 * None 531 * 532 * Side Effects: 533 * Only those that come from the various arguments. 534 */ 535 void 536 Main_ParseArgLine(char *line) 537 { 538 char **argv; /* Manufactured argument vector */ 539 int argc; /* Number of arguments in argv */ 540 char *args; /* Space used by the args */ 541 char *buf, *p1; 542 char *argv0 = Var_Value(".MAKE", VAR_GLOBAL, &p1); 543 size_t len; 544 545 if (line == NULL) 546 return; 547 for (; *line == ' '; ++line) 548 continue; 549 if (!*line) 550 return; 551 552 buf = emalloc(len = strlen(line) + strlen(argv0) + 2); 553 (void)snprintf(buf, len, "%s %s", argv0, line); 554 if (p1) 555 free(p1); 556 557 argv = brk_string(buf, &argc, TRUE, &args); 558 free(buf); 559 MainParseArgs(argc, argv); 560 561 free(args); 562 free(argv); 563 } 564 565 Boolean 566 Main_SetObjdir(const char *path) 567 { 568 struct stat sb; 569 char *p = NULL; 570 char buf[MAXPATHLEN + 1]; 571 Boolean rc = FALSE; 572 573 /* expand variable substitutions */ 574 if (strchr(path, '$') != 0) { 575 snprintf(buf, MAXPATHLEN, "%s", path); 576 path = p = Var_Subst(NULL, buf, VAR_GLOBAL, 0); 577 } 578 579 if (path[0] != '/') { 580 snprintf(buf, MAXPATHLEN, "%s/%s", curdir, path); 581 path = buf; 582 } 583 584 /* look for the directory and try to chdir there */ 585 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 586 if (chdir(path)) { 587 (void)fprintf(stderr, "make warning: %s: %s.\n", 588 path, strerror(errno)); 589 } else { 590 strncpy(objdir, path, MAXPATHLEN); 591 Var_Set(".OBJDIR", objdir, VAR_GLOBAL, 0); 592 setenv("PWD", objdir, 1); 593 Dir_InitDot(); 594 rc = TRUE; 595 } 596 } 597 598 if (p) 599 free(p); 600 return rc; 601 } 602 603 604 /*- 605 * main -- 606 * The main function, for obvious reasons. Initializes variables 607 * and a few modules, then parses the arguments give it in the 608 * environment and on the command line. Reads the system makefile 609 * followed by either Makefile, makefile or the file given by the 610 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 611 * flags it has received by then uses either the Make or the Compat 612 * module to create the initial list of targets. 613 * 614 * Results: 615 * If -q was given, exits -1 if anything was out-of-date. Else it exits 616 * 0. 617 * 618 * Side Effects: 619 * The program exits when done. Targets are created. etc. etc. etc. 620 */ 621 int 622 main(int argc, char **argv) 623 { 624 Lst targs; /* target nodes to create -- passed to Make_Init */ 625 Boolean outOfDate = TRUE; /* FALSE if all targets up to date */ 626 struct stat sb, sa; 627 char *p1, *path, *pwd; 628 char mdpath[MAXPATHLEN]; 629 char *machine = getenv("MACHINE"); 630 const char *machine_arch = getenv("MACHINE_ARCH"); 631 char *syspath = getenv("MAKESYSPATH"); 632 Lst sysMkPath; /* Path of sys.mk */ 633 char *cp = NULL, *start; 634 /* avoid faults on read-only strings */ 635 static char defsyspath[] = _PATH_DEFSYSPATH; 636 char found_path[MAXPATHLEN + 1]; /* for searching for sys.mk */ 637 struct timeval rightnow; /* to initialize random seed */ 638 639 /* 640 * Set the seed to produce a different random sequences 641 * on each program execution. 642 */ 643 gettimeofday(&rightnow, NULL); 644 srandom(rightnow.tv_sec + rightnow.tv_usec); 645 646 if ((progname = strrchr(argv[0], '/')) != NULL) 647 progname++; 648 else 649 progname = argv[0]; 650 #ifdef RLIMIT_NOFILE 651 /* 652 * get rid of resource limit on file descriptors 653 */ 654 { 655 struct rlimit rl; 656 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 657 rl.rlim_cur != rl.rlim_max) { 658 rl.rlim_cur = rl.rlim_max; 659 (void) setrlimit(RLIMIT_NOFILE, &rl); 660 } 661 } 662 #endif 663 /* 664 * Find where we are and take care of PWD for the automounter... 665 * All this code is so that we know where we are when we start up 666 * on a different machine with pmake. 667 */ 668 if (getcwd(curdir, MAXPATHLEN) == NULL) { 669 (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 670 exit(2); 671 } 672 673 if (stat(curdir, &sa) == -1) { 674 (void)fprintf(stderr, "%s: %s: %s.\n", 675 progname, curdir, strerror(errno)); 676 exit(2); 677 } 678 679 /* 680 * Overriding getcwd() with $PWD totally breaks MAKEOBJDIRPREFIX 681 * since the value of curdir can very depending on how we got 682 * here. Ie sitting at a shell prompt (shell that provides $PWD) 683 * or via subdir.mk in which case its likely a shell which does 684 * not provide it. 685 * So, to stop it breaking this case only, we ignore PWD if 686 * MAKEOBJDIRPREFIX is set or MAKEOBJDIR contains a transform. 687 */ 688 if ((pwd = getenv("PWD")) != NULL && getenv("MAKEOBJDIRPREFIX") == NULL) { 689 const char *makeobjdir = getenv("MAKEOBJDIR"); 690 691 if (makeobjdir == NULL || !strchr(makeobjdir, '$')) { 692 if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino && 693 sa.st_dev == sb.st_dev) 694 (void) strncpy(curdir, pwd, MAXPATHLEN); 695 } 696 } 697 698 /* 699 * Get the name of this type of MACHINE from utsname 700 * so we can share an executable for similar machines. 701 * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 702 * 703 * Note that both MACHINE and MACHINE_ARCH are decided at 704 * run-time. 705 */ 706 if (!machine) { 707 #ifdef MAKE_NATIVE 708 struct utsname utsname; 709 710 if (uname(&utsname) == -1) { 711 (void)fprintf(stderr, "%s: uname failed (%s).\n", progname, 712 strerror(errno)); 713 exit(2); 714 } 715 machine = utsname.machine; 716 #else 717 #ifdef MAKE_MACHINE 718 machine = MAKE_MACHINE; 719 #else 720 machine = "unknown"; 721 #endif 722 #endif 723 } 724 725 if (!machine_arch) { 726 #ifndef MACHINE_ARCH 727 #ifdef MAKE_MACHINE_ARCH 728 machine_arch = MAKE_MACHINE_ARCH; 729 #else 730 machine_arch = "unknown"; 731 #endif 732 #else 733 machine_arch = MACHINE_ARCH; 734 #endif 735 } 736 737 /* 738 * Just in case MAKEOBJDIR wants us to do something tricky. 739 */ 740 Var_Init(); /* Initialize the lists of variables for 741 * parsing arguments */ 742 Var_Set(".CURDIR", curdir, VAR_GLOBAL, 0); 743 Var_Set("MACHINE", machine, VAR_GLOBAL, 0); 744 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL, 0); 745 #ifdef MAKE_VERSION 746 Var_Set("MAKE_VERSION", MAKE_VERSION, VAR_GLOBAL, 0); 747 #endif 748 Var_Set(".newline", "\n", VAR_GLOBAL, 0); /* handy for :@ loops */ 749 750 /* 751 * Find the .OBJDIR. If MAKEOBJDIRPREFIX, or failing that, 752 * MAKEOBJDIR is set in the environment, try only that value 753 * and fall back to .CURDIR if it does not exist. 754 * 755 * Otherwise, try _PATH_OBJDIR.MACHINE, _PATH_OBJDIR, and 756 * finally _PATH_OBJDIRPREFIX`pwd`, in that order. If none 757 * of these paths exist, just use .CURDIR. 758 */ 759 Dir_Init(curdir); 760 (void) Main_SetObjdir(curdir); 761 762 if ((path = getenv("MAKEOBJDIRPREFIX")) != NULL) { 763 (void) snprintf(mdpath, MAXPATHLEN, "%s%s", path, curdir); 764 (void) Main_SetObjdir(mdpath); 765 } else if ((path = getenv("MAKEOBJDIR")) != NULL) { 766 (void) Main_SetObjdir(path); 767 } else { 768 (void) snprintf(mdpath, MAXPATHLEN, "%s.%s", _PATH_OBJDIR, machine); 769 if (!Main_SetObjdir(mdpath) && !Main_SetObjdir(_PATH_OBJDIR)) { 770 (void) snprintf(mdpath, MAXPATHLEN, "%s%s", 771 _PATH_OBJDIRPREFIX, curdir); 772 (void) Main_SetObjdir(mdpath); 773 } 774 } 775 776 create = Lst_Init(FALSE); 777 makefiles = Lst_Init(FALSE); 778 printVars = FALSE; 779 variables = Lst_Init(FALSE); 780 beSilent = FALSE; /* Print commands as executed */ 781 ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 782 noExecute = FALSE; /* Execute all commands */ 783 noRecursiveExecute = FALSE; /* Execute all .MAKE targets */ 784 keepgoing = FALSE; /* Stop on error */ 785 allPrecious = FALSE; /* Remove targets when interrupted */ 786 queryFlag = FALSE; /* This is not just a check-run */ 787 noBuiltins = FALSE; /* Read the built-in rules */ 788 touchFlag = FALSE; /* Actually update targets */ 789 usePipes = TRUE; /* Catch child output in pipes */ 790 debug = 0; /* No debug verbosity, please. */ 791 jobsRunning = FALSE; 792 793 maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */ 794 #ifdef REMOTE 795 maxJobs = DEFMAXJOBS; /* Set default max concurrency */ 796 #else 797 maxJobs = maxLocal; 798 #endif 799 compatMake = FALSE; /* No compat mode */ 800 801 802 /* 803 * Initialize the parsing, directory and variable modules to prepare 804 * for the reading of inclusion paths and variable settings on the 805 * command line 806 */ 807 808 /* 809 * Initialize various variables. 810 * MAKE also gets this name, for compatibility 811 * .MAKEFLAGS gets set to the empty string just in case. 812 * MFLAGS also gets initialized empty, for compatibility. 813 */ 814 Parse_Init(); 815 Var_Set("MAKE", argv[0], VAR_GLOBAL, 0); 816 Var_Set(".MAKE", argv[0], VAR_GLOBAL, 0); 817 Var_Set(MAKEFLAGS, "", VAR_GLOBAL, 0); 818 Var_Set(MAKEOVERRIDES, "", VAR_GLOBAL, 0); 819 Var_Set("MFLAGS", "", VAR_GLOBAL, 0); 820 Var_Set(".ALLTARGETS", "", VAR_GLOBAL, 0); 821 822 /* 823 * First snag any flags out of the MAKE environment variable. 824 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 825 * in a different format). 826 */ 827 #ifdef POSIX 828 Main_ParseArgLine(getenv("MAKEFLAGS")); 829 #else 830 Main_ParseArgLine(getenv("MAKE")); 831 #endif 832 833 MainParseArgs(argc, argv); 834 835 /* 836 * Be compatible if user did not specify -j and did not explicitly 837 * turned compatibility on 838 */ 839 if (!compatMake && !forceJobs) { 840 compatMake = TRUE; 841 } 842 843 /* 844 * Initialize archive, target and suffix modules in preparation for 845 * parsing the makefile(s) 846 */ 847 Arch_Init(); 848 Targ_Init(); 849 Suff_Init(); 850 Trace_Init(tracefile); 851 852 DEFAULT = NILGNODE; 853 (void)time(&now); 854 855 Trace_Log(MAKESTART, NULL); 856 857 /* 858 * Set up the .TARGETS variable to contain the list of targets to be 859 * created. If none specified, make the variable empty -- the parser 860 * will fill the thing in with the default or .MAIN target. 861 */ 862 if (!Lst_IsEmpty(create)) { 863 LstNode ln; 864 865 for (ln = Lst_First(create); ln != NILLNODE; 866 ln = Lst_Succ(ln)) { 867 char *name = (char *)Lst_Datum(ln); 868 869 Var_Append(".TARGETS", name, VAR_GLOBAL); 870 } 871 } else 872 Var_Set(".TARGETS", "", VAR_GLOBAL, 0); 873 874 875 /* 876 * If no user-supplied system path was given (through the -m option) 877 * add the directories from the DEFSYSPATH (more than one may be given 878 * as dir1:...:dirn) to the system include path. 879 */ 880 if (syspath == NULL || *syspath == '\0') 881 syspath = defsyspath; 882 else 883 syspath = strdup(syspath); 884 885 for (start = syspath; *start != '\0'; start = cp) { 886 for (cp = start; *cp != '\0' && *cp != ':'; cp++) 887 continue; 888 if (*cp == ':') { 889 *cp++ = '\0'; 890 } 891 /* look for magic parent directory search string */ 892 if (strncmp(".../", start, 4) != 0) { 893 (void) Dir_AddDir(defIncPath, start); 894 } else { 895 if (Dir_FindHereOrAbove(curdir, start+4, 896 found_path, sizeof(found_path))) { 897 (void) Dir_AddDir(defIncPath, found_path); 898 } 899 } 900 } 901 if (syspath != defsyspath) 902 free(syspath); 903 904 /* 905 * Read in the built-in rules first, followed by the specified 906 * makefile, if it was (makefile != (char *) NULL), or the default 907 * makefile and Makefile, in that order, if it wasn't. 908 */ 909 if (!noBuiltins) { 910 LstNode ln; 911 912 sysMkPath = Lst_Init(FALSE); 913 Dir_Expand(_PATH_DEFSYSMK, 914 Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath, 915 sysMkPath); 916 if (Lst_IsEmpty(sysMkPath)) 917 Fatal("%s: no system rules (%s).", progname, 918 _PATH_DEFSYSMK); 919 ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile); 920 if (ln != NILLNODE) 921 Fatal("%s: cannot open %s.", progname, 922 (char *)Lst_Datum(ln)); 923 } 924 925 if (!Lst_IsEmpty(makefiles)) { 926 LstNode ln; 927 928 ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile); 929 if (ln != NILLNODE) 930 Fatal("%s: cannot open %s.", progname, 931 (char *)Lst_Datum(ln)); 932 } else if (!ReadMakefile(UNCONST("makefile"), NULL)) 933 (void)ReadMakefile(UNCONST("Makefile"), NULL); 934 935 (void)ReadMakefile(UNCONST(".depend"), NULL); 936 937 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 938 if (p1) 939 free(p1); 940 941 if (!jobServer && !compatMake) 942 Job_ServerStart(maxJobs); 943 if (DEBUG(JOB)) 944 printf("job_pipe %d %d, maxjobs %d maxlocal %d compat %d\n", job_pipe[0], job_pipe[1], maxJobs, 945 maxLocal, compatMake); 946 947 Main_ExportMAKEFLAGS(TRUE); /* initial export */ 948 949 Check_Cwd_av(0, NULL, 0); /* initialize it */ 950 951 952 /* 953 * For compatibility, look at the directories in the VPATH variable 954 * and add them to the search path, if the variable is defined. The 955 * variable's value is in the same format as the PATH envariable, i.e. 956 * <directory>:<directory>:<directory>... 957 */ 958 if (Var_Exists("VPATH", VAR_CMD)) { 959 char *vpath, savec; 960 /* 961 * GCC stores string constants in read-only memory, but 962 * Var_Subst will want to write this thing, so store it 963 * in an array 964 */ 965 static char VPATH[] = "${VPATH}"; 966 967 vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE); 968 path = vpath; 969 do { 970 /* skip to end of directory */ 971 for (cp = path; *cp != ':' && *cp != '\0'; cp++) 972 continue; 973 /* Save terminator character so know when to stop */ 974 savec = *cp; 975 *cp = '\0'; 976 /* Add directory to search path */ 977 (void) Dir_AddDir(dirSearchPath, path); 978 *cp = savec; 979 path = cp + 1; 980 } while (savec == ':'); 981 (void)free((Address)vpath); 982 } 983 984 /* 985 * Now that all search paths have been read for suffixes et al, it's 986 * time to add the default search path to their lists... 987 */ 988 Suff_DoPaths(); 989 990 /* 991 * Propagate attributes through :: dependency lists. 992 */ 993 Targ_Propagate(); 994 995 /* print the initial graph, if the user requested it */ 996 if (DEBUG(GRAPH1)) 997 Targ_PrintGraph(1); 998 999 /* print the values of any variables requested by the user */ 1000 if (printVars) { 1001 LstNode ln; 1002 1003 for (ln = Lst_First(variables); ln != NILLNODE; 1004 ln = Lst_Succ(ln)) { 1005 char *var = (char *)Lst_Datum(ln); 1006 char *value; 1007 1008 if (strchr(var, '$')) { 1009 value = p1 = Var_Subst(NULL, var, VAR_GLOBAL, 0); 1010 } else { 1011 value = Var_Value(var, VAR_GLOBAL, &p1); 1012 } 1013 printf("%s\n", value ? value : ""); 1014 if (p1) 1015 free(p1); 1016 } 1017 } 1018 1019 /* 1020 * Have now read the entire graph and need to make a list of targets 1021 * to create. If none was given on the command line, we consult the 1022 * parsing module to find the main target(s) to create. 1023 */ 1024 if (Lst_IsEmpty(create)) 1025 targs = Parse_MainName(); 1026 else 1027 targs = Targ_FindList(create, TARG_CREATE); 1028 1029 if (!compatMake && !printVars) { 1030 /* 1031 * Initialize job module before traversing the graph, now that 1032 * any .BEGIN and .END targets have been read. This is done 1033 * only if the -q flag wasn't given (to prevent the .BEGIN from 1034 * being executed should it exist). 1035 */ 1036 if (!queryFlag) { 1037 if (maxLocal == -1) 1038 maxLocal = maxJobs; 1039 Job_Init(maxJobs, maxLocal); 1040 jobsRunning = TRUE; 1041 } 1042 1043 /* Traverse the graph, checking on all the targets */ 1044 outOfDate = Make_Run(targs); 1045 } else if (!printVars) { 1046 /* 1047 * Compat_Init will take care of creating all the targets as 1048 * well as initializing the module. 1049 */ 1050 Compat_Run(targs); 1051 } 1052 1053 #ifdef CLEANUP 1054 Lst_Destroy(targs, NOFREE); 1055 Lst_Destroy(variables, NOFREE); 1056 Lst_Destroy(makefiles, NOFREE); 1057 Lst_Destroy(create, (void (*)(ClientData))) free; 1058 #endif 1059 1060 /* print the graph now it's been processed if the user requested it */ 1061 if (DEBUG(GRAPH2)) 1062 Targ_PrintGraph(2); 1063 1064 Trace_Log(MAKEEND, 0); 1065 1066 Suff_End(); 1067 Targ_End(); 1068 Arch_End(); 1069 Var_End(); 1070 Parse_End(); 1071 Dir_End(); 1072 Job_End(); 1073 Trace_End(); 1074 1075 if (queryFlag && outOfDate) 1076 return(1); 1077 else 1078 return(0); 1079 } 1080 1081 /*- 1082 * ReadMakefile -- 1083 * Open and parse the given makefile. 1084 * 1085 * Results: 1086 * TRUE if ok. FALSE if couldn't open file. 1087 * 1088 * Side Effects: 1089 * lots 1090 */ 1091 static Boolean 1092 ReadMakefile(ClientData p, ClientData q __unused) 1093 { 1094 char *fname = p; /* makefile to read */ 1095 FILE *stream; 1096 size_t len = MAXPATHLEN; 1097 char *name, *path = emalloc(len); 1098 int setMAKEFILE; 1099 1100 if (!strcmp(fname, "-")) { 1101 Parse_File("(stdin)", stdin); 1102 Var_Set("MAKEFILE", "", VAR_GLOBAL, 0); 1103 } else { 1104 setMAKEFILE = strcmp(fname, ".depend"); 1105 1106 /* if we've chdir'd, rebuild the path name */ 1107 if (strcmp(curdir, objdir) && *fname != '/') { 1108 size_t plen = strlen(curdir) + strlen(fname) + 2; 1109 if (len < plen) 1110 path = erealloc(path, len = 2 * plen); 1111 1112 (void)snprintf(path, len, "%s/%s", curdir, fname); 1113 if ((stream = fopen(path, "r")) != NULL) { 1114 fname = path; 1115 goto found; 1116 } 1117 1118 /* If curdir failed, try objdir (ala .depend) */ 1119 plen = strlen(objdir) + strlen(fname) + 2; 1120 if (len < plen) 1121 path = erealloc(path, len = 2 * plen); 1122 (void)snprintf(path, len, "%s/%s", objdir, fname); 1123 if ((stream = fopen(path, "r")) != NULL) { 1124 fname = path; 1125 goto found; 1126 } 1127 } else if ((stream = fopen(fname, "r")) != NULL) 1128 goto found; 1129 /* look in -I and system include directories. */ 1130 name = Dir_FindFile(fname, parseIncPath); 1131 if (!name) 1132 name = Dir_FindFile(fname, 1133 Lst_IsEmpty(sysIncPath) ? defIncPath : sysIncPath); 1134 if (!name || !(stream = fopen(name, "r"))) { 1135 free(path); 1136 return(FALSE); 1137 } 1138 fname = name; 1139 /* 1140 * set the MAKEFILE variable desired by System V fans -- the 1141 * placement of the setting here means it gets set to the last 1142 * makefile specified, as it is set by SysV make. 1143 */ 1144 found: 1145 if (setMAKEFILE) 1146 Var_Set("MAKEFILE", fname, VAR_GLOBAL, 0); 1147 Parse_File(fname, stream); 1148 (void)fclose(stream); 1149 } 1150 free(path); 1151 return(TRUE); 1152 } 1153 1154 1155 /* 1156 * If MAKEOBJDIRPREFIX is in use, make ends up not in .CURDIR 1157 * in situations that would not arrise with ./obj (links or not). 1158 * This tends to break things like: 1159 * 1160 * build: 1161 * ${MAKE} includes 1162 * 1163 * This function spots when ${.MAKE:T} or ${.MAKE} is a command (as 1164 * opposed to an argument) in a command line and if so returns 1165 * ${.CURDIR} so caller can chdir() so that the assumptions made by 1166 * the Makefile hold true. 1167 * 1168 * If ${.MAKE} does not contain any '/', then ${.MAKE:T} is skipped. 1169 * 1170 * The chdir() only happens in the child process, and does nothing if 1171 * MAKEOBJDIRPREFIX and MAKEOBJDIR are not in the environment so it 1172 * should not break anything. Also if NOCHECKMAKECHDIR is set we 1173 * do nothing - to ensure historic semantics can be retained. 1174 */ 1175 static int Check_Cwd_Off = 0; 1176 1177 static char * 1178 Check_Cwd_av(int ac, char **av, int copy) 1179 { 1180 static char *make[4]; 1181 static char *cur_dir = NULL; 1182 char **mp; 1183 char *cp; 1184 int is_cmd, next_cmd; 1185 int i; 1186 int n; 1187 1188 if (Check_Cwd_Off) 1189 return NULL; 1190 1191 if (make[0] == NULL) { 1192 if (Var_Exists("NOCHECKMAKECHDIR", VAR_GLOBAL)) { 1193 Check_Cwd_Off = 1; 1194 return NULL; 1195 } 1196 1197 make[1] = Var_Value(".MAKE", VAR_GLOBAL, &cp); 1198 if ((make[0] = strrchr(make[1], '/')) == NULL) { 1199 make[0] = make[1]; 1200 make[1] = NULL; 1201 } else 1202 ++make[0]; 1203 make[2] = NULL; 1204 cur_dir = Var_Value(".CURDIR", VAR_GLOBAL, &cp); 1205 } 1206 if (ac == 0 || av == NULL) 1207 return NULL; /* initialization only */ 1208 1209 if (getenv("MAKEOBJDIR") == NULL && 1210 getenv("MAKEOBJDIRPREFIX") == NULL) 1211 return NULL; 1212 1213 1214 next_cmd = 1; 1215 for (i = 0; i < ac; ++i) { 1216 is_cmd = next_cmd; 1217 1218 n = strlen(av[i]); 1219 cp = &(av[i])[n - 1]; 1220 if (strspn(av[i], "|&;") == n) { 1221 next_cmd = 1; 1222 continue; 1223 } else if (*cp == ';' || *cp == '&' || *cp == '|' || *cp == ')') { 1224 next_cmd = 1; 1225 if (copy) { 1226 do { 1227 *cp-- = '\0'; 1228 } while (*cp == ';' || *cp == '&' || *cp == '|' || 1229 *cp == ')' || *cp == '}') ; 1230 } else { 1231 /* 1232 * XXX this should not happen. 1233 */ 1234 fprintf(stderr, "WARNING: raw arg ends in shell meta '%s'\n", 1235 av[i]); 1236 } 1237 } else 1238 next_cmd = 0; 1239 1240 cp = av[i]; 1241 if (*cp == ';' || *cp == '&' || *cp == '|') 1242 is_cmd = 1; 1243 1244 #ifdef check_cwd_debug 1245 fprintf(stderr, "av[%d] == %s '%s'", 1246 i, (is_cmd) ? "cmd" : "arg", av[i]); 1247 #endif 1248 if (is_cmd != 0) { 1249 if (*cp == '(' || *cp == '{' || 1250 *cp == ';' || *cp == '&' || *cp == '|') { 1251 do { 1252 ++cp; 1253 } while (*cp == '(' || *cp == '{' || 1254 *cp == ';' || *cp == '&' || *cp == '|'); 1255 if (*cp == '\0') { 1256 next_cmd = 1; 1257 continue; 1258 } 1259 } 1260 if (strcmp(cp, "cd") == 0 || strcmp(cp, "chdir") == 0) { 1261 #ifdef check_cwd_debug 1262 fprintf(stderr, " == cd, done.\n"); 1263 #endif 1264 return NULL; 1265 } 1266 for (mp = make; *mp != NULL; ++mp) { 1267 n = strlen(*mp); 1268 if (strcmp(cp, *mp) == 0) { 1269 #ifdef check_cwd_debug 1270 fprintf(stderr, " %s == '%s', chdir(%s)\n", 1271 cp, *mp, cur_dir); 1272 #endif 1273 return cur_dir; 1274 } 1275 } 1276 } 1277 #ifdef check_cwd_debug 1278 fprintf(stderr, "\n"); 1279 #endif 1280 } 1281 return NULL; 1282 } 1283 1284 char * 1285 Check_Cwd_Cmd(const char *cmd) 1286 { 1287 char *cp, *bp; 1288 char **av; 1289 int ac; 1290 1291 if (Check_Cwd_Off) 1292 return NULL; 1293 1294 if (cmd) { 1295 av = brk_string(cmd, &ac, TRUE, &bp); 1296 #ifdef check_cwd_debug 1297 fprintf(stderr, "splitting: '%s' -> %d words\n", 1298 cmd, ac); 1299 #endif 1300 } else { 1301 ac = 0; 1302 av = NULL; 1303 bp = NULL; 1304 } 1305 cp = Check_Cwd_av(ac, av, 1); 1306 if (bp) { 1307 free(av); 1308 free(bp); 1309 } 1310 return cp; 1311 } 1312 1313 void 1314 Check_Cwd(const char **argv) 1315 { 1316 char *cp; 1317 int ac; 1318 1319 if (Check_Cwd_Off) 1320 return; 1321 1322 for (ac = 0; argv[ac] != NULL; ++ac) 1323 /* NOTHING */; 1324 if (ac == 3 && *argv[1] == '-') { 1325 cp = Check_Cwd_Cmd(argv[2]); 1326 } else { 1327 cp = Check_Cwd_av(ac, UNCONST(argv), 0); 1328 } 1329 if (cp) { 1330 chdir(cp); 1331 } 1332 } 1333 1334 /*- 1335 * Cmd_Exec -- 1336 * Execute the command in cmd, and return the output of that command 1337 * in a string. 1338 * 1339 * Results: 1340 * A string containing the output of the command, or the empty string 1341 * If err is not NULL, it contains the reason for the command failure 1342 * 1343 * Side Effects: 1344 * The string must be freed by the caller. 1345 */ 1346 char * 1347 Cmd_Exec(const char *cmd, const char **err) 1348 { 1349 const char *args[4]; /* Args for invoking the shell */ 1350 int fds[2]; /* Pipe streams */ 1351 int cpid; /* Child PID */ 1352 int pid; /* PID from wait() */ 1353 char *res; /* result */ 1354 int status; /* command exit status */ 1355 Buffer buf; /* buffer to store the result */ 1356 char *cp; 1357 int cc; 1358 1359 1360 *err = NULL; 1361 1362 if (!shellName) 1363 Shell_Init(); 1364 /* 1365 * Set up arguments for shell 1366 */ 1367 args[0] = shellName; 1368 args[1] = "-c"; 1369 args[2] = cmd; 1370 args[3] = NULL; 1371 1372 /* 1373 * Open a pipe for fetching its output 1374 */ 1375 if (pipe(fds) == -1) { 1376 *err = "Couldn't create pipe for \"%s\""; 1377 goto bad; 1378 } 1379 1380 /* 1381 * Fork 1382 */ 1383 switch (cpid = vfork()) { 1384 case 0: 1385 /* 1386 * Close input side of pipe 1387 */ 1388 (void) close(fds[0]); 1389 1390 /* 1391 * Duplicate the output stream to the shell's output, then 1392 * shut the extra thing down. Note we don't fetch the error 1393 * stream...why not? Why? 1394 */ 1395 (void) dup2(fds[1], 1); 1396 (void) close(fds[1]); 1397 1398 (void) execv(shellPath, UNCONST(args)); 1399 _exit(1); 1400 /*NOTREACHED*/ 1401 1402 case -1: 1403 *err = "Couldn't exec \"%s\""; 1404 goto bad; 1405 1406 default: 1407 /* 1408 * No need for the writing half 1409 */ 1410 (void) close(fds[1]); 1411 1412 buf = Buf_Init(MAKE_BSIZE); 1413 1414 do { 1415 char result[BUFSIZ]; 1416 cc = read(fds[0], result, sizeof(result)); 1417 if (cc > 0) 1418 Buf_AddBytes(buf, cc, (Byte *) result); 1419 } 1420 while (cc > 0 || (cc == -1 && errno == EINTR)); 1421 1422 /* 1423 * Close the input side of the pipe. 1424 */ 1425 (void) close(fds[0]); 1426 1427 /* 1428 * Wait for the process to exit. 1429 */ 1430 while(((pid = wait(&status)) != cpid) && (pid >= 0)) 1431 continue; 1432 1433 res = (char *)Buf_GetAll (buf, &cc); 1434 Buf_Destroy(buf, FALSE); 1435 1436 if (cc == 0) 1437 *err = "Couldn't read shell's output for \"%s\""; 1438 1439 if (status) 1440 *err = "\"%s\" returned non-zero status"; 1441 1442 /* 1443 * Null-terminate the result, convert newlines to spaces and 1444 * install it in the variable. 1445 */ 1446 res[cc] = '\0'; 1447 cp = &res[cc]; 1448 1449 if (cc > 0 && *--cp == '\n') { 1450 /* 1451 * A final newline is just stripped 1452 */ 1453 *cp-- = '\0'; 1454 } 1455 while (cp >= res) { 1456 if (*cp == '\n') { 1457 *cp = ' '; 1458 } 1459 cp--; 1460 } 1461 break; 1462 } 1463 return res; 1464 bad: 1465 res = emalloc(1); 1466 *res = '\0'; 1467 return res; 1468 } 1469 1470 /*- 1471 * Error -- 1472 * Print an error message given its format. 1473 * 1474 * Results: 1475 * None. 1476 * 1477 * Side Effects: 1478 * The message is printed. 1479 */ 1480 /* VARARGS */ 1481 void 1482 Error(const char *fmt, ...) 1483 { 1484 va_list ap; 1485 1486 va_start(ap, fmt); 1487 fprintf(stderr, "%s: ", progname); 1488 (void)vfprintf(stderr, fmt, ap); 1489 va_end(ap); 1490 (void)fprintf(stderr, "\n"); 1491 (void)fflush(stderr); 1492 } 1493 1494 /*- 1495 * Fatal -- 1496 * Produce a Fatal error message. If jobs are running, waits for them 1497 * to finish. 1498 * 1499 * Results: 1500 * None 1501 * 1502 * Side Effects: 1503 * The program exits 1504 */ 1505 /* VARARGS */ 1506 void 1507 Fatal(const char *fmt, ...) 1508 { 1509 va_list ap; 1510 1511 va_start(ap, fmt); 1512 if (jobsRunning) 1513 Job_Wait(); 1514 Job_TokenFlush(); 1515 1516 (void)vfprintf(stderr, fmt, ap); 1517 va_end(ap); 1518 (void)fprintf(stderr, "\n"); 1519 (void)fflush(stderr); 1520 1521 PrintOnError(NULL); 1522 1523 if (DEBUG(GRAPH2) || DEBUG(GRAPH3)) 1524 Targ_PrintGraph(2); 1525 Trace_Log(MAKEERROR, 0); 1526 exit(2); /* Not 1 so -q can distinguish error */ 1527 } 1528 1529 /* 1530 * Punt -- 1531 * Major exception once jobs are being created. Kills all jobs, prints 1532 * a message and exits. 1533 * 1534 * Results: 1535 * None 1536 * 1537 * Side Effects: 1538 * All children are killed indiscriminately and the program Lib_Exits 1539 */ 1540 /* VARARGS */ 1541 void 1542 Punt(const char *fmt, ...) 1543 { 1544 va_list ap; 1545 1546 va_start(ap, fmt); 1547 (void)fprintf(stderr, "%s: ", progname); 1548 (void)vfprintf(stderr, fmt, ap); 1549 va_end(ap); 1550 (void)fprintf(stderr, "\n"); 1551 (void)fflush(stderr); 1552 1553 PrintOnError(NULL); 1554 1555 DieHorribly(); 1556 } 1557 1558 /*- 1559 * DieHorribly -- 1560 * Exit without giving a message. 1561 * 1562 * Results: 1563 * None 1564 * 1565 * Side Effects: 1566 * A big one... 1567 */ 1568 void 1569 DieHorribly(void) 1570 { 1571 if (jobsRunning) 1572 Job_AbortAll(); 1573 if (DEBUG(GRAPH2)) 1574 Targ_PrintGraph(2); 1575 Trace_Log(MAKEERROR, 0); 1576 exit(2); /* Not 1, so -q can distinguish error */ 1577 } 1578 1579 /* 1580 * Finish -- 1581 * Called when aborting due to errors in child shell to signal 1582 * abnormal exit. 1583 * 1584 * Results: 1585 * None 1586 * 1587 * Side Effects: 1588 * The program exits 1589 */ 1590 void 1591 Finish(int errors) 1592 /* number of errors encountered in Make_Make */ 1593 { 1594 Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 1595 } 1596 1597 /* 1598 * emalloc -- 1599 * malloc, but die on error. 1600 */ 1601 void * 1602 emalloc(size_t len) 1603 { 1604 void *p; 1605 1606 if ((p = malloc(len)) == NULL) 1607 enomem(); 1608 return(p); 1609 } 1610 1611 /* 1612 * estrdup -- 1613 * strdup, but die on error. 1614 */ 1615 char * 1616 estrdup(const char *str) 1617 { 1618 char *p; 1619 1620 if ((p = strdup(str)) == NULL) 1621 enomem(); 1622 return(p); 1623 } 1624 1625 /* 1626 * erealloc -- 1627 * realloc, but die on error. 1628 */ 1629 void * 1630 erealloc(void *ptr, size_t size) 1631 { 1632 if ((ptr = realloc(ptr, size)) == NULL) 1633 enomem(); 1634 return(ptr); 1635 } 1636 1637 /* 1638 * enomem -- 1639 * die when out of memory. 1640 */ 1641 void 1642 enomem(void) 1643 { 1644 (void)fprintf(stderr, "%s: %s.\n", progname, strerror(errno)); 1645 exit(2); 1646 } 1647 1648 /* 1649 * enunlink -- 1650 * Remove a file carefully, avoiding directories. 1651 */ 1652 int 1653 eunlink(const char *file) 1654 { 1655 struct stat st; 1656 1657 if (lstat(file, &st) == -1) 1658 return -1; 1659 1660 if (S_ISDIR(st.st_mode)) { 1661 errno = EISDIR; 1662 return -1; 1663 } 1664 return unlink(file); 1665 } 1666 1667 /* 1668 * execError -- 1669 * Print why exec failed, avoiding stdio. 1670 */ 1671 void 1672 execError(const char *af, const char *av) 1673 { 1674 #ifdef USE_IOVEC 1675 int i = 0; 1676 struct iovec iov[8]; 1677 #define IOADD(s) \ 1678 (void)(iov[i].iov_base = UNCONST(s), \ 1679 iov[i].iov_len = strlen(iov[i].iov_base), \ 1680 i++) 1681 #else 1682 #define IOADD (void)write(2, s, strlen(s)) 1683 #endif 1684 1685 IOADD(progname); 1686 IOADD(": "); 1687 IOADD(af); 1688 IOADD("("); 1689 IOADD(av); 1690 IOADD(") failed ("); 1691 IOADD(strerror(errno)); 1692 IOADD(")\n"); 1693 1694 #ifdef USE_IOVEC 1695 (void)writev(2, iov, 8); 1696 #endif 1697 } 1698 1699 /* 1700 * usage -- 1701 * exit with usage message 1702 */ 1703 static void 1704 usage(void) 1705 { 1706 (void)fprintf(stderr, 1707 "usage: %s [-BeikNnqrstWX] [-D variable] [-d flags] [-f makefile]\n\ 1708 [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n\ 1709 [-V variable] [variable=value] [target ...]\n", progname); 1710 exit(2); 1711 } 1712 1713 1714 int 1715 PrintAddr(ClientData a, ClientData b) 1716 { 1717 printf("%lx ", (unsigned long) a); 1718 return b ? 0 : 0; 1719 } 1720 1721 1722 1723 void 1724 PrintOnError(const char *s) 1725 { 1726 char tmp[64]; 1727 1728 if (s) 1729 printf("%s", s); 1730 1731 printf("\n%s: stopped in %s\n", progname, curdir); 1732 strncpy(tmp, "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", 1733 sizeof(tmp) - 1); 1734 s = Var_Subst(NULL, tmp, VAR_GLOBAL, 0); 1735 if (s && *s) 1736 printf("%s", s); 1737 } 1738 1739 void 1740 Main_ExportMAKEFLAGS(Boolean first) 1741 { 1742 static int once = 1; 1743 char tmp[64]; 1744 char *s; 1745 1746 if (once != first) 1747 return; 1748 once = 0; 1749 1750 strncpy(tmp, "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", 1751 sizeof(tmp)); 1752 s = Var_Subst(NULL, tmp, VAR_CMD, 0); 1753 if (s && *s) { 1754 #ifdef POSIX 1755 setenv("MAKEFLAGS", s, 1); 1756 #else 1757 setenv("MAKE", s, 1); 1758 #endif 1759 } 1760 } 1761