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.
klamav/src/ctcron.cpp

333 lines
8.6 KiB

/***************************************************************************
* CT Cron Implementation *
* -------------------------------------------------------------------- *
* Copyright (C) 1999, Gary Meyer <gary@meyer.net> *
* -------------------------------------------------------------------- *
* This program 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. *
***************************************************************************/
// Do not introduce any Qt or KDE dependencies into the "CT"-prefixed classes.
// I want to be able to reuse these classes with another GUI toolkit. -GM 11/99
#include "ctcron.h"
#include "cttask.h"
#include "ctvariable.h"
#include <pwd.h> // pwd, getpwnam(), getpwuid()
#include <assert.h>
#include <qfile.h>
#include <kprocess.h>
#include <ktempfile.h>
#include <stdlib.h> // system
using namespace std;
CTCron::CTCron(bool _syscron, string ) :
syscron(_syscron)
{
int uid(getuid());
KTempFile tmp;
tmp.setAutoDelete(true);
tmp.close();
tmpFileName = tmp.name();
QString readCommand;
/* if (uid == 0)
// root, so provide requested crontab
{
if (syscron)
{
readCommand = "cat /etc/crontab > " + KProcess::quote(tmpFileName);
writeCommand = "cat " + KProcess::quote(tmpFileName) + " > /etc/crontab";
login = (const char *)i18n("(System Crontab)").local8Bit();
name = "";
}
else
{
readCommand = QString("crontab -u ") + _login.c_str() + " -l > " + KProcess::quote(tmpFileName);
writeCommand = QString("crontab -u ") + _login.c_str() + " " + KProcess::quote(tmpFileName);
if (!initFromPasswd(getpwnam(_login.c_str())))
{
error = i18n("No password entry found for user '%1'").arg(_login.c_str());
}
}
}
else*/
// regular user, so provide user's own crontab
{
readCommand = "crontab -l > " + KProcess::quote(tmpFileName);
writeCommand = "crontab " + KProcess::quote(tmpFileName);
if (!initFromPasswd(getpwuid(uid)))
{
error = i18n("No password entry found for uid '%1'").arg(uid);
}
}
if (name.empty())
name = login;
initialTaskCount = 0;
initialVariableCount = 0;
if (isError())
return;
// Don't set error if it can't be read, it means the user
// doesn't have a crontab.
if (system(QFile::encodeName(readCommand)) == 0)
{
ifstream cronfile(QFile::encodeName(tmpFileName));
cronfile >> *this;
}
initialTaskCount = task.size();
initialVariableCount = variable.size();
}
CTCron::CTCron(const struct passwd *pwd) :
syscron(false)
{
Q_ASSERT(pwd != 0L);
KTempFile tmp;
tmp.setAutoDelete(true);
tmp.close();
tmpFileName = tmp.name();
QString readCommand = QString("crontab -u ") + QString(pwd->pw_name) + " -l > " + KProcess::quote(tmpFileName);
writeCommand = QString("crontab -u ") + QString(pwd->pw_name) + " " + KProcess::quote(tmpFileName);
initFromPasswd(pwd);
initialTaskCount = 0;
initialVariableCount = 0;
if (isError())
return;
// Don't set error if it can't be read, it means the user
// doesn't have a crontab.
if (system(QFile::encodeName(readCommand)) == 0)
{
ifstream cronfile(QFile::encodeName(tmpFileName));
cronfile >> *this;
}
initialTaskCount = task.size();
initialVariableCount = variable.size();
}
bool CTCron::initFromPasswd(const struct passwd *pwd)
{
if (pwd == 0)
{
return false;
}
else
{
login = pwd->pw_name;
name = pwd->pw_gecos;
return true;
}
}
void CTCron::operator = (const CTCron& source)
{
assert(!source.syscron);
for (CTVariableIterator i = const_cast<CTCron&>(source).variable.begin();
i != source.variable.end(); ++i)
{
CTVariable* tmp = new CTVariable(**i);
variable.push_back(tmp);
}
for (CTTaskIterator i = const_cast<CTCron&>(source).task.begin();
i != source.task.end(); ++i)
{
CTTask* tmp = new CTTask(**i);
task.push_back(tmp);
}
}
istream& operator >> (istream& inputStream, CTCron& cron)
{
const int MAX = 1024;
char buffer[MAX];
string line("");
string comment("");
while (inputStream)
{
inputStream.getline(buffer, MAX);
line = buffer;
// search for comments "#" but not disabled tasks "#\"
if ((line.find("#") == 0) && (line.find("\\") != 1))
{
// If the first 10 characters don't contain a character, it's probably a disabled entry.
int first_text = line.find_first_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
if (first_text < 0)
continue;
if (first_text < 10)
{
// remove leading pound sign
line = line.substr(1,line.length()-1);
// remove leading whitespace
while (line.find_first_of(" \t") == 0)
line = line.substr(1,line.length()-1);
comment = line;
continue;
}
}
// else
{
// either a task or a variable
int firstWhiteSpace(line.find_first_of(" \t"));
int firstEquals(line.find("="));
// if there is an equals sign and either there is no
// whitespace or the first whitespace is after the equals
// sign, it must be a variable
if ((firstEquals > 0) && ((firstWhiteSpace == -1) ||
firstWhiteSpace > firstEquals))
{
// create variable
CTVariable *tmp = new CTVariable(line, comment);
cron.variable.push_back(tmp);
comment = "";
}
else
// must be a task, either enabled or disabled
{
if (firstWhiteSpace > 0)
{
//kdDebug() << line << endl;
CTTask *tmp = new CTTask(line, comment, cron.syscron);
cron.task.push_back(tmp);
comment = "";
}
}
}
}
return inputStream;
}
ostream& operator << (ostream& outputStream, const CTCron& cron)
{
int itemCount(0);
for (CTVariableIterator i = const_cast<CTCron&>(cron).variable.begin();
i != cron.variable.end(); ++i)
{
outputStream << **i;
itemCount++;
}
for (CTTaskIterator i = const_cast<CTCron&>(cron).task.begin();
i != cron.task.end(); ++i)
{
outputStream << **i;
itemCount++;
}
if (itemCount > 0)
{
outputStream << "# This file was written by KlamAV using code disembowelled from KCron.\n";
outputStream << "# KCron is (c) 1999, Gary Meyer; if your cron file looks screwed up \n";
outputStream << "# then that is probably (c) Robert Hogan and you should file a bug report.\n";
outputStream << "# Original notice from KCron reads:\n";
outputStream << "# Although KCron supports most crontab formats, use care when editing.\n";
outputStream << "# Note: Lines beginning with \"#\\\" indicates a disabled task.\n";
}
return outputStream;
}
CTCron::~CTCron()
{
for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
delete *i;
for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
delete *i;
}
void CTCron::apply()
{
// write to temp file
ofstream cronfile(QFile::encodeName(tmpFileName));
cronfile << *this << flush;
// install temp file into crontab
if (system(QFile::encodeName(writeCommand)) != 0)
{
error = i18n("An error occurred while updating crontab.");
}
// remove the temp file
(void) unlink(QFile::encodeName(tmpFileName));
if (isError())
return;
// mark as applied
for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
(*i)->apply();
for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
(*i)->apply();
initialTaskCount = task.size();
initialVariableCount = variable.size();
}
void CTCron::cancel()
{
for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
(*i)->cancel();
for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
(*i)->cancel();
}
bool CTCron::dirty()
{
bool isDirty(false);
if (initialTaskCount != task.size()) isDirty = true;
if (initialVariableCount != variable.size()) isDirty = true;
for (CTTaskIterator i = task.begin(); i != task.end(); ++i)
if ((*i)->dirty()) isDirty = true;
for (CTVariableIterator i = variable.begin(); i != variable.end(); ++i)
if ((*i)->dirty()) isDirty = true;
return isDirty;
}
string CTCron::path() const
{
string path;
for (CTVariableIterator var = const_cast<CTCron*>(this)->variable.begin();
var != variable.end(); var++)
{
if ((*var)->variable == "PATH")
{
path = (*var)->value;
}
}
return path;
}