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