summaryrefslogtreecommitdiff
path: root/example/kibitz
diff options
context:
space:
mode:
Diffstat (limited to 'example/kibitz')
-rwxr-xr-xexample/kibitz415
1 files changed, 415 insertions, 0 deletions
diff --git a/example/kibitz b/example/kibitz
new file mode 100755
index 0000000..eacb139
--- /dev/null
+++ b/example/kibitz
@@ -0,0 +1,415 @@
+#!/bin/sh
+# -*- tcl -*-
+# The next line is executed by /bin/sh, but not tcl \
+exec tclsh "$0" ${1+"$@"}
+
+package require Expect
+
+
+# allow another user to share a shell (or other program) with you
+# See kibitz(1) man page for complete info.
+# Author: Don Libes, NIST
+# Date written: December 5, 1991
+# Date last editted: October 19, 1994
+# Version: 2.11
+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 "(%|#|\\$) $" ;# default prompt
+set noproc 0
+set tty "" ;# default if no -tty flag
+set allow_escape 1 ;# allow escapes if true
+set escape_char \035 ;# control-right-bracket
+set escape_printable "^\]"
+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).
+#set proxy "kibitz" ;# uncomment and set if you want kibitz to use
+ ;# some other account on remote systems
+
+# 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: kibitz \[args] user \[program ...]\n"
+ send_user " or: kibitz \[args] user@host \[program ...]\n"
+ exit
+}
+
+log_user 0
+set timeout -1
+
+set user [lindex $argv 0]
+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 kibitz session has user_number == 1 on local machine.
+# User who is responding to kibitz has user_number == 2.
+# User who originated kibitz session has user_number == 3 on remote machine.
+
+# user 1 invokes kibitz as "kibitz user[@host]"
+# user 2 invokes kibitz as "kibitz -####" (some pid).
+# user 3 invokes kibitz as "kibitz -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
+}
+
+# get domainname. Unfortunately, on some systems, domainname(1)
+# returns NIS domainname which is not the internet domainname.
+proc domainname {} {
+ # open pops stack upon failure
+ set rc [catch {open /etc/resolv.conf r} file]
+ if {$rc==0} {
+ while {-1!=[gets $file buf]} {
+ if 1==[scan $buf "domain %s" name] {
+ close $file
+ return $name
+ }
+ }
+ close $file
+ }
+
+ # fall back to using domainname
+ if {0==[catch {exec domainname} name]} {return $name}
+
+ error "could not figure out domainname"
+}
+
+if $user_number==1 {
+ if $noproc==0 {
+ if {[llength $argv]>1} {
+ set pid [eval spawn [lrange $argv 1 end]]
+ } else {
+ # if running as CGI, shell may not be set!
+ set shell /bin/sh
+ catch {set shell $env(SHELL)}
+ set pid [spawn $shell]
+ }
+ set shell $spawn_id
+ }
+
+ # is user2 remote?
+ regexp (\[^@\]*)@*(.*) $user ignore tmp host
+ set user $tmp
+ if ![string match $host ""] {
+ set h_rc [catch {exec hostname} hostname]
+ set d_rc [catch domainname domainname]
+
+ if {![is_prefix $h_rc $host $hostname]
+ && ![is_prefix $d_rc $host $hostname.$domainname]} {
+ set user2_islocal 0
+ }
+ }
+
+ if !$user2_islocal {
+ if $verbose {send_user "connecting to $host\n"}
+
+ if ![info exists proxy] {
+ proc whoami {} {
+ global env
+ if {[info exists env(USER)]} {return $env(USER)}
+ if {[info exists env(LOGNAME)]} {return $env(LOGNAME)}
+ if {![catch {exec whoami} user]} {return $user}
+ if {![catch {exec logname} user]} {return $user}
+ # error "can't figure out who you are!"
+ }
+ set proxy [whoami]
+ }
+ spawn rlogin $host -l $proxy -8
+ set userin $spawn_id
+ set userout $spawn_id
+
+ catch {set prompt $env(EXPECT_PROMPT)}
+
+ set timeout 120
+ expect {
+ assword: {
+ stty -echo
+ send_user "password (for $proxy) on $host: "
+ set old_timeout $timeout; set timeout -1
+ expect_user -re "(.*)\n"
+ send_user "\n"
+ set timeout $old_timeout
+ send "$expect_out(1,string)\r"
+ # bother resetting echo?
+ exp_continue
+ } incorrect* {
+ send_user "invalid password or account\n"
+ exit
+ } "TERM = *) " {
+ send "\r"
+ exp_continue
+ } timeout {
+ send_user "connection to $host timed out\n"
+ exit
+ } eof {
+ send_user "connection to host failed: $expect_out(buffer)"
+ exit
+ } -re $prompt
+ }
+ if {$verbose} {send_user "starting kibitz on $host\n"}
+ # the kill protects user1 from receiving user3's
+ # prompt if user2 exits via expect's exit.
+ send "$kibitz $kibitz_flags -r $user;kill -9 $$\r"
+
+ expect {
+ -re "kibitz $kibitz_flags -r $user.*KRUN" {}
+ -re "kibitz $kibitz_flags -r $user.*(kibitz\[^\r\]*)\r" {
+ send_user "unable to start kibitz on $host: \"$expect_out(1,string)\"\n"
+ send_user "try rlogin by hand followed by \"kibitz $user\"\n"
+ exit
+ }
+ timeout {
+ send_user "unable to start kibitz on $host: "
+ set expect_out(buffer) "timed out"
+ set timeout 0; expect -re .+
+ send_user $expect_out(buffer)
+ exit
+ }
+ }
+ expect {
+ -re ".*\n" {
+ # pass back diagnostics
+ # should really strip out extra cr
+ send_user $expect_out(buffer)
+ exp_continue
+ }
+ KABORT exit
+ default exit
+ KDATA
+ }
+ }
+}
+
+if {$user_number==2} {
+ set pid [string trimleft $user -]
+}
+
+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 "kibitz[info level].[history nextid]> "
+}
+
+set esc_match {}
+if {$allow_escape} {
+ set esc_match {
+ $escape_char {
+ send_user "\nto exit kibitz, enter: exit\n"
+ send_user "to suspend kibitz, press appropriate job control sequence\n"
+ send_user "to return to kibitzing, enter: return\n"
+ interpreter
+ send_user "returning to kibitz\n"
+ }
+ }
+}
+
+proc prompt1 {} {
+ return "kibitz[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
+
+ if ![file readable $userinfile] {
+ send_user "Eh? No one is asking you to kibitz.\n"
+ exit -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
+
+ 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 {} {
+ # 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
+}
+
+if {$local_io} {
+ proc mkfifo {f} {
+ if 0==[catch {exec mkfifo $f}] return ;# POSIX
+ if 0==[catch {exec mknod $f p}] return
+ # some systems put mknod in wierd places
+ if 0==[catch {exec /usr/etc/mknod $f p}] return ;# Sun
+ if 0==[catch {exec /etc/mknod $f p}] return ;# AIX, Cray
+ puts "Couldn't figure out how to make a fifo - where is mknod?"
+ abort
+ }
+
+ 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
+ # make sure other user can access despite umask
+ exec chmod 666 $userinfile $useroutfile
+
+ if {$verbose} {send_user "asking $user to type: kibitz -$pid\n"}
+
+ # can't use exec since write insists on being run from a tty!
+ set rc [catch {
+ system echo "Can we talk? Run: \"kibitz -$pid\"" | \
+ write $user $tty
+ }
+ ]
+ if {$rc} {rmfifos;abort}
+
+ 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 {$allow_escape} {send_user "Escape sequence is $escape_printable\r\n"}
+
+ 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
+ close -i $shell
+ return
+ } -output $shell \
+ -input $shell eof {
+ close -i $userout
+ wait -i $userout
+ return
+ } -output "$user_spawn_id $userout"
+ }
+ wait -i $shell
+ }
+}
+
+if {$local_io} rmfifos