[Openmcl-devel] where is OS-level feedback stored when launching an external program that does not exist

Pascal J. Bourguignon pjb at informatimago.com
Tue Apr 17 15:14:41 PDT 2012


clayton stanley <cstanley at cstanley.no-ip.biz> writes:

> For these reasons, I would like to launch the executable directly from
> CCL; no shell layer in between. 

That's what run-program does.  And that's why Gary had to explicitely
call the shell.


> Thing is, when I do this and the executable does not exist, the only
> feedback I get from the process object is the error code. I was hoping
> that the OS would give me some sort of one-liner string feedback,
> saying that someSpecificExecutable doesn't exist; much like bash does
> when you try to launch a non-existing executable from that shell.


The OS gives feedback, in the form of a return code, and setting the
errno variable by the execve(2) syscall.  However, this happens in the
child process, after fork(2), and this child process can return only a
status code to the parent process.  It returns the status 71 which means
on Linux: EX_OSERR system error (e.g., can't fork).

(ccl:run-program "zorglub"  '()  :wait t)
--> #<external-process (zorglub)[27801] (exited : 71) #x302001B11A9D>




> Maybe this information just doesn't exist, and therefore all I have to
> go off of in this situation is the exit code. I also think that
> another way to ask this question is, how does bash produce that
> one-line feedback message when it tries to launch a process that
> doesn't exist? does it go off of just the error code, or is there
> additional information available that it captures from the os? b/c
> what I'm really trying to do is get that same information in the lisp
> process.

The information exist, but in the child process.  It is not easily
recovered by the parent process.

------------------------------------------------------------------------
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(){


    int pid=fork();
    if(pid==0){
        // child
        char* argv[]={"zorglub",0};
        char* envv[]={"TERM=xterm",0};
        int res=execve("zorglub",argv,envv);
        int execve_errno=errno;
        printf("execve res     = %d\n",res);
        if(res<0){
            printf("execve errno   = %d\n",execve_errno);
            printf("execve msg     = %s\n",strerror(execve_errno));
        }
        fflush(stdout);
    }else if(pid>0){
        // parent
        int status=0;
        pid_t res=waitpid(pid,&status,0);
        int waitpid_errno=errno;
        printf("waitpid res    = %d\n",res);
        if(res<0){
            printf("waitpid errno  = %d\n",waitpid_errno);
            printf("waitpid msg    = %s\n",strerror(waitpid_errno));
        }else{
            printf("waitpid status = %d\n",status);
        }
        fflush(stdout);
        exit(0);
    }else{
        // error
        perror("fork");
        exit(1);
    }
    return(0);
}
------------------------------------------------------------------------


[pjb at kuiper :0 tmp]$ ./e
execve res     = -1
execve errno   = 2
execve msg     = No such file or directory
waitpid res    = 28203
waitpid status = 0
[pjb at kuiper :0 tmp]$ 





One solution would be for the implementation to create an additionnal
close-on-exec pipe between the parent and the child, and have the child
report the errno back to the parent thru the pipe when execve cannot
work.




Or, if you want it to work on implementations that don't do that (I
don't know any who does), run a program that you know is present, and
that tests for execve return code itself, reporting it thru stderr or
some other mean by yourself:

cl-user> (ccl:run-program "/bin/sh"  '("-c" "zorglub < /tmp/zorglub.input > /tmp/zorglub.output 2> /tmp/zorglub.error") :wait t)
#<external-process (/bin/sh -c zorglub < /tmp/zorglub.input > /tmp/zorglub.output 2> /tmp/zorglub.error)[28299] (exited : 127) #x302001C7112D>
cl-user> (cat "/tmp/zorglub.error")
/bin/sh: zorglub: command not found
; No value
cl-user> 


Redirecting thru files work in all implementations, even those that
don't provide stream arguments for all three streams.  (And even those
who do, they often have to actually copy the data to temporary files,
eg. when you pass a non-os-stream lisp stream, so you don't lose much by
doing it yourself).


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
A bad day in () is better than a good day in {}.




More information about the Openmcl-devel mailing list