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