ssh-cron-1.05.00/build0000755000175000017500000000631514741005603013427 0ustar frankfrank#!/usr/bin/icmake -t. #define LOGENV "SSHCRON" #include "icmconf" string g_logPath = getenv(LOGENV)[1], g_cwd = chdir(""); // initial working directory, ends in / int g_echo = ON; #include "icmake/cuteoln" #include "icmake/backtick" #include "icmake/setopt" #include "icmake/run" #include "icmake/md" #include "icmake/pathfile" #include "icmake/findall" #include "icmake/loginstall" #include "icmake/logzip" #include "icmake/logfile" #include "icmake/uninstall" #include "icmake/special" #include "icmake/clean" #include "icmake/manpage" #include "icmake/install" #include "icmake/gitlab" void main(int argc, list argv) { string option; int idx; for (idx = listlen(argv); idx--; ) { if (argv[idx] == "-q") { g_echo = OFF; argv -= (list)"-q"; } } echo(g_echo); option = argv[1]; if (option == "clean") clean(0); if (option == "distclean") clean(1); if (option != "") special(); if (option == "install") install(argv[2], argv[3]); if (option == "uninstall") uninstall(argv[2]); if (option == "gitlab") gitlab(); if (option == "man") manpage(); if ("VERSION" younger "version/version.h") system("touch version/version.h `grep -l Icmbuild:: *.cc */*.cc`"); if (option == "library") { system("icmbuild library"); exit(0); } if (option == "program") { system("icmbuild program"); exit(0); } if (option == "xref") { system("icmbuild program"); run("oxref -fxs tmp/lib" LIBRARY ".a > " PROJECT ".xref"); exit(0); } printf("Usage: build [-q -P] what\n" "Where\n" " [-q]: run quietly, do not show executed commands\n" "`what' is one of:\n" " clean - clean up remnants of previous " "compilations\n" " distclean - clean + fully remove tmp/\n" " library - build " PROJECT "'s library\n" " man - build the man-page (requires Yodl)\n" " program - build PROJECT\n" " xref - same a `program', also builds xref file\n" " using oxref\n" " install selection [base] - to install the software in the \n" " locations defined in the INSTALL.im file,\n" " optionally below base\n" " selection can be\n" " x, to install all components,\n" " or a combination of:\n" " b (binary program),\n" " d (documentation),\n" " m (man-page)\n" " uninstall logfile - remove files and empty directories listed\n" " in the file 'logfile'\n" " gitlab - prepare gitlab's web-pages update\n" " (internal use only)\n" "\n" ); exit(1); } ssh-cron-1.05.00/changelog0000644000175000017500000001235514740777616014300 0ustar frankfrankssh-cron (1.05.00) * Requires bobcat >= 6.07.00 and icmake >= 13.00,03. * Changed ArgConfig::None into ArgConfig::NoArg. * Building uses a SPCH and multi-compilation. * The compiler is called using the value of the ${ICMAKE_CPPSTD} environment variable specifying the C++ standard to use. -- Frank B. Brokken Sun, 12 Jan 2025 18:42:24 +0100 ssh-cron (1.04.01) * cron/hmac.cc uses aes-256-cbc to construct the message HMAC of the used passphrase. * aes-256-cbc requires a 32 character long key, which is ensured by daemon/getpassphrase.cc * Passphrases must be at least 10 characters long. -- Frank B. Brokken Fri, 21 Oct 2022 08:53:53 +0200 ssh-cron (1.04.00) * Ready for libbobcat6 * Added 'c++std' defining the c++ standard to use for compilation. Compilation commands also use -Werror * Renamed the 'oxref' option in the 'build' script to 'xref' * Repaired warning-based errors. -- Frank B. Brokken Sat, 17 Sep 2022 11:16:52 +0200 ssh-cron (1.03.01) * Removed -q from ssh-cron's build script * Repaired the icmake/findall function -- Frank B. Brokken Tue, 29 Jun 2021 17:17:29 +0200 ssh-cron (1.03.00) * Parser adapted to the code generated by bisonc++ 6.04.01 * Repaired flaws in the parser's grammar specifications * Scanner adapted to the code generated by flexc++ 2.08.01 * Requires bobcat >= 5.05.00 -- Frank B. Brokken Sat, 14 Nov 2020 10:08:53 +0100 ssh-cron (1.02.00) * Requires bobcat >= 5.00.00 -- Frank B. Brokken Wed, 24 Apr 2019 12:22:31 +0200 ssh-cron (1.01.01) * Migrated from Github to Gitlab * Precompiled headers are used by default * INSTALL.im uses g++ and standards version c++17 -- Frank B. Brokken Mon, 25 Jun 2018 12:00:53 +0200 ssh-cron (1.01.00) * The user is interactively given an opportunity to remove an existing (left-over) ipc file when (re)starting ssh-cron. * Added option --forced (or: -f) to force the removal of an already existing ipc-file during daemon startup. * Build scripts adapted to icmake 8.00.04. -- Frank B. Brokken Mon, 14 Dec 2015 13:15:41 +0100 ssh-cron (1.00.01) * Kevin Brodsky observed that the installation scripts used 'chdir' rather than 'cd'. Fixed in this release. * Kevin Brodsky also observed that the combined size of all precompiled headers might exceed some disks capacities. The option -P was added to the ./build script to prevent the use of precompiled headers. -- Frank B. Brokken Mon, 05 Oct 2015 21:15:45 +0200 ssh-cron (1.00.00) * Update to version 1.00.00 after being operational for one year without issues. * Added 'INSTALL' and 'required' * Standardized the (de)installation procedures -- Frank B. Brokken Sat, 03 Oct 2015 10:10:18 +0200 ssh-cron (0.92.00) * cron/call checked the need to activate a program by either looking for a matching month daynr, OR by looking for a matching day-of-week number. This is wrong: a spec. like * * * * 4 should only run on Wednesdays. The check now requires all time specifications to match the current time. -- Frank B. Brokken Thu, 18 Sep 2014 08:33:24 +0200 ssh-cron (0.91.03) * Michael Tautschnig reported a FTBFS error, probably due to a missing -lpthread flag. Now added. -- Frank B. Brokken Tue, 26 Aug 2014 09:11:41 +0200 ssh-cron (0.91.02) * No idea what required this subminor version, but according to Debian's changelog we're at 0.91.02.... -- Frank B. Brokken Tue, 26 Aug 2014 09:11:41 +0200 ssh-cron (0.91.01) * Changed 'pass phrase' into 'passphrase' following Tony Mancill's advice -- Frank B. Brokken Sat, 14 Jun 2014 22:31:08 +0200 ssh-cron (0.91.00) * A passphrase is required when starting the ssh-cron daemon or when modifiying the daemon's scheduled commands. -- Frank B. Brokken Mon, 09 Jun 2014 13:45:06 +0200 ssh-cron (0.90.00) * Commands using an ssh-key requiring a passphrase have been successfully executed when scheduled. When running ssh-cron as a daemon scheduling continued after the user starting the daemon had logged out. * Be advised: to run (or compile) ssh-cron, bobcat >= 3.23.00 is required. * SSH-cron's development status is now BETA. -- Frank B. Brokken Sat, 07 Jun 2014 16:39:32 +0200 ssh-cron (0.80.00) * SSH-cron's development status is now ALPHA: daemon,--no-daemon, --list, --reload, and --terminate have been shown to work as planned. * Be advised that compiling and running ssh-cron requires at least Bobcat 3.23.00, which is currently only available from Bobcat's git repo: commit 9eb8bc8029a4472d12a92a350b302ae2f71f496e Date: Wed Jun 4 21:21:05 2014 +0200 -- Frank B. Brokken Wed, 04 Jun 2014 21:35:39 +0200 ssh-cron (0.10.00) * Proof of concept operational -- Frank B. Brokken Mon, 12 May 2014 10:43:33 +0200 ssh-cron (0.00.00) * Start of Project. -- Frank B. Brokken Thu, 07 May 2014 20:44:12 +0200 ssh-cron-1.05.00/CLASSES0000644000175000017500000000027714324446662013436 0ustar frankfrankipcfunction cronentry options ipcfunction crondata options cronentry cron options scanner parser scanner options daemon parser options cron ssh-cron-1.05.00/Copyright-notice0000644000175000017500000000253014324446662015562 0ustar frankfrank-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Ssh-cron implements a cron-like daemon that is able to use ssh-connections using ssh keys that are protected by passphrases. Copyright (C) 2012-2014 Frank B. Brokken (f.b.brokken@rug.nl) 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEVAwUBU+ESSH2yqL7q5NiqAQjaKAf/Ysdc6tSEAOUZz/rKWawJIlIhWmZI5U28 EIHg7A93edB5OV9emtIwXJ/j7YpAkLJKM5m8zX/RenOmmYuvDNIwhy4j8QTnxcEC Gm4w/OvFWgzHxbewRTSCeqjR3OML8NrJyzM6hSHtMrG00ifusp/2ldgEuwKTbZvX weqUFCKFkqQrf/CnkkG+phZmZl5/ubUClcCR1lJF+rmPMcHtbGyiFqbjNWH/o+VY +ry261sGzcgGxA2x3BKAGv0YuHCb0vco8OymBnuKk27OyAUn8hrgGQ0KlEl3hOqN ydhuEqUZibu7Dm3ufLzzWTrecb+niFc1bQqXRxpDtt6nWNXVaoDByA== =kAf+ -----END PGP SIGNATURE----- ssh-cron-1.05.00/cron/0000755000175000017500000000000014333652630013343 5ustar frankfrankssh-cron-1.05.00/cron/parentprocess.cc0000644000175000017500000000161714324446663016556 0ustar frankfrank#include "cron.ih" // stop() handles the termination of the child process // daemon/terminate ends the process via --terminate void Cron::parentProcess() { // Set up the parent's sides of the pipes OFdStream toChild(d_childInput.writeOnly()); d_toChild = &toChild; thread requestThread; if (d_options.daemon()) { requestThread = thread(requestHandler, this); requestThread.detach(); // ends when main() ends } defineRunFunction(); d_options.msg() << "scheduler: executing /usr/bin/ssh-add" << endl; sendCommand("/usr/bin/ssh-add"); cronLoop(); if (int status = waitForChild()) scheduler() << "ssh-agent (pid = " << pid() << ") returned " << status << endl; else idmsg() << "normal end of ssh-agent (pid = " << pid() << ')' << endl; } ssh-cron-1.05.00/cron/requesthandler.cc0000644000175000017500000000014014324446663016702 0ustar frankfrank#include "cron.ih" void Cron::requestHandler(Cron *cronPtr) { cronPtr->handleRequests(); } ssh-cron-1.05.00/cron/scheduler.cc0000644000175000017500000000014614324446663015640 0ustar frankfrank#include "cron.ih" ostream &Cron::scheduler() const { return d_options.msg() << "scheduler: "; } ssh-cron-1.05.00/cron/data.cc0000644000175000017500000000011414324446663014566 0ustar frankfrank#include "cron.ih" string Cron::s_agent = "/usr/bin/ssh-agent /bin/bash"; ssh-cron-1.05.00/cron/stop.cc0000644000175000017500000000014414324446663014645 0ustar frankfrank#include "cron.ih" void Cron::stop(size_t signal) { d_run = false; kill(pid(), SIGTERM); } ssh-cron-1.05.00/cron/hmac2str.cc.stdby0000644000175000017500000000036714324446663016536 0ustar frankfrank#include "cron.ih" string Cron::hmac2str(string const &passPhrase) { ostringstream out; out << setfill('0'); for (unsigned char ch: passPhrase) out << setw(2) << (ch >> 4) << setw(2) << (ch & 0xff); return out.str(); } ssh-cron-1.05.00/cron/handlerequests.cc0000644000175000017500000000345014324446663016712 0ustar frankfrank#include "cron.ih" void Cron::handleRequests() { ifstream ipcFile; Exception::open(ipcFile, Options::instance().ipcFile()); int shmemId; ipcFile >> shmemId; SharedStream sharedStream(shmemId); SharedCondition cond(sharedStream.attachSharedCondition()); cond.lock(); size_t index; // index for CronData elements while (true) { idmsg() << "waiting for requests" << endl; cond.wait(); Function request = readRequest(sharedStream); if (request > TERMINATE) { scheduler() << "received invalid function request " << request << endl; continue; } (request == MORE ? idmsg() : scheduler()) << "received request " << nameOf(request) << endl; streamsize writeOffset = sharedStream.tellg(); switch (request) { case LIST: { index = 0; idmsg() << "answering MORE" << endl; writeRequest(sharedStream, MORE); list(&index, writeOffset, sharedStream); } break; case MORE: if (index != d_cronData.size()) list(&index, writeOffset, sharedStream); else { idmsg() << "answering DONE" << endl; writeRequest(sharedStream, DONE); } break; case RELOAD: if (not reload(sharedStream)) continue; break; default: break; } idmsg() << "notifying the requestor" << endl; cond.notify(); } } ssh-cron-1.05.00/cron/list.cc0000644000175000017500000000101514324446663014631 0ustar frankfrank#include "cron.ih" void Cron::list(size_t *index, streamsize offset, SharedStream &out) { out.seekp(offset); out.truncate(offset); // clear any previous contents if (*index == 0) // write an initial \n separator out.put('\n'); for (; *index != d_cronData.size(); ++*index) { streamsize lastOK = out.tellp(); if (not (out << d_cronData[*index] << endl)) { out.truncate(lastOK); return; } } out << endl; } ssh-cron-1.05.00/cron/reload.cc0000644000175000017500000000074314324446663015133 0ustar frankfrank#include "cron.ih" bool Cron::reload(istream &sharedIn) { string passPhrase; getline(sharedIn, passPhrase); if (hmac(passPhrase) != d_passPhrase) return false; string path; getline(sharedIn, path); idmsg() << "reloading from " << path << endl; d_cronData = CronData(); d_cronData.messages(false); ifstream in; Exception::open(in, path); Parser parser(in, d_cronData); parser.parse(); return true; } ssh-cron-1.05.00/cron/runparentprocess.cc0000644000175000017500000000011314324446663017271 0ustar frankfrank#include "cron.ih" void Cron::runParentProcess() { parentProcess(); } ssh-cron-1.05.00/cron/childprocess.cc0000644000175000017500000000044314324446662016343 0ustar frankfrank#include "cron.ih" void Cron::childProcess() { Process process(Process::DIRECT, s_agent); // ssh-add works OK, but requires package ssh-askpass to be installed process.start(); // this point is never reached fmsg << "could not execute `" << s_agent << '\'' << endl; } ssh-cron-1.05.00/cron/execute.cc0000644000175000017500000000060614324446663015325 0ustar frankfrank#include "cron.ih" void Cron::execute(CronEntry const &entry) { string command("("); for (size_t idx = 0, end = entry.nSettings(); idx != end; ++idx) command += d_cronData.environment()[idx] + ';'; command += "_run_ " + entry.command() + ")&"; scheduler() << entry.command() << endl; idmsg() << "executed as " << command << endl; sendCommand(command); } ssh-cron-1.05.00/cron/definerunfunction.cc0000644000175000017500000000060314324446663017405 0ustar frankfrank#include "cron.ih" void Cron::defineRunFunction() { std::string const &mailer = d_options.mailer(); if (mailer.empty()) *d_toChild << R"( _run_() { eval $* 2>&1 > /dev/null } )"; else *d_toChild << R"( _run_() { out=`eval $* 2>&1` [ "$out" == "" ] || echo "$out" | )" << mailer << R"( } )"; idmsg() << "defined _run_()" << endl; } ssh-cron-1.05.00/cron/call.cc0000644000175000017500000000062214324446662014573 0ustar frankfrank#include "cron.ih" bool Cron::call(DateTime const &now, CronEntry const &entry) { return specified(now.minutes(), entry.minutes()) && specified(now.hours(), entry.hours()) && specified(now.month() + 1, entry.monthOfYear()) && specified(now.monthDayNr(), entry.dayOfMonth()) && specified(now.weekday(), entry.dayOfWeek()); } ssh-cron-1.05.00/cron/cron.ih0000644000175000017500000000133614324446662014637 0ustar frankfrank#include "cron.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../parser/parser.h" #include "../crondata/crondata.h" #include "../cronentry/cronentry.h" #include "../options/options.h" using namespace std; using namespace FBB; inline bool Cron::specified(size_t value, set const &request) { return request.find(value) != request.end(); } ssh-cron-1.05.00/cron/writerequest.cc0000644000175000017500000000034614324446663016427 0ustar frankfrank#include "cron.ih" void Cron::writeRequest(ostream &out, Function value) { out.seekp(SharedCondition::size()); // the shared cond. is at offset 0 out.write(reinterpret_cast(&value), sizeof(Function)); } ssh-cron-1.05.00/cron/readrequest.cc0000644000175000017500000000055514324446663016212 0ustar frankfrank#include "cron.ih" Cron::Function Cron::readRequest(istream &in) { in.clear(); // previously executed `read' commands // may have raised in's failbit. in.seekg(SharedCondition::size()); Function value; in.read(reinterpret_cast(&value), sizeof(Function)); return value; } ssh-cron-1.05.00/cron/cron.h0000644000175000017500000000402114324446662014460 0ustar frankfrank#ifndef INCLUDED_CRON_ #define INCLUDED_CRON_ #include #include #include #include #include "../ipcfunction/ipcfunction.h" namespace FBB { class DateTime; class SharedStream; } class CronEntry; class CronData; class Options; class Cron: public IPCFunction, public FBB::Fork { enum EndOfRun {}; Options &d_options; CronData &d_cronData; FBB::Pipe d_childInput; // child reads this std::ostream *d_toChild = 0; std::string d_passPhrase; volatile bool d_run = true; // set to false by stop static std::string s_agent; public: Cron(CronData &cronData); void runParentProcess(); void stop(size_t signal); void setPassPhrase(std::string const &passPhrase); static Function readRequest(std::istream &in); static void writeRequest(std::ostream &out, Function value); static std::string hmac2str(std::string const &passPhrase); private: void childRedirections() override; void childProcess() override; void parentProcess() override; std::ostream &idmsg() const; // imsg << "scheduler: " std::ostream &scheduler() const; // d_options.msg() << "scheduler: " void defineRunFunction(); void sendCommand(std::string line); void cronLoop(); void runCronJobs(); bool call(FBB::DateTime const &now, CronEntry const &entry); void execute(CronEntry const &entry); void handleRequests(); // separate thread void list(size_t *index, std::streamsize offset, FBB::SharedStream &sharedStream); bool reload(std::istream &in); static bool specified(size_t value, std::set const &request); static void requestHandler(Cron *cron); static std::string hmac(std::string const &passPhrase); }; inline void Cron::setPassPhrase(std::string const &passPhrase) { d_passPhrase = hmac(passPhrase); } #endif ssh-cron-1.05.00/cron/cronloop.cc0000644000175000017500000000115114324446662015511 0ustar frankfrank#include "cron.ih" void Cron::cronLoop() // called from parentprocess try { idmsg() << "starting cronloop" << endl; while (d_run) { size_t seconds = time(0) % 60; if (seconds != 0) { idmsg() << "sleeping for " << (60 - seconds) << " seconds" << endl; sleep(60 - seconds); // ends at a sigint signal } runCronJobs(); if (time(0) % 60 == 0) sleep(1); // ends at a sighup signal } } catch(EndOfRun) {} ssh-cron-1.05.00/cron/cron1.cc0000644000175000017500000000016514324446662014704 0ustar frankfrank#include "cron.ih" Cron::Cron(CronData &cronData) : d_options(Options::instance()), d_cronData(cronData) {} ssh-cron-1.05.00/cron/runcronjobs.cc0000644000175000017500000000054714324446663016233 0ustar frankfrank#include "cron.ih" void Cron::runCronJobs() // called from cronloop { DateTime now(DateTime::LOCALTIME); for (CronEntry const &entry: d_cronData.cronEntries()) { if (call(now, entry)) { if (not d_run) throw EndOfRun(); // caught by cronloop execute(entry); } } } ssh-cron-1.05.00/cron/sendcommand.cc0000644000175000017500000000014114324446663016145 0ustar frankfrank#include "cron.ih" void Cron::sendCommand(string line) { *d_toChild << line << endl; } ssh-cron-1.05.00/cron/childredirections.cc0000644000175000017500000000040514324446662017355 0ustar frankfrank#include "cron.ih" void Cron::childRedirections() { d_childInput.readFrom(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); open("/dev/null", O_WRONLY); // reopen cout open("/dev/null", O_WRONLY); // reopen cerr } ssh-cron-1.05.00/cron/idmsg.cc0000644000175000017500000000012714324446663014764 0ustar frankfrank#include "cron.ih" ostream &Cron::idmsg() const { return imsg << "scheduler: "; } ssh-cron-1.05.00/cron/hmac.cc0000644000175000017500000000036414324446663014574 0ustar frankfrank#include "cron.ih" string Cron::hmac(string const &passPhrase) { HMacBuf hmacbuf(passPhrase, "aes-256-cbc", "sha256", 1024); ostream out(&hmacbuf); out << passPhrase << eoi; string hash = hmacbuf.hash(); return hash; } ssh-cron-1.05.00/cron/frame0000644000175000017500000000003714324446663014367 0ustar frankfrank#include "cron.ih" Cron:: { } ssh-cron-1.05.00/crondata/0000755000175000017500000000000014333652630014175 5ustar frankfrankssh-cron-1.05.00/crondata/insert.cc0000644000175000017500000000035614324446663016023 0ustar frankfrank#include "crondata.ih" ostream &CronData::insert(ostream &out) const { for (auto &spec: d_environment) out << spec << '\n'; for (auto &entry: d_cronEntries) entry.insert(out) << '\n'; return out << flush; } ssh-cron-1.05.00/crondata/addnr.cc0000644000175000017500000000034714324446663015607 0ustar frankfrank#include "crondata.ih" void CronData::addNr(size_t nr) { if (d_entryBegin <= nr && nr <= d_entryEnd) // <=, so allowEnd is d_wip.insert(nr); // handled else outOfRange(nr); } ssh-cron-1.05.00/crondata/invalidrange.cc0000644000175000017500000000034114324446663017154 0ustar frankfrank#include "crondata.ih" void CronData::invalidRange(size_t first, size_t last) const { emsg << "Line " << d_lineNr << " (" << d_entryName << "): invalid range " << first << '-' << last << endl; } ssh-cron-1.05.00/crondata/data.cc0000644000175000017500000000116014324446663015422 0ustar frankfrank#include "crondata.ih" size_t CronData::s_values[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, }; char const *const CronData::s_month[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; char const *const CronData::s_day[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; ssh-cron-1.05.00/crondata/addrange.cc0000644000175000017500000000104614324446663016261 0ustar frankfrank#include "crondata.ih" void CronData::addRange(size_t first, size_t last, size_t step) { if (first < d_entryBegin or d_entryEnd <= last) invalidRange(first, last); if (step == 0) emsg << "Line " << d_lineNr << ": step size must be >= 1" << endl; if (first > last) { emsg << "Line " << d_lineNr << ": invalid range " << first << '-' << last << endl; } if (emsg.count() != 0) return; for ( ; first <= last; first += step) d_wip.insert(first); } ssh-cron-1.05.00/crondata/sethours.cc0000644000175000017500000000024314324446663016366 0ustar frankfrank#include "crondata.ih" void CronData::setHours() { d_next.setHours(assign()); d_entryName = "day of month"; d_entryBegin = 1; d_entryEnd = 32; } ssh-cron-1.05.00/crondata/reset.cc0000644000175000017500000000033614324446663015637 0ustar frankfrank#include "crondata.ih" void CronData::reset(size_t lineNr) { d_lineNr = lineNr; d_entryBegin = 0; d_entryEnd = 60; d_entryName = "minutes"; d_names.clear(); d_all = false; d_wip.clear(); } ssh-cron-1.05.00/crondata/crondata.ih0000644000175000017500000000025514324446663016323 0ustar frankfrank#include "crondata.h" #include #include #include #include "../options/options.h" using namespace std; using namespace FBB; ssh-cron-1.05.00/crondata/addcroncommand.cc0000644000175000017500000000054714324446663017472 0ustar frankfrank#include "crondata.ih" void CronData::addCronCommand() { d_next.setEnvironment(d_lastSize, d_environment.size(), &d_environment); d_lastSize = d_environment.size(); d_cronEntries.push_back(d_next); if (d_info) imsg << Options::instance().basename() << ": cron " << d_cronEntries.size() << '\n' << d_next << endl; } ssh-cron-1.05.00/crondata/setdayofmonth.cc0000644000175000017500000000023014324446663017372 0ustar frankfrank#include "crondata.ih" void CronData::setDayOfMonth() { d_next.setDayOfMonth(assign()); d_entryName = "month of year"; d_entryEnd = 13; } ssh-cron-1.05.00/crondata/addname.cc0000644000175000017500000000016614324446663016107 0ustar frankfrank#include "crondata.ih" void CronData::addName(std::string const &name) { d_names.push_back(String::lc(name)); } ssh-cron-1.05.00/crondata/setmonthofyear.cc0000644000175000017500000000026414324446663017564 0ustar frankfrank#include "crondata.ih" void CronData::setMonthOfYear() { d_next.setMonthOfYear(assign(s_month)); d_entryName = "day of week"; d_entryBegin = 0; d_entryEnd = 7; } ssh-cron-1.05.00/crondata/assign2.cc0000644000175000017500000000123514324446663016062 0ustar frankfrank#include "crondata.ih" set CronData::assign(char const *const *names, bool allowEnd) { size_t size = d_entryEnd - d_entryBegin; for (string const &name: d_names) { char const *const *ptr = find(names, names + size, name); if (ptr != names + size) d_wip.insert(d_entryBegin + ptr - names); else emsg << "Line " << d_lineNr << " (" << d_entryName << "): `" << name << "' not supported" << endl; } d_names.clear(); if (allowEnd && d_wip.find(d_entryEnd) != d_wip.end()) { d_wip.erase(d_entryEnd); d_wip.insert(0); } return assign(); } ssh-cron-1.05.00/crondata/setenvvar.cc0000644000175000017500000000061714324446663016534 0ustar frankfrank#include "crondata.ih" void CronData::setEnvVar(string const &var, string const &value) { if (not value.empty()) { d_environment.push_back(var + '=' + String::trim(value)); if (d_info) imsg << Options::instance().basename() << ": envvar " << d_environment.size() << " `" << d_environment.back() << '\'' << endl; } } ssh-cron-1.05.00/crondata/crondata1.cc0000644000175000017500000000017314324446663016370 0ustar frankfrank#include "crondata.ih" CronData::CronData() : d_entryName("minutes"), d_info(not Options::instance().reload()) {} ssh-cron-1.05.00/crondata/setminutes.cc0000644000175000017500000000021314324446663016707 0ustar frankfrank#include "crondata.ih" void CronData::setMinutes() { d_next.setMinutes(assign()); d_entryName = "hours"; d_entryEnd = 24; } ssh-cron-1.05.00/crondata/assign.cc0000644000175000017500000000104614324446663016000 0ustar frankfrank#include "crondata.ih" set CronData::assign() { set dest; if (d_wip.size()) { size_t last = *d_wip.rbegin(); if (last >= d_entryEnd) { outOfRange(last); return dest; } } if (emsg.count() == 0) { if (!d_all) dest = d_wip; else { dest.insert(s_values, s_values + d_entryEnd); dest.insert(dest.end(), CronEntry::STAR); } } d_wip.clear(); d_all = false; return dest; } ssh-cron-1.05.00/crondata/setdayofweek.cc0000644000175000017500000000015014324446663017201 0ustar frankfrank#include "crondata.ih" void CronData::setDayOfWeek() { d_next.setDayOfWeek(assign(s_day, true)); } ssh-cron-1.05.00/crondata/process.cc0000644000175000017500000000031514324446663016170 0ustar frankfrank#include "crondata.ih" void CronData::process() { if (emsg.count() == 0) addCronCommand(); d_entryName = "minutes"; d_entryEnd = 60; d_next = CronEntry(); emsg.setCount(0); } ssh-cron-1.05.00/crondata/setcommand.cc0000644000175000017500000000016214324446663016644 0ustar frankfrank#include "crondata.ih" void CronData::setCommand(std::string const &command) { d_next.setCommand(command); } ssh-cron-1.05.00/crondata/outofrange.cc0000644000175000017500000000030414324446663016661 0ustar frankfrank#include "crondata.ih" void CronData::outOfRange(size_t nr) { emsg << "Line " << d_lineNr << " (" << d_entryName << "): " << nr << " out of range" << endl; d_wip.clear(); } ssh-cron-1.05.00/crondata/setall.cc0000644000175000017500000000025114324446663015775 0ustar frankfrank#include "crondata.ih" void CronData::setAll(size_t step) { if (step == 1) d_all = true; else addRange(d_entryBegin, d_entryEnd - 1, step); } ssh-cron-1.05.00/crondata/frame0000644000175000017500000000004714324446663015222 0ustar frankfrank#include "crondata.ih" CronData:: { } ssh-cron-1.05.00/crondata/crondata.h0000644000175000017500000000522514324446663016154 0ustar frankfrank#ifndef INCLUDED_CRONDATA_ #define INCLUDED_CRONDATA_ #include #include #include #include "../cronentry/cronentry.h" class CronData { friend std::ostream &operator<<(std::ostream &out, CronData const &cronData); std::vector d_environment; std::vector d_cronEntries; size_t d_lastSize = 0; CronEntry d_next; std::string d_entryName; size_t d_entryBegin = 0; size_t d_entryEnd = 60; std::set d_wip; std::vector d_names; // names used for time specifications // at a cron-job line size_t d_lineNr; bool d_all = false; bool d_info = true; static size_t s_values[60]; static char const *const s_month[12]; static char const *const s_day[7]; public: CronData(); void addNr(size_t nr); void addRange(size_t first, size_t last, size_t step); void setAll(size_t step); void addName(std::string const &str); void setCommand(std::string const &command); void process(); void reset(size_t lineNr = 0); // 0 means: do not update lineNr void messages(bool on = true); void setMinutes(); void setHours(); void setDayOfMonth(); void setMonthOfYear(); void setDayOfWeek(); void setEnvVar(std::string const &var, std::string const &value); size_t lineNr() const; size_t size() const; std::vector const &cronEntries() const; CronEntry const &operator[](size_t index) const; std::vector const &environment() const; private: std::set assign(); std::set assign(char const *const *names, bool allowEnd = false); void invalidRange(size_t first, size_t last) const; void outOfRange(size_t nr); void addCronCommand(); std::ostream &insert(std::ostream &out) const; }; inline size_t CronData::lineNr() const { return d_lineNr; } inline void CronData::messages(bool onOff) { d_info = onOff; } inline CronEntry const &CronData::operator[](size_t index) const { return d_cronEntries[index]; } inline std::vector const &CronData::cronEntries() const { return d_cronEntries; } inline size_t CronData::size() const { return d_cronEntries.size(); } inline std::vector const &CronData::environment() const { return d_environment; } inline std::ostream &operator<<(std::ostream &out, CronData const &cronData) { return cronData.insert(out); } #endif ssh-cron-1.05.00/cronentry/0000755000175000017500000000000014741230065014422 5ustar frankfrankssh-cron-1.05.00/cronentry/insert.cc0000644000175000017500000000053314324446663016250 0ustar frankfrank#include "cronentry.ih" ostream &CronEntry::insert(ostream &out) const { showSet(out, d_minutes); out << " "; showSet(out, d_hours); out << " "; showSet(out, d_dayOfMonth); out << " "; showSet(out, d_monthOfYear); out << " "; showSet(out, d_dayOfWeek); return out << " " << d_command; } ssh-cron-1.05.00/cronentry/cronentry.h0000644000175000017500000000532214324446663016632 0ustar frankfrank#ifndef INCLUDED_CRONENTRY_ #define INCLUDED_CRONENTRY_ #include #include #include #include class CronEntry { friend std::ostream &operator<<(std::ostream &out, CronEntry const &entry); size_t d_begin = 0; size_t d_end = 0; std::vector const *d_environment; std::set d_minutes; std::set d_hours; std::set d_dayOfMonth; std::set d_monthOfYear; std::set d_dayOfWeek; std::string d_command; public: enum { STAR = 100 // * used to specify time }; void setEnvironment(size_t begin, size_t end, std::vector const *environment); void setCommand(std::string const &src); void setMinutes(std::set &&src); void setHours(std::set &&src); void setDayOfMonth(std::set &&src); void setMonthOfYear(std::set &&src); void setDayOfWeek(std::set &&src); size_t nSettings() const; std::string const &command() const; std::set const &minutes() const; std::set const &hours() const; std::set const &dayOfMonth() const; std::set const &monthOfYear() const; std::set const &dayOfWeek() const; std::ostream &insert(std::ostream &out) const; private: static void showSet(std::ostream &out, std::set const &nrSet); }; inline void CronEntry::setCommand(std::string const &src) { d_command = src; } inline void CronEntry::setMinutes(std::set &&src) { d_minutes = std::move(src); } inline void CronEntry::setHours(std::set &&src) { d_hours = std::move(src); } inline void CronEntry::setDayOfMonth(std::set &&src) { d_dayOfMonth = std::move(src); } inline void CronEntry::setMonthOfYear(std::set &&src) { d_monthOfYear = std::move(src); } inline void CronEntry::setDayOfWeek(std::set &&src) { d_dayOfWeek = std::move(src); } inline size_t CronEntry::nSettings() const { return d_end; } inline std::string const &CronEntry::command() const { return d_command; } inline std::set const &CronEntry::minutes() const { return d_minutes; } inline std::set const &CronEntry::hours() const { return d_hours; } inline std::set const &CronEntry::dayOfMonth() const { return d_dayOfMonth; } inline std::set const &CronEntry::monthOfYear() const { return d_monthOfYear; } inline std::set const &CronEntry::dayOfWeek() const { return d_dayOfWeek; } #endif ssh-cron-1.05.00/cronentry/setenvironment.cc0000644000175000017500000000034614324446663020026 0ustar frankfrank#include "cronentry.ih" void CronEntry::setEnvironment(size_t begin, size_t end, std::vector const *environment) { d_begin = begin; d_end = end; d_environment = environment; } ssh-cron-1.05.00/cronentry/operatorinsert.cc0000644000175000017500000000112214324446663020017 0ustar frankfrank#include "cronentry.ih" ostream &operator<<(ostream &out, CronEntry const &entry) { auto begin = entry.d_environment->begin() + entry.d_begin; auto end = entry.d_environment->begin() + entry.d_end; bool envVars = begin != end; if (envVars && entry.d_begin > 0) // separate previous command list by out.put('\n'); // empty line for ( ; begin != end; ++begin) out << "Envvar: " << *begin << '\n'; if (envVars) // separate env. vars from command(s) out.put('\n'); entry.insert(out); return out; } ssh-cron-1.05.00/cronentry/showset.cc0000644000175000017500000000050314324446663016435 0ustar frankfrank#include "cronentry.ih" void CronEntry::showSet(ostream &out, set const &nrSet) { if (nrSet.find(STAR) != nrSet.end()) { out << '*'; return; } auto begin = nrSet.begin(); out << *begin++; for (auto end = nrSet.end(); begin != end; ++begin) out << ',' << *begin; } ssh-cron-1.05.00/cronentry/frame0000644000175000017500000000005114324446663015445 0ustar frankfrank#include "cronentry.ih" CronEntry:: { } ssh-cron-1.05.00/cronentry/cronentry.ih0000644000175000017500000000010214324446663016772 0ustar frankfrank#include "cronentry.h" #include using namespace std; ssh-cron-1.05.00/crontab0000644000175000017500000000032414324446663013763 0ustar frankfrank# this file is used in the POC demo, and is for my use only. # it requires the ssh-key to log into suffix.rc.rug.nl * * * * * /bin/date >> /tmp/out * * * * * /usr/bin/ssh suffix.rc.rug.nl ls www >> /tmp/out ssh-cron-1.05.00/daemon/0000755000175000017500000000000014333652630013645 5ustar frankfrankssh-cron-1.05.00/daemon/parentprocess.cc0000644000175000017500000000057314324446663017060 0ustar frankfrank#include "daemon.ih" void Daemon::parentProcess() { ofstream ipcFile; // open the daemon's ipc-file: Exception::open(ipcFile, Options::instance().ipcFile()); // see also cron/handlerequests and daemon/terminate ipcFile << d_shmem.id() << '\n' << pid() << endl; cout << '\n' << d_cronData << endl; } ssh-cron-1.05.00/daemon/terminate.cc0000644000175000017500000000034114324446663016151 0ustar frankfrank#include "daemon.ih" void Daemon::terminate() const { basename() << "--terminate" << endl; IPCInfo info = getIPCInfo(); idmsg() << "terminating process " << info.pid << endl; kill(info.pid, SIGTERM); } ssh-cron-1.05.00/daemon/getpassphrase.cc0000644000175000017500000000176114324446663017041 0ustar frankfrank#include "daemon.ih" void Daemon::getPassPhrase() { Tty tty; tty.echo(Tty::OFF); ifstream in; Exception::open(in, "/dev/tty"); while (true) { cout << "Enter passphrase: " << flush; string passphrase1; getline(in, passphrase1); if (passphrase1.length() < 10) throw Exception{} << "\n" "Error: passphrases must be at leas 10 characters long"; cout << "\nEnter same passphrase again: " << flush; string passphrase2; getline(in, passphrase2); cout << endl; if (passphrase1 == passphrase2) { // see cron/hmac.cc: the passphrase must be 32 chars long while (passphrase1.length() < 32) passphrase1 += passphrase1; passphrase1.resize(32); d_cron.setPassPhrase(passphrase1); break; } cout << "Different passphrases. Try again\n\n"; } } ssh-cron-1.05.00/daemon/enterthread.cc0000644000175000017500000000026514324446663016473 0ustar frankfrank#include "daemon.ih" void Daemon::enterThread(Daemon *obj) { Tty tty; tty.echo(Tty::OFF); cin.ignore(numeric_limits::max(), '\n'); kill(getpid(), SIGTERM); } ssh-cron-1.05.00/daemon/list.cc0000644000175000017500000000104414324446663015135 0ustar frankfrank#include "daemon.ih" bool Daemon::list(istream &in) { in.clear(); Function function = Cron::readRequest(in); if (function > TERMINATE) { basename() << "received corrupted function request, value = " << function << endl; return false; } idmsg() << "received " << nameOf(function) << endl; if (function == DONE) return false; string line; while (getline(in, line)) cout << line << '\n'; return true; } ssh-cron-1.05.00/daemon/run.cc0000644000175000017500000000052414324446663014770 0ustar frankfrank#include "daemon.ih" void Daemon::run() { if (d_options.ipc()) ipc(); // handles commands to the daemon else if (d_options.foreground()) childProcess(); // ssh-cron runs in the foreground else daemonize(); // ssh-cron runs in the background } ssh-cron-1.05.00/daemon/reload.cc0000644000175000017500000000242014324446663015427 0ustar frankfrank#include "daemon.ih" void Daemon::reload() { basename() << "--reload" << endl; // send the name of the cron-file to the daemon unique_ptr path(realpath(ArgConfig::instance()[0], 0)); // verify the availability of the IPC file IPCInfo info = getIPCInfo(); SharedStream sharedStream(info.shmemID); SharedCondition cond(sharedStream.attachSharedCondition(0)); cond.lock(); for (size_t attempt = 0; attempt != 3; ++attempt) { Cron::writeRequest(sharedStream, RELOAD); // the offset is just beyond the request // retrieve the passphrase string passPhrase = askPassPhrase(); sharedStream << passPhrase << '\n' << path.get() << endl; sharedStream.truncate(sharedStream.tellp()); idmsg() << "notifying the daemon: RELOAD " << path.get() << endl; cond.notify(); cv_status status = cond.wait_for(chrono::seconds(5)); cond.unlock(); if (status != cv_status::timeout) { // show the scheduled jobs to be reloaded cout << '\n' << d_cronData << endl; return; } cout << "Invalid passphrase.\n" << endl; } cout << "Giving up after three attempts." << endl; } ssh-cron-1.05.00/daemon/listrequest.cc0000644000175000017500000000202114324446663016542 0ustar frankfrank#include "daemon.ih" void Daemon::listRequest() { basename() << "--list" << endl; IPCInfo info = getIPCInfo(); SharedStream sharedStream(info.shmemID); SharedCondition cond(sharedStream.attachSharedCondition(0)); cond.lock(); Cron::writeRequest(sharedStream, LIST); Function function = LIST; do { idmsg() << "notifying [" << nameOf(function) << "] the daemon " << endl; cond.notify(); // notify the server (waiting remote process) // now wait for the answer cv_status status = cond.wait_for(chrono::seconds(2)); if (status == cv_status::no_timeout) function = MORE; else { cond.unlock(); fmsg << "--list: no response from process " << info.pid << endl; } } while (list(sharedStream)); // process the reply cond.unlock(); // allow the daemon to return to its waiting // state } ssh-cron-1.05.00/daemon/daemon.ih0000644000175000017500000000107714324446663015446 0ustar frankfrank#include "daemon.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../options/options.h" #include "../parser/parser.h" using namespace std; using namespace FBB; struct Daemon::IPCInfo { size_t shmemID; size_t pid; }; ssh-cron-1.05.00/daemon/childprocess.cc0000644000175000017500000000132514324446663016646 0ustar frankfrank#include "daemon.ih" void Daemon::childProcess() { Signal::instance().add(SIGINT, *this); Signal::instance().add(SIGTERM, *this); thread waiter; // waits for Enter with --no-daemon if (d_options.daemon()) { prepareDaemon(); imsg << "daemon: starting the scheduler" << endl; } else { cout << "Press the `Enter' key to end `" << d_options.basename() << '\'' << endl; waiter = thread(enterThread, this); waiter.detach(); idmsg() << "starting the scheduler" << endl; } d_cron.fork(); if (d_options.daemon()) cleanup(); throw 0; // correctly end the child process at main } ssh-cron-1.05.00/daemon/daemon1.cc0000644000175000017500000000077514324446663015520 0ustar frankfrank#include "daemon.ih" Daemon::Daemon() : d_options(Options::instance()), d_cron(d_cronData) { if (not d_options.cronfile()) // no file command-line argument return; ifstream in; Exception::open(in, ArgConfig::instance()[0]); Parser parser(in, d_cronData); // parse the input file parser.parse(); // filling d_cronData if (d_cronData.size() == 0) // warn if no commands wmsg << "no cron-commands to execute." << endl; } ssh-cron-1.05.00/daemon/daemon.h0000644000175000017500000000267114324446663015276 0ustar frankfrank#ifndef INCLUDED_DAEMON_ #define INCLUDED_DAEMON_ #include #include #include #include "../ipcfunction/ipcfunction.h" #include "../crondata/crondata.h" #include "../cron/cron.h" class Options; namespace FBB { class SharedCondition; class SharedStream; } class Daemon: public IPCFunction, public FBB::Fork, public FBB::SignalHandler { struct IPCInfo; Options &d_options; CronData d_cronData; Cron d_cron; FBB::SharedMemory d_shmem; public: Daemon(); void run(); private: std::ostream &idmsg() const; // imsg inserts basename : std::ostream &basename() const; // options.msg() inserts basename : void foreground(); // don't fork, just call the child process void daemonize(); // run the daemon in the background void ipc(); // do the other commands, involving ipc void createIPCfile(); void cleanup(); void parentProcess() override; void childProcess() override; void signalHandler(size_t signum) override; void terminate() const; IPCInfo getIPCInfo() const; void getPassPhrase(); std::string askPassPhrase(); void reload(); void listRequest(); bool list(std::istream &in); static void enterThread(Daemon *obj); }; #endif ssh-cron-1.05.00/daemon/createipcfile.cc0000644000175000017500000000114114324446663016757 0ustar frankfrank#include "daemon.ih" // called from daemonize() void Daemon::createIPCfile() { string const &ipcFile = d_options.ipcFile(); unique_ptr buffer(new char[ipcFile.length() + 6 + 1]); strcpy(buffer.get() + ipcFile.copy(buffer.get(), string::npos), "XXXXXX"); int fd = mkstemp(buffer.get()); if (fd != -1) { close(fd); fd = rename(buffer.get(), d_options.ipcFile().c_str()); } if (fd == -1) fmsg << "cannot create ipc file `" << d_options.ipcFile() << '\'' << endl; } ssh-cron-1.05.00/daemon/basename.cc0000644000175000017500000000017014324446663015734 0ustar frankfrank#include "daemon.ih" ostream &Daemon::basename() const { return d_options.msg() << d_options.basename() << ": "; } ssh-cron-1.05.00/daemon/signalhandler.cc0000644000175000017500000000015714324446663017001 0ustar frankfrank#include "daemon.ih" void Daemon::signalHandler(size_t signal) { d_cron.stop(signal); cerr << '\n'; } ssh-cron-1.05.00/daemon/getipcinfo.cc0000644000175000017500000000065514324446663016320 0ustar frankfrank#include "daemon.ih" Daemon::IPCInfo Daemon::getIPCInfo() const { ifstream ipcFile; Exception::open(ipcFile, Options::instance().ipcFile()); IPCInfo info; if (not (ipcFile >> info.shmemID >> info.pid)) fmsg << "corrupted " << Options::instance().ipcFile() << endl; idmsg() << "IPC info: shared memory ID: " << info.shmemID << ", daemon PID: " << info.pid << endl; return info; } ssh-cron-1.05.00/daemon/idmsg.cc0000644000175000017500000000015214324446663015264 0ustar frankfrank#include "daemon.ih" ostream &Daemon::idmsg() const { return imsg << d_options.basename() << ": "; } ssh-cron-1.05.00/daemon/askpassphrase.cc0000644000175000017500000000044014324446663017031 0ustar frankfrank#include "daemon.ih" string Daemon::askPassPhrase() { Tty tty; tty.echo(Tty::OFF); ifstream in; Exception::open(in, "/dev/tty"); cout << "Enter passphrase: " << flush; string passphrase; getline(in, passphrase); cout << endl; return passphrase; } ssh-cron-1.05.00/daemon/cleanup.cc0000644000175000017500000000032714324446663015614 0ustar frankfrank#include "daemon.ih" void Daemon::cleanup() // only called by daemons { d_shmem.kill(); // when the child process ends it throws away its own pid file: unlink(d_options.ipcFile().c_str()); } ssh-cron-1.05.00/daemon/frame0000644000175000017500000000004314324446663014666 0ustar frankfrank#include "daemon.ih" Daemon:: { } ssh-cron-1.05.00/daemon/ipc.cc0000644000175000017500000000047114324446663014740 0ustar frankfrank#include "daemon.ih" void Daemon::ipc() { switch (d_options.ipcFunction()) { case TERMINATE: terminate(); break; case LIST: listRequest(); break; case RELOAD: reload(); break; default: break; } } ssh-cron-1.05.00/daemon/daemonize.cc0000644000175000017500000000216014324446663016135 0ustar frankfrank#include "daemon.ih" void Daemon::daemonize() { string const &ipcFile = d_options.ipcFile(); if (access(ipcFile.c_str(), F_OK) == 0) { bool remove = d_options.forced(); if (not remove) { wmsg << ipcFile << " is in the way. Remove it [Ny]? "; string answer; remove = getline(cin, answer) && (answer == "y" || answer == "yes"); } if (not remove or unlink(ipcFile.c_str()) != 0) fmsg << "cannot continue as " << ipcFile << " cannot be removed " << endl; } getPassPhrase(); createIPCfile(); // create it with access mode 0600, // parentProcess() writes information to it d_shmem = SharedMemory(1, SharedMemory::kB);// create the shared memory try { SharedCondition::create(d_shmem); // create the shared condition } catch (exception const &exc) { unlink(ipcFile.c_str()); throw; } idmsg() << "starting the daemon" << endl; fork(); } ssh-cron-1.05.00/documentation/0000755000175000017500000000000014324446663015262 5ustar frankfrankssh-cron-1.05.00/documentation/man/0000755000175000017500000000000014741230061016017 5ustar frankfrankssh-cron-1.05.00/documentation/man/ssh-cron.yo0000644000175000017500000003223714324446663020151 0ustar frankfrankgagmacrowarning(cron argument phrase key passphrase) includefile(../../release.yo) htmlbodyopt(text)(#27408B) htmlbodyopt(bgcolor)(#FFFAF0) gagmacrowarning(ssh-cron) mailto(f.b.brokken@rug.nl) DEFINEMACRO(lsoption)(3)(\ bf(--ARG1)=tt(ARG3) (bf(-ARG2))\ ) DEFINEMACRO(laoption)(2)(\ bf(--ARG1)=tt(ARG2)\ ) DEFINEMACRO(loption)(1)(\ bf(--ARG1)\ ) DEFINEMACRO(soption)(1)(\ bf(-ARG1)\ ) DEFINEMACRO(s)(0)(bf(ssh-cron)) DEFINEMACRO(S)(0)(bf(Ssh-Cron)) DELETEMACRO(tt) DEFINEMACRO(tt)(1)(em(ARG1)) manpage(ssh-cron)(1)(_CurYrs_)(ssh-cron__CurVers_) (ssh-cron - ssh-aware cron-like daemon) manpagename(ssh-cron)(cron-like daemon able to use ssh-connections) manpagesynopsis() bf(ssh-cron) [OPTIONS] tt([crontab-file]) nl() [OPTIONS] - cf. section bf(OPTIONS)nl() [crontab-file] - file containing jobs to run.nl() manpagedescription() Consider the situation where a computer every now and then must access a remote computer to do some useful things at that remote computer (like running a bf(stealth)(1) file integrity scan). In order to do so the computer must be allowed to make bf(ssh)(1) connections to the remote computer. But since the commands are not executed by the user but by bf(cron)(1), the ssh-keys which are required to access the remote computer cannot use passphrases. This is an undesirable situation: if the computer running the tt(ssh) commands gets compromised, then the remote computers are compromised as well, since the attacker may access these remote systems using ssh keys not requiring pass phrases. S() offers a way out of this undesirable situation, while still allowing commands to be executed on remote computers. Here's how this is realized: itemization( it() Normally, s() runs as a daemon program. When s() starts it first reads and parses a crontab-like specification file. Following this, s() spawns a child process, and terminates. it() S()'s daemon process itself spawns an bf(ssh-agent)(1) child process, executing all scheduled commands. it() In addition, s()'s daemon defines communication channels between itself and its bf(ssh-agent)(1) child process; it() S()'s daemon sends the command bf(ssh-add)(1) to its child process as its first command to execute, and using normal user-interaction means (e.g., using bf(ssh-askpass)(1)) em(ssh-agent) is provided with the required passphrase(s) for the ssh key(s). it() S()'s daemon now monitors the time, firing off scheduled commands at their required moments in time. If these commands require access to remote computers, then this access is granted, as em(ssh-agent) is able to provide the passphrase(s). it() If an s() daemon process is already running, then the tt(--reload) option (see below), can be used to load the s() daemon with the commands and environment variable settings from another tt(crontab-file), replacing the currently stored commands and environment settings by the ones provided in the reloaded file. ) When shell control characters (like redirection symbols) must be used in command specifications, they should be escaped. E.g., as in tt(echo hello world \> /dev/null). Users sharing a computer each define their own s() specification file. When a user logs out and leaves the system the daemon process continues to run, executing its scheduled commands at their scheduled times, using ssh-keys whenever required. If the accounts for which s() jobs are running are ever compromised, the remote computers remain safe, as the passphrases of the available ssh-keys remain unavailable. To prevent unauthorized modifications of the commands scheduled by the s() daemon themselves a passphrase is required when starting s()'s daemon process. The passphrase itself is not stored by the daemon (instead, it stores a bf(sha256)(1) hash value), which avoids access to the s() daemon's passphrase by browsing the computer's memory. The passphrase must be at least 10 characters long and must be provided when reloading s() daemon's scheduled commands. The scheduled commands may be listed, however. This is allowed without providing a passphrase since the file containing the scheduled commands will usually also be available on the computer. Likewise, since a user may always terminate his/her own programs an s() daemon process can be terminated from another s() program using the tt(--terminate) command line option. The above mentioned facilities are not supported by bf(crontab)(1) itself. bf(Cron)(1), which is responsible for executing scheduled crontab commands, has no access to the passphrases of ssh-keys (which are otherwise provided em(ssh-agent)). manpagesection(RETURN VALUE) S() returns 0 if the daemon was successfully started. Otherwise 1 is returned. manpageoptions() Where available, single letter options are listed between parentheses following their associated long-option variants. Single letter options require arguments if their associated long options also require arguments. Several options have default values. Run tt(ssh-cron --help) for an overview of the implemented default option values. Also, several options can be specified in a configuration file (where this doesn't hold true, it is explicitly mentioned at the relevant options). The configuration file (not to be confused with the file containing the scheduled commands, which is provided as s() command-line file argument) ignores empty lines and all information on lines starting at a hash-mark (tt(#), optionally preceded by blanks and/or tabs). The configuration file is used to specify s()'s options using their long variants. However, in the configuration file the initial hyphens of command-line options must be omitted, and optionally a colon may be appended to these long options names. Note that multi-word option arguments should not be surrounded by quotes. Examples: verb( stdout syslog-facility: LOCAL0 mailer: /usr/bin/mail -s "some subject" me@myhost.warpnet.nl ) Command-line options always override configuration file options. itemization( it() laoption(agent)(agent)nl() absolute path to the agent program (plus its argument(s)) providing the ssh-keys. By default tt(/usr/bin/ssh-agent /bin/bash) is used. it() lsoption(config)(c)(path)nl() config file containing long option specifications. By default tt(~/.ssh-cron) is used. This option cannot be specified in the configuration file. it() loption(forced) (soption(f))nl() When restarting s() and an existing (leftover) ipc-file file exists, then the user is interactively given the opportunity to remove the existing ipc-file during daemon-startup. it() loption(help) (soption(h))nl() basic usage information is written to the standard output stream (only interpreted in combination with tt(--no-daemon)). This option cannot be specified in the configuration file. it() lsoption(ipc-file)(p)(path)nl() when s() runs as a daemon, then tt(path) specifies the path of the file holding the daemon's shared memory ID and process ID. The ipc file must be available if s() is connecting to or starting a daemon process (the former situation occurs with the options tt(--list, --reload), and tt(--terminate)). If s() detects an existing tt(ipc-file) at daemon startup and the option tt(--forced) was not specified, then the user is interactively given the opportunity to remove the existing file. If the existing ipc-file can or should not be removed, then the daemon is not started. To end a daemon process use tt(ssh-cron --terminate), or send a SIGINT (tt(ctrl-C)) or SIGTERM signal to the process-id found as the second value in the tt(ipc-file). By default tt(~/.ssh-cron.ipc) is used. it() loption(list) (soption(l))nl() list the currently defined environment settings and cron-commands (the tt(crontab-file) argument must be omitted). This option is incompatible with (--no-daemon, --reload,) and tt(--terminate). This option cannot be specified in the configuration file. it() lsoption(log)(L)(path)nl() log messages are appended to tt(path). If tt(path) does not exist, it is created first. it() lsoption(mailer)(m)(command)nl() information written to the standard output or standard error streams of the commands executed by s() is sent by e-mail to the current user. Use tt(--mailer) to redefine (or to suppress sending e-mail by specifying an empty mailer command (i.e., tt(--mailer ""))). By default tt(/usr/bin/mail -s \"Ssh-cron $*\" $USER@localhost) is used, with tt($*) replaced by the exected command as specified in the tt(crontab) file argument. it() loption(no-daemon) nl() s() is not run as a daemon. To properly end s() if not running as a daemon, press the `Enter' key, enter tt(ctrl-C) or send s() a tt(SIGTERM) signal. This option is incompatible with ( --list, --reload,) and tt(--terminate). This option cannot be specified in the configuration file. it() loption(reload) (soption(r))nl() reload the s() daemon with de cron-commands defined in the tt(crontab-file) argument (which must be provided). This option is incompatible with (--list, --no-daemon,) and tt(--terminate). This option cannot be specified in the configuration file. it() loption(stdout) (soption(s))nl() in addition to using a log file and syslog messages send all messages to the standard output. This option is not available if s() runs as a daemon process. This option cannot be specified in the configuration file. it() loption(syslog)nl() messages are sent to the syslog daemon when this option is specified. By default syslog messages are written to the tt(DAEMON) facility with priority tt(NOTICE). it() laoption(syslog-facility)(facility)nl() the facility that is used to write the syslog messages to. By default this is tt(DAEMON). For an overview of facilities and their meanings, see, e.g., bf(syslog)(3). With s() the facilities tt(DAEMON, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7), and tt(USER) can be used. By default facility tt(DAEMON) is used. it() laoption(syslog-priority)(priority)nl() the priority that is used to write the syslog messages to. By default this is tt(NOTICE). For an overview of priorities and their meanings, see, e.g., bf(syslog)(3). With s() all defined priorities can be used. E.g., tt( EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO) and tt(DEBUG). By default priority tt(NOTICE) is used. it() laoption(syslog-tag)(tag)nl() syslog messages can be provided with a em(tag), which can be used to filter them from the log-files. See also section tt(RSYSLOG FILTERING) below. By default the tag tt(SSH-CRON) is used. it() loption(terminate) (soption(t))nl() terminate a running s() daemon program, using the daemon's process ID found in the ipc-file's second value. The tt(crontab-file) argument must be omitted. This option is incompatible tt with (--list, --nodaemon,) and tt(--reload) . This option cannot be specified in the configuration file. it() loption(verbose)nl() additional messages about s()'s mode of operation are sent to s()'s log facilities (specified by tt(--log, --syslog,) and/or tt(--stdout)). it() loption(version) (soption(v))nl() s()'s version number is written to the standard output stream. This option cannot be specified in the configuration file. ) manpagesection(RSYSLOG FILTERING) When using bf(rsyslogd)(1) property based filters may be used to filter syslog messages and write them to a file of your choice. E.g., to filter messages starting with the syslog message tag (e.g., tt(SSH-CRON)) use verb( :syslogtag, isequal, "SSH-CRON:" /var/log/ssh-cron.log :syslogtag, isequal, "SSH-CRON:" stop ) Note that the colon is part of the tag, but is not specified with the tt(syslog-tag) option. This causes all messages having the tt(SSH-CRON:) tag to be written on tt(/var/log/ssh-cron.log) after which they are discarded. More extensive filtering is also supported, see, e.g., tt(http://www.rsyslog.com/doc/rsyslog_conf_filter.html) and tt(http://www.rsyslog.com/doc/property_replacer.html) manpageseealso() bf(cron)(1), bf(crontab)(1), bf(crontab)(5), , bf(rsyslogd)(1), bf(ssh)(1), bf(ssh-add)(1), bf(ssh-agent)(1), bf(ssh-askpass)(1), bf(stealth)(1), bf(syslog)(3) manpagebugs() None reported. manpagesection(COPYRIGHT) This is free software, distributed under the terms of the `GNU General Public License'. Copyright remains with the author. s() is available at tt(https://fbb-git.gitlab.io/ssh-cron/). manpagesection(ORGANIZATION) Center for Information Technology, University of Groningen. manpageauthor() Frank B. Brokken (bf(f.b.brokken@rug.nl)). ssh-cron-1.05.00/icmake/0000755000175000017500000000000014740775444013646 5ustar frankfrankssh-cron-1.05.00/icmake/setopt0000644000175000017500000000034114324446663015101 0ustar frankfrankstring setOpt(string install_im, string envvar) { list optvar; string ret; optvar = getenv(envvar); if (optvar[0] == "1") ret = optvar[1]; else ret = install_im; return ret; } ssh-cron-1.05.00/icmake/manpage0000644000175000017500000000054514324446663015201 0ustar frankfrank#define MANPAGE "../../tmp/man/" ${PROJECT} ".1" void manpage() { md("tmp/man tmp/manhtml"); chdir("documentation/man"); if (PROJECT ".yo" younger MANPAGE || "release.yo" younger MANPAGE) { run("yodl2man -o " MANPAGE " " PROJECT); run("yodl2html -o ../../tmp/manhtml/" PROJECT ".1.html " PROJECT); } exit(0); } ssh-cron-1.05.00/icmake/findall0000644000175000017500000000117314324446663015200 0ustar frankfrank// assuming we're in g_cwd, all entries of type 'type' matching source/pattern // are returned w/o final \n list findAll(string type, string source, string pattern) { string cmd; list entries; list ret; int idx; chdir(source); cmd = "find ./ -mindepth 1 -maxdepth 1 -type " + type; if (pattern != "") pattern = "-name '" + pattern + "'"; entries = backtick(cmd + " " + pattern + " -printf \"%f\\n\""); if (idx > 0 && strlen(entries[0]) > 0) { for (idx = listlen(entries); idx--; ) ret += (list)cutEoln(entries[idx]); } chdir(g_cwd); return ret; } ssh-cron-1.05.00/icmake/log0000755000175000017500000000063214324446663014352 0ustar frankfrank#!/bin/bash find tmp/install -type f -exec md5sum "{}" \; | sed 's|tmp/install|'$1'|' > $2 find tmp/install -type l -exec printf "link %s\n" "{}" \; | sed 's|tmp/install|'$1'|' >> $2 find tmp/install -type d -exec printf "dir %s\n" "{}" \; | sed 's|tmp/install|'$1'|' >> $2 ssh-cron-1.05.00/icmake/pathfile0000644000175000017500000000055214324446663015363 0ustar frankfranklist path_file(string path) { list ret; int len; int idx; for (len = strlen(path), idx = len; idx--; ) { if (path[idx] == "/") { ret = (list)substr(path, 0, idx) + (list)substr(path, idx + 1, len); return ret; } } ret = (list)"" + (list)path; return ret; } ssh-cron-1.05.00/icmake/clean0000644000175000017500000000044314740767717014660 0ustar frankfrankvoid clean(int dist) { run("rm -rf " "build-stamp configure-stamp " "options/SKEL " "tmp/*.o tmp/*-stamp " + "o */o release.yo tmp/lib*.a " ); if (dist) run("rm -rf spch tmp *.ih.gch */*.ih.gch"); exit(0); } ssh-cron-1.05.00/icmake/uninstall0000644000175000017500000000045614324446663015603 0ustar frankfrankvoid uninstall(string logfile) { int idx; list entry; string dir; list line; if (!exists(logfile)) { printf("installation log file " + logfile + " not found\n"); exit(0); } run("icmake/remove " + logfile + " " + (string)g_echo); exit(0); } ssh-cron-1.05.00/icmake/cuteoln0000644000175000017500000000023414324446663015235 0ustar frankfrankstring cutEoln(string text) { int len; len = strlen(text) - 1; if (text[len] == "\n") text = substr(text, 0, len); return text; } ssh-cron-1.05.00/icmake/run0000644000175000017500000000033014324446663014365 0ustar frankfrankint g_dryrun = setOpt("", "DRYRUN") != ""; void runP(int testValue, string cmd) { if (g_dryrun) printf(cmd, "\n"); else system(testValue, cmd); } void run(string cmd) { runP(0, cmd); } ssh-cron-1.05.00/icmake/md0000644000175000017500000000074014324446663014166 0ustar frankfrank// md: target should be a series of blank-delimited directories to be created // If an element is a whildcard, the directory will always be created, // using mkdir -p. // // uses: run() void md(string target) { int idx; list paths; string dir; if (!exists(target)) run("mkdir -p " + target); else if (((int)stat(target)[0] & S_IFDIR) == 0) { printf(target + " exists, but is not a directory\n"); exit(1); } } ssh-cron-1.05.00/icmake/gitlab0000644000175000017500000000022314324446663015024 0ustar frankfrankvoid gitlab() { run("cp -r release.yo tmp/manhtml/ssh-cron.1.html ../../wip"); run("cp changelog ../../wip/changelog.txt"); exit(0); } ssh-cron-1.05.00/icmake/remove0000755000175000017500000000117014324446663015064 0ustar frankfrank#!/bin/bash g_echo=$2 rm_f() { [ $g_echo -ne 0 ] && echo rm $1 rm -f $1 } rm_dir() { [ $g_echo -ne 0 ] && echo rmdir $1 rmdir --ignore-fail-on-non-empty -p $1 } IFS=" " for line in `cat $1` do field1=`echo $line | awk '{printf $1}'` field2=`echo $line | awk '{printf $2}'` if [ $field1 == "link" ] ; then rm_f $field2 elif [ $field1 == "dir" ] ; then rm_dir $field2 elif [ -e "$field2" ] ; then if [ "$field1" != "`md5sum $field2 | awk '{printf $1}'`" ] ; then echo $field2 changed, not removed else rm_f $field2 fi fi done rm_f $1 ssh-cron-1.05.00/icmake/backtick0000644000175000017500000000016014324446663015335 0ustar frankfranklist backtick(string arg) { list ret; echo(OFF); ret = `arg`; echo(g_echo); return ret; } ssh-cron-1.05.00/icmake/install0000644000175000017500000000335314324446663015237 0ustar frankfrank void install(string request, string dest) { string target; int components = 0; list pathsplit; string base; base = "tmp/install/"; md(base); if (request == "x") components = 63; else { if (strfind(request, "b") != -1) components |= 2; if (strfind(request, "d") != -1) components |= 4; if (strfind(request, "m") != -1) components |= 8; } if (components & 2) { target = base + BINARY; pathsplit = path_file(target); printf(" installing the executable `", target, "'\n"); logFile("tmp/bin", "binary", pathsplit[0], pathsplit[1]); } if (components & (4 | 8)) { target = base + DOC "/"; if (components & 4) { printf(" installing changelog at `", target, "\n"); logZip("", "changelog", target ); printf(" installing the README file at `", target, "\n"); logZip("", "README", target ); } if (components & 8) { printf(" installing the html-manual page at `", target, "\n"); logInstall("tmp/manhtml", "", target); } } if (components & 8) { target = base + MAN "/"; printf(" installing the manual page below `", target, "'\n"); logZip("tmp/man", "ssh-cron.1", target); } chdir(g_cwd); if (dest == "") dest = "/"; else md(dest); dest = cutEoln(backtick("realpath " + dest)[0]); if (g_logPath != "") backtick("icmake/log " + dest + " " + g_logPath); run("tar cf - -Ctmp/install . | tar xf - -C" + dest); printf("\n Installation completed\n"); exit(0); } ssh-cron-1.05.00/icmake/logfile0000644000175000017500000000025714324446663015212 0ustar frankfrankvoid logFile(string srcdir, string src, string destdir, string dest) { chdir(g_cwd); md(destdir); run("cp " + srcdir + "/" + src + " " + destdir + "/" + dest); } ssh-cron-1.05.00/icmake/loginstall0000644000175000017500000000213214324446663015733 0ustar frankfrank// source and dest, absolute or reachable from g_cwd, should exist. // files and links in source matching dest (if empty: all) are copied to dest // and are logged in g_log // Before they are logged, dest is created void logInstall(string src, string pattern, string dest) { list entries; int idx; chdir(g_cwd); md(dest); src += "/"; dest += "/"; if (listlen(makelist(O_DIR, src)) == 0) { printf("Warning: ", src, " not found: can't install ", src, pattern, " at ", dest, "\n"); return; } entries = findAll("f", src, pattern); // all files in the src dir. for (idx = listlen(entries); idx--; ) // cp all files to the target run("cp " + src + entries[idx] + " " + dest); // dir chdir(g_cwd); entries = findAll("l", src, pattern); // find all links for (idx = listlen(entries); idx--; ) { if (strlen(entries[idx]) != 0) // install existing links run("cp " CPOPTS " " + src + entries[idx] + " " + dest); } } ssh-cron-1.05.00/icmake/special0000644000175000017500000000034114740775350015203 0ustar frankfrankvoid special() { if (! exists("release.yo") || "VERSION" newer "release.yo") run("gcc -E VERSION.h | grep -v '#' | sed 's/\\\"//g' > " "release.yo"); } ssh-cron-1.05.00/icmake/logzip0000644000175000017500000000165614324446663015101 0ustar frankfrank// names may be a series of files in src, not a wildcard. // if it's empty then all files in src are used. // the files are gzipped and logged in dest. // src and dest do not have to end in / void logZip(string src, string names, string dest) { list files; int idx; string file; chdir(g_cwd); md(dest); dest += "/"; if (src != "") { if (listlen(makelist(O_DIR, src)) == 0) { printf("Warning: ", src, " not found: can't install ", src, names, " at ", dest, "\n"); return; } chdir(src); } if (names == "") files = makelist("*"); else files = strtok(names, " "); for (idx = listlen(files); idx--; ) { file = files[idx]; run("gzip -n -9 < " + file + " > " + file + ".gz"); } run("tar cf - *.gz | (cd " + g_cwd + "; cd " + dest + "; tar xf -)"); run("rm *.gz"); } ssh-cron-1.05.00/icmconf0000644000175000017500000000103114740767532013750 0ustar frankfrank#include "INSTALL.im" #define MULTICOMP "jobs -q" #define SPCH "" #define ADD_LIBRARIES "pthread bobcat" #define ADD_LIBRARY_PATHS "" #define LIBRARY "modules" #define MAIN "main.cc" #define OBJ_EXT ".o" #define SHAREDREQ "" #define SOURCES "*.cc" #define TMP_DIR "tmp" #define USE_ALL "a" #define IH ".ih" #define USE_ECHO ON #define USE_VERSION #define DEFCOM "program" ssh-cron-1.05.00/icmconf.lib0000644000175000017500000000073414324446663014523 0ustar frankfrank#define PRECOMP "-x c++-header" #define CLS #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" #define USE_ECHO ON #define IH ".ih" #define CXX "g++" #define CXXFLAGS " --std=c++2a -Wall -O2 " \ " -fdiagnostics-color=never " #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define DEFCOM "library" ssh-cron-1.05.00/input0000644000175000017500000000053214324446663013473 0ustar frankfrank# comment # comment PATH = /usr/local/bin:/usr/bin:/bin # min hr day-of-month month-of-year day-of-week cmnd # */15 0 * * * # 90 25 32 Jan,Feb Sun /usr/bin/hello world # * * * * * ssh styx "date \> /tmp/date" # * * * * * date \> /tmp/date MORE="additional var" 0 0 1 1 0 noaction ssh-cron-1.05.00/INSTALL0000644000175000017500000000751714324446662013453 0ustar frankfrankTo install ssh-cron by hand instead of using a binary distribution perform the following steps: 0. ssh-cron and its construction depends, in addition to the normally standard available system software on specific software and versions which is documented in the file `required'. (If you compile the bobcat library yourself, note that ssh-cron does not use the SSL, Milter and Xpointer classes; they may --as far as ssh-cron is concerned-- be left out of the library by running './build light') 1. It is expected you use icmake for the package construction. For this a top-level script (build) and support scripts in the ./icmake/ directory are available. By default, the 'build' script echoes the commands it executes to the standard output stream. By specifying the option -q (e.g., ./build -q ...) this is prevented, significantly reducing the output generated by 'build'. 2. Inspect the values of the variables in the file INSTALL.im Modify these when necessary. 3. Run ./build program [strip] to compile ssh-cron. The argument `strip' is optional and strips symbolic information from the final executable. 4. If you installed Yodl then you can create the documentation: ./build man builds the man-page. 5. Before installing the components of ssh-cron, consider defining the environment variable SSHCRON, defining its value as the (preferably absolute) filename of a file on which installed files and directories are logged. Defining the SSHCRON environment variable as ~/.ssh-cron usually works well. 6. Run (probably as root) ./build install 'what' 'base' to install. Here, 'what' specifies what you want to install. Specify: x, to install all components, or specify a combination of: b (binary program), d (standard documentation), m (man-page) E.g., use ./build install b 'base' if you only want to be able to run ssh-cron, and want it to be installed below 'base'. ./build install's last argument 'base' is optional: the base directory below which the requested files are installed. This base directory is prepended to the paths #defined in the INSTALL.im file. If 'base' is not specified, then INSTALL.im's #defined paths are used as-is. When requesting non-existing elements (e.g., ./build install x was requested, but the man-page hasn't been created) then these non-existing elements are silently ignored by the installation process. If the environment variable SSHCRON was defined when issuing the `./build install ...' command then a log of all installed files is written to the file indicated by the SSHCRON environment variable (see also the next item). Defining the SSHCRON environment variable as ~/.ssh-cron usually works well. 7. Uninstalling previously installed components of ssh-cron is easy if the environment variable SSHCRON was defined before issuing the `./build install ...' command. In that case, run the command ./build uninstall logfile where 'logfile' is the file that was written by ./build install. Modified files and non-empty directories are not removed, but the logfile itself is removed following the de-installation. 8. Following the installation nothing in the directory tree which contains this file (i.e., INSTALL) is required for the proper functioning of ssh-cron, so consider removing it. If you only want to remove left-over files from the build-process, just run ./build distclean ssh-cron-1.05.00/INSTALL.im0000644000175000017500000000260214740767425014052 0ustar frankfrank // The name of the project: #define PROJECT "ssh-cron" // When defined, these overrule COMPILER and COMPILER_OPTIONS // COMPILER and COMPILER_OPTIONS are now obsolete // Instead of CXX and CXXFLAGS, CC and CFLAGS can be used. // Their #define values are overruled by identically named environment // variables. // the compiler to use. #define CXX "ccache g++" // the compiler options to use. #define CXXFLAGS "-Wall -Werror -O2 -pthread "\ "-fdiagnostics-color=never" // flags passed to the linker #define LDFLAGS "" #define CPOPTS // COMPONENTS TO INSTALL // ===================== // For an operational non-Debian installation, you probably must be // `root'. // If necessary, adapt DOC, HDR, LIB and MAN (below) to your situation. // The provided locations are used by Debian Linux. // With 'build install' you can dynamically specify a location to prepend // to the locations configured here, and select which components you want // to install // ONLY USE ABSOLUTE DIRECTORY NAMES: // the final program #define BINARY "/usr/bin/"${PROJECT} // the directory where the standard documentation is stored #define DOC "/usr/share/doc/"${PROJECT} // the directory whre the manual page is stored #define MAN "/usr/share/man/man1" ssh-cron-1.05.00/ipcfunction/0000755000175000017500000000000014741230065014720 5ustar frankfrankssh-cron-1.05.00/ipcfunction/data.cc0000644000175000017500000000040514324446663016151 0ustar frankfrank#include "ipcfunction.ih" LinearMap IPCFunction::s_nameMap = { {NONE, "NONE"}, {DONE, "DONE"}, {LIST, "LIST"}, {MORE, "MORE"}, {RELOAD, "RELOAD"}, {TERMINATE, "TERMINATE"} }; ssh-cron-1.05.00/ipcfunction/ipcfunction.ih0000644000175000017500000000005714324446663017577 0ustar frankfrank#include "ipcfunction.h" using namespace FBB; ssh-cron-1.05.00/ipcfunction/ipcfunction.h0000644000175000017500000000074714324446663017434 0ustar frankfrank#ifndef INCLUDED_IPCFUNCTION_ #define INCLUDED_IPCFUNCTION_ #include struct IPCFunction { enum Function: unsigned int { NONE, DONE, LIST, MORE, RELOAD, TERMINATE }; private: static FBB::LinearMap s_nameMap; public: static char const *nameOf(Function fun); }; inline char const *IPCFunction::nameOf(Function fun) { return s_nameMap[fun]; } #endif ssh-cron-1.05.00/ipcfunction/frame0000644000175000017500000000005514324446663015747 0ustar frankfrank#include "ipcfunction.ih" IPCFunction:: { } ssh-cron-1.05.00/main.cc0000644000175000017500000000322314741230041013624 0ustar frankfrank#include "main.ih" // Room for Args initialization namespace // the anonymous namespace can be used here { Arg::LongOption longOptions[] = { // only interpreted from the command-line Arg::LongOption("help", 'h'), Arg::LongOption("version", 'v'), Arg::LongOption("list", 'l'), Arg::LongOption("no-daemon", Arg::NoArg), Arg::LongOption("reload", 'r'), Arg::LongOption("stdout", 's'), Arg::LongOption("terminate", 't'), Arg::LongOption("config", 'c'), Arg::LongOption("forced", 'f'), // all options below are also interpreted when specified by // the config file Arg::LongOption("agent", Arg::Required), Arg::LongOption("ipc-file", 'i'), Arg::LongOption("log", 'L'), Arg::LongOption("mailer", 'm'), Arg::LongOption("syslog", Arg::NoArg), Arg::LongOption("syslog-facility", Arg::Required), Arg::LongOption("syslog-priority", Arg::Required), Arg::LongOption("syslog-tag", Arg::Required), Arg::LongOption("verbose", Arg::NoArg), }; auto longEnd = longOptions + sizeof(longOptions) / sizeof(longOptions[0]); } int main(int argc, char **argv) try { ArgConfig &arg = ArgConfig::initialize("c:fhi:lL:m:rstv", longOptions, longEnd, argc, argv); arg.versionHelp(Options::usage, Icmbuild::version, 0); Daemon daemon; daemon.run(); } catch (exception const &exc) { if (exc.what() != to_string(fmsg.id())) cerr << exc.what() << endl; return 1; } catch (int x) { return ArgConfig::instance().option("hv") ? 0 : 1; } ssh-cron-1.05.00/main.ih0000644000175000017500000000033614740774724013665 0ustar frankfrank#include #include #include #include #include "version/version.h" #include "daemon/daemon.h" #include "options/options.h" using namespace std; using namespace FBB; ssh-cron-1.05.00/options/0000755000175000017500000000000014740775074014107 5ustar frankfrankssh-cron-1.05.00/options/syslogfacility.cc0000644000175000017500000000103114324446663017453 0ustar frankfrank#include "options.ih" Facility Options::syslogFacility() const { Facility facility; string option; if (not d_arg.option(&option, "syslog-facility")) facility = s_defaultSyslogFacility; else { LinearMap::const_iterator iter = s_syslogFacilities.find(option); if (iter == s_syslogFacilities.end()) fmsg << "syslog facility " << option << " not supported" << endl; facility = iter->second; } return facility; } ssh-cron-1.05.00/options/loadconfigfile.cc0000644000175000017500000000067514324446663017370 0ustar frankfrank#include "options.ih" void Options::loadConfigFile() { string configFile; if (not d_arg.option(&configFile, 'c')) { configFile = User().homedir() + s_defaultConfigFile; if (access(configFile.c_str(), R_OK) != 0) configFile.clear(); } if (not configFile.empty()) d_arg.open(configFile); // read the arg config file, which is also // the cron-file } ssh-cron-1.05.00/options/instance.cc0000644000175000017500000000021314324446663016213 0ustar frankfrank#include "options.ih" Options &Options::instance() { if (s_options == 0) s_options = new Options(); return *s_options; } ssh-cron-1.05.00/options/data.cc0000644000175000017500000000257214324446663015332 0ustar frankfrank#include "options.ih" Options *Options::s_options = 0; char const Options::s_defaultAgent[] = "/usr/bin/ssh-agent /bin/bash"; char const Options::s_defaultIPCfile[] = ".ssh-cron.ipc"; char const Options::s_defaultConfigFile[] = ".ssh-cron"; char const Options::s_defaultMailer[] = "/usr/bin/mail -s \"Ssh-cron $*\" $USER@localhost"; char const Options::s_defaultSyslogIdent[] = "SSH-CRON"; Facility Options::s_defaultSyslogFacility = Facility::DAEMON; Priority Options::s_defaultSyslogPriority = Priority::NOTICE; LinearMap const Options::s_syslogFacilities = { {"DAEMON", Facility::DAEMON}, {"LOCAL0", Facility::LOCAL0}, {"LOCAL1", Facility::LOCAL1}, {"LOCAL2", Facility::LOCAL2}, {"LOCAL3", Facility::LOCAL3}, {"LOCAL4", Facility::LOCAL4}, {"LOCAL5", Facility::LOCAL5}, {"LOCAL6", Facility::LOCAL6}, {"LOCAL7", Facility::LOCAL7}, {"USER", Facility::USER} }; LinearMap const Options::s_syslogPriorities = { {"EMERG", Priority::EMERG}, {"ALERT", Priority::ALERT}, {"CRIT", Priority::CRIT}, {"ERR", Priority::ERR}, {"WARNING", Priority::WARNING}, {"NOTICE", Priority::NOTICE}, {"INFO", Priority::INFO}, {"DEBUG", Priority::DEBUG} }; ssh-cron-1.05.00/options/options1.cc0000644000175000017500000000343214740770455016172 0ustar frankfrank#include "options.ih" Options::Options() : d_arg(ArgConfig::instance()), d_msg(&d_multiBuf) { // --help and --version already handled by versionHelp, but if nothing // is requested on the command line help is also provided. if ( d_arg.nArgs() == 0 && d_arg.nOptions() == 0 && d_arg.nLongOptions() == 0 ) { usage(d_arg.basename()); throw 0; } d_foreground = d_arg.option(0, "no-daemon"); if ((d_list = d_arg.option('l'))) d_ipcFunction = LIST; if ((d_reload = d_arg.option('r'))) d_ipcFunction = RELOAD; if ((d_terminate = d_arg.option('t'))) d_ipcFunction = TERMINATE; d_forced = d_arg.option('f'); checkAction(); if (d_arg.option('s')) { if (d_foreground) d_multiBuf.insert(cout); else wmsg << "--stdout ignored: " << d_arg.basename() << " runs as a daemon process" << endl; } loadConfigFile(); if (not d_arg.option(&d_agent, "agent")) d_agent = s_defaultAgent; if (not d_arg.option(&d_IPCfile, 'i')) d_IPCfile = User().homedir() + s_defaultIPCfile; string logName; if (d_arg.option(&logName, 'L')) { d_log.open(logName); if (not d_log) fmsg << "could not open " << logName << endl; d_multiBuf.insert(d_log); } if (not d_arg.option(&d_mailer, 'm')) d_mailer = s_defaultMailer; bool useSyslog = setSyslog(); if (not d_arg.option(0, "verbose")) // verbose messages appear in the imsg.off(); // logs else if (useSyslog || not logName.empty()) imsg.reset(d_msg); else wmsg << "--verbose ignored: --syslog or --log not specified" << endl; } ssh-cron-1.05.00/options/usage.cc0000644000175000017500000000773314741230041015511 0ustar frankfrank// usage.cc #include "options.ih" void Options::usage(std::string const &progname) { cout << "\n" << progname << " by " << Icmbuild::author << "\n" << progname << " V" << Icmbuild::version << " " << Icmbuild::years << "\n" "\n" "Usage: " << progname << " [options] [crontab]\n" "Where:\n" " [options] - optional arguments (short options between parentheses,\n" " option descriptions starting with (C) can only be used\n" " on the command-line and are ignored when specified in " "the\n" " configuration file (see also option --config):\n" " --agent agent - absolute path to the agent program providing\n" " the ssh-keys\n" " (default `" << s_defaultAgent << "')\n" " --config (-c) path - (C) config file containing long option " "specifications\n" " (default `$HOME/" << s_defaultConfigFile << ")`\n" " --forced (-f) - (C) When restarting " << progname << " an existing\n" " (leftover) ipc-file is removed\n" " --help (-h) - (C) provide this help\n" " --ipc-file (-i) path - `path' is the path name of the file\n" " containing the info used for IPC\n" " (default `$HOME/" << s_defaultIPCfile << "')\n" " --list (-l) - list the currently defined cron-commands\n" " (the `crontab' file is only used to specify " "options)\n" " --log (-L) path - log messages are appended to `path'. If " "path\n" " does not exist, it is created first\n" " --mailer (-m) command - `command' is the command mailing the\n" " output of executed commands (default\n" " `" << s_defaultMailer << "'\n" " --no-daemon - (C) do not run as a daemon\n" " --reload (-r) - (C) reload a running " << progname << " daemon\n" " with the specifications in the crontab-file\n" " --stdout (-s) - (C) logged messages are also written to " "stdout\n" " (only in combination with --no-daemon)\n" " --syslog - write syslog messages\n" " --syslog-facility fac - fac: syslog facility to use\n" " (default `" << s_defaultSyslogFacility << "')\n" " --syslog-priority pri - pri: syslog priority to use\n" " (default `" << s_defaultSyslogPriority << "')\n" " --syslog-tag id - id: identifier prefixed to syslog " "messages\n" " (default `" << s_defaultSyslogIdent << "')\n" " --terminate (-t) - (C) terminate a running " << progname << " program\n" " (the `crontab' file is only used to specify " "options)\n" " --verbose - logs additional information. Implies " "--syslog\n" " --version (-v) - (C) show version information and terminate\n" "\n" " crontab - crontab-like file specifying crontab commands and\n" " (optional) environment variable definitions\n" "\n"; } ssh-cron-1.05.00/options/setsyslog.cc0000644000175000017500000000050214324446663016444 0ustar frankfrank#include "options.ih" bool Options::setSyslog() { if (not d_arg.option(0, "syslog")) return false; d_syslog.reset( new SyslogStream( syslogTag(), syslogPriority(), syslogFacility() ) ); d_multiBuf.insert(*d_syslog); return true; } ssh-cron-1.05.00/options/checkaction.cc0000644000175000017500000000167314324446663016675 0ustar frankfrank#include "options.ih" void Options::checkAction() const { // only one of these options may be specified if (d_list + d_reload + d_terminate + d_foreground > 1) { fmsg << "incompatible options:"; if (d_list) fmsg << " --list"; if (d_reload) fmsg << " --reload"; if (d_terminate) fmsg << " --terminate"; if (d_foreground) fmsg << " --no-daemon"; fmsg << endl; } // if no argument then --list or --terminate are required if (d_arg.nArgs() == 0) { if (not (d_list || d_terminate)) fmsg << "crontab file required" << endl; } else if (d_list || d_terminate) // --list and --terminate cannot accept a crontab file fmsg << "crontab file incompatible with --list and --terminate" << endl; } ssh-cron-1.05.00/options/options.h0000644000175000017500000000667014324446663015761 0ustar frankfrank#ifndef INCLUDED_OPTIONS_ #define INCLUDED_OPTIONS_ #include #include #include #include #include #include #include "../ipcfunction/ipcfunction.h" namespace FBB { class SyslogStream; } class Options: public IPCFunction { FBB::ArgConfig &d_arg; std::unique_ptr d_syslog; FBB::Log d_log; FBB::MultiBuf d_multiBuf; std::ostream d_msg; // d_msg handles all messages to // syslog and/or d_log std::string d_agent; std::string d_IPCfile; std::string d_mailer; FBB::LinearMap::const_iterator d_syslogFacility; FBB::LinearMap::const_iterator d_syslogPriority; bool d_foreground; bool d_list; bool d_reload; bool d_terminate; bool d_forced; Function d_ipcFunction = NONE; static Options *s_options; static FBB::Facility s_defaultSyslogFacility; static FBB::Priority s_defaultSyslogPriority; static char const s_defaultAgent[]; static char const s_defaultConfigFile[]; static char const s_defaultIPCfile[]; static char const s_defaultSyslogIdent[]; static char const s_defaultMailer[]; static FBB::LinearMap const s_syslogFacilities; static FBB::LinearMap const s_syslogPriorities; public: static Options &instance(); Options(Options const &other) = delete; bool foreground() const; bool daemon() const; bool ipc() const; bool cronfile() const; bool reload() const; bool forced() const; Function ipcFunction() const; std::string const &agent() const; std::string const &basename() const; std::string const &ipcFile() const; std::string const &mailer() const; std::ostream &msg(); static void usage(std::string const &progname); private: Options(); bool setSyslog(); void checkAction() const; void loadConfigFile(); std::string syslogTag() const; FBB::Priority syslogPriority() const; FBB::Facility syslogFacility() const; }; inline std::ostream &Options::msg() { return d_msg; } inline bool Options::foreground() const { return d_foreground; } inline bool Options::daemon() const { return not d_foreground; } inline bool Options::forced() const { return d_forced; } inline bool Options::reload() const { return d_reload; } inline bool Options::ipc() const { return d_list || d_terminate || d_reload; } inline bool Options::cronfile() const { return d_arg.nArgs(); } inline IPCFunction::Function Options::ipcFunction() const { return d_ipcFunction; } inline std::string const &Options::agent() const { return d_agent; } inline std::string const &Options::basename() const { return d_arg.basename(); } inline std::string const &Options::ipcFile() const { return d_IPCfile; } inline std::string const &Options::mailer() const { return d_mailer; } #endif ssh-cron-1.05.00/options/options.ih0000644000175000017500000000037014740774735016127 0ustar frankfrank#include "options.h" #include #include #include #include #include #include "../version/version.h" void usage(std::string const &progname); using namespace std; using namespace FBB; ssh-cron-1.05.00/options/syslogpriority.cc0000644000175000017500000000103614324446663017535 0ustar frankfrank#include "options.ih" Priority Options::syslogPriority() const { Priority priority; string option; if (not d_arg.option(&option, "syslog-priority")) priority = s_defaultSyslogPriority; else { LinearMap::const_iterator iter = s_syslogPriorities.find(option); if (iter == s_syslogPriorities.end()) fmsg << "syslog priority " << option << " not supported" << endl; priority = iter->second; } return priority; } ssh-cron-1.05.00/options/frame0000644000175000017500000000004514324446663015120 0ustar frankfrank#include "options.ih" Options:: { } ssh-cron-1.05.00/options/syslogtag.cc0000644000175000017500000000025714324446663016433 0ustar frankfrank#include "options.ih" string Options::syslogTag() const { string tag; if (not d_arg.option(&tag, "syslog-tag")) tag = s_defaultSyslogIdent; return tag; } ssh-cron-1.05.00/parser/0000755000175000017500000000000014333652630013676 5ustar frankfrankssh-cron-1.05.00/parser/parser.h0000644000175000017500000000205414324446663015353 0ustar frankfrank// Generated by Bisonc++ V6.04.01 on Fri, 13 Nov 2020 13:03:52 +0100 #ifndef Parser_h_included #define Parser_h_included // $insert baseclass #include "parserbase.h" // $insert scanner.h #include "../scanner/scanner.h" class CronData; class Parser: public ParserBase { CronData &d_cronData; // $insert scannerobject Scanner d_scanner; public: Parser(std::istream &in, CronData &cronData); int parse(); private: void addSet(std::set &lhs, std::set const &rhs) const; void error(); // called on (syntax) errors int lex(); // returns the next token from the // lexical scanner. void print(); // use, e.g., d_token, d_loc void exceptionHandler(std::exception const &exc); // support functions for parse(): void executeAction_(int ruleNr); void errorRecovery_(); void nextCycle_(); void nextToken_(); void print_(); }; #endif ssh-cron-1.05.00/parser/parser1.cc0000644000175000017500000000016714324446663015575 0ustar frankfrank#include "parser.ih" Parser::Parser(istream &in, CronData &cronData) : d_cronData(cronData), d_scanner(in) {} ssh-cron-1.05.00/parser/error.cc0000644000175000017500000000020114324446663015336 0ustar frankfrank#include "parser.ih" void Parser::error() { emsg << "Syntax error at line " << d_cronData.lineNr() << endl; } ssh-cron-1.05.00/parser/parse.cc0000644000175000017500000010612214324446663015330 0ustar frankfrank// Generated by Bisonc++ V6.04.01 on Sat, 14 Nov 2020 10:06:30 +0100 // base/comment // $insert class.ih #include "parser.ih" // The FIRST element of SR arrays shown below uses `d_type', defining the // state's type, and `d_lastIdx' containing the last element's index. If // d_lastIdx contains the REQ_TOKEN bitflag (see below) then the state needs // a token: if in this state d_token is Reserved_::UNDETERMINED_, nextToken() will be // called // The LAST element of SR arrays uses `d_token' containing the last retrieved // token to speed up the (linear) seach. Except for the first element of SR // arrays, the field `d_action' is used to determine what to do next. If // positive, it represents the next state (used with SHIFT); if zero, it // indicates `ACCEPT', if negative, -d_action represents the number of the // rule to reduce to. // `lookup()' tries to find d_token in the current SR array. If it fails, and // there is no default reduction UNEXPECTED_TOKEN_ is thrown, which is then // caught by the error-recovery function. // The error-recovery function will pop elements off the stack until a state // having bit flag ERR_ITEM is found. This state has a transition on errTok_ // which is applied. In this errTok_ state, while the current token is not a // proper continuation, new tokens are obtained by nextToken(). If such a // token is found, error recovery is successful and the token is // handled according to the error state's SR table and parsing continues. // During error recovery semantic actions are ignored. // A state flagged with the DEF_RED flag will perform a default // reduction if no other continuations are available for the current token. // The ACCEPT STATE never shows a default reduction: when it is reached the // parser returns ACCEPT(). During the grammar // analysis phase a default reduction may have been defined, but it is // removed during the state-definition phase. // So: // s_x[] = // { // [_field_1_] [_field_2_] // // First element: {state-type, idx of last element}, // Other elements: {required token, action to perform}, // ( < 0: reduce, // 0: ACCEPT, // > 0: next state) // } // base/declarations namespace // anonymous { char const author[] = "Frank B. Brokken (f.b.brokken@rug.nl)"; enum Reserved_ { UNDETERMINED_ = -2, EOF_ = -1, errTok_ = 256 }; enum StateType // modify statetype/data.cc when this enum changes { NORMAL, ERR_ITEM, REQ_TOKEN, ERR_REQ, // ERR_ITEM | REQ_TOKEN DEF_RED, // state having default reduction ERR_DEF, // ERR_ITEM | DEF_RED REQ_DEF, // REQ_TOKEN | DEF_RED ERR_REQ_DEF // ERR_ITEM | REQ_TOKEN | DEF_RED }; inline bool operator&(StateType lhs, StateType rhs) { return (static_cast(lhs) & rhs) != 0; } enum StateTransition { ACCEPT_ = 0, // `ACCEPT' TRANSITION }; struct PI_ // Production Info { size_t d_nonTerm; // identification number of this production's // non-terminal size_t d_size; // number of elements in this production }; struct SR_ // Shift Reduce info, see its description above { union { int _field_1_; // initializer, allowing initializations // of the SR s_[] arrays StateType d_type; int d_token; }; union { int _field_2_; int d_lastIdx; // if negative, the state uses SHIFT int d_action; // may be negative (reduce), // postive (shift), or 0 (accept) }; }; // $insert staticdata enum // size to expand the state-stack with when { // full STACK_EXPANSION_ = 10 }; // Productions Info Records: PI_ const s_productionInfo[] = { {0, 0}, // not used: reduction values are negative {270, 2}, // 1: startrule -> startrule line {270, 0}, // 2: startrule -> {272, 1}, // 3: nr (NR) -> NR {273, 0}, // 4: opt_nr_step -> {273, 2}, // 5: opt_nr_step ('/') -> '/' nr {274, 1}, // 6: nr_add -> nr {275, 4}, // 7: nr_range ('-') -> nr '-' nr opt_nr_step {275, 1}, // 8: nr_range -> nr_add {276, 3}, // 9: nr_Sequence (',') -> nr_Sequence ',' nr_range {276, 1}, // 10: nr_Sequence -> nr_range {277, 1}, // 11: opt_ws (WS) -> WS {277, 0}, // 12: opt_ws -> {278, 1}, // 13: _tokenNoWs (NR) -> NR {278, 1}, // 14: _tokenNoWs (ID) -> ID {278, 1}, // 15: _tokenNoWs ('*') -> '*' {278, 1}, // 16: _tokenNoWs ('/') -> '/' {278, 1}, // 17: _tokenNoWs (',') -> ',' {278, 1}, // 18: _tokenNoWs ('-') -> '-' {278, 1}, // 19: _tokenNoWs (CHAR) -> CHAR {278, 1}, // 20: _tokenNoWs ('=') -> '=' {279, 1}, // 21: _tokenAny (WS) -> WS {279, 1}, // 22: _tokenAny -> _tokenNoWs {280, 0}, // 23: _tokenMatched -> {281, 2}, // 24: _tokenAnyMatched -> _tokenAny _tokenMatched {282, 2}, // 25: token_noWs -> _tokenNoWs _tokenMatched {283, 2}, // 26: tokens -> tokens _tokenAny {283, 1}, // 27: tokens -> _tokenAnyMatched {284, 1}, // 28: opt_tokens -> tokens {284, 0}, // 29: opt_tokens -> {285, 3}, // 30: _nameContents ('=') -> opt_ws '=' opt_tokens {286, 1}, // 31: _nameID (ID) -> ID {287, 2}, // 32: nameLine -> _nameID _nameContents {288, 2}, // 33: _all ('*') -> '*' opt_nr_step {289, 1}, // 34: _timeUnit -> nr_range {289, 1}, // 35: _timeUnit (ID) -> ID {290, 3}, // 36: _timeSequence (',') -> _timeSequence ',' _timeUnit {290, 1}, // 37: _timeSequence -> _timeUnit {291, 1}, // 38: time_numberedSpec -> _all {291, 1}, // 39: time_numberedSpec -> nr_Sequence {292, 1}, // 40: time_spec -> _all {292, 1}, // 41: time_spec -> _timeSequence {293, 2}, // 42: _minutes (WS) -> time_numberedSpec WS {294, 2}, // 43: _hours (WS) -> time_numberedSpec WS {295, 2}, // 44: _dayOfMonth (WS) -> time_numberedSpec WS {296, 2}, // 45: _monthOfYear (WS) -> time_spec WS {297, 2}, // 46: _dayOfWeek (WS) -> time_spec WS {298, 2}, // 47: _command -> token_noWs opt_tokens {299, 6}, // 48: cronLine -> _minutes _hours _dayOfMonth _monthOfYear _dayOfWeek _command {300, 1}, // 49: _line_contents -> nameLine {300, 1}, // 50: _line_contents -> cronLine {300, 1}, // 51: _line_contents (errTok_) -> errTok_ {301, 0}, // 52: _line_preamble -> {302, 2}, // 53: _opt_line_contents -> _line_preamble _line_contents {302, 0}, // 54: _opt_line_contents -> {271, 2}, // 55: line ('\x0a') -> _opt_line_contents '\x0a' {303, 1}, // 56: startrule_$ -> startrule }; // State info and SR_ transitions for each state. SR_ s_0[] = { { { DEF_RED}, { 2} }, { { 270}, { 1} }, // startrule { { 0}, { -2} }, }; SR_ s_1[] = { { { REQ_DEF}, { 6} }, { { 271}, { 2} }, // line { { 302}, { 3} }, // _opt_line_contents { { 301}, { 4} }, // _line_preamble { { EOF_}, { ACCEPT_} }, { { 10}, { -54} }, // '\x0a' { { 0}, { -52} }, }; SR_ s_2[] = { { { DEF_RED}, { 1} }, { { 0}, { -1} }, }; SR_ s_3[] = { { { REQ_TOKEN}, { 2} }, { { 10}, { 5} }, // '\x0a' { { 0}, { 0} }, }; SR_ s_4[] = { { { ERR_REQ}, { 16} }, { { 300}, { 6} }, // _line_contents { { 287}, { 7} }, // nameLine { { 299}, { 8} }, // cronLine { { errTok_}, { 9} }, // errTok_ { { 286}, { 10} }, // _nameID { { 293}, { 11} }, // _minutes { { 259}, { 12} }, // ID { { 291}, { 13} }, // time_numberedSpec { { 288}, { 14} }, // _all { { 276}, { 15} }, // nr_Sequence { { 42}, { 16} }, // '*' { { 275}, { 17} }, // nr_range { { 272}, { 18} }, // nr { { 274}, { 19} }, // nr_add { { 258}, { 20} }, // NR { { 0}, { 0} }, }; SR_ s_5[] = { { { DEF_RED}, { 1} }, { { 0}, { -55} }, }; SR_ s_6[] = { { { DEF_RED}, { 1} }, { { 0}, { -53} }, }; SR_ s_7[] = { { { DEF_RED}, { 1} }, { { 0}, { -49} }, }; SR_ s_8[] = { { { DEF_RED}, { 1} }, { { 0}, { -50} }, }; SR_ s_9[] = { { { DEF_RED}, { 1} }, { { 0}, { -51} }, }; SR_ s_10[] = { { { REQ_DEF}, { 4} }, { { 285}, { 21} }, // _nameContents { { 277}, { 22} }, // opt_ws { { 257}, { 23} }, // WS { { 0}, { -12} }, }; SR_ s_11[] = { { { REQ_TOKEN}, { 10} }, { { 294}, { 24} }, // _hours { { 291}, { 25} }, // time_numberedSpec { { 288}, { 14} }, // _all { { 276}, { 15} }, // nr_Sequence { { 42}, { 16} }, // '*' { { 275}, { 17} }, // nr_range { { 272}, { 18} }, // nr { { 274}, { 19} }, // nr_add { { 258}, { 20} }, // NR { { 0}, { 0} }, }; SR_ s_12[] = { { { DEF_RED}, { 1} }, { { 0}, { -31} }, }; SR_ s_13[] = { { { REQ_TOKEN}, { 2} }, { { 257}, { 26} }, // WS { { 0}, { 0} }, }; SR_ s_14[] = { { { DEF_RED}, { 1} }, { { 0}, { -38} }, }; SR_ s_15[] = { { { REQ_DEF}, { 2} }, { { 44}, { 27} }, // ',' { { 0}, { -39} }, }; SR_ s_16[] = { { { REQ_DEF}, { 3} }, { { 273}, { 28} }, // opt_nr_step { { 47}, { 29} }, // '/' { { 0}, { -4} }, }; SR_ s_17[] = { { { DEF_RED}, { 1} }, { { 0}, { -10} }, }; SR_ s_18[] = { { { REQ_DEF}, { 2} }, { { 45}, { 30} }, // '-' { { 0}, { -6} }, }; SR_ s_19[] = { { { DEF_RED}, { 1} }, { { 0}, { -8} }, }; SR_ s_20[] = { { { DEF_RED}, { 1} }, { { 0}, { -3} }, }; SR_ s_21[] = { { { DEF_RED}, { 1} }, { { 0}, { -32} }, }; SR_ s_22[] = { { { REQ_TOKEN}, { 2} }, { { 61}, { 31} }, // '=' { { 0}, { 0} }, }; SR_ s_23[] = { { { DEF_RED}, { 1} }, { { 0}, { -11} }, }; SR_ s_24[] = { { { REQ_TOKEN}, { 10} }, { { 295}, { 32} }, // _dayOfMonth { { 291}, { 33} }, // time_numberedSpec { { 288}, { 14} }, // _all { { 276}, { 15} }, // nr_Sequence { { 42}, { 16} }, // '*' { { 275}, { 17} }, // nr_range { { 272}, { 18} }, // nr { { 274}, { 19} }, // nr_add { { 258}, { 20} }, // NR { { 0}, { 0} }, }; SR_ s_25[] = { { { REQ_TOKEN}, { 2} }, { { 257}, { 34} }, // WS { { 0}, { 0} }, }; SR_ s_26[] = { { { DEF_RED}, { 1} }, { { 0}, { -42} }, }; SR_ s_27[] = { { { REQ_TOKEN}, { 5} }, { { 275}, { 35} }, // nr_range { { 272}, { 18} }, // nr { { 274}, { 19} }, // nr_add { { 258}, { 20} }, // NR { { 0}, { 0} }, }; SR_ s_28[] = { { { DEF_RED}, { 1} }, { { 0}, { -33} }, }; SR_ s_29[] = { { { REQ_TOKEN}, { 3} }, { { 272}, { 36} }, // nr { { 258}, { 20} }, // NR { { 0}, { 0} }, }; SR_ s_30[] = { { { REQ_TOKEN}, { 3} }, { { 272}, { 37} }, // nr { { 258}, { 20} }, // NR { { 0}, { 0} }, }; SR_ s_31[] = { { { REQ_DEF}, { 15} }, { { 284}, { 38} }, // opt_tokens { { 283}, { 39} }, // tokens { { 281}, { 40} }, // _tokenAnyMatched { { 279}, { 41} }, // _tokenAny { { 257}, { 42} }, // WS { { 278}, { 43} }, // _tokenNoWs { { 258}, { 44} }, // NR { { 259}, { 45} }, // ID { { 42}, { 46} }, // '*' { { 47}, { 47} }, // '/' { { 44}, { 48} }, // ',' { { 45}, { 49} }, // '-' { { 260}, { 50} }, // CHAR { { 61}, { 51} }, // '=' { { 0}, { -29} }, }; SR_ s_32[] = { { { REQ_TOKEN}, { 12} }, { { 296}, { 52} }, // _monthOfYear { { 292}, { 53} }, // time_spec { { 288}, { 54} }, // _all { { 290}, { 55} }, // _timeSequence { { 42}, { 16} }, // '*' { { 289}, { 56} }, // _timeUnit { { 275}, { 57} }, // nr_range { { 259}, { 58} }, // ID { { 272}, { 18} }, // nr { { 274}, { 19} }, // nr_add { { 258}, { 20} }, // NR { { 0}, { 0} }, }; SR_ s_33[] = { { { REQ_TOKEN}, { 2} }, { { 257}, { 59} }, // WS { { 0}, { 0} }, }; SR_ s_34[] = { { { DEF_RED}, { 1} }, { { 0}, { -43} }, }; SR_ s_35[] = { { { DEF_RED}, { 1} }, { { 0}, { -9} }, }; SR_ s_36[] = { { { DEF_RED}, { 1} }, { { 0}, { -5} }, }; SR_ s_37[] = { { { REQ_DEF}, { 3} }, { { 273}, { 60} }, // opt_nr_step { { 47}, { 29} }, // '/' { { 0}, { -4} }, }; SR_ s_38[] = { { { DEF_RED}, { 1} }, { { 0}, { -30} }, }; SR_ s_39[] = { { { REQ_DEF}, { 12} }, { { 279}, { 61} }, // _tokenAny { { 257}, { 42} }, // WS { { 278}, { 43} }, // _tokenNoWs { { 258}, { 44} }, // NR { { 259}, { 45} }, // ID { { 42}, { 46} }, // '*' { { 47}, { 47} }, // '/' { { 44}, { 48} }, // ',' { { 45}, { 49} }, // '-' { { 260}, { 50} }, // CHAR { { 61}, { 51} }, // '=' { { 0}, { -28} }, }; SR_ s_40[] = { { { DEF_RED}, { 1} }, { { 0}, { -27} }, }; SR_ s_41[] = { { { DEF_RED}, { 2} }, { { 280}, { 62} }, // _tokenMatched { { 0}, { -23} }, }; SR_ s_42[] = { { { DEF_RED}, { 1} }, { { 0}, { -21} }, }; SR_ s_43[] = { { { DEF_RED}, { 1} }, { { 0}, { -22} }, }; SR_ s_44[] = { { { DEF_RED}, { 1} }, { { 0}, { -13} }, }; SR_ s_45[] = { { { DEF_RED}, { 1} }, { { 0}, { -14} }, }; SR_ s_46[] = { { { DEF_RED}, { 1} }, { { 0}, { -15} }, }; SR_ s_47[] = { { { DEF_RED}, { 1} }, { { 0}, { -16} }, }; SR_ s_48[] = { { { DEF_RED}, { 1} }, { { 0}, { -17} }, }; SR_ s_49[] = { { { DEF_RED}, { 1} }, { { 0}, { -18} }, }; SR_ s_50[] = { { { DEF_RED}, { 1} }, { { 0}, { -19} }, }; SR_ s_51[] = { { { DEF_RED}, { 1} }, { { 0}, { -20} }, }; SR_ s_52[] = { { { REQ_TOKEN}, { 12} }, { { 297}, { 63} }, // _dayOfWeek { { 292}, { 64} }, // time_spec { { 288}, { 54} }, // _all { { 290}, { 55} }, // _timeSequence { { 42}, { 16} }, // '*' { { 289}, { 56} }, // _timeUnit { { 275}, { 57} }, // nr_range { { 259}, { 58} }, // ID { { 272}, { 18} }, // nr { { 274}, { 19} }, // nr_add { { 258}, { 20} }, // NR { { 0}, { 0} }, }; SR_ s_53[] = { { { REQ_TOKEN}, { 2} }, { { 257}, { 65} }, // WS { { 0}, { 0} }, }; SR_ s_54[] = { { { DEF_RED}, { 1} }, { { 0}, { -40} }, }; SR_ s_55[] = { { { REQ_DEF}, { 2} }, { { 44}, { 66} }, // ',' { { 0}, { -41} }, }; SR_ s_56[] = { { { DEF_RED}, { 1} }, { { 0}, { -37} }, }; SR_ s_57[] = { { { DEF_RED}, { 1} }, { { 0}, { -34} }, }; SR_ s_58[] = { { { DEF_RED}, { 1} }, { { 0}, { -35} }, }; SR_ s_59[] = { { { DEF_RED}, { 1} }, { { 0}, { -44} }, }; SR_ s_60[] = { { { DEF_RED}, { 1} }, { { 0}, { -7} }, }; SR_ s_61[] = { { { DEF_RED}, { 1} }, { { 0}, { -26} }, }; SR_ s_62[] = { { { DEF_RED}, { 1} }, { { 0}, { -24} }, }; SR_ s_63[] = { { { REQ_TOKEN}, { 12} }, { { 298}, { 67} }, // _command { { 282}, { 68} }, // token_noWs { { 278}, { 69} }, // _tokenNoWs { { 258}, { 44} }, // NR { { 259}, { 45} }, // ID { { 42}, { 46} }, // '*' { { 47}, { 47} }, // '/' { { 44}, { 48} }, // ',' { { 45}, { 49} }, // '-' { { 260}, { 50} }, // CHAR { { 61}, { 51} }, // '=' { { 0}, { 0} }, }; SR_ s_64[] = { { { REQ_TOKEN}, { 2} }, { { 257}, { 70} }, // WS { { 0}, { 0} }, }; SR_ s_65[] = { { { DEF_RED}, { 1} }, { { 0}, { -45} }, }; SR_ s_66[] = { { { REQ_TOKEN}, { 7} }, { { 289}, { 71} }, // _timeUnit { { 275}, { 57} }, // nr_range { { 259}, { 58} }, // ID { { 272}, { 18} }, // nr { { 274}, { 19} }, // nr_add { { 258}, { 20} }, // NR { { 0}, { 0} }, }; SR_ s_67[] = { { { DEF_RED}, { 1} }, { { 0}, { -48} }, }; SR_ s_68[] = { { { REQ_DEF}, { 15} }, { { 284}, { 72} }, // opt_tokens { { 283}, { 39} }, // tokens { { 281}, { 40} }, // _tokenAnyMatched { { 279}, { 41} }, // _tokenAny { { 257}, { 42} }, // WS { { 278}, { 43} }, // _tokenNoWs { { 258}, { 44} }, // NR { { 259}, { 45} }, // ID { { 42}, { 46} }, // '*' { { 47}, { 47} }, // '/' { { 44}, { 48} }, // ',' { { 45}, { 49} }, // '-' { { 260}, { 50} }, // CHAR { { 61}, { 51} }, // '=' { { 0}, { -29} }, }; SR_ s_69[] = { { { DEF_RED}, { 2} }, { { 280}, { 73} }, // _tokenMatched { { 0}, { -23} }, }; SR_ s_70[] = { { { DEF_RED}, { 1} }, { { 0}, { -46} }, }; SR_ s_71[] = { { { DEF_RED}, { 1} }, { { 0}, { -36} }, }; SR_ s_72[] = { { { DEF_RED}, { 1} }, { { 0}, { -47} }, }; SR_ s_73[] = { { { DEF_RED}, { 1} }, { { 0}, { -25} }, }; // State array: SR_ *s_state[] = { s_0, s_1, s_2, s_3, s_4, s_5, s_6, s_7, s_8, s_9, s_10, s_11, s_12, s_13, s_14, s_15, s_16, s_17, s_18, s_19, s_20, s_21, s_22, s_23, s_24, s_25, s_26, s_27, s_28, s_29, s_30, s_31, s_32, s_33, s_34, s_35, s_36, s_37, s_38, s_39, s_40, s_41, s_42, s_43, s_44, s_45, s_46, s_47, s_48, s_49, s_50, s_51, s_52, s_53, s_54, s_55, s_56, s_57, s_58, s_59, s_60, s_61, s_62, s_63, s_64, s_65, s_66, s_67, s_68, s_69, s_70, s_71, s_72, s_73, }; } // anonymous namespace ends // $insert polymorphicCode namespace Meta_ { size_t const *t_nErrors; // $insert idoftag char const *idOfTag_[] = { "INT", "STRING", "" }; size_t const *s_nErrors_; Base::~Base() {} } // namespace Meta_ // If the parsing function call (i.e., parse()' needs arguments, then provide // an overloaded function. The code below doesn't rely on parameters, so no // arguments are required. Furthermore, parse uses a function try block to // allow us to do ACCEPT and ABORT from anywhere, even from within members // called by actions, simply throwing the appropriate exceptions. // base/base1 ParserBase::ParserBase() : d_token(Reserved_::UNDETERMINED_), // $insert baseclasscode d_requiredTokens_(0) { Meta_::t_nErrors = &d_nErrors_; } // base/clearin void ParserBase::clearin_() { d_nErrors_ = 0; d_stackIdx = -1; d_stateStack.clear(); d_token = Reserved_::UNDETERMINED_; d_next = TokenPair{ Reserved_::UNDETERMINED_, STYPE_{} }; d_recovery = false; d_acceptedTokens_ = d_requiredTokens_; d_val_ = STYPE_{}; push_(0); } // base/debugfunctions void ParserBase::setDebug(bool mode) { d_actionCases_ = false; d_debug_ = mode; } void ParserBase::setDebug(DebugMode_ mode) { d_actionCases_ = mode & ACTIONCASES; d_debug_ = mode & ON; } // base/lex void ParserBase::lex_(int token) { d_token = token; if (d_token <= 0) d_token = Reserved_::EOF_; d_terminalToken = true; } // base/lookup int ParserBase::lookup_() const { // if the final transition is negative, then we should reduce by the rule // given by its positive value. SR_ const *sr = s_state[d_state]; SR_ const *last = sr + sr->d_lastIdx; for ( ; ++sr != last; ) // visit all but the last SR entries { if (sr->d_token == d_token) return sr->d_action; } if (sr == last) // reached the last element { if (sr->d_action < 0) // default reduction { return sr->d_action; } // No default reduction, so token not found, so error. throw UNEXPECTED_TOKEN_; } // not at the last element: inspect the nature of the action // (< 0: reduce, 0: ACCEPT, > 0: shift) int action = sr->d_action; return action; } // base/pop void ParserBase::pop_(size_t count) { if (d_stackIdx < static_cast(count)) { ABORT(); } d_stackIdx -= count; d_state = d_stateStack[d_stackIdx].first; d_vsp = &d_stateStack[d_stackIdx]; } // base/poptoken void ParserBase::popToken_() { d_token = d_next.first; d_val_ = std::move(d_next.second); d_next.first = Reserved_::UNDETERMINED_; } // base/push void ParserBase::push_(size_t state) { size_t currentSize = d_stateStack.size(); if (stackSize_() == currentSize) { size_t newSize = currentSize + STACK_EXPANSION_; d_stateStack.resize(newSize); } ++d_stackIdx; d_stateStack[d_stackIdx] = StatePair{ d_state = state, std::move(d_val_) }; d_vsp = &d_stateStack[d_stackIdx]; if (d_stackIdx == 0) { } else { } } // base/pushtoken void ParserBase::pushToken_(int token) { d_next = TokenPair{ d_token, std::move(d_val_) }; d_token = token; } // base/redotoken void ParserBase::redoToken_() { if (d_token != Reserved_::UNDETERMINED_) pushToken_(d_token); } // base/reduce void ParserBase::reduce_(int rule) { PI_ const &pi = s_productionInfo[rule]; d_token = pi.d_nonTerm; pop_(pi.d_size); d_terminalToken = false; } // base/shift void ParserBase::shift_(int action) { push_(action); popToken_(); // token processed if (d_recovery and d_terminalToken) { d_recovery = false; d_acceptedTokens_ = 0; } } // base/startrecovery void ParserBase::startRecovery_() { int lastToken = d_token; // give the unexpected token a // chance to be processed // again. pushToken_(Reserved_::errTok_); // specify errTok_ as next token push_(lookup_()); // push the error state d_token = lastToken; // reactivate the unexpected // token (we're now in an // ERROR state). d_recovery = true; } // base/top inline size_t ParserBase::top_() const { return d_stateStack[d_stackIdx].first; } // derived/errorrecovery void Parser::errorRecovery_() { // When an error has occurred, pop elements off the stack until the top // state has an error-item. If none is found, the default recovery // mode (which is to abort) is activated. // // If EOF is encountered without being appropriate for the current state, // then the error recovery will fall back to the default recovery mode. // (i.e., parsing terminates) if (d_acceptedTokens_ >= d_requiredTokens_)// only generate an error- { // message if enough tokens ++d_nErrors_; // were accepted. Otherwise error(); // simply skip input } // get the error state while (not (s_state[top_()][0].d_type & ERR_ITEM)) { pop_(); } // In the error state, looking up a token allows us to proceed. // Continuation may be require multiple reductions, but eventually a // terminal-token shift is used. See nextCycle_ for details. startRecovery_(); } // derived/executeaction void Parser::executeAction_(int production) try { if (token_() != Reserved_::UNDETERMINED_) pushToken_(token_()); // save an already available token switch (production) { // $insert actioncases case 1: #line 19 "grammar" { d_val_ = std::move(vs_(-1)); } break; case 3: #line 3 "inc/nr" { d_val_ = stol(d_scanner.matched()); } break; case 4: #line 10 "inc/nr" { d_val_ = 1; } break; case 5: #line 15 "inc/nr" { d_val_ = vs_(0).get(); } break; case 6: #line 22 "inc/nr" { d_cronData.addNr(vs_(0).get()); } break; case 7: #line 30 "inc/nr" { d_cronData.addRange(vs_(-3).get(), vs_(-1).get(), vs_(0).get()); } break; case 8: #line 35 "inc/nr" { d_val_ = std::move(vs_(0)); } break; case 9: #line 39 "inc/nr" { d_val_ = std::move(vs_(-2)); } break; case 10: #line 41 "inc/nr" { d_val_ = std::move(vs_(0)); } break; case 11: #line 3 "inc/ws" { d_val_ = std::move(vs_(0)); } break; case 13: #line 3 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 14: #line 5 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 15: #line 7 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 16: #line 9 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 17: #line 11 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 18: #line 13 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 19: #line 15 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 20: #line 17 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 21: #line 21 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 22: #line 23 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 23: #line 26 "inc/token" { d_val_ = d_scanner.matched(); } break; case 24: #line 35 "inc/token" { d_val_ = vs_(0).get(); } break; case 25: #line 43 "inc/token" { d_val_ = vs_(0).get(); } break; case 26: #line 50 "inc/token" { d_val_ = vs_(-1).get() + d_scanner.matched(); } break; case 27: #line 55 "inc/token" { d_val_ = vs_(0).get(); } break; case 28: #line 62 "inc/token" { d_val_ = std::move(vs_(0)); } break; case 29: #line 63 "inc/token" { d_val_ = string{}; } break; case 30: #line 8 "inc/nameline" { d_val_ = vs_(0).get(); } break; case 31: #line 15 "inc/nameline" { d_val_ = d_scanner.matched(); } break; case 32: #line 22 "inc/nameline" { d_cronData.setEnvVar(vs_(-1).get(), vs_(0).get()); } break; case 33: #line 3 "inc/time" { d_cronData.setAll(vs_(0).get()); } break; case 34: #line 10 "inc/time" { d_val_ = std::move(vs_(0)); } break; case 35: #line 12 "inc/time" { d_cronData.addName(d_scanner.matched()); } break; case 36: #line 19 "inc/time" { d_val_ = std::move(vs_(-2)); } break; case 37: #line 21 "inc/time" { d_val_ = std::move(vs_(0)); } break; case 38: #line 27 "inc/time" { d_val_ = std::move(vs_(0)); } break; case 39: #line 29 "inc/time" { d_val_ = std::move(vs_(0)); } break; case 40: #line 34 "inc/time" { d_val_ = std::move(vs_(0)); } break; case 41: #line 36 "inc/time" { d_val_ = std::move(vs_(0)); } break; case 42: #line 4 "inc/cronline" { d_cronData.setMinutes(); } break; case 43: #line 12 "inc/cronline" { d_cronData.setHours(); } break; case 44: #line 20 "inc/cronline" { d_cronData.setDayOfMonth(); } break; case 45: #line 28 "inc/cronline" { d_cronData.setMonthOfYear(); } break; case 46: #line 36 "inc/cronline" { d_cronData.setDayOfWeek(); } break; case 47: #line 44 "inc/cronline" { d_cronData.setCommand(vs_(-1).get() + vs_(0).get()); } break; case 48: #line 51 "inc/cronline" { d_cronData.process(); } break; case 49: #line 3 "inc/line" { d_val_ = std::move(vs_(0)); } break; case 50: #line 5 "inc/line" { d_val_ = std::move(vs_(0)); } break; case 51: #line 7 "inc/line" { d_val_ = std::move(vs_(0)); } break; case 52: #line 10 "inc/line" { d_cronData.reset(d_scanner.lineNr()); } break; case 53: #line 17 "inc/line" { d_val_ = std::move(vs_(-1)); } break; case 55: #line 23 "inc/line" { d_val_ = std::move(vs_(-1)); } break; } } catch (std::exception const &exc) { exceptionHandler(exc); } // derived/nextcycle void Parser::nextCycle_() try { if (s_state[state_()]->d_type & REQ_TOKEN) nextToken_(); // obtain next token int action = lookup_(); // lookup d_token in d_state if (action > 0) // SHIFT: push a new state { shift_(action); return; } if (action < 0) // REDUCE: execute and pop. { if (recovery_()) redoToken_(); else executeAction_(-action); // next token is the rule's LHS reduce_(-action); return; } if (recovery_()) ABORT(); else ACCEPT(); } catch (ErrorRecovery_) { if (not recovery_()) errorRecovery_(); else { if (token_() == Reserved_::EOF_) ABORT(); popToken_(); // skip the failing token } } // derived/nexttoken void Parser::nextToken_() { // If d_token is Reserved_::UNDETERMINED_ then if savedToken_() is // Reserved_::UNDETERMINED_ another token is obtained from lex(). Then // savedToken_() is assigned to d_token. // no need for a token: got one already if (token_() != Reserved_::UNDETERMINED_) { return; } if (savedToken_() != Reserved_::UNDETERMINED_) { popToken_(); // consume pending token } else { ++d_acceptedTokens_; // accept another token (see // errorRecover()) lex_(lex()); print_(); } print(); } // derived/print void Parser::print_() { // $insert print } // derived/parse int Parser::parse() try { // The parsing algorithm: // Initially, state 0 is pushed on the stack, and all relevant variables // are initialized by Base::clearin_. // // Then, in an eternal loop: // // 1. If a state is a REQ_TOKEN type, then the next token is obtained // from nextToken(). This may very well be the currently available // token. When retrieving a terminal token d_terminal is set to true. // // 2. lookup() is called, d_token is looked up in the current state's // SR_ array. // // 4. Depending on the result of the lookup() function the next state is // shifted on the parser's stack, a reduction by some rule is applied, // or the parsing function returns ACCEPT(). When a reduction is // called for, any action that may have been defined for that // reduction is executed. // // 5. An error occurs if d_token is not found, and the state has no // default reduction. clearin_(); // initialize, push(0) while (true) { // $insert prompt nextCycle_(); } } catch (Return_ retValue) { return retValue or d_nErrors_; } // derived/tail ssh-cron-1.05.00/parser/addset.cc0000644000175000017500000000020014324446663015450 0ustar frankfrank#include "parser.ih" void Parser::addSet(set &lhs, set const &rhs) const { lhs.insert(rhs.begin(), rhs.end()); } ssh-cron-1.05.00/parser/parserpre.ih0000644000175000017500000000004314324446663016227 0ustar frankfrank#include #include ssh-cron-1.05.00/parser/parser.ih0000644000175000017500000000124614324446663015526 0ustar frankfrank// Generated by Bisonc++ V6.04.01 on Fri, 13 Nov 2020 13:03:52 +0100 // Include this file in the sources of the class Parser. // $insert class.h #include "parser.h" #include #include #include "../options/options.h" #include "../crondata/crondata.h" // $insert lex inline int Parser::lex() { return d_scanner.lex(); } inline void Parser::print() { print_(); // displays tokens if --print was specified } inline void Parser::exceptionHandler(std::exception const &exc) { throw; // re-implement to handle exceptions thrown by actions } using namespace std; using namespace FBB; ssh-cron-1.05.00/parser/icmconf0000644000175000017500000000007514324446663015250 0ustar frankfrank#define LIBRARY "parser" #include "../icmconf.lib" ssh-cron-1.05.00/parser/inc/0000755000175000017500000000000014324446663014456 5ustar frankfrankssh-cron-1.05.00/parser/inc/ws0000644000175000017500000000004114324446663015025 0ustar frankfrankopt_ws: WS | // empty ; ssh-cron-1.05.00/parser/inc/line0000644000175000017500000000052314324446663015330 0ustar frankfrank_line_contents: nameLine // either an option or an environment var | cronLine // time specification + action | error ; _line_preamble: { d_cronData.reset(d_scanner.lineNr()); } ; _opt_line_contents: _line_preamble _line_contents | // empty ; line: _opt_line_contents '\n' ; ssh-cron-1.05.00/parser/inc/cronline0000644000175000017500000000120714324446663016212 0ustar frankfrank_minutes: time_numberedSpec WS { d_cronData.setMinutes(); } ; _hours: time_numberedSpec WS { d_cronData.setHours(); } ; _dayOfMonth: time_numberedSpec WS { d_cronData.setDayOfMonth(); } ; _monthOfYear: time_spec WS { d_cronData.setMonthOfYear(); } ; _dayOfWeek: time_spec WS { d_cronData.setDayOfWeek(); } ; _command: token_noWs opt_tokens { d_cronData.setCommand($1 + $2); } ; cronLine: _minutes _hours _dayOfMonth _monthOfYear _dayOfWeek _command { d_cronData.process(); } ; ssh-cron-1.05.00/parser/inc/time0000644000175000017500000000071014324446663015335 0ustar frankfrank_all: '*' opt_nr_step // empty set indicates `all valid specifications { d_cronData.setAll($2); } ; _timeUnit: nr_range | ID { d_cronData.addName(d_scanner.matched()); } ; _timeSequence: _timeSequence ',' _timeUnit | _timeUnit ; //------------------------------------------------------------------ time_numberedSpec: _all | nr_Sequence ; time_spec: _all | _timeSequence ; ssh-cron-1.05.00/parser/inc/nr0000644000175000017500000000061014324446663015015 0ustar frankfranknr: NR { $$ = stol(d_scanner.matched()); } ; opt_nr_step: // empty { $$ = 1; } | '/' nr { $$ = $2; } ; nr_add: nr { d_cronData.addNr($1); } ; nr_range: nr '-' nr opt_nr_step { d_cronData.addRange($1, $3, $4); } | nr_add ; nr_Sequence: nr_Sequence ',' nr_range | nr_range ; ssh-cron-1.05.00/parser/inc/nameline0000644000175000017500000000055714324446663016200 0ustar frankfrank// OK input is: // // ID = whatever // the blanks around the = are optional and will be removed _nameContents: opt_ws '=' opt_tokens // ID =(contents-to-be-stripped)? { $$ = $3; } ; _nameID: ID { $$ = d_scanner.matched(); } ; nameLine: _nameID _nameContents { d_cronData.setEnvVar($1, $2); } ; ssh-cron-1.05.00/parser/inc/token0000644000175000017500000000104714324446663015523 0ustar frankfrank_tokenNoWs: NR | ID | '*' | '/' | ',' | '-' | CHAR | '=' ; _tokenAny: WS | _tokenNoWs ; _tokenMatched: { $$ = d_scanner.matched(); } ; _tokenAnyMatched: _tokenAny _tokenMatched { $$ = $2; } ; token_noWs: _tokenNoWs _tokenMatched { $$ = $2; } ; tokens: tokens _tokenAny { $$ = $1 + d_scanner.matched(); } | _tokenAnyMatched { $$ = $1; } ; opt_tokens: tokens | { $$ = string{}; } ; ssh-cron-1.05.00/parser/grammar0000644000175000017500000000100414324446663015251 0ustar frankfrank%filenames parser %scanner ../scanner/scanner.h %token-path ../scanner/tokens.h %baseclass-preinclude parserpre.ih %polymorphic STRING: std::string; INT: int %token WS NR ID CHAR %type opt_tokens tokens token_noWs _tokenAnyMatched _tokenMatched _nameContents _nameID %type nr opt_nr_step %% startrule: startrule line | // empty ; %include inc/nr %include inc/ws %include inc/token %include inc/nameline %include inc/time %include inc/cronline %include inc/line ssh-cron-1.05.00/parser/frame0000644000175000017500000000004314324446663014717 0ustar frankfrank#include "parser.ih" Parser:: { } ssh-cron-1.05.00/parser/parserbase.h0000644000175000017500000002467614324446663016224 0ustar frankfrank// Generated by Bisonc++ V6.04.01 on Sat, 14 Nov 2020 10:06:30 +0100 // hdr/includes #ifndef ParserBase_h_included #define ParserBase_h_included #include #include #include // $insert polyincludes #include // $insert preincludes #include "parserpre.ih" #include "../scanner/tokens.h" // hdr/baseclass namespace // anonymous { struct PI_; } // $insert polymorphic enum class Tag_ { INT, STRING, }; namespace Meta_ { extern size_t const *t_nErrors; extern size_t const *s_nErrors_; template struct TypeOf; template struct TagOf; // $insert polymorphicSpecializations enum { sizeofTag_ = 2 }; extern char const *idOfTag_[]; template <> struct TagOf { static Tag_ const tag = Tag_::INT; }; template <> struct TagOf { static Tag_ const tag = Tag_::STRING; }; template <> struct TypeOf { typedef int type; }; template <> struct TypeOf { typedef std::string type; }; // Individual semantic value classes are derived from Base, offering a // member returning the value's Tag_, a member cloning the object of its // derived Semantic and a member returning a pointerr to its // derived Semantic data. See also Bisonc++'s distribution file // README.polymorphic-techical class Base { protected: Tag_ d_baseTag; // d_baseTag is assigned by Semantic. public: Base() = default; Base(Base const &other) = delete; virtual ~Base(); Tag_ tag() const; Base *clone() const; void *data() const; private: virtual Base *vClone() const = 0; virtual void *vData() const = 0; }; inline Base *Base::clone() const { return vClone(); } inline void *Base::data() const { return vData(); } inline Tag_ Base::tag() const { return d_baseTag; } // The class Semantic stores a semantic value of the type matching tg_ template class Semantic: public Base { typename TypeOf::type d_data; public: Semantic(); Semantic(Semantic const &other); // req'd for cloning // This constructor member template forwards its arguments to // d_data, allowing it to be initialized using whatever // constructor is available for DataType template Semantic(Params &&...params); private: Base *vClone() const override; void *vData() const override; }; template Semantic::Semantic() { d_baseTag = tg_; // Base's data member: } template Semantic::Semantic(Semantic const &other) : d_data(other.d_data) { d_baseTag = other.d_baseTag; } template template Semantic::Semantic(Params &&...params) : d_data(std::forward(params) ...) { d_baseTag = tg_; } template Base *Semantic::vClone() const { return new Semantic{*this}; } template void *Semantic::vData() const { return const_cast::type *>(&d_data); } // The class SType wraps a pointer to Base. It becomes the polymorphic // STYPE_ type. It also defines get members, allowing constructions like // $$.get to be used. class SType: private std::unique_ptr { typedef std::unique_ptr BasePtr; public: SType() = default; SType(SType const &other); SType(SType &&tmp); ~SType() = default; // Specific overloads are needed for SType = SType assignments SType &operator=(SType const &rhs); SType &operator=(SType &rhs); // required so it is used // instead of the template op= SType &operator=(SType &&tmp); // $insert polymorphicOpAssignDecl SType &operator=(int const &value); SType &operator=(int &&tmp); SType &operator=(std::string const &value); SType &operator=(std::string &&tmp); template void assign(Args &&...args); // By default the get()-members check whether the specified // matches the tag returned by SType::tag (d_data's tag). If they // don't match a run-time fatal error results. template typename TypeOf::type &get(); template typename TypeOf::type const &get() const; Tag_ tag() const; bool valid() const; }; inline SType::SType(SType const &other) : BasePtr{other ? other->clone() : 0} {} inline SType::SType(SType &&tmp) : BasePtr{std::move(tmp)} {} inline SType &SType::operator=(SType const &rhs) { reset(rhs->clone()); return *this; } inline SType &SType::operator=(SType &rhs) { reset(rhs->clone()); return *this; } inline SType &SType::operator=(SType &&tmp) { BasePtr::operator=(std::move(tmp)); return *this; } // $insert polymorphicOpAssignImpl inline SType &SType::operator=(int const &value) { assign< Tag_::INT >(value); return *this; } inline SType &SType::operator=(int &&tmp) { assign< Tag_::INT >(std::move(tmp)); return *this; } inline SType &SType::operator=(std::string const &value) { assign< Tag_::STRING >(value); return *this; } inline SType &SType::operator=(std::string &&tmp) { assign< Tag_::STRING >(std::move(tmp)); return *this; } template void SType::assign(Args &&...args) { reset(new Semantic(std::forward(args) ...)); } template typename TypeOf::type &SType::get() { // $insert warnTagMismatches if (tag() != tg) { if (*t_nErrors != 0) const_cast(this)->assign(); else { std::cerr << "[Fatal] calling `.get(tg)] << ">()', but Tag " << idOfTag_[static_cast(tag())] << " is encountered. Try " "option --debug and call setDebug(Parser::ACTIONCASES)\n"; throw 1; // ABORTs } } return *static_cast::type *>( (*this)->data() ); } template typename TypeOf::type const &SType::get() const { // $insert warnTagMismatches if (tag() != tg) { if (*t_nErrors != 0) const_cast(this)->assign(); else { std::cerr << "[Fatal] calling `.get(tg)] << ">()', but Tag " << idOfTag_[static_cast(tag())] << " is encountered. Try " "option --debug and call setDebug(Parser::ACTIONCASES)\n"; throw 1; // ABORTs } } return *static_cast::type *>( (*this)->data() ); } inline Tag_ SType::tag() const { return valid() ? (*this)->tag() : static_cast(sizeofTag_); } inline bool SType::valid() const { return BasePtr::get() != 0; } } // namespace Meta_ // $insert parserbase class ParserBase: public Tokens { public: enum DebugMode_ { OFF = 0, ON = 1 << 0, ACTIONCASES = 1 << 1 }; // $insert tokens // $insert STYPE typedef Meta_::SType STYPE_; private: // state semval typedef std::pair StatePair; // token semval typedef std::pair TokenPair; int d_stackIdx = -1; std::vector d_stateStack; StatePair *d_vsp = 0; // points to the topmost value stack size_t d_state = 0; TokenPair d_next; int d_token; bool d_terminalToken = false; bool d_recovery = false; protected: enum Return_ { PARSE_ACCEPT_ = 0, // values used as parse()'s return values PARSE_ABORT_ = 1 }; enum ErrorRecovery_ { UNEXPECTED_TOKEN_, }; bool d_actionCases_ = false; // set by options/directives bool d_debug_ = true; size_t d_requiredTokens_; size_t d_nErrors_; // initialized by clearin() size_t d_acceptedTokens_; STYPE_ d_val_; ParserBase(); void ABORT() const; void ACCEPT() const; void ERROR() const; STYPE_ &vs_(int idx); // value stack element idx int lookup_() const; int savedToken_() const; int token_() const; size_t stackSize_() const; size_t state_() const; size_t top_() const; void clearin_(); void errorVerbose_(); void lex_(int token); void popToken_(); void pop_(size_t count = 1); void pushToken_(int token); void push_(size_t nextState); void redoToken_(); bool recovery_() const; void reduce_(int rule); void shift_(int state); void startRecovery_(); public: void setDebug(bool mode); void setDebug(DebugMode_ mode); }; // hdr/abort inline void ParserBase::ABORT() const { throw PARSE_ABORT_; } // hdr/accept inline void ParserBase::ACCEPT() const { throw PARSE_ACCEPT_; } // hdr/error inline void ParserBase::ERROR() const { throw UNEXPECTED_TOKEN_; } // hdr/savedtoken inline int ParserBase::savedToken_() const { return d_next.first; } // hdr/opbitand inline ParserBase::DebugMode_ operator&(ParserBase::DebugMode_ lhs, ParserBase::DebugMode_ rhs) { return static_cast( static_cast(lhs) & rhs); } // hdr/opbitor inline ParserBase::DebugMode_ operator|(ParserBase::DebugMode_ lhs, ParserBase::DebugMode_ rhs) { return static_cast(static_cast(lhs) | rhs); }; // hdr/recovery inline bool ParserBase::recovery_() const { return d_recovery; } // hdr/stacksize inline size_t ParserBase::stackSize_() const { return d_stackIdx + 1; } // hdr/state inline size_t ParserBase::state_() const { return d_state; } // hdr/token inline int ParserBase::token_() const { return d_token; } // hdr/vs inline ParserBase::STYPE_ &ParserBase::vs_(int idx) { return (d_vsp + idx)->second; } #endif ssh-cron-1.05.00/README0000644000175000017500000000272314324446662013274 0ustar frankfrankWelcome to SSH-CRON. Ssh-cron is now in its beta stage. I wrote ssh-cron after a discussion with Jean-Paul van Oosten about the dangers of using ssh keys without passphrases. But when using ssh keys with passphrases your cron jobs performing tasks at remote computers, suddenly can't be used anymore, since cron cannot provide the passphrases. It's also not possible to simply start ssh-agent and then crontab as a child process, as crontab loses access to ssh-agent's passphrases. Ssh-cron was subsequently designed to allow jobs requiring access to ssh-keys to be run regularly. In other words, ssh-cron combines crontab facilities with the use of ssh keys protected by passphrases. More information about ssh-cron and how to use its options and crontab-like specification file is found in ssh-cron's man-page. To compile ssh-cron from scratch you need a fairly recent Gnu g++ compiler (e.g. version 4.9.1 or more recent) and you need the Bobcat library (available at SourceForge and also as, e.g. Debian package). Compilation involves compiling all .cc files in this and all subdirectories, and then linking these components together. However, program construction is simplified if you also install icmake (also available at Sourceforge and as Debian package). If you have icmake available, check the defines in INSTALL.im for appropriateness for your system. Adapt them if necessary and simply run './build program' from this directory. Frank B. Brokken (f.b.brokken@rug.nl) ssh-cron-1.05.00/README.protocol0000644000175000017500000000431314324446662015131 0ustar frankfrankWhen using the daemon, the following protocol is used to communicate with the daemon: The ipc file contains the process ID of the daemon and the ID of its shared memory. The daemon started a service thread, calling the SharedCondition wait() function and waiting for things to happen. To request an action from the child, a process puts a request value (enum value) in the shared memory's assigned location, and notifies the daemon. This may be all that's needed, or the daemon has to respond. The organization of the shared memory is as follows: SharedCondition | request-field | free-area... The following requests and actions are defined: Request: Action: TERMINATE the daemon terminates, no further action LIST the requesting process starts a transmission loop, the child writes info about the current cron-actions until changing the request field into DONE LOAD the daemon starts a transmission loop and the requesting process writes info about the new set of cron-actions until changing the request field into DONE DONE communication loop completed A communication loop looks like this: --------------------------------------------------------------------- Initiating process Handling process --------------------------------------------------------------------- loop: lock loop: wait lock write request write free area, if neeeded notify release maybe end the loop (at, e.g., TERMINATE) lock wait_for(seconds(2)) process request maybe end the loop (at, e.g., TERMINATE) notify release error if timeout back to loop back to loop --------------------------------------------------------------------- ssh-cron-1.05.00/required0000644000175000017500000000071414324446663014156 0ustar frankfrankThis file lists non-standard software only. Thus, standard utilities like cp, mv, sed, etc, etc, are not explicitly mentioned. Neither is the g++ compiler explicitly mentioned, but a fairly recent one is assumed. Required software for building Ssh-cron 1.00.00 ----------------------------------------------- libbobcat-dev (>= 4.01.00), To use the provided build-script: icmake (>= 8.00.04) To construct the man-page: yodl (>= 3.06.0) ssh-cron-1.05.00/scanner/0000755000175000017500000000000014741230065014030 5ustar frankfrankssh-cron-1.05.00/scanner/lex.cc0000644000175000017500000003452314324446663015150 0ustar frankfrank// Generated by Flexc++ V2.08.01 on Sat, 14 Nov 2020 10:05:45 +0100 #include #include #include #include //FBB #include // $insert class_ih #include "scanner.ih" // s_ranges_: use (unsigned) characters as index to obtain // that character's range-number. // The range for EOF is defined in a constant in the // class header file size_t const ScannerBase::s_ranges_[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 5, 6, 7, 7, 7, 7, 7, 7, 8, 9,10,11,12,13,14,14, 14,14,14,14,14,14,14,14,15,15,15,16,17,17,17,18,18,18,18,18,18,18,18,18,18, 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,19,19,19,19,20,21,22,22,22, 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23, 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, 23,23,23,23,23,23, }; // $insert startcondinfo // s_dfa_ contains the rows of *all* DFAs ordered by start state. The // enum class StartCondition_is defined in the baseclass header. // StartCondition_::INITIAL is always 0. Each entry defines the row to // transit to if the column's character range was sensed. Row numbers are // relative to the used DFA, and d_dfaBase_ is set to the first row of // the subset to use. The row's final two values are respectively the // rule that may be matched at this state, and the rule's FINAL flag. If // the final value equals FINAL (= 1) then, if there's no continuation, // the rule is matched. If the BOL flag (8) is also set (so FINAL + BOL (= // 9) is set) then the rule only matches when d_atBOL is also true. int const ScannerBase::s_dfa_[][27] = { // INITIAL { 1, 2, 3, 1, 2, 1, 4, 1, 3, 1, 3, 3, 1, 3, 5, 1, 3, 1, 6, 1, 6, 1, 6, 1,-1, -1, 0}, // 0 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 5, -1}, // 1 {-1, 2,-1,-1, 2,-1, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 1, 0}, // 2 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 4, -1}, // 3 { 7, 7,-1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,-1, 5, 0}, // 4 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 5,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 2, -1}, // 5 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 6,-1,-1, 6,-1,-1,-1, 6,-1, 6,-1, 6,-1,-1, 3, -1}, // 6 { 7, 7,-1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,-1, -1, 0}, // 7 }; int const (*ScannerBase::s_dfaBase_[])[27] = { s_dfa_ + 0, }; size_t ScannerBase::s_istreamNr = 0; // $insert inputImplementation ScannerBase::Input::Input() : d_in(0), d_lineNr(1) {} ScannerBase::Input::Input(std::istream *iStream, size_t lineNr) : d_in(iStream), d_lineNr(lineNr) {} size_t ScannerBase::Input::get() { switch (size_t ch = next()) // get the next input char { case '\n': ++d_lineNr; [[fallthrough]]; default: return ch; } } size_t ScannerBase::Input::next() { size_t ch; if (d_deque.empty()) // deque empty: next char fm d_in { if (d_in == 0) return AT_EOF; ch = d_in->get(); return *d_in ? ch : static_cast(AT_EOF); } ch = d_deque.front(); d_deque.pop_front(); return ch; } void ScannerBase::Input::reRead(size_t ch) { if (ch < 0x100) { if (ch == '\n') --d_lineNr; d_deque.push_front(ch); } } void ScannerBase::Input::reRead(std::string const &str, size_t fm) { for (size_t idx = str.size(); idx-- > fm; ) reRead(str[idx]); } ScannerBase::ScannerBase(std::istream &in, std::ostream &out) : d_out(new std::ostream(out.rdbuf())), // $insert interactiveInit d_in(0), d_dfaBase_(s_dfa_) { p_pushStream("(istream)", new std::istream(in.rdbuf())); } void ScannerBase::switchStream_(std::istream &in, size_t lineNr) { d_input->close(); d_streamStack.back().input = { new std::istream(in.rdbuf()), lineNr }; } ScannerBase::ScannerBase(std::string const &infilename, std::string const &outfilename) : d_out(outfilename == "-" ? new std::ostream(std::cout.rdbuf()) : outfilename == "" ? new std::ostream(std::cerr.rdbuf()) : new std::ofstream(outfilename)), d_dfaBase_(s_dfa_) { p_pushStream(infilename, { new std::ifstream(infilename) }); } void ScannerBase::switchStreams(std::istream &in, std::ostream &out) { switchStream_(in, 1); switchOstream(out); } void ScannerBase::switchIstream(std::string const &infilename) { d_input->close(); d_filename = infilename; d_streamStack.back().input = new std::ifstream(infilename); d_atBOL = true; } void ScannerBase::switchStreams(std::string const &infilename, std::string const &outfilename) { switchOstream(outfilename); switchIstream(infilename); } void ScannerBase::pushStream(std::istream &istr) { p_pushStream("(istream)", new std::istream(istr.rdbuf())); //streamPtr); } void ScannerBase::pushStream(std::string const &name) { std::istream *streamPtr = new std::ifstream(name); if (!*streamPtr) { delete streamPtr; throw std::runtime_error("Cannot read " + name); } p_pushStream(name, streamPtr); } // static std::string ScannerBase::setCwd(std::string const &name) // any name { using namespace std; using namespace filesystem; error_code ec; if (not exists(name, ec)) // not a filename return name; // a filename: get its auto path = canonical(name); // full pathname current_path(path.parent_path(), ec); return path.string(); // return the pathname } void ScannerBase::p_pushStream(std::string const &name, std::istream *streamPtr) { if (d_streamStack.size() == s_maxSizeofStreamStack_) { delete streamPtr; throw std::length_error("Max stream stack size exceeded"); } d_filename = name; d_streamStack.push_back(StreamStruct{setCwd(d_filename), { streamPtr } }); d_input = &d_streamStack.back().input; d_atBOL = true; } void ScannerBase::switchOstream(std::ostream &out) { *d_out << std::flush; d_out.reset(new std::ostream(out.rdbuf())); } // $insert debugFunctions void ScannerBase::setDebug(bool onOff) {} bool ScannerBase::debug() const { return false; } void ScannerBase::redo(size_t nChars) { size_t from = nChars >= length() ? 0 : length() - nChars; d_input->reRead(d_matched, from); d_matched.resize(from); } void ScannerBase::switchOstream(std::string const &outfilename) { *d_out << std::flush; d_out.reset( outfilename == "-" ? new std::ostream(std::cout.rdbuf()) : outfilename == "" ? new std::ostream(std::cerr.rdbuf()) : new std::ofstream(outfilename)); } bool ScannerBase::popStream() { using namespace std::filesystem; d_input->close(); if (d_streamStack.size() <= 1) return false; d_streamStack.pop_back(); d_filename = path{ setCwd(d_streamStack.back().pushedName) }.filename().string(); d_input = &d_streamStack.back().input; return true; } // See the manual's section `Run-time operations' section for an explanation // of this member. ScannerBase::ActionType_ ScannerBase::actionType_(size_t range) { d_nextState = d_dfaBase_[d_state][range]; if (d_nextState != -1) // transition is possible return ActionType_::CONTINUE; if (knownFinalState()) // FINAL state reached return ActionType_::MATCH; if (d_matched.size()) return ActionType_::ECHO_FIRST; // no match, echo the 1st char return range != s_rangeOfEOF_ ? ActionType_::ECHO_CH : ActionType_::RETURN; } void ScannerBase::accept(size_t nChars) // old name: less { if (nChars < d_matched.size()) { d_input->reRead(d_matched, nChars); d_matched.resize(nChars); } } void ScannerBase::setMatchedSize(size_t length) { d_input->reRead(d_matched, length); // reread the tail section d_matched.resize(length); // return what's left } // At this point a rule has been matched. The next character is not part of // the matched rule and is sent back to the input. The final match length // is determined, the index of the matched rule is determined, and then // d_atBOL is updated. Finally the rule's index is returned. // The numbers behind the finalPtr assignments are explained in the // manual's `Run-time operations' section. size_t ScannerBase::matched_(size_t ch) { d_input->reRead(ch); FinalData *finalPtr; if (not d_atBOL) // not at BOL finalPtr = &d_final.std; // then use the std rule (3, 4) // at BOL else if (not available(d_final.std.rule)) // only a BOL rule avail. finalPtr = &d_final.bol; // use the BOL rule (6) else if (not available(d_final.bol.rule)) // only a std rule is avail. finalPtr = &d_final.std; // use the std rule (7) else if ( // Both are available (8) d_final.bol.length != // check lengths of matched texts d_final.std.length // unequal lengths, use the rule ) // having the longer match length finalPtr = d_final.bol.length > d_final.std.length ? &d_final.bol : &d_final.std; else // lengths are equal: use 1st rule finalPtr = d_final.bol.rule < d_final.std.rule ? &d_final.bol : &d_final.std; setMatchedSize(finalPtr->length); d_atBOL = d_matched.back() == '\n'; return finalPtr->rule; } size_t ScannerBase::getRange_(int ch) // using int to prevent casts { return ch == AT_EOF ? as(s_rangeOfEOF_) : s_ranges_[ch]; } // At this point d_nextState contains the next state and continuation is // possible. The just read char. is appended to d_match void ScannerBase::continue_(int ch) { d_state = d_nextState; if (ch != AT_EOF) d_matched += ch; } void ScannerBase::echoCh_(size_t ch) { *d_out << as(ch); d_atBOL = ch == '\n'; } // At this point there is no continuation. The last character is // pushed back into the input stream as well as all but the first char. in // the buffer. The first char. in the buffer is echoed to stderr. // If there isn't any 1st char yet then the current char doesn't fit any // rules and that char is then echoed void ScannerBase::echoFirst_(size_t ch) { d_input->reRead(ch); d_input->reRead(d_matched, 1); echoCh_(d_matched[0]); } // Update the rules associated with the current state, do this separately // for BOL and std rules. // If a rule was set, update the rule index and the current d_matched // length. void ScannerBase::updateFinals_() { size_t len = d_matched.size(); int const *rf = d_dfaBase_[d_state] + s_finIdx_; if (rf[0] != -1) // update to the latest std rule { d_final.std = FinalData { as(rf[0]), len }; } if (rf[1] != -1) // update to the latest bol rule { d_final.bol = FinalData { as(rf[1]), len }; } } void ScannerBase::reset_() { d_final = Final{ FinalData{s_unavailable, 0}, FinalData {s_unavailable, 0} }; d_state = 0; d_return = true; if (!d_more) d_matched.clear(); d_more = false; } int Scanner::executeAction_(size_t ruleIdx) try { switch (ruleIdx) { // $insert actions case 1: { #line 13 "lexer" return Tokens::WS; } break; case 2: { #line 15 "lexer" return Tokens::NR; } break; case 3: { #line 17 "lexer" return Tokens::ID; } break; case 4: { #line 19 "lexer" return matched()[0]; } break; case 5: { #line 21 "lexer" return Tokens::CHAR; } break; } noReturn_(); return 0; } catch (Leave_ value) { return static_cast(value); } int Scanner::lex_() { reset_(); preCode(); while (true) { size_t ch = get_(); // fetch next char size_t range = getRange_(ch); // determine the range updateFinals_(); // update the state's Final info switch (actionType_(range)) // determine the action { case ActionType_::CONTINUE: continue_(ch); continue; case ActionType_::MATCH: { d_token_ = executeAction_(matched_(ch)); if (return_()) { print(); postCode(PostEnum_::RETURN); return d_token_; } break; } case ActionType_::ECHO_FIRST: echoFirst_(ch); break; case ActionType_::ECHO_CH: echoCh_(ch); break; case ActionType_::RETURN: if (!popStream()) { postCode(PostEnum_::END); return 0; } postCode(PostEnum_::POP); continue; } // switch postCode(PostEnum_::WIP); reset_(); preCode(); } // while } void ScannerBase::print_() const { } ssh-cron-1.05.00/scanner/scanner.ih0000644000175000017500000000010314324446663016007 0ustar frankfrank#include "scanner.h" #include "tokens.h" // end of scanner.ih ssh-cron-1.05.00/scanner/scanner.h0000644000175000017500000000305014324446663015642 0ustar frankfrank// Generated by Flexc++ V2.08.00 on Fri, 13 Nov 2020 12:59:07 +0100 #ifndef Scanner_H_INCLUDED_ #define Scanner_H_INCLUDED_ // $insert baseclass_h #include "scannerbase.h" // $insert classHead class Scanner: public ScannerBase { bool d_returnCommand = false; public: explicit Scanner(std::istream &in = std::cin, std::ostream &out = std::cout); Scanner(std::string const &infile, std::string const &outfile); // $insert lexFunctionDecl int lex(); private: int lex_(); int executeAction_(size_t ruleNr); void print(); void preCode(); // re-implement this function for code that must // be exec'ed before the patternmatching starts void postCode(PostEnum_ type); // re-implement this function for code that must // be exec'ed after the rules's actions. }; // $insert scannerConstructors inline Scanner::Scanner(std::istream &in, std::ostream &out) : ScannerBase(in, out) {} inline Scanner::Scanner(std::string const &infile, std::string const &outfile) : ScannerBase(infile, outfile) {} // $insert inlineLexFunction inline int Scanner::lex() { return lex_(); } inline void Scanner::preCode() { // optionally replace by your own code } inline void Scanner::postCode([[maybe_unused]] PostEnum_ type) { // optionally replace by your own code } inline void Scanner::print() { print_(); } #endif // Scanner_H_INCLUDED_ ssh-cron-1.05.00/scanner/icmconf0000644000175000017500000000007614324446663015406 0ustar frankfrank#define LIBRARY "scanner" #include "../icmconf.lib" ssh-cron-1.05.00/scanner/tokens.h0000644000175000017500000000027514324446663015522 0ustar frankfrank#ifndef INCLUDED_TOKENS_ #define INCLUDED_TOKENS_ struct Tokens { // Symbolic tokens: enum Tokens_ { WS = 257, NR, ID, CHAR, }; }; #endif ssh-cron-1.05.00/scanner/main.cc0000644000175000017500000000061014324446663015272 0ustar frankfrank//#include //#include "scanner.h" // //using namespace std; // //int main() //{ // Scanner scanner; // // while (int value = scanner.lex()) // { // cout << "token: "; // if (value < 1000) // cout << static_cast(value); // else // cout << value; // // cout << ", matched: " << scanner.matched() << '\n'; // } //} ssh-cron-1.05.00/scanner/lexer0000644000175000017500000000065414324446663015111 0ustar frankfrank%filenames scanner //%interactive //%debug ID [[:alpha:]_][[:alnum:]_-]* %% //%nowarn ^[ \t]*(#.*)? // ignore ws (+ comment) at BOL [ \t]+ return Tokens::WS; [0-9]+ return Tokens::NR; {ID} return Tokens::ID; [*/,=\n-] return matched()[0]; . return Tokens::CHAR; ssh-cron-1.05.00/scanner/scannerbase.h0000644000175000017500000002762414324446663016512 0ustar frankfrank// Generated by Flexc++ V2.08.01 on Sat, 14 Nov 2020 10:05:45 +0100 #ifndef ScannerBASE_H_INCLUDED #define ScannerBASE_H_INCLUDED #include #include #include #include #include #include class ScannerBase { // idx: rule, value: tail length (NO_INCREMENTS if no tail) typedef std::vector VectorInt; static size_t const s_unavailable = std::numeric_limits::max(); enum { AT_EOF = -1 }; protected: enum Leave_ {}; enum class ActionType_ { CONTINUE, // transition succeeded, go on ECHO_CH, // echo ch itself (d_matched empty) ECHO_FIRST, // echo d_matched[0], push back the rest MATCH, // matched a rule RETURN, // no further continuation, lex returns 0. }; enum class PostEnum_ { END, // postCode called when lex_() ends POP, // postCode called after switching files RETURN, // postCode called when lex_() returns WIP // postCode called when a non-returning rule // was matched }; public: // $insert startcondenum enum class StartCondition_{ INITIAL, }; private: struct FinalData { size_t rule; size_t length; }; struct Final { FinalData std; FinalData bol; }; // class Input encapsulates all input operations. // Its member get() returns the next input character // $insert inputInterface class Input { std::deque d_deque; // pending input chars std::istream *d_in; // ptr for easy streamswitching size_t d_lineNr; // line count public: Input(); // iStream: dynamically allocated Input(std::istream *iStream, size_t lineNr = 1); size_t get(); // the next range void reRead(size_t ch); // push back 'ch' (if < 0x100) // push back str from idx 'fmIdx' void reRead(std::string const &str, size_t fmIdx); size_t lineNr() const { return d_lineNr; } size_t nPending() const { return d_deque.size(); } void setPending(size_t size) { d_deque.erase(d_deque.begin(), d_deque.end() - size); } void close() // force closing the stream { delete d_in; d_in = 0; // switchStreams also closes } private: size_t next(); // obtain the next character }; protected: struct StreamStruct { std::string pushedName; Input input; }; private: std::vector d_streamStack; std::string d_filename; // name of the currently processed static size_t s_istreamNr; // file. With istreams it receives // the name "", where // # is the sequence number of the // istream (starting at 1) int d_startCondition = 0; int d_lopSC = 0; size_t d_state = 0; int d_nextState; std::shared_ptr d_out; bool d_atBOL = true; // the matched text starts at BOL Final d_final; // only used interactively: std::istream *d_in; // points to the input stream std::shared_ptr d_line; // holds line fm d_in Input *d_input; // input now in d_streamStack std::string d_matched; // matched characters std::string d_lopMatched; // matched lop-rule characters std::string::iterator d_lopIter; std::string::iterator d_lopTail; std::string::iterator d_lopEnd; size_t d_lopPending; // # pending input chars at lop1_ bool d_return; // return after a rule's action bool d_more = false; // set to true by more() size_t (ScannerBase::*d_get)() = &ScannerBase::getInput; protected: std::istream *d_in_; int d_token_; // returned by lex_ int const (*d_dfaBase_)[27]; static int const s_dfa_[][27]; static int const (*s_dfaBase_[])[27]; enum: bool { s_interactive_ = false }; enum: size_t { s_rangeOfEOF_ = 24, s_finIdx_ = 25, s_nRules_ = 6, s_maxSizeofStreamStack_ = 10 }; static size_t const s_ranges_[]; static size_t const s_rf_[][2]; public: ScannerBase(ScannerBase const &other) = delete; ScannerBase &operator=(ScannerBase const &rhs) = delete; bool debug() const; std::string const &filename() const; std::string const &matched() const; size_t length() const; size_t lineNr() const; void setDebug(bool onOff); void switchOstream(std::ostream &out); void switchOstream(std::string const &outfilename); void switchStreams(std::istream &in, std::ostream &out = std::cout); void switchIstream(std::string const &infilename); void switchStreams(std::string const &infilename, std::string const &outfilename); // $insert interactiveDecl protected: ScannerBase(std::istream &in, std::ostream &out); ScannerBase(std::string const &infilename, std::string const &outfilename); ~ScannerBase(); bool popStream(); std::ostream &out(); void echo() const; void leave(int retValue) const; // `accept(n)' returns all but the first `n' characters of the current // token back to the input stream, where they will be rescanned when the // scanner looks for the next match. // So, it matches n of the characters in the input buffer, and so it accepts // n characters, rescanning the rest. void accept(size_t nChars = 0); // former: less void redo(size_t nChars = 0); // rescan the last nChar // characters, reducing // length() by nChars void more(); void push(size_t ch); // push char to Input void push(std::string const &txt); // same: chars std::vector const &streamStack() const; void pushStream(std::istream &curStream); void pushStream(std::string const &curName); void setFilename(std::string const &name); void setMatched(std::string const &text); static std::string istreamName_(); // members used by lex_(): they end in _ and should not be used // otherwise. ActionType_ actionType_(size_t range); // next action bool return_(); // 'return' from codeblock size_t matched_(size_t ch); // handles a matched rule size_t getRange_(int ch); // convert char to range size_t get_(); // next character size_t state_() const; // current state void continue_(int ch); // handles a transition void echoCh_(size_t ch); // echoes ch, sets d_atBOL void echoFirst_(size_t ch); // handles unknown input void updateFinals_(); // update a state's Final info void noReturn_(); // d_return to false void print_() const; // optionally print token void pushFront_(size_t ch); // return char to Input void reset_(); // prepare for new cycle // next input stream: void switchStream_(std::istream &in, size_t lineNr); void lopf_(size_t tail); // matched fixed size tail void lop1_(int lopSC); // matched ab for a/b void lop2_(); // matches the LOP's b tail void lop3_(); // catch-all while matching b void lop4_(); // matches the LOP's a head // $insert startconddecl StartCondition_ startCondition() const; // current start condition void begin(StartCondition_ startCondition); private: static StartCondition_ constexpr SC(int sc); static int constexpr SC(StartCondition_ sc); size_t getInput(); size_t getLOP(); void p_pushStream(std::string const &name, std::istream *streamPtr); void setMatchedSize(size_t length); bool knownFinalState(); static std::string setCwd(std::string const &filename); template static ReturnType constexpr as(ArgType value); static bool constexpr available(size_t value); }; inline ScannerBase::~ScannerBase() { d_input->close(); } template inline ReturnType constexpr ScannerBase::as(ArgType value) { return static_cast(value); } // $insert startcondimpl inline ScannerBase::StartCondition_ constexpr ScannerBase::SC(int sc) { return as(sc); } inline int constexpr ScannerBase::SC(StartCondition_ sc) { return as(sc); } inline ScannerBase::StartCondition_ ScannerBase::startCondition() const { return SC(d_startCondition); } inline void ScannerBase::begin(StartCondition_ startCondition) { // d_state is reset to 0 by reset_() d_dfaBase_ = s_dfaBase_[d_startCondition = SC(startCondition)]; } inline bool ScannerBase::knownFinalState() { return (d_atBOL && available(d_final.bol.rule)) || available(d_final.std.rule); } inline bool constexpr ScannerBase::available(size_t value) { return value != std::numeric_limits::max(); } inline std::ostream &ScannerBase::out() { return *d_out; } inline void ScannerBase::push(size_t ch) { d_input->reRead(ch); } inline void ScannerBase::push(std::string const &str) { d_input->reRead(str, 0); } inline std::vector const &ScannerBase::streamStack() const { return d_streamStack; } inline void ScannerBase::setFilename(std::string const &name) { d_filename = name; } inline void ScannerBase::setMatched(std::string const &text) { d_matched = text; } inline std::string const &ScannerBase::matched() const { return d_matched; } inline std::string const &ScannerBase::filename() const { return d_filename; } inline void ScannerBase::echo() const { *d_out << d_matched; } inline size_t ScannerBase::length() const { return d_matched.size(); } inline void ScannerBase::leave(int retValue) const { throw as(retValue); } inline size_t ScannerBase::lineNr() const { return d_input->lineNr(); } inline void ScannerBase::more() { d_more = true; } inline size_t ScannerBase::state_() const { return d_state; } inline size_t ScannerBase::get_() { return (this->*d_get)(); } inline size_t ScannerBase::getInput() { return d_input->get(); } inline bool ScannerBase::return_() { return d_return; } inline void ScannerBase::noReturn_() { d_return = false; } #endif // ScannerBASE_H_INCLUDED ssh-cron-1.05.00/scanner/frame0000644000175000017500000000004514324446663015056 0ustar frankfrank#include "scanner.ih" Scanner:: { } ssh-cron-1.05.00/ssh-cron.xref0000644000175000017500000004315414324446663015042 0ustar frankfrankoxref by Frank B. Brokken (f.b.brokken@rug.nl) oxref V2.00.03 2012-2022 CREATED Sat, 17 Sep 2022 09:25:33 +0000 CROSS REFERENCE FOR: -fxs tmp/libmodules.a ---------------------------------------------------------------------- CROSS REFERENCE LISTING: addCronCommand() Full name: CronData::addCronCommand() Source: addcroncommand.cc Used By: process.cc: CronData::process() addName(std::__cxx11::basic_string, std::allocator > const&) Full name: CronData::addName(std::__cxx11::basic_string, std::allocator > const&) Source: addname.cc Used By: parse.cc: Parser::executeAction_(int) addNr(unsigned long) Full name: CronData::addNr(unsigned long) Source: addnr.cc Used By: parse.cc: Parser::executeAction_(int) addRange(unsigned long, unsigned long, unsigned long) Full name: CronData::addRange(unsigned long, unsigned long, unsigned long) Source: addrange.cc Used By: setall.cc: CronData::setAll(unsigned long) parse.cc: Parser::executeAction_(int) assign() Full name: CronData::assign() Source: assign.cc Used By: assign2.cc: CronData::assign(char const* const*, bool) setdayofmonth.cc: CronData::setDayOfMonth() sethours.cc: CronData::setHours() setminutes.cc: CronData::setMinutes() assign(char const* const*, bool) Full name: CronData::assign(char const* const*, bool) Source: assign2.cc Used By: setdayofweek.cc: CronData::setDayOfWeek() setmonthofyear.cc: CronData::setMonthOfYear() author Full name: Icmbuild::author Source: version.cc Used By: usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) basename() const Full name: Daemon::basename() const Source: basename.cc Used By: list.cc: Daemon::list(std::istream&) listrequest.cc: Daemon::listRequest() reload.cc: Daemon::reload() terminate.cc: Daemon::terminate() const call(FBB::DateTime const&, CronEntry const&) Full name: Cron::call(FBB::DateTime const&, CronEntry const&) Source: call.cc Used By: runcronjobs.cc: Cron::runCronJobs() checkAction() const Full name: Options::checkAction() const Source: checkaction.cc Used By: options1.cc: Options::Options() childProcess() Full name: Daemon::childProcess() Source: childprocess.cc Used By: parentprocess.cc: Daemon::parentProcess() childProcess() Full name: Cron::childProcess() Source: childprocess.cc Used By: childredirections.cc: Cron::childRedirections() cleanup() Full name: Daemon::cleanup() Source: cleanup.cc Used By: childprocess.cc: Daemon::childProcess() createIPCfile() Full name: Daemon::createIPCfile() Source: createipcfile.cc Used By: daemonize.cc: Daemon::daemonize() Cron(CronData&) Full name: Cron::Cron(CronData&) Source: cron1.cc Used By: daemon1.cc: Daemon::Daemon() CronData() Full name: CronData::CronData() Source: crondata1.cc Used By: reload.cc: Cron::reload(std::istream&) daemon1.cc: Daemon::Daemon() cronLoop() Full name: Cron::cronLoop() Source: cronloop.cc Used By: parentprocess.cc: Cron::parentProcess() cxx11] Full name: Options::s_syslogPriorities[abi:cxx11] Source: data.cc Used By: syslogpriority.cc: Options::syslogPriority() const cxx11] Full name: Options::s_syslogFacilities[abi:cxx11] Source: data.cc Used By: syslogfacility.cc: Options::syslogFacility() const cxx11] Full name: Cron::s_agent[abi:cxx11] Source: data.cc Used By: childprocess.cc: Cron::childProcess() cxx11]() Full name: Daemon::askPassPhrase[abi:cxx11]() Source: askpassphrase.cc Used By: reload.cc: Daemon::reload() cxx11]() const Full name: Options::syslogTag[abi:cxx11]() const Source: syslogtag.cc Used By: setsyslog.cc: Options::setSyslog() daemonize() Full name: Daemon::daemonize() Source: daemonize.cc Used By: run.cc: Daemon::run() defineRunFunction() Full name: Cron::defineRunFunction() Source: definerunfunction.cc Used By: parentprocess.cc: Cron::parentProcess() enterThread(Daemon*) Full name: Daemon::enterThread(Daemon*) Source: enterthread.cc Used By: childprocess.cc: Daemon::childProcess() error() Full name: Parser::error() Source: error.cc Used By: parse.cc: Parser::errorRecovery_() execute(CronEntry const&) Full name: Cron::execute(CronEntry const&) Source: execute.cc Used By: runcronjobs.cc: Cron::runCronJobs() getIPCInfo() const Full name: Daemon::getIPCInfo() const Source: getipcinfo.cc Used By: listrequest.cc: Daemon::listRequest() reload.cc: Daemon::reload() terminate.cc: Daemon::terminate() const getPassPhrase() Full name: Daemon::getPassPhrase() Source: getpassphrase.cc Used By: daemonize.cc: Daemon::daemonize() handleRequests() Full name: Cron::handleRequests() Source: handlerequests.cc Used By: requesthandler.cc: Cron::requestHandler(Cron*) hmac(std::__cxx11::basic_string, std::allocator > const&) Full name: Cron::hmac(std::__cxx11::basic_string, std::allocator > const&) Source: hmac.cc Used By: reload.cc: Cron::reload(std::istream&) getpassphrase.cc: Daemon::getPassPhrase() idmsg() const Full name: Daemon::idmsg() const Source: idmsg.cc Used By: childprocess.cc: Daemon::childProcess() daemonize.cc: Daemon::daemonize() getipcinfo.cc: Daemon::getIPCInfo() const list.cc: Daemon::list(std::istream&) listrequest.cc: Daemon::listRequest() reload.cc: Daemon::reload() terminate.cc: Daemon::terminate() const idmsg() const Full name: Cron::idmsg() const Source: idmsg.cc Used By: cronloop.cc: Cron::cronLoop() definerunfunction.cc: Cron::defineRunFunction() execute.cc: Cron::execute(CronEntry const&) handlerequests.cc: Cron::handleRequests() parentprocess.cc: Cron::parentProcess() reload.cc: Cron::reload(std::istream&) insert(std::ostream&) const Full name: CronData::insert(std::ostream&) const Source: insert.cc Used By: parentprocess.cc: Daemon::parentProcess() reload.cc: Daemon::reload() insert(std::ostream&) const Full name: CronEntry::insert(std::ostream&) const Source: insert.cc Used By: operatorinsert.cc: operator<<(std::ostream&, CronEntry const&) insert.cc: CronData::insert(std::ostream&) const instance() Full name: Options::instance() Source: instance.cc Used By: addcroncommand.cc: CronData::addCronCommand() crondata1.cc: CronData::CronData() setenvvar.cc: CronData::setEnvVar(std::__cxx11::basic_string, std::allocator > const&, std::__cxx11::basic_string, std::allocator > const&) cron1.cc: Cron::Cron(CronData&) handlerequests.cc: Cron::handleRequests() daemon1.cc: Daemon::Daemon() getipcinfo.cc: Daemon::getIPCInfo() const parentprocess.cc: Daemon::parentProcess() invalidRange(unsigned long, unsigned long) const Full name: CronData::invalidRange(unsigned long, unsigned long) const Source: invalidrange.cc Used By: addrange.cc: CronData::addRange(unsigned long, unsigned long, unsigned long) ipc() Full name: Daemon::ipc() Source: ipc.cc Used By: run.cc: Daemon::run() lex_() Full name: Scanner::lex_() Source: lex.cc Used By: parse.cc: Parser::nextToken_() list(std::istream&) Full name: Daemon::list(std::istream&) Source: list.cc Used By: listrequest.cc: Daemon::listRequest() list(unsigned long*, long, FBB::SharedStream&) Full name: Cron::list(unsigned long*, long, FBB::SharedStream&) Source: list.cc Used By: handlerequests.cc: Cron::handleRequests() listRequest() Full name: Daemon::listRequest() Source: listrequest.cc Used By: ipc.cc: Daemon::ipc() loadConfigFile() Full name: Options::loadConfigFile() Source: loadconfigfile.cc Used By: options1.cc: Options::Options() operator<<(std::ostream&, CronEntry const&) Full name: operator<<(std::ostream&, CronEntry const&) Source: operatorinsert.cc Used By: addcroncommand.cc: CronData::addCronCommand() list.cc: Cron::list(unsigned long*, long, FBB::SharedStream&) Options() Full name: Options::Options() Source: options1.cc Used By: instance.cc: Options::instance() outOfRange(unsigned long) Full name: CronData::outOfRange(unsigned long) Source: outofrange.cc Used By: addnr.cc: CronData::addNr(unsigned long) assign.cc: CronData::assign() parentProcess() Full name: Cron::parentProcess() Source: parentprocess.cc Used By: childredirections.cc: Cron::childRedirections() parse() Full name: Parser::parse() Source: parse.cc Used By: reload.cc: Cron::reload(std::istream&) daemon1.cc: Daemon::Daemon() Parser(std::istream&, CronData&) Full name: Parser::Parser(std::istream&, CronData&) Source: parser1.cc Used By: reload.cc: Cron::reload(std::istream&) daemon1.cc: Daemon::Daemon() ParserBase() Full name: ParserBase::ParserBase() Source: parse.cc Used By: parser1.cc: Parser::Parser(std::istream&, CronData&) process() Full name: CronData::process() Source: process.cc Used By: parse.cc: Parser::executeAction_(int) readRequest(std::istream&) Full name: Cron::readRequest(std::istream&) Source: readrequest.cc Used By: handlerequests.cc: Cron::handleRequests() list.cc: Daemon::list(std::istream&) reload() Full name: Daemon::reload() Source: reload.cc Used By: ipc.cc: Daemon::ipc() reload(std::istream&) Full name: Cron::reload(std::istream&) Source: reload.cc Used By: handlerequests.cc: Cron::handleRequests() requestHandler(Cron*) Full name: Cron::requestHandler(Cron*) Source: requesthandler.cc Used By: parentprocess.cc: Cron::parentProcess() reset(unsigned long) Full name: CronData::reset(unsigned long) Source: reset.cc Used By: parse.cc: Parser::executeAction_(int) runCronJobs() Full name: Cron::runCronJobs() Source: runcronjobs.cc Used By: cronloop.cc: Cron::cronLoop() s_day Full name: CronData::s_day Source: data.cc Used By: setdayofweek.cc: CronData::setDayOfWeek() s_defaultAgent Full name: Options::s_defaultAgent Source: data.cc Used By: options1.cc: Options::Options() usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) s_defaultConfigFile Full name: Options::s_defaultConfigFile Source: data.cc Used By: loadconfigfile.cc: Options::loadConfigFile() usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) s_defaultIPCfile Full name: Options::s_defaultIPCfile Source: data.cc Used By: options1.cc: Options::Options() usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) s_defaultMailer Full name: Options::s_defaultMailer Source: data.cc Used By: options1.cc: Options::Options() usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) s_defaultSyslogFacility Full name: Options::s_defaultSyslogFacility Source: data.cc Used By: syslogfacility.cc: Options::syslogFacility() const usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) s_defaultSyslogIdent Full name: Options::s_defaultSyslogIdent Source: data.cc Used By: syslogtag.cc: Options::syslogTag[abi:cxx11]() const usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) s_defaultSyslogPriority Full name: Options::s_defaultSyslogPriority Source: data.cc Used By: syslogpriority.cc: Options::syslogPriority() const usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) s_month Full name: CronData::s_month Source: data.cc Used By: setmonthofyear.cc: CronData::setMonthOfYear() s_nameMap Full name: IPCFunction::s_nameMap Source: data.cc Used By: handlerequests.cc: Cron::handleRequests() list.cc: Daemon::list(std::istream&) listrequest.cc: Daemon::listRequest() s_options Full name: Options::s_options Source: data.cc Used By: instance.cc: Options::instance() s_values Full name: CronData::s_values Source: data.cc Used By: assign.cc: CronData::assign() ScannerBase(std::istream&, std::ostream&) Full name: ScannerBase::ScannerBase(std::istream&, std::ostream&) Source: lex.cc Used By: parser1.cc: Parser::Parser(std::istream&, CronData&) scheduler() const Full name: Cron::scheduler() const Source: scheduler.cc Used By: execute.cc: Cron::execute(CronEntry const&) handlerequests.cc: Cron::handleRequests() parentprocess.cc: Cron::parentProcess() sendCommand(std::__cxx11::basic_string, std::allocator >) Full name: Cron::sendCommand(std::__cxx11::basic_string, std::allocator >) Source: sendcommand.cc Used By: execute.cc: Cron::execute(CronEntry const&) parentprocess.cc: Cron::parentProcess() setAll(unsigned long) Full name: CronData::setAll(unsigned long) Source: setall.cc Used By: parse.cc: Parser::executeAction_(int) setCommand(std::__cxx11::basic_string, std::allocator > const&) Full name: CronData::setCommand(std::__cxx11::basic_string, std::allocator > const&) Source: setcommand.cc Used By: parse.cc: Parser::executeAction_(int) setDayOfMonth() Full name: CronData::setDayOfMonth() Source: setdayofmonth.cc Used By: parse.cc: Parser::executeAction_(int) setDayOfWeek() Full name: CronData::setDayOfWeek() Source: setdayofweek.cc Used By: parse.cc: Parser::executeAction_(int) setEnvironment(unsigned long, unsigned long, std::vector, std::allocator >, std::allocator, std::allocator > > > const*) Full name: CronEntry::setEnvironment(unsigned long, unsigned long, std::vector, std::allocator >, std::allocator, std::allocator > > > const*) Source: setenvironment.cc Used By: addcroncommand.cc: CronData::addCronCommand() setEnvVar(std::__cxx11::basic_string, std::allocator > const&, std::__cxx11::basic_string, std::allocator > const&) Full name: CronData::setEnvVar(std::__cxx11::basic_string, std::allocator > const&, std::__cxx11::basic_string, std::allocator > const&) Source: setenvvar.cc Used By: parse.cc: Parser::executeAction_(int) setHours() Full name: CronData::setHours() Source: sethours.cc Used By: parse.cc: Parser::executeAction_(int) setMinutes() Full name: CronData::setMinutes() Source: setminutes.cc Used By: parse.cc: Parser::executeAction_(int) setMonthOfYear() Full name: CronData::setMonthOfYear() Source: setmonthofyear.cc Used By: parse.cc: Parser::executeAction_(int) setSyslog() Full name: Options::setSyslog() Source: setsyslog.cc Used By: options1.cc: Options::Options() showSet(std::ostream&, std::set, std::allocator > const&) Full name: CronEntry::showSet(std::ostream&, std::set, std::allocator > const&) Source: showset.cc Used By: insert.cc: CronEntry::insert(std::ostream&) const signalHandler(unsigned long) Full name: Daemon::signalHandler(unsigned long) Source: signalhandler.cc Used By: parentprocess.cc: Daemon::parentProcess() stop(unsigned long) Full name: Cron::stop(unsigned long) Source: stop.cc Used By: signalhandler.cc: Daemon::signalHandler(unsigned long) syslogFacility() const Full name: Options::syslogFacility() const Source: syslogfacility.cc Used By: setsyslog.cc: Options::setSyslog() syslogPriority() const Full name: Options::syslogPriority() const Source: syslogpriority.cc Used By: setsyslog.cc: Options::setSyslog() terminate() const Full name: Daemon::terminate() const Source: terminate.cc Used By: ipc.cc: Daemon::ipc() usage(std::__cxx11::basic_string, std::allocator > const&) Full name: Options::usage(std::__cxx11::basic_string, std::allocator > const&) Source: usage.cc Used By: options1.cc: Options::Options() version Full name: Icmbuild::version Source: version.cc Used By: usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) writeRequest(std::ostream&, IPCFunction::Function) Full name: Cron::writeRequest(std::ostream&, IPCFunction::Function) Source: writerequest.cc Used By: handlerequests.cc: Cron::handleRequests() listrequest.cc: Daemon::listRequest() reload.cc: Daemon::reload() years Full name: Icmbuild::years Source: version.cc Used By: usage.cc: Options::usage(std::__cxx11::basic_string, std::allocator > const&) ssh-cron-1.05.00/version/0000775000175000017500000000000014741222066014070 5ustar frankfrankssh-cron-1.05.00/version/version.h0000664000175000017500000000034214741230041015715 0ustar frankfrank#ifndef INCLUDED_VERSION_H_ #define INCLUDED_VERSION_H_ #include "../VERSION" namespace Icmbuild { char const version[] = VERSION; char const years[] = YEARS; char const author[] = AUTHOR; } #endif ssh-cron-1.05.00/VERSION0000644000175000017500000000015514741230026013445 0ustar frankfrank#define AUTHOR "Frank B. Brokken (f.b.brokken@rug.nl)"; #define VERSION "1.05.00" #define YEARS "2014-2025" ssh-cron-1.05.00/VERSION.h0000644000175000017500000000010414324446662013701 0ustar frankfrank#include "VERSION" SUBST(_CurVers_)(VERSION) SUBST(_CurYrs_)(YEARS)