linux - 通过 perl 脚本搜索文件系统,同时忽略远程挂载

标签 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 , 但它似乎并不完全有用。当我针对 CIFS 安装测试内置 stat 时,我得到了 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}, $!";

}

最佳答案

stat()dev 字段告诉您 inode 所在的设备号。这可用于区分不同的挂载点,因为它们的设备号与您开始时的设备号不同。

关于linux - 通过 perl 脚本搜索文件系统,同时忽略远程挂载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22923873/

相关文章:

linux - 有没有什么方法可以在 WSL 下运行 perf?

regex - Perl:如何用它的值替换变量

perl - 为什么 [^\w] 匹配一些单词字符而 [^\p{Word}] 不匹配?

mysql - 获取 Template::Plugin::Date 来接受 MySQL 日期和日期时间

c++ - 你如何将 LuaPlus 包含到你的项目中?

PowerShell - 如何计算参数数量

php - 如何在 PHP 中将变量重置为 NULL?

java - 在虚拟机中从 Linux 启动 Windows 程序。

Python 脚本 grep 目录

c# - Mono 中的 HTTP 监听器不读取 HTTP 请求