Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

macls

by snafu (Chaplain)
on Jun 06, 2001 at 22:00 UTC ( #86322=sourcecode: print w/ replies, xml ) Need Help??

Category: Utility scripts
Author/Contact Info Jim Conner
jconner@enterit.com
http://www.myspace.com/notjames
Description:

Rev ver 1.0:
This script is intended to get the mtime, atime, ctime information from a file or a list of files in a given directory. This is helpful to do basic file security auditing on your system. Read the comments in the script to get usage.

Updates:
Rev ver 2.1

  • Added locale tz tweak.
  • Added symbolic permissions modes to output. Many thanks to pwalker@pwccanada.com @ http://php.ca/manual/ru/function.fileperms.php. He doesn't know he helped but his code was invaluable to the symbolic mode code I added to this script.
  • Finally made a few changes that were suggested from Jeffa. Made other minor (beautification) changes.
  • General clean up.
  • Syntax changes that I felt made the script easier to read and more maintainable. Added GPL comments at top with (c) 2001. Subversion tags added for info only.
  • If there are tweaks performed on the script I would sincerely appreciate an email with a copy of the script with your changes.

    Tested successfully on: Linux, Solaris, FreeBSD

    Comments would be appreciated.

    #!/usr/bin/perl -w
    # Written by Jim Conner (Snafu)
    # 4/10/2001 (original creation)
    #
    # macls --
    # Nifty lil utility I wrote to be able to
    # get the mtime, ctime, and atime values from
    # any file of your choice.
    #
    #    Copyright (C) 2001  Jim Conner jconner|@at@|enterit|.dot.|com
    #
    #    This program is free software; you can redistribute it and/or mod
    +ify
    #    it under the terms of the GNU General Public License as published
    + by
    #    the Free Software Foundation; either version 2 of the License, or
    #    (at your option) any later version.
    #
    #    This program is distributed in the hope that it will be useful,
    #    but WITHOUT ANY WARRANTY; without even the implied warranty of
    #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #    GNU General Public License for more details.
    #
    #    You should have received a copy of the GNU General Public License
    + along
    #    with this program; if not, write to the Free Software Foundation,
    + Inc.,
    #    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    #
    ###################################################
    # HOW TO USE!!
    # It is quite simple.  All you do is supply this
    # script with the directory(ies)/file(s) you want to get
    # info on and voila! there's your info.
    #
    # Examples:
    #
    # macls /tmp
    #  This will give you a listing of all files in /tmp
    #
    # macls file1 file2 file3
    #  This will give you a listing of files 1 2 and 3.
    #
    # macls
    #  This will give you a listing of all files in the
    #  present working directory.
    #
    # TODO:
    #  Add command line args and options.  One of the
    #  most important of which would be -h (help)
    #
    #  Translate the mode to human readable (Unix)
    #  terms ie (drwxrwxr-x) ==> completed for rev 2.0 (done)
    #
    # $Revision: 437 $
    # $Author: jconner $
    # $Id: macls 437 2006-08-17 16:44:39Z jconner $
    #
    # Version: 1.1
    #
    # Audit Trail:
    #  4/9/2k1  - First conceptualized and started on authoring
    #  4/10/2k1 - Released version 1.0
    #  4/5/2k2  - Released version 2.0
    #
    # ********************************************************
    use strict;
    use File::Basename;
    
    ####################
    
    my $DEBUG = 0;     # default to no debugging msgs.
    
    ####################
    my $plProgName = basename($0);
    my $count      = 0;
    my $total      = 0;
    my $locale     = (localtime time() + 3600 *
                     (12 - (gmtime)[2]))[2] - 12;
    my @filename;
    ####################
    
    
    if  ( $#ARGV == -1 )
    {
        @filename = &readall();
    }
    elsif ( $#ARGV >= 0 )
    {
        if ( -d $ARGV[0] )
        {
            @filename = &readall($ARGV[0]);
        }
        else
        {
            @filename = @ARGV;
        }
    }
    
    for my $filename ( @filename )
    {
    
    # reference info:
    #  0 dev      device number of filesystem
    #  1 ino      inode number
    #  2 mode     file mode  (type and permissions)
    #  3 nlink    number of (hard) links to the file
    #  4 uid      numeric user ID of file's owner
    #  5 gid      numeric group ID of file's owner
    #  6 rdev     the device identifier (special files only)
    #  7 size     total size of file, in bytes
    #  8 atime    last access time since the epoch
    #  9 mtime    last modify time since the epoch
    # 10 ctime    inode change time (NOT creation time!) since the epoch  
    +<-- NNNOOOTTT GOOD!! :(
    # 11 blksize  preferred block size for file system I/O
    # 12 blocks   actual number of blocks allocated
    #
    #(The epoch was at 00:00 January 1, 1970 GMT.)
    ####
    # from mknod(2) (good info!)
    #        S_ISUID   04000   Set user ID on execution.
    #        S_ISGID   020#0   Set group ID on execution if # is 7, 5, 3, 
    +or 1.
    #                          Enable mandatory file/record locking if # i
    +s
    #                          6, 4, 2, or 0.
    #        S_ISVTX   01000   Save text image  after execution.
    #        S_IRWXU   00700   Read, write, execute by owner.
    #        S_IRUSR   00400   Read by owner.
    #        S_IWUSR   00200   Write by owner.
    #        S_IXUSR   00100   Execute (search if a directory) by owner.
    #        S_IRWXG   00070   Read, write, execute by group.
    #        S_IRGRP   00040   Read by group.
    #        S_IWGRP   00020   Write by group.
    #        S_IXGRP   00010   Execute by group.
    #        S_IRWXO   00007   Read, write, execute  (search) by others.
    #        S_IROTH   00004   Read by others.
    #        S_IWOTH   00002   Write by others
    #        S_IXOTH   00001   Execute by others.
    #        S_ISVTX           On directories, restricted deletion flag.
    
        ( $count >= 1 ) ?
            printf("\n%65s\n",'*' x 55)
            :
            print "\n";
    
        warn "$0: $filename: $!\n" and next if ( ! open (F,$filename) );
    
        my ($mode,  $uid,
            $gid,   $size,
            $atime, $mtime,
            $ctime, $blksize,
            $blocks)       = (stat(F))[2,4,5,7 .. 12];
        my $sym_mode       = &determine_file_type($mode);
        my $username       = getpwuid($uid);
        my $grpname        = getgrgid($gid);
        my @atime_readable = &fixgmt($atime,'atime');
        my @mtime_readable = &fixgmt($mtime,'mtime');
        my @ctime_readable = &fixgmt($ctime,'ctime');
        $mode &= 07777;
    
        print "MACtime for: \"$filename\"\n";
        printf("Mode(%s => %04o) %s(%i) %s(%i)\t%i bytes  %i blocks\n",
                     $sym_mode,
                           $mode,
                                 ($username || 'Unknown'),
                                    $uid,
                                        ($grpname || 'Unknown'),
                                           $gid,
                                                $size,
                                                          $blocks,);
    
        print "Modified time\t........ @mtime_readable\n";
        print "Access time  \t........ @atime_readable\n";
        print "Inode Change \t........ @ctime_readable\n";
    
        close(F);
    
        $count++;
        $total = $total + $size;
    }
    
    my $K  = $total / 1024;
    my $M  = ($total / 1024) / 1024;
    
    print "\nTotal files checked : $count\n";
    print "Total size in bytes : $total\n";
    printf("Total size in Kbytes: %iK\n", $K);
    printf("Total size in Mbytes: %iM\n\n", $M) if ( $M > 0.9 );
    
    sub fixgmt
    {
        my ($object, $type) = @_ ;
    
        print gmtime($object) ."\n" if $DEBUG;
        my($aday,$mon,$nday,$gmtime,$year)
                            = split(/\s+/,gmtime($object));
        my($hour,$min,$sec) = split(/:/,$gmtime);
    
        # Do math on gmt time to make it localtime.
        # Should get this from system LCTIME but I dunno
        # how to do that yet...sooo
    
        # Im gonna brute force the math for now.
        $hour  = abs($hour + $locale );
        $hour  = "0$hour"  if ( $hour < 10 );
        $nday  = "0$nday"  if ( $nday  < 10 );
    
        my $ltime = "$hour:$min:$sec";
    
        if ( $DEBUG )
        {
            print "Object type is: $type\n";
            print "Object value is: $object\n";
            print "Alpha day = $aday\nMonth = $mon\n".
                  "Number day = $nday\nGMTTime = $gmtime\nYear = $year\n";
            print "Hour = $hour\nMinute = $min\nSecond = $sec\n";
            print "LocalTime = $ltime\n\n";
        }
    
        return($aday,$mon,$nday,$ltime,$year);
    }
    
    sub readall
    {
        my $dir = shift();
    
        if ( $dir )
        {
            chdir($dir);
            opendir(ALL,".") or die("Unable to read: $!\n");
        }
        else
        {
            opendir(ALL,".") or die("Unable to read: $!\n");
        }
    
        my @files = grep(!/(^\.\.*?)/,readdir(ALL))
                        or die("Unable to get file list: $!\n");
    
        return(@files);
    }
    
    sub determine_file_type
    {
        my $mode = shift();
        my ($type, %owner, %group, %world);
    
    # borrowed from:
    # pwalker@pwccanada.com @ http://php.ca/manual/ru/function.fileperms.p
    +hp
    
        # // Unknown
        $type = '?';
        # // Unix domain socket
        (($mode & 0xC000) == 0xC000 ) and $type = 's';
        # // Directory
        (($mode & 0x4000) == 0x4000 ) and $type = 'd';
        # // Symbolic link
        (($mode & 0xA000) == 0xA000 ) and $type = 'l';
        # // Regular file
        (($mode & 0x8000) == 0x8000 ) and $type = '-';
        # // Block special file
        (($mode & 0x6000) == 0x6000 ) and $type = 'b';
        # // Character special file
        (($mode & 0x2000) == 0x2000 ) and $type = 'c';
        # // Named pipe
        (($mode & 0x1000) == 0x1000 ) and $type = 'p';
    
    #/* Determine permissions */
        $owner{'read'}    = ($mode & 00400) ? 'r' : '-';
        $owner{'write'}   = ($mode & 00200) ? 'w' : '-';
        $owner{'execute'} = ($mode & 00100) ? 'x' : '-';
        $group{'read'}    = ($mode & 00040) ? 'r' : '-';
        $group{'write'}   = ($mode & 00020) ? 'w' : '-';
        $group{'execute'} = ($mode & 00010) ? 'x' : '-';
        $world{'read'}    = ($mode & 00004) ? 'r' : '-';
        $world{'write'}   = ($mode & 00002) ? 'w' : '-';
        $world{'execute'} = ($mode & 00001) ? 'x' : '-';
    
    #/* Adjust for SUID, SGID and sticky bit */
    
        $owner{'execute'} = ($owner{execute} eq 'x') ? 's' : 'S'
            if ( $mode & 0x800 );
    
        $group{'execute'} = ($group{execute} eq 'x') ? 's' : 'S'
            if ( $mode & 0x400 );
    
        $world{'execute'} = ($world{execute} eq 'x') ? 't' : 'T'
            if ( $mode & 0x200 );
    
    # done borrowing :)
    
        $type .= $owner{'read'}.$owner{'write'}.$owner{'execute'}.
                 $group{'read'}.$group{'write'}.$group{'execute'}.
                 $world{'read'}.$world{'write'}.$world{'execute'};
    
        return($type);
    }
    
    

    Comment on macls
    Download Code
    (jeffa) Re: macls.pl
    by jeffa (Chancellor) on Jun 06, 2001 at 22:15 UTC
      Very small critisms that go a long way:
      1. Instead of using $DEBUG as a variable, why not 'declare' it as a constant:
        use constant DEBUG => 0;
      2. Testing if something is equal to "1" is overkill, all you need to know is if the variable is non-zero or not. Both of these are equal in consequence:
        print gmtime($object) ."\n" if $DEBUG == "1"; print gmtime($object) ."\n" if $DEBUG; # ahem, but since we'll be using the constant DEBUG print gmtime($object) ."\n" if DEBUG; # sorry i didn't mention this ea +rlier
      3. last issue, your first for loop:
        for ( @filename ) { my $filename = $_; ... }
        can be more consisely written as:
        for my $filename (@filename) { ... }
      Other than that, it works, and that's the most important thing, right? :)

      Jeff

      R-R-R--R-R-R--R-R-R--R-R-R--R-R-R--
      L-L--L-L--L-L--L-L--L-L--L-L--L-L--
      
        Oh man!! That is great! I didn't know I could create a for loop like that (similar to shell). Thanks for that bit of info.

        As for the $DEBUG...well, I didn't know I could do that either! =P That would make this much cleaner. I will make the changes. Thanks for the information.

        Yup...it works. I really like it. It has been a very helpful tool to me in my work. Thanks for the info Jeff. Talk at ya later.

        ----------
        - Jim

        Hey Jeffa,
        FYI, the constantness of the variables, once set, seems to mean that I don't have to use a '$' to reference a token. Instead, I should reference a constant token all by itself e.g. DEBUG vs $DEBUG
        use constant DEBUG => 0; if ( DEBUG ) { ... } # RIGHT if ( $DEBUG ) { ... } # Wrong

        Once, I figured this out using perldoc constant all worked very nicely. Thanks again for your input.

        ----------
        - Jim

    Back to Code Catacombs

    Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Node Status?
    node history
    Node Type: sourcecode [id://86322]
    help
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others browsing the Monastery: (9)
    As of 2014-10-01 07:18 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      How do you remember the number of days in each month?











      Results (389 votes), past polls