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