From: Karel Zak <kzak@redhat.com>
To: Phillip Susi <psusi@ubuntu.com>
Cc: util-linux@vger.kernel.org
Subject: Re: script input redirection / eof handling
Date: Mon, 2 Dec 2013 18:02:08 +0100 [thread overview]
Message-ID: <20131202170208.GI5572@x2.net.home> (raw)
In-Reply-To: <529C9CFF.5030709@ubuntu.com>
On Mon, Dec 02, 2013 at 09:45:19AM -0500, Phillip Susi wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 12/2/2013 7:54 AM, Karel Zak wrote:
> > Note, that if you want to support this scenario (stdin is not a
> > terminal) then send a patch ;-)
>
> It seems to work fine up until it hits eof, which can also happen on a
well, it's nasty that the code ignores return codes and it call's tty
ioctls/functions for non-tty file descriptors.
> tty and you'll get the same bad behavior, so I think refusing to run
> on a non tty isn't a proper fix.
>
> >> Yep, I think it would be enough to add
> >>
> >> kill(0, SIGTERM);
> >>
> >> before done() in doinput() to avoid orphans.
>
> You don't want to just make sure the children die, you want to make
> sure that the child sees the eof and capture any final output it may have.
never ending orphans suck...
The possible solution (hack) to emulate end-of-file is by write "exit\n" to
the master tty. For example patch below works for me (it also make it
more robust for non-ttys).
Karel
diff --git a/term-utils/script.c b/term-utils/script.c
index c18274c..8437ec8 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -107,6 +107,7 @@ int fflg = 0;
int qflg = 0;
int tflg = 0;
int forceflg = 0;
+int isterm;
int die;
int resized;
@@ -230,9 +231,6 @@ main(int argc, char **argv) {
die_if_link(fname);
}
- if (!isatty(STDIN_FILENO))
- errx(EXIT_FAILURE, _("The stdin is not a terminal."));
-
if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
warn(_("cannot open %s"), fname);
fail();
@@ -314,11 +312,21 @@ doinput(void) {
else if (cc < 0 && errno == EINTR && resized)
{
/* transmit window change information to the child */
- ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&win);
- ioctl(slave, TIOCSWINSZ, (char *)&win);
+ if (isterm) {
+ ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&win);
+ ioctl(slave, TIOCSWINSZ, (char *)&win);
+ }
resized = 0;
- }
- else
+ } else if (cc == 0 && errno == 0) {
+ /* end-of-file, probably "foo | script" */
+ strcpy(ibuf, "exit\n");
+ if (write(master, ibuf, 5) < 0) {
+ warn (_("write failed"));
+ fail();
+ }
+ pause(); /* wait for SIGCHLD */
+ break;
+ } else
break;
}
@@ -473,6 +481,9 @@ void
fixtty(void) {
struct termios rtt;
+ if (!isterm)
+ return;
+
rtt = tt;
cfmakeraw(&rtt);
rtt.c_lflag &= ~ECHO;
@@ -503,7 +514,8 @@ done(void) {
master = -1;
} else {
- tcsetattr(STDIN_FILENO, TCSADRAIN, &tt);
+ if (isterm)
+ tcsetattr(STDIN_FILENO, TCSADRAIN, &tt);
if (!qflg)
printf(_("Script done, file is %s\n"), fname);
#ifdef HAVE_LIBUTEMPTER
@@ -524,9 +536,19 @@ done(void) {
void
getmaster(void) {
#if defined(HAVE_LIBUTIL) && defined(HAVE_PTY_H)
- tcgetattr(STDIN_FILENO, &tt);
- ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&win);
- if (openpty(&master, &slave, NULL, &tt, &win) < 0) {
+ int rc;
+
+ isterm = isatty(STDIN_FILENO);
+
+ if (isterm) {
+ if (tcgetattr(STDIN_FILENO, &tt) != 0)
+ err(EXIT_FAILURE, _("failed to get terminal attributes"));
+ ioctl(STDIN_FILENO, TIOCGWINSZ, (char *) &win);
+ rc = openpty(&master, &slave, NULL, &tt, &win);
+ } else
+ rc = openpty(&master, &slave, NULL, NULL, NULL);
+
+ if (rc < 0) {
warn(_("openpty failed"));
fail();
}
@@ -534,6 +556,8 @@ getmaster(void) {
char *pty, *bank, *cp;
struct stat stb;
+ isterm = isatty(STDIN_FILENO);
+
pty = &line[strlen("/dev/ptyp")];
for (bank = "pqrs"; *bank; bank++) {
line[strlen("/dev/pty")] = *bank;
@@ -552,9 +576,11 @@ getmaster(void) {
ok = access(line, R_OK|W_OK) == 0;
*tp = 'p';
if (ok) {
- tcgetattr(STDIN_FILENO, &tt);
- ioctl(STDIN_FILENO, TIOCGWINSZ,
- (char *)&win);
+ if (isterm) {
+ tcgetattr(STDIN_FILENO, &tt);
+ ioctl(STDIN_FILENO, TIOCGWINSZ,
+ (char *)&win);
+ }
return;
}
close(master);
@@ -577,8 +603,10 @@ getslave(void) {
warn(_("cannot open %s"), line);
fail();
}
- tcsetattr(slave, TCSANOW, &tt);
- ioctl(slave, TIOCSWINSZ, (char *)&win);
+ if (isterm) {
+ tcsetattr(slave, TCSANOW, &tt);
+ ioctl(slave, TIOCSWINSZ, (char *)&win);
+ }
#endif
setsid();
ioctl(slave, TIOCSCTTY, 0);
next prev parent reply other threads:[~2013-12-02 17:02 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-10-31 14:21 script input redirection / eof handling Phillip Susi
2013-12-02 12:36 ` Karel Zak
2013-12-02 12:54 ` Karel Zak
2013-12-02 14:45 ` Phillip Susi
2013-12-02 17:02 ` Karel Zak [this message]
2013-12-02 18:06 ` Phillip Susi
2013-12-02 22:36 ` Karel Zak
2013-12-02 23:25 ` Karel Zak
2013-12-03 12:55 ` Karel Zak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20131202170208.GI5572@x2.net.home \
--to=kzak@redhat.com \
--cc=psusi@ubuntu.com \
--cc=util-linux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.