my program created a script that executes sftp command using expect. The script should download a file from SFTP server. When the script is generated, my program call system command to run the script. The script should exit when an error is encountered. For example, if the password is wrong. How am I be able to get the error returned by sftp command?
Below is the code that generates and run the script:
downloadFileFromServer()
{
ofstream downloadScript;
string result, command;
downloadScript.open("/temp/download.sh");
downloadScript << "#!/usr/bin/expect -f \n";
downloadScript << "spawn sftp -P " + <port number> +
" " + <user name> +
"@" + <IP> + "\n";
downloadScript << "expect { \ntimeout {\nsend_user \"Permission denied\\n\"\nexit\n}\n}\n";
downloadScript << "send \"" + <password> + "\\n\"\n";
downloadScript << "expect \"sftp>\"""\n";
downloadScript << "send \"cd " + <source directory> + "\\n\"\n";
downloadScript << "expect \"sftp>\"""\n";
downloadScript << "send \"lcd " + <destination directory> + "\\n\"\n";
downloadScript << "expect \"sftp>\"""\n";
downloadScript << "send \"get " + <file name> + "\\n\"\n";
downloadScript << "expect \"sftp>\"""\n";
downloadScript << "send \"exit\\n\"\n";
downloadScript << "expect -exact \"$\"""\n";
downloadScript.close();
command = "chmod +x /temp/download.sh && /temp/download.sh";
system(command.c_str());
}
Below is the script created:
#!/usr/bin/expect -f
spawn sftp -P <port numner> <user name>@<IP>
expect "<user name>@<IP>'s password:"
expect {
timeout {
send_user "Permission denied\n"
exit
}
}
send "<password>\n"
expect "sftp>"
send "cd <source directory>\n"
expect "sftp>"
send "lcd <destination directory>\n"
expect "sftp>"
send "get <file name>\n"
expect "sftp>"
send "exit\n"
expect -exact "$"
I want my program to catch the "Permission denied" error.
All processes set a numeric exit code (0..255) when they end. Change the expect script so that you can distinguish between the script ending normally (when usually the exit code will be 0) and the explicit exit
after an error. Do this by adding a parameter to that line, eg:
...
send_user "Permission denied\n"
exit 77
...
You can recover this code in a C/C++ program with
int wstatus = system(command.c_str());
if (WIFEXITED(wstatus))
int exit_code = WEXITSTATUS(wstatus);
The wstatus
is formed of 2 parts, the exit code of the process, and a some flags giving information about whether the process ran or was interrupted and so on. Use the above macros to extract the information.
See man 3 exit
, man waitpid
.