0

I am trying to get rid of the "Removing leading" messages from a cron that runs a backup job with tar. The emails still have these messages, and I'm using cronic to only send emails when there are errors.:

ERROR OUTPUT:
/bin/tar: Removing leading `/' from member names
/bin/tar: Removing leading `/' from hard link targets
/bin/tar: Removing leading `/' from member names

I edited the tar -czf to include the -C option that I got from this thread as such.

my($tarcmd) = "$tar -czf $backupname -C / $args $backup";

Where can I remove the leading slash as mentioned in Orville Bennet's blog post?

Perhaps somewhere in this section of the script?

            # drobo=/path/to/drobo
if( /^\s*drobo\s*=\s*(.*)$/ ) {
$drobopath=$1;
}
            # tarargs=global tar arguments
elsif( /^\s*tarargs\s*=\s*(.*)$/ ) {
$tarargs=$1;
}
            # backup [condition] =/path/for/backup [tar args]
elsif( /^\s*backup\s*(\[[^\]]*\])?\s*=\s*(.*)$/ ) {
push(@backup,$2);
if( $1 ) {
    $condition{$2} = $1;

Here is the entire script:

#!/usr/bin/perl -W
use POSIX;
# Global variables
# Host name will be used as name of directory for backups on drobo
my($hostname)=`/bin/hostname`;
chomp($hostname);
my($configfile)="/etc/drobo-backup.conf";
my($tar)="/bin/tar";        # Path to tar utility
my($mkdir)="/bin/mkdir";    # Path to mkdir utility
my($verbose)=0;
my($testmode)=0;

sub Usage {
    print "Usage: drobo-backup [-v] [-c configfile]\n";
    print "   -v : verbose mode";
    print "   -c : specify configuration file (default $configfile)";
    print "   -n : printd but don't execute commands (for testing config)";
    exit 1;
}

# Subroutine to back up one directory to drobo
sub do_backup {
    my($drobo,$args,$backup,$cond) = @_;

# The backup arg may include per-backup tar args.  Strip off these
# and quotes to get at the filename
    my($backuppath)=$backup;
# If quoted, remove quotes for naming.  Otherwise it is required not
# not to have embedded blanks so that per-backup tar arguments may follow.
    if( $backuppath =~ /^"([^"]*)"/ ) { # double quotes
    $backuppath = $1;
    }
    elsif( $backuppath =~ /^'([^']*)'/ ) { # single quotes
    $backuppath = $1;
    }
    elsif( $backuppath =~ /^(\S*)/ ) { # otherwise no blanks in path
    $backuppath = $1;
    }

    if( -d $backuppath || -f $backuppath ) { # check it is a valid dir or file
    my($drobodir) = "$drobo/$hostname";
    # make sure the drobo subdirectory for this host exists
    my($mkdircmd) = "$mkdir $drobodir";
    if( $verbose ) {
        print "$mkdircmd\n";
    }
    if( ! ($testmode || -d $drobodir) ) {
        system($mkdircmd);
    }
    # if it did not work, bail.
    if( ! ($testmode || -d $drobodir) ) {
        print "Failed to create destination dir $drobodir\n";
        exit 1;
    }
# construct tarfile name, e.g. usr-local.tgz
    my($backupfilestem) = $backuppath;
                # Sanitize the tarfile name
    while($backupfilestem =~ s,^/,,) { next; } # remove any leading slash(es)
    while($backupfilestem =~ s,/$,,) { next; } # remove any trailing slash(es)
    $backupfilestem =~ s,/,-,g; # all internal slashes become hyphens
    $backupfilestem =~ s/[^-\.\w]/X/g;# all remaining non-word chars exc . become X

    my($backupname)="$drobodir/$backupfilestem-new.tgz";
    my($backuprename) = "$drobodir/$backupfilestem.tgz";
    my($tarcmd) = "$tar -czf $backupname -C / $args $backup";

    if( $cond ) {
        $cond =~ s/^\[//;   # remove the [ ] around condition
        $cond =~ s/\]$//;
        $cond =~ s/BKPATH/$backuppath/g; # convenience substitutions
        $cond =~ s/TARFILE/$backuprename/g;
        $cond =~ s/TARDIR/$drobodir/g;
    }
    if( $cond && WEXITSTATUS(system("test $cond")) != 0 ) {
        if( $verbose ) {
        print "Condition [$cond] tests false\n";
        print "No backup of $backuppath\n";
        }
    }
    else {
        if( $verbose ) {
        if( $cond ) {
            print "Condition [$cond] tests true\n";
        }
        print "$tarcmd\n";
        }
    # tar returns 0 for success, 1 for warnings such as file changed while
    # being copied.  So we take either as meaning success.  Rename foo-new.tgz
    # to the (usually existing) foo.tgz.  N.B. system() returns status<<8.
        if( !$testmode ) {
        if( WEXITSTATUS(system($tarcmd)) >= 2 ) {
            print "\nBackup of $backuppath FAILED\n\n";
            # to avoid bad backup being renamed to good in second try, call it bad
            $backuprename = "$drobodir/$backupfilestem-FAILED.tgz";
        }
        if( rename("$backupname","$backuprename") ) {
            print "Backed up $backuppath to $backuprename\n";
        }
        else {
            print "Failed to rename $backupname to $backuprename: $!\n";
        }
        }
    }
    }
    else {
    print "$backuppath is not a directory or file\n";
    }
}



# default arguments to use on every backup
my($tarargs)="--atime-preserve --one-file-system";


# set default drobopath according to dsm (lc) or cis (rh) network

my($drobopath)="/path"; #
if($hostname =~ /\.our\.domain\.edu/) {
    $drobopath="/path"; #
}


# Process command line arguments
while(@ARGV) {
    if( $ARGV[0] eq "-c" ) {    # -c configfile
    shift (@ARGV);
    if(@ARGV) {
        $configfile = $ARGV[0];
    }
    else {
        Usage();
    }
    }
    elsif( $ARGV[0] eq "-v" ) { # -v (verbose mode)
    ++$verbose;
    }
    elsif( $ARGV[0] eq "-n" ) { # -n (no-exec mode)
    $testmode = 1;
    }
    else {          # unrecognized argument
    Usage();
    }

    shift (@ARGV);
}


open(CONFIGFILE,$configfile) || die("Cannot open configfile $configfile: $!");

if($verbose) {
    print "Reading configfile $configfile\n";
}

my(@backup);
my(%condition);
my($configline) = 0;
foreach (<CONFIGFILE>) {
    $configline++;
    if( /^\s*#/ || /^\s*$/ ) {  # skip blank & comment lines (first nonblank is #)
    next;
    }
                # drobo=/path/to/drobo
    if( /^\s*drobo\s*=\s*(.*)$/ ) {
    $drobopath=$1;
    }
                # tarargs=global tar arguments
    elsif( /^\s*tarargs\s*=\s*(.*)$/ ) {
    $tarargs=$1;
    }
                # backup [condition] =/path/for/backup [tar args]
    elsif( /^\s*backup\s*(\[[^\]]*\])?\s*=\s*(.*)$/ ) {
    push(@backup,$2);
    if( $1 ) {
        $condition{$2} = $1;
    }
    }
    else {
    print "Unknown config directive at line $configline in $configfile:\n";
    print;
    exit 1;
    }
}

close(CONFIGFILE);


my($path);
foreach $path (@backup) {
    do_backup($drobopath,$tarargs,$path,$condition{$path});
}


# For unknown reason, rename of some files often fails.  Try again here.

foreach $tarfile ( glob("$drobopath/$hostname/*-new.tgz") ) {
    $rename_name = $tarfile;
    $rename_name =~ s/-new\.tgz$/.tgz/;
    if( rename($tarfile,$rename_name) ) {
    print "Second try renamed $tarfile to $rename_name\n";
    }
}
1

In your perl script, the filenames are read from a file with foreach (<CONFIGFILE>) and added to an array with push(@backup,$2);. For each item in the array (foreach $path (@backup)) the subroutine do_backup() is called and the filename is parameter $backup. This is used unchanged in setting the $tarcmd, as you noted. The solution is therefore to edit this variable just before that line:

$backup =~ s|/|| if $backup =~ m|^['"]?/|; # remove any leading slash
my($tarcmd) = "$tar -czf $backupname -C / $args $backup";

This will substitute (s|/||) the first slash by nothing, if the variable matches the pattern ^['"]?/, i.e. at the start, a possible quote or double-quote, then a slash. This is because earlier code assumes that the path given in this variable might be surrounded by quotes, for example to protect spaces.

However, you can only do this and add the -C / if the path does start with slash, so unless you are sure this is the case you should probably have 2 versions, eg

my($tarcmd);
if($backup =~ m|^['"]?/|){
   $backup =~ s|/||;  # remove any leading slash
   $tarcmd = "$tar -czf $backupname -C / $args $backup";
}else{
   $tarcmd = "$tar -czf $backupname $args $backup";
}
|improve this answer|||||
  • If you remove the first slash with nothing, the script becomes sensitive to which directory the script is run, which may not be desirable. – Johan Myréen Dec 13 '16 at 19:23
  • Sorry, I was getting there. – meuh Dec 13 '16 at 19:27
  • This is in my opinion the cleanest solution. You should in one way or another try to avoid give absolute paths as directories. – Johan Myréen Dec 13 '16 at 19:41
0

You will have to do something like:

tar -czf backup.tar.gz -C / $(ls /)

i.e. list all files and directories in the root directory without a leading slash. But this is perhaps not a very sensible thing to do, since the root directory contains all kinds on entries you wouldn't want to back up, like the /proc directory, the /dev directory, etc.

|improve this answer|||||
  • Well we use a Drobo for backups and it has a config file to include/exclude files. But this doesn't seem like the most elegant solution. How about the last idea from another post? Adding this to the end or the tar command: 2>&1 | grep -v "Removing leading". – RobbieTheK Dec 13 '16 at 18:43
  • Perhaps use $(/bin/ls -A /), just in case there are .files. – Erik Bennett Apr 1 '19 at 19:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.