Forum OpenACS Development: Problems with psql and passwords in the APM
psql has the nasty habit of reporting all interesting information on
stderr, including the password prompt, there is no option to send it
to stdout instead, so I use redirecting. Tcl exec
doesn't seem to be able to redirect stderr to stdout, but bash can
so I wrap the call to psql in a bash -c "|psql -U nsadmin -W
-f some.sql myacsdb 2>&1"
. This works perfectly, all stderr
goes to stdout, which I can read with, well, read
$fd
.
The biggest problem I have at the moment is that there seems to be no simple way to ask how many bytes are available in the pipe. I am currently using this code, which works to the point of entering the password but then comes to a full stop.
ad_proc db_source_sql_file { {-callback apm_ns_write_callback} file } { Sources a SQL file (in psql format). } { set file_name [file tail $file] set pguser [db_get_username] set pgport [db_get_port] if { ![string equal $pgport ""] } { set pgport "--port $pgport" } cd [file dirname $file] #Tcl-Exec can't redirect stderr to a the new pipe, so we use bash #We need this because psql likes to write a lot of things to stderr and #has no option to divert it to stdout (because they expect the shell can do it ?!?) set fp [open "|/bin/bash -c "[file join [db_get_pgbin] psql] [db_get_database] $pgport -U $pguser -W -f $file_name 2>&1"" "r+"] #This is pretty tricky, we expect exactly this string: "Password: " #(-W on psql makes it ALWAYS ask for the password (I checked psql's source) #scan till password: set line "" while { ![eof $fp] } { append line [read $fp 1] puts stderr $line if { [string first "Password:" $line] != -1 } { break } } if { [string first "Password:" $line] == -1 } { return -code error -errorinfo "Didn't get 'Password:' from psql (result '[ad_quotehtml $line]') " -errorcode 3 } puts $fp [db_get_password] #this is where it hangs. psql doesn't give me anymore new lines, #so [gets $fp line] blocks 'till the end of days. #I am certain psql is running as it shows up the the process list. set error_found 0 while { [gets $fp line] >= 0 } { if { ![string is space $line] } { apm_callback_and_log $callback "[ad_quotehtml $line] " set error_line [expr { [string first ERROR $line] != -1 || [string first FATAL $line] != -1 } ] if { $error_line } { set error_found $error_line append error_lines "$line " } } } if { $error_found } { global errorCode return -code error -errorinfo $error_lines -errorcode $errorCode } }
Who can give me some suggestions of how to make it work and make it a bit more fault tolerant?