2014-04-07 15 views
2

我已經編寫了一個perl腳本,用於在服務器中搜索世界可寫文件。但是經過一些測試後,我發現我在邏輯上犯了一個錯誤。具體來說,我告訴它不要搜索/。我最初的想法是,我一直在尋找本地安裝的卷,同時避免那些偏遠的品種(CIFS,NFS,what-have-you)。通過perl腳本搜索文件系統,同時忽略遠程座標

我沒有考慮到的是,並非每個目錄都有唯一的卷。因此,在我的掃描中排除/,我錯過了幾個應該包含的目錄。現在我需要修改腳本以包含這些腳本,同時仍排除遠程卷。

#!/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,但它似乎並不完全有幫助。當我測試內置statCIFS安裝我得到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}, $!"; 

} 

回答

0

stat()dev域結果告訴你的設備號的inode住在。這可以用來區分不同的安裝點,因爲它們將與您開始使用的設備號不同。

+0

當你說「開始於」時,你是指我從哪裏運行腳本? – theillien

+0

在我的鍵盤上撥了一段時間然後往下走,然後回溯到不必要的路徑後,我相信我有我需要的東西:https://codereview.stackexchange.com/questions/46611/perl-script-to-find-world-可寫 - 文件 - 在本地的目錄只。我接受你的解決方案不僅僅是因爲它是唯一的(;)),而是因爲它正是我所需要的(以及我所要求的):正確的方向。 – theillien