1.0.31.27: RUN-PROGRAM process group change
[sbcl.git] / src / runtime / run-program.c
1 /*
2  * support for the Lisp function RUN-PROGRAM and friends
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
9  * This software is derived from the CMU CL system, which was
10  * written at Carnegie Mellon University and released into the
11  * public domain. The software is in the public domain and is
12  * provided with absolutely no warranty. See the COPYING and CREDITS
13  * files for more information.
14  */
15
16 #include "sbcl.h"
17
18 #ifndef LISP_FEATURE_WIN32
19
20 #include <stdlib.h>
21 #include <sys/file.h>
22 #include <sys/types.h>
23 #include <signal.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <sys/ioctl.h>
27 #include <unistd.h>
28
29 #include <sys/ioctl.h>
30 #include <termios.h>
31
32
33 /* borrowed from detachtty's detachtty.c, in turn borrowed from APUE
34  * example code found at
35  * http://www.yendor.com/programming/unix/apue/pty/main.c
36
37 -brkint
38
39  */
40
41 int set_noecho(int fd)
42 {
43     struct termios  stermios;
44
45     if (tcgetattr(fd, &stermios) < 0) return 0;
46
47     stermios.c_lflag &= ~(  ECHO | /* ECHOE |  ECHOK | */  ECHONL);
48     stermios.c_oflag |= (ONLCR);
49     stermios.c_iflag &= ~(BRKINT);
50     stermios.c_iflag |= (ICANON|ICRNL);
51
52     stermios.c_cc[VERASE]=0177;
53     if (tcsetattr(fd, TCSANOW, &stermios) < 0) return 0;
54     return 1;
55 }
56
57 extern char **environ;
58 int spawn(char *program, char *argv[], int sin, int sout, int serr,
59           int search, char *envp[], char *pty_name, int wait)
60 {
61     int pid = fork();
62     int fd;
63     sigset_t sset;
64
65     if (pid != 0)
66         return pid;
67
68     /* Put us in our own process group, but only if we need not
69      * share stdin with our parent. In the latter case we claim
70      * control of the terminal. */
71     if (sin >= 0) {
72 #if defined(LISP_FEATURE_HPUX)
73       setsid();
74 #elif defined(LISP_FEATURE_DARWIN)
75       setpgid(0, getpid());
76 #elif defined(SVR4) || defined(__linux__) || defined(__osf__)
77       setpgrp();
78 #else
79       setpgrp(0, getpid());
80 #endif
81     } else {
82       tcsetpgrp(0, getpgrp());
83     }
84
85     /* unblock signals */
86     sigemptyset(&sset);
87     sigprocmask(SIG_SETMASK, &sset, NULL);
88
89     /* If we are supposed to be part of some other pty, go for it. */
90     if (pty_name) {
91 #if !defined(LISP_FEATURE_HPUX) && !defined(SVR4)
92         fd = open("/dev/tty", O_RDWR, 0);
93         if (fd >= 0) {
94             ioctl(fd, TIOCNOTTY, 0);
95             close(fd);
96         }
97 #endif
98         fd = open(pty_name, O_RDWR, 0);
99         dup2(fd, 0);
100         set_noecho(0);
101         dup2(fd, 1);
102         dup2(fd, 2);
103         close(fd);
104     } else{
105     /* Set up stdin, stdout, and stderr */
106     if (sin >= 0)
107         dup2(sin, 0);
108     if (sout >= 0)
109         dup2(sout, 1);
110     if (serr >= 0)
111         dup2(serr, 2);
112     }
113     /* Close all other fds. */
114 #ifdef SVR4
115     for (fd = sysconf(_SC_OPEN_MAX)-1; fd >= 3; fd--)
116         close(fd);
117 #else
118     for (fd = getdtablesize()-1; fd >= 3; fd--)
119         close(fd);
120 #endif
121
122     environ = envp;
123     /* Exec the program. */
124     if (search)
125       execvp(program, argv);
126     else
127       execv(program, argv);
128
129     exit (1);
130 }
131 #else  /* !LISP_FEATURE_WIN32 */
132
133 #  include <windows.h>
134 #  include <process.h>
135 #  include <stdio.h>
136 #  include <stdlib.h>
137 #  include <fcntl.h>
138 #  include <io.h>
139
140 #define   READ_HANDLE  0
141 #define   WRITE_HANDLE 1
142
143 /* These functions do not attempt to deal with wchar_t variations. */
144
145 /* Get the value of _environ maintained by MSVCRT */
146 char **msvcrt_environ ( void ) {
147     return ( _environ );
148 }
149
150 /* Set up in, out, err pipes and spawn a program, waiting or otherwise. */
151 HANDLE spawn (
152     const char *program,
153     const char *const *argv,
154     int in,
155     int out,
156     int err,
157     int search,
158     char *envp,
159     char *ptyname,
160     int wait
161     )
162 {
163     int stdout_backup, stdin_backup, stderr_backup, wait_mode;
164     HANDLE hProcess;
165     HANDLE hReturn;
166
167     /* Duplicate and save the original stdin/out/err handles. */
168     stdout_backup = _dup (  _fileno ( stdout ) );
169     stdin_backup  = _dup (  _fileno ( stdin  ) );
170     stderr_backup = _dup (  _fileno ( stderr ) );
171
172     /* If we are not using stdin/out/err
173      * then duplicate the new pipes to current stdin/out/err handles.
174      *
175      * Default std fds are used if in, out or err parameters
176      * are -1. */
177
178     hReturn = (HANDLE)-1;
179     hProcess = (HANDLE)-1;
180     if ( ( out >= 0 ) && ( out != _fileno ( stdout ) ) ) {
181         if ( _dup2 ( out, _fileno ( stdout ) ) != 0 ) goto error_exit;
182     }
183     if ( ( in >= 0 ) && ( in != _fileno ( stdin ) ) ) {
184         if ( _dup2 ( in,  _fileno ( stdin )  ) != 0 ) goto error_exit_out;
185     }
186     if ( ( err >= 0 ) && ( err != _fileno ( stderr ) ) ) {
187         if ( _dup2 ( err, _fileno ( stderr ) ) != 0 ) goto error_exit_in;
188     }
189
190     /* Set the wait mode. */
191     if ( 0 == wait ) {
192         wait_mode = P_NOWAIT;
193     } else {
194         wait_mode = P_WAIT;
195     }
196
197     /* Spawn process given on the command line*/
198     if (search)
199         hProcess = (HANDLE) spawnvp ( wait_mode, program, argv );
200     else
201         hProcess = (HANDLE) spawnv ( wait_mode, program, argv );
202
203     /* Now that the process is launched, replace the original
204      * in/out/err handles and close the backups. */
205
206     if ( _dup2 ( stderr_backup, _fileno ( stderr ) ) != 0 ) goto error_exit;
207  error_exit_in:
208     if ( _dup2 ( stdin_backup,  _fileno ( stdin )  ) != 0 ) goto error_exit;
209  error_exit_out:
210     if ( _dup2 ( stdout_backup, _fileno ( stdout ) ) != 0 ) goto error_exit;
211
212     hReturn = hProcess;
213
214  error_exit:
215     close ( stdout_backup );
216     close ( stdin_backup  );
217     close ( stderr_backup );
218
219     return hReturn;
220
221 }
222
223
224 #endif /* !LISP_FEATURE_WIN32 */