2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
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.
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.
23 * Author: James da Silva, Systems Design and Analysis Group
24 * Computer Science Department
25 * University of Maryland at College Park
28 * $Id: infofile.c,v 1.44.4.4 1999/11/10 14:36:10 oliva Exp $
30 * manage current info file
38 static char *infodir = (char *)0;
39 static char *infofile = (char *)0;
40 static char *newinfofile;
44 /*# define HEADER (sizeof(info_t)-DUMP_LEVELS*sizeof(stats_t))*/
46 static DBM *infodb = NULL;
52 FILE *open_txinfofile(host, disk, mode)
59 assert(infofile == (char *)0);
61 writing = (*mode == 'w');
63 host = sanitise_filename(host);
64 disk = sanitise_filename(disk);
66 infofile = vstralloc(infodir,
75 /* create the directory structure if in write mode */
77 if (mkpdir(infofile, 02755, (uid_t)-1, (gid_t)-1) == -1) {
83 newinfofile = stralloc2(infofile, ".new");
86 infof = fopen(newinfofile, mode);
88 amflock(fileno(infof), "info");
91 infof = fopen(infofile, mode);
92 /* no need to lock readers */
95 if(infof == (FILE *)0) {
104 int close_txinfofile(infof)
109 assert(infofile != (char *)0);
112 rc = rename(newinfofile, infofile);
114 amfunlock(fileno(infof), "info");
120 rc = rc || fclose(infof);
127 int read_txinfofile(infof, info) /* XXX - code assumes AVG_COUNT == 3 */
138 /* get version: command: lines */
140 if((line = agets(infof)) == NULL) return -1;
141 rc = sscanf(line, "version: %d", &version);
143 if(rc != 1) return -2;
145 if((line = agets(infof)) == NULL) return -1;
146 rc = sscanf(line, "command: %d", &info->command);
148 if(rc != 1) return -2;
150 /* get rate: and comp: lines for full dumps */
154 if((line = agets(infof)) == NULL) return -1;
155 rc = sscanf(line, "full-rate: %f %f %f",
156 &pp->rate[0], &pp->rate[1], &pp->rate[2]);
158 if(rc > 3) return -2;
160 if((line = agets(infof)) == NULL) return -1;
161 rc = sscanf(line, "full-comp: %f %f %f",
162 &pp->comp[0], &pp->comp[1], &pp->comp[2]);
164 if(rc > 3) return -2;
166 /* get rate: and comp: lines for incr dumps */
170 if((line = agets(infof)) == NULL) return -1;
171 rc = sscanf(line, "incr-rate: %f %f %f",
172 &pp->rate[0], &pp->rate[1], &pp->rate[2]);
174 if(rc > 3) return -2;
176 if((line = agets(infof)) == NULL) return -1;
177 rc = sscanf(line, "incr-comp: %f %f %f",
178 &pp->comp[0], &pp->comp[1], &pp->comp[2]);
180 if(rc > 3) return -2;
182 /* get stats for dump levels */
184 for(rc = -2; (line = agets(infof)) != NULL; free(line)) {
185 stats_t onestat; /* one stat record */
189 if(line[0] == '/' && line[1] == '/') {
192 return 0; /* normal end of record */
194 else if (strncmp(line,"last_level:",11) == 0) {
197 memset(&onestat, 0, sizeof(onestat));
203 if(strncmp(line, sc, sizeof(sc)-1) != 0) {
210 skip_whitespace(s, ch);
211 if(ch == '\0' || sscanf((s - 1), "%d", &level) != 1) {
216 skip_whitespace(s, ch);
217 if(ch == '\0' || sscanf((s - 1), "%ld", &onestat.size) != 1) {
222 skip_whitespace(s, ch);
223 if(ch == '\0' || sscanf((s - 1), "%ld", &onestat.csize) != 1) {
228 skip_whitespace(s, ch);
229 if(ch == '\0' || sscanf((s - 1), "%ld", &onestat.secs) != 1) {
234 skip_whitespace(s, ch);
235 if(ch == '\0' || sscanf((s - 1), "%ld", &date) != 1) {
240 skip_whitespace(s, ch);
242 if(sscanf((s - 1), "%d", &onestat.filenum) != 1) {
247 skip_whitespace(s, ch);
251 strncpy(onestat.label, s-1, sizeof(onestat.label)-1);
252 onestat.label[sizeof(onestat.label)-1] = '\0';
255 onestat.date = date; /* time_t not guarranteed to be long */
257 if(level < 0 || level > DUMP_LEVELS-1) break;
259 info->inf[level] = onestat;
262 if(line == NULL) return -1;
264 rc = sscanf(line, "last_level: %d %d",
265 &info->last_level, &info->consecutive_runs);
268 if(rc > 2) return -2;
271 if((line = agets(infof)) == NULL) return -1;
277 int write_txinfofile(infof, info)
286 fprintf(infof, "version: %d\n", 0);
288 fprintf(infof, "command: %d\n", info->command);
292 fprintf(infof, "full-rate:");
293 for(i=0; i<AVG_COUNT; i++)
294 if(pp->rate[i] >= 0.0)
295 fprintf(infof, " %f", pp->rate[i]);
296 fprintf(infof, "\n");
298 fprintf(infof, "full-comp:");
299 for(i=0; i<AVG_COUNT; i++)
300 if(pp->comp[i] >= 0.0)
301 fprintf(infof, " %f", pp->comp[i]);
302 fprintf(infof, "\n");
306 fprintf(infof, "incr-rate:");
307 for(i=0; i<AVG_COUNT; i++)
308 if(pp->rate[i] >= 0.0)
309 fprintf(infof, " %f", pp->rate[i]);
310 fprintf(infof, "\n");
312 fprintf(infof, "incr-comp:");
313 for(i=0; i<AVG_COUNT; i++)
314 if(pp->comp[i] >= 0.0)
315 fprintf(infof, " %f", pp->comp[i]);
316 fprintf(infof, "\n");
318 for(level=0; level<DUMP_LEVELS; level++) {
319 sp = &info->inf[level];
321 if(sp->date < (time_t)0 && sp->label[0] == '\0') continue;
323 fprintf(infof, "stats: %d %ld %ld %ld %ld", level,
324 sp->size, sp->csize, sp->secs, (long)sp->date);
325 if(sp->label[0] != '\0')
326 fprintf(infof, " %d %s", sp->filenum, sp->label);
327 fprintf(infof, "\n");
330 fprintf(infof, "last_level: %d %d\n", info->last_level, info->consecutive_runs);
331 fprintf(infof, "//\n");
336 int delete_txinfofile(host, disk)
340 char *fn = NULL, *fn_new = NULL;
343 host = sanitise_filename(host);
344 disk = sanitise_filename(disk);
345 fn = vstralloc(infodir,
350 fn_new = stralloc2(fn, ".new");
358 rc = rmpdir(fn, infodir);
366 static char *lockname = NULL;
369 int open_infofile(filename)
373 assert(infodir == (char *)0);
375 infodir = stralloc(filename);
377 return 0; /* success! */
379 /* lock the dbm file */
381 lockname = newstralloc2(lockname, filename, ".lck");
382 if((lockfd = open(lockname, O_CREAT|O_RDWR, 0644)) == -1)
385 if(amflock(lockfd, "info") == -1) {
391 if(!(infodb = dbm_open(filename, O_CREAT|O_RDWR, 0644))) {
392 amfunlock(lockfd, "info");
398 return (infodb == NULL); /* return 1 on error */
402 void close_infofile()
405 assert(infodir != (char *)0);
411 if(amfunlock(lockfd, "info") == -1)
412 error("could not unlock infofile: %s", strerror(errno));
421 /* Convert a dump level to a GMT based time stamp */
422 char *get_dumpdate(info, lev)
426 static char stamp[20]; /* YYYY:MM:DD:hh:mm:ss */
433 for(l = 0; l < lev; l++) {
434 this = info->inf[l].date;
435 if (this > last) last = this;
439 ap_snprintf(stamp, sizeof(stamp), "%d:%d:%d:%d:%d:%d",
440 t->tm_year+1900, t->tm_mon+1, t->tm_mday,
441 t->tm_hour, t->tm_min, t->tm_sec);
446 double perf_average(a, d)
447 /* Weighted average */
448 float *a; /* array of items to average */
449 double d; /* default value */
451 double sum; /* running total */
452 int n; /* number of items in sum */
459 for(i = 0; i < AVG_COUNT; i++) {
476 memset(info, '\0', sizeof(info_t));
478 for(i = 0; i < AVG_COUNT; i++) {
479 info->full.comp[i] = info->incr.comp[i] = -1.0;
480 info->full.rate[i] = info->incr.rate[i] = -1.0;
483 for(i = 0; i < DUMP_LEVELS; i++) {
484 info->inf[i].date = (time_t)-1;
487 info->last_level = -1;
488 info->consecutive_runs = -1;
493 int get_info(hostname, diskname, info)
494 char *hostname, *diskname;
499 (void) zero_info(info);
505 infof = open_txinfofile(hostname, diskname, "r");
508 rc = -1; /* record not found */
511 rc = read_txinfofile(infof, info);
513 close_txinfofile(infof);
520 k.dptr = vstralloc(hostname, ":", diskname, NULL);
521 k.dsize = strlen(k.dptr)+1;
525 d = dbm_fetch(infodb, k);
528 rc = -1; /* record not found */
531 memcpy(info, d.dptr, d.dsize);
541 int get_firstkey(hostname, hostname_size, diskname, diskname_size)
542 char *hostname, *diskname;
543 int hostname_size, diskname_size;
554 k = dbm_firstkey(infodb);
555 if(k.dptr == NULL) return 0;
560 skip_whitespace(s, ch);
561 if(ch == '\0') return 0;
563 while(ch && ch != ':') {
564 if(fp >= hostname+hostname_size-1) {
571 if(fp == NULL) return 0;
574 if(ch != ':') return 0;
576 copy_string(s, ch, diskname, diskname_size, fp);
577 if(fp == NULL) return 0;
584 int get_nextkey(hostname, hostname_size, diskname, diskname_size)
585 char *hostname, *diskname;
586 int hostname_size, diskname_size;
597 k = dbm_nextkey(infodb);
598 if(k.dptr == NULL) return 0;
603 skip_whitespace(s, ch);
604 if(ch == '\0') return 0;
606 while(ch && ch != ':') {
607 if(fp >= hostname+hostname_size-1) {
614 if(fp == NULL) return 0;
617 if(ch != ':') return 0;
619 copy_string(s, ch, diskname, diskname_size, fp);
620 if(fp == NULL) return 0;
627 int put_info(hostname, diskname, info)
628 char *hostname, *diskname;
635 infof = open_txinfofile(hostname, diskname, "w");
637 if(infof == NULL) return -1;
639 rc = write_txinfofile(infof, info);
641 rc = rc || close_txinfofile(infof);
650 k.dptr = vstralloc(hostname, ":", diskname, NULL);
651 k.dsize = strlen(k.dptr)+1;
653 d.dptr = (char *)info;
654 d.dsize = sizeof(info_t);
658 if(dbm_store(infodb, k, d, DBM_REPLACE) != 0) {
669 int del_info(hostname, diskname)
670 char *hostname, *diskname;
673 return delete_txinfofile(hostname, diskname);
680 k.dptr = vstralloc(hostname, ":", diskname, NULL);
681 k.dsize = strlen(key)+1;
683 /* delete key and record */
685 if(dbm_delete(infodb, k) != 0) {
703 printf("command word: %d\n", info->command);
704 printf("full dump rate (K/s) %5.1f, %5.1f, %5.1f\n",
705 info->full.rate[0],info->full.rate[1],info->full.rate[2]);
706 printf("full comp rate %5.1f, %5.1f, %5.1f\n",
707 info->full.comp[0]*100,info->full.comp[1]*100,info->full.comp[2]*100);
708 printf("incr dump rate (K/s) %5.1f, %5.1f, %5.1f\n",
709 info->incr.rate[0],info->incr.rate[1],info->incr.rate[2]);
710 printf("incr comp rate %5.1f, %5.1f, %5.1f\n",
711 info->incr.comp[0]*100,info->incr.comp[1]*100,info->incr.comp[2]*100);
712 for(i = 0; i < DUMP_LEVELS; i++) {
714 if( sp->size != -1) {
716 printf("lev %d date %ld tape %s filenum %d size %ld csize %ld secs %ld\n",
717 i, (long)sp->date, sp->label, sp->filenum,
718 sp->size, sp->csize, sp->secs);
722 printf("last_level: %d %d\n", info->last_level, info->consecutive_runs);
726 void dump_db(host, disk)
732 if((rc = get_info(host, disk, &info)) == 0) {
735 printf("cannot fetch information for %s:%s rc=%d\n", host, disk, rc);
747 printf("info database %s:\n--------\n", str);
749 k = dbm_firstkey(infodb);
750 while(k.dptr != NULL) {
752 printf("%3d: KEY %s =\n", rec, k.dptr);
754 d = dbm_fetch(infodb, k);
755 memset(&info, '\0', sizeof(info));
756 memcpy(&info, d.dptr, d.dsize);
758 num = (d.dsize-HEADER)/sizeof(stats_t);
761 k = dbm_nextkey(infodb);
775 unsigned long malloc_hist_1, malloc_size_1;
776 unsigned long malloc_hist_2, malloc_size_2;
778 for(fd = 3; fd < FD_SETSIZE; fd++) {
780 * Make sure nobody spoofs us with a lot of extra open files
781 * that would cause an open we do to get a very high file
782 * descriptor, which in turn might be used as an index into
783 * an array (e.g. an fd_set).
788 set_pname("infofile");
790 malloc_size_1 = malloc_inuse(&malloc_hist_1);
792 for(i = 1; i < argc; ++i) {
795 fprintf(stderr,"usage: %s host disk [host disk ...]\n",argv[0]);
798 open_infofile("curinfo");
799 dump_db(argv[i], argv[i+1]);
802 open_infofile(argv[i]);
808 malloc_size_2 = malloc_inuse(&malloc_hist_2);
810 if(malloc_size_1 != malloc_size_2) {
811 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);