2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
17 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
27 #include <afs/com_err.h>
28 #include <afs/bubasics.h>
30 #include <afs/tcdata.h>
32 #include "error_macros.h"
34 #define SET_FLAG(set) \
36 curPollPtr->flags |= (set); \
39 #define CLEAR_FLAG(clear) \
41 curPollPtr->flags &= ~(clear); \
44 /* globals for backup coordinator status management */
46 dlqlinkT statusHead; /* chain of status blocks */
47 struct Lock statusQueueLock; /* access control for status chain */
48 struct Lock cmdLineLock; /* lock on the cmdLine */
50 afs_int32 lastTaskCode; /* Error code from task that last finished */
53 * get next item for status interrogation, if any.
61 ptr = (dlqlinkP) linkPtr;
63 /* if last known item has terminated, reset ptr */
72 /* if we're back at the head again */
73 if (ptr == &statusHead)
75 return ((statusP) ptr);
85 ptr = (dlqlinkP) linkPtr;
87 /* if last known item has terminated, reset ptr */
96 /* if we're back at the head again */
97 if (ptr == &statusHead) {
100 return ((statusP) ptr);
109 char **targv[MAXV]; /*Ptr to parsed argv stuff */
110 afs_int32 targc; /*Num parsed arguments */
112 char *internalCmdLine;
114 internalCmdLine = cmdLine;
117 code = cmd_ParseLine(internalCmdLine, targv, &targc, MAXV);
119 printf("Couldn't parse line: '%s'", error_message(code));
122 free(internalCmdLine);
125 * Because the "-at" option cannot be wildcarded, we cannot fall
126 * into recusive loop here by setting dispatchCount to 1.
128 doDispatch(targc, targv, 1);
134 struct rx_connection *tconn = (struct rc_connection *)0;
135 statusP curPollPtr = 0;
137 struct tciStatusS statusPtr;
139 /* task information */
140 afs_uint32 taskFlags;
141 afs_uint32 localTaskFlags;
142 afs_uint32 temp; /* for flag manipulation */
150 extern struct bc_config *bc_globalConfig;
151 extern struct rx_connection *bc_GetConn();
157 rx_DestroyConnection(tconn);
158 tconn = (struct rc_connection *)0;
161 curPollPtr = nextItem(curPollPtr);
163 if (curPollPtr == 0) {
164 #ifdef AFS_PTHREAD_ENV
165 struct timespec delaytime;
167 delayTime.tv_sec = 5;
168 delayTime.tv_nsec = 0;
169 pthread_delay_np(&delayTime);
172 IOMGR_Sleep(5); /* wait a while */
173 #endif /*else AFS_PTHREAD_ENV */
177 /* save useful information */
178 localTaskFlags = curPollPtr->flags;
179 taskId = curPollPtr->taskId;
180 port = curPollPtr->port;
181 atTime = curPollPtr->scheduledDump;
182 jobNumber = curPollPtr->jobNumber;
185 /* reset certain flags; local kill; */
186 CLEAR_FLAG(ABORT_LOCAL);
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;
194 deleteStatusNode(curPollPtr);
200 /* A task not started yet - check its start time */
201 if (localTaskFlags & STARTING || atTime) {
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.
207 * Avoid multiple processes trouncing the cmdLine by placing
210 if (atTime && (atTime <= time(0))) {
211 lock_cmdLine(); /* Will unlock in cmdDispatch */
213 cmdLine = curPollPtr->cmdLine;
215 curPollPtr->cmdLine = 0;
218 printf("Starting scheduled dump: job %d\n", jobNumber);
219 printf("schedD> %s\n", cmdLine);
222 LWP_CreateProcess(cmdDispatch, 16384, LWP_NORMAL_PRIORITY,
223 (void *)2, "cmdDispatch", &dispatchPid);
228 printf("Couldn't create cmdDispatch task\n");
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;
236 deleteStatusNode(curPollPtr);
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,
248 printf("Job %d cont: Local kill ignored - use normal kill\n",
253 code = (afs_int32) bc_GetConn(bc_globalConfig, port, &tconn);
255 SET_FLAG(CONTACT_LOST);
259 if (CheckTCVersion(tconn)) {
260 SET_FLAG(CONTACT_LOST);
264 /* Send abort to TC requst if we have to */
265 if (localTaskFlags & ABORT_REQUEST) {
266 code = TC_RequestAbort(tconn, taskId);
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;
274 deleteStatusNode(curPollPtr);
280 curPollPtr->flags &= ~ABORT_REQUEST;
281 curPollPtr->flags |= ABORT_SENT;
286 /* otherwise just get the status */
287 code = TC_GetStatus(tconn, taskId, &statusPtr);
289 if (code == TC_NODENOTFOUND) {
290 printf("Job %d: %s - no such task on port %d, deleting\n",
291 jobNumber, curPollPtr->taskName, port);
293 if (localTaskFlags & NOREMOVE) {
294 curPollPtr->flags |= (STARTING | TASK_ERROR);
295 curPollPtr->scheduledDump = 0;
297 deleteStatusNode(curPollPtr); /* delete this status node */
303 SET_FLAG(CONTACT_LOST);
307 /* in case we previously lost contact or couldn't find */
308 CLEAR_FLAG(CONTACT_LOST);
310 /* extract useful status */
311 taskFlags = statusPtr.flags;
313 /* update local status */
316 /* remember some status flags in local struct */
318 (DRIVE_WAIT | OPR_WAIT | CALL_WAIT | TASK_DONE | ABORT_DONE |
320 curPollPtr->flags &= ~temp; /* clear */
321 curPollPtr->flags |= (taskFlags & temp); /* update */
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;
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);
337 printf("Job %d: %s Aborted", jobNumber,
338 curPollPtr->taskName);
340 if (taskFlags & TASK_ERROR)
341 printf(" with errors\n");
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);
354 printf("Job %d Failed with errors\n", jobNumber);
360 if (!(localTaskFlags & SILENT)) {
361 if (curPollPtr->dbDumpId)
362 printf("Job %d: %s: DumpID %u finished", jobNumber,
363 curPollPtr->taskName, curPollPtr->dbDumpId);
365 printf("Job %d: %s finished", jobNumber,
366 curPollPtr->taskName);
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);
381 /* make call to destroy task on server */
382 code = TC_EndStatus(tconn, taskId);
384 printf("Job %d: %s, error in job termination cleanup\n",
385 jobNumber, curPollPtr->taskName);
387 if (localTaskFlags & NOREMOVE) {
388 curPollPtr->flags |= STARTING;
389 curPollPtr->scheduledDump = 0;
391 deleteStatusNode(curPollPtr); /* unlink and destroy local task */
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.
407 afs_int32 retval = 0;
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;
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.
431 afs_int32 done = 0, rcode, t;
432 extern statusP findStatus();
434 t = (TASK_DONE | ABORT_DONE | TASK_ERROR);
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);
444 #endif /*else AFS_PTHREAD_ENV */
446 /* Check if we are done */
448 ptr = findStatus(taskId);
449 if (!ptr || (ptr->flags & t)) {
450 rcode = (ptr ? ptr->flags : 0);