root/trunk/nt/fakecygpty.c

Revision 4124, 5.2 kB (checked in by gotoh, 2 years ago)

Correct snv:eol-style and svn:executable for some files like others.

  • Property svn:eol-style set to native
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 #include <windows.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <fcntl.h>
42 #include <errno.h>
43 #include <termios.h>
44
45 #define BUFSIZE          1024   /* size of communication buffer */
46 #define COMMAND_PREFIX   "f_"
47 #define MY_NAME "fakecygpty"
48
49 /* global variables */
50 int child_pid;          /* pid of child proces  */
51 int masterfd;           /* fd of pty served to child process */
52
53 /* Create pty and fork/exec target process */
54 /* This function sets child_pid and masterfd */
55 void
56 exec_target(char* argv[])
57 {
58   int fd;
59   int pid;
60
61   masterfd = open ("/dev/ptmx", O_RDWR);
62   if (masterfd < 0)
63     {
64       perror("Cannot open pseudo tty");
65       exit (1);
66     }
67
68   pid = fork ();
69   if (pid < 0)
70     {
71       perror ("Failed to fork");
72       return;
73     }
74
75   if (pid == 0)
76     {
77       int slave;
78
79       setsid();
80
81       slave = open (ptsname (masterfd), O_RDWR);
82       if (slave < 0)
83         {
84           perror ("Failed to open slave fd");
85           exit (1);
86         }
87
88     for (fd = 0 ; fd < 3 ; fd++)
89       {
90         if (slave != fd)
91           {
92             if (dup2 (slave, fd) < 0)
93               {
94                 perror ("Failed to dup2");
95                 exit (1);
96               }
97           }
98         fcntl (fd, F_SETFD, 0);
99       }
100
101     if (slave > 2) close (slave);
102
103     execvp (argv[0], argv);
104
105     fprintf (stderr, "Failed to execute \"%s\".", argv[0]);
106     perror ("execvp");
107     exit (1);
108   }
109
110   child_pid = pid;
111
112   return;
113 }
114
115
116 struct termios oldtm;
117
118 void
119 setup_tty_attributes (void)
120 {
121   struct termios tm;
122
123   if (tcgetattr (masterfd, &tm) == 0)
124     {
125       /* Inhibit echo when executed under emacs/windows environment */
126       if (! isatty (0))
127         {
128           tm.c_iflag |= IGNCR;
129           tm.c_lflag &= ~ECHO;
130         }
131       tcsetattr (masterfd, TCSANOW, &tm);
132     }
133
134   if (tcgetattr (0, &oldtm) == 0)
135     {
136       tm = oldtm;
137       tm.c_iflag &= ~(ICRNL | IXON | IXOFF);
138       tm.c_iflag |= IGNBRK;
139       tm.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE);
140       tcsetattr (0, TCSANOW, &tm);
141     }
142 }
143
144 void
145 restore_tty_attributes (void)
146 {
147   tcsetattr (0, TCSANOW, &oldtm);
148 }
149
150 char *
151 real_command_name (char* my_name)
152 {
153   char *p;
154
155   /* Assume mutlbyte characters do not occur here */
156   p = strrchr (my_name, '/');
157   if (p == NULL)
158     {
159       p = strrchr (my_name, '\\');
160
161       if (p == NULL)
162         p = my_name;
163       else
164         p++;
165     }
166   else
167     p++;
168
169   if (strcmp (p, MY_NAME) == 0)
170     {
171       return NULL;    /* I am invoked as explicit wrapper program */
172     }
173
174   if (strncmp (p, COMMAND_PREFIX, strlen (COMMAND_PREFIX)) != 0)
175     {
176       fprintf (stderr, "Illegal program name format. \'%s\'\n", my_name);
177       exit (1);
178     }
179
180   return p + strlen (COMMAND_PREFIX);
181 }
182
183 /* Signal handler for convert SIGINT into ^C on pty */
184 /* This seems not able to be done within cygwin POSIX framework */
185 BOOL WINAPI
186 ctrl_handler(DWORD e)
187 {
188   switch (e)
189     {
190     case CTRL_C_EVENT:
191       write (masterfd, "\003", 1);
192       return TRUE;
193
194     case CTRL_CLOSE_EVENT:
195       kill (child_pid, SIGKILL);
196       return FALSE;
197     }
198   return FALSE;
199 }
200
201 int
202 main (int argc, char* argv[])
203 {
204   struct termios oldtm;
205   fd_set sel, sel0;
206   int status;
207   char* newarg0;
208
209   /* SIGINT and SIGBREAK are indistinctive under cygwin environment. */
210   /* Using Win32API to handle SIGINT.                              */
211   SetConsoleCtrlHandler (ctrl_handler, TRUE);
212
213   if (argc < 1)
214     {
215       fprintf (stderr, "Unable to get arg[0].");
216       exit (1);
217     }
218
219   newarg0 = real_command_name (argv[0]);
220   if (newarg0)
221     {
222       argv[0] = newarg0;
223       exec_target (argv);     /* This sets globals masterfd, child_pid */
224     }
225   else
226     exec_target (argv + 1); /* This sets globals masterfd, child_pid */
227
228   setup_tty_attributes ();
229
230   FD_ZERO (&sel0);
231   FD_SET (masterfd, &sel0);
232   FD_SET (0, &sel0);
233
234   /* communication loop */
235   while (1)
236     {
237       char buf[BUFSIZE];
238       int ret;
239
240       sel = sel0;
241       if (select (FD_SETSIZE, &sel, NULL, NULL, NULL) <= 0)
242         break;
243
244       if (FD_ISSET (masterfd, &sel))
245         {
246           ret = read (masterfd, buf, BUFSIZE);
247           if (ret > 0)
248               write (1, buf, ret);
249           else
250             break;
251         }
252       else if (FD_ISSET (0, &sel))
253         {
254           ret = read (0, buf, BUFSIZE);
255           if (ret > 0)
256               write (masterfd, buf, ret);
257           else
258             {
259               FD_CLR (0, &sel0);
260               close (masterfd);
261             }
262         }
263     }
264
265   restore_tty_attributes ();
266
267   kill (child_pid, SIGKILL);
268   waitpid (child_pid, &status, 0);
269   return status;
270 }
271
Note: See TracBrowser for help on using the browser.