Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

exec() fails with strange message

by dissident (Beadle)
on May 17, 2024 at 20:37 UTC ( [id://11159519]=perlquestion: print w/replies, xml ) Need Help??

dissident has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to make a function similar to system(), which collects stdin and stdout as well.
I know that there are some modules with stuff like that.
But the purpose of this is a) to learn and b) to have this simple task solved without big module.

So I have a subroutine "system2" in the code below.
It takes as argument a command line string, and other stuff.

This subroutine "system2" gets called from the subroutine "main" at the end of the code.
To test it, I am using a simple C program:

#include <stdio.h> main() { fprintf(stdout,"This is output on stdout! \n"); fprintf(stderr,"This is output on stderr! \n"); sleep(10); return 0; }

My Perl script described above is this:

#!/usr/local/bin/perl use strict; use warnings; use POSIX ":sys_wait_h"; $|++; # away with buffering # stringref read_a_file( string filename) sub read_a_file { my $fn = shift; local $/ = undef; open FILE, $fn or return undef; my $text = <FILE>; close FILE or return undef; return \$text; } # int system2( string cmdline, # stringref retmsg, # stringref stdoutttxr, # stringref stderrtxr) sub system2 { my $er = shift; my $cmd = shift; my $stdouttxr = shift; my $stderrtxr = shift; my $retval; my $stdoutfn = '/tmp/teststdout'; my $stderrfn = '/tmp/teststderr'; unlink ($stdoutfn) if (-e $stdoutfn); unlink ($stderrfn) if (-e $stderrfn); my $pid = fork(); if ($pid < 0) { $$er .= "Forking failed with return code $pid."; return $pid; } elsif ($pid == 0) { # CHILD use POSIX qw(setsid); setsid() or die "Can't start a new session: $!"; chdir('/'); $SIG{HUP} = 'IGNORE'; umask 0033; close STDIN or die; close STDOUT or die; close STDERR or die; open(STDIN, '</dev/null') or die; open(STDOUT, ">$stdoutfn") or die; open(STDERR, ">$stderrfn") or die; my @argv = split(/ /, $cmd); exec( @argv); } my $wpid = waitpid($pid,0); my $normalexit = WIFEXITED(${^CHILD_ERROR_NATIVE}); if ($normalexit) { $retval = WEXITSTATUS(${^CHILD_ERROR_NATIVE}); } else { if (WIFSIGNALED(${^CHILD_ERROR_NATIVE})) { $$er .= "Child terminated due to signal"; if (WTERMSIG(${^CHILD_ERROR_NATIVE})) { $$er .= ": SIGTERM"; } } } if (-e $stdoutfn) { if (-s $stdoutfn) { my $s = read_a_file($stdoutfn); die if (not defined $s); $$$stdouttxr = $s; } unlink ($stdoutfn); } if (-e $stderrfn) { if (-s $stderrfn) { my $s = read_a_file($stderrfn); die if (not defined $s); $$$stderrtxr = $s; } unlink ($stderrfn); } return $retval; } sub main { my $er = ''; my $cmd = '/path_to_a_out/a.out'; my $stdouttxr = undef; my $stderrtxr = undef; my $ret = system2($cmd,\$er,\$stdouttxr,\$stderrtxr); if (defined $ret) { print "return value = '$ret'\n"; } else { print "return value = undef\n"; } if ($er ne '') { print "Error text: '$er'\n"; } else { print "No error text!\n"; } if (defined $stdouttxr) { print "STDOUT: '$$$stdouttxr'\n"; } else { print "No stdout output!\n"; } if (defined $stderrtxr) { print "STDERR: '$$$stderrtxr'\n"; } else { print "No stderr output!\n"; } return 0; } exit main();

No matter whether I use '/path_to_a_out/a.out' or 'exec /path_to_a_out/a.out' as command string, the output is always this:

% perl -w system2.pl return value = '2' No error text! No stdout output! STDERR: 'sh: Syntax error: word unexpected (expecting ")") ' %

This looks to me as if Perl gives something to sh, which the latter is unable to swallow.
Any idea what am I doing wrong?

Replies are listed 'Best First'.
Re: exec() fails with strange message
by hv (Prior) on May 17, 2024 at 21:43 UTC

    What have you done to try to debug it? If it were me, I think the first thing I would do would be to show the command I'm about to execute.

    In your code you invoke system2() like this:

    system2($cmd,\$er,\$stdouttxr,\$stderrtxr);

    But in system2() you unpack the arguments like this:

    my $er = shift; my $cmd = shift; my $stdouttxr = shift; my $stderrtxr = shift;

    Learning how to debug straightforward things, for example by confirming the things that "can't possibly be wrong", will take you a big step forward. :)

      Thank you!
      The lack of sleep takes its toll... -.-
      Yes, with a debug print command I'd have noticed that I changed the order of arguments in the function... *facepalm*
      Now it works like as it should, with arguments in the subroutine and its call in the same order, and without the exec.
      I guess my error somehow made Perl call sh instead of sending the command to execvp directly, leading to the confusing message.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11159519]
Approved by johngg
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (4)
As of 2024-06-17 19:55 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.