通过perl脚本搜索文件系统,同时忽略远程安装

时间:2014-04-07 21:56:55

标签: linux perl scripting

我编写了一个perl脚本,旨在搜索服务器以查找世界可写文件。经过一些测试,我发现我在逻辑上犯了一个错误。具体来说,我告诉它不要搜索/。我最初的想法是,我一直在寻找本地安装的卷,同时避免使用远程类型(CIFSNFS,你有什么)。

我没有考虑到的是并非每个目录都有唯一的卷。因此,通过在我的扫描中排除/,我错过了应该包含的几个目录。现在我需要重新编写脚本以包含那些仍然排除远程卷的脚本。

#!/usr/bin/perl

# Directives which establish our execution environment
use warnings;
use strict;
use Fcntl ':mode';
use File::Find;
no warnings 'File::Find';
no warnings 'uninitialized';

# Variables used throughout the script
my $DIR = "/var/log/tivoli/";
my $MTAB = "/etc/mtab";
my $PERMFILE = "world_writable_w_files.txt";
my $TMPFILE = "world_writable_files.tmp";
my $EXCLUDE = "/usr/local/etc/world_writable_excludes.txt";

# Compile a list of mountpoints that need to be scanned
my @mounts;

# Create the filehandle for the /etc/mtab file
open MT, "<${MTAB}" or die "Cannot open ${MTAB}, $!";

# We only want the local mountpoints that are not "/"
while (<MT>) {
  if ($_ =~ /ext[34]/) {
    my @line = split;
    push(@mounts, $line[1]) unless ($_ =~ /root/);
  }
}

close MT;

# Read in the list of excluded files
my $regex = do {
  open EXCLD, "<${EXCLUDE}" or die "Cannot open ${EXCLUDE}, $!\n";
  my @ignore = <EXCLD>;
  chomp @ignore;
  local $" = '|';
  qr/@ignore/;
};

# Create the output file path if it doesn't already exist.
mkdir "${DIR}" or die "Cannot execute mkdir on ${DIR}, $!" unless (-d "${DIR}");

# Create the filehandle for writing the findings
open WWFILE, ">${DIR}${TMPFILE}" or die "Cannot open ${DIR}${TMPFILE}, $!";

foreach (@mounts) {
  # The anonymous subroutine which is executed by File::Find
  find sub {
    return unless -f; # Is it a regular file...

    # ...and world writable.
    return unless (((stat)[2] & S_IWUSR) && ((stat)[2] & S_IWGRP) && ((stat)[2] & S_IWOTH));

    # Add the file to the list of found world writable files unless it is
    # in the list if exclusions
    print WWFILE "$File::Find::name\n" unless ($File::Find::name =~ $regex);

  }, $_;
}

close WWFILE;

# If no world-writable files have been found ${TMPFILE} should be zero-size;
# Delete it so Tivoli won't alert
if (-z "${DIR}${TMPFILE}") {
  unlink "${DIR}${TMPFILE}";

} else {
  rename("${DIR}${TMPFILE}","${DIR}${PERMFILE}") or die "Cannot rename file ${DIR}${TMPFILE}, $!";

}

我现在对如何解决这个问题感到有点失落。我知道我可以使用stat -f -c %T获取必要的信息,但我没有看到perl内置stat的类似选项(除非我误解了相关说明)输出字段;也许它可以在S_个变量中找到?)。

我正在寻找正确方向的推动力。我真的不想放弃shell命令来获取这些信息。

编辑:我发现this answer to a similar question,但似乎并不完全有用。当我针对stat挂载测试内置CIFS时,我得到18。也许我需要的是一个完整的值列表,可以返回远程文件进行比较?

EDIT2:这是符合要求的新形式的脚本:

#!/usr/bin/perl

# Directives which establish our execution environment
use warnings;
use strict;
use Fcntl ':mode';
use File::Find;
no warnings 'File::Find';
no warnings 'uninitialized';

# Variables used throughout the script
my $DIR = "/var/log/tivoli/";
my $MTAB = "/etc/mtab";
my $PERMFILE = "world_writable_w_files.txt";
my $TMPFILE = "world_writable_files.tmp";
my $EXCLUDE = "/usr/local/etc/world_writable_excludes.txt";
my $ROOT = "/";
my @devNum;

# Create an array of the file stats for "/"
my @rootStats = stat("${ROOT}");

# Compile a list of mountpoints that need to be scanned
my @mounts;

open MT, "<${MTAB}" or die "Cannot open ${MTAB}, $!";

# We only want the local mountpoints
while (<MT>) {
  if ($_ =~ /ext[34]/) {
    my @line = split;
    push(@mounts, $line[1]);
  }
}

close MT;

# Build an array of each mountpoint's device number for future comparison
foreach (@mounts) {
  my @stats = stat($_);
  push(@devNum, $stats[0]);
}

# Read in the list of excluded files and create a regex from them
my $regExcld = do {
  open XCLD, "<${EXCLUDE}" or die "Cannot open ${EXCLUDE}, $!\n";
  my @ignore = <XCLD>;
  chomp @ignore;
  local $" = '|';
  qr/@ignore/;

};

# Create a regex to compare file device numbers to.
my $devRegex = do {
  chomp @devNum;
  local $" = '|';
  qr/@devNum/;

};

# Create the output file path if it doesn't already exist.
mkdir("${DIR}" or die "Cannot execute mkdir on ${DIR}, $!") unless (-d "${DIR}");

# Create our filehandle for writing our findings
open WWFILE, ">${DIR}${TMPFILE}" or die "Cannot open ${DIR}${TMPFILE}, $!";

foreach (@mounts) {
  # The anonymous subroutine which is executed by File::Find
  find sub {
    # Is it in a basic directory, ...
    return if $File::Find::dir =~ /sys|proc|dev/;

    # ...a regular file, ...
    return unless -f;

    # ...local, ...
    my @dirStats = stat($File::Find::name);
    return unless $dirStats[0] =~ $devRegex;

    # ...and world writable?
    return unless (((stat)[2] & S_IWUSR) && ((stat)[2] & S_IWGRP) && ((stat)[2] & S_IWOTH));

    # If so, add the file to the list of world writable files unless it is
    # in the list if exclusions
    print(WWFILE "$File::Find::name\n") unless ($File::Find::name =~ $regExcld);

  }, $_;

}

close WWFILE;

# If no world-writable files have been found ${TMPFILE} should be zero-size;
# Delete it so Tivoli won't alert
if (-z "${DIR}${TMPFILE}") {
  unlink "${DIR}${TMPFILE}";

} else {
  rename("${DIR}${TMPFILE}","${DIR}${PERMFILE}") or die "Cannot rename file ${DIR}${TMPFILE}, $!";

}

1 个答案:

答案 0 :(得分:0)

dev的{​​{1}}字段结果会告诉您inode所在的设备编号。这可用于区分不同的挂载点,因为它们的设备编号与您开始的设备编号不同。