Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??
Regarding my use of $!, I only access it when the output is undefined, which I thought happened when something goes wrong with starting ssh. Is that not the case?

Yes, you are right, sorry. I initially misread your code (my brain just ignored the defined), but then I corrected that. Or so I thought, I forgot the $! part. The naming is still problematic, because it's not an ssh problem, it's a problem starting ssh.

I admit I never tested piped opens

Oh yes you did, implicitly in every `` and in every qx. "Unsafe" pipe opens are the more verbose variant of qx. I think you could replace qx with a function similar to this one:

sub inefficient_qx { my $cmd=shift; local *PIPE; open PIPE,"$cmd |" or die "Could not open pipe from $cmd"; # ^-- intentionally written using an old-style bareword handle +for ancient perls if (wantarray) { my @tmp=<PIPE>; close PIPE or die "Close pipe failed: $!"; return @tmp; } else { my $tmp=do { local $/=<PIPE> }; close PIPE or die "Close pipe failed: $!"; return $tmp; } }

The unsafe parts:

  • relying on the shell (or, to be more precise, one of a thousand different shells randomly installed as /bin/sh) to parse $cmd
  • not dropping permissions when running as root

"Safe pipe opens" drop privileges, that's the ($EUID, $EGID) = ($UID, $GID) part. And, "safe pipe opens" use the list form of exec, avoiding shell issues.

This was the only way (except for manually messing with pipes) to do it until perl 5.8.0 arrived. Perl 5.8.0 extends the three-argument-form of open (open $handle, $mode, $filename) to accept a list of command and arguments in place of $filename when $mode is either "-|" or "|-" (open $handle, $mode, @list). This way, you could get a moderately safe variant of qx, but unfortunately, if @list has exactly one element, perl starts guesswork with that one element:

> perl -E 'open my $pipe,"-|","pstree --ascii --arguments --long $$ 1> +&2" or die $!;' perl -E open my $pipe,"-|","pstree --ascii --arguments --long $$ 1>&2" + or die $!; `-sh -c pstree --ascii --arguments --long 22176 1>&2 `-pstree --ascii --arguments --long 22176 >

If the one-element list would not be treated specially, perl would complain that it could not find an executable with that funny name. This can be seen by incrementing the list size to 2:

> perl -E 'open my $pipe,"-|","pstree --ascii --arguments --long $$ 1> +&2","dummy" or die $!;' No such file or directory at -e line 1. >

So, despite the elegant call, three-argument pipe open still messes with the shell, and you should really use the "safe pipe opens" code from perlipc. If your script runs with elevated privileges (e.g. running as root or setuid/setgid), there is no other way to drop privileges.


The special treatment of a single-element list is, of course, not specific to more-than-two-arguments pipe open. system and exec show the same behaviour:

> perl -E 'system("pstree --ascii --arguments --long $$ 1>&2")==0 or d +ie $!' perl -E system("pstree --ascii --arguments --long $$ 1>&2")==0 or die +$! `-sh -c pstree --ascii --arguments --long 20620 1>&2 `-pstree --ascii --arguments --long 20620 > perl -E 'system("pstree --ascii --arguments --long $$ 1>&2","dummy") +' alex@enterprise pts/0 16:09:53 /home/alex>perl -E 'system("pstree --ascii --arguments --long $$ 1>&2" +,"dummy")==0 or die $!' No such file or directory at -e line 1. > perl -E 'exec("pstree --ascii --arguments --long $$ 1>&2") or die $! +' sh -c pstree --ascii --arguments --long 20657 1>&2 `-pstree --ascii --arguments --long 20657 > perl -E 'exec("pstree --ascii --arguments --long $$ 1>&2","dummy") o +r die $!' No such file or directory at -e line 1. >

But unlike open, system and exec have a workaround. Specify the real executable as indirect object and the shell magic is gone:

> perl -E '@list=("pstree --ascii --arguments --long $$ 1>&2"); system + { $list[0] } @list and die $!' No such file or directory at -e line 1. > perl -E '@list=("pstree --ascii --arguments --long $$ 1>&2"); exec { + $list[0] } @list or die $!' No such file or directory at -e line 1. >

This is documented in exec and shorter also in system. Pipe open lacks this functionality / workaround, and you have to resort to the quite long code from "Safe pipe open" in perlipc.


Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

In reply to Re^3: Ssh and qx by afoken
in thread Ssh and qx by cbeckley

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?

What's my password?
Create A New User
Domain Nodelet?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (3)
As of 2022-06-26 17:59 GMT
Find Nodes?
    Voting Booth?
    My most frequent journeys are powered by:

    Results (86 votes). Check out past polls.