(root)/
texinfo-7.1/
info/
pseudotty.c
       1  /* pseudotty - open pseudo-terminal and print name of slave device to
       2     standard output.  Read and ignore any data sent to terminal.  This
       3     is so we can run tests interactively without messing up the screen.
       4  
       5     Copyright 2014-2023 Free Software Foundation, Inc.
       6  
       7     This program is free software: you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation, either version 3 of the License, or
      10     (at your option) any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19     
      20     Originally written by Gavin Smith.  */
      21  
      22  #define _XOPEN_SOURCE 600
      23  /* for posix_openpt */
      24  
      25  #include <config.h>
      26  #include <errno.h>
      27  #include <error.h>
      28  #include <stdio.h>
      29  #include <fcntl.h>
      30  #include <unistd.h>
      31  #include <sys/ioctl.h>
      32  #include <sys/types.h>
      33  #include <sys/select.h>
      34  #include <stdlib.h>
      35  #include <string.h>
      36  
      37  #if defined __sun || defined __hpux /* Solaris, HP-UX */
      38  #include <stropts.h>
      39  #endif
      40  
      41  #include "termdep.h"
      42  
      43  /* Used by "error" function. */
      44  const char *program_name = "pseudotty";
      45  
      46  int
      47  main (int argc, char *argv[])
      48  {
      49    int master, slave, control;
      50    char *name;
      51    fd_set read_set;
      52  
      53    error (0, 0, "getting pty master fd");
      54    master = posix_openpt (O_RDWR);
      55    if (master == -1)
      56      exit (1);
      57  
      58    error (0, 0, "unlocking slave device");
      59    if (grantpt (master) < 0 || unlockpt (master) < 0)
      60      exit (1);
      61    error (0, 0, "getting file name of slave device...");
      62    name = ptsname (master);
      63    if (!name)
      64      exit (1);
      65    error (0, 0, "%s", name);
      66  
      67    error (0, 0, "opening slave device");
      68    slave = open (name, O_RDWR);
      69    if (slave == -1)
      70      exit (1);
      71  
      72  #if defined __sun || defined __hpux /* Solaris, HP-UX */
      73    if (isastream (slave))
      74      {
      75        error (0, 0, "performing STREAMS ioctl's on slave");
      76        if (ioctl (slave, I_PUSH, "ptem") < 0
      77            || ioctl (slave, I_PUSH, "ldterm") < 0
      78  #  if defined __sun
      79            || ioctl (slave, I_PUSH, "ttcompat") < 0
      80  #  endif
      81           )
      82          error (1, 0, "STREAMS ioctl's failed");
      83      }
      84  #endif
      85  
      86  #if defined (HAVE_TERMIOS_H)
      87    {
      88    struct termios t;
      89    long int disable;
      90    disable = fpathconf (slave, _PC_VDISABLE);
      91    if (tcgetattr (slave, &t) == -1)
      92      error (0, 0, "error calling tcgetattr");
      93    else
      94      {
      95        t.c_cc[VSTART] = disable; /* C-q */
      96        t.c_cc[VSTOP] = disable;  /* C-s */
      97        t.c_cc[VKILL] = disable;  /* C-u */
      98        t.c_cc[VINTR] = disable;  /* C-c */
      99        t.c_lflag &= (~ICANON & ~ECHO);
     100        t.c_cc[VMIN] = 1;
     101        t.c_cc[VTIME] = 0;
     102        if (tcsetattr (slave, TCSANOW, &t) == -1)
     103          error (0, 0, "error calling tcsetattr");
     104      }
     105    }
     106  #endif
     107  
     108  #if defined (TIOCSWINSZ)
     109    {
     110      struct winsize ws;
     111      ws.ws_col = ws.ws_row = 0;
     112  
     113      error (0, 0, "attempting to set window size");
     114      if (ioctl (master, TIOCSWINSZ, &ws) == 0)
     115        error (0, 0, "...succeeded");
     116      else
     117        error (0, 0, "...failed");
     118    }
     119  #endif 
     120  
     121    printf ("%s\n", name);
     122    if (fclose (stdout) != 0)
     123      error (1, 0, "error closing stdout: aborting");
     124  
     125    error (0, 0, "opening control channel");
     126    control = open (argv[1], O_RDONLY);
     127    if (control == -1)
     128      error (1, 0, "error opening control channel: aborting");
     129  
     130  
     131    FD_ZERO (&read_set);
     132  
     133    error (0, 0, "entering main loop");
     134    while (1)
     135      {
     136        FD_SET (master, &read_set);
     137        FD_SET (control, &read_set);
     138  
     139        select (FD_SETSIZE, &read_set, 0, 0, 0);
     140  
     141        if (FD_ISSET (control, &read_set))
     142          {
     143            char c;
     144            int success;
     145            errno = 0;
     146            while (1)
     147              {
     148                error (0, 0, "trying to read");
     149                success = read (control, &c, 1);
     150                if (success < 0)
     151                  {
     152                    if (errno != EINTR)
     153                      error (1, errno, "read error on control channel");
     154                  }
     155                else if (success == 0)
     156                  {
     157                    error (1, 0, "end of file on control channel");
     158                  }
     159                else if (success == 1)
     160                  {
     161                    error (0, 0, "read byte 0x%02X", c);
     162                    break;
     163                  }
     164              }
     165  
     166            /* Feed any read bytes to the program being controlled. */
     167            do
     168              {
     169                success = write (master, &c, 1);
     170                if (success == 0)
     171                  {
     172                    error (0, 0, "couldn't send byte!");
     173                    sleep (1);
     174                    continue;
     175                  }
     176              }
     177            while (success == -1 && errno == EINTR);
     178  
     179            if (success != 1)
     180              {
     181                /* The controlled process has probably exited, or been killed. */
     182                error (0, 0, "couldn't send byte (giving up)");
     183                sleep (1);
     184              }
     185          }
     186  
     187        if (FD_ISSET (master, &read_set))
     188          {
     189            char c;
     190            int success;
     191            errno = 0;
     192            do
     193              {
     194                success = read (master, &c, 1);
     195              }
     196            while (success == -1 && errno == EINTR);
     197  
     198            if (success == -1)
     199              {
     200                /* The controlled process has probably exited, or been killed. */
     201                error (0, 0, "read error on master fd");
     202                sleep (1);
     203              }
     204          }
     205      }
     206  
     207    return 0; /* NOTREACHED */
     208  }