Draft NEWS for sbcl-2.4.7
[sbcl.git] / src / runtime / run-program.c
blob65ca971443c8c4435ae290c8911bd6a53bd0b62a
1 /*
2 * Unix support for the Lisp function RUN-PROGRAM and friends
3 */
5 /*
6 * This software is part of the SBCL system. See the README file for
7 * more information.
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.
16 #ifdef __linux__
17 /* glibc won't give us close_range without this */
18 #define _GNU_SOURCE
19 #endif
21 #include "genesis/sbcl.h"
22 #include <stdlib.h>
23 #include <sys/file.h>
24 #include <sys/types.h>
25 #include <signal.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include <unistd.h>
30 #include <sys/wait.h>
31 #include <sys/ioctl.h>
32 #include <termios.h>
33 #include <errno.h>
34 #include <dirent.h>
35 #include <sys/syscall.h>
36 #include "interr.h" // for lose()
38 #ifdef LISP_FEATURE_OPENBSD
39 #include <util.h>
40 #endif
42 /* borrowed from detachtty's detachtty.c, in turn borrowed from APUE
43 * example code found at
44 * http://www.yendor.com/programming/unix/apue/pty/main.c
46 -brkint
50 int set_noecho(int fd)
52 struct termios stermios;
54 if (tcgetattr(fd, &stermios) < 0) return 0;
56 stermios.c_lflag &= ~( ECHO | /* ECHOE | ECHOK | */ ECHONL);
57 stermios.c_oflag |= (ONLCR);
58 stermios.c_iflag &= ~(BRKINT);
59 stermios.c_iflag |= (ICANON|ICRNL);
61 stermios.c_cc[VERASE]=0177;
62 if (tcsetattr(fd, TCSANOW, &stermios) < 0) return 0;
63 return 1;
66 #if defined(LISP_FEATURE_OPENBSD)
68 int
69 set_pty(char *pty_name)
71 int fd;
73 if ((fd = open(pty_name, O_RDWR, 0)) == -1 ||
74 login_tty(fd) == -1)
75 return (0);
76 return (set_noecho(STDIN_FILENO));
79 #else /* !LISP_FEATURE_OPENBSD */
81 int
82 set_pty(char *pty_name)
84 int fd;
86 #if !defined(SVR4) && !defined(__HAIKU__)
87 fd = open("/dev/tty", O_RDWR, 0);
88 if (fd >= 0) {
89 ioctl(fd, TIOCNOTTY, 0);
90 close(fd);
92 #endif
93 if ((fd = open(pty_name, O_RDWR, 0)) == -1)
94 return (-1);
95 dup2(fd, 0);
96 set_noecho(0);
97 dup2(fd, 1);
98 dup2(fd, 2);
99 close(fd);
100 return (0);
103 #endif /* !LISP_FEATURE_OPENBSD */
105 int closefrom_fddir(char *dir, int lowfd)
107 DIR *d;
108 struct dirent *ent;
109 int fd;
111 /* This may fail if e.g. the program is running in
112 * a chroot that does not include /proc, or potentially
113 * on old kernel versions. */
114 d = opendir(dir);
115 if (!d) return -1;
117 for (ent = readdir(d); ent; ent = readdir(d)) {
118 /* atoi will return bogus values for certain inputs, but lowfd will
119 * prevent us from closing anything we care about. */
120 fd = atoi(ent->d_name);
121 if (fd >= 0 && fd >= lowfd)
122 close(fd);
124 closedir(d);
125 return 0;
128 void closefds_range(unsigned int first, unsigned int last)
130 int fds_closed = 0;
131 // Try using close_range syscall first.
132 #if defined(LISP_FEATURE_OS_PROVIDES_CLOSE_RANGE_WRAPPER)
133 // Prefer the libc wrapper, if it exists at build time.
134 fds_closed = !close_range(first, last, 0);
135 #elif defined(LISP_FEATURE_LINUX) && defined(__NR_close_range)
136 // Use syscall(2) if we could detect the syscall number at build time.
137 fds_closed = !syscall(__NR_close_range, first, last, 0);
138 #endif
139 // Otherwise (if the syscall information isn't availble at build time or if
140 // the run time kernel doesn't support the syscall), fall back to close()
141 // in a for loop.
142 if (!fds_closed)
144 unsigned int close_fd;
145 if (last == ~0U)
147 #if defined SVR4 || defined LISP_FEATURE_ANDROID
148 last = sysconf(_SC_OPEN_MAX)-1;
149 #else
150 last = getdtablesize()-1;
151 #endif
153 for (close_fd = first; close_fd <= last; close_fd++)
155 close(close_fd);
160 void closefds_from(int lowfd, int* dont_close)
162 if (dont_close) {
163 /* dont_close is a sorted simple-array of tagged ints */
164 uword_t length = fixnum_value(((uword_t*)dont_close)[-1]);
165 uword_t i;
166 for (i = 0; i < length; i++)
168 int fd = dont_close[i];
169 closefds_range(lowfd, fd - 1);
170 lowfd = fd+1;
174 #if defined(LISP_FEATURE_OPENBSD) || defined(LISP_FEATURE_NETBSD) \
175 || defined(LISP_FEATURE_DRAGONFLY) || defined(LISP_FEATURE_FREEBSD) \
176 || defined(LISP_FEATURE_SUNOS)
177 closefrom(lowfd);
178 #else
179 int fds_closed = 0;
181 /* readdir() uses malloc, which is prone to deadlocking
182 #ifdef LISP_FEATURE_LINUX
183 if (!fds_closed)
184 fds_closed = !closefrom_fddir("/proc/self/fd/", lowfd);
185 #endif
186 #ifdef LISP_FEATURE_DARWIN
187 if (!fds_closed)
188 fds_closed = !closefrom_fddir("/dev/fd/", lowfd);
189 #endif
192 if (!fds_closed)
193 closefds_range(lowfd, ~0U);
194 #endif
197 int wait_for_exec(int pid, int channel[2]) {
198 if ((-1 != pid) && (-1 != channel[1])) {
199 int child_errno = 0;
200 int bytes = sizeof(int);
201 int n;
202 char *p = (char*)&child_errno;
203 close(channel[1]);
204 /* Try to read child errno from channel. */
205 while ((bytes > 0) &&
206 (n = read(channel[0], p, bytes))) {
207 if (-1 == n) {
208 if (EINTR == errno) {
209 continue;
210 } else {
211 break;
213 } else {
214 bytes -= n;
215 p += n;
218 close(channel[0]);
219 if (child_errno) {
220 int status;
221 waitpid(pid, &status, 0);
222 /* Our convention to tell Lisp that it was the exec or
223 chdir that failed, not the fork. */
224 /* FIXME: there are other values waitpid(2) can return. */
225 if (WIFEXITED(status)) {
226 pid = -WEXITSTATUS(status);
228 errno = child_errno;
231 return pid;
234 extern char **environ;
237 #ifdef LISP_FEATURE_OS_PROVIDES_POSIX_SPAWN
239 #include <spawn.h>
240 int pspawn(char *program, char *argv[], int sin, int sout, int serr,
241 int search, char *envp[], __attribute__((unused)) char *pty_name,
242 __attribute__((unused)) char *pwd, __attribute__((unused)) int* dont_close)
244 pid_t pid;
245 posix_spawn_file_actions_t actions;
246 posix_spawnattr_t attr;
247 short flags = POSIX_SPAWN_SETSIGMASK;
249 posix_spawn_file_actions_init(&actions);
250 posix_spawnattr_init(&attr);
252 sigset_t sset;
253 sigemptyset(&sset);
255 posix_spawnattr_setsigmask(&attr, &sset);
257 if (sin >= 0) {
258 posix_spawn_file_actions_adddup2(&actions, sin, 0);
259 flags |= POSIX_SPAWN_SETPGROUP;
260 } else
262 #ifdef LISP_FEATURE_DARWIN
263 posix_spawn_file_actions_addinherit_np(&actions, 0);
264 #endif
266 if (sout >= 0)
267 posix_spawn_file_actions_adddup2(&actions, sout, 1);
268 else
270 #ifdef LISP_FEATURE_DARWIN
271 posix_spawn_file_actions_addinherit_np(&actions, 1);
272 #endif
274 if (serr >= 0)
275 posix_spawn_file_actions_adddup2(&actions, serr, 2);
276 else
278 #ifdef LISP_FEATURE_DARWIN
279 posix_spawn_file_actions_addinherit_np(&actions, 2);
280 #endif
283 #ifdef LISP_FEATURE_DARWIN
284 flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
285 #elif defined LISP_FEATURE_LINUX
286 posix_spawn_file_actions_addclosefrom_np(&actions, 3);
287 #endif
289 posix_spawnattr_setflags(&attr, flags);
291 int ret;
293 if (search)
294 ret = posix_spawnp(&pid, program, &actions, &attr, argv, envp);
295 else
296 ret = posix_spawn(&pid, program, &actions, &attr, argv, envp);
298 posix_spawn_file_actions_destroy(&actions);
299 posix_spawnattr_destroy(&attr);
301 if (ret) {
302 errno = ret;
303 return -2;
306 return pid;
308 #endif
310 int spawn(char *program, char *argv[], int sin, int sout, int serr,
311 int search, char *envp[], char *pty_name,
312 int channel[2],
313 char *pwd, int* dont_close)
315 pid_t pid;
316 sigset_t sset;
317 int failure_code = 2;
319 pid = fork();
320 if (pid) {
321 return pid;
323 close (channel[0]);
325 /* Put us in our own process group, but only if we need not
326 * share stdin with our parent. In the latter case we claim
327 * control of the terminal. */
328 if (sin >= 0) {
329 #ifdef LISP_FEATURE_OPENBSD
330 setsid();
331 #elif defined(LISP_FEATURE_DARWIN)
332 setpgid(0, getpid());
333 #elif defined SVR4 || defined __linux__ || defined __osf__ || defined __GLIBC__ || defined __HAIKU__
334 setpgrp();
335 #else
336 setpgrp(0, getpid());
337 #endif
338 } else {
339 tcsetpgrp(0, getpgrp());
342 /* unblock signals */
343 sigemptyset(&sset);
344 sigprocmask(SIG_SETMASK, &sset, NULL);
346 /* If we are supposed to be part of some other pty, go for it. */
347 if (pty_name)
348 set_pty(pty_name);
349 else {
350 /* Set up stdin, stdout, and stderr */
351 if (sin >= 0)
352 dup2(sin, 0);
353 if (sout >= 0)
354 dup2(sout, 1);
355 if (serr >= 0)
356 dup2(serr, 2);
358 /* Close all other fds. First arrange for the pipe fd to be the
359 * lowest free fd, then close every open fd above that. */
360 channel[1] = dup2(channel[1], 3);
361 closefds_from(4, dont_close);
363 if (-1 != channel[1]) {
364 if (-1==fcntl(channel[1], F_SETFD, FD_CLOEXEC)) {
365 close(channel[1]);
366 channel[1] = -1;
370 if (pwd && chdir(pwd) < 0) {
371 failure_code = 3;
372 } else {
373 if (envp) {
374 environ = envp;
376 /* Exec the program. */
377 if (search)
378 execvp(program, argv);
379 else
380 execv(program, argv);
383 /* When exec or chdir fails and channel is available, send the errno value. */
384 if (-1 != channel[1]) {
385 int our_errno = errno;
386 int bytes = sizeof(int);
387 int n;
388 char *p = (char*)&our_errno;
389 while ((bytes > 0) &&
390 (n = write(channel[1], p, bytes))) {
391 if (-1 == n) {
392 if (EINTR == errno) {
393 continue;
394 } else {
395 break;
397 } else {
398 bytes -= n;
399 p += n;
402 close(channel[1]);
404 _exit(failure_code);