Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: SHTTY



hoh@xxxxxxxxxx wrote:
> Hi.
> 
> I have a problem with a change made to zsh between beta6 and beta9.
>
> If I su to another user, e.g. root su:ing to news, then the zle
> option is unset and TTY is "".
>
> The reason can be found in init.c where SHTTY is opened with this code:
> 
>     if (isatty(0))
>         SHTTY = movefd(open(ttyname(0), O_RDWR));
>     else
>         SHTTY = movefd(open("/dev/tty", O_RDWR));
> 
> There is a VERY BIG difference between the old "dup(0)" and the new
> "open(ttyname(0), O_RDWR)" if the su:ed to user don't have permission
> to open the tty. In that case SHTTY is set to -1 and then the interactive
> part of zsh just falls apart.
> 
> Why was this change made?

This was made because in the new code I/O for the TTY all goes via the
fd SHTTY's output file, shout (compare with other shells, where this
is distinct from stdout and always attached to the tty while fd 0 is).
It's not possible to guarantee that fd 0 is opened r/w.  In fact, if
you do 'exec <anyfile' within zsh it will only be opened for reading.
This means that, in the case you are having problems with, it's not
actually possible to guarantee output to the terminal at all.  (Try
'exec <$TTY' before an su to another zsh with your patch and you'll
have problems.)

The following does the best I can think of: if opening the tty r/w
fails, it dup's 0, and if that means opening the editor output fails,
it dups 1 for shout if that's a tty.  (Since about the only remaining
way of getting tty output would be stderr this is fairly general.)  To
avoid code to keep track of fileno(shout), I've set the close-on-exec
flag for that.  This all makes it a little more complex than I would
hope: but as I said, there's no guaranteed way of getting read/write
access to the tty via a single fd.

I have actually tested this and it now works even if fd 0 is read-only.

*** Src/init.c.otty	Mon Jul  3 13:34:02 1995
--- Src/init.c	Thu Jul  6 11:30:23 1995
***************
*** 328,342 ****
      setbuffer(stderr, errbuf, BUFSIZ);
  #endif
  
      if (shout) {
  	fclose(shout);
  	shout = 0;
      }
  
      /* Make sure the tty is opened read/write. */
!     if (isatty(0))
  	SHTTY = movefd(open(ttyname(0), O_RDWR));
!     else
  	SHTTY = movefd(open("/dev/tty", O_RDWR));
  
      if (SHTTY != -1) {
--- 328,346 ----
      setbuffer(stderr, errbuf, BUFSIZ);
  #endif
  
+     if (SHTTY >= 10 && (!shout || SHTTY != fileno(shout)))
+ 	close(SHTTY);
      if (shout) {
  	fclose(shout);
  	shout = 0;
      }
  
      /* Make sure the tty is opened read/write. */
!     if (isatty(0)) {
  	SHTTY = movefd(open(ttyname(0), O_RDWR));
! 	if (SHTTY == -1)
! 	    SHTTY = movefd(dup(0));
!     } else
  	SHTTY = movefd(open("/dev/tty", O_RDWR));
  
      if (SHTTY != -1) {
***************
*** 348,353 ****
--- 352,368 ----
  
  	/* Associate terminal file descriptor with a FILE pointer */
  	shout = fdopen(SHTTY, "w");
+ 	/* As a last resort, see if stdout is a tty and use that. */
+ 	if (!shout && isatty(1)) {
+ 	    int shfd = movefd(dup(1));
+ 	    if (shfd != -1) {
+ #ifdef FD_CLOEXEC
+ 		/* Don't leave this fd around in exec'd procs */
+ 		fcntl(shfd, F_SETFD, FD_CLOEXEC);
+ #endif
+ 		shout = fdopen(shfd, "w");
+ 	    }
+ 	}
  
          /* We will only use zle if shell is interactive, *
           * SHTTY != -1, and shout != 0                   */

-- 
Peter Stephenson <P.Stephenson@xxxxxxxxxxxxx>  Tel: +44 1792 205678 extn. 4461
WWW:  http://python.swan.ac.uk/~pypeters/      Fax: +44 1792 295324
Department of Physics, University of Wales, Swansea,
Singleton Park, Swansea, SA2 8PP, U.K.



Messages sorted by: Reverse Date, Date, Thread, Author