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

I've written a perl script that generates some bioinformatic reports drawn from data in a MySQL database. The reports are written into their own directory and the script itself generates a little stdout telling what it is doing. This script actually has several small modules and a main driver. The problem is that I want to use a system or exec inside a cgi script to run the process. Here's the cgi code:
#!/usr/bin/perl -wT #use strict; use CGI qw(:standard); # important shortcuts use Fcntl qw(:flock); # imports LOCK_EX, LOCK_SH, LOCK_NB my $timestamp = localtime; my $userID = 'No'; my $passwrd; sub bail { my $error = "@_"; print h1("Unexpected Error"), p($error), end_html; } sub runReports { print "Generating Reports\n"; system("./Kreports.plx"); } $TITLE = "Kim's Report Generator"; $LOGFILE = "/usr/tmp/KreportLog"; print header,start_html($TITLE),h1($TITLE); $q = CGI->new(); #my ( $name, $value); print hr, start_form; # hr() emits a horizontal rule: <HR> #print $q->p( $timestamp ); print p( "User ID:", $q->textfield( -NAME => "name" ) ); print p( "Passwrd:", $q->password_field( -NAME => "passwrd")); print p( submit( "send" ), reset( "clear" ) ); print hr; print end_form; # for each name in hash produce the value foreach $ID ( $q->param ) { foreach $value ( $q->param( $ID ) ) { if ( $value eq 'Kim' ) { $userID = 'OK'; } if ($value eq 'Knecht' ) { $passwrd = 'OK'; } } } my $ret; if ( ($userID eq 'OK') and ($passwrd eq 'OK') ) { &runReports(); } else { print "Unauthorized!\n"; }
This may be a dumb question but I'm new to cgi programming and aint proud. Just need to learn how to do it. I've tried locating the report generator inside the cgi-bin and running it in it's own directory. The behavior is that the system call is ignored both ways! Thanks

Replies are listed 'Best First'.
Re: How to do system calls in cgi programs
by tachyon (Chancellor) on Jan 04, 2003 at 05:28 UTC

    Hi the problem will most probably be that you need the full path to your script. It should definately work if you call it like:

    system( "/usr/bin/perl /full/path/to/the/script.plx" )

    You are not bothering checking the return code (should be 0 if no error ) I am assuming an 0755 permissions mask (remember your CGI runs as user 'nobody' or 'apache' rather than user 'you' so it needs permissions to exec).

    With your code you are using both the OO and the method call interface from CGI.pm - I have modified it to use just the method interface and have cleaned up the logic for you.

    #!/usr/bin/perl -wT $|++; use strict; use CGI qw(:standard); # important shortcuts use Fcntl qw(:flock); # imports LOCK_EX, LOCK_SH, LOCK_NB my $timestamp = localtime; # this should be as suggested above "/usr/bin/perl /path/to/Kreports.p +lx" my $script_to_call = "./Kreports.plx"; $TITLE = "Kim's Report Generator"; $LOGFILE = "/usr/tmp/KreportLog"; print header,start_html($TITLE),h1($TITLE); if ( param('name') ) { # if we have a name we must have been called from our form if ( ( param('name') eq 'Kim' ) and ( param('passwrd') eq 'Knecht' + ) ) { &runReports(); } else { print "Unauthorized!\n"; } } else { # no name param so show form print hr, start_form; # hr() emits a horizontal rule: <HR> print p( $timestamp ); print p( "User ID:", textfield( -NAME => "name" ) ); print p( "Passwrd:", password_field( -NAME => "passwrd")); print p( submit( "send" ), reset( "clear" ) ); print hr; print end_form; } ##### Subs ##### sub bail { my $error = "@_"; print h1("Unexpected Error"), p($error), end_html; } sub runReports { print "Generating Reports\n"; my $exit_val = system($script_to_call); if ( $exit_val ) { print "<p>System call failed with an exit value $exit_val\n"; print "<p>Let's see what a backtic exec shows us\n"; print '<pre>', `$script_to_call`, '</pre>'; } }

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      Strangely, this solution doesn't seem to work. All the permissions are wide open and there is no error reported from the system call. I placed an else clause in runReports() to indicate success but there is no print out from that either.
      sub runReports { print "Generating Reports for $script_to_call\n"; my $exit_val = system($script_to_call); if ( $exit_val ) { print "<p>System call failed with an exit value $exit_val\n"; print "<p>Let's see what a backtic exec shows us\n"; print '<pre>', `$script_to_call`, '</pre>'; } else { print "<p>Look for reports in /home/donfox/BioDataProject/kim/Re +ports"; } }
      The program just runs but no reports are generated. The driver script for the reports works fro mthe command line, both in the cgi-bin and back in it's own directory. ??? Tanks
      This cretainly cleans up the logic. Tidy! But the resulting behavior is unchanged. No output from system(). I added an else to confirm that all went well in case of return of 0. No print out there either. Script runs and no reports! Permissions are everywhere wide open and Kreports.plx runs from command line on cgi-bin or at home.

        You will have a path/permissions problem. Debugging 101 - simplify and distill. Make a very simple program:

        #!/usr/bin/perl print "<h1>That worked!</h1>";

        Exec this via a system call from your CGI using a full path call - it should work without problems. If that is the case you have just isolated the problem to you reports script. You need to understand that the user, permissions and PATH on the command line often different from the CGI case. How they differ is setup dependent. Note that -T or taint mode stops you from doing things like system(param('script_to_exec')) as you need to untaint the value before you will be allowed to use it to do dangerous things.

        It seems highly likely that you are not checking for the success of open() or DBI->connect within you report script (and these are failing) but without seeing code this is just a guess.

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: How to do system calls in cgi programs
by dws (Chancellor) on Jan 04, 2003 at 08:08 UTC
    On first glance, it looks like you're running into a buffering problem. Perl buffers STDOUT by default. The various prints that you've done before invoking system() might still be buffered at the time the program you've invoked starts spewing stuff to STDOUT or STDERR.

    To unbuffer STDOUT, add   $|++; to the top of your script, right before the   use strict; that you've accidentally commented out.

      Thanks, Did that with no change in program behavior.
