bos: suppress unnecessary warn if -noauth
[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 #include <afs/procmgmt.h>
14 #include <roken.h>
15
16 #include <ctype.h>
17
18 #include <lwp.h>
19 #include <afs/ktime.h>
20 #include <afs/afsutil.h>
21 #include <opr/queue.h>
22
23 #include "bnode.h"
24 #include "bnode_internal.h"
25 #include "bosprototypes.h"
26
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);
38
39 #define SDTIME          60      /* time in seconds given to a process to evaporate */
40
41 struct bnode_ops cronbnode_ops = {
42     cron_create,
43     cron_timeout,
44     cron_getstat,
45     cron_setstat,
46     cron_delete,
47     cron_procexit,
48     cron_getstring,
49     cron_getparm,
50     cron_restartp,
51     cron_hascore,
52     cron_procstarted,
53 };
54
55 struct cronbnode {
56     struct bnode b;
57     afs_int32 zapTime;          /* time we sent a sigterm */
58     char *command;
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? */
69 };
70
71 static int
72 cron_hascore(struct bnode *abnode)
73 {
74     char tbuffer[256];
75
76     bnode_CoreName(abnode, NULL, tbuffer);
77     if (access(tbuffer, 0) == 0)
78         return 1;
79     else
80         return 0;
81 }
82
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 */
87 int
88 ScheduleCronBnode(struct cronbnode *abnode)
89 {
90     afs_int32 code;
91     afs_int32 temp;
92     struct bnode_proc *tp;
93
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);
97         return 0;
98     }
99
100     /* otherwise we're supposed to be running, figure out when */
101     if (abnode->when == 0) {
102         /* one shot */
103         if (abnode->everRun) {
104             /* once is enough */
105             bnode_Delete((struct bnode *)abnode);
106             return 0;
107         }
108         /* otherwise start it */
109         if (!abnode->running) {
110             /* start up */
111             abnode->lastStart = FT_ApproxTime();
112             code = bnode_NewProc((struct bnode *)abnode, abnode->command, NULL, &tp);
113             if (code) {
114                 bozo_Log("cron bnode %s failed to start (code %d)\n",
115                          abnode->b.name, code);
116                 return code;
117             }
118             abnode->everRun = 1;
119             abnode->running = 1;
120             abnode->proc = tp;
121             return 0;
122         }
123     } else {
124         /* run periodically */
125         if (abnode->running)
126             return 0;
127         /* otherwise find out when to run it, and do it then */
128         temp = abnode->when - FT_ApproxTime();
129         if (temp < 1)
130             temp = 1;           /* temp is when to start dude */
131         bnode_SetTimeout((struct bnode *)abnode, temp);
132     }
133     return 0;
134 }
135
136 static int
137 cron_restartp(struct bnode *abnode)
138 {
139     return 0;
140 }
141
142 static int
143 cron_delete(struct bnode *bn)
144 {
145     struct cronbnode *abnode = (struct cronbnode *)bn;
146     free(abnode->command);
147     free(abnode->whenString);
148     free(abnode);
149     return 0;
150 }
151
152 struct bnode *
153 cron_create(char *ainstance, char *acommand, char *awhen,
154             char *unused1, char *unused2, char *unused3)
155 {
156     struct cronbnode *te;
157     afs_int32 code;
158     char *cmdpath;
159
160     /* construct local path from canonical (wire-format) path */
161     if (ConstructLocalBinPath(acommand, &cmdpath)) {
162         bozo_Log("BNODE: command path invalid '%s'\n", acommand);
163         return NULL;
164     }
165
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)) {
169         free(te);
170         free(cmdpath);
171         return NULL;
172     }
173     te->when = ktime_next(&te->whenToRun, 0);
174     te->command = cmdpath;
175     te->whenString = strdup(awhen);
176     return (struct bnode *)te;
177 }
178
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 */
181 static int
182 cron_timeout(struct bnode *bn)
183 {
184     struct cronbnode *abnode = (struct cronbnode *)bn;
185     afs_int32 temp;
186     afs_int32 code;
187     struct bnode_proc *tp;
188
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);
197             if (code) {
198                 bozo_Log("cron failed to start bnode %s (code %d)\n",
199                          abnode->b.name, code);
200                 return code;
201             }
202             abnode->everRun = 1;
203             abnode->running = 1;
204             abnode->proc = tp;
205         } else {
206             /* woke up too early, try again */
207             temp = abnode->when - FT_ApproxTime();
208             if (temp < 1)
209                 temp = 1;
210             bnode_SetTimeout((struct bnode *)abnode, temp);
211         }
212     } else {
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);
219     }
220     return 0;
221 }
222
223 static int
224 cron_getstat(struct bnode *bn, afs_int32 * astatus)
225 {
226     struct cronbnode *abnode = (struct cronbnode *)bn;
227     afs_int32 temp;
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;
237     } else
238         temp = BSTAT_NORMAL;
239     *astatus = temp;
240     return 0;
241 }
242
243 static int
244 cron_setstat(struct bnode *bn, afs_int32 astatus)
245 {
246     struct cronbnode *abnode = (struct cronbnode *)bn;
247     if (abnode->waitingForShutdown)
248         return BZBUSY;
249     if (astatus == BSTAT_SHUTDOWN) {
250         if (abnode->running) {
251             /* start shutdown */
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
257              * run this cron job.
258              */
259         } else {
260             /* Tell bproc() to no longer run this cron job */
261             bnode_SetTimeout((struct bnode *)abnode, 0);
262         }
263     } else if (astatus == BSTAT_NORMAL) {
264         /* start the cron job
265          * Figure out when to run next and schedule it
266          */
267         abnode->when = ktime_next(&abnode->whenToRun, 0);
268         ScheduleCronBnode(abnode);
269     }
270     return 0;
271 }
272
273 static int
274 cron_procstarted(struct bnode *bn, struct bnode_proc *aproc)
275 {
276     return 0;   /* no op */
277 }
278
279 static int
280 cron_procexit(struct bnode *bn, struct bnode_proc *aproc)
281 {
282     struct cronbnode *abnode = (struct cronbnode *) bn;
283     /* process has exited */
284
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,
288                  aproc->lastSignal);
289     else if (aproc->lastExit)
290         bozo_Log("cron job %s exited with non-zero code %d\n", abnode->b.name,
291                  aproc->lastExit);
292
293     abnode->waitingForShutdown = 0;
294     abnode->running = 0;
295     abnode->killSent = 0;
296     abnode->proc = (struct bnode_proc *)0;
297
298     /* Figure out when to run next and schedule it */
299     abnode->when = ktime_next(&abnode->whenToRun, 0);
300     ScheduleCronBnode(abnode);
301     return 0;
302 }
303
304 static int
305 cron_getstring(struct bnode *bn, char *abuffer, afs_int32 alen)
306 {
307     struct cronbnode *abnode = (struct cronbnode *)bn;
308     if (abnode->running)
309         strcpy(abuffer, "running now");
310     else if (abnode->when == 0)
311         strcpy(abuffer, "waiting to run once");
312     else
313         sprintf(abuffer, "run next at %s", ktime_DateOf(abnode->when));
314     return 0;
315 }
316
317 static int
318 cron_getparm(struct bnode *bn, afs_int32 aindex, char *abuffer,
319              afs_int32 alen)
320 {
321     struct cronbnode *abnode = (struct cronbnode *)bn;
322     if (aindex == 0)
323         strcpy(abuffer, abnode->command);
324     else if (aindex == 1) {
325         strcpy(abuffer, abnode->whenString);
326     } else
327         return BZDOM;
328     return 0;
329 }