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

I have this non strict perl script which contains this and is executed from a java servlet:

$fooDir = "D:/foo"; system("touch $fooDir/test"); system("\"$fooDir/bar.bat\"");

The file "test" appears in D:/foo, but bar.bat does not appear to be executed.

If I execute bar.bat manually, or if I execute the perl script manually, bar.bat executes.

What's more frustrating is, this used to work. I'm not quite sure how it broke. I was fixing an unrelated part of the servlet which isn't directly connected to the perl program. $fooDir is a constantly changing directory, but the root directory (I should mention this is Windows) is fully open, permissions wise, to "everyone" and "system" users.

Any ideas?

Replies are listed 'Best First'.
Re: Can't execute system() when called from servlet (security)
by tye (Sage) on May 28, 2014 at 22:37 UTC

    Things like servlets tend to have reduced permissions in ways that can be surprising. For example, you probably can't access a network shared directory. Such might be causing your script to fail. You might want to make sure STDERR of your script gets redirected to an appropriate place that you can check when debugging a failure but that periodically gets cleaned up (and that you are certain can always be written to). Perhaps like:

    system("\"$fooDir/bar.bat\" 2>>D:/foo$$.log");

    - tye        

Re: Can't execute system() when called from servlet
by Anonymous Monk on May 28, 2014 at 16:54 UTC

    Does $fooDir contain spaces? Why are you adding the extra quotes around the command name?

    You really should be checking the return value of system: system(...) == 0 or die "system failed, \$?=$?"; (see the docs for more detailed error checking).

    Also, I'm sure you know you really should be using strict.

    You probably should look into some modules such as IPC::Run3 or IPC::System::Simple for easier and "safer" execution of external commands.

    Lastly, you can look into modules such as File::Spec, File::Path and friends for better handling of filenames and file operations.

      Forgot one: Are you sure that $fooDir is always an absolute pathname?

Re: Can't execute system() when called from servlet
by Laurent_R (Canon) on May 28, 2014 at 17:51 UTC
    I also don't really see the need for the extra quotes. Otherwise, reading your script, I have trouble figuring out whether you are running in under Windows or Unix, some parts seem to indicate the latter and some others the former. It would be nice to specify.
Re: Can't execute system() when called from servlet
by Anonymous Monk on May 28, 2014 at 20:57 UTC

    Any ideas?

    You didn't follow the rabbit trail of system documentation

    You're calling the shell, and which shell depends on your perl configuration (its a variable)

    $ perl -V:sh sh='cmd /x /c';

    Your goal should be to avoid the shell most of the time

      This is a good point - unless you know that you need it, you should always avoid headaches and avoid the shell! Modules such as IPC::Run3 and IPC::System::Simple have an API that allows you to avoid calling the shell, make sure to read their docs. Anyway, here's the relevant bits of doc from system and exec:

      Note that argument processing varies depending on the number of arguments. If there is more than one argument in LIST, or if LIST is an array with more than one value, starts the program given by the first element of the list with arguments given by the rest of the list. If there is only one scalar argument, the argument is checked for shell metacharacters, and if there are any, the entire argument is passed to the system's command shell for parsing (this is /bin/sh -c on Unix platforms, but varies on other platforms). If there are no shell metacharacters in the argument, it is split into words and passed directly to execvp, which is more efficient.
      Using an indirect object with exec or system is also more secure. This usage (which also works fine with system()) forces interpretation of the arguments as a multivalued list, even if the list had just one argument. That way you're safe from the shell expanding wildcards or splitting up words with whitespace in them.
      @args = ( "echo surprise" ); exec @args; # subject to shell escapes if @args == 1 exec { $args[0] } @args; # safe even with one-arg list
      The first version, the one without the indirect object, ran the echo program, passing it "surprise" an argument. The second version didn't; it tried to run a program named "echo surprise", didn't find it, and set $? to a non-zero value indicating failure.
Re: Can't execute system() when called from servlet
by Anonymous Monk on May 29, 2014 at 23:21 UTC
    Wow, that is one heck of a rube goldberg machine ... use the web to run java to run perl to run the shell to run touch. Amazing.