/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ #include #include #include #include #include #include #include #include #include #include "bnode.h" #include "bnode_internal.h" #include "bosprototypes.h" struct bnode *cron_create(char *, char *, char *, char *, char *, char *); static int cron_hascore(struct bnode *bnode); static int cron_restartp(struct bnode *bnode); static int cron_delete(struct bnode *bnode); static int cron_timeout(struct bnode *bnode); static int cron_getstat(struct bnode *bnode, afs_int32 *status); static int cron_setstat(struct bnode *bnode, afs_int32 status); static int cron_procstarted(struct bnode *bnode, struct bnode_proc *proc); static int cron_procexit(struct bnode *bnode, struct bnode_proc *proc); static int cron_getstring(struct bnode *bnode, char *abuffer, afs_int32 alen); static int cron_getparm(struct bnode *bnode, afs_int32, char *, afs_int32); #define SDTIME 60 /* time in seconds given to a process to evaporate */ struct bnode_ops cronbnode_ops = { cron_create, cron_timeout, cron_getstat, cron_setstat, cron_delete, cron_procexit, cron_getstring, cron_getparm, cron_restartp, cron_hascore, cron_procstarted, }; struct cronbnode { struct bnode b; afs_int32 zapTime; /* time we sent a sigterm */ char *command; char *whenString; /* string rep. of when to run */ struct bnode_proc *proc; afs_int32 lastStart; /* time last started process */ afs_int32 nextRun; /* next time to run, if no proc running */ struct ktime whenToRun; /* high-level rep of when should we run this guy */ afs_int32 when; /* computed at creation time and procexit time */ char everRun; /* true if ever ran */ char waitingForShutdown; /* have we started any shutdown procedure? */ char running; /* is process running? */ char killSent; /* have we tried sigkill signal? */ }; static int cron_hascore(struct bnode *abnode) { char tbuffer[256]; bnode_CoreName(abnode, NULL, tbuffer); if (access(tbuffer, 0) == 0) return 1; else return 0; } /* run at creation or after process exit. figures out if we're all done (if a one shot run) or when we should run again. Sleeps until we should run again. Note that the computation of when we should run again is made in procexit and/or create procs. This guy only schedules the sleep */ int ScheduleCronBnode(struct cronbnode *abnode) { afs_int32 code; afs_int32 temp; struct bnode_proc *tp; /* If this proc is shutdown, tell bproc() to no longer run this job */ if (abnode->b.goal == BSTAT_SHUTDOWN) { bnode_SetTimeout((struct bnode *)abnode, 0); return 0; } /* otherwise we're supposed to be running, figure out when */ if (abnode->when == 0) { /* one shot */ if (abnode->everRun) { /* once is enough */ bnode_Delete((struct bnode *)abnode); return 0; } /* otherwise start it */ if (!abnode->running) { /* start up */ abnode->lastStart = FT_ApproxTime(); code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp); if (code) { bozo_Log("cron bnode %s failed to start (code %d)\n", abnode->b.name, code); return code; } abnode->everRun = 1; abnode->running = 1; abnode->proc = tp; return 0; } } else { /* run periodically */ if (abnode->running) return 0; /* otherwise find out when to run it, and do it then */ temp = abnode->when - FT_ApproxTime(); if (temp < 1) temp = 1; /* temp is when to start dude */ bnode_SetTimeout((struct bnode *)abnode, temp); } return 0; } static int cron_restartp(struct bnode *abnode) { return 0; } static int cron_delete(struct bnode *bn) { struct cronbnode *abnode = (struct cronbnode *)bn; free(abnode->command); free(abnode->whenString); free(abnode); return 0; } struct bnode * cron_create(char *ainstance, char *acommand, char *awhen, char *unused1, char *unused2, char *unused3) { struct cronbnode *te; afs_int32 code; char *cmdpath; /* construct local path from canonical (wire-format) path */ if (ConstructLocalBinPath(acommand, &cmdpath)) { bozo_Log("BNODE: command path invalid '%s'\n", acommand); return NULL; } te = calloc(1, sizeof(struct cronbnode)); code = ktime_ParsePeriodic(awhen, &te->whenToRun); if ((code < 0) || (bnode_InitBnode((struct bnode *)te, &cronbnode_ops, ainstance) != 0)) { free(te); free(cmdpath); return NULL; } te->when = ktime_next(&te->whenToRun, 0); te->command = cmdpath; te->whenString = strdup(awhen); return (struct bnode *)te; } /* called to SIGKILL a process if it doesn't terminate normally. In cron, also start up a process if it is time and not already running */ static int cron_timeout(struct bnode *bn) { struct cronbnode *abnode = (struct cronbnode *)bn; afs_int32 temp; afs_int32 code; struct bnode_proc *tp; if (!abnode->running) { if (abnode->when == 0) return 0; /* spurious timeout activation */ /* not running, perhaps we should start it */ if (FT_ApproxTime() >= abnode->when) { abnode->lastStart = FT_ApproxTime(); bnode_SetTimeout((struct bnode *)abnode, 0); code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp); if (code) { bozo_Log("cron failed to start bnode %s (code %d)\n", abnode->b.name, code); return code; } abnode->everRun = 1; abnode->running = 1; abnode->proc = tp; } else { /* woke up too early, try again */ temp = abnode->when - FT_ApproxTime(); if (temp < 1) temp = 1; bnode_SetTimeout((struct bnode *)abnode, temp); } } else { if (!abnode->waitingForShutdown) return 0; /* spurious */ /* send kill and turn off timer */ bnode_StopProc(abnode->proc, SIGKILL); abnode->killSent = 1; bnode_SetTimeout((struct bnode *)abnode, 0); } return 0; } static int cron_getstat(struct bnode *bn, afs_int32 * astatus) { struct cronbnode *abnode = (struct cronbnode *)bn; afs_int32 temp; if (abnode->waitingForShutdown) temp = BSTAT_SHUTTINGDOWN; else if (abnode->b.goal == 0) temp = BSTAT_SHUTDOWN; else if (abnode->everRun && abnode->when == 0 && !abnode->running) { /* special hack: bnode deletion won't happen if bnode is active, so * we make bnodes that are ready to be deleted automatically appear * as BSTAT_SHUTDOWN so bnode_Delete is happy. */ temp = BSTAT_SHUTDOWN; } else temp = BSTAT_NORMAL; *astatus = temp; return 0; } static int cron_setstat(struct bnode *bn, afs_int32 astatus) { struct cronbnode *abnode = (struct cronbnode *)bn; if (abnode->waitingForShutdown) return BZBUSY; if (astatus == BSTAT_SHUTDOWN) { if (abnode->running) { /* start shutdown */ bnode_StopProc(abnode->proc, SIGTERM); abnode->waitingForShutdown = 1; bnode_SetTimeout((struct bnode *)abnode, SDTIME); /* When shutdown is complete, bproc() calls BOP_PROCEXIT() * [cron_procexit()] which will tell bproc() to no longer * run this cron job. */ } else { /* Tell bproc() to no longer run this cron job */ bnode_SetTimeout((struct bnode *)abnode, 0); } } else if (astatus == BSTAT_NORMAL) { /* start the cron job * Figure out when to run next and schedule it */ abnode->when = ktime_next(&abnode->whenToRun, 0); ScheduleCronBnode(abnode); } return 0; } static int cron_procstarted(struct bnode *bn, struct bnode_proc *aproc) { return 0; /* no op */ } static int cron_procexit(struct bnode *bn, struct bnode_proc *aproc) { struct cronbnode *abnode = (struct cronbnode *) bn; /* process has exited */ /* log interesting errors for folks */ if (aproc->lastSignal) bozo_Log("cron job %s exited due to signal %d\n", abnode->b.name, aproc->lastSignal); else if (aproc->lastExit) bozo_Log("cron job %s exited with non-zero code %d\n", abnode->b.name, aproc->lastExit); abnode->waitingForShutdown = 0; abnode->running = 0; abnode->killSent = 0; abnode->proc = (struct bnode_proc *)0; /* Figure out when to run next and schedule it */ abnode->when = ktime_next(&abnode->whenToRun, 0); ScheduleCronBnode(abnode); return 0; } static int cron_getstring(struct bnode *bn, char *abuffer, afs_int32 alen) { struct cronbnode *abnode = (struct cronbnode *)bn; if (abnode->running) strcpy(abuffer, "running now"); else if (abnode->when == 0) strcpy(abuffer, "waiting to run once"); else sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when)); return 0; } static int cron_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer, afs_int32 alen) { struct cronbnode *abnode = (struct cronbnode *)bn; if (aindex == 0) strcpy(abuffer, abnode->command); else if (aindex == 1) { strcpy(abuffer, abnode->whenString); } else return BZDOM; return 0; }