summaryrefslogtreecommitdiffstats
path: root/bin/rivlogin.in
diff options
context:
space:
mode:
Diffstat (limited to 'bin/rivlogin.in')
-rw-r--r--bin/rivlogin.in1005
1 files changed, 1005 insertions, 0 deletions
diff --git a/bin/rivlogin.in b/bin/rivlogin.in
new file mode 100644
index 0000000..12554d5
--- /dev/null
+++ b/bin/rivlogin.in
@@ -0,0 +1,1005 @@
+#! @EXPECT_PATH@ --
+##
+## $Id: rivlogin.in,v 1.15 2004/01/11 05:39:15 heas Exp $
+##
+## Copyright (C) 1997-2004 by Terrapin Communications, Inc.
+## All rights reserved.
+##
+## This software may be freely copied, modified and redistributed
+## without fee for non-commerical purposes provided that this license
+## remains intact and unmodified with any RANCID distribution.
+##
+## There is no warranty or other guarantee of fitness of this software.
+## It is provided solely "as is". The author(s) disclaim(s) all
+## responsibility and liability with respect to this software's usage
+## or its effect upon hardware, computer systems, other software, or
+## anything else.
+##
+## Except where noted otherwise, rancid was written by and is maintained by
+## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz.
+##
+#
+# The login expect scripts were based on Erik Sherk's gwtn, by permission.
+#
+# rivlogin - Riverstone (and Enterasys SSR) login
+#
+# Based upon rscmd (see nmops.org)
+# rscmd - Riverstone Networks Automated login
+# by Mike MacFaden, Kiran Addepalli
+# Riverstone Networks, 2000
+#
+# Returned to the RANCID crowd by andrew fort
+
+# Global vars section
+
+# program diagnostics
+set verbose 0
+set success 1
+set config 0
+
+# in seconds to wait for data back from device
+set timeout 10
+set tempfile "/tmp/rivlogin.[exec date]"
+
+# cli command prompt
+set my_prompt ">"
+set enable_prompt "\#"
+
+set default_user ""
+set output_file ""
+set conf_prompt "*\(config\)# "
+set logging 0
+set config_mode 0
+
+# Password file for routers to access
+set password_file $env(HOME)/.cloginrc
+
+# If no -c or -s specified, just automate router login ala rsh
+set do_command 0
+set do_script 0
+set log_user 0
+
+# The default CLI mode to login to is "enable" mode
+set enable 1
+
+# The default is to look in the password file to find the passwords. This
+# tracks if we receive them on the command line.
+set do_passwd 1
+set do_enapasswd 1
+
+# cmd usage
+set usage "Error: Usage: $argv0 \[-noenable\] \
+\[-f cloginrc-file\] \[-c command\] \[-Evar=x\] \[-s script-file\] \
+\[-x command-file\] \[-t timeout\] \[-o output-file\] \
+router \[router...\]\n"
+
+# Procedures Section
+
+
+#
+# Sets Xterm title if interactive...if its an xterm and the user cares
+#
+
+proc label { host } {
+
+ global env
+
+ # if CLOGIN has an 'x' in it, don't set the xterm name/banner
+ if [info exists env(CLOGIN)] {
+ if {[string first "x" $env(CLOGIN)] != -1} { return }
+ }
+
+ if [info exists env(TERM)] {
+ if [regexp \^(xterm|vs) $env(TERM) ignore ] {
+ send_user "\033]1;[lindex [split $host "."] 0]\a"
+ send_user "\033]2;$host\a"
+ }
+ }
+}
+
+
+# This is a helper function to make the password file easier to
+# maintain.
+# NOTES: Using this the password file has the form:
+# add password sl* pete cow
+# add password at* steve
+# add password * hanky-pie
+
+proc add { var args } {
+
+ global $var
+ lappend $var $args
+}
+
+# Loads the password file. Note that as this file is tcl, and that
+# it is sourced, the user better know what to put in there, as it
+# could install more than just password info... I will assume however,
+# that a "bad guy" could just as easy put such code in the clogin
+# script, so I will leave .cloginrc as just an extention of that script
+
+proc source_password_file { } {
+
+ global env password_file read_password_file
+
+ if { [info exists read_password_file] } {
+ return 1
+ }
+
+ if { [info exists password_file] == 0 } {
+ set password_file $env(HOME)/.cloginrc
+ }
+
+ set read_password_file 1
+ file stat $password_file fileinfo
+
+ if { [expr ($fileinfo(mode) & 007)] != 0000 } {
+ puts "ERROR: $password_file must not be group or world readable and writable\n"
+ return 1
+ }
+
+ source $password_file
+}
+
+# pre: var is x, router is y
+# post: return routerr entry from database else null string
+
+proc find { var router } {
+
+ if {[ source_password_file ] == 0 } {
+ return {}
+ }
+
+ upvar $var list
+ if { [info exists list] } {
+ foreach line $list {
+ if { [string match [lindex $line 0] $router ] } {
+ return [lrange $line 1 end]
+ }
+ }
+ }
+ return {}
+}
+
+
+# pre: login completed ok
+# post: terminate login session by closing tcp connection
+
+proc auto_exit { } {
+
+ global telnet_id
+
+ if { $verbose == 1 } {
+ puts "DEBUG: auto_exit closing connection to pid $telnet_id\n"
+ }
+ close -i telnet_id
+}
+
+# perform login basic to a router
+# pre: args are valid, router is reachable via network
+# post: return 0 on successful login, else 1
+#
+# NOTE: a number of globals are setup: my_prompt, telnet_id are key
+# and paging of cli output is disabled
+
+proc login { router user userpswd passwd enapasswd } {
+
+ global login_array
+ global telnet_id
+ global expect_out
+ global spawn_id
+ global verbose
+ global config verbose my_prompt
+
+ if { $verbose == 1 } {
+ puts "DEBUG: login router = $router"
+ puts "DEBUG: login username = $user"
+ puts "DEBUG: login userpasswd = $userpswd"
+ puts "DEBUG: login passwd = $passwd"
+ puts "DEBUG: login enapasswd = $enapasswd"
+ }
+
+ spawn -noecho telnet $router
+ set telnet_id $spawn_id
+
+ if { $telnet_id == 0 } {
+ puts "ERROR: login: spawn telnet session failed.\n"
+ return 1
+ }
+
+ # wait for initial 'Press RETURN to...' response
+ sleep 0.3
+
+ expect "*"
+ send "\r"
+
+ # If password fails 3 times then expect again
+ set pass_attempt 0
+
+ expect {
+
+ -re ".*> " { }
+
+ "Password:" {
+ incr pass_attempt
+ send "$passwd\r"
+ exp_continue
+ }
+
+ "Username: " {
+
+ set pattempt 0
+
+ send "$user\r"
+ expect {
+
+ "Password: " {
+
+ incr pattempt
+ if {$pattempt == 1} {
+ send "$userpswd\r";
+ } else {
+ send "$enapasswd\r";
+ }
+ exp_continue
+ }
+
+ -re ".*> " { exp_continue;}
+ }
+ }
+
+ "%TELNETD-W-BADPASSWD" {
+ puts "ERROR: bad userid or password to telnet."
+ return 1
+ }
+ "%CONS-W-AUTH_PASSWD" {
+ exp_continue
+ }
+
+ "% Authentication failed." {
+ puts "ERROR: bad userid or password to telnet."
+ return 1
+ }
+
+
+ "Authentication Failed:" {
+ puts "ERROR: bad userid or password to radius/tacacs+"
+ return 1
+ }
+
+ "Connection closed *" {
+ if {$pass_attempt == 3} {
+ puts "ERROR: Maximum attempts for password reached. Check password. Exiting.";
+ puts $expect_out(0,string);
+ return 1
+ }
+ }
+
+ timeout {
+ puts "ERROR: Timeout on login. Exiting.";
+ return 1
+ }
+
+ eof {
+ puts "ERROR: device closed telnet connection during login"
+ return 1
+ }
+ }
+
+ # save my_prompt for later use
+ send "\r"
+ expect -re ".*> "
+ set abc "$expect_out(buffer)"
+ set my_prompt "[lindex $abc 0]"
+ regexp {(.*[^>])} $my_prompt my
+
+ return 0;
+}
+
+
+# pre: login completed ok
+# post: turn off paging of commands
+
+proc disable_cli_paging { } {
+ global my_prompt
+
+ send "cli set terminal rows 0\r"
+
+ expect {
+ "$my_prompt" {return 0 }
+ }
+ return 1
+}
+
+# pre: login returned 0, prompt at top level
+# post: turn off command completion return 0
+# on error, return 1
+
+proc disable_cmd_autocomplete { } {
+ global my_prompt
+
+ send "cli set command completion off\r"
+ expect {
+
+ $my_prompt { }
+
+ timeout {
+ puts "ERROR:disable_cmd_autocomplete(TIMEOUT)";
+ return 0;
+ }
+
+ }
+
+ return 0
+}
+
+# pre: login returned 0, do_enable returned 0, cli is in enable or config mode
+# post: issues logout cli to device, returns 0
+
+proc logout { prompt } {
+ global config_mode enable_prompt
+
+ # in case of not being at root cmd...
+ # verify top level prompt state, move to it if necessary
+
+ if { $config_mode == 1 } {
+
+ send "exit\r"
+
+ expect {
+ "Do you want*" {
+ send "no\r"
+ }
+
+ "$enable_prompt" { }
+
+ timeout { puts "ERROR: logout: timeout from config mode\n" }
+ eof { puts "ERROR: device dropped connection\n" }
+ }
+ set config_mode 0
+ }
+
+ send "logout\r"
+ expect {
+
+ "Are you sure*" {
+ send "yes\r"
+ return 0
+ }
+ }
+}
+
+# pre: current mode allows transition to enable mode
+# post: enable mode entered, my_prompt updated, return 0 else 1
+
+proc do_enable { enauser enapasswd userpswd } {
+ global expect_out verbose
+ global my_prompt enable_prompt
+ set enable_prompt [ string trimright $my_prompt ">" ]
+ set enable_prompt $enable_prompt\#
+
+ if { $verbose == 1 } {
+ puts "DEBUG: do_enable: my_prompt = $my_prompt ena_prompt = $enable_prompt"
+ }
+
+ send "enable\r"
+
+ expect {
+ Username: { send "$enauser\r"; exp_continue }
+ Password: { send "$userpswd\r"; exp_continue }
+
+ "$my_prompt" {
+ puts "ERROR: do_enable failed to gain enable mode."
+ return 1
+ }
+
+ "CONS-W-AUTH_PASSWD" { send "$enapasswd\r"; }
+
+ "$enable_prompt " { }
+ "%SYS-W-NOPASSWD*" { }
+
+ "Authentication Failed: Access Denied" {
+ puts "ERROR: Bad user or password for enable mode."
+ return 1
+ }
+ }
+
+ set my_prompt $enable_prompt
+ return 0
+}
+
+# pre: current mode allows transition to enable mode
+# post: enable mode entered, my_prompt updated, return 0 else 1
+
+proc do_configure { } {
+ global expect_out verbose config_mode
+ global my_prompt
+ set config_prompt [ string trimright $my_prompt "\#" ]
+ set config_prompt $config_prompt\(config\)\#
+
+ if { $verbose == 1 } {
+ puts "DEBUG: do_config: my_prompt = $my_prompt cfg_prompt = $config_prompt"
+ }
+
+ send "configure\r"
+ expect {
+ "$config_prompt " { }
+ "$my_prompt" {
+ }
+
+ eof { return 1}
+ timeout { return 1}
+ }
+
+ set config_mode 1
+ set my_prompt $config_prompt
+ return 0
+}
+
+# track sent/received from device to output_file
+# pre: outut_file is valid filename w/write access
+# post: logfile open, global var logging == 1, return 0 , else 1
+
+proc start_logfile { output_file } {
+ global logging
+
+ if { [ string length $output_file ] != 0 } {
+ set rc [ catch {
+ log_file -noappend $output_file
+ } errMsg ]
+
+ if { $rc != 0 } {
+ puts "ERROR: open file $output_file for write access failed. $errMsg\n"
+ return 1
+ }
+ set logging 1
+ }
+
+ return 0
+}
+
+proc run_commands { prompt cmdstring } {
+ global sendstring
+
+ set commands [split $cmdstring \;]
+ set num_commands [llength $cmdstring]
+
+ for {set i 0} {$i < $num_commands} { incr i} {
+ regsub -- {[ ]*([^\.]*)} [subst -nocommands [lindex $commands $i]] {\1} sendstring
+
+ if {[ run_single_command $prompt $sendstring ] == 1} {
+ puts "ERROR: command '$sendstring' not processed by device. Check previous error messages."
+ return 1
+ }
+ }
+ return 0
+}
+
+
+# Run commands given on the command line
+# pre: prompt is current system cli prompt, cmdstring is command to execute
+# post: return 0 on success else 1
+# NOTE: output from router ends up in output_file if specified
+# expect internal input buffer is reset to "" after each command
+
+proc run_single_command { prompt cmdstring } {
+ global verbose
+ set rc 0
+ set seen_prompt 0
+ set seen_timeout 0
+ set need_ays 0
+ set delay 0
+
+ if {$verbose == 1} {
+ puts "DEBUG: run_commands: prompt=$prompt \"$cmdstring\" "
+ }
+
+ # ays == "are you sure" - must send back yes
+ if { [string compare $cmdstring "save startup" ] == 0 } {
+ set need_ays 1
+ set delay 1
+ if {$verbose == 1} {
+ puts "DEBUG: save startup cmd seen, set need_ays = 1"
+ }
+ }
+
+ # TODO: add case for copy command to startup, also prompts for ok
+
+ # TODO: if we see config command: system set name note it
+ # if we see a save active, then update system prompts as well
+
+ send "$cmdstring\r"
+
+ if { $delay == 1} {
+ sleep 1
+ }
+
+ expect {
+
+ "%CLI-E-IVCMD*" {
+ puts "ERROR: run_commands(command rejected by device)\n"
+ set rc 1
+ }
+
+ "%CLI-E-FACUNKNWN*" {
+ puts "ERROR: run_commands(command rejected by device)\n"
+ set rc 1
+ }
+
+ "%SYS-I-ADDFAILED*" {
+ puts "ERROR: run_commands(command rejected by device)\n"
+ set rc 1
+ }
+ "%TFTP-E-REMOTE,*" {
+ puts "ERROR: run_commands(command rejected by device)\n"
+ set rc 1
+ }
+
+ "%SYS-E-PRIMARY_NO_SUCH_IMAGE*" {
+ puts "ERROR: run_commands(command rejected by device)\n"
+ set rc 1
+ }
+
+ "want to overwrite " {
+ send "yes\r"
+ if {$verbose == 1} {
+ puts "DEBUG: got overwrite question, set need_ays to 0"
+ }
+ set need_ays 0
+ }
+
+
+ "%CONFIG-E-DUPLICATE,*" {
+ }
+
+ "$prompt" {
+ if { $seen_prompt == 0 } {
+ set seen_prompt 1
+ }
+
+ if {$verbose == 1} {
+ puts "DEBUG: saw double prompt, exiting expect loop\n"
+ }
+
+ if { $need_ays == 1 } {
+ exp_continue
+ }
+ }
+
+ -re ".* More: m,<space> --- Quit: q --- One line: <return> ---" {
+ send "q"
+ exp_continue
+ }
+
+
+ timeout {
+ if {$verbose == 1} {
+ puts "DEBUG: timeout occured for the $seen_time time\n"
+ }
+
+ if { $seen_timeout == 0 } {
+ set seen_timeout 1
+ send "\r\r"
+ exp_continue
+ }
+
+ puts "ERROR:run_commands(TIMEOUT)"
+ set rc 1
+ }
+
+ eof {
+ puts "ERROR:run_commands(connection closed by device)\n"
+ set rc 1
+ }
+
+ "\n" { exp_continue }
+ }
+
+ # clear input buffer of any remaining data
+ expect "*"
+ return $rc
+}
+
+
+# pre: RSTONE_USER env var is set
+# post: update global "default_user" to this string
+
+proc init_userid { } {
+ global default_user
+
+ if {[ info exists env(RSTONE_USER) ] } {
+ set default_user $env(RSTONE_USER)
+ } else {
+ # This uses "id" which I think is portable. At least it has existed
+ # (without options) on all machines/OSes I've been on recently -
+ # unlike whoami or id -nu.
+ regexp {\(([^)]*)} [exec id] junk default_user
+ }
+}
+
+proc source_script_file { filename } {
+ global my_prompt
+
+ expect -re "$my_prompt" {}
+
+ source $filename
+
+}
+
+
+# pre: login completed ok, filename contains set of cli commands one per line
+# post: each command is extracted from filename and sent to device
+# return 0 on success, return 1 on error
+# NOTE: for scripts that begin with "configure", change the mode to configure
+# before executing the following commands
+
+proc process_script_file { filename } {
+
+ global my_prompt verbose
+ set rc 0
+ set ifile ""
+
+ set rc [ catch {
+ set ifile [ open $filename r]
+ } errMsg ]
+
+ if { $rc != 0 } {
+ puts "ERROR: process_script_file: open script file $filename for read access failed. $errMsg\n"
+ return 1
+ }
+
+ set line_cnt 0
+
+ while { [eof $ifile] != 1 } {
+
+ set bytes [ gets $ifile cmd ]
+ incr line_cnt
+
+ if { $bytes < 0 } {
+ break
+ } elseif { $bytes == 0 } {
+ continue
+ }
+
+ if { $verbose == 1 } {
+ puts "DEBUG: line:$line_cnt cmd = $cmd\n"
+ }
+
+ # skip comments in script files
+ if { [regexp "^\#" $cmd] != 1 } {
+
+ # puts "$cmd rc = [string compare $cmd "configure" ]\n"
+
+ if { [string compare $cmd "configure" ] == 0 } {
+
+ do_configure
+
+ } else {
+ if {[ run_commands $my_prompt $cmd ] == 1} {
+ puts "ERROR: line $line_cnt in $filename not processed by device. Check previous error msgs."
+ set rc 1
+ break
+ }
+ }
+ }
+ }
+
+ close $ifile
+ return $rc
+}
+
+
+
+# pre: filename is valid file
+# post: remove extended ascii sequences and other cruft
+# and prepend a header: rscmd: ip-addr : date
+# TODO: should watch all file commands more closely
+
+proc strip_log { filename router } {
+
+ global tempfile
+
+ set rc [ catch {
+ set ifile [ open $filename r]
+ } errMsg ]
+
+ if { $rc != 0 } {
+ puts "ERROR: strip_log: open script file $filename for read access failed. $errMsg\n"
+ return 1
+ }
+ set rc [ catch {
+ set ofile [ open $tempfile w]
+ } errMsg ]
+
+ if { $rc != 0 } {
+ puts "ERROR: strip_log: open temp file $tempfile for write access failed. $errMsg\n"
+ return 1
+ }
+
+ set nl 0
+
+ puts $ofile "rscmd: $router : [exec date]"
+
+ while { [eof $ifile] != 1 } {
+
+ set bytes [ gets $ifile cmd ]
+ if { $bytes <= 0 } {
+ break
+ }
+ incr nl
+ if { $nl <= 2 } {
+ continue
+ }
+
+ regsub -all -- "\r" $cmd "" newcmd
+ puts $ofile $newcmd
+ }
+
+ close $ifile
+ close $ofile
+ set rc 0
+ file copy -force $tempfile $filename
+ file delete $tempfile
+ return $rc
+}
+
+#
+# main section
+#
+
+
+if { $verbose == 1 } {
+ puts "\n\nrscmd: Version 1.1 started on [exec date]"
+ puts "[exec uname -a]"
+ puts "Expect Version: [exp_version]\n"
+}
+
+# send input like in a fast and consistent human style
+set send_human {.1 .3 1 .05 2}
+
+# initialize default_user variable
+init_userid
+
+# Parse Command Line
+
+for {set idx 0} {$idx < $argc} {incr idx} {
+
+ set arg [lindex $argv $idx]
+
+ switch -glob -- $arg {
+
+ -c* -
+ -C* {
+ if {! [ regexp .\[cC\](.+) $arg ignore command]} {
+ incr idx
+ set command [ lindex $argv $idx ]
+ }
+ set do_command 1
+ # Environment variable to pass to -s scripts
+ } -E*
+ {
+ if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]} {
+ set E$varname $varvalue
+ } else {
+ send_user "Error: invalid format for -E in $arg\n"
+ exit 1
+ }
+ # Expect script to run
+ } -s* -
+ -S* {
+ if {! [ regexp .\[sS\](.+) $arg ignore sfile]} {
+ incr idx
+ set sfile [ lindex $argv $idx ]
+ }
+
+ if { ! [ file exists $sfile ] } {
+ puts "ERROR: invalid argument script file \"$sfile\" does not exist.\n"
+ exit 1
+ }
+ if { ! [ file readable $sfile ] } {
+ puts "ERROR: invalid argument script file \"$sfile\" permissions disallow read access.\n"
+ exit 1
+ }
+
+ set do_script 1
+ # Command file
+ } -x* -
+ -X {
+ if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} {
+ incr idx
+ set cmd_file [ lindex $argv $idx ]
+ }
+ if [ catch {set cmd_fd [open $cmd_file r]} reason ] {
+ send_user "\nError: $reason\n"
+ exit 1
+ }
+ set cmd_text [read $cmd_fd]
+ close $cmd_fd
+ set command [join [split $cmd_text \n] \;]
+ set do_command 1
+ } -f* -
+ -F* {
+ if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
+ incr idx
+ set password_file [ lindex $argv $idx ]
+ }
+
+ } -o* -
+ -O* {
+ if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {
+ incr idx
+ set output_file [ lindex $argv $idx ]
+ if { $verbose == 1 } {
+ puts "DEBUG: output file: $output_file"
+ }
+ }
+
+ } -t* -
+ -T* {
+ incr idx
+ set timeout [ lindex $argv $idx ]
+
+ } -noenable {
+ set enable 0
+ } -* {
+ puts "ERROR:unkown argument passed: $arg\n"
+ puts $usage
+ exit 1
+
+ } default {
+ break
+ }
+ }
+}
+
+# Verify at least one router is specified
+#
+if { $idx == $argc } {
+ puts "\n$usage"
+ exit 1
+}
+
+# main loop
+
+foreach router [lrange $argv $idx end] {
+set router [string tolower $router]
+
+# Figure out passwords
+if {$verbose == 1} {
+ puts "DEBUG: do_passwd = $do_passwd\n"
+ puts "DEBUG: do_enablepasswd = $do_enapasswd\n"
+}
+
+if { $do_passwd || $do_enapasswd } {
+ set pswd [find password $router]
+ if { [llength $pswd] == 0 } {
+ puts "ERROR: - no password for $router in $password_file.\n"
+ exit 1
+ }
+ if { $do_enapasswd && [llength $pswd] < 2 } {
+ puts "ERROR: no enable password found for $router in $password_file."
+ exit 1
+ }
+
+ set passwd [join [lindex $pswd 0] ""]
+ set enapasswd [join [lindex $pswd 1] ""]
+}
+
+
+# Figure out user to login with if necessary
+
+if {[info exists username]} {
+ # command line username
+ set user $username
+} else {
+ set user [join [find user $router] ""]
+ if { "$user" == "" } { set user $default_user }
+}
+
+# Figure out username's password
+
+if {[info exists userpasswd]} {
+ # command line username
+ set userpswd $userpasswd
+} else {
+ set userpswd [join [find userpassword $router] ""]
+ if { "$userpswd" == "" } { set userpswd $passwd }
+}
+
+# Figure out enable username
+
+if {[info exists enausername]} {
+ # command line enausername
+ set enauser $enausername
+} else {
+ set enauser [join [find enauser $router] ""]
+ if { "$enauser" == "" } { set enauser $user }
+}
+
+# Login to the router, set my_prompt to router's cmd prompt
+
+if {[login $router $user $userpswd $passwd $enapasswd ]} {
+ if { $verbose == 1 } {
+ puts "DEBUG: login to $router failed\n"
+ }
+ exit 1
+}
+
+if {$verbose == 1 } {
+ puts "DEBUG: login completed ok\n"
+}
+
+if { $enable == 1 } {
+
+ if { [do_enable $enauser $enapasswd $userpswd] == 1} {
+ if { $verbose == 1 } {
+ puts "DEBUG: switch to enable mode on $router failed\n"
+ }
+ exit 1
+ }
+}
+
+# run in one of three modes
+
+if { $do_command } {
+
+ disable_cmd_autocomplete
+ disable_cli_paging
+
+ if {[ start_logfile $output_file] != 0 } {
+ exit 1
+ }
+
+ if {[ run_commands $my_prompt $command ]} {
+
+ log_file
+ exit 1
+
+ } else {
+
+ logout $my_prompt
+
+ }
+
+} elseif { $do_script } {
+
+ disable_cmd_autocomplete
+ disable_cli_paging
+
+ if {[ start_logfile $output_file] != 0 } {
+ exit 1
+ }
+
+ #if { [process_script_file $sfile] == 1} {
+# puts "DEBUG: logfile $output_file closed on error\n"
+# logout $my_prompt
+# exit 1
+# }
+
+ source_script_file $sfile
+
+ logout $my_prompt
+
+} else {
+
+ label $router
+ log_user 1
+
+ if {[ start_logfile $output_file] != 0 } {
+ exit 1
+ }
+ interact
+ log_file
+}
+
+if { $verbose == 1 } {
+ puts "DEBUG: exiting normally.\n"
+}
+
+if { $logging == 1} {
+ log_file
+ strip_log $output_file $router
+}
+}
+
+# puts "\n"
+exit 0