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.44.2.17.4.6.2.16.2.10 2005/10/11 14:50:00 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 {
74 struct repdata_s *next;
77 #define data(dp) ((repdata_t *)(dp)->up)
79 struct cumulative_stats {
80 int dumpdisks, tapedisks;
81 double taper_time, dumper_time;
82 double outsize, origsize, tapesize;
83 double coutsize, corigsize; /* compressed dump only */
86 int dumpdisks[10], tapedisks[10]; /* by-level breakdown of disk count */
88 typedef struct taper_s {
91 double coutsize, corigsize;
96 taper_t *stats_by_tape = NULL;
97 taper_t *current_tape = NULL;
99 typedef struct strange_s {
104 struct strange_s *next;
107 strange_t *first_strange=NULL, *last_strange=NULL;
109 float total_time, startup_time, planner_time;
111 /* count files to tape */
115 char *today_datestamp;
116 char *tape_labels = NULL;
117 int last_run_tapes = 0;
118 static int degraded_mode = 0; /* defined in driverio too */
123 char *tapestart_error = NULL;
125 FILE *logfile, *mailf;
133 line_t *errsum = NULL;
134 line_t *errdet = NULL;
135 line_t *notes = NULL;
137 static char MaxWidthsRequested = 0; /* determined via config data */
140 long int unitdivisor;
142 /* local functions */
143 int contline_next P((void));
144 void addline P((line_t **lp, char *str));
145 void usage P((void));
146 int main P((int argc, char **argv));
148 void copy_template_file P((char *lbl_templ));
149 void do_postscript_output P((void));
150 void handle_start P((void));
151 void handle_finish P((void));
152 void handle_note P((void));
153 void handle_summary P((void));
154 void handle_stats P((void));
155 void handle_error P((void));
156 void handle_disk P((void));
157 repdata_t *handle_success P((void));
158 void handle_strange P((void));
159 void handle_failed P((void));
160 void generate_missing P((void));
161 void output_tapeinfo P((void));
162 void output_lines P((line_t *lp, FILE *f));
163 void output_stats P((void));
164 void output_summary P((void));
165 void output_strange P((void));
166 void sort_disks P((void));
167 int sort_by_time P((disk_t *a, disk_t *b));
168 int sort_by_name P((disk_t *a, disk_t *b));
169 void bogus_line P((void));
170 char *nicedate P((int datestamp));
171 static char *prefix P((char *host, char *disk, int level));
172 static char *prefixstrange P((char *host, char *disk, int level, int len_host, int len_disk));
173 static void addtostrange P((char *host, char *disk, int level, char *str));
174 repdata_t *find_repdata P((disk_t *dp, char *datestamp, int level));
177 static int ColWidth(int From, int To) {
179 for (i=From; i<=To && ColumnData[i].Name != NULL; i++) {
180 Width+= ColumnData[i].PrefixSpace + ColumnData[i].Width;
185 static char *Rule(int From, int To) {
187 int Leng= ColWidth(0, ColumnDataCount());
188 char *RuleSpace= alloc(Leng+1);
189 ThisLeng= ColWidth(From, To);
190 for (i=0;i<ColumnData[From].PrefixSpace; i++)
192 for (; i<ThisLeng; i++)
194 RuleSpace[ThisLeng]= '\0';
198 static char *TextRule(int From, int To, char *s) {
199 ColumnInfo *cd= &ColumnData[From];
200 int leng, nbrules, i, txtlength;
201 int RuleSpaceSize= ColWidth(0, ColumnDataCount());
202 char *RuleSpace= alloc(RuleSpaceSize), *tmp;
205 if(leng >= (RuleSpaceSize - cd->PrefixSpace))
206 leng = RuleSpaceSize - cd->PrefixSpace - 1;
207 ap_snprintf(RuleSpace, RuleSpaceSize, "%*s%*.*s ", cd->PrefixSpace, "",
209 txtlength = cd->PrefixSpace + leng + 1;
210 nbrules = ColWidth(From,To) - txtlength;
211 for(tmp=RuleSpace + txtlength, i=nbrules ; i>0; tmp++,i--)
217 char *sDivZero(float a, float b, int cn) {
218 ColumnInfo *cd= &ColumnData[cn];
219 static char PrtBuf[256];
221 ap_snprintf(PrtBuf, sizeof(PrtBuf),
222 "%*s", cd->Width, "-- ");
224 ap_snprintf(PrtBuf, sizeof(PrtBuf),
225 cd->Format, cd->Width, cd->Precision, a/b);
241 void addline(lp, str)
247 /* allocate new line node */
248 new = (line_t *) alloc(sizeof(line_t));
250 new->str = stralloc(str);
252 /* add to end of list */
253 for(p = *lp, q = NULL; p != NULL; q = p, p = p->next);
254 if(q == NULL) *lp = new;
260 error("Usage: amreport conf [-f output-file] [-l logfile] [-p postscript-file]");
271 char *logfname, *psfname, *outfname, *subj_str = NULL;
274 unsigned long malloc_hist_1, malloc_size_1;
275 unsigned long malloc_hist_2, malloc_size_2;
276 char *mail_cmd = NULL, *printer_cmd = NULL;
278 char my_cwd[STR_SIZE];
279 char *ColumnSpec = "";
285 set_pname("amreport");
287 malloc_size_1 = malloc_inuse(&malloc_hist_1);
289 /* Process options */
291 erroutput_type = ERR_INTERACTIVE;
296 if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
297 error("cannot determine current working directory");
301 config_dir = stralloc2(my_cwd, "/");
302 if ((config_name = strrchr(my_cwd, '/')) != NULL) {
303 config_name = stralloc(config_name + 1);
306 if (argv[1][0] == '-') {
310 config_name = stralloc(argv[1]);
311 config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
313 while((opt = getopt(argc, argv, "f:l:p:")) != EOF) {
316 if (outfname != NULL) {
317 error("you may specify at most one -f");
319 if (*optarg == '/') {
320 outfname = stralloc(optarg);
322 outfname = vstralloc(my_cwd, "/", optarg, NULL);
326 if (logfname != NULL) {
327 error("you may specify at most one -l");
329 if (*optarg == '/') {
330 logfname = stralloc(optarg);
332 logfname = vstralloc(my_cwd, "/", optarg, NULL);
336 if (psfname != NULL) {
337 error("you may specify at most one -p");
339 if (*optarg == '/') {
340 psfname = stralloc(optarg);
342 psfname = vstralloc(my_cwd, "/", optarg, NULL);
363 printf("You must run amreport with '-f <output file>' because configure\n");
364 printf("didn't find a mailer.\n");
371 /* read configuration files */
373 conffile = stralloc2(config_dir, CONFFILE_NAME);
374 if(read_conffile(conffile)) {
375 error("errors processing config file \"%s\"", conffile);
378 conf_diskfile = getconf_str(CNF_DISKFILE);
379 if (*conf_diskfile == '/') {
380 conf_diskfile = stralloc(conf_diskfile);
382 conf_diskfile = stralloc2(config_dir, conf_diskfile);
384 if((diskq = read_diskfile(conf_diskfile)) == NULL) {
385 error("could not load disklist \"%s\"", conf_diskfile);
387 amfree(conf_diskfile);
388 conf_tapelist = getconf_str(CNF_TAPELIST);
389 if (*conf_tapelist == '/') {
390 conf_tapelist = stralloc(conf_tapelist);
392 conf_tapelist = stralloc2(config_dir, conf_tapelist);
394 if(read_tapelist(conf_tapelist)) {
395 error("could not read tapelist \"%s\"", conf_tapelist);
397 amfree(conf_tapelist);
398 conf_infofile = getconf_str(CNF_INFOFILE);
399 if (*conf_infofile == '/') {
400 conf_infofile = stralloc(conf_infofile);
402 conf_infofile = stralloc2(config_dir, conf_infofile);
404 if(open_infofile(conf_infofile)) {
405 error("could not open info db \"%s\"", conf_infofile);
407 amfree(conf_infofile);
409 today_datestamp = construct_datestamp(NULL);
411 displayunit = getconf_str(CNF_DISPLAYUNIT);
412 unitdivisor = getconf_unit_divisor();
414 ColumnSpec = getconf_str(CNF_COLUMNSPEC);
415 if(SetColumDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
417 curprog = P_REPORTER;
422 ColumnSpec = ""; /* use the default */
423 if(SetColumDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
425 curprog = P_REPORTER;
432 for (cn = 0; ColumnData[cn].Name != NULL; cn++) {
433 if (ColumnData[cn].MaxWidth) {
434 MaxWidthsRequested = 1;
442 conf_logdir = getconf_str(CNF_LOGDIR);
443 if (*conf_logdir == '/') {
444 conf_logdir = stralloc(conf_logdir);
446 conf_logdir = stralloc2(config_dir, conf_logdir);
448 logfname = vstralloc(conf_logdir, "/", "log", NULL);
452 if((logfile = fopen(logfname, "r")) == NULL) {
454 curprog = P_REPORTER;
455 curstr = vstralloc("could not open log ",
464 while(logfile && get_logline(logfile)) {
466 case L_START: handle_start(); break;
467 case L_FINISH: handle_finish(); break;
469 case L_INFO: handle_note(); break;
470 case L_WARNING: handle_note(); break;
472 case L_SUMMARY: handle_summary(); break;
473 case L_STATS: handle_stats(); break;
475 case L_ERROR: handle_error(); break;
476 case L_FATAL: handle_error(); break;
478 case L_DISK: handle_disk(); break;
480 case L_SUCCESS: handle_success(); break;
481 case L_STRANGE: handle_strange(); break;
482 case L_FAIL: handle_failed(); break;
486 curprog = P_REPORTER;
487 curstr = stralloc2("unexpected log line: ", curstr);
497 subj_str = vstralloc(getconf_str(CNF_ORG),
498 " ", amflush_run ? "AMFLUSH" : "AMANDA",
499 " ", "MAIL REPORT FOR",
500 " ", nicedate(run_datestamp ? atoi(run_datestamp) : 0),
503 /* lookup the tapetype and printer type from the amanda.conf file. */
504 tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
505 printer = getconf_str(CNF_PRINTER);
507 /* ignore SIGPIPE so if a child process dies we do not also go away */
508 signal(SIGPIPE, SIG_IGN);
510 /* open pipe to mailer */
513 /* output to a file */
514 if((mailf = fopen(outfname,"w")) == NULL) {
515 error("could not open output file: %s %s", outfname, strerror(errno));
517 fprintf(mailf, "To: %s\n", getconf_str(CNF_MAILTO));
518 fprintf(mailf, "Subject: %s\n\n", subj_str);
522 mail_cmd = vstralloc(MAILER,
523 " -s", " \"", subj_str, "\"",
524 " ", getconf_str(CNF_MAILTO),
526 if((mailf = popen(mail_cmd, "w")) == NULL)
527 error("could not open pipe to \"%s\": %s",
528 mail_cmd, strerror(errno));
532 /* open pipe to print spooler if necessary) */
535 /* if the postscript_label_template (tp->lbl_templ) field is not */
536 /* the empty string (i.e. it is set to something), open the */
537 /* postscript debugging file for writing. */
538 if ((strcmp(tp->lbl_templ, "")) != 0) {
539 if ((postscript = fopen(psfname, "w")) == NULL) {
541 curprog = P_REPORTER;
542 curstr = vstralloc("could not open ",
553 if (strcmp(printer, "") != 0) /* alternate printer is defined */
554 /* print to the specified printer */
556 printer_cmd = vstralloc(LPRCMD, " ", LPRFLAG, printer, NULL);
558 printer_cmd = vstralloc(LPRCMD, NULL);
561 /* print to the default printer */
562 printer_cmd = vstralloc(LPRCMD, NULL);
565 if ((strcmp(tp->lbl_templ, "")) != 0) {
567 if ((postscript = popen(printer_cmd, "w")) == NULL) {
569 curprog = P_REPORTER;
570 curstr = vstralloc("could not open pipe to ",
580 curprog = P_REPORTER;
581 curstr = stralloc("no printer command defined");
591 if(!got_finish) fputs("*** THE DUMPS DID NOT FINISH PROPERLY!\n\n", mailf);
595 if(first_strange || errsum) {
596 fprintf(mailf,"\nFAILURE AND STRANGE DUMP SUMMARY:\n");
597 if(first_strange) output_strange();
598 if(errsum) output_lines(errsum, mailf);
600 fputs("\n\n", mailf);
605 fprintf(mailf,"\n\014\nFAILED AND STRANGE DUMP DETAILS:\n");
606 output_lines(errdet, mailf);
609 fprintf(mailf,"\n\014\nNOTES:\n");
610 output_lines(notes, mailf);
613 if(sortq.head != NULL) {
614 fprintf(mailf,"\n\014\nDUMP SUMMARY:\n");
617 fprintf(mailf,"\n(brought to you by Amanda version %s)\n",
621 do_postscript_output();
625 /* close postscript file */
626 if (psfname && postscript) {
627 /* it may be that postscript is NOT opened */
631 if (postscript != NULL && pclose(postscript) != 0)
632 error("printer command failed: %s", printer_cmd);
636 /* close output file */
641 if(pclose(mailf) != 0)
642 error("mail command failed: %s", mail_cmd);
646 amfree(run_datestamp);
654 malloc_size_2 = malloc_inuse(&malloc_hist_2);
656 if(malloc_size_1 != malloc_size_2) {
657 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
665 #define mb(f) ((f)/1024) /* kbytes -> mbutes */
666 #define du(f) ((f)/unitdivisor) /* kbytes -> displayunit */
667 #define pct(f) ((f)*100.0) /* percent */
668 #define hrmn(f) ((int)(f)+30)/3600, (((int)(f)+30)%3600)/60
669 #define mnsc(f) ((int)(f+0.5))/60, ((int)(f+0.5)) % 60
671 #define divzero(fp,a,b) \
675 fprintf((fp)," -- "); \
676 else if ((q = (a)/q) >= 999.95) \
677 fprintf((fp), "###.#"); \
679 fprintf((fp), "%5.1f",q); \
681 #define divzero_wide(fp,a,b) \
685 fprintf((fp)," -- "); \
686 else if ((q = (a)/q) >= 99999.95) \
687 fprintf((fp), "#####.#"); \
689 fprintf((fp), "%7.1f",q); \
694 tapetype_t *tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
695 int tapesize, marksize, lv, first;
697 tapesize = tp->length;
698 marksize = tp->filemark;
700 stats[2].dumpdisks = stats[0].dumpdisks + stats[1].dumpdisks;
701 stats[2].tapedisks = stats[0].tapedisks + stats[1].tapedisks;
702 stats[2].outsize = stats[0].outsize + stats[1].outsize;
703 stats[2].origsize = stats[0].origsize + stats[1].origsize;
704 stats[2].tapesize = stats[0].tapesize + stats[1].tapesize;
705 stats[2].coutsize = stats[0].coutsize + stats[1].coutsize;
706 stats[2].corigsize = stats[0].corigsize + stats[1].corigsize;
707 stats[2].taper_time = stats[0].taper_time + stats[1].taper_time;
708 stats[2].dumper_time = stats[0].dumper_time + stats[1].dumper_time;
710 if(!got_finish) /* no driver finish line, estimate total run time */
711 total_time = stats[2].taper_time + planner_time;
713 fprintf(mailf,"STATISTICS:\n");
715 " Total Full Incr.\n");
717 " -------- -------- --------\n");
720 "Estimate Time (hrs:min) %2d:%02d\n", hrmn(planner_time));
723 "Run Time (hrs:min) %2d:%02d\n", hrmn(total_time));
726 "Dump Time (hrs:min) %2d:%02d %2d:%02d %2d:%02d\n",
727 hrmn(stats[2].dumper_time), hrmn(stats[0].dumper_time),
728 hrmn(stats[1].dumper_time));
731 "Output Size (meg) %8.1f %8.1f %8.1f\n",
732 mb(stats[2].outsize), mb(stats[0].outsize), mb(stats[1].outsize));
735 "Original Size (meg) %8.1f %8.1f %8.1f\n",
736 mb(stats[2].origsize), mb(stats[0].origsize),
737 mb(stats[1].origsize));
739 fprintf(mailf, "Avg Compressed Size (%%) ");
740 divzero(mailf, pct(stats[2].coutsize),stats[2].corigsize);
742 divzero(mailf, pct(stats[0].coutsize),stats[0].corigsize);
744 divzero(mailf, pct(stats[1].coutsize),stats[1].corigsize);
746 if(stats[1].dumpdisks > 0) fputs(" (level:#disks ...)", mailf);
750 "Filesystems Dumped %4d %4d %4d",
751 stats[2].dumpdisks, stats[0].dumpdisks, stats[1].dumpdisks);
753 if(stats[1].dumpdisks > 0) {
755 for(lv = 1; lv < 10; lv++) if(dumpdisks[lv]) {
756 fputs(first?" (":" ", mailf);
758 fprintf(mailf, "%d:%d", lv, dumpdisks[lv]);
764 fprintf(mailf, "Avg Dump Rate (k/s) ");
765 divzero_wide(mailf, stats[2].outsize,stats[2].dumper_time);
767 divzero_wide(mailf, stats[0].outsize,stats[0].dumper_time);
769 divzero_wide(mailf, stats[1].outsize,stats[1].dumper_time);
774 "Tape Time (hrs:min) %2d:%02d %2d:%02d %2d:%02d\n",
775 hrmn(stats[2].taper_time), hrmn(stats[0].taper_time),
776 hrmn(stats[1].taper_time));
779 "Tape Size (meg) %8.1f %8.1f %8.1f\n",
780 mb(stats[2].tapesize), mb(stats[0].tapesize),
781 mb(stats[1].tapesize));
783 fprintf(mailf, "Tape Used (%%) ");
784 divzero(mailf, pct(stats[2].tapesize+marksize*stats[2].tapedisks),tapesize);
786 divzero(mailf, pct(stats[0].tapesize+marksize*stats[0].tapedisks),tapesize);
788 divzero(mailf, pct(stats[1].tapesize+marksize*stats[1].tapedisks),tapesize);
790 if(stats[1].tapedisks > 0) fputs(" (level:#disks ...)", mailf);
794 "Filesystems Taped %4d %4d %4d",
795 stats[2].tapedisks, stats[0].tapedisks, stats[1].tapedisks);
797 if(stats[1].tapedisks > 0) {
799 for(lv = 1; lv < 10; lv++) if(tapedisks[lv]) {
800 fputs(first?" (":" ", mailf);
802 fprintf(mailf, "%d:%d", lv, tapedisks[lv]);
808 fprintf(mailf, "Avg Tp Write Rate (k/s) ");
809 divzero_wide(mailf, stats[2].tapesize,stats[2].taper_time);
811 divzero_wide(mailf, stats[0].tapesize,stats[0].taper_time);
813 divzero_wide(mailf, stats[1].tapesize,stats[1].taper_time);
817 int label_length = strlen(stats_by_tape->label) + 5;
818 fprintf(mailf,"\nUSAGE BY TAPE:\n");
819 fprintf(mailf," %-*s Time Size %% Nb\n",
820 label_length, "Label");
821 for(current_tape = stats_by_tape; current_tape != NULL;
822 current_tape = current_tape->next) {
823 fprintf(mailf, " %-*s", label_length, current_tape->label);
824 fprintf(mailf, " %2d:%02d", hrmn(current_tape->taper_time));
825 fprintf(mailf, " %8.0f%s ", du(current_tape->coutsize), displayunit);
826 divzero(mailf, pct(current_tape->coutsize +
827 marksize * current_tape->tapedisks),
829 fprintf(mailf, " %4d\n", current_tape->tapedisks);
837 void output_tapeinfo()
843 if (last_run_tapes > 0) {
845 fprintf(mailf, "The dumps were flushed to tape%s %s.\n",
846 last_run_tapes == 1 ? "" : "s",
847 tape_labels ? tape_labels : "");
849 fprintf(mailf, "These dumps were to tape%s %s.\n",
850 last_run_tapes == 1 ? "" : "s",
851 tape_labels ? tape_labels : "");
856 "*** A TAPE ERROR OCCURRED: %s.\n", tapestart_error);
857 fputs("Some dumps may have been left in the holding disk.\n", mailf);
859 "Run amflush%s to flush them to tape.\n",
860 amflush_run ? " again" : "");
863 tp = lookup_last_reusable_tape(skip);
865 run_tapes = getconf_int(CNF_RUNTAPES);
868 fputs("The next tape Amanda expects to use is: ", mailf);
870 fprintf(mailf, "The next %d tapes Amanda expects to use are: ",
873 while(run_tapes > 0) {
875 fprintf(mailf, "%s", tp->label);
877 fputs("a new tape", mailf);
879 if(run_tapes > 1) fputs(", ", mailf);
883 tp = lookup_last_reusable_tape(skip);
887 lasttp = lookup_tapepos(lookup_nb_tape());
888 run_tapes = getconf_int(CNF_RUNTAPES);
889 if(lasttp && run_tapes > 0 && lasttp->datestamp == 0) {
891 while(lasttp && run_tapes > 0 && lasttp->datestamp == 0) {
893 lasttp = lasttp->prev;
896 lasttp = lookup_tapepos(lookup_nb_tape());
898 fprintf(mailf, "The next new tape already labelled is: %s.\n",
902 fprintf(mailf, "The next %d new tapes already labelled are: %s", c,
904 lasttp = lasttp->prev;
906 while(lasttp && c > 0 && lasttp->datestamp == 0) {
907 fprintf(mailf, ", %s", lasttp->label);
908 lasttp = lasttp->prev;
911 fprintf(mailf, ".\n");
917 void output_strange()
919 int len_host=0, len_disk=0;
923 for(strange=first_strange; strange != NULL; strange = strange->next) {
924 if(strlen(strange->hostname) > len_host)
925 len_host = strlen(strange->hostname);
926 if(strlen(strange->diskname) > len_disk)
927 len_disk = strlen(strange->diskname);
929 for(strange=first_strange; strange != NULL; strange = strange->next) {
930 str = vstralloc(" ", prefixstrange(strange->hostname, strange->diskname, strange->level, len_host, len_disk),
931 " ", strange->str, NULL);
932 fprintf(mailf, "%s\n", str);
936 void output_lines(lp, f)
954 int sort_by_time(a, b)
957 return data(b)->dumper.sec - data(a)->dumper.sec;
960 int sort_by_name(a, b)
965 rc = strcmp(a->host->hostname, b->host->hostname);
966 if(rc == 0) rc = strcmp(a->name, b->name);
974 sortq.head = sortq.tail = NULL;
975 while(!empty(*diskq)) {
976 dp = dequeue_disk(diskq);
977 if(data(dp) == NULL) { /* create one */
978 find_repdata(dp, run_datestamp, 0);
980 insert_disk(&sortq, dp, sort_by_name);
984 void CheckStringMax(ColumnInfo *cd, char *s) {
992 void CheckIntMax(ColumnInfo *cd, int n) {
996 ap_snprintf(testBuf, sizeof(testBuf),
997 cd->Format, cd->Width, cd->Precision, n);
1004 void CheckFloatMax(ColumnInfo *cd, double d) {
1008 ap_snprintf(testBuf, sizeof(testBuf),
1009 cd->Format, cd->Width, cd->Precision, d);
1016 static int HostName;
1021 static int Compress;
1022 static int DumpTime;
1023 static int DumpRate;
1024 static int TapeTime;
1025 static int TapeRate;
1027 void CalcMaxWidth() {
1028 /* we have to look for columspec's, that require the recalculation.
1029 * we do here the same loops over the sortq as is done in
1030 * output_summary. So, if anything is changed there, we have to
1031 * change this here also.
1037 for(dp = sortq.head; dp != NULL; dp = dp->next) {
1039 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
1041 char TimeRateBuffer[40];
1043 CheckStringMax(&ColumnData[HostName], dp->host->hostname);
1044 CheckStringMax(&ColumnData[Disk], dp->name);
1045 if (repdata->dumper.result == L_BOGUS &&
1046 repdata->taper.result == L_BOGUS)
1048 CheckIntMax(&ColumnData[Level], repdata->level);
1049 if(repdata->dumper.result == L_SUCCESS) {
1050 CheckFloatMax(&ColumnData[OrigKB], du(repdata->dumper.origsize));
1051 CheckFloatMax(&ColumnData[OutKB], du(repdata->dumper.outsize));
1052 if(dp->compress == COMP_NONE)
1055 f = repdata->dumper.origsize;
1056 CheckStringMax(&ColumnData[Disk],
1057 sDivZero(pct(repdata->dumper.outsize), f, Compress));
1060 ap_snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1061 "%3d:%02d", mnsc(repdata->dumper.sec));
1063 ap_snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1065 CheckStringMax(&ColumnData[DumpTime], TimeRateBuffer);
1067 CheckFloatMax(&ColumnData[DumpRate], repdata->dumper.kps);
1070 cd= &ColumnData[TapeTime];
1071 if(repdata->taper.result == L_FAIL) {
1072 CheckStringMax(cd, "FAILED");
1075 if(repdata->taper.result == L_SUCCESS)
1076 ap_snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1077 "%3d:%02d", mnsc(repdata->taper.sec));
1079 ap_snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1081 CheckStringMax(cd, TimeRateBuffer);
1083 cd= &ColumnData[TapeRate];
1084 if(repdata->taper.result == L_SUCCESS)
1085 CheckFloatMax(cd, repdata->taper.kps);
1087 CheckStringMax(cd, "N/A ");
1093 void output_summary()
1097 char *ds="DUMPER STATS";
1098 char *ts=" TAPER STATS";
1101 int i, h, w1, wDump, wTape;
1102 float outsize, origsize;
1105 HostName = StringToColumn("HostName");
1106 Disk = StringToColumn("Disk");
1107 Level = StringToColumn("Level");
1108 OrigKB = StringToColumn("OrigKB");
1109 OutKB = StringToColumn("OutKB");
1110 Compress = StringToColumn("Compress");
1111 DumpTime = StringToColumn("DumpTime");
1112 DumpRate = StringToColumn("DumpRate");
1113 TapeTime = StringToColumn("TapeTime");
1114 TapeRate = StringToColumn("TapeRate");
1116 /* at first determine if we have to recalculate our widths */
1117 if (MaxWidthsRequested)
1120 /* title for Dumper-Stats */
1121 w1= ColWidth(HostName, Level);
1122 wDump= ColWidth(OrigKB, DumpRate);
1123 wTape= ColWidth(TapeTime, TapeRate);
1125 /* print centered top titles */
1132 fprintf(mailf, "%*s", w1+h, "");
1133 fprintf(mailf, "%-*s", wDump-h, ds);
1140 fprintf(mailf, "%*s", h, "");
1141 fprintf(mailf, "%-*s", wTape-h, ts);
1144 /* print the titles */
1145 for (i=0; ColumnData[i].Name != NULL; i++) {
1147 ColumnInfo *cd= &ColumnData[i];
1148 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1149 if (cd->Format[1] == '-')
1153 if(strcmp(cd->Title,"ORIG-KB") == 0) {
1154 /* cd->Title must be re-allocated in write-memory */
1155 cd->Title = stralloc("ORIG-KB");
1156 cd->Title[5] = displayunit[0];
1158 if(strcmp(cd->Title,"OUT-KB") == 0) {
1159 /* cd->Title must be re-allocated in write-memory */
1160 cd->Title = stralloc("OUT-KB");
1161 cd->Title[4] = displayunit[0];
1163 fprintf(mailf, fmt, cd->Width, cd->Title);
1167 /* print the rules */
1168 fputs(tmp=Rule(HostName, Level), mailf); amfree(tmp);
1169 fputs(tmp=Rule(OrigKB, DumpRate), mailf); amfree(tmp);
1170 fputs(tmp=Rule(TapeTime, TapeRate), mailf); amfree(tmp);
1173 for(dp = sortq.head; dp != NULL; dp = dp->next) {
1176 char TimeRateBuffer[40];
1177 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
1180 cd= &ColumnData[HostName];
1181 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1182 fprintf(mailf, cd->Format, cd->Width, cd->Width, dp->host->hostname);
1184 cd= &ColumnData[Disk];
1185 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1186 devlen= strlen(dp->name);
1187 if (devlen > cd->Width) {
1189 fprintf(mailf, cd->Format, cd->Width-1, cd->Precision-1,
1190 dp->name+devlen - (cd->Width-1) );
1193 fprintf(mailf, cd->Format, cd->Width, cd->Width, dp->name);
1195 cd= &ColumnData[Level];
1196 if (repdata->dumper.result == L_BOGUS &&
1197 repdata->taper.result == L_BOGUS) {
1199 fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
1200 tmp=TextRule(OrigKB, TapeRate, "NO FILE TO FLUSH"));
1202 fprintf(mailf, "%*s%s\n", cd->PrefixSpace+cd->Width, "",
1203 tmp=TextRule(OrigKB, TapeRate, "MISSING"));
1209 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1210 fprintf(mailf, cd->Format, cd->Width, cd->Precision,repdata->level);
1212 if (repdata->dumper.result == L_SKIPPED) {
1213 fprintf(mailf, "%s\n",
1214 tmp=TextRule(OrigKB, TapeRate, "SKIPPED"));
1218 if (repdata->dumper.result == L_FAIL) {
1219 fprintf(mailf, "%s\n",
1220 tmp=TextRule(OrigKB, TapeRate, "FAILED"));
1225 if(repdata->dumper.result == L_SUCCESS)
1226 origsize = repdata->dumper.origsize;
1228 origsize = repdata->taper.origsize;
1230 if(repdata->taper.result == L_SUCCESS)
1231 outsize = repdata->taper.outsize;
1233 outsize = repdata->dumper.outsize;
1235 cd= &ColumnData[OrigKB];
1236 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1238 fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(origsize));
1240 fprintf(mailf, "%*.*s", cd->Width, cd->Width, "N/A");
1242 cd= &ColumnData[OutKB];
1243 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1245 fprintf(mailf, cd->Format, cd->Width, cd->Precision, du(outsize));
1247 cd= &ColumnData[Compress];
1248 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1250 if(dp->compress == COMP_NONE)
1252 else if(origsize < 1.0)
1257 fputs(sDivZero(pct(outsize), f, Compress), mailf);
1259 cd= &ColumnData[DumpTime];
1260 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1261 if(repdata->dumper.result == L_SUCCESS)
1262 ap_snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1263 "%3d:%02d", mnsc(repdata->dumper.sec));
1265 ap_snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1267 fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
1269 cd= &ColumnData[DumpRate];
1270 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1271 if(repdata->dumper.result == L_SUCCESS)
1272 fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->dumper.kps);
1274 fprintf(mailf, "%*s", cd->Width, "N/A ");
1276 cd= &ColumnData[TapeTime];
1277 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1278 if(repdata->taper.result == L_FAIL) {
1279 fprintf(mailf, "%s\n",
1280 tmp=TextRule(TapeTime, TapeRate, "FAILED "));
1285 if(repdata->taper.result == L_SUCCESS)
1286 ap_snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1287 "%3d:%02d", mnsc(repdata->taper.sec));
1289 ap_snprintf(TimeRateBuffer, sizeof(TimeRateBuffer),
1291 fprintf(mailf, cd->Format, cd->Width, cd->Width, TimeRateBuffer);
1293 cd= &ColumnData[TapeRate];
1294 fprintf(mailf, "%*s", cd->PrefixSpace, "");
1295 if(repdata->taper.result == L_SUCCESS)
1296 fprintf(mailf, cd->Format, cd->Width, cd->Precision, repdata->taper.kps);
1298 fprintf(mailf, "%*s", cd->Width, "N/A ");
1307 printf("line %d of log is bogus\n", curlinenum);
1311 char *nicedate(datestamp)
1314 * Formats an integer of the form YYYYMMDD into the string
1315 * "Monthname DD, YYYY". A pointer to the statically allocated string
1316 * is returned, so it must be copied to other storage (or just printed)
1317 * before calling nicedate() again.
1320 static char nice[64];
1321 static char *months[13] = { "BogusMonth",
1322 "January", "February", "March", "April", "May", "June",
1323 "July", "August", "September", "October", "November", "December"
1325 int year, month, day;
1327 year = datestamp / 10000;
1328 day = datestamp % 100;
1329 month = (datestamp / 100) % 100;
1331 ap_snprintf(nice, sizeof(nice), "%s %d, %d", months[month], day, year);
1338 static int started = 0;
1348 skip_whitespace(s, ch);
1349 #define sc "datestamp"
1350 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1357 skip_whitespace(s, ch);
1363 skip_non_whitespace(s, ch);
1365 run_datestamp = newstralloc(run_datestamp, fp);
1368 skip_whitespace(s, ch);
1370 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1377 skip_whitespace(s, ch);
1383 skip_non_whitespace(s, ch);
1386 label = stralloc(fp);
1390 fp = vstralloc(tape_labels, ", ", label, NULL);
1391 amfree(tape_labels);
1394 tape_labels = stralloc(label);
1399 if(stats_by_tape == NULL) {
1400 stats_by_tape = current_tape = (taper_t *)alloc(sizeof(taper_t));
1403 current_tape->next = (taper_t *)alloc(sizeof(taper_t));
1404 current_tape = current_tape->next;
1406 current_tape->label = label;
1407 current_tape->taper_time = 0.0;
1408 current_tape->coutsize = 0.0;
1409 current_tape->corigsize = 0.0;
1410 current_tape->tapedisks = 0;
1411 current_tape->next = NULL;
1431 skip_whitespace(s, ch);
1433 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1434 return; /* ignore bogus line */
1439 skip_whitespace(s, ch);
1445 skip_non_whitespace(s, ch);
1447 run_datestamp = newstralloc(run_datestamp, fp);
1452 if(amflush_run && normal_run) {
1455 " reporter: both amflush and planner output in log, ignoring amflush.");
1460 void handle_finish()
1466 if(curprog == P_DRIVER || curprog == P_AMFLUSH || curprog == P_PLANNER) {
1470 skip_whitespace(s, ch);
1472 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1480 skip_whitespace(s, ch);
1485 skip_non_whitespace(s, ch); /* ignore the date string */
1487 skip_whitespace(s, ch);
1489 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1490 /* older planner doesn't write time */
1491 if(curprog == P_PLANNER) return;
1499 skip_whitespace(s, ch);
1504 if(sscanf(s - 1, "%f", &a_time) != 1) {
1508 if(curprog == P_PLANNER) {
1509 planner_time = a_time;
1512 total_time = a_time;
1523 if(curprog == P_DRIVER) {
1527 skip_whitespace(s, ch);
1528 #define sc "startup time"
1529 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1537 skip_whitespace(s, ch);
1542 if(sscanf(s - 1, "%f", &startup_time) != 1) {
1546 planner_time = startup_time;
1555 str = vstralloc(" ", program_str[curprog], ": ", curstr, NULL);
1556 addline(¬es, str);
1565 char *s = NULL, *nl;
1568 if(curlog == L_ERROR && curprog == P_TAPER) {
1572 skip_whitespace(s, ch);
1573 #define sc "no-tape"
1574 if(ch == '\0' || strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
1582 skip_whitespace(s, ch);
1584 if((nl = strchr(s - 1, '\n')) != NULL) {
1587 tapestart_error = newstralloc(tapestart_error, s - 1);
1592 /* else some other tape error, handle like other errors */
1594 s = vstralloc(" ", program_str[curprog], ": ",
1595 logtype_str[curlog], " ", curstr, NULL);
1596 addline(&errsum, s);
1602 void handle_summary()
1615 char *hostname = NULL, *diskname = NULL;
1617 if(curprog != P_PLANNER && curprog != P_AMFLUSH) {
1623 for(dp = diskq->head; dp != NULL; dp = dp->next)
1631 skip_whitespace(s, ch);
1637 skip_non_whitespace(s, ch);
1639 hostname = newstralloc(hostname, fp);
1642 skip_whitespace(s, ch);
1648 skip_non_whitespace(s, ch);
1650 diskname = newstralloc(diskname, fp);
1653 dp = lookup_disk(hostname, diskname);
1655 dp = add_disk(hostname, diskname);
1663 repdata_t *handle_success()
1666 float sec, kps, kbytes, origkb;
1671 char *hostname = NULL;
1672 char *diskname = NULL;
1677 if(curprog != P_TAPER && curprog != P_DUMPER && curprog != P_PLANNER) {
1685 skip_whitespace(s, ch);
1691 skip_non_whitespace(s, ch);
1693 hostname = stralloc(fp);
1696 skip_whitespace(s, ch);
1703 skip_non_whitespace(s, ch);
1705 diskname = stralloc(fp);
1708 skip_whitespace(s, ch);
1716 skip_non_whitespace(s, ch);
1718 datestamp = stralloc(fp);
1721 level = atoi(datestamp);
1723 datestamp = newstralloc(datestamp, run_datestamp);
1726 skip_whitespace(s, ch);
1727 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1734 skip_integer(s, ch);
1737 skip_whitespace(s, ch);
1738 /* Planner success messages (for skipped
1739 dumps) do not contain statistics */
1740 if(curprog != P_PLANNER) {
1741 if(curprog != P_DUMPER ||
1742 sscanf(s - 1,"[sec %f kb %f kps %f orig-kb %f",
1743 &sec, &kbytes, &kps, &origkb) != 4) {
1745 if(sscanf(s - 1,"[sec %f kb %f kps %f",
1746 &sec, &kbytes, &kps) != 3) {
1755 if(origkb == 0.0) origkb = 0.1;
1760 dp = lookup_disk(hostname, diskname);
1762 addtostrange(hostname, diskname, level, "ERROR [not in disklist]");
1769 repdata = find_repdata(dp, datestamp, level);
1771 if(curprog == P_PLANNER) {
1772 repdata->dumper.result = L_SKIPPED;
1779 if(curprog == P_TAPER)
1780 sp = &(repdata->taper);
1781 else sp = &(repdata->dumper);
1790 get_info(hostname, diskname, &inf);
1791 tm = localtime(&inf.inf[level].date);
1792 Idatestamp = 10000*(tm->tm_year+1900) +
1793 100*(tm->tm_mon+1) + tm->tm_mday;
1795 if(atoi(datestamp) == Idatestamp) {
1796 /* grab original size from record */
1797 origkb = (double)inf.inf[level].size;
1806 sp->result = L_SUCCESS;
1807 sp->datestamp = repdata->datestamp;
1810 sp->origsize = origkb;
1811 sp->outsize = kbytes;
1813 if(curprog == P_TAPER) {
1814 if(current_tape == NULL) {
1815 error("current_tape == NULL");
1817 stats[i].taper_time += sec;
1818 sp->filenum = ++tapefcount;
1819 sp->tapelabel = current_tape->label;
1820 tapedisks[level] +=1;
1821 stats[i].tapedisks +=1;
1822 stats[i].tapesize += kbytes;
1823 current_tape->taper_time += sec;
1824 current_tape->coutsize += kbytes;
1825 current_tape->corigsize += origkb;
1826 current_tape->tapedisks += 1;
1829 if(curprog == P_DUMPER) {
1830 stats[i].dumper_time += sec;
1831 if(dp->compress == COMP_NONE) {
1832 sp->origsize = kbytes;
1835 stats[i].coutsize += kbytes;
1836 stats[i].corigsize += sp->origsize;
1838 dumpdisks[level] +=1;
1839 stats[i].dumpdisks +=1;
1840 stats[i].origsize += sp->origsize;
1841 stats[i].outsize += kbytes;
1847 void handle_strange()
1850 char *strangestr = NULL;
1853 repdata = handle_success();
1855 addline(&errdet,"");
1856 str = vstralloc("/-- ", prefix(repdata->disk->host->hostname,
1857 repdata->disk->name, repdata->level),
1860 addline(&errdet, str);
1863 while(contline_next()) {
1864 get_logline(logfile);
1865 #define sc "sendbackup: warning "
1866 if(strncmp(curstr, sc, sizeof(sc)-1) == 0) {
1867 strangestr = newstralloc(strangestr, curstr+sizeof(sc)-1);
1869 addline(&errdet, curstr);
1871 addline(&errdet,"\\--------");
1873 str = vstralloc("STRANGE", " ", strangestr, NULL);
1874 addtostrange(repdata->disk->host->hostname, repdata->disk->name, repdata->level,
1880 void handle_failed()
1900 skip_whitespace(s, ch);
1906 skip_non_whitespace(s, ch);
1909 skip_whitespace(s, ch);
1915 skip_non_whitespace(s, ch);
1918 skip_whitespace(s, ch);
1924 skip_non_whitespace(s, ch);
1926 datestamp = stralloc(fp);
1928 if(strlen(datestamp) < 3) { /* there is no datestamp, it's the level */
1929 level = atoi(datestamp);
1930 datestamp = newstralloc(datestamp, run_datestamp);
1932 else { /* read the level */
1933 skip_whitespace(s, ch);
1934 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
1939 skip_integer(s, ch);
1942 skip_whitespace(s, ch);
1949 if((s = strchr(errstr, '\n')) != NULL) {
1953 dp = lookup_disk(hostname, diskname);
1955 addtostrange(hostname, diskname, level, "ERROR [not in disklist]");
1957 repdata = find_repdata(dp, datestamp, level);
1959 if(curprog == P_TAPER)
1960 sp = &(repdata->taper);
1961 else sp = &(repdata->dumper);
1963 if(sp->result != L_SUCCESS)
1964 sp->result = L_FAIL;
1968 str = vstralloc("FAILED", " ", errstr, NULL);
1969 addtostrange(hostname, diskname, level, str);
1972 if(curprog == P_DUMPER) {
1973 addline(&errdet,"");
1974 str = vstralloc("/-- ", prefix(hostname, diskname, level),
1978 addline(&errdet, str);
1980 while(contline_next()) {
1981 get_logline(logfile);
1982 addline(&errdet, curstr);
1984 addline(&errdet,"\\--------");
1989 void generate_missing()
1993 for(dp = diskq->head; dp != NULL; dp = dp->next) {
1994 if(dp->todo && data(dp) == NULL) {
1995 addtostrange(dp->host->hostname, dp->name, -987, "RESULTS MISSING");
2001 prefix (host, disk, level)
2006 char number[NUM_STR_SIZE];
2007 static char *str = NULL;
2009 ap_snprintf(number, sizeof(number), "%d", level);
2010 str = newvstralloc(str,
2011 " ", host ? host : "(host?)",
2012 " ", disk ? disk : "(disk?)",
2013 level != -987 ? " lev " : "",
2014 level != -987 ? number : "",
2020 prefixstrange (host, disk, level, len_host, len_disk)
2024 int len_host, len_disk;
2028 char number[NUM_STR_SIZE];
2029 static char *str = NULL;
2031 ap_snprintf(number, sizeof(number), "%d", level);
2032 h=malloc(len_host+1);
2034 strncpy(h, host, len_host);
2036 strncpy(h, "(host?)", len_host);
2039 for(l = strlen(h); l < len_host; l++) {
2042 d=malloc(len_disk+1);
2044 strncpy(d, disk, len_disk);
2046 strncpy(d, "(disk?)", len_disk);
2049 for(l = strlen(d); l < len_disk; l++) {
2052 str = newvstralloc(str,
2055 level != -987 ? " lev " : "",
2056 level != -987 ? number : "",
2064 addtostrange (host, disk, level, str)
2072 strange = malloc(sizeof(strange_t));
2073 strange->hostname = stralloc(host);
2074 strange->diskname = stralloc(disk);
2075 strange->level = level;
2076 strange->str = stralloc(str);
2077 strange->next = NULL;
2078 if(first_strange == NULL) {
2079 first_strange = strange;
2082 last_strange->next = strange;
2084 last_strange = strange;
2087 void copy_template_file(lbl_templ)
2094 if (strchr(lbl_templ, '/') == NULL) {
2095 lbl_templ = stralloc2(config_dir, lbl_templ);
2097 lbl_templ = stralloc(lbl_templ);
2099 if ((fd = open(lbl_templ, 0)) < 0) {
2101 curprog = P_REPORTER;
2102 curstr = vstralloc("could not open PostScript template file ",
2109 afclose(postscript);
2112 while ((numread = read(fd, buf, sizeof(buf))) > 0) {
2113 if (fwrite(buf, numread, 1, postscript) != 1) {
2115 curprog = P_REPORTER;
2116 curstr = vstralloc("error copying PostScript template file ",
2123 afclose(postscript);
2129 curprog = P_REPORTER;
2130 curstr = vstralloc("error reading PostScript template file ",
2137 afclose(postscript);
2144 repdata_t *find_repdata(dp, datestamp, level)
2149 repdata_t *repdata, *prev;
2152 datestamp = run_datestamp;
2154 for(repdata = data(dp); repdata != NULL && (repdata->level != level || strcmp(repdata->datestamp,datestamp)!=0); repdata = repdata->next) {
2158 repdata = (repdata_t *)alloc(sizeof(repdata_t));
2159 memset(repdata, '\0',sizeof(repdata_t));
2161 repdata->datestamp = stralloc(datestamp ? datestamp : "");
2162 repdata->level = level;
2163 repdata->dumper.result = L_BOGUS;
2164 repdata->taper.result = L_BOGUS;
2165 repdata->next = NULL;
2167 prev->next = repdata;
2169 dp->up = (void *)repdata;
2175 void do_postscript_output()
2177 tapetype_t *tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
2180 float outsize, origsize;
2181 int tapesize, marksize;
2183 tapesize = tp->length;
2184 marksize = tp->filemark;
2186 for(current_tape = stats_by_tape; current_tape != NULL;
2187 current_tape = current_tape->next) {
2189 if (current_tape->label == NULL) {
2193 copy_template_file(tp->lbl_templ);
2195 /* generate a few elements */
2196 fprintf(postscript,"(%s) DrawDate\n\n",
2197 nicedate(run_datestamp ? atoi(run_datestamp) : 0));
2198 fprintf(postscript,"(Amanda Version %s) DrawVers\n",version());
2199 fprintf(postscript,"(%s) DrawTitle\n", current_tape->label);
2202 fprintf(postscript, "(Total Size: %6.1f MB) DrawStat\n",
2203 mb(current_tape->coutsize));
2204 fprintf(postscript, "(Tape Used (%%) ");
2205 divzero(postscript, pct(current_tape->coutsize +
2206 marksize * current_tape->tapedisks),
2208 fprintf(postscript," %%) DrawStat\n");
2209 fprintf(postscript, "(Compression Ratio: ");
2210 divzero(postscript, pct(current_tape->coutsize),current_tape->corigsize);
2211 fprintf(postscript," %%) DrawStat\n");
2212 fprintf(postscript,"(Filesystems Taped: %4d) DrawStat\n",
2213 current_tape->tapedisks);
2218 "(-) (%s) (-) ( 0) ( 32) ( 32) DrawHost\n",
2219 current_tape->label);
2221 for(dp = sortq.head; dp != NULL; dp = dp->next) {
2222 if (dp->todo == 0) {
2225 for(repdata = data(dp); repdata != NULL; repdata = repdata->next) {
2227 if(repdata->taper.tapelabel != current_tape->label) {
2231 if(repdata->dumper.result == L_SUCCESS)
2232 origsize = repdata->dumper.origsize;
2234 origsize = repdata->taper.origsize;
2236 if(repdata->taper.result == L_SUCCESS)
2237 outsize = repdata->taper.outsize;
2239 outsize = repdata->dumper.outsize;
2241 if (repdata->taper.result == L_SUCCESS) {
2242 if(origsize != 0.0) {
2243 fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8.0f) (%8.0f) DrawHost\n",
2244 dp->host->hostname, dp->name, repdata->level,
2245 repdata->taper.filenum, origsize,
2249 fprintf(postscript,"(%s) (%s) (%d) (%3.0d) (%8s) (%8.0f) DrawHost\n",
2250 dp->host->hostname, dp->name, repdata->level,
2251 repdata->taper.filenum, "N/A",
2258 fprintf(postscript,"\nshowpage\n");