source: trunk/third/vte/gnome-pty-helper/gnome-login-support.c @ 20883

Revision 20883, 6.9 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20882, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * gnome-login-support.c:
3 *    Replacement for systems that lack login_tty, open_pty and forkpty
4 *
5 * Author:
6 *    Miguel de Icaza (miguel@gnu.org)
7 *
8 *
9 */
10#include <config.h>
11#include <termios.h>
12#include <unistd.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <fcntl.h>
16#include <string.h>
17#include <sys/ioctl.h>
18#include <termios.h>
19#include <stdlib.h>
20#include <sys/stat.h>
21#include <errno.h>
22#include <grp.h>
23#include <sys/types.h>
24#include "gnome-login-support.h"
25
26/*
27 * HAVE_OPENPTY => HAVE_FORKPTY
28 */
29
30#ifndef HAVE_LOGIN_TTY
31int
32login_tty (int fd)
33{
34        pid_t pid = getpid ();
35
36        /* Create the session */
37        setsid ();
38
39#ifdef TIOCSCTTY
40        if (ioctl (fd, TIOCSCTTY, 0) == -1)
41                return -1;
42#else /* !TIOCSTTY */
43        /* Hackery to set controlling tty on SVR4 -
44           on SVR4 the first terminal we open after sesid()
45           becomes our controlling terminal, thus we must
46           find the name of, open, and re-close the tty
47           since we already have it open at this point. */
48        {
49                char *ctty;
50                int ct_fdes;
51
52                ctty = ttyname(fd);
53                ct_fdes = open(ctty, O_RDWR);
54                close(ct_fdes);
55        }
56#endif /* !TIOCSTTY */
57
58#if defined (_POSIX_VERSION) || defined (__svr4__)
59        tcsetpgrp (0, pid);
60#elif defined (TIOCSPGRP)
61        ioctl (0, TIOCSPGRP, &pid);
62#endif
63
64        dup2 (fd, 0);
65        dup2 (fd, 1);
66        dup2 (fd, 2);
67        if (fd > 2)
68                close (fd);
69
70        return 0;
71}
72#endif
73
74#ifndef HAVE_OPENPTY
75static int
76pty_open_master_bsd (char *pty_name, int *used_bsd)
77{
78        int pty_master;
79        char *ptr1, *ptr2;
80
81        *used_bsd = 1;
82
83        strcpy (pty_name, "/dev/ptyXX");
84        for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
85        {
86                pty_name [8] = *ptr1;
87                for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
88                {
89                        pty_name [9] = *ptr2;
90
91                        /* Try to open master */
92                        if ((pty_master = open (pty_name, O_RDWR)) == -1) {
93                                if (errno == ENOENT)  /* Different from EIO */
94                                        return -1;    /* Out of pty devices */
95                                else
96                                        continue;      /* Try next pty device */
97                        }
98                        pty_name [5] = 't';            /* Change "pty" to "tty" */
99                        if (access (pty_name, (R_OK | W_OK))){
100                                close (pty_master);
101                                pty_name [5] = 'p';
102                                continue;
103                        }
104                        return pty_master;
105                }
106        }
107        return -1;  /* Ran out of pty devices */
108}
109
110static int
111pty_open_slave_bsd (const char *pty_name)
112{
113        int pty_slave;
114        struct group *group_info = getgrnam ("tty");
115
116        if (group_info != NULL)
117        {
118                /* The following two calls will only succeed if we are root */
119
120                chown (pty_name, getuid (), group_info->gr_gid);
121                chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP);
122        }
123        else
124        {
125                chown (pty_name, getuid (), -1);
126                chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP);
127        }
128
129#ifdef HAVE_REVOKE
130        revoke (pty_name);
131#endif
132
133        if ((pty_slave = open (pty_name, O_RDWR)) == -1){
134                return -1;
135        }
136
137        return pty_slave;
138}
139
140/* SystemVish pty opening */
141#if defined (HAVE_GRANTPT)
142
143#ifdef HAVE_STROPTS_H
144#    include <stropts.h>
145#endif
146
147static int
148pty_open_slave (const char *pty_name)
149{
150        int pty_slave = open (pty_name, O_RDWR);
151
152        if (pty_slave == -1)
153                return -1;
154
155#ifdef HAVE_STROPTS_H
156#if !defined(__osf__)
157        if (!ioctl (pty_slave, I_FIND, "ptem"))
158                if (ioctl (pty_slave, I_PUSH, "ptem") == -1){
159                        close (pty_slave);
160                        return -1;
161                }
162
163    if (!ioctl (pty_slave, I_FIND, "ldterm"))
164            if (ioctl (pty_slave, I_PUSH, "ldterm") == -1){
165                    close (pty_slave);
166                    return -1;
167            }
168
169#if !defined(sgi) && !defined(__sgi)
170    if (!ioctl (pty_slave, I_FIND, "ttcompat"))
171            if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
172            {
173                    perror ("ioctl (pty_slave, I_PUSH, \"ttcompat\")");
174                    close (pty_slave);
175                    return -1;
176            }
177#endif /* sgi || __sgi */
178#endif /* __osf__ */
179#endif /* HAVE_STROPTS_H */
180
181    return pty_slave;
182}
183
184static int
185pty_open_master (char *pty_name, int *used_bsd)
186{
187        int pty_master;
188        char *slave_name;
189
190        strcpy (pty_name, "/dev/ptmx");
191
192        pty_master = open (pty_name, O_RDWR);
193
194        if ((pty_master == -1) && (errno == ENOENT)) {
195                strcpy (pty_name, "/dev/ptc"); /* AIX */
196                pty_master = open (pty_name, O_RDWR);
197        }
198
199        /*
200         * Try BSD open, this is needed for Linux which
201         * might have Unix98 devices but no kernel support
202         * for those.
203         */
204        if (pty_master == -1) {
205                *used_bsd = 1;
206                return pty_open_master_bsd (pty_name, used_bsd);
207        }
208        *used_bsd = 0;
209
210        if (grantpt (pty_master) == -1 || unlockpt (pty_master) == -1) {
211                close (pty_master);
212                return -1;
213        }
214        if ((slave_name = ptsname (pty_master)) == NULL){
215                close (pty_master);
216                return -1;
217        }
218        strcpy (pty_name, slave_name);
219        return pty_master;
220}
221#else
222#    define pty_open_master pty_open_master_bsd
223#    define pty_open_slave  pty_open_slave_bsd
224#endif
225
226int
227openpty (int *master_fd, int *slave_fd, char *name,
228         struct termios *termp, struct winsize *winp)
229{
230        int pty_master, pty_slave, used_bsd = 0;
231        struct group *group_info;
232        char line [256];
233
234        pty_master = pty_open_master (line, &used_bsd);
235        fcntl (pty_master, F_SETFD, FD_CLOEXEC);
236
237        if (pty_master == -1)
238                return -1;
239
240        group_info = getgrnam ("tty");
241
242        if (group_info != NULL){
243                chown (line, getuid (), group_info->gr_gid);
244                chmod (line, S_IRUSR | S_IWUSR | S_IWGRP);
245        } else {
246                chown (line, getuid (), -1);
247                chmod (line, S_IRUSR | S_IWUSR | S_IWGRP);
248        }
249
250#ifdef HAVE_REVOKE
251        revoke (line);
252#endif
253
254        /* Open slave side */
255        if (used_bsd)
256                pty_slave = pty_open_slave_bsd (line);
257        else
258                pty_slave = pty_open_slave (line);
259
260        if (pty_slave == -1){
261                close (pty_master);
262
263                errno = ENOENT;
264                return -1;
265        }
266        fcntl (pty_slave, F_SETFD, FD_CLOEXEC);
267
268        *master_fd = pty_master;
269        *slave_fd  = pty_slave;
270
271        if (termp)
272                tcsetattr (pty_slave, TCSAFLUSH, termp);
273
274        if (winp)
275                ioctl (pty_slave, TIOCSWINSZ, winp);
276
277        if (name)
278                strcpy (name, line);
279
280        return 0;
281}
282
283pid_t
284forkpty (int *master_fd, char *name, struct termios *termp, struct winsize *winp)
285{
286        int master, slave;
287        pid_t pid;
288
289        if (openpty (&master, &slave, name, termp, winp) == -1)
290                return -1;
291
292        pid = fork ();
293
294        if (pid == -1)
295                return -1;
296
297        /* Child */
298        if (pid == 0){
299                close (master);
300                login_tty (slave);
301        } else {
302                *master_fd = master;
303                close (slave);
304        }
305
306        return pid;
307}
308#endif /* HAVE_OPENPTY */
309
310int
311n_read (int fd, void *buf, int count)
312{
313        int n = 0, i;
314        char *buffer;
315
316        buffer = (char*) buf;
317        while (n < count) {
318                i = read (fd, buffer + n, count - n);
319                switch (i) {
320                case -1:
321                        switch (errno) {
322                        case EINTR:
323                        case EAGAIN:
324#ifdef ERESTART
325                        case ERESTART:
326#endif
327                                /* suppress these errors */
328                                break;
329                        default:
330                                return -1;
331                                break;
332                        }
333                        break;
334                case 0:
335                        return n;
336                        break;
337                default:
338                        n += i;
339                        break;
340                }
341        }
342
343        return n;
344}
345
346int
347n_write (int fd, const void *buf, int count)
348{
349        int n = 0, i;
350        const char *buffer;
351
352        buffer = (char*) buf;
353        while (n < count) {
354                i = write (fd, buffer + n, count - n);
355                switch (i) {
356                case -1:
357                        switch (errno) {
358                        case EINTR:
359                        case EAGAIN:
360#ifdef ERESTART
361                        case ERESTART:
362#endif
363                                /* suppress these errors */
364                                break;
365                        default:
366                                return -1;
367                                break;
368                        }
369                        break;
370                case 0:
371                        return n;
372                        break;
373                default:
374                        n += i;
375                        break;
376                }
377        }
378
379        return n;
380}
Note: See TracBrowser for help on using the repository browser.