|Just another Perl shrine|
Re: Ssh and qxby afoken (Chancellor)
|on Mar 31, 2017 at 05:52 UTC||Need Help??|
Why no qx?
qx (and the equivalent ``) uses some heuristics to find out if the default shell needs to be invoked. For simple cases, like qx(foo bar baz), the shell is not needed. But when non-alphanumeric characters come into play, the entire string is passed to the default shell. And at that point, you can not win the game. The default shell is /bin/sh, and that's all you know. It may be a symlink to /bin/bash, which currently has four major versions with different behavior. It may be ash or debian's fork, dash. It may be some csh, or something completely different. And of course, all of those possible shells have different parsing and quoting rules. Start at https://www.in-ulm.de/~mascheck/various/ if you want to get an impression of what traps you may find. And don't make me start complaining about command.com and cmd.exe.
So, you definitively want to avoid the shell. "Safe pipe opens" avoids the shell by avoiding the biggest problem - parsing a string into a program and number of arguments. The "safe pipe opens" receipe uses the list form of exec, completely bypassing all parsing. Of course, that requires that you pass a list to the function, not a string.
Another problem is the exit status guessing. For openssh, the exit status is defined in one simple sentence:
ssh exits with the exit status of the remote command or with 255 if an error occurred.
So, if you see an exit code of less than 255, ssh has returned the exit code of the remote program, any number between 0 and 254. If you see an exit code of 255, ssh may have run into trouble. Or it simply has returned the exit code of the remote command, which may also have been 255. That's not what your code does. Your code expects the remote program to exit with code 0. Several programs don't, like cmp, diff, and grep, to name just three.
Also, there is more than that. The exit status ($?) is more than the exit code. It also has a flag that indicates a core dump, and it returns the number of the signal - if any - that killed the process.
$! is something completely different, it is errno from the C library. It does not contain any information about ssh problems, but just tells you what went wrong if something went wrong when attempting to start ssh. So the names ssh_ret_code and ssh_ret_message are at best misleading. Note that $!, like errno, is NOT reset when a libc function was successful. Quite the opposite is true: errno and thus also $! contains garbage (old errors) if a function was successful.
Last, using qx in scalar context forces the user of your function to split the returned text into lines, wasting memory. qx supports list context, but your function doesn't.
So, some final words?
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)