Keep – backup system
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

388 lines
12 KiB

/* This file is part of the Keep project
Copyright (C) 2006 Jean-Rémy Falleri <jr.falleri@laposte.net>
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 <kprocess.h>
#include <kdebug.h>
#include <tqfile.h>
#include <keepsettings.h>
RDBManager::RDBManager()
{
}
RDBManager::~RDBManager()
{
}
void RDBManager::slotCheckBackup()
{
TQValueList<Backup> backups = outdatedBackupList();
TQValueList<Backup>::iterator it;
for ( it = backups.begin(); it != backups.end(); ++it )
{
doBackup(*it);
}
}
void RDBManager::slotForceBackup(TQValueList<Backup> backupList)
{
TQValueList<Backup>::iterator it;
for ( it = backupList.begin(); it != backupList.end(); ++it )
{
doBackup(*it);
}
}
TQString RDBManager::compareAtTime(Backup backup, TQDateTime date)
{
// Gets the rdiff-backup process
TDEProcess *proc = RDBProcess();
// Adds the options
*proc << "--compare-at-time";
*proc << TQString::number(date.toTime_t()); // increment date
// Adds source and dest
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.source())));
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
// Adds the listener
RDBListener *listen = new RDBListener();
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
// Starts the process
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
kdDebug() << "Error starting rdiff-backup" << endl;
TQStringList output = listen->stdOut();
TQStringList::iterator it = output.begin();
kdDebug() << "Executed process: " << proc->args() << endl;
delete listen;
delete proc;
return (*it);
}
TQString RDBManager::listChangedSince(Backup backup, TQDateTime date)
{
// Gets the rdiff-backup process
TDEProcess *proc = RDBProcess();
// Adds the options
*proc << "--list-changed-since";
*proc << TQString::number(date.toTime_t()); // increment date
// Adds the dest
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
// Adds a listener
RDBListener *listen = new RDBListener();
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
// Starts the process
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
kdDebug() << "Error starting rdiff-backup" << endl;
TQStringList output = listen->stdOut();
TQStringList::iterator it = output.begin();
kdDebug() << "Executed process: " << proc->args() << endl;
delete listen;
delete proc;
return (*it);
}
TQString RDBManager::listAtTime(Backup backup, TQDateTime date)
{
// Gets the rdiff-backup process
TDEProcess *proc = RDBProcess();
// Adds the options
*proc << "--list-at-time";
*proc << TQString::number(date.toTime_t()); // increment date
// Adds the dest
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
// Adds a listener
RDBListener *listen = new RDBListener();
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
// Starts the process
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
kdDebug() << "Error starting rdiff-backup" << endl;
TQStringList output = listen->stdOut();
TQStringList::iterator it = output.begin();
kdDebug() << "Executed process: " << proc->args() << endl;
delete listen;
delete proc;
return (*it);
}
TQValueList<TQDateTime> RDBManager::incrementList(Backup backup)
{
// Gets the rdiff-backup process
TDEProcess *proc = RDBProcess();
// Adds the options
*proc << "--list-increments";
*proc << "-v2";
*proc << "--parsable-output";
// Adds the dest
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
// Adds a listener
RDBListener *listen = new RDBListener();
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
// Starts the process
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
kdDebug() << "Error starting rdiff-backup" << endl;
TQStringList output = listen->stdOut();
TQStringList::iterator it = output.begin();
TQStringList lines = TQStringList::split("\n",*it);
TQValueList<TQDateTime> dateList;
TQStringList::iterator it2 = output.begin();
for ( it2 = lines.begin(); it2 != lines.end(); ++it2 )
{
TQStringList field = TQStringList::split(" ",*it2);
TQStringList::iterator dateStr = field.begin();
long timestamp = (*dateStr).toUInt();
TQDateTime datetime;
datetime.setTime_t(timestamp);
dateList.append(datetime);
}
kdDebug() << "Executed process: " << proc->args() << endl;
delete listen;
delete proc;
return dateList;
}
TQDateTime RDBManager::lastIncrement(Backup backup)
{
TQValueList<TQDateTime> increments = incrementList(backup);
TQDateTime last = increments.last();
return last;
}
TQValueList<Backup> RDBManager::outdatedBackupList()
{
BackupConfig config;
TQValueList<Backup> backups = config.backupList();
TQValueList<Backup> outdated;
TQValueList<Backup>::iterator it;
kdDebug() << "Detecting outdated backup." << endl;
for ( it = backups.begin(); it != backups.end(); ++it )
{
TQDateTime last = lastIncrement(*it);
TQDate today = TQDate::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,TQDateTime time)
{
// Gets the rdiff-backup process
TDEProcess *proc = RDBProcess();
// Adds the options
*proc << "--force";
*proc << "--restore-as-of";
*proc << TQString::number(time.toTime_t()); // Date of the increment to restore
// Adds source and dest
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.source())));
// Adds a listener (for output recording)
RDBListener *listen = new RDBListener();
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
connect(proc,TQT_SIGNAL(receivedStderr(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdErr(TDEProcess *,char *,int)));
// Starts the process
if ( !proc->start(TDEProcess::Block, TDEProcess::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
TDEProcess *proc = RDBProcess();
*proc << "-V";
// Adds a listener (for output recording)
RDBListener *listen = new RDBListener();
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
// Starts the process
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
kdDebug() << "Error starting rdiff-backup" << endl;
TQStringList outList = listen->stdOut();
TQStringList::iterator out = outList.begin();
kdDebug() << "Executed process: " << proc->args() << endl;
delete listen;
delete proc;
if ( *out == "" )
return false;
return true;
}
TQString RDBManager::RDBVersion()
{
// Gets the rdiff-backup process
TDEProcess *proc = RDBProcess();
*proc << "-V";
// Adds a listener (for output recording)
RDBListener *listen = new RDBListener();
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
// Starts the process
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
kdDebug() << "Error starting rdiff-backup" << endl;
TQStringList outList = listen->stdOut();
TQStringList::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
TDEProcess *proc = RDBProcess(KeepSettings::controlRDBPriority,KeepSettings::rDBPriority());
// Adds include and exclude
if ( backup.useIncludeExclude() )
{
TQStringList includeExcludeList = backup.includeExcludeList();
TQStringList::iterator it;
for ( it = includeExcludeList.begin(); it != includeExcludeList.end(); ++it )
{
TQString type = (*it).left(1);
TQString file = (*it).right((*it).length() - 1);
if ( type == "I" )
{
*proc << "--include";
*proc << TQString(TQFile::encodeName(TDEProcess::quote(file)));
}
else if ( type == "E" )
{
*proc << "--exclude";
*proc << TQString(TQFile::encodeName(TDEProcess::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
{
TQStringList optionList = backup.optionList();
for ( TQStringList::Iterator it = optionList.begin(); it != optionList.end(); ++it )
{
*proc << *it;
}
}
// Adds source and dest
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.source())));
*proc << TQString(TQFile::encodeName(TDEProcess::quote(backup.dest())));
// Adds a listener (for output recording)
RDBListener *listen = new RDBListener();
connect(proc,TQT_SIGNAL(receivedStdout(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdOut(TDEProcess *,char *,int)));
connect(proc,TQT_SIGNAL(receivedStderr(TDEProcess *,char *,int)),listen,TQT_SLOT(receivedStdErr(TDEProcess *,char *,int)));
// Starts the process
if ( !proc->start(TDEProcess::Block, TDEProcess::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
TDEProcess *proc = RDBProcess();
// Adds the options
*proc << "--remove-older-than" << TQString("%1").arg(backup.deleteAfter()) + "D";
// Adds dest
*proc << backup.dest();
// Starts the process
if ( !proc->start(TDEProcess::Block, TDEProcess::AllOutput) )
kdDebug() << "Error starting rdiff-backup" << endl;
kdDebug() << "Executed process: " << proc->args() << endl;
delete proc;
}
TDEProcess *RDBManager::RDBProcess(bool isNice,int niceLevel)
{
TDEProcess *proc = new TDEProcess();
proc->setUseShell(true);
if ( isNice )
{
*proc << "nice" << "-n" << TQString("%1").arg(niceLevel);
}
*proc << "rdiff-backup";
return proc;
}
#include "rdbmanager.moc"