summaryrefslogtreecommitdiffstats
path: root/zupdate.cc
diff options
context:
space:
mode:
Diffstat (limited to 'zupdate.cc')
-rw-r--r--zupdate.cc56
1 files changed, 33 insertions, 23 deletions
diff --git a/zupdate.cc b/zupdate.cc
index e87d9e1..fce00b3 100644
--- a/zupdate.cc
+++ b/zupdate.cc
@@ -67,15 +67,20 @@ void show_help()
"to be safe and not cause any data loss. Therefore, existing lzip\n"
"compressed files are never overwritten nor deleted.\n"
"\nThe names of the original files must have one of the following extensions:\n"
- "\n'.bz2', '.gz', '.xz', or '.zst', which are recompressed to '.lz'.\n"
+ "\n'.bz2', '.gz', '.xz', '.zst', or '.Z', which are recompressed to '.lz'.\n"
"\n'.tbz', '.tbz2', '.tgz', '.txz', or '.tzst', which are recompressed to '.tlz'.\n"
"\nUsage: zupdate [options] [files]\n"
"\nExit status is 0 if all the compressed files were successfully recompressed\n"
- "(if needed), compared, and deleted (if requested). Non-zero otherwise.\n"
+ "(if needed), compared, and deleted (if requested). 1 if a non-fatal error\n"
+ "occurred (file not found or not regular, or has invalid format, or can't be\n"
+ "deleted). 2 if a fatal error occurred (compressor can't be run, or\n"
+ "comparison fails).\n"
"\nOptions:\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
+ " -e, --expand-extensions expand combined extensions; tgz -> tar.lz\n"
" -f, --force don't skip a file even if the .lz exists\n"
+ " -i, --ignore-errors ignore non-fatal errors\n"
" -k, --keep keep (don't delete) input files\n"
" -l, --lzip-verbose pass one option -v to the lzip compressor\n"
" -M, --format=<list> process only the formats in <list>\n"
@@ -94,7 +99,7 @@ void show_help()
}
-int cant_execute( const std::string & command, const int status )
+void cant_execute( const std::string & command, const int status )
{
if( verbosity >= 0 )
{
@@ -105,7 +110,6 @@ int cant_execute( const std::string & command, const int status )
std::fprintf( stderr, "%s: Can't execute '%s'\n",
program_name, command.c_str() );
}
- return 1;
}
@@ -130,11 +134,11 @@ void set_permissions( const char * const rname, const struct stat & in_stats )
}
- // Return 0 if success, -1 if file skipped, 1 if error.
+// Return value: 0 = success, -1 = file skipped, 1 = error, 2 = fatal error.
int zupdate_file( const std::string & name, const char * const lzip_name,
const std::vector< std::string > & lzip_args2,
- const bool force, const bool keep_input_files,
- const bool no_rcfile )
+ const bool expand, const bool force,
+ const bool keep_input_files, const bool no_rcfile )
{
// bzip2, gzip, and lzip are the primary formats. xz and zstd are optional.
static int disable_xz = -1; // tri-state bool
@@ -155,7 +159,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
}
rname.assign( name, 0, name.size() - std::strlen( extension_from( eindex ) ) );
rname += ( std::strcmp( extension_to( eindex ), ".tar" ) == 0 ) ?
- ".tlz" : ".lz"; // keep combined extension
+ ( expand ? ".tar.lz" : ".tlz" ) : ".lz";
}
const char * const compressor_name = get_compressor_name( format_index );
if( !compressor_name )
@@ -226,7 +230,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
std::fprintf( stderr, "Recompressing file '%s'\n", name.c_str() );
int fda[2]; // pipe between decompressor and compressor
if( pipe( fda ) < 0 )
- { show_error( "Can't create pipe", errno ); return 1; }
+ { show_error( "Can't create pipe", errno ); return 2; }
const pid_t pid = fork();
if( pid == 0 ) // child1 (decompressor)
@@ -250,7 +254,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
_exit( 1 );
}
if( pid < 0 ) // parent
- { show_fork_error( compressor_name ); return 1; }
+ { show_fork_error( compressor_name ); return 2; }
const pid_t pid2 = fork();
if( pid2 == 0 ) // child2 (lzip compressor)
@@ -276,19 +280,19 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
_exit( 1 );
}
if( pid2 < 0 ) // parent
- { show_fork_error( lzip_name ); return 1; }
+ { show_fork_error( lzip_name ); return 2; }
close( fda[0] ); close( fda[1] );
- int retval = wait_for_child( pid, compressor_name );
- int retval2 = wait_for_child( pid2, lzip_name );
+ const int retval = wait_for_child( pid, compressor_name );
+ const int retval2 = wait_for_child( pid2, lzip_name );
if( retval || retval2 )
{ if( !lz_lz_exists ) std::remove( rname2.c_str() ); // lzip < 1.20
- std::remove( rname.c_str() ); return 1; }
+ std::remove( rname.c_str() ); return retval2 ? 2 : 1; }
if( stat( rname.c_str(), &st ) != 0 &&
( lz_lz_exists || stat( rname2.c_str(), &st ) != 0 ||
std::rename( rname2.c_str(), rname.c_str() ) != 0 ) )
{ show_file_error( rname.c_str(), "Error renaming output file", errno );
- return 1; } // lzip < 1.11
+ return 2; } // lzip < 1.11
set_permissions( rname.c_str(), in_stats );
}
@@ -296,8 +300,8 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
if( lz_exists && verbosity >= 1 )
std::fprintf( stderr, "Comparing file '%s'\n", name.c_str() );
std::string zcmp_command( invocation_name );
- unsigned i = zcmp_command.size();
- while( i > 0 && zcmp_command[i-1] != '/' ) --i;
+ unsigned i = zcmp_command.size();
+ while( i > 0 && zcmp_command[i-1] != '/' ) --i; // strip "zupdate"
zcmp_command.resize( i ); zcmp_command.insert( zcmp_command.begin(), '\'' );
zcmp_command += "zcmp' "; // '[dir/]zcmp'
if( no_rcfile ) zcmp_command += "-N ";
@@ -307,7 +311,7 @@ int zupdate_file( const std::string & name, const char * const lzip_name,
int status = std::system( zcmp_command.c_str() );
if( status != 0 )
{ if( !lz_exists ) std::remove( rname.c_str() );
- return cant_execute( zcmp_command, status ); }
+ cant_execute( zcmp_command, status ); return 2; }
}
if( !keep_input_files && std::remove( name.c_str() ) != 0 && errno != ENOENT )
@@ -329,7 +333,9 @@ int main( const int argc, const char * const argv[] )
int recursive = 0; // 1 = '-r', 2 = '-R'
std::list< std::string > filenames;
std::vector< std::string > lzip_args2; // args to lzip, maybe empty
+ bool expand = false;
bool force = false;
+ bool ignore_errors = false;
bool keep_input_files = false;
bool no_rcfile = false;
program_name = "zupdate";
@@ -347,8 +353,10 @@ int main( const int argc, const char * const argv[] )
{ '7', 0, Arg_parser::no },
{ '8', 0, Arg_parser::no },
{ '9', 0, Arg_parser::no },
+ { 'e', "expand-extensions", Arg_parser::no },
{ 'f', "force", Arg_parser::no },
{ 'h', "help", Arg_parser::no },
+ { 'i', "ignore-errors", Arg_parser::no },
{ 'k', "keep", Arg_parser::no },
{ 'l', "lzip-verbose", Arg_parser::no },
{ 'M', "format", Arg_parser::yes },
@@ -367,7 +375,7 @@ int main( const int argc, const char * const argv[] )
const Arg_parser parser( argc, argv, options );
if( parser.error().size() ) // bad option
- { show_error( parser.error().c_str(), 0, true ); return 1; }
+ { show_error( parser.error().c_str(), 0, true ); return 2; }
maybe_process_config_file( parser );
@@ -383,8 +391,10 @@ int main( const int argc, const char * const argv[] )
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
lzip_args2.push_back( "-" ); lzip_args2.back() += code; break;
+ case 'e': expand = true; break;
case 'f': force = true; break;
case 'h': show_help(); return 0;
+ case 'i': ignore_errors = true; break;
case 'k': keep_input_files = true; break;
case 'l': lzip_args2.push_back( "-v" ); break;
case 'M': parse_format_list( arg, pn ); break;
@@ -410,7 +420,7 @@ int main( const int argc, const char * const argv[] )
const char * const lzip_name = get_compressor_name( fmt_lz );
if( !lzip_name )
- { show_error( "Missing name of compressor for lzip format." ); return 1; }
+ { show_error( "Missing name of compressor for lzip format." ); return 2; }
for( ; argind < parser.arguments(); ++argind )
filenames.push_back( parser.argument( argind ) );
@@ -422,11 +432,11 @@ int main( const int argc, const char * const argv[] )
bool error = false;
while( next_filename( filenames, input_filename, error, recursive, true ) )
{
- int tmp = zupdate_file( input_filename, lzip_name, lzip_args2, force,
- keep_input_files, no_rcfile );
+ int tmp = zupdate_file( input_filename, lzip_name, lzip_args2, expand,
+ force, keep_input_files, no_rcfile );
if( tmp < 0 ) error = true;
if( tmp > retval ) retval = tmp;
- if( tmp > 0 ) break;
+ if( tmp >= 2 || ( tmp == 1 && !ignore_errors ) ) break;
}
if( error && retval == 0 ) retval = 1;
return retval;