Managing file permissions correctly is critical in Oracle environments, especially when working with directories like ORACLE_HOME or GRID_HOME. A single incorrect permission or ownership change can break binaries, prevent databases from starting, or cause patching and upgrade failures.
This blog explains a safe, repeatable, and automated approach to capture and restore file permissions in a Unix directory using a simple Perl script. This method is extremely useful before patching, cloning, migrations, or OS-level changes, where permission drift is a common risk.
Why Capturing File Permissions Matters
In real-world Oracle administration, permissions change more often than expected:
- After patching (RU / PSU / OJVM)
- During manual troubleshooting
- While copying ORACLE_HOME or GRID_HOME
- After OS hardening or security scans
- In RAC environments, where node-specific ownership can differ
Once permissions are altered, restoring them manually is time-consuming and error-prone. This is where capturing permissions beforehand becomes a lifesaver.
Purpose of the Permission Capture Script
This script is designed to:
- Capture file permissions (octal format)
- Capture owner and group information
- Generate a restore script that can safely revert permissions
It does not reset permissions to defaults.
Instead, it restores them exactly as they were at the time of capture.
This makes it ideal for:
- ORACLE_HOME
- GRID_HOME
- Any application directory requiring permission consistency
Requirements
Before using the script, ensure the following:
- Unix / Linux OS
- Perl installed (default on most Unix systems)
- Shell access
- Proper user privileges:
oracleuser for ORACLE_HOMErootuser for GRID_HOME (RAC environments)
Script Overview
You will work with one Perl script:
permission.pl
#!/usr/bin/perl -w
#
# Captures file permissions and the owner of the files
# useage : perm1.pl <path to capture permission>
#
# MODIFIED
# uaswatha 12th March 2018 address filename with spaces (request from customer)
use strict;
use warnings;
use File::Find;
use POSIX();
my (@dir) = @ARGV;
my $linecount=0 ;
#print @ARGV, $#ARGV;
if ($#ARGV < 0) {
print "\n\nOpps....Invalid Syntax !!!!\n" ;
print "Usage : ./perm1.pl <path to capture permission>\n\n" ;
print "Example : ./perm1.pl /home/oralce\n\n" ;
exit ;
}
my $logdir=$dir[0] ;
#my ($sec, $min, $hr, $day, $mon, $year) = localtime;
##my ($dow,$mon,$date,$hr,$min,$sec,$year) = POSIX::strftime( '%a %b %d %H %M %S %Y', localtime);
my $date = POSIX::strftime( '%a-%b-%d-%H-%M-%S-%Y', localtime);
my $logfile="permission-".$date;
my $cmdfile="restore-perm-".$date.".cmd" ;
open LOGFILE, "> $logfile" or die $! ;
open CMDFILE, "> $cmdfile" or die $! ;
find(\&process_file,@dir);
print "Following log files are generated\n" ;
print "logfile : ".$logfile. "\n" ;
print "Command file : ".$cmdfile. "\n" ;
print "Linecount : ".$linecount."\n" ;
close (LOGFILE) ;
close (CMDFILE) ;
sub process_file {
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks,$username,$user,$pass,$comment,$home,$shell,$group);
my %uiduname = () ;
my %gidgname = () ;
my $filename = $File::Find::name;
#### Building uid, username hash
open (PASSWDFILE, '/etc/passwd') ;
while ( <PASSWDFILE>) {
($user,$pass,$uid,$gid,$comment,$home,$shell)=split (/:/) ;
$uiduname{$uid}=$user ;
}
close (PASSWDFILE) ;
#### Building gid, groupname hash
open (GRPFILE, '/etc/group') ;
while ( <GRPFILE>) {
($group,$pass,$gid)=split (/:/) ;
$gidgname{$gid}=$group ;
}
close (GRPFILE) ;
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat("$filename");
# printf "%o %s %s %s\n", $mode & 07777, $uiduname{$uid}, $gidgname{$gid}, $filename ;
printf LOGFILE "%o %s %s %s\n", $mode & 07777, $uiduname{$uid}, $gidgname{$gid}, "\"$filename\"" ;
printf CMDFILE "%s %s%s%s %s\n", "chown ",$uiduname{$uid}, ":", $gidgname{$gid}, "\"$filename\"" ;
printf CMDFILE "%s %o %s\n", "chmod ",$mode & 07777, "\"$filename\"" ;
# printf "%o %s %s %s\n", $mode & 07777, $uiduname{$uid}, $gidgname{$gid}, \",$filename,\" ;
$linecount++ ;
}
When executed, it generates two output files:
- permission-<timestamp>
- Stores permissions, owner, group, and file paths
- restore-perm-<timestamp>.cmd
- A ready-to-run shell script to restore everything
Step-by-Step: Capturing Directory Permissions
1. Download the Script
Create the permission.pl script and copy it to your server.
2. Log in as the Correct User
For ORACLE_HOME:
oracle
For GRID_HOME (RAC):
root
3. Place the Script
Example location:
/home/oracle/scripts
4. Grant Execute Permission
chmod 755 permission.pl
5. Run the Script
cd /home/oracle/scripts
./permission.pl <Path_to_Directory>
Example:
./permission.pl /u01/app/oracle/product/19.0.0/dbhome_1
Files Generated by the Script
1. permission-<timestamp>
This file captures:
- Permission (octal)
- Owner
- Group
- Full file path
Sample output:
755 oracle oinstall <ORACLE_HOME>
750 oracle oinstall <ORACLE_HOME>/root.sh
644 oracle oinstall <ORACLE_HOME>/install.platform
6755 root root <ORACLE_HOME>/tsh.sh
6751 oracle oinstall <ORACLE_HOME>/bin/oracle
This file acts as a snapshot of your directory permissions.
2. restore-perm-<timestamp>.cmd
This is an auto-generated restore script.
Sample content:
chown oracle:oinstall <ORACLE_HOME>
chmod 755 <ORACLE_HOME>
chown root:root <ORACLE_HOME>/tsh.sh
chmod 6755 <ORACLE_HOME>/tsh.sh
chown oracle:oinstall <ORACLE_HOME>/bin/oracle
chmod 6751 <ORACLE_HOME>/bin/oracle
You can run this script at any time to restore permissions exactly as captured.
Step-by-Step: Restoring Permissions
1. Copy the Restore Script
If needed, copy restore-perm-<timestamp>.cmd to the target node or server.
2. Grant Execute Permission
chmod 755 restore-perm-<timestamp>.cmd
3. Execute the Restore Script
./restore-perm-<timestamp>.cmd
This will:
- Restore ownership (
chown) - Restore permissions (
chmod) - Apply changes file by file
RAC and GRID_HOME Considerations
For Oracle RAC environments, keep these points in mind:
- Run both permission.pl and restore-perm as root
- Review the restore script for:
- Node-specific paths
- Hostname-specific entries
- If required, adjust node names before execution
This avoids accidental permission issues across cluster nodes.
Best Practices Before Running the Script
✔ Always capture permissions before patching
✔ Store the restore script in a safe backup location
✔ Review the restore script in RAC setups
✔ Test in non-production environments first
✔ Do not edit permissions manually unless required
Important Caution
This script is provided for educational purposes only and is not supported by Oracle Support Services.
Although tested internally and widely used by DBAs, you should:
- Review the script
- Test it in your environment
- Verify formatting after downloading (tabs, spaces, line endings)
Different editors and operating systems can alter script formatting.
When Should You Use This Script?
This script is extremely useful during:
- Oracle patching (RU / OJVM)
- ORACLE_HOME cloning
- OS migrations
- Security hardening
- Disaster recovery preparation
- Permission troubleshooting
In short, any time permissions matter — this script protects you.
Final Thoughts
File permission issues are one of the most common yet overlooked causes of Oracle downtime. This simple Perl-based solution gives DBAs a reliable rollback mechanism for permissions, saving hours of manual work and reducing risk.
If you manage Oracle databases in production, capturing permissions before change should be a standard habit.




