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>
15 #include <sys/types.h>
24 #include <afs/ktime.h>
25 #include <afs/afsutil.h>
26 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
29 static int cron_timeout(), cron_getstat(), cron_setstat(), cron_delete();
30 static int cron_procexit(), cron_getstring(), cron_getparm(), cron_restartp();
31 static int cron_hascore();
32 struct bnode *cron_create();
33 extern char *ktime_DateOf();
35 #define SDTIME 60 /* time in seconds given to a process to evaporate */
37 struct bnode_ops cronbnode_ops = {
52 afs_int32 zapTime; /* time we sent a sigterm */
54 char *whenString; /* string rep. of when to run */
55 struct bnode_proc *proc;
56 afs_int32 lastStart; /* time last started process */
57 afs_int32 nextRun; /* next time to run, if no proc running */
58 struct ktime whenToRun; /* high-level rep of when should we run this guy */
59 afs_int32 when; /* computed at creation time and procexit time */
60 char everRun; /* true if ever ran */
61 char waitingForShutdown; /* have we started any shutdown procedure? */
62 char running; /* is process running? */
63 char killSent; /* have we tried sigkill signal? */
66 static int cron_hascore(abnode)
67 register struct ezbnode *abnode; {
70 bnode_CoreName(abnode, (char *) 0, tbuffer);
71 if (access(tbuffer, 0) == 0) return 1;
75 /* run at creation or after process exit. figures out if we're all done (if a
76 one shot run) or when we should run again. Sleeps until we should run again.
77 Note that the computation of when we should run again is made in procexit
78 and/or create procs. This guy only schedules the sleep */
79 ScheduleCronBnode(abnode)
80 register struct cronbnode *abnode; {
81 register afs_int32 code;
82 register afs_int32 temp;
83 struct bnode_proc *tp;
85 /* If this proc is shutdown, tell bproc() to no longer run this job */
86 if (abnode->b.goal == BSTAT_SHUTDOWN) {
87 bnode_SetTimeout(abnode, 0);
91 /* otherwise we're supposed to be running, figure out when */
92 if (abnode->when == 0) {
94 if (abnode->everRun) {
99 /* otherwise start it */
100 if (!abnode->running) {
102 abnode->lastStart = FT_ApproxTime();
103 code = bnode_NewProc(abnode, abnode->command, (char *) 0, &tp);
105 bozo_Log("cron bnode %s failed to start (code %d)\n",
106 abnode->b.name, code);
116 /* run periodically */
117 if (abnode->running) return 0;
118 /* otherwise find out when to run it, and do it then */
119 temp = abnode->when - FT_ApproxTime();
120 if (temp < 1) temp = 1; /* temp is when to start dude */
121 bnode_SetTimeout(abnode, temp);
125 static int cron_restartp (abnode)
126 register struct cronbnode *abnode; {
130 static int cron_delete(abnode)
131 struct cronbnode *abnode; {
132 free(abnode->command);
133 free(abnode->whenString);
138 struct bnode *cron_create(ainstance, acommand, awhen)
142 struct cronbnode *te;
145 extern char *copystr();
147 /* construct local path from canonical (wire-format) path */
148 if (ConstructLocalBinPath(acommand, &cmdpath)) {
149 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
150 return (struct bnode *)0;
153 te = (struct cronbnode *) malloc(sizeof(struct cronbnode));
154 memset(te, 0, sizeof(struct cronbnode));
155 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
159 return (struct bnode *) 0;
161 bnode_InitBnode(te, &cronbnode_ops, ainstance);
162 te->when = ktime_next(&te->whenToRun, 0);
163 te->command = cmdpath;
164 te->whenString = copystr(awhen);
165 return (struct bnode *) te;
168 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
169 start up a process if it is time and not already running */
170 static int cron_timeout(abnode)
171 struct cronbnode *abnode; {
172 register afs_int32 temp;
173 register afs_int32 code;
174 struct bnode_proc *tp;
176 if (!abnode->running) {
177 if (abnode->when == 0) return 0; /* spurious timeout activation */
178 /* not running, perhaps we should start it */
179 if (FT_ApproxTime() >= abnode->when) {
180 abnode->lastStart = FT_ApproxTime();
181 bnode_SetTimeout(abnode, 0);
182 code = bnode_NewProc(abnode, abnode->command, (char *) 0, &tp);
184 bozo_Log("cron failed to start bnode %s (code %d)\n",
185 abnode->b.name, code);
193 /* woke up too early, try again */
194 temp = abnode->when - FT_ApproxTime();
195 if (temp < 1) temp = 1;
196 bnode_SetTimeout(abnode, temp);
200 if (!abnode->waitingForShutdown) return 0; /* spurious */
201 /* send kill and turn off timer */
202 bnode_StopProc(abnode->proc, SIGKILL);
203 abnode->killSent = 1;
204 bnode_SetTimeout(abnode, 0);
209 static int cron_getstat(abnode, astatus)
210 struct cronbnode *abnode;
211 afs_int32 *astatus; {
212 register afs_int32 temp;
213 if (abnode->waitingForShutdown) temp = BSTAT_SHUTTINGDOWN;
214 else if (abnode->b.goal == 0) temp = BSTAT_SHUTDOWN;
215 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
216 /* special hack: bnode deletion won't happen if bnode is active, so
217 we make bnodes that are ready to be deleted automatically appear
218 as BSTAT_SHUTDOWN so bnode_Delete is happy. */
219 temp = BSTAT_SHUTDOWN;
221 else temp = BSTAT_NORMAL;
226 static int cron_setstat(abnode, astatus)
227 register struct cronbnode *abnode;
230 if (abnode->waitingForShutdown) return BZBUSY;
231 if (astatus == BSTAT_SHUTDOWN) {
232 if (abnode->running) {
234 bnode_StopProc(abnode->proc, SIGTERM);
235 abnode->waitingForShutdown = 1;
236 bnode_SetTimeout(abnode, SDTIME);
237 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
238 * [cron_procexit()] which will tell bproc() to no longer
242 /* Tell bproc() to no longer run this cron job */
243 bnode_SetTimeout(abnode, 0);
246 else if (astatus == BSTAT_NORMAL) {
247 /* start the cron job
248 * Figure out when to run next and schedule it
250 abnode->when = ktime_next(&abnode->whenToRun, 0);
251 ScheduleCronBnode(abnode);
256 static int cron_procexit(abnode, aproc)
257 struct cronbnode *abnode;
258 struct bnode_proc *aproc; {
259 /* process has exited */
261 /* log interesting errors for folks */
262 if (aproc->lastSignal)
263 bozo_Log("cron job %s exited due to signal %d\n",
264 abnode->b.name, aproc->lastSignal);
265 else if (aproc->lastExit)
266 bozo_Log("cron job %s exited with non-zero code %d\n",
267 abnode->b.name, aproc->lastExit);
269 abnode->waitingForShutdown = 0;
271 abnode->killSent = 0;
272 abnode->proc = (struct bnode_proc *) 0;
274 /* Figure out when to run next and schedule it */
275 abnode->when = ktime_next(&abnode->whenToRun, 0);
276 ScheduleCronBnode(abnode);
280 static int cron_getstring(abnode, abuffer, alen)
281 struct cronbnode *abnode;
284 if (abnode->running) strcpy(abuffer, "running now");
285 else if (abnode->when==0) strcpy(abuffer, "waiting to run once");
286 else sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
290 static cron_getparm(abnode, aindex, abuffer, alen)
291 struct cronbnode *abnode;
295 if (aindex == 0) strcpy(abuffer, abnode->command);
296 else if (aindex == 1) {
297 strcpy(abuffer, abnode->whenString);