diff options
Diffstat (limited to 'zupdate.cc')
-rw-r--r-- | zupdate.cc | 56 |
1 files changed, 33 insertions, 23 deletions
@@ -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; |