Search code examples
perlcmdpsexec

Unable to handle exception handling on a Psexec command in perl


I am trying to exit the for loop if the psexec command fails or more importantly if it takes more time , i am using Time::Out module in this program , but the psexec command does not exit ,am i using it wrong? Is there any other way to deal with this situation.

#$nb_secs means number of seconds
  for my $host1 (@servers){
        timeout $nb_secs => sub {
                 # do stuff that might timeout.
                $returnFileNames=`psexec \\\\$host1 cmd /c "dir /s 
                 d:\\dd\` ;
        }; 

        next if $@;
}

Solution

  • There are various reasons why a SIGALRM will not get delivered to a process, and you have discovered one of them. A workaround is the poor man's alarm -- run a separate process in the background to monitor the long running process and to kill it after some time has expired. On Windows and with a command where you need to capture the output, it would look something like this:

    # $pid is the id of the process to monitor
    my $pid = open my $proc_fh, '-|', "psexec \\\\$host1 cmd /c "dir /s d:\\dd\";
    
    my $pma = "sleep 1,kill(0,$pid)||exit for 1..$nb_secs;"
            . "kill -9,$pid;system 'taskkill /f /pid $pid >nul'";
    my $pma_pid = system 1, $^X, "-e", $pma;
    
    # read input from the external process.
    my $returnFilenames;
    while (<$proc_fh>) {
        $returnFilenames .= $_;
    }
    close $proc_fh;
    

    The poor man's alarm is a little program with two parts. The first part counts up to $nb_secs seconds and terminates if the monitored process is no longer running (if kill 0,$pid returns a false value). The second part of the program, if it is reached, terminates the monitored process. In this instance, we try two different ways (kill -9 ... and system 'taskkill /f ...') to terminate the process.