version 1.452, 2020/11/08 14:19:15 |
version 1.453, 2020/11/08 14:50:24 |
Line 116 __COPYRIGHT("@(#) Copyright (c) 1988, 19 |
|
Line 116 __COPYRIGHT("@(#) Copyright (c) 1988, 19 |
|
"All rights reserved."); |
"All rights reserved."); |
#endif |
#endif |
|
|
#ifndef DEFMAXLOCAL |
#ifndef DEFMAXLOCAL |
#define DEFMAXLOCAL DEFMAXJOBS |
#define DEFMAXLOCAL DEFMAXJOBS |
#endif |
#endif |
|
|
CmdOpts opts; |
CmdOpts opts; |
time_t now; /* Time at start of make */ |
time_t now; /* Time at start of make */ |
GNode *DEFAULT; /* .DEFAULT node */ |
GNode *DEFAULT; /* .DEFAULT node */ |
Boolean allPrecious; /* .PRECIOUS given on line by itself */ |
Boolean allPrecious; /* .PRECIOUS given on line by itself */ |
Boolean deleteOnError; /* .DELETE_ON_ERROR: set */ |
Boolean deleteOnError; /* .DELETE_ON_ERROR: set */ |
|
|
static int maxJobTokens; /* -j argument */ |
static int maxJobTokens; /* -j argument */ |
Boolean enterFlagObj; /* -w and objdir != srcdir */ |
Boolean enterFlagObj; /* -w and objdir != srcdir */ |
|
|
Boolean preserveUndefined; |
Boolean preserveUndefined; |
static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ |
static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ |
Boolean doing_depend; /* Set while reading .depend */ |
Boolean doing_depend; /* Set while reading .depend */ |
static Boolean jobsRunning; /* TRUE if the jobs might be running */ |
static Boolean jobsRunning; /* TRUE if the jobs might be running */ |
static const char * tracefile; |
static const char *tracefile; |
static int ReadMakefile(const char *); |
static int ReadMakefile(const char *); |
static void purge_cached_realpaths(void); |
static void purge_cached_realpaths(void); |
|
|
static Boolean ignorePWD; /* if we use -C, PWD is meaningless */ |
static Boolean ignorePWD; /* if we use -C, PWD is meaningless */ |
static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ |
static char objdir[MAXPATHLEN + 1]; /* where we chdir'ed to */ |
char curdir[MAXPATHLEN + 1]; /* Startup directory */ |
char curdir[MAXPATHLEN + 1]; /* Startup directory */ |
char *progname; /* the program name */ |
char *progname; /* the program name */ |
char *makeDependfile; |
char *makeDependfile; |
pid_t myPid; |
pid_t myPid; |
int makelevel; |
int makelevel; |
Line 155 static int errors = 0; |
|
Line 155 static int errors = 0; |
|
static char * |
static char * |
explode(const char *flags) |
explode(const char *flags) |
{ |
{ |
size_t len; |
size_t len; |
char *nf, *st; |
char *nf, *st; |
const char *f; |
const char *f; |
|
|
if (flags == NULL) |
if (flags == NULL) |
return NULL; |
return NULL; |
|
|
for (f = flags; *f; f++) |
for (f = flags; *f; f++) |
if (!ch_isalpha(*f)) |
if (!ch_isalpha(*f)) |
break; |
break; |
|
|
if (*f) |
if (*f) |
return bmake_strdup(flags); |
return bmake_strdup(flags); |
|
|
len = strlen(flags); |
len = strlen(flags); |
st = nf = bmake_malloc(len * 3 + 1); |
st = nf = bmake_malloc(len * 3 + 1); |
while (*flags) { |
while (*flags) { |
*nf++ = '-'; |
*nf++ = '-'; |
*nf++ = *flags++; |
*nf++ = *flags++; |
*nf++ = ' '; |
*nf++ = ' '; |
} |
} |
*nf = '\0'; |
*nf = '\0'; |
return st; |
return st; |
} |
} |
|
|
/* |
/* |
|
|
" [-C directory] [-D variable] [-d flags] [-f makefile]\n" |
" [-C directory] [-D variable] [-d flags] [-f makefile]\n" |
" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" |
" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" |
" [-V variable] [-v variable] [variable=value] [target ...]\n", |
" [-V variable] [-v variable] [variable=value] [target ...]\n", |
progname); |
progname); |
exit(2); |
exit(2); |
} |
} |
|
|
static void |
static void |
parse_debug_option_F(const char *modules) |
parse_debug_option_F(const char *modules) |
{ |
{ |
const char *mode; |
const char *mode; |
size_t len; |
size_t len; |
char *fname; |
char *fname; |
|
|
if (opts.debug_file != stdout && opts.debug_file != stderr) |
if (opts.debug_file != stdout && opts.debug_file != stderr) |
fclose(opts.debug_file); |
fclose(opts.debug_file); |
|
|
if (*modules == '+') { |
if (*modules == '+') { |
modules++; |
modules++; |
mode = "a"; |
mode = "a"; |
} else |
} else |
mode = "w"; |
mode = "w"; |
|
|
if (strcmp(modules, "stdout") == 0) { |
if (strcmp(modules, "stdout") == 0) { |
opts.debug_file = stdout; |
opts.debug_file = stdout; |
return; |
return; |
} |
} |
if (strcmp(modules, "stderr") == 0) { |
if (strcmp(modules, "stderr") == 0) { |
opts.debug_file = stderr; |
opts.debug_file = stderr; |
return; |
return; |
} |
} |
|
|
len = strlen(modules); |
len = strlen(modules); |
fname = bmake_malloc(len + 20); |
fname = bmake_malloc(len + 20); |
memcpy(fname, modules, len + 1); |
memcpy(fname, modules, len + 1); |
|
|
/* Let the filename be modified by the pid */ |
/* Let the filename be modified by the pid */ |
if (strcmp(fname + len - 3, ".%d") == 0) |
if (strcmp(fname + len - 3, ".%d") == 0) |
snprintf(fname + len - 2, 20, "%d", getpid()); |
snprintf(fname + len - 2, 20, "%d", getpid()); |
|
|
opts.debug_file = fopen(fname, mode); |
opts.debug_file = fopen(fname, mode); |
if (opts.debug_file == NULL) { |
if (opts.debug_file == NULL) { |
fprintf(stderr, "Cannot open debug file %s\n", |
fprintf(stderr, "Cannot open debug file %s\n", |
fname); |
fname); |
usage(); |
usage(); |
} |
} |
free(fname); |
free(fname); |
} |
} |
|
|
static void |
static void |
Line 253 parse_debug_options(const char *argvalue |
|
Line 253 parse_debug_options(const char *argvalue |
|
opts.debug &= DEBUG_LINT; |
opts.debug &= DEBUG_LINT; |
break; |
break; |
case 'A': |
case 'A': |
opts.debug = ~(0|DEBUG_LINT); |
opts.debug = ~(0 | DEBUG_LINT); |
break; |
break; |
case 'a': |
case 'a': |
opts.debug |= DEBUG_ARCH; |
opts.debug |= DEBUG_ARCH; |
Line 334 parse_debug_options(const char *argvalue |
|
Line 334 parse_debug_options(const char *argvalue |
|
usage(); |
usage(); |
} |
} |
} |
} |
|
|
debug_setbuf: |
debug_setbuf: |
/* |
/* |
* Make the debug_file unbuffered, and make |
* Make the debug_file unbuffered, and make |
Line 359 is_relpath(const char *path) |
|
Line 360 is_relpath(const char *path) |
|
while ((cp = strstr(cp, "/.")) != NULL) { |
while ((cp = strstr(cp, "/.")) != NULL) { |
cp += 2; |
cp += 2; |
if (*cp == '.') |
if (*cp == '.') |
cp++; |
cp++; |
if (cp[0] == '/' || cp[0] == '\0') |
if (cp[0] == '/' || cp[0] == '\0') |
return TRUE; |
return TRUE; |
} |
} |
Line 395 MainParseArgJobsInternal(const char *arg |
|
Line 396 MainParseArgJobsInternal(const char *arg |
|
char end; |
char end; |
if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) { |
if (sscanf(argvalue, "%d,%d%c", &jp_0, &jp_1, &end) != 2) { |
(void)fprintf(stderr, |
(void)fprintf(stderr, |
"%s: internal error -- J option malformed (%s)\n", |
"%s: internal error -- J option malformed (%s)\n", |
progname, argvalue); |
progname, argvalue); |
usage(); |
usage(); |
} |
} |
if ((fcntl(jp_0, F_GETFD, 0) < 0) || |
if ((fcntl(jp_0, F_GETFD, 0) < 0) || |
Line 733 Main_SetObjdir(const char *fmt, ...) |
|
Line 734 Main_SetObjdir(const char *fmt, ...) |
|
if ((strcmp(path, curdir) != 0 && access(path, W_OK) != 0) || |
if ((strcmp(path, curdir) != 0 && access(path, W_OK) != 0) || |
(chdir(path) != 0)) { |
(chdir(path) != 0)) { |
(void)fprintf(stderr, "make warning: %s: %s.\n", |
(void)fprintf(stderr, "make warning: %s: %s.\n", |
path, strerror(errno)); |
path, strerror(errno)); |
} else { |
} else { |
snprintf(objdir, sizeof objdir, "%s", path); |
snprintf(objdir, sizeof objdir, "%s", path); |
Var_Set(".OBJDIR", objdir, VAR_GLOBAL); |
Var_Set(".OBJDIR", objdir, VAR_GLOBAL); |
Line 781 Main_SetVarObjdir(const char *var, const |
|
Line 782 Main_SetVarObjdir(const char *var, const |
|
int |
int |
str2Lst_Append(StringList *lp, char *str, const char *sep) |
str2Lst_Append(StringList *lp, char *str, const char *sep) |
{ |
{ |
char *cp; |
char *cp; |
int n; |
int n; |
|
|
if (!sep) |
if (!sep) |
sep = " \t"; |
sep = " \t"; |
|
|
for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { |
for (n = 0, cp = strtok(str, sep); cp; cp = strtok(NULL, sep)) { |
Lst_Append(lp, cp); |
Lst_Append(lp, cp); |
n++; |
n++; |
} |
} |
return n; |
return n; |
} |
} |
|
|
#ifdef SIGINFO |
#ifdef SIGINFO |
Line 816 siginfo(int signo MAKE_ATTR_UNUSED) |
|
Line 817 siginfo(int signo MAKE_ATTR_UNUSED) |
|
void |
void |
MakeMode(const char *mode) |
MakeMode(const char *mode) |
{ |
{ |
char *mode_freeIt = NULL; |
char *mode_freeIt = NULL; |
|
|
if (mode == NULL) { |
if (mode == NULL) { |
(void)Var_Subst("${" MAKE_MODE ":tl}", |
(void)Var_Subst("${" MAKE_MODE ":tl}", |
VAR_GLOBAL, VARE_WANTRES, &mode_freeIt); |
VAR_GLOBAL, VARE_WANTRES, &mode_freeIt); |
/* TODO: handle errors */ |
/* TODO: handle errors */ |
mode = mode_freeIt; |
mode = mode_freeIt; |
} |
|
|
|
if (mode[0] != '\0') { |
|
if (strstr(mode, "compat")) { |
|
opts.compatMake = TRUE; |
|
forceJobs = FALSE; |
|
} |
} |
|
|
|
if (mode[0] != '\0') { |
|
if (strstr(mode, "compat")) { |
|
opts.compatMake = TRUE; |
|
forceJobs = FALSE; |
|
} |
#if USE_META |
#if USE_META |
if (strstr(mode, "meta")) |
if (strstr(mode, "meta")) |
meta_mode_init(mode); |
meta_mode_init(mode); |
#endif |
#endif |
} |
} |
|
|
free(mode_freeIt); |
free(mode_freeIt); |
} |
} |
|
|
static void |
static void |
Line 876 PrintVar(const char *varname, Boolean ex |
|
Line 877 PrintVar(const char *varname, Boolean ex |
|
static Boolean |
static Boolean |
GetBooleanVar(const char *varname, Boolean fallback) |
GetBooleanVar(const char *varname, Boolean fallback) |
{ |
{ |
char *expr = str_concat3("${", varname, ":U}"); |
char *expr = str_concat3("${", varname, ":U}"); |
char *value; |
char *value; |
Boolean res; |
Boolean res; |
|
|
(void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value); |
(void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &value); |
/* TODO: handle errors */ |
/* TODO: handle errors */ |
res = ParseBoolean(value, fallback); |
res = ParseBoolean(value, fallback); |
free(value); |
free(value); |
free(expr); |
free(expr); |
return res; |
return res; |
} |
} |
|
|
static void |
static void |
Line 910 doPrintVars(void) |
|
Line 911 doPrintVars(void) |
|
static Boolean |
static Boolean |
runTargets(void) |
runTargets(void) |
{ |
{ |
GNodeList *targs; /* target nodes to create -- passed to Make_Init */ |
GNodeList *targs; /* target nodes to create */ |
Boolean outOfDate; /* FALSE if all targets up to date */ |
Boolean outOfDate; /* FALSE if all targets up to date */ |
|
|
/* |
/* |
Line 1060 HandlePWD(const struct stat *curdir_st) |
|
Line 1061 HandlePWD(const struct stat *curdir_st) |
|
if (ignorePWD || (pwd = getenv("PWD")) == NULL) |
if (ignorePWD || (pwd = getenv("PWD")) == NULL) |
return; |
return; |
|
|
if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) != NULL) { |
if (Var_Value("MAKEOBJDIRPREFIX", VAR_CMDLINE, &prefix_freeIt) != |
|
NULL) { |
bmake_free(prefix_freeIt); |
bmake_free(prefix_freeIt); |
return; |
return; |
} |
} |
Line 1211 ReadBuiltinRules(void) |
|
Line 1213 ReadBuiltinRules(void) |
|
StringList *sysMkPath = Lst_New(); |
StringList *sysMkPath = Lst_New(); |
|
|
Dir_Expand(_PATH_DEFSYSMK, |
Dir_Expand(_PATH_DEFSYSMK, |
Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath, |
Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath, |
sysMkPath); |
sysMkPath); |
if (Lst_IsEmpty(sysMkPath)) |
if (Lst_IsEmpty(sysMkPath)) |
Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); |
Fatal("%s: no system rules (%s).", progname, _PATH_DEFSYSMK); |
|
|
Line 1222 ReadBuiltinRules(void) |
|
Line 1224 ReadBuiltinRules(void) |
|
|
|
if (ln == NULL) |
if (ln == NULL) |
Fatal("%s: cannot open %s.", |
Fatal("%s: cannot open %s.", |
progname, (const char *)sysMkPath->first->datum); |
progname, (const char *)sysMkPath->first->datum); |
|
|
/* Free the list but not the actual filenames since these may still |
/* Free the list but not the actual filenames since these may still |
* be used in GNodes. */ |
* be used in GNodes. */ |
Line 1244 InitMaxJobs(void) |
|
Line 1246 InitMaxJobs(void) |
|
n = (int)strtol(value, NULL, 0); |
n = (int)strtol(value, NULL, 0); |
if (n < 1) { |
if (n < 1) { |
(void)fprintf(stderr, |
(void)fprintf(stderr, |
"%s: illegal value for .MAKE.JOBS " |
"%s: illegal value for .MAKE.JOBS " |
"-- must be positive integer!\n", |
"-- must be positive integer!\n", |
progname); |
progname); |
exit(1); |
exit(1); |
} |
} |
|
|
Line 1312 ReadFirstDefaultMakefile(void) |
|
Line 1314 ReadFirstDefaultMakefile(void) |
|
char *prefs; |
char *prefs; |
|
|
(void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}", |
(void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}", |
VAR_CMDLINE, VARE_WANTRES, &prefs); |
VAR_CMDLINE, VARE_WANTRES, &prefs); |
/* TODO: handle errors */ |
/* TODO: handle errors */ |
|
|
/* XXX: This should use a local list instead of opts.makefiles |
/* XXX: This should use a local list instead of opts.makefiles |
Line 1358 main_Init(int argc, char **argv) |
|
Line 1360 main_Init(int argc, char **argv) |
|
|
|
if (uname(&utsname) == -1) { |
if (uname(&utsname) == -1) { |
(void)fprintf(stderr, "%s: uname failed (%s).\n", progname, |
(void)fprintf(stderr, "%s: uname failed (%s).\n", progname, |
strerror(errno)); |
strerror(errno)); |
exit(2); |
exit(2); |
} |
} |
|
|
Line 1393 main_Init(int argc, char **argv) |
|
Line 1395 main_Init(int argc, char **argv) |
|
#ifndef MAKEFILE_PREFERENCE_LIST |
#ifndef MAKEFILE_PREFERENCE_LIST |
# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" |
# define MAKEFILE_PREFERENCE_LIST "makefile Makefile" |
#endif |
#endif |
Var_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, |
Var_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST, VAR_GLOBAL); |
VAR_GLOBAL); |
|
Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL); |
Var_Set(MAKE_DEPENDFILE, ".depend", VAR_GLOBAL); |
|
|
CmdOpts_Init(); |
CmdOpts_Init(); |
Line 1472 main_Init(int argc, char **argv) |
|
Line 1473 main_Init(int argc, char **argv) |
|
*/ |
*/ |
if (getcwd(curdir, MAXPATHLEN) == NULL) { |
if (getcwd(curdir, MAXPATHLEN) == NULL) { |
(void)fprintf(stderr, "%s: getcwd: %s.\n", |
(void)fprintf(stderr, "%s: getcwd: %s.\n", |
progname, strerror(errno)); |
progname, strerror(errno)); |
exit(2); |
exit(2); |
} |
} |
|
|
Line 1486 main_Init(int argc, char **argv) |
|
Line 1487 main_Init(int argc, char **argv) |
|
*/ |
*/ |
if (stat(curdir, &sa) == -1) { |
if (stat(curdir, &sa) == -1) { |
(void)fprintf(stderr, "%s: %s: %s.\n", |
(void)fprintf(stderr, "%s: %s: %s.\n", |
progname, curdir, strerror(errno)); |
progname, curdir, strerror(errno)); |
exit(2); |
exit(2); |
} |
} |
|
|
Line 1539 main_PrepareMaking(void) |
|
Line 1540 main_PrepareMaking(void) |
|
if (!opts.noBuiltins || opts.printVars == PVM_NONE) { |
if (!opts.noBuiltins || opts.printVars == PVM_NONE) { |
/* ignore /dev/null and anything starting with "no" */ |
/* ignore /dev/null and anything starting with "no" */ |
(void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}", |
(void)Var_Subst("${.MAKE.DEPENDFILE:N/dev/null:Nno*:T}", |
VAR_CMDLINE, VARE_WANTRES, &makeDependfile); |
VAR_CMDLINE, VARE_WANTRES, &makeDependfile); |
if (makeDependfile[0] != '\0') { |
if (makeDependfile[0] != '\0') { |
/* TODO: handle errors */ |
/* TODO: handle errors */ |
doing_depend = TRUE; |
doing_depend = TRUE; |
Line 1556 main_PrepareMaking(void) |
|
Line 1557 main_PrepareMaking(void) |
|
{ |
{ |
void *freeIt; |
void *freeIt; |
Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt), |
Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &freeIt), |
VAR_GLOBAL); |
VAR_GLOBAL); |
bmake_free(freeIt); |
bmake_free(freeIt); |
|
|
} |
} |
|
|
InitMaxJobs(); |
InitMaxJobs(); |
Line 1573 main_PrepareMaking(void) |
|
Line 1573 main_PrepareMaking(void) |
|
if (!opts.compatMake) |
if (!opts.compatMake) |
Job_ServerStart(maxJobTokens, jp_0, jp_1); |
Job_ServerStart(maxJobTokens, jp_0, jp_1); |
DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", |
DEBUG5(JOB, "job_pipe %d %d, maxjobs %d, tokens %d, compat %d\n", |
jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); |
jp_0, jp_1, opts.maxJobs, maxJobTokens, opts.compatMake ? 1 : 0); |
|
|
if (opts.printVars == PVM_NONE) |
if (opts.printVars == PVM_NONE) |
Main_ExportMAKEFLAGS(TRUE); /* initial export */ |
Main_ExportMAKEFLAGS(TRUE); /* initial export */ |
|
|
return 0; |
return 0; |
} |
} |
|
|
|
|
|
|
/*- |
/*- |
* Cmd_Exec -- |
* Cmd_Exec -- |
* Execute the command in cmd, and return the output of that command |
* Execute the command in cmd, and return the output of that command |
|
|
char * |
char * |
Cmd_Exec(const char *cmd, const char **errfmt) |
Cmd_Exec(const char *cmd, const char **errfmt) |
{ |
{ |
const char *args[4]; /* Args for invoking the shell */ |
const char *args[4]; /* Args for invoking the shell */ |
int fds[2]; /* Pipe streams */ |
int fds[2]; /* Pipe streams */ |
int cpid; /* Child PID */ |
int cpid; /* Child PID */ |
int pid; /* PID from wait() */ |
int pid; /* PID from wait() */ |
int status; /* command exit status */ |
int status; /* command exit status */ |
Buffer buf; /* buffer to store the result */ |
Buffer buf; /* buffer to store the result */ |
ssize_t bytes_read; |
ssize_t bytes_read; |
char *res; /* result */ |
char *res; /* result */ |
size_t res_len; |
size_t res_len; |
char *cp; |
char *cp; |
int savederr; /* saved errno */ |
int savederr; /* saved errno */ |
|
|
*errfmt = NULL; |
*errfmt = NULL; |
|
|
if (!shellName) |
if (!shellName) |
Shell_Init(); |
Shell_Init(); |
/* |
/* |
* Set up arguments for shell |
* Set up arguments for shell |
*/ |
|
args[0] = shellName; |
|
args[1] = "-c"; |
|
args[2] = cmd; |
|
args[3] = NULL; |
|
|
|
/* |
|
* Open a pipe for fetching its output |
|
*/ |
|
if (pipe(fds) == -1) { |
|
*errfmt = "Couldn't create pipe for \"%s\""; |
|
goto bad; |
|
} |
|
|
|
/* |
|
* Fork |
|
*/ |
|
switch (cpid = vFork()) { |
|
case 0: |
|
(void)close(fds[0]); /* Close input side of pipe */ |
|
|
|
/* |
|
* Duplicate the output stream to the shell's output, then |
|
* shut the extra thing down. Note we don't fetch the error |
|
* stream...why not? Why? |
|
*/ |
*/ |
(void)dup2(fds[1], 1); |
args[0] = shellName; |
(void)close(fds[1]); |
args[1] = "-c"; |
|
args[2] = cmd; |
|
args[3] = NULL; |
|
|
Var_ExportVars(); |
/* |
|
* Open a pipe for fetching its output |
|
*/ |
|
if (pipe(fds) == -1) { |
|
*errfmt = "Couldn't create pipe for \"%s\""; |
|
goto bad; |
|
} |
|
|
(void)execv(shellPath, UNCONST(args)); |
/* |
_exit(1); |
* Fork |
/*NOTREACHED*/ |
*/ |
|
switch (cpid = vFork()) { |
|
case 0: |
|
(void)close(fds[0]); /* Close input side of pipe */ |
|
|
|
/* |
|
* Duplicate the output stream to the shell's output, then |
|
* shut the extra thing down. Note we don't fetch the error |
|
* stream...why not? Why? |
|
*/ |
|
(void)dup2(fds[1], 1); |
|
(void)close(fds[1]); |
|
|
case -1: |
Var_ExportVars(); |
*errfmt = "Couldn't exec \"%s\""; |
|
goto bad; |
|
|
|
default: |
(void)execv(shellPath, UNCONST(args)); |
(void)close(fds[1]); /* No need for the writing half */ |
_exit(1); |
|
/*NOTREACHED*/ |
|
|
|
case -1: |
|
*errfmt = "Couldn't exec \"%s\""; |
|
goto bad; |
|
|
savederr = 0; |
default: |
Buf_Init(&buf); |
(void)close(fds[1]); /* No need for the writing half */ |
|
|
do { |
savederr = 0; |
char result[BUFSIZ]; |
Buf_Init(&buf); |
bytes_read = read(fds[0], result, sizeof result); |
|
if (bytes_read > 0) |
do { |
Buf_AddBytes(&buf, result, (size_t)bytes_read); |
char result[BUFSIZ]; |
} while (bytes_read > 0 || (bytes_read == -1 && errno == EINTR)); |
bytes_read = read(fds[0], result, sizeof result); |
if (bytes_read == -1) |
if (bytes_read > 0) |
savederr = errno; |
Buf_AddBytes(&buf, result, (size_t)bytes_read); |
|
} while (bytes_read > 0 || |
(void)close(fds[0]); /* Close the input side of the pipe. */ |
(bytes_read == -1 && errno == EINTR)); |
|
if (bytes_read == -1) |
/* Wait for the process to exit. */ |
savederr = errno; |
while((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0) |
|
JobReapChild(pid, status, FALSE); |
(void)close( |
|
fds[0]); /* Close the input side of the pipe. */ |
res_len = Buf_Len(&buf); |
|
res = Buf_Destroy(&buf, FALSE); |
/* Wait for the process to exit. */ |
|
while ((pid = waitpid(cpid, &status, 0)) != cpid && pid >= 0) |
if (savederr != 0) |
JobReapChild(pid, status, FALSE); |
*errfmt = "Couldn't read shell's output for \"%s\""; |
|
|
res_len = Buf_Len(&buf); |
if (WIFSIGNALED(status)) |
res = Buf_Destroy(&buf, FALSE); |
*errfmt = "\"%s\" exited on a signal"; |
|
else if (WEXITSTATUS(status) != 0) |
if (savederr != 0) |
*errfmt = "\"%s\" returned non-zero status"; |
*errfmt = "Couldn't read shell's output for \"%s\""; |
|
|
/* Convert newlines to spaces. A final newline is just stripped */ |
if (WIFSIGNALED(status)) |
if (res_len > 0 && res[res_len - 1] == '\n') |
*errfmt = "\"%s\" exited on a signal"; |
res[res_len - 1] = '\0'; |
else if (WEXITSTATUS(status) != 0) |
for (cp = res; *cp != '\0'; cp++) |
*errfmt = "\"%s\" returned non-zero status"; |
if (*cp == '\n') |
|
*cp = ' '; |
/* Convert newlines to spaces. A final newline is just stripped */ |
break; |
if (res_len > 0 && res[res_len - 1] == '\n') |
} |
res[res_len - 1] = '\0'; |
return res; |
for (cp = res; *cp != '\0'; cp++) |
|
if (*cp == '\n') |
|
*cp = ' '; |
|
break; |
|
} |
|
return res; |
bad: |
bad: |
return bmake_strdup(""); |
return bmake_strdup(""); |
} |
} |
|
|
/* Print a printf-style error message. |
/* Print a printf-style error message. |
|
|
get_cached_realpaths(void) |
get_cached_realpaths(void) |
{ |
{ |
|
|
if (!cached_realpaths) { |
if (!cached_realpaths) { |
cached_realpaths = Targ_NewGN("Realpath"); |
cached_realpaths = Targ_NewGN("Realpath"); |
#ifndef DEBUG_REALPATH_CACHE |
#ifndef DEBUG_REALPATH_CACHE |
cached_realpaths->flags = INTERNAL; |
cached_realpaths->flags = INTERNAL; |
#endif |
#endif |
} |
} |
|
|
return cached_realpaths; |
return cached_realpaths; |
} |
} |
|
|
/* purge any relative paths */ |
/* purge any relative paths */ |
static void |
static void |
purge_cached_realpaths(void) |
purge_cached_realpaths(void) |
{ |
{ |
GNode *cache = get_cached_realpaths(); |
GNode *cache = get_cached_realpaths(); |
HashEntry *he, *nhe; |
HashEntry *he, *nhe; |
HashIter hi; |
HashIter hi; |
|
|
HashIter_Init(&hi, &cache->context); |
HashIter_Init(&hi, &cache->context); |
he = HashIter_Next(&hi); |
he = HashIter_Next(&hi); |
while (he != NULL) { |
while (he != NULL) { |
nhe = HashIter_Next(&hi); |
nhe = HashIter_Next(&hi); |
if (he->key[0] != '/') { |
if (he->key[0] != '/') { |
if (DEBUG(DIR)) |
if (DEBUG(DIR)) |
fprintf(stderr, "cached_realpath: purging %s\n", he->key); |
fprintf(stderr, "cached_realpath: purging %s\n", |
HashTable_DeleteEntry(&cache->context, he); |
he->key); |
|
HashTable_DeleteEntry(&cache->context, he); |
|
} |
|
he = nhe; |
} |
} |
he = nhe; |
|
} |
|
} |
} |
|
|
char * |
char * |
cached_realpath(const char *pathname, char *resolved) |
cached_realpath(const char *pathname, char *resolved) |
{ |
{ |
GNode *cache; |
GNode *cache; |
const char *rp; |
const char *rp; |
void *freeIt; |
void *freeIt; |
|
|
if (pathname == NULL || pathname[0] == '\0') |
if (pathname == NULL || pathname[0] == '\0') |
return NULL; |
return NULL; |
|
|
cache = get_cached_realpaths(); |
cache = get_cached_realpaths(); |
|
|
if ((rp = Var_Value(pathname, cache, &freeIt)) != NULL) { |
if ((rp = Var_Value(pathname, cache, &freeIt)) != NULL) { |
/* a hit */ |
/* a hit */ |
strncpy(resolved, rp, MAXPATHLEN); |
strncpy(resolved, rp, MAXPATHLEN); |
resolved[MAXPATHLEN - 1] = '\0'; |
resolved[MAXPATHLEN - 1] = '\0'; |
} else if ((rp = realpath(pathname, resolved)) != NULL) { |
} else if ((rp = realpath(pathname, resolved)) != NULL) { |
Var_Set(pathname, rp, cache); |
Var_Set(pathname, rp, cache); |
} /* else should we negative-cache? */ |
} /* else should we negative-cache? */ |
|
|
bmake_free(freeIt); |
bmake_free(freeIt); |
return rp ? resolved : NULL; |
return rp ? resolved : NULL; |
} |
} |
|
|
/* |
/* |
Line 2079 cached_realpath(const char *pathname, ch |
|
Line 2080 cached_realpath(const char *pathname, ch |
|
Boolean |
Boolean |
shouldDieQuietly(GNode *gn, int bf) |
shouldDieQuietly(GNode *gn, int bf) |
{ |
{ |
static int quietly = -1; |
static int quietly = -1; |
|
|
if (quietly < 0) { |
if (quietly < 0) { |
if (DEBUG(JOB) || !GetBooleanVar(".MAKE.DIE_QUIETLY", TRUE)) |
if (DEBUG(JOB) || !GetBooleanVar(".MAKE.DIE_QUIETLY", TRUE)) |
quietly = 0; |
quietly = 0; |
else if (bf >= 0) |
else if (bf >= 0) |
quietly = bf; |
quietly = bf; |
else |
else |
quietly = gn != NULL && (gn->type & OP_MAKE); |
quietly = gn != NULL && (gn->type & OP_MAKE); |
} |
} |
return quietly; |
return quietly; |
} |
} |
|
|
static void |
static void |
SetErrorVars(GNode *gn) |
SetErrorVars(GNode *gn) |
{ |
{ |
StringListNode *ln; |
StringListNode *ln; |
|
|
/* |
/* |
* We can print this even if there is no .ERROR target. |
* We can print this even if there is no .ERROR target. |
*/ |
*/ |
Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL); |
Var_Set(".ERROR_TARGET", gn->name, VAR_GLOBAL); |
Var_Delete(".ERROR_CMD", VAR_GLOBAL); |
Var_Delete(".ERROR_CMD", VAR_GLOBAL); |
|
|
for (ln = gn->commands->first; ln != NULL; ln = ln->next) { |
for (ln = gn->commands->first; ln != NULL; ln = ln->next) { |
const char *cmd = ln->datum; |
const char *cmd = ln->datum; |
|
|
if (cmd == NULL) |
if (cmd == NULL) |
break; |
break; |
Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL); |
Var_Append(".ERROR_CMD", cmd, VAR_GLOBAL); |
} |
} |
} |
} |
|
|
void |
void |
PrintOnError(GNode *gn, const char *s) |
PrintOnError(GNode *gn, const char *s) |
{ |
{ |
static GNode *en = NULL; |
static GNode *en = NULL; |
const char *expr; |
const char *expr; |
char *cp; |
char *cp; |
|
|
if (DEBUG(HASH)) { |
|
Targ_Stats(); |
|
Var_Stats(); |
|
} |
|
|
|
/* we generally want to keep quiet if a sub-make died */ |
if (DEBUG(HASH)) { |
if (shouldDieQuietly(gn, -1)) |
Targ_Stats(); |
return; |
Var_Stats(); |
|
} |
|
|
|
/* we generally want to keep quiet if a sub-make died */ |
|
if (shouldDieQuietly(gn, -1)) |
|
return; |
|
|
if (s) |
if (s) |
printf("%s", s); |
printf("%s", s); |
|
|
printf("\n%s: stopped in %s\n", progname, curdir); |
printf("\n%s: stopped in %s\n", progname, curdir); |
|
|
if (en) |
if (en) |
return; /* we've been here! */ |
return; /* we've been here! */ |
if (gn) |
if (gn) |
SetErrorVars(gn); |
SetErrorVars(gn); |
expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}"; |
expr = "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}"; |
(void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); |
(void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &cp); |
/* TODO: handle errors */ |
/* TODO: handle errors */ |
printf("%s", cp); |
printf("%s", cp); |
free(cp); |
free(cp); |
fflush(stdout); |
fflush(stdout); |
|
|
/* |
/* |
* Finally, see if there is a .ERROR target, and run it if so. |
* Finally, see if there is a .ERROR target, and run it if so. |
*/ |
*/ |
en = Targ_FindNode(".ERROR"); |
en = Targ_FindNode(".ERROR"); |
if (en) { |
if (en) { |
en->type |= OP_SPECIAL; |
en->type |= OP_SPECIAL; |
Compat_Make(en, en); |
Compat_Make(en, en); |
} |
} |
} |
} |
|
|
void |
void |
Main_ExportMAKEFLAGS(Boolean first) |
Main_ExportMAKEFLAGS(Boolean first) |
{ |
{ |
static Boolean once = TRUE; |
static Boolean once = TRUE; |
const char *expr; |
const char *expr; |
char *s; |
char *s; |
|
|
if (once != first) |
if (once != first) |
return; |
return; |
once = FALSE; |
once = FALSE; |
|
|
expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; |
expr = "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}"; |
(void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s); |
(void)Var_Subst(expr, VAR_CMDLINE, VARE_WANTRES, &s); |
/* TODO: handle errors */ |
/* TODO: handle errors */ |
if (s[0] != '\0') { |
if (s[0] != '\0') { |
#ifdef POSIX |
#ifdef POSIX |
setenv("MAKEFLAGS", s, 1); |
setenv("MAKEFLAGS", s, 1); |
#else |
#else |
setenv("MAKE", s, 1); |
setenv("MAKE", s, 1); |
#endif |
#endif |
} |
} |
} |
} |
|
|
char * |
char * |
getTmpdir(void) |
getTmpdir(void) |
{ |
{ |
static char *tmpdir = NULL; |
static char *tmpdir = NULL; |
|
|
if (!tmpdir) { |
if (!tmpdir) { |
struct stat st; |
struct stat st; |
|
|
/* |
/* |
* Honor $TMPDIR but only if it is valid. |
* Honor $TMPDIR but only if it is valid. |
* Ensure it ends with /. |
* Ensure it ends with /. |
*/ |
*/ |
(void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, |
(void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP "}/", VAR_GLOBAL, |
VARE_WANTRES, &tmpdir); |
VARE_WANTRES, &tmpdir); |
/* TODO: handle errors */ |
/* TODO: handle errors */ |
if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { |
if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { |
free(tmpdir); |
free(tmpdir); |
tmpdir = bmake_strdup(_PATH_TMP); |
tmpdir = bmake_strdup(_PATH_TMP); |
|
} |
} |
} |
} |
return tmpdir; |
return tmpdir; |
|
} |
} |
|
|
/* |
/* |
Line 2208 getTmpdir(void) |
|
Line 2209 getTmpdir(void) |
|
int |
int |
mkTempFile(const char *pattern, char **out_fname) |
mkTempFile(const char *pattern, char **out_fname) |
{ |
{ |
static char *tmpdir = NULL; |
static char *tmpdir = NULL; |
char tfile[MAXPATHLEN]; |
char tfile[MAXPATHLEN]; |
int fd; |
int fd; |
|
|
if (pattern == NULL) |
if (pattern == NULL) |
pattern = TMPPAT; |
pattern = TMPPAT; |
if (tmpdir == NULL) |
if (tmpdir == NULL) |
tmpdir = getTmpdir(); |
tmpdir = getTmpdir(); |
if (pattern[0] == '/') { |
if (pattern[0] == '/') { |
snprintf(tfile, sizeof tfile, "%s", pattern); |
snprintf(tfile, sizeof tfile, "%s", pattern); |
} else { |
} else { |
snprintf(tfile, sizeof tfile, "%s%s", tmpdir, pattern); |
snprintf(tfile, sizeof tfile, "%s%s", tmpdir, pattern); |
} |
} |
if ((fd = mkstemp(tfile)) < 0) |
if ((fd = mkstemp(tfile)) < 0) |
Punt("Could not create temporary file %s: %s", tfile, strerror(errno)); |
Punt("Could not create temporary file %s: %s", tfile, |
if (out_fname) { |
strerror(errno)); |
*out_fname = bmake_strdup(tfile); |
if (out_fname) { |
} else { |
*out_fname = bmake_strdup(tfile); |
unlink(tfile); /* we just want the descriptor */ |
} else { |
} |
unlink( |
return fd; |
tfile); /* we just want the descriptor */ |
|
} |
|
return fd; |
} |
} |
|
|
/* |
/* |
Line 2239 mkTempFile(const char *pattern, char **o |
|
Line 2242 mkTempFile(const char *pattern, char **o |
|
Boolean |
Boolean |
ParseBoolean(const char *s, Boolean bf) |
ParseBoolean(const char *s, Boolean bf) |
{ |
{ |
switch(s[0]) { |
switch (s[0]) { |
case '\0': /* not set - the default wins */ |
case '\0': /* not set - the default wins */ |
break; |
break; |
case '0': |
case '0': |
case 'F': |
case 'F': |
case 'f': |
case 'f': |
case 'N': |
case 'N': |
case 'n': |
case 'n': |
return FALSE; |
return FALSE; |
case 'O': |
case 'O': |
case 'o': |
case 'o': |
return s[1] != 'F' && s[1] != 'f'; |
return s[1] != 'F' && s[1] != 'f'; |
default: |
default: |
return TRUE; |
return TRUE; |
} |
} |
return bf; |
return bf; |
} |
} |