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