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>
13 #include <afs/procmgmt.h>
23 #include <afs/ktime.h>
24 #include <afs/afsutil.h>
27 #include "bosprototypes.h"
29 struct bnode *cron_create(char *, char *, char *, char *, char *, char *);
30 static int cron_hascore(struct bnode *bnode);
31 static int cron_restartp(struct bnode *bnode);
32 static int cron_delete(struct bnode *bnode);
33 static int cron_timeout(struct bnode *bnode);
34 static int cron_getstat(struct bnode *bnode, afs_int32 *status);
35 static int cron_setstat(struct bnode *bnode, afs_int32 status);
36 static int cron_procexit(struct bnode *bnode, struct bnode_proc *proc);
37 static int cron_getstring(struct bnode *bnode, char *abuffer, afs_int32 alen);
38 static int cron_getparm(struct bnode *bnode, afs_int32, char *, afs_int32);
40 #define SDTIME 60 /* time in seconds given to a process to evaporate */
42 struct bnode_ops cronbnode_ops = {
57 afs_int32 zapTime; /* time we sent a sigterm */
59 char *whenString; /* string rep. of when to run */
60 struct bnode_proc *proc;
61 afs_int32 lastStart; /* time last started process */
62 afs_int32 nextRun; /* next time to run, if no proc running */
63 struct ktime whenToRun; /* high-level rep of when should we run this guy */
64 afs_int32 when; /* computed at creation time and procexit time */
65 char everRun; /* true if ever ran */
66 char waitingForShutdown; /* have we started any shutdown procedure? */
67 char running; /* is process running? */
68 char killSent; /* have we tried sigkill signal? */
72 cron_hascore(struct bnode *abnode)
76 bnode_CoreName(abnode, NULL, tbuffer);
77 if (access(tbuffer, 0) == 0)
83 /* run at creation or after process exit. figures out if we're all done (if a
84 one shot run) or when we should run again. Sleeps until we should run again.
85 Note that the computation of when we should run again is made in procexit
86 and/or create procs. This guy only schedules the sleep */
88 ScheduleCronBnode(struct cronbnode *abnode)
92 struct bnode_proc *tp;
94 /* If this proc is shutdown, tell bproc() to no longer run this job */
95 if (abnode->b.goal == BSTAT_SHUTDOWN) {
96 bnode_SetTimeout((struct bnode *)abnode, 0);
100 /* otherwise we're supposed to be running, figure out when */
101 if (abnode->when == 0) {
103 if (abnode->everRun) {
105 bnode_Delete((struct bnode *)abnode);
108 /* otherwise start it */
109 if (!abnode->running) {
111 abnode->lastStart = FT_ApproxTime();
112 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
114 bozo_Log("cron bnode %s failed to start (code %d)\n",
115 abnode->b.name, code);
124 /* run periodically */
127 /* otherwise find out when to run it, and do it then */
128 temp = abnode->when - FT_ApproxTime();
130 temp = 1; /* temp is when to start dude */
131 bnode_SetTimeout((struct bnode *)abnode, temp);
137 cron_restartp(struct bnode *abnode)
143 cron_delete(struct bnode *bn)
145 struct cronbnode *abnode = (struct cronbnode *)bn;
146 free(abnode->command);
147 free(abnode->whenString);
153 cron_create(char *ainstance, char *acommand, char *awhen,
154 char *unused1, char *unused2, char *unused3)
156 struct cronbnode *te;
160 /* construct local path from canonical (wire-format) path */
161 if (ConstructLocalBinPath(acommand, &cmdpath)) {
162 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
166 te = (struct cronbnode *)malloc(sizeof(struct cronbnode));
167 memset(te, 0, sizeof(struct cronbnode));
168 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
169 if ((code < 0) || (bnode_InitBnode((struct bnode *)te, &cronbnode_ops, ainstance) != 0)) {
174 te->when = ktime_next(&te->whenToRun, 0);
175 te->command = cmdpath;
176 te->whenString = copystr(awhen);
177 return (struct bnode *)te;
180 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
181 start up a process if it is time and not already running */
183 cron_timeout(struct bnode *bn)
185 struct cronbnode *abnode = (struct cronbnode *)bn;
188 struct bnode_proc *tp;
190 if (!abnode->running) {
191 if (abnode->when == 0)
192 return 0; /* spurious timeout activation */
193 /* not running, perhaps we should start it */
194 if (FT_ApproxTime() >= abnode->when) {
195 abnode->lastStart = FT_ApproxTime();
196 bnode_SetTimeout((struct bnode *)abnode, 0);
197 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
199 bozo_Log("cron failed to start bnode %s (code %d)\n",
200 abnode->b.name, code);
207 /* woke up too early, try again */
208 temp = abnode->when - FT_ApproxTime();
211 bnode_SetTimeout((struct bnode *)abnode, temp);
214 if (!abnode->waitingForShutdown)
215 return 0; /* spurious */
216 /* send kill and turn off timer */
217 bnode_StopProc(abnode->proc, SIGKILL);
218 abnode->killSent = 1;
219 bnode_SetTimeout((struct bnode *)abnode, 0);
225 cron_getstat(struct bnode *bn, afs_int32 * astatus)
227 struct cronbnode *abnode = (struct cronbnode *)bn;
229 if (abnode->waitingForShutdown)
230 temp = BSTAT_SHUTTINGDOWN;
231 else if (abnode->b.goal == 0)
232 temp = BSTAT_SHUTDOWN;
233 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
234 /* special hack: bnode deletion won't happen if bnode is active, so
235 * we make bnodes that are ready to be deleted automatically appear
236 * as BSTAT_SHUTDOWN so bnode_Delete is happy. */
237 temp = BSTAT_SHUTDOWN;
245 cron_setstat(struct bnode *bn, afs_int32 astatus)
247 struct cronbnode *abnode = (struct cronbnode *)bn;
248 if (abnode->waitingForShutdown)
250 if (astatus == BSTAT_SHUTDOWN) {
251 if (abnode->running) {
253 bnode_StopProc(abnode->proc, SIGTERM);
254 abnode->waitingForShutdown = 1;
255 bnode_SetTimeout((struct bnode *)abnode, SDTIME);
256 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
257 * [cron_procexit()] which will tell bproc() to no longer
261 /* Tell bproc() to no longer run this cron job */
262 bnode_SetTimeout((struct bnode *)abnode, 0);
264 } else if (astatus == BSTAT_NORMAL) {
265 /* start the cron job
266 * Figure out when to run next and schedule it
268 abnode->when = ktime_next(&abnode->whenToRun, 0);
269 ScheduleCronBnode(abnode);
275 cron_procexit(struct bnode *bn, struct bnode_proc *aproc)
277 struct cronbnode *abnode = (struct cronbnode *) bn;
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 bnode *bn, char *abuffer, afs_int32 alen)
302 struct cronbnode *abnode = (struct cronbnode *)bn;
304 strcpy(abuffer, "running now");
305 else if (abnode->when == 0)
306 strcpy(abuffer, "waiting to run once");
308 sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
313 cron_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
316 struct cronbnode *abnode = (struct cronbnode *)bn;
318 strcpy(abuffer, abnode->command);
319 else if (aindex == 1) {
320 strcpy(abuffer, abnode->whenString);