----
'''Calling arbitrary commandline tools via cgi, showing output as html-page'''
'''''Example'''''
Showing the system-log-events happened the last 24 hours from ''server'':
http://host/cgi-bin/prog/cgiframe.tcl?exec=eldump.exe -s server -l system -l -M -L -A 24 -Q
'''Attention!'''
* Be sure to protect the directory this proc is called from (.tclaccess) to not open an security leak!
* Move the proc in it's own subdirectory; only commands from within these directory are accessible via CGIFRAME
----
set cgiframe_version 0.08
#===============================================================================
# Packages
#===============================================================================
# Achtung: Nicht-Standard-Paket bgexec erforderlich!
if {[catch {package require ncgi
package require html
package require bgexec} rc]} {
# absoluter Notausstieg - keine CGI-Header!
puts "Content-Type: text/plain\n\nFehler `$rc` - Abbruch!"
exit 1
}
#===============================================================================
# Unterprozeduren
#===============================================================================
proc progSpec path {
# Pfadangabe IMMER als relativ zu CGI-BIN betrachten, Dirs aber erlauben!
# 0.08: möglicherweise kommt Drivespec nicht zuerst; da aber bei file join
# die zuletzt angegebene DriveSpec 'gewinnt' (wenn sie am Anfang steht),
# wäre durch ../../d:/.. die Prüfung kompromittierbar! daher schon am
# Anfang mögliche ./\\ wegnehmen!
set path [string trimleft $path {./\\}]
if {[string range $path 1 1] == ":"} {
set path [string replace $path 0 1]
}
set path [string trimleft $path {./\\}]
# Fehler (bis v0.04): durch Folgendes wird ein Backslash auch in den
# KommandoPARAMETERN in einen Slash umgesetzt!!
#set path [file join [pwd] $path]; # Voraussetzung: PWD liefert CGI-BIN!
set path "[file join [pwd] [lindex $path 0]] [lrange $path 1 end]"
# ggf. hier Fehler melden!
set prog [lindex $path 0]
if {![file isfile $prog] || ![file executable $prog]} {
abort Die Datei
$prog
existiert nicht oder ist nicht \
ausführbar oder kein Programm!
}
return $path
}
#-------------------------------------------------------------------------------
proc header {} {
# CGI- und HTML-Header
# Möglichen Aufruf von der Kommandozeile zu Debuggingzwecken berücksichtigen
if {[info exists ::env(REQUEST_URI)]} {
ncgi::reset
ncgi::parse
ncgi::header ; # schon hier, falls Fehlermeldungen früh generiert werden!
}
# CSS hier einfügen oder einbinden
::html::headTag {style type="text/css">
Fehler: |
---|
[join $args] |
(Das Skript wurde vorzeitig beendet) |
" footer exit 1 } #------------------------------------------------------------------------------- proc outLine data { # später hier alles wunderschön als Tabelle formatieren... # oder nur wechselnde Hintergründe je Zeile # evtl. sollte PID hier zV stehen (für gemischte Ausgaben versch. Procs) if {[string equal $::cgiframe_filter ""] || \ [string match -nocase $::cgiframe_filter $data]} { incr ::lineCount # puts [encoding convertfrom cp437 $data]; # bis v0.6 puts $data } } #=============================================================================== # Main #=============================================================================== header set exec [ncgi::value exec] set exec [progSpec $exec] # was ist mit STDERR? Offenbar gibt der tclhttpd stderr standardmässig zurück... fconfigure stdout -buffering line -blocking 0 fconfigure stdin -buffering line -blocking 0 set lineCount 0 puts "Ergebnis von $exec" if {[string equal $::cgiframe_filter ""]} { puts ":
; # später Tabellenbeginn etc. set processHandle [bgExec $exec outLine pCount] fconfigure $processHandle -encoding cp437; # v0.7; entspr. BgExec-Option fehlt! # Abbruch nicht von bgExec behandeln lassen, da dort (noch) kein Process-Kill! after $::cgiframe_timeout { # set pCount 0; # eigentlich nicht nötig, da Ausstieg via Abort! # Prozess beenden: catch {exec -- [auto_execok pv.exe] -k -f -i [pid $processHandle]} rc; # Callback zurücksetzen - keine Fehler mehr ausgeben! Nützt nichts: # proc outLine data {} catch {close $processHandle} rc; # bewirkt Broken_Pipe zumindest bei Tcl- # Progs, die dadurch natürlich auch enden. Was ist mit anderen Progs? testen! puts
puts "$::lineCount Zeile(n) Output" abort Abbruch durch Timeout!
($rc) } vwait pCount puts
puts "$::lineCount Zeile(n) Output" footer exit 0 #*******************************************************************************