diff options
Diffstat (limited to 'src/ctcron.cpp')
-rw-r--r-- | src/ctcron.cpp | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/src/ctcron.cpp b/src/ctcron.cpp new file mode 100644 index 0000000..68a6483 --- /dev/null +++ b/src/ctcron.cpp @@ -0,0 +1,332 @@ +/*************************************************************************** + * CT Cron Implementation * + * -------------------------------------------------------------------- * + * Copyright (C) 1999, Gary Meyer <[email protected]> * + * -------------------------------------------------------------------- * + * 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; +} |