1# Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software 2# Foundation, Inc. 3# 4# This file is part of DejaGnu. 5# 6# DejaGnu is free software; you can redistribute it and/or modify it 7# under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# DejaGnu is distributed in the hope that it will be useful, but 12# WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14# General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with DejaGnu; if not, write to the Free Software Foundation, 18# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 20# This file was written by Bob Manson (manson@cygnus.com) 21 22# 23# Open a connection to the remote DOS host. 24# 25proc dos_open { dest args } { 26 global destbat_num 27 28 if ![info exists destbat_num] { 29 set destbat_num [pid] 30 } 31 if { [board_info $dest conninfo] == "" } { 32 global board_info 33 set name [board_info $dest name] 34 35 set board_info($name,conninfo) "b${destbat_num}.bat" 36 incr destbat_num 37 } 38 39 if [board_info $dest exists fileid] { 40 return [board_info $dest fileid] 41 } 42 43 verbose "doing a dos_open to $dest" 44 45 set shell_prompt [board_info $dest shell_prompt] 46 47 set shell_id [remote_raw_open $dest] 48 49 if { $shell_id == "" || $shell_id < 0 } { 50 return -1 51 } 52 53 if [board_info $dest exists init_command] { 54 remote_send $dest "[board_info $dest init_command]\n" 55 remote_expect $dest 10 { 56 -re "$shell_prompt" { } 57 default { 58 perror "failed connection to DOS on $dest." 59 return -1 60 } 61 } 62 } 63 64 if [board_info $dest exists ftp_directory] { 65 set dir [board_info $dest ftp_directory] 66 regsub -all "/" "$dir" "\\" dir 67 remote_send $dest "cd $dir\n" 68 remote_expect $dest 10 { 69 -re "$shell_prompt" { } 70 default { 71 perror "failed connection to DOS on $dest." 72 return -1 73 } 74 } 75 } 76 77 if [board_info $dest exists dos_dir] { 78 set dos_dir [board_info $dest dos_dir] 79 regsub -all "^(\[a-zA-Z]:).*$" "$dos_dir" "\\1" drive 80 regsub -all "^\[a-zA-Z]:" "$dos_dir" "" dos_dir 81 remote_send $dest "${drive}\n" 82 remote_expect $dest 10 { 83 -re "$shell_prompt" { } 84 default { 85 perror "failed connection to DOS on $dest." 86 return -1 87 } 88 } 89 remote_send $dest "cd $dos_dir\n" 90 remote_expect $dest 10 { 91 -re "$shell_prompt" { } 92 default { 93 perror "failed connection to DOS on $dest." 94 return -1 95 } 96 } 97 } 98 99 global target_alias 100 if [info exists target_alias] { 101 set talias $target_alias 102 } else { 103 set talias "foo-bar" 104 } 105 106 global board_info 107 if [board_info $dest exists name] { 108 set n [board_info $dest name] 109 } else { 110 set n $dest 111 } 112 set board_info($n,fileid) $shell_id 113 114 if [board_info $dest exists init_script] { 115 remote_exec $dest "[board_info $dest init_script] $talias" 116 } 117 118 verbose "Succeeded in connecting to DOS." 119 return $shell_id 120} 121 122# 123# Close the connection to the remote host. If we're telnetting there, we 124# need to exit the connection first (ataman telnetd gets confused otherwise). 125# 126proc dos_close { dest args } { 127 if [board_info $dest exists fileid] { 128 if { [board_info $dest connect] == "telnet" } { 129 remote_send $dest "exit\n" 130 sleep 2 131 } 132 return [remote_raw_close $dest] 133 } 134} 135 136proc dos_prep_command { dest cmdline } { 137 global board_info 138 139 set name [board_info $dest name] 140 set shell_id [remote_open "$dest"] 141 142 set localbat "/tmp/b[pid].bat" 143 set remotebat [board_info $dest conninfo] 144 145 verbose "opened" 146 if { $shell_id != "" && $shell_id >= 0 } { 147 set fileid [open "$localbat" "w"] 148 puts -nonewline $fileid "@echo off\r\n$cmdline\r\nif errorlevel 1 echo *** DOSEXIT code 1\r\nif not errorlevel 1 echo *** DOSEXIT code 0\r\n" 149 close $fileid 150 set result [remote_download $dest $localbat $remotebat] 151 } else { 152 set result "" 153 } 154 remote_file build delete $localbat 155 return $result 156} 157 158# 159# Run CMDLINE on DESTHOST. We handle two cases; one is where we're at 160# a DOS prompt, and the other is where we're in GDB. 161# We run CMDLINE by creating a batchfile, downloading it, and then 162# executing it; this handles the case where the commandline is too 163# long for command.com to deal with. 164# 165 166proc dos_exec { dest program pargs inp outp } { 167 set cmdline "$program $pargs" 168 169 set shell_prompt [board_info $dest shell_prompt] 170 171 if { $inp != "" } { 172 set inp [remote_download $dest $inp inpfile] 173 if { $inp != "" } { 174 set inp " < $inp" 175 } 176 } 177 178 if { $outp != "" } { 179 set outpf " > tempout" 180 } else { 181 set outpf "" 182 } 183 184 verbose "cmdline is $cmdline$inp." 2 185 186 # Make a DOS batch file; we use @echo off so we don't have to see 187 # the DOS command prompts and such. 188 for { set i 0 } { $i < 2 } { incr i } { 189 set exit_status -1 190 verbose "calling open" 191 set batfile [dos_prep_command $dest "$cmdline$inp$outpf"] 192 if { $batfile != "" } { 193 if { [dos_start_command $batfile $dest] == "" } { 194 # FIXME: The 300 below should be a parameter. 195 set result [remote_wait $dest 300] 196 set exit_status [lindex $result 0] 197 set output [lindex $result 1] 198 } 199 } 200 if { $exit_status >= 0 } { 201 if { $outp != "" } { 202 remote_upload $dest tempout $outp 203 remote_file $dest delete tempout 204 } 205 return [list $exit_status $output] 206 } 207 if { $exit_status != -2 } { 208 remote_close $dest 209 remote_reboot $dest 210 } 211 } 212 return [list -1 "program execution failed"] 213} 214 215# 216# Start CMDLINE executing on DEST. 217# There are two cases that we handle, one where we're at a DOS prompt 218# and the other is when the remote machine is running GDB. 219# 220 221proc dos_start_command { cmdline dest } { 222 set shell_prompt [board_info $dest shell_prompt] 223 set prefix "" 224 set ok 0 225 for { set i 0 } {$i <= 2 && ! $ok} { incr i } { 226 set shell_id [remote_open $dest] 227 if { $shell_id != "" && $shell_id > 0 } { 228 remote_send $dest "echo k\r" 229 remote_expect $dest 20 { 230 -re "\\(gdb\\)" { 231 set shell_prompt "\\(gdb\\)" 232 # gdb uses 'shell command'. 233 set prefix "shell " 234 set ok 1 235 } 236 -re "$shell_prompt" { 237 set ok 1 238 } 239 default { } 240 } 241 } 242 if { ! $ok } { 243 remote_close $dest 244 remote_reboot $dest 245 } 246 } 247 if { ! $ok } { 248 return "unable to start command" 249 } else { 250 remote_send $dest "${prefix}${cmdline}\n" 251 remote_expect $dest 2 { 252 -re "${cmdline}\[\r\n\]\[\r\n\]?" { } 253 timeout { } 254 } 255 return "" 256 } 257} 258 259# 260# Send STRING to DEST, translating all LFs to CRs first, and sending one 261# line at a time because of strangeness with telnet in some circumstances. 262# 263 264proc dos_send { dest string } { 265 verbose "Sending '$string' to $dest" 2 266 # Convert LFs to CRs, 'cause that is what DOS wants to see. 267 set first 1 268 set string [string trimright $string "\r\n"] 269 foreach line [split $string "\r\n"] { 270 if {$first} { 271 set first 0 272 } else { 273 # small delay between lines, to keep from 274 # overwhelming the stupid telnet server. 275 sleep 1.0 276 } 277 remote_raw_send $dest "$line\r" 278 } 279} 280 281# 282# Spawn PROGRAM on DEST, and return the spawn_id associated with the 283# connection; we can only spawn one command at a time. 284# 285 286proc dos_spawn { dest program args } { 287 verbose "running $program on $dest" 288 set remotebat [dos_prep_command $dest $program] 289 290 for { set x 0 } { $x < 3 } { incr x } { 291 if { [dos_start_command $remotebat $dest] == "" } { 292 return [board_info $dest fileid] 293 } 294 remote_close $dest 295 remote_reboot $dest 296 } 297 return -1 298} 299 300proc dos_wait { dest timeout } { 301 set output "" 302 set shell_prompt [board_info $dest shell_prompt] 303 set status 1 304 305 verbose "waiting in dos_wait" 306 remote_expect $dest $timeout { 307 -re "(.*)\[*\]\[*\]\[*\] DOSEXIT code (\[0-9\]+)\[\r\n\]\[\r\n\]?" { 308 verbose "got exit status" 309 append output $expect_out(1,string) 310 set status $expect_out(2,string) 311 exp_continue 312 } 313 314 -re "(.*)${shell_prompt}" { 315 append output $expect_out(1,string) 316 verbose "output from dos is:'$output'" 317 return [list $status $output] 318 } 319 320 -re "(.*)\\(gdb\\)" { 321 append output $expect_out(1,string) 322 return [list $status $output] 323 } 324 325 -re "In.*cygwin.*except" { 326 remote_close $dest 327 remote_reboot $dest 328 return [list -2 $output] 329 } 330 331 -re "\[\r\n\]+" { 332 # This is a bit obscure. We only want to put whole 333 # lines into the output string, because otherwise we 334 # might miss a prompt because we only got 1/2 of it the 335 # first time 'round. The other tricky bit is that 336 # expect_out(buffer) will contain everything before and including 337 # the matched pattern. 338 append output $expect_out(buffer) 339 exp_continue -continue_timer 340 } 341 342 timeout { 343 warning "timeout in dos_wait" 344 if { [dos_interrupt_job $dest] == "" } { 345 return [list 1 $output] 346 } 347 } 348 349 eof { 350 warning "got EOF from dos host." 351 } 352 } 353 354 remote_close $dest 355 356 return [list -1 $output] 357} 358 359proc dos_load { dest prog args } { 360 global dos_dll_loaded 361 set progargs "" 362 set inpfile "" 363 if { [llength $args] > 0 } { 364 set progargs [lindex $args 1] 365 } 366 if { [llength $args] > 1 } { 367 set inpfile [lindex $args 1] 368 } 369 if ![info exists dos_dll_loaded] { 370 if ![is_remote host] { 371 global target_alias 372 373 set comp [get_multilibs] 374 if [file exists "${comp}/winsup/new-cygwin1.dll"] { 375 set dll "${comp}/winsup/new-cygwin1.dll" 376 set dll_name "cygwin1.dll" 377 } elseif [file exists "${comp}/winsup/new-cygwin.dll"] { 378 set dll "${comp}/winsup/new-cygwin.dll" 379 set dll_name "cygwin.dll" 380 } elseif [file exists ${comp}/lib/cygwin1.dll] { 381 set dll "${comp}/lib/cygwin1.dll" 382 set dll_name "cygwin1.dll" 383 } elseif [file exists ${comp}/lib/cygwin.dll] { 384 set dll "${comp}/lib/cygwin.dll" 385 set dll_name "cygwin.dll" 386 } else { 387 error "couldn't find cygwin.dll:$comp" 388 return "fail" 389 } 390 remote_download $dest $dll $dll_name 391 } 392 set dos_dll_loaded 1 393 } 394 set remote_prog [remote_download $dest $prog "aout.exe"] 395 set result [remote_exec $dest $remote_prog $progargs $inpfile] 396 set status [lindex $result 0] 397 set output [lindex $result 1] 398 set status2 [check_for_board_status output] 399 if { $status2 >= 0 } { 400 set status $status2 401 } 402 if { $status != 0 } { 403 set status "fail" 404 } else { 405 set status "pass" 406 } 407 return [list $status $output] 408} 409 410proc dos_file { dest op args } { 411 switch $op { 412 delete { 413 foreach x $args { 414 remote_exec $dest "del" "$x" 415 } 416 return 417 418 } 419 default { 420 return [eval standard_file \{$dest\} \{$op\} $args] 421 } 422 } 423} 424 425# 426# Interrupt the current spawned command being run; the only tricky 427# part is that we have to handle the "Terminate batch job" prompt. 428# 429proc dos_interrupt_job { host } { 430 set shell_prompt [board_info $host shell_prompt] 431 432 remote_send $host "\003" 433 remote_expect $host 10 { 434 -re "Terminate batch job.*Y/N\[)\]\[?\] *$" { 435 remote_send $host "n\n" 436 exp_continue 437 } 438 -re "$shell_prompt" { 439 return "" 440 } 441 -re ">" { 442 remote_send $host "\n" 443 exp_continue 444 } 445 } 446 return "fail" 447} 448 449proc dos_copy_download { host localfile remotefile } { 450 remote_file build delete "[board_info $host local_dir]/$remotefile" 451 if [remote_file build exists $localfile] { 452 set result [remote_download build $localfile "[board_info $host local_dir]/$remotefile"] 453 if { $result != "" } { 454 remote_exec build "chmod" "a+rw $result" 455 return $remotefile 456 } 457 } else { 458 return "" 459 } 460} 461 462proc dos_copy_upload { host remotefile localfile } { 463 remote_file build delete $localfile 464 if [file exists "[board_info $host local_dir]/$remotefile"] { 465 set result [remote_download build "[board_info $host local_dir]/$remotefile" $localfile] 466 } else { 467 set result "" 468 } 469 if { $result != "" } { 470 remote_exec build "chmod" "a+rw $result" 471 return $result 472 } 473} 474 475proc dos_copy_file { dest op args } { 476 if { $op == "delete" } { 477 set file "[board_info $dest local_dir]/[lindex $args 0]" 478 remote_file build delete $file 479 } 480} 481 482set_board_info protocol "dos" 483set_board_info shell_prompt "(^|\[\r\n\])\[a-zA-Z\]:\[^\r\n\]*>\[ \t\]*$" 484set_board_info needs_status_wrapper 1 485