2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998, 2000 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: reporter.c,v 1.132 2006/08/28 17:02:48 martinea Exp $
30 * nightly Amanda Report generator
51 /* don't have (or need) a skipped type except internally to reporter */
52 #define L_SKIPPED L_MARKER
54 typedef struct line_s {
59 typedef struct timedata_s {
61 double origsize, outsize;
68 typedef struct repdata_s {
71 double est_nsize, est_csize;
76 struct repdata_s *next;
79 #define data(dp) ((repdata_t *)(dp)->up)
81 static struct cumulative_stats {
82 int dumpdisks, tapedisks, tapechunks;
83 double taper_time, dumper_time;
84 double outsize, origsize, tapesize;
85 double coutsize, corigsize; /* compressed dump only */
88 static int dumpdisks[10], tapedisks[10], tapechunks[10]; /* by-level breakdown of disk count */
90 typedef struct taper_s {
93 double coutsize, corigsize;
94 int tapedisks, tapechunks;
98 static taper_t *stats_by_tape = NULL;
99 static taper_t *current_tape = NULL;
101 typedef struct strange_s {
106 struct strange_s *next;
109 static strange_t *first_strange=NULL, *last_strange=NULL;
111 static double total_time, startup_time, planner_time;
113 /* count files to tape */
114 static int tapefcount = 0;
116 static char *run_datestamp;
117 static char *tape_labels = NULL;
118 static int last_run_tapes = 0;
119 static int degraded_mode = 0; /* defined in driverio too */
120 static int normal_run = 0;
121 static int amflush_run = 0;
122 static int got_finish = 0;
124 static char *tapestart_error = NULL;
126 static FILE *logfile, *mailf;
128 static FILE *postscript;
129 static char *printer;
131 static disklist_t diskq;
132 static disklist_t sortq;
134 static line_t *errsum = NULL;
135 static line_t *errdet = NULL;
136 static line_t *notes = NULL;
138 static char MaxWidthsRequested = 0; /* determined via config data */
141 long int unitdivisor;
143 /* local functions */
144 int main(int argc, char **argv);
146 static char * nicedate(const char * datestamp);
147 static char * prefix(char *host, char *disk, int level);
148 static char * prefixstrange(char *host, char *disk, int level,
149 size_t len_host, size_t len_disk);
150 static char * Rule(int From, int To);
151 static char * sDivZero(double a, double b, int cn);
152 static char * TextRule(int From, int To, char *s);
153 static int ColWidth(int From, int To);
154 static int contline_next(void);
155 static int sort_by_name(disk_t *a, disk_t *b);
156 static repdata_t *find_repdata(disk_t *dp, char *datestamp, int level);
157 static repdata_t *handle_chunk(void);
158 static repdata_t *handle_success(logtype_t logtype);
159 static void addline(line_t **lp, char *str);
160 static void addtostrange(char *host, char *disk, int level, char *str);
161 static void bogus_line(const char *);
162 static void CalcMaxWidth(void);
163 static void CheckFloatMax(ColumnInfo *cd, double d);
164 static void CheckIntMax(ColumnInfo *cd, int n);
165 static void CheckStringMax(ColumnInfo *cd, char *s);
166 static void copy_template_file(char *lbl_templ);
167 static void do_postscript_output(void);
168 static void generate_missing(void);
169 static void generate_bad_estimate(void);
170 static void handle_disk(void);
171 static void handle_error(void);
172 static void handle_failed(void);
173 static void handle_finish(void);
174 static void handle_note(void);
175 static void handle_partial(void);
176 static void handle_start(void);
177 static void handle_stats(void);
178 static void handle_strange(void);
179 static void handle_summary(void);
180 static void output_lines(line_t *lp, FILE *f);
181 static void output_stats(void);
182 static void output_strange(void);
183 static void output_summary(void);
184 static void output_tapeinfo(void);
185 static void sort_disks(void);
186 static void usage(void);
194 for (i=From; i<=To && ColumnData[i].Name != NULL; i++) {
195 Width+= ColumnData[i].PrefixSpace + ColumnData[i].Width;
206 int Leng= ColWidth(0, ColumnDataCount());
207 char *RuleSpace= alloc((size_t)(Leng+1));
208 ThisLeng= ColWidth(From, To);
209 for (i=0;i<ColumnData[From].PrefixSpace; i++)
211 for (; i<ThisLeng; i++)
213 RuleSpace[ThisLeng]= '\0';
223 ColumnInfo *cd= &ColumnData[From];
225 int nbrules, i, txtlength;
226 int RuleSpaceSize= ColWidth(0, ColumnDataCount());
227 char *RuleSpace= alloc((size_t)RuleSpaceSize), *tmp;
229 leng = (int)strlen(s);
230 if(leng >= (RuleSpaceSize - cd->PrefixSpace))
231 leng = RuleSpaceSize - cd->PrefixSpace - 1;
232 snprintf(RuleSpace, (size_t)RuleSpaceSize, "%*s%*.*s ", cd->PrefixSpace, "",
234 txtlength = cd->PrefixSpace + leng + 1;
235 nbrules = ColWidth(From,To) - txtlength;
236 for(tmp=RuleSpace + txtlength, i=nbrules ; i>0; tmp++,i--)
248 ColumnInfo *cd= &ColumnData[cn];
249 static char PrtBuf[256];
251 snprintf(PrtBuf, SIZEOF(PrtBuf),
252 "%*s", cd->Width, "-- ");
254 snprintf(PrtBuf, SIZEOF(PrtBuf),
255 cd->Format, cd->Width, cd->Precision, a/b);
264 if ((ch = getc(logfile)) != EOF) {
265 if (ungetc(ch, logfile) == EOF) {
266 if (ferror(logfile)) {
267 error("ungetc failed: %s\n", strerror(errno));
270 error("ungetc failed: EOF\n");
284 /* allocate new line node */
285 new = (line_t *) alloc(SIZEOF(line_t));
287 new->str = stralloc(str);
289 /* add to end of list */
294 while (p->next != NULL)
303 error("Usage: amreport conf [-i] [-M address] [-f output-file] [-l logfile] [-p postscript-file] [-o configoption]*");
316 char *logfname, *psfname, *outfname, *subj_str = NULL;
319 unsigned long malloc_hist_1, malloc_size_1;
320 unsigned long malloc_hist_2, malloc_size_2;
321 char *mail_cmd = NULL, *printer_cmd = NULL;
323 char my_cwd[STR_SIZE];
324 char *ColumnSpec = "";
329 int new_argc, my_argc;
330 char **new_argv, **my_argv;
331 char *lbl_templ = NULL;
335 set_pname("amreport");
337 dbopen(DBG_SUBDIR_SERVER);
339 /* Don't die when child closes pipe */
340 signal(SIGPIPE, SIG_IGN);
342 malloc_size_1 = malloc_inuse(&malloc_hist_1);
344 /* Process options */
346 erroutput_type = ERR_INTERACTIVE;
351 if (getcwd(my_cwd, SIZEOF(my_cwd)) == NULL) {
352 error("cannot determine current working directory");
356 parse_server_conf(argc, argv, &new_argc, &new_argv);
361 config_dir = stralloc2(my_cwd, "/");
362 if ((config_name = strrchr(my_cwd, '/')) != NULL) {
363 config_name = stralloc(config_name + 1);
366 if (my_argv[1][0] == '-') {
370 config_name = stralloc(my_argv[1]);
371 config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
372 --my_argc; ++my_argv;
373 while((opt = getopt(my_argc, my_argv, "M:f:l:p:i")) != EOF) {
379 if (mailto != NULL) {
380 error("you may specify at most one -M");
383 mailto = stralloc(optarg);
384 if(!validate_mailto(mailto)) {
385 error("mail address has invalid characters");
390 if (outfname != NULL) {
391 error("you may specify at most one -f");
394 if (*optarg == '/') {
395 outfname = stralloc(optarg);
397 outfname = vstralloc(my_cwd, "/", optarg, NULL);
401 if (logfname != NULL) {
402 error("you may specify at most one -l");
405 if (*optarg == '/') {
406 logfname = stralloc(optarg);
408 logfname = vstralloc(my_cwd, "/", optarg, NULL);
412 if (psfname != NULL) {
413 error("you may specify at most one -p");
416 if (*optarg == '/') {
417 psfname = stralloc(optarg);
419 psfname = vstralloc(my_cwd, "/", optarg, NULL);
433 if( !mailout && mailto ){
434 printf("You cannot specify both -i & -M at the same time\n");
441 printf("You must run amreport with '-f <output file>' because configure\n");
442 printf("didn't find a mailer.\n");
449 /* read configuration files */
451 conffile = stralloc2(config_dir, CONFFILE_NAME);
452 /* Ignore error from read_conffile */
453 read_conffile(conffile);
456 dbrename(config_name, DBG_SUBDIR_SERVER);
458 report_bad_conf_arg();
459 conf_diskfile = getconf_str(CNF_DISKFILE);
460 if (*conf_diskfile == '/') {
461 conf_diskfile = stralloc(conf_diskfile);
463 conf_diskfile = stralloc2(config_dir, conf_diskfile);
465 /* Ignore error from read_diskfile */
466 read_diskfile(conf_diskfile, &diskq);
467 amfree(conf_diskfile);
468 if(mailout && !mailto &&
469 getconf_seen(CNF_MAILTO) && strlen(getconf_str(CNF_MAILTO)) > 0) {
470 mailto = getconf_str(CNF_MAILTO);
471 if(!validate_mailto(mailto)){
476 conf_tapelist = getconf_str(CNF_TAPELIST);
477 if (*conf_tapelist == '/') {
478 conf_tapelist = stralloc(conf_tapelist);
480 conf_tapelist = stralloc2(config_dir, conf_tapelist);
482 /* Ignore error from read_tapelist */
483 read_tapelist(conf_tapelist);
484 amfree(conf_tapelist);
485 conf_infofile = getconf_str(CNF_INFOFILE);
486 if (*conf_infofile == '/') {
487 conf_infofile = stralloc(conf_infofile);
489 conf_infofile = stralloc2(config_dir, conf_infofile);
491 if(open_infofile(conf_infofile)) {
492 error("could not open info db \"%s\"", conf_infofile);
495 amfree(conf_infofile);
497 displayunit = getconf_str(CNF_DISPLAYUNIT);
498 unitdivisor = getconf_unit_divisor();
500 ColumnSpec = getconf_str(CNF_COLUMNSPEC);
501 if(SetColumDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
503 curprog = P_REPORTER;
508 ColumnSpec = ""; /* use the default */
509 if(SetColumDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
511 curprog = P_REPORTER;
518 for (cn = 0; ColumnData[cn].Name != NULL; cn++) {
519 if (ColumnData[cn].MaxWidth) {
520 MaxWidthsRequested = 1;
528 conf_logdir = getconf_str(CNF_LOGDIR);
529 if (*conf_logdir == '/') {
530 conf_logdir = stralloc(conf_logdir);
532 conf_logdir = stralloc2(config_dir, conf_logdir);
534 logfname = vstralloc(conf_logdir, "/", "log", NULL);
538 if((logfile = fopen(logfname, "r")) == NULL) {
540 curprog = P_REPORTER;
541 curstr = vstralloc("could not open log ",
550 while(logfile && get_logline(logfile)) {
552 case L_START: handle_start(); break;
553 case L_FINISH: handle_finish(); break;
555 case L_INFO: handle_note(); break;
556 case L_WARNING: handle_note(); break;
558 case L_SUMMARY: handle_summary(); break;
559 case L_STATS: handle_stats(); break;
561 case L_ERROR: handle_error(); break;
562 case L_FATAL: handle_error(); break;
564 case L_DISK: handle_disk(); break;
566 case L_SUCCESS: handle_success(curlog); break;
567 case L_CHUNKSUCCESS: handle_success(curlog); break;
568 case L_CHUNK: handle_chunk(); break;
569 case L_PARTIAL: handle_partial(); break;
570 case L_STRANGE: handle_strange(); break;
571 case L_FAIL: handle_failed(); break;
575 curprog = P_REPORTER;
576 curstr = stralloc2("unexpected log line: ", curstr);
585 generate_bad_estimate();
588 subj_str = vstralloc(getconf_str(CNF_ORG),
589 " ", amflush_run ? "AMFLUSH" : "AMANDA",
590 " ", "MAIL REPORT FOR",
591 " ", nicedate(run_datestamp ? run_datestamp : "0"),
594 /* lookup the tapetype and printer type from the amanda.conf file. */
595 tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
596 printer = getconf_str(CNF_PRINTER);
598 /* ignore SIGPIPE so if a child process dies we do not also go away */
599 signal(SIGPIPE, SIG_IGN);
601 /* open pipe to mailer */
604 /* output to a file */
605 if((mailf = fopen(outfname,"w")) == NULL) {
606 error("could not open output file: %s %s", outfname, strerror(errno));
609 fprintf(mailf, "To: %s\n", mailto);
610 fprintf(mailf, "Subject: %s\n\n", subj_str);
615 mail_cmd = vstralloc(MAILER,
616 " -s", " \"", subj_str, "\"",
618 if((mailf = popen(mail_cmd, "w")) == NULL) {
619 error("could not open pipe to \"%s\": %s",
620 mail_cmd, strerror(errno));
626 printf("No mail sent! ");
627 printf("No valid mail address has been specified in amanda.conf or on the commmand line\n");
634 /* open pipe to print spooler if necessary) */
637 /* if the postscript_label_template (tp->lbl_templ) field is not */
638 /* the empty string (i.e. it is set to something), open the */
639 /* postscript debugging file for writing. */
641 lbl_templ = tapetype_get_lbl_templ(tp);
642 if (tp && lbl_templ && strcmp(lbl_templ, "") != 0) {
643 if ((postscript = fopen(psfname, "w")) == NULL) {
645 curprog = P_REPORTER;
646 curstr = vstralloc("could not open ",
657 if (strcmp(printer, "") != 0) /* alternate printer is defined */
658 /* print to the specified printer */
660 printer_cmd = vstralloc(LPRCMD, " ", LPRFLAG, printer, NULL);
662 printer_cmd = vstralloc(LPRCMD, NULL);
665 /* print to the default printer */
666 printer_cmd = vstralloc(LPRCMD, NULL);
669 lbl_templ = tapetype_get_lbl_templ(tp);
670 if (tp && lbl_templ && strcmp(lbl_templ, "") != 0) {
672 if ((postscript = popen(printer_cmd, "w")) == NULL) {
674 curprog = P_REPORTER;
675 curstr = vstralloc("could not open pipe to ",
685 curprog = P_REPORTER;
686 curstr = stralloc("no printer command defined");
697 if(!got_finish) fputs("*** THE DUMPS DID NOT FINISH PROPERLY!\n\n", mailf);
701 if(first_strange || errsum) {
702 fprintf(mailf,"\nFAILURE AND STRANGE DUMP SUMMARY:\n");
703 if(first_strange) output_strange();
704 if(errsum) output_lines(errsum, mailf);
706 fputs("\n\n", mailf);
711 fprintf(mailf,"\n\014\nFAILED AND STRANGE DUMP DETAILS:\n");
712 output_lines(errdet, mailf);
715 fprintf(mailf,"\n\014\nNOTES:\n");
716 output_lines(notes, mailf);
719 if(sortq.head != NULL) {
720 fprintf(mailf,"\n\014\nDUMP SUMMARY:\n");
723 fprintf(mailf,"\n(brought to you by Amanda version %s)\n",
728 do_postscript_output();
732 /* close postscript file */
733 if (psfname && postscript) {
734 /* it may be that postscript is NOT opened */
738 if (postscript != NULL && pclose(postscript) != 0) {
739 error("printer command failed: %s", printer_cmd);
745 /* close output file */
750 if(pclose(mailf) != 0) {
751 error("mail command failed: %s", mail_cmd);
758 free_disklist(&diskq);
759 free_new_argv(new_argc, new_argv);
760 free_server_config();
761 amfree(run_datestamp);
769 malloc_size_2 = malloc_inuse(&malloc_hist_2);
771 if(malloc_size_1 != malloc_size_2) {
772 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
781 #define mb(f) ((f)/1024) /* kbytes -> mbutes */
782 #define du(f) ((f)/unitdivisor) /* kbytes -> displayunit */
783 #define pct(f) ((f)*100.0) /* percent */
784 #define hrmn(f) ((int)(f)+30)/3600, (((int)(f)+30)%3600)/60
785 #define mnsc(f) ((int)(f+0.5))/60, ((int)(f+0.5)) % 60
787 #define divzero(fp,a,b) \
791 fprintf((fp)," -- "); \
792 else if ((q = (a)/q) >= 999.95) \
793 fprintf((fp), "###.#"); \
795 fprintf((fp), "%5.1lf",q); \
797 #define divzero_wide(fp,a,b) \
801 fprintf((fp)," -- "); \
802 else if ((q = (a)/q) >= 99999.95) \
803 fprintf((fp), "#####.#"); \
805 fprintf((fp), "%7.1lf",q); \
812 tapetype_t *tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
818 tapesize = tapetype_get_length(tp);
819 marksize = tapetype_get_filemark(tp);
821 tapesize = 100 * 1024 * 1024;
822 marksize = 1 * 1024 * 1024;
825 stats[2].dumpdisks = stats[0].dumpdisks + stats[1].dumpdisks;
826 stats[2].tapedisks = stats[0].tapedisks + stats[1].tapedisks;
827 stats[2].tapechunks = stats[0].tapechunks + stats[1].tapechunks;
828 stats[2].outsize = stats[0].outsize + stats[1].outsize;
829 stats[2].origsize = stats[0].origsize + stats[1].origsize;
830 stats[2].tapesize = stats[0].tapesize + stats[1].tapesize;
831 stats[2].coutsize = stats[0].coutsize + stats[1].coutsize;
832 stats[2].corigsize = stats[0].corigsize + stats[1].corigsize;
833 stats[2].taper_time = stats[0].taper_time + stats[1].taper_time;
834 stats[2].dumper_time = stats[0].dumper_time + stats[1].dumper_time;
836 if(!got_finish) /* no driver finish line, estimate total run time */
837 total_time = stats[2].taper_time + planner_time;
839 idle_time = (total_time - startup_time) - stats[2].taper_time;
840 if(idle_time < 0) idle_time = 0.0;
842 fprintf(mailf,"STATISTICS:\n");
844 " Total Full Incr.\n");
846 " -------- -------- --------\n");
849 "Estimate Time (hrs:min) %2d:%02d\n", hrmn(planner_time));
852 "Run Time (hrs:min) %2d:%02d\n", hrmn(total_time));
855 "Dump Time (hrs:min) %2d:%02d %2d:%02d %2d:%02d\n",
856 hrmn(stats[2].dumper_time), hrmn(stats[0].dumper_time),
857 hrmn(stats[1].dumper_time));
860 "Output Size (meg) %8.1lf %8.1lf %8.1lf\n",
861 mb(stats[2].outsize), mb(stats[0].outsize), mb(stats[1].outsize));
864 "Original Size (meg) %8.1lf %8.1lf %8.1lf\n",
865 mb(stats[2].origsize), mb(stats[0].origsize),
866 mb(stats[1].origsize));
868 fprintf(mailf, "Avg Compressed Size (%%) ");
869 divzero(mailf, pct(stats[2].coutsize),stats[2].corigsize);
871 divzero(mailf, pct(stats[0].coutsize),stats[0].corigsize);
873 divzero(mailf, pct(stats[1].coutsize),stats[1].corigsize);
875 if(stats[1].dumpdisks > 0) fputs(" (level:#disks ...)", mailf);
879 "Filesystems Dumped %4d %4d %4d",
880 stats[2].dumpdisks, stats[0].dumpdisks, stats[1].dumpdisks);
882 if(stats[1].dumpdisks > 0) {
884 for(lv = 1; lv < 10; lv++) if(dumpdisks[lv]) {
885 fputs(first?" (":" ", mailf);
887 fprintf(mailf, "%d:%d", lv, dumpdisks[lv]);
893 fprintf(mailf, "Avg Dump Rate (k/s) ");
894 divzero_wide(mailf, stats[2].outsize,stats[2].dumper_time);
896 divzero_wide(mailf, stats[0].outsize,stats[0].dumper_time);
898 divzero_wide(mailf, stats[1].outsize,stats[1].dumper_time);
903 "Tape Time (hrs:min) %2d:%02d %2d:%02d %2d:%02d\n",
904 hrmn(stats[2].taper_time), hrmn(stats[0].taper_time),
905 hrmn(stats[1].taper_time));
908 "Tape Size (meg) %8.1lf %8.1lf %8.1lf\n",
909 mb(stats[2].tapesize), mb(stats[0].tapesize),
910 mb(stats[1].tapesize));
912 fprintf(mailf, "Tape Used (%%) ");
913 divzero(mailf, pct(stats[2].tapesize+marksize*(stats[2].tapedisks+stats[2].tapechunks)),(double)tapesize);
915 divzero(mailf, pct(stats[0].tapesize+marksize*(stats[0].tapedisks+stats[0].tapechunks)),(double)tapesize);
917 divzero(mailf, pct(stats[1].tapesize+marksize*(stats[1].tapedisks+stats[1].tapechunks)),(double)tapesize);
919 if(stats[1].tapedisks > 0) fputs(" (level:#disks ...)", mailf);
923 "Filesystems Taped %4d %4d %4d",
924 stats[2].tapedisks, stats[0].tapedisks, stats[1].tapedisks);
926 if(stats[1].tapedisks > 0) {
928 for(lv = 1; lv < 10; lv++) if(tapedisks[lv]) {
929 fputs(first?" (":" ", mailf);
931 fprintf(mailf, "%d:%d", lv, tapedisks[lv]);
937 if(stats[1].tapechunks > 0) fputs(" (level:#chunks ...)", mailf);
941 "Chunks Taped %4d %4d %4d",
942 stats[2].tapechunks, stats[0].tapechunks, stats[1].tapechunks);
944 if(stats[1].tapechunks > 0) {
946 for(lv = 1; lv < 10; lv++) if(tapechunks[lv]) {
947 fputs(first?" (":" ", mailf);
949 fprintf(mailf, "%d:%d", lv, tapechunks[lv]);
955 fprintf(mailf, "Avg Tp Write Rate (k/s) ");
956 divzero_wide(mailf, stats[2].tapesize,stats[2].taper_time);
958 divzero_wide(mailf, stats[0].tapesize,stats[0].taper_time);
960 divzero_wide(mailf, stats[1].tapesize,stats[1].taper_time);
964 int label_length = (int)strlen(stats_by_tape->label) + 5;
965 fprintf(mailf,"\nUSAGE BY TAPE:\n");
966 fprintf(mailf," %-*s Time Size %% Nb Nc\n",
967 label_length, "Label");
968 for(current_tape = stats_by_tape; current_tape != NULL;
969 current_tape = current_tape->next) {
970 fprintf(mailf, " %-*s", label_length, current_tape->label);
971 fprintf(mailf, " %2d:%02d", hrmn(current_tape->taper_time));
972 fprintf(mailf, " %8.0lf%s ", du(current_tape->coutsize), displayunit);
973 divzero(mailf, pct(current_tape->coutsize + marksize *
974 (current_tape->tapedisks+current_tape->tapechunks)),
976 fprintf(mailf, " %4d", current_tape->tapedisks);
977 fprintf(mailf, " %4d\n", current_tape->tapechunks);
985 output_tapeinfo(void)
991 if (last_run_tapes > 0) {
993 fprintf(mailf, "The dumps were flushed to tape%s %s.\n",
994 last_run_tapes == 1 ? "" : "s",
995 tape_labels ? tape_labels : "");
997 fprintf(mailf, "These dumps were to tape%s %s.\n",
998 last_run_tapes == 1 ? "" : "s",
999 tape_labels ? tape_labels : "");
1004 "*** A TAPE ERROR OCCURRED: %s.\n", tapestart_error);
1005 fputs("Some dumps may have been left in the holding disk.\n", mailf);
1007 "Run amflush%s to flush them to tape.\n",
1008 amflush_run ? " again" : "");
1011 tp = lookup_last_reusable_tape(skip);
1013 run_tapes = getconf_int(CNF_RUNTAPES);
1016 fputs("The next tape Amanda expects to use is: ", mailf);
1017 else if(run_tapes > 1)
1018 fprintf(mailf, "The next %d tapes Amanda expects to use are: ",
1021 while(run_tapes > 0) {
1023 fprintf(mailf, "%s", tp->label);
1026 fprintf(mailf, "a new tape");
1028 fprintf(mailf, "%d new tapes", run_tapes);
1032 if(run_tapes > 1) fputs(", ", mailf);
1036 tp = lookup_last_reusable_tape(skip);
1038 fputs(".\n", mailf);
1040 lasttp = lookup_tapepos(lookup_nb_tape());
1041 run_tapes = getconf_int(CNF_RUNTAPES);
1042 if(lasttp && run_tapes > 0 && strcmp(lasttp->datestamp,"0") == 0) {
1044 while(lasttp && run_tapes > 0 && strcmp(lasttp->datestamp,"0") == 0) {
1046 lasttp = lasttp->prev;
1049 lasttp = lookup_tapepos(lookup_nb_tape());
1051 fprintf(mailf, "The next new tape already labelled is: %s.\n",
1055 fprintf(mailf, "The next %d new tapes already labelled are: %s", c,
1057 lasttp = lasttp->prev;
1059 while(lasttp && c > 0 && strcmp(lasttp->datestamp,"0") == 0) {
1060 fprintf(mailf, ", %s", lasttp->label);
1061 lasttp = lasttp->prev;
1064 fprintf(mailf, ".\n");
1071 output_strange(void)
1073 size_t len_host=0, len_disk=0;
1077 for(strange=first_strange; strange != NULL; strange = strange->next) {
1078 if(strlen(strange->hostname) > len_host)
1079 len_host = strlen(strange->hostname);
1080 if(strlen(strange->diskname) > len_disk)
1081 len_disk = strlen(strange->diskname);
1083 for(strange=first_strange; strange != NULL; strange = strange->next) {
1084 str = vstralloc(" ", prefixstrange(strange->hostname, strange->diskname, strange->level, len_host, len_disk),
1085 " ", strange->str, NULL);
1086 fprintf(mailf, "%s\n", str);
1117 rc = strcmp(a->host->hostname, b->host->hostname);
1118 if(rc == 0) rc = strcmp(a->name, b->name);
1127 sortq.head = sortq.tail = NULL;
1128 while(!empty(diskq)) {
1129 dp = dequeue_disk(&diskq);
1130 if(data(dp) == NULL) { /* create one */
1131 find_repdata(dp, run_datestamp, 0);
1133 insert_disk(&sortq, dp, sort_by_name);
1143 int l = (int)strlen(s);
1159 snprintf(testBuf, SIZEOF(testBuf),
1160 cd->Format, cd->Width, cd->Precision, n);
1161 l = (int)strlen(testBuf);
1175 snprintf(testBuf, SIZEOF(testBuf),
1176 cd->Format, cd->Width, cd->Precision, d);
1177 l = (int)strlen(testBuf);
1183 static int HostName;
1188 static int Compress;
1189 static int DumpTime;
1190 static int DumpRate;
1191 static int TapeTime;
1192 static int TapeRate;
1197 /* we have to look for columspec's, that require the recalculation.
1198 * we do here the same loops over the sortq as is done in
1199 * output_summary. So, if anything is changed there, we have to
1200 * change this here also.
1206 for(dp = sortq.head; dp != NULL; dp = dp->next) {
1208 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
1209 char TimeRateBuffer[40];
1211 CheckStringMax(&ColumnData[HostName], dp->host->hostname);
1212 CheckStringMax(&ColumnData[Disk], dp->name);
1213 if (repdata->dumper.result == L_BOGUS &&
1214 repdata->taper.result == L_BOGUS)
1216 CheckIntMax(&ColumnData[Level], repdata->level);
1217 if(repdata->dumper.result == L_SUCCESS ||
1218 repdata->dumper.result == L_CHUNKSUCCESS) {
1219 CheckFloatMax(&ColumnData[OrigKB],
1220 (double)du(repdata->dumper.origsize));
1221 CheckFloatMax(&ColumnData[OutKB],
1222 (double)du(repdata->dumper.outsize));
1223 if(dp->compress == COMP_NONE)
1226 f = repdata->dumper.origsize;
1227 CheckStringMax(&ColumnData[Disk],
1228 sDivZero(pct(repdata->dumper.outsize), f, Compress));
1231 snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
1232 "%3d:%02d", mnsc(repdata->dumper.sec));
1234 snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
1236 CheckStringMax(&ColumnData[DumpTime], TimeRateBuffer);
1238 CheckFloatMax(&ColumnData[DumpRate], repdata->dumper.kps);
1241 if(repdata->taper.result == L_FAIL) {
1242 CheckStringMax(&ColumnData[TapeTime], "FAILED");
1245 if(repdata->taper.result == L_SUCCESS ||
1246 repdata->taper.result == L_CHUNKSUCCESS)
1247 snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
1248 "%3d:%02d", mnsc(repdata->taper.sec));
1250 snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
1252 CheckStringMax(&ColumnData[TapeTime], TimeRateBuffer);
1254 if(repdata->taper.result == L_SUCCESS ||
1255 repdata->taper.result == L_CHUNKSUCCESS)
1256 CheckFloatMax(&ColumnData[TapeRate], repdata->taper.kps);
1258 CheckStringMax(&ColumnData[TapeRate], "N/A ");
1265 output_summary(void)
1269 char *ds="DUMPER STATS";
1270 char *ts=" TAPER STATS";
1273 int i, h, w1, wDump, wTape;
1274 double outsize, origsize;
1277 HostName = StringToColumn("HostName");
1278 Disk = StringToColumn("Disk");
1279 Level = StringToColumn("Level");
1280 OrigKB = StringToColumn("OrigKB");
1281 OutKB = StringToColumn("OutKB");
1282 Compress = StringToColumn("Compress");
1283 DumpTime = StringToColumn("DumpTime");
1284 DumpRate = StringToColumn("DumpRate");
1285 TapeTime = StringToColumn("TapeTime");
1286 TapeRate = StringToColumn("TapeRate");
1288 /* at first determine if we have to recalculate our widths */
1289 if (MaxWidthsRequested)
1292 /* title for Dumper-Stats */
1293 w1= ColWidth(HostName, Level);
1294 wDump= ColWidth(OrigKB, DumpRate);
1295 wTape= ColWidth(TapeTime, TapeRate);
1297 /* print centered top titles */
1298 h = (int)strlen(ds);
1304 fprintf(mailf, "%*s", w1+h, "");
1305 fprintf(mailf, "%-*s", wDump-h, ds);
1306 h = (int)strlen(ts);
1312 fprintf(mailf, "%*s", h, "");
1313 fprintf(mailf, "%-*s", wTape-h, ts);
1316 /* print the titles */
1317 for (i=0; ColumnData[i].Name != NULL; i++) {
1319 ColumnInfo *cd= &ColumnData[i];
1320 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1321 if (cd->Format[1] == '-')
1325 if(strcmp(cd->Title,"ORIG-KB") == 0) {
1326 /* cd->Title must be re-allocated in write-memory */
1327 cd->Title = stralloc("ORIG-KB");
1328 cd->Title[5] = displayunit[0];
1330 if(strcmp(cd->Title,"OUT-KB") == 0) {
1331 /* cd->Title must be re-allocated in write-memory */
1332 cd->Title = stralloc("OUT-KB");
1333 cd->Title[4] = displayunit[0];
1335 fprintf(mailf, fmt, cd->Width, cd->Title);
1339 /* print the rules */
1340 fputs(tmp=Rule(HostName, Level), mailf); amfree(tmp);
1341 fputs(tmp=Rule(OrigKB, DumpRate), mailf); amfree(tmp);
1342 fputs(tmp=Rule(TapeTime, TapeRate), mailf); amfree(tmp);
1345 for(dp = sortq.head; dp != NULL; dp = dp->next) {
1348 char TimeRateBuffer[40];
1349 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
1353 cd= &ColumnData[HostName];
1354 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1355 fprintf(mailf, cd->Format, cd->Width, cd->Width, dp->host->hostname);
1357 cd= &ColumnData[Disk];
1358 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1359 devname = sanitize_string(dp->name);
1360 devlen = strlen(devname);
1361 if (devlen > (size_t)cd->Width) {
1363 fprintf(mailf, cd->Format, cd->Width-1, cd->Precision-1,
1364 devname+devlen - (cd->Width-1) );
1367 fprintf(mailf, cd->Format, cd->Width, cd->Width, devname);
1369 cd= &ColumnData[Level];
1370 if (repdata->dumper.result == L_BOGUS &&
1371 repdata->taper.result == L_BOGUS) {
1373 fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
1374 tmp=TextRule(OrigKB, TapeRate, "NO FILE TO FLUSH"));
1376 fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
1377 tmp=TextRule(OrigKB, TapeRate, "MISSING"));
1383 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1384 fprintf(mailf, cd->Format, cd->Width, cd->Precision,repdata->level);
1386 if (repdata->dumper.result == L_SKIPPED) {
1387 fprintf(mailf, "%s\n",
1388 tmp=TextRule(OrigKB, TapeRate, "SKIPPED"));
1392 if (repdata->dumper.result == L_FAIL && (repdata->chunker.result != L_PARTIAL && repdata->taper.result != L_PARTIAL)) {
1393 fprintf(mailf, "%s\n",
1394 tmp=TextRule(OrigKB, TapeRate, "FAILED"));
1399 if(repdata->dumper.result == L_SUCCESS ||
1400 repdata->dumper.result == L_CHUNKSUCCESS)
1401 origsize = repdata->dumper.origsize;
1402 else if(repdata->taper.result == L_SUCCESS ||
1403 repdata->taper.result == L_PARTIAL)
1404 origsize = repdata->taper.origsize;
1406 origsize = repdata->chunker.origsize;
1408 if(repdata->taper.result == L_SUCCESS ||
1409 repdata->taper.result == L_PARTIAL ||
1410 repdata->taper.result == L_CHUNKSUCCESS)
1411 outsize = repdata->taper.outsize;
1412 else if(repdata->chunker.result == L_SUCCESS ||
1413 repdata->chunker.result == L_PARTIAL ||
1414 repdata->chunker.result == L_CHUNKSUCCESS)
1415 outsize = repdata->chunker.outsize;
1417 outsize = repdata->dumper.outsize;
1419 cd= &ColumnData[OrigKB];
1420 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1421 if(isnormal(origsize))
1422 fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(origsize));
1424 fprintf(mailf, "%*.*s", cd->Width, cd->Width, "N/A");
1426 cd= &ColumnData[OutKB];
1427 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1429 fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(outsize));
1431 cd= &ColumnData[Compress];
1432 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1434 if(dp->compress == COMP_NONE)
1436 else if(origsize < 1.0)
1441 fputs(sDivZero(pct(outsize), f, Compress), mailf);
1443 cd= &ColumnData[DumpTime];
1444 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1445 if(repdata->dumper.result == L_SUCCESS ||
1446 repdata->dumper.result == L_CHUNKSUCCESS)
1447 snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
1448 "%3d:%02d", mnsc(repdata->dumper.sec));
1450 snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
1452 fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
1454 cd= &ColumnData[DumpRate];
1455 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1456 if(repdata->dumper.result == L_SUCCESS ||
1457 repdata->dumper.result == L_CHUNKSUCCESS)
1458 fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->dumper.kps);
1460 fprintf(mailf, "%*s", cd->Width, "N/A ");
1462 cd= &ColumnData[TapeTime];
1463 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1464 if(repdata->taper.result == L_FAIL) {
1465 fprintf(mailf, "%s\n",
1466 tmp=TextRule(TapeTime, TapeRate, "FAILED "));
1471 if(repdata->taper.result == L_SUCCESS ||
1472 repdata->taper.result == L_PARTIAL ||
1473 repdata->taper.result == L_CHUNKSUCCESS)
1474 snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
1475 "%3d:%02d", mnsc(repdata->taper.sec));
1477 snprintf(TimeRateBuffer, SIZEOF(TimeRateBuffer),
1479 fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
1481 cd= &ColumnData[TapeRate];
1482 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1483 if(repdata->taper.result == L_SUCCESS ||
1484 repdata->taper.result == L_PARTIAL ||
1485 repdata->taper.result == L_CHUNKSUCCESS)
1486 fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->taper.kps);
1488 fprintf(mailf, "%*s", cd->Width, "N/A ");
1490 if(repdata->chunker.result == L_PARTIAL ||
1491 repdata->taper.result == L_PARTIAL) {
1492 fprintf(mailf, " PARTIAL");
1502 const char *err_text)
1504 printf("line %d of log is bogus: <%s>\n", curlinenum, curstr);
1505 printf(" Scan failed at: <%s>\n", err_text);
1510 * Formats an integer of the form YYYYMMDDHHMMSS into the string
1511 * "Monthname DD, YYYY". A pointer to the statically allocated string
1512 * is returned, so it must be copied to other storage (or just printed)
1513 * before calling nicedate() again.
1517 const char *datestamp)
1519 static char nice[64];
1522 static char *months[13] = { "BogusMonth",
1523 "January", "February", "March", "April", "May", "June",
1524 "July", "August", "September", "October", "November", "December"
1526 int year, month, day;
1528 strncpy(date, datestamp, 8);
1530 numdate = atoi(date);
1531 year = numdate / 10000;
1532 day = numdate % 100;
1533 month = (numdate / 100) % 100;
1537 snprintf(nice, SIZEOF(nice), "%s %d, %d", months[month], day, year);
1545 static int started = 0;
1555 skip_whitespace(s, ch);
1556 #define sc "datestamp"
1557 if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
1564 skip_whitespace(s, ch);
1570 skip_non_whitespace(s, ch);
1572 run_datestamp = newstralloc(run_datestamp, fp);
1575 skip_whitespace(s, ch);
1577 if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
1584 skip_whitespace(s, ch);
1590 skip_non_whitespace(s, ch);
1593 label = stralloc(fp);
1597 fp = vstralloc(tape_labels, ", ", label, NULL);
1598 amfree(tape_labels);
1601 tape_labels = stralloc(label);
1606 if(stats_by_tape == NULL) {
1607 stats_by_tape = current_tape = (taper_t *)alloc(SIZEOF(taper_t));
1610 current_tape->next = (taper_t *)alloc(SIZEOF(taper_t));
1611 current_tape = current_tape->next;
1613 current_tape->label = label;
1614 current_tape->taper_time = 0.0;
1615 current_tape->coutsize = 0.0;
1616 current_tape->corigsize = 0.0;
1617 current_tape->tapedisks = 0;
1618 current_tape->tapechunks = 0;
1619 current_tape->next = NULL;
1639 skip_whitespace(s, ch);
1641 if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
1642 return; /* ignore bogus line */
1647 skip_whitespace(s, ch);
1653 skip_non_whitespace(s, ch);
1655 run_datestamp = newstralloc(run_datestamp, fp);
1660 if(amflush_run && normal_run) {
1663 " reporter: both amflush and planner output in log, ignoring amflush.");
1675 if(curprog == P_DRIVER || curprog == P_AMFLUSH || curprog == P_PLANNER) {
1679 skip_whitespace(s, ch);
1681 if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
1689 skip_whitespace(s, ch);
1694 skip_non_whitespace(s, ch); /* ignore the date string */
1696 skip_whitespace(s, ch);
1698 if(ch == '\0' || strncmp(s - 1, sc, SIZEOF(sc)-1) != 0) {
1699 /* older planner doesn't write time */
1700 if(curprog == P_PLANNER) return;
1708 skip_whitespace(s, ch);
1713 if(sscanf(s - 1, "%lf", &a_time) != 1) {
1717 if(curprog == P_PLANNER) {
1718 planner_time = a_time;
1721 total_time = a_time;
1732 char *hostname, *diskname, *datestamp;
1734 double sec, kps, nbytes, cbytes;
1738 if(curprog == P_DRIVER) {
1742 skip_whitespace(s, ch);
1743 #define sc "startup time"
1744 if(ch != '\0' && strncmp(s - 1, sc, sizeof(sc)-1) == 0) {
1749 skip_whitespace(s, ch);
1754 if(sscanf(s - 1, "%lf", &startup_time) != 1) {
1758 planner_time = startup_time;
1760 #define sc "estimate"
1761 else if(ch != '\0' && strncmp(s - 1, sc, sizeof(sc)-1) == 0) {
1766 skip_whitespace(s, ch);
1772 skip_non_whitespace(s, ch);
1774 hostname = stralloc(fp);
1777 skip_whitespace(s, ch);
1784 skip_non_whitespace(s, ch);
1786 diskname = stralloc(fp);
1789 skip_whitespace(s, ch);
1797 skip_non_whitespace(s, ch);
1799 datestamp = stralloc(fp);
1802 skip_whitespace(s, ch);
1803 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1810 skip_integer(s, ch);
1811 if(level < 0 || level > 9) {
1818 skip_whitespace(s, ch);
1820 if(sscanf(s - 1,"[sec %lf nkb %lf ckb %lf kps %lf",
1821 &sec, &nbytes, &cbytes, &kps) != 4) {
1829 dp = lookup_disk(hostname, diskname);
1831 addtostrange(hostname, diskname, level,
1832 "ERROR [not in disklist]");
1839 repdata = find_repdata(dp, datestamp, level);
1841 repdata->est_nsize = nbytes;
1842 repdata->est_csize = cbytes;
1863 str = vstralloc(" ", program_str[curprog], ": ", curstr, NULL);
1864 addline(¬es, str);
1874 char *s = NULL, *nl;
1877 if(curlog == L_ERROR && curprog == P_TAPER) {
1881 skip_whitespace(s, ch);
1882 #define sc "no-tape"
1883 if(ch != '\0' && strncmp(s - 1, sc, SIZEOF(sc)-1) == 0) {
1888 skip_whitespace(s, ch);
1890 if((nl = strchr(s - 1, '\n')) != NULL) {
1893 tapestart_error = newstralloc(tapestart_error, s - 1);
1898 /* else some other tape error, handle like other errors */
1900 /* else some other tape error, handle like other errors */
1902 s = vstralloc(" ", program_str[curprog], ": ",
1903 logtype_str[curlog], " ", curstr, NULL);
1904 addline(&errsum, s);
1911 handle_summary(void)
1918 static int nb_disk=0;
1923 char *s, *fp, *qdiskname;
1925 char *hostname = NULL, *diskname = NULL;
1927 if(curprog != P_PLANNER && curprog != P_AMFLUSH) {
1933 for(dp = diskq.head; dp != NULL; dp = dp->next)
1941 skip_whitespace(s, ch);
1947 skip_non_whitespace(s, ch);
1949 hostname = newstralloc(hostname, fp);
1952 skip_whitespace(s, ch);
1959 skip_quoted_string(s, ch);
1961 diskname = unquote_string(qdiskname);
1964 dp = lookup_disk(hostname, diskname);
1966 dp = add_disk(&diskq, hostname, diskname);
1974 /* XXX Just a placeholder, in case we decide to do something with L_CHUNK
1975 * log entries. Right now they're just the equivalent of L_SUCCESS, but only
1976 * for a split chunk of the overall dumpfile.
1982 double sec, kps, kbytes;
1987 char *hostname = NULL;
1988 char *diskname = NULL;
1993 if(curprog != P_TAPER) {
2001 skip_whitespace(s, ch);
2007 skip_non_whitespace(s, ch);
2009 hostname = stralloc(fp);
2012 skip_whitespace(s, ch);
2019 skip_quoted_string(s, ch);
2021 diskname = unquote_string(fp);
2024 skip_whitespace(s, ch);
2032 skip_non_whitespace(s, ch);
2034 datestamp = stralloc(fp);
2037 skip_whitespace(s, ch);
2038 if(ch == '\0' || sscanf(s - 1, "%d", &chunk) != 1) {
2045 skip_integer(s, ch);
2047 skip_whitespace(s, ch);
2048 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2055 skip_integer(s, ch);
2058 if(level < 0 || level > 9) {
2066 skip_whitespace(s, ch);
2067 if(sscanf(s - 1,"[sec %lf kb %lf kps %lf", &sec, &kbytes, &kps) != 3) {
2076 dp = lookup_disk(hostname, diskname);
2080 str = vstralloc(" ", prefix(hostname, diskname, level),
2081 " ", "ERROR [not in disklist]",
2083 addline(&errsum, str);
2091 repdata = find_repdata(dp, datestamp, level);
2093 sp = &(repdata->taper);
2101 if(current_tape == NULL) {
2102 error("current_tape == NULL");
2104 if (sp->filenum == 0) {
2105 sp->filenum = ++tapefcount;
2106 sp->tapelabel = current_tape->label;
2108 tapechunks[level] +=1;
2109 stats[i].tapechunks +=1;
2110 current_tape->taper_time += sec;
2111 current_tape->coutsize += kbytes;
2112 current_tape->tapechunks += 1;
2123 double kbytes = 0.0;
2124 double origkb = 0.0;
2127 char *s, *fp, *qdiskname;
2129 char *hostname = NULL;
2130 char *diskname = NULL;
2135 if(curprog != P_TAPER && curprog != P_DUMPER && curprog != P_PLANNER &&
2136 curprog != P_CHUNKER) {
2144 skip_whitespace(s, ch);
2150 skip_non_whitespace(s, ch);
2152 hostname = stralloc(fp);
2155 skip_whitespace(s, ch);
2162 skip_quoted_string(s, ch);
2164 diskname = unquote_string(qdiskname);
2166 skip_whitespace(s, ch);
2174 skip_non_whitespace(s, ch);
2176 datestamp = stralloc(fp);
2179 if(strlen(datestamp) < 3) {
2180 level = atoi(datestamp);
2181 datestamp = newstralloc(datestamp, run_datestamp);
2184 skip_whitespace(s, ch);
2185 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2192 skip_integer(s, ch);
2195 if(level < 0 || level > 9) {
2202 skip_whitespace(s, ch);
2203 /* Planner success messages (for skipped
2204 dumps) do not contain statistics */
2205 if(curprog != P_PLANNER) {
2208 if((curprog != P_DUMPER)
2209 || (sscanf(s - 1,"[sec %lf kb %lf kps %lf orig-kb %lf",
2210 &sec, &kbytes, &kps, &origkb) != 4)) {
2212 if(sscanf(s - 1,"[sec %lf kb %lf kps %lf",
2213 &sec, &kbytes, &kps) != 3) {
2222 if(!isnormal(origkb))
2228 dp = lookup_disk(hostname, diskname);
2230 addtostrange(hostname, qdiskname, level, "ERROR [not in disklist]");
2237 repdata = find_repdata(dp, datestamp, level);
2239 if(curprog == P_PLANNER) {
2240 repdata->dumper.result = L_SKIPPED;
2247 if(curprog == P_TAPER)
2248 sp = &(repdata->taper);
2249 else if(curprog == P_DUMPER)
2250 sp = &(repdata->dumper);
2251 else sp = &(repdata->chunker);
2260 get_info(hostname, diskname, &inf);
2261 tm = localtime(&inf.inf[level].date);
2263 Idatestamp = 10000*(tm->tm_year+1900) +
2264 100*(tm->tm_mon+1) + tm->tm_mday;
2266 Idatestamp = 19000101;
2269 if(atoi(datestamp) == Idatestamp) {
2270 /* grab original size from record */
2271 origkb = (double)inf.inf[level].size;
2277 if (curprog == P_DUMPER &&
2278 (sp->result == L_FAIL || sp->result == L_PARTIAL)) {
2279 addtostrange(hostname, qdiskname, level, "was successfully retried");
2286 sp->result = L_SUCCESS;
2287 sp->datestamp = repdata->datestamp;
2290 sp->origsize = origkb;
2291 sp->outsize = kbytes;
2293 if(curprog == P_TAPER) {
2294 if(current_tape == NULL) {
2295 error("current_tape == NULL");
2298 stats[i].taper_time += sec;
2299 sp->filenum = ++tapefcount;
2300 sp->tapelabel = current_tape->label;
2301 tapedisks[level] +=1;
2302 stats[i].tapedisks +=1;
2303 stats[i].tapesize += kbytes;
2304 sp->outsize = kbytes;
2305 if(!isnormal(repdata->chunker.outsize) && isnormal(repdata->dumper.outsize)) { /* dump to tape */
2306 stats[i].outsize += kbytes;
2307 if(dp->compress != COMP_NONE) {
2308 stats[i].coutsize += kbytes;
2311 if (logtype == L_SUCCESS || logtype== L_PARTIAL) {
2312 current_tape->taper_time += sec;
2313 current_tape->coutsize += kbytes;
2315 current_tape->corigsize += origkb;
2316 current_tape->tapedisks += 1;
2319 if(curprog == P_DUMPER) {
2320 stats[i].dumper_time += sec;
2321 if(dp->compress == COMP_NONE) {
2322 sp->origsize = kbytes;
2325 stats[i].corigsize += sp->origsize;
2327 dumpdisks[level] +=1;
2328 stats[i].dumpdisks +=1;
2329 stats[i].origsize += sp->origsize;
2332 if(curprog == P_CHUNKER) {
2333 sp->outsize = kbytes;
2334 stats[i].outsize += kbytes;
2335 if(dp->compress != COMP_NONE) {
2336 stats[i].coutsize += kbytes;
2343 handle_partial(void)
2348 repdata = handle_success(L_PARTIAL);
2352 if(curprog == P_TAPER)
2353 sp = &(repdata->taper);
2354 else if(curprog == P_DUMPER)
2355 sp = &(repdata->dumper);
2356 else sp = &(repdata->chunker);
2358 sp->result = L_PARTIAL;
2362 handle_strange(void)
2365 char *strangestr = NULL;
2369 repdata = handle_success(L_SUCCESS);
2373 qdisk = quote_string(repdata->disk->name);
2375 addline(&errdet,"");
2376 str = vstralloc("/-- ", prefix(repdata->disk->host->hostname,
2377 qdisk, repdata->level),
2380 addline(&errdet, str);
2383 while(contline_next()) {
2384 get_logline(logfile);
2385 #define sc "sendbackup: warning "
2386 if(strncmp(curstr, sc, SIZEOF(sc)-1) == 0) {
2387 strangestr = newstralloc(strangestr, curstr+SIZEOF(sc)-1);
2389 addline(&errdet, curstr);
2391 addline(&errdet,"\\--------");
2393 str = vstralloc("STRANGE", " ", strangestr, NULL);
2394 addtostrange(repdata->disk->host->hostname, qdisk, repdata->level, str);
2409 char *s, *fp, *qdiskname;
2421 skip_whitespace(s, ch);
2427 skip_non_whitespace(s, ch);
2430 skip_whitespace(s, ch);
2436 skip_quoted_string(s, ch);
2438 diskname = unquote_string(qdiskname);
2440 skip_whitespace(s, ch);
2447 skip_non_whitespace(s, ch);
2449 datestamp = stralloc(fp);
2451 if(strlen(datestamp) < 3) { /* there is no datestamp, it's the level */
2452 level = atoi(datestamp);
2453 datestamp = newstralloc(datestamp, run_datestamp);
2455 else { /* read the level */
2456 skip_whitespace(s, ch);
2457 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2463 skip_integer(s, ch);
2466 skip_whitespace(s, ch);
2474 if((s = strchr(errstr, '\n')) != NULL) {
2478 dp = lookup_disk(hostname, diskname);
2481 addtostrange(hostname, qdiskname, level, "ERROR [not in disklist]");
2483 repdata = find_repdata(dp, datestamp, level);
2485 if(curprog == P_TAPER)
2486 sp = &(repdata->taper);
2487 else sp = &(repdata->dumper);
2489 if(sp->result != L_SUCCESS)
2490 sp->result = L_FAIL;
2494 str = vstralloc("FAILED", " ", errstr, NULL);
2495 addtostrange(hostname, qdiskname, level, str);
2498 if(curprog == P_DUMPER) {
2499 addline(&errdet,"");
2500 str = vstralloc("/-- ", prefix(hostname, qdiskname, level),
2504 addline(&errdet, str);
2506 while(contline_next()) {
2507 get_logline(logfile);
2508 addline(&errdet, curstr);
2510 addline(&errdet,"\\--------");
2517 generate_missing(void)
2522 for(dp = diskq.head; dp != NULL; dp = dp->next) {
2523 if(dp->todo && data(dp) == NULL) {
2524 qdisk = quote_string(dp->name);
2525 addtostrange(dp->host->hostname, qdisk, -987, "RESULTS MISSING");
2532 generate_bad_estimate(void)
2539 for(dp = diskq.head; dp != NULL; dp = dp->next) {
2541 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
2542 if(repdata->est_csize >= 0.1) {
2543 if(repdata->taper.result == L_SUCCESS ||
2544 repdata->taper.result == L_PARTIAL ||
2545 repdata->taper.result == L_CHUNKSUCCESS)
2546 outsize = repdata->taper.outsize;
2547 else if(repdata->chunker.result == L_SUCCESS ||
2548 repdata->chunker.result == L_PARTIAL ||
2549 repdata->chunker.result == L_CHUNKSUCCESS)
2550 outsize = repdata->chunker.outsize;
2552 outsize = repdata->dumper.outsize;
2554 if(repdata->est_csize * 0.9 > outsize) {
2556 " big estimate: %s %s %d",
2557 repdata->disk->host->hostname,
2558 repdata->disk->name,
2563 " est: %.0lf%s out %.0lf%s",
2564 du(repdata->est_csize), displayunit,
2565 du(outsize), displayunit);
2569 else if(repdata->est_csize * 1.1 < outsize) {
2571 " small estimate: %s %s %d",
2572 repdata->disk->host->hostname,
2573 repdata->disk->name,
2578 " est: %.0lf%s out %.0lf%s",
2579 du(repdata->est_csize), displayunit,
2580 du(outsize), displayunit);
2596 char number[NUM_STR_SIZE];
2597 static char *str = NULL;
2599 snprintf(number, SIZEOF(number), "%d", level);
2600 str = newvstralloc(str,
2601 " ", host ? host : "(host?)",
2602 " ", disk ? disk : "(disk?)",
2603 level != -987 ? " lev " : "",
2604 level != -987 ? number : "",
2620 char number[NUM_STR_SIZE];
2621 static char *str = NULL;
2623 snprintf(number, SIZEOF(number), "%d", level);
2624 h=alloc(len_host+1);
2626 strncpy(h, host, len_host);
2628 strncpy(h, "(host?)", len_host);
2631 for(l = strlen(h); l < len_host; l++) {
2634 d=alloc(len_disk+1);
2636 strncpy(d, disk, len_disk);
2638 strncpy(d, "(disk?)", len_disk);
2641 for(l = strlen(d); l < len_disk; l++) {
2644 str = newvstralloc(str,
2647 level != -987 ? " lev " : "",
2648 level != -987 ? number : "",
2665 strange = alloc(SIZEOF(strange_t));
2666 strange->hostname = stralloc(host);
2667 strange->diskname = stralloc(disk);
2668 strange->level = level;
2669 strange->str = stralloc(str);
2670 strange->next = NULL;
2671 if(first_strange == NULL) {
2672 first_strange = strange;
2675 last_strange->next = strange;
2677 last_strange = strange;
2689 if (strchr(lbl_templ, '/') == NULL) {
2690 lbl_templ = stralloc2(config_dir, lbl_templ);
2692 lbl_templ = stralloc(lbl_templ);
2694 if ((fd = open(lbl_templ, 0)) < 0) {
2696 curprog = P_REPORTER;
2697 curstr = vstralloc("could not open PostScript template file ",
2705 afclose(postscript);
2708 while ((numread = read(fd, buf, SIZEOF(buf))) > 0) {
2709 if (fwrite(buf, (size_t)numread, 1, postscript) != 1) {
2711 curprog = P_REPORTER;
2712 curstr = vstralloc("error copying PostScript template file ",
2720 afclose(postscript);
2726 curprog = P_REPORTER;
2727 curstr = vstralloc("error reading PostScript template file ",
2735 afclose(postscript);
2744 /*@keep@*/ disk_t *dp,
2748 repdata_t *repdata, *prev;
2751 datestamp = run_datestamp;
2753 for(repdata = data(dp); repdata != NULL && (repdata->level != level || strcmp(repdata->datestamp,datestamp)!=0); repdata = repdata->next) {
2757 repdata = (repdata_t *)alloc(SIZEOF(repdata_t));
2758 memset(repdata, '\0', SIZEOF(repdata_t));
2760 repdata->datestamp = stralloc(datestamp ? datestamp : "");
2761 repdata->level = level;
2762 repdata->dumper.result = L_BOGUS;
2763 repdata->taper.result = L_BOGUS;
2764 repdata->next = NULL;
2766 prev->next = repdata;
2768 dp->up = (void *)repdata;
2775 do_postscript_output(void)
2777 tapetype_t *tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
2780 double outsize, origsize;
2787 tapesize = tapetype_get_length(tp);
2788 marksize = tapetype_get_filemark(tp);
2790 for(current_tape = stats_by_tape; current_tape != NULL;
2791 current_tape = current_tape->next) {
2793 if (current_tape->label == NULL) {
2797 copy_template_file(tapetype_get_lbl_templ(tp));
2799 /* generate a few elements */
2800 fprintf(postscript,"(%s) DrawDate\n\n",
2801 nicedate(run_datestamp ? run_datestamp : "0"));
2802 fprintf(postscript,"(Amanda Version %s) DrawVers\n",version());
2803 fprintf(postscript,"(%s) DrawTitle\n", current_tape->label);
2806 fprintf(postscript, "(Total Size: %6.1lf MB) DrawStat\n",
2807 mb(current_tape->coutsize));
2808 fprintf(postscript, "(Tape Used (%%) ");
2809 divzero(postscript, pct(current_tape->coutsize +
2810 marksize * (current_tape->tapedisks + current_tape->tapechunks)),
2812 fprintf(postscript," %%) DrawStat\n");
2813 fprintf(postscript, "(Compression Ratio: ");
2814 divzero(postscript, pct(current_tape->coutsize),current_tape->corigsize);
2815 fprintf(postscript," %%) DrawStat\n");
2816 fprintf(postscript,"(Filesystems Taped: %4d) DrawStat\n",
2817 current_tape->tapedisks);
2822 "(-) (%s) (-) ( 0) ( 32) ( 32) DrawHost\n",
2823 current_tape->label);
2825 for(dp = sortq.head; dp != NULL; dp = dp->next) {
2826 if (dp->todo == 0) {
2829 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
2831 if(repdata->taper.tapelabel != current_tape->label) {
2835 if(repdata->dumper.result == L_SUCCESS ||
2836 repdata->dumper.result == L_PARTIAL)
2837 origsize = repdata->dumper.origsize;
2839 origsize = repdata->taper.origsize;
2841 if(repdata->taper.result == L_SUCCESS ||
2842 repdata->taper.result == L_PARTIAL)
2843 outsize = repdata->taper.outsize;
2845 outsize = repdata->dumper.outsize;
2847 if (repdata->taper.result == L_SUCCESS ||
2848 repdata->taper.result == L_PARTIAL) {
2849 if(isnormal(origsize)) {
2850 fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8.0lf) (%8.0lf) DrawHost\n",
2851 dp->host->hostname, dp->name, repdata->level,
2852 repdata->taper.filenum, origsize,
2856 fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8s) (%8.0lf) DrawHost\n",
2857 dp->host->hostname, dp->name, repdata->level,
2858 repdata->taper.filenum, "N/A",
2865 fprintf(postscript,"\nshowpage\n");