c6e75c6241243c118f68860a6bc53850e53df41d
[gnulib.git] / lib / openpty.c
1 /* Open a pseudo-terminal.
2    Copyright (C) 2010-2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 #include <config.h>
18
19 /* Specification.  */
20 #include <pty.h>
21
22 #if HAVE_OPENPTY
23
24 /* Provide a wrapper with the prototype of glibc-2.8 and newer.  */
25 # undef openpty
26 int
27 rpl_openpty (int *amaster, int *aslave, char *name,
28              struct termios const *termp, struct winsize const *winp)
29 {
30   /* Cast away const, for implementations with weaker prototypes.  */
31   return openpty (amaster, aslave, name, (struct termios *) termp,
32                   (struct winsize *) winp);
33 }
34
35 #else /* AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 10, mingw */
36
37 # include <fcntl.h>
38 # include <string.h>
39 # include <sys/ioctl.h>
40 # include <termios.h>
41 # include <unistd.h>
42 # if defined __sun || defined __hpux /* Solaris, HP-UX */
43 #  include <stropts.h>
44 # endif
45
46 int
47 openpty (int *amaster, int *aslave, char *name,
48          struct termios const *termp, struct winsize const *winp)
49 {
50   int master;
51   char *slave_name;
52   int slave;
53
54 # if HAVE__GETPTY /* IRIX */
55
56   slave_name = _getpty (&master, O_RDWR, 0622, 0);
57   if (slave_name == NULL)
58     return -1;
59
60 # else /* AIX 5.1, HP-UX 11, Solaris 10, mingw */
61
62 #  if HAVE_POSIX_OPENPT /* Solaris 10 */
63
64   master = posix_openpt (O_RDWR | O_NOCTTY);
65   if (master < 0)
66     return -1;
67
68 #  else /* AIX 5.1, HP-UX 11, Solaris 9, mingw */
69
70 #   ifdef _AIX /* AIX */
71
72   master = open ("/dev/ptc", O_RDWR | O_NOCTTY);
73   if (master < 0)
74     return -1;
75
76 #   else /* HP-UX 11, Solaris 9, mingw */
77
78   /* HP-UX, Solaris have /dev/ptmx.
79      HP-UX also has /dev/ptym/clone, but this should not be needed.
80      Linux also has /dev/ptmx, but Linux already has openpty().
81      MacOS X also has /dev/ptmx, but MacOS X already has openpty().
82      OSF/1 also has /dev/ptmx and /dev/ptmx_bsd, but OSF/1 already has
83      openpty().  */
84   master = open ("/dev/ptmx", O_RDWR | O_NOCTTY);
85   if (master < 0)
86     return -1;
87
88 #   endif
89
90 #  endif
91
92   /* If all this does not work, we could try to open, one by one:
93      - On MacOS X: /dev/pty[p-w][0-9a-f]
94      - On *BSD:    /dev/pty[p-sP-S][0-9a-v]
95      - On Minix:   /dev/pty[p-q][0-9a-f]
96      - On AIX:     /dev/ptyp[0-9a-f]
97      - On HP-UX:   /dev/pty[p-r][0-9a-f]
98      - On OSF/1:   /dev/pty[p-q][0-9a-f]
99      - On Solaris: /dev/pty[p-r][0-9a-f]
100    */
101 # endif
102
103   /* This call does not require a dependency to the 'grantpt' module,
104      because AIX, HP-UX, IRIX, Solaris all have the grantpt() function.  */
105   if (grantpt (master))
106     goto fail;
107
108   /* This call does not require a dependency to the 'unlockpt' module,
109      because AIX, HP-UX, IRIX, Solaris all have the unlockpt() function.  */
110   if (unlockpt (master))
111     goto fail;
112
113 # if !HAVE__GETPTY /* !IRIX */
114   slave_name = ptsname (master);
115   if (slave_name == NULL)
116     goto fail;
117 # endif
118
119   slave = open (slave_name, O_RDWR | O_NOCTTY);
120   if (slave == -1)
121     goto fail;
122
123 # if defined __sun || defined __hpux /* Solaris, HP-UX */
124   if (ioctl (slave, I_PUSH, "ptem") < 0
125       || ioctl (slave, I_PUSH, "ldterm") < 0
126 #  if defined __sun
127       || ioctl (slave, I_PUSH, "ttcompat") < 0
128 #  endif
129      )
130     {
131       close (slave);
132       goto fail;
133     }
134 # endif
135
136   /* XXX Should we ignore errors here?  */
137   if (termp)
138     tcsetattr (slave, TCSAFLUSH, termp);
139   if (winp)
140     ioctl (slave, TIOCSWINSZ, winp);
141
142   *amaster = master;
143   *aslave = slave;
144   if (name != NULL)
145     strcpy (name, slave_name);
146
147   return 0;
148
149  fail:
150   close (master);
151   return -1;
152 }
153
154 #endif