convert-from-bsd-to-posix-string-and-memory-functions-20010807
[openafs.git] / src / bozo / cronbnodeops.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
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
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID("$Header$");
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <lwp.h>
18 #include <time.h>
19 #include <ctype.h>
20 #include <stdio.h>
21 #ifdef AFS_NT40_ENV
22 #include <io.h>
23 #endif
24 #include <afs/ktime.h>
25 #include <afs/afsutil.h>
26 #include <afs/procmgmt.h>  /* signal(), kill(), wait(), etc. */
27 #include "bnode.h"
28
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();
34
35 #define SDTIME          60          /* time in seconds given to a process to evaporate */
36
37 struct bnode_ops cronbnode_ops = {
38     cron_create,
39     cron_timeout,
40     cron_getstat,
41     cron_setstat,
42     cron_delete,
43     cron_procexit,
44     cron_getstring,
45     cron_getparm,
46     cron_restartp,
47     cron_hascore,
48 };
49     
50 struct cronbnode {
51     struct bnode b;
52     afs_int32 zapTime;          /* time we sent a sigterm */
53     char *command;
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? */
64 };
65
66 static int cron_hascore(abnode)
67 register struct ezbnode *abnode; {
68     char tbuffer[256];
69
70     bnode_CoreName(abnode, (char *) 0, tbuffer);
71     if (access(tbuffer, 0) == 0) return 1;
72     else return 0;
73 }
74
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;
84
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);
88         return 0;
89     }
90
91     /* otherwise we're supposed to be running, figure out when */
92     if (abnode->when == 0) {
93         /* one shot */
94         if (abnode->everRun) {
95             /* once is enough */
96             bnode_Delete(abnode);
97             return 0;
98         }
99         /* otherwise start it */
100         if (!abnode->running) {
101             /* start up */
102             abnode->lastStart = FT_ApproxTime();
103             code = bnode_NewProc(abnode, abnode->command, (char *) 0, &tp);
104             if (code) {
105                 bozo_Log("cron bnode %s failed to start (code %d)\n",
106                          abnode->b.name, code);
107                 return code;
108             }
109             abnode->everRun = 1;
110             abnode->running = 1;
111             abnode->proc = tp;
112             return 0;
113         }
114     }
115     else {
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);
122     }
123 }
124
125 static int cron_restartp (abnode)
126 register struct cronbnode *abnode; {
127     return 0;
128 }
129
130 static int cron_delete(abnode)
131 struct cronbnode *abnode; {
132     free(abnode->command);
133     free(abnode->whenString);
134     free(abnode);
135     return 0;
136 }
137
138 struct bnode *cron_create(ainstance, acommand, awhen)
139 char *ainstance;
140 char *awhen;
141 char *acommand; {
142     struct cronbnode *te;
143     afs_int32 code;
144     char *cmdpath;
145     extern char *copystr();
146
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;
151     }
152
153     te = (struct cronbnode *) malloc(sizeof(struct cronbnode));
154     memset(te, 0, sizeof(struct cronbnode));
155     code = ktime_ParsePeriodic(awhen, &te->whenToRun);
156     if (code < 0) {
157         free(te);
158         free(cmdpath);
159         return (struct bnode *) 0;
160     }
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;
166 }
167
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;
175
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);
183             if (code) {
184                 bozo_Log("cron failed to start bnode %s (code %d)\n",
185                          abnode->b.name, code);
186                 return code;
187             }
188             abnode->everRun = 1;
189             abnode->running = 1;
190             abnode->proc = tp;
191         }
192         else {
193             /* woke up too early, try again */
194             temp = abnode->when - FT_ApproxTime();
195             if (temp < 1) temp = 1;
196             bnode_SetTimeout(abnode, temp);
197         }
198     }
199     else {
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);
205     }
206     return 0;
207 }
208
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;
220     }
221     else temp = BSTAT_NORMAL;
222     *astatus = temp;
223     return 0;
224 }
225
226 static int cron_setstat(abnode, astatus)
227 register struct cronbnode *abnode;
228 afs_int32 astatus; {
229
230     if (abnode->waitingForShutdown) return BZBUSY;
231     if (astatus == BSTAT_SHUTDOWN) {
232        if (abnode->running) {
233           /* start shutdown */
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
239            * run this cron job.
240            */
241        } else {
242           /* Tell bproc() to no longer run this cron job */
243           bnode_SetTimeout(abnode, 0);
244        }
245     }
246     else if (astatus == BSTAT_NORMAL) {
247         /* start the cron job
248          * Figure out when to run next and schedule it
249          */
250         abnode->when = ktime_next(&abnode->whenToRun, 0);
251         ScheduleCronBnode(abnode);
252     }
253     return 0;
254 }
255
256 static int cron_procexit(abnode, aproc)
257 struct cronbnode *abnode;
258 struct bnode_proc *aproc; {
259     /* process has exited */
260
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);
268
269     abnode->waitingForShutdown = 0;
270     abnode->running = 0;
271     abnode->killSent = 0;
272     abnode->proc = (struct bnode_proc *) 0;
273
274     /* Figure out when to run next and schedule it */
275     abnode->when = ktime_next(&abnode->whenToRun, 0);
276     ScheduleCronBnode(abnode);
277     return 0;
278 }
279
280 static int cron_getstring(abnode, abuffer, alen)
281 struct cronbnode *abnode;
282 char *abuffer;
283 afs_int32 alen;{
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));
287     return 0;
288 }
289
290 static cron_getparm(abnode, aindex, abuffer, alen)
291 struct cronbnode *abnode;
292 afs_int32 aindex;
293 char *abuffer;
294 afs_int32 alen; {
295     if (aindex == 0) strcpy(abuffer, abnode->command);
296     else if (aindex == 1) {
297         strcpy(abuffer, abnode->whenString);
298     }
299     else return BZDOM;
300     return 0;
301 }