[ale] How can I delete links that can't be seen by stat?

Scott Plante splante at insightsys.com
Wed Dec 12 15:10:24 EST 2012


I'm reaching way back to stuff I learned in the '80s, but it looks like the actual file is gone, but the directory entry is still there. As I recall, directory entries were file names that pointed to inodes, and the inode had pointers to the blocks of the file, permissions, etc. An inode could have multiple directory entries and these were "hard links" usually created with ln but no "-s" parameter. The file was only deleted when the last hard linked directory entry was removed. The number right after the permissions in "ls -l" was the number of hard links. Inodes not deleted but with no directory entries are what ended up in lost+found. This could happen if you deleted an open file then powered off without closing it. 


It looks like these are directory entries that somehow ended up remaining after the file was deleted. You might try the "unlink" command. I'm not sure how this would have happened, though. Is it reproducible? 

Scott 
----- Original Message -----

From: "James Sumners" <james.sumners at gmail.com> 
To: "Atlanta Linux Enthusiasts - Yes! We run Linux!" <ale at ale.org> 
Sent: Tuesday, December 11, 2012 1:00:25 PM 
Subject: [ale] How can I delete links that can't be seen by stat? 

Check out https://www.dropbox.com/s/moq4wmeas42blu9/broken_links.png 

In the screenshot, you'll see a list of links that have no properties 
whatsoever according to `ls`. These are supposed to be hard links. 

Here's the scenario: 

I have an NFS mount where I send nightly backups. These nightly 
backups use a common "full backup" and a series of differential 
backups. I'm using rsync to do this. At some point, the nightly 
backups failed due to low disk space and got out-of-sync. So I'm 
removing old backups and starting anew. However, after deleting the 
first few "old" backups I encountered this problem where `rm` can't 
remove these files since it can't lstat() them. 

Anyone know how I can delete these links? 

For reference, my backup script is: 

################################################## 

#!/bin/bash 

# Pre-execution check for bsfl 
# Set options afterward 
if [ ! -f /etc/bsfl ]; then 
echo "Backup script requires bsfl (https://code.google.com/p/bsfl/)." 
exit 1 
fi 
source /etc/bsfl 

### Options ### 

# Set to the desired logfile path and name 
LOG_FILE="$(dirname $0)/logs/runbackup-$(date +'%m-%d-%Y').log" 

# Set to the file that contains backup exclusions (format = line 
separated paths) 
EXCLUDES="$(dirname $0)/excludes" 

# Set to the NFS mount point 
# Be sure to configure /etc/fstab appropriately 
NFS_DIR="$(dirname $0)/clyde" 

# Set to test string for testing NFS mount success 
NFS_MOUNT_TEST="^clyde" 

# Set to the remote backup container directory 
# Backups will be stored in subdirectories of this directory 
BACKUP_DIR="${NFS_DIR}" 

# Set to the email address that will recieve notifications 
# of backup failures 
ERROR_EMAIL_ADDR="your_email_address at mail.clayton.edu" 


### Begin actual script ### 

function notify { 
mail -s "Backup failure on $(hostname)" ${ERROR_EMAIL_ADDR} < ${LOG_FILE} 
} 

# Turn on bsfl logging support 
LOG_ENABLED="yes" 

# We need to be root to 1) read all files and 2) mount the NFS 
USER=$(whoami) 
if [ "${USER}" != "root" ]; then 
log_error "Backup must be run as root." 
notify 
die 2 "Backup must be run as root." 
fi 

log "Mounting NFS" 
mount ${NFS_DIR} 

NFS_MOUNTED=$(cat /proc/mounts | grep ${NFS_MOUNT_TEST}) 
if [ ! $? -eq 0 ]; then 
log_error "Could not mount NFS." 
notify 
umount ${NFS_DIR} 
die 3 "Could not mount NFS." 
fi 

# Let's make sure we have enough room on the remote system 
STAT_INFO=$(stat -f --format='%b %a %S' ${NFS_DIR}) 
TOTAL_BLOCKS=$(echo ${STAT_INFO} | awk '{print $1}') 
FREE_BLOCKS=$(echo ${STAT_INFO} | awk '{print $2}') 
BLOCK_SIZE=$(echo ${STAT_INFO} | awk '{print $3}') 
# (1024bytes * 1024kilobytes) / (x bytes) = (1 megabyte [in bytes]) / (x bytes) 
# => number of blocks in 1 megabyte = y 
REMOTE_FREE_BYTES=$(echo "${FREE_BLOCKS} / (1048576 / ${BLOCK_SIZE})" | bc -l) 
log "Remote free bytes = ${REMOTE_FREE_BYTES}" 

