(root)/
glibc-2.38/
support/
support_openpty.c
       1  /* Open a pseudoterminal.
       2     Copyright (C) 2018-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <support/tty.h>
      20  #include <support/check.h>
      21  #include <support/support.h>
      22  
      23  #include <errno.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  
      27  #include <fcntl.h>
      28  #include <termios.h>
      29  #include <sys/ioctl.h>
      30  #include <unistd.h>
      31  
      32  /* As ptsname, but allocates space for an appropriately-sized string
      33     using malloc.  */
      34  static char *
      35  xptsname (int fd)
      36  {
      37    int rv;
      38    size_t buf_len = 128;
      39    char *buf = xmalloc (buf_len);
      40    for (;;)
      41      {
      42        rv = ptsname_r (fd, buf, buf_len);
      43        if (rv)
      44          FAIL_EXIT1 ("ptsname_r: %s", strerror (errno));
      45  
      46        if (memchr (buf, '\0', buf_len))
      47          return buf; /* ptsname succeeded and the buffer was not truncated */
      48  
      49        buf_len *= 2;
      50        buf = xrealloc (buf, buf_len);
      51      }
      52  }
      53  
      54  void
      55  support_openpty (int *a_outer, int *a_inner, char **a_name,
      56                   const struct termios *termp,
      57                   const struct winsize *winp)
      58  {
      59    int outer = -1, inner = -1;
      60    char *namebuf = 0;
      61  
      62    outer = posix_openpt (O_RDWR | O_NOCTTY);
      63    if (outer == -1)
      64      FAIL_EXIT1 ("posix_openpt: %s", strerror (errno));
      65  
      66    if (grantpt (outer))
      67      FAIL_EXIT1 ("grantpt: %s", strerror (errno));
      68  
      69    if (unlockpt (outer))
      70      FAIL_EXIT1 ("unlockpt: %s", strerror (errno));
      71  
      72  
      73  #ifdef TIOCGPTPEER
      74    inner = ioctl (outer, TIOCGPTPEER, O_RDWR | O_NOCTTY);
      75  #endif
      76    if (inner == -1)
      77      {
      78        /* The kernel might not support TIOCGPTPEER, fall back to open
      79           by name.  */
      80        namebuf = xptsname (outer);
      81        inner = open (namebuf, O_RDWR | O_NOCTTY);
      82        if (inner == -1)
      83          FAIL_EXIT1 ("%s: %s", namebuf, strerror (errno));
      84      }
      85  
      86    if (termp)
      87      {
      88        if (tcsetattr (inner, TCSAFLUSH, termp))
      89          FAIL_EXIT1 ("tcsetattr: %s", strerror (errno));
      90      }
      91  #ifdef TIOCSWINSZ
      92    if (winp)
      93      {
      94        if (ioctl (inner, TIOCSWINSZ, winp))
      95          FAIL_EXIT1 ("TIOCSWINSZ: %s", strerror (errno));
      96      }
      97  #endif
      98  
      99    if (a_name)
     100      {
     101        if (!namebuf)
     102          namebuf = xptsname (outer);
     103        *a_name = namebuf;
     104      }
     105    else
     106      free (namebuf);
     107    *a_outer = outer;
     108    *a_inner = inner;
     109  }