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.8.5 2005/09/30 19:13:36 martinea 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 */
140 /* get version: command: lines */
142 if((line = agets(infof)) == NULL) return -1;
143 rc = sscanf(line, "version: %d", &version);
145 if(rc != 1) return -2;
147 if((line = agets(infof)) == NULL) return -1;
148 rc = sscanf(line, "command: %d", &info->command);
150 if(rc != 1) return -2;
152 /* get rate: and comp: lines for full dumps */
156 if((line = agets(infof)) == NULL) return -1;
157 rc = sscanf(line, "full-rate: %f %f %f",
158 &pp->rate[0], &pp->rate[1], &pp->rate[2]);
160 if(rc > 3) return -2;
162 if((line = agets(infof)) == NULL) return -1;
163 rc = sscanf(line, "full-comp: %f %f %f",
164 &pp->comp[0], &pp->comp[1], &pp->comp[2]);
166 if(rc > 3) return -2;
168 /* get rate: and comp: lines for incr dumps */
172 if((line = agets(infof)) == NULL) return -1;
173 rc = sscanf(line, "incr-rate: %f %f %f",
174 &pp->rate[0], &pp->rate[1], &pp->rate[2]);
176 if(rc > 3) return -2;
178 if((line = agets(infof)) == NULL) return -1;
179 rc = sscanf(line, "incr-comp: %f %f %f",
180 &pp->comp[0], &pp->comp[1], &pp->comp[2]);
182 if(rc > 3) return -2;
184 /* get stats for dump levels */
186 for(rc = -2; (line = agets(infof)) != NULL; free(line)) {
187 stats_t onestat; /* one stat record */
191 if(line[0] == '/' && line[1] == '/') {
194 return 0; /* normal end of record */
196 else if (strncmp(line,"last_level:",11) == 0) {
199 else if (strncmp(line,"history:",8) == 0) {
202 memset(&onestat, 0, sizeof(onestat));
208 if(strncmp(line, sc, sizeof(sc)-1) != 0) {
215 skip_whitespace(s, ch);
216 if(ch == '\0' || sscanf((s - 1), "%d", &level) != 1) {
221 skip_whitespace(s, ch);
222 if(ch == '\0' || sscanf((s - 1), "%ld", &onestat.size) != 1) {
227 skip_whitespace(s, ch);
228 if(ch == '\0' || sscanf((s - 1), "%ld", &onestat.csize) != 1) {
233 skip_whitespace(s, ch);
234 if(ch == '\0' || sscanf((s - 1), "%ld", &onestat.secs) != 1) {
239 skip_whitespace(s, ch);
240 if(ch == '\0' || sscanf((s - 1), "%ld", &date) != 1) {
245 skip_whitespace(s, ch);
247 if(sscanf((s - 1), "%d", &onestat.filenum) != 1) {
252 skip_whitespace(s, ch);
256 strncpy(onestat.label, s-1, sizeof(onestat.label)-1);
257 onestat.label[sizeof(onestat.label)-1] = '\0';
260 onestat.date = date; /* time_t not guarranteed to be long */
262 if(level < 0 || level > DUMP_LEVELS-1) break;
264 info->inf[level] = onestat;
267 if(line == NULL) return -1;
269 rc = sscanf(line, "last_level: %d %d",
270 &info->last_level, &info->consecutive_runs);
273 if(rc > 2) return -2;
277 for(i=0;i<=NB_HISTORY;i++) {
278 info->history[i].level = -2;
280 for(rc = -2; (line = agets(infof)) != NULL; free(line)) {
281 history_t onehistory; /* one history record */
284 if(line[0] == '/' && line[1] == '/') {
285 info->history[nb_history].level = -2;
288 return 0; /* normal end of record */
291 memset(&onehistory, 0, sizeof(onehistory));
296 #define sc "history:"
297 if(strncmp(line, sc, sizeof(sc)-1) != 0) {
304 skip_whitespace(s, ch);
305 if(ch == '\0' || sscanf((s - 1), "%d", &onehistory.level) != 1) {
310 skip_whitespace(s, ch);
311 if(ch == '\0' || sscanf((s - 1), "%ld", &onehistory.size) != 1) {
316 skip_whitespace(s, ch);
317 if(ch == '\0' || sscanf((s - 1), "%ld", &onehistory.csize) != 1) {
322 skip_whitespace(s, ch);
323 if(ch == '\0' || sscanf((s - 1), "%ld", &date) != 1) {
328 onehistory.date = date; /* time_t not guarranteed to be long */
330 onehistory.secs = -1;
331 skip_whitespace(s, ch);
333 if(sscanf((s - 1), "%ld", &onehistory.secs) != 1) {
339 info->history[nb_history++] = onehistory;
342 if((line = agets(infof)) == NULL) return -1; /* // line */
348 int write_txinfofile(infof, info)
357 fprintf(infof, "version: %d\n", 0);
359 fprintf(infof, "command: %d\n", info->command);
363 fprintf(infof, "full-rate:");
364 for(i=0; i<AVG_COUNT; i++)
365 if(pp->rate[i] >= 0.0)
366 fprintf(infof, " %f", pp->rate[i]);
367 fprintf(infof, "\n");
369 fprintf(infof, "full-comp:");
370 for(i=0; i<AVG_COUNT; i++)
371 if(pp->comp[i] >= 0.0)
372 fprintf(infof, " %f", pp->comp[i]);
373 fprintf(infof, "\n");
377 fprintf(infof, "incr-rate:");
378 for(i=0; i<AVG_COUNT; i++)
379 if(pp->rate[i] >= 0.0)
380 fprintf(infof, " %f", pp->rate[i]);
381 fprintf(infof, "\n");
383 fprintf(infof, "incr-comp:");
384 for(i=0; i<AVG_COUNT; i++)
385 if(pp->comp[i] >= 0.0)
386 fprintf(infof, " %f", pp->comp[i]);
387 fprintf(infof, "\n");
389 for(level=0; level<DUMP_LEVELS; level++) {
390 sp = &info->inf[level];
392 if(sp->date < (time_t)0 && sp->label[0] == '\0') continue;
394 fprintf(infof, "stats: %d %ld %ld %ld %ld", level,
395 sp->size, sp->csize, sp->secs, (long)sp->date);
396 if(sp->label[0] != '\0')
397 fprintf(infof, " %d %s", sp->filenum, sp->label);
398 fprintf(infof, "\n");
401 fprintf(infof, "last_level: %d %d\n", info->last_level, info->consecutive_runs);
403 for(i=0;info->history[i].level > -1;i++) {
404 fprintf(infof, "history: %d %ld %ld %ld %ld\n",info->history[i].level,
405 info->history[i].size, info->history[i].csize,
406 info->history[i].date, info->history[i].secs);
408 fprintf(infof, "//\n");
413 int delete_txinfofile(host, disk)
417 char *fn = NULL, *fn_new = NULL;
420 host = sanitise_filename(host);
421 disk = sanitise_filename(disk);
422 fn = vstralloc(infodir,
427 fn_new = stralloc2(fn, ".new");
435 rc = rmpdir(fn, infodir);
443 static char *lockname = NULL;
446 int open_infofile(filename)
450 assert(infodir == (char *)0);
452 infodir = stralloc(filename);
454 return 0; /* success! */
456 /* lock the dbm file */
458 lockname = newstralloc2(lockname, filename, ".lck");
459 if((lockfd = open(lockname, O_CREAT|O_RDWR, 0644)) == -1)
462 if(amflock(lockfd, "info") == -1) {
468 if(!(infodb = dbm_open(filename, O_CREAT|O_RDWR, 0644))) {
469 amfunlock(lockfd, "info");
475 return (infodb == NULL); /* return 1 on error */
479 void close_infofile()
482 assert(infodir != (char *)0);
488 if(amfunlock(lockfd, "info") == -1)
489 error("could not unlock infofile: %s", strerror(errno));
498 /* Convert a dump level to a GMT based time stamp */
499 char *get_dumpdate(info, lev)
503 static char stamp[20]; /* YYYY:MM:DD:hh:mm:ss */
510 for(l = 0; l < lev; l++) {
511 this = info->inf[l].date;
512 if (this > last) last = this;
516 ap_snprintf(stamp, sizeof(stamp), "%d:%d:%d:%d:%d:%d",
517 t->tm_year+1900, t->tm_mon+1, t->tm_mday,
518 t->tm_hour, t->tm_min, t->tm_sec);
523 double perf_average(a, d)
524 /* Weighted average */
525 float *a; /* array of items to average */
526 double d; /* default value */
528 double sum; /* running total */
529 int n; /* number of items in sum */
536 for(i = 0; i < AVG_COUNT; i++) {
553 memset(info, '\0', sizeof(info_t));
555 for(i = 0; i < AVG_COUNT; i++) {
556 info->full.comp[i] = info->incr.comp[i] = -1.0;
557 info->full.rate[i] = info->incr.rate[i] = -1.0;
560 for(i = 0; i < DUMP_LEVELS; i++) {
561 info->inf[i].date = (time_t)-1;
564 info->last_level = -1;
565 info->consecutive_runs = -1;
567 for(i=0;i<=NB_HISTORY;i++) {
568 info->history[i].level = -2;
569 info->history[i].size = 0;
570 info->history[i].csize = 0;
571 info->history[i].date = 0;
576 int get_info(hostname, diskname, info)
577 char *hostname, *diskname;
582 (void) zero_info(info);
588 infof = open_txinfofile(hostname, diskname, "r");
591 rc = -1; /* record not found */
594 rc = read_txinfofile(infof, info);
596 close_txinfofile(infof);
603 k.dptr = vstralloc(hostname, ":", diskname, NULL);
604 k.dsize = strlen(k.dptr)+1;
608 d = dbm_fetch(infodb, k);
611 rc = -1; /* record not found */
614 memcpy(info, d.dptr, d.dsize);
624 int get_firstkey(hostname, hostname_size, diskname, diskname_size)
625 char *hostname, *diskname;
626 int hostname_size, diskname_size;
637 k = dbm_firstkey(infodb);
638 if(k.dptr == NULL) return 0;
643 skip_whitespace(s, ch);
644 if(ch == '\0') return 0;
646 while(ch && ch != ':') {
647 if(fp >= hostname+hostname_size-1) {
654 if(fp == NULL) return 0;
657 if(ch != ':') return 0;
659 copy_string(s, ch, diskname, diskname_size, fp);
660 if(fp == NULL) return 0;
667 int get_nextkey(hostname, hostname_size, diskname, diskname_size)
668 char *hostname, *diskname;
669 int hostname_size, diskname_size;
680 k = dbm_nextkey(infodb);
681 if(k.dptr == NULL) return 0;
686 skip_whitespace(s, ch);
687 if(ch == '\0') return 0;
689 while(ch && ch != ':') {
690 if(fp >= hostname+hostname_size-1) {
697 if(fp == NULL) return 0;
700 if(ch != ':') return 0;
702 copy_string(s, ch, diskname, diskname_size, fp);
703 if(fp == NULL) return 0;
710 int put_info(hostname, diskname, info)
711 char *hostname, *diskname;
718 infof = open_txinfofile(hostname, diskname, "w");
720 if(infof == NULL) return -1;
722 rc = write_txinfofile(infof, info);
724 rc = rc || close_txinfofile(infof);
733 k.dptr = vstralloc(hostname, ":", diskname, NULL);
734 k.dsize = strlen(k.dptr)+1;
736 d.dptr = (char *)info;
737 d.dsize = sizeof(info_t);
741 if(dbm_store(infodb, k, d, DBM_REPLACE) != 0) {
752 int del_info(hostname, diskname)
753 char *hostname, *diskname;
756 return delete_txinfofile(hostname, diskname);
763 k.dptr = vstralloc(hostname, ":", diskname, NULL);
764 k.dsize = strlen(key)+1;
766 /* delete key and record */
768 if(dbm_delete(infodb, k) != 0) {
786 printf("command word: %d\n", info->command);
787 printf("full dump rate (K/s) %5.1f, %5.1f, %5.1f\n",
788 info->full.rate[0],info->full.rate[1],info->full.rate[2]);
789 printf("full comp rate %5.1f, %5.1f, %5.1f\n",
790 info->full.comp[0]*100,info->full.comp[1]*100,info->full.comp[2]*100);
791 printf("incr dump rate (K/s) %5.1f, %5.1f, %5.1f\n",
792 info->incr.rate[0],info->incr.rate[1],info->incr.rate[2]);
793 printf("incr comp rate %5.1f, %5.1f, %5.1f\n",
794 info->incr.comp[0]*100,info->incr.comp[1]*100,info->incr.comp[2]*100);
795 for(i = 0; i < DUMP_LEVELS; i++) {
797 if( sp->size != -1) {
799 printf("lev %d date %ld tape %s filenum %d size %ld csize %ld secs %ld\n",
800 i, (long)sp->date, sp->label, sp->filenum,
801 sp->size, sp->csize, sp->secs);
805 printf("last_level: %d %d\n", info->last_level, info->consecutive_runs);
809 void dump_db(host, disk)
815 if((rc = get_info(host, disk, &info)) == 0) {
818 printf("cannot fetch information for %s:%s rc=%d\n", host, disk, rc);
830 printf("info database %s:\n--------\n", str);
832 k = dbm_firstkey(infodb);
833 while(k.dptr != NULL) {
835 printf("%3d: KEY %s =\n", rec, k.dptr);
837 d = dbm_fetch(infodb, k);
838 memset(&info, '\0', sizeof(info));
839 memcpy(&info, d.dptr, d.dsize);
841 num = (d.dsize-HEADER)/sizeof(stats_t);
844 k = dbm_nextkey(infodb);
857 unsigned long malloc_hist_1, malloc_size_1;
858 unsigned long malloc_hist_2, malloc_size_2;
862 set_pname("infofile");
864 malloc_size_1 = malloc_inuse(&malloc_hist_1);
866 for(i = 1; i < argc; ++i) {
869 fprintf(stderr,"usage: %s host disk [host disk ...]\n",argv[0]);
872 open_infofile("curinfo");
873 dump_db(argv[i], argv[i+1]);
876 open_infofile(argv[i]);
882 malloc_size_2 = malloc_inuse(&malloc_hist_2);
884 if(malloc_size_1 != malloc_size_2) {
885 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);