reindent-20030715
[openafs.git] / src / bucoord / bc_status.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
14     ("$Header$");
15
16 #include <afs/stds.h>
17 #include <sys/types.h>
18 #include <stdio.h>
19 #ifdef AFS_NT40_ENV
20 #include <winsock2.h>
21 #else
22 #include <strings.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <netdb.h>
26 #endif
27 #include <afs/com_err.h>
28 #include <afs/bubasics.h>
29 #include <lock.h>
30 #include <afs/tcdata.h>
31 #include "bc.h"
32 #include "error_macros.h"
33
34 #define SET_FLAG(set)                           \
35     lock_Status();                              \
36     curPollPtr->flags |= (set);                 \
37     unlock_Status();
38
39 #define CLEAR_FLAG(clear)                       \
40     lock_Status();                              \
41     curPollPtr->flags &= ~(clear);              \
42     unlock_Status();
43
44 /* globals for backup coordinator status management */
45
46 dlqlinkT statusHead;            /* chain of status blocks */
47 struct Lock statusQueueLock;    /* access control for status chain */
48 struct Lock cmdLineLock;        /* lock on the cmdLine */
49
50 afs_int32 lastTaskCode;         /* Error code from task that last finished */
51
52 /* nextItem
53  *      get next item for status interrogation, if any.
54  */
55 static statusP
56 nextItem(linkPtr)
57      statusP linkPtr;
58 {
59     dlqlinkP ptr;
60
61     ptr = (dlqlinkP) linkPtr;
62
63     /* if last known item has terminated, reset ptr */
64     if (ptr == 0) {
65         ptr = &statusHead;
66         if (dlqEmpty(ptr))
67             return (0);
68     }
69
70     ptr = ptr->dlq_next;
71
72     /* if we're back at the head again */
73     if (ptr == &statusHead)
74         return (0);
75     return ((statusP) ptr);
76 }
77
78 #ifdef notdef
79 static statusP
80 nextItem(linkPtr)
81      statusP linkPtr;
82 {
83     dlqlinkP ptr;
84
85     ptr = (dlqlinkP) linkPtr;
86
87     /* if last known item has terminated, reset ptr */
88     if (ptr == 0) {
89         ptr = &statusHead;
90         if (dlqEmpty(ptr))
91             return (0);
92     }
93
94     ptr = ptr->dlq_next;
95
96     /* if we're back at the head again */
97     if (ptr == &statusHead) {
98         ptr = ptr->dlq_next;
99     }
100     return ((statusP) ptr);
101 }
102 #endif /* notdef */
103
104 char *cmdLine;
105
106 cmdDispatch()
107 {
108 #define MAXV    100
109     char **targv[MAXV];         /*Ptr to parsed argv stuff */
110     afs_int32 targc;            /*Num parsed arguments */
111     afs_int32 code;
112     char *internalCmdLine;
113
114     internalCmdLine = cmdLine;
115     unlock_cmdLine();
116
117     code = cmd_ParseLine(internalCmdLine, targv, &targc, MAXV);
118     if (code) {
119         printf("Couldn't parse line: '%s'", error_message(code));
120         return (1);
121     }
122     free(internalCmdLine);
123
124     /*
125      * Because the "-at" option cannot be wildcarded, we cannot fall
126      * into recusive loop here by setting dispatchCount to 1.
127      */
128     doDispatch(targc, targv, 1);
129     cmd_FreeArgv(targv);
130 }
131
132 statusWatcher()
133 {
134     struct rx_connection *tconn = (struct rc_connection *)0;
135     statusP curPollPtr = 0;
136
137     struct tciStatusS statusPtr;
138
139     /* task information */
140     afs_uint32 taskFlags;
141     afs_uint32 localTaskFlags;
142     afs_uint32 temp;            /* for flag manipulation */
143     afs_int32 jobNumber;
144     afs_int32 taskId;
145     afs_int32 port;
146     afs_int32 atTime;
147     PROCESS dispatchPid;
148
149     afs_int32 code = 0;
150     extern struct bc_config *bc_globalConfig;
151     extern struct rx_connection *bc_GetConn();
152
153     lastTaskCode = 0;
154
155     while (1) {                 /*w */
156         if (tconn)
157             rx_DestroyConnection(tconn);
158         tconn = (struct rc_connection *)0;
159
160         lock_Status();
161         curPollPtr = nextItem(curPollPtr);
162
163         if (curPollPtr == 0) {
164 #ifdef AFS_PTHREAD_ENV
165             struct timespec delaytime;
166             unlock_Status();
167             delayTime.tv_sec = 5;
168             delayTime.tv_nsec = 0;
169             pthread_delay_np(&delayTime);
170 #else
171             unlock_Status();
172             IOMGR_Sleep(5);     /* wait a while */
173 #endif /*else AFS_PTHREAD_ENV */
174             continue;
175         }
176
177         /* save useful information */
178         localTaskFlags = curPollPtr->flags;
179         taskId = curPollPtr->taskId;
180         port = curPollPtr->port;
181         atTime = curPollPtr->scheduledDump;
182         jobNumber = curPollPtr->jobNumber;
183         unlock_Status();
184
185         /* reset certain flags; local kill; */
186         CLEAR_FLAG(ABORT_LOCAL);
187
188         /* An abort request before the command even started */
189         if (atTime && (localTaskFlags & ABORT_REQUEST)) {
190             if (localTaskFlags & NOREMOVE) {
191                 curPollPtr->flags |= (STARTING | ABORT_DONE);   /* Will ignore on other passes */
192                 curPollPtr->scheduledDump = 0;
193             } else {
194                 deleteStatusNode(curPollPtr);
195             }
196             curPollPtr = 0;
197             continue;
198         }
199
200         /* A task not started yet - check its start time */
201         if (localTaskFlags & STARTING || atTime) {
202             /*
203              * Start a timed dump if its time has come.  When the job is 
204              * started, it will allocate its own status structure so this 
205              * one is no longer needed: delete it. 
206              *
207              * Avoid multiple processes trouncing the cmdLine by placing 
208              * lock around it.
209              */
210             if (atTime && (atTime <= time(0))) {
211                 lock_cmdLine(); /* Will unlock in cmdDispatch */
212
213                 cmdLine = curPollPtr->cmdLine;
214                 lock_Status();
215                 curPollPtr->cmdLine = 0;
216                 unlock_Status();
217
218                 printf("Starting scheduled dump: job %d\n", jobNumber);
219                 printf("schedD> %s\n", cmdLine);
220
221                 code =
222                     LWP_CreateProcess(cmdDispatch, 16384, LWP_NORMAL_PRIORITY,
223                                       (void *)2, "cmdDispatch", &dispatchPid);
224                 if (code) {
225                     if (cmdLine)
226                         free(cmdLine);
227                     unlock_cmdLine();
228                     printf("Couldn't create cmdDispatch task\n");
229                 }
230
231                 if (localTaskFlags & NOREMOVE) {
232                     curPollPtr->flags |= STARTING;      /* Will ignore on other passes */
233                     curPollPtr->flags |= (code ? TASK_ERROR : TASK_DONE);
234                     curPollPtr->scheduledDump = 0;
235                 } else {
236                     deleteStatusNode(curPollPtr);
237                 }
238                 curPollPtr = 0;
239             }
240             continue;
241         }
242
243         if (localTaskFlags & ABORT_LOCAL) {
244             /* kill the local task */
245             if ((localTaskFlags & CONTACT_LOST) != 0) {
246                 printf("Job %d: in contact with butc at port %d\n", jobNumber,
247                        port);
248                 printf("Job %d cont: Local kill ignored - use normal kill\n",
249                        jobNumber);
250             }
251         }
252
253         code = (afs_int32) bc_GetConn(bc_globalConfig, port, &tconn);
254         if (code) {
255             SET_FLAG(CONTACT_LOST);
256             continue;
257         }
258
259         if (CheckTCVersion(tconn)) {
260             SET_FLAG(CONTACT_LOST);
261             continue;
262         }
263
264         /* Send abort to TC requst if we have to */
265         if (localTaskFlags & ABORT_REQUEST) {
266             code = TC_RequestAbort(tconn, taskId);
267             if (code) {
268                 com_err("statusWatcher", code, "; Can't post abort request");
269                 com_err("statusWatcher", 0, "...Deleting job");
270                 if (localTaskFlags & NOREMOVE) {
271                     curPollPtr->flags |= (STARTING | TASK_ERROR);
272                     curPollPtr->scheduledDump = 0;
273                 } else {
274                     deleteStatusNode(curPollPtr);
275                 }
276                 curPollPtr = 0;
277                 continue;
278             } else {
279                 lock_Status();
280                 curPollPtr->flags &= ~ABORT_REQUEST;
281                 curPollPtr->flags |= ABORT_SENT;
282                 unlock_Status();
283             }
284         }
285
286         /* otherwise just get the status */
287         code = TC_GetStatus(tconn, taskId, &statusPtr);
288         if (code) {
289             if (code == TC_NODENOTFOUND) {
290                 printf("Job %d: %s - no such task on port %d, deleting\n",
291                        jobNumber, curPollPtr->taskName, port);
292
293                 if (localTaskFlags & NOREMOVE) {
294                     curPollPtr->flags |= (STARTING | TASK_ERROR);
295                     curPollPtr->scheduledDump = 0;
296                 } else {
297                     deleteStatusNode(curPollPtr);       /* delete this status node */
298                 }
299                 curPollPtr = 0;
300                 continue;
301             }
302
303             SET_FLAG(CONTACT_LOST);
304             continue;
305         }
306
307         /* in case we previously lost contact or couldn't find */
308         CLEAR_FLAG(CONTACT_LOST);
309
310         /* extract useful status */
311         taskFlags = statusPtr.flags;
312
313         /* update local status */
314         lock_Status();
315
316         /* remember some status flags in local struct */
317         temp =
318             (DRIVE_WAIT | OPR_WAIT | CALL_WAIT | TASK_DONE | ABORT_DONE |
319              TASK_ERROR);
320         curPollPtr->flags &= ~temp;     /* clear */
321         curPollPtr->flags |= (taskFlags & temp);        /* update */
322
323         curPollPtr->dbDumpId = statusPtr.dbDumpId;
324         curPollPtr->nKBytes = statusPtr.nKBytes;
325         strcpy(curPollPtr->volumeName, statusPtr.volumeName);
326         curPollPtr->volsFailed = statusPtr.volsFailed;
327         curPollPtr->lastPolled = statusPtr.lastPolled;
328         unlock_Status();
329
330         /* Are we done */
331         if (taskFlags & TASK_DONE) {    /*done */
332             if (taskFlags & ABORT_DONE) {
333                 if (curPollPtr->dbDumpId)
334                     printf("Job %d: %s: DumpID %u Aborted", jobNumber,
335                            curPollPtr->taskName, curPollPtr->dbDumpId);
336                 else
337                     printf("Job %d: %s Aborted", jobNumber,
338                            curPollPtr->taskName);
339
340                 if (taskFlags & TASK_ERROR)
341                     printf(" with errors\n");
342                 else
343                     printf("\n");
344
345                 lastTaskCode = 1;
346             }
347
348             else if (taskFlags & TASK_ERROR) {
349                 if (!(localTaskFlags & SILENT)) {
350                     if (curPollPtr->dbDumpId)
351                         printf("Job %d: DumpID %u Failed with errors\n",
352                                jobNumber, curPollPtr->dbDumpId);
353                     else
354                         printf("Job %d Failed with errors\n", jobNumber);
355                 }
356                 lastTaskCode = 2;
357             }
358
359             else {
360                 if (!(localTaskFlags & SILENT)) {
361                     if (curPollPtr->dbDumpId)
362                         printf("Job %d: %s: DumpID %u finished", jobNumber,
363                                curPollPtr->taskName, curPollPtr->dbDumpId);
364                     else
365                         printf("Job %d: %s finished", jobNumber,
366                                curPollPtr->taskName);
367
368                     if (curPollPtr->volsTotal) {
369                         printf(". %d volumes dumped",
370                                (curPollPtr->volsTotal -
371                                 curPollPtr->volsFailed));
372                         if (curPollPtr->volsFailed)
373                             printf(", %d failed", curPollPtr->volsFailed);
374                     }
375
376                     printf("\n");
377                 }
378                 lastTaskCode = 0;
379             }
380
381             /* make call to destroy task on server */
382             code = TC_EndStatus(tconn, taskId);
383             if (code)
384                 printf("Job %d: %s, error in job termination cleanup\n",
385                        jobNumber, curPollPtr->taskName);
386
387             if (localTaskFlags & NOREMOVE) {
388                 curPollPtr->flags |= STARTING;
389                 curPollPtr->scheduledDump = 0;
390             } else {
391                 deleteStatusNode(curPollPtr);   /* unlink and destroy local task */
392             }
393             curPollPtr = 0;
394         }                       /*done */
395     }                           /*w */
396 }
397
398 /* bc_jobNumber
399  *      Allocate a job number. Computes the maximum of all the job numbers
400  *      and then returns the maximum+1.
401  *      If no jobs are found, returns 1.
402  */
403
404 afs_int32
405 bc_jobNumber()
406 {
407     afs_int32 retval = 0;
408     dlqlinkP ptr;
409
410     ptr = statusHead.dlq_next;
411     while (ptr != &statusHead) {
412         /* compute max of all job numbers */
413         if (((statusP) ptr)->jobNumber > retval)
414             retval = ((statusP) ptr)->jobNumber;
415
416         ptr = ptr->dlq_next;
417     }
418     retval++;
419     return (retval);
420 }
421
422 /* waitForTask
423  *    Wait for a specific task to finish and then return.
424  *    Return the task's flags when it's done. If the job
425  *    had been cleaned up, then just return 0.
426  */
427 waitForTask(taskId)
428      afs_uint32 taskId;
429 {
430     statusP ptr;
431     afs_int32 done = 0, rcode, t;
432     extern statusP findStatus();
433
434     t = (TASK_DONE | ABORT_DONE | TASK_ERROR);
435     while (!done) {
436         /* Sleep 2 seconds */
437 #ifdef AFS_PTHREAD_ENV
438         struct timespec delaytime;
439         delayTime.tv_sec = 2;
440         delayTime.tv_nsec = 0;
441         pthread_delay_np(&delayTime);
442 #else
443         IOMGR_Sleep(2);
444 #endif /*else AFS_PTHREAD_ENV */
445
446         /* Check if we are done */
447         lock_Status();
448         ptr = findStatus(taskId);
449         if (!ptr || (ptr->flags & t)) {
450             rcode = (ptr ? ptr->flags : 0);
451             done = 1;
452         }
453         unlock_Status();
454     }
455     return rcode;
456 }