Re: How to do system calls in cgi programs
by OM_Zen (Scribe) on Jan 04, 2003 at 07:34 UTC
    Hi,

    The cgi program could have the open with "|" or the other exec " " for the calls to the system commands .
Re: How to do system calls in cgi programs
by vek (Prior) on Jan 04, 2003 at 15:23 UTC
    A few points to consider.

    Your CGI program will be running in cgi-bin so make sure that Kreports.plx resides in that directory. If it doesn't you'll have to provide the full path:
    my $reportProg = "/some-path-to/Kreports.plx";
    Make sure that the user running your CGI prog has permission to actually run Kreports.plx. Make sure that Kreports.plx actually works - i.e does it run without errors or problems in a non CGI environment?

    Last but not least, make sure you always check the return value from a system call as that could give you some rather handy info as to why Kreports.plx is not running (returns 0 on success, 1 on failure):
    my $reportProg = "/some-path-to/Kreports.plx"; system($reportProg) && do { my $errorMsg = "Could not run $reportProg - $!\n"; # your additional error handling code here };
    -- vek --
      Kreports.plx runs correctly from the command line in both the cgi-bin and back in it's own directory. It uses absolute paths so in will run anywhere. The courious thing is that the check for return value doesn't produce anything. Ths cgi script runs but no result from system() either way and no reports.
      sub runReports { print "Generating Reports for $script_to_call\n"; my $exit_val = system($script_to_call); if ( $exit_val ) { print "<p>System call failed with an exit value $exit_val\n"; print "<p>Let's see what a backtic exec shows us\n"; print '<pre>', `$script_to_call`, '</pre>'; } else { print "<p>Look for reports in /home/donfox/BioDataProject/kim/Re +ports"; } }
        Are you getting a </html> tag at the end of the page ?. If not, check the Apache error_log.
        poj
        Is Kreports.plx silently failing perhaps? Remember that the user running your CGI prog will be the same user that is running Kreports.plx. Does that user (e.g nobody) have permission to create a file in /home/donfox/BioDataProject/kim/Reports?

        Seeing as we don't know what Kreports.plx is actually doing, make sure that it can run successfully on the command line as the same user that runs your CGI prog.

        Update: Obviously you will not be able to run Kreports.plx on the command line as user 'nobody' but you should still check to see if user 'nobody' has permission to do all the things Kreports.plx will need to do when generating the reports.

        -- vek --