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