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 <afs/param.h>
11 #include <sys/types.h>
20 #include <afs/ktime.h>
21 #include <afs/afsutil.h>
22 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
25 static int cron_timeout(), cron_getstat(), cron_setstat(), cron_delete();
26 static int cron_procexit(), cron_getstring(), cron_getparm(), cron_restartp();
27 static int cron_hascore();
28 struct bnode *cron_create();
29 extern char *ktime_DateOf();
31 #define SDTIME 60 /* time in seconds given to a process to evaporate */
33 struct bnode_ops cronbnode_ops = {
48 afs_int32 zapTime; /* time we sent a sigterm */
50 char *whenString; /* string rep. of when to run */
51 struct bnode_proc *proc;
52 afs_int32 lastStart; /* time last started process */
53 afs_int32 nextRun; /* next time to run, if no proc running */
54 struct ktime whenToRun; /* high-level rep of when should we run this guy */
55 afs_int32 when; /* computed at creation time and procexit time */
56 char everRun; /* true if ever ran */
57 char waitingForShutdown; /* have we started any shutdown procedure? */
58 char running; /* is process running? */
59 char killSent; /* have we tried sigkill signal? */
62 static int cron_hascore(abnode)
63 register struct ezbnode *abnode; {
66 bnode_CoreName(abnode, (char *) 0, tbuffer);
67 if (access(tbuffer, 0) == 0) return 1;
71 /* run at creation or after process exit. figures out if we're all done (if a
72 one shot run) or when we should run again. Sleeps until we should run again.
73 Note that the computation of when we should run again is made in procexit
74 and/or create procs. This guy only schedules the sleep */
75 ScheduleCronBnode(abnode)
76 register struct cronbnode *abnode; {
77 register afs_int32 code;
78 register afs_int32 temp;
79 struct bnode_proc *tp;
81 /* If this proc is shutdown, tell bproc() to no longer run this job */
82 if (abnode->b.goal == BSTAT_SHUTDOWN) {
83 bnode_SetTimeout(abnode, 0);
87 /* otherwise we're supposed to be running, figure out when */
88 if (abnode->when == 0) {
90 if (abnode->everRun) {
95 /* otherwise start it */
96 if (!abnode->running) {
98 abnode->lastStart = FT_ApproxTime();
99 code = bnode_NewProc(abnode, abnode->command, (char *) 0, &tp);
101 bozo_Log("cron bnode %s failed to start (code %d)\n",
102 abnode->b.name, code);
112 /* run periodically */
113 if (abnode->running) return 0;
114 /* otherwise find out when to run it, and do it then */
115 temp = abnode->when - FT_ApproxTime();
116 if (temp < 1) temp = 1; /* temp is when to start dude */
117 bnode_SetTimeout(abnode, temp);
121 static int cron_restartp (abnode)
122 register struct cronbnode *abnode; {
126 static int cron_delete(abnode)
127 struct cronbnode *abnode; {
128 free(abnode->command);
129 free(abnode->whenString);
134 struct bnode *cron_create(ainstance, acommand, awhen)
138 struct cronbnode *te;
141 extern char *copystr();
143 /* construct local path from canonical (wire-format) path */
144 if (ConstructLocalBinPath(acommand, &cmdpath)) {
145 bozo_Log("BNODE: command path invalid '%s'\n", acommand);
146 return (struct bnode *)0;
149 te = (struct cronbnode *) malloc(sizeof(struct cronbnode));
150 bzero(te, sizeof(struct cronbnode));
151 code = ktime_ParsePeriodic(awhen, &te->whenToRun);
155 return (struct bnode *) 0;
157 bnode_InitBnode(te, &cronbnode_ops, ainstance);
158 te->when = ktime_next(&te->whenToRun, 0);
159 te->command = cmdpath;
160 te->whenString = copystr(awhen);
161 return (struct bnode *) te;
164 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
165 start up a process if it is time and not already running */
166 static int cron_timeout(abnode)
167 struct cronbnode *abnode; {
168 register afs_int32 temp;
169 register afs_int32 code;
170 struct bnode_proc *tp;
172 if (!abnode->running) {
173 if (abnode->when == 0) return 0; /* spurious timeout activation */
174 /* not running, perhaps we should start it */
175 if (FT_ApproxTime() >= abnode->when) {
176 abnode->lastStart = FT_ApproxTime();
177 bnode_SetTimeout(abnode, 0);
178 code = bnode_NewProc(abnode, abnode->command, (char *) 0, &tp);
180 bozo_Log("cron failed to start bnode %s (code %d)\n",
181 abnode->b.name, code);
189 /* woke up too early, try again */
190 temp = abnode->when - FT_ApproxTime();
191 if (temp < 1) temp = 1;
192 bnode_SetTimeout(abnode, temp);
196 if (!abnode->waitingForShutdown) return 0; /* spurious */
197 /* send kill and turn off timer */
198 bnode_StopProc(abnode->proc, SIGKILL);
199 abnode->killSent = 1;
200 bnode_SetTimeout(abnode, 0);
205 static int cron_getstat(abnode, astatus)
206 struct cronbnode *abnode;
207 afs_int32 *astatus; {
208 register afs_int32 temp;
209 if (abnode->waitingForShutdown) temp = BSTAT_SHUTTINGDOWN;
210 else if (abnode->b.goal == 0) temp = BSTAT_SHUTDOWN;
211 else if (abnode->everRun && abnode->when == 0 && !abnode->running) {
212 /* special hack: bnode deletion won't happen if bnode is active, so
213 we make bnodes that are ready to be deleted automatically appear
214 as BSTAT_SHUTDOWN so bnode_Delete is happy. */
215 temp = BSTAT_SHUTDOWN;
217 else temp = BSTAT_NORMAL;
222 static int cron_setstat(abnode, astatus)
223 register struct cronbnode *abnode;
226 if (abnode->waitingForShutdown) return BZBUSY;
227 if (astatus == BSTAT_SHUTDOWN) {
228 if (abnode->running) {
230 bnode_StopProc(abnode->proc, SIGTERM);
231 abnode->waitingForShutdown = 1;
232 bnode_SetTimeout(abnode, SDTIME);
233 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
234 * [cron_procexit()] which will tell bproc() to no longer
238 /* Tell bproc() to no longer run this cron job */
239 bnode_SetTimeout(abnode, 0);
242 else if (astatus == BSTAT_NORMAL) {
243 /* start the cron job
244 * Figure out when to run next and schedule it
246 abnode->when = ktime_next(&abnode->whenToRun, 0);
247 ScheduleCronBnode(abnode);
252 static int cron_procexit(abnode, aproc)
253 struct cronbnode *abnode;
254 struct bnode_proc *aproc; {
255 /* process has exited */
257 /* log interesting errors for folks */
258 if (aproc->lastSignal)
259 bozo_Log("cron job %s exited due to signal %d\n",
260 abnode->b.name, aproc->lastSignal);
261 else if (aproc->lastExit)
262 bozo_Log("cron job %s exited with non-zero code %d\n",
263 abnode->b.name, aproc->lastExit);
265 abnode->waitingForShutdown = 0;
267 abnode->killSent = 0;
268 abnode->proc = (struct bnode_proc *) 0;
270 /* Figure out when to run next and schedule it */
271 abnode->when = ktime_next(&abnode->whenToRun, 0);
272 ScheduleCronBnode(abnode);
276 static int cron_getstring(abnode, abuffer, alen)
277 struct cronbnode *abnode;
280 if (abnode->running) strcpy(abuffer, "running now");
281 else if (abnode->when==0) strcpy(abuffer, "waiting to run once");
282 else sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
286 static cron_getparm(abnode, aindex, abuffer, alen)
287 struct cronbnode *abnode;
291 if (aindex == 0) strcpy(abuffer, abnode->command);
292 else if (aindex == 1) {
293 strcpy(abuffer, abnode->whenString);