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>
16 #include <sys/types.h>
29 #include <afs/ktime.h>
30 #include <afs/afsutil.h>
31 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
33 #include "bosprototypes.h"
35 struct bnode *cron_create(char *, char *, char *, char *, char *, char *);
36 static int cron_hascore(struct bnode *bnode);
37 static int cron_restartp(struct bnode *bnode);
38 static int cron_delete(struct bnode *bnode);
39 static int cron_timeout(struct bnode *bnode);
40 static int cron_getstat(struct bnode *bnode, afs_int32 *status);
41 static int cron_setstat(struct bnode *bnode, afs_int32 status);
42 static int cron_procexit(struct bnode *bnode, struct bnode_proc *proc);
43 static int cron_getstring(struct bnode *bnode, char *abuffer, afs_int32 alen);
44 static int cron_getparm(struct bnode *bnode, afs_int32, char *, afs_int32);
46 #define SDTIME 60 /* time in seconds given to a process to evaporate */
48 struct bnode_ops cronbnode_ops = {
63 afs_int32 zapTime; /* time we sent a sigterm */
65 char *whenString; /* string rep. of when to run */
66 struct bnode_proc *proc;
67 afs_int32 lastStart; /* time last started process */
68 afs_int32 nextRun; /* next time to run, if no proc running */
69 struct ktime whenToRun; /* high-level rep of when should we run this guy */
70 afs_int32 when; /* computed at creation time and procexit time */
71 char everRun; /* true if ever ran */
72 char waitingForShutdown; /* have we started any shutdown procedure? */
73 char running; /* is process running? */
74 char killSent; /* have we tried sigkill signal? */
78 cron_hascore(struct bnode *abnode)
82 bnode_CoreName(abnode, NULL, tbuffer);
83 if (access(tbuffer, 0) == 0)
89 /* run at creation or after process exit. figures out if we're all done (if a
90 one shot run) or when we should run again. Sleeps until we should run again.
91 Note that the computation of when we should run again is made in procexit
92 and/or create procs. This guy only schedules the sleep */
94 ScheduleCronBnode(struct cronbnode *abnode)
98 struct bnode_proc *tp;
100 /* If this proc is shutdown, tell bproc() to no longer run this job */
101 if (abnode->b.goal == BSTAT_SHUTDOWN) {
102 bnode_SetTimeout((struct bnode *)abnode, 0);
106 /* otherwise we're supposed to be running, figure out when */
107 if (abnode->when == 0) {
109 if (abnode->everRun) {
111 bnode_Delete((struct bnode *)abnode);
114 /* otherwise start it */
115 if (!abnode->running) {
117 abnode->lastStart = FT_ApproxTime();
118 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
120 bozo_Log("cron bnode %s failed to start (code %d)\n",
121 abnode->b.name, code);
130 /* run periodically */
133 /* otherwise find out when to run it, and do it then */
134 temp = abnode->when - FT_ApproxTime();
136 temp = 1; /* temp is when to start dude */
137 bnode_SetTimeout((struct bnode *)abnode, temp);
143 cron_restartp(struct bnode *abnode)
149 cron_delete(struct bnode *bn)
151 struct cronbnode *abnode = (struct cronbnode *)bn;
152 free(abnode->command);
153 free(abnode->whenString);
159 cron_create(char *ainstance, char *acommand, char *awhen,
160 char *unused1, char *unused2, char *unused3)
162 struct cronbnode *te;
166 /* construct local path from canonical (wire-format) path */
167 if (ConstructLocalBinPath(acommand, &cmdpath)) {
168 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
172 te = (struct cronbnode *)malloc(sizeof(struct cronbnode));
173 memset(te, 0, sizeof(struct cronbnode));
174 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
175 if ((code < 0) || (bnode_InitBnode((struct bnode *)te, &cronbnode_ops, ainstance) != 0)) {
180 te->when = ktime_next(&te->whenToRun, 0);
181 te->command = cmdpath;
182 te->whenString = copystr(awhen);
183 return (struct bnode *)te;
186 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
187 start up a process if it is time and not already running */
189 cron_timeout(struct bnode *bn)
191 struct cronbnode *abnode = (struct cronbnode *)bn;
194 struct bnode_proc *tp;
196 if (!abnode->running) {
197 if (abnode->when == 0)
198 return 0; /* spurious timeout activation */
199 /* not running, perhaps we should start it */
200 if (FT_ApproxTime() >= abnode->when) {
201 abnode->lastStart = FT_ApproxTime();
202 bnode_SetTimeout((struct bnode *)abnode, 0);
203 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
205 bozo_Log("cron failed to start bnode %s (code %d)\n",
206 abnode->b.name, code);
213 /* woke up too early, try again */
214 temp = abnode->when - FT_ApproxTime();
217 bnode_SetTimeout((struct bnode *)abnode, temp);
220 if (!abnode->waitingForShutdown)
221 return 0; /* spurious */
222 /* send kill and turn off timer */
223 bnode_StopProc(abnode->proc, SIGKILL);
224 abnode->killSent = 1;
225 bnode_SetTimeout((struct bnode *)abnode, 0);
231 cron_getstat(struct bnode *bn, afs_int32 * astatus)
233 struct cronbnode *abnode = (struct cronbnode *)bn;
235 if (abnode->waitingForShutdown)
236 temp = BSTAT_SHUTTINGDOWN;
237 else if (abnode->b.goal == 0)
238 temp = BSTAT_SHUTDOWN;
239 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
240 /* special hack: bnode deletion won't happen if bnode is active, so
241 * we make bnodes that are ready to be deleted automatically appear
242 * as BSTAT_SHUTDOWN so bnode_Delete is happy. */
243 temp = BSTAT_SHUTDOWN;
251 cron_setstat(struct bnode *bn, afs_int32 astatus)
253 struct cronbnode *abnode = (struct cronbnode *)bn;
254 if (abnode->waitingForShutdown)
256 if (astatus == BSTAT_SHUTDOWN) {
257 if (abnode->running) {
259 bnode_StopProc(abnode->proc, SIGTERM);
260 abnode->waitingForShutdown = 1;
261 bnode_SetTimeout((struct bnode *)abnode, SDTIME);
262 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
263 * [cron_procexit()] which will tell bproc() to no longer
267 /* Tell bproc() to no longer run this cron job */
268 bnode_SetTimeout((struct bnode *)abnode, 0);
270 } else if (astatus == BSTAT_NORMAL) {
271 /* start the cron job
272 * Figure out when to run next and schedule it
274 abnode->when = ktime_next(&abnode->whenToRun, 0);
275 ScheduleCronBnode(abnode);
281 cron_procexit(struct bnode *bn, struct bnode_proc *aproc)
283 struct cronbnode *abnode = (struct cronbnode *) bn;
284 /* process has exited */
286 /* log interesting errors for folks */
287 if (aproc->lastSignal)
288 bozo_Log("cron job %s exited due to signal %d\n", abnode->b.name,
290 else if (aproc->lastExit)
291 bozo_Log("cron job %s exited with non-zero code %d\n", abnode->b.name,
294 abnode->waitingForShutdown = 0;
296 abnode->killSent = 0;
297 abnode->proc = (struct bnode_proc *)0;
299 /* Figure out when to run next and schedule it */
300 abnode->when = ktime_next(&abnode->whenToRun, 0);
301 ScheduleCronBnode(abnode);
306 cron_getstring(struct bnode *bn, char *abuffer, afs_int32 alen)
308 struct cronbnode *abnode = (struct cronbnode *)bn;
310 strcpy(abuffer, "running now");
311 else if (abnode->when == 0)
312 strcpy(abuffer, "waiting to run once");
314 sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
319 cron_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
322 struct cronbnode *abnode = (struct cronbnode *)bn;
324 strcpy(abuffer, abnode->command);
325 else if (aindex == 1) {
326 strcpy(abuffer, abnode->whenString);