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>
13 #include <afs/procmgmt.h>
19 #include <afs/ktime.h>
20 #include <afs/afsutil.h>
23 #include "bnode_internal.h"
24 #include "bosprototypes.h"
26 struct bnode *cron_create(char *, char *, char *, char *, char *, char *);
27 static int cron_hascore(struct bnode *bnode);
28 static int cron_restartp(struct bnode *bnode);
29 static int cron_delete(struct bnode *bnode);
30 static int cron_timeout(struct bnode *bnode);
31 static int cron_getstat(struct bnode *bnode, afs_int32 *status);
32 static int cron_setstat(struct bnode *bnode, afs_int32 status);
33 static int cron_procstarted(struct bnode *bnode, struct bnode_proc *proc);
34 static int cron_procexit(struct bnode *bnode, struct bnode_proc *proc);
35 static int cron_getstring(struct bnode *bnode, char *abuffer, afs_int32 alen);
36 static int cron_getparm(struct bnode *bnode, afs_int32, char *, afs_int32);
38 #define SDTIME 60 /* time in seconds given to a process to evaporate */
40 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(struct bnode *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(struct cronbnode *abnode)
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((struct bnode *)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((struct bnode *)abnode);
107 /* otherwise start it */
108 if (!abnode->running) {
110 abnode->lastStart = FT_ApproxTime();
111 code = bnode_NewProc((struct bnode *)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((struct bnode *)abnode, temp);
136 cron_restartp(struct bnode *abnode)
142 cron_delete(struct bnode *bn)
144 struct cronbnode *abnode = (struct cronbnode *)bn;
145 free(abnode->command);
146 free(abnode->whenString);
152 cron_create(char *ainstance, char *acommand, char *awhen,
153 char *unused1, char *unused2, char *unused3)
155 struct cronbnode *te;
159 /* construct local path from canonical (wire-format) path */
160 if (ConstructLocalBinPath(acommand, &cmdpath)) {
161 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
165 te = calloc(1, sizeof(struct cronbnode));
166 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
167 if ((code < 0) || (bnode_InitBnode((struct bnode *)te, &cronbnode_ops, ainstance) != 0)) {
172 te->when = ktime_next(&te->whenToRun, 0);
173 te->command = cmdpath;
174 te->whenString = strdup(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 bnode *bn)
183 struct cronbnode *abnode = (struct cronbnode *)bn;
186 struct bnode_proc *tp;
188 if (!abnode->running) {
189 if (abnode->when == 0)
190 return 0; /* spurious timeout activation */
191 /* not running, perhaps we should start it */
192 if (FT_ApproxTime() >= abnode->when) {
193 abnode->lastStart = FT_ApproxTime();
194 bnode_SetTimeout((struct bnode *)abnode, 0);
195 code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
197 bozo_Log("cron failed to start bnode %s (code %d)\n",
198 abnode->b.name, code);
205 /* woke up too early, try again */
206 temp = abnode->when - FT_ApproxTime();
209 bnode_SetTimeout((struct bnode *)abnode, temp);
212 if (!abnode->waitingForShutdown)
213 return 0; /* spurious */
214 /* send kill and turn off timer */
215 bnode_StopProc(abnode->proc, SIGKILL);
216 abnode->killSent = 1;
217 bnode_SetTimeout((struct bnode *)abnode, 0);
223 cron_getstat(struct bnode *bn, afs_int32 * astatus)
225 struct cronbnode *abnode = (struct cronbnode *)bn;
227 if (abnode->waitingForShutdown)
228 temp = BSTAT_SHUTTINGDOWN;
229 else if (abnode->b.goal == 0)
230 temp = BSTAT_SHUTDOWN;
231 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
232 /* special hack: bnode deletion won't happen if bnode is active, so
233 * we make bnodes that are ready to be deleted automatically appear
234 * as BSTAT_SHUTDOWN so bnode_Delete is happy. */
235 temp = BSTAT_SHUTDOWN;
243 cron_setstat(struct bnode *bn, afs_int32 astatus)
245 struct cronbnode *abnode = (struct cronbnode *)bn;
246 if (abnode->waitingForShutdown)
248 if (astatus == BSTAT_SHUTDOWN) {
249 if (abnode->running) {
251 bnode_StopProc(abnode->proc, SIGTERM);
252 abnode->waitingForShutdown = 1;
253 bnode_SetTimeout((struct bnode *)abnode, SDTIME);
254 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
255 * [cron_procexit()] which will tell bproc() to no longer
259 /* Tell bproc() to no longer run this cron job */
260 bnode_SetTimeout((struct bnode *)abnode, 0);
262 } else if (astatus == BSTAT_NORMAL) {
263 /* start the cron job
264 * Figure out when to run next and schedule it
266 abnode->when = ktime_next(&abnode->whenToRun, 0);
267 ScheduleCronBnode(abnode);
273 cron_procstarted(struct bnode *bn, struct bnode_proc *aproc)
275 return 0; /* no op */
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);