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