root/lang/objective-cplusplus/i3/trunk/tmp/pty2.c @ 36260

Revision 35247, 5.4 kB (checked in by saturday06, 4 years ago)

azaza

  • Property svn:executable set to *
Line 
1/*
2 * Fake cygwin pty   --  fakecygpty --
3 *
4 *        Copyright (C) 2005 Kyotaro Horiguchi <horiguti@meaodwy.org>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either versions 2, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with fiber, see the file COPYING.  If not, write to the Free
19 * Software Foundation Inc., 59 Temple Place - Suite 330, Boston,
20 * MA 02111-1307, USA.
21 */
22
23/*
24 * HISTORY
25 * -------
26 *
27 *    09 Jun, 2005 : Version 1.0.0 - first release.
28 *    15 Jun, 2005 : Version 1.0.1 - bug fix and change coding style.
29 */
30
31/*
32 * COMPILATION
33 * -------
34 * gcc -o fakecygpty.exe fakecygpty.c
35 *
36 */
37
38#if defined(__INTERIX) && !defined(_ALL_SOURCE)
39#define _ALL_SOURCE
40#endif
41
42#include <errno.h>
43#include <fcntl.h>
44#include <signal.h>
45//#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <sys/time.h>
49#include <sys/types.h>
50#include <sys/wait.h>
51#include <termios.h>
52#include <unistd.h>
53
54#define BUFSIZE 1024 /* size of communication buffer */
55
56/* global variables */
57int child_pid;          /* pid of child proces  */
58int master_fd;          /* fd of pty served to child process */
59
60void e(const char* message) {
61    char newline[] = "\r\n";
62    write(2, message, strlen(message));
63    write(2, newline, strlen(newline));
64}
65
66
67/* Create pty and fork/exec target process */
68/* This function sets child_pid and master_fd */
69void exec_target(char* argv[]) {
70    int fd;
71    int pid;
72
73    master_fd = open("/dev/ptmx", O_RDWR);
74    if (master_fd < 0) {
75        e("Cannot open pseudo tty");
76        exit(1);
77    }
78
79    pid = fork();
80    if (pid < 0) {
81        e("Failed to fork");
82        return;
83    }
84
85    if (pid == 0) {
86        int slave = 0;
87        setsid();
88       
89        slave = open(ptsname(master_fd), O_RDWR);
90        if (slave < 0) {
91            e("Failed to open slave fd");
92            exit(1);
93        }
94
95        for (fd = 0 ; fd < 3 ; fd++) {
96            if (slave != fd) {
97                if (dup2(slave, fd) < 0) {
98                    e("Failed to dup2");
99                    exit(1);
100                }
101            }
102            fcntl(fd, F_SETFD, 0);
103        }
104
105        if (slave > 2) {
106            close(slave);
107        }
108
109        execvp(argv[0], argv);
110
111        e("Failed to execute");
112        exit(1);
113    }
114       
115    child_pid = pid;
116
117    return;
118}
119
120struct termios oldtm;
121
122void setup_tty_attributes(void) {
123    struct termios tm;
124
125    if (tcgetattr(master_fd, &tm) == 0) {
126        /* Inhibit echo when executed under emacs/windows environment */
127        if (!isatty(0)) {
128            tm.c_iflag |= IGNCR;
129            tm.c_lflag &= ~ECHO;
130        }
131        tcsetattr(master_fd, TCSANOW, &tm);
132    }
133
134    if (tcgetattr(0, &oldtm) == 0) {
135        tm = oldtm;
136        tm.c_iflag &= ~(ICRNL | IXON | IXOFF);
137        tm.c_iflag |= IGNBRK;
138        tm.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE);
139        tcsetattr(0, TCSANOW, &tm);
140    }
141}
142
143void restore_tty_attributes(void) {
144    tcsetattr(0, TCSANOW, &oldtm);
145}
146
147#ifdef __CYGWIN__
148/* Signal handler for convert SIGINT into ^C on pty */
149/* This seems not able to be done within cygwin POSIX framework */
150#include <windows.h>
151BOOL WINAPI ctrl_handler(DWORD e) {
152    switch (e) {
153    case CTRL_C_EVENT:
154        write(master_fd, "\003", 1);
155        return TRUE;
156
157    case CTRL_CLOSE_EVENT:
158        kill(child_pid, SIGKILL);
159        return FALSE;
160    }
161    return FALSE;
162}
163#endif
164
165int main(int argc, char* argv[]) {
166    fd_set read_fd_set;
167    fd_set write_fd_set;
168    int status = 0;
169
170    if (argc < 2) {
171        e("Unable to get argv[1]");
172        return 1;
173    }
174
175#ifdef __CYGWIN__
176    /* SIGINT and SIGBREAK are indistinctive under cygwin environment. */
177    /* Using Win32API to handle SIGINT.                              */
178    SetConsoleCtrlHandler(ctrl_handler, TRUE);
179#endif
180    setup_tty_attributes();
181    exec_target(argv + 1);
182
183    FD_ZERO(&read_fd_set);
184    FD_SET(0, &read_fd_set);
185    FD_SET(master_fd, &read_fd_set);
186
187    FD_ZERO(&write_fd_set);
188    FD_SET(1, &write_fd_set);
189    FD_SET(master_fd, &write_fd_set);
190
191    while (1) {
192        if (select(master_fd + 1,
193                   &read_fd_set, &write_fd_set, NULL, NULL) < 0) {
194            break;
195        }
196
197        if (FD_ISSET(master_fd, &read_fd_set)) {
198            char buf[BUFSIZE];
199            int ret = read(master_fd, buf, sizeof(buf));
200            if (ret > 0) {
201                write(1, buf, ret);
202            } else if (ret == 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
203                break;
204            }
205        }
206
207        if (FD_ISSET(0, &sel)) {
208            char buf[BUFSIZE];
209            int ret = read(0, buf, sizeof(buf));
210            if (ret > 0) {
211                int ret2 = write(master_fd, buf, ret);
212                if (ret2 == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
213                    e("write(master_fd): noblocking !?");
214                }
215            } else if (ret == 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
216                break;
217            }
218        }
219    }
220
221    waitpid(child_pid, &status, 0);
222
223    FD_CLR(0, &sel);
224    restore_tty_attributes();
225    close(master_fd);
226    return status;
227}
228
Note: See TracBrowser for help on using the browser.