home *** CD-ROM | disk | FTP | other *** search
- /*
- * CyberCron.c
- *
- * Copyright ⌐ 1992 by Christopher A. Wichura (caw@miroc.chi.il.us). All rights
- * reserved.
- */
-
- struct RxsLib *RexxSysBase;
- unsigned long ARexxLibCount = 0;
-
- /*
- * here we have storage for the current crontab file, sendmail command and
- * the name of our log file
- */
-
- UBYTE CronTabName[256];
- UBYTE SendMailCmd[256];
- UBYTE LogFile[256];
-
- /*
- * storage for two large buffers. we reuse these in several different
- * places within CyberCron
- */
-
- UBYTE BigBufOne[BIG_BUF_SIZE];
- UBYTE BigBufTwo[BIG_BUF_SIZE];
-
- /*
- * these are used by the ParseEvent() routine when no priority or stack size
- * is specified.
- */
-
- ULONG DefaultStackSize = 4096;
- BYTE DefaultPriority = 0;
-
- /*
- * this global is the list header for all cybernodes. we tell who added the
- * event (crontab or via a rexx command) by whether or not the CNB_CRONTAB
- * bit is set in the cn_Flags field.
- */
-
- struct List EventList;
-
- #define CYBERCRON GetString(&LocaleInfo, MSG_PROGNAME)
-
- #define ARG_TEMPLATE "CRONTAB/K,LOGFILE/K,SENDMAIL/K,DEFSTACK/K/N,DEFPRI/K/N,TOOLPRI=CRONPRI/K/N,PORTNAME/K"
- enum CmdlineReadArgs {
- ARG_CRONTAB,
- ARG_LOGFILE,
- ARG_SENDMAIL,
- ARG_STACK,
- ARG_PRI,
- ARG_CPRI,
- ARG_PORTNAME,
- ARG_sizeof
- };
-
- /* extern references to our version and revision numbers */
-
- extern ULONG __far Version;
- extern ULONG __far Revision;
- extern UBYTE __far VersionID[];
-
- /* storage for the pointer to StdErr */
-
- BPTR StdErr = NULL;
-
- /* our old task priority */
-
- WORD OldPriority = -1;
-
- /* for our main ReadArgs call so we can free it later */
-
- struct RDArgs *MyArgs = NULL;
- struct RDArgs *ArgsPtr = NULL;
- STRPTR WBArgs = NULL;
-
- /* stuff used in launching/destroying jobs */
-
- struct MyPublicSema *jobSema;
- ULONG NumSystemJobs = 0;
- ULONG NumARexxJobs = 0;
-
- /* Semaphore to protect Log() being called under EndSystemJob() */
-
- struct MyPublicSema *logSema;
-
- /* stuff for our timer port */
-
- struct MsgPort *TimerPort = NULL;
- struct timerequest TimerIO;
- BOOL TimerUP = FALSE;
- BOOL DoingTimeRequest = FALSE;
-
- /* stuff for our notify request */
-
- struct NotifyRequest MyNotifyRequest;
- BYTE NotifySignal = -1;
- BOOL NotifyUP = FALSE;
-
- /* stuff for our rexx port */
-
- struct MsgPort *RexxPort = NULL;
-
- /* global flags */
-
- BOOL BringerDown = FALSE; /* trying to quit ? */
- BOOL Suspended = FALSE; /* currently suspended ? */
-
- /* storage for our old pr_WindowPtr */
-
- APTR OldWindowPtr;
-
- /* specifies the maximum number of jobs for each of the queues */
-
- struct JobQueue jobQueue[27];
-
- /*
- * flag: should ErrorMsg() try and use requesters instead of writing to
- * StdErr?
- */
-
- BOOL ErrorsToStdErr = TRUE;
-
- /* stuff for our locale support */
-
- struct LocaleInfo LocaleInfo;
-
- /* storage for a couple library bases */
-
- struct Library *UtilityBase = NULL;
- struct Library *OwnDevUnitBase = NULL;
-
- /* used in some date calculations */
-
- static UBYTE DayTable[2][12] =
- {
- {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
- {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
- };
-
- /* this is our main routine */
-
- int __regargs main(char *cmdptr, int cmdlen, struct WBStartup * WBMsg)
- {
- char *ArgArray[ARG_sizeof];
- ULONG NSignal, TSignal, RSignal;
- ULONG signals;
- ULONG numJobs;
- int index;
- BPTR lock;
-
- struct timeval tr_time;
-
- #define TextBuf BigBufOne
-
- OldWindowPtr = ((struct Process *) FindTask(NULL))->pr_WindowPtr;
- ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) - 1;
-
- StdErr = ((struct Process *) FindTask(NULL))->pr_CES;
- if (StdErr == NULL)
- StdErr = Output();
-
- /*
- * the first thing we do is try and open up the local library and
- * grab our catalog as we will need it if we want to print any error
- * messages or other text
- */
-
- if (LocaleInfo.li_LocaleBase = (APTR) OpenLibrary("locale.library", 38))
- LocaleInfo.li_Catalog = OpenCatalogA(NULL, "CyberCron.catalog", NULL);
-
- /*
- * if started from the Workbench then we need to make an argstring
- * from our tooltypes as well as try and clone Workbench's CLI
- * structure
- */
-
- if (WBMsg) {
- ErrorsToStdErr = FALSE;
-
- if (!(WBArgs = WBtoCLIargs(WBMsg, ARG_TEMPLATE)))
- MyExit(5);
-
- /*
- * make us into a CLI so we have a path to propigate to jobs
- * we start
- */
- WB2CLI(WBMsg, DefaultStackSize, DOSBase);
- }
-
- /* try and open OwnDevUnit.library */
- OwnDevUnitBase = OpenLibrary(ODU_NAME, 0);
-
- /* try and open up utility.library */
- if (!(UtilityBase = OpenLibrary("utility.library", 37))) {
- ErrorMsg(MSG_COULDNT_OPEN, "utility.library");
- MyExit(20);
- }
-
- NewList(&EventList);
-
- if (!(jobSema = InitMyPublicSemaphore(GetString(&LocaleInfo, MSG_JOB_SEMA_NAME), sizeof(UBYTE) * JOB_TABLE_SIZE))) {
- ErrorMsg(MSG_NO_PUB_SEMA);
- MyExit(5);
- }
-
- if (!(logSema = InitMyPublicSemaphore(GetString(&LocaleInfo, MSG_LOG_SEMA_NAME), 0))) {
- ErrorMsg(MSG_NO_PUB_SEMA);
- MyExit(5);
- }
-
- /* do the stuff needed to call ReadArgs to parse the command line */
- memset(ArgArray, 0, sizeof(ArgArray));
-
- if (!(MyArgs = (struct RDArgs *) AllocDosObject(DOS_RDARGS, TAG_DONE))) {
- ErrorMsg(MSG_NO_RDARGS);
- MyExit(5);
- }
-
- if (!(MyArgs->RDA_ExtHelp = (UBYTE *) AllocVec(strlen(GetString(&LocaleInfo, MSG_ARG_HELP)) + strlen(GetString(&LocaleInfo, MSG_COPYRIGHT)) + (2 * strlen(CYBERCRON)) + strlen(VersionID) + 10, MEMF_CLEAR))) {
- ErrorMsg(MSG_OUTOFMEM);
- MyExit(5);
- }
-
- sprintf((char *) MyArgs->RDA_ExtHelp, GetString(&LocaleInfo, MSG_ARG_HELP), CYBERCRON, VersionID, GetString(&LocaleInfo, MSG_COPYRIGHT), CYBERCRON);
-
- if (WBArgs) {
- MyArgs->RDA_Source.CS_Buffer = WBArgs;
- MyArgs->RDA_Source.CS_Length = strlen(WBArgs);
- MyArgs->RDA_Source.CS_CurChr = 0L;
- }
-
- /* now call ReadArgs to parse the command line */
- ArgsPtr = ReadArgs(ARG_TEMPLATE, (LONG *) & ArgArray, MyArgs);
-
- /* free the memory we used for this ReadArgs() call */
- FreeVec((char *) MyArgs->RDA_ExtHelp);
- FreeVec(WBArgs);
- WBArgs = NULL;
-
- if (!ArgsPtr) {
- Fault(IoErr(), NULL, TextBuf, BIG_BUF_SIZE_BASE);
- ErrorMsg(MSG_STRING_HACK, TextBuf);
- MyExit(5);
- }
-
- if (ArgArray[ARG_CRONTAB])
- if (strlen(ArgArray[ARG_CRONTAB]) + 1 > sizeof(CronTabName)) {
- ErrorMsg(MSG_CRONTAB_NAME_TOO_LONG);
- MyExit(5);
- }
- else
- strcpy(CronTabName, ArgArray[ARG_CRONTAB]);
- else
- strcpy(CronTabName, "S:CronTab");
-
- if (ArgArray[ARG_LOGFILE])
- if (strlen(ArgArray[ARG_LOGFILE]) + 1 > sizeof(LogFile)) {
- ErrorMsg(MSG_LOGFILE_NAME_TOO_LONG);
- MyExit(5);
- }
- else
- strcpy(LogFile, ArgArray[ARG_LOGFILE]);
-
- if (ArgArray[ARG_SENDMAIL])
- if (strlen(ArgArray[ARG_SENDMAIL]) + 1 > sizeof(SendMailCmd)) {
- ErrorMsg(MSG_SENDMAIL_COMMAND_TOO_LONG);
- MyExit(5);
- }
- else
- strcpy(SendMailCmd, ArgArray[ARG_SENDMAIL]);
-
- if (ArgArray[ARG_STACK])
- DefaultStackSize = *((LONG *) ArgArray[ARG_STACK]);
- else {
-
- /*
- * if we have a cli attached to us then get the default stack
- * size out of it. Otherwise leave it be. WBtoCLIargs() will
- * probably have set DefaultStackSize for us already in such
- * a case. If not, the hard-coded default of 4096 will be
- * used
- */
-
- struct CommandLineInterface *cli;
-
- if (cli = Cli())
- DefaultStackSize = sizeof(LONG) * cli->cli_DefaultStack;
- }
-
- if (DefaultStackSize < 2048)
- DefaultStackSize = 2048;
-
- if (ArgArray[ARG_PRI])
- DefaultPriority = *((LONG *) ArgArray[ARG_PRI]) & 0xFF;
-
- if (ArgArray[ARG_CPRI])
- OldPriority = SetTaskPri(FindTask(NULL), *((LONG *) ArgArray[ARG_CPRI]) & 0xFF);
-
- /*
- * open up our ARexx port. Check to see if we're already using that
- * port first, though.
- */
- Forbid();
-
- if (FindPort(ArgArray[ARG_PORTNAME] ? ArgArray[ARG_PORTNAME] : "CYBERCRON")) {
- /* port already exists so fail */
- Permit();
- ErrorMsg(MSG_ALREADY_RUNNING, (ArgArray[ARG_PORTNAME] ? ArgArray[ARG_PORTNAME] : "CYBERCRON"));
- MyExit(5);
- }
- else {
- if (!(RexxPort = CreatePort((ArgArray[ARG_PORTNAME] ? ArgArray[ARG_PORTNAME] : "CYBERCRON"), 0))) {
- Permit();
- ErrorMsg(MSG_CANT_CREATE_AREXX_PORT);
- MyExit(5);
- }
- }
-
- Permit();
-
- RSignal = 1L << RexxPort->mp_SigBit;
-
- /* open up the timer */
- if (!(TimerPort = CreatePort(NULL, 0))) {
- ErrorMsg(MSG_CANT_CREATE_TIMER_PORT);
- MyExit(5);
- }
-
- if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *) & TimerIO, 0)) {
- ErrorMsg(MSG_COULDNT_OPEN, TIMERNAME);
- MyExit(5);
- }
-
- TimerIO.tr_node.io_Message.mn_ReplyPort = TimerPort;
- TSignal = 1L << TimerPort->mp_SigBit;
- TimerUP = TRUE;
-
- if ((NotifySignal = AllocSignal(-1)) == -1) {
- ErrorMsg(MSG_COULDNT_ALLOC_NOTIFY_SIG);
- MyExit(5);
- }
-
- NSignal = 1L << NotifySignal;
-
- memset((char *) &MyNotifyRequest, 0, sizeof(struct NotifyRequest));
-
- MyNotifyRequest.nr_Name = CronTabName;
- MyNotifyRequest.nr_Flags = NRF_SEND_SIGNAL;
- MyNotifyRequest.nr_stuff.nr_Signal.nr_Task = FindTask(NULL);
- MyNotifyRequest.nr_stuff.nr_Signal.nr_SignalNum = NotifySignal;
-
- if (StartNotify(&MyNotifyRequest) == DOSFALSE) {
- ErrorMsg(MSG_COULDNT_START_NOTIFY);
- MyExit(5);
- }
- NotifyUP = TRUE;
-
- ReadCronTab();
-
- /* initialize jobQueue Maximums */
- for (index = 0; index < 27; index++) {
- jobQueue[index].jq_Max = 1;
- jobQueue[index].jq_Cur = 0;
- NewList((struct List *) & jobQueue[index].jq_FIFOList);
- }
-
- /*
- * set queue 0 to 0xFFFFFFFF (infinite) so that jobs with no queue
- * specified will use one with no limits
- */
- jobQueue[0].jq_Max = 0xFFFFFFFF;
-
- /* print a banner to the world saying we've started */
- if (!WBMsg) {
- sprintf(TextBuf, GetString(&LocaleInfo, MSG_DAEMON_STARTED), CYBERCRON, VersionID);
- PutStr(TextBuf);
- PutStr("\n");
- PutStr(GetString(&LocaleInfo, MSG_COPYRIGHT));
- Flush(Output());
- }
-
- Log(MSG_DAEMON_STARTED, CYBERCRON, VersionID);
- Log(MSG_PORTNAME, (ArgArray[ARG_PORTNAME] ? ArgArray[ARG_PORTNAME] : "CYBERCRON"));
-
- ErrorsToStdErr = TRUE;
-
- /*
- * loop forever waiting for each minute and checking to see if we
- * need to do anything. also look for break, notify, etc.
- * BringerDown can be set by the ARexx SHUTDOWN command so check it
- * as well.
- */
-
- for (; BringerDown == FALSE;) {
- TimerIO.tr_node.io_Command = TR_ADDREQUEST;
- TimerIO.tr_time.tv_micro = 0;
- GetSysTime(&tr_time);
- TimerIO.tr_time.tv_secs = 60 - tr_time.tv_secs % 60;
- SetSignal(0L, TSignal);
- SendIO((struct IORequest *) & TimerIO);
- DoingTimeRequest = TRUE;
-
- signals = Wait(TSignal | NSignal | RSignal | SIGBREAKF_CTRL_C);
-
- if (signals & TSignal) {
- GetMsg(TimerPort);
- DoingTimeRequest = FALSE;
- if (Suspended == FALSE)
- ScanForJobs();
- }
-
- if (signals & NSignal)
- if (lock = Lock(CronTabName, ACCESS_READ)) {
- FreeEvents(TRUE);
-
- /*
- * not really an error, but ReadCronTab()
- * will send messages along the lines of
- * parse error in line # if they occur so we
- * spit this out to let them know why they
- * are getting these parse errors.
- */
-
- ErrorMsg(MSG_CRONTAB_MODIFIED);
- Log(MSG_CRONTAB_MODIFIED);
-
- ReadCronTab();
- UnLock(lock);
- }
-
- if (signals & RSignal)
- HandleRexxEvents();
-
- if (DoingTimeRequest) {
- DoingTimeRequest = FALSE;
-
- AbortIO((struct IORequest *) & TimerIO);
- WaitIO((struct IORequest *) & TimerIO);
- }
-
- if (signals & SIGBREAKF_CTRL_C)
- break;
- }
-
- BringerDown = TRUE;
-
- ObtainSemaphore(&jobSema->mps_Sema);
- numJobs = NumSystemJobs + NumARexxJobs;
- ReleaseSemaphore(&jobSema->mps_Sema);
-
- if (numJobs) {
- ErrorMsg(MSG_WAITING_TO_QUIT);
-
- for (; numJobs;) {
- TimerIO.tr_node.io_Command = TR_ADDREQUEST;
- TimerIO.tr_time.tv_secs = 15;
- TimerIO.tr_time.tv_micro = 0;
- SetSignal(0L, TSignal);
- SendIO((struct IORequest *) & TimerIO);
- DoingTimeRequest = TRUE;
-
- signals = Wait(TSignal | RSignal);
-
- if (signals & TSignal) {
- GetMsg(TimerPort);
- DoingTimeRequest = FALSE;
- }
-
- if (signals & RSignal)
- HandleRexxEvents();
-
- if (DoingTimeRequest) {
- DoingTimeRequest = FALSE;
-
- AbortIO((struct IORequest *) & TimerIO);
- WaitIO((struct IORequest *) & TimerIO);
- }
-
- ObtainSemaphore(&jobSema->mps_Sema);
- numJobs = NumSystemJobs + NumARexxJobs;
- ReleaseSemaphore(&jobSema->mps_Sema);
- }
- }
-
- MyExit(0);
- }
-
- /* loop through the event list looking for any jobs to start */
-
- void ScanForJobs(void)
- {
- struct CyberNode *cn, *tcn;
-
- UBYTE DayOfWeek;
- UWORD Month;
- ULONG Day;
- ULONG Hour;
- ULONG Min;
- BOOL TimeMatch;
-
- SystemTime_t st;
- static ULONG LastScan = 0;
-
- GetSystemTime(&st, FALSE);
-
- /*
- * figure out if the time has gone backwards. This could happen if
- * the clock was reloaded, etc. We use a 5 minute threshhold. If it
- * goes back farther than that then we assume the user knows what
- * they are doing.
- */
- {
- ULONG MSSC = st.st_tvsecs / 60; /* MSSC stands for Minutes
- * Since System Creation */
-
- if (MSSC >= (LastScan - 5) && MSSC <= LastScan)
- return;
- else
- LastScan = MSSC;
- }
-
- /* initilize the bit fields for us to do comparisons against */
- DayOfWeek = 1L << st.st_DOW;
- Month = 1L << st.st_Month;
- Day = 1L << st.st_Day;
- Hour = 1L << st.st_Hour;
- if (st.st_Min > 31)
- Min = 1L << (st.st_Min - 32);
- else
- Min = 1L << st.st_Min;
-
- /* loop through the list looking for events to do */
- for (cn = (struct CyberNode *) EventList.lh_Head; cn->cn_Node.ln_Succ;
- cn = (struct CyberNode *) cn->cn_Node.ln_Succ) {
-
- TimeMatch = FALSE;
-
- if (cn->cn_DayOfWeek & DayOfWeek)
- if (cn->cn_Month & Month)
- if (cn->cn_Day & Day)
- if (cn->cn_Hour & Hour)
- if ((st.st_Min > 31 && cn->cn_HiMin & Min) ||
- (st.st_Min < 32 && cn->cn_LoMin & Min))
- TimeMatch = TRUE;
-
- ObtainSemaphore(&jobSema->mps_Sema);
-
- if (TimeMatch || cn->cn_DelayedCount) {
- if (ProcessQueue(cn, TimeMatch)) {
- if (cn->cn_Flags & CNF_REXX)
- StartRexxJob(cn);
- else
- StartSystemJob(cn);
-
- if (cn->cn_Flags & CNF_EXECONE) {
- tcn = (struct CyberNode *) cn->cn_Node.ln_Pred;
- DeleteEvent(cn);
- cn = tcn;
- }
- }
- }
-
- ReleaseSemaphore(&jobSema->mps_Sema);
- }
- }
-
- /*
- * this routine will decide if we can run the job now or if it is to be
- * delayed because we are currently at the maximum number of jobs allowed
- * for the specified queue. it serializes the delayed jobs on the queue by
- * using a fifo mechanism which is maintained here
- */
-
- BOOL ProcessQueue(struct CyberNode * cn, BOOL TimeMatch)
- {
- struct QueueFIFO *qf;
- BOOL RetVal;
- BOOL AddFIFO;
-
- AddFIFO = RetVal = FALSE;
-
- if (jobQueue[cn->cn_ObeyQueue].jq_Cur >= jobQueue[cn->cn_ObeyQueue].jq_Max) {
- if (TimeMatch)
- AddFIFO = TRUE;
- else
- return FALSE;
- }
-
- if (!AddFIFO) {
- if (cn->cn_DelayedCount) {
- qf = (struct QueueFIFO *) RemHead((struct List *) & jobQueue[cn->cn_ObeyQueue].jq_FIFOList);
-
- if (qf->qf_CyberNode == cn) {
- RetVal = TRUE;
- cn->cn_DelayedCount--;
- FreeVec(qf);
- }
- else {
- AddHead((struct List *) & jobQueue[cn->cn_ObeyQueue].jq_FIFOList, (struct Node *) qf);
- }
-
- /*
- * if we were delayed but we would also start a job
- * at this time anyway, we need to queue a new job to
- * occur
- */
- if (TimeMatch)
- AddFIFO = TRUE;
- }
- else if (TimeMatch)
- RetVal = TRUE;
- }
-
- if (AddFIFO) {
- if (qf = (struct QueueFIFO *) AllocVec(sizeof(struct QueueFIFO), MEMF_CLEAR)) {
- qf->qf_CyberNode = cn;
- AddTail((struct List *) & jobQueue[cn->cn_ObeyQueue].jq_FIFOList, (struct Node *) qf);
- cn->cn_DelayedCount++;
- }
- }
-
- return RetVal;
- }
-
-
- void HandleRexxEvents(void)
- {
- struct RexxMsg *msg;
-
- /* this is the table of ARexx commands that CyberCron knows. the
- format is as follows:
-
- 1) a short that is the length of the command name
- 2) a pointer to the command name
- 3) a short to descibe the args to pass to the function.
- value 0 = no args
- value 1 = pointer to string after command name
- value 2 = an integer
- value 3 = pointer to the current ARexx message
- 4) a short to describe the return value from the function
- value 0 = no returns, set rc to zero
- value 1 = return an argstring
- value 2 = return integer in rc
- value 3 = return an argstring already in argstring format
- 5) a pointer to the function
- */
-
- #define NUMRXCMDS 22
- static struct {
- short len;
- char *RxCmd;
- short args;
- short ret;
- APTR func;
- } CmdTbl[NUMRXCMDS] = {
-
- /* indent makes this look so ugly... sigh... */
-
- {
- 8, "SHUTDOWN", 0, 0, (APTR) & rx_Shutdown
- },
- {
- 4, "QUIT", 0, 0, (APTR) & rx_Shutdown
- },
- {
- 7, "VERSION", 0, 1, (APTR) & rx_Version
- },
- {
- 7, "SUSPEND", 0, 0, (APTR) & rx_Suspend
- },
- {
- 6, "RESUME", 0, 0, (APTR) & rx_Resume
- },
- {
- 14, "NEW_EVENT_FILE", 1, 2, (APTR) & rx_NewEventFile
- },
- {
- 16, "CLOSE_EVENT_FILE", 0, 0, (APTR) & rx_CloseEventFile
- },
- {
- 9, "ADD_EVENT", 1, 2, (APTR) & rx_AddEvent
- },
- {
- 11, "SHOW_STATUS", 0, 1, (APTR) & rx_ShowStatus
- },
- {
- 17, "PURGE_REXX_EVENTS", 0, 0, (APTR) & rx_PurgeRexxEvents
- },
- {
- 17, "DELETE_REXX_EVENT", 1, 2, (APTR) & rx_DeleteRexxEvent
- },
- {
- 12, "DELETE_EVENT", 1, 2, (APTR) & rx_DeleteEvent
- },
- {
- 11, "LIST_EVENTS", 0, 3, (APTR) & rx_ListEvents
- },
- {
- 10, "SHOW_EVENT", 1, 1, (APTR) & rx_ShowEvent
- },
- {
- 12, "NEW_LOG_FILE", 1, 2, (APTR) & rx_NewLogFile
- },
- {
- 14, "CLOSE_LOG_FILE", 0, 0, (APTR) & rx_CloseLogFile
- },
- {
- 13, "SET_QUEUE_MAX", 1, 2, (APTR) & rx_SetQueueMax
- },
- {
- 13, "GET_QUEUE_MAX", 1, 2, (APTR) & rx_GetQueueMax
- },
- {
- 15, "EVENT_NEXT_EXEC", 1, 1, (APTR) & rx_EventNextExec
- },
- {
- 18, "NEXT_EVENT_TO_EXEC", 0, 1, (APTR) & rx_NextEventToExec
- },
- {
- 11, "EXPAND_SSSC", 2, 1, (APTR) & rx_ExpandSSSC
- },
- {
- 13, "SSSC_TO_ASCII", 2, 1, (APTR) & rx_SSSCtoASCII
- }
- };
-
- /*
- * if we can't get ahold of the rexx system library then we spin
- * emptying our message port by replying to everything. shouldn't
- * happen, but if some idiot tries sending us messages when they
- * don't have ARexx then its better safe than sorry
- */
-
- if (GetARexxLib() == FALSE) {
- ErrorMsg(MSG_CANT_HANDLE_REXX_EVENT, RXSNAME);
- Log(MSG_CANT_HANDLE_REXX_EVENT, RXSNAME);
-
- while ((msg = (struct RexxMsg *) GetMsg(RexxPort)))
- ReplyMsg((struct Message *) msg);
-
- return;
- }
-
- /*
- * we've got the ARexx library so spin on our port looking for
- * messages. if its a reply then a command/string we launched has
- * finished and ARexx is returning its results to us. Otherwise,
- * it's a command we are to execute so call DoMsg() to dispatch it
- */
-
- while ((msg = (struct RexxMsg *) GetMsg(RexxPort)))
- if (msg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
- if (!msg->rm_Args[3])
- Log(MSG_JOB_ENDED, (UWORD) msg->rm_Args[2]);
-
- /*
- * when a system job can't find the command it wanted
- * to execute, the shell automatically prints out
- * that it couldn't find it or whatever the error
- * might happen to be. Thus, the user is informed of
- * this based on wherever they may have redirected
- * output. ARexx, on the other hand, does not do
- * this for us. So here I have duplicated what the RX
- * activator prints out when it can't start a job.
- * Note that ARexxErrorMsg() is a hack defined in
- * CyberCron.h since this isn't normally available
- * from the standard C= includes
- */
-
- if (msg->rm_Result1)
- if (msg->rm_Result2)
- FPrintf(msg->rm_Stdout, GetString(&LocaleInfo, MSG_AREXX_RETURNED_2), msg->rm_Result1,
- msg->rm_Result2, (ARexxErrorMsg(msg->rm_Result2))->ns_Buff);
- else
- FPrintf(msg->rm_Stdout, GetString(&LocaleInfo, MSG_AREXX_RETURNED_1), msg->rm_Result1);
-
- Close(msg->rm_Stdout);
- Close(msg->rm_Stdin);
- FreeJobNum((UWORD) msg->rm_Args[2]);
- ObtainSemaphore(&jobSema->mps_Sema);
- jobQueue[(int) msg->rm_Args[4]].jq_Cur--;
- ReleaseSemaphore(&jobSema->mps_Sema);
- if (msg->rm_Args[1])
- DeleteArgstring(msg->rm_Args[1]);
- DeleteArgstring(msg->rm_Args[0]);
- DeleteRexxMsg(msg);
- NumARexxJobs--;
- }
- else
- DoMsg(msg, (APTR) & CmdTbl, NUMRXCMDS, BringerDown);
-
- FreeARexxLib();
- }
-
- void rx_Shutdown(void)
- {
- BringerDown = TRUE;
- }
-
- STRPTR rx_Version(void)
- {
- return VersionID;
- }
-
- void rx_Suspend(void)
- {
- Suspended = TRUE;
- }
-
- void rx_Resume(void)
- {
- Suspended = FALSE;
- }
-
- int rx_NewEventFile(STRPTR name)
- {
- BPTR lock;
-
- if (lock = Lock(name, ACCESS_READ)) {
- if (strlen(name) + 1 > sizeof(CronTabName)) {
- ErrorMsg(MSG_CRONTAB_NAME_TOO_LONG);
- UnLock(lock);
- return RC_WARN;
- }
-
- FreeEvents(TRUE);
-
- if (NotifyUP) {
- EndNotify(&MyNotifyRequest);
- NotifyUP = FALSE;
- }
-
- strcpy(CronTabName, name);
-
- memset((char *) &MyNotifyRequest, 0, sizeof(struct NotifyRequest));
-
- MyNotifyRequest.nr_Name = CronTabName;
- MyNotifyRequest.nr_Flags = NRF_SEND_SIGNAL;
- MyNotifyRequest.nr_stuff.nr_Signal.nr_Task = FindTask(NULL);
- MyNotifyRequest.nr_stuff.nr_Signal.nr_SignalNum = NotifySignal;
-
- if (StartNotify(&MyNotifyRequest) == DOSFALSE) {
- ErrorMsg(MSG_COULDNT_START_NOTIFY);
- UnLock(lock);
- strcpy(CronTabName, "<None>");
- return RC_ERROR;
- }
- NotifyUP = TRUE;
-
- /* again, not really an error */
- ErrorMsg(MSG_CRONTAB_CHANGED);
- Log(MSG_CRONTAB_CHANGED);
-
- ReadCronTab();
- UnLock(lock);
- return RC_OK;
- }
-
- return RC_WARN;
- }
-
-
- void rx_CloseEventFile(void)
- {
- FreeEvents(TRUE);
- EndNotify(&MyNotifyRequest);
- NotifyUP = FALSE;
- strcpy(CronTabName, "<None>");
- }
-
- int rx_NewLogFile(STRPTR name)
- {
- if (strlen(name) + 1 > sizeof(LogFile)) {
- ErrorMsg(MSG_LOGFILE_NAME_TOO_LONG);
- return RC_WARN;
- }
-
- ObtainSemaphore(&logSema->mps_Sema);
- strcpy(LogFile, name);
- ReleaseSemaphore(&logSema->mps_Sema);
-
- return RC_OK;
- }
-
- void rx_CloseLogFile(void)
- {
- ObtainSemaphore(&logSema->mps_Sema);
- LogFile[0] = '\0';
- ReleaseSemaphore(&logSema->mps_Sema);
- }
-
- STRPTR rx_ShowStatus(void)
- {
- sprintf(BigBufOne, "%s \"%s\" \"%s\"",
- (Suspended ? "SUSPENDED" : "ACTIVE"), CronTabName,
- (LogFile[0] ? LogFile : (UBYTE *) "<None>"));
-
- return BigBufOne;
- }
-
- void rx_PurgeRexxEvents(void)
- {
- FreeEvents(FALSE);
- }
-
- int rx_AddEvent(STRPTR event)
- {
- struct CyberNode *cn;
-
- if (cn = ParseEvent(event)) {
- AddTail(&EventList, (struct Node *) cn);
- return RC_OK;
- }
- else
- return RC_ERROR;
- }
-
- int rx_DeleteRexxEvent(STRPTR name)
- {
- struct CyberNode *cn;
-
- if ((cn = FindEvent(name)) && !(cn->cn_Flags & CNF_CRONTAB)) {
- DeleteEvent(cn);
- return RC_OK;
- }
-
- return RC_ERROR;
- }
-
- int rx_DeleteEvent(STRPTR name)
- {
- struct CyberNode *cn;
-
- if (cn = FindEvent(name)) {
- DeleteEvent(cn);
- return RC_OK;
- }
-
- return RC_ERROR;
- }
-
- STRPTR rx_ListEvents(void)
- {
- struct CyberNode *cn;
- STRPTR string, string2;
- ULONG num;
-
- num = 0;
- for (cn = (struct CyberNode *) EventList.lh_Head; cn->cn_Node.ln_Succ;
- cn = (struct CyberNode *) cn->cn_Node.ln_Succ)
- num++;
-
- if (num == 0)
- return CreateArgstring("<None>", 6);
-
- if (!(string = CreateArgstring(NULL, num * 11)))
- return NULL;
-
- string2 = string;
- for (cn = (struct CyberNode *) EventList.lh_Head; cn->cn_Node.ln_Succ;
- cn = (struct CyberNode *) cn->cn_Node.ln_Succ) {
- sprintf(string2, "0x%08lx ", cn);
- string2 += 11;
- }
-
- *--string2 = '\0';
-
- return string;
- }
-
- #define rxSE_Buf BigBufOne
-
- STRPTR rx_ShowEvent(STRPTR name)
- {
- struct CyberNode *cn;
- STRPTR ptr;
- ULONG Bits[2];
-
- if (!(cn = FindEvent(name)))
- return NULL;
-
- sprintf(rxSE_Buf, "0x%08lx ", cn);
- ptr = &rxSE_Buf[11];
-
- if (cn->cn_Name) {
- sprintf(ptr, ":NAME %s ", cn->cn_Name);
- ptr += strlen(ptr);
- }
-
- Bits[0] = cn->cn_LoMin, Bits[1] = cn->cn_HiMin;
- UnParseBits(Bits, ptr, 0, 59);
- ptr += strlen(ptr);
- *ptr++ = ' ';
-
- Bits[1] = 0;
-
- Bits[0] = cn->cn_Hour;
- UnParseBits(Bits, ptr, 0, 23);
- ptr += strlen(ptr);
- *ptr++ = ' ';
-
- Bits[0] = cn->cn_Day;
- UnParseBits(Bits, ptr, 1, 31);
- ptr += strlen(ptr);
- *ptr++ = ' ';
-
- Bits[0] = cn->cn_Month;
- UnParseBits(Bits, ptr, 1, 12);
- ptr += strlen(ptr);
- *ptr++ = ' ';
-
- Bits[0] = cn->cn_DayOfWeek;
- UnParseBits(Bits, ptr, 0, 6);
- ptr += strlen(ptr);
- *ptr++ = ' ';
-
- if (cn->cn_Flags & CNF_EXECONE) {
- strcpy(ptr, ":EXECONCE ");
- ptr += 10;
- }
-
- if (cn->cn_Flags & CNF_NOLOG) {
- strcpy(ptr, ":NOLOG ");
- ptr += 7;
- }
-
- if (cn->cn_Flags & CNF_REXX) {
- strcpy(ptr, ":REXX ");
- ptr += 6;
- }
- else {
- if (cn->cn_Stack != DefaultStackSize) {
- sprintf(ptr, ":STACK %ld ", cn->cn_Stack);
- ptr += strlen(ptr);
- }
-
- if (cn->cn_Priority != DefaultPriority) {
- sprintf(ptr, ":PRI %ld ", cn->cn_Priority);
- ptr += strlen(ptr);
- }
-
- if (cn->cn_CustomShell) {
- sprintf(ptr, ":CUSTOMSH %s ", cn->cn_CustomShell);
- ptr += strlen(ptr);
- }
- else if (cn->cn_Flags & CNF_SYSSH) {
- strcpy(ptr, ":SYSSH ");
- ptr += 7;
- }
- }
-
- strcpy(ptr, cn->cn_Command);
- ptr += strlen(ptr);
- *ptr++ = ' ';
-
- if (cn->cn_Args) {
- strcpy(ptr, cn->cn_Args);
- ptr += strlen(ptr);
- *ptr++ = ' ';
- }
-
- if (cn->cn_ReDirIn) {
- sprintf(ptr, "< %s ", cn->cn_ReDirIn);
- ptr += strlen(ptr);
- }
-
- if (cn->cn_SendToUser && SendMailCmd[0]) {
- sprintf(ptr, ":MAILUSER %s ", cn->cn_SendToUser);
- ptr += strlen(ptr);
- }
- else {
- if (cn->cn_ReDirOut) {
- sprintf(ptr, "%s %s ", (cn->cn_Flags & CNF_OUTAPP ? ">>" : ">"), cn->cn_ReDirOut);
- ptr += strlen(ptr);
- }
- }
-
- if (cn->cn_ReDirErr) {
- sprintf(ptr, "2%s %s ", (cn->cn_Flags & CNF_ERRAPP ? ">>" : ">"), cn->cn_ReDirErr);
- ptr += strlen(ptr);
- }
-
- if (cn->cn_ObeyQueue) {
- sprintf(ptr, ":OBEYQUEUE %lc ", cn->cn_ObeyQueue + 'a' - 1);
- ptr += 13;
- }
-
- *--ptr = '\0';
-
- return rxSE_Buf;
- }
-
- int rx_SetQueueMax(STRPTR argline)
- {
- int queueNum;
-
- if (isalpha(*argline)) {
- queueNum = tolower(*argline) - 'a' + 1;
-
- argline++;
-
- while (isspace(*argline++)) ;
-
- if (*--argline) {
- jobQueue[queueNum].jq_Max = atol(argline);
- return RC_OK;
- }
- }
-
- return RC_ERROR;
- }
-
- int rx_GetQueueMax(STRPTR argline)
- {
- int queueNum;
-
- if (isalpha(*argline)) {
- queueNum = tolower(*argline) - 'a' + 1;
- return (int) jobQueue[queueNum].jq_Max;
- }
- else
- return -1;
- }
-
- STRPTR rx_EventNextExec(STRPTR name)
- {
- struct CyberNode *cn;
- SystemTime_t st;
-
- if (!(cn = FindEvent(name)))
- return NULL;
-
- GetSystemTime(&st, FALSE);
-
- sprintf(BigBufOne, "%ld", EventNextExecutes(cn, &st));
-
- return BigBufOne;
- }
-
- STRPTR rx_NextEventToExec(void)
- {
- struct CyberNode *cn, *bestcn;
- ULONG secs, bestsecs;
- SystemTime_t st;
-
- GetSystemTime(&st, FALSE);
-
- bestcn = (struct CyberNode *) NULL;
- bestsecs = -1;
-
- for (cn = (struct CyberNode *) EventList.lh_Head; cn->cn_Node.ln_Succ;
- cn = (struct CyberNode *) cn->cn_Node.ln_Succ) {
- secs = EventNextExecutes(cn, &st);
- if (secs && secs < bestsecs) {
- bestcn = cn;
- bestsecs = secs;
- }
- }
-
- if (bestcn) {
- sprintf(BigBufOne, "0x%08lx %ld", bestcn, bestsecs);
- return BigBufOne;
- }
- else
- return "<None>";
- }
-
- STRPTR rx_ExpandSSSC(int SSSC)
- {
- SystemTime_t st;
-
- st.st_tvsecs = SSSC;
-
- GetSystemTime(&st, TRUE);
-
- sprintf(BigBufOne, "%ld %ld %ld %ld %ld %ld %ld", st.st_Sec, st.st_Min,
- st.st_Hour, st.st_Day, st.st_Month, st.st_Year, st.st_DOW);
-
- return BigBufOne;
- }
-
- STRPTR rx_SSSCtoASCII(int SSSC)
- {
- struct DateTime dat;
- UBYTE Day[LEN_DATSTRING + 1];
- UBYTE Date[LEN_DATSTRING + 1];
- UBYTE Time[LEN_DATSTRING + 1];
-
- dat.dat_Stamp.ds_Days = SSSC / SECSINDAY, SSSC %= SECSINDAY;
- dat.dat_Stamp.ds_Minute = SSSC / SECSINMINUTE, SSSC %= SECSINMINUTE;
- dat.dat_Stamp.ds_Tick = SSSC * TICKS_PER_SECOND;
-
- dat.dat_Format = FORMAT_DOS;
- dat.dat_Flags = 0;
- dat.dat_StrDay = Day;
- dat.dat_StrDate = Date;
- dat.dat_StrTime = Time;
-
- memset(Day, 0, LEN_DATSTRING + 1);
- memset(Date, 0, LEN_DATSTRING + 1);
- memset(Time, 0, LEN_DATSTRING + 1);
- DateToStr(&dat);
-
- sprintf(BigBufOne, "%s %s %s", Day, Date, Time);
-
- return BigBufOne;
- }
-
- STRPTR WBtoCLIargs(struct WBStartup * WBMsg, STRPTR ArgTemplate)
- {
- UBYTE *Argline, *ArglineSave, *SourcePtr, *DestPtr;
- struct Library *IconBase;
- UBYTE tempChar;
- BOOL sawEqual;
- int index;
- ULONG size;
- BPTR oldDir;
- struct DiskObject *dob;
-
- if (!(IconBase = OpenLibrary("icon.library", 37)))
- return NULL;
-
- oldDir = CurrentDir(WBMsg->sm_ArgList[0].wa_Lock);
-
- if (!(dob = GetDiskObjectNew(WBMsg->sm_ArgList[0].wa_Name))) {
- CurrentDir(oldDir);
- CloseLibrary(IconBase);
- return NULL;
- }
-
- /*
- * if there are tooltypes then figure out how much memory we need to
- * allocate to hold them as a command line. anything that isn't a
- * legal argument in our command line template is ignored. This lets
- * things like DONOTWAIT be used without causing an error at
- * ReadArgs() time.
- */
-
- if (dob->do_ToolTypes)
- for (size = index = 0; dob->do_ToolTypes[index]; index++) {
- SourcePtr = dob->do_ToolTypes[index];
- DestPtr = BigBufOne;
-
- while (tempChar = *SourcePtr++)
- if (tempChar == '=')
- break;
- else
- *DestPtr++ = tempChar;
-
- *DestPtr = '\0';
-
- if (FindArg(ArgTemplate, BigBufOne) != -1)
- size += strlen(dob->do_ToolTypes[index]) + 3;
- }
- else
- size = 0;
-
- if (Argline = AllocVec(size + 2, MEMF_CLEAR)) {
- ArglineSave = Argline;
-
- if (dob->do_ToolTypes)
- for (index = 0; dob->do_ToolTypes[index]; index++) {
- SourcePtr = dob->do_ToolTypes[index];
- DestPtr = BigBufOne;
- sawEqual = FALSE;
-
- while (tempChar = *SourcePtr++)
- if (tempChar == '=') {
- sawEqual = TRUE;
- break;
- }
- else
- *DestPtr++ = tempChar;
-
- *DestPtr = '\0';
-
- if (FindArg(ArgTemplate, BigBufOne) != -1) {
- CopyMem(BigBufOne, Argline, DestPtr - BigBufOne);
- Argline += DestPtr - BigBufOne;
-
- /*
- * if we saw an equals sign when we
- * broke the argument name out then
- * we know we need to copy the
- * argument's data over. if we
- * didn't see it then this argument
- * is a switch and thus has no more
- * data to copy over
- */
-
- if (sawEqual) {
- *Argline++ = ' ';
- *Argline++ = '\"';
-
- while (tempChar = *SourcePtr++)
- *Argline++ = tempChar;
-
- *Argline++ = '\"';
- }
-
- *Argline++ = ' ';
- }
- }
-
- *Argline++ = '\n';
- *Argline = '\0';
- }
- else
- ArglineSave = NULL;
-
- if (dob->do_StackSize)
- DefaultStackSize = dob->do_StackSize;
-
- FreeDiskObject(dob);
- CurrentDir(oldDir);
- CloseLibrary(IconBase);
- return ArglineSave;
- }
-
- void MyExit(int error)
- {
- if (OldPriority != -1)
- SetTaskPri(FindTask(NULL), OldPriority);
-
- if (ARexxLibCount)
- CloseLibrary((struct Library *) RexxSysBase);
-
- FreeEvents(TRUE);
- FreeEvents(FALSE);
-
- if (NotifyUP)
- EndNotify(&MyNotifyRequest);
-
- FreeSignal(NotifySignal);
-
- if (TimerUP) {
- if (DoingTimeRequest) {
- AbortIO((struct IORequest *) & TimerIO);
- WaitIO((struct IORequest *) & TimerIO);
- }
-
- CloseDevice((struct IORequest *) & TimerIO);
- }
-
- if (TimerPort)
- DeletePort(TimerPort);
-
- if (RexxPort)
- DeletePort(RexxPort);
-
- if (ArgsPtr)
- FreeArgs(ArgsPtr);
-
- if (MyArgs)
- FreeDosObject(DOS_RDARGS, MyArgs);
-
- if (logSema)
- FreeMyPublicSemaphore(logSema);
-
- if (jobSema)
- FreeMyPublicSemaphore(jobSema);
-
- CloseLibrary(UtilityBase);
-
- CloseLibrary(OwnDevUnitBase);
-
- FreeVec(WBArgs);
-
- if (LocaleInfo.li_LocaleBase) {
- CloseCatalog(LocaleInfo.li_Catalog);
- CloseLibrary((struct Library *) LocaleInfo.li_LocaleBase);
- }
-
- ((struct Process *) FindTask(NULL))->pr_WindowPtr = OldWindowPtr;
-
- XCEXIT(error);
- }
-
- /*
- * this routine will read the crontab file, calling ParseEvent() to create
- * CyberNodes, and then link them into the event list.
- *
- */
-
- #define RCT_Buf BigBufOne
-
- void ReadCronTab(void)
- {
- BPTR fh;
- struct CyberNode *cn;
- ULONG line = 0;
- LONG error;
-
- if (!(fh = Open(CronTabName, MODE_OLDFILE))) {
- ErrorMsg(MSG_OPENING_CRONTAB, CronTabName);
- Log(MSG_OPENING_CRONTAB, CronTabName);
- return;
- }
-
- while (FGets(fh, RCT_Buf, BIG_BUF_SIZE_BASE)) {
- line++;
-
- if (RCT_Buf[0] == '#' || RCT_Buf[0] == '\n')
- continue;
-
- if (cn = ParseEvent(RCT_Buf)) {
- cn->cn_Flags |= CNF_CRONTAB;
- AddTail(&EventList, (struct Node *) cn);
- }
- else {
- ErrorMsg(MSG_PARSING, line, CronTabName);
- Log(MSG_PARSING, line, CronTabName);
- }
- }
-
- error = IoErr();
-
- if (error) {
- Fault(error, NULL, RCT_Buf, BIG_BUF_SIZE_BASE);
- ErrorMsg(MSG_IO_FAULT_IN_CRONTAB, error, RCT_Buf, line + 1, CronTabName);
- Log(MSG_IO_FAULT_IN_CRONTAB, error, RCT_Buf, line + 1, CronTabName);
- }
-
- Close(fh);
- }
-
- /*
- * this routine will parse an ASCII string and make a CyberNode out of it.
- * it returns NULL if there was an error during the parse. otherwise it
- * returns a pointer to the node.
- *
- * note that we do something really sneaky here. we use the ReadArgs() routine
- * to do the initial parse!. This means that the order in which items occur
- * in a crontab entry can be virtually anything the user desires!
- */
-
- #define PE_TEMPLATE "Event/M,</K,>/K,>>/K,2>/K,2>>/K,:NAME/K,:STACK/K/N,:PRI/K/N,:CUSTOMSH/K,:MAILUSER/K,:OBEYQUEUE/K,:SYSSH/S,:REXX/S,:NOLOG/S,:EXECONCE/S"
-
- enum ParseEventReadArgs {
- PEARG_EVENT,
- PEARG_REDIRIN,
- PEARG_REDIROUT,
- PEARG_REDIROUT2,
- PEARG_REDIRERR,
- PEARG_REDIRERR2,
- PEARG_REXXNAME,
- PEARG_STACK,
- PEARG_PRI,
- PEARG_CUSTOMSH,
- PEARG_MAILUSER,
- PEARG_OBEYQUEUE,
- PEARG_SYSSH,
- PEARG_REXX,
- PEARG_NOLOG,
- PEARG_EXECONE,
- PEARG_sizeof
- };
-
- enum Events {
- EVENT_MINUTE,
- EVENT_HOUR,
- EVENT_DAY,
- EVENT_MONTH,
- EVENT_DOW,
- EVENT_COMMAND,
- EVENT_ARGS
- };
-
- #define PE_Buf BigBufTwo
-
- struct CyberNode *ParseEvent(STRPTR event)
- {
- struct CyberNode *cn;
- struct RDArgs *PArgsPtr;
- struct RDArgs *PMyArgs;
- char *ArgArray[PEARG_sizeof];
-
- register char **EventArgs;
- register int index;
- ULONG size;
- ULONG Bits[2];
-
- /* allocate our RDArgs structure */
- if (!(PMyArgs = (struct RDArgs *) AllocDosObject(DOS_RDARGS, TAG_DONE)))
- return (struct CyberNode *) NULL;
-
- PMyArgs->RDA_Flags |= RDAF_NOPROMPT;
-
- /*
- * set up the buffer for our ReadArgs() call. We have to copy over
- * the string and put a new line at the end of it because of a
- * limitation of ReadArgs(). sigh.
- */
-
- {
- ULONG length;
-
- length = strlen(event);
- if (length + 2 > sizeof(PE_Buf)) {
- FreeDosObject(DOS_RDARGS, PMyArgs);
- return (struct CyberNode *) NULL;
- }
-
- CopyMem(event, PE_Buf, length);
-
- PE_Buf[length++] = '\n';
- PE_Buf[length] = '\0';
-
- PMyArgs->RDA_Source.CS_Buffer = PE_Buf;
- PMyArgs->RDA_Source.CS_Length = length;
- PMyArgs->RDA_Source.CS_CurChr = 0L;
- }
-
- /*
- * here we walk through the event line to make sure it isnt all
- * blank.
- */
-
- while (isspace(*event))
- event++;
-
- if (!*event) {
- FreeDosObject(DOS_RDARGS, PMyArgs);
- return (struct CyberNode *) NULL;
- }
-
- memset(ArgArray, 0, sizeof(ArgArray));
-
- /* now we call ReadArgs() */
- PArgsPtr = ReadArgs(PE_TEMPLATE, (LONG *) & ArgArray, PMyArgs);
-
- if (!PArgsPtr) {
- FreeDosObject(DOS_RDARGS, PMyArgs);
- return (struct CyberNode *) NULL;
- }
-
- /*
- * if they specified a name to be known as via the rexx port, make
- * sure it doesn't start with 0x because that's what we use to prefix
- * a hex number for nodes with no name and we don't want the user
- * fooling around with names we consider private.
- */
-
- if (ArgArray[PEARG_REXXNAME])
- if (ArgArray[PEARG_REXXNAME][0] == '0' && tolower(ArgArray[PEARG_REXXNAME][1]) == 'x') {
- FreeArgs(PArgsPtr);
- FreeDosObject(DOS_RDARGS, PMyArgs);
- return (struct CyberNode *) NULL;
- }
-
-
- /*
- * ok, ReadArgs has parsed the event for us. make sure that we have
- * at least 5 time specs and a command name.
- */
- EventArgs = (char **) ArgArray[PEARG_EVENT];
-
- for (index = EVENT_MINUTE; index < EVENT_COMMAND; index++, EventArgs++)
- if (!*EventArgs || !isdigit(*EventArgs[0]) && *EventArgs[0] != '*') {
- FreeArgs(PArgsPtr);
- FreeDosObject(DOS_RDARGS, PMyArgs);
- return (struct CyberNode *) NULL;
- }
-
- /*
- * we have the five time spec strings. now check to make sure we
- * have a command name. we will also calculate its size as well as
- * the size of any args for the command while we are at it
- */
-
- if (!*EventArgs) {
- FreeArgs(PArgsPtr);
- FreeDosObject(DOS_RDARGS, PMyArgs);
- return (struct CyberNode *) NULL;
- }
-
- size = strlen(*EventArgs++) + 1;
-
- while (*EventArgs)
- size += strlen(*EventArgs++) + 1;
-
- /*
- * now figure out the memory needed to store the other textual items
- * for this node
- */
-
- if (ArgArray[PEARG_REDIRIN])
- size += strlen(ArgArray[PEARG_REDIRIN]) + 1;
-
- if (ArgArray[PEARG_REDIROUT])
- size += strlen(ArgArray[PEARG_REDIROUT]) + 1;
- if (ArgArray[PEARG_REDIROUT2]) {
- size += strlen(ArgArray[PEARG_REDIROUT2]) + 1;
- if (ArgArray[PEARG_REDIROUT])
- size -= strlen(ArgArray[PEARG_REDIROUT]) + 1;
- }
-
- if (ArgArray[PEARG_REDIRERR])
- size += strlen(ArgArray[PEARG_REDIRERR]) + 1;
- if (ArgArray[PEARG_REDIRERR2]) {
- size += strlen(ArgArray[PEARG_REDIRERR2]) + 1;
- if (ArgArray[PEARG_REDIRERR])
- size -= strlen(ArgArray[PEARG_REDIRERR]) + 1;
- }
-
- if (ArgArray[PEARG_REXXNAME])
- size += strlen(ArgArray[PEARG_REXXNAME]) + 1;
- if (ArgArray[PEARG_CUSTOMSH])
- size += strlen(ArgArray[PEARG_CUSTOMSH]) + 1;
-
- if (ArgArray[PEARG_MAILUSER])
- size += strlen(ArgArray[PEARG_MAILUSER]) + 1;
-
- if (ArgArray[PEARG_OBEYQUEUE] && !isalpha(ArgArray[PEARG_OBEYQUEUE][0])) {
- FreeArgs(PArgsPtr);
- FreeDosObject(DOS_RDARGS, PMyArgs);
- return (struct CyberNode *) NULL;
- }
-
- if (!(cn = (struct CyberNode *) AllocVec(size + sizeof(struct CyberNode) + 1, MEMF_CLEAR))) {
- FreeArgs(PArgsPtr);
- FreeDosObject(DOS_RDARGS, PMyArgs);
- return (struct CyberNode *) NULL;
- }
-
- /*
- * now that we have got the memory for the CyberNode start filling it
- * in. we start by testing the STACK and PRI fields of the arg list
- * and use Atol() to get their values if present. We then test the
- * REXX and NOLOG flags and use them to set the cn_Flags element.
- */
-
- if (ArgArray[PEARG_STACK])
- cn->cn_Stack = *((LONG *) ArgArray[PEARG_STACK]);
- if (cn->cn_Stack < 2048)
- cn->cn_Stack = DefaultStackSize;
-
- if (ArgArray[PEARG_PRI])
- cn->cn_Priority = *((LONG *) ArgArray[PEARG_PRI]) & 0xFF;
- else
- cn->cn_Priority = DefaultPriority;
-
- if (ArgArray[PEARG_OBEYQUEUE])
- cn->cn_ObeyQueue = tolower(ArgArray[PEARG_OBEYQUEUE][0]) - 'a' + 1;
-
- if (ArgArray[PEARG_REXX])
- cn->cn_Flags |= CNF_REXX;
-
- if (ArgArray[PEARG_NOLOG])
- cn->cn_Flags |= CNF_NOLOG;
-
- if (ArgArray[PEARG_SYSSH])
- cn->cn_Flags |= CNF_SYSSH;
-
- if (ArgArray[PEARG_EXECONE])
- cn->cn_Flags |= CNF_EXECONE;
-
- /*
- * now prepare to copy the textual items over into memory behind the
- * CyberNode
- */
-
- event = (char *) cn + sizeof(struct CyberNode);
-
- if (ArgArray[PEARG_REXXNAME]) {
- cn->cn_Name = event;
- size = strlen(ArgArray[PEARG_REXXNAME]) + 1;
- CopyMem(ArgArray[PEARG_REXXNAME], event, size);
- event += size;
- }
- if (ArgArray[PEARG_REDIRIN]) {
- cn->cn_ReDirIn = event;
- size = strlen(ArgArray[PEARG_REDIRIN]) + 1;
- CopyMem(ArgArray[PEARG_REDIRIN], event, size);
- event += size;
- }
- if (ArgArray[PEARG_REDIROUT] && !ArgArray[PEARG_REDIROUT2]) {
- cn->cn_ReDirOut = event;
- size = strlen(ArgArray[PEARG_REDIROUT]) + 1;
- CopyMem(ArgArray[PEARG_REDIROUT], event, size);
- event += size;
- }
- if (ArgArray[PEARG_REDIROUT2]) {
- cn->cn_ReDirOut = event;
- size = strlen(ArgArray[PEARG_REDIROUT2]) + 1;
- CopyMem(ArgArray[PEARG_REDIROUT2], event, size);
- event += size;
- cn->cn_Flags |= CNF_OUTAPP;
- }
- if (ArgArray[PEARG_REDIRERR] && !ArgArray[PEARG_REDIRERR2]) {
- cn->cn_ReDirErr = event;
- size = strlen(ArgArray[PEARG_REDIRERR]) + 1;
- CopyMem(ArgArray[PEARG_REDIRERR], event, size);
- event += size;
- }
- if (ArgArray[PEARG_REDIRERR2]) {
- cn->cn_ReDirErr = event;
- size = strlen(ArgArray[PEARG_REDIRERR2]) + 1;
- CopyMem(ArgArray[PEARG_REDIRERR2], event, size);
- event += size;
- cn->cn_Flags |= CNF_ERRAPP;
- }
- if (ArgArray[PEARG_CUSTOMSH]) {
- cn->cn_CustomShell = event;
- size = strlen(ArgArray[PEARG_CUSTOMSH]) + 1;
- CopyMem(ArgArray[PEARG_CUSTOMSH], event, size);
- event += size;
- }
- if (ArgArray[PEARG_MAILUSER]) {
- cn->cn_SendToUser = event;
- size = strlen(ArgArray[PEARG_MAILUSER]) + 1;
- CopyMem(ArgArray[PEARG_MAILUSER], event, size);
- event += size;
- }
-
- EventArgs = (char **) ArgArray[PEARG_EVENT];
- cn->cn_Command = event;
- index = EVENT_COMMAND;
- size = strlen(EventArgs[index]);
- CopyMem(EventArgs[index++], event, size);
- event += size;
- *event++ = 0;
-
- if (EventArgs[index]) {
- cn->cn_Args = event;
- while (EventArgs[index]) {
- size = strlen(EventArgs[index]);
- CopyMem(EventArgs[index++], event, size);
- event += size;
- *event++ = ' ';
- }
- }
- else
- cn->cn_Args = NULL;
-
- *--event = 0;
-
- /*
- * Now we need to convert the ASCII time values into bitmaps to store
- * in the node. Note that we do not check to see if the time strings
- * are within range or not. We simply logically AND away any invalid
- * bits and use whats left.
- */
-
- ParseBits(Bits, EventArgs[EVENT_MINUTE]);
- cn->cn_LoMin = Bits[0], cn->cn_HiMin = Bits[1] & 0xFFFFFFF;
-
- ParseBits(Bits, EventArgs[EVENT_HOUR]);
- cn->cn_Hour = Bits[0] & 0xFFFFFF;
-
- ParseBits(Bits, EventArgs[EVENT_DAY]);
- cn->cn_Day = Bits[0] & 0xFFFFFFFE;
-
- ParseBits(Bits, EventArgs[EVENT_MONTH]);
- cn->cn_Month = Bits[0] & 0x1FFE;
-
- ParseBits(Bits, EventArgs[EVENT_DOW]);
- cn->cn_DayOfWeek = Bits[0] & 0x7F;
-
- /*
- * we need to see if cn_Command has any spaces in it and set
- * cn_CommandHasSpace accordingly. this lets the job starters make
- * some more intelligent choices.
- */
-
- {
- BOOL HasSpace;
- STRPTR ptr;
-
- HasSpace = FALSE;
-
- for (ptr = cn->cn_Command; *ptr; ptr++)
- if (isspace(*ptr)) {
- HasSpace = TRUE;
- break;
- }
-
- cn->cn_CommandHasSpace = HasSpace;
- }
-
- FreeArgs(PArgsPtr);
- FreeDosObject(DOS_RDARGS, PMyArgs);
- return cn;
- }
-
- /*
- * this routine will try to figure out the next time an event would be
- * executed.
- */
-
- ULONG EventNextExecutes(struct CyberNode * cn, SystemTime_t * st)
- {
- ULONG days, days2;
- ULONG min, hour, day, month, dow, year;
- ULONG dayTarget, yearTarget;
- BOOL isLeap;
-
- for (days = -1, year = 1978; year < st->st_Year; year++)
- days += LEAP(year) ? 366 : 365;
-
- yearTarget = year + 8;
-
- for (; year < yearTarget; year++) {
- isLeap = LEAP(year);
-
- for (month = (year == st->st_Year) ? st->st_Month : 1; month < 13; month++)
- if (cn->cn_Month & (1L << month)) {
- day = (month == st->st_Month && year == st->st_Year) ? st->st_Day : 1;
- dayTarget = DayTable[isLeap][month - 1] + 1;
-
- {
- int i;
-
- for (days2 = days, i = 1; i < month; i++)
- days2 += DayTable[isLeap][i - 1];
- }
-
- dow = (days2 + day) % 7;
-
- for (; day < dayTarget; day++, dow = ++dow % 7)
- if ((cn->cn_DayOfWeek & (1L << dow)) && (cn->cn_Day & (1L << day)))
- for (hour = (day == st->st_Day && month == st->st_Month && year == st->st_Year) ? st->st_Hour : 0; hour < 24; hour++)
- if (cn->cn_Hour & (1L << hour))
- for (min = (hour == st->st_Hour && day == st->st_Day && month == st->st_Month && year == st->st_Year) ? st->st_Min + 1 : 0; min < 60; min++)
- if ((min > 31 && cn->cn_HiMin & (1L << (min - 32))) ||
- (min < 32 && cn->cn_LoMin & (1L << min)))
- return ((days2 + day) * SECSINDAY +
- (hour * SECSINHOUR) +
- (min * SECSINMINUTE));
- }
-
- days += isLeap ? 366 : 365;
- }
-
- /*
- * if we get down here then we couldn't find anytime within a seven
- * year span that satisfies the requirements to run this event. we
- * return zero in this case to let the caller know that no match was
- * found
- */
- return 0;
- }
-
- /*
- * this will take an ASCII time string and convert it into a bitmap for
- * storage in a CyberNode
- */
-
- void ParseBits(ULONG * bits, STRPTR tstr)
- {
- register char *ptr;
- int start, end;
- int save;
-
- if (*tstr == '*') {
- bits[0] = bits[1] = 0xFFFFFFFF;
- return;
- }
- else
- bits[0] = bits[1] = 0;
-
- for (;;) {
- ptr = tstr;
- while (isdigit(*ptr))
- ptr++;
-
- save = *ptr, *ptr = NULL;
- end = start = atol(tstr);
-
- if (save == '-') {
- tstr = ++ptr;
-
- while (isdigit(*ptr))
- ptr++;
-
- save = *ptr, *ptr = NULL;
- end = atol(tstr);
- }
-
- if (start >= 0 && end >= start)
- while (start <= end) {
- if (start >= 64)
- break;
-
- if (start < 32)
- bits[0] |= 1L << start;
- else
- bits[1] |= 1L << (start - 32);
-
- start++;
- }
-
- if (!save)
- break;
- else
- tstr = ptr + 1;
- }
- }
-
- /* convert a bit field back into an ASCII time string */
-
- void UnParseBits(ULONG * bits, STRPTR ptr, int lowBit, int hiBit)
- {
- STRPTR tptr;
- int curBit, startBit;
- BOOL isOn, lastOn;
-
- /* first check to see if everything is specified and return "*" if so */
- for (curBit = lowBit; curBit <= hiBit; curBit++)
- if ((curBit < 32 && !(bits[0] & 1L << curBit)) || (curBit > 31 && !(bits[1] & 1L << (curBit - 32))))
- break;
-
- if (curBit == hiBit + 1) {
- strcpy(ptr, "*");
- return;
- }
-
- /* it's not "*" so walk through and build things the hard way */
- tptr = ptr;
- *tptr = 0;
- lastOn = FALSE;
-
- for (curBit = lowBit; curBit < hiBit + 2; curBit++) {
- if ((curBit < 32 && (bits[0] & 1L << curBit)) || (curBit > 31 && (bits[1] & 1L << (curBit - 32))))
- isOn = TRUE;
- else
- isOn = FALSE;
-
- if (isOn & !lastOn) {
- sprintf(tptr, "%ld", curBit);
- startBit = curBit;
- }
-
- if (!isOn)
- if (lastOn && startBit != curBit - 1)
- sprintf(tptr, "-%ld,", curBit - 1);
- else if (tptr > ptr && *(tptr - 1) != ',')
- strcpy(tptr, ",");
-
- tptr += strlen(tptr);
- lastOn = isOn;
- }
-
- if (tptr == ptr)
- strcpy(ptr, "*"); /* Uh oh. Somehow we have a field
- * with nothing specified. Fill it
- * in with a "*" */
-
- else
- *--tptr = '\0';
-
- return;
- }
-
- /* find a specific CyberNode by name */
-
- struct CyberNode *FindEvent(STRPTR name)
- {
- struct CyberNode *cn;
- struct CyberNode *eventAddr;
-
- if (!name || name[0] == '\0')
- return (struct CyberNode *) NULL;
-
- if (name[0] == '0' && tolower(name[1]) == 'x')
- stch_l(&name[2], (long *) &eventAddr);
- else
- eventAddr = 0;
-
- for (cn = (struct CyberNode *) EventList.lh_Head; cn->cn_Node.ln_Succ;
- cn = (struct CyberNode *) cn->cn_Node.ln_Succ)
- if (cn == eventAddr || (cn->cn_Name && stricmp(name, cn->cn_Name) == 0))
- return cn;
-
- return (struct CyberNode *) NULL;
- }
-
- /*
- * this routine will walk through the event list and free all the nodes in
- * it of a given type. If called with TRUE it will free crontab entries,
- * otherwise it will free Rexx entries
- */
-
- void FreeEvents(BOOL DoCronTabEntries)
- {
- register struct CyberNode *cn;
- register struct CyberNode *tcn;
- UBYTE Flags;
-
- for (cn = (struct CyberNode *) EventList.lh_Head; cn->cn_Node.ln_Succ;
- cn = (struct CyberNode *) cn->cn_Node.ln_Succ) {
- Flags = cn->cn_Flags & CNF_CRONTAB;
-
- if ((DoCronTabEntries && Flags) || (!DoCronTabEntries && !Flags)) {
- tcn = (struct CyberNode *) cn->cn_Node.ln_Pred;
- DeleteEvent(cn);
- cn = tcn;
- }
- }
- }
-
- /*
- * this will delete the resources used for a specific event. it checks to
- * see if there are any QueueFIFO messages pending for the specified event
- * and removes them as needed.
- */
-
- void DeleteEvent(struct CyberNode * cn)
- {
- register struct QueueFIFO *qf;
- register struct QueueFIFO *tqf;
-
- if (cn->cn_DelayedCount) {
- for (qf = (struct QueueFIFO *) & jobQueue[cn->cn_ObeyQueue].jq_FIFOList;
- qf->qf_Node.mln_Succ; qf = (struct QueueFIFO *) qf->qf_Node.mln_Succ) {
- if (qf->qf_CyberNode == cn) {
- tqf = (struct QueueFIFO *) qf->qf_Node.mln_Pred;
- Remove((struct Node *) qf);
- FreeVec(qf);
- qf = tqf;
- }
- }
- }
-
- Remove((struct Node *) cn);
- FreeVec(cn);
- }
-
- /*
- * this allocates an output filehandle for us which output will be piped
- * through to sendmail over
- */
-
- #define SSM_Buf BigBufOne
- #define SSM_Buf2 BigBufTwo
-
- BPTR SetupSendMail(STRPTR cmdName, STRPTR cmdArgs, STRPTR userName)
- {
- BPTR pfho, pfhi, ofh;
- UBYTE pipeName[36];
-
- struct timeval tr_time;
-
- GetSysTime(&tr_time);
-
- sprintf(pipeName, "PIPE:CyberCron.%08lx.%08lx", tr_time.tv_secs, tr_time.tv_micro);
-
- sprintf(SSM_Buf2, GetString(&LocaleInfo, MSG_REALNAME_TEMPLATE), CYBERCRON, VersionID);
- sprintf(SSM_Buf, SendMailCmd, "cybercron", SSM_Buf2);
-
- ofh = Open("NIL:", MODE_NEWFILE);
- if (!ofh)
- return NULL;
-
- pfho = Open(pipeName, MODE_NEWFILE);
- if (!pfho) {
- Close(ofh);
- return NULL;
- }
-
- pfhi = Open(pipeName, MODE_OLDFILE);
- if (!pfhi) {
- Close(pfho);
- Close(ofh);
- return NULL;
- }
-
- if (SystemTags(SSM_Buf, SYS_Input, pfhi, SYS_Output, ofh, SYS_Asynch, TRUE,
- NP_StackSize, 32768, NP_CopyVars, TRUE, NP_Cli, TRUE, TAG_DONE) == -1) {
- Close(pfho);
- Close(pfhi);
- Close(ofh);
- return NULL;
- }
-
- FPrintf(pfho, GetString(&LocaleInfo, MSG_TO_SUBJECT), userName, cmdName, (cmdArgs ? " " : NULL), cmdArgs);
- Flush(pfho);
-
- return pfho;
- }
-
- UBYTE SJ_Buf[1024 + 12];
- UBYTE CN_Buf[sizeof(SJ_Buf)];
-
- /* this routine will start up a job using System() */
-
- void StartSystemJob(struct CyberNode * cn)
- {
- BPTR ifh, ofh /* , efh */ ;
- struct SystemECdata *ecdata;
-
- struct TagItem tlist[20];
- int tlistIdx = 0;
-
- if (cn->cn_Args) {
- if (cn->cn_CommandHasSpace)
- sprintf(SJ_Buf, "\"%s\" %s", cn->cn_Command, cn->cn_Args);
- else
- sprintf(SJ_Buf, "%s %s", cn->cn_Command, cn->cn_Args);
-
- sprintf(CN_Buf, "\"╗%s½ %s\"", cn->cn_Command, cn->cn_Args);
- }
- else {
- if (cn->cn_CommandHasSpace)
- sprintf(SJ_Buf, "\"%s\"", cn->cn_Command);
- else
- strcpy(SJ_Buf, cn->cn_Command);
-
- sprintf(CN_Buf, "\"╗%s½\"", cn->cn_Command);
- }
-
- if (!(ecdata = AllocVec(sizeof(struct SystemECdata), MEMF_CLEAR)))
- return;
-
- ecdata->jobNo = GetJobNum();
- if (!ecdata->jobNo) {
- Log(MSG_JOB_TABLE_FULL, CN_Buf);
- FreeVec(ecdata);
- return;
- }
-
- if (cn->cn_ReDirIn)
- ifh = Open(cn->cn_ReDirIn, MODE_OLDFILE);
- else
- ifh = Open("NIL:", MODE_OLDFILE);
-
- if (!ifh) {
- Log(MSG_COULDNT_OPEN_REDIRECTION, GetString(&LocaleInfo, MSG_REDIRIN), CN_Buf);
- FreeJobNum(ecdata->jobNo);
- FreeVec(ecdata);
- return;
- }
-
- tlist[tlistIdx].ti_Tag = SYS_Input;
- tlist[tlistIdx++].ti_Data = (ULONG) ifh;
-
- if (cn->cn_SendToUser && SendMailCmd[0])
- ofh = SetupSendMail(cn->cn_Command, cn->cn_Args, cn->cn_SendToUser);
- else {
- if (cn->cn_ReDirOut)
- ofh = Open(cn->cn_ReDirOut, (cn->cn_Flags & CNF_OUTAPP ? MODE_READWRITE : MODE_NEWFILE));
- else
- ofh = Open("NIL:", MODE_NEWFILE);
-
- if (ofh && (cn->cn_Flags & CNF_OUTAPP))
- Seek(ofh, 0, OFFSET_END);
- }
-
- if (!ofh) {
- Log(MSG_COULDNT_OPEN_REDIRECTION, GetString(&LocaleInfo, MSG_REDIROUT), CN_Buf);
- Close(ifh);
- FreeJobNum(ecdata->jobNo);
- FreeVec(ecdata);
- return;
- }
-
- tlist[tlistIdx].ti_Tag = SYS_Output;
- tlist[tlistIdx++].ti_Data = (ULONG) ofh;
-
- tlist[tlistIdx].ti_Tag = SYS_Asynch;
- tlist[tlistIdx++].ti_Data = TRUE;
-
- /*
- Sigh.. Randell tells me that StdErr is pretty much unofficially "not for use"
- under 2.0. This is here for the day that it can be used. All that should need
- to be done is to pull out the comments. Oh well.
-
- Do not uncomment this code. NP_Error and NP_ErrorClose are __IGNORED__ by the
- system right now so if you specify stderr redirection, it will open the file and never
- close it.
-
- if (cn->cn_ReDirErr) {
- efh = Open(cn->cn_ReDirErr, (cn->cn_Flags & CNF_ERRAPP ? MODE_READWRITE : MODE_NEWFILE));
- if (!efh) {
- Log(MSG_COULDNT_OPEN_REDIRECTION, GetString(&LocaleInfo, MSG_REDIRERR), CN_Buf);
- Close(ofh);
- Close(ifh);
- FreeJobNum(ecdata->jobNo);
- FreeVec(ecdata);
- return;
- }
-
- if (cn->cn_Flags & CNF_ERRAPP)
- Seek(efh, 0, OFFSET_END);
-
- tlist[tlistIdx].ti_Tag = NP_Error;
- tlist[tlistIdx++].ti_Data = (ULONG)efh;
- tlist[tlistIdx].ti_Tag = NP_CloseError;
- tlist[tlistIdx++].ti_Data = TRUE;
- } else {
- tlist[tlistIdx].ti_Tag = NP_Error;
- tlist[tlistIdx++].ti_Data = (ULONG)StdErr;
- tlist[tlistIdx].ti_Tag = NP_CloseError;
- tlist[tlistIdx++].ti_Data = FALSE;
- }
- */
- tlist[tlistIdx].ti_Tag = NP_StackSize;
- tlist[tlistIdx++].ti_Data = (ULONG) cn->cn_Stack;
-
- tlist[tlistIdx].ti_Tag = NP_Priority;
- tlist[tlistIdx++].ti_Data = (ULONG) cn->cn_Priority;
-
- if (cn->cn_CustomShell) {
- tlist[tlistIdx].ti_Tag = SYS_CustomShell;
- tlist[tlistIdx++].ti_Data = (ULONG) cn->cn_CustomShell;
- }
- else {
- tlist[tlistIdx].ti_Tag = SYS_UserShell;
- tlist[tlistIdx++].ti_Data = ((cn->cn_Flags & CNF_SYSSH) ? FALSE : TRUE);
- }
-
- tlist[tlistIdx].ti_Tag = NP_Cli;
- tlist[tlistIdx++].ti_Data = TRUE;
-
- tlist[tlistIdx].ti_Tag = NP_CopyVars;
- tlist[tlistIdx++].ti_Data = TRUE;
-
- tlist[tlistIdx].ti_Tag = NP_ExitCode;
- tlist[tlistIdx++].ti_Data = (ULONG) & EndSystemJob;
-
- tlist[tlistIdx].ti_Tag = NP_ExitData;
- tlist[tlistIdx++].ti_Data = (ULONG) ecdata;
-
- tlist[tlistIdx].ti_Tag = TAG_DONE;
- tlist[tlistIdx].ti_Data = 0;
-
- ecdata->queueNo = cn->cn_ObeyQueue;
- ecdata->flags = cn->cn_Flags & CNF_NOLOG;
-
- if (SystemTagList(SJ_Buf, tlist) == -1) {
- Log(MSG_COULDNT_START_SYSTEM_JOB, CN_Buf);
- /*
- See above for why this is currently commented out.
-
- if (cn->cn_ReDirErr)
- Close(efh);
- */
- Close(ofh);
- Close(ifh);
- FreeJobNum(ecdata->jobNo);
- FreeVec(ecdata);
- return;
- }
-
- if (!(cn->cn_Flags & CNF_NOLOG))
- Log(MSG_JOB_STARTED, ecdata->jobNo, CN_Buf);
-
- ObtainSemaphore(&jobSema->mps_Sema);
- NumSystemJobs++;
- jobQueue[cn->cn_ObeyQueue].jq_Cur++;
- ReleaseSemaphore(&jobSema->mps_Sema);
- }
-
- int __saveds __asm EndSystemJob(register __d0 int rc, register __d1 struct SystemECdata * data)
- {
- if (!data->flags)
- Log(MSG_JOB_ENDED, data->jobNo);
-
- FreeJobNum(data->jobNo);
-
- ObtainSemaphore(&jobSema->mps_Sema);
- NumSystemJobs--;
- jobQueue[data->queueNo].jq_Cur--;
- ReleaseSemaphore(&jobSema->mps_Sema);
-
- FreeVec(data);
-
- return rc;
- }
-
- void StartRexxJob(struct CyberNode * cn)
- {
- struct RexxMsg *msg;
- struct MsgPort *rexxServerPort;
- UWORD jobNo;
- BPTR ifh, ofh;
-
- if (cn->cn_Command[0] == '`') {
- if (cn->cn_Args)
- sprintf(SJ_Buf, "%s %s", &cn->cn_Command[1], cn->cn_Args);
- else
- strcpy(SJ_Buf, &cn->cn_Command[1]);
-
- sprintf(CN_Buf, "\"%s\"", SJ_Buf);
- }
- else {
- strcpy(SJ_Buf, cn->cn_Command);
- sprintf(CN_Buf, "\"╗%s½%s%s\"", cn->cn_Command, (cn->cn_Args ? " " : NULL), cn->cn_Args);
- }
-
- if (GetARexxLib() == NULL) {
- ErrorMsg(MSG_CANT_START_AREXX_NO_LIB, CN_Buf, RXSNAME);
- Log(MSG_CANT_START_AREXX_NO_LIB, CN_Buf, RXSNAME);
- return;
- }
-
- jobNo = GetJobNum();
- if (!jobNo) {
- Log(MSG_JOB_TABLE_FULL, CN_Buf);
- FreeARexxLib();
- return;
- }
-
- if (cn->cn_ReDirIn)
- ifh = Open(cn->cn_ReDirIn, MODE_OLDFILE);
- else
- ifh = Open("NIL:", MODE_OLDFILE);
-
- if (!ifh) {
- Log(MSG_COULDNT_OPEN_REDIRECTION, GetString(&LocaleInfo, MSG_REDIRIN), CN_Buf);
- FreeJobNum(jobNo);
- FreeARexxLib();
- return;
- }
-
- if (cn->cn_SendToUser && SendMailCmd[0])
- ofh = SetupSendMail((cn->cn_Command[0] == '`' ? SJ_Buf : cn->cn_Command),
- (cn->cn_Command[0] == '`' ? NULL : cn->cn_Args), cn->cn_SendToUser);
- else {
- if (cn->cn_ReDirOut)
- ofh = Open(cn->cn_ReDirOut, (cn->cn_Flags & CNF_OUTAPP ? MODE_READWRITE : MODE_NEWFILE));
- else
- ofh = Open("NIL:", MODE_NEWFILE);
-
- if (ofh && (cn->cn_Flags & CNF_OUTAPP))
- Seek(ofh, 0, OFFSET_END);
- }
-
- if (!ofh) {
- Log(MSG_COULDNT_OPEN_REDIRECTION, GetString(&LocaleInfo, MSG_REDIROUT), CN_Buf);
- Close(ifh);
- FreeJobNum(jobNo);
- FreeARexxLib();
- return;
- }
-
- if (!(msg = CreateRexxMsg(RexxPort, "rexx", RXSDIR))) {
- Log(MSG_CANT_CREATE_AREXX_OBJECT, GetString(&LocaleInfo, MSG_REXXMSG), CN_Buf);
- Close(ofh);
- Close(ifh);
- FreeJobNum(jobNo);
- FreeARexxLib();
- return;
- }
-
- if (!(msg->rm_Args[0] = CreateArgstring(SJ_Buf, strlen(SJ_Buf)))) {
- Log(MSG_CANT_CREATE_AREXX_OBJECT, GetString(&LocaleInfo, MSG_ARGSTRING), CN_Buf);
- DeleteRexxMsg(msg);
- Close(ofh);
- Close(ifh);
- FreeJobNum(jobNo);
- FreeARexxLib();
- return;
- }
-
- if (cn->cn_Args && cn->cn_Command[0] != '`') {
- if (!(msg->rm_Args[1] = CreateArgstring(cn->cn_Args, strlen(cn->cn_Args)))) {
- Log(MSG_CANT_CREATE_AREXX_OBJECT, GetString(&LocaleInfo, MSG_ARGSTRING), CN_Buf);
- DeleteArgstring(msg->rm_Args[0]);
- DeleteRexxMsg(msg);
- Close(ofh);
- Close(ifh);
- FreeJobNum(jobNo);
- FreeARexxLib();
- return;
- }
- }
- else
- msg->rm_Args[1] = NULL;
-
- msg->rm_Action = RXFUNC;
- if (cn->cn_Command[0] == '`')
- msg->rm_Action |= RXFF_STRING;
-
- if (msg->rm_Args[1])
- msg->rm_Action |= 1; /* one argument string passed in */
-
- msg->rm_Args[2] = (STRPTR) jobNo;
- msg->rm_Args[3] = (STRPTR) (cn->cn_Flags & CNF_NOLOG);
- msg->rm_Args[4] = (STRPTR) cn->cn_ObeyQueue;
-
- msg->rm_Stdin = ifh;
- msg->rm_Stdout = ofh;
-
- Forbid();
- if (rexxServerPort = FindPort(RXSDIR))
- PutMsg(rexxServerPort, (struct Message *) msg);
- Permit();
-
- if (rexxServerPort) {
- if (!msg->rm_Args[3])
- Log(MSG_JOB_STARTED, jobNo, CN_Buf);
- ObtainSemaphore(&jobSema->mps_Sema);
- NumARexxJobs++;
- jobQueue[cn->cn_ObeyQueue].jq_Cur++;
- ReleaseSemaphore(&jobSema->mps_Sema);
- }
- else {
- Log(MSG_CANT_FIND_REXX_HOST, RXSDIR, CN_Buf);
- if (msg->rm_Args[1])
- DeleteArgstring(msg->rm_Args[1]);
- DeleteArgstring(msg->rm_Args[0]);
- DeleteRexxMsg(msg);
- Close(ofh);
- Close(ifh);
- FreeJobNum(jobNo);
- }
-
- FreeARexxLib();
- }
-
- /*
- * this routine will attempt to get a job number for us. it returns the job
- * number or 0 if no jobs are free.
- */
-
- UWORD GetJobNum(void)
- {
- register UWORD job;
- register int index;
- register UBYTE mask;
-
- ObtainSemaphore(&jobSema->mps_Sema);
-
- for (job = 0; job < JOB_TABLE_SIZE * sizeof(UBYTE); job++) {
- index = job / sizeof(UBYTE);
- mask = 1L << (job - index * sizeof(UBYTE));
-
- if (jobSema->mps_SemaData[index] & mask)
- continue;
-
- jobSema->mps_SemaData[index] |= mask;
- ReleaseSemaphore(&jobSema->mps_Sema);
- return (UWORD) (job + 1);
- }
-
- ReleaseSemaphore(&jobSema->mps_Sema);
- return (UWORD) 0;
- }
-
- /* this routine will free a job number previously allocated */
-
- void FreeJobNum(UWORD job)
- {
- register int index;
- register UBYTE mask;
-
- if (!job || job >= JOB_TABLE_SIZE * sizeof(UBYTE))
- return;
-
- job--;
-
- index = job / sizeof(UBYTE);
- mask = 1L << (job - index * sizeof(UBYTE));
-
- ObtainSemaphore(&jobSema->mps_Sema);
- jobSema->mps_SemaData[index] &= ~mask;
- ReleaseSemaphore(&jobSema->mps_Sema);
- }
-
- void __stdargs Log(ULONG fmtId,...)
- {
- va_list args;
- BPTR loghandle;
- struct DateTime dat;
- UBYTE Date[LEN_DATSTRING + 1];
- UBYTE Time[LEN_DATSTRING + 1];
-
- DateStamp(&dat.dat_Stamp);
-
- dat.dat_Format = FORMAT_DOS;
- dat.dat_Flags = 0;
- dat.dat_StrDay = NULL;
- dat.dat_StrDate = Date;
- dat.dat_StrTime = Time;
-
- memset(Date, 0, LEN_DATSTRING + 1);
- memset(Time, 0, LEN_DATSTRING + 1);
- DateToStr(&dat);
-
- va_start(args, fmtId);
-
- ObtainSemaphore(&logSema->mps_Sema);
- if (LogFile[0]) {
- if (OwnDevUnitBase)
- if (LockDevUnit("LOG-UPDATE.LOCK", 0, CYBERCRON, 0L))
- goto dieLog;
-
- if (loghandle = Open(LogFile, MODE_READWRITE)) {
- Seek(loghandle, 0, OFFSET_END);
-
- FPrintf(loghandle, "(%s %s) ", Date, Time);
- VFPrintf(loghandle, GetString(&LocaleInfo, fmtId), (LONG *) args);
- FPutC(loghandle, '\n');
- Close(loghandle);
- }
-
- if (OwnDevUnitBase)
- FreeDevUnit("LOG-UPDATE.LOCK", 0);
- }
- dieLog:
- ReleaseSemaphore(&logSema->mps_Sema);
-
- va_end(args);
- }
-
- /*
- * this routine sets up a public semaphore. If it already exists we just
- * bump its use count up by one. Otherwise we have to allocate a new one.
- * semaDataSize is a number of bytes to allocate with the semaphore that can
- * be shared by those locking the semaphore. Let's us have "global" data
- * between seperate processes. These routines don't care what is put in
- * this data space. It will be cleared to 0s when first allocated, though.
- */
-
- struct MyPublicSema *InitMyPublicSemaphore(STRPTR semaName, ULONG semaDataSize)
- {
- struct MyPublicSema *theSema;
- ULONG semaNameLen;
-
- if (!semaName)
- return (struct MyPublicSema *) NULL;
-
- /*
- * we want the semaphore's name to be a longword in length, at least
- * in space allocated for it
- */
- semaNameLen = ((strlen(semaName) + 3) / 4) * 4;
-
- Forbid();
- if (theSema = (struct MyPublicSema *) FindSemaphore(semaName))
- theSema->mps_UseCount++; /* only safe way to diddle
- * with this is under
- * Forbid()... sigh */
- else {
-
- /*
- * we didn't find the semaphore around already so we have to
- * allocate and initialize it
- */
- if (!(theSema = AllocVec(sizeof(struct MyPublicSema) + semaNameLen + semaDataSize, MEMF_CLEAR | MEMF_PUBLIC))) {
- Permit();
- return (struct MyPublicSema *) NULL;
- }
-
- strcpy(theSema->mps_SemaName, semaName);
- theSema->mps_Sema.ss_Link.ln_Name = theSema->mps_SemaName;
- if (semaDataSize)
- theSema->mps_SemaData = &theSema->mps_SemaName[semaNameLen];
- theSema->mps_UseCount = 1;
-
- AddSemaphore(&theSema->mps_Sema);
- }
-
- Permit();
-
- return theSema;
- }
-
- /*
- * this dealocates what we got from InitMyPublicSemaphore(). If there are
- * others still using it then just down the use count. Otherwise remove the
- * semaphore from the public lists and down the use count.
- */
-
- void FreeMyPublicSemaphore(struct MyPublicSema * mySema)
- {
- if (mySema) {
- ObtainSemaphore(&mySema->mps_Sema);
- Forbid();
- ReleaseSemaphore(&mySema->mps_Sema);
- if (!--mySema->mps_UseCount) {
- RemSemaphore(&mySema->mps_Sema);
- FreeVec(mySema);
- }
- Permit();
- }
- }
-
- /*
- * this function will open the ARexx library for us. it handles nested
- * calls to open the library such that we only call OpenLibrary() once. each
- * time a rexx command is run, we call this routine to open the library and
- * when the RexxMsg comes back we call FreeARexxLib() to decrement the nest
- * count.
- */
-
- BOOL GetARexxLib(void)
- {
- if (ARexxLibCount) {
- ARexxLibCount++;
- return TRUE;
- }
-
- if (!(RexxSysBase = (struct RxsLib *) OpenLibrary(RXSNAME, 0)))
- return FALSE;
-
- ARexxLibCount = 1;
- return TRUE;
- }
-
- /*
- * this routine is the opposite of GetARexxLib(). it frees a nested open
- * count for the ARexx library. if the count goes to zero then we call
- * CloseLibrary() to free the library for real.
- */
-
- void FreeARexxLib(void)
- {
- if (!--ARexxLibCount)
- CloseLibrary((struct Library *) RexxSysBase);
- }
-
- /*
- * we use this function to send error messages to StdErr. We prefix all
- * messages with "CyberCron:" since the message might be dumped into a
- * stream with other people sending output to it
- */
-
- void __stdargs ErrorMsg(ULONG fmtId,...)
- {
- va_list args;
-
- struct IntuitionBase *IntuitionBase;
- ULONG my_IDCMP;
- struct EasyStruct ezRequest;
-
-
- if (ErrorsToStdErr) {
- if (StdErr) {
- FPrintf(StdErr, "%s: ", CYBERCRON);
-
- va_start(args, fmtId);
- VFPrintf(StdErr, GetString(&LocaleInfo, fmtId), (LONG *) args);
- FPutC(StdErr, '\n');
- Flush(StdErr);
- va_end(args);
- }
- }
- else {
- /* grab intuition, do an EasyRequest and then free intuition */
- if (IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37L)) {
- ezRequest.es_StructSize = sizeof(struct EasyStruct);
- ezRequest.es_Flags = 0;
- ezRequest.es_Title = GetString(&LocaleInfo, MSG_REQWINTITLE);
- ezRequest.es_TextFormat = GetString(&LocaleInfo, fmtId);
- ezRequest.es_GadgetFormat = GetString(&LocaleInfo, MSG_CONTINUE_GAD);
-
- my_IDCMP = 0L;
-
- va_start(args, fmtId);
- EasyRequestArgs((struct Window *) NULL, &ezRequest, &my_IDCMP, args);
- va_end(args);
-
- CloseLibrary((struct Library *) IntuitionBase);
- }
- }
- }
-
- void GetSystemTime(SystemTime_t * st, BOOL stIsSet)
- {
- struct timeval tr_time;
- struct ClockData cd;
-
- if (!stIsSet) {
- GetSysTime(&tr_time);
- st->st_tvsecs = tr_time.tv_secs;
- }
-
- Amiga2Date(st->st_tvsecs, &cd);
-
- st->st_Year = cd.year;
- st->st_Month = cd.month;
- st->st_Day = cd.mday;
-
- st->st_Hour = cd.hour;
- st->st_Min = cd.min;
- st->st_Sec = cd.sec;
-
- st->st_DOW = cd.wday;
- }
-