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>
29 #include <afs/ktime.h>
30 #include <afs/afsutil.h>
31 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
34 static int cron_timeout(), cron_getstat(), cron_setstat(), cron_delete();
35 static int cron_procexit(), cron_getstring(), cron_getparm(), cron_restartp();
36 static int cron_hascore();
37 struct bnode *cron_create();
39 #define SDTIME 60 /* time in seconds given to a process to evaporate */
41 struct bnode_ops cronbnode_ops = {
56 afs_int32 zapTime; /* time we sent a sigterm */
58 char *whenString; /* string rep. of when to run */
59 struct bnode_proc *proc;
60 afs_int32 lastStart; /* time last started process */
61 afs_int32 nextRun; /* next time to run, if no proc running */
62 struct ktime whenToRun; /* high-level rep of when should we run this guy */
63 afs_int32 when; /* computed at creation time and procexit time */
64 char everRun; /* true if ever ran */
65 char waitingForShutdown; /* have we started any shutdown procedure? */
66 char running; /* is process running? */
67 char killSent; /* have we tried sigkill signal? */
71 cron_hascore(register struct ezbnode *abnode)
75 bnode_CoreName(abnode, NULL, tbuffer);
76 if (access(tbuffer, 0) == 0)
82 /* run at creation or after process exit. figures out if we're all done (if a
83 one shot run) or when we should run again. Sleeps until we should run again.
84 Note that the computation of when we should run again is made in procexit
85 and/or create procs. This guy only schedules the sleep */
87 ScheduleCronBnode(register struct cronbnode *abnode)
89 register afs_int32 code;
90 register afs_int32 temp;
91 struct bnode_proc *tp;
93 /* If this proc is shutdown, tell bproc() to no longer run this job */
94 if (abnode->b.goal == BSTAT_SHUTDOWN) {
95 bnode_SetTimeout(abnode, 0);
99 /* otherwise we're supposed to be running, figure out when */
100 if (abnode->when == 0) {
102 if (abnode->everRun) {
104 bnode_Delete(abnode);
107 /* otherwise start it */
108 if (!abnode->running) {
110 abnode->lastStart = FT_ApproxTime();
111 code = bnode_NewProc(abnode, abnode->command, NULL, &tp);
113 bozo_Log("cron bnode %s failed to start (code %d)\n",
114 abnode->b.name, code);
123 /* run periodically */
126 /* otherwise find out when to run it, and do it then */
127 temp = abnode->when - FT_ApproxTime();
129 temp = 1; /* temp is when to start dude */
130 bnode_SetTimeout(abnode, temp);
136 cron_restartp(register struct cronbnode *abnode)
142 cron_delete(struct cronbnode *abnode)
144 free(abnode->command);
145 free(abnode->whenString);
151 cron_create(char *ainstance, char *acommand, char *awhen)
153 struct cronbnode *te;
156 extern char *copystr();
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 = (struct cronbnode *)malloc(sizeof(struct cronbnode));
165 memset(te, 0, sizeof(struct cronbnode));
166 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
167 if ((code < 0) || (bnode_InitBnode(te, &cronbnode_ops, ainstance) != 0)) {
172 te->when = ktime_next(&te->whenToRun, 0);
173 te->command = cmdpath;
174 te->whenString = copystr(awhen);
175 return (struct bnode *)te;
178 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
179 start up a process if it is time and not already running */
181 cron_timeout(struct cronbnode *abnode)
183 register afs_int32 temp;
184 register afs_int32 code;
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(abnode, 0);
194 code = bnode_NewProc(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(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(abnode, 0);
222 cron_getstat(struct cronbnode *abnode, afs_int32 * astatus)
224 register afs_int32 temp;
225 if (abnode->waitingForShutdown)
226 temp = BSTAT_SHUTTINGDOWN;
227 else if (abnode->b.goal == 0)
228 temp = BSTAT_SHUTDOWN;
229 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
230 /* special hack: bnode deletion won't happen if bnode is active, so
231 * we make bnodes that are ready to be deleted automatically appear
232 * as BSTAT_SHUTDOWN so bnode_Delete is happy. */
233 temp = BSTAT_SHUTDOWN;
241 cron_setstat(register struct cronbnode *abnode, afs_int32 astatus)
243 if (abnode->waitingForShutdown)
245 if (astatus == BSTAT_SHUTDOWN) {
246 if (abnode->running) {
248 bnode_StopProc(abnode->proc, SIGTERM);
249 abnode->waitingForShutdown = 1;
250 bnode_SetTimeout(abnode, SDTIME);
251 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
252 * [cron_procexit()] which will tell bproc() to no longer
256 /* Tell bproc() to no longer run this cron job */
257 bnode_SetTimeout(abnode, 0);
259 } else if (astatus == BSTAT_NORMAL) {
260 /* start the cron job
261 * Figure out when to run next and schedule it
263 abnode->when = ktime_next(&abnode->whenToRun, 0);
264 ScheduleCronBnode(abnode);
270 cron_procexit(struct cronbnode *abnode, struct bnode_proc *aproc)
272 /* process has exited */
274 /* log interesting errors for folks */
275 if (aproc->lastSignal)
276 bozo_Log("cron job %s exited due to signal %d\n", abnode->b.name,
278 else if (aproc->lastExit)
279 bozo_Log("cron job %s exited with non-zero code %d\n", abnode->b.name,
282 abnode->waitingForShutdown = 0;
284 abnode->killSent = 0;
285 abnode->proc = (struct bnode_proc *)0;
287 /* Figure out when to run next and schedule it */
288 abnode->when = ktime_next(&abnode->whenToRun, 0);
289 ScheduleCronBnode(abnode);
294 cron_getstring(struct cronbnode *abnode, char *abuffer, afs_int32 alen)
297 strcpy(abuffer, "running now");
298 else if (abnode->when == 0)
299 strcpy(abuffer, "waiting to run once");
301 sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
306 cron_getparm(struct cronbnode *abnode, afs_int32 aindex, char *abuffer,
310 strcpy(abuffer, abnode->command);
311 else if (aindex == 1) {
312 strcpy(abuffer, abnode->whenString);