Replace FSF snail mail address with URLs.
[platform/upstream/glibc.git] / login / openpty.c
1 /* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
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    <http://www.gnu.org/licenses/>.  */
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <pty.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <termios.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28
29
30 /* Return the result of ptsname_r in the buffer pointed to by PTS,
31    which should be of length BUF_LEN.  If it is too long to fit in
32    this buffer, a sufficiently long buffer is allocated using malloc,
33    and returned in PTS.  0 is returned upon success, -1 otherwise.  */
34 static int
35 pts_name (int fd, char **pts, size_t buf_len)
36 {
37   int rv;
38   char *buf = *pts;
39
40   for (;;)
41     {
42       char *new_buf;
43
44       if (buf_len)
45         {
46           rv = ptsname_r (fd, buf, buf_len);
47
48           if (rv != 0 || memchr (buf, '\0', buf_len))
49             /* We either got an error, or we succeeded and the
50                returned name fit in the buffer.  */
51             break;
52
53           /* Try again with a longer buffer.  */
54           buf_len += buf_len;   /* Double it */
55         }
56       else
57         /* No initial buffer; start out by mallocing one.  */
58         buf_len = 128;          /* First time guess.  */
59
60       if (buf != *pts)
61         /* We've already malloced another buffer at least once.  */
62         new_buf = realloc (buf, buf_len);
63       else
64         new_buf = malloc (buf_len);
65       if (! new_buf)
66         {
67           rv = -1;
68           __set_errno (ENOMEM);
69           break;
70         }
71       buf = new_buf;
72     }
73
74   if (rv == 0)
75     *pts = buf;         /* Return buffer to the user.  */
76   else if (buf != *pts)
77     free (buf);         /* Free what we malloced when returning an error.  */
78
79   return rv;
80 }
81
82 /* Create pseudo tty master slave pair and set terminal attributes
83    according to TERMP and WINP.  Return handles for both ends in
84    AMASTER and ASLAVE, and return the name of the slave end in NAME.  */
85 int
86 openpty (int *amaster, int *aslave, char *name,
87          const struct termios *termp, const struct winsize *winp)
88 {
89 #ifdef PATH_MAX
90   char _buf[PATH_MAX];
91 #else
92   char _buf[512];
93 #endif
94   char *buf = _buf;
95   int master, slave;
96
97   master = getpt ();
98   if (master == -1)
99     return -1;
100
101   if (grantpt (master))
102     goto fail;
103
104   if (unlockpt (master))
105     goto fail;
106
107   if (pts_name (master, &buf, sizeof (_buf)))
108     goto fail;
109
110   slave = open (buf, O_RDWR | O_NOCTTY);
111   if (slave == -1)
112     {
113       if (buf != _buf)
114         free (buf);
115
116       goto fail;
117     }
118
119   /* XXX Should we ignore errors here?  */
120   if(termp)
121     tcsetattr (slave, TCSAFLUSH, termp);
122   if (winp)
123     ioctl (slave, TIOCSWINSZ, winp);
124
125   *amaster = master;
126   *aslave = slave;
127   if (name != NULL)
128     strcpy (name, buf);
129
130   if (buf != _buf)
131     free (buf);
132   return 0;
133
134  fail:
135   close (master);
136   return -1;
137 }
138 libutil_hidden_def (openpty)