summaryrefslogtreecommitdiffstats
path: root/misc-utils/script.c
diff options
context:
space:
mode:
authorKarel Zak2010-04-27 12:11:31 +0200
committerKarel Zak2010-04-27 12:11:31 +0200
commitf1014a4f33b67ccd15baff4d07fbb09f5660028b (patch)
tree1028e0916c0e9dacde8a9bf776015cd72a0289c5 /misc-utils/script.c
parentlogger: add note about 'kern' to the man page (diff)
downloadkernel-qcow2-util-linux-f1014a4f33b67ccd15baff4d07fbb09f5660028b.tar.gz
kernel-qcow2-util-linux-f1014a4f33b67ccd15baff4d07fbb09f5660028b.tar.xz
kernel-qcow2-util-linux-f1014a4f33b67ccd15baff4d07fbb09f5660028b.zip
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@gmail.com. Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'misc-utils/script.c')
-rw-r--r--misc-utils/script.c48
1 files changed, 30 insertions, 18 deletions
diff --git a/misc-utils/script.c b/misc-utils/script.c
index b877c3129..e3ccb1a18 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);
}