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>
14 #include <sys/types.h>
27 #include <afs/ktime.h>
28 #include <afs/afsutil.h>
29 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
31 #include "bosprototypes.h"
33 struct bnode *cron_create(char *, char *, char *, char *, char *, char *);
34 static int cron_hascore(struct bnode *bnode);
35 static int cron_restartp(struct bnode *bnode);
36 static int cron_delete(struct bnode *bnode);
37 static int cron_timeout(struct bnode *bnode);
38 static int cron_getstat(struct bnode *bnode, afs_int32 *status);
39 static int cron_setstat(struct bnode *bnode, afs_int32 status);
40 static int cron_procexit(struct bnode *bnode, struct bnode_proc *proc);
41 static int cron_getstring(struct bnode *bnode, char *abuffer, afs_int32 alen);
42 static int cron_getparm(struct bnode *bnode, afs_int32, char *, afs_int32);
44 #define SDTIME 60 /* time in seconds given to a process to evaporate */
46 struct bnode_ops cronbnode_ops = {
61 afs_int32 zapTime; /* time we sent a sigterm */
63 char *whenString; /* string rep. of when to run */
64 struct bnode_proc *proc;
65 afs_int32 lastStart; /* time last started process */
66 afs_int32 nextRun; /* next time to run, if no proc running */
67 struct ktime whenToRun; /* high-level rep of when should we run this guy */
68 afs_int32 when; /* computed at creation time and procexit time */
69 char everRun; /* true if ever ran */
70 char waitingForShutdown; /* have we started any shutdown procedure? */
71 char running; /* is process running? */
72 char killSent; /* have we tried sigkill signal? */
76 cron_hascore(struct bnode *abnode)
80 bnode_CoreName(abnode, NULL, tbuffer);
81 if (access(tbuffer, 0) == 0)
87 /* run at creation or after process exit. figures out if we're all done (if a
88 one shot run) or when we should run again. Sleeps until we should run again.
89 Note that the computation of when we should run again is made in procexit
90 and/or create procs. This guy only schedules the sleep */
92 ScheduleCronBnode(struct cronbnode *abnode)
96 struct bnode_proc *tp;
98 /* If this proc is shutdown, tell bproc() to no longer run this job */
99 if (abnode->b.goal == BSTAT_SHUTDOWN) {
100 bnode_SetTimeout((struct bnode *)abnode, 0);
104 /* otherwise we're supposed to be running, figure out when */
105 if (abnode->when == 0) {
107 if (abnode->everRun) {
109 bnode_Delete((struct bnode *)abnode);
112 /* otherwise start it */
113 if (!abnode->running) {
115 abnode->lastStart = FT_ApproxTime();
116 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
118 bozo_Log("cron bnode %s failed to start (code %d)\n",
119 abnode->b.name, code);
128 /* run periodically */
131 /* otherwise find out when to run it, and do it then */
132 temp = abnode->when - FT_ApproxTime();
134 temp = 1; /* temp is when to start dude */
135 bnode_SetTimeout((struct bnode *)abnode, temp);
141 cron_restartp(struct bnode *abnode)
147 cron_delete(struct bnode *bn)
149 struct cronbnode *abnode = (struct cronbnode *)bn;
150 free(abnode->command);
151 free(abnode->whenString);
157 cron_create(char *ainstance, char *acommand, char *awhen,
158 char *unused1, char *unused2, char *unused3)
160 struct cronbnode *te;
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((struct bnode *)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 bnode *bn)
189 struct cronbnode *abnode = (struct cronbnode *)bn;
192 struct bnode_proc *tp;
194 if (!abnode->running) {
195 if (abnode->when == 0)
196 return 0; /* spurious timeout activation */
197 /* not running, perhaps we should start it */
198 if (FT_ApproxTime() >= abnode->when) {
199 abnode->lastStart = FT_ApproxTime();
200 bnode_SetTimeout((struct bnode *)abnode, 0);
201 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
203 bozo_Log("cron failed to start bnode %s (code %d)\n",
204 abnode->b.name, code);
211 /* woke up too early, try again */
212 temp = abnode->when - FT_ApproxTime();
215 bnode_SetTimeout((struct bnode *)abnode, temp);
218 if (!abnode->waitingForShutdown)
219 return 0; /* spurious */
220 /* send kill and turn off timer */
221 bnode_StopProc(abnode->proc, SIGKILL);
222 abnode->killSent = 1;
223 bnode_SetTimeout((struct bnode *)abnode, 0);
229 cron_getstat(struct bnode *bn, afs_int32 * astatus)
231 struct cronbnode *abnode = (struct cronbnode *)bn;
233 if (abnode->waitingForShutdown)
234 temp = BSTAT_SHUTTINGDOWN;
235 else if (abnode->b.goal == 0)
236 temp = BSTAT_SHUTDOWN;
237 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
238 /* special hack: bnode deletion won't happen if bnode is active, so
239 * we make bnodes that are ready to be deleted automatically appear
240 * as BSTAT_SHUTDOWN so bnode_Delete is happy. */
241 temp = BSTAT_SHUTDOWN;
249 cron_setstat(struct bnode *bn, afs_int32 astatus)
251 struct cronbnode *abnode = (struct cronbnode *)bn;
252 if (abnode->waitingForShutdown)
254 if (astatus == BSTAT_SHUTDOWN) {
255 if (abnode->running) {
257 bnode_StopProc(abnode->proc, SIGTERM);
258 abnode->waitingForShutdown = 1;
259 bnode_SetTimeout((struct bnode *)abnode, SDTIME);
260 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
261 * [cron_procexit()] which will tell bproc() to no longer
265 /* Tell bproc() to no longer run this cron job */
266 bnode_SetTimeout((struct bnode *)abnode, 0);
268 } else if (astatus == BSTAT_NORMAL) {
269 /* start the cron job
270 * Figure out when to run next and schedule it
272 abnode->when = ktime_next(&abnode->whenToRun, 0);
273 ScheduleCronBnode(abnode);
279 cron_procexit(struct bnode *bn, struct bnode_proc *aproc)
281 struct cronbnode *abnode = (struct cronbnode *) bn;
282 /* process has exited */
284 /* log interesting errors for folks */
285 if (aproc->lastSignal)
286 bozo_Log("cron job %s exited due to signal %d\n", abnode->b.name,
288 else if (aproc->lastExit)
289 bozo_Log("cron job %s exited with non-zero code %d\n", abnode->b.name,
292 abnode->waitingForShutdown = 0;
294 abnode->killSent = 0;
295 abnode->proc = (struct bnode_proc *)0;
297 /* Figure out when to run next and schedule it */
298 abnode->when = ktime_next(&abnode->whenToRun, 0);
299 ScheduleCronBnode(abnode);
304 cron_getstring(struct bnode *bn, char *abuffer, afs_int32 alen)
306 struct cronbnode *abnode = (struct cronbnode *)bn;
308 strcpy(abuffer, "running now");
309 else if (abnode->when == 0)
310 strcpy(abuffer, "waiting to run once");
312 sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
317 cron_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
320 struct cronbnode *abnode = (struct cronbnode *)bn;
322 strcpy(abuffer, abnode->command);
323 else if (aindex == 1) {
324 strcpy(abuffer, abnode->whenString);