Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / bucoord / dump_sched.c
CommitLineData
805e021f
CE
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/ktime.h>
20#include <afs/budb_client.h>
21#include <afs/cmd.h>
22#include <afs/com_err.h>
23#include <afs/bubasics.h>
24
25#include "bc.h"
26#include "error_macros.h"
27#include "bucoord_internal.h"
28#include "bucoord_prototypes.h"
29
30/* code to manage dump schedules
31 * specific to the ubik database implementation
32 */
33
34extern struct bc_config *bc_globalConfig;
35extern struct udbHandleS udbHandle;
36extern char *whoami;
37
38static int ListDumpSchedule(struct bc_dumpSchedule *adump, int alevel);
39
40/* ------------------------------------
41 * command level routines
42 * ------------------------------------
43 */
44
45/* bc_AddDumpCmd
46 * add a dump schedule
47 * params:
48 * parm 0: list of dump names
49 * parm 1: expiration date (list)
50 */
51
52int
53bc_AddDumpCmd(struct cmd_syndesc *as, void *arock)
54{
55 char *dname; /* dump schedule name */
56 int code;
57 afs_int32 expType, expDate;
58 struct cmd_item *ti;
59 udbClientTextP ctPtr;
60
61 /* if an expiration date has been specified */
62 if (as->parms[1].items) {
63 code = bc_ParseExpiration(&as->parms[1], &expType, &expDate);
64 if (code) {
65 printf("Invalid expiration date syntax\n");
66 return (1);
67 }
68 } else {
69 /* no expiration date specified */
70 expDate = 0;
71 expType = BC_NO_EXPDATE;
72 }
73
74 /* lock schedules and check validity */
75 ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
76
77 code = bc_LockText(ctPtr);
78 if (code)
79 ERROR(code);
80
81 code = bc_UpdateDumpSchedule();
82 if (code) {
83 afs_com_err(whoami, code, "; Can't retrieve dump schedule");
84 return (code);
85 }
86
87 /* process each dump name using the expiration date computed above */
88 for (ti = as->parms[0].items; ti != 0; ti = ti->next) {
89 /* get next dump name to process */
90 dname = ti->data;
91
92 /* validate the name dump name length */
93 if (strlen(dname) >= BU_MAX_DUMP_PATH) {
94 afs_com_err(whoami, 0, "Dump names must be < %d characters",
95 BU_MAX_DUMP_PATH);
96 afs_com_err(whoami, 0, "Dump %s not added", dname);
97 code = -1;
98 continue;
99 }
100
101 code =
102 bc_CreateDumpSchedule(bc_globalConfig, dname, expDate, expType);
103 if (code) {
104 if (code == -1)
105 afs_com_err(whoami, 0, "Dump already exists");
106 else if (code == -2)
107 afs_com_err(whoami, 0, "Invalid path name '%s'", dname);
108 else if (code == -3)
109 afs_com_err(whoami, 0, "Name specification error");
110 else
111 afs_com_err(whoami, code, "; Failed to create dump schedule");
112 continue;
113 }
114
115 /* save the new schedule item */
116 code = bc_SaveDumpSchedule();
117 if (code) {
118 afs_com_err(whoami, code, "Cannot save dump schedule");
119 afs_com_err(whoami, 0,
120 "Changes are temporary - for this session only");
121 break;
122 }
123
124 afs_com_err(whoami, 0, "Created new dump schedule %s", dname);
125 }
126
127 error_exit:
128 if (ctPtr->lockHandle)
129 bc_UnlockText(ctPtr);
130 return (code);
131}
132
133
134/* bc_DeleteDumpCmd
135 * delete a dump schedule
136 */
137
138int
139bc_DeleteDumpCmd(struct cmd_syndesc *as, void *arock)
140{
141 /* parm 0 is vol set name
142 * parm 1 is dump schedule name
143 */
144 char *dname;
145 int code;
146 udbClientTextP ctPtr;
147
148 /* lock schedules and check validity */
149 ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
150
151 code = bc_LockText(ctPtr);
152 if (code)
153 ERROR(code);
154
155 code = bc_UpdateDumpSchedule();
156 if (code) {
157 afs_com_err(whoami, code, "; Can't retrieve dump schedule");
158 return (code);
159 }
160
161 dname = as->parms[0].items->data;
162
163 code = bc_DeleteDumpSchedule(bc_globalConfig, dname);
164 if (code) {
165 if (code == -1)
166 afs_com_err(whoami, 0, "No such dump as %s", dname);
167 else
168 afs_com_err(whoami, code, "; Failed to delete dump schedule");
169 goto error_exit;
170 }
171
172 code = bc_SaveDumpSchedule();
173 if (code == 0)
174 printf("backup: deleted dump schedule %s\n", dname);
175 else {
176 afs_com_err(whoami, code, "Cannot save dump schedule file");
177 afs_com_err(whoami, 0, "Deletion is temporary - for this session only");
178 }
179
180 error_exit:
181 if (ctPtr->lockHandle != 0)
182 bc_UnlockText(ctPtr);
183 return code;
184}
185
186/* ListDumpSchedule
187 * Print out the dump schedule tree whose root is adump. Alevel should
188 * be passed in as 0, and is incremented for the recursive calls
189 * entry:
190 * adump - ptr to the root node of a dump schedule
191 * alevel - 0
192 */
193
194static int
195ListDumpSchedule(struct bc_dumpSchedule *adump, int alevel)
196{
197 int i;
198 struct bc_dumpSchedule *child;
199
200 /* sanity check for loops */
201 if (alevel > 100) {
202 printf("backup: recursing listing dump schedule\n");
203 return -1;
204 }
205
206 /* move to appropriate indentation level */
207 for (i = 0; i < alevel; i++)
208 printf(" ");
209
210 /* name is a pathname style name, determine trailing name and only print
211 * it
212 */
213
214 printf("/%s ", tailCompPtr(adump->name));
215
216
217 /* list expiration time */
218 switch (adump->expType) {
219 case BC_ABS_EXPDATE:
220 /* absolute expiration date. Never expires if date is 0 */
221 if (adump->expDate) {
222 time_t t = adump->expDate;
223 printf("expires at %.24s", cTIME(&t));
224 }
225 break;
226
227 case BC_REL_EXPDATE:
228 {
229 struct ktime_date kt;
230
231 /* expiration date relative to the time that the dump is done */
232 LongTo_ktimeRelDate(adump->expDate, &kt);
233 printf(" expires in %s", RelDatetoString(&kt));
234 }
235 break;
236
237 default:
238 break;
239 }
240 printf("\n");
241 for (child = adump->firstChild; child; child = child->nextSibling)
242 ListDumpSchedule(child, alevel + 1);
243
244 return 0;
245}
246
247/* bc_ListDumpScheduleCmd
248 * list the (internally held) dump schedule tree
249 * parameters:
250 * ignored
251 */
252
253int
254bc_ListDumpScheduleCmd(struct cmd_syndesc *as, void *arock)
255{
256 /* no parms */
257 int code;
258 struct bc_dumpSchedule *tdump;
259
260 /* first check to see if schedules must be updated */
261 code = bc_UpdateDumpSchedule();
262 if (code) {
263 afs_com_err(whoami, code, "; Can't retrieve dump schedule");
264 return (code);
265 }
266
267 /* go through entire list, displaying trees for root-level dump
268 * schedules
269 */
270 for (tdump = bc_globalConfig->dsched; tdump; tdump = tdump->next) {
271 /* if this is a root-level dump, show it and its kids */
272 if (!tdump->parent)
273 ListDumpSchedule(tdump, 0);
274 }
275 return 0;
276}
277
278
279/* bc_SetExpCmd
280 * Set/clear expiration date on existing dump node
281 * params:
282 * parm 0: list of dump names
283 * parm 1: expiration date (list)
284 */
285
286int
287bc_SetExpCmd(struct cmd_syndesc *as, void *arock)
288{
289 char *dname; /* dump schedule name */
290 struct cmd_item *ti;
291 struct bc_dumpSchedule *node, *parent;
292 afs_int32 expType, expDate;
293 udbClientTextP ctPtr;
294 int code;
295
296 /* if an expiration date has been specified */
297 if (as->parms[1].items) {
298 code = bc_ParseExpiration(&as->parms[1], &expType, &expDate);
299 if (code) {
300 printf("Invalid expiration date syntax\n");
301 return (1);
302 }
303 } else {
304 /* no expiration date specified */
305 expDate = 0;
306 expType = BC_NO_EXPDATE;
307 }
308
309 /* lock schedules and check validity */
310 ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
311
312 code = bc_LockText(ctPtr);
313 if (code)
314 ERROR(code);
315
316 code = bc_UpdateDumpSchedule();
317 if (code) {
318 afs_com_err(whoami, code, "; Can't retrieve dump schedule");
319 return (code);
320 }
321
322 /* process each dump name using the expiration date computed above */
323 for (ti = as->parms[0].items; ti != 0; ti = ti->next) {
324 /* get next dump name to process */
325 dname = ti->data;
326
327 /* validate the name dump name length */
328 if (strlen(dname) >= BU_MAX_DUMP_PATH) {
329 code = -1;
330 afs_com_err(whoami, 0, "Dump names must be < %d characters",
331 BU_MAX_DUMP_PATH);
332 afs_com_err(whoami, 0, "Dump %s not added", dname);
333 continue;
334 }
335
336 code = FindDump(bc_globalConfig, dname, &parent, &node);
337 if (code) {
338 afs_com_err(whoami, 0, "Dump level %s not found", dname);
339 continue;
340 }
341
342 node->expDate = expDate;
343 node->expType = expType;
344 }
345
346 code = bc_SaveDumpSchedule();
347 if (code) {
348 afs_com_err(whoami, code, "Cannot save dump schedule");
349 afs_com_err(whoami, 0,
350 "Expiration changes effective for this session only");
351 }
352
353 error_exit:
354 if (ctPtr->lockHandle)
355 bc_UnlockText(ctPtr);
356 return (code);
357}
358
359
360
361/* ------------------------------------
362 * general dump schedule handling routines
363 * ------------------------------------
364 */
365
366int
367bc_ParseDumpSchedule(void)
368{
369 char tbuffer[1024];
370 char dsname[256], period[64];
371 char *tp;
372 afs_int32 code;
373 udbClientTextP ctPtr;
374 struct bc_dumpSchedule *tds;
375 struct bc_dumpSchedule **ppds, *pds;
376 afs_int32 expDate, expType;
377
378 FILE *stream;
379
380 /* initialize locally used variables */
381 ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
382 stream = ctPtr->textStream;
383
384 if (ctPtr->textSize == 0) /* nothing defined yet */
385 return (0);
386
387 if (stream == NULL)
388 return (BC_INTERNALERROR);
389
390 rewind(stream);
391
392 /* check the magic number and version */
393 tp = fgets(tbuffer, sizeof(tbuffer), stream);
394 if (tp == 0)
395 /* can't read first line - error */
396 return (BC_INTERNALERROR);
397 else {
398 afs_int32 dsmagic, dsversion;
399
400 /* read the first line, and then check magic # and version */
401
402 code = sscanf(tbuffer, "%d %d", &dsmagic, &dsversion);
403 if ((code != 2)
404 || (dsmagic != BC_SCHEDULE_MAGIC)
405 || (dsversion != BC_SCHEDULE_VERSION)
406 ) {
407 /* invalid or unexpected header - error */
408 afs_com_err(whoami, 0, "Unable to understand dump schedule file");
409 return (BC_INTERNALERROR);
410 }
411 }
412
413 while (1) {
414 /* read all of the lines out */
415 tp = fgets(tbuffer, sizeof(tbuffer), stream);
416 if (tp == 0)
417 break; /* hit eof? */
418 code =
419 sscanf(tbuffer, "%s %s %d %d", dsname, period, &expDate,
420 &expType);
421 if (code != 4) {
422 afs_com_err(whoami, 0,
423 "Syntax error in dump schedule file, line is: %s",
424 tbuffer);
425 return (BC_INTERNALERROR);
426 }
427 tds = calloc(1, sizeof(struct bc_dumpSchedule));
428
429 tds->next = (struct bc_dumpSchedule *)0;
430 tds->name = strdup(dsname);
431
432 tds->expDate = expDate;
433 tds->expType = expType;
434
435 /* find the end of the schedule list, and append the new item to it */
436 ppds = &bc_globalConfig->dsched;
437 pds = *ppds;
438 while (pds != 0) {
439 ppds = &pds->next;
440 pds = *ppds;
441 }
442 *ppds = tds;
443 }
444 return 0;
445}
446
447int
448bc_SaveDumpSchedule(void)
449{
450 struct bc_dumpSchedule *tdump;
451 udbClientTextP ctPtr;
452 afs_int32 code = 0;
453
454 extern struct bc_config *bc_globalConfig;
455
456 /* setup the right ptr */
457 ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
458
459 /* must be locked */
460 if (ctPtr->lockHandle == 0)
461 return (BC_INTERNALERROR);
462
463 /* truncate the file */
464 code = ftruncate(fileno(ctPtr->textStream), 0);
465 if (code)
466 ERROR(errno);
467
468 rewind(ctPtr->textStream);
469
470 /* write the new information */
471 fprintf(ctPtr->textStream, "%d %d\n", BC_SCHEDULE_MAGIC,
472 BC_SCHEDULE_VERSION);
473
474 for (tdump = bc_globalConfig->dsched; tdump; tdump = tdump->next) {
475 fprintf(ctPtr->textStream, "%s %s %d %d\n", tdump->name, "any",
476 tdump->expDate, tdump->expType);
477 }
478
479 if (ferror(ctPtr->textStream))
480 return (BC_INTERNALERROR);
481
482 fflush(ctPtr->textStream); /* debug */
483
484 /* send to server */
485 code = bcdb_SaveTextFile(ctPtr);
486 if (code)
487 ERROR(code);
488
489 /* increment local version number */
490 ctPtr->textVersion++;
491
492 /* update locally stored file size */
493 ctPtr->textSize = filesize(ctPtr->textStream);
494 error_exit:
495 return (code);
496}
497
498
499/* ------------------------------------
500 * misc. support routines - specific to dump schedules
501 * ------------------------------------
502 */
503
504afs_int32
505bc_UpdateDumpSchedule(void)
506{
507 struct bc_dumpSchedule *dumpPtr, *nextDumpPtr;
508 struct udbHandleS *uhptr = &udbHandle;
509 udbClientTextP ctPtr;
510 afs_int32 code;
511 int lock = 0;
512
513 /* lock schedules and check validity */
514 ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
515
516 code = bc_CheckTextVersion(ctPtr);
517 if (code != BC_VERSIONMISMATCH) {
518 ERROR(code); /* Version matches or some other error */
519 }
520
521 /* Must update the dump schedules */
522 /* If we are not already locked, then lock it now */
523 if (!ctPtr->lockHandle) {
524 code = bc_LockText(ctPtr);
525 if (code)
526 ERROR(code);
527 lock = 1;
528 }
529
530 if (ctPtr->textVersion != -1) {
531 printf("backup: obsolete dump schedule - updating\n");
532
533 /* clear all old schedule information */
534 dumpPtr = bc_globalConfig->dsched;
535 while (dumpPtr) {
536 nextDumpPtr = dumpPtr->next;
537 free(dumpPtr);
538 dumpPtr = nextDumpPtr;
539 }
540 bc_globalConfig->dsched = 0;;
541 }
542
543 /* open a temp file to store the config text received from buserver *
544 * The open file stream is stored in ctPtr->textStream */
545 code =
546 bc_openTextFile(ctPtr,
547 &bc_globalConfig->
548 tmpTextFileNames[TB_DUMPSCHEDULE][0]);
549 if (code)
550 ERROR(code);
551 /* now get a fresh set of information from the database */
552 code = bcdb_GetTextFile(ctPtr);
553 if (code)
554 ERROR(code);
555
556 /* fetch the version number */
557 code =
558 ubik_BUDB_GetTextVersion(uhptr->uh_client, 0, ctPtr->textType,
559 &ctPtr->textVersion);
560 if (code)
561 ERROR(code);
562
563 /* parse the file */
564 code = bc_ParseDumpSchedule();
565 if (code)
566 ERROR(code);
567
568 /* rebuild the tree */
569 code = bc_ProcessDumpSchedule(bc_globalConfig);
570 if (code)
571 ERROR(code);
572
573 error_exit:
574 if (lock && ctPtr->lockHandle)
575 bc_UnlockText(ctPtr);
576 return (code);
577}
578