2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 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: find.c,v 1.33 2006/07/06 13:13:15 martinea Exp $
30 * controlling process for the Amanda backup system
41 int find_match(char *host, char *disk);
42 void search_holding_disk(find_result_t **output_find);
43 char *find_nicedate(char *datestamp);
44 static int find_compare(const void *, const void *);
45 static int parse_taper_datestamp_log(char *logline, char **datestamp, char **level);
46 static gboolean logfile_has_tape(char * label, char * datestamp,
49 static char *find_sort_order = NULL;
51 find_result_t * find_dump(disklist_t* diskqp) {
52 char *conf_logdir, *logfile = NULL;
53 int tape, maxtape, logs;
56 find_result_t *output_find = NULL;
58 conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
59 maxtape = lookup_nb_tape();
61 for(tape = 1; tape <= maxtape; tape++) {
63 tp = lookup_tapepos(tape);
64 if(tp == NULL) continue;
66 /* search log files */
70 /* new-style log.<date>.<seq> */
72 for(seq = 0; 1; seq++) {
73 char seq_str[NUM_STR_SIZE];
75 g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
76 logfile = newvstralloc(logfile,
77 conf_logdir, "/log.", tp->datestamp, ".", seq_str, NULL);
78 if(access(logfile, R_OK) != 0) break;
79 if (search_logfile(&output_find, tp->label, tp->datestamp,
85 /* search old-style amflush log, if any */
87 logfile = newvstralloc(logfile, conf_logdir, "/log.",
88 tp->datestamp, ".amflush", NULL);
89 if(access(logfile,R_OK) == 0) {
90 if (search_logfile(&output_find, tp->label, tp->datestamp,
96 /* search old-style main log, if any */
98 logfile = newvstralloc(logfile, conf_logdir, "/log.", tp->datestamp,
100 if(access(logfile,R_OK) == 0) {
101 if (search_logfile(&output_find, tp->label, tp->datestamp,
106 if(logs == 0 && strcmp(tp->datestamp,"0") != 0)
108 _("Warning: no log files found for tape %s written %s\n"),
109 tp->label, find_nicedate(tp->datestamp));
114 search_holding_disk(&output_find);
122 char *conf_logdir, *logfile = NULL;
123 char *pathlogfile = NULL;
124 int tape, maxtape, logs;
127 char **output_find_log = NULL;
130 conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
131 maxtape = lookup_nb_tape();
133 output_find_log = alloc((maxtape*5+10) * SIZEOF(char *));
134 current_log = output_find_log;
136 for(tape = 1; tape <= maxtape; tape++) {
138 tp = lookup_tapepos(tape);
139 if(tp == NULL) continue;
141 /* search log files */
145 /* new-style log.<date>.<seq> */
147 for(seq = 0; 1; seq++) {
148 char seq_str[NUM_STR_SIZE];
150 g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
151 logfile = newvstralloc(logfile, "log.", tp->datestamp, ".", seq_str, NULL);
152 pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
153 if (access(pathlogfile, R_OK) != 0) break;
154 if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
155 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
156 *current_log = stralloc(logfile);
164 /* search old-style amflush log, if any */
166 logfile = newvstralloc(logfile, "log.", tp->datestamp, ".amflush", NULL);
167 pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
168 if (access(pathlogfile, R_OK) == 0) {
169 if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
170 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
171 *current_log = stralloc(logfile);
178 /* search old-style main log, if any */
180 logfile = newvstralloc(logfile, "log.", tp->datestamp, NULL);
181 pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
182 if (access(pathlogfile, R_OK) == 0) {
183 if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
184 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
185 *current_log = stralloc(logfile);
192 if(logs == 0 && strcmp(tp->datestamp,"0") != 0)
193 g_fprintf(stderr, _("Warning: no log files found for tape %s written %s\n"),
194 tp->label, find_nicedate(tp->datestamp));
200 return(output_find_log);
205 find_result_t **output_find)
207 GSList *holding_file_list;
212 holding_file_list = holding_get_files(NULL, 1);
214 for(e = holding_file_list; e != NULL; e = e->next) {
217 holding_file = (char *)e->data;
219 if (!holding_file_get_dumpfile(holding_file, &file))
222 if (file.dumplevel < 0 || file.dumplevel > 9) {
223 dumpfile_free_data(&file);
230 if((dp = lookup_disk(file.name, file.disk)))
232 if((s = strrchr(file.name,'.')) == NULL)
237 dumpfile_free_data(&file);
241 if(find_match(file.name,file.disk)) {
242 find_result_t *new_output_find = g_new0(find_result_t, 1);
243 new_output_find->next=*output_find;
244 new_output_find->timestamp = stralloc(file.datestamp);
245 new_output_find->hostname = stralloc(file.name);
246 new_output_find->diskname = stralloc(file.disk);
247 new_output_find->level=file.dumplevel;
248 new_output_find->label=stralloc(holding_file);
249 new_output_find->partnum=stralloc("--");
250 new_output_find->filenum=0;
251 new_output_find->status=stralloc("OK");
252 *output_find=new_output_find;
254 dumpfile_free_data(&file);
257 g_slist_free_full(holding_file_list);
261 get_write_timestamp(char *tapelabel)
265 if (!tapelabel || !(tp = lookup_tapelabel(tapelabel)))
268 return tp->datestamp;
277 find_result_t *i, *j;
279 size_t nb_compare=strlen(find_sort_order);
282 for(k=0;k<nb_compare;k++) {
283 char sort_key = find_sort_order[k];
284 if (isupper((int)sort_key)) {
286 sort_key = tolower(sort_key);
287 j = *(find_result_t **)i1;
288 i = *(find_result_t **)j1;
290 i = *(find_result_t **)i1;
291 j = *(find_result_t **)j1;
295 case 'h' : compare=strcmp(i->hostname,j->hostname);
297 case 'k' : compare=strcmp(i->diskname,j->diskname);
299 case 'd' : compare=strcmp(i->timestamp,j->timestamp);
301 case 'l' : compare=j->level - i->level;
303 case 'f' : compare=(i->filenum == j->filenum) ? 0 :
304 ((i->filenum < j->filenum) ? -1 : 1);
306 case 'b' : compare=compare_possibly_null_strings(i->label,
309 case 'w': compare=strcmp(get_write_timestamp(i->label),
310 get_write_timestamp(j->label));
313 if(strcmp(i->partnum, "--") != 0 &&
314 strcmp(j->partnum, "--") != 0){
315 compare = atoi(i->partnum) - atoi(j->partnum);
317 else compare=strcmp(i->partnum,j->partnum);
329 find_result_t **output_find)
331 find_result_t *output_find_result;
332 find_result_t **array_find_result = NULL;
336 find_sort_order = sort_order;
337 /* qsort core dump if nothing to sort */
338 if(*output_find==NULL)
341 /* How many result */
342 for(output_find_result=*output_find;
344 output_find_result=output_find_result->next) {
348 /* put the list in an array */
349 array_find_result=alloc(nb_result * SIZEOF(find_result_t *));
350 for(output_find_result=*output_find,no_result=0;
352 output_find_result=output_find_result->next,no_result++) {
353 array_find_result[no_result]=output_find_result;
357 qsort(array_find_result,nb_result,SIZEOF(find_result_t *),
360 /* put the sorted result in the list */
362 no_result<nb_result-1; no_result++) {
363 array_find_result[no_result]->next = array_find_result[no_result+1];
365 array_find_result[nb_result-1]->next=NULL;
366 *output_find=array_find_result[0];
367 amfree(array_find_result);
372 find_result_t *output_find)
374 find_result_t *output_find_result;
375 int max_len_datestamp = 4;
376 int max_len_hostname = 4;
377 int max_len_diskname = 4;
378 int max_len_level = 2;
379 int max_len_label =12;
380 int max_len_filenum = 4;
381 int max_len_part = 4;
382 int max_len_status = 6;
385 for(output_find_result=output_find;
387 output_find_result=output_find_result->next) {
390 len=strlen(find_nicedate(output_find_result->timestamp));
391 if((int)len > max_len_datestamp)
392 max_len_datestamp=(int)len;
394 len=strlen(output_find_result->hostname);
395 if((int)len > max_len_hostname)
396 max_len_hostname = (int)len;
398 qdiskname=quote_string(output_find_result->diskname);
399 len=strlen(qdiskname);
401 if((int)len > max_len_diskname)
402 max_len_diskname = (int)len;
404 if (output_find_result->label != NULL) {
405 len=strlen(output_find_result->label);
406 if((int)len > max_len_label)
407 max_len_label = (int)len;
410 len=strlen(output_find_result->status);
411 if((int)len > max_len_status)
412 max_len_status = (int)len;
414 len=strlen(output_find_result->partnum);
415 if((int)len > max_len_part)
416 max_len_part = (int)len;
420 * Since status is the rightmost field, we zap the maximum length
421 * because it is not needed. The code is left in place in case
422 * another column is added later.
426 if(output_find==NULL) {
427 g_printf(_("\nNo dump to list\n"));
430 g_printf(_("\ndate%*s host%*s disk%*s lv%*s tape or file%*s file%*s part%*s status\n"),
431 max_len_datestamp-4,"",
432 max_len_hostname-4 ,"",
433 max_len_diskname-4 ,"",
435 max_len_label-12 ,"",
436 max_len_filenum-4 ,"",
438 for(output_find_result=output_find;
440 output_find_result=output_find_result->next) {
442 char * formatted_label;
444 qdiskname = quote_string(output_find_result->diskname);
445 formatted_label = output_find_result->label;
446 if (formatted_label == NULL)
447 formatted_label = "";
450 /* sec and kb are omitted here, for compatibility with the existing
451 * output from 'amadmin' */
452 g_printf("%-*s %-*s %-*s %*d %-*s %*lld %*s %-*s\n",
454 find_nicedate(output_find_result->timestamp),
455 max_len_hostname, output_find_result->hostname,
456 max_len_diskname, qdiskname,
457 max_len_level, output_find_result->level,
458 max_len_label, formatted_label,
459 max_len_filenum, (long long)output_find_result->filenum,
460 max_len_part, output_find_result->partnum,
461 max_len_status, output_find_result->status
471 find_result_t **output_find)
473 find_result_t *output_find_result, *prev;
476 for(output_find_result=*output_find;
478 output_find_result=output_find_result->next) {
480 amfree(output_find_result->timestamp);
481 amfree(output_find_result->hostname);
482 amfree(output_find_result->diskname);
483 amfree(output_find_result->label);
484 amfree(output_find_result->partnum);
485 amfree(output_find_result->status);
486 prev = output_find_result;
497 disk_t *dp = lookup_disk(host,disk);
498 return (dp && dp->todo);
505 static char nice[20];
506 int year, month, day;
507 int hours, minutes, seconds;
508 char date[9], atime[7];
509 int numdate, numtime;
511 strncpy(date, datestamp, 8);
513 numdate = atoi(date);
514 year = numdate / 10000;
515 month = (numdate / 100) % 100;
518 if(strlen(datestamp) <= 8) {
519 g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d",
523 strncpy(atime, &(datestamp[8]), 6);
525 numtime = atoi(atime);
526 hours = numtime / 10000;
527 minutes = (numtime / 100) % 100;
528 seconds = numtime % 100;
530 g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d %02d:%02d:%02d",
531 year, month, day, hours, minutes, seconds);
538 parse_taper_datestamp_log(
549 skip_whitespace(s, ch);
553 if(strncmp_const_skip(s - 1, "datestamp", s, ch) != 0) {
557 skip_whitespace(s, ch);
562 skip_non_whitespace(s, ch);
565 skip_whitespace(s, ch);
569 if(strncmp_const_skip(s - 1, "label", s, ch) != 0) {
573 skip_whitespace(s, ch);
578 skip_non_whitespace(s, ch);
584 /* Returns TRUE if the given logfile mentions the given tape. */
585 static gboolean logfile_has_tape(char * label, char * datestamp,
588 char * ck_datestamp, *ck_label;
589 if((logf = fopen(logfile, "r")) == NULL) {
590 error(_("could not open logfile %s: %s"), logfile, strerror(errno));
594 while(get_logline(logf)) {
595 if(curlog == L_START && curprog == P_TAPER) {
596 if(parse_taper_datestamp_log(curstr,
597 &ck_datestamp, &ck_label) == 0) {
598 g_printf(_("strange log line \"start taper %s\" curstr='%s'\n"),
600 } else if(strcmp(ck_datestamp, datestamp) == 0
601 && strcmp(ck_label, label) == 0) {
612 /* Like (strcmp(label1, label2) == 0), except that NULL values force TRUE. */
613 static gboolean volume_matches(const char * label1, const char * label2) {
614 return (label1 == NULL || label2 == NULL || strcmp(label1, label2) == 0);
617 /* WARNING: Function accesses globals find_diskqp, curlog, curlog, curstr,
618 * dynamic_disklist */
621 find_result_t **output_find,
623 const char *passed_datestamp,
625 disklist_t * dynamic_disklist)
628 char *host, *host_undo;
629 char *disk, *qdisk, *disk_undo;
630 char *date, *date_undo;
631 char *partnum=NULL, *partnum_undo;
634 char *current_label = NULL;
639 char *ck_datestamp, *datestamp;
643 find_result_t *part_find = NULL; /* List for all part of a DLE */
644 find_result_t *a_part_find;
645 gboolean right_label = FALSE;
646 gboolean found_something = FALSE;
649 regmatch_t pmatch[3];
653 g_return_val_if_fail(output_find != NULL, 0);
654 g_return_val_if_fail(logfile != NULL, 0);
656 datestamp = g_strdup(passed_datestamp);
658 if((logf = fopen(logfile, "r")) == NULL) {
659 error(_("could not open logfile %s: %s"), logfile, strerror(errno));
664 while(get_logline(logf)) {
665 if (curlog == L_START && curprog == P_TAPER) {
666 if(parse_taper_datestamp_log(curstr, &ck_datestamp,
668 g_printf(_("strange log line in %s \"start taper %s\"\n"),
672 if (datestamp != NULL) {
673 if (strcmp(datestamp, ck_datestamp) != 0) {
674 g_printf(_("Log file %s stamped %s, expecting %s!\n"),
675 logfile, ck_datestamp, datestamp);
680 right_label = volume_matches(label, ck_label);
681 if (label && datestamp && right_label) {
682 found_something = TRUE;
684 amfree(current_label);
685 current_label = g_strdup(ck_label);
686 if (datestamp == NULL) {
687 datestamp = g_strdup(ck_datestamp);
693 if ((curlog == L_SUCCESS ||
694 curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTPARTIAL) &&
695 curprog == P_TAPER) {
699 if (curlog == L_SUCCESS || curlog == L_CHUNKSUCCESS ||
700 curlog == L_DONE || curlog == L_FAIL ||
701 curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTIAL ||
702 curlog == L_PARTPARTIAL ) {
706 skip_whitespace(s, ch);
708 g_printf(_("strange log line in %s \"%s\"\n"),
713 if (curlog == L_PART || curlog == L_PARTPARTIAL) {
714 char * part_label = s - 1;
715 skip_non_whitespace(s, ch);
718 if (strcmp(current_label, part_label) != 0) {
719 g_printf("PART label %s doesn't match START label %s\n",
720 part_label, current_label);
723 skip_whitespace(s, ch);
725 g_printf("strange log line in %s \"%s\"\n",
731 skip_non_whitespace(s, ch);
733 fileno = atoi(number);
736 skip_whitespace(s, ch);
738 g_printf("strange log line in %s \"%s\"\n",
745 skip_non_whitespace(s, ch);
749 skip_whitespace(s, ch);
751 g_printf(_("strange log line in %s \"%s\"\n"),
756 skip_quoted_string(s, ch);
759 disk = unquote_string(qdisk);
761 skip_whitespace(s, ch);
763 g_printf(_("strange log line in %s \"%s\"\n"),
768 skip_non_whitespace(s, ch);
772 if(strlen(date) < 3) { /* old log didn't have datestamp */
774 date = stralloc(datestamp);
776 if (curlog == L_CHUNK || curlog == L_PART ||
777 curlog == L_PARTPARTIAL || curlog == L_DONE){
778 skip_whitespace(s, ch);
780 skip_non_whitespace(s, ch);
781 partnum_undo = s - 1;
782 *partnum_undo = '\0';
784 skip_whitespace(s, ch);
785 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
786 g_printf(_("strange log line in %s \"%s\"\n"),
793 skip_whitespace(s, ch);
795 g_printf(_("strange log line in %s \"%s\"\n"),
800 if((s = strchr(s, '\n')) != NULL) {
804 /* extract sec, kb, kps from 'rest', if present. This isn't the stone age
805 * anymore, so we'll just do it the easy way (a regex) */
806 bzero(®ex, sizeof(regex));
807 reg_result = regcomp(®ex,
808 "\\[sec ([0-9.]+) kb ([0-9]+) kps [0-9.]+\\]", REG_EXTENDED);
809 if (reg_result != 0) {
810 error("Error compiling regular expression for parsing log lines");
814 /* an error here just means the line wasn't found -- not fatal. */
815 reg_result = regexec(®ex, rest, sizeof(pmatch)/sizeof(*pmatch), pmatch, 0);
816 if (reg_result == 0) {
819 str = find_regex_substring(rest, pmatch[1]);
823 str = find_regex_substring(rest, pmatch[2]);
824 kb = OFF_T_ATOI(str);
832 dp = lookup_disk(host,disk);
834 if (dynamic_disklist == NULL) {
837 dp = add_disk(dynamic_disklist, host, disk);
838 enqueue_disk(dynamic_disklist, dp);
840 if (find_match(host, disk)) {
841 if(curprog == P_TAPER) {
842 find_result_t *new_output_find = g_new0(find_result_t, 1);
843 new_output_find->timestamp = stralloc(date);
844 new_output_find->hostname=stralloc(host);
845 new_output_find->diskname=stralloc(disk);
846 new_output_find->level=level;
847 new_output_find->partnum = stralloc(partnum);
848 new_output_find->label=stralloc(current_label);
849 new_output_find->status=NULL;
850 new_output_find->filenum=filenum;
851 new_output_find->sec=sec;
852 new_output_find->kb=kb;
853 new_output_find->next=NULL;
854 if (curlog == L_SUCCESS) {
855 new_output_find->status = stralloc("OK");
856 new_output_find->next = *output_find;
857 *output_find = new_output_find;
858 found_something = TRUE;
859 } else if (curlog == L_CHUNKSUCCESS || curlog == L_DONE ||
860 curlog == L_PARTIAL || curlog == L_FAIL) {
862 if (curlog == L_PARTIAL || curlog == L_FAIL) {
863 /* change status of each part */
864 for (a_part_find = part_find; a_part_find;
865 a_part_find = a_part_find->next) {
866 if (curlog == L_PARTIAL)
867 a_part_find->status = stralloc("PARTIAL");
869 a_part_find->status = stralloc(rest);
872 if (part_find) { /* find last element */
873 for (a_part_find = part_find;
874 a_part_find->next != NULL;
875 a_part_find=a_part_find->next) {
877 /* merge part_find to *output_find */
878 a_part_find->next = *output_find;
879 *output_find = part_find;
881 found_something = TRUE;
883 free_find_result(&new_output_find);
884 } else { /* part line */
885 if (curlog == L_PART || curlog == L_CHUNK)
886 new_output_find->status=stralloc("OK");
887 else /* PARTPARTIAL */
888 new_output_find->status=stralloc("PARTIAL");
889 /* Add to part_find list */
890 new_output_find->next = part_find;
891 part_find = new_output_find;
892 found_something = TRUE;
895 else if(curlog == L_FAIL) {
896 /* print other failures too -- this is a hack to ensure that failures which
897 * did not make it to tape are also listed in the output of 'amadmin x find';
898 * users that do not want this information (e.g., Amanda::DB::Catalog) should
899 * filter dumps with a NULL label. */
900 find_result_t *new_output_find = g_new0(find_result_t, 1);
901 new_output_find->next=*output_find;
902 new_output_find->timestamp = stralloc(date);
903 new_output_find->hostname=stralloc(host);
904 new_output_find->diskname=stralloc(disk);
905 new_output_find->level=level;
906 new_output_find->label=NULL;
907 new_output_find->partnum=stralloc(partnum);
908 new_output_find->filenum=0;
909 new_output_find->sec=sec;
910 new_output_find->kb=kb;
911 new_output_find->status=vstralloc(
913 program_str[(int)curprog],
917 *output_find=new_output_find;
918 found_something = TRUE;
925 if (part_find != NULL) {
927 /* parse log file until PARTIAL/DONE/SUCCESS/FAIL from taper */
928 while(get_logline(logf)) {
929 if (curprog == P_TAPER &&
930 (curlog == L_DONE || curlog == L_SUCCESS ||
931 curlog == L_PARTIAL || curlog == L_FAIL)) {
936 for (a_part_find = part_find; a_part_find;
937 a_part_find = a_part_find->next) {
938 if (curlog == L_PARTIAL)
939 a_part_find->status = stralloc("PARTIAL");
940 else if (curlog == L_FAIL)
941 a_part_find->status = stralloc("FAIL");
943 for (a_part_find = part_find;
944 a_part_find->next != NULL;
945 a_part_find=a_part_find->next) {
947 /* merge part_find to *output_find */
948 a_part_find->next = *output_find;
949 *output_find = part_find;
955 amfree(current_label);
957 return found_something;
962 * Return the set of dumps that match *all* of the given patterns (we consider
963 * an empty pattern to match .*, though). If 'ok' is true, will only match
964 * dumps with SUCCESS status.
966 * Returns a newly allocated list of results, where all strings are also newly
967 * allocated. Apparently some part of Amanda leaks under this condition.
971 find_result_t *output_find,
978 find_result_t *cur_result;
979 find_result_t *matches = NULL;
981 for(cur_result=output_find;
983 cur_result=cur_result->next) {
984 char level_str[NUM_STR_SIZE];
985 g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
986 if((!hostname || *hostname == '\0' || match_host(hostname, cur_result->hostname)) &&
987 (!diskname || *diskname == '\0' || match_disk(diskname, cur_result->diskname)) &&
988 (!datestamp || *datestamp== '\0' || match_datestamp(datestamp, cur_result->timestamp)) &&
989 (!level || *level== '\0' || match_level(level, level_str)) &&
990 (!ok || !strcmp(cur_result->status, "OK"))){
992 find_result_t *curmatch = g_new0(find_result_t, 1);
993 memcpy(curmatch, cur_result, SIZEOF(find_result_t));
995 curmatch->timestamp = stralloc(cur_result->timestamp);
996 curmatch->hostname = stralloc(cur_result->hostname);
997 curmatch->diskname = stralloc(cur_result->diskname);
998 curmatch->level = cur_result->level;
999 curmatch->label = cur_result->label? stralloc(cur_result->label) : NULL;
1000 curmatch->filenum = cur_result->filenum;
1001 curmatch->sec = cur_result->sec;
1002 curmatch->kb = cur_result->kb;
1003 curmatch->status = stralloc(cur_result->status);
1004 curmatch->partnum = stralloc(cur_result->partnum);
1006 curmatch->next = matches;
1015 * Return the set of dumps that match one or more of the given dumpspecs,
1016 * If 'ok' is true, only dumps with a SUCCESS status will be matched.
1018 * Returns a newly allocated list of results, where all strings are also newly
1019 * allocated. Apparently some part of Amanda leaks under this condition.
1022 dumps_match_dumpspecs(
1023 find_result_t *output_find,
1027 find_result_t *cur_result;
1028 find_result_t *matches = NULL;
1032 for(cur_result=output_find;
1034 cur_result=cur_result->next) {
1035 char level_str[NUM_STR_SIZE];
1036 g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
1037 for (dumpspec = dumpspecs; dumpspec; dumpspec = dumpspec->next) {
1038 ds = (dumpspec_t *)dumpspec->data;
1039 if((!ds->host || *ds->host == '\0' || match_host(ds->host, cur_result->hostname)) &&
1040 (!ds->disk || *ds->disk == '\0' || match_disk(ds->disk, cur_result->diskname)) &&
1041 (!ds->datestamp || *ds->datestamp== '\0' || match_datestamp(ds->datestamp, cur_result->timestamp)) &&
1042 (!ds->level || *ds->level== '\0' || match_level(ds->level, level_str)) &&
1043 (!ok || !strcmp(cur_result->status, "OK"))){
1045 find_result_t *curmatch = alloc(SIZEOF(find_result_t));
1046 memcpy(curmatch, cur_result, SIZEOF(find_result_t));
1048 curmatch->timestamp = stralloc(cur_result->timestamp);
1049 curmatch->hostname = stralloc(cur_result->hostname);
1050 curmatch->diskname = stralloc(cur_result->diskname);
1051 curmatch->level = cur_result->level;
1052 curmatch->label = cur_result->label? stralloc(cur_result->label) : NULL;
1053 curmatch->filenum = cur_result->filenum;
1054 curmatch->status = stralloc(cur_result->status);
1055 curmatch->partnum = stralloc(cur_result->partnum);
1057 curmatch->next = matches;
1069 find_result_t *output_find,
1075 find_result_t *output_find_result;
1077 for(output_find_result=output_find;
1079 output_find_result=output_find_result->next) {
1080 if( !strcmp(output_find_result->hostname, hostname) &&
1081 !strcmp(output_find_result->diskname, diskname) &&
1082 !strcmp(output_find_result->timestamp, datestamp) &&
1083 output_find_result->level == level) {
1085 return output_find_result;