source: trunk/j/src/jpty/jpty.c @ 8163

Last change on this file since 8163 was 8163, checked in by piso, 17 years ago

Ignore SIGHUP to work around Linux kernel bug (2.6.9).

File size: 4.0 KB
Line 
1/*
2 * jpty.c
3 *
4 * Copyright (C) 2000-2004 Peter Graves
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 */
20
21#ifndef __CYGWIN__
22#include <fcntl.h>
23#include <grp.h>
24#include <sys/ioctl.h>
25#include <sys/stat.h>
26#include <termios.h>
27#define __USE_XOPEN
28#endif
29
30#include <signal.h>
31#include <stdlib.h>
32#include <unistd.h>
33#include <string.h>
34
35#ifndef __CYGWIN__
36static void set_noecho(int fd);
37static void loop(int fdm);
38static int  open_master_pty(char *name, size_t size);
39#endif
40
41int main(int argc, char *argv[]) 
42{
43#ifndef __CYGWIN__
44    char slave_name[256];
45    pid_t pid;
46    int fdm;
47#endif
48    int i = 1;
49
50    if (argc < 2)
51  exit(1);
52
53    /* Check for -cd option. */
54    if (!strcmp("-cd", argv[i])) {
55        /* Next arg is directory to change to. */
56        if (++i < argc) {
57            if (chdir(argv[i]) < 0)
58                exit(1);
59            ++i;
60        }
61    }
62
63    /* We should not be out of args here! */
64    if (i >= argc)
65  exit(1);
66
67#ifdef __CYGWIN__
68    setenv("TERM", "dumb", 1);
69    execvp(argv[i], &argv[i]);
70    exit(1); /* Not reached. */
71#else
72    fdm = open_master_pty(slave_name, sizeof(slave_name));
73
74    if (fdm < 0)
75  exit(1);
76
77    pid = fork();
78
79    if (pid < 0)
80  exit(1);
81
82    if (pid == 0) { 
83        /* Child process. */
84        int slave;
85
86        close(fdm);
87
88        if (setsid() < 0)
89      exit(1);
90
91        slave = open(slave_name, O_RDWR);
92
93        if (slave < 0)
94      exit(1);
95
96#ifdef __linux__
97        if (ioctl(slave, TIOCSCTTY, NULL) < 0)
98      exit(1);
99#endif
100        if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
101      exit(1);
102        if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
103      exit(1);
104        if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
105      exit(1);
106
107        if (slave > STDERR_FILENO)
108      close(slave);
109
110        set_noecho(STDIN_FILENO);
111
112        putenv("TERM=dumb");
113 
114  /* Ignore SIGHUP to work around Linux kernel bug (2.6.9).
115   * http://lkml.org/lkml/2004/10/21/119 */
116  signal(SIGHUP, SIG_IGN);
117
118        execvp(argv[i], &argv[i]);
119
120        /* Not reached. */
121        exit(1);
122    }
123
124    /* Parent process. */
125    loop(fdm);
126    exit(0);
127#endif
128}
129
130#ifndef __CYGWIN__
131static void set_noecho(int fd)
132{
133    struct termios t;
134    if (tcgetattr(fd, &t) < 0)
135  exit(1);
136    t.c_lflag &= ~(ECHO | ECHOCTL | ECHOE | ECHOK | ECHOKE | ECHONL | ECHOPRT);
137    t.c_oflag &= ~(ONLCR);
138    if (tcsetattr(fd, TCSANOW, &t) < 0)
139  exit(1);
140}
141
142/* Copy stdin to fdm, copy fdm to stdout. */
143static void loop(int fdm)
144{
145    char buf[1024];
146    fd_set fdset;
147    int done = 0;
148
149    while (!done) {
150        FD_ZERO(&fdset);
151        FD_SET(STDIN_FILENO, &fdset);
152        FD_SET(fdm, &fdset);
153
154        select(fdm + 1, &fdset, NULL, NULL, NULL);
155
156        if (FD_ISSET(fdm, &fdset)) {
157            int i = read(fdm, buf, sizeof(buf));
158
159            if (i > 0)
160                write(STDOUT_FILENO, buf, i);
161            else
162                done = 1;
163        }
164
165        if (FD_ISSET(STDIN_FILENO, &fdset)) {
166            int i = read(STDIN_FILENO, buf, sizeof(buf));
167
168            if (i > 0)
169                write(fdm, buf, i);
170            else
171                done = 1;
172        }
173    }
174}
175
176static int open_master_pty(char *namebuf, size_t bufsize)
177{ 
178    int fdm;
179    char *sname;
180
181    fdm = open("/dev/ptmx", O_RDWR);
182    if (fdm < 0)
183  return -1;
184
185    unlockpt(fdm);
186    grantpt(fdm);
187
188    sname = ptsname(fdm);
189    if (strlen(sname) >= bufsize)
190  return -1;
191    strcpy(namebuf, sname);
192
193    return fdm;
194}
195#endif
Note: See TracBrowser for help on using the repository browser.