Search code examples
bashperlsamba

Different Exit Status in Perls system than in Bash


I want to check, if a user has access rights to a certain samba-share. I'm currently doing this using the command smbclient in Version 4.3.11-Ubuntu.

Apparently it is not a good idea to use the exit status for evaluation of success, as described in this question: Exit codes of smbclient

But nevertheless I have some strange behaviour. I get different exit status when calling the program with Perls system function.

perldoc -f system tells me this:

The return value is the exit status of the program as returned by the "wait" call.

When calling from commandline I get EXIT 1

user@host:~$ smbclient //server/share MyFalsePassword --user=any.user -c "cd somefolder;"; echo "EXIT $?"
WARNING: The "syslog" option is deprecated
session setup failed: NT_STATUS_LOGON_FAILURE
EXIT 1

Calling the same whitin Perl I get EXIT 256.

user@host:~$ perl -E 'say "EXIT " . system("smbclient //server/share MyFalsePassword --user=any.user -c \"cd somefolder;\"");'
WARNING: The "syslog" option is deprecated
session setup failed: NT_STATUS_LOGON_FAILURE
EXIT 256

I also have the value 256 in the variable $? whitin Perl.

Note: I get EXIT 0 in both (Bash and Perl) if I use the correct credentials.

My question: Why do I get different exit status from Bash and Perl if I use wrong credentials? How do I check correctly?

I use Perl v5.22 on Ubuntu 16.04.


Solution

  • The exit status returned by system is a two-byte number, which packs the exit code returned by the program into high bits, while the low 8 bits are set if the process was killed by a signal. The low 7 bits are the signal number and the 8th bit shows whether the core was dumped.

    So to get the actual exit of the program do as the next sentence from the docs you quote says

    To get the actual exit value, shift right by eight

    and 256 >> 8 gives us 1.

    The system's return is available in the variable $?, interrogated as spelled out in system

    if ($? == -1) {
        print "failed to execute: $!\n";
    }
    elsif ($? & 127) {
        printf "child died with signal %d, %s coredump\n",
            ($? & 127),  ($? & 128) ? 'with' : 'without';
    }
    else {
        printf "child exited with value %d\n", $? >> 8;
    }
    

    The return is best saved or $? examined right away, before it gets cleared.


    The bit shifting can be avoided by using IPC::System::Simple, which returns the program's exit value directly. Thanks to daxim for the comment. To investigate the signal we still need $? but this comes up far less frequently. The module simplifies system and qx use and error checking.