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