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