util-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes
@ 2014-12-27 17:17 Sami Kerola
  2014-12-27 17:17 ` [PATCH 15/22] script: use signalfd() to catch signals Sami Kerola
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: Sami Kerola @ 2014-12-27 17:17 UTC (permalink / raw)
  To: util-linux; +Cc: Sami Kerola

Hi,

As I mentioned in

http://comments.gmane.org/gmane.linux.utilities.util-linux-ng/10390

the previous patch set was not complete.  The script(1) had signals and
io-streams race that is now fixed with changes 0015 to 0018.

The patches below can be also found from my github repository branch
'script'.

https://github.com/kerolasa/lelux-utiliteetit/tree/script


Sami Kerola (22):
  chsh: remove function prototypes
  chfn, chsh: share illegal_passwd_chars() function
  chsh: use getline() to support arbitrarily long lines
  chsh: set few variables read-only and rename one of them
  chsh: allow user to set shell to /bin/sh if none is set
  chsh: clean up parse_argv()
  chsh: rewrite function interacting with user to get path to new shell
  chsh: simplify check_shell()
  chsh: fail get_shell_list() check when /etc/shells cannot be opened
  newgrp: simplify if else clauses
  newgrp: move shell determination closer where it is used
  newgrp: set function arguments read-only when possible
  script: remove function prototypes
  script: add struct script_control and remove global variables
=== end of earlier submission ===
  script: use signalfd() to catch signals
  script: use poll() rather than select()
  script: merge doinput() and output() functions to do_io()
  script: remove io vs signal race
  script: add 'Script started' line always to capture file
  script: move do_io() content to small functions
  script: replace strftime() workaround with CFLAGS = -Wno-format-y2k
  script: use correct input type, move comment, and so on

 login-utils/Makemodule.am |   4 +-
 login-utils/ch-common.c   |  34 ++
 login-utils/ch-common.h   |   6 +
 login-utils/chfn.c        |  16 +-
 login-utils/chsh.c        | 365 +++++++++----------
 login-utils/newgrp.c      |  25 +-
 term-utils/Makemodule.am  |   1 +
 term-utils/script.c       | 866 ++++++++++++++++++++--------------------------
 tests/ts/script/race      |   4 -
 9 files changed, 594 insertions(+), 727 deletions(-)
 create mode 100644 login-utils/ch-common.c
 create mode 100644 login-utils/ch-common.h

-- 
2.2.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 15/22] script: use signalfd() to catch signals
  2014-12-27 17:17 [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes Sami Kerola
@ 2014-12-27 17:17 ` Sami Kerola
  2014-12-27 17:17 ` [PATCH 16/22] script: use poll() rather than select() Sami Kerola
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sami Kerola @ 2014-12-27 17:17 UTC (permalink / raw)
  To: util-linux; +Cc: Sami Kerola, Wolfgang Richter, Ruediger Meier

This is incomplete change.  Working command requires the subsequent
select() to poll() change as well.

Addresses: https://github.com/karelzak/util-linux/pull/62
CC: Wolfgang Richter <wolf@cs.cmu.edu>
CC: Ruediger Meier <ruediger.meier@ga-group.nl>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
---
 term-utils/script.c | 47 ++++++++++++++---------------------------------
 1 file changed, 14 insertions(+), 33 deletions(-)

diff --git a/term-utils/script.c b/term-utils/script.c
index 8f59fe8..315c46b 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -63,6 +63,8 @@
 #include <stddef.h>
 #include <sys/wait.h>
 #include <poll.h>
+#include <sys/signalfd.h>
+#include <assert.h>
 
 #include "closestream.h"
 #include "nls.h"
@@ -106,8 +108,8 @@ struct script_control {
 	 isterm:1,		/* is child process running as terminal */
 	 resized:1,		/* has terminal been resized */
 	 die:1;			/* terminate program */
-	sigset_t block_mask;	/* signals that are blocked */
-	sigset_t unblock_mask;	/* original signal mask */
+	sigset_t sigset;	/* catch SIGCHLD and SIGWINCH with signalfd() */
+	int sigfd;		/* file descriptor for signalfd() */
 };
 struct script_control *gctl;	/* global control structure, used in signal handlers */
 
@@ -245,16 +247,13 @@ static void doinput(struct script_control *ctl)
 
 	FD_ZERO(&readfds);
 
-	/* block SIGCHLD */
-	sigprocmask(SIG_SETMASK, &ctl->block_mask, &ctl->unblock_mask);
-
 	while (!ctl->die) {
 		FD_SET(STDIN_FILENO, &readfds);
 
 		errno = 0;
 		/* wait for input or signal (including SIGCHLD) */
 		if ((cc = pselect(STDIN_FILENO + 1, &readfds, NULL, NULL, NULL,
-				  &ctl->unblock_mask)) > 0) {
+				  NULL)) > 0) {
 
 			if ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0) {
 				if (write_all(ctl->master, ibuf, cc)) {
@@ -278,9 +277,6 @@ static void doinput(struct script_control *ctl)
 		}
 	}
 
-	/* unblock SIGCHLD */
-	sigprocmask(SIG_SETMASK, &ctl->unblock_mask, NULL);
-
 	/* To be sure that we don't miss any data */
 	wait_for_empty_fd(ctl, ctl->slave);
 	wait_for_empty_fd(ctl, ctl->master);
@@ -349,29 +345,24 @@ static void dooutput(struct script_control *ctl)
 	do {
 		if (ctl->die || errsv == EINTR) {
 			struct pollfd fds[] = {
+				{.fd = ctl->sigfd, .events = POLLIN | POLLERR | POLLHUP},
 				{.fd = ctl->master, .events = POLLIN}
 			};
 			if (poll(fds, 1, 50) <= 0)
 				break;
 		}
 
-		/* block SIGCHLD */
-		sigprocmask(SIG_SETMASK, &ctl->block_mask, &ctl->unblock_mask);
-
 		FD_SET(ctl->master, &readfds);
 		errno = 0;
 
 		/* wait for input or signal (including SIGCHLD) */
 		if ((cc = pselect(ctl->master + 1, &readfds, NULL, NULL, NULL,
-				  &ctl->unblock_mask)) > 0) {
+				  NULL)) > 0) {
 
 			cc = read(ctl->master, obuf, sizeof(obuf));
 		}
 		errsv = errno;
 
-		/* unblock SIGCHLD */
-		sigprocmask(SIG_SETMASK, &ctl->unblock_mask, NULL);
-
 		if (ctl->tflg)
 			gettimeofday(&tv, NULL);
 
@@ -562,7 +553,6 @@ int main(int argc, char **argv)
 		.master = -1,
 		0
 	};
-	struct sigaction sa;
 	int ch;
 
 	enum { FORCE_OPTION = CHAR_MAX + 1 };
@@ -650,19 +640,15 @@ int main(int argc, char **argv)
 #ifdef HAVE_LIBUTEMPTER
 	utempter_add_record(master, NULL);
 #endif
-	/* setup SIGCHLD handler */
-	sigemptyset(&sa.sa_mask);
-	sa.sa_flags = 0;
-	sa.sa_handler = sig_finish;
-	sigaction(SIGCHLD, &sa, NULL);
-
-	/* init mask for SIGCHLD */
-	sigprocmask(SIG_SETMASK, NULL, &ctl.block_mask);
-	sigaddset(&ctl.block_mask, SIGCHLD);
+	/* setup signal handler */
+	assert(sigemptyset(&ctl.sigset) == 0);
+	assert(sigaddset(&ctl.sigset, SIGCHLD) == 0);
+	assert(sigaddset(&ctl.sigset, SIGWINCH) == 0);
+	assert(sigprocmask(SIG_BLOCK, &ctl.sigset, NULL) == 0);
+	if ((ctl.sigfd = signalfd(-1, &ctl.sigset, 0)) < 0)
+		err(EXIT_FAILURE, _("cannot set signal handler"));
 
-	sigprocmask(SIG_SETMASK, &ctl.block_mask, &ctl.unblock_mask);
 	ctl.child = fork();
-	sigprocmask(SIG_SETMASK, &ctl.unblock_mask, NULL);
 
 	if (ctl.child < 0) {
 		warn(_("fork failed"));
@@ -670,9 +656,7 @@ int main(int argc, char **argv)
 	}
 	if (ctl.child == 0) {
 
-		sigprocmask(SIG_SETMASK, &ctl.block_mask, NULL);
 		ctl.subchild = ctl.child = fork();
-		sigprocmask(SIG_SETMASK, &ctl.unblock_mask, NULL);
 
 		if (ctl.child < 0) {
 			warn(_("fork failed"));
@@ -682,9 +666,6 @@ int main(int argc, char **argv)
 			dooutput(&ctl);
 		else
 			doshell(&ctl);
-	} else {
-		sa.sa_handler = resize;
-		sigaction(SIGWINCH, &sa, NULL);
 	}
 	doinput(&ctl);
 
-- 
2.2.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 16/22] script: use poll() rather than select()
  2014-12-27 17:17 [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes Sami Kerola
  2014-12-27 17:17 ` [PATCH 15/22] script: use signalfd() to catch signals Sami Kerola
