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>
19 #include <afs/ktime.h>
20 #include <afs/afsutil.h>
23 #include "bosprototypes.h"
25 struct bnode *cron_create(char *, char *, char *, char *, char *, char *);
26 static int cron_hascore(struct bnode *bnode);
27 static int cron_restartp(struct bnode *bnode);
28 static int cron_delete(struct bnode *bnode);
29 static int cron_timeout(struct bnode *bnode);
30 static int cron_getstat(struct bnode *bnode, afs_int32 *status);
31 static int cron_setstat(struct bnode *bnode, afs_int32 status);
32 static int cron_procstarted(struct bnode *bnode, struct bnode_proc *proc);
33 static int cron_procexit(struct bnode *bnode, struct bnode_proc *proc);
34 static int cron_getstring(struct bnode *bnode, char *abuffer, afs_int32 alen);
35 static int cron_getparm(struct bnode *bnode, afs_int32, char *, afs_int32);
37 #define SDTIME 60 /* time in seconds given to a process to evaporate */
39 struct bnode_ops cronbnode_ops = {
55 afs_int32 zapTime; /* time we sent a sigterm */
57 char *whenString; /* string rep. of when to run */
58 struct bnode_proc *proc;
59 afs_int32 lastStart; /* time last started process */
60 afs_int32 nextRun; /* next time to run, if no proc running */
61 struct ktime whenToRun; /* high-level rep of when should we run this guy */
62 afs_int32 when; /* computed at creation time and procexit time */
63 char everRun; /* true if ever ran */
64 char waitingForShutdown; /* have we started any shutdown procedure? */
65 char running; /* is process running? */
66 char killSent; /* have we tried sigkill signal? */
70 cron_hascore(struct bnode *abnode)
74 bnode_CoreName(abnode, NULL, tbuffer);
75 if (access(tbuffer, 0) == 0)
81 /* run at creation or after process exit. figures out if we're all done (if a
82 one shot run) or when we should run again. Sleeps until we should run again.
83 Note that the computation of when we should run again is made in procexit
84 and/or create procs. This guy only schedules the sleep */
86 ScheduleCronBnode(struct cronbnode *abnode)
90 struct bnode_proc *tp;
92 /* If this proc is shutdown, tell bproc() to no longer run this job */
93 if (abnode->b.goal == BSTAT_SHUTDOWN) {
94 bnode_SetTimeout((struct bnode *)abnode, 0);
98 /* otherwise we're supposed to be running, figure out when */
99 if (abnode->when == 0) {
101 if (abnode->everRun) {
103 bnode_Delete((struct bnode *)abnode);
106 /* otherwise start it */
107 if (!abnode->running) {
109 abnode->lastStart = FT_ApproxTime();
110 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
112 bozo_Log("cron bnode %s failed to start (code %d)\n",
113 abnode->b.name, code);
122 /* run periodically */
125 /* otherwise find out when to run it, and do it then */
126 temp = abnode->when - FT_ApproxTime();
128 temp = 1; /* temp is when to start dude */
129 bnode_SetTimeout((struct bnode *)abnode, temp);
135 cron_restartp(struct bnode *abnode)
141 cron_delete(struct bnode *bn)
143 struct cronbnode *abnode = (struct cronbnode *)bn;
144 free(abnode->command);
145 free(abnode->whenString);
151 cron_create(char *ainstance, char *acommand, char *awhen,
152 char *unused1, char *unused2, char *unused3)
154 struct cronbnode *te;
158 /* construct local path from canonical (wire-format) path */
159 if (ConstructLocalBinPath(acommand, &cmdpath)) {
160 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
164 te = calloc(1, sizeof(struct cronbnode));
165 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
166 if ((code < 0) || (bnode_InitBnode((struct bnode *)te, &cronbnode_ops, ainstance) != 0)) {
171 te->when = ktime_next(&te->whenToRun, 0);
172 te->command = cmdpath;
173 te->whenString = strdup(awhen);
174 return (struct bnode *)te;
177 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
178 start up a process if it is time and not already running */
180 cron_timeout(struct bnode *bn)
182 struct cronbnode *abnode = (struct cronbnode *)bn;
185 struct bnode_proc *tp;
187 if (!abnode->running) {
188 if (abnode->when == 0)
189 return 0; /* spurious timeout activation */
190 /* not running, perhaps we should start it */
191 if (FT_ApproxTime() >= abnode->when) {
192 abnode->lastStart = FT_ApproxTime();
193 bnode_SetTimeout((struct bnode *)abnode, 0);
194 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
196 bozo_Log("cron failed to start bnode %s (code %d)\n",
197 abnode->b.name, code);
204 /* woke up too early, try again */
205 temp = abnode->when - FT_ApproxTime();
208 bnode_SetTimeout((struct bnode *)abnode, temp);
211 if (!abnode->waitingForShutdown)
212 return 0; /* spurious */
213 /* send kill and turn off timer */
214 bnode_StopProc(abnode->proc, SIGKILL);
215 abnode->killSent = 1;
216 bnode_SetTimeout((struct bnode *)abnode, 0);
222 cron_getstat(struct bnode *bn, afs_int32 * astatus)
224 struct cronbnode *abnode = (struct cronbnode *)bn;
226 if (abnode->waitingForShutdown)
227 temp = BSTAT_SHUTTINGDOWN;
228 else if (abnode->b.goal == 0)
229 temp = BSTAT_SHUTDOWN;
230 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
231 /* special hack: bnode deletion won't happen if bnode is active, so
232 * we make bnodes that are ready to be deleted automatically appear
233 * as BSTAT_SHUTDOWN so bnode_Delete is happy. */
234 temp = BSTAT_SHUTDOWN;
242 cron_setstat(struct bnode *bn, afs_int32 astatus)
244 struct cronbnode *abnode = (struct cronbnode *)bn;
245 if (abnode->waitingForShutdown)
247 if (astatus == BSTAT_SHUTDOWN) {
248 if (abnode->running) {
250 bnode_StopProc(abnode->proc, SIGTERM);
251 abnode->waitingForShutdown = 1;
252 bnode_SetTimeout((struct bnode *)abnode, SDTIME);
253 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
254 * [cron_procexit()] which will tell bproc() to no longer
258 /* Tell bproc() to no longer run this cron job */
259 bnode_SetTimeout((struct bnode *)abnode, 0);
261 } else if (astatus == BSTAT_NORMAL) {
262 /* start the cron job
263 * Figure out when to run next and schedule it
265 abnode->when = ktime_next(&abnode->whenToRun, 0);
266 ScheduleCronBnode(abnode);
272 cron_procstarted(struct bnode *bn, struct bnode_proc *aproc)
274 return 0; /* no op */
278 cron_procexit(struct bnode *bn, struct bnode_proc *aproc)
280 struct cronbnode *abnode = (struct cronbnode *) bn;
281 /* process has exited */
283 /* log interesting errors for folks */
284 if (aproc->lastSignal)
285 bozo_Log("cron job %s exited due to signal %d\n", abnode->b.name,
287 else if (aproc->lastExit)
288 bozo_Log("cron job %s exited with non-zero code %d\n", abnode->b.name,
291 abnode->waitingForShutdown = 0;
293 abnode->killSent = 0;
294 abnode->proc = (struct bnode_proc *)0;
296 /* Figure out when to run next and schedule it */
297 abnode->when = ktime_next(&abnode->whenToRun, 0);
298 ScheduleCronBnode(abnode);
303 cron_getstring(struct bnode *bn, char *abuffer, afs_int32 alen)
305 struct cronbnode *abnode = (struct cronbnode *)bn;
307 strcpy(abuffer, "running now");
308 else if (abnode->when == 0)
309 strcpy(abuffer, "waiting to run once");
311 sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
316 cron_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
319 struct cronbnode *abnode = (struct cronbnode *)bn;
321 strcpy(abuffer, abnode->command);
322 else if (aindex == 1) {
323 strcpy(abuffer, abnode->whenString);