Ubuntu – How to use `expect` with `zipcloak` II

expectUbuntu

This question is a followup on this question, as I figured out the solution I presented in the previous question does not work anymore. It worked sometime, but now expect does not work as expected. Here is the full code again:

#!/bin/bash
MYPWD="mypassword"

expect -c ' 
    spawn zipcloak test.upd
    expect "*Enter password*" 
    sleep 1
    send  "'"$MYPWD"'\r"
    sleep 1
    expect "*Verify password*" 
    sleep 1
    send  "'"$MYPWD"'\r"
    sleep 1
    '

This bash script does not encrypt the file test.upd, but creates files in my directory starting with "zi", like zi0gA1rU or zi8Vv6OD.

Why is that? What are those files? Why does the above script sometimes work, and sometimes it does not? Is there no way to make expect to behave as it should?

Where can I find the source code of zipcloak, so I can rewrite it to avoid using expect?

Additional information:

  • I have to execute this command as root, as the zipfile has root rights. Maybe that is important?

    zipcloak -v
    Copyright (c) 1990-2008 Info-ZIP – Type 'zipcloak "-L"' for software license.

    This is ZipCloak 3.0 (July 5th 2008), by Info-ZIP.
    Currently maintained by E. Gordon. Please send bug reports to
    the authors using the web page at www.info-zip.org; see README for details.

    Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip,
    as of above date; see http://www.info-zip.org/ for other sites.

    Compiled with gcc 4.6.1 for Unix (Linux ELF) on Jun 11 2011.

    ZipCloak special compilation options:
    [encryption, version 2.91 of 05 Jan 2007]

After it stopped working, I needed to set the last sleep to 2. Then it worked again. But later, this also did not work anymore. So I set the sleep to 5 seconds. For now, my script is working. But NOT reliable.

Debug output with exp_internal 1 set:

spawn /usr/bin/test.upd
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {28746}

expect: does "" (spawn_id exp6) match glob pattern "*Enter password*"? no
Enter password: 
expect: does "Enter password: " (spawn_id exp6) match glob pattern "*Enter password*"? yes
expect: set expect_out(0,string) "Enter password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "Enter password: "
send: sending "XXX\r" to { exp6 }

expect: does "" (spawn_id exp6) match glob pattern "*Verify password*"? no

Verify password: 
expect: does "\r\nVerify password: " (spawn_id exp6) match glob pattern "*Verify password*"? yes
expect: set expect_out(0,string) "\r\nVerify password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "\r\nVerify password: "
send: sending "XXX\r" to { exp6 }
argv[0] = expect  argv[1] = -c  argv[2] = 
    exp_internal 1
    spawn /usr/bin/zipcloak "test.upd"
    expect "*Enter password*"
    sleep 1
    send  "XXX\r"
    sleep 1
    expect "*Verify password*"
    sleep 1
    send  "XXX\r"
    sleep 1

set argc 0
set argv0 "expect"
set argv ""

Update: The output of the second script posted by glenn is:

spawn zipcloak test.upd
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {9956}
Gate keeper glob pattern for 'password: $' is 'password: '. Activating booster.

expect: does "" (spawn_id exp6) match regular expression "password: $"? Gate "password: "? gate=no
Enter password:
expect: does "Enter password: " (spawn_id exp6) match regular expression "password: $"? Gate "password: "? gate=yes re=yes
expect: set expect_out(0,string) "password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "Enter password: "
send: sending "mypassword\r" to { exp6 }
expect: continuing expect

expect: does "" (spawn_id exp6) match regular expression "password: $"? Gate "password: "? gate=no
mypassword

expect: does "mypassword\r\n" (spawn_id exp6) match regular expression "password: $"? Gate "password: "? gate=no
expect: timed out
argv[0] = expect  argv[1] = -c  argv[2] =
    exp_internal 1
    spawn zipcloak test.upd
    expect {
        -re {password: $} {send "mypassword\r"; exp_continue}
        eof
    }

set argc 0
set argv0 "expect"
set argv ""

Update

I actually want to specify the filename and the password on the commandline to call the code as

./myscript.sh test.upd pass

Here is the script:

