This is the mail archive of the cygwin-patches mailing list for the Cygwin project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Fix tcgetpgrp output


I'd like to have your opinion for this patch before I check it in, since
I'm not sure this is the right way to fix it.

When I debugged the luit/tcsh problem yesterday, I found that the
tcgetpgrp function does not behave as advertised.

Per POSIX, the tcgetpgrp function returns the pgrp ID only if the file
descriptor references the controlling tty of the process.  If the
process has no ctty, or if the descriptor references another tty not
being the controlling tty, the function is supposed to set errno to
ENOTTY and return -1.

Cygwin OTOH, always returns the pgid of the tty, even if it's not the
controlling tty of the process.  This leads potentially to weird
results, as you can see in the output of the testcase below.

And then there's Linux, with a tiny special case.

If a Linux process opens the master side of a pty and then calls
tcgetpgrp on this file, the tcgetpgrp will return 0.  However, as soon
as a child process has called setsid() and opened the slave side of the
pty and made that tty its controlling tty, tcgetprgrp(master) returns
the own pid, not 0.  Don't look into the Linux man page, this behaviour
is not documented.

I checked that on Solaris as well, and Solaris behaves POSIX-compliant.
Here the master side returns -1/ENOTTY, unless you open the master side
without the O_NOCTTY flag and the opening process has no controlling tty
at that time.

My patch makes Cygwin behave like Linux.  It's just an additional test
in tcgetpgrp.  I'm not sure if that's TRTTD for two reasons.

- Since Linux behaves obviously not POSIX-compliant with respect to the
  master pty, I'm not sure we should really reflect Linux literally.
  Maybe it's better to behave POSIX-compliant and return -1/ENOTTY for a
  non-controlling master all the time, just as on Solaris?

- My first approach changed the actual values in tc->pgid, rather than
  just making a test for the ctty in tcgetprgrp.  I'm still wondering if
  the code should better try to maintain the correct values in the
  datastructures, or if it's better to just have this check in tcgetpgrp.

Ok, I used the following test application to verify the behaviour on
Linux, Solaris, and Cygwin:

==== SNIP ====
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/fcntl.h>
#include <sys/wait.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>

int main ()
  int master, slave, status;
  char pts[256];

  printf ("parent pid: %d\n", getpid ());
  if ((master = open ("/dev/ptmx", O_RDWR | O_NOCTTY)) >= 0)
      int ret; 
      grantpt (master);
      unlockpt (master);
      printf ("parent tcgetpgrp master: %d\n", tcgetpgrp (master));
      strcpy (pts, ptsname (master));
      switch (fork ())
	case -1:
	case 0:	// child
	  ret = setsid ();
	  printf ("child pid: %d (setsid: %d)\n", getpid (), ret);
	  printf ("child tcgetpgrp master before open: %d\n", tcgetpgrp (master));
	  if ((slave = open (pts, O_RDWR)) >= 0)
	      printf ("child tcgetpgrp master after open: %d\n", tcgetpgrp (master));
	      printf ("child tcgetpgrp slave: %d\n", tcgetpgrp (slave));
	      close (slave);
	default:// parent
	  wait (&status);
	  printf ("parent tcgetpgrp master: %d\n", tcgetpgrp (master));
      close (master);
      return 0;
  return 1;
==== SNAP ====

Output on Linux:

  parent pid: 14670
  parent tcgetpgrp master: 0
  child pid: 14671 (setsid: 14671)
  child tcgetpgrp master before open: 0
  child tcgetpgrp master after open: 14671
  child tcgetpgrp slave: 14671
  parent tcgetpgrp master: 0

Output on Solaris 10:

  parent pid: 20372
  parent tcgetpgrp master: -1
  child pid: 20374 (setsid: 20374)
  child tcgetpgrp master before open: -1
  child tcgetpgrp master after open: -1
  child tcgetpgrp slave: 20374
  parent tcgetpgrp master: -1

Output on Cygwin without my patch:

  parent pid: 3704
  parent tcgetpgrp master: 3704
  child pid: 1056 (setsid: 1056)
  child tcgetpgrp master before open: 3704
  child tcgetpgrp master after open: 1056
  child tcgetpgrp slave: 1056
  parent tcgetpgrp master: 1056

Output on Cygwin with my patch:

  parent pid: 4016
  parent tcgetpgrp master: 0
  child pid: 872 (setsid: 872)
  child tcgetpgrp master before open: 0
  child tcgetpgrp master after open: 872
  child tcgetpgrp slave: 872
  parent tcgetpgrp master: 0

So my patch results in a behaviour just like on Linux for now.

Patch attached.


	* fhandler.h (fhandler_pty_master::tcgetpgrp): Declare.
	* (fhandler_termios::tcgetpgrp): Only return
	valid pgid if tty is controlling tty.  Set errno to ENOTTY and
	return -1 otherwise.
	(fhandler_pty_master::tcgetpgrp): New function.  Return 0 for
	master side of pty if it's not the controlling tty of the process.

Index: fhandler.h
RCS file: /cvs/src/src/winsup/cygwin/fhandler.h,v
retrieving revision 1.381
diff -u -p -r1.381 fhandler.h
--- fhandler.h	28 Sep 2009 12:10:32 -0000	1.381
+++ fhandler.h	6 Oct 2009 08:58:34 -0000
@@ -1109,6 +1109,7 @@ public:
   int dup (fhandler_base *);
   void fixup_after_fork (HANDLE parent);
   void fixup_after_exec ();
+  int tcgetpgrp ();
 class fhandler_tty_master: public fhandler_pty_master
RCS file: /cvs/src/src/winsup/cygwin/,v
retrieving revision 1.74
diff -u -p -r1.74
---	3 Jan 2009 05:12:20 -0000	1.74
+++	6 Oct 2009 08:58:34 -0000
@@ -99,7 +99,16 @@ fhandler_termios::tcsetpgrp (const pid_t
 fhandler_termios::tcgetpgrp ()
-  return tc->pgid;
+  if (myself->ctty != -1 && myself->ctty == tc->ntty)
+    return tc->pgid;
+  set_errno (ENOTTY);
+  return -1;
+fhandler_pty_master::tcgetpgrp ()
+  return myself->ctty != -1 && myself->ctty == tc->ntty ? tc->pgid : 0;

Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]