public inbox for util-linux@vger.kernel.org
 help / color / mirror / Atom feed
* script input redirection / eof handling
@ 2013-10-31 14:21 Phillip Susi
  2013-12-02 12:36 ` Karel Zak
  0 siblings, 1 reply; 9+ messages in thread
From: Phillip Susi @ 2013-10-31 14:21 UTC (permalink / raw)
  To: util-linux

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I came across an old bug filed in debian about script being redirected
from a file misbehaving.  It seems that when the master ( input )
process hits eof, it exits immediately, orphaning the child ( output )
and user processes.

I believe the correct thing to do is signal the eof to the user
process and wait for the children to exit, but I'm not sure how to
make a pty signal eof.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQEcBAEBAgAGBQJScmdWAAoJEJrBOlT6nu75JIQH/1Eqt6gsG+vKGc8xpybIE6F7
UGgo8sLyn++PE3U6MZQcsWj2nHZ6p76uHOp4Kn1sk8xrb2zetueQTF1idtgJO7nS
PKhwbfInD3ocSuEQB1HygMmKTKuXT9qYCBj18AT9ZQp7eQ5ocz+nvNnGHQuR4KPR
/CsI0D0/BnTO32ayh6qgE1HtxD0sUY4K1Qw3MyyChINwFAU9q8p3Y9Lz5RqQTTZk
2j3kc6jDdNaGy1b6w1exhEMrhs7zC1LRvz5GhqM+ODVAN/YiMh4eKYH9a4OrYXru
l8Df0gDWNRrQhqrJxvOMKph/DZO1sZEZP3ZG/kOXak/cpbHVy0MkGepP0qId91g=
=ZaJO
-----END PGP SIGNATURE-----

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

* Re: script input redirection / eof handling
  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
  0 siblings, 1 reply; 9+ messages in thread
From: Karel Zak @ 2013-12-02 12:36 UTC (permalink / raw)
  To: Phillip Susi; +Cc: util-linux

On Thu, Oct 31, 2013 at 10:21:10AM -0400, Phillip Susi wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> I came across an old bug filed in debian about script being redirected
> from a file misbehaving. 

Do you mean something like:

   echo "ps uf" | script

.. if yes, then it's pretty unexpected usage. The code expects that
stdin is terminal. (For example it copy the current terminal
attributes the new pseudo-terminal.)

Unfortunately it does not check tcgetatt() return code so the problem 
is not visible. I'll fix it.

> It seems that when the master ( input )
> process hits eof, it exits immediately, orphaning the child ( output )
> and user processes.

Yep, I think it would be enough to add 

       kill(0, SIGTERM);

before done() in doinput() to avoid orphans.

    Karel

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

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

* Re: script input redirection / eof handling
  2013-12-02 12:36 ` Karel Zak
@ 2013-12-02 12:54   ` Karel Zak
  2013-12-02 14:45     ` Phillip Susi
  0 siblings, 1 reply; 9+ messages in thread
From: Karel Zak @ 2013-12-02 12:54 UTC (permalink / raw)
  To: Phillip Susi; +Cc: util-linux

On Mon, Dec 02, 2013 at 01:36:59PM +0100, Karel Zak wrote:
> On Thu, Oct 31, 2013 at 10:21:10AM -0400, Phillip Susi wrote:
> > -----BEGIN PGP SIGNED MESSAGE-----
> > Hash: SHA1
> > 
> > I came across an old bug filed in debian about script being redirected
> > from a file misbehaving. 
> 
> Do you mean something like:
> 
>    echo "ps uf" | script
> 
> .. if yes, then it's pretty unexpected usage. The code expects that
> stdin is terminal. (For example it copy the current terminal
> attributes the new pseudo-terminal.)
> 
> Unfortunately it does not check tcgetatt() return code so the problem 
> is not visible. I'll fix it.

Note, that if you want to support this scenario (stdin is not a
terminal) then send a patch ;-) 

I guess you have to initialize the terminal (see inlude/ttyutils.h, 
reset_virtual_console()) and use this dummy struct termios instead of
the current 'tt'.

> Yep, I think it would be enough to add 
> 
>        kill(0, SIGTERM);
> 
> before done() in doinput() to avoid orphans.

 This is probably not the best solution (because shell will print
 "Terminated" etc.), but it's definitely better than orphans.

    Karel

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

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

* Re: script input redirection / eof handling
  2013-12-02 12:54   ` Karel Zak
@ 2013-12-02 14:45     ` Phillip Susi
  2013-12-02 17:02       ` Karel Zak
  0 siblings, 1 reply; 9+ messages in thread
From: Phillip Susi @ 2013-12-02 14:45 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux

-----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
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.


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQEcBAEBAgAGBQJSnJz9AAoJEI5FoCIzSKrw6j0IAKZvkym0kJQfWghombuTnV1z
5FCcWPz3Jyo9V96X+fnD3cXpkkPjIM5ZUIBaRJubUYX65AKebXaXw+FkE9YyXsIR
Jeegewp5IlSlF3zbZzCSUchI/gK0KCHv1yKe21xD20iGAy9MGApXBJszsOaREbU2
nG9mFYwviFDQnURBfwHxvS7Bf4S+6i1wgKeS58EqSeXpMpMDCimTw1/mv8MLnGdS
0nzCrPZvgRZcc2avYPSWYs8ZLtFgu5rDuJ7J9TfEuiEzGWCqlPXQYF1a6nHvpT0W
KSdu+1bzsasdrEXFF6Iai2NvFndg9JXqiLCGfKdELbJayYPjwltOtl41PfalG/w=
=2lT4
-----END PGP SIGNATURE-----

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

* Re: script input redirection / eof handling
  2013-12-02 14:45     ` Phillip Susi
