Version 3 of UNIX only exec wrapper

Updated 2002-01-08 01:18:54

How to fork an external program and get back it's stdout and stderr without blocking and WITH a timeout!

 proc _exec { prog { var "" } { tmpfile "" } { i 0 } { to 5 } } {

     if { ! [ regexp {^file\d+$} $prog ] } {
        set tmpfile _exec-[ clock seconds ][ clock clicks ]
        set tmpfile /tmp/$tmpfile

        if { [ catch {
           set fid [ open "|$prog 2>$tmpfile" ]
           fconfigure $fid -blocking off
           fconfigure $fid -buffering full
        } err ] } {
           file delete -force $tmpfile
           return -code error "_exec: $err"
        }
     } else {
        set fid $prog
     }

     set ret [ read $fid ]

     if { ($i / 10) >= $to } {
        if { ! [ string length $ret ] } {
           set ret timed_out
        }
     }

     if { [ string length $ret ] || [ file size $tmpfile ] } {
        set pids [ pid $fid ]

        catch { ::close $fid }
        foreach pid $pids {
           catch { exec kill -KILL $pid }
        }
        set fid [ open $tmpfile r ]
        set err [ read $fid [ file size $tmpfile ] ]
        catch { ::close $fid }
        file delete -force $tmpfile
        if { [ string length $var ] } {
           set ::$var [ list $ret $err ]
        }
     } else {
        incr i
        after 100 [ list _exec $fid $var $tmpfile $i ]
     }
 }

Usage example:

 # of course, you really want to trace the variable,
 # not vwait on it!
 _exec "curl http://www.ligo.caltech.edu" foo
 vwait ::foo
 puts $::foo