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