@ 2013-12-02 17:02       ` Karel Zak
  2013-12-02 18:06         ` Phillip Susi
  0 siblings, 1 reply; 9+ messages in thread
From: Karel Zak @ 2013-12-02 17:02 UTC (permalink / raw)
  To: Phillip Susi; +Cc: util-linux

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);

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

* Re: script input redirection / eof handling
  2013-12-02 17:02       ` Karel Zak
@ 2013-12-02 18:06         ` Phillip Susi
  2013-12-02 22:36           ` Karel Zak
  2013-12-02 23:25           ` Karel Zak
  0 siblings, 2 replies; 9+ messages in thread
From: Phillip Susi @ 2013-12-02 18:06 UTC (permalink / raw)
  To: Karel Zak; +Cc: util-linux

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 12/2/2013 12:02 PM, Karel Zak wrote:
> never ending orphans suck...

Yes, but the idea is not to orphan them in the first place and wait
for them to terminate instead.

> 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).

That only works if the program on the other end knows what "exit"
means, which is basically only true if it's a shell.  Surely there
must be a proper way to signal EOF over a pty?  Can you use shutdown()
on a pty?


-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQEcBAEBAgAGBQJSnMwNAAoJEI5FoCIzSKrwwvYH+wRd0hXZwZKhElWgpLIjWNOO
82ulPzt1Cld085qllaG8VvO0CSN3JERHD5Eo8iB+YIuI32lNO2dGuGw0MwYJ72cn
whUEqT7BNcnDCDqhPba/ZYcGJ8mCp+3+58BDth8NPu+nma7d6V0n4sAbqO+w6uCS
VZOO9qo2cKYGqs7E2YYWLHBadMGkyLjpDd9j7ZsLxEe6ezb1vFLxSmJQ3CiNLz+i
q2okm0GUipkhMAMCC8zuV1GnUf5sJuSx6QiSkIE5Mok9d8HqOtXTt8F7URAa+YVC
tBtM7dMIfXEQCJil16hTn+KdgiAtNE4BaGkyevW2kohwmKQgKU51/CHlofWGK1s=
=6Ihg
-----END PGP SIGNATURE-----

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

* Re: script input redirection / eof handling
  2013-12-02 18:06         ` Phillip Susi
@ 2013-12-02 22:36           ` Karel Zak
  2013-12-02 23:25           ` Karel Zak
  1 sibling, 0 replies; 9+ messages in thread
From: Karel Zak @ 2013-12-02 22:36 UTC (permalink / raw)
  To: Phillip Susi; +Cc: util-linux

On Mon, Dec 02, 2013 at 01:06:05PM -0500, Phillip Susi wrote:
> That only works if the program on the other end knows what "exit"

yep, fingers have been faster than brain.. (I forgot we have
--command).

> means, which is basically only true if it's a shell.  Surely there
> must be a proper way to signal EOF over a pty?  Can you use shutdown()
> on a pty?

I'm going to play with that tomorrow.

    Karel

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

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

* Re: script input redirection / eof handling
  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
  1 sibling, 1 reply; 9+ messages in thread
From: Karel Zak @ 2013-12-02 23:25 UTC (permalink / raw)
  To: Phillip Susi; +Cc: util-linux

On Mon, Dec 02, 2013 at 01:06:05PM -0500, Phillip Susi wrote:
> That only works if the program on the other end knows what "exit"
> means, which is basically only true if it's a shell.  Surely there
> must be a proper way to signal EOF over a pty?  Can you use shutdown()
> on a pty?

 Oh, now it reminds me... in include/ttyutils.h we have macros to
 generate tty control chars, for example ^C

			char eof = DEF_EOF;

			if (write(master, &eof, 1) < 0) {
				warn (_("write failed"));
				fail();
			}
            pause();
           
 is what we need. 

    Karel

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

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

* Re: script input redirection / eof handling
  2013-12-02 23:25           ` Karel Zak
@ 2013-12-03 12:55             ` Karel Zak
  0 siblings, 0 replies; 9+ messages in thread
From: Karel Zak @ 2013-12-03 12:55 UTC (permalink / raw)
  To: Phillip Susi; +Cc: util-linux

On Tue, Dec 03, 2013 at 12:25:13AM +0100, Karel Zak wrote:
> On Mon, Dec 02, 2013 at 01:06:05PM -0500, Phillip Susi wrote:
> > That only works if the program on the other end knows what "exit"
> > means, which is basically only true if it's a shell.  Surely there
> > must be a proper way to signal EOF over a pty?  Can you use shutdown()
> > on a pty?
> 
>  Oh, now it reminds me... in include/ttyutils.h we have macros to
>  generate tty control chars, for example ^C
> 
> 			char eof = DEF_EOF;
> 
> 			if (write(master, &eof, 1) < 0) {
> 				warn (_("write failed"));
> 				fail();
> 			}
>             pause();
>            
>  is what we need. 

 It was more tricky than I have originally expected, but it seems it
 works. (It seems that it is not enough to send EOF, you have to be
 sure that someone already listens on slave side.)

    Karel

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

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

end of thread, other threads:[~2013-12-03 12:55 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox