blob: 3c418bed24683c81105dc1e001553b259df38754 [file] [log] [blame]
#!/usr/bin/expect
# Copyright 2000, 2001, 2004 by Paul Mattes.
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and that
# both that copyright notice and this permission notice appear in
# supporting documentation.
#
# s3270 is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the file LICENSE for more details.
#
# Based on cms_cmd.expect licenced as above, modifications generating
# zseries-console:
# (C) Copyright IBM Corp. 2004, 2005, 2006
# and released under the GNU Public License V2
#
# Read in the glue functions.
set lib [file dirname $argv0]
source "$lib/x3270_glue.expect"
set P "console-zseries"
if { [llength $argv] != 4 } {
puts stderr "Usage: $P <VM Userid> <VM Password> zseries <VM System>"
exit 1
}
set username [lindex $argv 0]
set password [lindex $argv 1]
set hostname [lindex $argv 3]
set command "ipllnx"
# Procedure to wait for a READ prompt from CMS or CP.
proc waitread {} {
Snap Save
while {[Snap Ascii [expr [Snap Rows]-1] [expr [Snap Cols]-17] 4]
!= "Read"} {
Snap Wait Output
}
}
# Procedure to check for the CMS "Ready" prompt.
# Returns its row number, or -1 for "MORE..." state, and leaves a screen with
# data to read in the Snap buffer.
proc cmd_done {} {
global verbose
Snap Save
while {1} {
if {[Snap Ascii [expr [Snap Rows]-1] [expr [Snap Cols]-20] 7]
== "More..."} {
if {$verbose} {puts "More..."}
return -1
}
set i [expr [Snap Rows]-2]
while {$i >= 0} {
set text [Snap Ascii $i 0 [Snap Cols]]
switch -regexp -- $text {
"Ready; T=.*" {return $i}
"Ready\(.*\); T=.*" {
error [Snap Ascii [expr $i-1] 0 \
[Snap Cols]]
}
"^ *\$" {}
"00: Please choose*" { return $i }
default {
if {$verbose} {
#puts "Incomplete $i '[string trimright $text]'"
}
set mylength [string length [string trimright $text]]
if { $mylength > 5 } {
if {[Snap Ascii $i [expr $mylength-6] 6] == "login:"} {
puts "Hohooooooooo login prompt found"
return $i
}
}
set i 0
}
}
incr i -1
}
Snap Wait Output
}
}
# Execute a command, return the output.
proc cms_cmd {text} {
global verbose
# Clear the screen.
Clear
# Send the command.
String "$text\n"
# 'first' is the row where the first line of output will appear. For
# the first screenful it's 1; after that it's 0.
set first 1
# r is the result.
set r {}
while {1} {
# Wait for a screenful.
set d [cmd_done]
# Dump out what's there.
set i $first
#set first 0
if {$d < 0} {set last [expr [Snap Rows]-2]} {set last $d}
while {$i <= $last} {
set r [linsert $r end [string trimright [Snap Ascii $i 0 [Snap Cols]]]]
incr i
}
if {$d >= 0} {
for {set n 0} {$n < [llength $r]} {incr n} {
puts [lindex $r $n]
}
break
}
# Clear the screen and go around again.
Clear
}
return $r
}
## Calculates how many lines are there in the s3270 screen buffer
proc find_last_line {} {
global debug
global verbose
Snap Save
if {$debug == 1} {
puts "v---"
foreach l [Snap Ascii] {
puts $l
}
puts "^---"
}
if {[Snap Ascii [expr [Snap Rows]-1] [expr [Snap Cols]-20] 7]
== "More..."} {
## To denote the console buffer is full
return -1
}
set i [expr [Snap Rows]-3]
while {$i >= 0} {
set text [Snap Ascii $i 0 [Snap Cols]]
switch -regexp -- $text {
"^ *\$" {
}
default {
return $i
}
}
incr i -1
}
## To denote the console buffer is empty
return -2
}
# Print the s3270 screen buffer
proc print_cons_buf {} {
##puts "<<output>>"
set output 0
while {1} {
# Grab the screen and clear it out.
Snap Save
Clear
set screen [Snap Ascii 0 0 [expr [Snap Rows]-3] [Snap Cols]]
# Find how many lines are populated and output those.
for {set last [llength $screen]} {$last >= 0} {incr last -1} {
switch -regexp -- [lindex $screen $last] {
"^ *\$" {
}
default {
break
}
}
}
##puts "last<$last>"
if {$last < 0} {
break
}
for {set line 0} {$line <= $last} {incr line} {
set output 1
puts -nonewline "\n[string trimright [lindex $screen $line]]"
}
}
##puts "output<$output>"
return $output
}
# Set 'verbose' to 1 to get debug output from the glue functions.
set verbose 1
set debug 0
proc note {m} {
global P
puts "$P: $m"
}
proc warn {m} {
global P
puts "$P: WARNING: $m"
}
proc winge {m} {
global P
puts "$P: MACHINE ERROR: reboot failed - $m"
}
note "Logging into the hosting VM system to restart the VM guest"
# Start s3270
Start
# Setverbose 1
# Connect to the host and wait for an input field.
Connect $hostname
Wait InputField
# Log in and wait for CP READ or VM READ mode.
note "logging in ... sending username"
String "$username\n"
# Wait for the input field, to proceed further. If timed out screen scrape
# the s3270 (error) message.
if {[catch {set ret_val [Wait 10 InputField]} err]} {
print_cons_buf
note "password never prompted"
exit 2
}
# Sometimes the input field is emitted before the output from the VMserver.
# Hence, after reading the input field wait for the output.
if {[catch {set ret_val [Wait 10 Output]} err]} {
print_cons_buf
note "No output seen even after the reading the InputFiled"
exit 2
}
if { [Ascii 2 0 19 ] == "Enter your password" } {
print_cons_buf
note "pasword prompted ..."
note "sending password ..."
String "$password\n"
} elseif { [Ascii 1 11 7] == "Already"} {
# If we can't log on, we're hosed.
Enter
print_cons_buf
warn "Already logged in. logging in here....."
String "logon $username here\n"
# Wait for the input field to proceed further
if {[catch {set ret_val [Wait 10 InputField]} err]} {
print_cons_buf
note "password never prompted"
exit 2
}
if { [Ascii 2 0 19 ] == "Enter your password"} {
print_cons_buf
note "sending password ..."
String "$password\n"
}
} elseif { [Ascii 1 20 19] == "not in CP directory" } {
print_cons_buf
note "'$username' is not a valid username"
exit 1
} else {
# Other unknown errors (firewall??)
print_cons_buf
warn "Unknown Error: Check the console log"
exit 1
}
if { [Ascii 1 11 23] == "PASSWORD NOT AUTHORIZED" } {
while {1} {
note "authorisation failure: PASSWORD NOT AUTHORIZED: holding ..."
after 5000
}
exit 1
} elseif { [Ascii 1 11 16] == "PASSWORD EXPIRED" } {
while {1} {
note "authorisation failure: PASSWORD EXPIRED: holding ..."
after 5000
}
note "Password expired"
exit 1
} {
note "Password authorized"
}
print_cons_buf
waitread
note "Connected to VM"
# If we're in CP mode, which means we disconnected last time, boot CMS.
if {[Ascii [expr [Rows]-1] [expr [Cols]-20] 2] == "Cp"} {
note "Starting CMS"
Clear
String "i cms\n"
String "no"
waitread
}
Snap save
set n [expr [Snap Rows]-2]
set first 1
while {$n >= $first} {
set lptext [Snap Ascii $first 0 [Snap Cols]]
set lplength [string length [string trimright $lptext]]
puts "$lptext "
incr first
}
# Enter an empty command to get a CMS prompt. If we don't do this, there will
# be a Ready prompt as the first line of output below.
Enter
cmd_done
note "Executing command $command"
cms_cmd $command
Clear
String "#cp term more 50 10\n"
set timeouts {1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 5}
set otimeout 0
set double 1
set cmdline {}
while {1} {
set ctimeout $otimeout
interact {
"" {
puts -nonewline "\b \b"
set cmdline [string range $cmdline 0 end-1]
flush stdout
}
"" {
puts -nonewline "\b \b"
set cmdline [string range $cmdline 0 end-1]
flush stdout
}
"\r" {
## When enter(alone) is pressesed, s3270 goes from
## "Running" to "Vm Read" mode. So, for actual one
## enter key press, two 'Enter'[a s3270 function] is
## required
String $cmdline
set cmdline {}
Enter
if {$double == 1} {
Enter
}
set double 1
print_cons_buf
if {$ctimeout != 0} {
set otimeout 0
return
}
}
-re "(.)" {
set char $interact_out(0,string)
puts -nonewline "$char"
set cmdline "$cmdline$char"
flush stdout
set double 0
if {$ctimeout != 0} {
set otimeout 0
return
}
}
timeout [lindex $timeouts $otimeout] {
## Read the console buffer and print it
##puts "<<timeout>>"
if {[print_cons_buf]} {
set otimeout 0
} elseif {$otimeout < 15} {
incr otimeout
}
#puts "TIMEOUT: $otimeout [lindex $timeouts $otimeout]"
return
}
}
}