38e8fd03759b0c2c8bc025167ecf85f85a5d1d3c
[debian/amanda] / server-src / find.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * All Rights Reserved.
5  *
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.
15  *
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.
22  *
23  * Author: James da Silva, Systems Design and Analysis Group
24  *                         Computer Science Department
25  *                         University of Maryland at College Park
26  */
27 /*
28  * $Id: find.c,v 1.33 2006/07/06 13:13:15 martinea Exp $
29  *
30  * controlling process for the Amanda backup system
31  */
32 #include "amanda.h"
33 #include "conffile.h"
34 #include "tapefile.h"
35 #include "logfile.h"
36 #include "holding.h"
37 #include "find.h"
38 #include "cmdline.h"
39
40 int find_match(char *host, char *disk);
41 void search_holding_disk(find_result_t **output_find);
42 char *find_nicedate(char *datestamp);
43 static int find_compare(const void *, const void *);
44 static int parse_taper_datestamp_log(char *logline, char **datestamp, char **level);
45 static gboolean logfile_has_tape(char * label, char * datestamp,
46                                  char * logfile);
47
48 static char *find_sort_order = NULL;
49
50 find_result_t * find_dump(disklist_t* diskqp) {
51     char *conf_logdir, *logfile = NULL;
52     int tape, maxtape, logs;
53     unsigned seq;
54     tape_t *tp;
55     find_result_t *output_find = NULL;
56
57     conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
58     maxtape = lookup_nb_tape();
59
60     for(tape = 1; tape <= maxtape; tape++) {
61
62         tp = lookup_tapepos(tape);
63         if(tp == NULL) continue;
64
65         /* search log files */
66
67         logs = 0;
68
69         /* new-style log.<date>.<seq> */
70
71         for(seq = 0; 1; seq++) {
72             char seq_str[NUM_STR_SIZE];
73
74             g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
75             logfile = newvstralloc(logfile,
76                         conf_logdir, "/log.", tp->datestamp, ".", seq_str, NULL);
77             if(access(logfile, R_OK) != 0) break;
78             if (search_logfile(&output_find, tp->label, tp->datestamp,
79                                logfile, diskqp)) {
80                 logs ++;
81             }
82         }
83
84         /* search old-style amflush log, if any */
85
86         logfile = newvstralloc(logfile, conf_logdir, "/log.",
87                                tp->datestamp, ".amflush", NULL);
88         if(access(logfile,R_OK) == 0) {
89             if (search_logfile(&output_find, tp->label, tp->datestamp,
90                                logfile, diskqp)) {
91                 logs ++;
92             }
93         }
94         
95         /* search old-style main log, if any */
96
97         logfile = newvstralloc(logfile, conf_logdir, "/log.", tp->datestamp,
98                                NULL);
99         if(access(logfile,R_OK) == 0) {
100             if (search_logfile(&output_find, tp->label, tp->datestamp,
101                                logfile, diskqp)) {
102                 logs ++;
103             }
104         }
105         if(logs == 0 && strcmp(tp->datestamp,"0") != 0)
106             g_fprintf(stderr,
107                       _("Warning: no log files found for tape %s written %s\n"),
108                       tp->label, find_nicedate(tp->datestamp));
109     }
110     amfree(logfile);
111     amfree(conf_logdir);
112
113     search_holding_disk(&output_find);
114
115     return(output_find);
116 }
117
118 char **
119 find_log(void)
120 {
121     char *conf_logdir, *logfile = NULL;
122     char *pathlogfile = NULL;
123     int tape, maxtape, logs;
124     unsigned seq;
125     tape_t *tp;
126     char **output_find_log = NULL;
127     char **current_log;
128
129     conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
130     maxtape = lookup_nb_tape();
131
132     output_find_log = alloc((maxtape*5+10) * SIZEOF(char *));
133     current_log = output_find_log;
134
135     for(tape = 1; tape <= maxtape; tape++) {
136
137         tp = lookup_tapepos(tape);
138         if(tp == NULL) continue;
139
140         /* search log files */
141
142         logs = 0;
143
144         /* new-style log.<date>.<seq> */
145
146         for(seq = 0; 1; seq++) {
147             char seq_str[NUM_STR_SIZE];
148
149             g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
150             logfile = newvstralloc(logfile, "log.", tp->datestamp, ".", seq_str, NULL);
151             pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
152             if (access(pathlogfile, R_OK) != 0) break;
153             if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
154                 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
155                     *current_log = stralloc(logfile);
156                     current_log++;
157                 }
158                 logs++;
159                 break;
160             }
161         }
162
163         /* search old-style amflush log, if any */
164
165         logfile = newvstralloc(logfile, "log.", tp->datestamp, ".amflush", NULL);
166         pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
167         if (access(pathlogfile, R_OK) == 0) {
168             if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
169                 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
170                     *current_log = stralloc(logfile);
171                     current_log++;
172                 }
173                 logs++;
174             }
175         }
176
177         /* search old-style main log, if any */
178
179         logfile = newvstralloc(logfile, "log.", tp->datestamp, NULL);
180         pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
181         if (access(pathlogfile, R_OK) == 0) {
182             if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
183                 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
184                     *current_log = stralloc(logfile);
185                     current_log++;
186                 }
187                 logs++;
188             }
189         }
190
191         if(logs == 0 && strcmp(tp->datestamp,"0") != 0)
192             g_fprintf(stderr, _("Warning: no log files found for tape %s written %s\n"),
193                    tp->label, find_nicedate(tp->datestamp));
194     }
195     amfree(logfile);
196     amfree(pathlogfile);
197     amfree(conf_logdir);
198     *current_log = NULL;
199     return(output_find_log);
200 }
201
202 void
203 search_holding_disk(
204     find_result_t **output_find)
205 {
206     GSList *holding_file_list;
207     GSList *e;
208     char *holding_file;
209     disk_t *dp;
210     dumpfile_t file;
211
212     holding_file_list = holding_get_files(NULL, 1);
213
214     for(e = holding_file_list; e != NULL; e = e->next) {
215         holding_file = (char *)e->data;
216
217         if (!holding_file_get_dumpfile(holding_file, &file))
218             continue;
219
220         if (file.dumplevel < 0 || file.dumplevel > 9)
221             continue;
222
223         dp = NULL;
224         for(;;) {
225             char *s;
226             if((dp = lookup_disk(file.name, file.disk)))
227                 break;
228             if((s = strrchr(file.name,'.')) == NULL)
229                 break;
230             *s = '\0';
231         }
232         if ( dp == NULL ) {
233             continue;
234         }
235
236         if(find_match(file.name,file.disk)) {
237             find_result_t *new_output_find =
238                 alloc(SIZEOF(find_result_t));
239             new_output_find->next=*output_find;
240             new_output_find->timestamp = stralloc(file.datestamp);
241             new_output_find->hostname = stralloc(file.name);
242             new_output_find->diskname = stralloc(file.disk);
243             new_output_find->level=file.dumplevel;
244             new_output_find->label=stralloc(holding_file);
245             new_output_find->partnum=stralloc("--");
246             new_output_find->filenum=0;
247             new_output_find->status=stralloc("OK");
248             *output_find=new_output_find;
249         }
250     }
251
252     g_slist_free_full(holding_file_list);
253 }
254
255 static int
256 find_compare(
257     const void *i1,
258     const void *j1)
259 {
260     int compare=0;
261     find_result_t *i, *j;
262
263     size_t nb_compare=strlen(find_sort_order);
264     size_t k;
265
266     for(k=0;k<nb_compare;k++) {
267         char sort_key = find_sort_order[k];
268         if (isupper((int)sort_key)) {
269             /* swap */
270             sort_key = tolower(sort_key);
271             j = *(find_result_t **)i1;
272             i = *(find_result_t **)j1;
273         } else {
274             i = *(find_result_t **)i1;
275             j = *(find_result_t **)j1;
276         }            
277         
278         switch (sort_key) {
279         case 'h' : compare=strcmp(i->hostname,j->hostname);
280                    break;
281         case 'k' : compare=strcmp(i->diskname,j->diskname);
282                    break;
283         case 'd' : compare=strcmp(i->timestamp,j->timestamp);
284                    break;
285         case 'l' : compare=j->level - i->level;
286                    break;
287         case 'f' : compare=(i->filenum == j->filenum) ? 0 :
288                            ((i->filenum < j->filenum) ? -1 : 1);
289                    break;
290         case 'b' : compare=compare_possibly_null_strings(i->label,
291                                                          j->label);
292                    break;
293         case 'p' :
294                    if(strcmp(i->partnum, "--") != 0 &&
295                       strcmp(j->partnum, "--") != 0){
296                       compare = atoi(i->partnum) - atoi(j->partnum);
297                    }
298                    else compare=strcmp(i->partnum,j->partnum);
299                    break;
300         }
301         if(compare != 0)
302             return compare;
303     }
304     return 0;
305 }
306
307 void
308 sort_find_result(
309     char *sort_order,
310     find_result_t **output_find)
311 {
312     find_result_t *output_find_result;
313     find_result_t **array_find_result = NULL;
314     size_t nb_result=0;
315     size_t no_result;
316
317     find_sort_order = sort_order;
318     /* qsort core dump if nothing to sort */
319     if(*output_find==NULL)
320         return;
321
322     /* How many result */
323     for(output_find_result=*output_find;
324         output_find_result;
325         output_find_result=output_find_result->next) {
326         nb_result++;
327     }
328
329     /* put the list in an array */
330     array_find_result=alloc(nb_result * SIZEOF(find_result_t *));
331     for(output_find_result=*output_find,no_result=0;
332         output_find_result;
333         output_find_result=output_find_result->next,no_result++) {
334         array_find_result[no_result]=output_find_result;
335     }
336
337     /* sort the array */
338     qsort(array_find_result,nb_result,SIZEOF(find_result_t *),
339           find_compare);
340
341     /* put the sorted result in the list */
342     for(no_result=0;
343         no_result<nb_result-1; no_result++) {
344         array_find_result[no_result]->next = array_find_result[no_result+1];
345     }
346     array_find_result[nb_result-1]->next=NULL;
347     *output_find=array_find_result[0];
348     amfree(array_find_result);
349 }
350
351 void
352 print_find_result(
353     find_result_t *output_find)
354 {
355     find_result_t *output_find_result;
356     int max_len_datestamp = 4;
357     int max_len_hostname  = 4;
358     int max_len_diskname  = 4;
359     int max_len_level     = 2;
360     int max_len_label     =12;
361     int max_len_filenum   = 4;
362     int max_len_part      = 4;
363     int max_len_status    = 6;
364     size_t len;
365
366     for(output_find_result=output_find;
367         output_find_result;
368         output_find_result=output_find_result->next) {
369         char *qdiskname;
370
371         len=strlen(find_nicedate(output_find_result->timestamp));
372         if((int)len > max_len_datestamp)
373             max_len_datestamp=(int)len;
374
375         len=strlen(output_find_result->hostname);
376         if((int)len > max_len_hostname)
377             max_len_hostname = (int)len;
378
379         qdiskname=quote_string(output_find_result->diskname);
380         len=strlen(qdiskname);
381         amfree(qdiskname);
382         if((int)len > max_len_diskname)
383             max_len_diskname = (int)len;
384
385         if (output_find_result->label != NULL) {
386             len=strlen(output_find_result->label);
387             if((int)len > max_len_label)
388                 max_len_label = (int)len;
389         }
390
391         len=strlen(output_find_result->status);
392         if((int)len > max_len_status)
393             max_len_status = (int)len;
394
395         len=strlen(output_find_result->partnum);
396         if((int)len > max_len_part)
397             max_len_part = (int)len;
398     }
399
400     /*
401      * Since status is the rightmost field, we zap the maximum length
402      * because it is not needed.  The code is left in place in case
403      * another column is added later.
404      */
405     max_len_status = 1;
406
407     if(output_find==NULL) {
408         g_printf(_("\nNo dump to list\n"));
409     }
410     else {
411         g_printf(_("\ndate%*s host%*s disk%*s lv%*s tape or file%*s file%*s part%*s status\n"),
412                max_len_datestamp-4,"",
413                max_len_hostname-4 ,"",
414                max_len_diskname-4 ,"",
415                max_len_level-2    ,"",
416                max_len_label-12   ,"",
417                max_len_filenum-4  ,"",
418                max_len_part-4  ,"");
419         for(output_find_result=output_find;
420                 output_find_result;
421                 output_find_result=output_find_result->next) {
422             char *qdiskname;
423             char * formatted_label;
424
425             qdiskname = quote_string(output_find_result->diskname);
426             formatted_label = output_find_result->label;
427             if (formatted_label == NULL)
428                 formatted_label = "";
429             /*@ignore@*/
430             g_printf("%-*s %-*s %-*s %*d %-*s %*lld %*s %-*s\n",
431                      max_len_datestamp, 
432                      find_nicedate(output_find_result->timestamp),
433                      max_len_hostname,  output_find_result->hostname,
434                      max_len_diskname,  qdiskname,
435                      max_len_level,     output_find_result->level,
436                      max_len_label,     formatted_label,
437                      max_len_filenum,   (long long)output_find_result->filenum,
438                      max_len_part,      output_find_result->partnum,
439                      max_len_status,    output_find_result->status
440                     );
441             /*@end@*/
442             amfree(qdiskname);
443         }
444     }
445 }
446
447 void
448 free_find_result(
449     find_result_t **output_find)
450 {
451     find_result_t *output_find_result, *prev;
452
453     prev=NULL;
454     for(output_find_result=*output_find;
455             output_find_result;
456             output_find_result=output_find_result->next) {
457         amfree(prev);
458         amfree(output_find_result->timestamp);
459         amfree(output_find_result->hostname);
460         amfree(output_find_result->diskname);
461         amfree(output_find_result->label);
462         amfree(output_find_result->partnum);
463         amfree(output_find_result->status);
464         amfree(output_find_result->timestamp);
465         prev = output_find_result;
466     }
467     amfree(prev);
468     *output_find = NULL;
469 }
470
471 int
472 find_match(
473     char *host,
474     char *disk)
475 {
476     disk_t *dp = lookup_disk(host,disk);
477     return (dp && dp->todo);
478 }
479
480 char *
481 find_nicedate(
482     char *datestamp)
483 {
484     static char nice[20];
485     int year, month, day;
486     int hours, minutes, seconds;
487     char date[9], atime[7];
488     int  numdate, numtime;
489
490     strncpy(date, datestamp, 8);
491     date[8] = '\0';
492     numdate = atoi(date);
493     year  = numdate / 10000;
494     month = (numdate / 100) % 100;
495     day   = numdate % 100;
496
497     if(strlen(datestamp) <= 8) {
498         g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d",
499                 year, month, day);
500     }
501     else {
502         strncpy(atime, &(datestamp[8]), 6);
503         atime[6] = '\0';
504         numtime = atoi(atime);
505         hours = numtime / 10000;
506         minutes = (numtime / 100) % 100;
507         seconds = numtime % 100;
508
509         g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d %02d:%02d:%02d",
510                 year, month, day, hours, minutes, seconds);
511     }
512
513     return nice;
514 }
515
516 static int
517 parse_taper_datestamp_log(
518     char *logline,
519     char **datestamp,
520     char **label)
521 {
522     char *s;
523     int ch;
524
525     s = logline;
526     ch = *s++;
527
528     skip_whitespace(s, ch);
529     if(ch == '\0') {
530         return 0;
531     }
532     if(strncmp_const_skip(s - 1, "datestamp", s, ch) != 0) {
533         return 0;
534     }
535
536     skip_whitespace(s, ch);
537     if(ch == '\0') {
538         return 0;
539     }
540     *datestamp = s - 1;
541     skip_non_whitespace(s, ch);
542     s[-1] = '\0';
543
544     skip_whitespace(s, ch);
545     if(ch == '\0') {
546         return 0;
547     }
548     if(strncmp_const_skip(s - 1, "label", s, ch) != 0) {
549         return 0;
550     }
551
552     skip_whitespace(s, ch);
553     if(ch == '\0') {
554         return 0;
555     }
556     *label = s - 1;
557     skip_non_whitespace(s, ch);
558     s[-1] = '\0';
559
560     return 1;
561 }
562
563 /* Returns TRUE if the given logfile mentions the given tape. */
564 static gboolean logfile_has_tape(char * label, char * datestamp,
565                                  char * logfile) {
566     FILE * logf;
567     char * ck_datestamp, *ck_label;
568     if((logf = fopen(logfile, "r")) == NULL) {
569         error(_("could not open logfile %s: %s"), logfile, strerror(errno));
570         /*NOTREACHED*/
571     }
572
573     while(get_logline(logf)) {
574         if(curlog == L_START && curprog == P_TAPER) {
575             if(parse_taper_datestamp_log(curstr,
576                                          &ck_datestamp, &ck_label) == 0) {
577                 g_printf(_("strange log line \"start taper %s\" curstr='%s'\n"),
578                          logfile, curstr);
579             } else if(strcmp(ck_datestamp, datestamp) == 0
580                       && strcmp(ck_label, label) == 0) {
581                 afclose(logf);
582                 return TRUE;
583             }
584         }
585     }
586
587     afclose(logf);
588     return FALSE;
589 }
590
591 /* Like (strcmp(label1, label2) == 0), except that NULL values force TRUE. */
592 static gboolean volume_matches(const char * label1, const char * label2) {
593     return (label1 == NULL || label2 == NULL || strcmp(label1, label2) == 0);
594 }
595
596 /* WARNING: Function accesses globals find_diskqp, curlog, curlog, curstr,
597  * dynamic_disklist */
598 gboolean
599 search_logfile(
600     find_result_t **output_find,
601     const char *label,
602     const char *passed_datestamp,
603     const char *logfile,
604     disklist_t * dynamic_disklist)
605 {
606     FILE *logf;
607     char *host, *host_undo;
608     char *disk, *qdisk, *disk_undo;
609     char *date, *date_undo;
610     char *partnum=NULL, *partnum_undo;
611     char *number;
612     int fileno;
613     char *current_label = NULL;
614     char *rest;
615     char *ck_label=NULL;
616     int level = 0; 
617     off_t filenum;
618     char *ck_datestamp, *datestamp;
619     char *s;
620     int ch;
621     disk_t *dp;
622     find_result_t *part_find = NULL;  /* List for all part of a DLE */
623     find_result_t *a_part_find;
624     gboolean right_label = FALSE;
625     gboolean found_something = FALSE;
626
627     g_return_val_if_fail(output_find != NULL, 0);
628     g_return_val_if_fail(logfile != NULL, 0);
629
630     datestamp = g_strdup(passed_datestamp);
631
632     if((logf = fopen(logfile, "r")) == NULL) {
633         error(_("could not open logfile %s: %s"), logfile, strerror(errno));
634         /*NOTREACHED*/
635     }
636
637     filenum = (off_t)0;
638     while(get_logline(logf)) {
639         if (curlog == L_START && curprog == P_TAPER) {
640             if(parse_taper_datestamp_log(curstr, &ck_datestamp,
641                                          &ck_label) == 0) {
642                 g_printf(_("strange log line in %s \"start taper %s\"\n"),
643                          logfile, curstr);
644                 continue;
645             }
646             if (datestamp != NULL) {
647                 if (strcmp(datestamp, ck_datestamp) != 0) {
648                     g_printf(_("Log file %s stamped %s, expecting %s!\n"),
649                              logfile, ck_datestamp, datestamp);
650                     break;
651                 }
652             }
653             
654             right_label = volume_matches(label, ck_label);
655             if (label && datestamp && right_label) {
656                 found_something = TRUE;
657             }
658             amfree(current_label);
659             current_label = g_strdup(ck_label);
660             if (datestamp == NULL) {
661                 datestamp = g_strdup(ck_datestamp);
662             }
663         }
664         if (!right_label) {
665             continue;
666         }
667         if ((curlog == L_SUCCESS ||
668              curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTPARTIAL) &&
669             curprog == P_TAPER) {
670             filenum++;
671         }
672         partnum = "--";
673         if (curlog == L_SUCCESS || curlog == L_CHUNKSUCCESS ||
674             curlog == L_DONE    || curlog == L_FAIL ||
675             curlog == L_CHUNK   || curlog == L_PART || curlog == L_PARTIAL ||
676             curlog == L_PARTPARTIAL ) {
677             s = curstr;
678             ch = *s++;
679
680             skip_whitespace(s, ch);
681             if(ch == '\0') {
682                 g_printf(_("strange log line in %s \"%s\"\n"),
683                     logfile, curstr);
684                 continue;
685             }
686
687             if (curlog == L_PART || curlog == L_PARTPARTIAL) {
688                 char * part_label = s - 1;
689                 skip_non_whitespace(s, ch);
690                 s[-1] = '\0';
691
692                 if (strcmp(current_label, part_label) != 0) {
693                     g_printf("PART label %s doesn't match START label %s\n",
694                              part_label, current_label);
695                     continue;
696                 }
697                 skip_whitespace(s, ch);
698                 if(ch == '\0') {
699                     g_printf("strange log line in %s \"%s\"\n",
700                            logfile, curstr);
701                     continue;
702                 }
703
704                 number = s - 1;
705                 skip_non_whitespace(s, ch);
706                 s[-1] = '\0';
707                 fileno = atoi(number);
708                 filenum = fileno;
709
710                 skip_whitespace(s, ch);
711                 if(ch == '\0') {
712                     g_printf("strange log line in %s \"%s\"\n",
713                            logfile, curstr);
714                     continue;
715                 }
716             }
717
718             host = s - 1;
719             skip_non_whitespace(s, ch);
720             host_undo = s - 1;
721             *host_undo = '\0';
722
723             skip_whitespace(s, ch);
724             if(ch == '\0') {
725                 g_printf(_("strange log line in %s \"%s\"\n"),
726                     logfile, curstr);
727                 continue;
728             }
729             qdisk = s - 1;
730             skip_quoted_string(s, ch);
731             disk_undo = s - 1;
732             *disk_undo = '\0';
733             disk = unquote_string(qdisk);
734
735             skip_whitespace(s, ch);
736             if(ch == '\0') {
737                 g_printf(_("strange log line in %s \"%s\"\n"),
738                          logfile, curstr);
739                 continue;
740             }
741             date = s - 1;
742             skip_non_whitespace(s, ch);
743             date_undo = s - 1;
744             *date_undo = '\0';
745
746             if(strlen(date) < 3) { /* old log didn't have datestamp */
747                 level = atoi(date);
748                 date = stralloc(datestamp);
749             } else {
750                 if (curlog == L_CHUNK || curlog == L_PART ||
751                     curlog == L_PARTPARTIAL || curlog == L_DONE){
752                     skip_whitespace(s, ch);
753                     partnum = s - 1;
754                     skip_non_whitespace(s, ch);
755                     partnum_undo = s - 1;
756                     *partnum_undo = '\0';
757                 }
758                 skip_whitespace(s, ch);
759                 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
760                     g_printf(_("strange log line in %s \"%s\"\n"),
761                     logfile, curstr);
762                     continue;
763                 }
764                 skip_integer(s, ch);
765             }
766
767             skip_whitespace(s, ch);
768             if(ch == '\0') {
769                 g_printf(_("strange log line in %s \"%s\"\n"),
770                     logfile, curstr);
771                 continue;
772             }
773             rest = s - 1;
774             if((s = strchr(s, '\n')) != NULL) {
775                 *s = '\0';
776             }
777
778             dp = lookup_disk(host,disk);
779             if ( dp == NULL ) {
780                 if (dynamic_disklist == NULL) {
781                     continue;
782                 }
783                 dp = add_disk(dynamic_disklist, host, disk);
784                 enqueue_disk(dynamic_disklist, dp);
785             }
786             if (find_match(host, disk)) {
787                 if(curprog == P_TAPER) {
788                     find_result_t *new_output_find =
789                         (find_result_t *)alloc(SIZEOF(find_result_t));
790                     new_output_find->timestamp = stralloc(date);
791                     new_output_find->hostname=stralloc(host);
792                     new_output_find->diskname=stralloc(disk);
793                     new_output_find->level=level;
794                     new_output_find->partnum = stralloc(partnum);
795                     new_output_find->label=stralloc(current_label);
796                     new_output_find->status=NULL;
797                     new_output_find->filenum=filenum;
798                     new_output_find->next=NULL;
799                     if (curlog == L_SUCCESS) {
800                         new_output_find->status = stralloc("OK");
801                         new_output_find->next = *output_find;
802                         *output_find = new_output_find;
803                         found_something = TRUE;
804                     } else if (curlog == L_CHUNKSUCCESS || curlog == L_DONE ||
805                                curlog == L_PARTIAL      || curlog == L_FAIL) {
806                         /* result line */
807                         if (curlog == L_PARTIAL || curlog == L_FAIL) {
808                             /* change status of each part */
809                             for (a_part_find = part_find; a_part_find;
810                                  a_part_find = a_part_find->next) {
811                                 if (curlog == L_PARTIAL)
812                                     a_part_find->status = stralloc("PARTIAL");
813                                 else
814                                     a_part_find->status = stralloc(rest);
815                             }
816                         }
817                         if (part_find) { /* find last element */
818                             for (a_part_find = part_find;
819                                  a_part_find->next != NULL;
820                                  a_part_find=a_part_find->next) {
821                             }
822                             /* merge part_find to *output_find */
823                             a_part_find->next = *output_find;
824                             *output_find = part_find;
825                             part_find = NULL;
826                             found_something = TRUE;
827                         }
828                         free_find_result(&new_output_find);
829                     } else { /* part line */
830                         if (curlog == L_PART || curlog == L_CHUNK)
831                             new_output_find->status=stralloc("OK");
832                         else /* PARTPARTIAL */
833                             new_output_find->status=stralloc("PARTIAL");
834                         /* Add to part_find list */
835                         new_output_find->next = part_find;
836                         part_find = new_output_find;
837                         found_something = TRUE;
838                     }
839                 }
840                 else if(curlog == L_FAIL) {     /* print other failures too */
841                     find_result_t *new_output_find =
842                         (find_result_t *)alloc(SIZEOF(find_result_t));
843                     new_output_find->next=*output_find;
844                     new_output_find->timestamp = stralloc(date);
845                     new_output_find->hostname=stralloc(host);
846                     new_output_find->diskname=stralloc(disk);
847                     new_output_find->level=level;
848                     new_output_find->label=NULL;
849                     new_output_find->partnum=stralloc(partnum);
850                     new_output_find->filenum=0;
851                     new_output_find->status=vstralloc(
852                          "FAILED (",
853                          program_str[(int)curprog],
854                          ") ",
855                          rest,
856                          NULL);
857                     *output_find=new_output_find;
858                     found_something = TRUE;
859                 }
860             }
861             amfree(disk);
862         }
863     }
864
865     if (part_find != NULL) {
866         if (label) {
867             /* parse log file until PARTIAL/DONE/SUCCESS/FAIL from taper */
868             while(get_logline(logf)) {
869                 if (curprog == P_TAPER &&
870                     (curlog == L_DONE || curlog == L_SUCCESS ||
871                      curlog == L_PARTIAL || curlog == L_FAIL)) {
872                     break;
873                 }
874             }
875         }
876         for (a_part_find = part_find; a_part_find;
877              a_part_find = a_part_find->next) {
878             if (curlog == L_PARTIAL)
879                 a_part_find->status = stralloc("PARTIAL");
880             else if (curlog == L_FAIL)
881                 a_part_find->status = stralloc("FAIL");
882         }
883         for (a_part_find = part_find;
884              a_part_find->next != NULL;
885              a_part_find=a_part_find->next) {
886         }
887         /* merge part_find to *output_find */
888         a_part_find->next = *output_find;
889         *output_find = part_find;
890         part_find = NULL;
891     }
892
893     afclose(logf);
894     amfree(datestamp);
895     amfree(current_label);
896
897     return found_something;
898 }
899
900
901 /*
902  * Return the set of dumps that match *all* of the given patterns (we consider
903  * an empty pattern to match .*, though).  If 'ok' is true, will only match
904  * dumps with SUCCESS status.
905  *
906  * Returns a newly allocated list of results, where all strings are also newly
907  * allocated.  Apparently some part of Amanda leaks under this condition.
908  */
909 find_result_t *
910 dumps_match(
911     find_result_t *output_find,
912     char *hostname,
913     char *diskname,
914     char *datestamp,
915     char *level,
916     int ok)
917 {
918     find_result_t *cur_result;
919     find_result_t *matches = NULL;
920
921     for(cur_result=output_find;
922         cur_result;
923         cur_result=cur_result->next) {
924         char level_str[NUM_STR_SIZE];
925         g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
926         if((!hostname || *hostname == '\0' || match_host(hostname, cur_result->hostname)) &&
927            (!diskname || *diskname == '\0' || match_disk(diskname, cur_result->diskname)) &&
928            (!datestamp || *datestamp== '\0' || match_datestamp(datestamp, cur_result->timestamp)) &&
929            (!level || *level== '\0' || match_level(level, level_str)) &&
930            (!ok || !strcmp(cur_result->status, "OK"))){
931
932             find_result_t *curmatch = alloc(SIZEOF(find_result_t));
933             memcpy(curmatch, cur_result, SIZEOF(find_result_t));
934
935             curmatch->timestamp = stralloc(cur_result->timestamp);
936             curmatch->hostname = stralloc(cur_result->hostname);
937             curmatch->diskname = stralloc(cur_result->diskname);
938             curmatch->level = cur_result->level;
939             curmatch->label = stralloc(cur_result->label);
940             curmatch->filenum = cur_result->filenum;
941             curmatch->status = stralloc(cur_result->status);
942             curmatch->partnum = stralloc(cur_result->partnum);
943
944             curmatch->next = matches;
945             matches = curmatch;
946         }
947     }
948
949     return(matches);
950 }
951
952 /*
953  * Return the set of dumps that match one or more of the given dumpspecs,
954  * If 'ok' is true, only dumps with a SUCCESS status will be matched.
955  * 
956  * Returns a newly allocated list of results, where all strings are also newly
957  * allocated.  Apparently some part of Amanda leaks under this condition.
958  */
959 find_result_t *
960 dumps_match_dumpspecs(
961     find_result_t *output_find,
962     GSList        *dumpspecs,
963     int ok)
964 {
965     find_result_t *cur_result;
966     find_result_t *matches = NULL;
967     GSList        *dumpspec;
968     dumpspec_t    *ds;
969
970     for(cur_result=output_find;
971         cur_result;
972         cur_result=cur_result->next) {
973         char level_str[NUM_STR_SIZE];
974         g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
975         for (dumpspec = dumpspecs; dumpspec; dumpspec = dumpspec->next) {
976             ds = (dumpspec_t *)dumpspec->data;
977             if((!ds->host || *ds->host == '\0' || match_host(ds->host, cur_result->hostname)) &&
978                (!ds->disk || *ds->disk == '\0' || match_disk(ds->disk, cur_result->diskname)) &&
979                (!ds->datestamp || *ds->datestamp== '\0' || match_datestamp(ds->datestamp, cur_result->timestamp)) &&
980                (!ds->level || *ds->level== '\0' || match_level(ds->level, level_str)) &&
981                (!ok || !strcmp(cur_result->status, "OK"))){
982
983                 find_result_t *curmatch = alloc(SIZEOF(find_result_t));
984                 memcpy(curmatch, cur_result, SIZEOF(find_result_t));
985
986                 curmatch->timestamp = stralloc(cur_result->timestamp);
987                 curmatch->hostname = stralloc(cur_result->hostname);
988                 curmatch->diskname = stralloc(cur_result->diskname);
989                 curmatch->level = cur_result->level;
990                 curmatch->label = stralloc(cur_result->label);
991                 curmatch->filenum = cur_result->filenum;
992                 curmatch->status = stralloc(cur_result->status);
993                 curmatch->partnum = stralloc(cur_result->partnum);
994
995                 curmatch->next = matches;
996                 matches = curmatch;
997                 break;
998             }
999         }
1000     }
1001
1002     return(matches);
1003 }
1004
1005 find_result_t *
1006 dump_exist(
1007     find_result_t *output_find,
1008     char *hostname,
1009     char *diskname,
1010     char *datestamp,
1011     int level)
1012 {
1013     find_result_t *output_find_result;
1014
1015     for(output_find_result=output_find;
1016         output_find_result;
1017         output_find_result=output_find_result->next) {
1018         if( !strcmp(output_find_result->hostname, hostname) &&
1019             !strcmp(output_find_result->diskname, diskname) &&
1020             !strcmp(output_find_result->timestamp, datestamp) &&
1021             output_find_result->level == level) {
1022
1023             return output_find_result;
1024         }
1025     }
1026     return(NULL);
1027 }