mod_perl使用system()或exec()调用或反引号的奇怪行为

时间:2014-07-09 12:04:35

标签: perl exec system mod-perl

我在Perl中开发了一个简单的脚本,让我验证是否安装了USB密钥并最终卸载它。

我不确定问题是否与编程或配置有关,如果我错了请告诉我,我会在服务器配置相关堆栈上重新发布我的问题。

基本问题是: 当我使用Perl在终端中执行这些脚本时,它工作得很好,当我在浏览器中使用mod_perl时,它显示了一些非常奇怪的行为。

来源

panelmin.pl

该程序只输出一条消息,指示系统设备/dev/sda1是否已安装在系统中。

#!/usr/bin/perl
use strict;
use warnings;

print "Content-type:text/html\n\n";
print "<html><head><title>USB test</title>";
print "</head><body>";

my $mounted = `df -h | grep /dev/sda1`;

if ($mounted eq '') {
        print '<h1>USB device not connected</h1>';
        print $mounted;
}
else {
        print '<h1>Device is connected</h1>';
}
print '</body></html>';

umount.pl

此程序从系统中卸载/dev/sda1设备。

#!/usr/bin/perl
print "Content-type:text/html\n\n";
print "<html><head><title>Umount</title></head><body>";
system("sudo", "umount", "/dev/sda1");
print "</body></html>";

测试场景

  1. 手动安装设备/dev/sda1,(在fstab中声明):

    $ mount -a
    

    确保设备已安装在系统中:

    $ mount
    /dev/sda1 on /mnt/usbstick type vfat (rw,relatime,uid=1000,gid=1000,fmask=0137,dmask=0027,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro)
    
  2. 在网络浏览器中执行panelmin.pl(为了清洁输出,我将使用curl):

    $ curl http://localhost/cgi-bin/admin/Q/panel/panelmin.pl
    <html><head><title>USB test</title></head><body><h1>Device is connected</h1></body></html>
    

    我们可以看到,输出是正确的。它检测到通过linux命令df -h设备/dev/sda1已安装在系统中。

  3. 在网络浏览器中执行umount.pl以卸载设备:

    $ curl http://localhost/cgi-bin/admin/Q/panel/umount.pl
    <html><head><title>Umount</title></head><body></body></html>
    
  4. 使用网络浏览器和linux命令行中的panelmin.pl脚本验证设备是否已安装。

    $ curl http://localhost/cgi-bin/admin/Q/panel/panelmin.pl
    <html><head><title>USB test</title></head><body><h1>USB device not connected</h1></body></html>
    

    似乎是正确的,但让我们使用df -h命令手动验证它:

    $ df -h | grep /dev/sda1
    /dev/sda1        15G  366M   15G   3% /mnt/usbstick
    

    我们可以看到设备仍然安装在系统中。

  5. 让我们重试整个过程,但这次不是在浏览器中执行脚本,而是在终端中使用Perl手动启动它们。首先让我们卸载设备。这也将表明用户处于sudoers状态,脚本可以卸载它。

    $ sudo umount /dev/sda1
    $ df -h | grep /dev/sda1
    

    让我们重复这个过程。

    $ mount -a (as superuser)
    $ df -h | grep /dev/sda1
    /dev/sda1        15G  366M   15G   3% /mnt/usbstick
    

    最后测试:

    $ perl panelmin.pl 
    Content-type:text/html
    <html><head><title>USB test</title></head><body><h1>Device is connected</h1></body>
    
    $ perl umount.pl 
    Content-type:text/html
    <html><head><title>Umount</title></head><body></body></html>
    
    $ perl panelmin.pl 
    Content-type:text/html
    <html><head><title>USB test</title></head><body><h1>USB device not connected</h1></body></html>
    
    $ df -h | grep /dev/sda1
    

    现在df -h | grep /dev/sda1返回空字符串,已证明umount.pl设法从系统中卸载设备,但只有在Perl的shell中执行。

    < / LI>

    尝试解决问题

    1. 确保在sudo umount /dev/sda1中执行umount.pl的用户有权这样做,我通过在脚本中执行whoami并在输出中打印来验证它。 / p>

    2. 尝试system()的不同语法,例如将参数分开或将其全部作为一个命令执行。

    3. 我验证了我的mod_perl是否在taint mode中执行了脚本,因为我听说它可能会影响执行外部进程。事实上在我的httpd.conf中没有PerlTaintCheck On,如果我理解正确,它会影响执行动态参数(出于安全原因),在我的脚本的情况下,它是相同的命令每一次。

    4. 我尝试使用不同的功能,将System替换为Exec或反引号等。

    5. 我尝试使用Apache2::SubProcess,就像他们here一样,但我必须承认我不确定我是否做得正确,我是Perl的新手(以及网上所有其他可用的)示例非常可怕,例如$r变量从未在其代码中启动,我只是将其声明为Apache2::RequestRec object,但它不起作用。

      < / LI>
    6. 我尝试更改env变量,就像他们在10.2.6. Starting a Long-Running External Program

    7. 小节中解释here一样
    8. 我在Apache目录中验证了日志,发现了错误但与这些脚本没有关系,我没有在这里发帖,因为我不想让它太乱了。

    9. 解释

      它适用于Perl而非mod_perl的事实并不令人惊讶,我发现最奇怪的是mod_perl脚本panelmin.pl似乎工作得很好使用它system()启动并在执行umount.pl后突然再次无法正常工作。现在我没有想法,我发现这种行为很奇怪,我依靠你们。我希望有人知道我该怎么做。感谢。

      请求结果

      1. umount.pl

        中捕获系统的输出
        #!/usr/bin/perl
        print "Content-type:text/html\n\n";
        print "<html><head><title>Umount</title></head><body>";
        my $res = `sudo umount /dev/sda1`;
        print "$res</body></html>";
        

        结果是无效的:

        $ curl http://localhost/cgi-bin/admin/Q/panel/umount.pl
        <html><head><title>Umount</title></head><body></body></html>
        

1 个答案:

答案 0 :(得分:0)

原来这个问题与编程没有关系,它与服务器配置有关。

这是Apache的错。它在多线程/多进程环境中工作。我不知道为什么,但这使他无法处理system()函数。当我限制它在单一过程模式下工作时,问题就解决了。

即使知道问题与编程没有关系,我认为它应该留在这里,因为当这个问题发生时,可能很难确定问题的根源,我想StackOverflow将是第一个寻找大多数问题的地方初学者。