Selective CHMOD in Perl with pattern matching

perl debian

Simple problems can become quite tricky to solve. Recently, I had to give FTP access to a large folder in which I had some private information.

I did not want to reorganize the folder just because of this access, and I was already using group permission that I couldn't change.

TIMTOWTDI applied, I choosed to created a small perl script that would check the name of a folder/file and, if this name matches some predefined pattern, would apply a specific chmod permission to it.

For example: pattern is “doh” and attached permission is “740”.

In the list below, directory todohpoh and file azodihazodihdoh will match and permission 740 will be applied to them.

$ ls -al /tmp  
total 64 
drwxrwxrwt 13 root     root     12288 oct 28 15:57 .
drwxr-xr-x 25 root     root     4096  fev 16  2009 .. 
-rw-r--r--  1 julien   julien   0     oct 28 15:57 azodihazodihdoh 
-rw-r--r--  1 julien   julien   2513  oct 13 14:30 dokulist  
drwxr-xr-x  2 julien   julien   4096  oct 27 18:18 prv 
drwxr-xr-x  2 alfresco hugetlb  4096  oct 27 10:46 sv728.tmp 
drwxr-xr-x  2 julien   julien   4096  oct 28 15:57 todohpoh  
drwxrwxrwt  2 root     root     4096  oct 12 07:58 .X11-unix 
drwxr-xr-x  2 julien   julien   4096  oct 27 18:19 xxXXprvfdz
drwxr-xr-x  2 julien   julien   4096  oct 27 18:19 xxzzzazzdazd
#! /usr/bin/perl -w
use strict;
# julien vehent - oct. 2009
# browse a list of folder and change the permission
# according to a defined list of patterns and perms
 
# perm_list contain pattern + associated chmod perm (user|group|others)
# the first pattern that matches is the one applied
# "default" is mandatory and applied when no pattern match the entry
#
my %perm_list = ( 
                  "prv" => "770", 
                  "default"=> "775" 
                );
 
my $verbose = 0;
 
sub check_recursively
{
   my $folder_name = $_[0];
 
   print "entering $folder_name\n";
 
   # open folder and loop on each entry
   opendir my($folder), $folder_name or die "Couldn't open $folder_name: $!\n";
 
   for my $entry (readdir($folder))
   {
      if(($entry eq ".") or ($entry eq ".."))
      {
         next;
      }
 
      my $entry_chmoded = 0;
 
      my $entry_full_path = $folder_name."/".$entry;
 
      # check entry with all patterns, except default
      foreach my $pattern (keys %perm_list)
      {
         # entry matches pattern, apply corresponding chmod and mark entry
         if (($entry =~ /$pattern/) and ($pattern ne "default"))
         {
            print "$pattern matches -> chmod $perm_list{$pattern} $entry_full_path\n" if $verbose == 1;
 
            system("chmod $perm_list{$pattern} \"$entry_full_path\"");
 
            $entry_chmoded = 1;
         }
      }
 
      # entry didn't match any pattern, apply default permission
      if($entry_chmoded == 0)
      {
         print "default -> chmod $perm_list{'default'} $entry_full_path\n" if $verbose == 1;
 
         system("chmod $perm_list{'default'} \"$entry_full_path\"");
      }
 
      #if entry is a folder, go visit it
      if ((-d $entry_full_path) and ($entry ne ".") and ($entry ne ".."))
      {
         check_recursively($entry_full_path);
      }
 
   }
   closedir($folder);
}
 
 
#--- MAIN CODE ---
unless(defined @ARGV)
{
   print "\nchmod_selected_folders.pl\njve - oct.2009\n\nusage: ./chmod_selected_folders.pl <folder 1> ... <folder n>\n\n";
}
 
print "using perm list:\n";
foreach my $pattern (keys %perm_list)
{
   print "  * pattern $pattern will be applied permission $perm_list{$pattern}\n";
}
 
# list of folder in stdin, loop on it
foreach my $folder_name (@ARGV)
{
   print "processing entries starting at $folder_name\n";
 
   check_recursively($folder_name);
}

If no pattern matches an entry, the one called default will be applied to it.