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_procstarted(struct bnode *bnode, struct bnode_proc *proc);
37 static int cron_procexit(struct bnode *bnode, struct bnode_proc *proc);
38 static int cron_getstring(struct bnode *bnode, char *abuffer, afs_int32 alen);
39 static int cron_getparm(struct bnode *bnode, afs_int32, char *, afs_int32);
41 #define SDTIME 60 /* time in seconds given to a process to evaporate */
43 struct bnode_ops cronbnode_ops = {
59 afs_int32 zapTime; /* time we sent a sigterm */
61 char *whenString; /* string rep. of when to run */
62 struct bnode_proc *proc;
63 afs_int32 lastStart; /* time last started process */
64 afs_int32 nextRun; /* next time to run, if no proc running */
65 struct ktime whenToRun; /* high-level rep of when should we run this guy */
66 afs_int32 when; /* computed at creation time and procexit time */
67 char everRun; /* true if ever ran */
68 char waitingForShutdown; /* have we started any shutdown procedure? */
69 char running; /* is process running? */
70 char killSent; /* have we tried sigkill signal? */
74 cron_hascore(struct bnode *abnode)
78 bnode_CoreName(abnode, NULL, tbuffer);
79 if (access(tbuffer, 0) == 0)
85 /* run at creation or after process exit. figures out if we're all done (if a
86 one shot run) or when we should run again. Sleeps until we should run again.
87 Note that the computation of when we should run again is made in procexit
88 and/or create procs. This guy only schedules the sleep */
90 ScheduleCronBnode(struct cronbnode *abnode)
94 struct bnode_proc *tp;
96 /* If this proc is shutdown, tell bproc() to no longer run this job */
97 if (abnode->b.goal == BSTAT_SHUTDOWN) {
98 bnode_SetTimeout((struct bnode *)abnode, 0);
102 /* otherwise we're supposed to be running, figure out when */
103 if (abnode->when == 0) {
105 if (abnode->everRun) {
107 bnode_Delete((struct bnode *)abnode);
110 /* otherwise start it */
111 if (!abnode->running) {
113 abnode->lastStart = FT_ApproxTime();
114 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
116 bozo_Log("cron bnode %s failed to start (code %d)\n",
117 abnode->b.name, code);
126 /* run periodically */
129 /* otherwise find out when to run it, and do it then */
130 temp = abnode->when - FT_ApproxTime();
132 temp = 1; /* temp is when to start dude */
133 bnode_SetTimeout((struct bnode *)abnode, temp);
139 cron_restartp(struct bnode *abnode)
145 cron_delete(struct bnode *bn)
147 struct cronbnode *abnode = (struct cronbnode *)bn;
148 free(abnode->command);
149 free(abnode->whenString);
155 cron_create(char *ainstance, char *acommand, char *awhen,
156 char *unused1, char *unused2, char *unused3)
158 struct cronbnode *te;
162 /* construct local path from canonical (wire-format) path */
163 if (ConstructLocalBinPath(acommand, &cmdpath)) {
164 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
168 te = (struct cronbnode *)malloc(sizeof(struct cronbnode));
169 memset(te, 0, sizeof(struct cronbnode));
170 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
171 if ((code < 0) || (bnode_InitBnode((struct bnode *)te, &cronbnode_ops, ainstance) != 0)) {
176 te->when = ktime_next(&te->whenToRun, 0);
177 te->command = cmdpath;
178 te->whenString = copystr(awhen);
179 return (struct bnode *)te;
182 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
183 start up a process if it is time and not already running */
185 cron_timeout(struct bnode *bn)
187 struct cronbnode *abnode = (struct cronbnode *)bn;
190 struct bnode_proc *tp;
192 if (!abnode->running) {
193 if (abnode->when == 0)
194 return 0; /* spurious timeout activation */
195 /* not running, perhaps we should start it */
196 if (FT_ApproxTime() >= abnode->when) {
197 abnode->lastStart = FT_ApproxTime();
198 bnode_SetTimeout((struct bnode *)abnode, 0);
199 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
201 bozo_Log("cron failed to start bnode %s (code %d)\n",
202 abnode->b.name, code);
209 /* woke up too early, try again */
210 temp = abnode->when - FT_ApproxTime();
213 bnode_SetTimeout((struct bnode *)abnode, temp);
216 if (!abnode->waitingForShutdown)
217 return 0; /* spurious */
218 /* send kill and turn off timer */
219 bnode_StopProc(abnode->proc, SIGKILL);
220 abnode->killSent = 1;
221 bnode_SetTimeout((struct bnode *)abnode, 0);
227 cron_getstat(struct bnode *bn, afs_int32 * astatus)
229 struct cronbnode *abnode = (struct cronbnode *)bn;
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(struct bnode *bn, afs_int32 astatus)
249 struct cronbnode *abnode = (struct cronbnode *)bn;
250 if (abnode->waitingForShutdown)
252 if (astatus == BSTAT_SHUTDOWN) {
253 if (abnode->running) {
255 bnode_StopProc(abnode->proc, SIGTERM);
256 abnode->waitingForShutdown = 1;
257 bnode_SetTimeout((struct bnode *)abnode, SDTIME);
258 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
259 * [cron_procexit()] which will tell bproc() to no longer
263 /* Tell bproc() to no longer run this cron job */
264 bnode_SetTimeout((struct bnode *)abnode, 0);
266 } else if (astatus == BSTAT_NORMAL) {
267 /* start the cron job
268 * Figure out when to run next and schedule it
270 abnode->when = ktime_next(&abnode->whenToRun, 0);
271 ScheduleCronBnode(abnode);
277 cron_procstarted(struct bnode *bn, struct bnode_proc *aproc)
279 return 0; /* no op */
283 cron_procexit(struct bnode *bn, struct bnode_proc *aproc)
285 struct cronbnode *abnode = (struct cronbnode *) bn;
286 /* process has exited */
288 /* log interesting errors for folks */
289 if (aproc->lastSignal)
290 bozo_Log("cron job %s exited due to signal %d\n", abnode->b.name,
292 else if (aproc->lastExit)
293 bozo_Log("cron job %s exited with non-zero code %d\n", abnode->b.name,
296 abnode->waitingForShutdown = 0;
298 abnode->killSent = 0;
299 abnode->proc = (struct bnode_proc *)0;
301 /* Figure out when to run next and schedule it */
302 abnode->when = ktime_next(&abnode->whenToRun, 0);
303 ScheduleCronBnode(abnode);
308 cron_getstring(struct bnode *bn, char *abuffer, afs_int32 alen)
310 struct cronbnode *abnode = (struct cronbnode *)bn;
312 strcpy(abuffer, "running now");
313 else if (abnode->when == 0)
314 strcpy(abuffer, "waiting to run once");
316 sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
321 cron_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
324 struct cronbnode *abnode = (struct cronbnode *)bn;
326 strcpy(abuffer, abnode->command);
327 else if (aindex == 1) {
328 strcpy(abuffer, abnode->whenString);