/*------------------------------------------------------------------------ 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 ------------------------------------------------------------------------*/ #include #include #include #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 struct { SConnection *pCon; int dolater; } 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; 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) { SCPrintf(self->pCon, eLogError, "ERROR in sicscron script: %s", pTcl->result); } if (self->iEnd == 2) { /* dolater command */ self->iEnd = 0; return 0; } self->tNext += self->iInterval; if (now > self->tNext) self->tNext = now + 1; } 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 == CRONLIST) { data = pSigData; if (self->iEnd == 2 && data->dolater) { tm = *localtime(&self->tNext); strftime(datim, sizeof datim, "%Y-%m-%d %T", &tm); SCPrintf(data->pCon, eLog, "%s %s", datim, self->pCommand); } else if (self->iEnd == 1 && !data->dolater) { tm = *localtime(&self->tNext); strftime(datim, sizeof datim, "%Y-%m-%d %T", &tm); SCPrintf(data->pCon, eLog, "%s %8d %s", datim, self->iInterval, self->pCommand); } } } /*-----------------------------------------------------------------------*/ 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) { if (strcasecmp(argv[0], "dolater") == 0) { data.dolater = 1; SCPrintf(pCon, eError, "Date Time Command"); } else { data.dolater = 0; SCPrintf(pCon, eError, "Date Time Interval Command"); } data.pCon = pCon; TaskSignal(pServ->pTasker, CRONLIST, &data); return 1; } /* enough arguments? */ if (argc < 3) { SCPrintf(pCon, eError, "ERROR: not enough arguments to %s", 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); TaskRegister(pServ->pTasker, CronTask, CronSignal, KillCron, pNew, 1); SCSendOK(pCon); return 1; }