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