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>
16 #include <sys/types.h>
35 #include <afs/ktime.h>
36 #include <afs/afsutil.h>
37 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
40 static int cron_timeout(), cron_getstat(), cron_setstat(), cron_delete();
41 static int cron_procexit(), cron_getstring(), cron_getparm(), cron_restartp();
42 static int cron_hascore();
43 struct bnode *cron_create();
44 extern char *ktime_DateOf();
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(register struct ezbnode *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(register struct cronbnode *abnode)
96 register afs_int32 code;
97 register afs_int32 temp;
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(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(abnode);
114 /* otherwise start it */
115 if (!abnode->running) {
117 abnode->lastStart = FT_ApproxTime();
118 code = bnode_NewProc(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(abnode, temp);
143 cron_restartp(register struct cronbnode *abnode)
149 cron_delete(struct cronbnode *abnode)
151 free(abnode->command);
152 free(abnode->whenString);
158 cron_create(char *ainstance, char *acommand, char *awhen)
160 struct cronbnode *te;
163 extern char *copystr();
165 /* construct local path from canonical (wire-format) path */
166 if (ConstructLocalBinPath(acommand, &cmdpath)) {
167 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
171 te = (struct cronbnode *)malloc(sizeof(struct cronbnode));
172 memset(te, 0, sizeof(struct cronbnode));
173 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
174 if ((code < 0) || (bnode_InitBnode(te, &cronbnode_ops, ainstance) != 0)) {
179 te->when = ktime_next(&te->whenToRun, 0);
180 te->command = cmdpath;
181 te->whenString = copystr(awhen);
182 return (struct bnode *)te;
185 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
186 start up a process if it is time and not already running */
188 cron_timeout(struct cronbnode *abnode)
190 register afs_int32 temp;
191 register afs_int32 code;
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(abnode, 0);
201 code = bnode_NewProc(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(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(abnode, 0);
229 cron_getstat(struct cronbnode *abnode, afs_int32 * astatus)
231 register afs_int32 temp;
232 if (abnode->waitingForShutdown)
233 temp = BSTAT_SHUTTINGDOWN;
234 else if (abnode->b.goal == 0)
235 temp = BSTAT_SHUTDOWN;
236 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
237 /* special hack: bnode deletion won't happen if bnode is active, so
238 * we make bnodes that are ready to be deleted automatically appear
239 * as BSTAT_SHUTDOWN so bnode_Delete is happy. */
240 temp = BSTAT_SHUTDOWN;
248 cron_setstat(register struct cronbnode *abnode, afs_int32 astatus)
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(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(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_procexit(struct cronbnode *abnode, struct bnode_proc *aproc)
279 /* process has exited */
281 /* log interesting errors for folks */
282 if (aproc->lastSignal)
283 bozo_Log("cron job %s exited due to signal %d\n", abnode->b.name,
285 else if (aproc->lastExit)
286 bozo_Log("cron job %s exited with non-zero code %d\n", abnode->b.name,
289 abnode->waitingForShutdown = 0;
291 abnode->killSent = 0;
292 abnode->proc = (struct bnode_proc *)0;
294 /* Figure out when to run next and schedule it */
295 abnode->when = ktime_next(&abnode->whenToRun, 0);
296 ScheduleCronBnode(abnode);
301 cron_getstring(struct cronbnode *abnode, char *abuffer, afs_int32 alen)
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 cronbnode *abnode, afs_int32 aindex, char *abuffer,
317 strcpy(abuffer, abnode->command);
318 else if (aindex == 1) {
319 strcpy(abuffer, abnode->whenString);