butc-xbsa-20040713
[openafs.git] / src / butc / tcprocs.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 /* procedures invoked by the rpc stub */
11
12 #include <afsconfig.h>
13 #include <afs/param.h>
14
15 RCSID
16     ("$Header$");
17
18 #include <sys/types.h>
19 #include <errno.h>
20 #ifdef AFS_NT40_ENV
21 #include <winsock2.h>
22 #else
23 #include <sys/file.h>
24 #include <netinet/in.h>
25 #endif
26 #include <rx/xdr.h>
27 #include <rx/rx.h>
28 #include <afs/afsint.h>
29 #include <stdio.h>
30 #include <afs/procmgmt.h>
31 #include <afs/assert.h>
32 #include <afs/prs_fs.h>
33 #include <sys/stat.h>
34 #include <afs/nfs.h>
35 #include <lwp.h>
36 #include <lock.h>
37 #include <afs/auth.h>
38 #include <afs/cellconfig.h>
39 #include <afs/keys.h>
40 #include <ubik.h>
41 #include <afs/tcdata.h>
42 #include "error_macros.h"
43 #include "butc_xbsa.h"
44
45 callPermitted(call)
46      struct rx_call *call;
47 {
48     /* before this code can be used, the rx connection, on the bucoord side, must */
49     /* be changed so that it will set up for token passing instead of using  a    */
50     /* simple rx connection that, below, returns a value of 0 from rx_SecurityClassOf */
51     return 1;
52 }
53
54 /* XBSA Global Parameters */
55 afs_int32 xbsaType;
56 #ifdef xbsa
57 struct butx_transactionInfo butxInfo;
58
59 #define rpc_c_protect_level_default 0
60 afs_uint32 dumpRestAuthnLevel = rpc_c_protect_level_default;
61 char *xbsaObjectOwner;
62 char *appObjectOwner;
63 char *adsmServerName;
64 char *xbsaSecToken;
65 char *xbsalGName;
66 #endif
67
68 /* -------------------------
69  * butc - interface routines - alphabetic order
70  * -------------------------
71  */
72
73 afs_int32
74 STC_LabelTape(acid, label, taskId)
75      struct rx_call *acid;
76      struct tc_tapeLabel *label;
77      afs_uint32 *taskId;
78 {
79 #ifdef AFS_PTHREAD_ENV
80     pthread_t pid;
81     pthread_attr_t tattr;
82     AFS_SIGSET_DECL;
83 #else
84     PROCESS pid;
85 #endif
86     struct labelTapeIf *ptr;
87     statusP statusPtr;
88     afs_int32 code;
89
90     extern int Labeller();
91     extern statusP createStatusNode();
92     extern afs_int32 allocTaskId();
93
94 #ifdef xbsa
95     if (CONF_XBSA)
96         return (TC_BADTASK);    /* LabelTape does not apply if XBSA */
97 #endif
98
99     if (callPermitted(acid) == 0)
100         return (TC_NOTPERMITTED);
101
102     ptr = (struct labelTapeIf *)malloc(sizeof(*ptr));
103     if (!ptr)
104         ERROR_EXIT(TC_NOMEMORY);
105     memcpy(&ptr->label, label, sizeof(ptr->label));
106
107     /* set up the status node */
108     *taskId = allocTaskId();    /* for bucoord */
109     ptr->taskId = *taskId;
110
111     statusPtr = createStatusNode();
112     if (!statusPtr)
113         ERROR_EXIT(TC_INTERNALERROR);
114
115     lock_Status();
116     statusPtr->taskId = *taskId;
117     statusPtr->lastPolled = time(0);
118     statusPtr->flags &= ~STARTING;      /* ok to examine */
119     strncpy(statusPtr->taskName, "Labeltape", sizeof(statusPtr->taskName));
120     unlock_Status();
121
122     /* create the LWP to do the real work behind the scenes */
123 #ifdef AFS_PTHREAD_ENV
124     code = pthread_attr_init(&tattr);
125     if (code)
126         ERROR_EXIT(code);
127
128     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
129     if (code)
130         ERROR_EXIT(code);
131
132     AFS_SIGSET_CLEAR();
133     code = pthread_create(&pid, &tattr, Labeller, ptr);
134     AFS_SIGSET_RESTORE();
135 #else
136     code =
137         LWP_CreateProcess(Labeller, 32768, 1, (void *)ptr, "labeller process",
138                           &pid);
139 #endif
140
141   error_exit:
142     if (code) {
143         if (statusPtr)
144             deleteStatusNode(statusPtr);
145         if (ptr)
146             free(ptr);
147     }
148
149     return (code);
150 }
151
152 /* STC_PerformDump
153  *      Tape coordinator server routine to do a dump
154  */
155
156 afs_int32
157 STC_PerformDump(rxCallId, tcdiPtr, tc_dumpArrayPtr, taskId)
158      struct rx_call *rxCallId;
159      struct tc_dumpInterface *tcdiPtr;
160      tc_dumpArray *tc_dumpArrayPtr;
161      afs_int32 *taskId;
162 {
163     struct dumpNode *newNode = 0;
164     statusP statusPtr = 0;
165 #ifdef AFS_PTHREAD_ENV
166     pthread_t pid;
167     pthread_attr_t tattr;
168     AFS_SIGSET_DECL;
169 #else
170     PROCESS pid;
171 #endif
172     afs_int32 code = 0;
173
174     extern statusP createStatusNode();
175     extern Dumper();
176
177     if (callPermitted(rxCallId) == 0)
178         return (TC_NOTPERMITTED);
179
180     /* should be verifying parameter validity */
181     *taskId = 0;
182
183     /* this creates a node in list, alots an id for it and prepares it for locking */
184     CreateNode(&newNode);
185
186     /*set up the parameters in the node, to be used by LWP */
187     strcpy(newNode->dumpSetName, tcdiPtr->dumpName);
188
189     newNode->dumpName = (char *)malloc(strlen(tcdiPtr->dumpPath) + 1);
190     strcpy(newNode->dumpName, tcdiPtr->dumpPath);
191
192     newNode->volumeSetName =
193         (char *)malloc(strlen(tcdiPtr->volumeSetName) + 1);
194     strcpy(newNode->volumeSetName, tcdiPtr->volumeSetName);
195
196     CopyTapeSetDesc(&(newNode->tapeSetDesc), &tcdiPtr->tapeSet);
197
198     newNode->dumps = (struct tc_dumpDesc *)
199         malloc(sizeof(struct tc_dumpDesc) *
200                tc_dumpArrayPtr->tc_dumpArray_len);
201     newNode->arraySize = tc_dumpArrayPtr->tc_dumpArray_len;
202     CopyDumpDesc(newNode->dumps, tc_dumpArrayPtr);
203
204     newNode->parent = tcdiPtr->parentDumpId;
205     newNode->level = tcdiPtr->dumpLevel;
206     newNode->doAppend = tcdiPtr->doAppend;
207 #ifdef xbsa
208     if (CONF_XBSA)
209         newNode->doAppend = 0;  /* Append flag is ignored if talking to XBSA */
210 #endif
211
212     /* create the status node */
213     statusPtr = createStatusNode();
214     if (!statusPtr)
215         ERROR_EXIT(TC_INTERNALERROR);
216
217     lock_Status();
218     statusPtr->taskId = newNode->taskID;
219     statusPtr->lastPolled = time(0);
220     statusPtr->flags &= ~STARTING;      /* ok to examine */
221     strncpy(statusPtr->taskName, "Dump", sizeof(statusPtr->taskName));
222     unlock_Status();
223
224     newNode->statusNodePtr = statusPtr;
225
226     /* create the LWP to do the real work behind the scenes */
227 #ifdef AFS_PTHREAD_ENV
228     code = pthread_attr_init(&tattr);
229     if (code)
230         ERROR_EXIT(code);
231
232     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
233     if (code)
234         ERROR_EXIT(code);
235
236     AFS_SIGSET_CLEAR();
237     code = pthread_create(&pid, &tattr, Dumper, newNode);
238     AFS_SIGSET_RESTORE();
239 #else
240     code =
241         LWP_CreateProcess(Dumper, 32768, 1, (void *)newNode, "dumper process",
242                           &pid);
243 #endif
244     if (code)
245         ERROR_EXIT(code);
246
247     *taskId = newNode->taskID;
248
249   error_exit:
250     if (code) {
251         if (statusPtr)
252             deleteStatusNode(statusPtr);
253         FreeNode(newNode->taskID);      /*  failed to create LWP to do the dump. */
254     }
255
256     return (code);
257 }
258
259 afs_int32
260 STC_PerformRestore(acid, dumpSetName, arestores, taskID)
261      struct rx_call *acid;
262      char *dumpSetName;         /* not used */
263      tc_restoreArray *arestores;
264      afs_int32 *taskID;
265 {
266     struct dumpNode *newNode;
267     statusP statusPtr;
268     afs_int32 code = 0;
269 #ifdef AFS_PTHREAD_ENV
270     pthread_t pid;
271     pthread_attr_t tattr;
272     AFS_SIGSET_DECL;
273 #else
274     PROCESS pid;
275 #endif
276
277     extern int Restorer();
278     extern statusP createStatusNode();
279
280     if (callPermitted(acid) == 0)
281         return (TC_NOTPERMITTED);
282
283     /* should  verify parameter validity */
284
285     /* this creates a node in list, alots an id for it and prepares it for locking */
286     CreateNode(&newNode);
287
288     newNode->restores = (struct tc_restoreDesc *)
289         malloc(sizeof(struct tc_restoreDesc) *
290                arestores->tc_restoreArray_len);
291     newNode->arraySize = arestores->tc_restoreArray_len;
292     CopyRestoreDesc(newNode->restores, arestores);
293     *taskID = newNode->taskID;
294
295     /* should log the intent */
296
297     /* create the status node */
298     statusPtr = createStatusNode();
299     if (!statusPtr)
300         ERROR_EXIT(TC_INTERNALERROR);
301
302     lock_Status();
303     statusPtr->taskId = newNode->taskID;
304     statusPtr->flags &= ~STARTING;      /* ok to examine */
305     statusPtr->lastPolled = time(0);
306     strncpy(statusPtr->taskName, "Restore", sizeof(statusPtr->taskName));
307     unlock_Status();
308
309     newNode->statusNodePtr = statusPtr;
310
311     /* create the LWP to do the real work behind the scenes */
312 #ifdef AFS_PTHREAD_ENV
313     code = pthread_attr_init(&tattr);
314     if (code)
315         ERROR_EXIT(code);
316
317     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
318     if (code)
319         ERROR_EXIT(code);
320
321     AFS_SIGSET_CLEAR();
322     code = pthread_create(&pid, &tattr, Restorer, newNode);
323     AFS_SIGSET_RESTORE();
324 #else
325     code =
326         LWP_CreateProcess(Restorer, 65368, 1, (void *)newNode,
327                           "restorer process", &pid);
328 #endif
329
330   error_exit:
331     if (code) {
332         if (statusPtr)
333             deleteStatusNode(statusPtr);
334         FreeNode(newNode->taskID);      /*  failed to create LWP to do the dump. */
335     }
336
337     return (code);
338 }
339
340 afs_int32
341 STC_ReadLabel(acid, label, taskId)
342      struct rx_call *acid;
343      struct tc_tapeLabel *label;
344      afs_uint32 *taskId;
345 {
346     afs_int32 code;
347
348     extern int ReadLabel();
349
350 #ifdef xbsa
351     if (CONF_XBSA)
352         return (TC_BADTASK);    /* ReadLabel does not apply if XBSA */
353 #endif
354
355     if (callPermitted(acid) == 0)
356         return (TC_NOTPERMITTED);
357
358     code = ReadLabel(label);    /* Synchronous */
359     return code;
360 }
361
362 /* STC_RestoreDb
363  *      restore the backup database from tape
364  */
365
366 afs_int32
367 STC_RestoreDb(rxCall, taskId)
368      struct rx_call *rxCall;
369      afs_uint32 *taskId;
370 {
371 #ifdef AFS_PTHREAD_ENV
372     pthread_t pid;
373     pthread_attr_t tattr;
374     AFS_SIGSET_DECL;
375 #else
376     PROCESS pid;
377 #endif
378     statusP statusPtr;
379     afs_int32 code = 0;
380
381     extern afs_int32 restoreDbFromTape();
382     extern statusP createStatusNode();
383     extern afs_int32 allocTaskId();
384
385 #ifdef xbsa
386     if (CONF_XBSA)
387         return (TC_BADTASK);    /* LabelTape does not apply if XBSA */
388 #endif
389
390     if (callPermitted(rxCall) == 0)
391         return (TC_NOTPERMITTED);
392
393     *taskId = allocTaskId();
394
395     /* create the status node */
396     statusPtr = createStatusNode();
397     if (!statusPtr)
398         ERROR_EXIT(TC_INTERNALERROR);
399
400     lock_Status();
401     statusPtr->taskId = *taskId;
402     statusPtr->flags &= ~STARTING;      /* ok to examine */
403     statusPtr->lastPolled = time(0);
404     strncpy(statusPtr->taskName, "RestoreDb", sizeof(statusPtr->taskName));
405     unlock_Status();
406
407 #ifdef AFS_PTHREAD_ENV
408     code = pthread_attr_init(&tattr);
409     if (code)
410         ERROR_EXIT(code);
411
412     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
413     if (code)
414         ERROR_EXIT(code);
415
416     AFS_SIGSET_CLEAR();
417     code = pthread_create(&pid, &tattr, restoreDbFromTape, (void *)*taskId);
418     AFS_SIGSET_RESTORE();
419 #else
420     code =
421         LWP_CreateProcess(restoreDbFromTape, 32768, 1, (void *)*taskId,
422                           "Db restore", &pid);
423 #endif
424
425   error_exit:
426     if (code) {
427         if (statusPtr)
428             deleteStatusNode(statusPtr);
429     }
430
431     return (code);
432 }
433
434 /* STC_SaveDb
435  *      restore the backup database from tape
436  */
437
438 afs_int32
439 STC_SaveDb(rxCall, archiveTime, taskId)
440      struct rx_call *rxCall;
441      Date archiveTime;
442      afs_uint32 *taskId;
443 {
444 #ifdef AFS_PTHREAD_ENV
445     pthread_t pid;
446     pthread_attr_t tattr;
447     AFS_SIGSET_DECL;
448 #else
449     PROCESS pid;
450 #endif
451     statusP statusPtr;
452     afs_int32 code = 0;
453     struct saveDbIf *ptr;
454
455     extern afs_int32 saveDbToTape();
456     extern statusP createStatusNode();
457     extern afs_int32 allocTaskId();
458
459 #ifdef xbsa
460     if (CONF_XBSA)
461         return (TC_BADTASK);    /* LabelTape does not apply if XBSA */
462 #endif
463
464     if (callPermitted(rxCall) == 0)
465         return (TC_NOTPERMITTED);
466
467     *taskId = allocTaskId();
468
469     ptr = (struct saveDbIf *)malloc(sizeof(struct saveDbIf));
470     if (!ptr)
471         ERROR_EXIT(TC_NOMEMORY);
472     ptr->archiveTime = archiveTime;
473     ptr->taskId = *taskId;
474
475     /* create the status node */
476     statusPtr = createStatusNode();
477     if (!statusPtr)
478         ERROR_EXIT(TC_INTERNALERROR);
479
480     lock_Status();
481     statusPtr->taskId = *taskId;
482     statusPtr->lastPolled = time(0);
483     statusPtr->flags &= ~STARTING;      /* ok to examine */
484     strncpy(statusPtr->taskName, "SaveDb", sizeof(statusPtr->taskName));
485     unlock_Status();
486
487     ptr->statusPtr = statusPtr;
488
489 #ifdef AFS_PTHREAD_ENV
490     code = pthread_attr_init(&tattr);
491     if (code)
492         ERROR_EXIT(code);
493
494     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
495     if (code)
496         ERROR_EXIT(code);
497
498     AFS_SIGSET_CLEAR();
499     code = pthread_create(&pid, &tattr, saveDbToTape, ptr);
500     AFS_SIGSET_RESTORE();
501 #else
502     code = LWP_CreateProcess(saveDbToTape, 32768, 1, ptr, "Db save", &pid);
503 #endif
504
505   error_exit:
506     if (code) {
507         if (statusPtr)
508             deleteStatusNode(statusPtr);
509         if (ptr)
510             free(ptr);
511     }
512
513     return (code);
514 }
515
516
517 /* STC_ScanDumps
518  *      read a dump (maybe more than one tape), and print out a summary
519  *      of its contents. If the flag is set, add to the database.
520  * entry:
521  *      addDbFlag - if set, the information will be added to the database
522  */
523
524 afs_int32
525 STC_ScanDumps(acid, addDbFlag, taskId)
526      struct rx_call *acid;
527      afs_int32 addDbFlag;
528      afs_uint32 *taskId;
529 {
530 #ifdef AFS_PTHREAD_ENV
531     pthread_t pid;
532     pthread_attr_t tattr;
533     AFS_SIGSET_DECL;
534 #else
535     PROCESS pid;
536 #endif
537     struct scanTapeIf *ptr;
538     statusP statusPtr;
539     afs_int32 code = 0;
540
541     extern afs_int32 ScanDumps();
542     extern afs_int32 allocTaskId();
543     extern statusP createStatusNode();
544
545 #ifdef xbsa
546     if (CONF_XBSA)
547         return (TC_BADTASK);    /* ScanDumps does not apply if XBSA */
548 #endif
549
550     if (callPermitted(acid) == 0)
551         return (TC_NOTPERMITTED);
552
553     *taskId = allocTaskId();
554
555     ptr = (struct scanTapeIf *)malloc(sizeof(*ptr));
556     if (!ptr)
557         ERROR_EXIT(TC_NOMEMORY);
558     ptr->addDbFlag = addDbFlag;
559     ptr->taskId = *taskId;
560
561     /* create the status node */
562     statusPtr = createStatusNode();
563     if (!statusPtr)
564         ERROR_EXIT(TC_INTERNALERROR);
565
566     lock_Status();
567     statusPtr->taskId = *taskId;
568     statusPtr->lastPolled = time(0);
569     statusPtr->flags &= ~STARTING;      /* ok to examine */
570     strncpy(statusPtr->taskName, "Scantape", sizeof(statusPtr->taskName));
571     unlock_Status();
572
573 #ifdef AFS_PTHREAD_ENV
574     code = pthread_attr_init(&tattr);
575     if (code)
576         ERROR_EXIT(code);
577
578     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
579     if (code)
580         ERROR_EXIT(code);
581
582     AFS_SIGSET_CLEAR();
583     code = pthread_create(&pid, &tattr, ScanDumps, ptr);
584     AFS_SIGSET_RESTORE();
585 #else
586     code =
587         LWP_CreateProcess(ScanDumps, 32768, 1, ptr, "scandump process", &pid);
588 #endif
589
590   error_exit:
591     if (code) {
592         if (statusPtr)
593             deleteStatusNode(statusPtr);
594         if (ptr)
595             free(ptr);
596     }
597
598     return code;
599 }
600
601 /* STC_TCInfo
602  *      return information about the tape coordinator. Currently this
603  *      is just the version number of the interface
604  */
605
606 afs_int32
607 STC_TCInfo(acid, tciptr)
608      struct rx_call *acid;
609      struct tc_tcInfo *tciptr;
610 {
611     if (callPermitted(acid) == 0)
612         return (TC_NOTPERMITTED);
613
614     tciptr->tcVersion = CUR_BUTC_VERSION;
615     return (0);
616 }
617
618 /* STC_DeleteDump
619  */
620 afs_int32
621 STC_DeleteDump(acid, dumpID, taskId)
622      struct rx_call *acid;
623      afs_uint32 dumpID;
624      afs_uint32 *taskId;
625 {
626     struct deleteDumpIf *ptr = 0;
627     statusP statusPtr = 0;
628     afs_int32 code = TC_BADTASK;        /* If not compiled -Dxbsa then fail */
629 #ifdef xbsa
630 #ifdef AFS_PTHREAD_ENV
631     pthread_t pid;
632     pthread_attr_t tattr;
633     AFS_SIGSET_DECL;
634 #else
635     PROCESS pid;
636 #endif
637 #endif
638     extern afs_int32 DeleteDump();
639     extern statusP createStatusNode();
640     extern afs_int32 allocTaskId();
641
642     *taskId = 0;
643     if (!CONF_XBSA)
644         return (TC_BADTASK);    /* Only do if butc is started as XBSA */
645
646 #ifdef xbsa
647     code = 0;
648     if (callPermitted(acid) == 0)
649         return (TC_NOTPERMITTED);
650
651     ptr = (struct deleteDumpIf *)malloc(sizeof(*ptr));
652     if (!ptr)
653         ERROR_EXIT(TC_NOMEMORY);
654
655     *taskId = allocTaskId();
656     ptr->dumpID = dumpID;
657     ptr->taskId = *taskId;
658
659     statusPtr = createStatusNode();
660     if (!statusPtr)
661         ERROR_EXIT(TC_INTERNALERROR);
662
663     lock_Status();
664     statusPtr->taskId = *taskId;
665     statusPtr->lastPolled = time(0);
666     statusPtr->flags &= ~STARTING;
667     strncpy(statusPtr->taskName, "DeleteDump", sizeof(statusPtr->taskName));
668     unlock_Status();
669
670 #ifdef AFS_PTHREAD_ENV
671     code = pthread_attr_init(&tattr);
672     if (code)
673         ERROR_EXIT(code);
674
675     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
676     if (code)
677         ERROR_EXIT(code);
678
679     AFS_SIGSET_CLEAR();
680     code = pthread_create(&pid, &tattr, DeleteDump, ptr);
681     AFS_SIGSET_RESTORE();
682 #else
683     code =
684         LWP_CreateProcess(DeleteDump, 32768, 1, ptr, "deletedump process",
685                           &pid);
686 #endif
687
688   error_exit:
689     if (code) {
690         if (statusPtr)
691             deleteStatusNode(statusPtr);
692         if (ptr)
693             free(ptr);
694     }
695 #endif /* xbsa */
696
697     return (code);
698 }
699
700 /* -----------------------------
701  * misc. routines
702  * -----------------------------
703  */
704
705 static
706 CopyDumpDesc(toDump, fromDump)
707      struct tc_dumpDesc *toDump;
708      tc_dumpArray *fromDump;
709 {
710     struct tc_dumpDesc *toPtr, *fromPtr;
711     int i;
712
713     toPtr = toDump;
714     fromPtr = fromDump->tc_dumpArray_val;
715     for (i = 0; i < fromDump->tc_dumpArray_len; i++) {
716         toPtr->vid = fromPtr->vid;
717         toPtr->vtype = fromPtr->vtype;
718         toPtr->partition = fromPtr->partition;
719         toPtr->date = fromPtr->date;
720         toPtr->cloneDate = fromPtr->cloneDate;
721         toPtr->hostAddr = fromPtr->hostAddr;
722         strcpy(toPtr->name, fromPtr->name);
723         fromPtr++;
724         toPtr++;
725     }
726     return 0;
727 }
728
729
730 static
731 CopyRestoreDesc(toRestore, fromRestore)
732      struct tc_restoreDesc *toRestore;
733      tc_restoreArray *fromRestore;
734 {
735     struct tc_restoreDesc *toPtr, *fromPtr;
736     int i;
737
738     toPtr = toRestore;
739     fromPtr = fromRestore->tc_restoreArray_val;
740     for (i = 0; i < fromRestore->tc_restoreArray_len; i++) {
741         toPtr->flags = fromPtr->flags;
742         toPtr->position = fromPtr->position;
743         strcpy(toPtr->tapeName, fromPtr->tapeName);
744         toPtr->dbDumpId = fromPtr->dbDumpId;
745         toPtr->initialDumpId = fromPtr->initialDumpId;
746         toPtr->origVid = fromPtr->origVid;
747         toPtr->vid = fromPtr->vid;
748         toPtr->partition = fromPtr->partition;
749         toPtr->dumpLevel = fromPtr->dumpLevel;
750         toPtr->hostAddr = fromPtr->hostAddr;
751         strcpy(toPtr->newName, fromPtr->newName);
752         strcpy(toPtr->oldName, fromPtr->oldName);
753         fromPtr++;
754         toPtr++;
755
756     }
757     return 0;
758 }
759
760 static
761 CopyTapeSetDesc(toPtr, fromPtr)
762      struct tc_tapeSet *toPtr, *fromPtr;
763 {
764
765     toPtr->id = fromPtr->id;
766     toPtr->maxTapes = fromPtr->maxTapes;
767     toPtr->a = fromPtr->a;
768     toPtr->b = fromPtr->b;
769     strcpy(toPtr->tapeServer, fromPtr->tapeServer);
770     strcpy(toPtr->format, fromPtr->format);
771
772     toPtr->expDate = fromPtr->expDate;
773     toPtr->expType = fromPtr->expType;
774     return 0;
775 }