joe_s has asked for the wisdom of the Perl Monks concerning the following question:

I'm writing a script to audit updates to files in a set of production unix directories (until we can implement a proper change control process).

I understand that mode from stat() contains file type and permission. As per the user manual, I extract the permissions using %o and a mask (see example below).

Question #1:
How can I extract the file type from mode ?
The mode (5 digit decimal) converts to a 6 digit octal.
Using the mask, returns the permissions (4 digits octal) (see example below).

Question #2:
Is there an easier way to audit changes to files ?
Are there existing functions or scripts to do this ?
(i.e. am I reinventing the wheel ?)

My approach is as follows:
I'll run a nightly cron job which will identify file adds and removes by comparision to previous nights results. I'll identify modifies and changes via mtime and ctime. I'll store all add/remove/update/changes in an audit file which will contain all the info in stat().

Thanks in advance for any help.

Joe

Example: ======= bshell6.0 > cat test.pl #!/opt/perl64/bin/perl my $file = $ARGV[0]; my $mode = (stat($file))[2]; print "File: $file\n"; print "mode = $mode\n"; printf "mode (octal) = %o\n", $mode; printf "Permissions = %04o\n", $mode & 07777; print "=============================\n"; bshell6.0 > ls -ldn testfile testdir drwxr-x--- 2 643 125 96 May 26 14:24 testdir -rwxr-x--- 1 643 125 0 May 26 14:24 testfile bshell6.0 > test.pl testfile File: testfile mode = 33256 mode (octal) = 100750 Permissions = 0750 ============================= bshell6.0 > test.pl testdir File: testdir mode = 16872 mode (octal) = 40750 Permissions = 0750 =============================

Replies are listed 'Best First'.
Re: Extract file type from stat() mode
by dragonchild (Archbishop) on May 26, 2005 at 19:16 UTC
    my $filetype = $mode & 0770000;

    That's your first question. What you really want to know is if the file has been modified or not. -M provides the last modification time.

    Best is to lock everything down so that you're the only one allowed to change anything by you taking over the root account and going from there. Anything else is a half-assed attempt.


    • In general, if you think something isn't in Perl, try it out, because it usually is. :-)
    • "What is the sound of Perl? Is it not the sound of a wall that people have stopped banging their heads against?"
Re: Extract file type from stat() mode
by brian_d_foy (Abbot) on May 26, 2005 at 19:22 UTC

    By file type, do you mean if it's a directory, plain file, and so on? You could get that out of the mode, I guess, but the file test operators do that too and they are much more clear to the guy who has to figure out what you are doing.

    See the -X entry in perlfunc. It's at the top of the alphabetical list of functions.

    Good luck :)

    --
    brian d foy <brian@stonehenge.com>
Re: Extract file type from stat() mode
by ysth (Canon) on May 26, 2005 at 20:49 UTC
    File type is better detected using the file test operators. You can pass them the special name _ to reuse the results of the previous stat/lstat/file test. Also see the filetest pragma for information on handling ACLs.
    use strict; use warnings; my $file = $ARGV[0]; my $mode = (lstat($file))[2]; print "File: $file\n"; print "mode = $mode\n"; printf "mode (octal) = %o\n", $mode; printf "Permissions = %04o\n", $mode & 07777; -r _ && print "File is readable by effective uid/gid.\n"; -w _ && print "File is writable by effective uid/gid.\n"; -x _ && print "File is executable by effective uid/gid.\n"; -o _ && print "File is owned by effective uid.\n"; -R _ && print "File is readable by real uid/gid.\n"; -W _ && print "File is writable by real uid/gid.\n"; -X _ && print "File is executable by real uid/gid.\n"; -O _ && print "File is owned by real uid.\n"; -e _ && print "File exists.\n"; -z _ && print "File has zero size (is empty).\n"; -s _ && printf "File has size: %d.\n", -s _; -f _ && print "File is a plain file.\n"; -d _ && print "File is a directory.\n"; -l _ && print "File is a symbolic link.\n"; -p _ && print "File is a named pipe (FIFO).\n"; -S _ && print "File is a socket.\n"; -b _ && print "File is a block special file.\n"; -c _ && print "File is a character special file.\n"; print "=============================\n";
Re: Extract file type from stat() mode
by rlucas (Scribe) on May 26, 2005 at 19:29 UTC
    Try looking at changetrack and tripwire. These are both fairly widely used programs for doing some or all of what you're after. Changetrack, I believe, mainly handles content changes (emailing diffs to root, etc), while tripwire can handle *all kinds* of stuff, like mod times, perms, size, etc., along with a dizzying array of options for things like "growable" files (e.g., only alert me if this log file should *decrease* in size), etc.

    Tripwire is available in Free and commercial versions, and the Free one is supported as many free things. However, if you were going to roll your own anyhow, dealing with the already-thought-out complexity of tripwire might be a blessing.

Re: Extract file type from stat() mode
by polettix (Vicar) on May 26, 2005 at 20:50 UTC
    If you want more after the answers above, read the free beta-chapter of Learning Perl 4 at OReilly: File Tests.

    Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

    Don't fool yourself.
Re: Extract file type from stat() mode
by Anonymous Monk on May 27, 2005 at 15:08 UTC
    For human readable stringified permissions, use Stat::lsMode.