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