@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
,@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
- ;; <Krystof> 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
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"
#-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)
(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)))
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;
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 */
int in,
int out,
int err,
+ int search,
+ char *envp,
+ char *ptyname,
int wait
)
{
}
/* 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. */