home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / tcl / expect / expect-4.7 / example / kibitz < prev    next >
Encoding:
Text File  |  1993-04-12  |  9.6 KB  |  405 lines

  1. #!../expect --
  2. # allow another user to share a shell (or other program) with you
  3. # See kibitz(1) man page for complete info.
  4. # Author: Don Libes, NIST
  5. # Date written: December 5, 1991
  6. # Date last editted:  March 29 1993
  7. # Version: 2.1
  8.  
  9. # if environment variable "EXPECT_PROMPT" exists, it is taken as a regular
  10. # expression which matches the end of your login prompt (but does not other-
  11. # wise occur while logging in).
  12.  
  13. set prompt "(%|#|\$) "        ;# default prompt
  14. set noproc 0
  15. set tty ""            ;# default if no -tty flag
  16. set allow_escape 1        ;# allow escapes if true
  17. set escape_char \035        ;# control-right-bracket
  18. set escape_printable "^\]"
  19. set verbose 1            ;# if true, describe what kibitz is doing
  20.  
  21. # if you are on a system such as HPUX 8.0 that requires "cat -u" for kibitz
  22. # to work, comment out the following line, and uncomment the next one.
  23. set catflags ""
  24. #set catflags "-u"
  25.  
  26. trap exit SIGINT
  27.  
  28. set argv [lrange $argv 1 end]
  29. while [llength $argv]>0 {
  30.     set flag [lindex $argv 0]
  31.     case $flag in \
  32.     "-noproc" {
  33.         set noproc 1
  34.         set argv [lrange $argv 1 end]
  35.     } "-catu" {
  36.         set catflags "-u"
  37.         set argv [lrange $argv 1 end]
  38.     } "-tty" {
  39.         set tty [lindex $argv 1]
  40.         set argv [lrange $argv 2 end]
  41.     } "-noescape" {
  42.         set allow_escape 0
  43.         set argv [lrange $argv 1 end]
  44.     } "-escape" {
  45.         set escape_char [lindex $argv 1]
  46.         set escape_printable $escape_char
  47.         set argv [lrange $argv 2 end]
  48.     } "-silent" {
  49.         set verbose 0
  50.         set argv [lrange $argv 1 end]
  51.     } default {
  52.         break
  53.     }
  54. }
  55.  
  56. if {([llength $argv]<1) && ($noproc==0)} {
  57.     send_user "usage: kibitz user \[program ...\]\n"
  58.     send_user "   or: kibitz user@host \[program ...\]\n"
  59.     exit
  60. }
  61.  
  62. # 2nd user invokes it as "kibitz -####" but there is no
  63. # reason to document this, as user is told this on the fly.
  64. # known internally as user_number==2
  65.  
  66. # 1st user on remote machine invokes it as "kibitz -r user"
  67. # and is known internally as user_number==3 while
  68. # locally known internally as user_number==1
  69.  
  70. log_user 0
  71. set timeout -1
  72.  
  73. set user [lindex $argv 0]
  74. if [string match -r $user] {
  75.     send_user "KRUN"    ;# this tells user_number 1 that we're running
  76.                 ;# and to prepare for possible error messages
  77.     set user_number 3
  78.     # need to check that it exists first!
  79.     set user [lindex $argv 1]
  80. } else {
  81.     set user_number [expr 1+(0==[string first - $user])]
  82. }
  83.  
  84. # at this point, user_number and user are correctly determined
  85.  
  86. #for debugging, uncommenting, leaves each user's session in a file: 1, 2 or 3
  87. #exec rm -f $user_number
  88. #debug -f $user_number 0
  89.  
  90. set user2_islocal 1    ;# assume local at first
  91.  
  92. # later move inside following if $user_number == 1
  93. # return true if x is a prefix of xjunk, given that prefixes are only
  94. # valid at . delimiters
  95. # if !do_if0, skip the whole thing - this is here just to make caller simpler
  96. proc is_prefix {do_if0 x xjunk} {
  97.     if 0!=$do_if0 {return 0}
  98.     set split [split $xjunk .]
  99.     for {set i [expr [llength $split]-1]} {$i>=0} {incr i -1} {
  100.         if [string match $x [join [lrange $split 0 $i] .]] {return 1}
  101.     }
  102.     return 0
  103. }
  104.  
  105. # get domainname.  Unfortunately, on some systems, domainname(1)
  106. # returns NIS domainname which is not the internet domainname.
  107. proc domainname {} {
  108.     # open pops stack upon failure
  109.     set rc [catch {open /etc/resolve.conf r} file]
  110.     if {$rc==0} {
  111.         while {-1!=[gets $file buf]} {
  112.             if 1==[scan $buf "domain %s" name] {
  113.                 close $file
  114.                 return $name
  115.             }
  116.         }
  117.         close $file
  118.     }
  119.  
  120.     # fall back to using domainname
  121.     if {0==[catch {exec domainname} name]} {return $name}
  122.  
  123.     error "could not figure out domainname"
  124. }
  125.  
  126. if $user_number==1 {
  127.     if $noproc==0 {
  128.         if [llength $argv]>1 {
  129.             set pid [eval spawn [lrange $argv 1 end]]
  130.         } else {
  131.             set pid [spawn $env(SHELL)]
  132.         }
  133.         set shell $spawn_id
  134.     }
  135.  
  136.     # is user2 remote?
  137.     regexp (\[^@\]*)@*(.*) $user ignore tmp host
  138.     set user $tmp
  139.     if ![string match $host ""] {
  140.         set h_rc [catch {exec hostname}    hostname]
  141.         set d_rc [catch domainname     domainname]
  142.  
  143.         if {![is_prefix $h_rc $host $hostname]
  144.          && ![is_prefix $d_rc $host $hostname.$domainname]} {
  145.             set user2_islocal 0
  146.         }
  147.     }
  148.  
  149.     if !$user2_islocal {
  150.         if $verbose {send_user "connecting to $host\n"}
  151.         spawn rlogin $host
  152.         set userin $spawn_id
  153.         set userout $spawn_id
  154.  
  155.         if [info exists env(EXPECT_PROMPT)] {
  156.             set prompt $env(EXPECT_PROMPT)
  157.         }
  158.  
  159.         set timeout 120
  160.         expect {
  161.             assword: {
  162.                 system stty -echo
  163.                 send_user "password (for [exec whoami]) on $host: "
  164.                 set old_timeout $timeout; set timeout -1
  165.                 expect_user -re "(.*)\n"
  166.                 send_user "\n"
  167.                 set timeout $old_timeout
  168.                 send "$expect_out(1,string)\r"
  169.                 # bother resetting echo?
  170.                 continue -expect
  171.             } incorrect* {
  172.                 send_user "invalid password or account\n"
  173.                 exit
  174.             } timeout {
  175.                 send_user "connection to $host timed out\n"
  176.                 exit
  177.             } eof {
  178.                 send_user "connection to host failed: $expect_out(buffer)"
  179.                 exit
  180.             } -re $prompt
  181.         }
  182.         if $verbose {send_user "starting kibitz on $host\n"}
  183.         # the kill protects user1 from receiving user3's
  184.         # prompt if user2 exits via expect's exit.
  185.         send "kibitz -r $user;kill -9 $$\r"
  186.  
  187.         expect {
  188.             -re "kibitz -r $user.*KRUN" {}
  189.             -re "kibitz -r $user.*(kibitz\[^\r\]*)\r" {
  190.                 send_user "unable to start kibitz on $host: \"$expect_out(1,string)\"\n"
  191.                 send_user "try rlogin by hand followed by \"kibitz $user\"\n"
  192.                 exit
  193.             }
  194.             timeout {
  195.                 send_user "unable to start kibitz on $host: "
  196.                 set expect_out(buffer) "timed out"
  197.                 set timeout 0; expect -re .+
  198.                 send_user $expect_out(buffer)
  199.                 exit
  200.             }
  201.         }
  202.         expect {
  203.             -re ".*\n" {
  204.                 # pass back diagnostics
  205.                 # should really strip out extra cr
  206.                 send_user $expect_out(buffer)
  207.                 continue -expect
  208.             }
  209.             KABORT exit
  210.             default exit
  211.             KDATA
  212.         }
  213.     }
  214. }
  215.  
  216. if $user_number==2 {
  217.     set pid [string trimleft $user -]
  218. }
  219.  
  220. set local_io [expr ($user_number==3)||$user2_islocal]
  221. if $local_io||($user_number==2) {
  222.     if 0==[info exists pid] {set pid [getpid]}
  223.  
  224.     set userinfile /tmp/exp0.$pid
  225.     set useroutfile /tmp/exp1.$pid
  226. }
  227.  
  228. proc prompt1 {} {
  229.     return "kibitz[info level].[history nextid]> "
  230. }
  231.  
  232. if {$allow_escape} {
  233.     expect_before -i $user_spawn_id $escape_char {
  234.     send_user "\nto exit kibitz, enter: exit\n"
  235.     send_user "to suspend kibitz, press appropriate job control sequence\n"
  236.     send_user "to return to kibitzing, enter: return\n"
  237.     interpreter
  238.     send_user "returning to kibitz\n"
  239.     continue -expect
  240.     }
  241.  
  242.     proc prompt1 {} {
  243.     return "kibitz[info level].[history nextid]> "
  244.     }
  245. }
  246.  
  247. set timeout -1
  248.  
  249. # kibitzer executes following code
  250. if $user_number==2 {
  251.     # for readability, swap variables
  252.     set tmp $userinfile
  253.     set userinfile $useroutfile
  254.     set useroutfile $tmp
  255.  
  256.     if ![file readable $userinfile] {
  257.         send_user "Eh?  No one is asking you to kibitz.\n"
  258.         exit -1
  259.     }
  260.     spawn sh -c "stty raw; exec < $userinfile; exec cat $catflags"
  261.     set userin $spawn_id
  262.  
  263.     set userout [open $useroutfile w]
  264.     # open will hang until other user's cat starts
  265.  
  266.     system stty -echo raw
  267.     if $allow_escape {send_user "Escape sequence is $escape_printable\n"}
  268.  
  269.     # While user is reading message, try to delete other fifo
  270.     exec rm -f $userinfile
  271.  
  272.     expect {
  273.         -i $user_spawn_id -re .+ {
  274.             puts $userout $expect_out(buffer) nonewline
  275.             flush $userout
  276.             continue -expect
  277.         }
  278.         -i $userin -re .+ {
  279.             send_user -raw $expect_out(buffer)
  280.             continue -expect
  281.         }
  282.     }
  283.     exit
  284. }
  285.  
  286. # only user_numbers 1 and 3 execute remaining code
  287.  
  288. proc abort {} {
  289.     global user_number
  290.  
  291.     # KABORT tells user_number 1 that user_number 3 has run into problems
  292.     # and is exiting, and diagnostics have been returned already
  293.     if $user_number==3 {send_user KABORT}
  294.     exit
  295. }
  296.  
  297. if $local_io {
  298.     proc mkfifo {f} {
  299.     if 0==[catch {exec mknod $f p}] return
  300.     # some systems put mknod in wierd places
  301.     if 0==[catch {exec /usr/etc/mknod $f p}] return    ;# Sun
  302.     if 0==[catch {exec /etc/mknod $f p}] return    ;# AIX, Cray
  303.     send_user "Couldn't figure out how to make a fifo - where is mknod?\n"
  304.     abort
  305.     }
  306.  
  307.     proc rmfifos {} {
  308.     global userinfile useroutfile
  309.     exec rm -f $userinfile $useroutfile
  310.     }
  311.  
  312.     trap {rmfifos; exit} SIGINT
  313.  
  314.     # create 2 fifos to communicate with other user
  315.     mkfifo $userinfile
  316.     mkfifo $useroutfile
  317.     # make sure other user can access despite umask
  318.     exec chmod 666 $userinfile $useroutfile
  319.  
  320.     if $verbose {send_user "asking $user to type:  kibitz -$pid\n"}
  321.  
  322.     # can't use exec since write insists on being run from a tty!
  323.     set rc [catch {
  324.            system echo "Can we talk?  Run: \"kibitz -$pid\"" | \
  325.             /bin/write $user $tty
  326.         }
  327.     ]
  328.     if $rc {rmfifos;abort}
  329.  
  330.     set userout [open $useroutfile w]
  331.     # open will hang until other user's cat starts
  332.  
  333.     spawn sh -c "stty raw; exec < $userinfile; \
  334.                     rm $userinfile; exec cat $catflags"
  335. #    eval spawn cat $catflags $userinfile
  336.     set userin $spawn_id
  337. }
  338.  
  339. system stty -echo raw
  340.  
  341. if $user_number==3 {
  342.     send_user "KDATA"    ;# this tells user_number 1 to send data
  343.  
  344.     interact {
  345.         -output $userout
  346.         -input $userin -output $user_spawn_id -eof {
  347.             wait -i $userin
  348.             return -tcl
  349.         }
  350.     }
  351. } else {
  352.     if $allow_escape {send_user "Escape sequence is $escape_printable\n"}
  353.  
  354.     if $noproc {
  355.         expect {
  356.             -i $user_spawn_id -re .+ {
  357.                 if $local_io {
  358.                     puts $userout $expect_out(buffer) nonewline 
  359.                     flush $userout
  360.                 } else {
  361.                     send -i $userout $expect_out(buffer)
  362.                 }
  363.                 continue -expect
  364.             }
  365.  
  366.             -i $userin -re .+ {
  367.                 send_user -raw $expect_out(buffer)
  368.                 continue -expect
  369.             } eof {
  370.                 wait -i $userin
  371.             }
  372.         }
  373.     } else {
  374.         expect {
  375.             -i $user_spawn_id -re .+ {
  376.                 send -i $shell $expect_out(buffer)
  377.                 continue -expect
  378.             }
  379.  
  380.             -i $userin -re .+ {
  381.                 send -i $shell $expect_out(buffer)
  382.                 continue -expect
  383.             } eof {
  384.                 wait -i $userin
  385.                 close -i $shell
  386.             }
  387.  
  388.             -i $shell -re .+ {
  389.                 send_user -raw $expect_out(buffer)
  390.                 if $local_io {
  391.                    puts $userout $expect_out(buffer) nonewline 
  392.                    flush $userout
  393.                 } else {
  394.                    send -i $userout $expect_out(buffer)
  395.                 }
  396.                 continue -expect
  397.             }
  398.         }
  399.  
  400.         wait -i $shell
  401.     }
  402. }
  403.  
  404. if $local_io rmfifos
  405.