@ 2014-12-27 17:17 ` Sami Kerola
  2014-12-27 17:17 ` [PATCH 17/22] script: merge doinput() and output() functions to do_io() Sami Kerola
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sami Kerola @ 2014-12-27 17:17 UTC (permalink / raw)
  To: util-linux; +Cc: Sami Kerola, Wolfgang Richter, Ruediger Meier

Finalize the signalfd() change by adding file descriptors to poll() loop.

Addresses: https://github.com/karelzak/util-linux/pull/62
CC: Wolfgang Richter <wolf@cs.cmu.edu>
CC: Ruediger Meier <ruediger.meier@ga-group.nl>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
---
 term-utils/script.c | 202 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 114 insertions(+), 88 deletions(-)

diff --git a/term-utils/script.c b/term-utils/script.c
index 315c46b..456355e 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -82,6 +82,8 @@
 
 #define DEFAULT_OUTPUT "typescript"
 
+enum { POLLFDS = 2 };
+
 struct script_control {
 	char *shell;		/* shell to be executed */
 	char *cflg;		/* command to be executed */
@@ -106,12 +108,10 @@ struct script_control {
 	 tflg:1,		/* include timing file */
 	 forceflg:1,		/* write output to links */
 	 isterm:1,		/* is child process running as terminal */
-	 resized:1,		/* has terminal been resized */
 	 die:1;			/* terminate program */
 	sigset_t sigset;	/* catch SIGCHLD and SIGWINCH with signalfd() */
 	int sigfd;		/* file descriptor for signalfd() */
 };
-struct script_control *gctl;	/* global control structure, used in signal handlers */
 
 static void __attribute__((__noreturn__)) usage(FILE *out)
 {
@@ -233,10 +233,10 @@ static void finish(struct script_control *ctl, int wait)
 
 static void doinput(struct script_control *ctl)
 {
-	int errsv = 0;
-	ssize_t cc = 0;
 	char ibuf[BUFSIZ];
-	fd_set readfds;
+	struct pollfd pfd[POLLFDS];
+	int ret, i;
+	ssize_t bytes;
 
 	/* close things irrelevant for this process */
 	if (ctl->typescriptfp)
@@ -245,35 +245,49 @@ static void doinput(struct script_control *ctl)
 		fclose(ctl->timingfp);
 	ctl->typescriptfp = ctl->timingfp = NULL;
 
-	FD_ZERO(&readfds);
+	pfd[0].fd = STDIN_FILENO;
+	pfd[0].events = POLLIN;
+	pfd[1].fd = ctl->sigfd;
+	pfd[1].events = POLLIN | POLLERR | POLLHUP;
 
 	while (!ctl->die) {
-		FD_SET(STDIN_FILENO, &readfds);
-
-		errno = 0;
-		/* wait for input or signal (including SIGCHLD) */
-		if ((cc = pselect(STDIN_FILENO + 1, &readfds, NULL, NULL, NULL,
-				  NULL)) > 0) {
-
-			if ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0) {
-				if (write_all(ctl->master, ibuf, cc)) {
+		/* wait for input or signal */
+		ret = poll(pfd, POLLFDS, -1);
+		if (ret < 0) {
+			if (errno == EAGAIN)
+				continue;
+			warn(_("poll failed"));
+			fail(ctl);
+		}
+		for (i = 0; i < POLLFDS; i++) {
+			if (pfd[i].revents == 0)
+				continue;
+			if (i == 0 && (bytes = read(pfd[i].fd, ibuf, BUFSIZ)) > 0) {
+				if (write_all(ctl->master, ibuf, bytes)) {
 					warn(_("write failed"));
 					fail(ctl);
 				}
 			}
-		}
-
-		if (cc < 0 && errno == EINTR && ctl->resized) {
-			/* transmit window change information to the child */
-			if (ctl->isterm) {
-				ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
-				ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
+			if (i == 1) {
+				struct signalfd_siginfo info;
+				ssize_t bytes;
+
+				bytes = read(pfd[i].fd, &info, sizeof(info));
+				assert(bytes == sizeof(info));
+				switch (info.ssi_signo) {
+				case SIGCHLD:
+					finish(ctl, 0);
+					break;
+				case SIGWINCH:
+					if (ctl->isterm) {
+						ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
+						ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
+					}
+					break;
+				default:
+					abort();
+				}
 			}
-			ctl->resized = 0;
-
-		} else if (cc <= 0 && errno != EINTR) {
-			errsv = errno;
-			break;
 		}
 	}
 
@@ -281,7 +295,7 @@ static void doinput(struct script_control *ctl)
 	wait_for_empty_fd(ctl, ctl->slave);
 	wait_for_empty_fd(ctl, ctl->master);
 
-	if (ctl->die == 0 && cc == 0 && errsv == 0) {
+	if (ctl->die == 0) {
 		/*
 		 * Forward EOF from stdin (detected by read() above) to slave
 		 * (shell) to correctly terminate the session. It seems we have
@@ -308,24 +322,41 @@ static void doinput(struct script_control *ctl)
 	done(ctl);
 }
 
-static void sig_finish(int dummy __attribute__((__unused__)))
+static void write_output(struct script_control *ctl, char *obuf,
+			    ssize_t bytes, double *oldtime)
 {
-	finish(gctl, 0);
-}
 
-static void resize(int dummy __attribute__((__unused__)))
-{
-	gctl->resized = 1;
+	if (ctl->tflg && ctl->timingfp) {
+		struct timeval tv;
+		double newtime;
+
+		gettimeofday(&tv, NULL);
+		newtime = tv.tv_sec + (double)tv.tv_usec / 1000000;
+		fprintf(ctl->timingfp, "%f %zd\n", newtime - *oldtime, bytes);
+		if (ctl->fflg)
+			fflush(ctl->timingfp);
+		*oldtime = newtime;
+	}
+	if (fwrite_all(obuf, 1, bytes, ctl->typescriptfp)) {
+		warn(_("cannot write script file"));
+		fail(ctl);
+	}
+	if (ctl->fflg)
+		fflush(ctl->typescriptfp);
+	if (write_all(STDOUT_FILENO, obuf, bytes)) {
+		warn(_("write failed"));
+		fail(ctl);
+	}
 }
 
+
 static void dooutput(struct script_control *ctl)
 {
-	ssize_t cc;
 	char obuf[BUFSIZ];
-	struct timeval tv;
-	double oldtime = time(NULL), newtime;
-	int errsv = 0;
-	fd_set readfds;
+	struct pollfd pfd[POLLFDS];
+	int ret, i;
+	ssize_t bytes;
+	double oldtime = time(NULL);
 
 	close(STDIN_FILENO);
 #ifdef HAVE_LIBUTIL
@@ -340,57 +371,53 @@ static void dooutput(struct script_control *ctl)
 		fprintf(ctl->typescriptfp, _("Script started on %s"), obuf);
 	}
 
-	FD_ZERO(&readfds);
-
-	do {
-		if (ctl->die || errsv == EINTR) {
-			struct pollfd fds[] = {
-				{.fd = ctl->sigfd, .events = POLLIN | POLLERR | POLLHUP},
-				{.fd = ctl->master, .events = POLLIN}
-			};
-			if (poll(fds, 1, 50) <= 0)
-				break;
-		}
-
-		FD_SET(ctl->master, &readfds);
-		errno = 0;
-
-		/* wait for input or signal (including SIGCHLD) */
-		if ((cc = pselect(ctl->master + 1, &readfds, NULL, NULL, NULL,
-				  NULL)) > 0) {
-
-			cc = read(ctl->master, obuf, sizeof(obuf));
-		}
-		errsv = errno;
-
-		if (ctl->tflg)
-			gettimeofday(&tv, NULL);
-
-		if (errsv == EINTR && cc <= 0)
-			continue;	/* try it again */
-		if (cc <= 0)
-			break;
-		if (ctl->tflg && ctl->timingfp) {
-			newtime = tv.tv_sec + (double)tv.tv_usec / 1000000;
-			fprintf(ctl->timingfp, "%f %zd\n", newtime - oldtime, cc);
-			oldtime = newtime;
-		}
-		if (fwrite_all(obuf, 1, cc, ctl->typescriptfp)) {
-			warn(_("cannot write script file"));
+	pfd[0].fd = ctl->master;
+	pfd[0].events = POLLIN;
+	pfd[1].fd = ctl->sigfd;
+	pfd[1].events = POLLIN | POLLERR | POLLHUP;
+
+	while (1) {
+		/* wait for input or signal */
+		ret = poll(pfd, POLLFDS, -1);
+		if (ret < 0) {
+			if (errno == EAGAIN)
+				continue;
+			warn(_("poll failed"));
 			fail(ctl);
 		}
-		if (ctl->fflg) {
-			fflush(ctl->typescriptfp);
-			if (ctl->tflg && ctl->timingfp)
-				fflush(ctl->timingfp);
-		}
-		if (write_all(STDOUT_FILENO, obuf, cc)) {
-			warn(_("write failed"));
-			fail(ctl);
+		for (i = 0; i < POLLFDS; i++) {
+			if (pfd[i].revents == 0)
+				continue;
+			if (i == 0) {
+				bytes = read(pfd[i].fd, obuf, BUFSIZ);
+				if (bytes < 0) {
+					if (errno == EAGAIN)
+						continue;
+					fail(ctl);
+				}
+				write_output(ctl, obuf, bytes, &oldtime);
+				continue;
+			}
+			if (i == 1) {
+				struct signalfd_siginfo info;
+				ssize_t bytes;
+
+				bytes = read(pfd[i].fd, &info, sizeof(info));
+				assert(bytes == sizeof(info));
+				switch (info.ssi_signo) {
+				case SIGCHLD:
+					done(ctl);
+					break;
+				case SIGWINCH:
+					/* nothing */
+					break;
+				default:
+					abort();
+				}
+			}
 		}
-	} while (1);
-
-	done(ctl);
+	}
+	abort();
 }
 
 static void getslave(struct script_control *ctl)
@@ -575,7 +602,6 @@ int main(int argc, char **argv)
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 	atexit(close_stdout);
-	gctl = &ctl;
 
 	while ((ch = getopt_long(argc, argv, "ac:efqt::Vh", longopts, NULL)) != -1)
 		switch (ch) {
-- 
2.2.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 17/22] script: merge doinput() and output() functions to do_io()
  2014-12-27 17:17 [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes Sami Kerola
  2014-12-27 17:17 ` [PATCH 15/22] script: use signalfd() to catch signals Sami Kerola
  2014-12-27 17:17 ` [PATCH 16/22] script: use poll() rather than select() Sami Kerola
@ 2014-12-27 17:17 ` Sami Kerola
  2014-12-27 17:17 ` [PATCH 18/22] script: remove io vs signal race Sami Kerola
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sami Kerola @ 2014-12-27 17:17 UTC (permalink / raw)
  To: util-linux; +Cc: Sami Kerola, Wolfgang Richter, Ruediger Meier

One item to poll() more is a lot less work for system than separete input
and output processes.

Addresses: https://github.com/karelzak/util-linux/pull/62
CC: Wolfgang Richter <wolf@cs.cmu.edu>
CC: Ruediger Meier <ruediger.meier@ga-group.nl>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
---
 term-utils/script.c | 220 ++++++++++++----------------------------------------
 1 file changed, 51 insertions(+), 169 deletions(-)

diff --git a/term-utils/script.c b/term-utils/script.c
index 456355e..4a761c6 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -82,7 +82,7 @@
 
 #define DEFAULT_OUTPUT "typescript"
 
-enum { POLLFDS = 2 };
+enum { POLLFDS = 3 };
 
 struct script_control {
 	char *shell;		/* shell to be executed */
@@ -93,7 +93,6 @@ struct script_control {
 	int master;		/* pseudoterminal master file descriptor */
 	int slave;		/* pseudoterminal slave file descriptor */
 	pid_t child;		/* child pid */
-	pid_t subchild;		/* subchild pid */
 	int childstatus;	/* child process exit value */
 	struct termios tt;	/* slave terminal runtime attributes */
 	struct winsize win;	/* terminal window size */
@@ -157,39 +156,15 @@ static void my_strftime(char *buf, size_t len, const char *fmt, const struct tm
 
 static void __attribute__((__noreturn__)) done(struct script_control *ctl)
 {
-	time_t tvec;
-
-	if (ctl->subchild) {
-		/* output process */
-		if (ctl->typescriptfp) {
-			if (!ctl->qflg) {
-				char buf[BUFSIZ];
-				tvec = time((time_t *)NULL);
-				my_strftime(buf, sizeof buf, "%c\n", localtime(&tvec));
-				fprintf(ctl->typescriptfp, _("\nScript done on %s"), buf);
-			}
-			if (close_stream(ctl->typescriptfp) != 0)
-				errx(EXIT_FAILURE, _("write error"));
-			ctl->typescriptfp = NULL;
-		}
-		if (ctl->timingfp && close_stream(ctl->timingfp) != 0)
-			errx(EXIT_FAILURE, _("write error"));
-		ctl->timingfp = NULL;
-
-		close(ctl->master);
-		ctl->master = -1;
-	} else {
-		/* input process */
-		if (ctl->isterm)
-			tcsetattr(STDIN_FILENO, TCSADRAIN, &ctl->tt);
-		if (!ctl->qflg)
-			printf(_("Script done, file is %s\n"), ctl->fname);
+	if (ctl->isterm)
+		tcsetattr(STDIN_FILENO, TCSADRAIN, &ctl->tt);
+	if (!ctl->qflg)
+		printf(_("Script done, file is %s\n"), ctl->fname);
 #ifdef HAVE_LIBUTEMPTER
-		if (ctl->master >= 0)
-			utempter_remove_record(ctl->master);
+	if (ctl->master >= 0)
+		utempter_remove_record(ctl->master);
 #endif
-		kill(ctl->child, SIGTERM);	/* make sure we don't create orphans */
-	}
+	kill(ctl->child, SIGTERM);	/* make sure we don't create orphans */
 
 	if (ctl->eflg) {
 		if (WIFSIGNALED(ctl->childstatus))
@@ -206,15 +181,6 @@ static void fail(struct script_control *ctl)
 	done(ctl);
 }
 
-static void wait_for_empty_fd(struct script_control *ctl, int fd)
-{
-	struct pollfd fds[] = {
-		{.fd = fd, .events = POLLIN}
-	};
-
-	while (ctl->die == 0 && poll(fds, 1, 100) == 1) ;
-}
-
 static void finish(struct script_control *ctl, int wait)
 {
 	int status;
@@ -231,97 +197,6 @@ static void finish(struct script_control *ctl, int wait)
 	errno = errsv;
 }
 
-static void doinput(struct script_control *ctl)
-{
-	char ibuf[BUFSIZ];
-	struct pollfd pfd[POLLFDS];
-	int ret, i;
-	ssize_t bytes;
-
-	/* close things irrelevant for this process */
-	if (ctl->typescriptfp)
-		fclose(ctl->typescriptfp);
-	if (ctl->timingfp)
-		fclose(ctl->timingfp);
-	ctl->typescriptfp = ctl->timingfp = NULL;
-
-	pfd[0].fd = STDIN_FILENO;
-	pfd[0].events = POLLIN;
-	pfd[1].fd = ctl->sigfd;
-	pfd[1].events = POLLIN | POLLERR | POLLHUP;
-
-	while (!ctl->die) {
-		/* wait for input or signal */
-		ret = poll(pfd, POLLFDS, -1);
-		if (ret < 0) {
-			if (errno == EAGAIN)
-				continue;
-			warn(_("poll failed"));
-			fail(ctl);
-		}
-		for (i = 0; i < POLLFDS; i++) {
-			if (pfd[i].revents == 0)
-				continue;
-			if (i == 0 && (bytes = read(pfd[i].fd, ibuf, BUFSIZ)) > 0) {
-				if (write_all(ctl->master, ibuf, bytes)) {
-					warn(_("write failed"));
-					fail(ctl);
-				}
-			}
-			if (i == 1) {
-				struct signalfd_siginfo info;
-				ssize_t bytes;
-
-				bytes = read(pfd[i].fd, &info, sizeof(info));
-				assert(bytes == sizeof(info));
-				switch (info.ssi_signo) {
-				case SIGCHLD:
-					finish(ctl, 0);
-					break;
-				case SIGWINCH:
-					if (ctl->isterm) {
-						ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
-						ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
-					}
-					break;
-				default:
-					abort();
-				}
-			}
-		}
-	}
-
-	/* To be sure that we don't miss any data */
-	wait_for_empty_fd(ctl, ctl->slave);
-	wait_for_empty_fd(ctl, ctl->master);
-
-	if (ctl->die == 0) {
-		/*
-		 * Forward EOF from stdin (detected by read() above) to slave
-		 * (shell) to correctly terminate the session. It seems we have
-		 * to wait for empty terminal FDs otherwise EOF maybe ignored
-		 * (why?) and typescript is incomplete.      -- kzak Dec-2013
-		 *
-		 * We usually use this when stdin is not a tty, for example:
-		 * echo "ps" | script
-		 */
-		int c = DEF_EOF;
-
-		if (write_all(ctl->master, &c, 1)) {
-			warn(_("write failed"));
-			fail(ctl);
-		}
-
-		/* wait for "exit" message from shell before we print "Script
-		 * done" in done() */
-		wait_for_empty_fd(ctl, ctl->master);
-	}
-
-	if (!ctl->die)
-		finish(ctl, 1);	/* wait for children */
-	done(ctl);
-}
-
 static void write_output(struct script_control *ctl, char *obuf,
 			    ssize_t bytes, double *oldtime)
 {
@@ -349,34 +224,31 @@ static void write_output(struct script_control *ctl, char *obuf,
 	}
 }
 
-
-static void dooutput(struct script_control *ctl)
+static void do_io(struct script_control *ctl)
 {
-	char obuf[BUFSIZ];
+	char buf[BUFSIZ];
 	struct pollfd pfd[POLLFDS];
 	int ret, i;
 	ssize_t bytes;
 	double oldtime = time(NULL);
 
-	close(STDIN_FILENO);
-#ifdef HAVE_LIBUTIL
-	close(ctl->slave);
-#endif
 	if (ctl->tflg && !ctl->timingfp)
 		ctl->timingfp = fdopen(STDERR_FILENO, "w");
 
+	pfd[0].fd = STDIN_FILENO;
+	pfd[0].events = POLLIN;
+	pfd[1].fd = ctl->master;
+	pfd[1].events = POLLIN;
+	pfd[2].fd = ctl->sigfd;
+	pfd[2].events = POLLIN | POLLERR | POLLHUP;
+
 	if (!ctl->qflg) {
 		time_t tvec = time((time_t *)NULL);
-		my_strftime(obuf, sizeof obuf, "%c\n", localtime(&tvec));
-		fprintf(ctl->typescriptfp, _("Script started on %s"), obuf);
+		my_strftime(buf, sizeof buf, "%c\n", localtime(&tvec));
+		fprintf(ctl->typescriptfp, _("Script started on %s"), buf);
 	}
 
-	pfd[0].fd = ctl->master;
-	pfd[0].events = POLLIN;
-	pfd[1].fd = ctl->sigfd;
-	pfd[1].events = POLLIN | POLLERR | POLLHUP;
-
-	while (1) {
+	while (!ctl->die) {
 		/* wait for input or signal */
 		ret = poll(pfd, POLLFDS, -1);
 		if (ret < 0) {
@@ -388,17 +260,33 @@ static void dooutput(struct script_control *ctl)
 		for (i = 0; i < POLLFDS; i++) {
 			if (pfd[i].revents == 0)
 				continue;
-			if (i == 0) {
-				bytes = read(pfd[i].fd, obuf, BUFSIZ);
+			if (i < 2) {
+				bytes = read(pfd[i].fd, buf, BUFSIZ);
 				if (bytes < 0) {
 					if (errno == EAGAIN)
 						continue;
 					fail(ctl);
 				}
-				write_output(ctl, obuf, bytes, &oldtime);
+				if (i == 0) {
+					if (write_all(ctl->master, buf, bytes)) {
+						warn(_("write failed"));
+						fail(ctl);
+					} else
+
+						/* without sync write_output()
+						 * will write both input &
+						 * shell output that looks like
+						 * double echoing */
+						fdatasync(ctl->master);
+					if (!ctl->isterm && !feof(stdin)) {
+						int c = DEF_EOF;
+						write_all(ctl->master, &c, 1);
+					}
+				} else
+					write_output(ctl, buf, bytes, &oldtime);
 				continue;
 			}
-			if (i == 1) {
+			if (i == 2) {
 				struct signalfd_siginfo info;
 				ssize_t bytes;
 
@@ -406,10 +294,13 @@ static void dooutput(struct script_control *ctl)
 				assert(bytes == sizeof(info));
 				switch (info.ssi_signo) {
 				case SIGCHLD:
-					done(ctl);
+					finish(ctl, 0);
 					break;
 				case SIGWINCH:
-					/* nothing */
+					if (ctl->isterm) {
+						ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
+						ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
+					}
 					break;
 				default:
 					abort();
@@ -417,7 +308,9 @@ static void dooutput(struct script_control *ctl)
 			}
 		}
 	}
-	abort();
+	if (!ctl->die)
+		finish(ctl, 1); /* wait for children */
+	done(ctl);
 }
 
 static void getslave(struct script_control *ctl)
@@ -680,20 +573,9 @@ int main(int argc, char **argv)
 		warn(_("fork failed"));
 		fail(&ctl);
 	}
-	if (ctl.child == 0) {
-
-		ctl.subchild = ctl.child = fork();
-
-		if (ctl.child < 0) {
-			warn(_("fork failed"));
-			fail(&ctl);
-		}
-		if (ctl.child)
-			dooutput(&ctl);
-		else
-			doshell(&ctl);
-	}
-	doinput(&ctl);
+	if (ctl.child == 0)
+		doshell(&ctl);
+	do_io(&ctl);
 
 	return EXIT_SUCCESS;
 }
-- 
2.2.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 18/22] script: remove io vs signal race
  2014-12-27 17:17 [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes Sami Kerola
                   ` (2 preceding siblings ...)
  2014-12-27 17:17 ` [PATCH 17/22] script: merge doinput() and output() functions to do_io() Sami Kerola
@ 2014-12-27 17:17 ` Sami Kerola
  2014-12-27 17:17 ` [PATCH 19/22] script: add 'Script started' line always to capture file Sami Kerola
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sami Kerola @ 2014-12-27 17:17 UTC (permalink / raw)
  To: util-linux; +Cc: Sami Kerola, Wolfgang Richter, Ruediger Meier

Make do_io() to run poll() until all streams are empty.  This should
remove the signal from child versus io handling race for good.

Addresses: https://github.com/karelzak/util-linux/pull/62
CC: Wolfgang Richter <wolf@cs.cmu.edu>
CC: Ruediger Meier <ruediger.meier@ga-group.nl>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
---
 term-utils/script.c  | 20 +++++++++++++-------
 tests/ts/script/race |  4 ----
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/term-utils/script.c b/term-utils/script.c
index 4a761c6..2def44a 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -92,6 +92,7 @@ struct script_control {
 	FILE *timingfp;		/* timing file pointer */
 	int master;		/* pseudoterminal master file descriptor */
 	int slave;		/* pseudoterminal slave file descriptor */
+	int poll_timeout;	/* poll() timeout, used in end of execution */
 	pid_t child;		/* child pid */
 	int childstatus;	/* child process exit value */
 	struct termios tt;	/* slave terminal runtime attributes */
@@ -185,16 +186,11 @@ static void finish(struct script_control *ctl, int wait)
 {
 	int status;
 	pid_t pid;
-	int errsv = errno;
 	int options = wait ? 0 : WNOHANG;
 
 	while ((pid = wait3(&status, options, 0)) > 0)
-		if (pid == ctl->child) {
+		if (pid == ctl->child)
 			ctl->childstatus = status;
-			ctl->die = 1;
-		}
-
-	errno = errsv;
 }
 
 static void write_output(struct script_control *ctl, char *obuf,
@@ -250,13 +246,15 @@ static void do_io(struct script_control *ctl)
 
 	while (!ctl->die) {
 		/* wait for input or signal */
-		ret = poll(pfd, POLLFDS, -1);
+		ret = poll(pfd, POLLFDS, ctl->poll_timeout);
 		if (ret < 0) {
 			if (errno == EAGAIN)
 				continue;
 			warn(_("poll failed"));
 			fail(ctl);
 		}
+		if (ret == 0)
+			ctl->die = 1;
 		for (i = 0; i < POLLFDS; i++) {
 			if (pfd[i].revents == 0)
 				continue;
@@ -295,6 +293,13 @@ static void do_io(struct script_control *ctl)
 				switch (info.ssi_signo) {
 				case SIGCHLD:
 					finish(ctl, 0);
+					ctl->poll_timeout = 10;
+					if (!ctl->isterm)
+						/* In situation such as 'date' in
+						* $ echo date | ./script
+						* ignore input when shell has
+						* exited.  */
+						pfd[0].fd = -1;
 					break;
 				case SIGWINCH:
 					if (ctl->isterm) {
@@ -471,6 +476,7 @@ int main(int argc, char **argv)
 		.line = "/dev/ptyXX",
 #endif
 		.master = -1,
+		.poll_timeout = -1,
 		0
 	};
 	int ch;
diff --git a/tests/ts/script/race b/tests/ts/script/race
index c947402..103a14a 100755
--- a/tests/ts/script/race
+++ b/tests/ts/script/race
@@ -24,10 +24,6 @@ ts_init "$*"
 
 ts_check_test_command "$TS_CMD_SCRIPT"
 
-# TODO see comments about script design
-# https://github.com/karelzak/util-linux/pull/62
-TS_KNOWN_FAIL="yes"
-
 bingofile="$TS_OUTDIR/${TS_TESTNAME}-bingo"
 
 set -o pipefail
-- 
2.2.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 19/22] script: add 'Script started' line always to capture file
  2014-12-27 17:17 [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes Sami Kerola
                   ` (3 preceding siblings ...)
  2014-12-27 17:17 ` [PATCH 18/22] script: remove io vs signal race Sami Kerola
@ 2014-12-27 17:17 ` Sami Kerola
  2014-12-27 17:17 ` [PATCH 20/22] script: move do_io() content to small functions Sami Kerola
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Sami Kerola @ 2014-12-27 17:17 UTC (permalink / raw)
  To: util-linux; +Cc: Sami Kerola

The scriptreplay(1) will expect the capture file to have a header that is
omited.  Before this change the --quiet option together with timing
caused following replay error.

$ script --quiet --timing=timing
[...]
$ scriptreplay timing typescript
[...]
scriptreplay: unexpected end of file on typescript

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
---
 term-utils/script.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/term-utils/script.c b/term-utils/script.c
index 2def44a..6e11fa3 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -227,6 +227,7 @@ static void do_io(struct script_control *ctl)
 	int ret, i;
 	ssize_t bytes;
 	double oldtime = time(NULL);
+	time_t tvec = time((time_t *)NULL);
 
 	if (ctl->tflg && !ctl->timingfp)
 		ctl->timingfp = fdopen(STDERR_FILENO, "w");
@@ -238,11 +239,8 @@ static void do_io(struct script_control *ctl)
 	pfd[2].fd = ctl->sigfd;
 	pfd[2].events = POLLIN | POLLERR | POLLHUP;
 
-	if (!ctl->qflg) {
-		time_t tvec = time((time_t *)NULL);
-		my_strftime(buf, sizeof buf, "%c\n", localtime(&tvec));
-		fprintf(ctl->typescriptfp, _("Script started on %s"), buf);
-	}
+	my_strftime(buf, sizeof buf, "%c\n", localtime(&tvec));
+	fprintf(ctl->typescriptfp, _("Script started on %s"), buf);
 
 	while (!ctl->die) {
 		/* wait for input or signal */
-- 
2.2.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 20/22] script: move do_io() content to small functions
  2014-12-27 17:17 [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes Sami Kerola
                   ` (4 preceding siblings ...)
  2014-12-27 17:17 ` [PATCH 19/22] script: add 'Script started' line always to capture file Sami Kerola
@ 2014-12-27 17:17 ` Sami Kerola
  2014-12-27 17:17 ` [PATCH 21/22] script: replace strftime() workaround with CFLAGS = -Wno-format-y2k Sami Kerola
  2014-12-27 17:17 ` [PATCH 22/22] script: use correct input type, move comment, and so on Sami Kerola
  7 siblings, 0 replies; 10+ messages in thread
From: Sami Kerola @ 2014-12-27 17:17 UTC (permalink / raw)
  To: util-linux; +Cc: Sami Kerola

The do_io() got to be a bit long with relatively deep indentation.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
---
 term-utils/script.c | 108 ++++++++++++++++++++++++++++------------------------
 1 file changed, 58 insertions(+), 50 deletions(-)

diff --git a/term-utils/script.c b/term-utils/script.c
index 6e11fa3..c1a9f5d 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -220,14 +220,63 @@ static void write_output(struct script_control *ctl, char *obuf,
 	}
 }
 
-static void do_io(struct script_control *ctl)
+static void handle_io(struct script_control *ctl, int fd, double *oldtime, int i)
 {
 	char buf[BUFSIZ];
+	ssize_t bytes;
+
+	bytes = read(fd, buf, sizeof(buf));
+	if (bytes < 0) {
+		if (errno == EAGAIN)
+			return;
+		fail(ctl);
+	}
+	if (i == 0) {
+		if (write_all(ctl->master, buf, bytes)) {
+			warn(_("write failed"));
+			fail(ctl);
+		} else
+			/* without sync write_output() will write both input &
+			 * shell output that looks like double echoing */
+			fdatasync(ctl->master);
+		if (!ctl->isterm && !feof(stdin)) {
+			int c = DEF_EOF;
+			write_all(ctl->master, &c, 1);
+		}
+	} else
+		write_output(ctl, buf, bytes, oldtime);
+}
+
+static void handle_signal(struct script_control *ctl, int fd)
+{
+	struct signalfd_siginfo info;
+	ssize_t bytes;
+
+	bytes = read(fd, &info, sizeof(info));
+	assert(bytes == sizeof(info));
+	switch (info.ssi_signo) {
+	case SIGCHLD:
+		finish(ctl, 0);
+		ctl->poll_timeout = 10;
+		return;
+	case SIGWINCH:
+		if (ctl->isterm) {
+			ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
+			ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
+		}
+		break;
+	default:
+		abort();
+	}
+}
+
+static void do_io(struct script_control *ctl)
+{
 	struct pollfd pfd[POLLFDS];
 	int ret, i;
-	ssize_t bytes;
 	double oldtime = time(NULL);
 	time_t tvec = time((time_t *)NULL);
+	char buf[128];
 
 	if (ctl->tflg && !ctl->timingfp)
 		ctl->timingfp = fdopen(STDERR_FILENO, "w");
@@ -257,57 +306,16 @@ static void do_io(struct script_control *ctl)
 			if (pfd[i].revents == 0)
 				continue;
 			if (i < 2) {
-				bytes = read(pfd[i].fd, buf, BUFSIZ);
-				if (bytes < 0) {
-					if (errno == EAGAIN)
-						continue;
-					fail(ctl);
-				}
-				if (i == 0) {
-					if (write_all(ctl->master, buf, bytes)) {
-						warn(_("write failed"));
-						fail(ctl);
-					} else
-
-						/* without sync write_output()
-						 * will write both input &
-						 * shell output that looks like
-						 * double echoing */
-						fdatasync(ctl->master);
-					if (!ctl->isterm && !feof(stdin)) {
-						int c = DEF_EOF;
-						write_all(ctl->master, &c, 1);
-					}
-				} else
-					write_output(ctl, buf, bytes, &oldtime);
+				handle_io(ctl, pfd[i].fd, &oldtime, i);
 				continue;
 			}
 			if (i == 2) {
-				struct signalfd_siginfo info;
-				ssize_t bytes;
-
-				bytes = read(pfd[i].fd, &info, sizeof(info));
-				assert(bytes == sizeof(info));
-				switch (info.ssi_signo) {
-				case SIGCHLD:
-					finish(ctl, 0);
-					ctl->poll_timeout = 10;
-					if (!ctl->isterm)
-						/* In situation such as 'date' in
-						* $ echo date | ./script
-						* ignore input when shell has
-						* exited.  */
-						pfd[0].fd = -1;
-					break;
-				case SIGWINCH:
-					if (ctl->isterm) {
-						ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
-						ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
-					}
-					break;
-				default:
-					abort();
-				}
+				handle_signal(ctl, pfd[i].fd);
+				if (!ctl->isterm && -1 < ctl->poll_timeout)
+					/* In situation such as 'date' in
+					* $ echo date | ./script
+					* ignore input when shell has exited.  */
+					pfd[0].fd = -1;
 			}
 		}
 	}
-- 
2.2.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 21/22] script: replace strftime() workaround with CFLAGS = -Wno-format-y2k
  2014-12-27 17:17 [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes Sami Kerola
                   ` (5 preceding siblings ...)
  2014-12-27 17:17 ` [PATCH 20/22] script: move do_io() content to small functions Sami Kerola
@ 2014-12-27 17:17 ` Sami Kerola
  2014-12-27 17:17 ` [PATCH 22/22] script: use correct input type, move comment, and so on Sami Kerola
  7 siblings, 0 replies; 10+ messages in thread
From: Sami Kerola @ 2014-12-27 17:17 UTC (permalink / raw)
  To: util-linux; +Cc: Sami Kerola

Nowadays, gcc(1) provides the -Wno-format-y2k option to prevent the
warning, so that the above workaround is no longer required.

Reference: http://man7.org/linux/man-pages/man3/strftime.3.html
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
---
 term-utils/Makemodule.am |  1 +
 term-utils/script.c      | 11 +----------
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/term-utils/Makemodule.am b/term-utils/Makemodule.am
index e7ac707..2bf916c 100644
--- a/term-utils/Makemodule.am
+++ b/term-utils/Makemodule.am
@@ -2,6 +2,7 @@ if BUILD_SCRIPT
 usrbin_exec_PROGRAMS += script
 dist_man_MANS += term-utils/script.1
 script_SOURCES = term-utils/script.c
+script_CFLAGS = $(AM_CFLAGS) -Wno-format-y2k
 script_LDADD = $(LDADD)
 if HAVE_UTIL
 script_LDADD += -lutil
diff --git a/term-utils/script.c b/term-utils/script.c
index c1a9f5d..7a992da 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -146,15 +146,6 @@ static void die_if_link(const struct script_control *ctl)
 		       "Program not started."), ctl->fname);
 }
 
-/*
- * Stop extremely silly gcc complaint on %c:
- *  warning: `%c' yields only last 2 digits of year in some locales
- */
-static void my_strftime(char *buf, size_t len, const char *fmt, const struct tm *tm)
-{
-	strftime(buf, len, fmt, tm);
-}
-
 static void __attribute__((__noreturn__)) done(struct script_control *ctl)
 {
 	if (ctl->isterm)
@@ -288,7 +279,7 @@ static void do_io(struct script_control *ctl)
 	pfd[2].fd = ctl->sigfd;
 	pfd[2].events = POLLIN | POLLERR | POLLHUP;
 
-	my_strftime(buf, sizeof buf, "%c\n", localtime(&tvec));
+	strftime(buf, sizeof buf, "%c\n", localtime(&tvec));
 	fprintf(ctl->typescriptfp, _("Script started on %s"), buf);
 
 	while (!ctl->die) {
-- 
2.2.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 22/22] script: use correct input type, move comment, and so on
  2014-12-27 17:17 [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes Sami Kerola
                   ` (6 preceding siblings ...)
  2014-12-27 17:17 ` [PATCH 21/22] script: replace strftime() workaround with CFLAGS = -Wno-format-y2k Sami Kerola
@ 2014-12-27 17:17 ` Sami Kerola
  2015-01-06 11:11   ` Karel Zak
  7 siblings, 1 reply; 10+ messages in thread
From: Sami Kerola @ 2014-12-27 17:17 UTC (permalink / raw)
  To: util-linux; +Cc: Sami Kerola

Minor corrections.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
---
 term-utils/script.c | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/term-utils/script.c b/term-utils/script.c
index 7a992da..c784f8a 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -179,7 +179,7 @@ static void finish(struct script_control *ctl, int wait)
 	pid_t pid;
 	int options = wait ? 0 : WNOHANG;
 
-	while ((pid = wait3(&status, options, 0)) > 0)
+	while ((pid = wait3(&status, options, NULL)) > 0)
 		if (pid == ctl->child)
 			ctl->childstatus = status;
 }
@@ -458,14 +458,6 @@ static void getmaster(struct script_control *ctl)
 #endif				/* not HAVE_LIBUTIL */
 }
 
-/*
- * script -t prints time delays as floating point numbers
- * The example program (scriptreplay) that we provide to handle this
- * timing output is a perl script, and does not handle numbers in
- * locale format (not even when "use locale;" is added).
- * So, since these numbers are not for human consumption, it seems
- * easiest to set LC_NUMERIC here.
- */
 int main(int argc, char **argv)
 {
 	struct script_control ctl = {
@@ -494,7 +486,14 @@ int main(int argc, char **argv)
 	};
 
 	setlocale(LC_ALL, "");
-	setlocale(LC_NUMERIC, "C");	/* see comment above */
+	/*
+	 * script -t prints time delays as floating point numbers.  The example
+	 * program (scriptreplay) that we provide to handle this timing output
+	 * is a perl script, and does not handle numbers in locale format (not
+	 * even when "use locale;" is added).  So, since these numbers are not
+	 * for human consumption, it seems easiest to set LC_NUMERIC here.
+	 */
+	setlocale(LC_NUMERIC, "C");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 	atexit(close_stdout);
@@ -531,7 +530,6 @@ int main(int argc, char **argv)
 		case 'h':
 			usage(stdout);
 			break;
-		case '?':
 		default:
 			usage(stderr);
 		}
@@ -579,6 +577,6 @@ int main(int argc, char **argv)
 	if (ctl.child == 0)
 		doshell(&ctl);
 	do_io(&ctl);
-
-	return EXIT_SUCCESS;
+	/* should not happen, do_io() calls done() */
+	return EXIT_FAILURE;
 }
-- 
2.2.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 22/22] script: use correct input type, move comment, and so on
  2014-12-27 17:17 ` [PATCH 22/22] script: use correct input type, move comment, and so on Sami Kerola
@ 2015-01-06 11:11   ` Karel Zak
  0 siblings, 0 replies; 10+ messages in thread
From: Karel Zak @ 2015-01-06 11:11 UTC (permalink / raw)
  To: Sami Kerola; +Cc: util-linux

On Sat, Dec 27, 2014 at 05:17:35PM +0000, Sami Kerola wrote:
> +	/*
> +	 * script -t prints time delays as floating point numbers.  The example
> +	 * program (scriptreplay) that we provide to handle this timing output

..pretty obsolete information, scriptreplay is in C since 2008:-)

I'll merge the script(1) changes later this week, I need to play with
that little bit more.

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-01-06 11:11 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-27 17:17 [PATCH 00/22] pull: follow-up to chsh, newgrp, and script changes Sami Kerola
2014-12-27 17:17 ` [PATCH 15/22] script: use signalfd() to catch signals Sami Kerola
2014-12-27 17:17 ` [PATCH 16/22] script: use poll() rather than select() Sami Kerola
2014-12-27 17:17 ` [PATCH 17/22] script: merge doinput() and output() functions to do_io() Sami Kerola
2014-12-27 17:17 ` [PATCH 18/22] script: remove io vs signal race Sami Kerola
2014-12-27 17:17 ` [PATCH 19/22] script: add 'Script started' line always to capture file Sami Kerola
2014-12-27 17:17 ` [PATCH 20/22] script: move do_io() content to small functions Sami Kerola
2014-12-27 17:17 ` [PATCH 21/22] script: replace strftime() workaround with CFLAGS = -Wno-format-y2k Sami Kerola
2014-12-27 17:17 ` [PATCH 22/22] script: use correct input type, move comment, and so on Sami Kerola
2015-01-06 11:11   ` Karel Zak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).