home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / TTYAgent.C < prev    next >
C/C++ Source or Header  |  1998-10-29  |  24KB  |  953 lines

  1. // $Id: TTYAgent.C,v 1.55 1998/10/29 09:16:22 zeller Exp $ -*- C++ -*-
  2. // An agent interface using ptys (pseudo ttys)
  3.  
  4. // Copyright (C) 1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char TTYAgent_rcsid[] = 
  30.     "$Id: TTYAgent.C,v 1.55 1998/10/29 09:16:22 zeller Exp $";
  31.  
  32. // Most of this code is based on `calldbx.c' from `xxgdb', by Pierre
  33. // Willard which in turn is based on `calldbx.c' from `xdbx', by Po
  34. // Cheung.  The open_master() and open_slave() routines are based on
  35. // the pty routines from the GNU `expect' library.
  36. //
  37. // I have not been able to test all possible configurations and
  38. // architectures.  If someone finds problems in this code, please
  39. // enlighten me.  I also apologize for the mess of `#ifdef's in this
  40. // file; please tell me about superfluous ones if you find some.
  41. //
  42. //                                                 (Andreas Zeller)
  43.  
  44.  
  45. #ifdef __GNUG__
  46. #pragma implementation
  47. #endif
  48.  
  49. // Options
  50.  
  51. // If 1, synchronize parent and child by sending an initialization sequence
  52. #define SYNCHRONIZE_PARENT_AND_CHILD 0
  53.  
  54.  
  55. #include "TTYAgent.h"
  56. #include "config.h"
  57.  
  58. DEFINE_TYPE_INFO_1(TTYAgent, LiterateAgent)
  59.  
  60. extern "C" {
  61.  
  62. #if HAVE_SYS_IOCTL_H
  63. #include <sys/ioctl.h>
  64. #endif
  65.  
  66. #if sun
  67. // On SunOS 4.1.4, <sys/ioctl.h> defines lots of symbols which are
  68. // redefined in <termios.h>.  We want the <termios.h> ones.
  69. #if defined(ECHO) && defined(O_ECHO) && ECHO == O_ECHO
  70. #undef ECHO
  71. #endif
  72.  
  73. #if defined(NL0) && defined(O_NL0) && NL0 == O_NL0
  74. #undef NL0
  75. #endif
  76.  
  77. #if defined(NL1) && defined(O_NL1) && NL1 == O_NL1
  78. #undef NL1
  79. #endif
  80.  
  81. #if defined(TAB0) && defined(O_TAB0) && TAB0 == O_TAB0
  82. #undef TAB0
  83. #endif
  84.  
  85. #if defined(TAB1) && defined(O_TAB1) && TAB1 == O_TAB1
  86. #undef TAB1
  87. #endif
  88.  
  89. #if defined(TAB2) && defined(O_TAB2) && TAB2 == O_TAB2
  90. #undef TAB2
  91. #endif
  92.  
  93. #if defined(XTABS) && defined(O_XTABS) && XTABS == O_XTABS
  94. #undef XTABS
  95. #endif
  96.  
  97. #if defined(CR0) && defined(O_CR0) && CR0 == O_CR0
  98. #undef CR0
  99. #endif
  100.  
  101. #if defined(CR1) && defined(O_CR1) && CR1 == O_CR1
  102. #undef CR1
  103. #endif
  104.  
  105. #if defined(CR2) && defined(O_CR2) && CR2 == O_CR2
  106. #undef CR2
  107. #endif
  108.  
  109. #if defined(CR3) && defined(O_CR3) && CR3 == O_CR3
  110. #undef CR3
  111. #endif
  112.  
  113. #if defined(FF0) && defined(O_FF0) && FF0 == O_FF0
  114. #undef FF0
  115. #endif
  116.  
  117. #if defined(FF1) && defined(O_FF1) && FF1 == O_FF1
  118. #undef FF1
  119. #endif
  120.  
  121. #if defined(BS0) && defined(O_BS0) && BS0 == O_BS0
  122. #undef BS0
  123. #endif
  124.  
  125. #if defined(BS1) && defined(O_BS1) && BS1 == O_BS1
  126. #undef BS1
  127. #endif
  128.  
  129. #if defined(TOSTOP) && defined(O_TOSTOP) && TOSTOP == O_TOSTOP
  130. #undef TOSTOP
  131. #endif
  132.  
  133. #if defined(FLUSHO) && defined(O_FLUSHO) && FLUSHO == O_FLUSHO
  134. #undef FLUSHO
  135. #endif
  136.  
  137. #if defined(PENDIN) && defined(O_PENDIN) && PENDIN == O_PENDIN
  138. #undef PENDIN
  139. #endif
  140.  
  141. #if defined(NOFLSH) && defined(O_NOFLSH) && NOFLSH == O_NOFLSH
  142. #undef NOFLSH
  143. #endif
  144. #endif // sun
  145.  
  146. // Nico van Waes <nico@yegal.njit.edu> says: under Solaris 2.6, one
  147. // must include <sys/types.h> and <sys/int_types.h> before
  148. // <termios.h>.
  149. #if HAVE_SYS_TYPES_H
  150. #include <sys/types.h>
  151. #endif
  152.  
  153. #if HAVE_SYS_INT_TYPES_H
  154. #include <sys/int_types.h>
  155. #endif
  156.  
  157. #ifdef __osf__
  158. // DEC OSF has some special treatment in this file; I hope these
  159. // `#ifdef __osf__' flags will be deleted by an OSF expert some day. - AZ
  160. #include <termio.h>
  161. #else // !__osf__
  162. #if HAVE_TCGETATTR && HAVE_TCSETATTR
  163. #if HAVE_TERMIOS_H
  164. #include <termios.h>
  165. #endif
  166. #else // !HAVE_TCGETATTR || !HAVE_TCSETATTR
  167. #if HAVE_TERMIO_H
  168. #include <termio.h>
  169. #endif
  170. #endif // !HAVE_TCGETATTR || !HAVE_TCSETATTR
  171. #endif // !__osf__
  172.  
  173. #if HAVE_SYS_STAT_H
  174. #include <sys/stat.h>
  175. #ifndef S_ISDIR
  176. #define S_ISDIR ((m) & S_IFMT == S_IFDIR)
  177. #endif
  178. #endif
  179.  
  180. #if HAVE_SYS_STROPTS_H
  181. #include <sys/stropts.h>
  182. #endif
  183.  
  184. #if HAVE_SYS_SYSMACROS_H
  185. #include <sys/sysmacros.h>
  186. #ifndef minor
  187. #define minor(x)        ((int)((x)&0377))
  188. #endif
  189. #endif
  190.  
  191. #if HAVE_FCNTL_H
  192. #include <fcntl.h>
  193. #endif
  194.  
  195. #if HAVE_SYS_VTY_H
  196. #include <sys/vty.h>
  197.  
  198. #ifndef MAXPTYNAMELEN
  199. #define MAXPTYNAMELEN 255
  200. #endif
  201.  
  202. #endif
  203. }
  204.  
  205.  
  206. #include <stdio.h>
  207. #include <errno.h>
  208. #include <signal.h>
  209.  
  210.  
  211. extern "C" {
  212. #if HAVE_SETPGID && !HAVE_SETPGID_DECL && !defined(setpgid)
  213.     int setpgid(pid_t pid, pid_t pgrp);
  214. #endif
  215. #if !HAVE_SETPGID && HAVE_SETPGRP2 && !defined(setpgid)
  216. #if !HAVE_SETPGRP2_DECL && !defined(setpgrp2)
  217.     int setpgrp2(pid_t pid, pid_t pgrp);
  218. #define setpgid setpgrp2
  219. #define HAVE_SETPGID 1
  220. #endif
  221. #endif
  222. #if !HAVE_SETPGID && HAVE_SETPGRP && !defined(setpgid)
  223. #if !HAVE_SETPGRP_DECL && !defined(setpgrp)
  224. #if HAVE_SETPRGP_VOID
  225.     int setpgrp();
  226. #else
  227.     int setpgrp(pid_t pid, pid_t pgrp);
  228. #endif // HAVE_SETPRGP_VOID
  229. #define setpgid setpgrp
  230. #define HAVE_SETPGID 1
  231. #endif
  232. #endif
  233. #if HAVE_TCGETATTR && !HAVE_TCGETATTR_DECL && !defined(tcgetattr)
  234.     int tcgetattr(int fd, struct termios *termios_p);
  235. #endif
  236. #if HAVE_TCSETATTR && !HAVE_TCSETATTR_DECL && !defined(tcsetattr)
  237.     int tcsetattr(int fd, int when, const struct termios *termios_p);
  238. #endif
  239. #if HAVE_TCGETPGRP && !HAVE_TCGETPGRP_DECL && !defined(tcgetpgrp)
  240.     pid_t tcgetpgrp(int fd);
  241. #endif
  242. #if HAVE_TCSETPGRP && !HAVE_TCSETPGRP_DECL && !defined(tcsetpgrp)
  243.     int tcsetpgrp(int fd, pid_t pgid);
  244. #endif
  245. #if HAVE_IOCTL && !HAVE_IOCTL_DECL && !defined(ioctl)
  246.     int ioctl(int fd, int request, ...);
  247. #endif
  248. #if HAVE_FCNTL && !HAVE_FCNTL_DECL && !defined(fcntl)
  249.     int fcntl(int fd, int command, ...);
  250. #endif
  251. #if HAVE_GETPTY && !HAVE_GETPTY_DECL && !defined(getpty)
  252.     int getpty(char *line, char *sline, int mode);
  253. #endif
  254. #if HAVE__GETPTY && !HAVE__GETPTY_DECL && !defined(_getpty)
  255.     char *_getpty(int *fildes, int oflag, mode_t mode, int nofork);
  256. #endif
  257. #if HAVE_SETSID && !HAVE_SETSID_DECL && !defined(setsid)
  258.     pid_t setsid(void);
  259. #endif
  260. #if !HAVE_SETSID && HAVE_SETPGRP && defined(SETPGRP_VOID)
  261. #define setsid() setpgrp()
  262. #define HAVE_SETSID 1
  263. #endif
  264. }
  265.  
  266. // Streams won't work on DEC OSF because there isn't any "ttcompat"
  267. // module and I don't know enough about any of this stuff to try to
  268. // figure it out now.  -- phil_brooks@MENTORG.COM (Phil Brooks)
  269. #if !defined(__osf__) && HAVE_PTSNAME && HAVE_GRANTPT \
  270.     && HAVE_UNLOCKPT && HAVE_IOCTL
  271.  
  272. #define HAVE_STREAMS 1
  273.  
  274. // Provide C++ declarations
  275. extern "C" {
  276. #if !HAVE_PTSNAME_DECL && !defined(ptsname)
  277.     char *ptsname(int master);
  278. #endif
  279. #if !HAVE_UNLOCKPT_DECL && !defined(unlockpt)
  280.     int unlockpt(int fd);
  281. #endif
  282. #if !HAVE_GRANTPT_DECL && !defined(grantpt)
  283.     int grantpt(int fd);
  284. #endif
  285. }
  286.  
  287. #endif // !defined(__osf__) && HAVE_PTSNAME && ...
  288.  
  289. #ifndef STDIN_FILENO
  290. #define STDIN_FILENO 0
  291. #endif
  292. #ifndef STDOUT_FILENO
  293. #define STDOUT_FILENO 1
  294. #endif
  295. #ifndef STDERR_FILENO
  296. #define STDERR_FILENO 2
  297. #endif
  298.  
  299. #ifndef R_OK
  300. /* 3b2 doesn't define these according to jthomas@nmsu.edu. */
  301. #define R_OK 04
  302. #define W_OK 02
  303. #endif
  304.  
  305. #if !defined(O_NONBLOCK) && defined(O_NDELAY)
  306. #define O_NONBLOCK O_NDELAY
  307. #endif
  308.  
  309. #if !defined(O_NONBLOCK) && defined(FNDELAY)
  310. #define O_NONBLOCK FNDELAY
  311. #endif
  312.  
  313. #if !defined(O_APPEND) && defined(FAPPEND)
  314. #define O_APPEND FAPPEND
  315. #endif
  316.  
  317. // Open a tty.
  318. // Like open(TTY, FLAGS), but care for EAGAIN and EWOULDBLOCK conditions
  319. int TTYAgent::open_tty(const char *tty, int flags)
  320. {
  321.     int fd = open(tty, flags);
  322.     if (fd >= 0)
  323.     return fd;
  324.  
  325.     if (false
  326. #ifdef EAGAIN
  327.     || errno == EAGAIN
  328. #endif
  329. #ifdef EWOULDBLOCK
  330.     || errno == EWOULDBLOCK
  331. #endif
  332.     )
  333.     {
  334.     // Resource temporarily unavailable: an operation that would
  335.     // block was attempted on an object that has non-blocking mode
  336.     // selected.  Trying the same operation again will block until
  337.     // some external condition makes it possible to read, write,
  338.     // or connect (whatever the operation).  So, we just try again.
  339.     _raiseIOWarning(string(tty) + " is temporary unavailable");
  340.     fd = open(tty, flags);
  341.     }
  342.  
  343.     return fd;
  344. }
  345.  
  346. // Check whether a TTY is usable
  347. bool TTYAgent::tty_ok(const char *tty)
  348. {
  349.     if (access(tty, R_OK | W_OK) != 0)
  350.     return false;        // No access
  351.  
  352.     int fd = open_tty(tty);
  353.     if (fd < 0)
  354.     return false;        // Cannot open
  355.  
  356.     close(fd);
  357.     return true;
  358. }
  359.  
  360.  
  361. // Open master side of pty.
  362. // Depending on the host features, we try a large variety of possibilities.
  363. void TTYAgent::open_master()
  364. {
  365.     char *line;
  366.     struct stat sb;
  367.  
  368.     // Setup defaults
  369.     push = false;
  370.  
  371. #if HAVE_GETPTY
  372.     // getpty() - an UTS feature
  373.     static char master_line[MAXPTYNAMELEN];
  374.     static char slave_line[MAXPTYNAMELEN];
  375.     master = getpty(master_line, slave_line, O_RDWR);
  376.     if (master >= 0)
  377.     {
  378.     // Verify slave side is usable
  379.     if (tty_ok(slave_line))
  380.     {
  381.         _master_tty  = master_line;
  382.         _slave_tty   = slave_line;
  383.         return;
  384.     }
  385.  
  386.     close(master);
  387.     }
  388. #endif
  389.  
  390. #if HAVE__GETPTY
  391.     // _getpty() - an SGI/IRIX feature
  392.     //
  393.     // Ferdinand Contreras <fcontre@clear.co.nz> reports: The pty man
  394.     // page says to set the O_NDELAY bit in the call to _getpty().
  395.     line = _getpty(&master, O_RDWR | O_NDELAY, 0600, 0);
  396.     if (line != 0 && master >= 0)
  397.     {
  398.     // Verify slave side is usable
  399.     //
  400.     // We don't use TTY_OK() here - it seems this breaks SGI TTY setup.
  401.     // The error messages generated are as follows:
  402.     // 
  403.     // dbx: cannot open /dev/ttyq<n>: I/O error
  404.     // dbx: child communication setup failed
  405.     //
  406.     // Ferdinand Contreras <fcontre@clear.co.nz> says:
  407.     //
  408.     // I've traced the execution and it seems that the slave tty
  409.     // doesn't like to be opened twice.  That is, the tty_ok(line)
  410.     // function call opens the tty and closes it after
  411.     // successfully opening it.  However, the next time it is
  412.     // opened via open_tty() in the function open_slave(), it gets
  413.     // a return code of EIO (errno=5). I've decided to just skip
  414.     // the call to tty_ok() since the slave tty will eventually be
  415.     // opened by open_slave().  Any errors would still be caught
  416.     // at that point.
  417.     if (access(line, R_OK | W_OK) == 0)
  418.     {
  419.         char *t = ttyname(master);
  420.         if (t)
  421.         _master_tty = t;
  422.         _slave_tty   = line;
  423.         return;
  424.     }
  425.     close(master);
  426.     }
  427. #endif
  428.  
  429.     if (stat("/dev/ptc", &sb) == 0)
  430.     {
  431.     // Try /dev/ptc - an AIX and SGI3 feature
  432.     master = open_tty("/dev/ptc");
  433.     if (master >= 0)
  434.     {
  435.         line = ttyname(master);
  436.         if (line != 0)
  437.         {
  438.         if (tty_ok(line))
  439.         {
  440. #if defined(SGI3) || defined(sgi3)
  441.             int ptynum = minor(sb.st_rdev);
  442.             char buffer[BUFSIZ];
  443.             sprintf(buffer, "/dev/ttyq%d", ptynum);
  444.             if (tty_ok(buffer))
  445.             {
  446.             _master_tty = line;
  447.             _slave_tty  = buffer;
  448.             return;
  449.             }
  450. #else
  451.             _master_tty = line;
  452.             _slave_tty  = line;
  453.             return;
  454. #endif
  455.         }
  456.         }
  457.         close(master);
  458.     }
  459.     }
  460.  
  461. #if HAVE_STREAMS
  462.     if (stat("/dev/ptmx", &sb) == 0)
  463.     {
  464.     // Try STREAMS - a SVR4 feature
  465.     master = open_tty("/dev/ptmx");
  466.     if (master >= 0)
  467.     {
  468.         line = ptsname(master);
  469.         if (line == NULL)
  470.         _raiseIOMsg("ptsname");
  471.         else if (grantpt(master))
  472.         _raiseIOMsg("grantpt " + string(line));
  473.         else if (unlockpt(master))
  474.         _raiseIOMsg("unlockpt " + string(line));
  475.         else if (!tty_ok(line))
  476.         _raiseIOMsg("access " + string(line));
  477.         else
  478.         {
  479.         // Everything ok - proceed
  480.         _master_tty = ttyname(master);
  481.         _slave_tty  = line;
  482. #ifdef TIOCFLUSH
  483.         ioctl(master, TIOCFLUSH, (char *)0);
  484. #endif
  485.         push = true;
  486.         return;
  487.         }
  488.  
  489.         close(master);
  490.     }
  491.     else
  492.         _raiseIOMsg("cannot open /dev/ptmx");
  493.     }
  494. #endif
  495.  
  496.     // Try PTY's
  497.     if (stat("/dev/pty/000", &sb) == 0)
  498.     {
  499.     // Try PTY's in /dev/pty/XXX and /dev/ttypXXX -- a UNICOS feature
  500. #if defined(CRAY) && defined(_SC_CRAY_NPTY)
  501.     int highpty = sysconf(_SC_CRAY_NPTY);
  502. #else
  503.     int highpty = 128;
  504. #endif
  505.     for (int i = 0; i < highpty; i++)
  506.     {
  507.         char nr[32];
  508.         sprintf(nr, "%03d", i);
  509.         string pty = string("/dev/pty/") + nr;
  510.         string tty = string("/dev/ttyp") + nr;
  511.         
  512.         master = open_tty(pty.chars());
  513.         if (master >= 0)
  514.         {
  515.         // Verify slave tty is usable
  516.         if (!tty_ok(tty))
  517.         {
  518.             close(master);
  519.             continue;
  520.         }
  521.  
  522.         _master_tty = pty;
  523.         _slave_tty  = tty;
  524.         return;
  525.         }
  526.     }
  527.     }
  528.  
  529.     const string p1 = "pqrstuvwxyzPQRSTUVWXYZ";
  530.     const string p2 = "0123456789abcdefghijklmnopqrstuvwxyz";
  531.  
  532.     if (stat("/dev/ptym", &sb) == 0 && S_ISDIR(sb.st_mode))
  533.     {
  534.     // Try PTY's in /dev/ptym/ptyXX and /dev/pty/ttyXX -- a HP-UX feature
  535.     for (int i = 0; i < int(p1.length()); i++)
  536.         for (int j = 0; j < int(p2.length()); j++)
  537.         {
  538.         string nr  = string(p1[i]) + p2[j];
  539.         string pty = "/dev/ptym/pty" + nr;
  540.         string tty = "/dev/pty/tty" + nr;
  541.         
  542.         master = open_tty(pty.chars());
  543.         if (master >= 0)
  544.         {
  545.             // Verify slave tty is usable
  546.             if (!tty_ok(tty))
  547.             {
  548.             close(master);
  549.             continue;
  550.             }
  551.  
  552.             _master_tty = pty;
  553.             _slave_tty  = tty;
  554.             return;
  555.         }
  556.         }
  557.     }
  558.  
  559.     // Try PTY's in /dev/pty?? -- a BSD and USG feature
  560.     // Slackware 3.0 wants [/zip]/dev/pty??, as
  561.     // Jim Van Zandt <jrv@vanzandt.mv.com> suggests.
  562.     for (int k = 0; k < 2; k++)
  563.     {
  564.     string prefix = (k == 0 ? "" : "/zip");
  565.  
  566.     for (int i = 0; i < int(p1.length()); i++)
  567.     {
  568.         for (int j = 0; j < int(p2.length()); j++)
  569.         {
  570.         string nr  = string(p1[i]) + p2[j];
  571.         string pty = prefix + "/dev/pty" + nr;
  572.         string tty = prefix + "/dev/tty" + nr;
  573.  
  574.         master = open_tty(pty.chars());
  575.         if (master >= 0)
  576.         {
  577.             // Verify slave tty is usable
  578.             if (!tty_ok(tty))
  579.             {
  580.             close(master);
  581.             continue;
  582.             }
  583.  
  584.             _master_tty = pty;
  585.             _slave_tty  = tty;
  586.             return;
  587.         }
  588.         }
  589.     }
  590.     }
  591.  
  592.     _raiseIOMsg("cannot open master pty");
  593.     return;
  594. }
  595.  
  596.  
  597. // Open slave side of the pty.  The slave pty name has been set
  598. // in slave_tty by open_master.
  599. void TTYAgent::open_slave()
  600. {
  601.     slave = open_tty(slave_tty().chars());
  602.     if (slave < 0)
  603.     {
  604.     _raiseIOMsg("cannot open " + slave_tty());
  605.     return;
  606.     }
  607.  
  608. #if HAVE_IOCTL && defined(TIOCSCTTY)
  609.     if (!push)
  610.     {
  611.     // This is required on some boxes (notably DEC OSF and
  612.     // FreeBSD); if it fails, don't complain.
  613.     if (ioctl(slave, TIOCSCTTY, 1) < 0)
  614.     {
  615.         // _raiseIOWarning("cannot allocate controlling terminal");
  616.     }
  617.     }
  618. #endif
  619.  
  620. #if HAVE_STREAMS && defined(I_PUSH)
  621.     if (push)
  622.     {
  623.     // Finish STREAMS setup.
  624.     if (ioctl(slave, I_PUSH, "ptem"))
  625.         _raiseIOWarning("ioctl ptem " + slave_tty());
  626.     if (ioctl(slave, I_PUSH, "ldterm"))
  627.         _raiseIOWarning("ioctl ldterm " + slave_tty());
  628.     if (ioctl(slave, I_PUSH, "ttcompat"))
  629.     {
  630.         // On HP-UX and other systems, this call always fails.
  631.         // Fortunately, it seems we can live without as well.  Hence,
  632.         // we suppress the warning message to avoid confusion.
  633. #if 0
  634.         _raiseIOWarning("ioctl ttcompat " + slave_tty());
  635. #endif
  636.     }
  637.     }
  638. #endif // I_PUSH
  639.  
  640.     return;
  641. }
  642.  
  643.  
  644. int TTYAgent::setupCommunication()
  645. {
  646.     open_master();
  647.     if (master < 0)
  648.     return -1;
  649.  
  650.     return 0;
  651. }
  652.  
  653. #if SYNCHRONIZE_PARENT_AND_CHILD
  654. static char TTY_INIT[] = { 'A', '\n' };
  655. #endif
  656.  
  657.  
  658. int TTYAgent::setupParentCommunication()
  659. {
  660. #if SYNCHRONIZE_PARENT_AND_CHILD
  661.     // Read initialization sequence from TTY (synchronizing)
  662.     char buf[BUFSIZ];
  663.     int ret = ::read(master, buf, sizeof(TTY_INIT));
  664.     if (ret <= 0)
  665.     raiseIOMsg("cannot read initialization sequence from child");
  666. #endif
  667.  
  668.  
  669. #if HAVE_FCNTL && defined(O_NONBLOCK)
  670.     // Set the child file descriptor to nonblocking mode
  671.     int flags = fcntl(master, F_GETFL, 0);
  672.     if (flags == -1)
  673.     {
  674.     _raiseIOWarning("cannot get file descriptor status flags");
  675.     }
  676.     else
  677.     {
  678.     if (fcntl(master, F_SETFL, flags | O_NONBLOCK) == -1)
  679.         _raiseIOWarning("cannot set file to non-blocking mode");
  680.     }
  681. #endif
  682.     
  683.     // Open file pointer with read/write access to child process
  684.     _inputfp = fdopen(master, "r+");
  685.     if (inputfp() == NULL)
  686.     {
  687.     raiseIOMsg("cannot associate input stream with pty master");
  688.     terminate();
  689.     return -1;
  690.     }
  691.  
  692.     _outputfp = _inputfp;
  693.     _errorfp  = NULL;
  694.  
  695. #if HAVE_SETBUF
  696.     // Set unbuffered mode
  697.     setbuf(_outputfp, NULL);
  698. #elif HAVE_SETVBUF && defined(_IONBF)
  699.     // According to lee@champion.tcs.co.jp (Lee Hounshell), this
  700.     // won't work on Linux ELF systems:
  701.     setvbuf(_outputfp, NULL, _IONBF, BUFSIZ);
  702. #endif
  703.  
  704. #if SYNCHRONIZE_PARENT_AND_CHILD
  705.     // Echo initialization sequence again
  706.     ::write(master, TTY_INIT, sizeof(TTY_INIT));
  707. #endif
  708.  
  709.     return 0;
  710. }
  711.  
  712.  
  713. int TTYAgent::setupChildCommunication()
  714. {
  715.     // Close master side of pty
  716.     close(master);
  717.  
  718.     int result = 0;
  719.     pid_t pid = getpid();
  720.  
  721.     // Make child a process leader:
  722.     // Set the process group of the pty and of us to our process id.
  723.  
  724. #if HAVE_SETSID || defined(setsid)
  725.     result = int(setsid());
  726. #else // !HAVE_SETSID
  727.  
  728.     // Clear controlling tty.  This means that we will not have a
  729.     // controlling tty until we open another terminal device.
  730. #if HAVE_IOCTL && defined(TIOCNOTTY)
  731.     int fd;
  732.  
  733. #if HAVE_TCGETSID && HAVE_TCGETPGRP
  734.     if ((tcgetsid(STDIN_FILENO) != tcgetpgrp(STDIN_FILENO)) &&
  735.     (fd = open_tty("/dev/tty", O_RDWR | O_NONBLOCK)) > 0)
  736. #else  // !HAVE_TCGETSID
  737.     if ((fd = open_tty("/dev/tty")) > 0)
  738. #endif // !HAVE_TCGETSID
  739.     {
  740.       result = ioctl(fd, TIOCNOTTY, 0);
  741.       close(fd);
  742.     }
  743.     if (result < 0)
  744.     _raiseIOMsg("cannot clear controlling tty");
  745. #endif // HAVE_IOCTL && defined(TIOCNOTTY)
  746.  
  747.     // Create a new process group.
  748. #if HAVE_SETPGID
  749.     result = setpgid(pid, pid);
  750. #endif // HAVE_SETPGID
  751. #endif // !HAVE_SETSID
  752.  
  753.     if (result < 0)
  754.     _raiseIOMsg("cannot create new process group");
  755.  
  756.     if (slave < 0)
  757.     {
  758.     // Open slave such that it becomes the controlling terminal.
  759.     open_slave();
  760.     }
  761.  
  762.     if (slave < 0)
  763.     return -1;
  764.  
  765.  
  766.     // Make this process the foreground process in the slave pty.
  767.     result = 0;
  768. #if HAVE_TCSETPGRP
  769.     result = tcsetpgrp(slave, pid);
  770. #elif HAVE_IOCTL && defined(TIOCSPGRP)
  771.     result = ioctl(slave, TIOCSPGRP, &pid);
  772. #endif
  773.  
  774.     if (result < 0)
  775.     _raiseIOMsg("cannot set terminal foreground process group");
  776.  
  777.     // Modify local and output mode of slave pty
  778. #if HAVE_TCGETATTR && HAVE_TCSETATTR
  779.     // Method 1.  Use termios, tcgetattr(), and tcsetattr().
  780.     struct termios settings;
  781.     result = tcgetattr(slave, &settings);
  782.     if (result < 0)
  783.     _raiseIOMsg("cannot get slave terminal settings");
  784.     else
  785.     {
  786. #ifdef ICANON
  787.     settings.c_lflag |= ICANON;     // Canonical mode
  788. #endif
  789. #ifdef ECHO
  790.     settings.c_lflag &= ~ECHO;      // No echo
  791. #endif
  792. #ifdef ECHONL
  793.     settings.c_lflag &= ~ECHONL;    // No echo of newlines
  794. #endif
  795. #ifdef ISIG
  796.     settings.c_lflag |= ISIG;       // Enable signal characters
  797. #endif
  798. #ifdef TOSTOP
  799.     settings.c_lflag &= ~TOSTOP;    // No interrupt on background processes
  800. #endif
  801. #ifdef NOFLSH
  802.     settings.c_lflag &= ~NOFLSH;    // Clear queues upon interrupt
  803. #endif
  804. #ifdef OPOST
  805.     settings.c_oflag &= ~OPOST;     // Do not process output data
  806. #endif
  807. #ifdef ONLCR
  808.     settings.c_oflag &= ~ONLCR;     // Do not map NL to CR-NL on output
  809. #endif
  810. #ifdef VDSUSP
  811.     settings.c_cc[VSUSP] = '\031';  // Set DELAYED SUSPEND to `^Y'
  812. #endif
  813. #ifdef VEOF
  814.     settings.c_cc[VEOF] = '\004';   // Set EOF character to `^D'
  815. #endif
  816. #ifdef VERASE
  817.     settings.c_cc[VERASE] = '\010'; // Set ERASE character to `^H'
  818. #endif
  819. #ifdef VINTR
  820.     settings.c_cc[VINTR] = '\003';  // Set INTERRUPT to `^C'
  821. #endif
  822. #ifdef VKILL
  823.     settings.c_cc[VKILL] = '\025';  // Set KILL character to `^U'
  824. #endif
  825. #ifdef VQUIT
  826.     settings.c_cc[VQUIT] = '\034';  // Set QUIT to `^\'
  827. #endif
  828. #ifdef VSUSP
  829.     settings.c_cc[VSUSP] = '\032';  // Set SUSPEND to `^Z'
  830. #endif
  831. #ifdef VREPRINT
  832.     settings.c_cc[VREPRINT] = '\022'; // Set REPRINT character to `^R'
  833. #endif
  834. #ifdef VWERASE
  835.     settings.c_cc[VWERASE] = '\027'; // Set WERASE character to `^W'
  836. #endif
  837.     result = tcsetattr(slave, TCSANOW, &settings);
  838.     if (result < 0)
  839.         _raiseIOMsg("cannot set slave terminal settings");
  840.     }
  841. #elif HAVE_IOCTL && defined(TIOCGETP) && defined(TIOCSETP)
  842.     // Method 2.  Use sgttyb, ioctl(TIOCGETP), and ioctl(TIOCSETP).
  843.     struct sgttyb settings;
  844.     result = ioctl(slave, TIOCGETP, &settings);
  845.     if (result < 0)
  846.     _raiseIOMsg("cannot get slave terminal settings");
  847.     else
  848.     {
  849. #ifdef ECHO
  850.     settings.sg_flags &= ~ECHO;    // No echo
  851. #endif
  852. #ifdef ISIG
  853.     settings.sg_flags |= ISIG;      // Enable signals
  854. #endif
  855. #ifdef CRMOD
  856.     settings.sg_flags &= ~CRMOD;    // Do not map NL to CR-NL on output
  857. #endif
  858.     result = ioctl(slave, TIOCSETP, &settings);
  859.     if (result < 0)
  860.         _raiseIOMsg("cannot set slave terminal settings");
  861.     }
  862. #elif HAVE_IOCTL && defined(TCGETA) && defined(TCSETA)
  863.     // Method 3.  Use termio, ioctl(TCGETA), and ioctl(TCSETA).
  864.     struct termio settings;
  865.     result = ioctl(slave, TCGETA, &settings);
  866.     if (result < 0)
  867.     _raiseIOMsg("cannot get slave terminal settings");
  868.     else
  869.     {
  870. #ifdef ICANON
  871.     settings.c_lflag |= ICANON;     // Canonical mode
  872. #endif
  873. #ifdef ECHO
  874.     settings.c_lflag &= ~ECHO;      // No echo
  875. #endif
  876. #ifdef ISIG
  877.     settings.c_lflag |= ISIG;       // Enable signal characters
  878. #endif
  879. #ifdef OPOST
  880.     settings.c_oflag &= ~OPOST;     // Do not process output data
  881. #endif
  882. #ifdef ONLCR
  883.     settings.c_oflag &= ~ONLCR;    // Do not map NL to CR-NL on output
  884. #endif
  885. #ifdef VDSUSP
  886.     settings.c_cc[VSUSP] = '\031';  // Set DELAYED SUSPEND to `^Y'
  887. #endif
  888. #ifdef VEOF
  889.     settings.c_cc[VEOF] = '\004';   // Set EOF character to `^D'
  890. #endif
  891. #ifdef VERASE
  892.     settings.c_cc[VERASE] = '\010'; // Set ERASE character to `^H'
  893. #endif
  894. #ifdef VINTR
  895.     settings.c_cc[VINTR] = '\003';  // Set INTERRUPT to `^C'
  896. #endif
  897. #ifdef VKILL
  898.     settings.c_cc[VKILL] = '\025';  // Set KILL character to `^U'
  899. #endif
  900. #ifdef VQUIT
  901.     settings.c_cc[VQUIT] = '\034';  // Set QUIT to `^\'
  902. #endif
  903. #ifdef VSUSP
  904.     settings.c_cc[VSUSP] = '\032';  // Set SUSPEND to `^Z'
  905. #endif
  906. #ifdef VREPRINT
  907.     settings.c_cc[VREPRINT] = '\022'; // Set REPRINT character to `^R'
  908. #endif
  909. #ifdef VWERASE
  910.     settings.c_cc[VWERASE] = '\027'; // Set WERASE character to `^W'
  911. #endif
  912.     result = ioctl(slave, TCSETA, &settings);
  913.     if (result < 0)
  914.         _raiseIOMsg("cannot set slave terminal settings");
  915.     }
  916. #else // !HAVE_TCGETATTR && !HAVE_IOCTL
  917.     // No method left.  There is probably something wrong with
  918.     // config.h -- HAVE_IOCTL may be missing, for instance.
  919.     // We actually might compile and run here, but without
  920.     // being able to reset echo mode, things will be real bad.
  921. #error no way to set child terminal mode -- please check the settings of
  922. #error HAVE_TCSETATTR, HAVE_IOCTL, HAVE_TERMIOS_H, HAVE_TERMIO_H in config.h
  923. #endif // !HAVE_IOCTL
  924.  
  925.     // Redirect stdin, stdout, stderr of child to pty
  926.     if (dup2(slave, STDIN_FILENO) < 0)
  927.     _raiseIOMsg("cannot redirect standard input to slave pty");
  928.     if (dup2(slave, STDOUT_FILENO) < 0)
  929.     _raiseIOMsg("cannot redirect standard output to slave pty");
  930.     if (dup2(slave, STDERR_FILENO) < 0)
  931.     _raiseIOMsg("cannot redirect standard error to slave pty");
  932.  
  933.     if (slave > STDERR_FILENO)
  934.     close(slave);
  935.  
  936.     // Unbuffer output data from child
  937.     fcntl(STDOUT_FILENO, F_SETFL, O_APPEND);
  938.     setbuf(stdout, NULL);
  939.  
  940. #if SYNCHRONIZE_PARENT_AND_CHILD
  941.     // Send an initialization sequence ...
  942.     ::write(STDOUT_FILENO, TTY_INIT, sizeof(TTY_INIT));
  943.  
  944.     // ... and read it back again
  945.     char buf[BUFSIZ];
  946.     int ret = ::read(STDIN_FILENO, buf, sizeof(TTY_INIT));
  947.     if (ret <= 0)
  948.     raiseIOMsg("cannot read initialization sequence from parent");
  949. #endif
  950.  
  951.     return 0;
  952. }
  953.