2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Author: James da Silva, Systems Design and Analysis Group
25 * Computer Science Department
26 * University of Maryland at College Park
29 * $Id: infofile.c,v 1.64 2006/07/25 18:18:48 martinea Exp $
31 * manage current info file
38 static void zero_info(info_t *);
40 static char *infodir = NULL;
41 static char *infofile = NULL;
42 static char *newinfofile;
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 *);
61 assert(infofile == (char *)0);
63 writing = (*mode == 'w');
65 myhost = sanitise_filename(host);
66 mydisk = sanitise_filename(disk);
68 infofile = vstralloc(infodir,
77 /* create the directory structure if in write mode */
79 if (mkpdir(infofile, 0755, (uid_t)-1, (gid_t)-1) == -1) {
85 newinfofile = stralloc2(infofile, ".new");
88 infof = fopen(newinfofile, mode);
90 amflock(fileno(infof), "info");
93 infof = fopen(infofile, mode);
94 /* no need to lock readers */
97 if(infof == (FILE *)0) {
112 assert(infofile != (char *)0);
115 rc = rename(newinfofile, infofile);
117 amfunlock(fileno(infof), "info");
123 rc = rc || fclose(infof);
130 /* XXX - code assumes AVG_COUNT == 3 */
145 /* get version: command: lines */
147 while ((line = agets(infof)) != NULL) {
152 if (line == NULL) return -1;
153 rc = sscanf(line, _("version: %d"), &version);
155 if(rc != 1) return -2;
157 while ((line = agets(infof)) != NULL) {
162 if (line == NULL) return -1;
163 rc = sscanf(line, _("command: %u"), &info->command);
165 if(rc != 1) return -2;
167 /* get rate: and comp: lines for full dumps */
171 while ((line = agets(infof)) != NULL) {
176 if (line == NULL) return -1;
177 rc = sscanf(line, "full-rate: %lf %lf %lf",
178 &pp->rate[0], &pp->rate[1], &pp->rate[2]);
180 if(rc > 3) return -2;
182 while ((line = agets(infof)) != NULL) {
187 if (line == NULL) return -1;
188 rc = sscanf(line, "full-comp: %lf %lf %lf",
189 &pp->comp[0], &pp->comp[1], &pp->comp[2]);
191 if(rc > 3) return -2;
193 /* get rate: and comp: lines for incr dumps */
197 while ((line = agets(infof)) != NULL) {
202 if (line == NULL) return -1;
203 rc = sscanf(line, "incr-rate: %lf %lf %lf",
204 &pp->rate[0], &pp->rate[1], &pp->rate[2]);
206 if(rc > 3) return -2;
208 while ((line = agets(infof)) != NULL) {
213 if (line == NULL) return -1;
214 rc = sscanf(line, "incr-comp: %lf %lf %lf",
215 &pp->comp[0], &pp->comp[1], &pp->comp[2]);
217 if(rc > 3) return -2;
219 /* get stats for dump levels */
221 for(rc = -2; (line = agets(infof)) != NULL; free(line)) {
222 stats_t onestat; /* one stat record */
228 if(line[0] == '/' && line[1] == '/') {
231 return 0; /* normal end of record */
233 else if (strncmp_const(line,"last_level:") == 0) {
236 else if (strncmp_const(line,"history:") == 0) {
239 memset(&onestat, 0, SIZEOF(onestat));
244 /* from here on, we had better be parsing a 'stats' line */
245 if(strncmp_const_skip(line, "stats:", s, ch) != 0) {
249 skip_whitespace(s, ch);
250 if(ch == '\0' || sscanf((s - 1), "%d", &level) != 1) {
255 skip_whitespace(s, ch);
256 if(ch == '\0' || sscanf((s - 1), "%lld", &off_t_tmp) != 1) {
259 onestat.size = (off_t)off_t_tmp;
262 skip_whitespace(s, ch);
263 if(ch == '\0' || sscanf((s - 1), "%lld", &off_t_tmp) != 1) {
266 onestat.csize = (off_t)off_t_tmp;
269 /* assume that the time fits in a long long */
270 skip_whitespace(s, ch);
271 if(ch == '\0' || sscanf((s - 1), "%lld", &off_t_tmp) != 1) {
274 onestat.secs = (time_t)off_t_tmp;
277 skip_whitespace(s, ch);
278 if(ch == '\0' || sscanf((s - 1), "%lld", &off_t_tmp) != 1) {
281 onestat.date = (time_t)off_t_tmp;
284 skip_whitespace(s, ch);
286 if(sscanf((s - 1), "%lld", &off_t_tmp) != 1) {
289 onestat.filenum = (off_t)off_t_tmp;
292 skip_whitespace(s, ch);
296 strncpy(onestat.label, s-1, SIZEOF(onestat.label)-1);
297 onestat.label[SIZEOF(onestat.label)-1] = '\0';
300 if(level < 0 || level > DUMP_LEVELS-1)
303 info->inf[level] = onestat;
306 if(line == NULL) return -1;
308 rc = sscanf(line, "last_level: %d %d",
309 &info->last_level, &info->consecutive_runs);
312 if(rc > 2) return -2;
316 for(i=0;i<=NB_HISTORY;i++) {
317 info->history[i].level = -2;
320 for(rc = -2; (line = agets(infof)) != NULL; free(line)) {
321 history_t onehistory; /* one history record */
326 if(line[0] == '/' && line[1] == '/') {
327 info->history[nb_history].level = -2;
330 return 0; /* normal end of record */
333 memset(&onehistory, 0, SIZEOF(onehistory));
338 if(strncmp_const_skip(line, "history:", s, ch) != 0) {
343 skip_whitespace(s, ch);
344 if(ch == '\0' || sscanf((s - 1), "%d", &onehistory.level) != 1) {
350 skip_whitespace(s, ch);
351 if(ch == '\0' || sscanf((s - 1), "%lld", &off_t_tmp) != 1) {
355 onehistory.size = (off_t)off_t_tmp;
358 skip_whitespace(s, ch);
359 if(ch == '\0' || sscanf((s - 1), "%lld", &off_t_tmp) != 1) {
363 onehistory.csize = (off_t)off_t_tmp;
366 skip_whitespace(s, ch);
367 if(ch == '\0' || sscanf((s - 1), "%lld", &off_t_tmp) != 1) {
371 onehistory.date = (time_t)off_t_tmp;
374 onehistory.secs = (unsigned long)-1;
375 skip_whitespace(s, ch);
377 if(sscanf((s - 1), "%lld", &off_t_tmp) != 1) {
381 onehistory.secs = (time_t)off_t_tmp;
385 info->history[nb_history++] = onehistory;
389 while ((line = agets(infof)) != NULL) {
394 if (line == NULL) return -1;
410 g_fprintf(infof, _("version: %d\n"), 0);
412 g_fprintf(infof, _("command: %u\n"), info->command);
416 g_fprintf(infof, "full-rate:");
417 for(i=0; i<AVG_COUNT; i++)
418 if(pp->rate[i] >= 0.0)
419 g_fprintf(infof, " %lf", pp->rate[i]);
420 g_fprintf(infof, "\n");
422 g_fprintf(infof, "full-comp:");
423 for(i=0; i<AVG_COUNT; i++)
424 if(pp->comp[i] >= 0.0)
425 g_fprintf(infof, " %lf", pp->comp[i]);
426 g_fprintf(infof, "\n");
430 g_fprintf(infof, "incr-rate:");
431 for(i=0; i<AVG_COUNT; i++)
432 if(pp->rate[i] >= 0.0)
433 g_fprintf(infof, " %lf", pp->rate[i]);
434 g_fprintf(infof, "\n");
436 g_fprintf(infof, "incr-comp:");
437 for(i=0; i<AVG_COUNT; i++)
438 if(pp->comp[i] >= 0.0)
439 g_fprintf(infof, " %lf", pp->comp[i]);
440 g_fprintf(infof, "\n");
442 for(level=0; level<DUMP_LEVELS; level++) {
443 sp = &info->inf[level];
445 if(sp->date < (time_t)0 && sp->label[0] == '\0') continue;
447 g_fprintf(infof, "stats: %d %lld %lld %jd %lld",
448 level, (long long)sp->size, (long long)sp->csize,
449 (intmax_t)sp->secs, (long long)sp->date);
450 if(sp->label[0] != '\0')
451 g_fprintf(infof, " %lld %s", (long long)sp->filenum, sp->label);
452 g_fprintf(infof, "\n");
455 g_fprintf(infof, _("last_level: %d %d\n"), info->last_level, info->consecutive_runs);
457 for(i=0;info->history[i].level > -1;i++) {
458 g_fprintf(infof, _("history: %d %lld %lld %jd %jd\n"),
459 info->history[i].level,
460 (long long)info->history[i].size,
461 (long long)info->history[i].csize,
462 (intmax_t)info->history[i].date,
463 (intmax_t)info->history[i].secs);
465 g_fprintf(infof, "//\n");
475 char *fn = NULL, *fn_new = NULL;
480 myhost = sanitise_filename(host);
481 mydisk = sanitise_filename(disk);
482 fn = vstralloc(infodir,
487 fn_new = stralloc2(fn, ".new");
495 rc = rmpdir(fn, infodir);
505 assert(infodir == NULL);
507 infodir = stralloc(filename);
509 return 0; /* success! */
515 assert(infodir != NULL);
520 /* Convert a dump level to a GMT based time stamp */
526 static char stamp[20]; /* YYYY:MM:DD:hh:mm:ss */
533 for(l = 0; l < lev; l++) {
534 this = info->inf[l].date;
535 if (this > last) last = this;
539 g_snprintf(stamp, SIZEOF(stamp), "%d:%d:%d:%d:%d:%d",
540 t->tm_year+1900, t->tm_mon+1, t->tm_mday,
541 t->tm_hour, t->tm_min, t->tm_sec);
551 double * a, /* array of items to average */
552 double d) /* default value */
554 double sum; /* running total */
555 int n; /* number of items in sum */
562 for(i = 0; i < AVG_COUNT; i++) {
580 memset(info, '\0', SIZEOF(info_t));
582 for(i = 0; i < AVG_COUNT; i++) {
583 info->full.comp[i] = info->incr.comp[i] = -1.0;
584 info->full.rate[i] = info->incr.rate[i] = -1.0;
587 for(i = 0; i < DUMP_LEVELS; i++) {
588 info->inf[i].date = (time_t)-1;
591 info->last_level = -1;
592 info->consecutive_runs = -1;
594 for(i=0;i<=NB_HISTORY;i++) {
595 info->history[i].level = -2;
596 info->history[i].size = (off_t)0;
597 info->history[i].csize = (off_t)0;
598 info->history[i].date = 0UL;
611 (void) zero_info(info);
616 infof = open_txinfofile(hostname, diskname, "r");
619 rc = -1; /* record not found */
622 rc = read_txinfofile(infof, info);
624 close_txinfofile(infof);
641 infof = open_txinfofile(hostname, diskname, "w");
643 if(infof == NULL) return -1;
645 rc = write_txinfofile(infof, info);
647 rc = rc || close_txinfofile(infof);
658 return delete_txinfofile(hostname, diskname);
664 void dump_rec(info_t *info);
673 g_printf(_("command word: %d\n"), info->command);
674 g_printf(_("full dump rate (K/s) %5.1lf, %5.1lf, %5.1lf\n"),
675 info->full.rate[0],info->full.rate[1],info->full.rate[2]);
676 g_printf(_("full comp rate %5.1lf, %5.1lf, %5.1lf\n"),
677 info->full.comp[0]*100,info->full.comp[1]*100,info->full.comp[2]*100);
678 g_printf(_("incr dump rate (K/s) %5.1lf, %5.1lf, %5.1lf\n"),
679 info->incr.rate[0],info->incr.rate[1],info->incr.rate[2]);
680 g_printf(_("incr comp rate %5.1lf, %5.1lf, %5.1lf\n"),
681 info->incr.comp[0]*100,info->incr.comp[1]*100,info->incr.comp[2]*100);
682 for(i = 0; i < DUMP_LEVELS; i++) {
684 if( sp->size != -1) {
686 g_printf(_("lev %d date %ld tape %s filenum %lld size %ld csize %ld secs %ld\n"),
687 i, (long)sp->date, sp->label, sp->filenum,
688 sp->size, sp->csize, sp->secs);
692 g_printf(_("last_level: %d %d\n"), info->last_level, info->consecutive_runs);
695 void dump_db( char *host, char *disk);
705 if((rc = get_info(host, disk, &info)) == 0) {
708 g_printf(_("cannot fetch information for %s:%s rc=%d\n"), host, disk, rc);
720 * Configure program for internationalization:
721 * 1) Only set the message locale for now.
722 * 2) Set textdomain for all amanda related programs to "amanda"
723 * We don't want to be forced to support dozens of message catalogs.
725 setlocale(LC_MESSAGES, "C");
726 textdomain("amanda");
730 set_pname("infofile");
732 dbopen(DBG_SUBDIR_SERVER);
734 for(i = 1; i < argc; ++i) {
736 g_fprintf(stderr,_("usage: %s host disk [host disk ...]\n"),argv[0]);
739 open_infofile("curinfo");
740 dump_db(argv[i], argv[i+1]);