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