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