STAT_INFO=$(stat -f --format='%b %a %S' /) 
TOTAL_BLOCKS=$(echo ${STAT_INFO} | awk '{print $1}') 
FREE_BLOCKS=$(echo ${STAT_INFO} | awk '{print $2}') 
BLOCK_SIZE=$(echo ${STAT_INFO} | awk '{print $3}') 
LOCAL_USED_BYTES=$(echo "(${TOTAL_BLOCKS} - ${FREE_BLOCKS}) / (1048576 
/ ${BLOCK_SIZE})" | bc -l) 
log "Local used bytes = ${LOCAL_USED_BYTES}" 

REMOTE_HAS_ROOM=$(echo "${REMOTE_FREE_BYTES} > ${LOCAL_USED_BYTES}" | bc -l) 
if [ ${REMOTE_HAS_ROOM} -eq 0 ]; then 
log_error "Remote system does not have enough free space for the backup." 
notify 
umount ${NFS_DIR} 
die 4 "Remote system does not have enough free space for the backup." 
else 
log "Remote system has enough room. Proceeding with backup." 
log "===== ===== ===== =====" 
log "" 
fi 

if [ ! -d ${BACKUP_DIR} ]; then 
mkdir ${BACKUP_DIR} 
fi 

DIR_READY=0 

today=$(date +'%m.%d.%Y') 
sixthday=$(date -d'-6 days' +'%m.%d.%Y') 
if [ -d "${BACKUP_DIR}/${sixthday}" ]; then 
# Move the sixth day to today 
log "Moving the oldest backup to be today's backup." 
mv "${BACKUP_DIR}/${sixthday}" "${BACKUP_DIR}/${today}" 2>&1 1>>${LOG_FILE} 
ln -sf "${BACKUP_DIR}/${today}" "${BACKUP_DIR}/complete_backup" 2>&1 
1>>${LOG_FILE} 
log "" 
DIR_READY=1 
fi 

if [ -d ${BACKUP_DIR}/${today} ]; then 
DIR_READY=1 
log "Today's backup directory already exists. Will update today's backup." 
log "" 
fi 

if [ ${DIR_READY} -eq 0 ]; then 
yesterday=$(date -d'-1 days' +'%m.%d.%Y') 
if [ -d "${BACKUP_DIR}/${yesterday}" ]; then 
log "Copying yeterday's backup (${yesterday}) into place for 
differential backup." 
cp -al "${BACKUP_DIR}/${yesterday}" "${BACKUP_DIR}/${today}" 2>&1 
1>>${LOG_FILE} 
log "" 
else 
last_backup_dir=$(ls -1 ${BACKUP_DIR} | sort -nr | head -n 1) 
log "Copying most recent backup (${last_backup_dir}) into place 
for differential backup." 
cp -al "${BACKUP_DIR}/${last_backup_dir}" "${BACKUP_DIR}/${today}" 
2>&1 1>>${LOG_FILE} 
log "" 
fi 

DIR_READY=1 
fi 

if [ ${DIR_READY} -eq 1 ]; then 
rsync --archive --one-file-system --hard-links --human-readable --inplace \ 
--numeric-ids --delete --delete-excluded --exclude-from=${EXCLUDES} \ 
--verbose --itemize-changes / "${BACKUP_DIR}/${today}" 2>&1 1>>${LOG_FILE} 
else 
log_error "Couldn't determine destination backup directory?" 
notify 
fi 

log "" 
log "===== ===== ===== =====" 
log "Backup complete." 

umount ${NFS_DIR} 

################################################## 

-- 
James Sumners 
http://james.roomfullofmirrors.com/ 

"All governments suffer a recurring problem: Power attracts 
pathological personalities. It is not that power corrupts but that it 
is magnetic to the corruptible. Such people have a tendency to become 
drunk on violence, a condition to which they are quickly addicted." 

Missionaria Protectiva, Text QIV (decto) 
CH:D 59 
_______________________________________________ 
Ale mailing list 
Ale at ale.org 
http://mail.ale.org/mailman/listinfo/ale 
See JOBS, ANNOUNCE and SCHOOLS lists at 
http://mail.ale.org/mailman/listinfo 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.ale.org/pipermail/ale/attachments/20121212/3c0fd2da/attachment.html>


More information about the Ale mailing list