2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <sys/types.h>
35 #include <afs/ktime.h>
36 #include <afs/afsutil.h>
37 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
40 static int cron_timeout(), cron_getstat(), cron_setstat(), cron_delete();
41 static int cron_procexit(), cron_getstring(), cron_getparm(), cron_restartp();
42 static int cron_hascore();
43 struct bnode *cron_create();
45 #define SDTIME 60 /* time in seconds given to a process to evaporate */
47 struct bnode_ops cronbnode_ops = {
62 afs_int32 zapTime; /* time we sent a sigterm */
64 char *whenString; /* string rep. of when to run */
65 struct bnode_proc *proc;
66 afs_int32 lastStart; /* time last started process */
67 afs_int32 nextRun; /* next time to run, if no proc running */
68 struct ktime whenToRun; /* high-level rep of when should we run this guy */
69 afs_int32 when; /* computed at creation time and procexit time */
70 char everRun; /* true if ever ran */
71 char waitingForShutdown; /* have we started any shutdown procedure? */
72 char running; /* is process running? */
73 char killSent; /* have we tried sigkill signal? */
77 cron_hascore(register struct ezbnode *abnode)
81 bnode_CoreName(abnode, NULL, tbuffer);
82 if (access(tbuffer, 0) == 0)
88 /* run at creation or after process exit. figures out if we're all done (if a
89 one shot run) or when we should run again. Sleeps until we should run again.
90 Note that the computation of when we should run again is made in procexit
91 and/or create procs. This guy only schedules the sleep */
93 ScheduleCronBnode(register struct cronbnode *abnode)
95 register afs_int32 code;
96 register afs_int32 temp;
97 struct bnode_proc *tp;
99 /* If this proc is shutdown, tell bproc() to no longer run this job */
100 if (abnode->b.goal == BSTAT_SHUTDOWN) {
101 bnode_SetTimeout(abnode, 0);
105 /* otherwise we're supposed to be running, figure out when */
106 if (abnode->when == 0) {
108 if (abnode->everRun) {
110 bnode_Delete(abnode);
113 /* otherwise start it */
114 if (!abnode->running) {
116 abnode->lastStart = FT_ApproxTime();
117 code = bnode_NewProc(abnode, abnode->command, NULL, &tp);
119 bozo_Log("cron bnode %s failed to start (code %d)\n",
120 abnode->b.name, code);
129 /* run periodically */
132 /* otherwise find out when to run it, and do it then */
133 temp = abnode->when - FT_ApproxTime();
135 temp = 1; /* temp is when to start dude */
136 bnode_SetTimeout(abnode, temp);
142 cron_restartp(register struct cronbnode *abnode)
148 cron_delete(struct cronbnode *abnode)
150 free(abnode->command);
151 free(abnode->whenString);
157 cron_create(char *ainstance, char *acommand, char *awhen)
159 struct cronbnode *te;
162 extern char *copystr();
164 /* construct local path from canonical (wire-format) path */
165 if (ConstructLocalBinPath(acommand, &cmdpath)) {
166 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
170 te = (struct cronbnode *)malloc(sizeof(struct cronbnode));
171 memset(te, 0, sizeof(struct cronbnode));
172 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
173 if ((code < 0) || (bnode_InitBnode(te, &cronbnode_ops, ainstance) != 0)) {
178 te->when = ktime_next(&te->whenToRun, 0);
179 te->command = cmdpath;
180 te->whenString = copystr(awhen);
181 return (struct bnode *)te;
184 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
185 start up a process if it is time and not already running */
187 cron_timeout(struct cronbnode *abnode)
189 register afs_int32 temp;
190 register afs_int32 code;
191 struct bnode_proc *tp;
193 if (!abnode->running) {
194 if (abnode->when == 0)
195 return 0; /* spurious timeout activation */
196 /* not running, perhaps we should start it */
197 if (FT_ApproxTime() >= abnode->when) {
198 abnode->lastStart = FT_ApproxTime();
199 bnode_SetTimeout(abnode, 0);
200 code = bnode_NewProc(abnode, abnode->command, NULL, &tp);
202 bozo_Log("cron failed to start bnode %s (code %d)\n",
203 abnode->b.name, code);
210 /* woke up too early, try again */
211 temp = abnode->when - FT_ApproxTime();
214 bnode_SetTimeout(abnode, temp);
217 if (!abnode->waitingForShutdown)
218 return 0; /* spurious */
219 /* send kill and turn off timer */
220 bnode_StopProc(abnode->proc, SIGKILL);
221 abnode->killSent = 1;
222 bnode_SetTimeout(abnode, 0);
228 cron_getstat(struct cronbnode *abnode, afs_int32 * astatus)
230 register afs_int32 temp;
231 if (abnode->waitingForShutdown)
232 temp = BSTAT_SHUTTINGDOWN;
233 else if (abnode->b.goal == 0)
234 temp = BSTAT_SHUTDOWN;
235 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
236 /* special hack: bnode deletion won't happen if bnode is active, so
237 * we make bnodes that are ready to be deleted automatically appear
238 * as BSTAT_SHUTDOWN so bnode_Delete is happy. */
239 temp = BSTAT_SHUTDOWN;
247 cron_setstat(register struct cronbnode *abnode, afs_int32 astatus)
249 if (abnode->waitingForShutdown)
251 if (astatus == BSTAT_SHUTDOWN) {
252 if (abnode->running) {
254 bnode_StopProc(abnode->proc, SIGTERM);
255 abnode->waitingForShutdown = 1;
256 bnode_SetTimeout(abnode, SDTIME);
257 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
258 * [cron_procexit()] which will tell bproc() to no longer
262 /* Tell bproc() to no longer run this cron job */
263 bnode_SetTimeout(abnode, 0);
265 } else if (astatus == BSTAT_NORMAL) {
266 /* start the cron job
267 * Figure out when to run next and schedule it
269 abnode->when = ktime_next(&abnode->whenToRun, 0);
270 ScheduleCronBnode(abnode);
276 cron_procexit(struct cronbnode *abnode, struct bnode_proc *aproc)
278 /* process has exited */
280 /* log interesting errors for folks */
281 if (aproc->lastSignal)
282 bozo_Log("cron job %s exited due to signal %d\n", abnode->b.name,
284 else if (aproc->lastExit)
285 bozo_Log("cron job %s exited with non-zero code %d\n", abnode->b.name,
288 abnode->waitingForShutdown = 0;
290 abnode->killSent = 0;
291 abnode->proc = (struct bnode_proc *)0;
293 /* Figure out when to run next and schedule it */
294 abnode->when = ktime_next(&abnode->whenToRun, 0);
295 ScheduleCronBnode(abnode);
300 cron_getstring(struct cronbnode *abnode, char *abuffer, afs_int32 alen)
303 strcpy(abuffer, "running now");
304 else if (abnode->when == 0)
305 strcpy(abuffer, "waiting to run once");
307 sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
312 cron_getparm(struct cronbnode *abnode, afs_int32 aindex, char *abuffer,
316 strcpy(abuffer, abnode->command);
317 else if (aindex == 1) {
318 strcpy(abuffer, abnode->whenString);