Imported Upstream version 2.5.2p1
[debian/amanda] / server-src / infofile.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Author: James da Silva, Systems Design and Analysis Group
24  *                         Computer Science Department
25  *                         University of Maryland at College Park
26  */
27 /*
28  * $Id: infofile.c,v 1.64 2006/07/25 18:18:48 martinea Exp $
29  *
30  * manage current info file
31  */
32 #include "amanda.h"
33 #include "conffile.h"
34 #include "infofile.h"
35 #include "token.h"
36
37 static void zero_info(info_t *);
38
39 #ifdef TEXTDB
40   static char *infodir = (char *)0;
41   static char *infofile = (char *)0;
42   static char *newinfofile;
43   static int writing;
44
45   static FILE *open_txinfofile(char *, char *, char *);
46   static int close_txinfofile(FILE *);
47   static int read_txinfofile(FILE *, info_t *);
48   static int write_txinfofile(FILE *, info_t *);
49   static int delete_txinfofile(char *, char *);
50 #else
51 #  define MAX_KEY 256
52 /*#  define HEADER      (SIZEOF(info_t)-DUMP_LEVELS*SIZEOF(stats_t))*/
53
54   static DBM *infodb = NULL;
55   static lockfd = -1;
56 #endif
57
58 #ifdef TEXTDB
59
60 static FILE *
61 open_txinfofile(
62     char *      host,
63     char *      disk,
64     char *      mode)
65 {
66     FILE *infof;
67     char *myhost;
68     char *mydisk;
69
70     assert(infofile == (char *)0);
71
72     writing = (*mode == 'w');
73
74     myhost = sanitise_filename(host);
75     mydisk = sanitise_filename(disk);
76
77     infofile = vstralloc(infodir,
78                          "/", myhost,
79                          "/", mydisk,
80                          "/info",
81                          NULL);
82
83     amfree(myhost);
84     amfree(mydisk);
85
86     /* create the directory structure if in write mode */
87     if (writing) {
88         if (mkpdir(infofile, 02755, (uid_t)-1, (gid_t)-1) == -1) {
89             amfree(infofile);
90             return NULL;
91         }
92     }
93
94     newinfofile = stralloc2(infofile, ".new");
95
96     if(writing) {
97         infof = fopen(newinfofile, mode);
98         if(infof != NULL)
99             amflock(fileno(infof), "info");
100     }
101     else {
102         infof = fopen(infofile, mode);
103         /* no need to lock readers */
104     }
105
106     if(infof == (FILE *)0) {
107         amfree(infofile);
108         amfree(newinfofile);
109         return NULL;
110     }
111
112     return infof;
113 }
114
115 static int
116 close_txinfofile(
117     FILE *infof)
118 {
119     int rc = 0;
120
121     assert(infofile != (char *)0);
122
123     if(writing) {
124         rc = rename(newinfofile, infofile);
125
126         amfunlock(fileno(infof), "info");
127     }
128
129     amfree(infofile);
130     amfree(newinfofile);
131
132     rc = rc || fclose(infof);
133     infof = NULL;
134     if (rc) rc = -1;
135
136     return rc;
137 }
138
139 /* XXX - code assumes AVG_COUNT == 3 */
140 static int
141 read_txinfofile(
142     FILE *      infof,
143     info_t *    info)
144 {
145     char *line = NULL;
146     int version;
147     int rc;
148     perf_t *pp;
149     char *s;
150     int ch;
151     int nb_history;
152     int i;
153
154     /* get version: command: lines */
155
156     while ((line = agets(infof)) != NULL) {
157         if (line[0] != '\0')
158             break;
159         amfree(line);
160     }
161     if (line == NULL) return -1;
162     rc = sscanf(line, "version: %d", &version);
163     amfree(line);
164     if(rc != 1) return -2;
165
166     while ((line = agets(infof)) != NULL) {
167         if (line[0] != '\0')
168             break;
169         amfree(line);
170     }
171     if (line == NULL) return -1;
172     rc = sscanf(line, "command: %u", &info->command);
173     amfree(line);
174     if(rc != 1) return -2;
175
176     /* get rate: and comp: lines for full dumps */
177
178     pp = &info->full;
179
180     while ((line = agets(infof)) != NULL) {
181         if (line[0] != '\0')
182             break;
183         amfree(line);
184     }
185     if (line == NULL) return -1;
186     rc = sscanf(line, "full-rate: %lf %lf %lf",
187                 &pp->rate[0], &pp->rate[1], &pp->rate[2]);
188     amfree(line);
189     if(rc > 3) return -2;
190
191     while ((line = agets(infof)) != NULL) {
192         if (line[0] != '\0')
193             break;
194         amfree(line);
195     }
196     if (line == NULL) return -1;
197     rc = sscanf(line, "full-comp: %lf %lf %lf",
198                 &pp->comp[0], &pp->comp[1], &pp->comp[2]);
199     amfree(line);
200     if(rc > 3) return -2;
201
202     /* get rate: and comp: lines for incr dumps */
203
204     pp = &info->incr;
205
206     while ((line = agets(infof)) != NULL) {
207         if (line[0] != '\0')
208             break;
209         amfree(line);
210     }
211     if (line == NULL) return -1;
212     rc = sscanf(line, "incr-rate: %lf %lf %lf",
213                 &pp->rate[0], &pp->rate[1], &pp->rate[2]);
214     amfree(line);
215     if(rc > 3) return -2;
216
217     while ((line = agets(infof)) != NULL) {
218         if (line[0] != '\0')
219             break;
220         amfree(line);
221     }
222     if (line == NULL) return -1;
223     rc = sscanf(line, "incr-comp: %lf %lf %lf",
224                 &pp->comp[0], &pp->comp[1], &pp->comp[2]);
225     amfree(line);
226     if(rc > 3) return -2;
227
228     /* get stats for dump levels */
229
230     for(rc = -2; (line = agets(infof)) != NULL; free(line)) {
231         stats_t onestat;        /* one stat record */
232         time_t date = 0;
233         time_t *date_p = &date;
234         time_t *secs_p;
235         int level = 0;
236
237         if (line[0] == '\0')
238             continue;
239         if(line[0] == '/' && line[1] == '/') {
240             rc = 0;
241             amfree(line);
242             return 0;                           /* normal end of record */
243         }
244         else if (strncmp_const(line,"last_level:") == 0) {
245             break;                              /* normal */
246         }
247         else if (strncmp_const(line,"history:") == 0) {
248             break;                              /* normal */
249         }
250         memset(&onestat, 0, SIZEOF(onestat));
251
252         s = line;
253         ch = *s++;
254
255         if(strncmp_const_skip(line, "stats:", s, ch) != 0) {
256             break;
257         }
258
259         skip_whitespace(s, ch);
260         if(ch == '\0' || sscanf((s - 1), "%d", &level) != 1) {
261             break;
262         }
263         skip_integer(s, ch);
264
265         skip_whitespace(s, ch);
266         if(ch == '\0' || sscanf((s - 1), OFF_T_FMT,
267                                 (OFF_T_FMT_TYPE *)&onestat.size) != 1) {
268             break;
269         }
270         skip_integer(s, ch);
271
272         skip_whitespace(s, ch);
273         if(ch == '\0' || sscanf((s - 1), OFF_T_FMT,
274                                 (OFF_T_FMT_TYPE *)&onestat.csize) != 1) {
275             break;
276         }
277         skip_integer(s, ch);
278
279         skip_whitespace(s, ch);
280         secs_p = &onestat.secs;
281         if(ch == '\0' || sscanf((s - 1), TIME_T_FMT,
282                                 (TIME_T_FMT_TYPE *)secs_p) != 1) {
283             break;
284         }
285         skip_integer(s, ch);
286
287         skip_whitespace(s, ch);
288         if(ch == '\0' || sscanf((s - 1), TIME_T_FMT,
289                                 (TIME_T_FMT_TYPE *)date_p) != 1) {
290             break;
291         }
292         skip_integer(s, ch);
293
294         skip_whitespace(s, ch);
295         if(ch != '\0') {
296             if(sscanf((s - 1), OFF_T_FMT,
297                         (OFF_T_FMT_TYPE *)&onestat.filenum) != 1) {
298                 break;
299             }
300             skip_integer(s, ch);
301
302             skip_whitespace(s, ch);
303             if(ch == '\0') {
304                 break;
305             }
306             strncpy(onestat.label, s-1, SIZEOF(onestat.label)-1);
307             onestat.label[SIZEOF(onestat.label)-1] = '\0';
308         }
309
310         onestat.date = date;    /* time_t not guarranteed to be long */
311
312         if(level < 0 || level > DUMP_LEVELS-1)
313             break;
314
315         info->inf[level] = onestat;
316     }
317    
318     if(line == NULL) return -1;
319
320     rc = sscanf(line, "last_level: %d %d", 
321                 &info->last_level, &info->consecutive_runs);
322
323     amfree(line);
324     if(rc > 2) return -2;
325     rc = 0;
326
327     nb_history = 0;
328     for(i=0;i<=NB_HISTORY;i++) {
329         info->history[i].level = -2;
330     }
331
332     for(rc = -2; (line = agets(infof)) != NULL; free(line)) {
333         history_t onehistory;   /* one history record */
334         time_t date;
335         time_t *date_p = &date;
336         time_t *secs_p;
337
338         if (line[0] == '\0')
339             continue;
340         date = 0L;
341         if(line[0] == '/' && line[1] == '/') {
342             info->history[nb_history].level = -2;
343             rc = 0;
344             amfree(line);
345             return 0;                           /* normal end of record */
346         }
347
348         memset(&onehistory, 0, SIZEOF(onehistory));
349
350         s = line;
351         ch = *s++;
352
353         if(strncmp_const_skip(line, "history:", s, ch) != 0) {
354             amfree(line);
355             break;
356         }
357
358         skip_whitespace(s, ch);
359         if(ch == '\0' || sscanf((s - 1), "%d", &onehistory.level) != 1) {
360             amfree(line);
361             break;
362         }
363         skip_integer(s, ch);
364
365         skip_whitespace(s, ch);
366         if(ch == '\0' || sscanf((s - 1), OFF_T_FMT,
367                                 (OFF_T_FMT_TYPE *)&onehistory.size) != 1) {
368             amfree(line);
369             break;
370         }
371         skip_integer(s, ch);
372
373         skip_whitespace(s, ch);
374         if(ch == '\0' || sscanf((s - 1), OFF_T_FMT,
375                                 (OFF_T_FMT_TYPE *)&onehistory.csize) != 1) {
376             amfree(line);
377             break;
378         }
379         skip_integer(s, ch);
380
381         skip_whitespace(s, ch);
382         if(ch == '\0' || sscanf((s - 1), TIME_T_FMT,
383                                 (TIME_T_FMT_TYPE *)date_p) != 1) {
384             amfree(line);
385             break;
386         }
387         skip_integer(s, ch);
388
389         onehistory.date = date; /* time_t not guaranteed to be long */
390
391         onehistory.secs = (unsigned long)-1;
392         skip_whitespace(s, ch);
393         secs_p = &onehistory.secs;
394         if(ch != '\0') {
395             if(sscanf((s - 1), TIME_T_FMT,
396                                 (TIME_T_FMT_TYPE *)secs_p) != 1) {
397                 amfree(line);
398                 break;
399             }
400             skip_integer(s, ch);
401         }
402
403         info->history[nb_history++] = onehistory;
404     }
405     amfree(line);
406
407     while ((line = agets(infof)) != NULL) {
408         if (line[0] != '\0')
409             break;
410         amfree(line);
411     }
412     if (line == NULL) return -1;
413     amfree(line);
414
415     return rc;
416 }
417
418 static int
419 write_txinfofile(
420     FILE *      infof,
421     info_t *    info)
422 {
423     int i;
424     stats_t *sp;
425     perf_t *pp;
426     int level;
427
428     fprintf(infof, "version: %d\n", 0);
429
430     fprintf(infof, "command: %u\n", info->command);
431
432     pp = &info->full;
433
434     fprintf(infof, "full-rate:");
435     for(i=0; i<AVG_COUNT; i++)
436         if(pp->rate[i] >= 0.0)
437             fprintf(infof, " %lf", pp->rate[i]);
438     fprintf(infof, "\n");
439
440     fprintf(infof, "full-comp:");
441     for(i=0; i<AVG_COUNT; i++)
442         if(pp->comp[i] >= 0.0)
443             fprintf(infof, " %lf", pp->comp[i]);
444     fprintf(infof, "\n");
445
446     pp = &info->incr;
447
448     fprintf(infof, "incr-rate:");
449     for(i=0; i<AVG_COUNT; i++)
450         if(pp->rate[i] >= 0.0)
451             fprintf(infof, " %lf", pp->rate[i]);
452     fprintf(infof, "\n");
453
454     fprintf(infof, "incr-comp:");
455     for(i=0; i<AVG_COUNT; i++)
456         if(pp->comp[i] >= 0.0)
457             fprintf(infof, " %lf", pp->comp[i]);
458     fprintf(infof, "\n");
459
460     for(level=0; level<DUMP_LEVELS; level++) {
461         sp = &info->inf[level];
462
463         if(sp->date < (time_t)0 && sp->label[0] == '\0') continue;
464
465         fprintf(infof, "stats: %d " OFF_T_FMT " " OFF_T_FMT
466                 " " TIME_T_FMT " " OFF_T_FMT,
467                 level, (OFF_T_FMT_TYPE)sp->size, (OFF_T_FMT_TYPE)sp->csize,
468                 (TIME_T_FMT_TYPE)sp->secs, (OFF_T_FMT_TYPE)sp->date);
469         if(sp->label[0] != '\0')
470             fprintf(infof, " " OFF_T_FMT " %s",
471                 (OFF_T_FMT_TYPE)sp->filenum, sp->label);
472         fprintf(infof, "\n");
473     }
474
475     fprintf(infof, "last_level: %d %d\n", info->last_level, info->consecutive_runs);
476
477     for(i=0;info->history[i].level > -1;i++) {
478         fprintf(infof, "history: %d " OFF_T_FMT " " OFF_T_FMT
479                 " " TIME_T_FMT " " TIME_T_FMT "\n",
480                 info->history[i].level,
481                 (OFF_T_FMT_TYPE)info->history[i].size,
482                 (OFF_T_FMT_TYPE)info->history[i].csize,
483                 (TIME_T_FMT_TYPE)info->history[i].date,
484                 (TIME_T_FMT_TYPE)info->history[i].secs);
485     }
486     fprintf(infof, "//\n");
487
488     return 0;
489 }
490
491 static int
492 delete_txinfofile(
493     char *      host,
494     char *      disk)
495 {
496     char *fn = NULL, *fn_new = NULL;
497     int rc;
498     char *myhost;
499     char *mydisk;
500
501     myhost = sanitise_filename(host);
502     mydisk = sanitise_filename(disk);
503     fn = vstralloc(infodir,
504                    "/", myhost,
505                    "/", mydisk,
506                    "/info",
507                    NULL);
508     fn_new = stralloc2(fn, ".new");
509
510     amfree(myhost);
511     amfree(mydisk);
512
513     unlink(fn_new);
514     amfree(fn_new);
515
516     rc = rmpdir(fn, infodir);
517     amfree(fn);
518
519     return rc;
520 }
521 #endif
522
523 #ifndef TEXTDB
524 static char *lockname = NULL;
525 #endif
526
527 int
528 open_infofile(
529     char *      filename)
530 {
531 #ifdef TEXTDB
532     assert(infodir == (char *)0);
533
534     infodir = stralloc(filename);
535
536     return 0; /* success! */
537 #else
538     /* lock the dbm file */
539
540     lockname = newstralloc2(lockname, filename, ".lck");
541     if((lockfd = open(lockname, O_CREAT|O_RDWR, 0644)) == -1)
542         return 2;
543
544     if(amflock(lockfd, "info") == -1) {
545         aclose(lockfd);
546         unlink(lockname);
547         return 3;
548     }
549
550     if(!(infodb = dbm_open(filename, O_CREAT|O_RDWR, 0644))) {
551         amfunlock(lockfd, "info");
552         aclose(lockfd);
553         unlink(lockname);
554         return 1;
555     }
556
557     return (infodb == NULL);    /* return 1 on error */
558 #endif
559 }
560
561 void
562 close_infofile(void)
563 {
564 #ifdef TEXTDB
565     assert(infodir != (char *)0);
566
567     amfree(infodir);
568 #else
569     dbm_close(infodb);
570
571     if(amfunlock(lockfd, "info") == -1) {
572         error("could not unlock infofile: %s", strerror(errno));
573         /*NOTREACHED*/
574     }
575
576     aclose(lockfd);
577     lockfd = -1;
578
579     unlink(lockname);
580 #endif
581 }
582
583 /* Convert a dump level to a GMT based time stamp */
584 char *
585 get_dumpdate(
586     info_t *    info,
587     int         lev)
588 {
589     static char stamp[20]; /* YYYY:MM:DD:hh:mm:ss */
590     int l;
591     time_t this, last;
592     struct tm *t;
593
594     last = EPOCH;
595
596     for(l = 0; l < lev; l++) {
597         this = info->inf[l].date;
598         if (this > last) last = this;
599     }
600
601     t = gmtime(&last);
602     snprintf(stamp, SIZEOF(stamp), "%d:%d:%d:%d:%d:%d",
603                 t->tm_year+1900, t->tm_mon+1, t->tm_mday,
604                 t->tm_hour, t->tm_min, t->tm_sec);
605
606     return stamp;
607 }
608
609 /*
610  * Weighted average
611  */
612 double
613 perf_average(
614     double *    a,      /* array of items to average */
615     double      d)      /* default value */
616 {
617     double sum; /* running total */
618     int n;      /* number of items in sum */
619     int w;      /* weight */
620     int i;      /* counter */
621
622     sum = 0.0;
623     n = 0;
624
625     for(i = 0; i < AVG_COUNT; i++) {
626         if(a[i] >= 0.0) {
627             w = AVG_COUNT - i;
628             sum += a[i] * w;
629             n += w;
630         }
631     }
632
633     if(n == 0) return d;
634     return sum / n;
635 }
636
637 static void
638 zero_info(
639     info_t *info)
640 {
641     int i;
642
643     memset(info, '\0', SIZEOF(info_t));
644
645     for(i = 0; i < AVG_COUNT; i++) {
646         info->full.comp[i] = info->incr.comp[i] = -1.0;
647         info->full.rate[i] = info->incr.rate[i] = -1.0;
648     }
649
650     for(i = 0; i < DUMP_LEVELS; i++) {
651         info->inf[i].date = (time_t)-1;
652     }
653
654     info->last_level = -1;
655     info->consecutive_runs = -1;
656
657     for(i=0;i<=NB_HISTORY;i++) {
658         info->history[i].level = -2;
659         info->history[i].size = (off_t)0;
660         info->history[i].csize = (off_t)0;
661         info->history[i].date = 0UL;
662     }
663     return;
664 }
665
666 int
667 get_info(
668     char *      hostname,
669     char *      diskname,
670     info_t *    info)
671 {
672     int rc;
673
674     (void) zero_info(info);
675
676     {
677 #ifdef TEXTDB
678         FILE *infof;
679
680         infof = open_txinfofile(hostname, diskname, "r");
681
682         if(infof == NULL) {
683             rc = -1; /* record not found */
684         }
685         else {
686             rc = read_txinfofile(infof, info);
687
688             close_txinfofile(infof);
689         }
690 #else
691         datum k, d;
692
693         /* setup key */
694
695         k.dptr = vstralloc(hostname, ":", diskname, NULL);
696         k.dsize = strlen(k.dptr)+1;
697
698         /* lookup record */
699
700         d = dbm_fetch(infodb, k);
701         amfree(k.dptr);
702         if(d.dptr == NULL) {
703             rc = -1; /* record not found */
704         }
705         else {
706             memcpy(info, d.dptr, d.dsize);
707             rc = 0;
708         }
709 #endif
710     }
711
712     return rc;
713 }
714
715
716 int
717 get_firstkey(
718     char *      hostname,
719     int         hostname_size,
720     char *      diskname,
721     int         diskname_size)
722 {
723 #ifdef TEXTDB
724     (void)hostname;             /* Quiet unused parameter warning */
725     (void)hostname_size;        /* Quiet unused parameter warning */
726     (void)diskname;             /* Quiet unused parameter warning */
727     (void)diskname_size;        /* Quiet unused parameter warning */
728
729     assert(0);
730     return 0;
731 #else
732     datum k;
733     int rc;
734     char *s, *fp;
735     int ch;
736
737     k = dbm_firstkey(infodb);
738     if(k.dptr == NULL) return 0;
739
740     s = k.dptr;
741     ch = *s++;
742
743     skip_whitespace(s, ch);
744     if(ch == '\0') return 0;
745     fp = hostname;
746     while(ch && ch != ':') {
747         if(fp >= hostname+hostname_size-1) {
748             fp = NULL;
749             break;
750         }
751         *fp = ch;
752         ch = *s++;
753     }
754     if(fp == NULL) return 0;
755     *fp = '\0';
756
757     if(ch != ':') return 0;
758     ch = *s++;
759     copy_string(s, ch, diskname, diskname_size, fp);
760     if(fp == NULL) return 0;
761
762     return 1;
763 #endif
764 }
765
766
767 int
768 get_nextkey(
769     char *      hostname,
770     int         hostname_size,
771     char *      diskname,
772     int         diskname_size)
773 {
774 #ifdef TEXTDB
775     (void)hostname;             /* Quiet unused parameter warning */
776     (void)hostname_size;        /* Quiet unused parameter warning */
777     (void)diskname;             /* Quiet unused parameter warning */
778     (void)diskname_size;        /* Quiet unused parameter warning */
779
780     assert(0);
781     return 0;
782 #else
783     datum k;
784     int rc;
785     char *s, *fp;
786     int ch;
787
788     k = dbm_nextkey(infodb);
789     if(k.dptr == NULL) return 0;
790
791     s = k.dptr;
792     ch = *s++;
793
794     skip_whitespace(s, ch);
795     if(ch == '\0') return 0;
796     fp = hostname;
797     while(ch && ch != ':') {
798         if(fp >= hostname+hostname_size-1) {
799             fp = NULL;
800             break;
801         }
802         *fp = ch;
803         ch = *s++;
804     }
805     if(fp == NULL) return 0;
806     *fp = '\0';
807
808     if(ch != ':') return 0;
809     ch = *s++;
810     copy_string(s, ch, diskname, diskname_size, fp);
811     if(fp == NULL) return 0;
812
813     return 1;
814 #endif
815 }
816
817
818 int
819 put_info(
820      char *     hostname,
821      char *     diskname,
822      info_t *   info)
823 {
824 #ifdef TEXTDB
825     FILE *infof;
826     int rc;
827
828     infof = open_txinfofile(hostname, diskname, "w");
829
830     if(infof == NULL) return -1;
831
832     rc = write_txinfofile(infof, info);
833
834     rc = rc || close_txinfofile(infof);
835
836     return rc;
837 #else
838     datum k, d;
839     int maxlev;
840
841     /* setup key */
842
843     k.dptr = vstralloc(hostname, ":", diskname, NULL);
844     k.dsize = strlen(k.dptr)+1;
845
846     d.dptr = (char *)info;
847     d.dsize = SIZEOF(info_t);
848
849     /* store record */
850
851     if(dbm_store(infodb, k, d, DBM_REPLACE) != 0) {
852         amfree(k.dptr);
853         return -1;
854     }
855
856     amfree(k.dptr);
857     return 0;
858 #endif
859 }
860
861
862 int
863 del_info(
864     char *      hostname,
865     char *      diskname)
866 {
867 #ifdef TEXTDB
868     return delete_txinfofile(hostname, diskname);
869 #else
870     char key[MAX_KEY];
871     datum k;
872
873     /* setup key */
874
875     k.dptr = vstralloc(hostname, ":", diskname, NULL);
876     k.dsize = strlen(key)+1;
877
878     /* delete key and record */
879
880     if(dbm_delete(infodb, k) != 0) {
881         amfree(k.dptr);
882         return -1;
883     }
884     amfree(k.dptr);
885     return 0;
886 #endif
887 }
888
889
890 #ifdef TEST
891
892 void dump_rec(info_t *info);
893
894 void
895 dump_rec(
896     info_t *    info)
897 {
898     int i;
899     stats_t *sp;
900
901     printf("command word: %d\n", info->command);
902     printf("full dump rate (K/s) %5.1lf, %5.1lf, %5.1lf\n",
903            info->full.rate[0],info->full.rate[1],info->full.rate[2]);
904     printf("full comp rate %5.1lf, %5.1lf, %5.1lf\n",
905            info->full.comp[0]*100,info->full.comp[1]*100,info->full.comp[2]*100);
906     printf("incr dump rate (K/s) %5.1lf, %5.1lf, %5.1lf\n",
907            info->incr.rate[0],info->incr.rate[1],info->incr.rate[2]);
908     printf("incr comp rate %5.1lf, %5.1lf, %5.1lf\n",
909            info->incr.comp[0]*100,info->incr.comp[1]*100,info->incr.comp[2]*100);
910     for(i = 0; i < DUMP_LEVELS; i++) {
911         sp = &info->inf[i];
912         if( sp->size != -1) {
913
914             printf("lev %d date %ld tape %s filenum " OFF_T_FMT " size %ld csize %ld secs %ld\n",
915                    i, (long)sp->date, sp->label, sp->filenum,
916                    sp->size, sp->csize, sp->secs);
917         }
918     }
919     putchar('\n');
920    printf("last_level: %d %d\n", info->last_level, info->consecutive_runs);
921 }
922
923 #ifdef TEXTDB
924 void dump_db( char *host, char *disk);
925
926 void
927 dump_db(
928     char *      host,
929     char *      disk)
930 {
931     info_t info;
932     int rc;
933
934     if((rc = get_info(host, disk, &info)) == 0) {
935         dump_rec(&info);
936     } else {
937         printf("cannot fetch information for %s:%s rc=%d\n", host, disk, rc);
938     }
939 }
940 #else
941 void
942 dump_db(
943     char *      str)
944 {
945     datum k,d;
946     int rec,r,num;
947     info_t info;
948
949
950     printf("info database %s:\n--------\n", str);
951     rec = 0;
952     k = dbm_firstkey(infodb);
953     while(k.dptr != NULL) {
954
955         printf("%3d: KEY %s =\n", rec, k.dptr);
956
957         d = dbm_fetch(infodb, k);
958         memset(&info, '\0', SIZEOF(info));
959         memcpy(&info, d.dptr, d.dsize);
960
961         num = (d.dsize-HEADER)/SIZEOF(stats_t);
962         dump_rec(&info);
963
964         k = dbm_nextkey(infodb);
965         rec++;
966     }
967     puts("--------\n");
968 }
969 #endif
970
971 int
972 main(
973     int         argc,
974     char **     argv)
975 {
976   int i;
977   unsigned long malloc_hist_1, malloc_size_1;
978   unsigned long malloc_hist_2, malloc_size_2;
979
980   safe_fd(-1, 0);
981
982   set_pname("infofile");
983
984   dbopen(DBG_SUBDIR_SERVER);
985
986   malloc_size_1 = malloc_inuse(&malloc_hist_1);
987
988   for(i = 1; i < argc; ++i) {
989 #ifdef TEXTDB
990     if(i+1 >= argc) {
991       fprintf(stderr,"usage: %s host disk [host disk ...]\n",argv[0]);
992       return 1;
993     }
994     open_infofile("curinfo");
995     dump_db(argv[i], argv[i+1]);
996     i++;
997 #else
998     open_infofile(argv[i]);
999     dump_db(argv[i]);
1000 #endif
1001     close_infofile();
1002   }
1003
1004   malloc_size_2 = malloc_inuse(&malloc_hist_2);
1005
1006   if(malloc_size_1 != malloc_size_2) {
1007     malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
1008   }
1009
1010   return 0;
1011 }
1012
1013 #endif /* TEST */