83b2233c52806df559d1ed21a2c9b5b4b7974b10
[openafs.git] / src / butc / lwps.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 <sys/types.h>
17 #ifdef AFS_NT40_ENV
18 #include <winsock2.h>
19 #include <conio.h>
20 #else
21 #include <sys/file.h>
22 #include <netinet/in.h>
23 #include <netdb.h>
24 #endif
25
26 #include <afs/procmgmt.h>
27 #include <rx/xdr.h>
28 #include <rx/rx.h>
29 #include <time.h>
30 #include <lwp.h>
31 #include <lock.h>
32 #include <afs/tcdata.h>
33 #include <afs/bubasics.h>       /* PA */
34 #include <afs/budb_client.h>
35 #include <afs/volser.h>
36 #include <afs/com_err.h>
37 #include "error_macros.h"
38 #include <afs/afsutil.h>
39 #include <errno.h>
40 #include "butc_xbsa.h"
41
42 /* GLOBAL CONFIGURATION PARAMETERS */
43 extern int dump_namecheck;
44 extern int queryoperator;
45 extern int tapemounted;
46 extern char *opencallout;
47 extern char *closecallout;
48 extern char *whoami;
49 extern char *extractDumpName();
50 extern int BufferSize;          /* Size in B stored for header info */
51 extern char *restoretofile;
52 FILE *restoretofilefd;
53 extern int forcemultiple;
54
55 /* XBSA Global Parameters */
56 afs_int32 xbsaType;
57 #ifdef xbsa
58 struct butx_transactionInfo butxInfo;
59 #endif
60
61 struct TapeBlock {              /* A 16KB tapeblock */
62     char mark[BUTM_HDRSIZE];    /* Header info */
63     char data[BUTM_BLKSIZE];    /* data */
64 } *bufferBlock;
65
66 afs_int32 dataSize;             /* Size of data to read on each xbsa_ReadObjectData() call (CONF_XBSA) */
67 afs_int32 tapeblocks;           /* Number of tape datablocks in buffer (!CONF_XBSA) */
68
69 /* notes
70  *      Need to re-write to:
71  *      1) non-interactive tape handling (optional)
72  *      2) compute tape and volume sizes for the database
73  *      3) compute and use tape id's for tape tracking (put on tape label)
74  *      4) status management
75  */
76
77 /* All the relevant info shared between Restorer and restoreVolume */
78 struct restoreParams {
79     struct dumpNode *nodePtr;
80     afs_int32 frag;
81     char mntTapeName[BU_MAXTAPELEN];
82     afs_int32 tapeID;
83     struct butm_tapeInfo *tapeInfoPtr;
84 };
85
86 /* Abort checks are done after each  BIGCHUNK of data transfer */
87 #define BIGCHUNK 102400
88
89 #define HEADER_CHECKS(vhptr, header)                                    \
90 {                                                                       \
91     afs_int32 magic, versionflags;                                              \
92                                                                         \
93     versionflags = ntohl(vhptr.versionflags);                           \
94     if ( versionflags == TAPE_VERSION_0 ||                              \
95              versionflags == TAPE_VERSION_1 ||                          \
96              versionflags == TAPE_VERSION_2 ||                          \
97              versionflags == TAPE_VERSION_3 ||                          \
98              versionflags == TAPE_VERSION_4 )       {                   \
99                                                                         \
100             magic = ntohl(vhptr.magic); /* another sanity check */      \
101             if (magic == TC_VOLBEGINMAGIC ||                            \
102                 magic == TC_VOLENDMAGIC ||                              \
103                 magic == TC_VOLCONTD )                 {                \
104                                                                         \
105                 memcpy(header, &vhptr, sizeof(struct volumeHeader));    \
106                 return (0);                                             \
107             } /* magic */                                               \
108         } /* versionflags */                                            \
109 }
110
111 extern FILE *logIO;
112 extern FILE *ErrorlogIO;
113 extern FILE *centralLogIO;
114 extern FILE *lastLogIO;
115 extern afs_int32 lastPass;      /* Set true during last pass of dump */
116 extern int debugLevel;
117 extern int autoQuery;
118 extern struct tapeConfig globalTapeConfig;
119 extern struct deviceSyncNode *deviceLatch;
120 extern char globalCellName[];
121 struct timeval tp;
122 struct timezone tzp;
123
124 /* forward declaration */
125 afs_int32 readVolumeHeader( /*char *buffer,afs_int32 bufloc,(struct volumeHeader *)vhptr */ );
126
127 /* The on-disk volume header or trailer can differ in size from platform to platform */
128 struct TapeBlock tapeBlock;
129 char tapeVolumeHT[sizeof(struct volumeHeader) + 2 * sizeof(char)];
130
131 void
132 PrintLog(log, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
133      FILE *log;
134      afs_int32 error1, error2;
135      char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
136 {
137     char *err1, *err2;
138
139     fprintf(log, str, a, b, c, d, e, f, g, h, i, j);
140     if (error1) {
141         err2 = "vols";
142         switch (error1) {
143         case VSALVAGE:
144             err1 = "Volume needs to be salvaged";
145             break;
146         case VNOVNODE:
147             err1 = "Bad vnode number quoted";
148             break;
149         case VNOVOL:
150             err1 = "Volume not attached, does not exist, or not on line";
151             break;
152         case VVOLEXISTS:
153             err1 = "Volume already exists";
154             break;
155         case VNOSERVICE:
156             err1 = "Volume is not in service";
157             break;
158         case VOFFLINE:
159             err1 = "Volume is off line";
160             break;
161         case VONLINE:
162             err1 = "Volume is already on line";
163             break;
164         case VDISKFULL:
165             err1 = "Partition is full";
166             break;
167         case VOVERQUOTA:
168             err1 = "Volume max quota exceeded";
169             break;
170         case VBUSY:
171             err1 = "Volume temporarily unavailable";
172             break;
173         case VMOVED:
174             err1 = "Volume has moved to another server";
175             break;
176         default:
177             err1 = (char *)error_message(error1);
178             err2 = (char *)error_table_name(error1);
179             break;
180         }
181         if (error1 == -1)
182             fprintf(log, "     Possible communication failure");
183         else
184             fprintf(log, "     %s: %s", err2, err1);
185         if (error2)
186             fprintf(log, ": %s", error_message(error2));
187         fprintf(log, "\n");
188     }
189     fflush(log);
190 }
191
192 void
193 TapeLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
194      int debug;
195      afs_int32 task, error1, error2;
196      char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
197 {
198     time_t now;
199     char tbuffer[32], *timestr;
200
201     now = time(0);
202     timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
203     timestr[24] = '\0';
204
205     fprintf(logIO, "%s: ", timestr);
206     if (task)
207         fprintf(logIO, "Task %u: ", task);
208     PrintLog(logIO, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
209
210     if (lastPass && lastLogIO) {
211         fprintf(lastLogIO, "%s: ", timestr);
212         if (task)
213             fprintf(lastLogIO, "Task %u: ", task);
214         PrintLog(lastLogIO, error1, error2, str, a, b, c, d, e, f, g, h, i,
215                  j);
216     }
217
218     /* Now print to the screen if debug level requires */
219     if (debug <= debugLevel)
220         PrintLog(stdout, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
221 }
222
223 void
224 TLog(task, str, a, b, c, d, e, f, g, h, i, j)
225      afs_int32 task;
226      char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
227 {
228     /* Sends message to TapeLog and stdout */
229     TapeLog(0, task, 0, 0, str, a, b, c, d, e, f, g, h, i, j);
230 }
231
232 void
233 ErrorLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j)
234      int debug;
235      afs_int32 task, error1, error2;
236      char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
237 {
238     time_t now;
239     char tbuffer[32], *timestr;
240
241     now = time(0);
242     timestr = afs_ctime(&now, tbuffer, sizeof(tbuffer));
243     timestr[24] = '\0';
244     fprintf(ErrorlogIO, "%s: ", timestr);
245
246     /* Print the time and task number */
247     if (task)
248         fprintf(ErrorlogIO, "Task %u: ", task);
249     PrintLog(ErrorlogIO, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
250
251     TapeLog(debug, task, error1, error2, str, a, b, c, d, e, f, g, h, i, j);
252 }
253
254 void
255 ELog(task, str, a, b, c, d, e, f, g, h, i, j)
256      afs_int32 task;
257      char *str, *a, *b, *c, *d, *e, *f, *g, *h, *i, *j;
258 {
259     /* Sends message to ErrorLog, TapeLog and stdout */
260     ErrorLog(0, task, 0, 0, str, a, b, c, d, e, f, g, h, i, j);
261 }
262
263 /* first proc called by anybody who intends to use the device */
264 void
265 EnterDeviceQueue(devLatch)
266      struct deviceSyncNode *devLatch;
267 {
268     ObtainWriteLock(&(devLatch->lock));
269     devLatch->flags = TC_DEVICEINUSE;
270 }
271
272 /* last proc called by anybody finishing using the device */
273 void
274 LeaveDeviceQueue(devLatch)
275      struct deviceSyncNode *devLatch;
276 {
277     devLatch->flags = 0;
278     ReleaseWriteLock(&(devLatch->lock));
279 }
280
281 #define BELLTIME 60             /* 60 seconds before a bell rings */
282 #define BELLCHAR 7              /* ascii for bell */
283
284
285 #ifdef AFS_PTHREAD_ENV
286 #ifdef AFS_NT40_ENV
287 /* WaitForKeystroke : Wait until a key has been struck or time (secconds)
288  * runs out and return to caller. The NT version of this function will return
289  * immediately after a key has been pressed (doesn't wait for cr).
290  * Input:
291  *   seconds: wait for <seconds> seconds before returning. If seconds < 0,
292  *            wait infinitely.
293  * Return Value:
294  *    1:  Keyboard input available
295  *    0:  seconds elapsed. Timeout.
296  *
297  * STOLEN FROM LWP_WaitForKeystroke()
298  */
299 int
300 WaitForKeystroke(int seconds)
301 {
302     time_t startTime, nowTime;
303     double timeleft = 1;
304     struct timeval twait;
305
306     time(&startTime);
307     twait.tv_sec = 0;
308     twait.tv_usec = 250;
309     if (seconds >= 0)
310         timeleft = seconds;
311
312     do {
313         /* check if we have a keystroke */
314         if (_kbhit())
315             return 1;
316         if (timeleft == 0)
317             break;
318
319         /* sleep for  LWP_KEYSTROKE_DELAY ms and let other
320          * process run some*/
321         select(0, 0, 0, 0, &twait);
322
323         if (seconds > 0) {      /* we only worry about elapsed time if 
324                                  * not looping forever (seconds < 0) */
325             time(&nowTime);
326             timeleft = seconds - difftime(nowTime, startTime);
327         }
328     } while (timeleft > 0);
329     return 0;
330 }
331 #else /* AFS_NT40)ENV */
332 extern int WaitForKeystroke(int);
333 /*
334  *      STOLEN FROM LWP_WaitForKeystroke()
335  */
336 int
337 WaitForKeystroke(int seconds)
338 {
339     fd_set rdfds;
340     int code;
341     struct timeval twait;
342     struct timeval *tp = NULL;
343
344 #ifdef AFS_LINUX20_ENV
345     if (stdin->_IO_read_ptr < stdin->_IO_read_end)
346         return 1;
347 #else
348     if (stdin->_cnt > 0)
349         return 1;
350 #endif
351     FD_ZERO(&rdfds);
352     FD_SET(fileno(stdin), &rdfds);
353
354     if (seconds >= 0) {
355         twait.tv_sec = seconds;
356         twait.tv_usec = 0;
357         tp = &twait;
358     }
359     code = select(1 + fileno(stdin), &rdfds, NULL, NULL, tp);
360     return (code == 1) ? 1 : 0;
361 }
362 #endif
363
364 /* GetResponseKey() - Waits for a specified period of time and
365  * returns a char when one has been typed by the user.
366  * Input:
367  *    seconds - how long to wait for a key press.
368  *    *key    - char entered by user
369  * Return Values: 
370  *    0 - Time ran out before the user typed a key.
371  *    1 - Valid char is being returned.
372  *
373  *    STOLEN FROM LWP_GetResponseKey();
374  */
375 int
376 GetResponseKey(int seconds, char *key)
377 {
378     int rc;
379
380     if (key == NULL)
381         return 0;               /* need space to store char */
382     fflush(stdin);              /* flush all existing data and start anew */
383
384     rc = WaitForKeystroke(seconds);
385     if (rc == 0) {              /* time ran out */
386         *key = 0;
387         return rc;
388     }
389
390     /* now read the char. */
391 #ifdef AFS_NT40_ENV
392     *key = getche();            /* get char and echo it to screen */
393 #else
394     *key = getchar();
395 #endif
396     return rc;
397 }
398 #endif /* AFS_PTHREAD_ENV
399         * 
400         * /* FFlushInput
401         * *     flush all input
402         * * notes:
403         * *     only external clients are in recoverDb.c. Was static. PA
404         */
405 void
406 FFlushInput()
407 {
408     int w;
409
410     fflush(stdin);
411
412     while (1) {
413 #ifdef AFS_PTHREAD_ENV
414         w = WaitForKeystroke(0);
415 #else
416         w = LWP_WaitForKeystroke(0);
417 #endif /* AFS_PTHREAD_ENV */
418
419         if (w) {
420 #ifdef AFS_NT40_ENV
421             getche();
422 #else
423             getchar();
424 #endif /* AFS_NT40_ENV */
425         } else {
426             return;
427         }
428     }
429 }
430
431 int
432 callOutRoutine(taskId, tapePath, flag, name, dbDumpId, tapecount)
433      afs_int32 taskId;
434      char *tapePath;
435      int flag;
436      char *name;
437      afs_uint32 dbDumpId;
438      int tapecount;
439 {
440     afs_int32 code = 0;
441     int pid;
442
443     char StapePath[256];
444     char ScallOut[256];
445     char Scount[10];
446     char Sopcode[16];
447     char Sdumpid[16];
448     char Stape[40];
449     char *callOut;
450
451     char *CO_argv[10];
452     char *CO_envp[1];
453
454
455     callOut = opencallout;
456     switch (flag) {
457     case READOPCODE:
458         strcpy(Sopcode, "restore");
459         break;
460     case APPENDOPCODE:
461         strcpy(Sopcode, "appenddump");
462         break;
463     case WRITEOPCODE:
464         strcpy(Sopcode, "dump");
465         break;
466     case LABELOPCODE:
467         strcpy(Sopcode, "labeltape");
468         break;
469     case READLABELOPCODE:
470         strcpy(Sopcode, "readlabel");
471         break;
472     case SCANOPCODE:
473         strcpy(Sopcode, "scantape");
474         break;
475     case RESTOREDBOPCODE:
476         strcpy(Sopcode, "restoredb");
477         break;
478     case SAVEDBOPCODE:
479         strcpy(Sopcode, "savedb");
480         break;
481     case CLOSEOPCODE:
482         strcpy(Sopcode, "unmount");
483         callOut = closecallout;
484         break;
485     default:
486         strcpy(Sopcode, "unknown");
487         break;
488     }
489
490     if (!callOut)               /* no script to call */
491         return 0;
492
493     strcpy(ScallOut, callOut);
494     CO_argv[0] = ScallOut;
495
496     strcpy(StapePath, tapePath);
497     CO_argv[1] = StapePath;
498
499     CO_argv[2] = Sopcode;
500
501     if (flag == CLOSEOPCODE) {
502         CO_argv[3] = NULL;
503     } else {
504         sprintf(Scount, "%d", tapecount);
505         CO_argv[3] = Scount;
506
507         /* The tape label name - special case labeltape */
508         if (!name || (strcmp(name, "") == 0))   /* no label */
509             strcpy(Stape, "none");
510         else {                  /* labeltape */
511 #ifdef AFS_NT40_ENV
512             if (!strcmp(name, TC_NULLTAPENAME)) /* pass "<NULL>" instead of <NULL> */
513                 strcpy(Stape, TC_QUOTEDNULLTAPENAME);
514             else
515 #endif
516                 strcpy(Stape, name);
517         }
518         CO_argv[4] = Stape;
519
520         /* The tape id */
521         if (!dbDumpId)
522             strcpy(Sdumpid, "none");
523         else
524             sprintf(Sdumpid, "%u", dbDumpId);
525         CO_argv[5] = Sdumpid;
526
527         CO_argv[6] = NULL;
528     }
529
530     CO_envp[0] = NULL;
531
532     pid = spawnprocve(callOut, CO_argv, CO_envp, 2);
533     if (pid < 0) {
534         ErrorLog(0, taskId, errno, 0,
535                  "Call to %s outside routine %s failed\n", Sopcode, callOut);
536         return 0;
537     }
538
539     return (pid);
540 }
541
542 /*
543  * unmountTape
544  *     Unmounts a tape and prints a warning if it can't unmount it.
545  *     Regardless of error, the closecallout routine will be called
546  *     (unless a tape is not mounted in the first place).
547  */
548 unmountTape(taskId, tapeInfoPtr)
549      afs_int32 taskId;
550      struct butm_tapeInfo *tapeInfoPtr;
551 {
552     afs_int32 code;
553     int cpid, status, rcpid;
554
555     code = butm_Dismount(tapeInfoPtr);
556     if (code && (code != BUTM_NOMOUNT))
557         ErrorLog(0, taskId, code, (tapeInfoPtr)->error,
558                  "Warning: Can't close tape\n");
559
560     if (tapemounted && closecallout) {
561         setStatus(taskId, CALL_WAIT);
562
563         cpid =
564             callOutRoutine(taskId, globalTapeConfig.device, CLOSEOPCODE, "",
565                            0, 1);
566         while (cpid) {          /* Wait until return */
567             status = 0;
568             rcpid = waitpid(cpid, &status, WNOHANG);
569             if (rcpid > 0) {
570                 tapemounted = 0;
571                 break;
572             }
573             if (rcpid == -1 && errno != EINTR) {
574                 tapemounted = 0;
575                 com_err(whoami, errno,
576                         "Error waiting for callout script to terminate.");
577                 break;
578             }
579 #ifdef AFS_PTHREAD_ENV
580             sleep(1);
581 #else
582             IOMGR_Sleep(1);
583 #endif
584
585             if (checkAbortByTaskId(taskId)) {
586                 TLog(taskId, "Callout routine has been aborted\n");
587                 if (kill(cpid, SIGKILL))        /* Cancel callout */
588                     ErrorLog(0, taskId, errno, 0,
589                              "Kill of callout process %d failed\n", cpid);
590                 break;
591             }
592         }
593     }
594     clearStatus(taskId, CALL_WAIT);
595 }
596
597 /* PrintPrompt
598  *      print out prompt to operator
599  * calledby:
600  *      PromptForTape only.
601  */
602
603 void static
604 PrintPrompt(flag, name, dumpid)
605      int flag;
606      char *name;
607 {
608     char tapename[BU_MAXTAPELEN + 32];
609     char *dn;
610
611     TAPENAME(tapename, name, dumpid);
612
613     printf("******* OPERATOR ATTENTION *******\n");
614     printf("Device :  %s \n", globalTapeConfig.device);
615
616     switch (flag) {
617     case READOPCODE:            /* mount for restore */
618         printf("Please put in tape %s for reading", tapename);
619         break;
620
621     case APPENDOPCODE:          /* mount for dump (appends) */
622
623         dn = extractDumpName(name);
624
625         if (!dn || !dumpid)
626             printf("Please put in last tape of dump set for appending dump");
627         else
628             printf
629                 ("Please put in last tape of dump set for appending dump %s (DumpID %u)",
630                  dn, dumpid);
631         break;
632
633     case WRITEOPCODE:           /* mount for dump */
634         if (strcmp(name, "") == 0)
635             printf("Please put in tape for writing");
636
637         /* The name is what we are going to label the tape as */
638         else
639             printf("Please put in tape %s for writing", tapename);
640         break;
641
642     case LABELOPCODE:           /* mount for labeltape */
643         printf("Please put in tape to be labelled as %s", tapename);
644         break;
645
646     case READLABELOPCODE:       /* mount for readlabel */
647         printf("Please put in tape whose label is to be read");
648         break;
649
650     case SCANOPCODE:            /* mount for scantape */
651         if (strcmp(name, "") == 0)
652             printf("Please put in tape to be scanned");
653         else
654             printf("Please put in tape %s for scanning", tapename);
655         break;
656
657     case RESTOREDBOPCODE:       /* Mount for restoredb */
658         printf("Please insert a tape %s for the database restore", tapename);
659         break;
660
661     case SAVEDBOPCODE:          /* Mount for savedb */
662         printf("Please insert a writeable tape %s for the database dump",
663                tapename);
664         break;
665
666     default:
667         break;
668     }
669     printf(" and hit return when done\n");
670 }
671
672 /* PromptForTape
673  *      Prompt the operator to change the tape. 
674  *      Use to be a void routine but now returns an error. Some calls
675  *      don't use the error code.
676  * notes:
677  *      only external clients are in recoverDb.c. Was static PA
678  */
679 afs_int32
680 PromptForTape(flag, name, dbDumpId, taskId, tapecount)
681      int flag;
682      char *name;
683      afs_uint32 dbDumpId;       /* Specific dump ID - If non-zero */
684      afs_uint32 taskId;
685      int tapecount;
686 {
687     register afs_int32 code = 0;
688     afs_int32 wcode;
689     afs_int32 start = 0;
690     char inchr;
691     int CallOut;
692     int cpid, status, rcpid;
693
694     if (checkAbortByTaskId(taskId))
695         ERROR_EXIT(TC_ABORTEDBYREQUEST);
696
697     if (dbDumpId)
698         TapeLog(2, taskId, 0, 0, "Prompt for tape %s (%u)\n", name, dbDumpId);
699     else
700         TapeLog(2, taskId, 0, 0, "Prompt for tape %s\n", name);
701
702     CallOut = (opencallout ? 1 : 0);
703     if (CallOut) {
704         setStatus(taskId, CALL_WAIT);
705
706         cpid =
707             callOutRoutine(taskId, globalTapeConfig.device, flag, name,
708                            dbDumpId, tapecount);
709         if (cpid == 0)
710             CallOut = 0;        /* prompt at screen */
711
712         while (CallOut) {       /* Check if callout routine finished */
713             status = 0;
714             rcpid = waitpid(cpid, &status, WNOHANG);
715             if (rcpid > 0) {
716                 if (rcpid != cpid)
717                     wcode = -1;
718                 else if (WIFEXITED(status))
719                     wcode = WEXITSTATUS(status);
720                 else
721                     wcode = -1;
722
723                 if (wcode == 0) {
724                     break;      /* All done */
725                 } else if (wcode == 1) {
726                     ERROR_EXIT(TC_ABORTEDBYREQUEST);    /* Abort */
727                 } else if ((flag == READOPCODE) && (wcode == 3)) {
728                     ERROR_EXIT(TC_SKIPTAPE);    /* Restore: skip the tape */
729                 } else {
730                     TLog(taskId,
731                          "Callout routine has exited with code %d: will prompt\n",
732                          wcode);
733                     CallOut = 0;        /* Switch to keyboard input */
734                     break;
735                 }
736             }
737             /* if waitpid experienced an error, we prompt */
738             if (rcpid == -1 && errno != EINTR) {
739                 com_err(whoami, errno,
740                         "Error waiting for callout script to terminate.");
741                 TLog(taskId,
742                      "Can't get exit status from callout script. will prompt\n");
743                 CallOut = 0;
744                 break;
745             }
746 #ifdef AFS_PTHREAD_ENV
747             sleep(1);
748 #else
749             IOMGR_Sleep(1);
750 #endif
751
752             if (checkAbortByTaskId(taskId)) {
753                 printf
754                     ("This tape operation has been aborted by the coordinator.\n");
755
756                 if (kill(cpid, SIGKILL))        /* Cancel callout */
757                     ErrorLog(0, taskId, errno, 0,
758                              "Kill of callout process %d failed\n", cpid);
759
760                 ERROR_EXIT(TC_ABORTEDBYREQUEST);
761             }
762         }
763     }
764
765     if (!CallOut) {
766         clearStatus(taskId, CALL_WAIT);
767         setStatus(taskId, OPR_WAIT);
768
769         PrintPrompt(flag, name, dbDumpId);
770
771         /* Loop until we get ok to go ahead (or abort) */
772         while (1) {
773             if (time(0) > start + BELLTIME) {
774                 start = time(0);
775                 FFlushInput();
776                 putchar(BELLCHAR);
777                 fflush(stdout);
778             }
779 #ifdef AFS_PTHREAD_ENV
780             wcode = GetResponseKey(5, &inchr);  /* inchr stores key read */
781 #else
782             wcode = LWP_GetResponseKey(5, &inchr);      /* inchr stores key read */
783 #endif
784             if (wcode == 1) {   /* keyboard input is available */
785
786                 if ((inchr == 'a') || (inchr == 'A')) {
787                     printf("This tape operation has been aborted.\n");
788                     ERROR_EXIT(TC_ABORTEDBYREQUEST);    /* Abort command */
789                 } else if ((flag == READOPCODE)
790                            && ((inchr == 's') || (inchr == 'S'))) {
791                     printf("This tape will be skipped.\n");
792                     ERROR_EXIT(TC_SKIPTAPE);    /* Restore: skip the tape */
793                 }
794                 break;          /* continue */
795             }
796
797             if (checkAbortByTaskId(taskId)) {
798                 printf
799                     ("This tape operation has been aborted by the coordinator.\n");
800                 ERROR_EXIT(TC_ABORTEDBYREQUEST);
801             }
802         }
803
804     }
805
806     printf("Thanks, now proceeding with tape ");
807     switch (flag) {
808     case RESTOREDBOPCODE:
809     case READOPCODE:
810         printf("reading");
811         break;
812
813     case APPENDOPCODE:
814         printf("append writing");
815         break;
816
817     case SAVEDBOPCODE:
818     case WRITEOPCODE:
819         printf("writing");
820         break;
821
822     case LABELOPCODE:
823         printf("labelling");
824         break;
825
826     case READLABELOPCODE:
827         printf("label reading");
828         break;
829
830     case SCANOPCODE:
831         printf("scanning");
832         break;
833
834     default:
835         printf("unknown");
836         break;
837     }
838
839     printf(" operation.\n");
840     if (!CallOut)
841         printf("**********************************\n");
842
843     TapeLog(2, taskId, 0, 0, "Proceeding with tape operation\n");
844     tapemounted = 1;
845
846   error_exit:
847     clearStatus(taskId, (OPR_WAIT | CALL_WAIT));
848     return (code);
849 }
850
851
852 /* VolHeaderToHost
853  *      convert the fields in the tapeVolHeader into host byte order,
854  *      placing the converted copy of the structure into the hostVolHeader
855  * entry:
856  *      tapeVolHeader - points to volume header read from tape
857  *      hostVolHeader - pointer to struct for result
858  * exit:
859  *      hostVolHeader - information in host byte order
860  */
861
862 afs_int32
863 VolHeaderToHost(hostVolHeader, tapeVolHeader)
864      struct volumeHeader *hostVolHeader, *tapeVolHeader;
865 {
866     switch (ntohl(tapeVolHeader->versionflags)) {
867     case TAPE_VERSION_0:
868         /* sizes in bytes and fields in host order */
869         memcpy(tapeVolHeader, hostVolHeader, sizeof(struct volumeHeader));
870         break;
871
872     case TAPE_VERSION_1:
873     case TAPE_VERSION_2:
874     case TAPE_VERSION_3:        /* for present */
875     case TAPE_VERSION_4:
876         /* sizes in K and fields in network order */
877         /* do the conversion field by field */
878
879         strcpy(hostVolHeader->preamble, tapeVolHeader->preamble);
880         strcpy(hostVolHeader->postamble, tapeVolHeader->postamble);
881         strcpy(hostVolHeader->volumeName, tapeVolHeader->volumeName);
882         strcpy(hostVolHeader->dumpSetName, tapeVolHeader->dumpSetName);
883         hostVolHeader->volumeID = ntohl(tapeVolHeader->volumeID);
884         hostVolHeader->server = ntohl(tapeVolHeader->server);
885         hostVolHeader->part = ntohl(tapeVolHeader->part);
886         hostVolHeader->from = ntohl(tapeVolHeader->from);
887         hostVolHeader->frag = ntohl(tapeVolHeader->frag);
888         hostVolHeader->magic = ntohl(tapeVolHeader->magic);
889         hostVolHeader->contd = ntohl(tapeVolHeader->contd);
890         hostVolHeader->dumpID = ntohl(tapeVolHeader->dumpID);
891         hostVolHeader->level = ntohl(tapeVolHeader->level);
892         hostVolHeader->parentID = ntohl(tapeVolHeader->parentID);
893         hostVolHeader->endTime = ntohl(tapeVolHeader->endTime);
894         hostVolHeader->versionflags = ntohl(tapeVolHeader->versionflags);
895         hostVolHeader->cloneDate = ntohl(tapeVolHeader->cloneDate);
896         break;
897
898     default:
899         return (TC_BADVOLHEADER);
900     }
901     return (0);
902 }
903
904 afs_int32
905 ReadVolHeader(taskId, tapeInfoPtr, volHeaderPtr)
906      afs_int32 taskId;
907      struct butm_tapeInfo *tapeInfoPtr;
908      struct volumeHeader *volHeaderPtr;
909 {
910     afs_int32 code = 0;
911     afs_int32 nbytes;
912     struct volumeHeader volHead;
913
914     /* Read the volume header */
915     code =
916         butm_ReadFileData(tapeInfoPtr, tapeBlock.data, sizeof(tapeVolumeHT),
917                           &nbytes);
918     if (code) {
919         ErrorLog(0, taskId, code, tapeInfoPtr->error,
920                  "Can't read volume header on tape\n");
921         ERROR_EXIT(code);
922     }
923
924     code = readVolumeHeader(tapeBlock.data, 0L, &volHead);
925     if (code) {
926         ErrorLog(0, taskId, code, 0,
927                  "Can't find volume header on tape block\n");
928         ERROR_EXIT(code);
929     }
930
931     code = VolHeaderToHost(volHeaderPtr, &volHead);
932     if (code) {
933         ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
934         ERROR_EXIT(code);
935     }
936
937   error_exit:
938     return code;
939 }
940
941 afs_int32 static
942 GetVolumeHead(taskId, tapeInfoPtr, position, volName, volId)
943      afs_int32 taskId;
944      struct butm_tapeInfo *tapeInfoPtr;
945      afs_int32 position;
946      char *volName;
947      afs_int32 volId;
948 {
949     afs_int32 code = 0;
950     struct volumeHeader tapeVolHeader;
951
952     /* Position directly to the volume and read the header */
953     if (position) {
954         code = butm_Seek(tapeInfoPtr, position);
955         if (code) {
956             ErrorLog(0, taskId, code, tapeInfoPtr->error,
957                      "Can't seek to position %u on tape\n", position);
958             ERROR_EXIT(code);
959         }
960
961         code = butm_ReadFileBegin(tapeInfoPtr);
962         if (code) {
963             ErrorLog(0, taskId, code, tapeInfoPtr->error,
964                      "Can't read FileBegin on tape\n");
965             ERROR_EXIT(code);
966         }
967
968         /* Read the volume header */
969         code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
970         if (code)
971             ERROR_EXIT(code);
972
973         /* Check if volume header matches */
974         if (strcmp(tapeVolHeader.volumeName, volName))
975             ERROR_EXIT(TC_BADVOLHEADER);
976         if (volId && (tapeVolHeader.volumeID != volId))
977             ERROR_EXIT(TC_BADVOLHEADER);
978         if (tapeVolHeader.magic != TC_VOLBEGINMAGIC)
979             ERROR_EXIT(TC_BADVOLHEADER);
980     }
981
982     /* Do a sequential search for the volume */
983     else {
984         while (1) {
985             code = butm_ReadFileBegin(tapeInfoPtr);
986             if (code) {
987                 ErrorLog(0, taskId, code, tapeInfoPtr->error,
988                          "Can't read FileBegin on tape\n");
989                 ERROR_EXIT(code);
990             }
991
992             code = ReadVolHeader(taskId, tapeInfoPtr, &tapeVolHeader);
993             if (code)
994                 ERROR_EXIT(TC_VOLUMENOTONTAPE);
995
996             /* Test if we found the volume */
997             if ((strcmp(tapeVolHeader.volumeName, volName) == 0)
998                 && (!volId || (volId == tapeVolHeader.volumeID)))
999                 break;
1000
1001             /* skip to the next HW EOF marker */
1002             code = SeekFile(tapeInfoPtr, 1);
1003             if (code) {
1004                 ErrorLog(0, taskId, code, tapeInfoPtr->error,
1005                          "Can't seek to next EOF on tape\n");
1006                 ERROR_EXIT(code);
1007             }
1008         }
1009     }
1010
1011   error_exit:
1012     return code;
1013 }
1014
1015 afs_int32
1016 GetRestoreTape(taskId, tapeInfoPtr, tname, tapeID, prompt)
1017      afs_int32 taskId;
1018      struct butm_tapeInfo *tapeInfoPtr;
1019      char *tname;
1020      afs_int32 tapeID;
1021      int prompt;
1022 {
1023     struct butm_tapeLabel tapeLabel;
1024     afs_int32 code = 0, rc;
1025     int tapecount = 1;
1026     struct budb_dumpEntry dumpEntry;
1027
1028     /* Make sure that the dump/tape is not a XBSA dump */
1029     rc = bcdb_FindDumpByID(tapeID, &dumpEntry);
1030     if (!rc && (dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1031         ErrorLog(0, taskId, 0, 0,
1032                  "Volumes from dump %u are XBSA dumps (skipping)\n", tapeID);
1033         ERROR_EXIT(TC_SKIPTAPE);
1034     }
1035
1036     while (1) {
1037         if (prompt) {
1038             code =
1039                 PromptForTape(READOPCODE, tname, tapeID, taskId, tapecount);
1040             if (code)
1041                 ERROR_EXIT(code);
1042         }
1043         prompt = 1;
1044         tapecount++;
1045
1046         code = butm_Mount(tapeInfoPtr, tname);
1047         if (code) {
1048             TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
1049             goto newtape;
1050         }
1051
1052         code = butm_ReadLabel(tapeInfoPtr, &tapeLabel, 1);
1053         if (code) {
1054             ErrorLog(0, taskId, code, tapeInfoPtr->error,
1055                      "Can't read tape label\n");
1056             goto newtape;
1057         }
1058
1059         /* Now check the label to see if the tapename matches or tapeids match */
1060         if (strcmp(TNAME(&tapeLabel), tname)
1061             || ((tapeLabel.structVersion >= TAPE_VERSION_3)
1062                 && (tapeLabel.dumpid != tapeID))) {
1063             char expectedName[BU_MAXTAPELEN + 32],
1064                 gotName[BU_MAXTAPELEN + 32];
1065
1066             TAPENAME(expectedName, tname, tapeID);
1067             LABELNAME(gotName, &tapeLabel);
1068
1069             TapeLog(0, taskId, 0, 0,
1070                     "Tape label expected %s, label seen %s\n", expectedName,
1071                     gotName);
1072             goto newtape;
1073         }
1074
1075         break;
1076
1077       newtape:
1078         unmountTape(taskId, tapeInfoPtr);
1079     }
1080
1081   error_exit:
1082     return code;
1083 }
1084
1085 afs_int32
1086 xbsaRestoreVolumeData(call, rparamsPtr)
1087      register struct rx_call *call;
1088      struct restoreParams *rparamsPtr;
1089 {
1090     afs_int32 code = 0;
1091 #ifdef xbsa
1092     afs_int32 curChunk, rc;
1093     afs_uint32 totalWritten;
1094     afs_int32 headBytes, tailBytes, w;
1095     afs_int32 taskId;
1096     struct volumeHeader volTrailer;
1097     afs_int32 vtsize = 0;
1098     int found;
1099     struct dumpNode *nodePtr;
1100     struct tc_restoreDesc *Restore;
1101     afs_int32 bytesRead, tbuffersize, endData = 0;
1102     char *buffer = (char *)bufferBlock, tbuffer[256];
1103
1104     nodePtr = rparamsPtr->nodePtr;
1105     Restore = nodePtr->restores;
1106     taskId = nodePtr->taskID;
1107
1108     /* Read the volume fragment one block at a time until
1109      * find a volume trailer
1110      */
1111     curChunk = BIGCHUNK + 1;
1112     tbuffersize = 0;
1113     totalWritten = 0;
1114
1115     while (!endData) {
1116         rc = xbsa_ReadObjectData(&butxInfo, buffer, dataSize, &bytesRead,
1117                                  &endData);
1118         if (restoretofile && (bytesRead > 0)) {
1119             fwrite(buffer, bytesRead, 1, restoretofilefd);      /* Save to a file */
1120         }
1121         if (rc != XBSA_SUCCESS) {
1122             ErrorLog(0, taskId, rc, 0,
1123                      "Unable to read volume data from the server\n");
1124             ERROR_EXIT(rc);
1125         }
1126
1127         /* Periodically update status structure and check if should abort */
1128         curChunk += bytesRead;
1129         if (curChunk > BIGCHUNK) {
1130             curChunk = 0;
1131             lock_Status();
1132             nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1133             unlock_Status();
1134
1135             if (checkAbortByTaskId(taskId))
1136                 ERROR_EXIT(TC_ABORTEDBYREQUEST);
1137         }
1138
1139         if (!endData && (bytesRead > 0)) {
1140             /* Fill tbuffer up with data from end of buffer and write
1141              * the remainder of buffer out.
1142              */
1143             if ((tbuffersize == 0) || (bytesRead >= sizeof(tbuffer))) {
1144                 /* Write out contents of tbuffer */
1145                 if (tbuffersize) {
1146                     w = rx_Write(call, tbuffer, tbuffersize);
1147                     if (w != tbuffersize) {
1148                         ErrorLog(0, taskId, -1, 0,
1149                                  "Error in RX write: Wrote %d bytes\n", w);
1150                         ERROR_EXIT(-1);
1151                     }
1152                     totalWritten += w;
1153                 }
1154                 /* fill tbuffer with end of buffer */
1155                 bytesRead -= sizeof(tbuffer);
1156                 memcpy(tbuffer, buffer + bytesRead, sizeof(tbuffer));
1157                 tbuffersize = sizeof(tbuffer);
1158                 /* Write out whatever is left over in buffer */
1159                 if (bytesRead) {
1160                     w = rx_Write(call, buffer, bytesRead);
1161                     if (w != bytesRead) {
1162                         ErrorLog(0, taskId, -1, 0,
1163                                  "Error in RX data write: Wrote %d bytes\n",
1164                                  w);
1165                         ERROR_EXIT(-1);
1166                     }
1167                     totalWritten += w;
1168                     bytesRead = 0;
1169                 }
1170             } else if ((tbuffersize + bytesRead) <= sizeof(tbuffer)) {
1171                 /* Copy all of buffer into tbuffer (it will fit) */
1172                 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1173                 tbuffersize += bytesRead;
1174                 bytesRead = 0;
1175             } else {
1176                 /* We need to write some of tbuffer out and fill it with buffer */
1177                 int towrite = bytesRead - (sizeof(tbuffer) - tbuffersize);
1178                 w = rx_Write(call, tbuffer, towrite);
1179                 if (w != towrite) {
1180                     ErrorLog(0, taskId, -1, 0,
1181                              "Error in RX write: Wrote %d bytes\n", w);
1182                     ERROR_EXIT(-1);
1183                 }
1184                 totalWritten += w;
1185                 tbuffersize -= w;
1186
1187                 /* Move the data in tbuffer up */
1188                 memcpy(tbuffer, tbuffer + towrite, tbuffersize);
1189
1190                 /* Now copy buffer in */
1191                 memcpy(tbuffer + tbuffersize, buffer, bytesRead);
1192                 tbuffersize += bytesRead;
1193                 bytesRead = 0;
1194             }
1195         }
1196     }
1197
1198     /* Pull the volume trailer from the last two buffers */
1199     found =
1200         FindVolTrailer2(tbuffer, tbuffersize, &headBytes, buffer, bytesRead,
1201                         &tailBytes, &volTrailer);
1202
1203     if (!found) {
1204         ErrorLog(0, taskId, TC_MISSINGTRAILER, 0, "Missing volume trailer\n");
1205         ERROR_EXIT(TC_MISSINGTRAILER);
1206     }
1207
1208     /* Now rx_write the data in the last two blocks */
1209     if (headBytes) {
1210         w = rx_Write(call, tbuffer, headBytes);
1211         if (w != headBytes) {
1212             ErrorLog(0, taskId, -1, 0,
1213                      "Error in RX trail1 write: Wrote %d bytes\n", w);
1214             ERROR_EXIT(-1);
1215         }
1216         totalWritten += w;
1217     }
1218     if (tailBytes) {
1219         w = rx_Write(call, buffer, tailBytes);
1220         if (w != tailBytes) {
1221             ErrorLog(0, taskId, -1, 0,
1222                      "Error in RX trail2 write: Wrote %d bytes\n", w);
1223             ERROR_EXIT(-1);
1224         }
1225         totalWritten += w;
1226     }
1227
1228   error_exit:
1229 #endif /*xbsa */
1230     return code;
1231 }
1232
1233 /* restoreVolume
1234  *      sends the contents of volume dump  to Rx Stream associated
1235  *      with <call>
1236  */
1237
1238 afs_int32
1239 restoreVolumeData(call, rparamsPtr)
1240      register struct rx_call *call;
1241      struct restoreParams *rparamsPtr;
1242 {
1243     afs_int32 curChunk;
1244     afs_uint32 totalWritten = 0;
1245     afs_int32 code;
1246     afs_int32 headBytes, tailBytes, w;
1247     afs_int32 taskId;
1248     afs_int32 nbytes;           /* # bytes data in last tape block read */
1249     struct volumeHeader tapeVolTrailer;
1250     int found;
1251     int moretoread;
1252     afs_int32 startRbuf, endRbuf, startWbuf, endWbuf, buf, pbuf, lastbuf;
1253     struct tc_restoreDesc *Restore;
1254     struct dumpNode *nodePtr;
1255     struct butm_tapeInfo *tapeInfoPtr;
1256     char *origVolName;
1257     afs_int32 origVolID;
1258
1259     nodePtr = rparamsPtr->nodePtr;
1260     taskId = nodePtr->taskID;
1261     Restore = nodePtr->restores;
1262     tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1263     origVolName = Restore[rparamsPtr->frag].oldName;
1264     origVolID = Restore[rparamsPtr->frag].origVid;
1265
1266     /* Read the volume one fragment at a time */
1267     while (rparamsPtr->frag < nodePtr->arraySize) {
1268         /*w */
1269         curChunk = BIGCHUNK + 1;        /* Check if should abort */
1270
1271         /* Read the volume fragment one block at a time until
1272          * find a volume trailer
1273          */
1274         moretoread = 1;
1275         startRbuf = 0;
1276         endRbuf = 0;
1277         startWbuf = 0;
1278         while (moretoread) {
1279             /* Fill the circular buffer with tape blocks
1280              * Search for volume trailer in the process.
1281              */
1282             buf = startRbuf;
1283             do {
1284                 code =
1285                     butm_ReadFileData(tapeInfoPtr, bufferBlock[buf].data,
1286                                       BUTM_BLKSIZE, &nbytes);
1287                 if (code) {
1288                     ErrorLog(0, taskId, code, tapeInfoPtr->error,
1289                              "Can't read FileData on tape %s\n",
1290                              rparamsPtr->mntTapeName);
1291                     ERROR_EXIT(code);
1292                 }
1293                 curChunk += BUTM_BLKSIZE;
1294
1295                 /* Periodically update status structure and check if should abort */
1296                 if (curChunk > BIGCHUNK) {
1297                     curChunk = 0;
1298
1299                     lock_Status();
1300                     nodePtr->statusNodePtr->nKBytes = totalWritten / 1024;
1301                     unlock_Status();
1302
1303                     if (checkAbortByTaskId(taskId))
1304                         ERROR_EXIT(TC_ABORTEDBYREQUEST);
1305                 }
1306
1307                 /* step to next block in buffer */
1308                 pbuf = buf;
1309                 buf = ((buf + 1) == tapeblocks) ? 0 : (buf + 1);
1310
1311                 /* If this is the end of the volume, the exit the loop */
1312                 if ((nbytes != BUTM_BLKSIZE)
1313                     ||
1314                     (FindVolTrailer
1315                      (bufferBlock[pbuf].data, nbytes, &tailBytes,
1316                       &tapeVolTrailer)))
1317                     moretoread = 0;
1318
1319             } while (moretoread && (buf != endRbuf));
1320
1321             /* Write the buffer upto (but not including) the last read block
1322              * If volume is completely read, then leave the last two blocks.
1323              */
1324             lastbuf = endWbuf = pbuf;
1325             if (!moretoread && (endWbuf != startWbuf))
1326                 endWbuf = (endWbuf == 0) ? (tapeblocks - 1) : (endWbuf - 1);
1327
1328             for (buf = startWbuf; buf != endWbuf;
1329                  buf = (((buf + 1) == tapeblocks) ? 0 : (buf + 1))) {
1330                 w = rx_Write(call, bufferBlock[buf].data, BUTM_BLKSIZE);
1331                 if (w != BUTM_BLKSIZE) {
1332                     ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1333                     ERROR_EXIT(-1);
1334                 }
1335                 totalWritten += BUTM_BLKSIZE;
1336             }
1337
1338             /* Setup pointers to refill buffer */
1339             startRbuf = ((lastbuf + 1) == tapeblocks) ? 0 : (lastbuf + 1);
1340             endRbuf = endWbuf;
1341             startWbuf = endWbuf;
1342         }
1343
1344         /* lastbuf is last block read and it has nbytes of data
1345          * startWbuf is the 2nd to last block read 
1346          * Seach for the volume trailer in these two blocks.
1347          */
1348         if (lastbuf == startWbuf)
1349             found =
1350                 FindVolTrailer2(NULL, 0, &headBytes,
1351                                 bufferBlock[lastbuf].data, nbytes, &tailBytes,
1352                                 &tapeVolTrailer);
1353         else
1354             found =
1355                 FindVolTrailer2(bufferBlock[startWbuf].data, BUTM_BLKSIZE,
1356                                 &headBytes, bufferBlock[lastbuf].data, nbytes,
1357                                 &tailBytes, &tapeVolTrailer);
1358         if (!found) {
1359             ErrorLog(0, taskId, TC_MISSINGTRAILER, 0,
1360                      "Missing volume trailer on tape %s\n",
1361                      rparamsPtr->mntTapeName);
1362             ERROR_EXIT(TC_MISSINGTRAILER);
1363         }
1364
1365         /* Now rx_write the data in the last two blocks */
1366         if (headBytes) {
1367             w = rx_Write(call, bufferBlock[startWbuf].data, headBytes);
1368             if (w != headBytes) {
1369                 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1370                 ERROR_EXIT(-1);
1371             }
1372             totalWritten += headBytes;
1373         }
1374         if (tailBytes) {
1375             w = rx_Write(call, bufferBlock[lastbuf].data, tailBytes);
1376             if (w != tailBytes) {
1377                 ErrorLog(0, taskId, -1, 0, "Error in RX write\n");
1378                 ERROR_EXIT(-1);
1379             }
1380             totalWritten += tailBytes;
1381         }
1382
1383         /* Exit the loop if the volume is not continued on next tape */
1384         if (!tapeVolTrailer.contd)
1385             break;              /* We've read the entire volume */
1386
1387         /* Volume is continued on next tape. 
1388          * Step to the next volume fragment and prompt for its tape.
1389          * When a volume has multiple frags, those frags are on different
1390          * tapes. So we know that we need to prompt for a tape.
1391          */
1392         rparamsPtr->frag++;
1393         if (rparamsPtr->frag >= nodePtr->arraySize)
1394             break;
1395
1396         unmountTape(taskId, tapeInfoPtr);
1397         strcpy(rparamsPtr->mntTapeName, Restore[rparamsPtr->frag].tapeName);
1398         rparamsPtr->tapeID =
1399             (Restore[rparamsPtr->frag].
1400              initialDumpId ? Restore[rparamsPtr->frag].
1401              initialDumpId : Restore[rparamsPtr->frag].dbDumpId);
1402         code =
1403             GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1404                            rparamsPtr->tapeID, 1);
1405         if (code)
1406             ERROR_EXIT(code);
1407
1408         /* Position to the frag and read the volume header */
1409         code =
1410             GetVolumeHead(taskId, tapeInfoPtr,
1411                           Restore[rparamsPtr->frag].position, origVolName,
1412                           origVolID);
1413         if (code) {
1414             ErrorLog(0, taskId, code, 0,
1415                      "Can't find volume %s (%u) on tape %s\n", origVolName,
1416                      origVolID, rparamsPtr->mntTapeName);
1417             ERROR_EXIT(TC_VOLUMENOTONTAPE);
1418         }
1419     }                           /*w */
1420
1421   error_exit:
1422     return code;
1423 }
1424
1425 /* SkipTape
1426  *    Find all the volumes on a specific tape and mark them to skip.
1427  */
1428 SkipTape(Restore, size, index, tapename, tapeid, taskid)
1429      struct tc_restoreDesc *Restore;
1430      afs_int32 size, index, tapeid, taskid;
1431      char *tapename;
1432 {
1433     afs_int32 i, tid;
1434
1435     for (i = index; i < size; i++) {
1436         if (Restore[i].flags & RDFLAG_SKIP)
1437             continue;
1438         tid =
1439             (Restore[i].initialDumpId ? Restore[i].initialDumpId : Restore[i].
1440              dbDumpId);
1441         if ((strcmp(Restore[i].tapeName, tapename) == 0) && (tid == tapeid)) {
1442             SkipVolume(Restore, size, i, Restore[i].origVid, taskid);
1443         }
1444     }
1445 }
1446
1447 /* SkipVolume
1448  *    Find all the entries for a volume and mark them to skip.
1449  */
1450 SkipVolume(Restore, size, index, volid, taskid)
1451      struct tc_restoreDesc *Restore;
1452      afs_int32 size, index, volid, taskid;
1453 {
1454     afs_int32 i;
1455     int report = 1;
1456
1457     for (i = index; i < size; i++) {
1458         if (Restore[i].flags & RDFLAG_SKIP)
1459             continue;
1460         if (Restore[i].origVid == volid) {
1461             Restore[i].flags |= RDFLAG_SKIP;
1462             if (report) {
1463                 TLog(taskid, "Restore: Skipping %svolume %s (%u)\n",
1464                      ((Restore[i].dumpLevel == 0) ? "" : "remainder of "),
1465                      Restore[i].oldName, volid);
1466                 report = 0;
1467             }
1468         }
1469     }
1470 }
1471
1472 xbsaRestoreVolume(taskId, restoreInfo, rparamsPtr)
1473      afs_uint32 taskId;
1474      struct tc_restoreDesc *restoreInfo;
1475      struct restoreParams *rparamsPtr;
1476 {
1477     afs_int32 code = 0;
1478 #ifdef xbsa
1479     afs_int32 rc;
1480     afs_int32 newServer, newPart, newVolId;
1481     char *newVolName;
1482     int restoreflags, havetrans = 0, startread = 0;
1483     afs_int32 bytesRead, endData = 0;
1484     afs_uint32 dumpID;
1485     struct budb_dumpEntry dumpEntry;
1486     char volumeNameStr[XBSA_MAX_PATHNAME], dumpIdStr[XBSA_MAX_OSNAME];
1487     struct volumeHeader volHeader, hostVolHeader;
1488
1489     if (restoretofile) {
1490         restoretofilefd = fopen(restoretofile, "w+");
1491     }
1492
1493     dumpID = restoreInfo->dbDumpId;
1494
1495     rc = bcdb_FindDumpByID(dumpID, &dumpEntry);
1496     if (rc) {
1497         ErrorLog(0, taskId, rc, 0, "Can't read database for dump %u\n",
1498                  dumpID);
1499         ERROR_EXIT(rc);
1500     }
1501
1502     /* ADSM servers restore ADSM and BUTA dumps */
1503     if ((xbsaType == XBSA_SERVER_TYPE_ADSM)
1504         && !(dumpEntry.flags & (BUDB_DUMP_ADSM | BUDB_DUMP_BUTA))) {
1505         ELog(taskId,
1506              "The dump requested by this restore operation for the "
1507              "volumeset is incompatible with this instance of butc\n");
1508         /* Skip the entire dump (one dump per tape) */
1509         ERROR_EXIT(TC_SKIPTAPE);
1510     }
1511
1512     /* make sure we are connected to the correct server. */
1513     if ((strlen((char *)dumpEntry.tapes.tapeServer) != 0)
1514         && (strcmp((char *)dumpEntry.tapes.tapeServer, butxInfo.serverName) !=
1515             0)) {
1516         if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS | BUDB_DUMP_BUTA))
1517             && !forcemultiple) {
1518             TLog(taskId,
1519                  "Dump %d is on server %s but butc is connected "
1520                  "to server %s (attempting to restore)\n", dumpID,
1521                  (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1522         } else {
1523             TLog(taskId,
1524                  "Dump %d is on server %s but butc is connected "
1525                  "to server %s (switching servers)\n", dumpID,
1526                  (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName);
1527
1528             rc = InitToServer(taskId, &butxInfo,
1529                               (char *)dumpEntry.tapes.tapeServer);
1530             if (rc != XBSA_SUCCESS)
1531                 ERROR_EXIT(TC_SKIPTAPE);
1532         }
1533     }
1534
1535     /* Start a transaction and query the server for the correct fileset dump */
1536     rc = xbsa_BeginTrans(&butxInfo);
1537     if (rc != XBSA_SUCCESS) {
1538         ELog(taskId, "Unable to create a new transaction\n");
1539         ERROR_EXIT(TC_SKIPTAPE);
1540     }
1541     havetrans = 1;
1542
1543     if (dumpEntry.flags & BUDB_DUMP_BUTA) {     /* old buta style names */
1544         sprintf(dumpIdStr, "/%d", dumpID);
1545         strcpy(volumeNameStr, "/");
1546         strcat(volumeNameStr, restoreInfo->oldName);
1547     } else {                    /* new butc names */
1548         extern char *butcdumpIdStr;
1549         strcpy(dumpIdStr, butcdumpIdStr);
1550         sprintf(volumeNameStr, "/%d", dumpID);
1551         strcat(volumeNameStr, "/");
1552         strcat(volumeNameStr, restoreInfo->oldName);
1553     }
1554
1555     rc = xbsa_QueryObject(&butxInfo, dumpIdStr, volumeNameStr);
1556     if (rc != XBSA_SUCCESS) {
1557         ELog(taskId,
1558              "Unable to locate object (%s) of dump (%s) on the server\n",
1559              volumeNameStr, dumpIdStr);
1560         ERROR_EXIT(rc);
1561     }
1562
1563     rc = xbsa_EndTrans(&butxInfo);
1564     havetrans = 0;
1565     if (rc != XBSA_SUCCESS) {
1566         ELog(taskId, "Unable to terminate the current transaction\n");
1567         ERROR_EXIT(rc);
1568     }
1569
1570     if (checkAbortByTaskId(taskId))
1571         ERROR_EXIT(TC_ABORTEDBYREQUEST);
1572
1573     /* Now start a transaction on the volume to restore and read the
1574      * volumeheader. We do this before starting a transaction on
1575      * volserver to restore the volume because the XBSA server may take
1576      * a while to mount and seek to the volume causing the volserver to
1577      * time out.
1578      */
1579     rc = xbsa_BeginTrans(&butxInfo);
1580     if (rc != XBSA_SUCCESS) {
1581         ELog(taskId, "Unable to create a new transaction\n");
1582         ERROR_EXIT(TC_SKIPTAPE);
1583     }
1584     havetrans = 1;
1585
1586     rc = xbsa_ReadObjectBegin(&butxInfo, (char *)&volHeader,
1587                               sizeof(volHeader), &bytesRead, &endData);
1588     if (restoretofile && (bytesRead > 0)) {
1589         fwrite((char *)&volHeader, bytesRead, 1, restoretofilefd);      /* Save to a file */
1590     }
1591     if (rc != XBSA_SUCCESS) {
1592         ELog(taskId,
1593              "Unable to begin reading of the volume from the server\n");
1594         ERROR_EXIT(rc);
1595     }
1596     startread = 1;
1597
1598     if ((bytesRead != sizeof(volHeader)) || endData) {
1599         ELog(taskId,
1600              "The size of data read (%d) does not equal the size of data requested (%d)\n",
1601              bytesRead, sizeof(volHeader));
1602         ERROR_EXIT(TC_BADVOLHEADER);
1603     }
1604
1605     /* convert and check the volume header */
1606     rc = VolHeaderToHost(&hostVolHeader, &volHeader);
1607     if (rc) {
1608         ErrorLog(0, taskId, code, 0, "Can't convert volume header\n");
1609         ERROR_EXIT(rc);
1610     }
1611
1612     if ((strcmp(hostVolHeader.volumeName, restoreInfo->oldName) != 0)
1613         || (restoreInfo->origVid
1614             && (hostVolHeader.volumeID != restoreInfo->origVid))
1615         || (hostVolHeader.magic != TC_VOLBEGINMAGIC))
1616         ERROR_EXIT(TC_BADVOLHEADER);
1617
1618     /* Set up prior restoring volume data */
1619     newVolName = restoreInfo->newName;
1620     newVolId = restoreInfo->vid;
1621     newServer = restoreInfo->hostAddr;
1622     newPart = restoreInfo->partition;
1623     restoreflags = 0;
1624     if ((restoreInfo->dumpLevel == 0)
1625         || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1626         restoreflags |= RV_FULLRST;
1627     if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1628         restoreflags |= RV_OFFLINE;
1629
1630     if (checkAbortByTaskId(taskId))
1631         ERROR_EXIT(TC_ABORTEDBYREQUEST);
1632
1633     /* Start the restore of the volume data. This is the code we want to return */
1634     code =
1635         UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1636                          restoreflags, xbsaRestoreVolumeData,
1637                          (char *)rparamsPtr);
1638   error_exit:
1639     if (startread) {
1640         rc = xbsa_ReadObjectEnd(&butxInfo);
1641         if (rc != XBSA_SUCCESS) {
1642             ELog(taskId,
1643                  "Unable to terminate reading of the volume from the server\n");
1644             ERROR_EXIT(rc);
1645         }
1646     }
1647
1648     if (havetrans) {
1649         rc = xbsa_EndTrans(&butxInfo);
1650         if (rc != XBSA_SUCCESS) {
1651             ELog(taskId, "Unable to terminate the current transaction\n");
1652             if (!code)
1653                 code = rc;
1654         }
1655     }
1656
1657     if (restoretofile && restoretofilefd) {
1658         fclose(restoretofilefd);
1659     }
1660 #endif
1661     return (code);
1662 }
1663
1664 restoreVolume(taskId, restoreInfo, rparamsPtr)
1665      afs_uint32 taskId;
1666      struct tc_restoreDesc *restoreInfo;
1667      struct restoreParams *rparamsPtr;
1668 {
1669     afs_int32 code = 0, rc;
1670     afs_int32 newServer, newPart, newVolId;
1671     char *newVolName;
1672     int restoreflags;
1673     afs_uint32 tapeID;
1674     struct butm_tapeInfo *tapeInfoPtr = rparamsPtr->tapeInfoPtr;
1675
1676     /* Check if we need a tape and prompt for one if so */
1677     tapeID =
1678         (restoreInfo->initialDumpId ? restoreInfo->
1679          initialDumpId : restoreInfo->dbDumpId);
1680     if ((rparamsPtr->frag == 0)
1681         || (strcmp(restoreInfo->tapeName, rparamsPtr->mntTapeName) != 0)
1682         || (tapeID != rparamsPtr->tapeID)) {
1683         /* Unmount the previous tape */
1684         unmountTape(taskId, tapeInfoPtr);
1685
1686         /* Remember this new tape */
1687         strcpy(rparamsPtr->mntTapeName, restoreInfo->tapeName);
1688         rparamsPtr->tapeID = tapeID;
1689
1690         /* Mount a new tape */
1691         rc = GetRestoreTape(taskId, tapeInfoPtr, rparamsPtr->mntTapeName,
1692                             rparamsPtr->tapeID,
1693                             ((rparamsPtr->frag == 0) ? autoQuery : 1));
1694         if (rc)
1695             ERROR_EXIT(rc);
1696     }
1697
1698     /* Seek to the correct spot and read the header information */
1699     rc = GetVolumeHead(taskId, tapeInfoPtr, restoreInfo->position,
1700                        restoreInfo->oldName, restoreInfo->origVid);
1701     if (rc)
1702         ERROR_EXIT(rc);
1703
1704     /* Set up prior restoring volume data */
1705     newVolName = restoreInfo->newName;
1706     newVolId = restoreInfo->vid;
1707     newServer = restoreInfo->hostAddr;
1708     newPart = restoreInfo->partition;
1709     restoreflags = 0;
1710     if ((restoreInfo->dumpLevel == 0)
1711         || (restoreInfo->flags & RDFLAG_FIRSTDUMP))
1712         restoreflags |= RV_FULLRST;
1713     if (!(restoreInfo->flags & RDFLAG_LASTDUMP))
1714         restoreflags |= RV_OFFLINE;
1715
1716     if (checkAbortByTaskId(taskId))
1717         ERROR_EXIT(TC_ABORTEDBYREQUEST);
1718
1719     /* Start the restore of the volume data. This is the code we
1720      * want to return.
1721      */
1722     code =
1723         UV_RestoreVolume(htonl(newServer), newPart, newVolId, newVolName,
1724                          restoreflags, restoreVolumeData, (char *)rparamsPtr);
1725
1726     /* Read the FileEnd marker for the volume and step to next FM */
1727     rc = butm_ReadFileEnd(tapeInfoPtr);
1728     if (rc) {
1729         ErrorLog(0, taskId, rc, tapeInfoPtr->error,
1730                  "Can't read EOF on tape\n");
1731     }
1732
1733   error_exit:
1734     return (code);
1735 }
1736
1737 /* Restorer
1738  *      created as a LWP by the server stub, <newNode> is a pointer to all
1739  *      the parameters Restorer needs
1740  */
1741 Restorer(newNode)
1742      struct dumpNode *newNode;
1743 {
1744     afs_int32 code = 0, tcode;
1745     afs_uint32 taskId;
1746     char *newVolName;
1747     struct butm_tapeInfo tapeInfo;
1748     struct tc_restoreDesc *Restore;
1749     struct tc_restoreDesc *RestoreDesc;
1750     struct restoreParams rparams;
1751     afs_int32 allocbufferSize;
1752     time_t startTime, endTime;
1753     afs_int32 goodrestore = 0;
1754
1755     taskId = newNode->taskID;
1756     setStatus(taskId, DRIVE_WAIT);
1757     EnterDeviceQueue(deviceLatch);
1758     clearStatus(taskId, DRIVE_WAIT);
1759
1760     printf("\n\n");
1761     TLog(taskId, "Restore\n");
1762
1763     memset(&tapeInfo, 0, sizeof(tapeInfo));
1764     if (!CONF_XBSA) {
1765         tapeInfo.structVersion = BUTM_MAJORVERSION;
1766         tcode = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
1767         if (tcode) {
1768             ErrorLog(0, taskId, tcode, tapeInfo.error,
1769                      "Can't initialize the tape module\n");
1770             ERROR_EXIT(tcode);
1771         }
1772     }
1773
1774     if (checkAbortByTaskId(taskId))
1775         ERROR_EXIT(TC_ABORTEDBYREQUEST);
1776
1777     memset(&rparams, 0, sizeof(rparams));
1778     rparams.nodePtr = newNode;
1779     rparams.tapeInfoPtr = &tapeInfo;
1780     Restore = newNode->restores;        /* Array of vol fragments to restore */
1781
1782     /* Allocate memory in which to restore the volumes data into */
1783     if (CONF_XBSA) {
1784         allocbufferSize = dataSize = BufferSize;
1785     } else {
1786         /* Must have at least two tape blocks */
1787         tapeblocks = BufferSize / BUTM_BLOCKSIZE;
1788         if (tapeblocks < 2)
1789             tapeblocks = 2;
1790         allocbufferSize = tapeblocks * BUTM_BLOCKSIZE;  /* This many full tapeblocks */
1791     }
1792     bufferBlock = NULL;
1793     bufferBlock = (struct TapeBlock *)malloc(allocbufferSize);
1794     if (!bufferBlock)
1795         ERROR_EXIT(TC_NOMEMORY);
1796     memset(bufferBlock, 0, allocbufferSize);
1797
1798     startTime = time(0);
1799     for (rparams.frag = 0; (rparams.frag < newNode->arraySize);
1800          rparams.frag++) {
1801         RestoreDesc = &Restore[rparams.frag];
1802
1803         /* Skip the volume if it was requested to */
1804         if (RestoreDesc->flags & RDFLAG_SKIP) {
1805             if (RestoreDesc->flags & RDFLAG_LASTDUMP) {
1806                 /* If the volume was restored, should bring it online */
1807             }
1808             continue;
1809         }
1810
1811         newVolName = RestoreDesc->newName;
1812
1813         /* Make sure the server to restore to is good */
1814         if (!RestoreDesc->hostAddr) {
1815             ErrorLog(0, taskId, 0, 0, "Illegal host ID 0 for volume %s\n",
1816                      newVolName);
1817             ERROR_EXIT(TC_INTERNALERROR);
1818         }
1819
1820         if (checkAbortByTaskId(taskId))
1821             ERROR_EXIT(TC_ABORTEDBYREQUEST);
1822
1823         TapeLog(1, taskId, 0, 0, "Restoring volume %s\n", newVolName);
1824         lock_Status();
1825         strncpy(newNode->statusNodePtr->volumeName, newVolName,
1826                 BU_MAXNAMELEN);
1827         unlock_Status();
1828
1829         /* restoreVolume function takes care of all the related fragments
1830          * spanning various tapes. On return the complete volume has been
1831          * restored 
1832          */
1833         if (CONF_XBSA) {
1834             tcode = xbsaRestoreVolume(taskId, RestoreDesc, &rparams);
1835         } else {
1836             tcode = restoreVolume(taskId, RestoreDesc, &rparams);
1837         }
1838         if (tcode) {
1839             if (tcode == TC_ABORTEDBYREQUEST) {
1840                 ERROR_EXIT(tcode);
1841             } else if (tcode == TC_SKIPTAPE) {
1842                 afs_uint32 tapeID;
1843                 tapeID =
1844                     (RestoreDesc->initialDumpId ? RestoreDesc->
1845                      initialDumpId : RestoreDesc->dbDumpId);
1846                 SkipTape(Restore, newNode->arraySize, rparams.frag,
1847                          RestoreDesc->tapeName, tapeID, taskId);
1848             } else {
1849                 ErrorLog(0, taskId, tcode, 0, "Can't restore volume %s\n",
1850                          newVolName);
1851                 SkipVolume(Restore, newNode->arraySize, rparams.frag,
1852                            RestoreDesc->origVid, taskId);
1853             }
1854             rparams.frag--;
1855             continue;
1856         }
1857
1858         goodrestore++;
1859     }
1860
1861   error_exit:
1862     endTime = time(0);
1863     if (!CONF_XBSA) {
1864         unmountTape(taskId, &tapeInfo);
1865     } else {
1866 #ifdef xbsa
1867         code = InitToServer(taskId, &butxInfo, 0);      /* Return to original server */
1868 #endif
1869     }
1870
1871     if (bufferBlock)
1872         free(bufferBlock);
1873
1874     if (code == TC_ABORTEDBYREQUEST) {
1875         ErrorLog(0, taskId, 0, 0, "Restore: Aborted by request\n");
1876         clearStatus(taskId, ABORT_REQUEST);
1877         setStatus(taskId, ABORT_DONE);
1878     } else if (code) {
1879         TapeLog(0, taskId, code, 0, "Restore: Finished with errors\n");
1880         setStatus(taskId, TASK_ERROR);
1881     } else {
1882         TLog(taskId, "Restore: Finished\n");
1883     }
1884
1885     if (centralLogIO && startTime) {
1886         long timediff;
1887         afs_int32 hrs, min, sec, tmp;
1888         char line[1024];
1889         struct tm tmstart, tmend;
1890
1891         localtime_r(&startTime, &tmstart);
1892         localtime_r(&endTime, &tmend);
1893         timediff = (int)endTime - (int)startTime;
1894         hrs = timediff / 3600;
1895         tmp = timediff % 3600;
1896         min = tmp / 60;
1897         sec = tmp % 60;
1898
1899         sprintf(line,
1900                 "%-5d  %02d/%02d/%04d %02d:%02d:%02d  "
1901                 "%02d/%02d/%04d %02d:%02d:%02d  " "%02d:%02d:%02d  "
1902                 "%d of %d volume%s restored\n", taskId, tmstart.tm_mon + 1,
1903                 tmstart.tm_mday, tmstart.tm_year + 1900, tmstart.tm_hour,
1904                 tmstart.tm_min, tmstart.tm_sec, tmend.tm_mon + 1,
1905                 tmend.tm_mday, tmend.tm_year + 1900, tmend.tm_hour,
1906                 tmend.tm_min, tmend.tm_sec, hrs, min, sec, goodrestore,
1907                 newNode->arraySize, ((newNode->arraySize > 1) ? "s" : ""));
1908
1909         fwrite(line, strlen(line), 1, centralLogIO);
1910         fflush(centralLogIO);
1911     }
1912
1913     setStatus(taskId, TASK_DONE);
1914
1915     FreeNode(taskId);
1916     LeaveDeviceQueue(deviceLatch);
1917     return (code);
1918 }
1919
1920 /* this is just scaffolding, creates new tape label with name <tapeName> */
1921
1922 GetNewLabel(tapeInfoPtr, pName, AFSName, tapeLabel)
1923      struct butm_tapeInfo *tapeInfoPtr;
1924      char *pName, *AFSName;
1925      struct butm_tapeLabel *tapeLabel;
1926 {
1927     struct timeval tp;
1928     struct timezone tzp;
1929     afs_uint32 size;
1930
1931     memset(tapeLabel, 0, sizeof(struct butm_tapeLabel));
1932
1933     if (!CONF_XBSA) {
1934         butm_GetSize(tapeInfoPtr, &size);
1935         if (!size)
1936             size = globalTapeConfig.capacity;
1937     } else {
1938         size = 0;               /* no tape size */
1939     }
1940     gettimeofday(&tp, &tzp);
1941
1942     tapeLabel->structVersion = CUR_TAPE_VERSION;
1943     tapeLabel->creationTime = tp.tv_sec;
1944     tapeLabel->size = size;
1945     tapeLabel->expirationDate = 0;      /* 1970 sometime */
1946     tapeLabel->dumpPath[0] = 0; /* no path name  */
1947     tapeLabel->useCount = 0;
1948     strcpy(tapeLabel->AFSName, AFSName);
1949     strcpy(tapeLabel->pName, pName);
1950     strcpy(tapeLabel->cell, globalCellName);
1951     strcpy(tapeLabel->comment, "AFS Backup Software");
1952     strcpy(tapeLabel->creator.name, "AFS 3.6");
1953     strcpy(tapeLabel->creator.instance, "");
1954     strcpy(tapeLabel->creator.cell, globalCellName);
1955 }
1956
1957 /* extracts trailer out of buffer, nbytes is set to total data in buffer - trailer size */
1958 afs_int32
1959 ExtractTrailer(buffer, size, nbytes, volTrailerPtr)
1960      char *buffer;
1961      afs_int32 *nbytes;
1962      afs_int32 size;
1963      struct volumeHeader *volTrailerPtr;
1964 {
1965     afs_int32 code = 0;
1966     afs_int32 startPos;
1967     struct volumeHeader tempTrailer;
1968
1969     for (startPos = 0;
1970          startPos <=
1971          (size - sizeof(struct volumeHeader) + sizeof(tempTrailer.pad));
1972          startPos++) {
1973         code = readVolumeHeader(buffer, startPos, &tempTrailer);
1974         if (code == 0) {
1975             code = VolHeaderToHost(volTrailerPtr, &tempTrailer);
1976             if (code)
1977                 break;
1978
1979             if (nbytes)
1980                 *nbytes = startPos;
1981             return 1;           /* saw the trailer */
1982         }
1983     }
1984
1985     if (nbytes)
1986         *nbytes = size / 2;
1987     return 0;                   /* did not see the trailer */
1988 }
1989
1990 int
1991 FindVolTrailer(buffer, size, dSize, volTrailerPtr)
1992      char *buffer;
1993      afs_int32 size;
1994      struct volumeHeader *volTrailerPtr;
1995      afs_int32 *dSize;          /* dataSize */
1996 {
1997     afs_int32 offset, s;
1998     int found;
1999
2000     *dSize = size;
2001     if (!buffer)
2002         return 0;
2003
2004     s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
2005     if (s > size)
2006         s = size;
2007
2008     found = ExtractTrailer((buffer + size - s), s, &offset, volTrailerPtr);
2009     if (found)
2010         *dSize -= (s - offset);
2011     return found;
2012 }
2013
2014 int
2015 FindVolTrailer2(buffera, sizea, dataSizea, bufferb, sizeb, dataSizeb,
2016                 volTrailerPtr)
2017      char *buffera;
2018      afs_int32 sizea;
2019      afs_int32 *dataSizea;
2020      char *bufferb;
2021      afs_int32 sizeb;
2022      afs_int32 *dataSizeb;
2023      struct volumeHeader *volTrailerPtr;
2024 {
2025     afs_int32 offset, s;
2026     afs_int32 headB, tailB;
2027     int found = 0;
2028
2029     if (!buffera)
2030         sizea = 0;
2031     if (!bufferb)
2032         sizeb = 0;
2033     *dataSizea = sizea;
2034     *dataSizeb = sizeb;
2035
2036     s = sizeof(struct volumeHeader) + sizeof(volTrailerPtr->pad);
2037     if (sizeb >= s) {
2038         found = FindVolTrailer(bufferb, sizeb, dataSizeb, volTrailerPtr);
2039     } else {
2040         tailB = sizeb;
2041         headB = (s - sizeb);    /*(s > sizeb) */
2042         if (headB > sizea) {
2043             headB = sizea;
2044             s = headB + tailB;
2045             if (!s)
2046                 return 0;
2047         }
2048
2049         memset(tapeVolumeHT, 0, sizeof(tapeVolumeHT));
2050         if (headB)
2051             memcpy(tapeVolumeHT, buffera + sizea - headB, headB);
2052         if (tailB)
2053             memcpy(tapeVolumeHT + headB, bufferb, tailB);
2054         if (ExtractTrailer(tapeVolumeHT, s, &offset, volTrailerPtr)) {
2055             found = 1;
2056             if (offset > headB) {
2057                 /* *dataSizea remains unchanged */
2058                 *dataSizeb = offset - headB;
2059             } else {
2060                 *dataSizea -= (headB - offset); /*(headB >= offset) */
2061                 *dataSizeb = 0;
2062             }
2063         }
2064     }
2065     return found;
2066 }
2067
2068 /* Returns true or false depending on whether the tape is expired or not */
2069
2070 Date
2071 ExpirationDate(dumpid)
2072      afs_int32 dumpid;
2073 {
2074     afs_int32 code;
2075     Date expiration = 0;
2076     struct budb_dumpEntry dumpEntry;
2077     struct budb_tapeEntry tapeEntry;
2078     struct budb_volumeEntry volEntry;
2079
2080     if (dumpid) {
2081         /*
2082          * Get the expiration date from DB if its there. The expiration of any tape
2083          * will be the most future expiration of any dump in the set. Can't use
2084          * bcdb_FindTape because dumpid here pertains to the initial dump id.
2085          */
2086         code = bcdb_FindLastTape(dumpid, &dumpEntry, &tapeEntry, &volEntry);
2087         if (!code)
2088             expiration = tapeEntry.expires;
2089     }
2090     return (expiration);
2091 }
2092
2093 int
2094 tapeExpired(tapeLabelPtr)
2095      struct butm_tapeLabel *tapeLabelPtr;
2096 {
2097     Date expiration;
2098     struct timeval tp;
2099     struct timezone tzp;
2100
2101     expiration = ExpirationDate(tapeLabelPtr->dumpid);
2102     if (!expiration)
2103         expiration = tapeLabelPtr->expirationDate;
2104
2105     gettimeofday(&tp, &tzp);
2106     return ((expiration < tp.tv_sec) ? 1 : 0);
2107 }
2108
2109 /* updateTapeLabel
2110  *      given the label on the tape, delete any old information from the
2111  *      database. 
2112
2113  * Deletes all entries that match the volset.dumpnode
2114  *      and the dump path.
2115  */
2116
2117 updateTapeLabel(labelIfPtr, tapeInfoPtr, newLabelPtr)
2118      struct labelTapeIf *labelIfPtr;
2119      struct butm_tapeInfo *tapeInfoPtr;
2120      struct butm_tapeLabel *newLabelPtr;
2121 {
2122     struct butm_tapeLabel oldLabel;
2123     afs_int32 i, code = 0;
2124     afs_uint32 taskId;
2125     int tapeIsLabeled = 0;
2126     int interactiveFlag;
2127     int tapecount = 1;
2128
2129     interactiveFlag = autoQuery;
2130     taskId = labelIfPtr->taskId;
2131
2132     while (1) {
2133         if (interactiveFlag) {
2134             code =
2135                 PromptForTape(LABELOPCODE, TNAME(newLabelPtr), 0,
2136                               labelIfPtr->taskId, tapecount);
2137             if (code)
2138                 ERROR_EXIT(code);
2139         }
2140         interactiveFlag = 1;
2141         tapecount++;
2142
2143         /* mount the tape */
2144         code = butm_Mount(tapeInfoPtr, newLabelPtr->AFSName);
2145         if (code) {
2146             TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
2147             goto newtape;
2148         }
2149
2150         code = butm_ReadLabel(tapeInfoPtr, &oldLabel, 1);       /* will rewind the tape */
2151         if (!code) {
2152             tapeIsLabeled = 1;
2153
2154             if ((strcmp(newLabelPtr->AFSName, "") != 0)
2155                 && (strcmp(oldLabel.pName, "") != 0)) {
2156                 /* We are setting the AFS name, yet tape 
2157                  * has a permanent name (not allowed).
2158                  */
2159                 TLog(taskId, "Can't label. Tape has permanent label '%s'\n",
2160                      oldLabel.pName);
2161                 goto newtape;
2162             }
2163
2164             if (!tapeExpired(&oldLabel)) {
2165                 if (!queryoperator) {
2166                     TLog(taskId, "This tape has not expired\n");
2167                     goto newtape;
2168                 }
2169                 if (Ask("This tape has not expired - proceed") == 0)
2170                     goto newtape;
2171             }
2172
2173             /* Keep the permanent name */
2174             if (strcmp(newLabelPtr->pName, "") == 0) {
2175                 strcpy(newLabelPtr->pName, oldLabel.pName);
2176             } else if (strcmp(newLabelPtr->pName, TC_NULLTAPENAME) == 0) {
2177                 strcpy(newLabelPtr->pName, "");
2178             }
2179         }
2180
2181         /* extract useful information from the old label */
2182         if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2183             newLabelPtr->dumpid = 0;
2184             newLabelPtr->useCount = oldLabel.useCount + 1;
2185         }
2186
2187         /* now write the new label */
2188         code = butm_Create(tapeInfoPtr, newLabelPtr, 1);        /* will rewind the tape */
2189         if (code) {
2190             ErrorLog(0, taskId, code, tapeInfoPtr->error,
2191                      "Can't label tape\n");
2192             goto newtape;
2193         }
2194
2195         break;
2196
2197       newtape:
2198         unmountTape(taskId, tapeInfoPtr);
2199     }
2200
2201     /* delete obsolete information from the database */
2202     if (tapeIsLabeled && oldLabel.structVersion >= TAPE_VERSION_3) {
2203         /* delete based on dump id */
2204         if (oldLabel.dumpid) {
2205             i = bcdb_deleteDump(oldLabel.dumpid, 0, 0, 0);
2206             if (i && (i != BUDB_NOENT))
2207                 ErrorLog(0, taskId, i, 0,
2208                          "Warning: Can't delete old dump %u from database\n",
2209                          oldLabel.dumpid);
2210         }
2211     }
2212
2213   error_exit:
2214     unmountTape(taskId, tapeInfoPtr);
2215     return (code);
2216 }
2217
2218 /* Labeller
2219  *      LWP created by the server stub. Labels the tape with name and size
2220  *      specified by <label>
2221  */
2222
2223 Labeller(labelIfPtr)
2224      struct labelTapeIf *labelIfPtr;
2225 {
2226     struct tc_tapeLabel *label = &labelIfPtr->label;
2227
2228     struct butm_tapeLabel newTapeLabel;
2229     struct butm_tapeInfo tapeInfo;
2230     afs_uint32 taskId;
2231     afs_int32 code = 0;
2232
2233     taskId = labelIfPtr->taskId;
2234     setStatus(taskId, DRIVE_WAIT);
2235     EnterDeviceQueue(deviceLatch);
2236     clearStatus(taskId, DRIVE_WAIT);
2237
2238     printf("\n\n");
2239     TLog(taskId, "Labeltape\n");
2240
2241     memset(&tapeInfo, 0, sizeof(tapeInfo));
2242     tapeInfo.structVersion = BUTM_MAJORVERSION;
2243     code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2244     if (code) {
2245         ErrorLog(0, taskId, code, tapeInfo.error,
2246                  "Can't initialize the tape module\n");
2247         ERROR_EXIT(code);
2248     }
2249
2250     GetNewLabel(&tapeInfo, label->pname, label->afsname, &newTapeLabel);
2251     if (label->size)
2252         newTapeLabel.size = label->size;
2253     else
2254         newTapeLabel.size = globalTapeConfig.capacity;
2255
2256     code = updateTapeLabel(labelIfPtr, &tapeInfo, &newTapeLabel);
2257     if (code)
2258         ERROR_EXIT(code);
2259
2260   error_exit:
2261     if (code == TC_ABORTEDBYREQUEST) {
2262         ErrorLog(0, taskId, 0, 0, "Labeltape: Aborted by request\n");
2263         clearStatus(taskId, ABORT_REQUEST);
2264         setStatus(taskId, ABORT_DONE);
2265     } else if (code) {
2266         ErrorLog(0, taskId, code, 0, "Labeltape: Finished with errors\n");
2267         setStatus(taskId, TASK_ERROR);
2268     } else {
2269         TLog(taskId, "Labelled tape %s size %u Kbytes\n",
2270              TNAME(&newTapeLabel), newTapeLabel.size);
2271     }
2272     setStatus(labelIfPtr->taskId, TASK_DONE);
2273
2274     free(labelIfPtr);
2275     LeaveDeviceQueue(deviceLatch);
2276     return (code);
2277 }
2278
2279 /* PrintTapeLabel
2280  *      print out the tape label.
2281  */
2282
2283 PrintTapeLabel(labelptr)
2284      struct butm_tapeLabel *labelptr;
2285 {
2286     char tapeName[BU_MAXTAPELEN + 32];
2287
2288     printf("Tape label\n");
2289     printf("----------\n");
2290     TAPENAME(tapeName, labelptr->pName, labelptr->dumpid);
2291     printf("permanent tape name = %s\n", tapeName);
2292     TAPENAME(tapeName, labelptr->AFSName, labelptr->dumpid);
2293     printf("AFS tape name = %s\n", tapeName);
2294     printf("creationTime = %s", ctime(&labelptr->creationTime));
2295     if (labelptr->expirationDate)
2296         printf("expirationDate = %s", cTIME(&labelptr->expirationDate));
2297     printf("cell = %s\n", labelptr->cell);
2298     printf("size = %u Kbytes\n", labelptr->size);
2299     printf("dump path = %s\n", labelptr->dumpPath);
2300
2301     if (labelptr->structVersion >= TAPE_VERSION_3) {
2302         printf("dump id = %u\n", labelptr->dumpid);
2303         printf("useCount = %d\n", labelptr->useCount);
2304     }
2305     printf("-- End of tape label --\n\n");
2306 }
2307
2308 /* ReadLabel 
2309  *      Read the label from a tape.
2310  *      Currently prints out a "detailed" summary of the label but passes
2311  *      back only selected fields.
2312  */
2313
2314 ReadLabel(label)
2315      struct tc_tapeLabel *label;
2316 {
2317     struct butm_tapeLabel newTapeLabel;
2318     struct butm_tapeInfo tapeInfo;
2319     afs_uint32 taskId;
2320     Date expir;
2321     afs_int32 code = 0;
2322     int interactiveFlag;
2323     int tapecount = 1;
2324
2325     EnterDeviceQueue(deviceLatch);
2326     taskId = allocTaskId();     /* reqd for lower level rtns */
2327
2328     printf("\n\n");
2329     TLog(taskId, "Readlabel\n");
2330
2331     memset(&tapeInfo, 0, sizeof(tapeInfo));
2332     tapeInfo.structVersion = BUTM_MAJORVERSION;
2333     code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
2334     if (code) {
2335         ErrorLog(0, taskId, code, tapeInfo.error,
2336                  "Can't initialize the tape module\n");
2337         ERROR_EXIT(code);
2338     }
2339     memset(&newTapeLabel, 0, sizeof(newTapeLabel));
2340
2341     interactiveFlag = autoQuery;
2342
2343     while (1) {
2344         if (interactiveFlag) {
2345             code = PromptForTape(READLABELOPCODE, "", 0, taskId, tapecount);
2346             if (code)
2347                 ERROR_EXIT(code);
2348         }
2349         interactiveFlag = 1;
2350         tapecount++;
2351
2352         code = butm_Mount(&tapeInfo, "");
2353         if (code) {
2354             TapeLog(0, taskId, code, tapeInfo.error, "Can't open tape\n");
2355             goto newtape;
2356         }
2357         break;
2358
2359       newtape:
2360         unmountTape(taskId, &tapeInfo);
2361     }
2362
2363     code = butm_ReadLabel(&tapeInfo, &newTapeLabel, 1); /* will rewind the tape */
2364     if (code) {
2365         if (code == BUTM_NOLABEL) {
2366             printf("Tape is unlabelled\n");
2367             ERROR_EXIT(code);
2368         }
2369         ErrorLog(1, taskId, code, tapeInfo.error, "Can't read tape label\n");
2370         ERROR_EXIT(code);
2371     }
2372
2373     /* copy the fields to be passed to the caller */
2374     label->size = newTapeLabel.size;
2375     label->tapeId = newTapeLabel.dumpid;
2376     strcpy(label->afsname, newTapeLabel.AFSName);
2377     strcpy(label->pname, newTapeLabel.pName);
2378
2379
2380     expir = ExpirationDate(newTapeLabel.dumpid);
2381     if (expir)
2382         newTapeLabel.expirationDate = expir;
2383
2384     PrintTapeLabel(&newTapeLabel);
2385
2386   error_exit:
2387     unmountTape(taskId, &tapeInfo);
2388
2389     if (code == TC_ABORTEDBYREQUEST)
2390         ErrorLog(0, taskId, 0, 0, "ReadLabel: Aborted by request\n");
2391     else if (code && (code != BUTM_NOLABEL))
2392         ErrorLog(0, taskId, code, 0, "ReadLabel: Finished with errors\n");
2393     else
2394         TLog(taskId, "ReadLabel: Finished\n");
2395
2396     LeaveDeviceQueue(deviceLatch);
2397     return (code);
2398 }
2399
2400 /* Function to read volume header and trailer structure from tape, taking
2401    into consideration, different word alignment rules.
2402 */
2403 afs_int32
2404 readVolumeHeader(buffer, bufloc, header)
2405      /*in */
2406      char *buffer;              /* buffer to read header from */
2407                                 /*in */ afs_int32 bufloc;
2408                                 /* header's location in buffer */
2409                                                 /*out */ struct volumeHeader *header;
2410                                                 /* header structure */
2411
2412 {
2413     struct volumeHeader vhptr, *tempvhptr;
2414     afs_int32 firstSplice = (afs_int32) & vhptr.pad - (afs_int32) & vhptr;
2415     int padLen = sizeof(vhptr.pad);     /* pad to achieve 4 byte alignment */
2416     int nextSplice = sizeof(struct volumeHeader) - firstSplice - padLen;
2417
2418     /* Four cases are to be handled
2419      * 
2420      * Volume Header (byte alignment)
2421      * -----------------------
2422      * Tape   In Core
2423      * ----   -------
2424      * Case 1:  4       1
2425      * Case 2:  4       4
2426      * Case 3:  1       1
2427      * Case 4:  1       4
2428      * -----------------------
2429      * 
2430      * Case 2 and Case 3 are identical cases and handled the same way.
2431      * Case 1 and Case 4 are separate cases. In one case the pad needs
2432      * to be removed and in the other, it needs to be spliced in. The
2433      * four cases are handled as follows
2434      */
2435     tempvhptr = (struct volumeHeader *)(buffer + bufloc);
2436     if ((strncmp(tempvhptr->preamble, "H++NAME#", 8) == 0)
2437         && (strncmp(tempvhptr->postamble, "T--NAME#", 8) == 0)) {
2438         /* Handle Cases 2 & 3 */
2439         memcpy(&vhptr, buffer + bufloc, sizeof(struct volumeHeader));
2440         HEADER_CHECKS(vhptr, header);
2441
2442         /* Handle Case 4 */
2443         memset(&vhptr, 0, sizeof(struct volumeHeader));
2444         memcpy(&vhptr, buffer + bufloc, firstSplice);
2445         memset(&vhptr.pad, 0, padLen);
2446         memcpy(&vhptr.volumeID, buffer + bufloc + firstSplice, nextSplice);
2447         HEADER_CHECKS(vhptr, header);
2448
2449         /* Handle Case 1 */
2450         memset(&vhptr, 0, sizeof(struct volumeHeader));
2451         memcpy(&vhptr, buffer + bufloc, firstSplice);
2452         memcpy(&vhptr + firstSplice, buffer + bufloc + firstSplice + padLen,
2453                nextSplice);
2454         HEADER_CHECKS(vhptr, header);
2455
2456     }
2457     return (TC_BADVOLHEADER);
2458 }