A safe deletion system using centralized trash storage in /scratch/trashcan.
Test with a single existing user:
cd ~/safe_rm_system
./deploy.sh -u yourusernameDeploy system-wide (all existing users):
cd ~/safe_rm_system
./deploy.shNote:
- New users created later will be set up automatically on first use of
rm - Deployment continues even if rm alias setup needs manual configuration
- The script will show exact commands if manual alias setup is needed
- Centralized trash:
/scratch/trashcan/<username>/trash - User symlink:
/home/<username>/.trash->/scratch/trashcan/<username>/trash - Automatic setup: New users are configured automatically on first use
- Automatic migration: If
~/.trashexists as a directory, it's renamed to~/.trash.old - Old trash cleanup:
trash_cleanupalso cleans~/.trash.olddirectories (including loose files) - Permissions: User owns,
installergroup (gid 1012) has read/write access - Note: SGID doesn't work reliably on NFS, so
trash_cleanupusessudo -ufor .trash.old operations
- Saves /home space:
/homehas limited storage,/scratchis larger - Easier management: Single location for admin cleanup instead of scanning every user's home
- Group access:
installergroup access to trash for cleanup operations - Simplified cleanup: Direct access to
/scratch/trashcan/*,sudo -ufor home directories
safe_rm_system/
├── bin/
│ ├── safe_rm.sh # User command (replaces rm)
│ ├── trash_cleanup.sh # Admin cleanup tool
│ ├── setup_centralized_trash.sh # Initial setup script
│ └── setup_alias.sh # Alias configuration helper
├── docs/ # Documentation (if needed)
├── deploy.sh # Quick deployment script
└── README.md # This file
cd ~
mkdir -p safe_rm_system/bin
cd safe_rm_system
git init
# Add files to bin/ directorycd ~/safe_rm_system
chmod +x bin/*
chmod +x deploy.sh
./bin/setup_centralized_trash.shThis will set up existing users with:
/scratch/trashcan/<user>/trashdirectories- Symlinks:
/home/<user>/.trash->/scratch/trashcan/<user>/trash - Proper permissions (770, attempts SGID where supported)
- Migration of existing
.trashdirectories to.trash.old
Note: New users created after deployment are handled automatically by safe_rm!
Manual method:
ln -sf ~/safe_rm_system/bin/safe_rm.sh /usr/local/sw/bin/safe_rm
ln -sf ~/safe_rm_system/bin/trash_cleanup.sh /usr/local/sw/bin/trash_cleanupOr use deploy script:
For all users:
~/safe_rm_system/deploy.shFor a single user (testing):
~/safe_rm_system/deploy.sh -u usernameNote: Using symlinks means updates to the git repo automatically update the installed scripts!
The deploy script automatically attempts to configure the rm alias. Deployment continues regardless of whether automatic setup succeeds.
How it works:
The script detects your system's bash configuration file (priority order):
/usr/local/etc/usersrc/common(OpenHPC/Custom - like spydur)/etc/bashrc(RHEL/CentOS/Rocky)/etc/bash.bashrc(Debian/Ubuntu)
It uses the first file it finds and checks if the alias already exists before adding it.
Automatic setup (happens during deploy.sh Step 3):
If successful:
[OK] Successfully added safe_rm alias to /usr/local/etc/usersrc/common
Done! Users just need to reload: source ~/.bashrc
If manual setup needed:
[WARN] No write permission to /usr/local/etc/usersrc/common
Manual setup required. Please run as root or with sudo:
[shows exact commands]
NOTE: Deployment will continue. You can set up the alias later.
Manual setup commands (choose based on your system):
For OpenHPC/Custom (like spydur with /usr/local/etc/usersrc/common):
sudo bash << 'EOF'
cat >> /usr/local/etc/usersrc/common << 'ALIASEOF'
# Safe rm - move files to trash instead of permanent deletion
if [ -f /usr/local/sw/bin/safe_rm ]; then
unalias rm 2>/dev/null
alias rm='/usr/local/sw/bin/safe_rm'
fi
ALIASEOF
EOFFor standard RHEL/CentOS/Rocky (/etc/bashrc):
sudo bash << 'EOF'
cat >> /etc/bashrc << 'ALIASEOF'
# Safe rm - move files to trash instead of permanent deletion
if [ -f /usr/local/sw/bin/safe_rm ]; then
unalias rm 2>/dev/null
alias rm='/usr/local/sw/bin/safe_rm'
fi
ALIASEOF
EOFFor Debian/Ubuntu (/etc/bash.bashrc):
sudo bash << 'EOF'
cat >> /etc/bash.bashrc << 'ALIASEOF'
# Safe rm - move files to trash instead of permanent deletion
if [ -f /usr/local/sw/bin/safe_rm ]; then
unalias rm 2>/dev/null
alias rm='/usr/local/sw/bin/safe_rm'
fi
ALIASEOF
EOFVerify alias is working:
# Open new terminal or reload:
source ~/.bashrc
# Check alias:
alias rm
# Should show: alias rm='/usr/local/sw/bin/safe_rm'Important notes:
- The script is idempotent (safe to run multiple times - checks for existing alias first)
- Deployment continues even if alias setup needs manual intervention
- Only ONE config file is used (not all of them)
Bypassing safe_rm: Users can still use real rm when needed:
command rm file.txt- use real rm/bin/rm file.txt- use real rm directly
As installer user:
crontab -e
# Add this line:
0 2 * * * /usr/local/sw/bin/trash_cleanup --do-it >> /usr/local/sw/logs/trash_cleanup.log 2>&1# Move to trash (interactive prompt)
rm file.txt
# Move to trash (force, no prompt)
rm -f file.txt
rm -rf directory/
# Permanently delete (bypass safe_rm)
command rm file.txt
/bin/rm file.txt# Dry run - show statistics only
trash_cleanup
# Actually clean trash older than 7 days (default)
trash_cleanup --do-it
# Check specific user
trash_cleanup -u jtonini
# Custom retention period
trash_cleanup -a 3d --do-it # 3 days
trash_cleanup -a 12h --do-it # 12 hours
trash_cleanup -a 30m --do-it # 30 minutes
# Clean specific user with custom age
trash_cleanup -u jtonini -a 1d --do-itcd ~/safe_rm_system
# Make changes to scripts in bin/
git add .
git commit -m "Description of changes"
git push
# Symlinks in /usr/local/sw/bin/ automatically point to updated versions!# Show statistics for all users
trash_cleanup
# Manual check
du -sh /scratch/trashcan/*
# Check specific user
du -sh /scratch/trashcan/jtonini# View recent cleanup history
tail -f /usr/local/sw/logs/trash_cleanup.log
# View full log
less /usr/local/sw/logs/trash_cleanup.log
# Example log entries:
# 2024-11-10 02:00:15 | CLEANED | jtonini | age: 7 days | 3 directories removed
# 2024-11-10 02:00:18 | CLEANED | jtonini/.trash.old | age: 7 days | 2 loose files removed
# 2024-11-10 02:00:20 | REMOVED | jtonini/.trash.old | empty directory older than 30 days
# 2024-11-10 02:00:25 | SUMMARY | age: 7 days | cleaned 45 out of 714 users | remaining size: 42.3GiBUsers can restore their own files:
# List trash contents
ls -la ~/.trash/
# Each deletion is in a timestamped directory
ls ~/.trash/20241110_143022_123456789/
# Restore a file
cp ~/.trash/20241110_143022_123456789/tmp/myfile.txt ~/myfile.txt
# Or move it back
mv ~/.trash/20241110_143022_123456789/tmp/myfile.txt ~/Admins can access any user's trash via /scratch/trashcan/<username>/trash/
If a user had an existing ~/.trash directory (not a symlink), the setup script automatically:
- Renames it to
~/.trash.old(preserves old data) - Creates new symlink:
~/.trash->/scratch/trashcan/<user>/trash - Shows notice to user
The trash_cleanup script handles .trash.old directories:
- Cleans timestamped directories using the same age policy as regular trash
- Also cleans loose files (files not in timestamped directories) based on file age
- Removes empty
.trash.olddirectories after 30 days (gives users time to check/migrate) - Uses
sudo -uto access user home directories (permission handling) - Eventually all
.trash.olddirectories will be cleaned up automatically
Users can manually:
# Check old trash
ls ~/.trash.old/
# Migrate important files
mv ~/.trash.old/important.txt ~/
# Delete if no longer needed
/bin/rm -rf ~/.trash.oldNew users are handled automatically! When a new user first runs rm, safe_rm will:
- Create
/scratch/trashcan/username/trash - Create symlink
/home/username/.trash - Migrate any existing
.trashdirectory if present
Manual setup only needed for:
Bulk migration of existing users:
./bin/setup_centralized_trash.shSingle user setup/verification:
./deploy.sh -u username- Git Repository:
~/safe_rm_system/ - Installed Scripts:
/usr/local/sw/bin/safe_rm,/usr/local/sw/bin/trash_cleanup - Centralized Trash:
/scratch/trashcan/<username>/trash/ - User Symlink:
/home/<username>/.trash->/scratch/trashcan/<username>/trash - Old Trash:
/home/<username>/.trash.old(migration from old system) - Logs:
/usr/local/sw/logs/trash_cleanup.log
/scratch/trashcan/ drwxrwsrwx installer:installer (777 + sticky)
/scratch/trashcan/jtonini/ drwxrwx--- jtonini:installer (770)
/scratch/trashcan/jtonini/trash/ drwxrwxrwx jtonini:installer (777)
/home/jtonini/.trash lrwxrwxrwx -> /scratch/trashcan/jtonini/trash
- 777 on trash/ allows installer group to delete files owned by users
- Note: SGID doesn't work reliably on NFS mounts like /scratch
- sudo -u is used by trash_cleanup for operations in user home directories
- Symlink makes trash accessible from user's home directory
The /usr/local/sw/logs/trash_cleanup.log file contains:
When old files are deleted:
2024-11-10 02:00:15 | CLEANED | jtonini | age: 7 days | 3 directories removed
2024-11-10 02:00:18 | CLEANED | asmith/.trash.old | age: 7 days | 2 directories removed
2024-11-10 02:00:19 | CLEANED | asmith/.trash.old | age: 7 days | 5 loose files removed
When empty .trash.old directories are deleted:
2024-11-10 02:00:20 | REMOVED | jtonini/.trash.old | empty directory older than 30 days
Overall statistics for the cleanup run:
2024-11-10 02:00:25 | SUMMARY | age: 7 days | cleaned 45 out of 714 users | remaining size: 42.3GiB
2024-11-10 02:00:25 | SUMMARY | .trash.old | cleaned 3 users | remaining old trash: 1.2GiB
Check if alias exists:
alias rmIf not set, the automatic setup may have needed manual configuration. Run:
./bin/setup_alias.shThis will either add the alias or show you the exact commands to run as root.
After setting up, reload your shell:
source ~/.bashrcCheck that /scratch/trashcan has proper permissions:
ls -ld /scratch/trashcan
# Should show: drwxrwsrwx
# Fix if needed:
chmod 2777 /scratch/trashcanCheck cron job:
crontab -l | grep trash_cleanup
# Check cron logs:
grep trash_cleanup /var/log/cron
# Test manually:
trash_cleanup --do-itRecreate it:
# As installer, ensure trash directory exists
sudo -u username mkdir -p /scratch/trashcan/username/trash
# Create symlink as user
sudo -u username ln -sf /scratch/trashcan/username/trash /home/username/.trashThis is expected - installer can't directly access user home directories. The trash_cleanup script uses sudo -u to work around this. Ensure installer has sudo privileges for all users.
- Each user can only access their own trash via the symlink
installergroup has access to centralized trash in/scratchfor cleanup.trash.olddirectories in home are accessed viasudo -ufor permission- Files in trash retain original permissions
- Regular
rmbypass (command rmor/bin/rm) available for permanent deletion - Timestamped directories prevent conflicts between deletions
-
v1.2 - Fixed permission handling
- Added
sudo -ufor all .trash.old operations - Added loose file cleanup in .trash.old
- Fixed SINGLE_USER flag respect in .trash.old section
- Changed trash directory permissions to 777 (NFS doesn't support SGID)
- Shows remaining trash size after cleanup (not initial size)
- Added
-
v1.1 - Bug fixes
- Fixed deploy.sh to use .sh extension for symlinks
- Added .trash.old migration and cleanup
- Improved reporting with user statistics
-
v1.0 - Initial release with centralized trash system
- safe_rm: Moves files to
/scratch/trashcan/<user>/trash - trash_cleanup: Scans centralized location, generates statistics
- setup_centralized_trash.sh: Automated setup with proper permissions
- Auto-migration: Existing ~/.trash renamed to ~/.trash.old
- safe_rm: Moves files to
To contribute or suggest improvements:
- Make changes in
~/safe_rm_system/ - Test thoroughly
- Commit with descriptive messages
- Update this README if needed
Internal tool for HPC cluster management.