Re: [PATCH] script: preserve child exit status

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Apr 22, 2010 at 01:49:51PM -0400, therealneworld@xxxxxxxxx wrote:
> On Fri, Mar 27, 2009 at 6:52 AM, Karel Zak <kzak@xxxxxxxxxx> wrote:
> > On Tue, Mar 10, 2009 at 09:49:56AM +0100, Karel Zak wrote:
> >> On Tue, Mar 03, 2009 at 12:19:03PM -0500, therealneworld@xxxxxxxxx wrote:
> >> > I was working on a project and need the abilities of script to record
> >> > the interaction but also needed to capture the exit status. I created
> >>
> >>  this request makes sense
> >
> >  I'm going to play with your patch later, we are before the next stable
> >  release now.
> 
> Did this change get added to script?

 Sorry, I forgot to add the patch ;-((

 Applied with some minor changes (see below) a few minutes ago, thanks.

    Karel


>From f1014a4f33b67ccd15baff4d07fbb09f5660028b Mon Sep 17 00:00:00 2001
From: Karel Zak <kzak@xxxxxxxxxx>
Date: Tue, 27 Apr 2010 12:11:31 +0200
Subject: [PATCH] script: preserve child exit status

The patch also removes unnecessary detection of child process
existence (by kill()). This code was replaces with SIGCHLD
hold/release around fork().

Based on the patch from therealneworld@xxxxxxxxxx

Signed-off-by: Karel Zak <kzak@xxxxxxxxxx>
---
 misc-utils/script.1 |    4 ++++
 misc-utils/script.c |   48 ++++++++++++++++++++++++++++++------------------
 2 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/misc-utils/script.1 b/misc-utils/script.1
index e017b63..24c6b57 100644
--- a/misc-utils/script.1
+++ b/misc-utils/script.1
@@ -41,6 +41,7 @@
 .Nm script
 .Op Fl a
 .Op Fl c Ar COMMAND
+.Op Fl e
 .Op Fl f
 .Op Fl q
 .Op Fl t
@@ -74,6 +75,9 @@ retaining the prior contents.
 Run the COMMAND rather than an interactive shell.
 This makes it easy for a script to capture the output of a program that
 behaves differently when its stdout is not a tty.
+.It Fl e
+Return the exit code of the child process. Uses the same format as bash
+termination on signal termination exit code is 128+n.
 .It Fl f
 Flush output after each write. This is nice for telecooperation:
 One person does `mkfifo foo; script -f foo' and another can
diff --git a/misc-utils/script.c b/misc-utils/script.c
index b877c31..e3ccb1a 100644
--- a/misc-utils/script.c
+++ b/misc-utils/script.c
@@ -81,6 +81,7 @@ int	master;
 int	slave;
 int	child;
 int	subchild;
+int	childstatus;
 char	*fname;
 
 struct	termios tt;
@@ -92,6 +93,7 @@ char	line[] = "/dev/ptyXX";
 #endif
 int	aflg = 0;
 char	*cflg = NULL;
+int	eflg = 0;
 int	fflg = 0;
 int	qflg = 0;
 int	tflg = 0;
@@ -127,6 +129,7 @@ die_if_link(char *fn) {
 
 int
 main(int argc, char **argv) {
+	sigset_t block_mask, unblock_mask;
 	struct sigaction sa;
 	extern int optind;
 	char *p;
@@ -150,7 +153,7 @@ main(int argc, char **argv) {
 		}
 	}
 
-	while ((ch = getopt(argc, argv, "ac:fqt")) != -1)
+	while ((ch = getopt(argc, argv, "ac:efqt")) != -1)
 		switch((char)ch) {
 		case 'a':
 			aflg++;
@@ -158,6 +161,9 @@ main(int argc, char **argv) {
 		case 'c':
 			cflg = optarg;
 			break;
+		case 'e':
+			eflg++;
+			break;
 		case 'f':
 			fflg++;
 			break;
@@ -170,7 +176,7 @@ main(int argc, char **argv) {
 		case '?':
 		default:
 			fprintf(stderr,
-				_("usage: script [-a] [-f] [-q] [-t] [file]\n"));
+				_("usage: script [-a] [-e] [-f] [-q] [-t] [file]\n"));
 			exit(1);
 		}
 	argc -= optind;
@@ -196,19 +202,30 @@ main(int argc, char **argv) {
 		printf(_("Script started, file is %s\n"), fname);
 	fixtty();
 
+	/* setup SIGCHLD handler */
 	sigemptyset(&sa.sa_mask);
 	sa.sa_flags = 0;
-
 	sa.sa_handler = finish;
 	sigaction(SIGCHLD, &sa, NULL);
 
+	/* init mask for SIGCHLD */
+	sigprocmask(SIG_SETMASK, NULL, &block_mask);
+	sigaddset(&block_mask, SIGCHLD);
+
+	sigprocmask(SIG_SETMASK, &block_mask, &unblock_mask);
 	child = fork();
+	sigprocmask(SIG_SETMASK, &unblock_mask, NULL);
+
 	if (child < 0) {
 		perror("fork");
 		fail();
 	}
 	if (child == 0) {
+
+		sigprocmask(SIG_SETMASK, &block_mask, NULL);
 		subchild = child = fork();
+		sigprocmask(SIG_SETMASK, &unblock_mask, NULL);
+
 		if (child < 0) {
 			perror("fork");
 			fail();
@@ -233,9 +250,6 @@ doinput() {
 
 	(void) fclose(fscript);
 
-	if (die == 0 && child && kill(child, 0) == -1 && errno == ESRCH)
-		die = 1;
-
 	while (die == 0) {
 		if ((cc = read(0, ibuf, BUFSIZ)) > 0) {
 			ssize_t wrt = write(master, ibuf, cc);
@@ -263,8 +277,10 @@ finish(int dummy) {
 	register int pid;
 
 	while ((pid = wait3(&status, WNOHANG, 0)) > 0)
-		if (pid == child)
+		if (pid == child) {
+			childstatus = status;
 			die = 1;
+		}
 }
 
 void
@@ -303,17 +319,6 @@ dooutput() {
 	my_strftime(obuf, sizeof obuf, "%c\n", localtime(&tvec));
 	fprintf(fscript, _("Script started on %s"), obuf);
 
-	if (die == 0 && child && kill(child, 0) == -1 && errno == ESRCH)
-		/*
-		 * the SIGCHLD handler could be executed when the "child"
-		 * variable is not set yet. It means that the "die" is zero
-		 * althought the child process is already done. We have to
-		 * check this thing now. Now we have the "child" variable
-		 * already initialized. For more details see main() and
-		 * finish().  --kzak 07-Aug-2007
-		 */
-		die = 1;
-
 	do {
 		if (die && flgs == 0) {
 			/* ..child is dead, but it doesn't mean that there is
@@ -436,6 +441,13 @@ done() {
 		if (!qflg)
 			printf(_("Script done, file is %s\n"), fname);
 	}
+
+	if(eflg) {
+		if (WIFSIGNALED(childstatus))
+			exit(WTERMSIG(childstatus) + 0x80);
+		else
+			exit(WEXITSTATUS(childstatus));
+	}
 	exit(0);
 }
 
-- 
1.6.6

--
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux