FreeBSD 10 clang port
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimGetPty-svr4.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$XConsortium: TermPrimGetPty-svr4.c /main/1 1996/04/21 19:17:39 drk $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
31  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
32  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
33  * (c) Copyright 1993, 1994 Novell, Inc.                                *
34  */
35
36 /**************************************************************************
37  *
38  *  Note: This code is based on the pty allocation code from xview.  It
39  *        was basically taken intact as were the comments...
40  */
41
42 #include "TermPrim.h"
43 #include "TermPrimOSDepI.h"
44 #include "TermPrimDebug.h"
45 #include "TermHeader.h"
46 #if !defined(linux)
47 #include <stropts.h>
48 #include <sys/conf.h>
49 #include <sys/stream.h>
50 #endif
51 #include <sys/termios.h>
52
53 #if defined(linux)
54 #undef USE_STREAMS_BUFMOD
55 #endif
56
57 #ifdef  USE_STREAMS_BUFMOD
58 #include <sys/bufmod.h>
59 #endif  /* USE_STREAMS_BUFMOD */
60
61 #include <errno.h>
62
63 /* last ditch fallback.  If the clone device is other than /dev/ptmx,
64  * it should have been set previously...
65  */
66 #ifndef PTY_CLONE_DEVICE
67 #define PTY_CLONE_DEVICE        "/dev/ptmx"
68 #endif  /* PTY_CLONE_DEVICE */
69
70
71 static int GetPty(char **ptySlave, char **ptyMaster)
72 {
73     char *c;
74     int ptyFd;
75     int ttyFd;
76     extern char *ptsname(int fd);
77
78     *ptyMaster = malloc(strlen(PTY_CLONE_DEVICE) + 1);
79     (void) strcpy(*ptyMaster, PTY_CLONE_DEVICE);
80
81     if (isDebugFSet('p', 10)) {
82 #ifdef  BBA
83 #pragma BBA_IGNORE
84 #endif  /*BBA*/
85         return(-1);
86     }
87
88     if ((ptyFd = open(*ptyMaster, O_RDWR, 0)) >= 0) {
89
90         /* use grantpt to prevent other processes from grabbing the tty that
91          * goes with the pty master we have opened.  It is a mandatory step
92          * in the SVR4 pty-tty initialization.  Note that /dev must be
93          * mounted read/write...
94          */
95         Debug('T', timeStamp("_DtTermPrimGetPty() calling grantpt()"));
96         if (grantpt(ptyFd) == -1) {
97             (void) perror("grantpt");
98             (void) close(ptyFd);
99             return(-1);
100         }
101
102         /* Unlock the pty master/slave pair so the slave can be opened later */
103         Debug('T', timeStamp("_DtTermPrimGetPty() calling unlockpt()"));
104         if (unlockpt(ptyFd) == -1) {
105             (void) perror("unlockpt");
106             (void) close(ptyFd);
107             return(-1);
108         }
109         Debug('T', timeStamp("_DtTermPrimGetPty() unlockpt() finished"));
110
111 #ifdef  USE_STREAMS_BUFMOD
112         if (ioctl(ptyFd, I_PUSH, "bufmod") == -1) {
113             (void) perror("I_PUSH bufmod");
114
115             /* We can't push bufmod.  This means that we're probably running
116              * on a generic SVR4 system.  We can ignore this error since
117              * bufmod is used for performance reasons only...
118              */
119         } else {
120             struct timeval timeval;
121             struct strioctl cmd;
122             unsigned int chunk;
123
124             /* Note that we're not using SB_SEND_ON_WRITE | SB_DEFER_CHUNK.
125              * Turns out the shell (or someone down the pty) does an ioctl
126              * when sending out each prompt.  Since this flushes any
127              * partially filled chunk automatically, we really don't need
128              * to do this...
129              */
130
131             chunk = SB_NO_DROPS | SB_NO_PROTO_CVT | SB_NO_HEADER;
132             cmd.ic_timout = 0;
133             cmd.ic_cmd = SBIOCSFLAGS;
134             cmd.ic_len = sizeof(u_long);
135             cmd.ic_dp = (char *) &chunk;
136             if (ioctl(ptyFd, I_STR, &cmd) < 0) {
137                 (void) perror("SBIOCSFLAGS");
138                 /* If we pushed bufmod, but this ioctl fails, it means we're
139                  * most likely running on a system with old bufmod (i.e., for
140                  * released OSs this must be Jupiter).  We treat this error
141                  * silently so developers and users of the Mars trees don't
142                  * get confused.  Treat it like bufmod wasn't there at all...
143                  */
144                 goto backoff;
145             }
146
147             timeval.tv_usec = 50000;
148             timeval.tv_sec = 0;
149             cmd.ic_cmd = SBIOCSTIME;
150             cmd.ic_timout = 0;
151             cmd.ic_len = sizeof(timeval);
152             cmd.ic_dp = (char *) &timeval;
153             if (ioctl(ptyFd, I_STR, &cmd) < 0) {
154                 /* These are legit errors.  If we have new bufmod, this
155                  * should have worked...
156                  */
157                 (void) perror("BSIOCSTIME");
158                 goto backoff;
159             }
160
161             /* I have made the chunk size the same as the buffer used in the
162              * ttysw.  One could experiment here, but this works...
163              */
164             {
165                 /* struct cbuf *sizeit; */
166                 /* chunk = sizeof(sizeit->cb_buf); */
167                 chunk = 2048; /* taken from xview source def of cbuf... */
168             }
169
170             cmd.ic_cmd = SBIOCSCHUNK;
171             cmd.ic_len = sizeof(int);
172             cmd.ic_dp = (char *) &chunk;
173
174             if (ioctl(ptyFd, I_STR, &cmd) < 0) {
175                 (void) perror("SBIOCSCHUNK");
176                 goto backoff;
177             }
178
179             /* We certainly don't want to truncate any packets, so set the
180              * snap length to zero...
181              */
182             chunk = 0;
183             cmd.ic_cmd = SBIOCSSNAP;
184             cmd.ic_len = sizeof(int);
185             cmd.ic_dp = (char *) &chunk;
186             if (ioctl(ptyFd, I_STR, &cmd) < 0) {
187                 (void) perror("SBIOCSSNAP");
188                 goto backoff;
189             }
190
191             goto ok;
192         }
193
194 backoff:
195         /* Something didn't work out, so pull bofmod off the stream and
196          * continue as if it weren't there...
197          */
198         if (ioctl(ptyFd, I_POP, 0) == -1) {
199             /* bufmod not working or wrong version... */
200             (void) perror("I_POP bufmod");
201         }
202
203 ok:
204 #endif  /* USE_STREAMS_BUFMOD */
205
206         /* get the pty slave name... */
207         if (c = ptsname(ptyFd)) {
208             *ptySlave = malloc(strlen(c) + 1);
209             (void) strcpy(*ptySlave, c);
210 #ifdef  NOTDEF
211             {
212                 int slaveFd;
213                 char buffer[BUFSIZ];
214
215                 if ((slaveFd = open(*ptySlave, O_RDWR, 0)) < 0) {
216                     (void) perror(*ptySlave);
217                     (void) fprintf(stderr, "it failed!\n");
218                     (void) sprintf(buffer, "ls -l %s", *ptySlave);
219                     (void) system(buffer);
220                 } else {
221                     (void) close(slaveFd);
222                 }
223             }
224 #endif  /* NOTDEF */
225             return(ptyFd);
226         } else {
227             /* ptsname on the pty master failed.  This should not happen!... */
228             (void) perror("ptsname");
229             (void) close(ptyFd);
230         }
231     } else {
232         (void) perror(*ptyMaster);
233     }
234     return(-1);
235 }
236
237 /* this is a public wrapper around the previous function that runs the          
238  * previous function setuid root...                                             
239  */
240 int
241 _DtTermPrimGetPty(char **ptySlave, char **ptyMaster)
242 {
243   int retValue;
244
245   /* this function needs to be suid root... */
246   (void) _DtTermPrimToggleSuidRoot(True);
247   retValue = GetPty(ptySlave, ptyMaster);
248   /* we now need to turn off setuid root... */
249   (void) _DtTermPrimToggleSuidRoot(False);
250
251   return(retValue);
252 }
253
254
255 static int
256 SetupPty(char *ptySlave, int ptyFd)
257 {
258     /*
259      * The following "pushes" were done at GetPty time, but
260      * they don't seem to stick after the file is closed on
261      * SVR4.2.  Not sure where else this applies.
262      */
263 #if !defined(linux)
264     if (ioctl(ptyFd, I_PUSH, "ptem") == -1) {
265             (void) perror("Error pushing ptem");
266             /* exit the subprocess */
267             return(1);
268     }
269
270     if (ioctl(ptyFd, I_PUSH, "ldterm") == -1) {
271             (void) perror("Error pushing ldterm");
272             /* exit the subprocess */
273             return(1);
274     }
275
276 #ifdef  USE_STREAMS_TTCOMPAT
277     if (ioctl(ptyFd, I_PUSH, "ttcompat") == -1) {
278             (void) perror("Error pushing ttcompat");
279             /* exit the subprocess */
280             return(1);
281     }
282 #endif  /* USE_STREAMS_TTCOMPAT */
283
284 #else /* linux */
285
286     chown(ptySlave, getuid(), getgid());
287     chmod(ptySlave, 0622);
288 #endif /* linux */
289
290     /* success... */
291     return(0);
292 }
293
294 int
295 _DtTermPrimSetupPty(char *ptySlave, int ptyFd)
296 {
297   int retValue;
298
299   /* this function needs to be suid root... */
300   (void) _DtTermPrimToggleSuidRoot(True);
301   retValue = SetupPty(ptySlave, ptyFd);
302   /* we now need to turn off setuid root... */
303   (void) _DtTermPrimToggleSuidRoot(False);
304
305   return(retValue);
306 }
307
308 void
309 _DtTermPrimReleasePty(char *ptySlave)
310 {
311     /* dummy function for STREAMS... */
312 }
313
314 void
315 _DtTermPrimPtyCleanup()
316 {
317     /* dummy function for STREAMS... */
318     return;
319 }