Add :directory argument to sb-ext:run-program.
[sbcl.git] / src / runtime / run-program.c
index ef9c51c..57df79a 100644 (file)
@@ -100,12 +100,13 @@ set_pty(char *pty_name)
 
 extern char **environ;
 int spawn(char *program, char *argv[], int sin, int sout, int serr,
-          int search, char *envp[], char *pty_name, int wait)
+          int search, char *envp[], char *pty_name, int wait, char *pwd)
 {
     pid_t pid;
     int fd;
     int channel[2];
     sigset_t sset;
+    int failure_code = 2;
 
     channel[0] = -1;
     channel[1] = -1;
@@ -140,10 +141,14 @@ int spawn(char *program, char *argv[], int sin, int sout, int serr,
             }
             close(channel[0]);
             if (child_errno) {
-                waitpid(pid, NULL, 0);
-                /* Our convention to tell Lisp that it was the exec that
-                 * failed, not the fork. */
-                pid = -2;
+                int status;
+                waitpid(pid, &status, 0);
+                /* Our convention to tell Lisp that it was the exec or
+                   chdir that failed, not the fork. */
+                /* FIXME: there are other values waitpid(2) can return. */
+                if (WIFEXITED(status)) {
+                  pid = -WEXITSTATUS(status);
+                }
                 errno = child_errno;
             }
         }
@@ -193,16 +198,20 @@ int spawn(char *program, char *argv[], int sin, int sout, int serr,
         if (fd != channel[1]) close(fd);
 #endif
 
-    if (envp) {
-      environ = envp;
+    if (pwd && chdir(pwd) < 0) {
+       failure_code = 3;
+    } else {
+        if (envp) {
+            environ = envp;
+        }
+        /* Exec the program. */
+        if (search)
+            execvp(program, argv);
+        else
+            execv(program, argv);
     }
-    /* Exec the program. */
-    if (search)
-      execvp(program, argv);
-    else
-      execv(program, argv);
 
-    /* When exec fails and channel is available, send the errno value. */
+    /* When exec or chdir fails and channel is available, send the errno value. */
     if (-1 != channel[1]) {
         int our_errno = errno;
         int bytes = sizeof(int);
@@ -223,7 +232,7 @@ int spawn(char *program, char *argv[], int sin, int sout, int serr,
         }
         close(channel[1]);
     }
-    _exit(1);
+    _exit(failure_code);
 }
 #else  /* !LISP_FEATURE_WIN32 */
 
@@ -254,7 +263,8 @@ HANDLE spawn (
     int search,
     char *envp,
     char *ptyname,
-    int wait
+    int wait,
+    char *pwd
     )
 {
     int stdout_backup, stdin_backup, stderr_backup, wait_mode;
@@ -291,6 +301,13 @@ HANDLE spawn (
         wait_mode = P_WAIT;
     }
 
+    /* Change working directory if supplied. */
+    if (pwd) {
+        if (chdir(pwd) < 0) {
+            goto error_exit;
+        }
+    }
+
     /* Spawn process given on the command line*/
     if (search)
         hProcess = (HANDLE) spawnvp ( wait_mode, program, (char* const* )argv );