FreeBSD Bugzilla – Attachment 198594 Details for
Bug 224270
Get exit status of process that's piped to another: set -o pipefail is missing for /bin/sh
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
my set -o pipefail patch
sh-pipefail-jilles.patch (text/plain), 6.95 KB, created by
Jilles Tjoelker
on 2018-10-24 18:22:04 UTC
(
hide
)
Description:
my set -o pipefail patch
Filename:
MIME Type:
Creator:
Jilles Tjoelker
Created:
2018-10-24 18:22:04 UTC
Size:
6.95 KB
patch
obsolete
>commit 418e2c1259fbb22cb488bb7eccdfe39b0c7df68f >Author: Jilles Tjoelker <jilles@stack.nl> >Date: Thu Dec 21 00:29:48 2017 +0100 > > sh: Add set -o pipefail > > The pipefail option allows checking the exit status of all commands in a > pipeline more easily, at a limited cost of complexity in sh itself. It works > similarly to the option in bash, ksh93 and mksh. > > Like ksh93 and unlike bash and mksh, the state of the option is saved when a > pipeline is started. Therefore, even in the case of commands like > A | B & > a later change of the option does not change the exit status, the same way > (A | B) & > works. > > Since SIGPIPE is not handled specially, more work in the script is required > for a proper exit status for pipelines containing commands such as head that > may terminate successfully without reading all input. This can be something > like > > ( > cmd1 > r=$? > if [ "$r" -gt 128 ] && [ "$(kill -l "$r")" = PIPE ]; then > exit 0 > else > exit "$r" > fi > ) | head > > PR: 224270 > >diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c >index 6fd4241fa687..04af0d6d82b9 100644 >--- a/bin/sh/jobs.c >+++ b/bin/sh/jobs.c >@@ -104,6 +104,7 @@ struct job { > char changed; /* true if status has changed */ > char foreground; /* true if running in the foreground */ > char remembered; /* true if $! referenced */ >+ char pipefail; /* pass any non-zero status */ > #if JOBS > char jobctl; /* job running under job control */ > struct job *next; /* job used after this one */ >@@ -143,6 +144,7 @@ static void setcurjob(struct job *); > static void deljob(struct job *); > static struct job *getcurjob(struct job *); > #endif >+static int getjobstatus(const struct job *); > static void printjobcmd(struct job *); > static void showjob(struct job *, int); > >@@ -340,6 +342,20 @@ jobscmd(int argc __unused, char *argv[] __unused) > return (0); > } > >+static int getjobstatus(const struct job *jp) >+{ >+ int i, status; >+ >+ if (!jp->pipefail) >+ return (jp->ps[jp->nprocs - 1].status); >+ for (i = jp->nprocs - 1; i >= 0; i--) { >+ status = jp->ps[i].status; >+ if (status != 0) >+ return (status); >+ } >+ return (0); >+} >+ > static void > printjobcmd(struct job *jp) > { >@@ -376,7 +392,7 @@ showjob(struct job *jp, int mode) > } > #endif > coredump = ""; >- status = jp->ps[jp->nprocs - 1].status; >+ status = getjobstatus(jp); > if (jp->state == 0) { > statestr = "Running"; > #if JOBS >@@ -555,7 +571,7 @@ waitcmdloop(struct job *job) > do { > if (job != NULL) { > if (job->state == JOBDONE) { >- status = job->ps[job->nprocs - 1].status; >+ status = getjobstatus(job); > if (WIFEXITED(status)) > retval = WEXITSTATUS(status); > else >@@ -780,6 +796,7 @@ makejob(union node *node __unused, int nprocs) > jp->nprocs = 0; > jp->foreground = 0; > jp->remembered = 0; >+ jp->pipefail = pipefailflag; > #if JOBS > jp->jobctl = jobctl; > jp->next = NULL; >@@ -1075,7 +1092,7 @@ waitforjob(struct job *jp, int *signaled) > if (jp->state == JOBSTOPPED) > setcurjob(jp); > #endif >- status = jp->ps[jp->nprocs - 1].status; >+ status = getjobstatus(jp); > if (signaled != NULL) > *signaled = WIFSIGNALED(status); > /* convert to 8 bits */ >diff --git a/bin/sh/options.h b/bin/sh/options.h >index b3819cc2795e..500d4ad5a903 100644 >--- a/bin/sh/options.h >+++ b/bin/sh/options.h >@@ -67,9 +67,10 @@ struct shparam { > #define Pflag optval[17] > #define hflag optval[18] > #define nologflag optval[19] >+#define pipefailflag optval[20] > > #define NSHORTOPTS 19 >-#define NOPTS 20 >+#define NOPTS 21 > > extern char optval[NOPTS]; > extern const char optletter[NSHORTOPTS]; >@@ -97,6 +98,7 @@ static const unsigned char optname[] = > "\010physical" > "\010trackall" > "\005nolog" >+ "\010pipefail" > ; > #endif > >diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 >index 98ec2f2c219b..5dba170f5ab8 100644 >--- a/bin/sh/sh.1 >+++ b/bin/sh/sh.1 >@@ -348,6 +348,18 @@ Another do-nothing option for > .Tn POSIX > compliance. > It only has a long name. >+.It Li pipefail >+Change the exit status of a pipeline to the last non-zero exit status of >+any command in the pipeline, if any. >+Since an exit due to >+.Dv SIGPIPE >+counts as a non-zero exit status, >+this option may cause non-zero exit status for successful pipelines >+if a command such as >+.Xr head 1 >+in the pipeline terminates with status 0 without reading its >+input completely. >+This option only has a long name. > .El > .Pp > The >@@ -865,12 +877,15 @@ If the keyword > .Ic !\& > does not precede the pipeline, the > exit status is the exit status of the last command specified >-in the pipeline. >+in the pipeline if the >+.Cm pipefail >+option is not set or all commands returned zero, >+or the last non-zero exit status of any command in the pipeline otherwise. > Otherwise, the exit status is the logical >-NOT of the exit status of the last command. >+NOT of that exit status. > That is, if >-the last command returns zero, the exit status is 1; if >-the last command returns greater than zero, the exit status >+that status is zero, the exit status is 1; if >+that status is greater than zero, the exit status > is zero. > .Pp > Because pipeline assignment of standard input or standard >diff --git a/bin/sh/tests/execution/pipefail1.0 b/bin/sh/tests/execution/pipefail1.0 >new file mode 100644 >index 000000000000..df23a012ca07 >--- /dev/null >+++ b/bin/sh/tests/execution/pipefail1.0 >@@ -0,0 +1,4 @@ >+# $FreeBSD$ >+ >+set -o pipefail >+: && : | : && : | : | : && : | : | : | : >diff --git a/bin/sh/tests/execution/pipefail2.42 b/bin/sh/tests/execution/pipefail2.42 >new file mode 100644 >index 000000000000..b9092661c76e >--- /dev/null >+++ b/bin/sh/tests/execution/pipefail2.42 >@@ -0,0 +1,4 @@ >+# $FreeBSD$ >+ >+set -o pipefail >+(exit 42) | : >diff --git a/bin/sh/tests/execution/pipefail3.42 b/bin/sh/tests/execution/pipefail3.42 >new file mode 100644 >index 000000000000..d96602b57f02 >--- /dev/null >+++ b/bin/sh/tests/execution/pipefail3.42 >@@ -0,0 +1,4 @@ >+# $FreeBSD$ >+ >+set -o pipefail >+: | (exit 42) >diff --git a/bin/sh/tests/execution/pipefail4.42 b/bin/sh/tests/execution/pipefail4.42 >new file mode 100644 >index 000000000000..3399dd8c4452 >--- /dev/null >+++ b/bin/sh/tests/execution/pipefail4.42 >@@ -0,0 +1,4 @@ >+# $FreeBSD$ >+ >+set -o pipefail >+(exit 43) | (exit 42) >diff --git a/bin/sh/tests/execution/pipefail5.42 b/bin/sh/tests/execution/pipefail5.42 >new file mode 100644 >index 000000000000..4effb2b3301e >--- /dev/null >+++ b/bin/sh/tests/execution/pipefail5.42 >@@ -0,0 +1,5 @@ >+# $FreeBSD$ >+ >+set -o pipefail >+(exit 42) | : & >+wait %+ >diff --git a/bin/sh/tests/execution/pipefail6.42 b/bin/sh/tests/execution/pipefail6.42 >new file mode 100644 >index 000000000000..7395d8c785a6 >--- /dev/null >+++ b/bin/sh/tests/execution/pipefail6.42 >@@ -0,0 +1,6 @@ >+# $FreeBSD$ >+ >+set -o pipefail >+(exit 42) | : & >+set +o pipefail >+wait %+ >diff --git a/bin/sh/tests/execution/pipefail7.0 b/bin/sh/tests/execution/pipefail7.0 >new file mode 100644 >index 000000000000..797d485f3c61 >--- /dev/null >+++ b/bin/sh/tests/execution/pipefail7.0 >@@ -0,0 +1,5 @@ >+# $FreeBSD$ >+ >+(exit 42) | : & >+set -o pipefail >+wait %+
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 224270
:
198515
| 198594