openafs-kill-dead-code-20050403
[openafs.git] / src / bucoord / dump.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 /*
11  * ALL RIGHTS RESERVED
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17 RCSID
18     ("$Header$");
19
20 #include <sys/types.h>
21 #include <afs/cmd.h>
22 #ifdef AFS_NT40_ENV
23 #include <winsock2.h>
24 #else
25 #include <sys/param.h>
26 #include <strings.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <netdb.h>
30 #include <sys/time.h>
31 #endif
32 #include <lwp.h>
33 #include <rx/rx.h>
34 #include <afs/bubasics.h>
35 #include <afs/butc.h>
36 #include <afs/com_err.h>
37 #include <lock.h>               /* for checking TC_ABORTFAILED. PA */
38 #include <afs/tcdata.h>         /* for checking TC_ABORTFAILED. PA */
39 #include <afs/butc.h>
40
41 #include "bc.h"
42 #include "error_macros.h"
43
44 struct bc_dumpTask bc_dumpTasks[BC_MAXSIMDUMPS];
45
46 extern char *bc_CopyString();
47 extern void bc_HandleMisc();
48 extern char *whoami;
49 extern char *tailCompPtr();
50 extern statusP createStatusNode();
51 extern afs_int32 bc_jobNumber();
52
53 extern afs_int32 lastTaskCode;
54
55 #define HOSTADDR(sockaddr) (sockaddr)->sin_addr.s_addr
56
57 /* bc_Dumper
58  *      called (indirectly) to make a dump
59  * entry:
60  *      aindex - index into dumpTask array, contains all the information 
61  *               relevant to the dump
62  */
63 bc_Dumper(aindex)
64 {
65     struct rx_connection *tconn;
66     register struct bc_volumeDump *tde;
67     afs_int32 count, port;
68     struct tc_dumpDesc *volDesc = 0;
69     struct tc_dumpArray volArray;
70     char *baseNamePtr;
71     statusP statusPtr;
72
73     struct tc_dumpInterface dumpInterface;
74     struct tc_dumpInterface *tcdiPtr = &dumpInterface;
75     register struct bc_dumpTask *dumpTaskPtr;
76
77     register afs_int32 code = 0;
78
79     dumpTaskPtr = &bc_dumpTasks[aindex];
80
81     if (!dumpTaskPtr->portOffset || (dumpTaskPtr->portCount == 0))
82         port = 0;
83     else
84         port = dumpTaskPtr->portOffset[0];
85
86     code = ConnectButc(dumpTaskPtr->config, port, &tconn);
87     if (code)
88         return (code);
89
90     /* count number of volumes to be dumped and
91      * build array of volumes to be sent to backup system 
92      */
93     for (count = 0, tde = dumpTaskPtr->volumes; tde;
94          tde = tde->next, count++);
95     volDesc =
96         (struct tc_dumpDesc *)malloc(count * sizeof(struct tc_dumpDesc));
97     if (!volDesc) {
98         com_err(whoami, BC_NOMEM, "");
99         ERROR(BC_NOMEM);
100     }
101
102     for (count = 0, tde = dumpTaskPtr->volumes; tde; tde = tde->next, count++) {
103         strcpy(volDesc[count].name, tde->name);
104         volDesc[count].vid = tde->vid;
105         volDesc[count].vtype = tde->volType;
106         volDesc[count].partition = tde->partition;
107         volDesc[count].hostAddr = HOSTADDR(&tde->server);       /* the internet address */
108         volDesc[count].date = tde->date;
109         volDesc[count].cloneDate = tde->cloneDate;      /* Not yet known */
110     }
111
112     volArray.tc_dumpArray_len = count;  /* element count */
113     volArray.tc_dumpArray_val = volDesc;        /* and data */
114
115     baseNamePtr = tailCompPtr(dumpTaskPtr->dumpName);
116
117     /* setup the interface structure */
118     memset(tcdiPtr, 0, sizeof(*tcdiPtr));
119
120     /* general */
121     strcpy(tcdiPtr->dumpPath, dumpTaskPtr->dumpName);
122     strcpy(tcdiPtr->volumeSetName, dumpTaskPtr->volSetName);
123
124     /* tapeset */
125     strcpy(tcdiPtr->tapeSet.format, dumpTaskPtr->volSetName);
126     strcat(tcdiPtr->tapeSet.format, ".");
127     strcat(tcdiPtr->tapeSet.format, baseNamePtr);
128     strcat(tcdiPtr->tapeSet.format, ".%d");
129     tcdiPtr->tapeSet.a = 1;
130     tcdiPtr->tapeSet.b = 1;
131     tcdiPtr->tapeSet.maxTapes = 1000000000;
132     tcdiPtr->tapeSet.expDate = dumpTaskPtr->expDate;    /* PA */
133     tcdiPtr->tapeSet.expType = dumpTaskPtr->expType;
134
135     /* construct dump set name */
136     strcpy(tcdiPtr->dumpName, dumpTaskPtr->volSetName);
137     strcat(tcdiPtr->dumpName, ".");
138     strcat(tcdiPtr->dumpName, baseNamePtr);
139
140     tcdiPtr->parentDumpId = dumpTaskPtr->parentDumpID;
141     tcdiPtr->dumpLevel = dumpTaskPtr->dumpLevel;
142     tcdiPtr->doAppend = dumpTaskPtr->doAppend;
143
144     /* start the dump on the tape coordinator */
145     printf("Starting dump\n");
146     code = TC_PerformDump(tconn, tcdiPtr, &volArray, &dumpTaskPtr->dumpID);
147     if (code) {
148         com_err(whoami, code, "; Failed to start dump");
149         ERROR(code);
150     }
151
152     com_err(whoami, 0, "Task %u: Dump (%s)", dumpTaskPtr->dumpID,
153             tcdiPtr->dumpName);
154
155     /* create status monitor block */
156     statusPtr = createStatusNode();
157     lock_Status();
158     statusPtr->taskId = dumpTaskPtr->dumpID;
159     statusPtr->port = port;
160     statusPtr->jobNumber = bc_jobNumber();
161     statusPtr->volsTotal = volArray.tc_dumpArray_len;
162     statusPtr->flags &= ~STARTING;
163     sprintf(statusPtr->taskName, "Dump (%s.%s)", dumpTaskPtr->volSetName,
164             baseNamePtr);
165     unlock_Status();
166
167   error_exit:
168     /* locally allocated resources */
169     if (volDesc)
170         free(volDesc);
171
172     if (tconn)
173         rx_DestroyConnection(tconn);
174
175     return (code);
176 }
177
178 /* freeDumpTaskVolumeList
179  *      free the list of volumes used for dumps
180  */
181
182 freeDumpTaskVolumeList(vdptr)
183      struct bc_volumeDump *vdptr;
184 {
185     struct bc_volumeDump *nextVdPtr;
186
187     while (vdptr != 0) {
188         nextVdPtr = vdptr->next;
189
190         if (vdptr->name)
191             free(vdptr->name);
192         free(vdptr);
193
194         vdptr = nextVdPtr;
195     }
196 }
197
198 /* bc_DmpRstStart
199  *     The other half of the dump/restore create process call. In bc_StartDmpRst, 
200  *     we allocated a dumpTask entry. Here we do the task and then free the entry.
201  */
202 bc_DmpRstStart(aindex)
203      afs_int32 aindex;
204 {
205     register struct bc_dumpTask *tdump;
206     register afs_int32 code;
207
208     tdump = &bc_dumpTasks[aindex];
209
210     code = (tdump->callProc) (aindex);
211     if (code)
212         lastTaskCode = code;
213
214     /* Cleanup allocated data structures */
215     freeDumpTaskVolumeList(tdump->volumes);
216     tdump->dumpID = 0;
217     if (tdump->dumpName)
218         free(tdump->dumpName);
219     if (tdump->newExt)
220         free(tdump->newExt);
221     if (tdump->volSetName)
222         free(tdump->volSetName);
223     if (tdump->portOffset)
224         free(tdump->portOffset);
225     tdump->flags &= ~BC_DI_INUSE;
226
227     return code;
228 }
229
230 /* bc_StartDmpRst
231  *      function to start dump running. Packages the relevant information
232  *      (from params) into any free dumpTask structure (globally allocated),
233  *      and then invokes bc_DmpRstStart to do the work, passing it a single 
234  *      parameter, the index into the dumpTask array.
235  *
236  * entry:
237  *      aconfig - normally is bc_globalConfig
238  *      aproc - bc_Dumper for doing dumps
239  *              bc_Restorer for doing restores
240  */
241
242 bc_StartDmpRst(aconfig, adname, avname, avolsToDump, adestServer,
243                adestPartition, afromDate, anewExt, aoldFlag, aparent, alevel,
244                aproc, ports, portCount, dsptr, append, dontExecute)
245      struct bc_config *aconfig;
246      char *adname;
247      char *avname;
248      struct bc_volumeDump *avolsToDump;
249      struct sockaddr_in *adestServer;
250      afs_int32 adestPartition;
251      afs_int32 afromDate;
252      char *anewExt;
253      int aoldFlag;
254      afs_int32 aparent, alevel;
255      int (*aproc) ();
256      afs_int32 *ports;
257      afs_int32 portCount;
258      struct bc_dumpSchedule *dsptr;
259      int append, dontExecute;
260 {
261     register int i;
262     register afs_int32 code;
263     char *junk;
264
265     for (i = 0; i < BC_MAXSIMDUMPS; i++)
266         if (!(bc_dumpTasks[i].flags & BC_DI_INUSE))
267             break;
268
269     if (i >= BC_MAXSIMDUMPS) {
270         com_err(whoami, BC_NOTLOCKED,
271                 "All of the dump/restore slots are in use, try again later");
272         return (BC_NOTLOCKED);
273     }
274
275     memset(&bc_dumpTasks[i], 0, sizeof(struct bc_dumpTask));
276     bc_dumpTasks[i].callProc = aproc;
277     bc_dumpTasks[i].config = aconfig;
278     bc_dumpTasks[i].volumes = avolsToDump;
279     bc_dumpTasks[i].flags = BC_DI_INUSE;
280     bc_dumpTasks[i].dumpName = bc_CopyString(adname);
281     bc_dumpTasks[i].volSetName = bc_CopyString(avname);
282     bc_dumpTasks[i].newExt = bc_CopyString(anewExt);
283     bc_dumpTasks[i].dumpLevel = alevel;
284     bc_dumpTasks[i].parentDumpID = aparent;
285     bc_dumpTasks[i].oldFlag = aoldFlag;
286     bc_dumpTasks[i].fromDate = afromDate;
287     bc_dumpTasks[i].destPartition = adestPartition;
288     bc_dumpTasks[i].portOffset = ports;
289     bc_dumpTasks[i].portCount = portCount;
290     bc_dumpTasks[i].doAppend = append;
291     bc_dumpTasks[i].dontExecute = dontExecute;
292
293     if (dsptr) {
294         /* This should be specified for dumps, but will be 0 for restores */
295         bc_dumpTasks[i].expDate = dsptr->expDate;
296         bc_dumpTasks[i].expType = dsptr->expType;
297     }
298     if (adestServer)
299         memcpy(&bc_dumpTasks[i].destServer, adestServer,
300                sizeof(struct sockaddr_in));
301     else
302         memset(&bc_dumpTasks[i].destServer, 0, sizeof(struct sockaddr_in));
303
304     code =
305         LWP_CreateProcess(bc_DmpRstStart, 20480, LWP_NORMAL_PRIORITY,
306                           (void *)i, "helper", &junk);
307     if (code) {
308         bc_HandleMisc(code);
309         com_err(whoami, code, "; Can't start thread");
310
311         /* Cleanup allocated data structures */
312         freeDumpTaskVolumeList(bc_dumpTasks[i].volumes);
313         bc_dumpTasks[i].dumpID = 0;
314         if (bc_dumpTasks[i].dumpName)
315             free(bc_dumpTasks[i].dumpName);
316         if (bc_dumpTasks[i].newExt)
317             free(bc_dumpTasks[i].newExt);
318         if (bc_dumpTasks[i].volSetName)
319             free(bc_dumpTasks[i].volSetName);
320         if (bc_dumpTasks[i].portOffset)
321             free(bc_dumpTasks[i].portOffset);
322         bc_dumpTasks[i].flags &= ~BC_DI_INUSE;
323         return (code);
324     }
325
326     return 0;
327 }
328
329 #ifdef notdef
330 /* bc_FindDumpSlot
331  *      Returns the dump slot of the dump with dumpID
332  * entry:
333  *      dumpID - id to look for
334  *      port - portoffset for tape coordinator
335  * exit:
336  *      0-n - i.e. 0 or positive number, is the dump slot
337  *      -1 - failed to find dumpID
338  */
339
340 afs_int32
341 bc_FindDumpSlot(dumpID, port)
342      afs_int32 dumpID;
343      afs_int32 port;
344 {
345     int i;
346
347     for (i = 0; i < BC_MAXSIMDUMPS; i++) {
348         if ((bc_dumpTasks[i].flags & BC_DI_INUSE)
349             && (bc_dumpTasks[i].dumpID == dumpID)
350             && ((afs_int32) bc_dumpTasks[i].portOffset == port)) {
351             return (i);
352         }
353     }
354     return (-1);
355 }
356 #endif
357
358 /* bc_LabelTape
359  *      opens a connection to the tape coordinator and requests that it
360  *      label a tape
361  */
362
363 bc_LabelTape(afsname, pname, size, config, port)
364      char *afsname, *pname;
365      struct bc_config *config;
366      afs_int32 port;
367      afs_int32 size;
368 {
369     struct rx_connection *tconn;
370     afs_int32 code = 0;
371     struct tc_tapeLabel label;
372     statusP statusPtr;
373     afs_uint32 taskId;
374
375     code = ConnectButc(config, port, &tconn);
376     if (code)
377         return (code);
378
379     memset(&label, 0, sizeof(label));
380     if (afsname)
381         strcpy(label.afsname, afsname);
382     if (pname)
383         strcpy(label.pname, (strcmp(pname, "") ? pname : "<NULL>"));
384     label.size = size;
385
386     code = TC_LabelTape(tconn, &label, &taskId);
387     if (code) {
388         com_err(whoami, code, "; Failed to start labeltape");
389         return (code);
390     }
391
392     /* create status monitor block */
393     statusPtr = createStatusNode();
394     lock_Status();
395     statusPtr->taskId = taskId;
396     statusPtr->port = port;
397     statusPtr->jobNumber = bc_jobNumber();
398     /* statusPtr->flags    |= SILENT; *//* don't report termination */
399     statusPtr->flags &= ~STARTING;      /* ok to examine */
400
401     sprintf(statusPtr->taskName, "Labeltape (%s)",
402             (pname ? pname : (afsname ? afsname : "<NULL>")));
403     unlock_Status();
404
405     return 0;
406 }
407
408 /* bc_ReadLabel
409  *      open a connection to the tape coordinator and read the label on
410  *      a tape
411  */
412
413 bc_ReadLabel(config, port)
414      struct bc_config *config;
415      afs_int32 port;
416 {
417     struct rx_connection *tconn;
418     struct tc_tapeLabel label;
419     afs_uint32 taskId;
420     afs_int32 code = 0;
421     char *tname = 0;
422
423     code = ConnectButc(config, port, &tconn);
424     if (code)
425         return (code);
426
427     memset(&label, 0, sizeof(label));
428     code = TC_ReadLabel(tconn, &label, &taskId);
429     if (code) {
430         if (code == BUTM_NOLABEL) {
431             printf("Tape read was unlabelled\n");
432             return 0;
433         }
434         com_err(whoami, code, "; Failed to start readlabel");
435         return (code);
436     }
437
438     if (strcmp(label.pname, ""))
439         tname = label.pname;
440     else if (strcmp(label.afsname, ""))
441         tname = label.afsname;
442
443     if (!tname) {
444         printf("Tape read was labelled : <NULL>  size : %u\n", label.size);
445     } else if (!label.tapeId) {
446         printf("Tape read was labelled : %s size : %lu Kbytes\n", tname,
447                label.size);
448     } else {
449         printf("Tape read was labelled : %s (%lu) size : %lu Kbytes\n", tname,
450                label.tapeId, label.size);
451     }
452
453     return 0;
454 }
455
456 bc_ScanDumps(config, dbAddFlag, port)
457      struct bc_config *config;
458      afs_int32 dbAddFlag;
459      afs_int32 port;
460 {
461     struct rx_connection *tconn;
462     statusP statusPtr;
463     afs_uint32 taskId;
464     afs_int32 code = 0;
465
466     code = ConnectButc(config, port, &tconn);
467     if (code)
468         return (code);
469
470     code = TC_ScanDumps(tconn, dbAddFlag, &taskId);
471     if (code) {
472         com_err(whoami, code, "; Failed to start scantape");
473         return (code);
474     }
475
476     /* create status monitor block */
477     statusPtr = createStatusNode();
478     lock_Status();
479     statusPtr->taskId = taskId;
480     statusPtr->port = port;
481     statusPtr->jobNumber = bc_jobNumber();
482     statusPtr->flags &= ~STARTING;      /* ok to examine */
483     sprintf(statusPtr->taskName, "Scantape");
484     unlock_Status();
485
486     return (0);
487 }
488
489 /*************/
490 /* utilities */
491 /*************/
492
493 /* get a connection to the tape controller */
494 afs_int32
495 bc_GetConn(aconfig, aport, tconn)
496      struct bc_config *aconfig;
497      afs_int32 aport;
498      struct rx_connection **tconn;
499 {
500     afs_int32 code = 0;
501     afs_uint32 host;
502     unsigned short port;
503     static struct rx_securityClass *rxsc;
504     struct bc_hostEntry *te;
505
506     *tconn = (struct rx_connection *)0;
507
508     /* use non-secure connections to butc */
509     if (!rxsc)
510         rxsc = rxnull_NewClientSecurityObject();
511     if (!rxsc || !aconfig)
512         return (-1);
513
514     for (te = aconfig->tapeHosts; te; te = te->next) {
515         if (te->portOffset == aport) {
516             /* found the right port */
517             host = te->addr.sin_addr.s_addr;
518             if (!host)
519                 return (BC_NOHOSTENTRY);        /* gethostbyname in bc_ParseHosts failed */
520
521             port = htons(BC_TAPEPORT + aport);
522
523             /* servers is 1; sec index is 0 */
524             *tconn = rx_NewConnection(host, port, 1, rxsc, 0);
525             return ((*tconn ? 0 : -1));
526         }
527     }
528     return (BC_NOHOSTENTRY);
529 }
530
531 /* CheckTCVersion
532  *      make sure we are talking to a compatible butc process.
533  * exit: 
534  *      0 - ok
535  *      -1 - not compatible
536  */
537
538 CheckTCVersion(tconn)
539      struct rx_connection *tconn;
540 {
541     struct tc_tcInfo tci;
542     afs_int32 code;
543
544     code = TC_TCInfo(tconn, &tci);
545     if (code)
546         return (code);
547
548     if (tci.tcVersion != CUR_BUTC_VERSION)
549         return (BC_VERSIONFAIL);
550
551     return 0;
552 }
553
554 ConnectButc(config, port, tconn)
555      struct bc_config *config;
556      afs_int32 port;
557      struct rx_connection **tconn;
558 {
559     afs_int32 code;
560
561     code = bc_GetConn(config, port, tconn);
562     if (code) {
563         com_err(whoami, code,
564                 "; Can't connect to tape coordinator at port %d", port);
565         return (code);
566     }
567
568     code = CheckTCVersion(*tconn);
569     if (code) {
570         rx_DestroyConnection(*tconn);
571
572         if (code == BC_VERSIONFAIL)
573             com_err(whoami, code,
574                     "; Backup and butc are not the same version");
575         else
576             com_err(whoami, code,
577                     "; Can't access tape coordinator at port %d", port);
578
579         return (code);
580     }
581
582     return (0);
583 }