afsconfig-and-rcsid-all-around-20010705
[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 <afs/param.h>
11 #include <afsconfig.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     rtruct 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, LWP_NORMAL_PRIORITY, 2,
228                                          "cmdDispatch", &dispatchPid);
229                 if ( code )
230                 {
231                     if (cmdLine) 
232                         free(cmdLine);
233                     unlock_cmdLine();
234                     printf("Couldn't create cmdDispatch task\n");
235                 }
236
237                 if (localTaskFlags & NOREMOVE) {
238                    curPollPtr->flags |= STARTING;  /* Will ignore on other passes */
239                    curPollPtr->flags |= (code?TASK_ERROR:TASK_DONE);
240                    curPollPtr->scheduledDump = 0;
241                 } else {
242                    deleteStatusNode(curPollPtr);
243                 }
244                 curPollPtr = 0;
245             }
246             continue;
247         }
248
249         if ( localTaskFlags & ABORT_LOCAL )
250         {
251             /* kill the local task */
252             if ( (localTaskFlags & CONTACT_LOST) != 0 )
253             {
254                 printf("Job %d: in contact with butc at port %d\n",
255                        jobNumber, port);
256                 printf("Job %d cont: Local kill ignored - use normal kill\n",
257                        jobNumber);
258             }
259         }
260
261         code = (afs_int32)bc_GetConn(bc_globalConfig, port, &tconn);
262         if (code)
263         {
264             SET_FLAG(CONTACT_LOST);
265             continue;
266         }
267
268         if ( CheckTCVersion(tconn) )
269         {
270             SET_FLAG(CONTACT_LOST);
271             continue;
272         }
273
274         /* Send abort to TC requst if we have to */
275         if ( localTaskFlags & ABORT_REQUEST )
276         {
277             code = TC_RequestAbort(tconn, taskId);
278             if ( code )
279             {
280                 com_err("statusWatcher", code, "; Can't post abort request");
281                 com_err("statusWatcher", 0, "...Deleting job");
282                 if (localTaskFlags & NOREMOVE) {
283                    curPollPtr->flags |= (STARTING|TASK_ERROR);
284                    curPollPtr->scheduledDump = 0;
285                 } else {
286                    deleteStatusNode(curPollPtr);
287                 }
288                 curPollPtr = 0;
289                 continue;
290             }
291             else
292             {
293                 lock_Status();
294                 curPollPtr->flags &= ~ABORT_REQUEST;
295                 curPollPtr->flags |= ABORT_SENT;
296                 unlock_Status();
297             }
298         }
299
300         /* otherwise just get the status */
301         code = TC_GetStatus(tconn, taskId, &statusPtr);
302         if (code)
303         {
304             if (code == TC_NODENOTFOUND)
305             {
306                 printf("Job %d: %s - no such task on port %d, deleting\n",
307                        jobNumber, curPollPtr->taskName, port);
308
309                 if (localTaskFlags & NOREMOVE) {
310                    curPollPtr->flags |= (STARTING|TASK_ERROR);
311                    curPollPtr->scheduledDump = 0;
312                 } else {
313                    deleteStatusNode(curPollPtr);      /* delete this status node */
314                 }
315                 curPollPtr = 0;
316                 continue;
317             }
318
319             SET_FLAG(CONTACT_LOST);
320             continue;
321         }
322
323         /* in case we previously lost contact or couldn't find */
324         CLEAR_FLAG(CONTACT_LOST);
325
326         /* extract useful status */
327         taskFlags = statusPtr.flags;
328
329         /* update local status */
330         lock_Status();
331
332         /* remember some status flags in local struct */
333         temp = (DRIVE_WAIT | OPR_WAIT | CALL_WAIT | TASK_DONE | ABORT_DONE | TASK_ERROR);
334         curPollPtr->flags &= ~temp;                     /* clear */
335         curPollPtr->flags |= (taskFlags & temp);        /* update */
336
337         curPollPtr->dbDumpId = statusPtr.dbDumpId;
338         curPollPtr->nKBytes = statusPtr.nKBytes;
339         strcpy(curPollPtr->volumeName, statusPtr.volumeName);
340         curPollPtr->volsFailed = statusPtr.volsFailed;
341         curPollPtr->lastPolled = statusPtr.lastPolled;
342         unlock_Status();
343
344         /* Are we done */
345         if (taskFlags & TASK_DONE)
346         { /*done*/
347             if (taskFlags & ABORT_DONE)
348             {
349                 if (curPollPtr->dbDumpId)
350                     printf("Job %d: %s: DumpID %u Aborted",
351                            jobNumber, curPollPtr->taskName, curPollPtr->dbDumpId);
352                 else
353                     printf("Job %d: %s Aborted", jobNumber, curPollPtr->taskName);
354
355                 if ( taskFlags & TASK_ERROR ) printf(" with errors\n");
356                 else                          printf("\n");
357                 
358                 lastTaskCode = 1;
359             }
360
361             else if (taskFlags & TASK_ERROR)
362             {
363                 if ( !(localTaskFlags & SILENT) ) {
364                    if (curPollPtr->dbDumpId)
365                       printf("Job %d: DumpID %u Failed with errors\n", 
366                              jobNumber, curPollPtr->dbDumpId);
367                    else
368                       printf("Job %d Failed with errors\n", jobNumber);
369                 }
370                 lastTaskCode = 2;
371             }
372
373             else
374             {
375                 if ( !(localTaskFlags & SILENT) )
376                 {
377                     if (curPollPtr->dbDumpId)
378                         printf("Job %d: %s: DumpID %u finished", 
379                                jobNumber, curPollPtr->taskName, curPollPtr->dbDumpId);
380                     else
381                         printf("Job %d: %s finished", jobNumber, curPollPtr->taskName);
382
383                     if (curPollPtr->volsTotal)
384                     {
385                         printf(". %d volumes dumped", (curPollPtr->volsTotal-
386                                                        curPollPtr->volsFailed));
387                         if ( curPollPtr->volsFailed)
388                            printf(", %d failed", curPollPtr->volsFailed);
389                     }
390
391                     printf("\n");
392                 }
393                 lastTaskCode = 0;
394             }
395
396             /* make call to destroy task on server */
397             code = TC_EndStatus(tconn, taskId);
398             if ( code )
399                printf("Job %d: %s, error in job termination cleanup\n",
400                       jobNumber, curPollPtr->taskName);
401             
402             if (localTaskFlags & NOREMOVE) {
403                curPollPtr->flags |= STARTING;
404                curPollPtr->scheduledDump = 0;
405             } else {
406                deleteStatusNode(curPollPtr);        /* unlink and destroy local task */
407             }
408             curPollPtr = 0;
409         } /*done*/
410     } /*w*/
411 }
412
413 /* bc_jobNumber
414  *      Allocate a job number. Computes the maximum of all the job numbers
415  *      and then returns the maximum+1.
416  *      If no jobs are found, returns 1.
417  */
418
419 afs_int32
420 bc_jobNumber()
421 {
422     afs_int32 retval = 0;
423     dlqlinkP ptr;
424
425     ptr = statusHead.dlq_next;
426     while ( ptr != &statusHead )
427     {
428         /* compute max of all job numbers */
429         if ( ((statusP) ptr)->jobNumber > retval )
430             retval = ((statusP) ptr)->jobNumber;
431
432         ptr = ptr->dlq_next;
433     }
434     retval++;
435     return(retval);
436 }
437
438 /* waitForTask
439  *    Wait for a specific task to finish and then return.
440  *    Return the task's flags when it's done. If the job
441  *    had been cleaned up, then just return 0.
442  */
443 waitForTask(taskId)
444     afs_uint32 taskId;
445 {
446     statusP ptr;
447     afs_int32 done=0, rcode, t;
448     extern statusP findStatus();
449
450     t = (TASK_DONE | ABORT_DONE | TASK_ERROR);
451     while (!done) {
452        /* Sleep 2 seconds */
453 #ifdef AFS_PTHREAD_ENV
454        struct timespec delaytime;
455        delayTime.tv_sec  = 2;
456        delayTime.tv_nsec = 0;
457        pthread_delay_np(&delayTime);
458 #else
459        IOMGR_Sleep(2);
460 #endif /*else AFS_PTHREAD_ENV*/
461
462        /* Check if we are done */
463        lock_Status();
464        ptr = findStatus(taskId);
465        if (!ptr || (ptr->flags & t)) {
466           rcode = (ptr ? ptr->flags : 0);
467           done=1;
468        }
469        unlock_Status();
470     }
471     return rcode;
472 }