time_t-pointer-conversions-20040908
[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
202
203 /* bc_ListDumpScheduleCmd
204  *      list the (internally held) dump schedule tree
205  * parameters:
206  *      ignored
207  */
208
209 afs_int32
210 bc_ListDumpScheduleCmd(as, arock)
211      struct cmd_syndesc *as;
212      char *arock;
213 {
214     /* no parms */
215     afs_int32 code;
216     register struct bc_dumpSchedule *tdump;
217
218     /* first check to see if schedules must be updated */
219     code = bc_UpdateDumpSchedule();
220     if (code) {
221         com_err(whoami, code, "; Can't retrieve dump schedule");
222         return (code);
223     }
224
225     /* go through entire list, displaying trees for root-level dump
226      * schedules
227      */
228     for (tdump = bc_globalConfig->dsched; tdump; tdump = tdump->next) {
229         /* if this is a root-level dump, show it and its kids */
230         if (!tdump->parent)
231             ListDumpSchedule(tdump, 0);
232     }
233     return 0;
234 }
235
236
237 /* bc_SetExpCmd
238  *      Set/clear expiration date on existing dump node
239  * params:
240  *      parm 0: list of dump names
241  *      parm 1: expiration date (list)
242  */
243
244 afs_int32
245 bc_SetExpCmd(as, arock)
246      struct cmd_syndesc *as;
247      char *arock;
248 {
249     register char *dname;       /* dump schedule name */
250     register struct cmd_item *ti;
251     struct bc_dumpSchedule *node, *parent;
252     afs_int32 expType, expDate;
253     udbClientTextP ctPtr;
254     register afs_int32 code;
255
256     afs_int32 bc_ParseExpiration();
257
258     /* if an expiration date has been specified */
259     if (as->parms[1].items) {
260         code = bc_ParseExpiration(&as->parms[1], &expType, &expDate);
261         if (code) {
262             printf("Invalid expiration date syntax\n");
263             return (1);
264         }
265     } else {
266         /* no expiration date specified */
267         expDate = 0;
268         expType = BC_NO_EXPDATE;
269     }
270
271     /* lock schedules and check validity */
272     ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
273
274     code = bc_LockText(ctPtr);
275     if (code)
276         ERROR(code);
277
278     code = bc_UpdateDumpSchedule();
279     if (code) {
280         com_err(whoami, code, "; Can't retrieve dump schedule");
281         return (code);
282     }
283
284     /* process each dump name using the expiration date computed above */
285     for (ti = as->parms[0].items; ti != 0; ti = ti->next) {
286         /* get next dump name to process */
287         dname = ti->data;
288
289         /* validate the name dump name length */
290         if (strlen(dname) >= BU_MAX_DUMP_PATH) {
291             code = -1;
292             com_err(whoami, 0, "Dump names must be < %d characters",
293                     BU_MAX_DUMP_PATH);
294             com_err(whoami, 0, "Dump %s not added", dname);
295             continue;
296         }
297
298         code = FindDump(bc_globalConfig, dname, &parent, &node);
299         if (code) {
300             com_err(whoami, 0, "Dump level %s not found", dname);
301             continue;
302         }
303
304         node->expDate = expDate;
305         node->expType = expType;
306     }
307
308     code = bc_SaveDumpSchedule();
309     if (code) {
310         com_err(whoami, code, "Cannot save dump schedule");
311         com_err(whoami, 0,
312                 "Expiration changes effective for this session only");
313     }
314
315   error_exit:
316     if (ctPtr->lockHandle)
317         bc_UnlockText(ctPtr);
318     return (code);
319 }
320
321
322
323 /* ------------------------------------
324  * general dump schedule handling routines
325  * ------------------------------------
326  */
327
328 bc_ParseDumpSchedule()
329 {
330     char tbuffer[1024];
331     char dsname[256], period[64];
332     char *tp;
333     afs_int32 code;
334     udbClientTextP ctPtr;
335     register struct bc_dumpSchedule *tds;
336     struct bc_dumpSchedule **ppds, *pds;
337     afs_int32 expDate, expType;
338
339     register FILE *stream;
340
341     /* initialize locally used variables */
342     ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
343     stream = ctPtr->textStream;
344
345     if (ctPtr->textSize == 0)   /* nothing defined yet */
346         return (0);
347
348     if (stream == NULL)
349         return (BC_INTERNALERROR);
350
351     rewind(stream);
352
353     /* check the magic number and version */
354     tp = fgets(tbuffer, sizeof(tbuffer), stream);
355     if (tp == 0)
356         /* can't read first line - error */
357         return (BC_INTERNALERROR);
358     else {
359         afs_int32 dsmagic, dsversion;
360
361         /* read the first line, and then check magic # and version */
362
363         code = sscanf(tbuffer, "%d %d", &dsmagic, &dsversion);
364         if ((code != 2)
365             || (dsmagic != BC_SCHEDULE_MAGIC)
366             || (dsversion != BC_SCHEDULE_VERSION)
367             ) {
368             /* invalid or unexpected header - error */
369             com_err(whoami, 0, "Unable to understand dump schedule file");
370             return (BC_INTERNALERROR);
371         }
372     }
373
374     while (1) {
375         /* read all of the lines out */
376         tp = fgets(tbuffer, sizeof(tbuffer), stream);
377         if (tp == 0)
378             break;              /* hit eof? */
379         code =
380             sscanf(tbuffer, "%s %s %d %d", dsname, period, &expDate,
381                    &expType);
382         if (code != 4) {
383             com_err(whoami, 0,
384                     "Syntax error in dump schedule file, line is: %s",
385                     tbuffer);
386             return (BC_INTERNALERROR);
387         }
388         tds =
389             (struct bc_dumpSchedule *)malloc(sizeof(struct bc_dumpSchedule));
390         memset(tds, 0, sizeof(*tds));
391
392         tds->next = (struct bc_dumpSchedule *)0;
393         tds->name = (char *)malloc(strlen(dsname) + 1);
394         strcpy(tds->name, dsname);
395
396         tds->expDate = expDate;
397         tds->expType = expType;
398
399         /* find the end of the schedule list, and append the new item to it */
400         ppds = &bc_globalConfig->dsched;
401         pds = *ppds;
402         while (pds != 0) {
403             ppds = &pds->next;
404             pds = *ppds;
405         }
406         *ppds = tds;
407     }
408     return 0;
409 }
410
411
412 bc_SaveDumpSchedule()
413 {
414     struct bc_dumpSchedule *tdump;
415     udbClientTextP ctPtr;
416     afs_int32 code = 0;
417
418     extern struct bc_config *bc_globalConfig;
419     extern afs_int32 filesize();
420
421     /* setup the right ptr */
422     ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
423
424     /* must be locked */
425     if (ctPtr->lockHandle == 0)
426         return (BC_INTERNALERROR);
427
428     /* truncate the file */
429     code = ftruncate(fileno(ctPtr->textStream), 0);
430     if (code)
431         ERROR(errno);
432
433     rewind(ctPtr->textStream);
434
435     /* write the new information */
436     fprintf(ctPtr->textStream, "%d %d\n", BC_SCHEDULE_MAGIC,
437             BC_SCHEDULE_VERSION);
438
439     for (tdump = bc_globalConfig->dsched; tdump; tdump = tdump->next) {
440         fprintf(ctPtr->textStream, "%s %s %d %d\n", tdump->name, "any",
441                 tdump->expDate, tdump->expType);
442     }
443
444     if (ferror(ctPtr->textStream))
445         return (BC_INTERNALERROR);
446
447     fflush(ctPtr->textStream);  /* debug */
448
449     /* send to server */
450     code = bcdb_SaveTextFile(ctPtr);
451     if (code)
452         ERROR(code);
453
454     /* increment local version number */
455     ctPtr->textVersion++;
456
457     /* update locally stored file size */
458     ctPtr->textSize = filesize(ctPtr->textStream);
459   error_exit:
460     return (code);
461 }
462
463
464 /* ------------------------------------
465  * misc. support routines - specific to dump schedules
466  * ------------------------------------
467  */
468
469 afs_int32
470 bc_UpdateDumpSchedule()
471 {
472     struct bc_dumpSchedule *dumpPtr, *nextDumpPtr;
473     struct udbHandleS *uhptr = &udbHandle;
474     udbClientTextP ctPtr;
475     afs_int32 code;
476     int lock = 0;
477
478     /* lock schedules and check validity */
479     ctPtr = &bc_globalConfig->configText[TB_DUMPSCHEDULE];
480
481     code = bc_CheckTextVersion(ctPtr);
482     if (code != BC_VERSIONMISMATCH) {
483         ERROR(code);            /* Version matches or some other error */
484     }
485
486     /* Must update the dump schedules */
487     /* If we are not already locked, then lock it now */
488     if (!ctPtr->lockHandle) {
489         code = bc_LockText(ctPtr);
490         if (code)
491             ERROR(code);
492         lock = 1;
493     }
494
495     if (ctPtr->textVersion != -1) {
496         printf("backup: obsolete dump schedule - updating\n");
497
498         /* clear all old schedule information */
499         dumpPtr = bc_globalConfig->dsched;
500         while (dumpPtr) {
501             nextDumpPtr = dumpPtr->next;
502             free(dumpPtr);
503             dumpPtr = nextDumpPtr;
504         }
505         bc_globalConfig->dsched = 0;;
506     }
507
508     /* open a temp file to store the config text received from buserver *
509      * The open file stream is stored in ctPtr->textStream */
510     code =
511         bc_openTextFile(ctPtr,
512                         &bc_globalConfig->
513                         tmpTextFileNames[TB_DUMPSCHEDULE][0]);
514     if (code)
515         ERROR(code);
516     /* now get a fresh set of information from the database */
517     code = bcdb_GetTextFile(ctPtr);
518     if (code)
519         ERROR(code);
520
521     /* fetch the version number */
522     code =
523         ubik_Call(BUDB_GetTextVersion, uhptr->uh_client, 0, ctPtr->textType,
524                   &ctPtr->textVersion);
525     if (code)
526         ERROR(code);
527
528     /* parse the file */
529     code = bc_ParseDumpSchedule();
530     if (code)
531         ERROR(code);
532
533     /* rebuild the tree */
534     code = bc_ProcessDumpSchedule(bc_globalConfig);
535     if (code)
536         ERROR(code);
537
538   error_exit:
539     if (lock && ctPtr->lockHandle)
540         bc_UnlockText(ctPtr);
541     return (code);
542 }
543
544 /* ListDumpSchedule
545  *      Print out the dump schedule tree whose root is adump. Alevel should
546  *      be passed in as 0, and is incremented for the recursive calls
547  * entry:
548  *      adump - ptr to the root node of a dump schedule
549  *      alevel - 0
550  */
551
552 static
553 ListDumpSchedule(adump, alevel)
554      int alevel;
555      register struct bc_dumpSchedule *adump;
556 {
557     register int i;
558     register struct bc_dumpSchedule *child;
559
560     char *tailCompPtr();
561
562     /* sanity check for loops */
563     if (alevel > 100) {
564         printf("backup: recursing listing dump schedule\n");
565         return -1;
566     }
567
568     /* move to appropriate indentation level */
569     for (i = 0; i < alevel; i++)
570         printf("    ");
571
572     /* name is a pathname style name, determine trailing name and only print
573      * it
574      */
575
576     printf("/%s ", tailCompPtr(adump->name));
577
578
579     /* list expiration time */
580     switch (adump->expType) {
581     case BC_ABS_EXPDATE:
582         /* absolute expiration date. Never expires if date is 0 */
583         if (adump->expDate) {
584             time_t t = adump->expDate;
585             printf("expires at %.24s", cTIME(&t));
586         }
587         break;
588
589     case BC_REL_EXPDATE:
590         {
591             struct ktime_date kt;
592
593             /* expiration date relative to the time that the dump is done */
594             LongTo_ktimeRelDate(adump->expDate, &kt);
595             printf(" expires in %s", RelDatetoString(&kt));
596         }
597         break;
598
599     default:
600         break;
601     }
602     printf("\n");
603     for (child = adump->firstChild; child; child = child->nextSibling)
604         ListDumpSchedule(child, alevel + 1);
605
606     return 0;
607 }