1 /*
2 * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
3 * University Research and Technology
4 * Corporation. All rights reserved.
5 * Copyright (c) 2004-2005 The University of Tennessee and The University
6 * of Tennessee Research Foundation. All rights
7 * reserved.
8 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9 * University of Stuttgart. All rights reserved.
10 * Copyright (c) 2004-2005 The Regents of the University of California.
11 * All rights reserved.
12 * Copyright (c) 2018 Cisco Systems, Inc. All rights reserved
13 * $COPYRIGHT$
14 *
15 * Additional copyrights may follow
16 *
17 * $HEADER$
18 */
19 /*-
20 * Copyright (c) 1990, 1993
21 * The Regents of the University of California. All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 4. Neither the name of the University nor the names of its contributors
32 * may be used to endorse or promote products derived from this software
33 * without specific prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
46 */
47
48 #include "opal_config.h"
49
50 #ifdef HAVE_SYS_CDEFS_H
51 # include <sys/cdefs.h>
52 #endif
53 #ifdef HAVE_SYS_TYPES_H
54 #include <sys/types.h>
55 #endif
56 #include <sys/stat.h>
57 #ifdef HAVE_SYS_IOCTL_H
58 #include <sys/ioctl.h>
59 #endif
60 #ifdef HAVE_FCNTL_H
61 #include <fcntl.h>
62 #endif
63 #ifdef HAVE_TERMIOS_H
64 # include <termios.h>
65 #else
66 # ifdef HAVE_TERMIO_H
67 # include <termio.h>
68 # endif
69 #endif
70 #include <errno.h>
71 #ifdef HAVE_UNISTD_H
72 # include <unistd.h>
73 #endif
74 #include <stdio.h>
75 # include <string.h>
76 #ifdef HAVE_GRP_H
77 #include <grp.h>
78 #endif
79 #ifdef HAVE_PTY_H
80 #include <pty.h>
81 #endif
82 #ifdef HAVE_UTMP_H
83 #include <utmp.h>
84 #endif
85
86 #ifdef HAVE_PTSNAME
87 # include <stdlib.h>
88 # ifdef HAVE_STROPTS_H
89 # include <stropts.h>
90 # endif
91 #endif
92
93 #ifdef HAVE_UTIL_H
94 #include <util.h>
95 #endif
96
97 #include "opal/util/opal_pty.h"
98
99 /* The only public interface is openpty - all others are to support
100 openpty() */
101
102 #if OPAL_ENABLE_PTY_SUPPORT == 0
103
104 int opal_openpty(int *amaster, int *aslave, char *name,
105 void *termp, void *winpp)
106 {
107 return -1;
108 }
109
110 #elif defined(HAVE_OPENPTY)
111
112 int opal_openpty(int *amaster, int *aslave, char *name,
113 struct termios *termp, struct winsize *winp)
114 {
115 return openpty(amaster, aslave, name, termp, winp);
116 }
117
118 #else
119
120 /* implement openpty in terms of ptym_open and ptys_open */
121
122 static int ptym_open(char *pts_name);
123 static int ptys_open(int fdm, char *pts_name);
124
125 int opal_openpty(int *amaster, int *aslave, char *name,
126 struct termios *termp, struct winsize *winp)
127 {
128 char line[20];
129 *amaster = ptym_open(line);
130 if (*amaster < 0) {
131 return -1;
132 }
133 *aslave = ptys_open(*amaster, line);
134 if (*aslave < 0) {
135 close(*amaster);
136 return -1;
137 }
138 if (name) {
139 // We don't know the max length of name, but we do know the
140 // max length of the source, so at least use that.
141 opal_string_copy(name, line, sizeof(line));
142 }
143 #ifndef TCSAFLUSH
144 #define TCSAFLUSH TCSETAF
145 #endif
146 if (termp) {
147 (void) tcsetattr(*aslave, TCSAFLUSH, termp);
148 }
149 #ifdef TIOCSWINSZ
150 if (winp) {
151 (void) ioctl(*aslave, TIOCSWINSZ, (char *) winp);
152 }
153 #endif
154 return 0;
155 }
156
157
158 static int ptym_open(char *pts_name)
159 {
160 int fdm;
161 #ifdef HAVE_PTSNAME
162 char *ptr;
163
164 #ifdef _AIX
165 strcpy(pts_name, "/dev/ptc");
166 #else
167 strcpy(pts_name, "/dev/ptmx");
168 #endif
169 fdm = open(pts_name, O_RDWR);
170 if (fdm < 0) {
171 return -1;
172 }
173 if (grantpt(fdm) < 0) { /* grant access to slave */
174 close(fdm);
175 return -2;
176 }
177 if (unlockpt(fdm) < 0) { /* clear slave's lock flag */
178 close(fdm);
179 return -3;
180 }
181 ptr = ptsname(fdm);
182 if (ptr == NULL) { /* get slave's name */
183 close(fdm);
184 return -4;
185 }
186 strcpy(pts_name, ptr); /* return name of slave */
187 return fdm; /* return fd of master */
188 #else
189 char *ptr1, *ptr2;
190
191 strcpy(pts_name, "/dev/ptyXY");
192 /* array index: 012345689 (for references in following code) */
193 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
194 pts_name[8] = *ptr1;
195 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
196 pts_name[9] = *ptr2;
197 /* try to open master */
198 fdm = open(pts_name, O_RDWR);
199 if (fdm < 0) {
200 if (errno == ENOENT) { /* different from EIO */
201 return -1; /* out of pty devices */
202 } else {
203 continue; /* try next pty device */
204 }
205 }
206 pts_name[5] = 't'; /* chage "pty" to "tty" */
207 return fdm; /* got it, return fd of master */
208 }
209 }
210 return -1; /* out of pty devices */
211 #endif
212 }
213
214
215 static int ptys_open(int fdm, char *pts_name)
216 {
217 int fds;
218 #ifdef HAVE_PTSNAME
219 /* following should allocate controlling terminal */
220 fds = open(pts_name, O_RDWR);
221 if (fds < 0) {
222 close(fdm);
223 return -5;
224 }
225 #if defined(__SVR4) && defined(__sun)
226 if (ioctl(fds, I_PUSH, "ptem") < 0) {
227 close(fdm);
228 close(fds);
229 return -6;
230 }
231 if (ioctl(fds, I_PUSH, "ldterm") < 0) {
232 close(fdm);
233 close(fds);
234 return -7;
235 }
236 #endif
237
238 return fds;
239 #else
240 int gid;
241 struct group *grptr;
242
243 grptr = getgrnam("tty");
244 if (grptr != NULL) {
245 gid = grptr->gr_gid;
246 } else {
247 gid = -1; /* group tty is not in the group file */
248 }
249 /* following two functions don't work unless we're root */
250 chown(pts_name, getuid(), gid);
251 chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
252 fds = open(pts_name, O_RDWR);
253 if (fds < 0) {
254 close(fdm);
255 return -1;
256 }
257 return fds;
258 #endif
259 }
260
261 #endif /* #ifdef HAVE_OPENPTY */