/* This file is part of the Keep project Copyright (C) 2006 Jean-Rémy Falleri Keep is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Keep is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Keep; if not, write to the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "rdbmanager.h" #include #include #include #include RDBManager::RDBManager() { } RDBManager::~RDBManager() { } void RDBManager::slotCheckBackup() { QValueList backups = outdatedBackupList(); QValueList::iterator it; for ( it = backups.begin(); it != backups.end(); ++it ) { doBackup(*it); } } void RDBManager::slotForceBackup(QValueList backupList) { QValueList::iterator it; for ( it = backupList.begin(); it != backupList.end(); ++it ) { doBackup(*it); } } QString RDBManager::compareAtTime(Backup backup, QDateTime date) { // Gets the rdiff-backup process KProcess *proc = RDBProcess(); // Adds the options *proc << "--compare-at-time"; *proc << QString::number(date.toTime_t()); // increment date // Adds source and dest *proc << QFile::encodeName(KProcess::quote(backup.source())); *proc << QFile::encodeName(KProcess::quote(backup.dest())); // Adds the listener RDBListener *listen = new RDBListener(); connect(proc,SIGNAL(receivedStdout(KProcess *,char *,int)),listen,SLOT(receivedStdOut(KProcess *,char *,int))); // Starts the process if ( !proc->start(KProcess::Block, KProcess::AllOutput) ) kdDebug() << "Error starting rdiff-backup" << endl; QStringList output = listen->stdOut(); QStringList::iterator it = output.begin(); kdDebug() << "Executed process: " << proc->args() << endl; delete listen; delete proc; return (*it); } QString RDBManager::listChangedSince(Backup backup, QDateTime date) { // Gets the rdiff-backup process KProcess *proc = RDBProcess(); // Adds the options *proc << "--list-changed-since"; *proc << QString::number(date.toTime_t()); // increment date // Adds the dest *proc << QFile::encodeName(KProcess::quote(backup.dest())); // Adds a listener RDBListener *listen = new RDBListener(); connect(proc,SIGNAL(receivedStdout(KProcess *,char *,int)),listen,SLOT(receivedStdOut(KProcess *,char *,int))); // Starts the process if ( !proc->start(KProcess::Block, KProcess::AllOutput) ) kdDebug() << "Error starting rdiff-backup" << endl; QStringList output = listen->stdOut(); QStringList::iterator it = output.begin(); kdDebug() << "Executed process: " << proc->args() << endl; delete listen; delete proc; return (*it); } QString RDBManager::listAtTime(Backup backup, QDateTime date) { // Gets the rdiff-backup process KProcess *proc = RDBProcess(); // Adds the options *proc << "--list-at-time"; *proc << QString::number(date.toTime_t()); // increment date // Adds the dest *proc << QFile::encodeName(KProcess::quote(backup.dest())); // Adds a listener RDBListener *listen = new RDBListener(); connect(proc,SIGNAL(receivedStdout(KProcess *,char *,int)),listen,SLOT(receivedStdOut(KProcess *,char *,int))); // Starts the process if ( !proc->start(KProcess::Block, KProcess::AllOutput) ) kdDebug() << "Error starting rdiff-backup" << endl; QStringList output = listen->stdOut(); QStringList::iterator it = output.begin(); kdDebug() << "Executed process: " << proc->args() << endl; delete listen; delete proc; return (*it); } QValueList RDBManager::incrementList(Backup backup) { // Gets the rdiff-backup process KProcess *proc = RDBProcess(); // Adds the options *proc << "--list-increments"; *proc << "-v2"; *proc << "--parsable-output"; // Adds the dest *proc << QFile::encodeName(KProcess::quote(backup.dest())); // Adds a listener RDBListener *listen = new RDBListener(); connect(proc,SIGNAL(receivedStdout(KProcess *,char *,int)),listen,SLOT(receivedStdOut(KProcess *,char *,int))); // Starts the process if ( !proc->start(KProcess::Block, KProcess::AllOutput) ) kdDebug() << "Error starting rdiff-backup" << endl; QStringList output = listen->stdOut(); QStringList::iterator it = output.begin(); QStringList lines = QStringList::split("\n",*it); QValueList dateList; QStringList::iterator it2 = output.begin(); for ( it2 = lines.begin(); it2 != lines.end(); ++it2 ) { QStringList field = QStringList::split(" ",*it2); QStringList::iterator dateStr = field.begin(); long timestamp = (*dateStr).toUInt(); QDateTime datetime; datetime.setTime_t(timestamp); dateList.append(datetime); } kdDebug() << "Executed process: " << proc->args() << endl; delete listen; delete proc; return dateList; } QDateTime RDBManager::lastIncrement(Backup backup) { QValueList increments = incrementList(backup); QDateTime last = increments.last(); return last; } QValueList RDBManager::outdatedBackupList() { BackupConfig config; QValueList backups = config.backupList(); QValueList outdated; QValueList::iterator it; kdDebug() << "Detecting outdated backup." << endl; for ( it = backups.begin(); it != backups.end(); ++it ) { QDateTime last = lastIncrement(*it); QDate today = QDate::currentDate(); if ( last.date().daysTo(today) >= (*it).interval() ) { kdDebug() << "Detected outdated backup: " << (*it).source() << endl; outdated.append(*it); } } return outdated; } void RDBManager::slotRestoreBackup(Backup backup,QDateTime time) { // Gets the rdiff-backup process KProcess *proc = RDBProcess(); // Adds the options *proc << "--force"; *proc << "--restore-as-of"; *proc << QString::number(time.toTime_t()); // Date of the increment to restore // Adds source and dest *proc << QFile::encodeName(KProcess::quote(backup.dest())); *proc << QFile::encodeName(KProcess::quote(backup.source())); // Adds a listener (for output recording) RDBListener *listen = new RDBListener(); connect(proc,SIGNAL(receivedStdout(KProcess *,char *,int)),listen,SLOT(receivedStdOut(KProcess *,char *,int))); connect(proc,SIGNAL(receivedStderr(KProcess *,char *,int)),listen,SLOT(receivedStdErr(KProcess *,char *,int))); // Starts the process if ( !proc->start(KProcess::Block, KProcess::AllOutput) ) kdDebug() << "Error starting rdiff-backup" << endl; kdDebug() << "Executed process: " << proc->args() << endl; if ( !listen->isOk() ) { kdDebug() << "Error message: " << listen->errorMessage() << endl; emit backupError(backup,listen->errorMessage()); } delete listen; delete proc; } bool RDBManager::isRDB() { // Gets the rdiff-backup process KProcess *proc = RDBProcess(); *proc << "-V"; // Adds a listener (for output recording) RDBListener *listen = new RDBListener(); connect(proc,SIGNAL(receivedStdout(KProcess *,char *,int)),listen,SLOT(receivedStdOut(KProcess *,char *,int))); // Starts the process if ( !proc->start(KProcess::Block, KProcess::AllOutput) ) kdDebug() << "Error starting rdiff-backup" << endl; QStringList outList = listen->stdOut(); QStringList::iterator out = outList.begin(); kdDebug() << "Executed process: " << proc->args() << endl; delete listen; delete proc; if ( *out == "" ) return false; return true; } QString RDBManager::RDBVersion() { // Gets the rdiff-backup process KProcess *proc = RDBProcess(); *proc << "-V"; // Adds a listener (for output recording) RDBListener *listen = new RDBListener(); connect(proc,SIGNAL(receivedStdout(KProcess *,char *,int)),listen,SLOT(receivedStdOut(KProcess *,char *,int))); // Starts the process if ( !proc->start(KProcess::Block, KProcess::AllOutput) ) kdDebug() << "Error starting rdiff-backup" << endl; QStringList outList = listen->stdOut(); QStringList::iterator out = outList.begin(); kdDebug() << "Executed process: " << proc->args() << endl; delete listen; delete proc; return (*out).mid(13,5); } void RDBManager::doBackup(Backup backup) { // Gets the rdiff-backup process KProcess *proc = RDBProcess(KeepSettings::controlRDBPriority,KeepSettings::rDBPriority()); // Adds include and exclude if ( backup.useIncludeExclude() ) { QStringList includeExcludeList = backup.includeExcludeList(); QStringList::iterator it; for ( it = includeExcludeList.begin(); it != includeExcludeList.end(); ++it ) { QString type = (*it).left(1); QString file = (*it).right((*it).length() - 1); if ( type == "I" ) { *proc << "--include"; *proc << QFile::encodeName(KProcess::quote(file)); } else if ( type == "E" ) { *proc << "--exclude"; *proc << QFile::encodeName(KProcess::quote(file)); } } } // Adds the option // For simple mode if ( !backup.useAdvancedConfig() ) { if ( !backup.useCompression() ) *proc << "--no-compression"; if ( backup.excludeSpecialFiles() ) *proc << "--exclude-special-files"; } // For advanced mode else { QStringList optionList = backup.optionList(); for ( QStringList::Iterator it = optionList.begin(); it != optionList.end(); ++it ) { *proc << *it; } } // Adds source and dest *proc << QFile::encodeName(KProcess::quote(backup.source())); *proc << QFile::encodeName(KProcess::quote(backup.dest())); // Adds a listener (for output recording) RDBListener *listen = new RDBListener(); connect(proc,SIGNAL(receivedStdout(KProcess *,char *,int)),listen,SLOT(receivedStdOut(KProcess *,char *,int))); connect(proc,SIGNAL(receivedStderr(KProcess *,char *,int)),listen,SLOT(receivedStdErr(KProcess *,char *,int))); // Starts the process if ( !proc->start(KProcess::Block, KProcess::AllOutput) ) kdDebug() << "Error starting rdiff-backup" << endl; kdDebug() << "Executed process: " << proc->args() << endl; kdDebug() << "Process status: " << listen->isOk() << endl; if ( !listen->isOk() ) { kdDebug() << "Error message: " << listen->errorMessage() << endl; emit backupError(backup,listen->errorMessage()); } else emit backupSuccess(backup); delete listen; delete proc; if ( !backup.neverDelete() ) { removeOldIncrements(backup); } } void RDBManager::removeOldIncrements(Backup backup) { // Gets the rdiff-backup process KProcess *proc = RDBProcess(); // Adds the options *proc << "--remove-older-than" << QString("%1").arg(backup.deleteAfter()) + "D"; // Adds dest *proc << backup.dest(); // Starts the process if ( !proc->start(KProcess::Block, KProcess::AllOutput) ) kdDebug() << "Error starting rdiff-backup" << endl; kdDebug() << "Executed process: " << proc->args() << endl; delete proc; } KProcess *RDBManager::RDBProcess(bool isNice,int niceLevel) { KProcess *proc = new KProcess(); proc->setUseShell(true); if ( isNice ) { *proc << "nice" << "-n" << QString("%1").arg(niceLevel); } *proc << "rdiff-backup"; return proc; } #include "rdbmanager.moc"