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>
34 #include <afs/ktime.h>
35 #include <afs/afsutil.h>
36 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
39 static int cron_timeout(), cron_getstat(), cron_setstat(), cron_delete();
40 static int cron_procexit(), cron_getstring(), cron_getparm(), cron_restartp();
41 static int cron_hascore();
42 struct bnode *cron_create();
43 extern char *ktime_DateOf();
45 #define SDTIME 60 /* time in seconds given to a process to evaporate */
47 struct bnode_ops cronbnode_ops = {
62 afs_int32 zapTime; /* time we sent a sigterm */
64 char *whenString; /* string rep. of when to run */
65 struct bnode_proc *proc;
66 afs_int32 lastStart; /* time last started process */
67 afs_int32 nextRun; /* next time to run, if no proc running */
68 struct ktime whenToRun; /* high-level rep of when should we run this guy */
69 afs_int32 when; /* computed at creation time and procexit time */
70 char everRun; /* true if ever ran */
71 char waitingForShutdown; /* have we started any shutdown procedure? */
72 char running; /* is process running? */
73 char killSent; /* have we tried sigkill signal? */
76 static int cron_hascore(register struct ezbnode *abnode) {
79 bnode_CoreName(abnode, NULL, tbuffer);
80 if (access(tbuffer, 0) == 0) return 1;
84 /* run at creation or after process exit. figures out if we're all done (if a
85 one shot run) or when we should run again. Sleeps until we should run again.
86 Note that the computation of when we should run again is made in procexit
87 and/or create procs. This guy only schedules the sleep */
88 int ScheduleCronBnode(register struct cronbnode *abnode)
90 register afs_int32 code;
91 register afs_int32 temp;
92 struct bnode_proc *tp;
94 /* If this proc is shutdown, tell bproc() to no longer run this job */
95 if (abnode->b.goal == BSTAT_SHUTDOWN) {
96 bnode_SetTimeout(abnode, 0);
100 /* otherwise we're supposed to be running, figure out when */
101 if (abnode->when == 0) {
103 if (abnode->everRun) {
105 bnode_Delete(abnode);
108 /* otherwise start it */
109 if (!abnode->running) {
111 abnode->lastStart = FT_ApproxTime();
112 code = bnode_NewProc(abnode, abnode->command, NULL, &tp);
114 bozo_Log("cron bnode %s failed to start (code %d)\n",
115 abnode->b.name, code);
125 /* run periodically */
126 if (abnode->running) return 0;
127 /* otherwise find out when to run it, and do it then */
128 temp = abnode->when - FT_ApproxTime();
129 if (temp < 1) temp = 1; /* temp is when to start dude */
130 bnode_SetTimeout(abnode, temp);
135 static int cron_restartp (register struct cronbnode *abnode)
140 static int cron_delete(struct cronbnode *abnode)
142 free(abnode->command);
143 free(abnode->whenString);
148 struct bnode *cron_create(char *ainstance, char *acommand, char *awhen)
150 struct cronbnode *te;
153 extern char *copystr();
155 /* construct local path from canonical (wire-format) path */
156 if (ConstructLocalBinPath(acommand, &cmdpath)) {
157 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
161 te = (struct cronbnode *) malloc(sizeof(struct cronbnode));
162 memset(te, 0, sizeof(struct cronbnode));
163 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
164 if ((code < 0) || (bnode_InitBnode(te, &cronbnode_ops, ainstance) != 0)) {
169 te->when = ktime_next(&te->whenToRun, 0);
170 te->command = cmdpath;
171 te->whenString = copystr(awhen);
172 return (struct bnode *) te;
175 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
176 start up a process if it is time and not already running */
177 static int cron_timeout(struct cronbnode *abnode)
179 register afs_int32 temp;
180 register afs_int32 code;
181 struct bnode_proc *tp;
183 if (!abnode->running) {
184 if (abnode->when == 0) return 0; /* spurious timeout activation */
185 /* not running, perhaps we should start it */
186 if (FT_ApproxTime() >= abnode->when) {
187 abnode->lastStart = FT_ApproxTime();
188 bnode_SetTimeout(abnode, 0);
189 code = bnode_NewProc(abnode, abnode->command, NULL, &tp);
191 bozo_Log("cron failed to start bnode %s (code %d)\n",
192 abnode->b.name, code);
200 /* woke up too early, try again */
201 temp = abnode->when - FT_ApproxTime();
202 if (temp < 1) temp = 1;
203 bnode_SetTimeout(abnode, temp);
207 if (!abnode->waitingForShutdown) return 0; /* spurious */
208 /* send kill and turn off timer */
209 bnode_StopProc(abnode->proc, SIGKILL);
210 abnode->killSent = 1;
211 bnode_SetTimeout(abnode, 0);
216 static int cron_getstat(struct cronbnode *abnode, afs_int32 *astatus)
218 register afs_int32 temp;
219 if (abnode->waitingForShutdown) temp = BSTAT_SHUTTINGDOWN;
220 else if (abnode->b.goal == 0) temp = BSTAT_SHUTDOWN;
221 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
222 /* special hack: bnode deletion won't happen if bnode is active, so
223 we make bnodes that are ready to be deleted automatically appear
224 as BSTAT_SHUTDOWN so bnode_Delete is happy. */
225 temp = BSTAT_SHUTDOWN;
227 else temp = BSTAT_NORMAL;
232 static int cron_setstat(register struct cronbnode *abnode, afs_int32 astatus)
234 if (abnode->waitingForShutdown) return BZBUSY;
235 if (astatus == BSTAT_SHUTDOWN) {
236 if (abnode->running) {
238 bnode_StopProc(abnode->proc, SIGTERM);
239 abnode->waitingForShutdown = 1;
240 bnode_SetTimeout(abnode, SDTIME);
241 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
242 * [cron_procexit()] which will tell bproc() to no longer
246 /* Tell bproc() to no longer run this cron job */
247 bnode_SetTimeout(abnode, 0);
250 else if (astatus == BSTAT_NORMAL) {
251 /* start the cron job
252 * Figure out when to run next and schedule it
254 abnode->when = ktime_next(&abnode->whenToRun, 0);
255 ScheduleCronBnode(abnode);
260 static int cron_procexit(struct cronbnode *abnode, struct bnode_proc *aproc)
262 /* process has exited */
264 /* log interesting errors for folks */
265 if (aproc->lastSignal)
266 bozo_Log("cron job %s exited due to signal %d\n",
267 abnode->b.name, aproc->lastSignal);
268 else if (aproc->lastExit)
269 bozo_Log("cron job %s exited with non-zero code %d\n",
270 abnode->b.name, aproc->lastExit);
272 abnode->waitingForShutdown = 0;
274 abnode->killSent = 0;
275 abnode->proc = (struct bnode_proc *) 0;
277 /* Figure out when to run next and schedule it */
278 abnode->when = ktime_next(&abnode->whenToRun, 0);
279 ScheduleCronBnode(abnode);
283 static int cron_getstring(struct cronbnode *abnode, char *abuffer,
286 if (abnode->running) strcpy(abuffer, "running now");
287 else if (abnode->when==0) strcpy(abuffer, "waiting to run once");
288 else sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
292 static int cron_getparm(struct cronbnode *abnode, afs_int32 aindex, char *abuffer, afs_int32 alen)
294 if (aindex == 0) strcpy(abuffer, abnode->command);
295 else if (aindex == 1) {
296 strcpy(abuffer, abnode->whenString);