summaryrefslogtreecommitdiffstats
path: root/term-utils/script.c
diff options
context:
space:
mode:
authorSami Kerola2014-12-26 13:37:36 +0100
committerSami Kerola2015-06-06 15:53:56 +0200
commitcf470183ea4a45d170e22aaac8c2397f5ffb0f35 (patch)
tree6c081f32ca71972d0f61417a44aeb4a0b4198cda /term-utils/script.c
parentscript: use signalfd() to catch signals (diff)
downloadkernel-qcow2-util-linux-cf470183ea4a45d170e22aaac8c2397f5ffb0f35.tar.gz
kernel-qcow2-util-linux-cf470183ea4a45d170e22aaac8c2397f5ffb0f35.tar.xz
kernel-qcow2-util-linux-cf470183ea4a45d170e22aaac8c2397f5ffb0f35.zip
script: use poll() rather than select()
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>
Diffstat (limited to 'term-utils/script.c')
-rw-r--r--term-utils/script.c202
1 files changed, 114 insertions, 88 deletions
diff --git a/term-utils/script.c b/term-utils/script.c
index 12abdd674..26ec8ff9c 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 */
/*
* For tests we want to be able to control time output
@@ -253,10 +253,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)
@@ -265,35 +265,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;
}
}
@@ -301,7 +315,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
@@ -328,24 +342,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
@@ -360,57 +391,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)
@@ -595,7 +622,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) {