Page 1 of 1

Return value

Posted: Sat Oct 08, 2005 2:55 am
by Dave
How does one get the return value for exec?

(set 'x (exec "command")) seems to return a nil x, regardless if the command is successful or not.

Posted: Sat Oct 08, 2005 7:39 am
by HPW
Works for me in windows.
But I have to kill the DOS-window.

Code: Select all

> (set 'x (exec "command"))
("Microsoft(R) Windows DOS" "(C)Copyright Microsoft Corp 1990-2001." 
 "" "C:\\PROGRA~1\\NEWLISP>") 
This works:

Code: Select all

> (set 'x (exec "dir un*.exe"))
(" Datentr?ger in Laufwerk C: ist Festplatte" " Volumeseriennummer: 4875-9A91" 
 "" " Verzeichnis von C:\\Programme\\newlisp" "" "26.09.2005  19:38            35.923 uninstall.exe" 
 "               1 Datei(en)         35.923 Bytes" "               0 Verzeichnis(se), 91.052.036.096 Bytes frei") 
Added later:
The above test was with newLISP-TK!
In native newLISP-shell the first hang up and the second work.

Posted: Sat Oct 08, 2005 12:28 pm
by Lutz
I don't have access to a Windows machine at the moment, but I think you can seperate commands with a semicolon in a DOS window and could put an 'exit' as a second statement:

(exec "dir *.exe; exit")

if exec returns 'nil' then it did not find the command shell try this instead:

(exec "cmd /c dir *.exe")

this would be 'cmd' for the NT cmd command shell and 'command' for older versions of Windows

Lutz

Posted: Sat Oct 08, 2005 4:31 pm
by Dave
I'm using newLISP as a scripting language under FreeBSD.

I am unclear about the term "return value", whether it is the data returned from the system process (say, a directory), or if it is the exit status of the process (success/fail). The reference says "The return value true is the process was successfully launched, else nil" (I think is s/b "if" btw). I am looking for the status of the process in this instance. I tried to query "$?", with the same results; nil on both pass and fail.

Posted: Sat Oct 08, 2005 4:49 pm
by Lutz
There are two forms of the syntax, with and without the second argument:

(1) 'exec' returns 'nil' if it could not launch the command given, else it returns a list of strings, each string beeing one of the output lines of std-out of the process launched.

(2) with the second argument given (stdin to the process), the return value is 'true' on success and 'nil' if the process could not be launched.

Lutz

Posted: Sun Oct 09, 2005 8:53 pm
by Dave
(set 'x (exec "ls /a_directory")) --- x will be the contents of the directory.
(set 'x (exec "ls /empty_directory")) --- x will be empty.

But this is where I have trouble understanding:

(set 'x (exec "ls /not_a_directory")) --- x will be empty NOT null, and the OS will output an error message.
(set 'x (exec "not_an_instruction")) --- x will be empty NOT null, and the OS will output an error message.

I am trying to test for failed calls to the system, and deal with them before they are sent to the output. Should I be using some form of catch/throw? How is it used in this way?

Posted: Sun Oct 09, 2005 9:57 pm
by Lutz
'exec' launches a shell process and returns whatever was standard-out via a pipe mechanism. There is no way to check stdout from the launched process before it gets returned. 'exec' fails if the command in exec couldn't be launched returning a 'nil'.

If you want a more direct control over OS system calls you could import system calls from the libraries of your OS. I.e.:

(import "libc.so" "kill")

could be used to import the kill system call and then you could do a:

(kill pid 9)

To send SIGKILL to a process ID and the function would return 0 for sucess -1 for error etc.

The purpose of 'exec' is to execute OS utilities/programs in a shell like fashion and capture stdout. But there is a way to capture std error using the following method:

Code: Select all

> (exec "ls *.abc 2>&1")
("ls: *.abc: No such file or directory") 
> 
The 2>&1 spec tell ls to redirect error output to stdout. This way it gets captured in the list returned by exec.

Lutz

Posted: Sun Oct 09, 2005 10:45 pm
by Dave
Very informative answer, Lutz! It shows me some things I will have to study.

Thanks. I'm a fan!

Posted: Fri Oct 14, 2005 5:34 pm
by statik
The 2>&1 is a format for stderr redirection that is only valid with the bourne-again shell. Keep that in mind when developing; all shells use different syntax when using stdio/out/err redirection.

Posted: Fri Oct 14, 2005 8:28 pm
by Dmi
Just checked 2>&1 on Tru64 with ksh and pure sh - it works like bash.
Even command.com (AFAI remember) works this way, despite in it it's only "idiom", I think.

Posted: Fri Oct 14, 2005 8:47 pm
by Dmi
Btw, there is a nice way in unix shell:

Code: Select all

$ mknod pipe p
$ ls pipe
prw-r--r--  1 dmi users 0 Oct 15 00:44 pipe
$ cat pipe >error&
[1] 22755
$ ls nonexistent 2>pipe
$ cat error
ls: nonexistent: No such file or directory
...but there is some special things about locking and end of file on the named pipe's ends

Posted: Fri Dec 09, 2005 2:18 pm
by nigelbrown
Lutz wrote: ...
If you want a more direct control over OS system calls you could import system calls from the libraries of your OS. I.e.:

(import "libc.so" "kill")
...
Lutz
Trying on Suse 10 I get (using newlisp compiled on system from source):
nigel@linux:~/newlisp-8.7.1> ./newlisp
newLISP v.8.7.1 on linux, execute 'newlisp -h' for more info.

> (import "libc.so" "kill")
/usr/lib/libc.so: invalid ELF header
problem loading library in function import : "libc.so"

>

Looking at libc.so shows:
linux:/home/nigel # ls -l /usr/lib/libc.so
-rw-r--r-- 1 root root 204 2005-09-10 03:20 /usr/lib/libc.so

I really want to call getuid (to find if newlisp is running as root).
Any tips on calling from libc ?

Nigel

Posted: Fri Dec 09, 2005 2:28 pm
by newdep
What happens when you provide the whole path?
>(import "/lib/libc.so.6" "fopen")

what does "ldd" give on libc.so ?
(Looks like the libc you revering to is not a shared lib...)

Posted: Fri Dec 09, 2005 7:21 pm
by nigelbrown
Thanks for pointing out the correct path - works as required viz:

nigel@linux:~/newlisp-8.7.1> ./newlisp
newLISP v.8.7.1 on linux, execute 'newlisp -h' for more info.

> (import "/lib/libc.so.6" "fopen")
fopen <401CF720>
> (import "/lib/libc.so.6" "getuid")
getuid <402075E0>
> (getuid)
1000
> (exit)
nigel@linux:~/newlisp-8.7.1> su
Password:
linux:/home/nigel/newlisp-8.7.1 # ./newlisp
newLISP v.8.7.1 on linux, execute 'newlisp -h' for more info.

> (import "/lib/libc.so.6" "getuid")
getuid <402075E0>
> (getuid)
0
>

as you expected:
linux:/home/nigel/newlisp-8.7.1 # ldd /usr/lib/libc.so
ldd: warning: you do not have execution permission for `/usr/lib/libc.so'
not a dynamic executable
linux:/home/nigel/newlisp-8.7.1 # ldd /lib/libc.so.6
/lib/ld-linux.so.2 (0x40000000)
linux-gate.so.1 => (0xffffe000)

Regards
Nigel