Back to index

glibc  2.9
openpty.c
Go to the documentation of this file.
00001 /* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <fcntl.h>
00022 #include <limits.h>
00023 #include <pty.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <termios.h>
00027 #include <unistd.h>
00028 #include <sys/types.h>
00029 
00030 
00031 /* Return the result of ptsname_r in the buffer pointed to by PTS,
00032    which should be of length BUF_LEN.  If it is too long to fit in
00033    this buffer, a sufficiently long buffer is allocated using malloc,
00034    and returned in PTS.  0 is returned upon success, -1 otherwise.  */
00035 static int
00036 pts_name (int fd, char **pts, size_t buf_len)
00037 {
00038   int rv;
00039   char *buf = *pts;
00040 
00041   for (;;)
00042     {
00043       char *new_buf;
00044 
00045       if (buf_len)
00046        {
00047          rv = ptsname_r (fd, buf, buf_len);
00048 
00049          if (rv != 0 || memchr (buf, '\0', buf_len))
00050            /* We either got an error, or we succeeded and the
00051               returned name fit in the buffer.  */
00052            break;
00053 
00054          /* Try again with a longer buffer.  */
00055          buf_len += buf_len;       /* Double it */
00056        }
00057       else
00058        /* No initial buffer; start out by mallocing one.  */
00059        buf_len = 128;              /* First time guess.  */
00060 
00061       if (buf != *pts)
00062        /* We've already malloced another buffer at least once.  */
00063        new_buf = realloc (buf, buf_len);
00064       else
00065        new_buf = malloc (buf_len);
00066       if (! new_buf)
00067        {
00068          rv = -1;
00069          __set_errno (ENOMEM);
00070          break;
00071        }
00072       buf = new_buf;
00073     }
00074 
00075   if (rv == 0)
00076     *pts = buf;             /* Return buffer to the user.  */
00077   else if (buf != *pts)
00078     free (buf);             /* Free what we malloced when returning an error.  */
00079 
00080   return rv;
00081 }
00082 
00083 /* Create pseudo tty master slave pair and set terminal attributes
00084    according to TERMP and WINP.  Return handles for both ends in
00085    AMASTER and ASLAVE, and return the name of the slave end in NAME.  */
00086 int
00087 openpty (int *amaster, int *aslave, char *name,
00088         const struct termios *termp, const struct winsize *winp)
00089 {
00090 #ifdef PATH_MAX
00091   char _buf[PATH_MAX];
00092 #else
00093   char _buf[512];
00094 #endif
00095   char *buf = _buf;
00096   int master, slave;
00097 
00098   master = getpt ();
00099   if (master == -1)
00100     return -1;
00101 
00102   if (grantpt (master))
00103     goto fail;
00104 
00105   if (unlockpt (master))
00106     goto fail;
00107 
00108   if (pts_name (master, &buf, sizeof (_buf)))
00109     goto fail;
00110 
00111   slave = open (buf, O_RDWR | O_NOCTTY);
00112   if (slave == -1)
00113     {
00114       if (buf != _buf)
00115        free (buf);
00116 
00117       goto fail;
00118     }
00119 
00120   /* XXX Should we ignore errors here?  */
00121   if(termp)
00122     tcsetattr (slave, TCSAFLUSH, termp);
00123   if (winp)
00124     ioctl (slave, TIOCSWINSZ, winp);
00125 
00126   *amaster = master;
00127   *aslave = slave;
00128   if (name != NULL)
00129     strcpy (name, buf);
00130 
00131   if (buf != _buf)
00132     free (buf);
00133   return 0;
00134 
00135  fail:
00136   close (master);
00137   return -1;
00138 }
00139 libutil_hidden_def (openpty)