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