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>
21 #include <opr/queue.h>
24 #include "bnode_internal.h"
25 #include "bosprototypes.h"
27 struct bnode
*cron_create(char *, char *, char *, char *, char *, char *);
28 static int cron_hascore(struct bnode
*bnode
);
29 static int cron_restartp(struct bnode
*bnode
);
30 static int cron_delete(struct bnode
*bnode
);
31 static int cron_timeout(struct bnode
*bnode
);
32 static int cron_getstat(struct bnode
*bnode
, afs_int32
*status
);
33 static int cron_setstat(struct bnode
*bnode
, afs_int32 status
);
34 static int cron_procstarted(struct bnode
*bnode
, struct bnode_proc
*proc
);
35 static int cron_procexit(struct bnode
*bnode
, struct bnode_proc
*proc
);
36 static int cron_getstring(struct bnode
*bnode
, char *abuffer
, afs_int32 alen
);
37 static int cron_getparm(struct bnode
*bnode
, afs_int32
, char *, afs_int32
);
39 #define SDTIME 60 /* time in seconds given to a process to evaporate */
41 struct bnode_ops cronbnode_ops
= {
57 afs_int32 zapTime
; /* time we sent a sigterm */
59 char *whenString
; /* string rep. of when to run */
60 struct bnode_proc
*proc
;
61 afs_int32 lastStart
; /* time last started process */
62 afs_int32 nextRun
; /* next time to run, if no proc running */
63 struct ktime whenToRun
; /* high-level rep of when should we run this guy */
64 afs_int32 when
; /* computed at creation time and procexit time */
65 char everRun
; /* true if ever ran */
66 char waitingForShutdown
; /* have we started any shutdown procedure? */
67 char running
; /* is process running? */
68 char killSent
; /* have we tried sigkill signal? */
72 cron_hascore(struct bnode
*abnode
)
76 bnode_CoreName(abnode
, NULL
, tbuffer
);
77 if (access(tbuffer
, 0) == 0)
83 /* run at creation or after process exit. figures out if we're all done (if a
84 one shot run) or when we should run again. Sleeps until we should run again.
85 Note that the computation of when we should run again is made in procexit
86 and/or create procs. This guy only schedules the sleep */
88 ScheduleCronBnode(struct cronbnode
*abnode
)
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((struct bnode
*)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((struct bnode
*)abnode
);
108 /* otherwise start it */
109 if (!abnode
->running
) {
111 abnode
->lastStart
= FT_ApproxTime();
112 code
= bnode_NewProc((struct bnode
*)abnode
, abnode
->command
, NULL
, &tp
);
114 bozo_Log("cron bnode %s failed to start (code %d)\n",
115 abnode
->b
.name
, code
);
124 /* run periodically */
127 /* otherwise find out when to run it, and do it then */
128 temp
= abnode
->when
- FT_ApproxTime();
130 temp
= 1; /* temp is when to start dude */
131 bnode_SetTimeout((struct bnode
*)abnode
, temp
);
137 cron_restartp(struct bnode
*abnode
)
143 cron_delete(struct bnode
*bn
)
145 struct cronbnode
*abnode
= (struct cronbnode
*)bn
;
146 free(abnode
->command
);
147 free(abnode
->whenString
);
153 cron_create(char *ainstance
, char *acommand
, char *awhen
,
154 char *unused1
, char *unused2
, char *unused3
)
156 struct cronbnode
*te
;
160 /* construct local path from canonical (wire-format) path */
161 if (ConstructLocalBinPath(acommand
, &cmdpath
)) {
162 bozo_Log("BNODE: command path invalid '%s'\n", acommand
);
166 te
= calloc(1, sizeof(struct cronbnode
));
167 code
= ktime_ParsePeriodic(awhen
, &te
->whenToRun
);
168 if ((code
< 0) || (bnode_InitBnode((struct bnode
*)te
, &cronbnode_ops
, ainstance
) != 0)) {
173 te
->when
= ktime_next(&te
->whenToRun
, 0);
174 te
->command
= cmdpath
;
175 te
->whenString
= strdup(awhen
);
176 return (struct bnode
*)te
;
179 /* called to SIGKILL a process if it doesn't terminate normally. In cron, also
180 start up a process if it is time and not already running */
182 cron_timeout(struct bnode
*bn
)
184 struct cronbnode
*abnode
= (struct cronbnode
*)bn
;
187 struct bnode_proc
*tp
;
189 if (!abnode
->running
) {
190 if (abnode
->when
== 0)
191 return 0; /* spurious timeout activation */
192 /* not running, perhaps we should start it */
193 if (FT_ApproxTime() >= abnode
->when
) {
194 abnode
->lastStart
= FT_ApproxTime();
195 bnode_SetTimeout((struct bnode
*)abnode
, 0);
196 code
= bnode_NewProc((struct bnode
*)abnode
, abnode
->command
, NULL
, &tp
);
198 bozo_Log("cron failed to start bnode %s (code %d)\n",
199 abnode
->b
.name
, code
);
206 /* woke up too early, try again */
207 temp
= abnode
->when
- FT_ApproxTime();
210 bnode_SetTimeout((struct bnode
*)abnode
, temp
);
213 if (!abnode
->waitingForShutdown
)
214 return 0; /* spurious */
215 /* send kill and turn off timer */
216 bnode_StopProc(abnode
->proc
, SIGKILL
);
217 abnode
->killSent
= 1;
218 bnode_SetTimeout((struct bnode
*)abnode
, 0);
224 cron_getstat(struct bnode
*bn
, afs_int32
* astatus
)
226 struct cronbnode
*abnode
= (struct cronbnode
*)bn
;
228 if (abnode
->waitingForShutdown
)
229 temp
= BSTAT_SHUTTINGDOWN
;
230 else if (abnode
->b
.goal
== 0)
231 temp
= BSTAT_SHUTDOWN
;
232 else if (abnode
->everRun
&& abnode
->when
== 0 && !abnode
->running
) {
233 /* special hack: bnode deletion won't happen if bnode is active, so
234 * we make bnodes that are ready to be deleted automatically appear
235 * as BSTAT_SHUTDOWN so bnode_Delete is happy. */
236 temp
= BSTAT_SHUTDOWN
;
244 cron_setstat(struct bnode
*bn
, afs_int32 astatus
)
246 struct cronbnode
*abnode
= (struct cronbnode
*)bn
;
247 if (abnode
->waitingForShutdown
)
249 if (astatus
== BSTAT_SHUTDOWN
) {
250 if (abnode
->running
) {
252 bnode_StopProc(abnode
->proc
, SIGTERM
);
253 abnode
->waitingForShutdown
= 1;
254 bnode_SetTimeout((struct bnode
*)abnode
, SDTIME
);
255 /* When shutdown is complete, bproc() calls BOP_PROCEXIT()
256 * [cron_procexit()] which will tell bproc() to no longer
260 /* Tell bproc() to no longer run this cron job */
261 bnode_SetTimeout((struct bnode
*)abnode
, 0);
263 } else if (astatus
== BSTAT_NORMAL
) {
264 /* start the cron job
265 * Figure out when to run next and schedule it
267 abnode
->when
= ktime_next(&abnode
->whenToRun
, 0);
268 ScheduleCronBnode(abnode
);
274 cron_procstarted(struct bnode
*bn
, struct bnode_proc
*aproc
)
276 return 0; /* no op */
280 cron_procexit(struct bnode
*bn
, struct bnode_proc
*aproc
)
282 struct cronbnode
*abnode
= (struct cronbnode
*) bn
;
283 /* process has exited */
285 /* log interesting errors for folks */
286 if (aproc
->lastSignal
)
287 bozo_Log("cron job %s exited due to signal %d\n", abnode
->b
.name
,
289 else if (aproc
->lastExit
)
290 bozo_Log("cron job %s exited with non-zero code %d\n", abnode
->b
.name
,
293 abnode
->waitingForShutdown
= 0;
295 abnode
->killSent
= 0;
296 abnode
->proc
= (struct bnode_proc
*)0;
298 /* Figure out when to run next and schedule it */
299 abnode
->when
= ktime_next(&abnode
->whenToRun
, 0);
300 ScheduleCronBnode(abnode
);
305 cron_getstring(struct bnode
*bn
, char *abuffer
, afs_int32 alen
)
307 struct cronbnode
*abnode
= (struct cronbnode
*)bn
;
309 strcpy(abuffer
, "running now");
310 else if (abnode
->when
== 0)
311 strcpy(abuffer
, "waiting to run once");
313 sprintf(abuffer
, "run next at %s", ktime_DateOf(abnode
->when
));
318 cron_getparm(struct bnode
*bn
, afs_int32 aindex
, char *abuffer
,
321 struct cronbnode
*abnode
= (struct cronbnode
*)bn
;
323 strcpy(abuffer
, abnode
->command
);
324 else if (aindex
== 1) {
325 strcpy(abuffer
, abnode
->whenString
);