root/lang/objective-cplusplus/i3/trunk/src/os-windows/fakecygpty.c @ 35148

Revision 35148, 5.0 kB (checked in by saturday06, 4 years ago)

uauaua

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/wait.h>
50#include <termios.h>
51#include <unistd.h>
52
53#define BUFSIZE 1024 /* size of communication buffer */
54
55/* global variables */
56int child_pid;          /* pid of child proces  */
57int master_fd;          /* fd of pty served to child process */
58
59void e(const char* message) {
60    char newline[] = "\r\n";
61    write(2, message, strlen(message));
62    write(2, newline, strlen(newline));
63}
64
65
66/* Create pty and fork/exec target process */
67/* This function sets child_pid and master_fd */
68void exec_target(char* argv[]) {
69    int fd;
70    int pid;
71
72    master_fd = open("/dev/ptmx", O_RDWR);
73    if (master_fd < 0) {
74        e("Cannot open pseudo tty");
75        exit(1);
76    }
77
78    pid = fork();
79    if (pid < 0) {
80        e("Failed to fork");
81        return;
82    }
83
84    if (pid == 0) {
85        int slave = 0;
86        setsid();
87       
88        slave = open(ptsname(master_fd), O_RDWR);
89        if (slave < 0) {
90            e("Failed to open slave fd");
91            exit(1);
92        }
93
94        for (fd = 0 ; fd < 3 ; fd++) {
95            if (slave != fd) {
96                if (dup2(slave, fd) < 0) {
97                    e("Failed to dup2");
98                    exit(1);
99                }
100            }
101            fcntl(fd, F_SETFD, 0);
102        }
103
104        if (slave > 2) {
105            close(slave);
106        }
107
108        execvp(argv[0], argv);
109
110        e("Failed to execute");
111        exit(1);
112    }
113       
114    child_pid = pid;
115
116    return;
117}
118
119struct termios oldtm;
120
121void setup_tty_attributes(void) {
122    struct termios tm;
123
124    if (tcgetattr(master_fd, &tm) == 0) {
125        /* Inhibit echo when executed under emacs/windows environment */
126        if (!isatty(0)) {
127            tm.c_iflag |= IGNCR;
128            tm.c_lflag &= ~ECHO;
129        }
130        tcsetattr(master_fd, TCSANOW, &tm);
131    }
132
133    if (tcgetattr(0, &oldtm) == 0) {
134        tm = oldtm;
135        tm.c_iflag &= ~(ICRNL | IXON | IXOFF);
136        tm.c_iflag |= IGNBRK;
137        tm.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE);
138        tcsetattr(0, TCSANOW, &tm);
139    }
140}
141
142void restore_tty_attributes(void) {
143    tcsetattr(0, TCSANOW, &oldtm);
144}
145
146#ifdef __CYGWIN__
147/* Signal handler for convert SIGINT into ^C on pty */
148/* This seems not able to be done within cygwin POSIX framework */
149#include <windows.h>
150BOOL WINAPI ctrl_handler(DWORD e) {
151    switch (e) {
152    case CTRL_C_EVENT:
153        write(master_fd, "\003", 1);
154        return TRUE;
155
156    case CTRL_CLOSE_EVENT:
157        kill(child_pid, SIGKILL);
158        return FALSE;
159    }
160    return FALSE;
161}
162#endif
163
164int main(int argc, char* argv[]) {
165    fd_set sel;
166    int status = 0;
167
168    if (argc < 2) {
169        e("Unable to get argv[1]");
170        return 1;
171    }
172
173#ifdef __CYGWIN__
174    /* SIGINT and SIGBREAK are indistinctive under cygwin environment. */
175    /* Using Win32API to handle SIGINT.                              */
176    SetConsoleCtrlHandler(ctrl_handler, TRUE);
177#endif
178    setup_tty_attributes();
179    exec_target(argv + 1);
180    FD_ZERO(&sel);
181    FD_SET(master_fd, &sel);
182    FD_SET(0, &sel);
183
184    while (1) {
185        if (select(master_fd + 1, &sel, NULL, NULL, NULL) < 0) {
186            break;
187        }
188        if (FD_ISSET(master_fd, &sel)) {
189            char buf[BUFSIZE];
190            int ret = read(master_fd, buf, sizeof(buf));
191            if (ret > 0) {
192                write(1, buf, ret);
193            } else if (ret == 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
194                break;
195            }
196        }
197        if (FD_ISSET(0, &sel)) {
198            char buf[BUFSIZE];
199            int ret = read(0, buf, sizeof(buf));
200            if (ret > 0) {
201                write(master_fd, buf, ret);
202            } else if (ret == 0 || (errno != EAGAIN && errno != EWOULDBLOCK)) {
203                break;
204            }
205        }
206    }
207
208    waitpid(child_pid, &status, 0);
209
210    FD_CLR(0, &sel);
211    restore_tty_attributes();
212    close(master_fd);
213    return status;
214}
215
Note: See TracBrowser for help on using the browser.