ssh-cron-2.00.00/build0000775000175000017500000000631515005102626013422 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-2.00.00/build-depends-on0000664000175000017500000000026715005410417015451 0ustar frankfrankNon-standard software required for building ssh-cron from its source files: g++: recent versions libbobcat-dev (>= 6.09.00) icmake (>= 13.02.00) yodl (>= 4.04.00) ssh-cron-2.00.00/changelog0000664000175000017500000001305115055301204014240 0ustar frankfrankssh-cron (2.00.00) * ${ICMAKE_CPPSTD} is used for all g++ compilations * Building requires bobcat >= 6.09.00 and icmake >= 13.02.00 * Added new option --uds (-u), removed option --ipc-file (-p). See the man-page for details. -- Frank B. Brokken Mon, 01 Sep 2025 13:24:43 +0200 ssh-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-2.00.00/CLASSES0000664000175000017500000000007615005102626013413 0ustar frankfrankudsreq options cronentry crondata scanner parser cron sshcron ssh-cron-2.00.00/Copyright-notice0000664000175000017500000000253015005102626015542 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-2.00.00/cron/0000775000175000017500000000000015005657715013347 5ustar frankfrankssh-cron-2.00.00/cron/parentprocess.cc0000664000175000017500000000241015005102626016525 0ustar frankfrank#define XERR "cron" #include "cron.ih" // via Fork void Cron::parentProcess() { // stream sending commands to the (remote) ssh server via the child OFdStream toChild(d_childInput.writeOnly()); d_toChild = &toChild; defineRun(); // define the bash _run_ function // add private ssh keys to ssh-agent. Those keys must be // available when ssh-cron starts. Commands sent to remote // hosts can thereafter use the private keys to connect, even // if the private keys are locally made unavailable once // ssh-cron has started. childExec("/usr/bin/ssh-add"); thread{ &Cron::cronCmds, this }.detach(); d_server.open(d_options.uds()); d_server.listen(); Signal::instance().add(SIGTERM, *this); Signal::instance().add(SIGINT, *this); while (true) { int fd = d_server.accept(); d_in.reset(new IFdStream{ fd }); // cf. sshcron/tocron.cc d_out.reset(new OFdStream{ fd }); string line; if (not getline(*d_in, line)) { d_in->clear(); continue; } request(line); // process the received request } } ssh-cron-2.00.00/cron/croncmd.cc0000664000175000017500000000063715005102626015273 0ustar frankfrank#include "cron.ih" // by croncmds.cc void Cron::cronCmd(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; childExec(command); } ssh-cron-2.00.00/cron/terminate.cc0000664000175000017500000000044615005102626015634 0ustar frankfrank#define XERR "cron" #include "cron.ih" // by request.cc, see also sshcron/terminate.cc void Cron::terminate() { endChild(); // Fork member *d_out << getpid() << endl; // send a confirmation to the client FileSystem{ d_options.uds() }.remove(); throw 0; } ssh-cron-2.00.00/cron/error.cc0000664000175000017500000000032715005102626014773 0ustar frankfrank#include "cron.ih" // SSHCron does not send erroneous commands. If one's received it is ignored // by request.cc void Cron::error() { imsg << d_options.basename() << " ignored invalid command" << endl; } ssh-cron-2.00.00/cron/data.cc0000664000175000017500000000040315005102626014546 0ustar frankfrank#include "cron.ih" string Cron::s_agent = "/usr/bin/ssh-agent /bin/bash"; void (Cron::*Cron::s_request[])() { // must follow UDSReq's sequence &Cron::error, &Cron::list, &Cron::reload, &Cron::terminate }; ssh-cron-2.00.00/cron/list.cc0000664000175000017500000000063615005102626014620 0ustar frankfrank#define XERR "cron" #include "cron.ih" // input: // LIST - already received // passphrase // output: // NOK - invalid passphrase // or // OK // d_cronData entries // LIST // by request.cc, see also sshcron/list void Cron::list() { if (not verifyPassphrase()) return; *d_out << "OK" << '\n' << d_cronData << "LIST" << endl; } ssh-cron-2.00.00/cron/request.cc0000664000175000017500000000027415005102626015333 0ustar frankfrank#define XERR "cron" #include "cron.ih" // by parentprocess.cc void Cron::request(string const &cmd) { ( this->*s_request[find(cmd)] )(); // error, list, reload, terminate } ssh-cron-2.00.00/cron/reload.cc0000664000175000017500000000122115005102626015102 0ustar frankfrank#define XERR "cron" #include "cron.ih" // input: // RELOAD - already received // passphrase // cronFile // output: // NOK - invalid passphrase // or // OK // or // errors in cronFile // by request.cc, see also sshcron/reload.cc void Cron::reload() { if (not verifyPassphrase()) return; string cronFile; getline(*d_in, cronFile); if (not load(cronFile)) { *d_out << "error(s) in " << cronFile << ": currently no crontab requests" << endl; return; } *d_out << "OK" << endl; idmsg() << "reloading cron commands from " << cronFile << endl; } ssh-cron-2.00.00/cron/childprocess.cc0000664000175000017500000000103015005102626016314 0ustar frankfrank#define XERR "cron" #include "cron.ih" // via Fork void Cron::childProcess() { // for testing purposes: // nothing happens but the received info is sent to cerr // string line; // getline(cin, line); // while (getline(cin, line)) // xerr(s_agent << line); Proc process(s_agent, Proc::REPLACE); // 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 << '\'' << noid; } ssh-cron-2.00.00/cron/childexec.cc0000664000175000017500000000027015005102626015567 0ustar frankfrank#include "cron.ih" // by parentprocess.cc, croncmds.cc void Cron::childExec(string const &line) { idmsg() << "executing " << line << endl; *d_toChild << line << endl; } ssh-cron-2.00.00/cron/cron.ih0000664000175000017500000000172615005102626014622 0ustar frankfrank#include "cron.h" #include "../xerr/xerr.ih" #include // open(...) in childredirectons.cc #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 chrono; using namespace FBB; // by childexec.cc, croncmd.cc, definerun.cc, reload.cc inline ostream &Cron::idmsg() const { return imsg << d_options.basename() << ": "; } // // by parentprocess.cc, handlerequests.cc, execute.cc //inline ostream &Cron::scheduler() const //{ // return d_options.msg() << "scheduler: "; //} // by add.cc // static inline bool Cron::call(size_t value, SizeSet const &specified) { return specified.find(value) != specified.end(); } ssh-cron-2.00.00/cron/definerun.cc0000664000175000017500000000143115005102626015616 0ustar frankfrank#include "cron.ih" // define a bash function _run_ executing its argument(s) by bash's eval // command, sending its output either to /dev/null or mailing it to the // configured mailer program // the _run_ function is then called by sendchild.cc // by parentprocess.cc namespace { char const devnull[] = R"( _run_() { eval $* 2>&1 > /dev/null } )"; char const beginRun[] = R"( _run_() { out=`eval $* 2>&1` [ "$out" == "" ] || echo "$out" | )"; char const endRun[] = R"( } )"; } // namespace void Cron::defineRun() { std::string const &mailer = d_options.mailer(); if (mailer.empty()) *d_toChild << devnull; else *d_toChild << beginRun << mailer << endRun; idmsg() << "defined _run_()" << endl; } ssh-cron-2.00.00/cron/WIP/0000775000175000017500000000000015003423076013773 5ustar frankfrankssh-cron-2.00.00/cron/cron.h0000664000175000017500000000517615005102626014454 0ustar frankfrank#ifndef INCLUDED_CRON_ #define INCLUDED_CRON_ #include #include #include #include #include #include #include #include #include #include #include #include "../udsreq/udsreq.h" #include "../crondata/crondata.h" namespace FBB { class DateTime; class IFdStream; class OFdStream; } class CronEntry; class CronData; class Options; // IPCFunction defines the function requests sent by ssh-cron // or set by ssh-cron not running as daemon class Cron: private UDSReq, public FBB::Fork, public FBB::SignalHandler { using SizeSet = std::set; using EntryVect = std::vector; Options &d_options; std::mutex d_mutex; FBB::LocalServerSocket d_server; std::string d_passphrase; std::unique_ptr d_in; std::unique_ptr d_out; FBB::Pipe d_childInput; // child reads STDIN from this pipe CronData d_cronData; std::ostream *d_toChild = 0; static std::string s_agent; static void (Cron::*s_request[])(); // error, list, reload, terminate public: Cron(std::string const &passphrase); ~Cron() override; private: void childRedirections() override; void childProcess() override; void parentProcess() override; void signalHandler(size_t signal) override; bool add(CronEntry const &entry, FBB::DateTime const &now); void childExec(std::string const &line); void cronCmd(CronEntry const &entry); // cmd sent to the child void cronCmds(); // separate thread (parentprocess.cc) EntryVect cronJobs(); // return crontab entries to process void defineRun(); // defines the _run_ bash fun. void error(); std::ostream &idmsg() const; // imsg << basneame : // .ih bool load(std::string const &cronFile); // load a cron file void list(); void reload(); void request(std::string const &cmd); void terminate(); bool verifyPassphrase(); static bool call(size_t value, SizeSet const &specified); // .ih static std::string hmac(std::string const &passphrase); }; //std::ostream &scheduler() const; // d_options.msg() << "scheduler: " //void sendChild(CronEntry const &entry); //void popQueue(std::stop_token stop); //static std::string hmac(std::string const &passPhrase); #endif ssh-cron-2.00.00/cron/verifypassphrase.cc0000664000175000017500000000041615005102626017237 0ustar frankfrank#define XERR "cron" #include "cron.ih" // by list.cc reload.cc bool Cron::verifyPassphrase() { string passphrase; getline(*d_in, passphrase); if (hmac(passphrase) == d_passphrase) return true; *d_out << "NOK" << endl; return false; } ssh-cron-2.00.00/cron/cron1.cc0000664000175000017500000000050115005102626014656 0ustar frankfrank#define XERR "cron" #include "cron.ih" // by daemon/daemon1.cc Cron::Cron(string const &passphrase) : d_options(Options::instance()), d_passphrase(hmac(passphrase)) { if (not load(d_options.cronFile())) // load the cron file fmsg << "terminating " << d_options.basename() << noid; } ssh-cron-2.00.00/cron/icmconf0000664000175000017500000000007315005102626014672 0ustar frankfrank#define LIBRARY "cron" #include "../icmconf.lib" ssh-cron-2.00.00/cron/cronjobs.cc0000664000175000017500000000072015005102626015456 0ustar frankfrank#define XERR "cron" #include "cron.ih" // called once a minute, checking whether jobs should be added to the queue // by parentprocess.cc Cron::EntryVect Cron::cronJobs() { DateTime now(DateTime::LOCALTIME); EntryVect ret; lock_guard _{ d_mutex }; for (CronEntry const &entry: d_cronData.cronEntries()) { if (add(entry, now)) // maybe add &entry to the queue ret.push_back(&entry); } return ret; } ssh-cron-2.00.00/cron/childredirections.cc0000664000175000017500000000042615005102626017340 0ustar frankfrank#include "cron.ih" // via Fork 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-2.00.00/cron/destructor.cc0000664000175000017500000000014215005102626016033 0ustar frankfrank#define XERR #include "cron.ih" // by sshcron/childprocess.cc // overrides Cron::~Cron() {} ssh-cron-2.00.00/cron/signalhandler.cc0000664000175000017500000000040315005102626016450 0ustar frankfrank#include "cron.ih" // by cron1.cc void Cron::signalHandler(size_t signal) { if (signal == SIGTERM or signal == SIGINT) { endChild(); // Fork member FileSystem{ d_options.uds() }.remove(); throw 0; } } ssh-cron-2.00.00/cron/hmac.cc0000664000175000017500000000062215005102626014550 0ustar frankfrank#include "cron.ih" // by cron1.cc erifypassphrase.cc // static string Cron::hmac(string const &passphrase) { string use{ passphrase }; while (use.length() <= 32) // hmac needs 32 byte strings use += passphrase; use.resize(32); HMacBuf hmacbuf(use, "aes-256-cbc", "sha256", 1024); ostream out(&hmacbuf); out << use << eoi; return hmacbuf.hash(); } ssh-cron-2.00.00/cron/croncmds.cc0000664000175000017500000000050015005102626015443 0ustar frankfrank#define XERR "cron" #include "cron.ih" // runs as a separate thread // by parentprocess.cc void Cron::cronCmds() { while (true) { time_t secs = time(0) % 60; this_thread::sleep_for(seconds(60 - secs)); for (CronEntry const *entry: cronJobs()) cronCmd(*entry); } } ssh-cron-2.00.00/cron/frame0000664000175000017500000000007615005102626014351 0ustar frankfrank#define XERR "cron" #include "cron.ih" // by Cron:: { } ssh-cron-2.00.00/cron/add.cc0000664000175000017500000000064015005102626014370 0ustar frankfrank#include "cron.ih" // by cronjobs.cc bool Cron::add(CronEntry const &entry, DateTime const &now) { return call(now.minutes(), entry.minutes()) && call(now.hours(), entry.hours()) && call(now.month() + 1, entry.monthOfYear()) && call(now.monthDayNr(), entry.dayOfMonth()) && call(now.weekday(), entry.dayOfWeek()); } ssh-cron-2.00.00/cron/load.cc0000664000175000017500000000045715005102626014565 0ustar frankfrank#define XERR "cron" #include "cron.ih" // by cron1.cc, reload.cc bool Cron::load(string const &cronFile) { d_cronData = CronData(); d_cronData.messages(false); ifstream in = Exception::factory(cronFile); Parser parser(in, d_cronData); return parser.parse() == 0; } ssh-cron-2.00.00/crondata/0000775000175000017500000000000015005657715014201 5ustar frankfrankssh-cron-2.00.00/crondata/insert.cc0000664000175000017500000000040415005102626015774 0ustar frankfrank#include "crondata.ih" // by operator<< 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-2.00.00/crondata/addnr.cc0000664000175000017500000000040015005102626015554 0ustar frankfrank#include "crondata.ih" // by parser/inc/nr 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-2.00.00/crondata/data.cc0000664000175000017500000000116015005102626015401 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-2.00.00/crondata/addrange.cc0000664000175000017500000000111215005102626016232 0ustar frankfrank#include "crondata.ih" // by parser/inc/nr, setall.cc 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-2.00.00/crondata/sethours.cc0000664000175000017500000000030215005102626016341 0ustar frankfrank#include "crondata.ih" // by parser/inc/cronline void CronData::setHours() { d_next.setHours(assign()); d_entryName = "day of month"; d_entryBegin = 1; d_entryEnd = 32; } ssh-cron-2.00.00/crondata/reset.cc0000664000175000017500000000037115005102626015615 0ustar frankfrank#include "crondata.ih" // by parser/inc/line 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-2.00.00/crondata/crondata.ih0000664000175000017500000000062315005102626016301 0ustar frankfrank#include "crondata.h" #include #include #include #include "../options/options.h" using namespace std; using namespace FBB; // by addrange.cc inline void CronData::invalidRange(size_t first, size_t last) const { emsg << "Line " << d_lineNr << " (" << d_entryName << "): invalid range " << first << '-' << last << endl; } ssh-cron-2.00.00/crondata/addcroncommand.cc0000664000175000017500000000056415005102626017450 0ustar frankfrank#include "crondata.ih" // by process.cc 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 << d_options->basename() << ": cron " << d_cronEntries.size() << '\n' << d_next << endl; } ssh-cron-2.00.00/crondata/setdayofmonth.cc0000664000175000017500000000026715005102626017363 0ustar frankfrank#include "crondata.ih" // by parser/inc/cronline void CronData::setDayOfMonth() { d_next.setDayOfMonth(assign()); d_entryName = "month of year"; d_entryEnd = 13; } ssh-cron-2.00.00/crondata/addname.cc0000664000175000017500000000022215005102626016057 0ustar frankfrank#include "crondata.ih" // by parser/inc/time void CronData::addName(std::string const &name) { d_names.push_back(String::lc(name)); } ssh-cron-2.00.00/crondata/setmonthofyear.cc0000664000175000017500000000032315005102626017537 0ustar frankfrank#include "crondata.ih" // by parser/inc/cronline void CronData::setMonthOfYear() { d_next.setMonthOfYear(assign(s_month)); d_entryName = "day of week"; d_entryBegin = 0; d_entryEnd = 7; } ssh-cron-2.00.00/crondata/assign2.cc0000664000175000017500000000132115005102626016035 0ustar frankfrank#include "crondata.ih" // by setmonthofyear.cc, setdayofweek.cc CronData::SizeSet 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-2.00.00/crondata/setenvvar.cc0000664000175000017500000000064515005102626016514 0ustar frankfrank#include "crondata.ih" // by parser/inc/nameline 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 << d_options->basename() << ": envvar " << d_environment.size() << " `" << d_environment.back() << '\'' << endl; } } ssh-cron-2.00.00/crondata/icmconf0000664000175000017500000000007715005102626015530 0ustar frankfrank#define LIBRARY "crondata" #include "../icmconf.lib" ssh-cron-2.00.00/crondata/crondata1.cc0000664000175000017500000000027415005102626016351 0ustar frankfrank#include "crondata.ih" // by parser1.cc, cron/cron1.cc CronData::CronData() : d_options(&Options::instance()), d_entryName("minutes"), d_info(not d_options->reload()) {} ssh-cron-2.00.00/crondata/setminutes.cc0000664000175000017500000000025215005102626016671 0ustar frankfrank#include "crondata.ih" // by parser/inc/cronline void CronData::setMinutes() { d_next.setMinutes(assign()); d_entryName = "hours"; d_entryEnd = 24; } ssh-cron-2.00.00/crondata/assign.cc0000664000175000017500000000115415005102626015757 0ustar frankfrank#include "crondata.ih" // by sethours.cc, setdayofmonth.cc, assign2.cc, setminutes.cc CronData::SizeSet CronData::assign() { SizeSet 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-2.00.00/crondata/setdayofweek.cc0000664000175000017500000000020715005102626017163 0ustar frankfrank#include "crondata.ih" // by parser/inc/cronline void CronData::setDayOfWeek() { d_next.setDayOfWeek(assign(s_day, true)); } ssh-cron-2.00.00/crondata/process.cc0000664000175000017500000000035415005102626016152 0ustar frankfrank#include "crondata.ih" // by parser/inc/cronline void CronData::process() { if (emsg.count() == 0) addCronCommand(); d_entryName = "minutes"; d_entryEnd = 60; d_next = CronEntry(); emsg.setCount(0); } ssh-cron-2.00.00/crondata/outofrange.cc0000664000175000017500000000034315005102626016643 0ustar frankfrank#include "crondata.ih" // by addnr.cc, assign.cc void CronData::outOfRange(size_t nr) { emsg << "Line " << d_lineNr << " (" << d_entryName << "): " << nr << " out of range" << endl; d_wip.clear(); } ssh-cron-2.00.00/crondata/setall.cc0000664000175000017500000000030515005102626015754 0ustar frankfrank#include "crondata.ih" // by parser/inc/time void CronData::setAll(size_t step) { if (step == 1) d_all = true; else addRange(d_entryBegin, d_entryEnd - 1, step); } ssh-cron-2.00.00/crondata/frame0000664000175000017500000000004715005102626015201 0ustar frankfrank#include "crondata.ih" CronData:: { } ssh-cron-2.00.00/crondata/crondata.f0000664000175000017500000000177515005102626016137 0ustar frankfrank // by parser/error.cc inline size_t CronData::lineNr() const { return d_lineNr; } // by cron/reload.cc inline void CronData::messages(bool onOff) { d_info = onOff; } // by cron/list.cc inline CronEntry const &CronData::operator[](size_t index) const { return d_cronEntries[index]; } // by cron/runcronjobs.cc inline std::vector const &CronData::cronEntries() const { return d_cronEntries; } // by parser/inc/cronline, cronentry/cronentry.f (setCommand) inline void CronData::setCommand(std::string const &command) { d_next.setCommand(command); } // by daemon/daemon1.cc, cron/handlerequest.cc, cron/list.cc inline size_t CronData::size() const { return d_cronEntries.size(); } // by cron/execute.cc inline std::vector const &CronData::environment() const { return d_environment; } // by daemon/parentprocess.cc inline std::ostream &operator<<(std::ostream &out, CronData const &cronData) { return cronData.insert(out); } ssh-cron-2.00.00/crondata/crondata.h0000664000175000017500000000454215005102626016134 0ustar frankfrank#ifndef INCLUDED_CRONDATA_ #define INCLUDED_CRONDATA_ #include #include #include #include "../cronentry/cronentry.h" class Options; class CronData { using SizeSet = std::set; friend std::ostream &operator<<(std::ostream &out, CronData const &cronData); Options const *d_options; 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; SizeSet 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); // .f void process(); void reset(size_t lineNr = 0); // 0 means: do not update lineNr void messages(bool on = true); // .f void setMinutes(); void setHours(); void setDayOfMonth(); void setMonthOfYear(); void setDayOfWeek(); void setEnvVar(std::string const &var, std::string const &value); size_t lineNr() const; // .f size_t size() const; // .f std::vector const &cronEntries() const; // .f CronEntry const &operator[](size_t index) const; // .f std::vector const &environment() const; // .f private: SizeSet assign(); SizeSet assign(char const *const *names, bool allowEnd = false); void invalidRange(size_t first, size_t last) const; // .ih void outOfRange(size_t nr); void addCronCommand(); std::ostream &insert(std::ostream &out) const; }; #include "crondata.f" #endif ssh-cron-2.00.00/cronentry/0000775000175000017500000000000015005657715014431 5ustar frankfrankssh-cron-2.00.00/cronentry/insert.cc0000664000175000017500000000056715005102626016236 0ustar frankfrank#include "cronentry.ih" // by operatorinsert.cc 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-2.00.00/cronentry/cronentry.h0000664000175000017500000000372315005102626016614 0ustar frankfrank#ifndef INCLUDED_CRONENTRY_ #define INCLUDED_CRONENTRY_ #include #include #include #include class CronEntry { using SizeSet = std::set; 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; SizeSet d_minutes; SizeSet d_hours; SizeSet d_dayOfMonth; SizeSet d_monthOfYear; SizeSet 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); // .f void setMinutes(SizeSet &&src); // .f void setHours(SizeSet &&src); // .f void setDayOfMonth(SizeSet &&src); // .f void setMonthOfYear(SizeSet &&src); // .f void setDayOfWeek(SizeSet &&src); // .f size_t nSettings() const; // .f std::string const &command() const; // .f SizeSet const &minutes() const; // .f SizeSet const &hours() const; // .f SizeSet const &dayOfMonth() const; // .f SizeSet const &monthOfYear() const; // .f SizeSet const &dayOfWeek() const; // .f std::ostream &insert(std::ostream &out) const; private: static void showSet(std::ostream &out, SizeSet const &nrSet); }; #include "cronentry.f" #endif ssh-cron-2.00.00/cronentry/setenvironment.cc0000664000175000017500000000041415005102626020001 0ustar frankfrank#include "cronentry.ih" // by crondata/addcroncommand.cc void CronEntry::setEnvironment(size_t begin, size_t end, std::vector const *environment) { d_begin = begin; d_end = end; d_environment = environment; } ssh-cron-2.00.00/cronentry/icmconf0000664000175000017500000000010015005102626015743 0ustar frankfrank#define LIBRARY "cronentry" #include "../icmconf.lib" ssh-cron-2.00.00/cronentry/cronentry.f0000664000175000017500000000304415005102626016606 0ustar frankfrank // by parser/inc/cronline inline void CronEntry::setCommand(std::string const &src) { d_command = src; } // by parser/inc/cronline crondata.setminutes.cc inline void CronEntry::setMinutes(SizeSet &&src) { d_minutes = std::move(src); } // by parser/inc/cronline crondata.sethours.cc inline void CronEntry::setHours(SizeSet &&src) { d_hours = std::move(src); } // by parser/inc/cronline crondata.setdayofmonth.cc inline void CronEntry::setDayOfMonth(SizeSet &&src) { d_dayOfMonth = std::move(src); } // by parser/inc/cronline crondata.setmonthofyear.cc inline void CronEntry::setMonthOfYear(SizeSet &&src) { d_monthOfYear = std::move(src); } // by parser/inc/cronline crondata.setdayofweek.cc inline void CronEntry::setDayOfWeek(SizeSet &&src) { d_dayOfWeek = std::move(src); } // cron/execute.cc inline size_t CronEntry::nSettings() const { return d_end; } // cron/execute.cc inline std::string const &CronEntry::command() const { return d_command; } // cron/call.cc inline CronEntry::SizeSet const &CronEntry::minutes() const { return d_minutes; } // cron/call.cc inline CronEntry::SizeSet const &CronEntry::hours() const { return d_hours; } // cron/call.cc inline CronEntry::SizeSet const &CronEntry::dayOfMonth() const { return d_dayOfMonth; } // cron/call.cc inline CronEntry::SizeSet const &CronEntry::monthOfYear() const { return d_monthOfYear; } // cron/call.cc inline CronEntry::SizeSet const &CronEntry::dayOfWeek() const { return d_dayOfWeek; } ssh-cron-2.00.00/cronentry/operatorinsert.cc0000664000175000017500000000112215005102626017776 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-2.00.00/cronentry/showset.cc0000664000175000017500000000052415005102626016417 0ustar frankfrank#include "cronentry.ih" // by insert.cc void CronEntry::showSet(ostream &out, SizeSet 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-2.00.00/cronentry/frame0000664000175000017500000000005115005102626015424 0ustar frankfrank#include "cronentry.ih" CronEntry:: { } ssh-cron-2.00.00/cronentry/cronentry.ih0000664000175000017500000000010215005102626016751 0ustar frankfrank#include "cronentry.h" #include using namespace std; ssh-cron-2.00.00/crontab0000664000175000017500000000032415005102626013742 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-2.00.00/documentation/0000775000175000017500000000000015005102626015241 5ustar frankfrankssh-cron-2.00.00/documentation/man/0000775000175000017500000000000015005102626016014 5ustar frankfrankssh-cron-2.00.00/documentation/man/ssh-cron.yo0000664000175000017500000003014515005102626020124 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 passphrases. 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 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. 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 a specified 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 in 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 or listing a running s() program's tt(crontab) file. 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@c-plusplus.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(forground) nl() s() is not run as a daemon. To properly end s() when it's not running as a daemon, execute s() bf(--terminate) in a separate process or end it using tt(ctrl-C) or by sending the process a tt(SIGTERM) signal. This option cannot be specified in the configuration file. it() loption(help) (soption(h))nl() s() ends after writing basic usage information to the standard output stream. This option cannot be specified in the configuration file. 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 tt(--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 first created. 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(reload) (soption(r))nl() reload the running s() program with de cron-commands defined in the tt(crontab-file) argument (which must be provided). This option is incompatible with tt(--list) 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/or writing 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() use this option to send messages to the syslog daemon. By default syslog messages are written to the syslog's tt(DAEMON) facility with priority tt(NOTICE). it() laoption(syslog-facility)(facility)nl() the syslog facility used when writing messages to the syslog daemon. 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 syslog priority used when writing messages to the syslog daemon. 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 simplifies locating them in the syslog 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. The tt(crontab-file) argument must be omitted. This option is incompatible tt with the (--list) and tt(--reload) options. This option cannot be specified in the configuration file. it() lsoption(uds)(u)(path)nl() when s() runs as a daemon or in the foreground, then tt(path) specifies the location of its tt(Unix) domain socket. When s() is called with the options tt(--list, --reload), or tt(--terminate) then it uses the tt(uds) file to communicate with the running s() proram. When the running s() program ends it removes the tt(uds) file. If the tt(uds) file couldn't be removed (e.g., s() received a tt(SIGKILL) signal) then the tt(uds) file must be removed `by hand' before s() can start again. By default tt(~/.ssh-cron.uds) is used. 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 results in writing all messages having the tt(SSH-CRON:) tag to be written on tt(/var/log/ssh-cron.log). 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) University of Groningen. manpageauthor() Frank B. Brokken (bf(f.b.brokken@rug.nl)). ssh-cron-2.00.00/handle.cc0000664000175000017500000000071715005102626014137 0ustar frankfrank#include "main.ih" int handle(exception_ptr ptr) try { rethrow_exception(ptr); } catch (int ret) // handle the known exceptions { return ArgConfig::instance().option("hv") ? 0 : ret; } catch (exception const &exc) { if (exc.what() != to_string(fmsg.id())) cerr << exc.what() << endl; return 1; } catch (...) // and handle an unexpected exception { cerr << "unexpected exception\n"; return 1; } ssh-cron-2.00.00/icmake/0000775000175000017500000000000015005102626013621 5ustar frankfrankssh-cron-2.00.00/icmake/setopt0000664000175000017500000000034115005102626015060 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-2.00.00/icmake/manpage0000664000175000017500000000054515005102626015160 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-2.00.00/icmake/findall0000664000175000017500000000117315005102626015157 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-2.00.00/icmake/log0000775000175000017500000000063215005102626014331 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-2.00.00/icmake/pathfile0000664000175000017500000000055215005102626015342 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-2.00.00/icmake/clean0000664000175000017500000000044315005102626014627 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-2.00.00/icmake/uninstall0000664000175000017500000000045615005102626015562 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-2.00.00/icmake/cuteoln0000664000175000017500000000023415005102626015214 0ustar frankfrankstring cutEoln(string text) { int len; len = strlen(text) - 1; if (text[len] == "\n") text = substr(text, 0, len); return text; } ssh-cron-2.00.00/icmake/run0000664000175000017500000000033015005102626014344 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-2.00.00/icmake/md0000664000175000017500000000074015005102626014145 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-2.00.00/icmake/gitlab0000664000175000017500000000022315005102626015003 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-2.00.00/icmake/remove0000775000175000017500000000117015005102626015043 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-2.00.00/icmake/backtick0000664000175000017500000000016015005102626015314 0ustar frankfranklist backtick(string arg) { list ret; echo(OFF); ret = `arg`; echo(g_echo); return ret; } ssh-cron-2.00.00/icmake/install0000664000175000017500000000335315005102626015216 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-2.00.00/icmake/logfile0000664000175000017500000000025715005102626015171 0ustar frankfrankvoid logFile(string srcdir, string src, string destdir, string dest) { chdir(g_cwd); md(destdir); run("cp " + srcdir + "/" + src + " " + destdir + "/" + dest); } ssh-cron-2.00.00/icmake/loginstall0000664000175000017500000000213215005102626015712 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-2.00.00/icmake/special0000664000175000017500000000034115005102626015162 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-2.00.00/icmake/logzip0000664000175000017500000000165615005102626015060 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-2.00.00/icmconf0000664000175000017500000000105315005416170013732 0ustar frankfrank#include "INSTALL.im" #define MULTICOMP "jobs -q" #define SPCH "-q -o " ${NOCOLORS} #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-2.00.00/icmconf.lib0000664000175000017500000000065115005102626014500 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 "-Wall -O2 -fdiagnostics-color=never " #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define DEFCOM "library" ssh-cron-2.00.00/input0000664000175000017500000000053015005102626013450 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-2.00.00/INSTALL0000664000175000017500000000751715005102626013433 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-2.00.00/INSTALL.im0000664000175000017500000000261615005150246014033 0ustar frankfrank // The name of the project: #define PROJECT "ssh-cron" #define NOCOLORS "-fdiagnostics-color=never" // 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 " ${NOCOLORS} // 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-2.00.00/main.cc0000664000175000017500000000311115005102626013617 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("config", 'c'), Arg::LongOption("foreground", Arg::NoArg), Arg::LongOption("help", 'h'), Arg::LongOption("list", 'l'), Arg::LongOption("reload", 'r'), Arg::LongOption("stdout", 's'), Arg::LongOption("terminate", 't'), Arg::LongOption("version", 'v'), // all options below are also interpreted when specified by // the config file Arg::LongOption("agent", Arg::Required), 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("uds", 'u'), Arg::LongOption("verbose", 'V'), }; auto longEnd = longOptions + size(longOptions); } int main(int argc, char **argv) try { ArgConfig &arg = ArgConfig::initialize("c:hi:lL:m:rstu:vV", longOptions, longEnd, argc, argv); arg.versionHelp(usage, Icmbuild::version, 0); SSHCron sshcron; sshcron.run(); } catch (...) { return handle(current_exception()); } ssh-cron-2.00.00/main.ih0000664000175000017500000000044515005102626013641 0ustar frankfrank#include #include #include #include #include "version/version.h" #include "options/options.h" #include "sshcron/sshcron.h" using namespace std; using namespace FBB; int handle(exception_ptr ptr); void usage(string const &progname); ssh-cron-2.00.00/options/0000775000175000017500000000000015005657715014101 5ustar frankfrankssh-cron-2.00.00/options/syslogfacility.cc0000664000175000017500000000102415005102626017434 0ustar frankfrank#include "options.ih" // by setsyslog.cc Facility Options::syslogFacility() const { Facility facility; string option; if (not d_arg.option(&option, "syslog-facility")) facility = s_defaultSyslogFacility; else { FacilityMap::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-2.00.00/options/loadconfigfile.cc0000664000175000017500000000100715005102626017335 0ustar frankfrank#include "options.ih" // by options1.cc void Options::loadConfigFile() { string configFile; // long options, default ~/.ssh-cron if (not d_arg.option(&configFile, 'c')) { configFile = User().homedir() + s_defaultConfigFile; if (not FileSystem{ configFile }.exists() ) configFile.clear(); } if (not configFile.empty()) d_arg.open(configFile); // read the arg config file, which is also // the cron-file } ssh-cron-2.00.00/options/instance.cc0000664000175000017500000000033015005657245016206 0ustar frankfrank#include "options.ih" // by daemon/daemon1.cc, cron/cron1.cc, crondata/crondata1.cc Options &Options::instance() { if (s_options.get() == 0) s_options.reset(new Options()); return *s_options; } ssh-cron-2.00.00/options/data.cc0000664000175000017500000000243215005657700015314 0ustar frankfrank#include "options.ih" unique_ptr Options::s_options; char const Options::s_defaultAgent[] = "/usr/bin/ssh-agent /bin/bash"; char const Options::s_defaultUDS[] = ".ssh-cron.uds"; 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; Options::FacilityMap 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} }; Options::PriorityMap 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-2.00.00/options/options1.cc0000664000175000017500000000371115005102626016150 0ustar frankfrank#define XERR "options" #include "options.ih" // by instance.cc 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 ) { d_arg.help(); throw 1; } d_foreground = d_arg.option(0, "foreground"); if ((d_list = d_arg.option('l'))) d_udsReq = LIST; if ((d_reload = d_arg.option('r'))) d_udsReq = RELOAD; if ((d_terminate = d_arg.option('t'))) d_udsReq = TERMINATE; 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_uds, 'u')) d_uds = User().homedir() + s_defaultUDS; checkAction(); // check for incompatible options 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')) // empty argument: no mail d_mailer = s_defaultMailer; // (cf. cron/definerun.cc) bool useSyslog = setSyslog(); if (not d_arg.option('V')) // 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; if (d_arg.nArgs() > 0) d_cronFile = FileSystem{ d_arg[0] }.canonical().string(); } ssh-cron-2.00.00/options/setsyslog.cc0000664000175000017500000000053115005102626016425 0ustar frankfrank#include "options.ih" // by options1.cc 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-2.00.00/options/checkaction.cc0000664000175000017500000000172315005102626016650 0ustar frankfrank#include "options.ih" // by options1.cc 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 << " --foreground"; fmsg << noid; } // if no argument then --list or --terminate are required if (d_arg.nArgs() == 0) { if (not (d_list || d_terminate)) fmsg << "crontab file required" << noid; } else if (d_list || d_terminate) // --list and --terminate cannot accept a crontab file fmsg << "crontab file incompatible with --list and --terminate" << noid; } ssh-cron-2.00.00/options/icmconf0000664000175000017500000000007615005102626015427 0ustar frankfrank#define LIBRARY "options" #include "../icmconf.lib" ssh-cron-2.00.00/options/options.h0000664000175000017500000000664515005657122015750 0ustar frankfrank#ifndef INCLUDED_OPTIONS_ #define INCLUDED_OPTIONS_ #include #include #include #include #include #include #include "../udsreq/udsreq.h" namespace FBB { class SyslogStream; } class Options: public UDSReq { using FacilityMap = std::unordered_map; using PriorityMap = std::unordered_map; FBB::ArgConfig &d_arg; std::unique_ptr d_syslog; FBB::Log d_log; FBB::MultiBuf d_multiBuf; std::string d_cronFile; // canonical d_arg[0] std::ostream d_msg; // d_msg handles all messages to // syslog and/or d_log std::string d_agent; std::string d_mailer; std::string d_uds; // e.g., ~/.ssh-cron.uds FacilityMap::const_iterator d_syslogFacility; PriorityMap::const_iterator d_syslogPriority; bool d_foreground; bool d_list; bool d_reload; bool d_terminate; Req d_udsReq; // requests received via the UDS static std::unique_ptr 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_defaultUDS[]; static char const s_defaultSyslogIdent[]; static char const s_defaultMailer[]; static FacilityMap const s_syslogFacilities; static PriorityMap const s_syslogPriorities; public: static Options &instance(); Options(Options const &other) = delete; size_t nArgs() const; // .f char const *arg(size_t idx) const; // .f std::string const &cronFile() const; // .f bool foreground() const; // .f bool daemon() const; // .f bool cronCmd() const; // e.g., --list, --terminate // .f bool reload() const; // .f std::string const &basename() const; // .f std::string const &mailer() const; std::ostream &msg(); // .f std::string const &uds() const; // .f Req request() const; // .f static char const *defaultAgent(); // .f static char const *defaultConfigFile(); // .f static char const *defaultMailer(); // .f static char const *defaultSyslogIdent(); // .f static FBB::Facility defaultSyslogFacility(); // .f static FBB::Priority defaultSyslogPriority(); // .f static char const *defaultUDS(); // .f private: Options(); bool setSyslog(); void checkAction() const; void loadConfigFile(); std::string syslogTag() const; FBB::Priority syslogPriority() const; FBB::Facility syslogFacility() const; }; #include "options.f" #endif ssh-cron-2.00.00/options/options.ih0000664000175000017500000000036315005102626016102 0ustar frankfrank#include "options.h" #include "../xerr/xerr.ih" #include #include #include #include #include #include "../version/version.h" using namespace std; using namespace FBB; ssh-cron-2.00.00/options/options.f0000664000175000017500000000370715005102626015734 0ustar frankfrank // by sshcron/reload.cc inline char const *Options::arg(size_t idx) const { return d_arg[idx]; } // by daemon/basename.cc, daemon/idmsg.cc, crondata/addcroncommand.cc, // crondata/setenvvar.cc, options/options1.cc inline std::string const &Options::basename() const { return d_arg.basename(); } // by daemon/run.cc inline bool Options::cronCmd() const { return d_list || d_terminate || d_reload; } inline std::string const &Options::cronFile() const { return d_cronFile; } // by daemon/childprocess.cc, cron/parentprocess.cc inline bool Options::daemon() const { return not d_foreground; } // static inline char const *Options::defaultAgent() { return s_defaultAgent; } // static inline char const *Options::defaultConfigFile() { return s_defaultConfigFile; } // static inline char const *Options::defaultMailer() { return s_defaultMailer; } // static inline char const *Options::defaultSyslogIdent() { return s_defaultSyslogIdent; } // static inline FBB::Facility Options::defaultSyslogFacility() { return s_defaultSyslogFacility; } // static inline FBB::Priority Options::defaultSyslogPriority() { return s_defaultSyslogPriority; } // static inline char const *Options::defaultUDS() { return s_defaultUDS; } // by daemon.run.cc inline bool Options::foreground() const { return d_foreground; } // by cron/definerunfunction.cc inline std::string const &Options::mailer() const { return d_mailer; } // by X inline std::ostream &Options::msg() { return d_msg; } // by daemon/daemon1.cc inline size_t Options::nArgs() const { return d_arg.nArgs(); } // by crondata/crondata1.cc inline bool Options::reload() const { return d_reload; } // by sshcron/tocron.cc inline Options::Req Options::request() const { return d_udsReq; } // by sshcron/tocron.cc cron/ inline std::string const &Options::uds() const { return d_uds; } ssh-cron-2.00.00/options/syslogpriority.cc0000664000175000017500000000102415005102626017511 0ustar frankfrank#include "options.ih" // by setsyslog.cc Priority Options::syslogPriority() const { Priority priority; string option; if (not d_arg.option(&option, "syslog-priority")) priority = s_defaultSyslogPriority; else { PriorityMap::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-2.00.00/options/frame0000664000175000017500000000004515005102626015077 0ustar frankfrank#include "options.ih" Options:: { } ssh-cron-2.00.00/options/syslogtag.cc0000664000175000017500000000030715005102626016406 0ustar frankfrank#include "options.ih" // by setsyslog.cc string Options::syslogTag() const { string tag; if (not d_arg.option(&tag, "syslog-tag")) tag = s_defaultSyslogIdent; return tag; } ssh-cron-2.00.00/parser/0000775000175000017500000000000015005657715013702 5ustar frankfrankssh-cron-2.00.00/parser/parser.h0000664000175000017500000000174215005102626015335 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 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-2.00.00/parser/parser1.cc0000664000175000017500000000016715005102626015554 0ustar frankfrank#include "parser.ih" Parser::Parser(istream &in, CronData &cronData) : d_cronData(cronData), d_scanner(in) {} ssh-cron-2.00.00/parser/error.cc0000664000175000017500000000020515005102626015321 0ustar frankfrank#include "parser.ih" void Parser::error() { // emsg << "Syntax error at line " << d_cronData.lineNr() << // endl; } ssh-cron-2.00.00/parser/parse.cc0000664000175000017500000010615515005102626015315 0ustar frankfrank// Generated by Bisonc++ V6.09.01 on Wed, 16 Apr 2025 12:02:15 +0200 // 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", "EndPolyType_" }; 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_ = d_token >= 0 ? std::move(d_next.second) : STYPE_{}; 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-2.00.00/parser/parserpre.ih0000664000175000017500000000004315005102626016206 0ustar frankfrank#include #include ssh-cron-2.00.00/parser/parser.ih0000664000175000017500000000124615005102626015505 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-2.00.00/parser/icmconf0000664000175000017500000000007515005102626015227 0ustar frankfrank#define LIBRARY "parser" #include "../icmconf.lib" ssh-cron-2.00.00/parser/inc/0000775000175000017500000000000015005102626014435 5ustar frankfrankssh-cron-2.00.00/parser/inc/ws0000664000175000017500000000004115005102626015004 0ustar frankfrankopt_ws: WS | // empty ; ssh-cron-2.00.00/parser/inc/line0000664000175000017500000000052315005102626015307 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-2.00.00/parser/inc/cronline0000664000175000017500000000120715005102626016171 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-2.00.00/parser/inc/time0000664000175000017500000000071015005102626015314 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-2.00.00/parser/inc/nr0000664000175000017500000000061015005102626014774 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-2.00.00/parser/inc/nameline0000664000175000017500000000055715005102626016157 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-2.00.00/parser/inc/token0000664000175000017500000000104715005102626015502 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-2.00.00/parser/grammar0000664000175000017500000000100415005102626015230 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-2.00.00/parser/frame0000664000175000017500000000004315005102626014676 0ustar frankfrank#include "parser.ih" Parser:: { } ssh-cron-2.00.00/parser/parserbase.h0000664000175000017500000002564315005102626016176 0ustar frankfrank// Generated by Bisonc++ V6.09.01 on Wed, 16 Apr 2025 12:02:15 +0200 // 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, END_TAG_ }; class EndPolyType_ {}; namespace Meta_ { extern size_t const *t_nErrors; extern size_t const *s_nErrors_; template struct TagOf; template struct TypeOf; // $insert polymorphicSpecializations extern char const *idOfTag_[]; template <> struct TagOf { static Tag_ const tag = Tag_::INT; }; template <> struct TagOf { static Tag_ const tag = Tag_::STRING; }; template <> struct TagOf { static Tag_ const tag = Tag_::END_TAG_; }; template <> struct TypeOf { using type = int; }; template <> struct TypeOf { using type = std::string; }; template <> struct TypeOf { using type = EndPolyType_; }; // 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 { using BasePtr = std::unique_ptr; public: SType(); 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); SType &operator=(EndPolyType_ const &value); SType &operator=(EndPolyType_ &&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; }; inline SType::SType() : std::unique_ptr(new Semantic{}) {} inline SType::SType(SType const &other) : BasePtr{ other->clone() } {} inline SType::SType(SType &&tmp) : BasePtr{ std::move(tmp) } { tmp = SType{}; // tmp remains valid } 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; } inline SType &SType::operator=(EndPolyType_ const &value) { assign< Tag_::END_TAG_ >(value); return *this; } inline SType &SType::operator=(EndPolyType_ &&tmp) { assign< Tag_::END_TAG_ >(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 (*this)->tag(); } } // namespace Meta_ // $insert parserbase class ParserBase: public Tokens { public: enum DebugMode_ { OFF = 0, ON = 1 << 0, ACTIONCASES = 1 << 1 }; // $insert tokens // $insert STYPE using STYPE_ = Meta_::SType; private: // state semval using StatePair = std::pair; // token semval using TokenPair = std::pair; 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-2.00.00/precomp0000664000175000017500000000006015005353356013764 0ustar frankfrankg++ -c -o $2 ${ICMAKE_CPPSTD} -O2 -x c++-header ssh-cron-2.00.00/README0000664000175000017500000000265115005102626013254 0ustar frankfrankWelcome to SSH-CRON. 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 15.0.1 or more recent) and you need the Bobcat library (available at Gitlab 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-2.00.00/scanner/0000775000175000017500000000000015005657715014037 5ustar frankfrankssh-cron-2.00.00/scanner/lex.cc0000664000175000017500000003571015005102626015126 0ustar frankfrank// Generated by Flexc++ V2.17.01 on Wed, 16 Apr 2025 11:56:10 +0200 #include #include #include #include #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, bool keepCwd) : d_out(new std::ostream(out.rdbuf())), // $insert interactiveInit d_in(0), d_dfaBase_(s_dfa_) { if (keepCwd) d_cwd = std::filesystem::current_path().string(); p_pushStream(s_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, bool keepCwd) : d_out(outfilename == "-" ? new std::ostream(std::cout.rdbuf()) : outfilename == "" ? new std::ostream(std::cerr.rdbuf()) : new std::ofstream(outfilename)), d_dfaBase_(s_dfa_) { if (keepCwd) d_cwd = std::filesystem::current_path().string(); p_pushStream(infilename, { new std::ifstream(infilename) }); toCwd(); } 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; std::ifstream *ptr = new std::ifstream(infilename); d_streamStack.back() = StreamStruct{ chgWorkingDir(d_filename), { ptr } }; 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); } void ScannerBase::toCwd() const { using namespace std; using namespace filesystem; if (d_cwd.empty()) return; error_code ec; current_path(d_cwd, ec); } // static std::string ScannerBase::chgWorkingDir(std::string const &name) // any name { using namespace std; using namespace filesystem; if (name == s_istream) // used with istreams return name; // a filename: get its auto path = absolute(name); // full pathname error_code ec; 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{chgWorkingDir(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{ chgWorkingDir(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); // size check needed since g++-15 d_atBOL = d_matched.size() > 0 and 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(); toCwd(); 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); toCwd(); return 0; } postCode(PostEnum_::POP); continue; } // switch postCode(PostEnum_::WIP); reset_(); preCode(); } // while } void ScannerBase::print_() const { } ssh-cron-2.00.00/scanner/scanner.ih0000664000175000017500000000010315005102626015766 0ustar frankfrank#include "scanner.h" #include "tokens.h" // end of scanner.ih ssh-cron-2.00.00/scanner/scanner.h0000664000175000017500000000305015005102626015621 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-2.00.00/scanner/icmconf0000664000175000017500000000007615005102626015365 0ustar frankfrank#define LIBRARY "scanner" #include "../icmconf.lib" ssh-cron-2.00.00/scanner/tokens.h0000664000175000017500000000027515005102626015501 0ustar frankfrank#ifndef INCLUDED_TOKENS_ #define INCLUDED_TOKENS_ struct Tokens { // Symbolic tokens: enum Tokens_ { WS = 257, NR, ID, CHAR, }; }; #endif ssh-cron-2.00.00/scanner/main.cc0000664000175000017500000000061015005102626015251 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-2.00.00/scanner/lexer0000664000175000017500000000065415005102626015070 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-2.00.00/scanner/scannerbase.h0000664000175000017500000003030715005102626016461 0ustar frankfrank// Generated by Flexc++ V2.17.01 on Wed, 16 Apr 2025 11:56:10 +0200 #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) using VectorInt = std::vector; static size_t const s_unavailable = std::numeric_limits::max(); static constexpr char const s_istream[] = "(istream)"; 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; size_t nPending() const; void setPending(size_t size); void close(); // force closing the stream private: size_t next(); // obtain the next character }; protected: struct StreamStruct { std::string pushedName; Input input; }; private: std::string d_cwd; 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 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; // $insert inputDeclaration Input *d_input; // input now in d_streamStack 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; bool debug() const; std::string const &filename() const; std::string const &cwd() 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, bool keepCwd = true); ScannerBase(std::string const &infilename, std::string const &outfilename, bool keepCwd = true); ~ScannerBase(); bool popStream(); std::ostream &out(); void echo() const; void leave(int retValue) const; void toCwd() 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 chgWorkingDir(std::string const &filename); template static ReturnType constexpr as(ArgType value); static bool constexpr available(size_t value); }; // $insert inputInline inline size_t ScannerBase::Input::lineNr() const { return d_lineNr; } inline size_t ScannerBase::Input::nPending() const { return d_deque.size(); } inline void ScannerBase::Input::setPending(size_t size) { d_deque.erase(d_deque.begin(), d_deque.end() - size); } inline void ScannerBase::Input::close() { delete d_in; d_in = 0; // switchStreams also closes } 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::cwd() const { return d_cwd; } 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-2.00.00/scanner/frame0000664000175000017500000000004515005102626015035 0ustar frankfrank#include "scanner.ih" Scanner:: { } ssh-cron-2.00.00/spch20000664000175000017500000000037715005362760013350 0ustar frankfrank#include "main.ih" #include "sshcron/sshcron.ih" #include "cron/cron.ih" #include "parser/parser.ih" #include "scanner/scanner.ih" #include "crondata/crondata.ih" #include "cronentry/cronentry.ih" #include "options/options.ih" #include "udsreq/udsreq.ih" ssh-cron-2.00.00/sshcron/0000775000175000017500000000000015005657715014065 5ustar frankfrankssh-cron-2.00.00/sshcron/parentprocess.cc0000664000175000017500000000032415005102626017245 0ustar frankfrank#define XERR "sshcron" #include "sshcron.ih" // by Fork // overrides void SSHCron::parentProcess() { // ssh-cron runs as daemon. The child process does prepareDaemon or runs // in the foreground. } ssh-cron-2.00.00/sshcron/tocron.cc0000664000175000017500000000123215005102626015660 0ustar frankfrank#define XERR "sshcron" #include "sshcron.ih" // by run.cc void SSHCron::toCron() { d_client.open(d_options.uds()); int fd = d_client.connect(); d_in.reset(new IFdStream{ fd }); // cf. cron/parentprocess.cc d_out.reset(new OFdStream{ fd }); switch (d_options.request()) { case TERMINATE: terminate(); // stops the daemon break; case LIST: // show the active cron-requests list(); break; case RELOAD: reload(); break; case ERROR: // not via d_options break; } } ssh-cron-2.00.00/sshcron/terminate.cc0000664000175000017500000000034215005102626016345 0ustar frankfrank#define XERR "sshcron" #include "sshcron.ih" // by tocron.cc void SSHCron::terminate() { *d_out << name(TERMINATE) << endl; int pid; *d_in >> pid; idmsg() << "terminated process " << pid << endl; } ssh-cron-2.00.00/sshcron/getpassphrase.cc0000664000175000017500000000142615005102626017232 0ustar frankfrank#define XERR "sshcron" #include "sshcron.ih" // the passphrase // by run.cc void SSHCron::getPassphrase() { Tty tty; tty.echo(Tty::OFF); ifstream in; Exception::open(in, "/dev/tty"); while (true) { cout << "Enter passphrase: " << flush; getline(in, d_passphrase); if (d_passphrase.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 (d_passphrase == passphrase2) break; cout << "Passphrases differ. Try again\n\n"; } tty.echo(Tty::ON); } ssh-cron-2.00.00/sshcron/list.cc0000664000175000017500000000121215005102626015325 0ustar frankfrank#define XERR "sshcron" #include "sshcron.ih" // by tocron.cc void SSHCron::list() { askPassphrase(); // in d_passphrase *d_out << name(LIST) << '\n' << // send the command d_passphrase << endl; string line; getline(*d_in, line); // get the (N)OK reply if (line == "NOK") { emsg << "invalid passphrase" << endl; return; } idmsg() << "--list requested" << endl; cout << '\n'; while (true) { getline(*d_in, line); if (line == "LIST") break; cout << line << '\n'; } cout << endl; } ssh-cron-2.00.00/sshcron/foreground.cc0000664000175000017500000000027515005102626016534 0ustar frankfrank//#define XERR "sshcron" #include "sshcron.ih" // by run.cc void SSHCron::foreground() { idmsg() << "running in the foreground: pid = " << getpid() << endl; childProcess(); } ssh-cron-2.00.00/sshcron/run.cc0000664000175000017500000000072515005102626015166 0ustar frankfrank#define XERR "sshcron" #include "sshcron.ih" // by ./main.cc void SSHCron::run() { if (d_options.cronCmd()) // list, reload, terminate: toCron(); // handles commands to the daemon else { getPassphrase(); if (d_options.foreground()) foreground(); // calls Cron::childProcess else daemon(); // Cron runs as daemon } } ssh-cron-2.00.00/sshcron/reload.cc0000664000175000017500000000127415005102626015630 0ustar frankfrank#define XERR "sshcron" #include "sshcron.ih" // by tocron.cc void SSHCron::reload() { char const *cronFile = d_options.arg(0); if (not FileSystem{ cronFile }.exists()) { emsg << '`' << cronFile << "': not found" << endl; return; } askPassphrase(); // in d_passphrase *d_out << name(RELOAD) << '\n' << d_passphrase << '\n' << cronFile << endl; string line; getline(*d_in, line); if (line == "NOK") emsg << "invalid passphrase" << endl; else if (line != "OK") emsg << line << endl; else idmsg() << "reloaded crontab file `" << cronFile << '\'' << endl; } ssh-cron-2.00.00/sshcron/sshcron.h0000664000175000017500000000215015005102626015675 0ustar frankfrank#ifndef INCLUDED_SSHCRON_ #define INCLUDED_SSHCRON_ #include #include #include #include "../udsreq/udsreq.h" namespace FBB { class IFdStream; class OFdStream; } class Options; class SSHCron: public FBB::Fork, private UDSReq { Options &d_options; FBB::LocalClientSocket d_client; std::string d_passphrase; std::unique_ptr d_in; std::unique_ptr d_out; public: SSHCron(); ~SSHCron() override; void run(); private: void childProcess() override; void parentProcess() override; void askPassphrase(); std::ostream &basename() const; // options.msg() inserts basename : void toCron(); // commands to the child, e.g., --list void daemon(); // run the daemon in the background void foreground(); void getPassphrase(); std::ostream &idmsg() const; // imsg inserts "'basename' : " void list(); void reload(); void terminate(); }; #endif ssh-cron-2.00.00/sshcron/childprocess.cc0000664000175000017500000000125615005102626017044 0ustar frankfrank#define XERR "sshcron" #include "sshcron.ih" // ssh-cron, when run in the foreground, acts like when running as daemon. // e.g., send it signals via another ssh-cron process using options like // --list (cf. request.cc). // by Fork, run.cc void SSHCron::childProcess() { if (not d_options.foreground()) prepareDaemon(); // Fork member else cout << "Issue a --terminate command using a separate `" << d_options.basename() << "' process" << endl; Cron cron{ d_passphrase }; d_passphrase = string{}; cron.fork(); throw 0; // correctly end the child process at main } ssh-cron-2.00.00/sshcron/sshcron.ih0000664000175000017500000000055615005102626016056 0ustar frankfrank#include "sshcron.h" #include "../xerr/xerr.ih" #include #include #include #include #include #include #include #include #include "../options/options.h" #include "../cron/cron.h" using namespace std; using namespace FBB; ssh-cron-2.00.00/sshcron/daemon.cc0000664000175000017500000000043015005102626015616 0ustar frankfrank//#define XERR "sshcron" #include "sshcron.ih" // by run.cc void SSHCron::daemon() { idmsg() << "starting the daemon" << endl; fork(); // SSHCron continues as daemon: // parentProcess ends SSHCron } ssh-cron-2.00.00/sshcron/icmconf0000664000175000017500000000007615005102626015413 0ustar frankfrank#define LIBRARY "sshcron" #include "../icmconf.lib" ssh-cron-2.00.00/sshcron/sshcron1.cc0000664000175000017500000000020115005102626016107 0ustar frankfrank//#define XERR "sshcron" #include "sshcron.ih" // by ./main.cc SSHCron::SSHCron() : d_options(Options::instance()) {} ssh-cron-2.00.00/sshcron/basename.cc0000664000175000017500000000024415005102626016131 0ustar frankfrank#include "sshcron.ih" // by list.cc reload.cc terminate.cc ostream &SSHCron::basename() const { return d_options.msg() << d_options.basename() << ": "; } ssh-cron-2.00.00/sshcron/destructor.cc0000664000175000017500000000013415005102626016552 0ustar frankfrank//#define XERR "sshcron" #include "sshcron.ih" // by ./main.cc SSHCron::~SSHCron() {} ssh-cron-2.00.00/sshcron/idmsg.cc0000664000175000017500000000031515005102626015460 0ustar frankfrank#include "sshcron.ih" // by daemon.cc, childprocess.cc, listrequest.cc, reload.cc, list.cc // terminate.cc ostream &SSHCron::idmsg() const { return imsg << d_options.basename() << ": "; } ssh-cron-2.00.00/sshcron/askpassphrase.cc0000664000175000017500000000045215005102626017227 0ustar frankfrank#include "sshcron.ih" // by list.cc reload.cc void SSHCron::askPassphrase() { Tty tty; tty.echo(Tty::OFF); ifstream in; Exception::open(in, "/dev/tty"); cout << "Enter passphrase: " << flush; getline(in, d_passphrase); // hmac(d_passphrase); cout << endl; } ssh-cron-2.00.00/sshcron/frame0000664000175000017500000000011215005102626015056 0ustar frankfrank//#define XERR "sshcron" #include "sshcron.ih" // by SSHCron:: { } ssh-cron-2.00.00/ssh-cron.xref0000664000175000017500000003727615005102626015031 0ustar frankfrankoxref by Frank B. Brokken (f.b.brokken@rug.nl) oxref V 2.02.00 2012-2024 CREATED Fri, 02 May 2025 08:28:37 +0000 OXREF ARGUMENTS: -fxs tmp/libmodules.a ---------------------------------------------------------------------- CROSS REFERENCE LISTING: add(CronEntry const&, FBB::DateTime const&) Full name: Cron::add(CronEntry const&, FBB::DateTime const&) Source: add.cc Used By: cronjobs.cc: Cron::cronJobs() 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) askPassphrase() Full name: SSHCron::askPassphrase() Source: askpassphrase.cc Used By: list.cc: SSHCron::list() reload.cc: SSHCron::reload() 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() checkAction() const Full name: Options::checkAction() const Source: checkaction.cc Used By: options1.cc: Options::Options() childExec(std::__cxx11::basic_string, std::allocator > const&) Full name: Cron::childExec(std::__cxx11::basic_string, std::allocator > const&) Source: childexec.cc Used By: croncmd.cc: Cron::cronCmd(CronEntry const&) parentprocess.cc: Cron::parentProcess() childProcess() Full name: SSHCron::childProcess() Source: childprocess.cc Used By: destructor.cc: SSHCron::~SSHCron() childProcess() Full name: Cron::childProcess() Source: childprocess.cc Used By: destructor.cc: Cron::~Cron() childRedirections() Full name: Cron::childRedirections() Source: childredirections.cc Used By: destructor.cc: Cron::~Cron() Cron(std::__cxx11::basic_string, std::allocator > const&) Full name: Cron::Cron(std::__cxx11::basic_string, std::allocator > const&) Source: cron1.cc Used By: childprocess.cc: SSHCron::childProcess() cronCmd(CronEntry const&) Full name: Cron::cronCmd(CronEntry const&) Source: croncmd.cc Used By: croncmds.cc: Cron::cronCmds() cronCmds() Full name: Cron::cronCmds() Source: croncmds.cc Used By: parentprocess.cc: Cron::parentProcess() CronData() Full name: CronData::CronData() Source: crondata1.cc Used By: cron1.cc: Cron::Cron(std::__cxx11::basic_string, std::allocator > const&) load.cc: Cron::load(std::__cxx11::basic_string, std::allocator > const&) cronJobs() Full name: Cron::cronJobs() Source: cronjobs.cc Used By: croncmds.cc: Cron::cronCmds() cxx11] Full name: Cron::s_agent[abi:cxx11] Source: data.cc Used By: childprocess.cc: Cron::childProcess() cxx11] Full name: Options::s_syslogFacilities[abi:cxx11] Source: data.cc Used By: syslogfacility.cc: Options::syslogFacility() const cxx11] Full name: Options::s_syslogPriorities[abi:cxx11] Source: data.cc Used By: syslogpriority.cc: Options::syslogPriority() const cxx11]() const Full name: Options::syslogTag[abi:cxx11]() const Source: syslogtag.cc Used By: setsyslog.cc: Options::setSyslog() daemon() Full name: SSHCron::daemon() Source: daemon.cc Used By: run.cc: SSHCron::run() defineRun() Full name: Cron::defineRun() Source: definerun.cc Used By: parentprocess.cc: Cron::parentProcess() error() Full name: Parser::error() Source: error.cc Used By: parse.cc: Parser::errorRecovery_() error() Full name: Cron::error() Source: error.cc Used By: data.cc: GLOBALS data.cc 7data.o find(std::__cxx11::basic_string, std::allocator > const&) Full name: UDSReq::find(std::__cxx11::basic_string, std::allocator > const&) Source: find.cc Used By: request.cc: Cron::request(std::__cxx11::basic_string, std::allocator > const&) foreground() Full name: SSHCron::foreground() Source: foreground.cc Used By: run.cc: SSHCron::run() getPassphrase() Full name: SSHCron::getPassphrase() Source: getpassphrase.cc Used By: run.cc: SSHCron::run() hmac(std::__cxx11::basic_string, std::allocator > const&) Full name: Cron::hmac(std::__cxx11::basic_string, std::allocator > const&) Source: hmac.cc Used By: cron1.cc: Cron::Cron(std::__cxx11::basic_string, std::allocator > const&) verifypassphrase.cc: Cron::verifyPassphrase() idmsg() const Full name: SSHCron::idmsg() const Source: idmsg.cc Used By: daemon.cc: SSHCron::daemon() foreground.cc: SSHCron::foreground() list.cc: SSHCron::list() reload.cc: SSHCron::reload() terminate.cc: SSHCron::terminate() 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 insert(std::ostream&) const Full name: CronData::insert(std::ostream&) const Source: insert.cc Used By: list.cc: Cron::list() instance() Full name: Options::instance() Source: instance.cc Used By: crondata1.cc: CronData::CronData() cron1.cc: Cron::Cron(std::__cxx11::basic_string, std::allocator > const&) sshcron1.cc: SSHCron::SSHCron() lex_() Full name: Scanner::lex_() Source: lex.cc Used By: parse.cc: Parser::nextToken_() list() Full name: Cron::list() Source: list.cc Used By: data.cc: GLOBALS data.cc 7data.o list() Full name: SSHCron::list() Source: list.cc Used By: tocron.cc: SSHCron::toCron() load(std::__cxx11::basic_string, std::allocator > const&) Full name: Cron::load(std::__cxx11::basic_string, std::allocator > const&) Source: load.cc Used By: cron1.cc: Cron::Cron(std::__cxx11::basic_string, std::allocator > const&) reload.cc: Cron::reload() loadConfigFile() Full name: Options::loadConfigFile() Source: loadconfigfile.cc Used By: options1.cc: Options::Options() name(UDSReq::Req) Full name: UDSReq::name(UDSReq::Req) Source: name.cc Used By: list.cc: SSHCron::list() reload.cc: SSHCron::reload() terminate.cc: SSHCron::terminate() operator<<(std::ostream&, CronEntry const&) Full name: operator<<(std::ostream&, CronEntry const&) Source: operatorinsert.cc Used By: addcroncommand.cc: CronData::addCronCommand() 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: SSHCron::parentProcess() Source: parentprocess.cc Used By: destructor.cc: SSHCron::~SSHCron() parentProcess() Full name: Cron::parentProcess() Source: parentprocess.cc Used By: destructor.cc: Cron::~Cron() parse() Full name: Parser::parse() Source: parse.cc Used By: load.cc: Cron::load(std::__cxx11::basic_string, std::allocator > const&) Parser(std::istream&, CronData&) Full name: Parser::Parser(std::istream&, CronData&) Source: parser1.cc Used By: load.cc: Cron::load(std::__cxx11::basic_string, std::allocator > const&) 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) reload() Full name: SSHCron::reload() Source: reload.cc Used By: tocron.cc: SSHCron::toCron() reload() Full name: Cron::reload() Source: reload.cc Used By: data.cc: GLOBALS data.cc 7data.o request(std::__cxx11::basic_string, std::allocator > const&) Full name: Cron::request(std::__cxx11::basic_string, std::allocator > const&) Source: request.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) 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: usage.cc: usage(std::__cxx11::basic_string, std::allocator > const&) options1.cc: Options::Options() s_defaultConfigFile Full name: Options::s_defaultConfigFile Source: data.cc Used By: usage.cc: usage(std::__cxx11::basic_string, std::allocator > const&) loadconfigfile.cc: Options::loadConfigFile() s_defaultMailer Full name: Options::s_defaultMailer Source: data.cc Used By: usage.cc: usage(std::__cxx11::basic_string, std::allocator > const&) options1.cc: Options::Options() s_defaultSyslogFacility Full name: Options::s_defaultSyslogFacility Source: data.cc Used By: usage.cc: usage(std::__cxx11::basic_string, std::allocator > const&) syslogfacility.cc: Options::syslogFacility() const s_defaultSyslogIdent Full name: Options::s_defaultSyslogIdent Source: data.cc Used By: usage.cc: usage(std::__cxx11::basic_string, std::allocator > const&) syslogtag.cc: Options::syslogTag[abi:cxx11]() const s_defaultSyslogPriority Full name: Options::s_defaultSyslogPriority Source: data.cc Used By: usage.cc: usage(std::__cxx11::basic_string, std::allocator > const&) syslogpriority.cc: Options::syslogPriority() const s_defaultUDS Full name: Options::s_defaultUDS Source: data.cc Used By: usage.cc: usage(std::__cxx11::basic_string, std::allocator > const&) options1.cc: Options::Options() s_month Full name: CronData::s_month Source: data.cc Used By: setmonthofyear.cc: CronData::setMonthOfYear() s_options Full name: Options::s_options Source: data.cc Used By: instance.cc: Options::instance() s_request Full name: Cron::s_request Source: data.cc Used By: request.cc: Cron::request(std::__cxx11::basic_string, std::allocator > const&) s_values Full name: CronData::s_values Source: data.cc Used By: assign.cc: CronData::assign() s_vect Full name: UDSReq::s_vect Source: data.cc Used By: find.cc: UDSReq::find(std::__cxx11::basic_string, std::allocator > const&) name.cc: UDSReq::name(UDSReq::Req) ScannerBase(std::istream&, std::ostream&, bool) Full name: ScannerBase::ScannerBase(std::istream&, std::ostream&, bool) Source: lex.cc Used By: parser1.cc: Parser::Parser(std::istream&, CronData&) setAll(unsigned long) Full name: CronData::setAll(unsigned long) Source: setall.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: Cron::signalHandler(unsigned long) Source: signalhandler.cc Used By: destructor.cc: Cron::~Cron() 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() Full name: Cron::terminate() Source: terminate.cc Used By: data.cc: GLOBALS data.cc 7data.o terminate() Full name: SSHCron::terminate() Source: terminate.cc Used By: tocron.cc: SSHCron::toCron() toCron() Full name: SSHCron::toCron() Source: tocron.cc Used By: run.cc: SSHCron::run() verifyPassphrase() Full name: Cron::verifyPassphrase() Source: verifypassphrase.cc Used By: list.cc: Cron::list() reload.cc: Cron::reload() ~Cron() Full name: Cron::~Cron() Source: destructor.cc Used By: childprocess.cc: SSHCron::childProcess() ssh-cron-2.00.00/udsreq/0000775000175000017500000000000015005657715013711 5ustar frankfrankssh-cron-2.00.00/udsreq/find.cc0000664000175000017500000000043015005102626015117 0ustar frankfrank#include "udsreq.ih" UDSReq::Req UDSReq::find(string const &name) { auto iter = find_if(s_vect.begin(), s_vect.end(), [&](Pair const &item) { return name == item.second; } ); return iter == s_vect.end() ? ERROR : iter->first; } ssh-cron-2.00.00/udsreq/data.cc0000664000175000017500000000022415005102626015111 0ustar frankfrank#include "udsreq.ih" UDSReq::Vect UDSReq::s_vect { { LIST, "list" }, { RELOAD, "reload" }, { TERMINATE, "terminate"}, }; ssh-cron-2.00.00/udsreq/udsreq.ih0000664000175000017500000000026315005102626015521 0ustar frankfrank#include "udsreq.h" #include "../xerr/xerr.ih" #include #include #include "../options/options.h" using namespace std; using namespace FBB; ssh-cron-2.00.00/udsreq/classes0000664000175000017500000000000015005102626015241 0ustar frankfrankssh-cron-2.00.00/udsreq/icmconf0000664000175000017500000000007515005102626015236 0ustar frankfrank#define LIBRARY "udsreq" #include "../icmconf.lib" ssh-cron-2.00.00/udsreq/name.cc0000664000175000017500000000041615005102626015123 0ustar frankfrank#include "udsreq.ih" char const *UDSReq::name(Req req) { auto iter = find_if(s_vect.begin(), s_vect.end(), [&](Pair const &item) { return req == item.first; } ); return iter == s_vect.end() ? "error" : iter->second; } ssh-cron-2.00.00/udsreq/udsreq.h0000664000175000017500000000067615005102626015360 0ustar frankfrank#ifndef INCLUDED_UDSREQ_ #define INCLUDED_UDSREQ_ #include #include struct UDSReq { enum Req { ERROR, LIST, RELOAD, TERMINATE }; private: using Pair = std::pair; using Vect = std::vector; static Vect s_vect; public: static char const *name(Req req); static Req find(std::string const &cmd); }; #endif ssh-cron-2.00.00/udsreq/frame0000664000175000017500000000004315005102626014705 0ustar frankfrank#include "udsreq.ih" UDSReq:: { } ssh-cron-2.00.00/usage.cc0000664000175000017500000000670215005102626014010 0ustar frankfrank// usage.cc #include "main.ih" namespace { char const usage1[] = R"( [options] [crontab] Where: [options] - optional arguments (short options between parentheses, option descriptions starting with (C) can only be used on the command-line and are ignored when specified in the configuration file (see also option --config): --agent agent - absolute path to the agent program providing the ssh-keys (default ')"; char const usage2[] = R"(') --config (-c) path - (C) config file containing long option specifications (default `$HOME/)"; char const usage3[] = R"(') --foreground - (C) do not run as a daemon" --help (-h) - (C) provide this help" --list (-l) - list the currently defined cron-commands in the crontab file to the standard output stream --log (-L) path - log messages are appended to `path'. If "path does not exist, it is created --mailer (-m) command - `command' is the command mailing the\n" output of executed commands. Specify command a "" to suppress sending e-mail (default `)"; char const usage4[] = R"(') --reload (-r) - (C) reload a running )"; char const usage5[] = R"( daemon with the specifications in the crontab-file --stdout (-s) - (C) logged messages are also written to stdout (only in combination with --foreground) --syslog - write syslog messages --syslog-facility fac - fac: syslog facility to use (default `)"; char const usage6[] = R"(') --syslog-priority pri - pri: syslog priority to use (default `)"; char const usage7[] = R"(') --syslog-tag id - id: identifier prefixed to syslog messages (default `)"; char const usage8[] = R"(') --terminate (-t) - (C) terminate a running )"; char const usage9[] = R"(program (the `crontab' file is only used to specify options) --uds (-u) path - `path' is the path-name of the unix domain socket (uds) file (default `$HOME/)"; char const usage10[] = R"(') --verbose (-V) - logs additional information. Implies --syslog --version (-v) - (C) show version information and terminate crontab - crontab-like file specifying crontab commands and (optional) environment variable definitions )"; } // namespace // by main/argconfig void usage(std::string const &progname) { cout << "\n" << progname << " by " << Icmbuild::author << "\n" << progname << " V" << Icmbuild::version << " " << Icmbuild::years << "\n" "\n" "Usage: " << progname << usage1 << Options::defaultAgent() << usage2 << Options::defaultConfigFile() << usage3 << Options::defaultMailer() << usage4 << progname << usage5 << Options::defaultSyslogFacility() << usage6 << Options::defaultSyslogPriority() << usage7 << Options::defaultSyslogIdent() << usage8 << progname << usage9 << Options::defaultUDS() << usage10; } ssh-cron-2.00.00/version/0000775000175000017500000000000015005102626014055 5ustar frankfrankssh-cron-2.00.00/version/version.h0000664000175000017500000000034215005102626015712 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-2.00.00/VERSION0000664000175000017500000000015515005102626013441 0ustar frankfrank#define AUTHOR "Frank B. Brokken (f.b.brokken@rug.nl)"; #define VERSION "2.00.00" #define YEARS "2014-2025" ssh-cron-2.00.00/VERSION.h0000664000175000017500000000010415005102626013661 0ustar frankfrank#include "VERSION" SUBST(_CurVers_)(VERSION) SUBST(_CurYrs_)(YEARS) ssh-cron-2.00.00/xerr/0000775000175000017500000000000015005102626013350 5ustar frankfrankssh-cron-2.00.00/xerr/xerr.ih0000664000175000017500000000153615005102626014657 0ustar frankfrank// define XERR to activate the xerr/xerr(2) macros: // xerr(insertion) // inserts the '<<' concatenated elements into std::cerr // preceded by the name of the source file, and ended by '\n' // xerr2(insertion, code) // performs the insertion if X is defined, and (unconditionally) // executes the statement(s) in `code'. `code' must be valid // C(++) code. // #ifdef XERR #include #define xerr(insertion) std::cerr << XERR "/" __FILE__ ": " << \ insertion << '\n' #define xerr2(insertion, code) \ { std::cerr << XERR "/" __FILE__ ": " << insertion << \ '\n'; code; } #else #define xerr(insertion) #define xerr2(insertion, code) code #endif