2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Author: James da Silva, Systems Design and Analysis Group
25 * Computer Science Department
26 * University of Maryland at College Park
29 * $Id: find.c,v 1.33 2006/07/06 13:13:15 martinea Exp $
31 * controlling process for the Amanda backup system
43 int find_match(char *host, char *disk);
44 static char *find_nicedate(char *datestamp);
45 static int len_find_nicedate(char *datestamp);
46 static int find_compare(const void *, const void *);
47 static int parse_taper_datestamp_log(char *logline, char **datestamp, char **level);
48 static gboolean logfile_has_tape(char * label, char * datestamp,
51 static char *find_sort_order = NULL;
52 static GStringChunk *string_chunk = NULL;
54 find_result_t * find_dump(disklist_t* diskqp) {
55 char *conf_logdir, *logfile = NULL;
56 int tape, tape1, maxtape, logs;
59 find_result_t *output_find = NULL;
60 gboolean *tape_seen = NULL;
62 if (string_chunk == NULL) {
63 string_chunk = g_string_chunk_new(32768);
65 conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
66 maxtape = lookup_nb_tape();
67 tape_seen = g_new0(gboolean, maxtape+1);
69 for(tape = 1; tape <= maxtape; tape++) {
71 if (tape_seen[tape] == 1)
73 tp = lookup_tapepos(tape);
74 if(tp == NULL) continue;
76 /* find all tape with the same datestamp */
77 for (tape1 = tape; tape1 <= maxtape; tape1++) {
78 tp1 = lookup_tapepos(tape1);
79 if (tp1 == NULL) continue;
80 if (strcmp(tp->datestamp, tp1->datestamp) != 0)
86 /* search log files */
90 /* new-style log.<date>.<seq> */
92 for(seq = 0; 1; seq++) {
93 char seq_str[NUM_STR_SIZE];
95 g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
96 logfile = newvstralloc(logfile,
97 conf_logdir, "/log.", tp->datestamp, ".", seq_str, NULL);
98 if(access(logfile, R_OK) != 0) break;
99 if (search_logfile(&output_find, NULL, tp->datestamp,
105 /* search old-style amflush log, if any */
107 logfile = newvstralloc(logfile, conf_logdir, "/log.",
108 tp->datestamp, ".amflush", NULL);
109 if(access(logfile,R_OK) == 0) {
110 if (search_logfile(&output_find, NULL, tp->datestamp,
116 /* search old-style main log, if any */
118 logfile = newvstralloc(logfile, conf_logdir, "/log.", tp->datestamp,
120 if(access(logfile,R_OK) == 0) {
121 if (search_logfile(&output_find, NULL, tp->datestamp,
131 search_holding_disk(&output_find, diskqp);
139 char *conf_logdir, *logfile = NULL;
140 char *pathlogfile = NULL;
141 int tape, maxtape, logs;
144 char **output_find_log = NULL;
147 conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
148 maxtape = lookup_nb_tape();
150 output_find_log = alloc((maxtape*5+10) * SIZEOF(char *));
151 current_log = output_find_log;
153 for(tape = 1; tape <= maxtape; tape++) {
155 tp = lookup_tapepos(tape);
156 if(tp == NULL) continue;
158 /* search log files */
162 /* new-style log.<date>.<seq> */
164 for(seq = 0; 1; seq++) {
165 char seq_str[NUM_STR_SIZE];
167 g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
168 logfile = newvstralloc(logfile, "log.", tp->datestamp, ".", seq_str, NULL);
169 pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
170 if (access(pathlogfile, R_OK) != 0) break;
171 if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
172 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
173 *current_log = stralloc(logfile);
181 /* search old-style amflush log, if any */
183 logfile = newvstralloc(logfile, "log.", tp->datestamp, ".amflush", NULL);
184 pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
185 if (access(pathlogfile, R_OK) == 0) {
186 if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
187 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
188 *current_log = stralloc(logfile);
195 /* search old-style main log, if any */
197 logfile = newvstralloc(logfile, "log.", tp->datestamp, NULL);
198 pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
199 if (access(pathlogfile, R_OK) == 0) {
200 if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
201 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
202 *current_log = stralloc(logfile);
209 if(logs == 0 && strcmp(tp->datestamp,"0") != 0)
210 g_fprintf(stderr, _("Warning: no log files found for tape %s written %s\n"),
211 tp->label, find_nicedate(tp->datestamp));
217 return(output_find_log);
222 find_result_t **output_find,
223 disklist_t * dynamic_disklist)
225 GSList *holding_file_list;
231 holding_file_list = holding_get_files(NULL, 1);
233 if (string_chunk == NULL) {
234 string_chunk = g_string_chunk_new(32768);
237 for(e = holding_file_list; e != NULL; e = e->next) {
240 holding_file = (char *)e->data;
242 if (!holding_file_get_dumpfile(holding_file, &file))
245 if (file.dumplevel < 0 || file.dumplevel >= DUMP_LEVELS) {
246 dumpfile_free_data(&file);
251 orig_name = g_strdup(file.name);
254 if((dp = lookup_disk(file.name, file.disk)))
256 if((s = strrchr(file.name,'.')) == NULL)
260 strcpy(file.name, orig_name); /* restore munged string */
264 if (dynamic_disklist == NULL) {
265 dumpfile_free_data(&file);
268 dp = add_disk(dynamic_disklist, file.name, file.disk);
269 enqueue_disk(dynamic_disklist, dp);
272 if(find_match(file.name,file.disk)) {
273 find_result_t *new_output_find = g_new0(find_result_t, 1);
274 new_output_find->next=*output_find;
275 new_output_find->timestamp = g_string_chunk_insert_const(string_chunk, file.datestamp);
276 new_output_find->write_timestamp = g_string_chunk_insert_const(string_chunk, "00000000000000");
277 new_output_find->hostname = g_string_chunk_insert_const(string_chunk, file.name);
278 new_output_find->diskname = g_string_chunk_insert_const(string_chunk, file.disk);
279 new_output_find->level=file.dumplevel;
280 new_output_find->label=g_string_chunk_insert_const(string_chunk, holding_file);
281 new_output_find->partnum = -1;
282 new_output_find->totalparts = -1;
283 new_output_find->filenum=0;
284 if (file.is_partial) {
285 new_output_find->status="PARTIAL";
286 new_output_find->dump_status="PARTIAL";
288 new_output_find->status="OK";
289 new_output_find->dump_status="OK";
291 new_output_find->message="";
292 new_output_find->kb = holding_file_size(holding_file, 1);
293 new_output_find->bytes = 0;
295 new_output_find->orig_kb = file.orig_size;
297 *output_find=new_output_find;
299 dumpfile_free_data(&file);
302 slist_free_full(holding_file_list, g_free);
311 find_result_t *i, *j;
313 size_t nb_compare=strlen(find_sort_order);
316 for(k=0;k<nb_compare;k++) {
317 char sort_key = find_sort_order[k];
318 if (isupper((int)sort_key)) {
320 sort_key = tolower(sort_key);
321 j = *(find_result_t **)i1;
322 i = *(find_result_t **)j1;
324 i = *(find_result_t **)i1;
325 j = *(find_result_t **)j1;
329 case 'h' : compare=strcmp(i->hostname,j->hostname);
331 case 'k' : compare=strcmp(i->diskname,j->diskname);
333 case 'd' : compare=strcmp(i->timestamp,j->timestamp);
335 case 'l' : compare=j->level - i->level;
337 case 'f' : compare=(i->filenum == j->filenum) ? 0 :
338 ((i->filenum < j->filenum) ? -1 : 1);
340 case 'b' : compare=compare_possibly_null_strings(i->label,
343 case 'w': compare=strcmp(i->write_timestamp, j->write_timestamp);
346 compare=i->partnum - j->partnum;
358 find_result_t **output_find)
360 find_result_t *output_find_result;
361 find_result_t **array_find_result = NULL;
365 find_sort_order = sort_order;
366 /* qsort core dump if nothing to sort */
367 if(*output_find==NULL)
370 /* How many result */
371 for(output_find_result=*output_find;
373 output_find_result=output_find_result->next) {
377 /* put the list in an array */
378 array_find_result=alloc(nb_result * SIZEOF(find_result_t *));
379 for(output_find_result=*output_find,no_result=0;
381 output_find_result=output_find_result->next,no_result++) {
382 array_find_result[no_result]=output_find_result;
386 qsort(array_find_result,nb_result,SIZEOF(find_result_t *),
389 /* put the sorted result in the list */
391 no_result<nb_result-1; no_result++) {
392 array_find_result[no_result]->next = array_find_result[no_result+1];
394 array_find_result[nb_result-1]->next=NULL;
395 *output_find=array_find_result[0];
396 amfree(array_find_result);
401 find_result_t *output_find)
403 find_result_t *output_find_result;
404 int max_len_datestamp = 4;
405 int max_len_hostname = 4;
406 int max_len_diskname = 4;
407 int max_len_level = 2;
408 int max_len_label =12;
409 int max_len_filenum = 4;
410 int max_len_part = 4;
411 int max_len_status = 6;
414 for(output_find_result=output_find;
416 output_find_result=output_find_result->next) {
419 len=len_find_nicedate(output_find_result->timestamp);
420 if((int)len > max_len_datestamp)
421 max_len_datestamp=(int)len;
423 len=strlen(output_find_result->hostname);
424 if((int)len > max_len_hostname)
425 max_len_hostname = (int)len;
427 len = len_quote_string(output_find_result->diskname);
428 if((int)len > max_len_diskname)
429 max_len_diskname = (int)len;
431 if (output_find_result->label != NULL) {
432 len = len_quote_string(output_find_result->label);
433 if((int)len > max_len_label)
434 max_len_label = (int)len;
437 len=strlen(output_find_result->status) + 1 + strlen(output_find_result->dump_status);
438 if((int)len > max_len_status)
439 max_len_status = (int)len;
441 s = g_strdup_printf("%d/%d", output_find_result->partnum,
442 output_find_result->totalparts);
444 if((int)len > max_len_part)
445 max_len_part = (int)len;
450 * Since status is the rightmost field, we zap the maximum length
451 * because it is not needed. The code is left in place in case
452 * another column is added later.
456 if(output_find==NULL) {
457 g_printf(_("\nNo dump to list\n"));
460 g_printf(_("\ndate%*s host%*s disk%*s lv%*s tape or file%*s file%*s part%*s status\n"),
461 max_len_datestamp-4,"",
462 max_len_hostname-4 ,"",
463 max_len_diskname-4 ,"",
465 max_len_label-12 ,"",
466 max_len_filenum-4 ,"",
468 for(output_find_result=output_find;
470 output_find_result=output_find_result->next) {
472 char * formatted_label;
476 qdiskname = quote_string(output_find_result->diskname);
477 if (output_find_result->label == NULL)
478 formatted_label = stralloc("");
480 formatted_label = quote_string(output_find_result->label);
482 if (strcmp(output_find_result->status, "OK") != 0 ||
483 strcmp(output_find_result->dump_status, "OK") != 0) {
484 status = vstralloc(output_find_result->status, " ",
485 output_find_result->dump_status, NULL);
487 status = stralloc(output_find_result->status);
491 /* sec and kb are omitted here, for compatibility with the existing
492 * output from 'amadmin' */
493 s = g_strdup_printf("%d/%d", output_find_result->partnum,
494 output_find_result->totalparts);
495 g_printf("%-*s %-*s %-*s %*d %-*s %*lld %*s %s %s\n",
497 find_nicedate(output_find_result->timestamp),
498 max_len_hostname, output_find_result->hostname,
499 max_len_diskname, qdiskname,
500 max_len_level, output_find_result->level,
501 max_len_label, formatted_label,
502 max_len_filenum, (long long)output_find_result->filenum,
505 output_find_result->message
511 amfree(formatted_label);
518 find_result_t **output_find)
520 find_result_t *output_find_result, *prev;
523 for(output_find_result=*output_find;
525 output_find_result=output_find_result->next) {
527 prev = output_find_result;
538 disk_t *dp = lookup_disk(host,disk);
539 return (dp && dp->todo);
546 static char nice[20];
547 int year, month, day;
548 int hours, minutes, seconds;
549 char date[9], atime[7];
550 int numdate, numtime;
552 strncpy(date, datestamp, 8);
554 numdate = atoi(date);
555 year = numdate / 10000;
556 month = (numdate / 100) % 100;
559 if(strlen(datestamp) <= 8) {
560 g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d",
564 strncpy(atime, &(datestamp[8]), 6);
566 numtime = atoi(atime);
567 hours = numtime / 10000;
568 minutes = (numtime / 100) % 100;
569 seconds = numtime % 100;
571 g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d %02d:%02d:%02d",
572 year, month, day, hours, minutes, seconds);
582 if(strlen(datestamp) <= 8) {
590 parse_taper_datestamp_log(
601 skip_whitespace(s, ch);
605 if(strncmp_const_skip(s - 1, "datestamp", s, ch) != 0) {
609 skip_whitespace(s, ch);
614 skip_non_whitespace(s, ch);
617 skip_whitespace(s, ch);
621 if(strncmp_const_skip(s - 1, "label", s, ch) != 0) {
625 skip_whitespace(s, ch);
630 skip_quoted_string(s, ch);
633 *label = unquote_string(*label);
637 /* Returns TRUE if the given logfile mentions the given tape. */
638 static gboolean logfile_has_tape(char * label, char * datestamp,
641 char * ck_datestamp, *ck_label = NULL;
642 if((logf = fopen(logfile, "r")) == NULL) {
643 error(_("could not open logfile %s: %s"), logfile, strerror(errno));
647 while(get_logline(logf)) {
648 if(curlog == L_START && curprog == P_TAPER) {
649 if(parse_taper_datestamp_log(curstr,
650 &ck_datestamp, &ck_label) == 0) {
651 g_printf(_("strange log line \"start taper %s\" curstr='%s'\n"),
653 } else if(strcmp(ck_datestamp, datestamp) == 0
654 && strcmp(ck_label, label) == 0) {
671 const char *datestamp)
679 return (strcmp(label1, label2) == 0);
681 /* check in tapelist */
682 if (!(tp = lookup_tapelabel(label2)))
685 if (strcmp(tp->datestamp, datestamp) != 0)
691 /* WARNING: Function accesses globals find_diskqp, curlog, curlog, curstr,
692 * dynamic_disklist */
695 find_result_t **output_find,
697 const char *passed_datestamp,
699 disklist_t * dynamic_disklist)
702 char *host, *host_undo;
703 char *disk, *qdisk, *disk_undo;
704 char *date, *date_undo;
710 char *current_label = stralloc("");
711 char *rest, *rest_undo;
715 char *ck_datestamp=NULL;
720 GHashTable* valid_label;
721 GHashTable* part_by_dle;
722 find_result_t *part_find;
723 find_result_t *a_part_find;
724 gboolean right_label = FALSE;
725 gboolean found_something = FALSE;
732 g_return_val_if_fail(output_find != NULL, 0);
733 g_return_val_if_fail(logfile != NULL, 0);
735 if (string_chunk == NULL) {
736 string_chunk = g_string_chunk_new(32768);
738 valid_label = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
739 part_by_dle = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
740 datestamp = g_strdup(passed_datestamp);
742 if((logf = fopen(logfile, "r")) == NULL) {
743 error(_("could not open logfile %s: %s"), logfile, strerror(errno));
748 while(get_logline(logf)) {
749 if (curlog == L_START && curprog == P_TAPER) {
752 if(parse_taper_datestamp_log(curstr, &ck_datestamp,
754 g_printf(_("strange log line in %s \"start taper %s\"\n"),
758 if (datestamp != NULL) {
759 if (strcmp(datestamp, ck_datestamp) != 0) {
760 g_printf(_("Log file %s stamped %s, expecting %s!\n"),
761 logfile, ck_datestamp, datestamp);
767 right_label = volume_matches(label, ck_label, ck_datestamp);
768 if (right_label && ck_label) {
769 g_hash_table_insert(valid_label, g_strdup(ck_label),
772 if (label && datestamp && right_label) {
773 found_something = TRUE;
775 amfree(current_label);
776 current_label = ck_label;
778 if (datestamp == NULL) {
779 datestamp = g_strdup(ck_datestamp);
786 (curlog == L_SUCCESS ||
787 curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTPARTIAL) &&
788 curprog == P_TAPER) {
790 } else if (right_label && curlog == L_PARTIAL && curprog == P_TAPER &&
796 if (curlog == L_SUCCESS || curlog == L_CHUNKSUCCESS ||
797 curlog == L_DONE || curlog == L_FAIL ||
798 curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTIAL ||
799 curlog == L_PARTPARTIAL ) {
803 skip_whitespace(s, ch);
805 g_printf(_("strange log line in %s \"%s\"\n"),
810 if (curlog == L_PART || curlog == L_PARTPARTIAL) {
812 char *qpart_label = s - 1;
814 skip_quoted_string(s, ch);
817 part_label = unquote_string(qpart_label);
818 if (!g_hash_table_lookup(valid_label, part_label)) {
822 amfree(current_label);
823 current_label = part_label;
825 skip_whitespace(s, ch);
827 g_printf("strange log line in %s \"%s\"\n",
833 skip_non_whitespace(s, ch);
835 fileno = atoi(number);
840 skip_whitespace(s, ch);
842 g_printf("strange log line in %s \"%s\"\n",
851 skip_non_whitespace(s, ch);
855 skip_whitespace(s, ch);
857 g_printf(_("strange log line in %s \"%s\"\n"),
862 skip_quoted_string(s, ch);
865 disk = unquote_string(qdisk);
867 skip_whitespace(s, ch);
869 g_printf(_("strange log line in %s \"%s\"\n"),
874 skip_non_whitespace(s, ch);
878 if(strlen(date) < 3) { /* old log didn't have datestamp */
880 date = stralloc(datestamp);
884 if (curprog == P_TAPER &&
885 (curlog == L_CHUNK || curlog == L_PART ||
886 curlog == L_PARTPARTIAL || curlog == L_PARTIAL ||
889 skip_whitespace(s, ch);
891 skip_non_whitespace(s, ch);
894 skip_whitespace(s, ch);
897 sscanf(number, "%d/%d", &partnum, &totalparts);
898 if (partnum > maxparts)
900 if (totalparts > maxparts)
901 maxparts = totalparts;
902 } else { /* nparts is not in all PARTIAL lines */
908 skip_whitespace(s, ch);
910 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
911 g_printf(_("Fstrange log line in %s \"%s\"\n"),
918 skip_whitespace(s, ch);
920 g_printf(_("strange log line in %s \"%s\"\n"),
925 skip_non_whitespace(s, ch);
928 if (strcmp(rest, "[sec") == 0) {
929 skip_whitespace(s, ch);
931 g_printf(_("strange log line in %s \"%s\"\n"),
936 skip_non_whitespace(s, ch);
937 skip_whitespace(s, ch);
939 skip_non_whitespace(s, ch);
942 if (strcmp(rest, "kb") != 0 &&
943 strcmp(rest, "bytes") != 0) {
944 g_printf(_("Bstrange log line in %s \"%s\"\n"),
949 skip_whitespace(s, ch);
951 g_printf(_("strange log line in %s \"%s\"\n"),
955 if (strcmp(rest, "kb") == 0) {
962 skip_non_whitespace(s, ch);
963 skip_whitespace(s, ch);
965 skip_non_whitespace(s, ch);
968 if (strcmp(rest, "kps") != 0) {
969 g_printf(_("Cstrange log line in %s \"%s\"\n"),
974 skip_whitespace(s, ch);
976 g_printf(_("strange log line in %s \"%s\"\n"),
980 /* kps = atof(s - 1); */
981 skip_non_whitespace(s, ch);
982 skip_whitespace(s, ch);
984 skip_non_whitespace(s, ch);
987 if (strcmp(rest, "orig-kb") != 0) {
991 skip_whitespace(s, ch);
993 g_printf(_("strange log line in %s \"%s\"\n"),
997 orig_kb = atof(s - 1);
1007 if (strncmp(rest, "error", 5) == 0) rest += 6;
1008 if (strncmp(rest, "config", 6) == 0) rest += 7;
1010 dp = lookup_disk(host,disk);
1012 if (dynamic_disklist == NULL) {
1015 dp = add_disk(dynamic_disklist, host, disk);
1016 enqueue_disk(dynamic_disklist, dp);
1018 if (find_match(host, disk)) {
1019 if(curprog == P_TAPER) {
1020 char *key = g_strdup_printf(
1021 "HOST:%s DISK:%s: DATE:%s LEVEL:%d",
1022 host, disk, date, level);
1023 find_result_t *new_output_find = g_new0(find_result_t, 1);
1024 part_find = g_hash_table_lookup(part_by_dle, key);
1026 if (maxparts < totalparts)
1027 maxparts = totalparts;
1028 for (a_part_find = part_find;
1030 a_part_find = a_part_find->next) {
1031 if (maxparts < a_part_find->partnum)
1032 maxparts = a_part_find->partnum;
1033 if (maxparts < a_part_find->totalparts)
1034 maxparts = a_part_find->totalparts;
1036 new_output_find->timestamp = g_string_chunk_insert_const(string_chunk, date);
1037 new_output_find->write_timestamp = g_string_chunk_insert_const(string_chunk, datestamp);
1038 new_output_find->hostname=g_string_chunk_insert_const(string_chunk, host);
1039 new_output_find->diskname=g_string_chunk_insert_const(string_chunk, disk);
1040 new_output_find->level=level;
1041 new_output_find->partnum = partnum;
1042 new_output_find->totalparts = totalparts;
1043 new_output_find->label=g_string_chunk_insert_const(string_chunk, current_label);
1044 new_output_find->status=NULL;
1045 new_output_find->dump_status=NULL;
1046 new_output_find->message="";
1047 new_output_find->filenum=filenum;
1048 new_output_find->sec=sec;
1049 new_output_find->kb=kb;
1050 new_output_find->bytes=bytes;
1051 new_output_find->orig_kb=orig_kb;
1052 new_output_find->next=NULL;
1053 if (curlog == L_SUCCESS) {
1054 new_output_find->status = "OK";
1055 new_output_find->dump_status = "OK";
1056 new_output_find->next = *output_find;
1057 new_output_find->partnum = 1; /* L_SUCCESS is pre-splitting */
1058 *output_find = new_output_find;
1059 found_something = TRUE;
1060 } else if (curlog == L_CHUNKSUCCESS || curlog == L_DONE ||
1061 curlog == L_PARTIAL || curlog == L_FAIL) {
1063 if (curlog == L_PARTIAL || curlog == L_FAIL) {
1064 /* set dump_status of each part */
1065 for (a_part_find = part_find;
1067 a_part_find = a_part_find->next) {
1068 if (curlog == L_PARTIAL)
1069 a_part_find->dump_status = "PARTIAL";
1071 a_part_find->dump_status = "FAIL";
1072 a_part_find->message = g_string_chunk_insert_const(string_chunk, rest);
1076 if (maxparts > -1) { /* format with part */
1077 /* must check if all part are there */
1078 int num_part = maxparts;
1079 for (a_part_find = part_find;
1081 a_part_find = a_part_find->next) {
1082 if (a_part_find->partnum == num_part &&
1083 strcmp(a_part_find->status, "OK") == 0)
1086 /* set dump_status of each part */
1087 for (a_part_find = part_find;
1089 a_part_find = a_part_find->next) {
1090 if (num_part == 0) {
1091 a_part_find->dump_status = "OK";
1093 a_part_find->dump_status = "FAIL";
1094 a_part_find->message =
1095 g_string_chunk_insert_const(string_chunk, "Missing part");
1100 if (curlog == L_DONE) {
1101 for (a_part_find = part_find;
1103 a_part_find = a_part_find->next) {
1104 if (a_part_find->totalparts == -1) {
1105 a_part_find->totalparts = maxparts;
1107 if (a_part_find->orig_kb == 0) {
1108 a_part_find->orig_kb = orig_kb;
1112 if (part_find) { /* find last element */
1113 for (a_part_find = part_find;
1114 a_part_find->next != NULL;
1115 a_part_find=a_part_find->next) {
1117 /* merge part_find to *output_find */
1118 a_part_find->next = *output_find;
1119 *output_find = part_find;
1122 found_something = TRUE;
1123 g_hash_table_remove(part_by_dle, key);
1125 free_find_result(&new_output_find);
1126 } else { /* part line */
1127 if (curlog == L_PART || curlog == L_CHUNK) {
1128 new_output_find->status = "OK";
1129 new_output_find->dump_status = "OK";
1130 } else { /* PARTPARTIAL */
1131 new_output_find->status = "PARTIAL";
1132 new_output_find->dump_status = "PARTIAL";
1134 /* Add to part_find list */
1136 new_output_find->next = part_find;
1137 part_find = new_output_find;
1139 new_output_find->next = NULL;
1140 part_find = new_output_find;
1142 g_hash_table_insert(part_by_dle, g_strdup(key),
1144 found_something = TRUE;
1148 else if(curlog == L_FAIL) {
1149 char *status_failed;
1150 /* print other failures too -- this is a hack to ensure that failures which
1151 * did not make it to tape are also listed in the output of 'amadmin x find';
1152 * users that do not want this information (e.g., Amanda::DB::Catalog) should
1153 * filter dumps with a NULL label. */
1154 find_result_t *new_output_find = g_new0(find_result_t, 1);
1155 new_output_find->next = *output_find;
1156 new_output_find->timestamp = g_string_chunk_insert_const(string_chunk, date);
1157 new_output_find->write_timestamp = g_strdup("00000000000000"); /* dump was not written.. */
1158 new_output_find->hostname=g_string_chunk_insert_const(string_chunk, host);
1159 new_output_find->diskname=g_string_chunk_insert_const(string_chunk, disk);
1160 new_output_find->level=level;
1161 new_output_find->label=NULL;
1162 new_output_find->partnum=partnum;
1163 new_output_find->totalparts=totalparts;
1164 new_output_find->filenum=0;
1165 new_output_find->sec=sec;
1166 new_output_find->kb=kb;
1167 new_output_find->bytes=bytes;
1168 new_output_find->orig_kb=orig_kb;
1169 status_failed = vstralloc(
1171 program_str[(int)curprog],
1175 new_output_find->status = g_string_chunk_insert_const(string_chunk, status_failed);
1176 amfree(status_failed);
1177 new_output_find->dump_status="";
1178 new_output_find->message="";
1179 *output_find=new_output_find;
1180 found_something = TRUE;
1188 g_hash_table_destroy(valid_label);
1191 amfree(current_label);
1193 return found_something;
1198 * Return the set of dumps that match *all* of the given patterns (we consider
1199 * an empty pattern to match .*, though). If 'ok' is true, will only match
1200 * dumps with SUCCESS status.
1202 * Returns a newly allocated list of results, where all strings are also newly
1203 * allocated. Apparently some part of Amanda leaks under this condition.
1207 find_result_t *output_find,
1214 find_result_t *cur_result;
1215 find_result_t *matches = NULL;
1217 for(cur_result=output_find;
1219 cur_result=cur_result->next) {
1220 char level_str[NUM_STR_SIZE];
1221 g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
1222 if((!hostname || *hostname == '\0' || match_host(hostname, cur_result->hostname)) &&
1223 (!diskname || *diskname == '\0' || match_disk(diskname, cur_result->diskname)) &&
1224 (!datestamp || *datestamp== '\0' || match_datestamp(datestamp, cur_result->timestamp)) &&
1225 (!level || *level== '\0' || match_level(level, level_str)) &&
1226 (!ok || !strcmp(cur_result->status, "OK")) &&
1227 (!ok || !strcmp(cur_result->dump_status, "OK"))){
1229 find_result_t *curmatch = g_new0(find_result_t, 1);
1230 memcpy(curmatch, cur_result, SIZEOF(find_result_t));
1232 curmatch->timestamp = cur_result->timestamp;
1233 curmatch->write_timestamp = cur_result->write_timestamp;
1234 curmatch->hostname = cur_result->hostname;
1235 curmatch->diskname = cur_result->diskname;
1236 curmatch->level = cur_result->level;
1237 curmatch->label = cur_result->label? cur_result->label : NULL;
1238 curmatch->filenum = cur_result->filenum;
1239 curmatch->sec = cur_result->sec;
1240 curmatch->kb = cur_result->kb;
1241 curmatch->bytes = cur_result->bytes;
1242 curmatch->orig_kb = cur_result->orig_kb;
1243 curmatch->status = cur_result->status;
1244 curmatch->dump_status = cur_result->dump_status;
1245 curmatch->message = cur_result->message;
1246 curmatch->partnum = cur_result->partnum;
1247 curmatch->totalparts = cur_result->totalparts;
1248 curmatch->next = matches;
1257 * Return the set of dumps that match one or more of the given dumpspecs,
1258 * If 'ok' is true, only dumps with a SUCCESS status will be matched.
1260 * Returns a newly allocated list of results, where all strings are also newly
1261 * allocated. Apparently some part of Amanda leaks under this condition.
1264 dumps_match_dumpspecs(
1265 find_result_t *output_find,
1269 find_result_t *cur_result;
1270 find_result_t *matches = NULL;
1274 for(cur_result=output_find;
1276 cur_result=cur_result->next) {
1277 char level_str[NUM_STR_SIZE];
1278 char *zeropad_ts = NULL;
1279 char *zeropad_w_ts = NULL;
1280 g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
1282 /* get the timestamp padded to full width */
1283 if (strlen(cur_result->timestamp) < 14) {
1284 zeropad_ts = g_new0(char, 15);
1285 memset(zeropad_ts, '0', 14);
1286 memcpy(zeropad_ts, cur_result->timestamp, strlen(cur_result->timestamp));
1288 if (strlen(cur_result->write_timestamp) < 14) {
1289 zeropad_w_ts = g_new0(char, 15);
1290 memset(zeropad_w_ts, '0', 14);
1291 memcpy(zeropad_w_ts, cur_result->write_timestamp, strlen(cur_result->write_timestamp));
1294 for (dumpspec = dumpspecs; dumpspec; dumpspec = dumpspec->next) {
1295 ds = (dumpspec_t *)dumpspec->data;
1296 if((!ds->host || *ds->host == '\0' || match_host(ds->host, cur_result->hostname)) &&
1297 (!ds->disk || *ds->disk == '\0' || match_disk(ds->disk, cur_result->diskname)) &&
1298 (!ds->datestamp || *ds->datestamp== '\0'
1299 || match_datestamp(ds->datestamp, cur_result->timestamp)
1300 || (zeropad_ts && match_datestamp(ds->datestamp, zeropad_ts))) &&
1301 (!ds->write_timestamp || *ds->write_timestamp== '\0'
1302 || match_datestamp(ds->write_timestamp, cur_result->write_timestamp)
1303 || (zeropad_w_ts && match_datestamp(ds->write_timestamp, zeropad_w_ts))) &&
1304 (!ds->level || *ds->level== '\0' || match_level(ds->level, level_str)) &&
1305 (!ok || !strcmp(cur_result->status, "OK")) &&
1306 (!ok || !strcmp(cur_result->dump_status, "OK"))) {
1308 find_result_t *curmatch = alloc(SIZEOF(find_result_t));
1309 memcpy(curmatch, cur_result, SIZEOF(find_result_t));
1311 curmatch->timestamp = cur_result->timestamp;
1312 curmatch->write_timestamp = cur_result->write_timestamp;
1313 curmatch->hostname = cur_result->hostname;
1314 curmatch->diskname = cur_result->diskname;
1315 curmatch->level = cur_result->level;
1316 curmatch->label = cur_result->label? cur_result->label : NULL;
1317 curmatch->filenum = cur_result->filenum;
1318 curmatch->status = cur_result->status;
1319 curmatch->dump_status = cur_result->dump_status;
1320 curmatch->message = cur_result->message;
1321 curmatch->partnum = cur_result->partnum;
1322 curmatch->totalparts = cur_result->totalparts;
1324 curmatch->next = matches;
1338 find_result_t *output_find,
1344 find_result_t *output_find_result;
1346 for(output_find_result=output_find;
1348 output_find_result=output_find_result->next) {
1349 if( !strcmp(output_find_result->hostname, hostname) &&
1350 !strcmp(output_find_result->diskname, diskname) &&
1351 !strcmp(output_find_result->timestamp, datestamp) &&
1352 output_find_result->level == level) {
1354 return output_find_result;