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