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