From 2a1151093b4562726e6be51aeec690bb6b1f7d79 Mon Sep 17 00:00:00 2001 From: Richard M Kreuter Date: Wed, 19 Dec 2007 02:28:12 +0000 Subject: [PATCH] 1.0.12.37: RUN-PROGRAM now uses execvp(3) to search for executables * RUN-PROGRAM now uses execvp(3) in the child, rather than a Lisp function in SBCL, to search for an executable to run. This makes RUN-PROGRAM slightly closer to most other languages' process creation facilities. * The function FIND-EXECUTABLE-IN-SEARCH-PATH has been removed. A note is added to the manual pointing users who need the old, idiosyncratic search behavior to look for it it in the CVS history. --- NEWS | 5 +++ doc/manual/beyond-ansi.texinfo | 36 +++++++++++++++++-- src/code/run-program.lisp | 78 +++++++++------------------------------- src/runtime/run-program.c | 27 ++++++++------ version.lisp-expr | 2 +- 5 files changed, 72 insertions(+), 76 deletions(-) diff --git a/NEWS b/NEWS index 10f07f0..b8f07dc 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,10 @@ ;;;; -*- coding: utf-8; -*- changes in sbcl-1.0.13 relative to sbcl-1.0.12: + * minor incompatible change: RUN-PROGRAM now uses execvp(3) to find + an executable in the search path, and does so in the child + process's PATH. The function FIND-EXECUTABLE-IN-SEARCH-PATH has + been removed; it can be found in the CVS history, for somebody who + needs that search behavior (see the manual). * minor incompatible change: compiler policy re. weakening type checks has changed: now type checks are weakened on if SAFETY < 2 and SAFETY < SPEED. diff --git a/doc/manual/beyond-ansi.texinfo b/doc/manual/beyond-ansi.texinfo index 2bb0ec6..dedf819 100644 --- a/doc/manual/beyond-ansi.texinfo +++ b/doc/manual/beyond-ansi.texinfo @@ -249,16 +249,48 @@ between classes and proper names and between lists of the form @comment node-name, next, previous, up @section Support For Unix +@menu +* Command-line arguments:: +* Querying the process environment:: +* Running external programs:: +@end menu + +@node Command-line arguments +@subsection Command-line arguments + The UNIX command line can be read from the variable -@code{sb-ext:*posix-argv*}. The UNIX environment can be queried with -the @code{sb-ext:posix-getenv} function. +@code{sb-ext:*posix-argv*}. + +@node Querying the process environment +@subsection Querying the process environment + +The UNIX environment can be queried with the +@code{sb-ext:posix-getenv} function. @include fun-sb-ext-posix-getenv.texinfo +@node Running external programs +@subsection Running external programs + External programs can be run with @code{sb-ext:run-program}. +@footnote{In SBCL versions prior to 1.0.13, @code{sb-ext:run-program} +searched for executables in a manner somewhat incompatible with other +languages. As of this version, SBCL uses the system library routine +@code{execvp(3)}, and no longer contains the function, +@code{find-executable-in-search-path}, which implemented the old +search. Users who need this function may find it +in @file{run-program.lisp} versions 1.67 and earlier in SBCL's CVS +repository here +@url{http://sbcl.cvs.sourceforge.net/sbcl/sbcl/src/code/run-program.lisp?view=log}. However, +we caution such users that this search routine finds executables that +system library routines do not.} @include fun-sb-ext-run-program.texinfo +When @code{sb-ext:run-program} is called with @code{wait} equal to +NIL, an instance of class @var{sb-ext:process} is returned. The +following functions are available for use with processes: + @include fun-sb-ext-process-p.texinfo @include fun-sb-ext-process-input.texinfo diff --git a/src/code/run-program.lisp b/src/code/run-program.lisp index 1be271f..b1331de 100644 --- a/src/code/run-program.lisp +++ b/src/code/run-program.lisp @@ -504,61 +504,19 @@ status slot." ,@body) (sb-sys:deallocate-system-memory ,sap ,size))))) -#-win32 -(sb-alien:define-alien-routine ("spawn" %spawn) sb-alien:int - (program sb-alien:c-string) - (argv (* sb-alien:c-string)) - (envp (* sb-alien:c-string)) - (pty-name sb-alien:c-string) - (stdin sb-alien:int) - (stdout sb-alien:int) - (stderr sb-alien:int)) - -#+win32 -(sb-alien:define-alien-routine ("spawn" %spawn) sb-win32::handle +(sb-alien:define-alien-routine spawn + #-win32 sb-alien:int + #+win32 sb-win32::handle (program sb-alien:c-string) (argv (* sb-alien:c-string)) (stdin sb-alien:int) (stdout sb-alien:int) (stderr sb-alien:int) + (search sb-alien:int) + (envp (* sb-alien:c-string)) + (pty-name sb-alien:c-string) (wait sb-alien:int)) -(defun spawn (program argv stdin stdout stderr envp pty-name wait) - #+win32 (declare (ignore envp pty-name)) - #+win32 (%spawn program argv stdin stdout stderr (if wait 1 0)) - #-win32 (declare (ignore wait)) - #-win32 (%spawn program argv envp pty-name stdin stdout stderr)) - -;;; FIXME: why are we duplicating standard library stuff and not using -;;; execvp(3)? We can extend our internal spawn() routine to take a -;;; flag to say whether to search... -;;; Is UNIX-FILENAME the name of a file that we can execute? -(defun unix-filename-is-executable-p (unix-filename) - (let ((filename (coerce unix-filename 'string))) - (values (and (eq (sb-unix:unix-file-kind filename) :file) - #-win32 - (sb-unix:unix-access filename sb-unix:x_ok))))) - -(defun find-executable-in-search-path (pathname &optional - (search-path (posix-getenv "PATH"))) - #+sb-doc - "Find the first executable file matching PATHNAME in any of the -colon-separated list of pathnames SEARCH-PATH" - (let ((program #-win32 pathname - #+win32 (merge-pathnames pathname (make-pathname :type "exe")))) - (loop for end = (position #-win32 #\: #+win32 #\; search-path - :start (if end (1+ end) 0)) - and start = 0 then (and end (1+ end)) - while start - ;; the truename of a file naming a directory is the - ;; directory, at least until pfdietz comes along and says why - ;; that's noncompliant -- CSR, c. 2003-08-10 - for truename = (probe-file (subseq search-path start end)) - for fullpath = (when truename - (unix-namestring (merge-pathnames program truename))) - when (and fullpath (unix-filename-is-executable-p fullpath)) - return fullpath))) - ;;; FIXME: There shouldn't be two semiredundant versions of the ;;; documentation. Since this is a public extension function, the ;;; documentation should be in the doc string. So all information from @@ -659,9 +617,8 @@ Users Manual for details about the PROCESS structure."#-win32" an alternative lossy representation of the new Unix environment, for compatibility with CMU CL"" :SEARCH - Look for PROGRAM in each of the directories along the $PATH + Look for PROGRAM in each of the directories in the child's $PATH environment variable. Otherwise an absolute pathname is required. - (See also FIND-EXECUTABLE-IN-SEARCH-PATH) :WAIT If non-NIL (default), wait until the created process finishes. If NIL, continue running Lisp until the program finishes."#-win32" @@ -739,20 +696,15 @@ Users Manual for details about the PROCESS structure."#-win32" #-win32 *handlers-installed* ;; Establish PROC at this level so that we can return it. proc - ;; It's friendly to allow the caller to pass any string - ;; designator, but internally we'd like SIMPLE-STRINGs. (simple-args (simplify-args args)) - ;; See the comment above about execlp(3). - (pfile (if search - (find-executable-in-search-path program) - (unix-namestring program))) + (progname (native-namestring program)) ;; Gag. (cookie (list 0))) - (unless pfile - (error "no such program: ~S" program)) - (unless (unix-filename-is-executable-p pfile) - (error "not executable: ~S" program)) (unwind-protect + ;; Note: despite the WITH-* names, these macros don't + ;; expand into UNWIND-PROTECT forms. They're just + ;; syntactic sugar to make the rest of the routine slightly + ;; easier to read. (macrolet ((with-fd-and-stream-for (((fd stream) which &rest args) &body body) `(multiple-value-bind (,fd ,stream) @@ -803,9 +755,11 @@ Users Manual for details about the PROCESS structure."#-win32" (with-environment-vec (environment-vec environment) (let ((child (without-gcing - (spawn pfile args-vec + (spawn progname args-vec stdin stdout stderr - environment-vec pty-name wait)))) + (if search 1 0) + environment-vec pty-name + (if wait 1 0))))) (when (minusp child) (error "couldn't fork child process: ~A" (strerror))) diff --git a/src/runtime/run-program.c b/src/runtime/run-program.c index 08feaa1..303b280 100644 --- a/src/runtime/run-program.c +++ b/src/runtime/run-program.c @@ -54,8 +54,9 @@ int set_noecho(int fd) return 1; } -int spawn(char *program, char *argv[], char *envp[], char *pty_name, - int stdin, int stdout, int stderr) +extern char **environ; +int spawn(char *program, char *argv[], int stdin, int stdout, int stderr, + int search, char *envp[], char *pty_name, int wait) { int pid = fork(); int fd; @@ -112,16 +113,14 @@ int spawn(char *program, char *argv[], char *envp[], char *pty_name, close(fd); #endif + environ = envp; /* Exec the program. */ - execve(program, argv, envp); + if (search) + execvp(program, argv); + else + execv(program, argv); - /* It didn't work, so try /bin/sh. */ - argv[0] = program; - argv[-1] = "sh"; - execve("/bin/sh", argv-1, envp); - - /* The exec didn't work, flame out. */ - exit(1); + exit (1); } #else /* !LISP_FEATURE_WIN32 */ @@ -149,6 +148,9 @@ HANDLE spawn ( int in, int out, int err, + int search, + char *envp, + char *ptyname, int wait ) { @@ -187,7 +189,10 @@ HANDLE spawn ( } /* Spawn process given on the command line*/ - hProcess = (HANDLE) spawnvp ( wait_mode, program, argv ); + if (search) + hProcess = (HANDLE) spawnvp ( wait_mode, program, argv ); + else + hProcess = (HANDLE) spawnv ( wait_mode, program, argv ); /* Now that the process is launched, replace the original * in/out/err handles and close the backups. */ diff --git a/version.lisp-expr b/version.lisp-expr index 17bce5f..b5bb713 100644 --- a/version.lisp-expr +++ b/version.lisp-expr @@ -17,4 +17,4 @@ ;;; checkins which aren't released. (And occasionally for internal ;;; versions, especially for internal versions off the main CVS ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".) -"1.0.12.36" +"1.0.12.37" -- 1.7.10.4