From 3019c48804fb43f97d5c8e8ee15b5ae13ab1c4a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Fri, 9 Jul 2021 15:32:09 +0200 Subject: Use set -e, -x in shell process, handle exit status correctly This makes the default behavior like make(1), but it is configurable. Furthermore, it is still a single shell process, which is arguably a benefit. --- build.1 | 16 ++++------------ build.c | 34 +++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/build.1 b/build.1 index cf66324..10ae999 100644 --- a/build.1 +++ b/build.1 @@ -77,17 +77,9 @@ This means that you can keep state across multiple commands. Note that all commands are executed regardless of the exit status of previous commands. .Pp +If a command fails, .Nm -exits with a positive status if a command failed. -Note that it checks the status -of the entire command sent to the shell, -not the individual command lines. -To emulate the behavior of -.Xr make 1 , -which fails if any individual command line fails, -you can use -.Ql set -e -in your command line. +exits with a positive status and aborts the build process. . .Sh EXAMPLES .Pp @@ -120,8 +112,8 @@ Assuming that the file starts with the following text, .Bd -literal -offset indent \&.\\" This document is built with the following shell commands: -\&.\\" $ refer -p refs doc.t | troff -ms | dpost > doc.ps && -\&.\\" $ ps2pdf doc.ps > doc.pdf && +\&.\\" $ refer -p refs doc.t | troff -ms | dpost > doc.ps +\&.\\" $ ps2pdf doc.ps > doc.pdf \&.\\" $ rm doc.ps \&. \&.\\" Apart from this file, it depends on the following files: diff --git a/build.c b/build.c index fc21925..600ac92 100644 --- a/build.c +++ b/build.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #define USAGE "usage: %s file [...]\n", name @@ -32,7 +33,7 @@ main(int argc, char *argv[]) { char *b, buf[MAXBUF], *cmd[MAXCMDS], *d, *dep, *name, *tgt; FILE *fp; - int c, dflag, fflag, i, icmd, j, s, status; + int c, dflag, fflag, i, icmd, j, s; struct stat sb, ssb; /* allocate memory */ @@ -43,10 +44,9 @@ main(int argc, char *argv[]) dep = malloc(MAXDEP*sizeof(char)); if (!dep) err(1, "malloc"); tgt = malloc(MAXTGT*sizeof(char)); - if (!dep) err(1, "malloc"); + if (!tgt) err(1, "malloc"); tgt[0] = dep[0] = 0; - status = 0; /* process arguments */ name = argv[0]; @@ -85,13 +85,13 @@ main(int argc, char *argv[]) /* command line */ if (strncmp(b, " $ ", 3) == 0 || strncmp(b, " $ ", 3) == 0) { - strncpy(cmd[icmd++],b+3,MAXBUF-1); + strncpy(cmd[icmd++], b+3, MAXBUF-1); /* find target */ for (b = b+3; *b; b++) { if (!(*b+1)) continue; if (*b != '>') continue; - strncpy(tgt,b+1,MAXTGT-1); + strncpy(tgt, b+1, MAXTGT-1); } @@ -113,7 +113,7 @@ main(int argc, char *argv[]) if (!icmd) { fprintf(stderr, "%s: no command line found\n", argv[i]); - continue; + goto next; } if (fflag || !*tgt) @@ -153,25 +153,33 @@ main(int argc, char *argv[]) uptodate: fprintf(stderr, "%s: already up-to-date\n", argv[i]); - goto done; + goto next; build: /* run commands */ buf[0] = 0; + strcat(buf, "set -ex\n"); for (j = 0; j < icmd; j++) { - fprintf(stderr, "%s: $ %s\n", argv[i], cmd[j]); strncat(buf, cmd[j], MAXBUF-1); strncat(buf, "\n", MAXBUF-1); } s = system(buf); - if (s != -1) - status += s; + if (s == 0) + goto next; + + if (WIFEXITED(s)) { + fprintf(stderr, "%s: exited with %d\n", + argv[i], WEXITSTATUS(s)); + exit(WEXITSTATUS(s)); + } else if (WIFSIGNALED(s)) { + fprintf(stderr, "%s: terminated by signal %d\n", + argv[i], WTERMSIG(s)); + exit(1); + } -done: +next: fclose(fp); } - - return status > 0; } void -- cgit v1.2.3