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