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