28 #include <boost/format.hpp>
51 using namespace zypp::filesystem;
53 #define WARNINGMAILPATH "/var/log/YaST2/"
54 #define FILEFORBACKUPFILES "YaSTBackupModifiedFiles"
55 #define MAXRPMMESSAGELINES 10000
57 #define WORKAROUNDRPMPWDBUG
61 namespace zypp_readonly_hack
71 #if 1 // No more need to escape whitespace since rpm-4.4.2.3
72 const char* quoteInFilename_m =
"\'\"";
74 const char* quoteInFilename_m =
" \t\'\"";
76 inline string rpmQuoteFilename(
const Pathname & path_r )
78 string path( path_r.asString() );
81 pos = path.find_first_of( quoteInFilename_m, pos ) )
83 path.insert( pos,
"\\" );
96 #if defined(WORKAROUNDRPMPWDBUG)
100 AutoDispose<char*> cwd( ::get_current_dir_name(), ::free );
103 WAR <<
"Can't get cwd!" << endl;
124 MIL <<
"trusted key added to zypp Keyring. Importing" << endl;
128 _rpmdb.importPubkey( key );
132 ERR <<
"Could not import key " << key.
id() <<
" (" << key.
name() <<
" from " << key.
path() <<
" in rpm database" << endl;
138 MIL <<
"Trusted key removed from zypp Keyring. Removing..." << endl;
143 _rpmdb.removePubkey( key );
147 ERR <<
"Could not remove key " << key.
id() <<
" (" << key.
name() <<
") from rpm database" << endl;
156 unsigned diffFiles(
const string file1,
const string file2,
string& out,
int maxlines)
166 ExternalProgram prog(argv,ExternalProgram::Discard_Stderr,
false, -1,
true);
177 if (maxlines<0?
true:count<maxlines)
192 inline string stringPath(
const Pathname & root_r,
const Pathname & sub_r )
205 if ( obj == RpmDb::DbSI_NO_INIT )
211 #define ENUM_OUT(B,C) str << ( obj & RpmDb::B ? C : '-' )
234 #define FAILIFNOTINITIALIZED if( ! initialized() ) { ZYPP_THROW(RpmDbNotOpenException()); }
245 : _dbStateInfo( DbSI_NO_INIT )
246 #warning Check for obsolete memebers
247 , _backuppath (
"/var/adm/backup")
248 , _packagebackups(false)
249 , _warndirexists(false)
256 setenv(
"RPM_IgnoreFailedSymlinks",
"1", 1 );
268 MIL <<
"~RpmDb()" << endl;
271 MIL <<
"~RpmDb() end" << endl;
281 db_path =
"/var/lib/rpm";
285 PathInfo rpmdb_info(
root() + db_path +
"/Packages");
287 if ( rpmdb_info.isExist() )
288 return rpmdb_info.mtime();
308 #define ENUM_OUT(B,C) str << ( _dbStateInfo & B ? C : '-' )
334 bool quickinit( root_r.empty() );
336 if ( root_r.empty() )
339 if ( dbPath_r.empty() )
340 dbPath_r =
"/var/lib/rpm";
342 if ( ! (root_r.absolute() && dbPath_r.absolute()) )
344 ERR <<
"Illegal root or dbPath: " <<
stringPath( root_r, dbPath_r ) << endl;
348 MIL <<
"Calling initDatabase: " <<
stringPath( root_r, dbPath_r )
349 << ( doRebuild_r ?
" (rebuilddb)" :
"" )
350 << ( quickinit ?
" (quickinit)" :
"" ) << endl;
374 MIL <<
"QUICK initDatabase (no systemRoot set)" << endl;
387 ERR <<
"Cleanup on error: state " << info << endl;
402 MIL <<
"Cleanup: state " << info << endl;
411 MIL <<
"Update mode: Cleanup delayed until closeOldDatabase." << endl;
414 #warning CHECK: notify root about conversion backup.
429 MIL <<
"Syncronizing keys with zypp keyring" << endl;
438 MIL <<
"InitDatabase: " << *
this << endl;
464 ERR <<
"Bad database directory: " << dbInfo.
dbDir() << endl;
471 MIL <<
"Found rpm4 database in " << dbInfo.
dbDir() << endl;
475 MIL <<
"Creating new rpm4 database in " << dbInfo.
dbDir() << endl;
487 DBG <<
"Initial state: " << info_r <<
": " <<
stringPath( root_r, dbPath_r );
506 DBG <<
"Access state: " << info_r <<
": " <<
stringPath( root_r, dbPath_r );
515 bool dbEmpty = dbptr->empty();
518 MIL <<
"Empty rpm4 database " << dbInfo.
dbV4() << endl;
523 MIL <<
"Found rpm3 database " << dbInfo.
dbV3() << endl;
534 WAR <<
"Backup converted rpm3 database failed: error(" << res <<
")" << endl;
541 MIL <<
"Backup converted rpm3 database: " << dbInfo.
dbV3ToV4() << endl;
550 WAR <<
"Non empty rpm3 and rpm4 database found: using rpm4" << endl;
556 DBG <<
"Convert state: " << info_r <<
": " <<
stringPath( root_r, dbPath_r );
562 MIL <<
"Rpm3 database backup: " << dbInfo.
dbV3ToV4() << endl;
574 const char * v3backup =
"packages.rpm3";
575 const char * master =
"Packages";
576 const char * index[] =
598 PathInfo pi( dbdir_r );
601 ERR <<
"Can't remove rpm4 database in non directory: " << dbdir_r << endl;
605 for (
const char ** f = index; *f; ++f )
614 pi( dbdir_r + master );
617 MIL <<
"Removing rpm4 database " << pi << endl;
623 pi( dbdir_r + v3backup );
626 MIL <<
"Removing converted rpm3 database backup " << pi << endl;
640 const char * master =
"packages.rpm";
641 const char * index[] =
643 "conflictsindex.rpm",
654 PathInfo pi( dbdir_r );
657 ERR <<
"Can't remove rpm3 database in non directory: " << dbdir_r << endl;
661 for (
const char ** f = index; *f; ++f )
670 #warning CHECK: compare vs existing v3 backup. notify root
671 pi( dbdir_r + master );
674 Pathname m( pi.path() );
679 Pathname b( m.extend(
"3" ) );
684 Pathname b( m.extend(
".deleted" ) );
694 MIL <<
"(Re)moved rpm3 database to " << pi << endl;
734 MIL <<
"Calling closeDatabase: " << *
this << endl;
765 MIL <<
"closeDatabase: " << *
this << endl;
796 MIL <<
"RpmDb::rebuildDatabase" << *
this << endl;
799 PathInfo dbMaster(
root() +
dbPath() +
"Packages" );
800 PathInfo dbMasterBackup( dbMaster.path().extend(
".y2backup" ) );
804 opts.push_back(
"--rebuilddb");
805 opts.push_back(
"-vv");
812 PathInfo newMaster(
root()
825 if ( ! report->progress( (100 * newMaster.size()) / dbMaster.size(),
root() +
dbPath()) )
827 WAR <<
"User requested abort." << endl;
833 if ( line.compare( 0, 2,
"D:" ) )
835 errmsg += line +
'\n';
843 if ( rpm_status != 0 )
862 void computeKeyRingSync( std::set<Edition> & rpmKeys_r, std::list<PublicKeyData> & zyppKeys_r )
873 void updateIf(
const Edition & rpmKey_r )
875 std::string keyRelease( rpmKey_r.
release() );
876 int comp = _release.compare( keyRelease );
880 _release.swap( keyRelease );
881 _inRpmKeys = &rpmKey_r;
882 _inZyppKeys =
nullptr;
883 if ( !keyRelease.empty() )
884 DBG <<
"Old key in R: gpg-pubkey-" << rpmKey_r.
version() <<
"-" << keyRelease << endl;
886 else if ( comp == 0 )
890 _inRpmKeys = &rpmKey_r;
894 DBG <<
"Old key in R: gpg-pubkey-" << rpmKey_r.
version() <<
"-" << keyRelease << endl;
897 void updateIf(
const PublicKeyData & zyppKey_r )
899 std::string keyRelease( zyppKey_r.gpgPubkeyRelease() );
900 int comp = _release.compare( keyRelease );
904 _release.swap( keyRelease );
905 _inRpmKeys =
nullptr;
906 _inZyppKeys = &zyppKey_r;
907 if ( !keyRelease.empty() )
908 DBG <<
"Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() <<
"-" << keyRelease << endl;
910 else if ( comp == 0 )
914 _inZyppKeys = &zyppKey_r;
918 DBG <<
"Old key in Z: gpg-pubkey-" << zyppKey_r.gpgPubkeyVersion() <<
"-" << keyRelease << endl;
921 std::string _release;
922 const Edition * _inRpmKeys;
923 const PublicKeyData * _inZyppKeys;
928 std::map<std::string,Key> _keymap;
930 for_( it, rpmKeys_r.begin(), rpmKeys_r.end() )
932 _keymap[(*it).version()].updateIf( *it );
935 for_( it, zyppKeys_r.begin(), zyppKeys_r.end() )
937 _keymap[(*it).gpgPubkeyVersion()].updateIf( *it );
941 std::set<Edition> rpmKeys;
942 std::list<PublicKeyData> zyppKeys;
943 for_( it, _keymap.begin(), _keymap.end() )
945 DBG <<
"gpg-pubkey-" << (*it).first <<
"-" << (*it).second._release <<
" "
946 << ( (*it).second._inRpmKeys ?
"R" :
"_" )
947 << ( (*it).second._inZyppKeys ?
"Z" :
"_" ) << endl;
948 if ( ! (*it).second._inRpmKeys )
950 zyppKeys.push_back( *(*it).second._inZyppKeys );
952 if ( ! (*it).second._inZyppKeys )
954 rpmKeys.insert( *(*it).second._inRpmKeys );
957 rpmKeys_r.swap( rpmKeys );
958 zyppKeys_r.swap( zyppKeys );
965 MIL <<
"Going to sync trusted keys..." << endl;
967 std::list<PublicKeyData> zyppKeys( getZYpp()->keyRing()->trustedPublicKeyData() );
968 computeKeyRingSync( rpmKeys, zyppKeys );
969 MIL << (mode_r &
SYNC_TO_KEYRING ?
"" :
"(skip) ") <<
"Rpm keys to export into zypp trusted keyring: " << rpmKeys.size() << endl;
970 MIL << (mode_r &
SYNC_FROM_KEYRING ?
"" :
"(skip) ") <<
"Zypp trusted keys to import into rpm database: " << zyppKeys.size() << endl;
976 MIL <<
"Exporting rpm keyring into zypp trusted keyring" <<endl;
981 TmpFile tmpfile( getZYpp()->tmpPath() );
983 ofstream tmpos( tmpfile.
path().
c_str() );
984 for_( it, rpmKeys.begin(), rpmKeys.end() )
988 getData(
string(
"gpg-pubkey"), *it, result );
989 tmpos << result->tag_description() << endl;
994 getZYpp()->keyRing()->multiKeyImport( tmpfile.
path(),
true );
998 ERR <<
"Could not import keys into in zypp keyring" << endl;
1006 MIL <<
"Importing zypp trusted keyring" << std::endl;
1007 for_( it, zyppKeys.begin(), zyppKeys.end() )
1011 importPubkey( getZYpp()->keyRing()->exportTrustedPublicKey( *it ) );
1019 MIL <<
"Trusted keys synced." << endl;
1041 WAR <<
"Key " << pubkey_r <<
" can not be imported. (READONLY MODE)" << endl;
1048 bool hasOldkeys =
false;
1050 for_( it, rpmKeys.begin(), rpmKeys.end() )
1054 MIL <<
"Key " << pubkey_r <<
" is already in the rpm trusted keyring. (skip import)" << endl;
1058 if ( keyEd.version() != (*it).version() )
1061 if ( keyEd.release() < (*it).release() )
1063 MIL <<
"Key " << pubkey_r <<
" is older than one in the rpm trusted keyring. (skip import)" << endl;
1071 MIL <<
"Key " << pubkey_r <<
" will be imported into the rpm trusted keyring." << (hasOldkeys?
"(update)":
"(new)") << endl;
1077 std::string keyName(
"gpg-pubkey-" + keyEd.version() );
1079 opts.push_back (
"-e" );
1080 opts.push_back (
"--allmatches" );
1081 opts.push_back (
"--" );
1082 opts.push_back ( keyName.c_str() );
1095 ERR <<
"Failed to remove key " << pubkey_r <<
" from RPM trusted keyring (ignored)" << endl;
1099 MIL <<
"Key " << pubkey_r <<
" has been removed from RPM trusted keyring" << endl;
1105 opts.push_back (
"--import" );
1106 opts.push_back (
"--" );
1107 opts.push_back ( pubkey_r.
path().asString().c_str() );
1123 _(
"Failed to import public key from file %s: %s"))
1128 MIL <<
"Key " << pubkey_r <<
" imported in rpm trusted keyring." << endl;
1145 set<Edition>::const_iterator found_edition = rpm_keys.end();
1148 for_( it, rpm_keys.begin(), rpm_keys.end() )
1150 if ( (*it).version() == pubkeyVersion )
1158 if (found_edition == rpm_keys.end())
1160 WAR <<
"Key " << pubkey_r.
id() <<
" is not in rpm db" << endl;
1164 string rpm_name(
"gpg-pubkey-" + found_edition->asString());
1167 opts.push_back (
"-e" );
1168 opts.push_back (
"--" );
1169 opts.push_back ( rpm_name.c_str() );
1178 if ( line.substr( 0, 6 ) ==
"error:" )
1180 WAR << line << endl;
1184 DBG << line << endl;
1190 if ( rpm_status != 0 )
1194 _(
"Failed to remove public key %s: %s")) % pubkey_r.
asString()
1199 MIL <<
"Key " << pubkey_r <<
" has been removed from RPM trusted keyring" << endl;
1211 list<PublicKey> ret;
1214 for ( it.
findByName(
string(
"gpg-pubkey" ) ); *it; ++it )
1216 Edition edition = it->tag_edition();
1221 getData(
string(
"gpg-pubkey"), edition, result );
1222 TmpFile file(getZYpp()->tmpPath());
1228 os << result->tag_description();
1239 ERR <<
"Could not dump key " << edition.
asString() <<
" in tmp file " << file.
path() << endl;
1252 for ( it.
findByName(
string(
"gpg-pubkey" ) ); *it; ++it )
1254 Edition edition = it->tag_edition();
1256 ret.insert( edition );
1273 list<FileInfo> result;
1308 if (!name_r.empty())
1310 res = (it->tag_name() == name_r);
1331 return it->tag_name();
1402 librpmDb::db_const_iterator it;
1417 librpmDb::db_const_iterator it;
1418 it.findPackage( name_r );
1432 void RpmDb::getData(
const string & name_r,
const Edition & ed_r,
1435 librpmDb::db_const_iterator it;
1436 it.findPackage( name_r, ed_r );
1449 PathInfo file( path_r );
1450 if ( ! file.isFile() )
1452 ERR <<
"Not a file: " << file << endl;
1456 FD_t fd = ::Fopen( file.asString().c_str(),
"r.ufdio" );
1457 if ( fd == 0 || ::Ferror(fd) )
1459 ERR <<
"Can't open file for reading: " << file <<
" (" << ::Fstrerror(fd) <<
")" << endl;
1465 rpmts ts = ::rpmtsCreate();
1467 ::rpmtsSetVSFlags( ts, RPMVSF_DEFAULT );
1468 int res = ::rpmReadPackageFile( ts, fd, path_r.asString().c_str(), NULL );
1478 case RPMRC_NOTFOUND:
1479 WAR <<
"Signature is unknown type. " << file << endl;
1483 WAR <<
"Signature does not verify. " << file << endl;
1486 case RPMRC_NOTTRUSTED:
1487 WAR <<
"Signature is OK, but key is not trusted. " << file << endl;
1491 WAR <<
"Public key is unavailable. " << file << endl;
1495 ERR <<
"Error reading header." << file << endl;
1511 opts.push_back (
"-V");
1512 opts.push_back (
"--nodeps");
1513 opts.push_back (
"--noscripts");
1514 opts.push_back (
"--nomd5");
1515 opts.push_back (
"--");
1516 opts.push_back (packageName.c_str());
1537 if (line.length() > 12 &&
1538 (line[0] ==
'S' || line[0] ==
's' ||
1539 (line[0] ==
'.' && line[7] ==
'T')))
1544 filename.assign(line, 11, line.length() - 11);
1545 fileList.insert(filename);
1585 #if defined(WORKAROUNDRPMPWDBUG)
1586 args.push_back(
"#/");
1588 args.push_back(
"rpm");
1589 args.push_back(
"--root");
1590 args.push_back(
_root.asString().c_str());
1591 args.push_back(
"--dbpath");
1592 args.push_back(
_dbPath.asString().c_str());
1594 const char* argv[args.size() + opts.size() + 1];
1596 const char** p = argv;
1597 p =
copy (args.begin (), args.end (), p);
1598 p =
copy (opts.begin (), opts.end (), p);
1624 int inputfileFd = ::fileno( inputfile );
1630 FD_SET( inputfileFd, &rfds );
1637 int retval = select( inputfileFd+1, &rfds, NULL, NULL, &tv );
1641 ERR <<
"select error: " <<
strerror(errno) << endl;
1642 if ( errno != EINTR )
1648 static size_t linebuffer_size = 0;
1649 static char * linebuffer = 0;
1650 ssize_t nread =
getline( &linebuffer, &linebuffer_size, inputfile );
1653 if ( ::feof( inputfile ) )
1660 if ( linebuffer[nread-1] ==
'\n' )
1662 line += string( linebuffer, nread );
1665 if ( ! ::ferror( inputfile ) || ::feof( inputfile ) )
1668 clearerr( inputfile );
1717 void RpmDb::processConfigFiles(
const string& line,
const string& name,
const char* typemsg,
const char* difffailmsg,
const char* diffgenmsg)
1719 string msg = line.substr(9);
1722 string file1s, file2s;
1726 pos1 = msg.find (typemsg);
1729 if ( pos1 == string::npos )
1732 pos2 = pos1 + strlen (typemsg);
1734 if (pos2 >= msg.length() )
1737 file1 = msg.substr (0, pos1);
1738 file2 = msg.substr (pos2);
1740 file1s = file1.asString();
1741 file2s = file2.asString();
1745 file1 =
_root + file1;
1746 file2 =
_root + file2;
1750 int ret =
diffFiles (file1.asString(), file2.asString(), out, 25);
1756 ERR <<
"Could not create " << file.asString() << endl;
1760 ofstream notify(file.asString().c_str(), ios::out|ios::app);
1763 ERR <<
"Could not open " << file << endl;
1769 notify <<
str::form(
_(
"Changed configuration files for %s:"), name.c_str()) << endl;
1772 ERR <<
"diff failed" << endl;
1774 file1s.c_str(), file2s.c_str()) << endl;
1779 file1s.c_str(), file2s.c_str()) << endl;
1784 if (out.substr(0,4) ==
"--- ")
1786 out.replace(4, file1.asString().length(), file1s);
1789 if (pos != string::npos)
1791 out.replace(pos+5, file2.asString().length(), file2s);
1794 notify << out << endl;
1797 notify.open(
"/var/lib/update-messages/yast2-packagemanager.rpmdb.configfiles");
1802 WAR <<
"rpm created " << file2 <<
" but it is not different from " << file2 << endl;
1818 report->start(filename);
1833 report->finish( excpt_r );
1849 MIL <<
"RpmDb::installPackage(" << filename <<
"," << flags <<
")" << endl;
1858 ERR <<
"backup of " << filename.asString() <<
" failed" << endl;
1861 report->progress( 0 );
1867 opts.push_back(
"-i");
1869 opts.push_back(
"-U");
1871 opts.push_back(
"--percent");
1875 opts.push_back(
"--ignorearch");
1878 opts.push_back(
"--nodigest");
1880 opts.push_back(
"--nosignature");
1882 opts.push_back (
"--excludedocs");
1884 opts.push_back (
"--noscripts");
1886 opts.push_back (
"--force");
1888 opts.push_back (
"--nodeps");
1890 opts.push_back (
"--ignoresize");
1892 opts.push_back (
"--justdb");
1894 opts.push_back (
"--test");
1896 opts.push_back(
"--");
1899 string quotedFilename( rpmQuoteFilename( workaroundRpmPwdBug( filename ) ) );
1900 opts.push_back ( quotedFilename.c_str() );
1907 vector<string> configwarnings;
1909 unsigned linecnt = 0;
1917 if (line.substr(0,2)==
"%%")
1920 sscanf (line.c_str () + 2,
"%d", &percent);
1921 report->progress( percent );
1924 rpmmsg += line+
'\n';
1926 if ( line.substr(0,8) ==
"warning:" )
1928 configwarnings.push_back(line);
1932 rpmmsg +=
"[truncated]\n";
1937 for (vector<string>::iterator it = configwarnings.begin();
1938 it != configwarnings.end(); ++it)
1942 _(
"rpm saved %s as %s, but it was impossible to determine the difference"),
1944 _(
"rpm saved %s as %s.\nHere are the first 25 lines of difference:\n"));
1947 _(
"rpm created %s as %s, but it was impossible to determine the difference"),
1949 _(
"rpm created %s as %s.\nHere are the first 25 lines of difference:\n"));
1952 if ( rpm_status != 0 )
1955 str::form(
"%s install failed", Pathname::basename(filename).c_str()),
1958 sstr <<
"rpm output:" << endl << rpmmsg << endl;
1959 historylog.
comment(sstr.str());
1964 else if ( ! rpmmsg.empty() )
1967 str::form(
"%s installed ok", Pathname::basename(filename).c_str()),
1970 sstr <<
"Additional rpm output:" << endl << rpmmsg << endl;
1971 historylog.
comment(sstr.str());
1975 report->finishInfo(
str::form(
"%s:\n%s\n",
_(
"Additional rpm output"), rpmmsg.c_str() ));
1989 +
"-" + package->edition().version()
1990 +
"-" + package->edition().release()
1991 +
"." + package->arch().asString(), flags );
2004 report->start( name_r );
2013 catch (RpmException & excpt_r)
2019 report->finish( excpt_r );
2036 MIL <<
"RpmDb::doRemovePackage(" << name_r <<
"," << flags <<
")" << endl;
2045 ERR <<
"backup of " << name_r <<
" failed" << endl;
2047 report->progress( 0 );
2051 report->progress( 100 );
2056 opts.push_back(
"-e");
2057 opts.push_back(
"--allmatches");
2060 opts.push_back(
"--noscripts");
2062 opts.push_back(
"--nodeps");
2064 opts.push_back(
"--justdb");
2066 opts.push_back (
"--test");
2069 WAR <<
"IGNORE OPTION: 'rpm -e' does not support '--force'" << endl;
2072 opts.push_back(
"--");
2073 opts.push_back(name_r.c_str());
2085 report->progress( 5 );
2086 unsigned linecnt = 0;
2093 rpmmsg += line+
'\n';
2096 rpmmsg +=
"[truncated]\n";
2097 report->progress( 50 );
2100 if ( rpm_status != 0 )
2103 str::form(
"%s remove failed", name_r.c_str()),
true );
2105 sstr <<
"rpm output:" << endl << rpmmsg << endl;
2106 historylog.
comment(sstr.str());
2111 else if ( ! rpmmsg.empty() )
2114 str::form(
"%s removed ok", name_r.c_str()),
true );
2117 sstr <<
"Additional rpm output:" << endl << rpmmsg << endl;
2118 historylog.
comment(sstr.str());
2122 report->finishInfo(
str::form(
"%s:\n%s\n",
_(
"Additional rpm output"), rpmmsg.c_str() ));
2151 Pathname backupFilename;
2156 INT <<
"_backuppath empty" << endl;
2164 ERR <<
"Error while getting changed files for package " <<
2165 packageName << endl;
2169 if (fileList.size() <= 0)
2171 DBG <<
"package " << packageName <<
" not changed -> no backup" << endl;
2183 struct tm *currentLocalTime = localtime(¤tTime);
2185 int date = (currentLocalTime->tm_year + 1900) * 10000
2186 + (currentLocalTime->tm_mon + 1) * 100
2187 + currentLocalTime->tm_mday;
2193 +
str::form(
"%s-%d-%d.tar.gz",packageName.c_str(), date, num);
2199 if (pi.isExist() && !pi.isFile())
2201 ERR << filestobackupfile.asString() <<
" already exists and is no file" << endl;
2205 ofstream fp ( filestobackupfile.asString().c_str(), ios::out|ios::trunc );
2209 ERR <<
"could not open " << filestobackupfile.asString() << endl;
2213 for (FileList::const_iterator cit = fileList.begin();
2214 cit != fileList.end(); ++cit)
2217 if ( name[0] ==
'/' )
2220 name = name.substr( 1 );
2222 DBG <<
"saving file "<< name << endl;
2227 const char*
const argv[] =
2232 _root.asString().c_str(),
2233 "--ignore-failed-read",
2235 backupFilename.asString().c_str(),
2237 filestobackupfile.asString().c_str(),
2248 for (
string output = tar.receiveLine(); output.length() ;output = tar.receiveLine())
2253 int ret = tar.close();
2257 ERR <<
"tar failed: " << tarmsg << endl;
2262 MIL <<
"tar backup ok" << endl;
2264 str::form(
_(
"created backup %s"), backupFilename.asString().c_str())