-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathel_lib
executable file
·2817 lines (2487 loc) · 86.4 KB
/
el_lib
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env expect
##################################################################################
#
# Copyright (C) 2008-2010 Craig Miller
#
# Copyright (C) 2005-2007 Freescale Semiconductor, Inc.
#
# See the file "COPYING" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# Distributed under BSD-Style License
#
##################################################################################
#
#
# Expect-lite
# Script logs into Remote-host, sends command file, while validating commands
# fails if validation fails, returns code 1 (0=passed)
#
# by Craig Miller [email protected] 19 Jan 2005
#
# Command Arguments:
# <Remote-Host|IP>
# <command_file>
# <user_directory>
# [additional constants, see usage]
#
#
# Requires Expect version supported 5.42.1 and later (although earlier versions may work)
#
#
#
#
##################################################################################
#
# The user may want to customize the following variables & procs to suite one's needs
#
#
# echo version in usage
set version "4.0.3.d4-lib"
#set starting expect timeout
set timeout 10
# EL_LIBRARY when set, places expect-lite in library mode,
# used for TCL programming calling expect-lite functions directly
# see documentation for more info
# Normally, this would be UNSET (or commented out)
#set EL_LIBRARY 1
# infinite_loop protection - Max number of looping permitted
# Protects against infinite loops by decrementing this number
# when value is Zero, _el_buffer_search will return 'not found' (-1)
# typically this should be set in the range of 5000-10000
set _el_infinite_loop 5000
# hardcoded login values - only used for telnet, and ssh logins
set user "root"
set pass ""
# User is now used by ssh_key method as well. If user is blank then the default
# user will be used (the user running the script). However if $user is defined
# then ssh_key will use the following command: ssh $user@$host
set user ""
# Print Warnings to stdout (when set to 1 = TRUE, 0 = FALSE)
set WARN 1
# Print Info messages to stdout (when set to 1 = TRUE, 0 = FALSE)
set INFO 1
# Print Expect Info messages to stdout (when set to 1 = TRUE, 0 = FALSE)
set EXP_INFO 0
# Select remote shell to spawn after logging into remote host
set remote_shell "bash"
set remote_shell ""
# Delay (in ms) to wait for host in Not Expect, and Dynamic Var Capture
# 100 ms is a good value for a local LAN, 200 ms if running across high speed internet
set delay_wait_for_host 100
# connects to login host, and logs in as $USER
#
# Choose one login method here
#
#set connect_method "telnet"
#set connect_method "ssh"
#set connect_method "ssh_key"
set connect_method "none"
# Path to telnet (helps in cygwin environments)
set _el_telnet "/usr/bin/telnet"
# set the user configurable prompt to something sane
set _el(prompt) ".*\$ $"
# set global color for comment ; or ;; lines
# select one of the following: none, blue, ltblue, gray, ltgray, cyan, black, pink, purple
set _el_comment_color ltblue
# End of Line Sequence (eols) - typically \n or \r\n
# some devices must have a CRLF at the end of line in order to respond
# This is also controlled by directive *EOLS LF|CRLF
set _el_eols "\n"
####################################################################################
#
# Vars & Procs below here should not require customization
#
#
#
# Initialization of Global Variables
#
#set _el_timeout to hold value of timeout (used to preserve value of timeout)
set _el_timeout $timeout
#Set the expect Match Buffer really large
match_max -d 10000
#Create Debug Log output == 1, no log ==0
set DEBUG_LOG 0
# declare array user_namespace (for user vars)
set user_namespace(0) 0
# declare array cli_namespace (for cli passed constants)
set cli_namespace(#) " "
# declare global array _el (for internal expect-lite vars)
set _el(0) 0
# clear NOFAIL flag 1=test should have failed
set _el(test_failed) 0
# clear native expect lines list
set _el(_el_lines) {}
# debugging aid: turn on to display match string and expect buffer
set DEBUG 0
# keep script running to end: turn on to never fail test
set NOFAIL 0
# global constant for timeout_multiplier mode
set timeout_multiplier "timeout_multiplier"
# global constant for script name aka arg0
set arg0 "arg0"
# set global fork count (for multiple sessions) to 0
set _el_fork(count) 0
# set global fork stack to blank
set _el_fork_stack {}
# set global fork id list to blank
set _el_fork_id_list { default }
# set default FORK session
set _el_fork(current) "default"
# set global fork_context array to blank
set _el_fork_context(default,eols) $_el_eols
#
# Scripts (aka Command files) are kept in buffers for random access, and looping
# Buffers are global, and are referenced by a "stack" number, the stack number allows multiple buffers to exist
#
# stack which contains list of valid buffers
set _el_buf(stack) "0"
# buf pointer - contains line number of buffer
set _el_buf(0,ptr) "0"
# expect-lite key characters (first char in expect-lite script)
set _out ">"
set _out_nowait ">>"
set _in "<"
set _in_noregex "<<"
set _not_in "-<"
set _timeout "@"
set _exec "!"
set _stdout_comment ";"
set _stdout_comment_nobuf ";;"
set _include "~"
set _include_fail "\\\*~"
set _setvar "+"
set _var "\$"
set _cond_regex "\\\?"
set _cond "?"
set _cond_else "::"
set _label "%"
set _incr_var "\\\+\\\$"
set _decr_var "\\-\\\$"
# cli Parameter Initialization
set remote_host "none"
set cmd_file ""
set user_dir ""
# set the default user configurable prompt to something sane
set _el(default_prompt) ".*\$ $"
# set ANSI colors for colored output
set el_color(red) "\033\[1;31m"
set el_color(blue) "\033\[0;34m"
set el_color(ltblue) "\033\[1;34m"
set el_color(black) "\033\[0;30m"
set el_color(cyan) "\033\[0;36m"
set el_color(gray) "\033\[1;30m"
set el_color(ltgray) "\033\[0;37m"
set el_color(green) "\033\[0;32m"
set el_color(yellow) "\033\[0;33m"
set el_color(purple) "\033\[0;35m"
set el_color(pink) "\033\[1;35m"
set el_color(nocolor) "\033\[0m"
set el_color(none) ""
# set INFO color
set el_info_color green
# set WARN color
set el_warn_color yellow
# set ERROR color
set el_err_color red
#
# Removes colour if terminal type is not xterm, vt100, cygwin
#
#
proc check_term_type { } {
global _el_comment_color el_color env el_info_color el_warn_color el_err_color
#disable global comment color if unknown
if { [lsearch [array names el_color] $_el_comment_color] == -1 } {
set _el_comment_color none
}
if { [catch { switch -glob -- $env(TERM) {
"xterm" -
"xterm-color" -
"vt100" -
"vt220" -
"ansi" -
"cygwin" {
# keep colors as set globally
}
default {
# set INFO color
set el_info_color none
# set WARN color
set el_warn_color none
# set ERROR color
set el_err_color none
# set global color
set _el_comment_color none
}
} } \
error ] } {
puts "Warning: No Terminal Type defined: $error"
# set INFO color
set el_info_color none
# set WARN color
set el_warn_color none
# set ERROR color
set el_err_color none
# set global color
set _el_comment_color none
}
}
#
# Wraps puts in selected global colour
#
#
proc cputs { str {l_color ""} } {
global _el_comment_color el_color
proc protect_puts { str } {
# catch stdout errors and quit
if { [catch { puts $str } error] } {
puts stderr "ERROR:$error"
exit 1
}
}
if {$_el_comment_color == "none"} {
# use no color
protect_puts $str
} elseif { $l_color != "" } {
# use supplied color
protect_puts "$el_color($l_color)$str$el_color(nocolor)"
} elseif {$_el_comment_color != "none"} {
# use global color
protect_puts "$el_color($_el_comment_color)$str$el_color(nocolor)"
}
}
#
# Expect Signal Handler, which checks for broken stdout pipe
# Default signal is SIGPIPE
#
#
trap {
catch { puts stderr "\nERROR:Broken Pipe\n" }
exit 2
} SIGPIPE
#
# Interact help
#
#
#
proc interact_help { } {
send_user "\n"
send_user "IDE: Help\n"
send_user " Key Action\n"
send_user " ---- ------\n"
send_user " <esc>s Step\n"
send_user " <esc>k sKip next step\n"
send_user " <esc>c Continue\n"
send_user " <esc>v show Vars\n"
send_user " <esc>0to9 Show N next lines of script\n"
send_user " <esc>-1to-9 Show N previous lines of script\n"
send_user " ctrl+D Quit & Exit expect-lite\n"
send_user " <esc>h this Help\n"
#send_user "\n"
return
}
#
# Expect Signal Handler, which places user into instant-interactive(tm) session
# Default signal is SIGQUIT or ^\
#
#
trap {
instant_interact_sig
} SIGQUIT
#
#
# Actual Signal Handler, which places user into instant-interactive(tm) session
# Default signal is SIGQUIT or ^\
# This function is also called by *INTERACT, providing similar functionality
#
proc instant_interact_sig {} {
global remote_host _el _el_fork_id_list _el_fork DEBUG NOFAIL el_info_color _el_eols _el_buf expect_out el_warn_color
# change user message depending on how the function is called
if { $_el(line) != "*INTERACT" } {
# called by user
cputs "\n\n Press '+++' to end instant-interact & return to script \n\n" $el_info_color
} else {
# called by script *INTERACT
cputs "\n\n Press '+++' to end interact session & return to script \n\n" $el_info_color
}
# do not allow script to fail during IDE
incr NOFAIL
protected_send "$_el_eols"
# preserve script fork session
push_session_id $_el_fork(current)
set restart_interact 1
# restart interact if *FORK is called to set to new spawn_id
while {$restart_interact} {
# Interact session connects user to remote session, and also:
# interprets *FORK, *SHOW commands
# Experimental: also interprets subset of expect-lite script commands
# Lines starting with >,?,$,~,;,*
# send, if, var assignment, include file, comment, directives respectively
if { [catch { interact {
-re {\+\+\+|^\x1b\x63|^`c} { #DEBUGGER '+++' or .c to exit interact session, continue script
set restart_interact 0
return
}
\004 { # ^D exit interact and expect-lite
puts "\nExiting interact & expect-lite.\n"
exit
}
-reset \005 { # test
_el_script_exec "\|>> pwd"
_el_script_exec "\|+\$P=\n/home/(\[a-z\]+)"
#exit
}
-re {(^\x1b|`)(s|k)} { #DEBUGGER .s=Next Step, k=skip step
# determine next or skip step
set param "s" ; # set default to step
catch { set param "$interact_out(2,string)" } error
# increment buffer line pointer
incr _el_buf($_el_buf(stack),ptr)
# read line from buffer
set line [ _el_buffer_read $_el_buf($_el_buf(stack),ptr) $_el_buf(stack) ]
#puts "==BUF====>$_el_buf($_el_buf(stack),ptr)||$line\n"
switch -regexp -- $line {
{^\*INT} {
# skip interact lines
cputs "$line" $el_info_color
protected_send "$_el_eols"
}
^\! { # Send prompt after native expect lines
if { $param == "k" } {
cputs "Skipping:$line" $el_info_color
protected_send "$_el_eols"
} else {
cputs "$line" $el_info_color
_el_script_exec "\|$line" $_el_buf(stack)
# kick the prompt
protected_send "$_el_eols"
}
}
^\> { # send line out and clump any following lines with < or +$
# clear clump list
set cli_list ""
# add lines to clump
while {$line!=-1} {
lappend cli_list $line
incr _el_buf($_el_buf(stack),ptr)
# read line from buffer
set line [ _el_buffer_read $_el_buf($_el_buf(stack),ptr) $_el_buf(stack) ]
#puts "===L==>$line"
# is line part of clump: expect, dynvar, not-expect
if {[regexp {^\<|^\+\$|^\-\<} $line] == 0} {
#No more clump, roll back pointer
incr _el_buf($_el_buf(stack),ptr) -1
set line -1
}
}
# send clump to _el_script_exec
#send_user "=====>$cli_list||$_el_buf(stack)"
foreach item $cli_list {
if { $item != "" } {
if { $param == "k" } {
cputs "Skipping:$item" $el_info_color
protected_send "$_el_eols"
} else {
# execute next step
cputs "$item" $el_info_color
_el_script_exec "\|$item" $_el_buf(stack)
#_el_script_exec "\|$item"
}
}
}
# end clump send
}
^\~ { # include a file
if { $param == "k" } {
cputs "Skipping:$line" $el_info_color
protected_send "$_el_eols"
} else {
cputs "$line" $el_info_color
# kick the prompt
protected_send "$_el_eols"
_el_script_exec "\|$line"
}
}
"-1" {
cputs "End of File" $el_warn_color
}
default {
if { $param == "k" } {
cputs "Skipping:$line" $el_info_color
protected_send "$_el_eols"
} else {
cputs "$line" $el_info_color
_el_script_exec "\|$line" $_el_buf(stack)
if {$_el(test_failed) == 1 } {
# step failed? kick the prompt
protected_send "$_el_eols"
}
}
}
}
}
-re {^(\x1b|`)([-]?[0-9])} { #DEBUGGER .-1to9 Show next or last 1-9 lines
# .1to9 or .-1to9
#send_user "=====>[scan $interact_out(0,string) %c]|$interact_out(0,string)"
#catch { set param "$interact_out(1,string)" } error
catch { set param "$interact_out(2,string)" } error
_el_buffer_show $param $_el_buf(stack)
protected_send "$_el_eols"
}
-re {^\x1bv|`v} { #DEBUGGER .v Show Vars
show_vars
protected_send "$_el_eols"
}
-re {\x1bh|`h} { #DEBUGGER .h Show help
interact_help
protected_send "$_el_eols"
}
-echo -re {(^>[a-zA-Z0-9/$.]|^\?[iI][fF]|^\$[a-zA-Z0-9]|^~[a-zA-Z0-9]|^;|^\*[A-Z]|^\+\$|^=\$|%[A-Z])(.+)\r} {
#### Support for EL commands in Interact
#### Permits pasting of multiple commands into Interact session
# create list of multiple pasted commands
set cli_list [split $interact_out(0,string) "\r"]
# OS identification - .dll or "" = Cygwin, .so=Linux, .dylib=MacOS X
set os_id [info sharedlibextension]
if { $os_id == ".dll" || $os_id == "" } {
# Special expect to pick up Cygwin Pasted lines, which come one at a time
while 1 {
expect_user {
-re {(.+)\r} {
# strip newlines and add to cli_list
regsub {\n|\r|\r\n} $expect_out(1,string) "" cli_item
lappend cli_list $cli_item
}
-timeout 1 timeout { break }
-re \003 {puts "\nAck!\n"; exit 1}
}
}
# end while
}
#end if os_id
# clear line of pasted text
send_user " \r"
if {$DEBUG} {
send_user "\nDEBUG: Evaluating:\n"
foreach d_item $cli_list {
send_user "\t$d_item\n"
}
}
#send_user "\n=====>$cli_list\n"
foreach item $cli_list {
#send_user "===I==>$item\n"
if { $item != "" } {
# call _el_script_exe in 'one-line' mode
# add buf_stack context to allow jumping to labels
_el_script_exec "\|$item" $_el_buf(stack)
}
}
protected_send "$_el_eols"
return
}
} } \
error] } {
puts stderr "CONNECT ERROR: lost connection to $remote_host \n $error"
# Fail script?
exit 1
}
protected_send "$_el_eols"
}
# restore script session
session_id_manager [ pop_session_id ]
set _el(success) 1
protected_send "$_el_eols"
# restore NOFAIL
incr NOFAIL -1
}
#
# Prompts are always a problem, this should _not_ require customization with the
# addition of User Defined Prompts '*/some_regex/' as of version 3.1.5
# These prompt regexs are setup to take just about any non-color prompt: >#%$
#
#
proc wait_for_prompt { } {
global timeout WARN _el DEBUG expect_out el_warn_color
#Accept '>' '#' '%' or '$' prompt
if { $timeout == 0 } {
# delay in ms
after 50
}
set TIMEOUT_RETURN 0
# User Defined prompt is $_el(prompt)
if {[catch { expect {
-re "$_el(prompt)" { }
-re ".*> $" { }
-re ".*# $" { }
-re ".*% $" { }
-re {.*\$ $} { }
timeout {
if {$WARN} { cputs "Warning:Prompt Timed Out!" $el_warn_color}
set TIMEOUT_RETURN 1
# is user defined prompt being used?
if { $_el(default_prompt) != $_el(prompt)} {
if {$DEBUG} {
# gobble as much return text as possible
expect -notransfer -re ".*\n+" { }
# print out debug info to help user
puts "DEBUG: User Defined Prompt:<<$_el(prompt)>>"
puts " Not Found in<<$expect_out(buffer)>>"
}
}
} } } \
error ] } {
puts "\nERROR: $error: Bad User Defined Prompt: $_el(prompt)"
# Quit expect-lite
exit 1
}
if {$TIMEOUT_RETURN} { return 1 } else { return 0 }
}
#
# Print Usage
#
#
proc usage {} {
global version
# puts "usage: expect-lite remote_host=<remote_host_IP> cmd_file=<command_file> \[user_dir=<user_dir>\] \[const1=value1\]"
puts "usage: expect-lite -c <command_file> \[ -r <remote_host_IP>\] \[-d <user_dir>\] \\ "
puts " \[const1=value1\] \[*DIRECTIVE\]"
puts " or: expect-lite c=<command_file> r=<remote_host_IP> \[d=<user_dir>\] \\ "
puts " \[const1=value1\] \[*DIRECTIVE\]"
puts " eg. ./expect-lite -c pm_alt.elt -r host8 -d /home/sw myvar=myvalue *NOFAIL"
puts " "
puts " additional login options: user_name=<username> user_password=<password>"
puts " eg. ./expect-lite c=pm_alternation.elt r=host-008 u=superuser p=mysecret"
puts " "
puts " additional logging options: -V|-v|-vv|--verbose"
puts " -V prints \'expected\' lines (i.e lines beginning with < & << )"
puts " -v prints warnings, and infos (i.e. conditionals, "
puts " dynamic var assignments)"
puts " -vv|--verbose prints warnings and debug (i.e. expect match info) "
puts " eg. ./expect-lite -vv r=host8 c=pm_alt.elt "
puts " "
puts "If set, the following environment variables will be used: "
puts " EL_REMOTE_HOST remote host to connect, default=none"
puts " EL_CMD_FILE name of expect-lite script"
puts " EL_USER_DIR change to this dir upon login"
puts " EL_CONNECT_METHOD telnet|ssh|ssh_key|none"
puts " EL_CONNECT_USER username for telnet|ssh"
puts " EL_CONNECT_PASS password for telnet|ssh"
puts " EL_DELAY_WAIT_FOR_HOST default=100"
puts " EL_* user defined constants"
puts " "
puts " Version $version by Craig Miller"
exit 0
}
#
# Takes full command path+file, and returns just the file name minus path
#
#
proc parse_cmd_file_nopath { cmd_file } {
# Is there a path component?
if {[regexp {/} $cmd_file] == 1 } {
set temp_list [split $cmd_file '/']
set len [expr [llength $temp_list] - 1 ]
return [lindex $temp_list $len]
} else {
return $cmd_file
}
}
#
# Assign cli arguments to the variable names
# Requires that $remote_host and $cmd_file are passed in via cli or
# that shell enviroment vars be set prior to running
# EL_REMOTE_HOST
# EL_CMD_FILE
# EL_USER_DIR
# EL_CONNECT_METHOD
# EL_CONNECT_USER
# EL_CONNECT_PASS
# EL_DELAY_WAIT_FOR_HOST
#
proc _el_read_args { argc argv } {
global remote_host cmd_file user_dir env connect_method user pass delay_wait_for_host
global cli_namespace timeout_multiplier arg0 WARN DEBUG EXP_INFO el_warn_color el_err_color
# default timeout_multiplier multiplier to 1
set cli_namespace($timeout_multiplier) 1
# If needed read parameters from Env Vars
catch { set remote_host $env(EL_REMOTE_HOST)}
if { $remote_host == "" } { set remote_host "none" }
if { $cmd_file=="" } { catch { set cmd_file $env(EL_CMD_FILE)} }
if { $user_dir=="" } { catch { set user_dir $env(EL_USER_DIR)} }
if { $user=="" } { catch { set user $env(EL_CONNECT_USER)} }
if { $pass=="" } { catch { set pass $env(EL_CONNECT_PASS)} }
if { [info exists env(EL_CONNECT_METHOD)] } { catch { set connect_method $env(EL_CONNECT_METHOD)} }
if { [regexp {none|telnet|ssh|ssh_key} $connect_method] == 0 } { set connect_method "none" }
if { [info exists env(EL_DELAY_WAIT_FOR_HOST)] } { catch { set delay_wait_for_host $env(EL_DELAY_WAIT_FOR_HOST)} }
if { $delay_wait_for_host == "" } { set delay_wait_for_host "100" }
# ensure arg list is separated by spaces
set argvstr [ join $argv ]
set argv [split $argvstr ]
set argc [ llength $argv ]
if { $argc >= 1 || $cmd_file!="" } {
# Walk thru additional args (should be cli constants)
for { set x 0 } { $x < $argc} { incr x } {
set optarg [ lindex $argv $x ]
catch {set optargval [ lindex $argv [expr $x + 1]]}
if { $optargval == "" } {
# no optargval, set to a sane value
set optargval "--"
}
#puts "=====>$x|$optarg|$optargval|"
# Make script executable: check if script name, no other argument or directive
# script name cannot have '=', which would be interpretted as a constant
if { [regexp {^[-*]|[=]} $optarg ] == 0 && [regexp {^[-*]|[=]} $optargval] == 1 } {
set cmd_file $optarg
set cli_namespace($arg0) [parse_cmd_file_nopath $cmd_file]
}
# look for help & debug options which overide script options
# added -r and -c for remote_host & cmd_file respectively
if { [catch { switch -glob -- $optarg {
-h -
--help { usage }
-v {set WARN 10; set INFO 10}
-vv -
--verbose {set WARN 10; set DEBUG 10}
-vvv {set WARN 0; set DEBUG 10}
-V -
--verify {set EXP_INFO 10; set INFO 10}
-r { set remote_host $optargval; incr x }
-c { set cmd_file $optargval; set cli_namespace($arg0) [parse_cmd_file_nopath $cmd_file] ; incr x }
-d { set user_dir $optargval; incr x }
-u { set user $optargval; incr x }
-p { set pass $optargval; incr x }
} } \
error ] } {
puts "Warning: Bad input option: $error"
}
#general vars
if [ regexp {.+=.*} $optarg ] {
# detect and parse args in format "var=value"
set user_var [string range $optarg 0 [expr [string first "=" $optarg] -1 ]]
set user_value [string range $optarg [expr [string first "=" $optarg] +1 ] [string length $optarg]]
#puts "->$user_var $user_value"
# populate required cli parameters and cli_constants
switch -glob -- $user_var {
remote_host -
r { set remote_host $user_value }
cmd_file -
c { set cmd_file $user_value
# set script constant arg0 with script name
set cli_namespace($arg0) [parse_cmd_file_nopath $cmd_file]
}
user_dir -
d {set user_dir $user_value }
user_name -
u {set user $user_value }
user_password -
p {set pass $user_value }
default {
set cli_namespace($user_var) $user_value
puts "Const: $user_var = $cli_namespace($user_var)"
}
}
}
#cli-based directives (in form *DIRECTIVE)
if [ regexp {\*[A-Z_]+} $optarg] {
_el_global_directive $optarg
}
}
#puts "->$remote_host|$cmd_file|$user_dir"
# check that require paremeters are present
if { $remote_host=="" } {
cputs "Error: Missing remote_host" $el_err_color
usage
}
if { $remote_host=="none" || $remote_host=="NONE" } {
if {$WARN} { cputs "Warning: Remote Host=none, using Localhost" $el_warn_color }
# don't use remote login method but use localhost
set connect_method "none"
}
if { $cmd_file=="" && [info exists ::EL_LIBRARY] != 1} {
cputs "Error: Missing cmd_file" $el_err_color
usage
}
}
# Assign any Environment Variables starting with 'EL_' to Constants
if { $DEBUG } {
puts "Env Vars -> Constants:"
}
foreach key [array names env] {
if {[regexp {^EL_} $key] == 1 } {
if { $DEBUG } {
puts "$key=$env($key)"
}
set cli_namespace($key) $env($key)
}
}
# show help if command file (script) is not given on command line
if { $argc < 1 && $cmd_file=="" } {
usage
}
}
#
# Takes full command path+file, and returns just the path to command file minus the filename
# This is used in including files
#
proc parse_cmd_file_path { cmd_file } {
# Is there a path component?
if {[regexp {/} $cmd_file] == 1 } {
set temp_list [split $cmd_file '/']
set len [expr [llength $temp_list] - 1 ]
regsub [lindex $temp_list $len] $cmd_file "" temp_path
return $temp_path
} else {
return ""
}
}
#
# Login Method which uses user and password via Telnet to log into hosts
# If this is not your access method use one of the other login methods
#
proc connect_telnet_host {remote_host {optional_suppress_stdout "no"}} {
global spawn_id user pass _el_timeout _el_telnet DEBUG
#This spawns the telnet program - auto generates spawn_id var
set timeout 5
if { ($optional_suppress_stdout == "suppress_stdout") && ($DEBUG != 1)} {
# turn off stdout - suppress login banners - show with -vv
log_user 0
}
if { [catch { spawn $_el_telnet $remote_host } error] } {
puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error"
# Fail script?
exit 1
}
#The script expects login
expect "ogin:"
#The script sends the user variable
if { [catch { send "$user\r" } error] } {
puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error"
# Fail script?
exit 1
}
#The script expects Password
expect "assword:"
#The script sends the password variable
# do not log password
set log_user 0
send "$pass\r"
set log_user 1
#wait_for_prompt
set timeout $_el_timeout
# turn on stdout
log_user 1
}
#
# Subroutine used by ssh user/password method
# If this is not your access method use one of the other login methods
#
proc zlogin { pass login_attempts } {
global remote_host _el_eols
set timeout 2
set MAXLOGINATTEMPT 10
#set login_attempts 0
while { $login_attempts < $MAXLOGINATTEMPT} {
#puts "loop: $login_attempts"
expect {
-re "assword:" {
# do not log password
set log_user 0
send "$pass$_el_eols"
set log_user 1
#puts "send pass"
}
-re "Are you sure you want to continue connecting" {
send "yes$_el_eols"
#zlogin $pass $login_attempts
}
-re "Last login" { return }
-re "Tomato" { return }
-re {.+\n} { #expect connected }
}
incr login_attempts
#puts "here"
}
if { $login_attempts >= $MAXLOGINATTEMPT} {
puts stderr "\nCONNECT ERROR:Unable to login to $remote_host \n "
exit 1
}
}
#
# Login Method which uses user and password via ssh to log into hosts
# If this is not your access method use one of the other login methods
#
proc connect_ssh_host {remote_host {optional_suppress_stdout "no"}} {
global spawn_id user pass _el_timeout DEBUG env
# work around for older versions of expect
#This spawns the ssh program - auto generates spawn_id var
#spawn ssh -l $user $remote_host
set timeout 15
if { $user == "" } {
# user username from environment
set user $env(USER)
}
# suppress stdout during login
if { ($optional_suppress_stdout == "suppress_stdout") && ($DEBUG != 1)} {
# turn off stdout - suppress login banners - show with -vv
log_user 0
}
if { [catch { spawn ssh -l $user $remote_host } error] } {
puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error"
# Fail script?
exit 1
}
# debug help
#exp_internal 1
set login_attempt 0
#better way of logging in (and catch any errors)
if { [ catch {zlogin $pass $login_attempt} error] } {
puts stderr "CONNECTION ERROR to $remote_host \n $error"
exit 1
}
# turn off the debugging
#exp_internal 0
set timeout $_el_timeout
# turn on stdout
log_user 1
}
#
# Login Method which assumes ssh keys are configured for login hosts
# If this is not your access method use one of the other login methods
#
proc connect_ssh_key_host {remote_host {optional_suppress_stdout "no"}} {
global spawn_id user pass _el_timeout DEBUG delay_wait_for_host _el_eols
# work around for older versions of expect
# Enable use of an alternet user for ssh_key method
# if $user is not blank, then use the alternet user
set timeout 30
if { $user != "" } {
set login_user "$user@"
} else {
set login_user ""
}
# suppress stdout during login
if { ($optional_suppress_stdout == "suppress_stdout") && ($DEBUG != 1)} {
# turn off stdout - suppress login banners - show with -vv
log_user 0
}
#This spawns the ssh program - auto generates spawn_id var
if { [catch { spawn ssh $login_user$remote_host } error] } {
puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error"
# Fail script?
exit 1
}
# TODO:Auto update ~/.ssh/known_hosts if needed
# Test the connection by sending a return
if { [catch { send "$_el_eols" } error] } {
puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n $error"
# Fail script?
exit 1
}
# allow time for remote banner (if present) to echo
#after [expr $delay_wait_for_host * 2]
# answer quetion if given, else take any response as "connected"
set timeout 5
expect {
-re "Are you sure you want to continue connecting" {
send "yes$_el_eols"
}
-re {.+} { #puts "expect-lite: Connected" }