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