How do I get "system" to report the correct failure message?


L

laredotornado

Hi,

I'm using Perl 5.16 on mac 10.9.1. I'm trying to get Perl to output the correct error message when I run a shell process and that process fails. I have this ...

system("$jbossHome/bin/jboss-cli.sh", "--file=$file");
if ( $? != 0 )
{
die"Failed to deploy $downloadedFile: $!\n";
}

However, what Perl reports is "Failed to deploy /tmp/my.war: Inappropriate ioctl for device" and when I run the command in a shell, the actual error message is "{"JBAS014653: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"JBAS014671: Failed services" => {"jboss.web.deployment.default-host./my" => "org.jboss.msc.service.StartException in service jboss.web.deployment.default-host./my: JBAS018040: Failed to start context"},"JBAS014771: Services with missing/unavailable dependencies" => ["jboss.deployment.unit.\"my.war\".jboss.security.jacc Missing[JBAS014861: <one or more transitive dependencies>]"]}}}".

Any ideas how I can output the correct error message?
 
Ad

Advertisements

R

Rainer Weikusat

I'm using Perl 5.16 on mac 10.9.1. I'm trying to get Perl to output the correct error message when I run a shell process and that process fails. I have this ...

system("$jbossHome/bin/jboss-cli.sh", "--file=$file");
if ( $? != 0 )
{
die"Failed to deploy $downloadedFile: $!\n";
}

However, what Perl reports is "Failed to deploy /tmp/my.war:
Inappropriate ioctl for device"

$! is the Perl-equivalent of errno and it is set when an operation
performed via the C library fails, usually, a system call. But no system
calls made by your program failed during system, the program executed in
this way 'failed' to accomplish something, hence, you got a non-zero
exit status back. But (for obvious reasons), the system cannot provide
error messages arbitrary "application failures". The value in $! is just
one which happened to have been left in there when the last system call
failed (which was very likely an expected failure during the course of
system and hence, not reported to your code).
 
T

Tim McDaniel

the correct error message when I run a shell process and that process
fails. I have this ... ....
$! is the Perl-equivalent of errno and it is set when an operation
performed via the C library fails, usually, a system call. But no
system calls made by your program failed during system,

To clarify standard Perl (UNIX, really) terminology: "system call"
roughly means a call into the operating system (or, I assume, if the
OS in question doesn't provide a particular Perl builtin function, it
might be an implementation provided by Perl).

Anyway, "system call" means things like sysread, fork, gmtime, and
such. It does not mean a call to the sub that happens to have the
name "system". In Perl, "system()" is not referred to as a "system
call".
But (for obvious reasons), the system cannot provide error messages
arbitrary "application failures".

Indeed, that's the operative point. If I want to analyze the results
of an external program, I have to capture its output in Perl using
`...` or `... 2>&1` (if supported by the OS and/or shell) or more
sophisticated methods. And I usually have to look at $?, as program
that fail often exit with a non-zero exit code, and that goes into $?.
See the perlfunc documentation for system to learn the structure of
$?.
 
C

C.DeRykus

Quoth (e-mail address removed):
....

You are checking $? and then printing $!. Properly speaking you need to check both:

use Fcntl qw/:sys_wait_h/;
my $st = system (...);
if ($st == -1) {
die "failed to run jboss-cli: $!";
}
elsif ($st != 0) {
if (WIFEXITED($?)) {
die sprintf "jboss-cli exited with status %i",
WEXITSTATUS($?);
}
elsif (WIFSIGNALED($?)) {
die sprintf "jboss-cli was killed with signal %i",
WTERMSIG($?);
}
else {
# shouldn't happen
die "jboss-cli failed: $?";
}
}

On systems which use non-standard return values from wait(2) you may
need to replace $? with ${^CHILD_ERROR_NATIVE}, though IIRC this is not consistent across perl versions.
}
However, what Perl reports is "Failed to deploy /tmp/my.war:
Inappropriate ioctl for device" and when I run the command in a shell,
the actual error message is "{"JBAS014653: Composite operation failed
and was rolled back. Steps that failed:" => {"Operation step-2" =>
{"JBAS014671: Failed services" =>
{"jboss.web.deployment.default-host./my" =>
"org.jboss.msc.service.StartException in service
jboss.web.deployment.default-host./my: JBAS018040: Failed to start
context"},"JBAS014771: Services with missing/unavailable dependencies"
=> ["jboss.deployment.unit.\"my.war\".jboss.security.jacc
Missing[JBAS014861: <one or more transitive dependencies>]"]}}}".

Any ideas how I can output the correct error message?

Does the command print this to stderr (or, indeed, stdout)? I would
expect this to be visible when you run the command via system, given
that you haven't redirected either. What matters is to make sure your
Perl program also realises something went wrong.

Or, maybe outputting stdout/stderr will convey enough:

use IPC::Run qw/run/;

@cmd = ("$jbossHome/bin/jboss-cli.sh", "--file=$file");

run( \@cmd, '>&', \$out_and_err )
or die "run: $? status=$out_and_err";
....
 
H

hymie!

In our last episode, the evil Dr. Lacto had captured our hero,
(e-mail address removed), who said:
system("$jbossHome/bin/jboss-cli.sh", "--file=$file");
if ( $? != 0 )
{
die"Failed to deploy $downloadedFile: $!\n";
}
Any ideas how I can output the correct error message?

$ perldoc -f system

This is not what you
want to use to capture the output from a command; for that you
should use merely backticks or "qx//", as described in
"`STRING`" in perlop.

--hymie! http://lactose.homelinux.net/~hymie (e-mail address removed)
 
Ad

Advertisements

L

laredotornado

Quoth (e-mail address removed):


You are checking $? and then printing $!. Properly speaking you need to check both:

use Fcntl qw/:sys_wait_h/;
my $st = system (...);
if ($st == -1) {
die "failed to run jboss-cli: $!";

elsif ($st != 0) {
if (WIFEXITED($?)) {
die sprintf "jboss-cli exited with status %i",


elsif (WIFSIGNALED($?)) {
die sprintf "jboss-cli was killed with signal %i",


else {
# shouldn't happen
die "jboss-cli failed: $?";



On systems which use non-standard return values from wait(2) you may
need to replace $? with ${^CHILD_ERROR_NATIVE}, though IIRC this is not consistent across perl versions.
}
However, what Perl reports is "Failed to deploy /tmp/my.war:
Inappropriate ioctl for device" and when I run the command in a shell,
the actual error message is "{"JBAS014653: Composite operation failed
and was rolled back. Steps that failed:" => {"Operation step-2" =>
{"JBAS014671: Failed services" =>
{"jboss.web.deployment.default-host./my" =>
"org.jboss.msc.service.StartException in service
jboss.web.deployment.default-host./my: JBAS018040: Failed to start
context"},"JBAS014771: Services with missing/unavailable dependencies"
=> ["jboss.deployment.unit.\"my.war\".jboss.security.jacc
Missing[JBAS014861: <one or more transitive dependencies>]"]}}}".

Any ideas how I can output the correct error message?
Does the command print this to stderr (or, indeed, stdout)? I would
expect this to be visible when you run the command via system, given
that you haven't redirected either. What matters is to make sure your
Perl program also realises something went wrong.



Or, maybe outputting stdout/stderr will convey enough:



use IPC::Run qw/run/;



@cmd = ("$jbossHome/bin/jboss-cli.sh", "--file=$file");



run( \@cmd, '>&', \$out_and_err )

or die "run: $? status=$out_and_err";

...

Thanks for all the replies. Ultimately the one Charles provided did accurately output the error I was hoping to capture.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top