243 lines
6.1 KiB
C
243 lines
6.1 KiB
C
/*------------------------------------------------------------------------
|
|
S I C S C R O N
|
|
|
|
A cron like command facility for SICS which allows to repeat a command
|
|
at given time intervals.
|
|
|
|
copyright: see copyright.h
|
|
|
|
Mark Koennecke, November 1999
|
|
|
|
modified to give more error output: Mark Koennecke, December 2010
|
|
|
|
added more functionality: list, stop, count
|
|
------------------------------------------------------------------------*/
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <time.h>
|
|
#include "macro.h"
|
|
#include "fortify.h"
|
|
#include "sics.h"
|
|
#include "splitter.h"
|
|
#include "sicscron.h"
|
|
|
|
typedef struct {
|
|
int iInterval;
|
|
time_t tNext;
|
|
char *pCommand;
|
|
SConnection *pCon;
|
|
int iEnd;
|
|
Statistics *stat;
|
|
} Cron, *pCron;
|
|
|
|
typedef enum {cron_list, cron_stop, cron_count} CronFunc;
|
|
|
|
typedef struct {
|
|
SConnection *pCon;
|
|
CronFunc func;
|
|
char *cmd;
|
|
int cnt;
|
|
} CronListData;
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
static void KillCron(void *pData)
|
|
{
|
|
pCron self = (pCron) pData;
|
|
|
|
if (!self) {
|
|
return;
|
|
}
|
|
if (self->pCommand) {
|
|
free(self->pCommand);
|
|
}
|
|
if (self->pCon) {
|
|
SCDeleteConnection(self->pCon);
|
|
}
|
|
if (self->stat) {
|
|
StatisticsKill(self->stat);
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static int CronTask(void *pData)
|
|
{
|
|
Statistics *old;
|
|
pCron self = (pCron) pData;
|
|
int iRet;
|
|
Tcl_Interp *pTcl = pServ->pSics->pTcl;
|
|
time_t now;
|
|
struct tm tm;
|
|
char datim[24];
|
|
|
|
if (!self) {
|
|
return 0;
|
|
}
|
|
|
|
now = time(NULL);
|
|
if (now >= self->tNext) {
|
|
MacroPush(self->pCon);
|
|
old = StatisticsBegin(self->stat);
|
|
iRet = Tcl_Eval(pTcl, self->pCommand);
|
|
StatisticsEnd(old);
|
|
MacroPop();
|
|
if (iRet != TCL_OK) {
|
|
if (strcmp(pTcl->result, "stop") == 0) {
|
|
SCPrintf(self->pCon, eLogError, "sicscron script '%s' stopped", self->pCommand);
|
|
self->iEnd = 0;
|
|
return 0;
|
|
}
|
|
|
|
SCPrintf(self->pCon, eLogError, "ERROR in sicscron script '%s': %s", self->pCommand, pTcl->result);
|
|
}
|
|
if (self->iEnd == 2) { /* dolater command */
|
|
self->iEnd = 0;
|
|
return 0;
|
|
}
|
|
self->tNext += self->iInterval;
|
|
if (now > self->tNext)
|
|
self->tNext = now;
|
|
}
|
|
if (self->iEnd <= 0) {
|
|
tm = *localtime(&now);
|
|
strftime(datim, sizeof datim, "%Y-%m-%d %T", &tm);
|
|
SCPrintf(self->pCon, eLog, "crontask'%s' terminating at %s", self->pCommand, datim);
|
|
}
|
|
return self->iEnd > 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static void CronSignal(void *pData, int iID, void *pSigData)
|
|
{
|
|
pCron self = (pCron) pData;
|
|
int *iInt;
|
|
struct tm tm;
|
|
char datim[24];
|
|
CronListData *data;
|
|
|
|
if (iID == SICSINT) {
|
|
iInt = (int *) pSigData;
|
|
if (*iInt == eEndServer) {
|
|
self->iEnd = 0;
|
|
}
|
|
}
|
|
if (iID == CRONFUNC) {
|
|
data = pSigData;
|
|
switch (data->func) {
|
|
case cron_list:
|
|
tm = *localtime(&self->tNext);
|
|
strftime(datim, sizeof datim, "%Y-%m-%d %T", &tm);
|
|
if (self->iInterval < 0) {
|
|
SCPrintf(data->pCon, eLog, "%s %s", datim, self->pCommand);
|
|
} else {
|
|
SCPrintf(data->pCon, eLog, "%s %8d %s", datim,
|
|
self->iInterval, self->pCommand);
|
|
}
|
|
break;
|
|
case cron_stop:
|
|
if (strcmp(data->cmd, self->pCommand) == 0) {
|
|
self->iEnd = 0;
|
|
data->cnt++;
|
|
}
|
|
break;
|
|
case cron_count:
|
|
if (strcmp(data->cmd, self->pCommand) == 0) {
|
|
data->cnt++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
int MakeCron(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pCron pNew = NULL;
|
|
int iVal, iRet, rights;
|
|
char *cmd;
|
|
CronListData data;
|
|
|
|
/* need user priv. */
|
|
if (!SCMatchRights(pCon, usUser)) {
|
|
return 0;
|
|
}
|
|
|
|
if (argc >= 2 && strcasecmp(argv[1], "list") == 0) {
|
|
data.func = cron_list;
|
|
SCPrintf(pCon, eLog, "Date Time Interval Command");
|
|
data.pCon = pCon;
|
|
TaskSignal(pServ->pTasker, CRONFUNC, &data);
|
|
return 1;
|
|
}
|
|
|
|
if (argc > 2 && strcasecmp(argv[1], "stop") == 0) {
|
|
data.func = cron_stop;
|
|
data.cmd = argv[2];
|
|
data.cnt = 0;
|
|
TaskSignal(pServ->pTasker, CRONFUNC, &data);
|
|
SCPrintf(pCon, eValue, "%d cron jobs stopped", data.cnt);
|
|
return 1;
|
|
}
|
|
|
|
if (argc > 2 && strcasecmp(argv[1], "count") == 0) {
|
|
data.func = cron_count;
|
|
data.cmd = argv[2];
|
|
data.cnt = 0;
|
|
TaskSignal(pServ->pTasker, CRONFUNC, &data);
|
|
SCPrintf(pCon, eValue, "%d", data.cnt);
|
|
return 1;
|
|
}
|
|
|
|
/* enough arguments? */
|
|
if (argc < 3) {
|
|
SCPrintf(pCon, eError, "ERROR: usage: %s <interval> <script>", argv[0]);
|
|
SCPrintf(pCon, eError, "ERROR: %s list", argv[0]);
|
|
SCPrintf(pCon, eError, "ERROR: %s stop <script>", argv[0]);
|
|
SCPrintf(pCon, eError, "ERROR: %s count <script>", argv[0]);
|
|
return 0;
|
|
}
|
|
|
|
/* interpret first argument as interval in seconds */
|
|
iRet = Tcl_GetInt(pSics->pTcl, argv[1], &iVal);
|
|
if (iRet != TCL_OK) {
|
|
SCWrite(pCon, "ERROR: failed to convert interval argument to int",
|
|
eError);
|
|
return 0;
|
|
}
|
|
|
|
/* concatenate the rest to the command */
|
|
cmd = Arg2Tcl(argc - 2, &argv[2], NULL, 0);
|
|
|
|
/* create data structure and install task */
|
|
pNew = (pCron) malloc(sizeof(Cron));
|
|
if (!pNew || !cmd) {
|
|
SCWrite(pCon, "ERROR: out of memory in sicscron", eError);
|
|
return 0;
|
|
}
|
|
pNew->pCon = SCCreateDummyConnection(pSics);
|
|
if (!pNew->pCon) {
|
|
SCWrite(pCon, "ERROR: out of memory in sicscron", eError);
|
|
return 0;
|
|
}
|
|
rights = SCGetRights(pCon);
|
|
if (rights > usMugger) {
|
|
/* transfer the rights to the dummy connection */
|
|
SCSetRights(pNew->pCon, rights);
|
|
}
|
|
pNew->pCommand = cmd;
|
|
pNew->tNext = time(NULL) + iVal;
|
|
if (strcasecmp(argv[0], "dolater") == 0) {
|
|
pNew->iInterval = -1;
|
|
pNew->iEnd = 2;
|
|
} else {
|
|
pNew->iInterval = iVal;
|
|
pNew->iEnd = 1;
|
|
}
|
|
pNew->stat = StatisticsNew(cmd);
|
|
|
|
TaskRegisterN(pServ->pTasker, cmd, CronTask, CronSignal, KillCron, pNew, TASK_PRIO_LOW);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|