#!/bin/bash
expect -c " 
    exp_internal 1
    spawn zipcloak \"$1\"
    expect {
        -re {password: \$} {send \"$2\r\"; exp_continue}
        expect eof
    }
"

However, it creates again a file starting with zi and does not encrypt the actual file. I had no idea that every little seemingly logic change could break the entire workflow of the expect script. Here is the ouput:

spawn zipcloak test.upd
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {16791}
Gate keeper glob pattern for 'password: $' is 'password: '. Activating booster.

expect: does "" (spawn_id exp6) match regular expression "password: $"? Gate "password: "? gate=no
"expect"? no
Enter password:
expect: does "Enter password: " (spawn_id exp6) match regular expression "password: $"? Gate "password: "? gate=yes re=yes
expect: set expect_out(0,string) "password: "
expect: set expect_out(spawn_id) "exp6"
expect: set expect_out(buffer) "Enter password: "
send: sending "pass\r" to { exp6 }
expect: continuing expect

expect: does "" (spawn_id exp6) match regular expression "password: $"? Gate "password: "? gate=no
"expect"? no
pass

expect: does "pass\r\n" (spawn_id exp6) match regular expression "password: $"? Gate "password: "? gate=no
"expect"? no
expect: timed out
argv[0] = expect  argv[1] = -c  argv[2] =
    exp_internal 1
    spawn zipcloak "test.upd"
    expect {
        -re {password: $} {send "pass\r"; exp_continue}
        expect eof
    }

set argc 0
set argv0 "expect"
set argv ""

Best Answer

I'd write that zipcloak-er as

#!/usr/bin/env expect
set zipfile [lindex $argv 0]
if {![file exists $zipfile]} {error "no such zipfile: $zipfile"}
set pass "mypassword"
spawn zipcloak $zipfile
expect {
    -re {password: $} {send "$pass\r"; exp_continue}
    eof
}

Since the "enter password: " and "verify password: " prompts have a common suffix, it makes sense to use exp_continue to reuse the code.


"does not work" is not helpful. Did you use exp_internal 1? Try this:

#!/bin/bash
MYPWD="mypassword"

expect -c " 
    exp_internal 1
    spawn zipcloak test.upd
    expect {
        -re {password: \$} {send \"$MYPWD\\r\"; exp_continue}
        eof
    }
"

Sorry Alex, I don't understand your issue. This is what happens for me in bash:

$ zip test.upd file
  adding: file (deflated 22%)
$ MYPWD="mypassword"
$ expect -c " 
    exp_internal 1
    spawn zipcloak test.upd
    expect {
        -re {password: \$} {send \"$MYPWD\\r\"; exp_continue}
        eof
    }
"
spawn zipcloak test.upd
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {27485}
Gate keeper glob pattern for 'password: $' is 'password: '. Activating booster.

expect: does "" (spawn_id exp4) match regular expression "password: $"? Gate "password: "? gate=no
Enter password: 
expect: does "Enter password: " (spawn_id exp4) match regular expression "password: $"? Gate "password: "? gate=yes re=yes
expect: set expect_out(0,string) "password: "
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "Enter password: "
send: sending "mypassword\r" to { exp4 }
expect: continuing expect

expect: does "" (spawn_id exp4) match regular expression "password: $"? Gate "password: "? gate=no

Verify password: 
expect: does "\r\nVerify password: " (spawn_id exp4) match regular expression "password: $"? Gate "password: "? gate=yes re=yes
expect: set expect_out(0,string) "password: "
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "\r\nVerify password: "
send: sending "mypassword\r" to { exp4 }
expect: continuing expect

expect: does "" (spawn_id exp4) match regular expression "password: $"? Gate "password: "? gate=no


expect: does "\r\n" (spawn_id exp4) match regular expression "password: $"? Gate "password: "? gate=no
encrypting: file

expect: does "\r\nencrypting: file\r\n" (spawn_id exp4) match regular expression "password: $"? Gate "password: "? gate=no
expect: read eof
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "\r\nencrypting: file\r\n"
argv[0] = expect  argv[1] = -c  argv[2] =  
    exp_internal 1
    spawn zipcloak test.upd
    expect {
        -re {password: $} {send "mypassword\r"; exp_continue}
        eof
    }

set argc 0
set argv0 "expect"
set argv ""
Related Question