#!/usr/local/bin/expect -- # kibitz2 - modified version of kibitz to be called from # connect to allow connection to fourc # Author: Mark Lumsden # Based on script kibitz # Author: Don Libes, NIST # Date written: December 12, 1995 # Date last editted: December 12, 1995 # Version: 1.0 exp_version -exit 5.0 # if environment variable "EXPECT_PROMPT" exists, it is taken as a regular # expression which matches the end of your login prompt (but does not other- # wise occur while logging in). set prompt "kibitz $" ;# default prompt set noproc 0 set tty "" ;# default if no -tty flag set allow_escape 1 ;# allow escapes if true set escape_char \1 ;# control-right-bracket set escape \035 set escape_printable "^A" set verbose 1 ;# if true, describe what kibitz is doing set kibitz "kibitz" ;# where kibitz lives if some unusual place. ;# this must end in "kibitz", but can have ;# things in front (like directory names). # The following code attempts to intuit whether cat buffers by default. # The -u flag is required on HPUX (8 and 9) and IBM AIX (3.2) systems. if [file exists $exp_exec_library/cat-buffers] { set catflags "-u" } else { set catflags "" } # If this fails, you can also force it by commenting in one of the following. # Or, you can use the -catu flag to the script. #set catflags "" #set catflags "-u" # Some flags must be passed onto the remote kibitz process. They are stored # in "kibitz_flags". Currently, they include -tty and -silent. set kibitz_flags "" while {[llength $argv]>0} { set flag [lindex $argv 0] switch -- $flag \ "-noproc" { set noproc 1 set argv [lrange $argv 1 end] } "-catu" { set catflags "-u" set argv [lrange $argv 1 end] } "-tty" { set tty [lindex $argv 1] set argv [lrange $argv 2 end] set kibitz_flags "$kibitz_flags -tty $tty" } "-noescape" { set allow_escape 0 set argv [lrange $argv 1 end] } "-escape" { set escape_char [lindex $argv 1] set escape_printable $escape_char set argv [lrange $argv 2 end] } "-silent" { set verbose 0 set argv [lrange $argv 1 end] set kibitz_flags "$kibitz_flags -silent" } "-proxy" { set proxy [lindex $argv 1] set argv [lrange $argv 2 end] } default { break } } if {([llength $argv]<1) && ($noproc==0)} { send_user "usage: kibitz2 \[args] user \[program ...]\n" send_user " or: kibitz22 \[args] user@host \[program ...]\n" exit } log_user 0 set timeout -1 set user [lindex $argv 0] set argrun [lindex $argv 1] if [string match -r $user] { send_user "KRUN" ;# this tells user_number 1 that we're running ;# and to prepare for possible error messages set user_number 3 # need to check that it exists first! set user [lindex $argv 1] } else { set user_number [expr 1+(0==[string first - $user])] } # at this point, user_number and user are correctly determined # User who originated kibitz2 session has user_number == 1 on local machine. # User who is responding to kibitz2 has user_number == 2. # User who originated kibitz2 session has user_number == 3 on remote machine. # user 1 invokes kibitz as "kibitz2 user[@host]" # user 2 invokes kibitz as "kibitz2 -####" (some pid). # user 3 invokes kibitz as "kibitz2 -r user". # uncomment for debugging: leaves each user's session in a file: 1, 2 or 3 #exec rm -f $user_number #exp_internal -f $user_number 0 set user2_islocal 1 ;# assume local at first # later move inside following if $user_number == 1 # return true if x is a prefix of xjunk, given that prefixes are only # valid at . delimiters # if !do_if0, skip the whole thing - this is here just to make caller simpler proc is_prefix {do_if0 x xjunk} { if 0!=$do_if0 {return 0} set split [split $xjunk .] for {set i [expr [llength $split]-1]} {$i>=0} {incr i -1} { if [string match $x [join [lrange $split 0 $i] .]] {return 1} } return 0 } if $user_number==1 { set file_fifo [open /tmp/fifo.out w] set file_pid [open /tmp/pid.out w] if [file exists /tmp/testfile.3] { exec rm /tmp/testfile.3 } exit -onexit { if [file exists /tmp/pid.out] { exec rm /tmp/pid.out } if [file exists /tmp/fifo.out] { exec rm /tmp/fifo.out } if [file exists /tmp/llogfile.1] { exec rm /tmp/llogfile.1 } if [file exists $userinfile] { exec rm $userinfile } if [file exists $useroutfile] { exec rm $useroutfile } puts "\nLocal Connect exiting - goodbye\n\r" } } if $user_number==2 { set pid [string trimleft $user -] exit -onexit { if [file exists /tmp/rlogfile.1] { exec rm /tmp/rlogfile.1 } puts "\nRemote Connect exiting - goodbye\n\r" } } set local_io [expr ($user_number==3)||$user2_islocal] if $local_io||($user_number==2) { if 0==[info exists pid] {set pid [pid]} set userinfile /tmp/exp0.$pid set useroutfile /tmp/exp1.$pid } proc prompt1 {} { return "connect[info level].[history nextid]> " } set esc_match {} if {$allow_escape} { set esc_match { $escape_char { send_user "\nto exit connect, enter: exit\n" send_user "to return to connect, enter: return\n" interpreter send_user "returning to connect\n" } } } proc prompt1 {} { return "connect[info level].[history nextid]> " } set timeout -1 # kibitzer executes following code if $user_number==2 { # for readability, swap variables set tmp $userinfile set userinfile $useroutfile set useroutfile $tmp exec touch /tmp/testfile.3 exec touch /tmp/rlogfile.1 spawn -open [open "|cat $catflags < $userinfile" "r"] set userin $spawn_id spawn -open [open $useroutfile w] set userout $spawn_id # open will hang until other user's cat starts exec rm /tmp/testfile.3 stty -echo raw if $allow_escape {send_user "Escape sequence is $escape_printable\r\n"} # While user is reading message, try to delete other fifo catch {exec rm -f $userinfile} eval interact $esc_match \ -output $userout \ -input $userin exit } # only user_numbers 1 and 3 execute remaining code proc abort {} { global user_number # KABORT tells user_number 1 that user_number 3 has run into problems # and is exiting, and diagnostics have been returned already if $user_number==3 {send_user KABORT} exit } set counter 1 while {1} { if $local_io { ####################################################################### # counter==1 for the first time things are performed by usernumber 1; # # i.e. before the first remote connect is called # ####################################################################### if {$counter==1} { proc mkfifo {f} { exec mkfifo $f return } ##################################################################### # proc mkfifo {f} may have to be altered for some systems: # # exec mknod $f p # # exec /usr/etc/mknod $f p :Sun # # exec /etc/mknod $f p : AIX, Cray # ##################################################################### proc rmfifos {} { global userinfile useroutfile catch {exec rm -f $userinfile $useroutfile} } trap {rmfifos; exit} {SIGINT SIGQUIT SIGTERM} } # create 2 fifos to communicate with other user mkfifo $userinfile mkfifo $useroutfile #chmod of fifos to make them readable and writable by everyone exec chmod 666 $userinfile $useroutfile if {$counter==1} { puts $file_fifo $userinfile puts $file_fifo $useroutfile close $file_fifo exec chmod 666 /tmp/fifo.out # make sure other user can access despite umask # write pid and username to file /tmp/pid.out set user2 [exec whoami] puts $file_pid $pid puts $file_pid $user2 close $file_pid exec chmod 666 /tmp/pid.out set pid [spawn $env(SHELL) -c "$argrun"] exec touch /tmp/llogfile.1 set shell $spawn_id } ############################################################################ # Key part of program - this allows for normal behaviour while constantly # # checking if a specific file exists. This file is created by user 2 when # # ready to connect - main difference from original kibitz. # ############################################################################ while {1} { interact { timeout 1 { if [file exists /tmp/testfile.3] break } $escape_char { send_user "\nto exit connect, enter: exit\n" send_user "to return to connect session, enter: return\n" interpreter send_user "returning to connect session\n" } -o eof { exit } } } set timeout -1 spawn -open [open $useroutfile w] set userout $spawn_id # open will hang until other user's cat starts spawn -open [open "|cat $catflags < $userinfile" "r"] set userin $spawn_id catch {exec rm $userinfile} } stty -echo raw if $user_number==3 { send_user "KDATA" ;# this tells user_number 1 to send data interact { -output $userout -input $userin eof { wait -i $userin return -tcl } -output $user_spawn_id } } else { if $noproc { interact { -output $userout -input $userin eof {wait -i $userin; return} -output $user_spawn_id } } else { eval interact $esc_match { -output $shell \ -input $userin eof { wait -i $userin return } -output $shell \ -input $shell -output "$user_spawn_id $userout" } } } incr counter puts "No longer assisted by connect\r" set spawn_id $shell rmfifos } if $local_io rmfifos