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