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.105 2006/03/09 16:51:42 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 float origsize, outsize;
68 typedef struct repdata_s {
75 struct repdata_s *next;
78 #define data(dp) ((repdata_t *)(dp)->up)
80 static struct cumulative_stats {
81 int dumpdisks, tapedisks, tapechunks;
82 double taper_time, dumper_time;
83 double outsize, origsize, tapesize;
84 double coutsize, corigsize; /* compressed dump only */
87 static int dumpdisks[10], tapedisks[10], tapechunks[10]; /* by-level breakdown of disk count */
89 typedef struct taper_s {
92 double coutsize, corigsize;
93 int tapedisks, tapechunks;
97 static taper_t *stats_by_tape = NULL;
98 static taper_t *current_tape = NULL;
100 typedef struct strange_s {
105 struct strange_s *next;
108 static strange_t *first_strange=NULL, *last_strange=NULL;
110 static float total_time, startup_time, planner_time;
112 /* count files to tape */
113 static int tapefcount = 0;
115 static char *run_datestamp;
116 static char *today_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 static int contline_next P((void));
145 static void addline P((line_t **lp, char *str));
146 static void usage P((void));
147 int main P((int argc, char **argv));
149 static void copy_template_file P((char *lbl_templ));
150 static void do_postscript_output P((void));
151 static void handle_start P((void));
152 static void handle_finish P((void));
153 static void handle_note P((void));
154 static void handle_summary P((void));
155 static void handle_stats P((void));
156 static void handle_error P((void));
157 static void handle_disk P((void));
158 static repdata_t *handle_success P((logtype_t logtype));
159 static repdata_t *handle_chunk P((void));
160 static void handle_partial P((void));
161 static void handle_strange P((void));
162 static void handle_failed P((void));
163 static void generate_missing P((void));
164 static void output_tapeinfo P((void));
165 static void output_lines P((line_t *lp, FILE *f));
166 static void output_stats P((void));
167 static void output_summary P((void));
168 static void output_strange P((void));
169 static void sort_disks P((void));
170 static int sort_by_name P((disk_t *a, disk_t *b));
171 static void bogus_line P((void));
172 static char *nicedate P((int datestamp));
173 static char *prefix P((char *host, char *disk, int level));
174 static char *prefixstrange P((char *host, char *disk, int level, int len_host, int len_disk));
175 static void addtostrange P((char *host, char *disk, int level, char *str));
176 static repdata_t *find_repdata P((disk_t *dp, char *datestamp, int level));
184 for (i=From; i<=To && ColumnData[i].Name != NULL; i++) {
185 Width+= ColumnData[i].PrefixSpace + ColumnData[i].Width;
195 int Leng= ColWidth(0, ColumnDataCount());
196 char *RuleSpace= alloc(Leng+1);
197 ThisLeng= ColWidth(From, To);
198 for (i=0;i<ColumnData[From].PrefixSpace; i++)
200 for (; i<ThisLeng; i++)
202 RuleSpace[ThisLeng]= '\0';
207 TextRule(From, To, s)
211 ColumnInfo *cd= &ColumnData[From];
212 int leng, nbrules, i, txtlength;
213 int RuleSpaceSize= ColWidth(0, ColumnDataCount());
214 char *RuleSpace= alloc(RuleSpaceSize), *tmp;
217 if(leng >= (RuleSpaceSize - cd->PrefixSpace))
218 leng = RuleSpaceSize - cd->PrefixSpace - 1;
219 snprintf(RuleSpace, RuleSpaceSize, "%*s%*.*s ", cd->PrefixSpace, "",
221 txtlength = cd->PrefixSpace + leng + 1;
222 nbrules = ColWidth(From,To) - txtlength;
223 for(tmp=RuleSpace + txtlength, i=nbrules ; i>0; tmp++,i--)
234 ColumnInfo *cd= &ColumnData[cn];
235 static char PrtBuf[256];
237 snprintf(PrtBuf, sizeof(PrtBuf),
238 "%*s", cd->Width, "-- ");
240 snprintf(PrtBuf, sizeof(PrtBuf),
241 cd->Format, cd->Width, cd->Precision, a/b);
263 /* allocate new line node */
264 new = (line_t *) alloc(sizeof(line_t));
266 new->str = stralloc(str);
268 /* add to end of list */
269 for(p = *lp, q = NULL; p != NULL; q = p, p = p->next);
270 if(q == NULL) *lp = new;
277 error("Usage: amreport conf [-f output-file] [-l logfile] [-p postscript-file]");
289 char *logfname, *psfname, *outfname, *subj_str = NULL;
292 unsigned long malloc_hist_1, malloc_size_1;
293 unsigned long malloc_hist_2, malloc_size_2;
294 char *mail_cmd = NULL, *printer_cmd = NULL;
296 char my_cwd[STR_SIZE];
297 char *ColumnSpec = "";
303 set_pname("amreport");
305 /* Don't die when child closes pipe */
306 signal(SIGPIPE, SIG_IGN);
308 malloc_size_1 = malloc_inuse(&malloc_hist_1);
310 /* Process options */
312 erroutput_type = ERR_INTERACTIVE;
317 if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
318 error("cannot determine current working directory");
322 config_dir = stralloc2(my_cwd, "/");
323 if ((config_name = strrchr(my_cwd, '/')) != NULL) {
324 config_name = stralloc(config_name + 1);
327 if (argv[1][0] == '-') {
331 config_name = stralloc(argv[1]);
332 config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
334 while((opt = getopt(argc, argv, "f:l:p:")) != EOF) {
337 if (outfname != NULL) {
338 error("you may specify at most one -f");
340 if (*optarg == '/') {
341 outfname = stralloc(optarg);
343 outfname = vstralloc(my_cwd, "/", optarg, NULL);
347 if (logfname != NULL) {
348 error("you may specify at most one -l");
350 if (*optarg == '/') {
351 logfname = stralloc(optarg);
353 logfname = vstralloc(my_cwd, "/", optarg, NULL);
357 if (psfname != NULL) {
358 error("you may specify at most one -p");
360 if (*optarg == '/') {
361 psfname = stralloc(optarg);
363 psfname = vstralloc(my_cwd, "/", optarg, NULL);
384 printf("You must run amreport with '-f <output file>' because configure\n");
385 printf("didn't find a mailer.\n");
392 /* read configuration files */
394 conffile = stralloc2(config_dir, CONFFILE_NAME);
395 if(read_conffile(conffile)) {
396 error("errors processing config file \"%s\"", conffile);
399 conf_diskfile = getconf_str(CNF_DISKFILE);
400 if (*conf_diskfile == '/') {
401 conf_diskfile = stralloc(conf_diskfile);
403 conf_diskfile = stralloc2(config_dir, conf_diskfile);
405 if(read_diskfile(conf_diskfile, &diskq) < 0) {
406 error("could not load disklist \"%s\"", conf_diskfile);
408 amfree(conf_diskfile);
409 conf_tapelist = getconf_str(CNF_TAPELIST);
410 if (*conf_tapelist == '/') {
411 conf_tapelist = stralloc(conf_tapelist);
413 conf_tapelist = stralloc2(config_dir, conf_tapelist);
415 if(read_tapelist(conf_tapelist)) {
416 error("could not read tapelist \"%s\"", conf_tapelist);
418 amfree(conf_tapelist);
419 conf_infofile = getconf_str(CNF_INFOFILE);
420 if (*conf_infofile == '/') {
421 conf_infofile = stralloc(conf_infofile);
423 conf_infofile = stralloc2(config_dir, conf_infofile);
425 if(open_infofile(conf_infofile)) {
426 error("could not open info db \"%s\"", conf_infofile);
428 amfree(conf_infofile);
430 today_datestamp = construct_datestamp(NULL);
432 displayunit = getconf_str(CNF_DISPLAYUNIT);
433 unitdivisor = getconf_unit_divisor();
435 ColumnSpec = getconf_str(CNF_COLUMNSPEC);
436 if(SetColumDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
438 curprog = P_REPORTER;
443 ColumnSpec = ""; /* use the default */
444 if(SetColumDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
446 curprog = P_REPORTER;
453 for (cn = 0; ColumnData[cn].Name != NULL; cn++) {
454 if (ColumnData[cn].MaxWidth) {
455 MaxWidthsRequested = 1;
463 conf_logdir = getconf_str(CNF_LOGDIR);
464 if (*conf_logdir == '/') {
465 conf_logdir = stralloc(conf_logdir);
467 conf_logdir = stralloc2(config_dir, conf_logdir);
469 logfname = vstralloc(conf_logdir, "/", "log", NULL);
473 if((logfile = fopen(logfname, "r")) == NULL) {
475 curprog = P_REPORTER;
476 curstr = vstralloc("could not open log ",
485 while(logfile && get_logline(logfile)) {
487 case L_START: handle_start(); break;
488 case L_FINISH: handle_finish(); break;
490 case L_INFO: handle_note(); break;
491 case L_WARNING: handle_note(); break;
493 case L_SUMMARY: handle_summary(); break;
494 case L_STATS: handle_stats(); break;
496 case L_ERROR: handle_error(); break;
497 case L_FATAL: handle_error(); break;
499 case L_DISK: handle_disk(); break;
501 case L_SUCCESS: handle_success(curlog); break;
502 case L_CHUNKSUCCESS: handle_success(curlog); break;
503 case L_CHUNK: handle_chunk(); break;
504 case L_PARTIAL: handle_partial(); break;
505 case L_STRANGE: handle_strange(); break;
506 case L_FAIL: handle_failed(); break;
510 curprog = P_REPORTER;
511 curstr = stralloc2("unexpected log line: ", curstr);
521 subj_str = vstralloc(getconf_str(CNF_ORG),
522 " ", amflush_run ? "AMFLUSH" : "AMANDA",
523 " ", "MAIL REPORT FOR",
524 " ", nicedate(run_datestamp ? atoi(run_datestamp) : 0),
527 /* lookup the tapetype and printer type from the amanda.conf file. */
528 tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
529 printer = getconf_str(CNF_PRINTER);
531 /* ignore SIGPIPE so if a child process dies we do not also go away */
532 signal(SIGPIPE, SIG_IGN);
534 /* open pipe to mailer */
537 /* output to a file */
538 if((mailf = fopen(outfname,"w")) == NULL) {
539 error("could not open output file: %s %s", outfname, strerror(errno));
541 fprintf(mailf, "To: %s\n", getconf_str(CNF_MAILTO));
542 fprintf(mailf, "Subject: %s\n\n", subj_str);
546 mail_cmd = vstralloc(MAILER,
547 " -s", " \"", subj_str, "\"",
548 " ", getconf_str(CNF_MAILTO),
550 if((mailf = popen(mail_cmd, "w")) == NULL)
551 error("could not open pipe to \"%s\": %s",
552 mail_cmd, strerror(errno));
556 /* open pipe to print spooler if necessary) */
559 /* if the postscript_label_template (tp->lbl_templ) field is not */
560 /* the empty string (i.e. it is set to something), open the */
561 /* postscript debugging file for writing. */
562 if ((strcmp(tp->lbl_templ, "")) != 0) {
563 if ((postscript = fopen(psfname, "w")) == NULL) {
565 curprog = P_REPORTER;
566 curstr = vstralloc("could not open ",
577 if (strcmp(printer, "") != 0) /* alternate printer is defined */
578 /* print to the specified printer */
580 printer_cmd = vstralloc(LPRCMD, " ", LPRFLAG, printer, NULL);
582 printer_cmd = vstralloc(LPRCMD, NULL);
585 /* print to the default printer */
586 printer_cmd = vstralloc(LPRCMD, NULL);
589 if ((strcmp(tp->lbl_templ, "")) != 0) {
591 if ((postscript = popen(printer_cmd, "w")) == NULL) {
593 curprog = P_REPORTER;
594 curstr = vstralloc("could not open pipe to ",
604 curprog = P_REPORTER;
605 curstr = stralloc("no printer command defined");
615 if(!got_finish) fputs("*** THE DUMPS DID NOT FINISH PROPERLY!\n\n", mailf);
619 if(first_strange || errsum) {
620 fprintf(mailf,"\nFAILURE AND STRANGE DUMP SUMMARY:\n");
621 if(first_strange) output_strange();
622 if(errsum) output_lines(errsum, mailf);
624 fputs("\n\n", mailf);
629 fprintf(mailf,"\n\014\nFAILED AND STRANGE DUMP DETAILS:\n");
630 output_lines(errdet, mailf);
633 fprintf(mailf,"\n\014\nNOTES:\n");
634 output_lines(notes, mailf);
637 if(sortq.head != NULL) {
638 fprintf(mailf,"\n\014\nDUMP SUMMARY:\n");
641 fprintf(mailf,"\n(brought to you by Amanda version %s)\n",
645 do_postscript_output();
649 /* close postscript file */
650 if (psfname && postscript) {
651 /* it may be that postscript is NOT opened */
655 if (postscript != NULL && pclose(postscript) != 0)
656 error("printer command failed: %s", printer_cmd);
660 /* close output file */
665 if(pclose(mailf) != 0)
666 error("mail command failed: %s", mail_cmd);
670 amfree(run_datestamp);
678 malloc_size_2 = malloc_inuse(&malloc_hist_2);
680 if(malloc_size_1 != malloc_size_2) {
681 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
689 #define mb(f) ((f)/1024) /* kbytes -> mbutes */
690 #define du(f) ((f)/unitdivisor) /* kbytes -> displayunit */
691 #define pct(f) ((f)*100.0) /* percent */
692 #define hrmn(f) ((int)(f)+30)/3600, (((int)(f)+30)%3600)/60
693 #define mnsc(f) ((int)(f+0.5))/60, ((int)(f+0.5)) % 60
695 #define divzero(fp,a,b) \
699 fprintf((fp)," -- "); \
700 else if ((q = (a)/q) >= 999.95) \
701 fprintf((fp), "###.#"); \
703 fprintf((fp), "%5.1f",q); \
705 #define divzero_wide(fp,a,b) \
709 fprintf((fp)," -- "); \
710 else if ((q = (a)/q) >= 99999.95) \
711 fprintf((fp), "#####.#"); \
713 fprintf((fp), "%7.1f",q); \
720 tapetype_t *tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
721 int tapesize, marksize, lv, first;
723 tapesize = tp->length;
724 marksize = tp->filemark;
726 stats[2].dumpdisks = stats[0].dumpdisks + stats[1].dumpdisks;
727 stats[2].tapedisks = stats[0].tapedisks + stats[1].tapedisks;
728 stats[2].tapechunks = stats[0].tapechunks + stats[1].tapechunks;
729 stats[2].outsize = stats[0].outsize + stats[1].outsize;
730 stats[2].origsize = stats[0].origsize + stats[1].origsize;
731 stats[2].tapesize = stats[0].tapesize + stats[1].tapesize;
732 stats[2].coutsize = stats[0].coutsize + stats[1].coutsize;
733 stats[2].corigsize = stats[0].corigsize + stats[1].corigsize;
734 stats[2].taper_time = stats[0].taper_time + stats[1].taper_time;
735 stats[2].dumper_time = stats[0].dumper_time + stats[1].dumper_time;
737 if(!got_finish) /* no driver finish line, estimate total run time */
738 total_time = stats[2].taper_time + planner_time;
740 idle_time = (total_time - startup_time) - stats[2].taper_time;
741 if(idle_time < 0) idle_time = 0.0;
743 fprintf(mailf,"STATISTICS:\n");
745 " Total Full Incr.\n");
747 " -------- -------- --------\n");
750 "Estimate Time (hrs:min) %2d:%02d\n", hrmn(planner_time));
753 "Run Time (hrs:min) %2d:%02d\n", hrmn(total_time));
756 "Dump Time (hrs:min) %2d:%02d %2d:%02d %2d:%02d\n",
757 hrmn(stats[2].dumper_time), hrmn(stats[0].dumper_time),
758 hrmn(stats[1].dumper_time));
761 "Output Size (meg) %8.1f %8.1f %8.1f\n",
762 mb(stats[2].outsize), mb(stats[0].outsize), mb(stats[1].outsize));
765 "Original Size (meg) %8.1f %8.1f %8.1f\n",
766 mb(stats[2].origsize), mb(stats[0].origsize),
767 mb(stats[1].origsize));
769 fprintf(mailf, "Avg Compressed Size (%%) ");
770 divzero(mailf, pct(stats[2].coutsize),stats[2].corigsize);
772 divzero(mailf, pct(stats[0].coutsize),stats[0].corigsize);
774 divzero(mailf, pct(stats[1].coutsize),stats[1].corigsize);
776 if(stats[1].dumpdisks > 0) fputs(" (level:#disks ...)", mailf);
780 "Filesystems Dumped %4d %4d %4d",
781 stats[2].dumpdisks, stats[0].dumpdisks, stats[1].dumpdisks);
783 if(stats[1].dumpdisks > 0) {
785 for(lv = 1; lv < 10; lv++) if(dumpdisks[lv]) {
786 fputs(first?" (":" ", mailf);
788 fprintf(mailf, "%d:%d", lv, dumpdisks[lv]);
794 fprintf(mailf, "Avg Dump Rate (k/s) ");
795 divzero_wide(mailf, stats[2].outsize,stats[2].dumper_time);
797 divzero_wide(mailf, stats[0].outsize,stats[0].dumper_time);
799 divzero_wide(mailf, stats[1].outsize,stats[1].dumper_time);
804 "Tape Time (hrs:min) %2d:%02d %2d:%02d %2d:%02d\n",
805 hrmn(stats[2].taper_time), hrmn(stats[0].taper_time),
806 hrmn(stats[1].taper_time));
809 "Tape Size (meg) %8.1f %8.1f %8.1f\n",
810 mb(stats[2].tapesize), mb(stats[0].tapesize),
811 mb(stats[1].tapesize));
813 fprintf(mailf, "Tape Used (%%) ");
814 divzero(mailf, pct(stats[2].tapesize+marksize*(stats[2].tapedisks+stats[2].tapechunks)),tapesize);
816 divzero(mailf, pct(stats[0].tapesize+marksize*(stats[0].tapedisks+stats[0].tapechunks)),tapesize);
818 divzero(mailf, pct(stats[1].tapesize+marksize*(stats[1].tapedisks+stats[1].tapechunks)),tapesize);
820 if(stats[1].tapedisks > 0) fputs(" (level:#disks ...)", mailf);
824 "Filesystems Taped %4d %4d %4d",
825 stats[2].tapedisks, stats[0].tapedisks, stats[1].tapedisks);
827 if(stats[1].tapedisks > 0) {
829 for(lv = 1; lv < 10; lv++) if(tapedisks[lv]) {
830 fputs(first?" (":" ", mailf);
832 fprintf(mailf, "%d:%d", lv, tapedisks[lv]);
838 if(stats[1].tapechunks > 0) fputs(" (level:#chunks ...)", mailf);
842 "Chunks Taped %4d %4d %4d",
843 stats[2].tapechunks, stats[0].tapechunks, stats[1].tapechunks);
845 if(stats[1].tapechunks > 0) {
847 for(lv = 1; lv < 10; lv++) if(tapechunks[lv]) {
848 fputs(first?" (":" ", mailf);
850 fprintf(mailf, "%d:%d", lv, tapechunks[lv]);
856 fprintf(mailf, "Avg Tp Write Rate (k/s) ");
857 divzero_wide(mailf, stats[2].tapesize,stats[2].taper_time);
859 divzero_wide(mailf, stats[0].tapesize,stats[0].taper_time);
861 divzero_wide(mailf, stats[1].tapesize,stats[1].taper_time);
865 int label_length = strlen(stats_by_tape->label) + 5;
866 fprintf(mailf,"\nUSAGE BY TAPE:\n");
867 fprintf(mailf," %-*s Time Size %% Nb Nc\n",
868 label_length, "Label");
869 for(current_tape = stats_by_tape; current_tape != NULL;
870 current_tape = current_tape->next) {
871 fprintf(mailf, " %-*s", label_length, current_tape->label);
872 fprintf(mailf, " %2d:%02d", hrmn(current_tape->taper_time));
873 fprintf(mailf, " %8.0f%s ", du(current_tape->coutsize), displayunit);
874 divzero(mailf, pct(current_tape->coutsize +
875 marksize * (current_tape->tapedisks+current_tape->tapechunks)),
877 fprintf(mailf, " %4d", current_tape->tapedisks);
878 fprintf(mailf, " %4d\n", current_tape->tapechunks);
893 if (last_run_tapes > 0) {
895 fprintf(mailf, "The dumps were flushed to tape%s %s.\n",
896 last_run_tapes == 1 ? "" : "s",
897 tape_labels ? tape_labels : "");
899 fprintf(mailf, "These dumps were to tape%s %s.\n",
900 last_run_tapes == 1 ? "" : "s",
901 tape_labels ? tape_labels : "");
906 "*** A TAPE ERROR OCCURRED: %s.\n", tapestart_error);
907 fputs("Some dumps may have been left in the holding disk.\n", mailf);
909 "Run amflush%s to flush them to tape.\n",
910 amflush_run ? " again" : "");
913 tp = lookup_last_reusable_tape(skip);
915 run_tapes = getconf_int(CNF_RUNTAPES);
918 fputs("The next tape Amanda expects to use is: ", mailf);
919 else if(run_tapes > 1)
920 fprintf(mailf, "The next %d tapes Amanda expects to use are: ",
923 while(run_tapes > 0) {
925 fprintf(mailf, "%s", tp->label);
927 fputs("a new tape", mailf);
929 if(run_tapes > 1) fputs(", ", mailf);
933 tp = lookup_last_reusable_tape(skip);
937 lasttp = lookup_tapepos(lookup_nb_tape());
938 run_tapes = getconf_int(CNF_RUNTAPES);
939 if(lasttp && run_tapes > 0 && lasttp->datestamp == 0) {
941 while(lasttp && run_tapes > 0 && lasttp->datestamp == 0) {
943 lasttp = lasttp->prev;
946 lasttp = lookup_tapepos(lookup_nb_tape());
948 fprintf(mailf, "The next new tape already labelled is: %s.\n",
952 fprintf(mailf, "The next %d new tapes already labelled are: %s", c,
954 lasttp = lasttp->prev;
956 while(lasttp && c > 0 && lasttp->datestamp == 0) {
957 fprintf(mailf, ", %s", lasttp->label);
958 lasttp = lasttp->prev;
961 fprintf(mailf, ".\n");
967 static void output_strange()
969 int len_host=0, len_disk=0;
973 for(strange=first_strange; strange != NULL; strange = strange->next) {
974 if(strlen(strange->hostname) > len_host)
975 len_host = strlen(strange->hostname);
976 if(strlen(strange->diskname) > len_disk)
977 len_disk = strlen(strange->diskname);
979 for(strange=first_strange; strange != NULL; strange = strange->next) {
980 str = vstralloc(" ", prefixstrange(strange->hostname, strange->diskname, strange->level, len_host, len_disk),
981 " ", strange->str, NULL);
982 fprintf(mailf, "%s\n", str);
1011 rc = strcmp(a->host->hostname, b->host->hostname);
1012 if(rc == 0) rc = strcmp(a->name, b->name);
1021 sortq.head = sortq.tail = NULL;
1022 while(!empty(diskq)) {
1023 dp = dequeue_disk(&diskq);
1024 if(data(dp) == NULL) { /* create one */
1025 find_repdata(dp, run_datestamp, 0);
1027 insert_disk(&sortq, dp, sort_by_name);
1032 CheckStringMax(cd, s)
1051 snprintf(testBuf, sizeof(testBuf),
1052 cd->Format, cd->Width, cd->Precision, n);
1060 CheckFloatMax(cd, d)
1067 snprintf(testBuf, sizeof(testBuf),
1068 cd->Format, cd->Width, cd->Precision, d);
1075 static int HostName;
1080 static int Compress;
1081 static int DumpTime;
1082 static int DumpRate;
1083 static int TapeTime;
1084 static int TapeRate;
1089 /* we have to look for columspec's, that require the recalculation.
1090 * we do here the same loops over the sortq as is done in
1091 * output_summary. So, if anything is changed there, we have to
1092 * change this here also.
1098 for(dp = sortq.head; dp != NULL; dp = dp->next) {
1100 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
1102 char TimeRateBuffer[40];
1104 CheckStringMax(&ColumnData[HostName], dp->host->hostname);
1105 CheckStringMax(&ColumnData[Disk], dp->name);
1106 if (repdata->dumper.result == L_BOGUS &&
1107 repdata->taper.result == L_BOGUS)
1109 CheckIntMax(&ColumnData[Level], repdata->level);
1110 if(repdata->dumper.result == L_SUCCESS ||
1111 repdata->dumper.result == L_CHUNKSUCCESS) {
1112 CheckFloatMax(&ColumnData[OrigKB], du(repdata->dumper.origsize));
1113 CheckFloatMax(&ColumnData[OutKB], du(repdata->dumper.outsize));
1114 if(dp->compress == COMP_NONE)
1117 f = repdata->dumper.origsize;
1118 CheckStringMax(&ColumnData[Disk],
1119 sDivZero(pct(repdata->dumper.outsize), f, Compress));
1122 snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1123 "%3d:%02d", mnsc(repdata->dumper.sec));
1125 snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1127 CheckStringMax(&ColumnData[DumpTime], TimeRateBuffer);
1129 CheckFloatMax(&ColumnData[DumpRate], repdata->dumper.kps);
1132 cd= &ColumnData[TapeTime];
1133 if(repdata->taper.result == L_FAIL) {
1134 CheckStringMax(cd, "FAILED");
1137 if(repdata->taper.result == L_SUCCESS ||
1138 repdata->taper.result == L_CHUNKSUCCESS)
1139 snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1140 "%3d:%02d", mnsc(repdata->taper.sec));
1142 snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1144 CheckStringMax(cd, TimeRateBuffer);
1146 cd= &ColumnData[TapeRate];
1147 if(repdata->taper.result == L_SUCCESS ||
1148 repdata->taper.result == L_CHUNKSUCCESS)
1149 CheckFloatMax(cd, repdata->taper.kps);
1151 CheckStringMax(cd, "N/A ");
1162 char *ds="DUMPER STATS";
1163 char *ts=" TAPER STATS";
1166 int i, h, w1, wDump, wTape;
1167 float outsize, origsize;
1170 HostName = StringToColumn("HostName");
1171 Disk = StringToColumn("Disk");
1172 Level = StringToColumn("Level");
1173 OrigKB = StringToColumn("OrigKB");
1174 OutKB = StringToColumn("OutKB");
1175 Compress = StringToColumn("Compress");
1176 DumpTime = StringToColumn("DumpTime");
1177 DumpRate = StringToColumn("DumpRate");
1178 TapeTime = StringToColumn("TapeTime");
1179 TapeRate = StringToColumn("TapeRate");
1181 /* at first determine if we have to recalculate our widths */
1182 if (MaxWidthsRequested)
1185 /* title for Dumper-Stats */
1186 w1= ColWidth(HostName, Level);
1187 wDump= ColWidth(OrigKB, DumpRate);
1188 wTape= ColWidth(TapeTime, TapeRate);
1190 /* print centered top titles */
1197 fprintf(mailf, "%*s", w1+h, "");
1198 fprintf(mailf, "%-*s", wDump-h, ds);
1205 fprintf(mailf, "%*s", h, "");
1206 fprintf(mailf, "%-*s", wTape-h, ts);
1209 /* print the titles */
1210 for (i=0; ColumnData[i].Name != NULL; i++) {
1212 ColumnInfo *cd= &ColumnData[i];
1213 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1214 if (cd->Format[1] == '-')
1218 if(strcmp(cd->Title,"ORIG-KB") == 0) {
1219 /* cd->Title must be re-allocated in write-memory */
1220 cd->Title = stralloc("ORIG-KB");
1221 cd->Title[5] = displayunit[0];
1223 if(strcmp(cd->Title,"OUT-KB") == 0) {
1224 /* cd->Title must be re-allocated in write-memory */
1225 cd->Title = stralloc("OUT-KB");
1226 cd->Title[4] = displayunit[0];
1228 fprintf(mailf, fmt, cd->Width, cd->Title);
1232 /* print the rules */
1233 fputs(tmp=Rule(HostName, Level), mailf); amfree(tmp);
1234 fputs(tmp=Rule(OrigKB, DumpRate), mailf); amfree(tmp);
1235 fputs(tmp=Rule(TapeTime, TapeRate), mailf); amfree(tmp);
1238 for(dp = sortq.head; dp != NULL; dp = dp->next) {
1241 char TimeRateBuffer[40];
1242 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
1245 cd= &ColumnData[HostName];
1246 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1247 fprintf(mailf, cd->Format, cd->Width, cd->Width, dp->host->hostname);
1249 cd= &ColumnData[Disk];
1250 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1251 devlen= strlen(dp->name);
1252 if (devlen > cd->Width) {
1254 fprintf(mailf, cd->Format, cd->Width-1, cd->Precision-1,
1255 dp->name+devlen - (cd->Width-1) );
1258 fprintf(mailf, cd->Format, cd->Width, cd->Width, dp->name);
1260 cd= &ColumnData[Level];
1261 if (repdata->dumper.result == L_BOGUS &&
1262 repdata->taper.result == L_BOGUS) {
1264 fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
1265 tmp=TextRule(OrigKB, TapeRate, "NO FILE TO FLUSH"));
1267 fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
1268 tmp=TextRule(OrigKB, TapeRate, "MISSING"));
1274 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1275 fprintf(mailf, cd->Format, cd->Width, cd->Precision,repdata->level);
1277 if (repdata->dumper.result == L_SKIPPED) {
1278 fprintf(mailf, "%s\n",
1279 tmp=TextRule(OrigKB, TapeRate, "SKIPPED"));
1283 if (repdata->dumper.result == L_FAIL && (repdata->chunker.result != L_PARTIAL && repdata->taper.result != L_PARTIAL)) {
1284 fprintf(mailf, "%s\n",
1285 tmp=TextRule(OrigKB, TapeRate, "FAILED"));
1290 if(repdata->dumper.result == L_SUCCESS ||
1291 repdata->dumper.result == L_CHUNKSUCCESS)
1292 origsize = repdata->dumper.origsize;
1293 else if(repdata->taper.result == L_SUCCESS ||
1294 repdata->taper.result == L_PARTIAL)
1295 origsize = repdata->taper.origsize;
1297 origsize = repdata->chunker.origsize;
1299 if(repdata->taper.result == L_SUCCESS ||
1300 repdata->taper.result == L_PARTIAL ||
1301 repdata->taper.result == L_CHUNKSUCCESS)
1302 outsize = repdata->taper.outsize;
1303 else if(repdata->chunker.result == L_SUCCESS ||
1304 repdata->chunker.result == L_PARTIAL ||
1305 repdata->chunker.result == L_CHUNKSUCCESS)
1306 outsize = repdata->chunker.outsize;
1308 outsize = repdata->dumper.outsize;
1310 cd= &ColumnData[OrigKB];
1311 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1313 fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(origsize));
1315 fprintf(mailf, "%*.*s", cd->Width, cd->Width, "N/A");
1317 cd= &ColumnData[OutKB];
1318 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1320 fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(outsize));
1322 cd= &ColumnData[Compress];
1323 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1325 if(dp->compress == COMP_NONE)
1327 else if(origsize < 1.0)
1332 fputs(sDivZero(pct(outsize), f, Compress), mailf);
1334 cd= &ColumnData[DumpTime];
1335 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1336 if(repdata->dumper.result == L_SUCCESS ||
1337 repdata->dumper.result == L_CHUNKSUCCESS)
1338 snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1339 "%3d:%02d", mnsc(repdata->dumper.sec));
1341 snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1343 fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
1345 cd= &ColumnData[DumpRate];
1346 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1347 if(repdata->dumper.result == L_SUCCESS ||
1348 repdata->dumper.result == L_CHUNKSUCCESS)
1349 fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->dumper.kps);
1351 fprintf(mailf, "%*s", cd->Width, "N/A ");
1353 cd= &ColumnData[TapeTime];
1354 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1355 if(repdata->taper.result == L_FAIL) {
1356 fprintf(mailf, "%s\n",
1357 tmp=TextRule(TapeTime, TapeRate, "FAILED "));
1362 if(repdata->taper.result == L_SUCCESS ||
1363 repdata->taper.result == L_PARTIAL ||
1364 repdata->taper.result == L_CHUNKSUCCESS)
1365 snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1366 "%3d:%02d", mnsc(repdata->taper.sec));
1368 snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1370 fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
1372 cd= &ColumnData[TapeRate];
1373 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1374 if(repdata->taper.result == L_SUCCESS ||
1375 repdata->taper.result == L_PARTIAL ||
1376 repdata->taper.result == L_CHUNKSUCCESS)
1377 fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->taper.kps);
1379 fprintf(mailf, "%*s", cd->Width, "N/A ");
1381 if(repdata->chunker.result == L_PARTIAL ||
1382 repdata->taper.result == L_PARTIAL) {
1383 fprintf(mailf, " PARTIAL");
1394 printf("line %d of log is bogus\n", curlinenum);
1402 * Formats an integer of the form YYYYMMDD into the string
1403 * "Monthname DD, YYYY". A pointer to the statically allocated string
1404 * is returned, so it must be copied to other storage (or just printed)
1405 * before calling nicedate() again.
1408 static char nice[64];
1409 static char *months[13] = { "BogusMonth",
1410 "January", "February", "March", "April", "May", "June",
1411 "July", "August", "September", "October", "November", "December"
1413 int year, month, day;
1415 year = datestamp / 10000;
1416 day = datestamp % 100;
1417 month = (datestamp / 100) % 100;
1419 snprintf(nice, sizeof(nice), "%s %d, %d", months[month], day, year);
1427 static int started = 0;
1437 skip_whitespace(s, ch);
1438 #define sc "datestamp"
1439 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1446 skip_whitespace(s, ch);
1452 skip_non_whitespace(s, ch);
1454 run_datestamp = newstralloc(run_datestamp, fp);
1457 skip_whitespace(s, ch);
1459 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1466 skip_whitespace(s, ch);
1472 skip_non_whitespace(s, ch);
1475 label = stralloc(fp);
1479 fp = vstralloc(tape_labels, ", ", label, NULL);
1480 amfree(tape_labels);
1483 tape_labels = stralloc(label);
1488 if(stats_by_tape == NULL) {
1489 stats_by_tape = current_tape = (taper_t *)alloc(sizeof(taper_t));
1492 current_tape->next = (taper_t *)alloc(sizeof(taper_t));
1493 current_tape = current_tape->next;
1495 current_tape->label = label;
1496 current_tape->taper_time = 0.0;
1497 current_tape->coutsize = 0.0;
1498 current_tape->corigsize = 0.0;
1499 current_tape->tapedisks = 0;
1500 current_tape->tapechunks = 0;
1501 current_tape->next = NULL;
1521 skip_whitespace(s, ch);
1523 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1524 return; /* ignore bogus line */
1529 skip_whitespace(s, ch);
1535 skip_non_whitespace(s, ch);
1537 run_datestamp = newstralloc(run_datestamp, fp);
1542 if(amflush_run && normal_run) {
1545 " reporter: both amflush and planner output in log, ignoring amflush.");
1557 if(curprog == P_DRIVER || curprog == P_AMFLUSH || curprog == P_PLANNER) {
1561 skip_whitespace(s, ch);
1563 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1571 skip_whitespace(s, ch);
1576 skip_non_whitespace(s, ch); /* ignore the date string */
1578 skip_whitespace(s, ch);
1580 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1581 /* older planner doesn't write time */
1582 if(curprog == P_PLANNER) return;
1590 skip_whitespace(s, ch);
1595 if(sscanf(s - 1, "%f", &a_time) != 1) {
1599 if(curprog == P_PLANNER) {
1600 planner_time = a_time;
1603 total_time = a_time;
1615 if(curprog == P_DRIVER) {
1619 skip_whitespace(s, ch);
1620 #define sc "startup time"
1621 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1629 skip_whitespace(s, ch);
1634 if(sscanf(s - 1, "%f", &startup_time) != 1) {
1638 planner_time = startup_time;
1648 str = vstralloc(" ", program_str[curprog], ": ", curstr, NULL);
1649 addline(¬es, str);
1659 char *s = NULL, *nl;
1662 if(curlog == L_ERROR && curprog == P_TAPER) {
1666 skip_whitespace(s, ch);
1667 #define sc "no-tape"
1668 if(ch != '\0' && strncmp(s - 1, sc, sizeof(sc)-1) == 0) {
1673 skip_whitespace(s, ch);
1675 if((nl = strchr(s - 1, '\n')) != NULL) {
1678 tapestart_error = newstralloc(tapestart_error, s - 1);
1683 /* else some other tape error, handle like other errors */
1685 /* else some other tape error, handle like other errors */
1687 s = vstralloc(" ", program_str[curprog], ": ",
1688 logtype_str[curlog], " ", curstr, NULL);
1689 addline(&errsum, s);
1703 static int nb_disk=0;
1710 char *hostname = NULL, *diskname = NULL;
1712 if(curprog != P_PLANNER && curprog != P_AMFLUSH) {
1718 for(dp = diskq.head; dp != NULL; dp = dp->next)
1726 skip_whitespace(s, ch);
1732 skip_non_whitespace(s, ch);
1734 hostname = newstralloc(hostname, fp);
1737 skip_whitespace(s, ch);
1744 skip_non_whitespace(s, ch);
1746 diskname = newstralloc(diskname, fp);
1749 dp = lookup_disk(hostname, diskname);
1751 dp = add_disk(&diskq, hostname, diskname);
1759 /* XXX Just a placeholder, in case we decide to do something with L_CHUNK
1760 * log entries. Right now they're just the equivalent of L_SUCCESS, but only
1761 * for a split chunk of the overall dumpfile.
1767 float sec, kps, kbytes;
1772 char *hostname = NULL;
1773 char *diskname = NULL;
1778 if(curprog != P_TAPER) {
1786 skip_whitespace(s, ch);
1792 skip_non_whitespace(s, ch);
1794 hostname = stralloc(fp);
1797 skip_whitespace(s, ch);
1804 skip_non_whitespace(s, ch);
1806 diskname = stralloc(fp);
1809 skip_whitespace(s, ch);
1817 skip_non_whitespace(s, ch);
1819 datestamp = stralloc(fp);
1822 level = atoi(datestamp);
1824 datestamp = newstralloc(datestamp, run_datestamp);
1827 skip_whitespace(s, ch);
1828 if(ch == '\0' || sscanf(s - 1, "%d", &chunk) != 1) {
1835 skip_integer(s, ch);
1837 skip_whitespace(s, ch);
1838 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1845 skip_integer(s, ch);
1847 skip_whitespace(s, ch);
1849 if(level < 0 || level > 9) {
1856 if(sscanf(s - 1,"[sec %f kb %f kps %f", &sec, &kbytes, &kps) != 3) {
1865 dp = lookup_disk(hostname, diskname);
1869 str = vstralloc(" ", prefix(hostname, diskname, level),
1870 " ", "ERROR [not in disklist]",
1872 addline(&errsum, str);
1880 repdata = find_repdata(dp, datestamp, level);
1882 sp = &(repdata->taper);
1890 if(current_tape == NULL) {
1891 error("current_tape == NULL");
1893 if (sp->filenum == 0) {
1894 sp->filenum = ++tapefcount;
1895 sp->tapelabel = current_tape->label;
1897 tapechunks[level] +=1;
1898 stats[i].tapechunks +=1;
1899 current_tape->taper_time += sec;
1900 current_tape->coutsize += kbytes;
1901 current_tape->tapechunks += 1;
1906 handle_success(logtype_t logtype)
1909 float sec, kps, kbytes, origkb;
1914 char *hostname = NULL;
1915 char *diskname = NULL;
1920 if(curprog != P_TAPER && curprog != P_DUMPER && curprog != P_PLANNER &&
1921 curprog != P_CHUNKER) {
1929 skip_whitespace(s, ch);
1935 skip_non_whitespace(s, ch);
1937 hostname = stralloc(fp);
1940 skip_whitespace(s, ch);
1947 skip_non_whitespace(s, ch);
1949 diskname = stralloc(fp);
1952 skip_whitespace(s, ch);
1960 skip_non_whitespace(s, ch);
1962 datestamp = stralloc(fp);
1965 level = atoi(datestamp);
1967 datestamp = newstralloc(datestamp, run_datestamp);
1970 skip_whitespace(s, ch);
1971 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1978 skip_integer(s, ch);
1980 if(level < 0 || level > 9) {
1987 skip_whitespace(s, ch);
1988 /* Planner success messages (for skipped
1989 dumps) do not contain statistics */
1990 if(curprog != P_PLANNER) {
1991 if(curprog != P_DUMPER ||
1992 sscanf(s - 1,"[sec %f kb %f kps %f orig-kb %f",
1993 &sec, &kbytes, &kps, &origkb) != 4) {
1995 if(sscanf(s - 1,"[sec %f kb %f kps %f",
1996 &sec, &kbytes, &kps) != 3) {
2005 if(origkb == 0.0) origkb = 0.1;
2010 dp = lookup_disk(hostname, diskname);
2012 addtostrange(hostname, diskname, level, "ERROR [not in disklist]");
2019 repdata = find_repdata(dp, datestamp, level);
2021 if(curprog == P_PLANNER) {
2022 repdata->dumper.result = L_SKIPPED;
2029 if(curprog == P_TAPER)
2030 sp = &(repdata->taper);
2031 else if(curprog == P_DUMPER)
2032 sp = &(repdata->dumper);
2033 else sp = &(repdata->chunker);
2042 get_info(hostname, diskname, &inf);
2043 tm = localtime(&inf.inf[level].date);
2044 Idatestamp = 10000*(tm->tm_year+1900) +
2045 100*(tm->tm_mon+1) + tm->tm_mday;
2047 if(atoi(datestamp) == Idatestamp) {
2048 /* grab original size from record */
2049 origkb = (double)inf.inf[level].size;
2058 sp->result = L_SUCCESS;
2059 sp->datestamp = repdata->datestamp;
2062 sp->origsize = origkb;
2063 sp->outsize = kbytes;
2065 if(curprog == P_TAPER) {
2066 if(current_tape == NULL) {
2067 error("current_tape == NULL");
2069 stats[i].taper_time += sec;
2070 sp->filenum = ++tapefcount;
2071 sp->tapelabel = current_tape->label;
2072 tapedisks[level] +=1;
2073 stats[i].tapedisks +=1;
2074 stats[i].tapesize += kbytes;
2075 sp->outsize = kbytes;
2076 if(repdata->chunker.outsize == 0.0 && repdata->dumper.outsize != 0.0) { /* dump to tape */
2077 stats[i].outsize += kbytes;
2078 if(dp->compress != COMP_NONE) {
2079 stats[i].coutsize += kbytes;
2082 if (logtype == L_SUCCESS || logtype== L_PARTIAL) {
2083 current_tape->taper_time += sec;
2084 current_tape->coutsize += kbytes;
2086 current_tape->corigsize += origkb;
2087 current_tape->tapedisks += 1;
2090 if(curprog == P_DUMPER) {
2091 stats[i].dumper_time += sec;
2092 if(dp->compress == COMP_NONE) {
2093 sp->origsize = kbytes;
2096 stats[i].corigsize += sp->origsize;
2098 dumpdisks[level] +=1;
2099 stats[i].dumpdisks +=1;
2100 stats[i].origsize += sp->origsize;
2103 if(curprog == P_CHUNKER) {
2104 sp->outsize = kbytes;
2105 stats[i].outsize += kbytes;
2106 if(dp->compress != COMP_NONE) {
2107 stats[i].coutsize += kbytes;
2119 repdata = handle_success(L_PARTIAL);
2121 if(curprog == P_TAPER)
2122 sp = &(repdata->taper);
2123 else if(curprog == P_DUMPER)
2124 sp = &(repdata->dumper);
2125 else sp = &(repdata->chunker);
2127 sp->result = L_PARTIAL;
2134 char *strangestr = NULL;
2137 repdata = handle_success(L_SUCCESS);
2139 addline(&errdet,"");
2140 str = vstralloc("/-- ", prefix(repdata->disk->host->hostname,
2141 repdata->disk->name, repdata->level),
2144 addline(&errdet, str);
2147 while(contline_next()) {
2148 get_logline(logfile);
2149 #define sc "sendbackup: warning "
2150 if(strncmp(curstr, sc, sizeof(sc)-1) == 0) {
2151 strangestr = newstralloc(strangestr, curstr+sizeof(sc)-1);
2153 addline(&errdet, curstr);
2155 addline(&errdet,"\\--------");
2157 str = vstralloc("STRANGE", " ", strangestr, NULL);
2158 addtostrange(repdata->disk->host->hostname, repdata->disk->name, repdata->level,
2185 skip_whitespace(s, ch);
2191 skip_non_whitespace(s, ch);
2194 skip_whitespace(s, ch);
2200 skip_non_whitespace(s, ch);
2203 skip_whitespace(s, ch);
2209 skip_non_whitespace(s, ch);
2211 datestamp = stralloc(fp);
2213 if(strlen(datestamp) < 3) { /* there is no datestamp, it's the level */
2214 level = atoi(datestamp);
2215 datestamp = newstralloc(datestamp, run_datestamp);
2217 else { /* read the level */
2218 skip_whitespace(s, ch);
2219 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
2224 skip_integer(s, ch);
2227 skip_whitespace(s, ch);
2234 if((s = strchr(errstr, '\n')) != NULL) {
2238 dp = lookup_disk(hostname, diskname);
2240 addtostrange(hostname, diskname, level, "ERROR [not in disklist]");
2242 repdata = find_repdata(dp, datestamp, level);
2244 if(curprog == P_TAPER)
2245 sp = &(repdata->taper);
2246 else sp = &(repdata->dumper);
2248 if(sp->result != L_SUCCESS)
2249 sp->result = L_FAIL;
2253 str = vstralloc("FAILED", " ", errstr, NULL);
2254 addtostrange(hostname, diskname, level, str);
2257 if(curprog == P_DUMPER) {
2258 addline(&errdet,"");
2259 str = vstralloc("/-- ", prefix(hostname, diskname, level),
2263 addline(&errdet, str);
2265 while(contline_next()) {
2266 get_logline(logfile);
2267 addline(&errdet, curstr);
2269 addline(&errdet,"\\--------");
2280 for(dp = diskq.head; dp != NULL; dp = dp->next) {
2281 if(dp->todo && data(dp) == NULL) {
2282 addtostrange(dp->host->hostname, dp->name, -987, "RESULTS MISSING");
2289 prefix (host, disk, level)
2294 char number[NUM_STR_SIZE];
2295 static char *str = NULL;
2297 snprintf(number, sizeof(number), "%d", level);
2298 str = newvstralloc(str,
2299 " ", host ? host : "(host?)",
2300 " ", disk ? disk : "(disk?)",
2301 level != -987 ? " lev " : "",
2302 level != -987 ? number : "",
2309 prefixstrange (host, disk, level, len_host, len_disk)
2313 int len_host, len_disk;
2317 char number[NUM_STR_SIZE];
2318 static char *str = NULL;
2320 snprintf(number, sizeof(number), "%d", level);
2321 h=malloc(len_host+1);
2323 strncpy(h, host, len_host);
2325 strncpy(h, "(host?)", len_host);
2328 for(l = strlen(h); l < len_host; l++) {
2331 d=malloc(len_disk+1);
2333 strncpy(d, disk, len_disk);
2335 strncpy(d, "(disk?)", len_disk);
2338 for(l = strlen(d); l < len_disk; l++) {
2341 str = newvstralloc(str,
2344 level != -987 ? " lev " : "",
2345 level != -987 ? number : "",
2354 addtostrange (host, disk, level, str)
2362 strange = malloc(sizeof(strange_t));
2363 strange->hostname = stralloc(host);
2364 strange->diskname = stralloc(disk);
2365 strange->level = level;
2366 strange->str = stralloc(str);
2367 strange->next = NULL;
2368 if(first_strange == NULL) {
2369 first_strange = strange;
2372 last_strange->next = strange;
2374 last_strange = strange;
2379 copy_template_file(lbl_templ)
2386 if (strchr(lbl_templ, '/') == NULL) {
2387 lbl_templ = stralloc2(config_dir, lbl_templ);
2389 lbl_templ = stralloc(lbl_templ);
2391 if ((fd = open(lbl_templ, 0)) < 0) {
2393 curprog = P_REPORTER;
2394 curstr = vstralloc("could not open PostScript template file ",
2402 afclose(postscript);
2405 while ((numread = read(fd, buf, sizeof(buf))) > 0) {
2406 if (fwrite(buf, numread, 1, postscript) != 1) {
2408 curprog = P_REPORTER;
2409 curstr = vstralloc("error copying PostScript template file ",
2417 afclose(postscript);
2423 curprog = P_REPORTER;
2424 curstr = vstralloc("error reading PostScript template file ",
2432 afclose(postscript);
2440 find_repdata(dp, datestamp, level)
2445 repdata_t *repdata, *prev;
2448 datestamp = run_datestamp;
2450 for(repdata = data(dp); repdata != NULL && (repdata->level != level || strcmp(repdata->datestamp,datestamp)!=0); repdata = repdata->next) {
2454 repdata = (repdata_t *)alloc(sizeof(repdata_t));
2455 memset(repdata, '\0',sizeof(repdata_t));
2457 repdata->datestamp = stralloc(datestamp ? datestamp : "");
2458 repdata->level = level;
2459 repdata->dumper.result = L_BOGUS;
2460 repdata->taper.result = L_BOGUS;
2461 repdata->next = NULL;
2463 prev->next = repdata;
2465 dp->up = (void *)repdata;
2471 static void do_postscript_output()
2473 tapetype_t *tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
2476 float outsize, origsize;
2477 int tapesize, marksize;
2479 tapesize = tp->length;
2480 marksize = tp->filemark;
2482 for(current_tape = stats_by_tape; current_tape != NULL;
2483 current_tape = current_tape->next) {
2485 if (current_tape->label == NULL) {
2489 copy_template_file(tp->lbl_templ);
2491 /* generate a few elements */
2492 fprintf(postscript,"(%s) DrawDate\n\n",
2493 nicedate(run_datestamp ? atoi(run_datestamp) : 0));
2494 fprintf(postscript,"(Amanda Version %s) DrawVers\n",version());
2495 fprintf(postscript,"(%s) DrawTitle\n", current_tape->label);
2498 fprintf(postscript, "(Total Size: %6.1f MB) DrawStat\n",
2499 mb(current_tape->coutsize));
2500 fprintf(postscript, "(Tape Used (%%) ");
2501 divzero(postscript, pct(current_tape->coutsize +
2502 marksize * (current_tape->tapedisks + current_tape->tapechunks)),
2504 fprintf(postscript," %%) DrawStat\n");
2505 fprintf(postscript, "(Compression Ratio: ");
2506 divzero(postscript, pct(current_tape->coutsize),current_tape->corigsize);
2507 fprintf(postscript," %%) DrawStat\n");
2508 fprintf(postscript,"(Filesystems Taped: %4d) DrawStat\n",
2509 current_tape->tapedisks);
2514 "(-) (%s) (-) ( 0) ( 32) ( 32) DrawHost\n",
2515 current_tape->label);
2517 for(dp = sortq.head; dp != NULL; dp = dp->next) {
2518 if (dp->todo == 0) {
2521 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
2523 if(repdata->taper.tapelabel != current_tape->label) {
2527 if(repdata->dumper.result == L_SUCCESS ||
2528 repdata->dumper.result == L_PARTIAL)
2529 origsize = repdata->dumper.origsize;
2531 origsize = repdata->taper.origsize;
2533 if(repdata->taper.result == L_SUCCESS ||
2534 repdata->taper.result == L_PARTIAL)
2535 outsize = repdata->taper.outsize;
2537 outsize = repdata->dumper.outsize;
2539 if (repdata->taper.result == L_SUCCESS ||
2540 repdata->taper.result == L_PARTIAL) {
2541 if(origsize != 0.0) {
2542 fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8.0f) (%8.0f) DrawHost\n",
2543 dp->host->hostname, dp->name, repdata->level,
2544 repdata->taper.filenum, origsize,
2548 fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8s) (%8.0f) DrawHost\n",
2549 dp->host->hostname, dp->name, repdata->level,
2550 repdata->taper.filenum, "N/A",
2557 fprintf(postscript,"\nshowpage\n");