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