include-afsconfig-before-param-h-20010712
[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     bzero(tcdiPtr, 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     bzero(&bc_dumpTasks[i], 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         bcopy(adestServer, &bc_dumpTasks[i].destServer, sizeof(struct sockaddr_in));
302     else
303         bzero(&bc_dumpTasks[i].destServer, sizeof(struct sockaddr_in));
304  
305     code = LWP_CreateProcess(bc_DmpRstStart, 20480, LWP_NORMAL_PRIORITY, i, "helper", &junk);
306     if (code)
307     {
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)   free(bc_dumpTasks[i].dumpName);
315         if (bc_dumpTasks[i].newExt)     free(bc_dumpTasks[i].newExt);
316         if (bc_dumpTasks[i].volSetName) free(bc_dumpTasks[i].volSetName);
317         if (bc_dumpTasks[i].portOffset) free(bc_dumpTasks[i].portOffset);
318         bc_dumpTasks[i].flags &= ~BC_DI_INUSE;
319         return(code);
320     }
321
322     return 0;
323 }
324
325 #ifdef notdef
326 /* bc_FindDumpSlot
327  *      Returns the dump slot of the dump with dumpID
328  * entry:
329  *      dumpID - id to look for
330  *      port - portoffset for tape coordinator
331  * exit:
332  *      0-n - i.e. 0 or positive number, is the dump slot
333  *      -1 - failed to find dumpID
334  */
335
336 afs_int32
337 bc_FindDumpSlot(dumpID, port)
338      afs_int32 dumpID;
339      afs_int32 port;
340 {
341     int i;
342     
343     for ( i = 0; i < BC_MAXSIMDUMPS; i++ )
344     {
345         if ( (bc_dumpTasks[i].flags & BC_DI_INUSE) &&
346              (bc_dumpTasks[i].dumpID == dumpID)    &&
347              ((afs_int32)bc_dumpTasks[i].portOffset == port) )
348         {
349             return(i);
350         }
351     }
352     return(-1);
353 }
354 #endif
355
356 /* bc_LabelTape
357  *      opens a connection to the tape coordinator and requests that it
358  *      label a tape
359  */
360
361 bc_LabelTape (afsname, pname, size, config, port)
362 char *afsname, *pname;
363 struct bc_config *config;
364 afs_int32 port;
365 afs_int32 size;
366 {
367     struct rx_connection *tconn;
368     afs_int32 code = 0;
369     struct tc_tapeLabel label;
370     statusP statusPtr;
371     afs_uint32 taskId;
372
373     code = ConnectButc(config, port, &tconn);
374     if (code) return(code);
375     
376     bzero(&label,sizeof(label));
377     if (afsname)
378        strcpy(label.afsname, afsname);
379     if (pname)
380        strcpy(label.pname, (strcmp(pname,"")?pname:"<NULL>"));
381     label.size = size;
382
383     code = TC_LabelTape(tconn, &label, &taskId);
384     if (code)
385     {
386         com_err(whoami,code,"; Failed to start labeltape");
387         return(code);
388     }
389
390     /* create status monitor block */
391     statusPtr = createStatusNode();
392     lock_Status();
393     statusPtr->taskId = taskId;
394     statusPtr->port = port;
395     statusPtr->jobNumber = bc_jobNumber();
396     /* statusPtr->flags    |= SILENT; */        /* don't report termination */
397     statusPtr->flags    &= ~STARTING;           /* ok to examine */
398
399     sprintf(statusPtr->taskName, "Labeltape (%s)",
400             (pname ? pname : (afsname ? afsname : "<NULL>")));
401     unlock_Status();
402     
403     return 0;
404 }
405
406 /* bc_ReadLabel
407  *      open a connection to the tape coordinator and read the label on
408  *      a tape
409  */
410
411 bc_ReadLabel(config,port)
412     struct bc_config *config;
413     afs_int32 port;
414 {
415     struct rx_connection *tconn;
416     struct tc_tapeLabel label;
417     afs_uint32 taskId;
418     afs_int32 code = 0;
419     char *tname=0;
420
421     code = ConnectButc(config, port, &tconn);
422     if (code) return(code);
423     
424     bzero(&label,sizeof(label));
425     code = TC_ReadLabel(tconn, &label, &taskId);
426     if (code) {
427         if (code == BUTM_NOLABEL) {
428            printf("Tape read was unlabelled\n");
429            return 0;
430         }
431         com_err(whoami,code,"; Failed to start readlabel");
432         return(code);
433     }
434
435     if (strcmp(label.pname,""))
436        tname = label.pname;
437     else if (strcmp(label.afsname,""))
438        tname = label.afsname;
439
440     if (!tname) {
441         printf("Tape read was labelled : <NULL>  size : %u\n",label.size);
442     }
443     else if (!label.tapeId) {
444         printf("Tape read was labelled : %s size : %lu Kbytes\n", tname, label.size);
445     }
446     else {
447         printf("Tape read was labelled : %s (%lu) size : %lu Kbytes\n", 
448                tname, label.tapeId, label.size);
449     }
450
451     return 0;
452 }
453
454 bc_ScanDumps(config, dbAddFlag, port)
455     struct bc_config *config;
456     afs_int32 dbAddFlag;
457     afs_int32 port;
458 {
459     struct rx_connection *tconn;
460     statusP statusPtr;
461     afs_uint32 taskId;
462     afs_int32 code = 0;
463
464     code = ConnectButc(config, port, &tconn);
465     if (code) return(code);
466     
467     code = TC_ScanDumps(tconn, dbAddFlag, &taskId);
468     if (code)
469     {
470         com_err(whoami, code, "; Failed to start scantape");
471         return(code);
472     }
473
474     /* create status monitor block */
475     statusPtr = createStatusNode();
476     lock_Status();
477     statusPtr->taskId    = taskId;
478     statusPtr->port      = port;
479     statusPtr->jobNumber =  bc_jobNumber();
480     statusPtr->flags    &= ~STARTING;           /* ok to examine */
481     sprintf(statusPtr->taskName, "Scantape");
482     unlock_Status();
483     
484     return(0);
485 }
486
487 /*************/
488 /* utilities */
489 /*************/
490
491 /* get a connection to the tape controller */
492 afs_int32
493 bc_GetConn (aconfig, aport, tconn)
494     struct bc_config *aconfig;
495     afs_int32 aport;
496     struct rx_connection **tconn;
497 {
498     afs_int32   code = 0;
499     afs_uint32 host;
500     unsigned short port;
501     static struct rx_securityClass *rxsc;
502     struct bc_hostEntry *te;
503
504     *tconn = (struct rx_connection *)0;
505
506     /* use non-secure connections to butc */
507     if (!rxsc)
508         rxsc = (struct rx_securityClass *) rxnull_NewClientSecurityObject();
509     if (!rxsc || !aconfig) return(-1);
510
511     for (te = aconfig->tapeHosts; te; te = te->next)
512     {
513         if ( te->portOffset == aport )
514         {
515             /* found the right port */
516             host = te->addr.sin_addr.s_addr;        
517             if (!host) return (BC_NOHOSTENTRY);  /* gethostbyname in bc_ParseHosts failed */
518
519             port = htons(BC_TAPEPORT + aport);
520
521             /* servers is 1; sec index is 0 */
522             *tconn = rx_NewConnection(host, port, 1, rxsc, 0);
523             return((*tconn ? 0 : -1));
524         }
525     }
526     return(BC_NOHOSTENTRY);
527 }
528
529 /* CheckTCVersion
530  *      make sure we are talking to a compatible butc process.
531  * exit: 
532  *      0 - ok
533  *      -1 - not compatible
534  */
535
536 CheckTCVersion(tconn)
537      struct rx_connection *tconn;
538 {
539     struct tc_tcInfo tci;
540     afs_int32 code;
541
542     code = TC_TCInfo(tconn, &tci);
543     if (code) return(code);
544     
545     if (tci.tcVersion != CUR_BUTC_VERSION)
546         return(BC_VERSIONFAIL);
547
548     return 0;
549 }
550 ConnectButc(config, port, tconn)
551     struct bc_config     *config;
552     afs_int32                port;
553     struct rx_connection **tconn;
554 {
555     afs_int32 code;
556
557     code = bc_GetConn(config, port, tconn);
558     if (code)
559     {
560         com_err(whoami,code,"; Can't connect to tape coordinator at port %d", port);
561         return(code);
562     }
563
564     code = CheckTCVersion(*tconn);
565     if (code)
566     {
567         rx_DestroyConnection(*tconn);
568
569         if (code == BC_VERSIONFAIL)
570             com_err(whoami, code, "; Backup and butc are not the same version");
571         else
572             com_err(whoami, code, "; Can't access tape coordinator at port %d", port);
573
574         return(code);
575     }
576     
577     return(0);
578 }