version 1.130, 2012/10/09 19:46:33 |
version 1.131, 2012/10/18 17:54:43 |
|
|
static void debug_kill_printf(const char *, ...); |
static void debug_kill_printf(const char *, ...); |
static void debug_vprintf(const char *, va_list); |
static void debug_vprintf(const char *, va_list); |
static void may_remove_target(Job *); |
static void may_remove_target(Job *); |
|
static const char *really_kill(Job *, int); |
|
static void print_error(Job *); |
|
static void internal_print_errors(void); |
|
|
|
static int dying_signal = 0; |
|
|
|
const char * basedirectory = NULL; |
|
|
static void |
static void |
kill_with_sudo_maybe(pid_t pid, int signo, const char *p) |
kill_with_sudo_maybe(pid_t pid, int signo, const char *p) |
{ |
{ |
|
|
really_kill(Job *job, int signo) |
really_kill(Job *job, int signo) |
{ |
{ |
pid_t pid = job->pid; |
pid_t pid = job->pid; |
job->sent_signal = signo; |
|
if (getpgid(pid) != getpgrp()) { |
if (getpgid(pid) != getpgrp()) { |
if (killpg(pid, signo) == 0) |
if (killpg(pid, signo) == 0) |
return "group got signal"; |
return "group got signal"; |
|
|
static void |
static void |
may_remove_target(Job *j) |
may_remove_target(Job *j) |
{ |
{ |
if ((j->sent_signal == SIGINT || j->sent_signal == SIGQUIT || |
int dying = check_dying_signal(); |
j->sent_signal == SIGHUP || j->sent_signal == SIGTERM) |
|
&& !noExecute && !Targ_Precious(j->node)) { |
if (dying && !noExecute && !Targ_Precious(j->node)) { |
const char *file = Var(TARGET_INDEX, j->node); |
const char *file = Var(TARGET_INDEX, j->node); |
int r = eunlink(file); |
int r = eunlink(file); |
|
|
|
|
} |
} |
} |
} |
|
|
|
static void |
|
buf_addcurdir(BUFFER *buf) |
|
{ |
|
const char *v = Var_Value(".CURDIR"); |
|
if (basedirectory != NULL) { |
|
size_t len = strlen(basedirectory); |
|
if (strncmp(basedirectory, v, len) == 0 && |
|
v[len] == '/') { |
|
v += len+1; |
|
} else if (strcmp(basedirectory, v) == 0) { |
|
Buf_AddString(buf, "."); |
|
return; |
|
} |
|
} |
|
Buf_AddString(buf, v); |
|
} |
|
|
|
static const char * |
|
shortened_curdir(void) |
|
{ |
|
static BUFFER buf; |
|
bool first = true; |
|
if (first) { |
|
Buf_Init(&buf, 0); |
|
buf_addcurdir(&buf); |
|
first = false; |
|
} |
|
return Buf_Retrieve(&buf); |
|
} |
|
|
static void |
static void |
|
quick_error(Job *j, int signo, bool first) |
|
{ |
|
if (first) { |
|
fprintf(stderr, "*** Signal SIG%s", sys_signame[signo]); |
|
fprintf(stderr, " in %s (", shortened_curdir()); |
|
} else |
|
fprintf(stderr, " "); |
|
|
|
fprintf(stderr, "%s", j->node->name); |
|
free(j->cmd); |
|
} |
|
|
|
static void |
print_error(Job *j) |
print_error(Job *j) |
{ |
{ |
static bool first = true; |
static bool first = true; |
|
BUFFER buf; |
|
|
if (j->exit_type == JOB_EXIT_BAD) { |
Buf_Init(&buf, 0); |
fprintf(stderr, "*** Error %d", j->code); |
|
if (j->sent_signal != 0 && j->code == j->sent_signal + 128) |
if (j->exit_type == JOB_EXIT_BAD) |
fprintf(stderr, " (SIG%s in shell)", |
Buf_printf(&buf, "*** Error %d", j->code); |
sys_signame[j->sent_signal]); |
else if (j->exit_type == JOB_SIGNALED) { |
} else if (j->exit_type == JOB_SIGNALED) { |
|
if (j->code < NSIG) |
if (j->code < NSIG) |
fprintf(stderr, "*** Signal SIG%s", |
Buf_printf(&buf, "*** Signal SIG%s", |
sys_signame[j->code]); |
sys_signame[j->code]); |
else |
else |
fprintf(stderr, "*** unknown signal %d", j->code); |
Buf_printf(&buf, "*** unknown signal %d", j->code); |
} else |
} else |
fprintf(stderr, "*** Should not happen %d", j->code); |
Buf_printf(&buf, "*** Should not happen %d/%d", |
|
j->exit_type, j->code); |
if (DEBUG(KILL) && (j->flags & JOB_LOST)) |
if (DEBUG(KILL) && (j->flags & JOB_LOST)) |
fprintf(stderr, "!"); |
Buf_AddChar(&buf, '!'); |
if (first) { |
if (first) { |
fprintf(stderr, " in %s", Var_Value(".CURDIR")); |
Buf_AddString(&buf, " in "); |
|
buf_addcurdir(&buf); |
first = false; |
first = false; |
} |
} |
fprintf(stderr, " (%s:%lu", j->location->fname, j->location->lineno); |
Buf_printf(&buf, " (%s:%lu", j->location->fname, j->location->lineno); |
fprintf(stderr, " '%s'", j->node->name); |
Buf_printf(&buf, " '%s'", j->node->name); |
if ((j->flags & (JOB_SILENT | JOB_IS_EXPENSIVE)) == JOB_SILENT) |
if ((j->flags & (JOB_SILENT | JOB_IS_EXPENSIVE)) == JOB_SILENT |
fprintf(stderr, ": %.120s%s", j->cmd, |
&& Buf_Size(&buf) < 140) { |
strlen(j->cmd) > 120 ? "..." : ""); |
size_t len = strlen(j->cmd); |
fprintf(stderr, ")\n"); |
Buf_AddString(&buf, ": "); |
|
if (len + Buf_Size(&buf) < 140) |
|
Buf_AddString(&buf, j->cmd); |
|
else { |
|
Buf_AddChars(&buf, 140 - Buf_Size(&buf), j->cmd); |
|
Buf_AddString(&buf, "..."); |
|
} |
|
} |
|
fprintf(stderr, "%s)\n", Buf_Retrieve(&buf)); |
|
Buf_Destroy(&buf); |
free(j->cmd); |
free(j->cmd); |
may_remove_target(j); |
|
} |
} |
|
static void |
|
quick_summary(int signo) |
|
{ |
|
Job *j, *k, *jnext; |
|
bool first = true; |
|
|
void |
k = errorJobs; |
print_errors(void) |
errorJobs = NULL; |
|
for (j = k; j != NULL; j = jnext) { |
|
jnext = j->next; |
|
if ((j->exit_type == JOB_EXIT_BAD && j->code == signo+128) || |
|
(j->exit_type == JOB_SIGNALED && j->code == signo)) { |
|
quick_error(j, signo, first); |
|
first = false; |
|
} else { |
|
j->next = errorJobs; |
|
errorJobs = j; |
|
} |
|
} |
|
if (!first) |
|
fprintf(stderr, ")\n"); |
|
} |
|
|
|
static void |
|
internal_print_errors() |
{ |
{ |
Job *j, *k, *jnext; |
Job *j, *k, *jnext; |
|
int dying; |
|
|
if (!errorJobs) |
if (!errorJobs) |
fprintf(stderr, "Stop in %s.\n", Var_Value(".CURDIR")); |
fprintf(stderr, "Stop in %s.\n", shortened_curdir()); |
|
|
|
for (j = errorJobs; j != NULL; j = j->next) |
|
may_remove_target(j); |
|
dying = check_dying_signal(); |
|
if (dying) |
|
quick_summary(dying); |
while (errorJobs != NULL) { |
while (errorJobs != NULL) { |
k = errorJobs; |
k = errorJobs; |
errorJobs = NULL; |
errorJobs = NULL; |
|
|
} |
} |
} |
} |
|
|
|
void |
|
print_errors(void) |
|
{ |
|
handle_all_signals(); |
|
internal_print_errors(); |
|
} |
|
|
static void |
static void |
setup_signal(int sig) |
setup_signal(int sig) |
{ |
{ |
|
|
|
|
if (length == 0) { |
if (length == 0) { |
Buf_Init(&buf, 0); |
Buf_Init(&buf, 0); |
Buf_printf(&buf, "%s in %s: ", Var_Value("MAKE"), Var_Value(".CURDIR")); |
Buf_printf(&buf, "%s in ", Var_Value("MAKE")); |
|
buf_addcurdir(&buf); |
|
Buf_AddString(&buf, ": "); |
length = Buf_Size(&buf); |
length = Buf_Size(&buf); |
} else |
} else |
Buf_Truncate(&buf, length); |
Buf_Truncate(&buf, length); |
|
|
fputs(Buf_Retrieve(&buf), stderr); |
fputs(Buf_Retrieve(&buf), stderr); |
} |
} |
|
|
|
int |
|
check_dying_signal(void) |
|
{ |
|
sigset_t set; |
|
if (dying_signal) |
|
return dying_signal; |
|
sigpending(&set); |
|
if (got_SIGINT || sigismember(&set, SIGINT)) |
|
return dying_signal = SIGINT; |
|
if (got_SIGHUP || sigismember(&set, SIGHUP)) |
|
return dying_signal = SIGHUP; |
|
if (got_SIGQUIT || sigismember(&set, SIGQUIT)) |
|
return dying_signal = SIGQUIT; |
|
if (got_SIGTERM || sigismember(&set, SIGTERM)) |
|
return dying_signal = SIGTERM; |
|
return 0; |
|
} |
|
|
void |
void |
handle_all_signals(void) |
handle_all_signals(void) |
{ |
{ |
|
|
handle_running_jobs(void) |
handle_running_jobs(void) |
{ |
{ |
sigset_t old; |
sigset_t old; |
|
|
/* reaping children in the presence of caught signals */ |
/* reaping children in the presence of caught signals */ |
|
|
/* first, we make sure to hold on new signals, to synchronize |
/* first, we make sure to hold on new signals, to synchronize |
|
|
|
|
debug_kill_printf("handle_fatal_signal(%d) called.\n", signo); |
debug_kill_printf("handle_fatal_signal(%d) called.\n", signo); |
|
|
|
dying_signal = signo; |
for (job = runningJobs; job != NULL; job = job->next) { |
for (job = runningJobs; job != NULL; job = job->next) { |
debug_kill_printf("passing to " |
debug_kill_printf("passing to " |
"child %ld running %s: %s\n", (long)job->pid, |
"child %ld running %s: %s\n", (long)job->pid, |
|
|
} |
} |
} |
} |
loop_handle_running_jobs(); |
loop_handle_running_jobs(); |
print_errors(); |
internal_print_errors(); |
|
|
/* die by that signal */ |
/* die by that signal */ |
sigprocmask(SIG_BLOCK, &sigset, NULL); |
sigprocmask(SIG_BLOCK, &sigset, NULL); |
|
|
kill(getpid(), signo); |
kill(getpid(), signo); |
sigprocmask(SIG_SETMASK, &emptyset, NULL); |
sigprocmask(SIG_SETMASK, &emptyset, NULL); |
/*NOTREACHED*/ |
/*NOTREACHED*/ |
|
fprintf(stderr, "This should never happen\n"); |
|
exit(1); |
} |
} |
|
|
/* |
/* |