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