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
42 int find_match(char *host, char *disk);
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, tape1, maxtape, logs;
56 find_result_t *output_find = NULL;
57 gboolean *tape_seen = NULL;
59 conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
60 maxtape = lookup_nb_tape();
61 tape_seen = g_new0(gboolean, maxtape+1);
63 for(tape = 1; tape <= maxtape; tape++) {
65 if (tape_seen[tape] == 1)
67 tp = lookup_tapepos(tape);
68 if(tp == NULL) continue;
70 /* find all tape with the same datestamp */
71 for (tape1 = tape; tape1 <= maxtape; tape1++) {
72 tp1 = lookup_tapepos(tape1);
73 if (tp1 == NULL) continue;
74 if (strcmp(tp->datestamp, tp1->datestamp) != 0)
80 /* search log files */
84 /* new-style log.<date>.<seq> */
86 for(seq = 0; 1; seq++) {
87 char seq_str[NUM_STR_SIZE];
89 g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
90 logfile = newvstralloc(logfile,
91 conf_logdir, "/log.", tp->datestamp, ".", seq_str, NULL);
92 if(access(logfile, R_OK) != 0) break;
93 if (search_logfile(&output_find, NULL, tp->datestamp,
99 /* search old-style amflush log, if any */
101 logfile = newvstralloc(logfile, conf_logdir, "/log.",
102 tp->datestamp, ".amflush", NULL);
103 if(access(logfile,R_OK) == 0) {
104 if (search_logfile(&output_find, NULL, tp->datestamp,
110 /* search old-style main log, if any */
112 logfile = newvstralloc(logfile, conf_logdir, "/log.", tp->datestamp,
114 if(access(logfile,R_OK) == 0) {
115 if (search_logfile(&output_find, NULL, tp->datestamp,
125 search_holding_disk(&output_find, diskqp);
133 char *conf_logdir, *logfile = NULL;
134 char *pathlogfile = NULL;
135 int tape, maxtape, logs;
138 char **output_find_log = NULL;
141 conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
142 maxtape = lookup_nb_tape();
144 output_find_log = alloc((maxtape*5+10) * SIZEOF(char *));
145 current_log = output_find_log;
147 for(tape = 1; tape <= maxtape; tape++) {
149 tp = lookup_tapepos(tape);
150 if(tp == NULL) continue;
152 /* search log files */
156 /* new-style log.<date>.<seq> */
158 for(seq = 0; 1; seq++) {
159 char seq_str[NUM_STR_SIZE];
161 g_snprintf(seq_str, SIZEOF(seq_str), "%u", seq);
162 logfile = newvstralloc(logfile, "log.", tp->datestamp, ".", seq_str, NULL);
163 pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
164 if (access(pathlogfile, R_OK) != 0) break;
165 if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
166 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
167 *current_log = stralloc(logfile);
175 /* search old-style amflush log, if any */
177 logfile = newvstralloc(logfile, "log.", tp->datestamp, ".amflush", NULL);
178 pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
179 if (access(pathlogfile, R_OK) == 0) {
180 if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
181 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
182 *current_log = stralloc(logfile);
189 /* search old-style main log, if any */
191 logfile = newvstralloc(logfile, "log.", tp->datestamp, NULL);
192 pathlogfile = newvstralloc(pathlogfile, conf_logdir, "/", logfile, NULL);
193 if (access(pathlogfile, R_OK) == 0) {
194 if (logfile_has_tape(tp->label, tp->datestamp, pathlogfile)) {
195 if (current_log == output_find_log || strcmp(*(current_log-1), logfile)) {
196 *current_log = stralloc(logfile);
203 if(logs == 0 && strcmp(tp->datestamp,"0") != 0)
204 g_fprintf(stderr, _("Warning: no log files found for tape %s written %s\n"),
205 tp->label, find_nicedate(tp->datestamp));
211 return(output_find_log);
216 find_result_t **output_find,
217 disklist_t * dynamic_disklist)
219 GSList *holding_file_list;
225 holding_file_list = holding_get_files(NULL, 1);
227 for(e = holding_file_list; e != NULL; e = e->next) {
230 holding_file = (char *)e->data;
232 if (!holding_file_get_dumpfile(holding_file, &file))
235 if (file.dumplevel < 0 || file.dumplevel >= DUMP_LEVELS) {
236 dumpfile_free_data(&file);
241 orig_name = g_strdup(file.name);
244 if((dp = lookup_disk(file.name, file.disk)))
246 if((s = strrchr(file.name,'.')) == NULL)
250 strcpy(file.name, orig_name); /* restore munged string */
254 if (dynamic_disklist == NULL) {
255 dumpfile_free_data(&file);
258 dp = add_disk(dynamic_disklist, file.name, file.disk);
259 enqueue_disk(dynamic_disklist, dp);
262 if(find_match(file.name,file.disk)) {
263 find_result_t *new_output_find = g_new0(find_result_t, 1);
264 new_output_find->next=*output_find;
265 new_output_find->timestamp = stralloc(file.datestamp);
266 new_output_find->write_timestamp = stralloc("00000000000000");
267 new_output_find->hostname = stralloc(file.name);
268 new_output_find->diskname = stralloc(file.disk);
269 new_output_find->level=file.dumplevel;
270 new_output_find->label=stralloc(holding_file);
271 new_output_find->partnum = -1;
272 new_output_find->totalparts = -1;
273 new_output_find->filenum=0;
274 if (file.is_partial) {
275 new_output_find->status=stralloc("PARTIAL");
276 new_output_find->dump_status=stralloc("PARTIAL");
278 new_output_find->status=stralloc("OK");
279 new_output_find->dump_status=stralloc("OK");
281 new_output_find->message=stralloc("");
282 new_output_find->kb = holding_file_size(holding_file, 1);
283 new_output_find->orig_kb = file.orig_size;
285 *output_find=new_output_find;
287 dumpfile_free_data(&file);
290 g_slist_free_full(holding_file_list);
299 find_result_t *i, *j;
301 size_t nb_compare=strlen(find_sort_order);
304 for(k=0;k<nb_compare;k++) {
305 char sort_key = find_sort_order[k];
306 if (isupper((int)sort_key)) {
308 sort_key = tolower(sort_key);
309 j = *(find_result_t **)i1;
310 i = *(find_result_t **)j1;
312 i = *(find_result_t **)i1;
313 j = *(find_result_t **)j1;
317 case 'h' : compare=strcmp(i->hostname,j->hostname);
319 case 'k' : compare=strcmp(i->diskname,j->diskname);
321 case 'd' : compare=strcmp(i->timestamp,j->timestamp);
323 case 'l' : compare=j->level - i->level;
325 case 'f' : compare=(i->filenum == j->filenum) ? 0 :
326 ((i->filenum < j->filenum) ? -1 : 1);
328 case 'b' : compare=compare_possibly_null_strings(i->label,
331 case 'w': compare=strcmp(i->write_timestamp, j->write_timestamp);
334 compare=i->partnum - j->partnum;
346 find_result_t **output_find)
348 find_result_t *output_find_result;
349 find_result_t **array_find_result = NULL;
353 find_sort_order = sort_order;
354 /* qsort core dump if nothing to sort */
355 if(*output_find==NULL)
358 /* How many result */
359 for(output_find_result=*output_find;
361 output_find_result=output_find_result->next) {
365 /* put the list in an array */
366 array_find_result=alloc(nb_result * SIZEOF(find_result_t *));
367 for(output_find_result=*output_find,no_result=0;
369 output_find_result=output_find_result->next,no_result++) {
370 array_find_result[no_result]=output_find_result;
374 qsort(array_find_result,nb_result,SIZEOF(find_result_t *),
377 /* put the sorted result in the list */
379 no_result<nb_result-1; no_result++) {
380 array_find_result[no_result]->next = array_find_result[no_result+1];
382 array_find_result[nb_result-1]->next=NULL;
383 *output_find=array_find_result[0];
384 amfree(array_find_result);
389 find_result_t *output_find)
391 find_result_t *output_find_result;
392 int max_len_datestamp = 4;
393 int max_len_hostname = 4;
394 int max_len_diskname = 4;
395 int max_len_level = 2;
396 int max_len_label =12;
397 int max_len_filenum = 4;
398 int max_len_part = 4;
399 int max_len_status = 6;
402 for(output_find_result=output_find;
404 output_find_result=output_find_result->next) {
408 len=strlen(find_nicedate(output_find_result->timestamp));
409 if((int)len > max_len_datestamp)
410 max_len_datestamp=(int)len;
412 len=strlen(output_find_result->hostname);
413 if((int)len > max_len_hostname)
414 max_len_hostname = (int)len;
416 qdiskname=quote_string(output_find_result->diskname);
417 len=strlen(qdiskname);
419 if((int)len > max_len_diskname)
420 max_len_diskname = (int)len;
422 if (output_find_result->label != NULL) {
423 char *qlabel = quote_string(output_find_result->label);
426 if((int)len > max_len_label)
427 max_len_label = (int)len;
430 len=strlen(output_find_result->status) + 1 + strlen(output_find_result->dump_status);
431 if((int)len > max_len_status)
432 max_len_status = (int)len;
434 s = g_strdup_printf("%d/%d", output_find_result->partnum,
435 output_find_result->totalparts);
437 if((int)len > max_len_part)
438 max_len_part = (int)len;
443 * Since status is the rightmost field, we zap the maximum length
444 * because it is not needed. The code is left in place in case
445 * another column is added later.
449 if(output_find==NULL) {
450 g_printf(_("\nNo dump to list\n"));
453 g_printf(_("\ndate%*s host%*s disk%*s lv%*s tape or file%*s file%*s part%*s status\n"),
454 max_len_datestamp-4,"",
455 max_len_hostname-4 ,"",
456 max_len_diskname-4 ,"",
458 max_len_label-12 ,"",
459 max_len_filenum-4 ,"",
461 for(output_find_result=output_find;
463 output_find_result=output_find_result->next) {
465 char * formatted_label;
469 qdiskname = quote_string(output_find_result->diskname);
470 if (output_find_result->label == NULL)
471 formatted_label = stralloc("");
473 formatted_label = quote_string(output_find_result->label);
475 if (strcmp(output_find_result->status, "OK") != 0 ||
476 strcmp(output_find_result->dump_status, "OK") != 0) {
477 status = vstralloc(output_find_result->status, " ",
478 output_find_result->dump_status, NULL);
480 status = stralloc(output_find_result->status);
484 /* sec and kb are omitted here, for compatibility with the existing
485 * output from 'amadmin' */
486 s = g_strdup_printf("%d/%d", output_find_result->partnum,
487 output_find_result->totalparts);
488 g_printf("%-*s %-*s %-*s %*d %-*s %*lld %*s %s %s\n",
490 find_nicedate(output_find_result->timestamp),
491 max_len_hostname, output_find_result->hostname,
492 max_len_diskname, qdiskname,
493 max_len_level, output_find_result->level,
494 max_len_label, formatted_label,
495 max_len_filenum, (long long)output_find_result->filenum,
498 output_find_result->message
504 amfree(formatted_label);
511 find_result_t **output_find)
513 find_result_t *output_find_result, *prev;
516 for(output_find_result=*output_find;
518 output_find_result=output_find_result->next) {
520 amfree(output_find_result->timestamp);
521 amfree(output_find_result->write_timestamp);
522 amfree(output_find_result->hostname);
523 amfree(output_find_result->diskname);
524 amfree(output_find_result->label);
525 amfree(output_find_result->status);
526 amfree(output_find_result->dump_status);
527 amfree(output_find_result->message);
528 prev = output_find_result;
539 disk_t *dp = lookup_disk(host,disk);
540 return (dp && dp->todo);
547 static char nice[20];
548 int year, month, day;
549 int hours, minutes, seconds;
550 char date[9], atime[7];
551 int numdate, numtime;
553 strncpy(date, datestamp, 8);
555 numdate = atoi(date);
556 year = numdate / 10000;
557 month = (numdate / 100) % 100;
560 if(strlen(datestamp) <= 8) {
561 g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d",
565 strncpy(atime, &(datestamp[8]), 6);
567 numtime = atoi(atime);
568 hours = numtime / 10000;
569 minutes = (numtime / 100) % 100;
570 seconds = numtime % 100;
572 g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d %02d:%02d:%02d",
573 year, month, day, hours, minutes, seconds);
580 parse_taper_datestamp_log(
591 skip_whitespace(s, ch);
595 if(strncmp_const_skip(s - 1, "datestamp", s, ch) != 0) {
599 skip_whitespace(s, ch);
604 skip_non_whitespace(s, ch);
607 skip_whitespace(s, ch);
611 if(strncmp_const_skip(s - 1, "label", s, ch) != 0) {
615 skip_whitespace(s, ch);
620 skip_non_whitespace(s, ch);
626 /* Returns TRUE if the given logfile mentions the given tape. */
627 static gboolean logfile_has_tape(char * label, char * datestamp,
630 char * ck_datestamp, *ck_label;
631 if((logf = fopen(logfile, "r")) == NULL) {
632 error(_("could not open logfile %s: %s"), logfile, strerror(errno));
636 while(get_logline(logf)) {
637 if(curlog == L_START && curprog == P_TAPER) {
638 if(parse_taper_datestamp_log(curstr,
639 &ck_datestamp, &ck_label) == 0) {
640 g_printf(_("strange log line \"start taper %s\" curstr='%s'\n"),
642 } else if(strcmp(ck_datestamp, datestamp) == 0
643 && strcmp(ck_label, label) == 0) {
658 const char *datestamp)
666 return (strcmp(label1, label2) == 0);
668 /* check in tapelist */
669 if (!(tp = lookup_tapelabel(label2)))
672 if (strcmp(tp->datestamp, datestamp) != 0)
678 /* WARNING: Function accesses globals find_diskqp, curlog, curlog, curstr,
679 * dynamic_disklist */
682 find_result_t **output_find,
684 const char *passed_datestamp,
686 disklist_t * dynamic_disklist)
689 char *host, *host_undo;
690 char *disk, *qdisk, *disk_undo;
691 char *date, *date_undo;
697 char *current_label = stralloc("");
702 char *ck_datestamp, *datestamp;
706 GHashTable* valid_label;
707 GHashTable* part_by_dle;
708 find_result_t *part_find;
709 find_result_t *a_part_find;
710 gboolean right_label = FALSE;
711 gboolean found_something = FALSE;
714 regmatch_t pmatch[4];
720 g_return_val_if_fail(output_find != NULL, 0);
721 g_return_val_if_fail(logfile != NULL, 0);
723 valid_label = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
724 part_by_dle = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
725 datestamp = g_strdup(passed_datestamp);
727 if((logf = fopen(logfile, "r")) == NULL) {
728 error(_("could not open logfile %s: %s"), logfile, strerror(errno));
733 while(get_logline(logf)) {
734 if (curlog == L_START && curprog == P_TAPER) {
735 if(parse_taper_datestamp_log(curstr, &ck_datestamp,
737 g_printf(_("strange log line in %s \"start taper %s\"\n"),
741 if (datestamp != NULL) {
742 if (strcmp(datestamp, ck_datestamp) != 0) {
743 g_printf(_("Log file %s stamped %s, expecting %s!\n"),
744 logfile, ck_datestamp, datestamp);
749 right_label = volume_matches(label, ck_label, ck_datestamp);
750 if (right_label && ck_label) {
751 g_hash_table_insert(valid_label, g_strdup(ck_label),
754 if (label && datestamp && right_label) {
755 found_something = TRUE;
757 amfree(current_label);
758 current_label = g_strdup(ck_label);
759 if (datestamp == NULL) {
760 datestamp = g_strdup(ck_datestamp);
765 (curlog == L_SUCCESS ||
766 curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTPARTIAL) &&
767 curprog == P_TAPER) {
769 } else if (right_label && curlog == L_PARTIAL && curprog == P_TAPER &&
775 if (curlog == L_SUCCESS || curlog == L_CHUNKSUCCESS ||
776 curlog == L_DONE || curlog == L_FAIL ||
777 curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTIAL ||
778 curlog == L_PARTPARTIAL ) {
782 skip_whitespace(s, ch);
784 g_printf(_("strange log line in %s \"%s\"\n"),
789 if (curlog == L_PART || curlog == L_PARTPARTIAL) {
790 char * part_label = s - 1;
792 skip_non_whitespace(s, ch);
795 if (!g_hash_table_lookup(valid_label, part_label))
797 amfree(current_label);
798 current_label = stralloc(part_label);
800 skip_whitespace(s, ch);
802 g_printf("strange log line in %s \"%s\"\n",
808 skip_non_whitespace(s, ch);
810 fileno = atoi(number);
815 skip_whitespace(s, ch);
817 g_printf("strange log line in %s \"%s\"\n",
826 skip_non_whitespace(s, ch);
830 skip_whitespace(s, ch);
832 g_printf(_("strange log line in %s \"%s\"\n"),
837 skip_quoted_string(s, ch);
840 disk = unquote_string(qdisk);
842 skip_whitespace(s, ch);
844 g_printf(_("strange log line in %s \"%s\"\n"),
849 skip_non_whitespace(s, ch);
853 if(strlen(date) < 3) { /* old log didn't have datestamp */
855 date = stralloc(datestamp);
859 if (curprog == P_TAPER &&
860 (curlog == L_CHUNK || curlog == L_PART ||
861 curlog == L_PARTPARTIAL || curlog == L_PARTIAL ||
863 skip_whitespace(s, ch);
865 skip_non_whitespace(s, ch);
867 sscanf(number, "%d/%d", &partnum, &totalparts);
868 if (partnum > maxparts)
870 if (totalparts > maxparts)
871 maxparts = totalparts;
873 skip_whitespace(s, ch);
874 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
875 g_printf(_("strange log line in %s \"%s\"\n"),
882 skip_whitespace(s, ch);
884 g_printf(_("strange log line in %s \"%s\"\n"),
889 if((s = strchr(s, '\n')) != NULL) {
893 /* extract sec, kb, kps, orig-kb from 'rest', if present. This isn't the stone age
894 * anymore, so we'll just do it the easy way (a regex) */
895 bzero(®ex, sizeof(regex));
896 reg_result = regcomp(®ex,
897 "\\[sec ([0-9.]+) kb ([0-9]+) kps [0-9.]+ orig-kb ([0-9]+)\\]", REG_EXTENDED);
898 if (reg_result != 0) {
899 error("Error compiling regular expression for parsing log lines");
903 /* an error here just means the line wasn't found -- not fatal. */
904 reg_result = regexec(®ex, rest, sizeof(pmatch)/sizeof(*pmatch), pmatch, 0);
905 if (reg_result == 0) {
908 str = find_regex_substring(rest, pmatch[1]);
912 str = find_regex_substring(rest, pmatch[2]);
913 kb = OFF_T_ATOI(str);
916 str = find_regex_substring(rest, pmatch[3]);
917 orig_kb = OFF_T_ATOI(str);
921 bzero(®ex, sizeof(regex));
922 /* the .* at the end of this captures the old {wr: .. } statistics */
923 reg_result = regcomp(®ex,
924 "\\[sec ([0-9.]+) kb ([0-9]+) kps [0-9.]+.*\\]", REG_EXTENDED);
925 if (reg_result != 0) {
926 error("Error compiling regular expression for parsing log lines");
930 /* an error here just means the line wasn't found -- not fatal. */
931 reg_result = regexec(®ex, rest, sizeof(pmatch)/sizeof(*pmatch), pmatch, 0);
932 if (reg_result == 0) {
935 str = find_regex_substring(rest, pmatch[1]);
939 str = find_regex_substring(rest, pmatch[2]);
940 kb = OFF_T_ATOI(str);
949 if (strncmp(rest, "error ", 6) == 0) rest += 6;
950 if (strncmp(rest, "config ", 7) == 0) rest += 7;
953 dp = lookup_disk(host,disk);
955 if (dynamic_disklist == NULL) {
958 dp = add_disk(dynamic_disklist, host, disk);
959 enqueue_disk(dynamic_disklist, dp);
961 if (find_match(host, disk)) {
962 if(curprog == P_TAPER) {
963 char *key = g_strdup_printf(
964 "HOST:%s DISK:%s: DATE:%s LEVEL:%d",
965 host, disk, date, level);
966 find_result_t *new_output_find = g_new0(find_result_t, 1);
967 part_find = g_hash_table_lookup(part_by_dle, key);
968 new_output_find->timestamp = stralloc(date);
969 new_output_find->write_timestamp = stralloc(datestamp);
970 new_output_find->hostname=stralloc(host);
971 new_output_find->diskname=stralloc(disk);
972 new_output_find->level=level;
973 new_output_find->partnum = partnum;
974 new_output_find->totalparts = totalparts;
975 new_output_find->label=stralloc(current_label);
976 new_output_find->status=NULL;
977 new_output_find->dump_status=NULL;
978 new_output_find->message=stralloc("");
979 new_output_find->filenum=filenum;
980 new_output_find->sec=sec;
981 new_output_find->kb=kb;
982 new_output_find->orig_kb=orig_kb;
983 new_output_find->next=NULL;
984 if (curlog == L_SUCCESS) {
985 new_output_find->status = stralloc("OK");
986 new_output_find->dump_status = stralloc("OK");
987 new_output_find->next = *output_find;
988 new_output_find->partnum = 1; /* L_SUCCESS is pre-splitting */
989 *output_find = new_output_find;
990 found_something = TRUE;
991 } else if (curlog == L_CHUNKSUCCESS || curlog == L_DONE ||
992 curlog == L_PARTIAL || curlog == L_FAIL) {
994 if (curlog == L_PARTIAL || curlog == L_FAIL) {
995 /* set dump_status of each part */
996 for (a_part_find = part_find;
998 a_part_find = a_part_find->next) {
999 amfree(a_part_find->dump_status);
1000 if (curlog == L_PARTIAL)
1001 a_part_find->dump_status = stralloc("PARTIAL");
1003 a_part_find->dump_status = stralloc("FAIL");
1004 amfree(a_part_find->message);
1005 a_part_find->message = stralloc(rest);
1009 if (maxparts > -1) { /* format with part */
1010 /* must check if all part are there */
1011 int num_part = maxparts;
1012 for (a_part_find = part_find;
1014 a_part_find = a_part_find->next) {
1015 if (a_part_find->partnum == num_part &&
1016 strcmp(a_part_find->status, "OK") == 0)
1019 /* set dump_status of each part */
1020 for (a_part_find = part_find;
1022 a_part_find = a_part_find->next) {
1023 amfree(a_part_find->dump_status);
1024 if (num_part == 0) {
1025 a_part_find->dump_status =
1028 a_part_find->dump_status =
1030 amfree(a_part_find->message);
1031 a_part_find->message =
1032 stralloc("Missing part");
1037 if (curlog == L_DONE) {
1038 for (a_part_find = part_find;
1040 a_part_find = a_part_find->next) {
1041 if (a_part_find->totalparts == -1) {
1042 a_part_find->totalparts = maxparts;
1044 if (a_part_find->orig_kb == 0) {
1045 a_part_find->orig_kb = orig_kb;
1049 if (part_find) { /* find last element */
1050 for (a_part_find = part_find;
1051 a_part_find->next != NULL;
1052 a_part_find=a_part_find->next) {
1054 /* merge part_find to *output_find */
1055 a_part_find->next = *output_find;
1056 *output_find = part_find;
1059 found_something = TRUE;
1060 g_hash_table_remove(part_by_dle, key);
1062 free_find_result(&new_output_find);
1063 } else { /* part line */
1064 if (curlog == L_PART || curlog == L_CHUNK) {
1065 new_output_find->status=stralloc("OK");
1066 new_output_find->dump_status=stralloc("OK");
1067 } else { /* PARTPARTIAL */
1068 new_output_find->status=stralloc("PARTIAL");
1069 new_output_find->dump_status=stralloc("PARTIAL");
1071 /* Add to part_find list */
1073 new_output_find->next = part_find;
1074 part_find = new_output_find;
1076 new_output_find->next = NULL;
1077 part_find = new_output_find;
1079 g_hash_table_insert(part_by_dle, g_strdup(key),
1081 found_something = TRUE;
1085 else if(curlog == L_FAIL) {
1086 /* print other failures too -- this is a hack to ensure that failures which
1087 * did not make it to tape are also listed in the output of 'amadmin x find';
1088 * users that do not want this information (e.g., Amanda::DB::Catalog) should
1089 * filter dumps with a NULL label. */
1090 find_result_t *new_output_find = g_new0(find_result_t, 1);
1091 new_output_find->next = *output_find;
1092 new_output_find->timestamp = stralloc(date);
1093 new_output_find->write_timestamp = g_strdup("00000000000000"); /* dump was not written.. */
1094 new_output_find->hostname=stralloc(host);
1095 new_output_find->diskname=stralloc(disk);
1096 new_output_find->level=level;
1097 new_output_find->label=NULL;
1098 new_output_find->partnum=partnum;
1099 new_output_find->totalparts=totalparts;
1100 new_output_find->filenum=0;
1101 new_output_find->sec=sec;
1102 new_output_find->kb=kb;
1103 new_output_find->kb=orig_kb;
1104 new_output_find->status=vstralloc(
1106 program_str[(int)curprog],
1110 new_output_find->dump_status=stralloc("");
1111 new_output_find->message=stralloc("");
1112 *output_find=new_output_find;
1113 found_something = TRUE;
1121 g_hash_table_destroy(valid_label);
1124 amfree(current_label);
1126 return found_something;
1131 * Return the set of dumps that match *all* of the given patterns (we consider
1132 * an empty pattern to match .*, though). If 'ok' is true, will only match
1133 * dumps with SUCCESS status.
1135 * Returns a newly allocated list of results, where all strings are also newly
1136 * allocated. Apparently some part of Amanda leaks under this condition.
1140 find_result_t *output_find,
1147 find_result_t *cur_result;
1148 find_result_t *matches = NULL;
1150 for(cur_result=output_find;
1152 cur_result=cur_result->next) {
1153 char level_str[NUM_STR_SIZE];
1154 g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
1155 if((!hostname || *hostname == '\0' || match_host(hostname, cur_result->hostname)) &&
1156 (!diskname || *diskname == '\0' || match_disk(diskname, cur_result->diskname)) &&
1157 (!datestamp || *datestamp== '\0' || match_datestamp(datestamp, cur_result->timestamp)) &&
1158 (!level || *level== '\0' || match_level(level, level_str)) &&
1159 (!ok || !strcmp(cur_result->status, "OK")) &&
1160 (!ok || !strcmp(cur_result->dump_status, "OK"))){
1162 find_result_t *curmatch = g_new0(find_result_t, 1);
1163 memcpy(curmatch, cur_result, SIZEOF(find_result_t));
1165 curmatch->timestamp = stralloc(cur_result->timestamp);
1166 curmatch->write_timestamp = stralloc(cur_result->write_timestamp);
1167 curmatch->hostname = stralloc(cur_result->hostname);
1168 curmatch->diskname = stralloc(cur_result->diskname);
1169 curmatch->level = cur_result->level;
1170 curmatch->label = cur_result->label? stralloc(cur_result->label) : NULL;
1171 curmatch->filenum = cur_result->filenum;
1172 curmatch->sec = cur_result->sec;
1173 curmatch->kb = cur_result->kb;
1174 curmatch->orig_kb = cur_result->orig_kb;
1175 curmatch->status = stralloc(cur_result->status);
1176 curmatch->dump_status = stralloc(cur_result->dump_status);
1177 curmatch->message = stralloc(cur_result->message);
1178 curmatch->partnum = cur_result->partnum;
1179 curmatch->totalparts = cur_result->totalparts;
1180 curmatch->next = matches;
1189 * Return the set of dumps that match one or more of the given dumpspecs,
1190 * If 'ok' is true, only dumps with a SUCCESS status will be matched.
1192 * Returns a newly allocated list of results, where all strings are also newly
1193 * allocated. Apparently some part of Amanda leaks under this condition.
1196 dumps_match_dumpspecs(
1197 find_result_t *output_find,
1201 find_result_t *cur_result;
1202 find_result_t *matches = NULL;
1206 for(cur_result=output_find;
1208 cur_result=cur_result->next) {
1209 char level_str[NUM_STR_SIZE];
1210 char *zeropad_ts = NULL;
1211 char *zeropad_w_ts = NULL;
1212 g_snprintf(level_str, SIZEOF(level_str), "%d", cur_result->level);
1214 /* get the timestamp padded to full width */
1215 if (strlen(cur_result->timestamp) < 14) {
1216 zeropad_ts = g_new0(char, 15);
1217 memset(zeropad_ts, '0', 14);
1218 memcpy(zeropad_ts, cur_result->timestamp, strlen(cur_result->timestamp));
1220 if (strlen(cur_result->write_timestamp) < 14) {
1221 zeropad_w_ts = g_new0(char, 15);
1222 memset(zeropad_w_ts, '0', 14);
1223 memcpy(zeropad_w_ts, cur_result->write_timestamp, strlen(cur_result->write_timestamp));
1226 for (dumpspec = dumpspecs; dumpspec; dumpspec = dumpspec->next) {
1227 ds = (dumpspec_t *)dumpspec->data;
1228 if((!ds->host || *ds->host == '\0' || match_host(ds->host, cur_result->hostname)) &&
1229 (!ds->disk || *ds->disk == '\0' || match_disk(ds->disk, cur_result->diskname)) &&
1230 (!ds->datestamp || *ds->datestamp== '\0'
1231 || match_datestamp(ds->datestamp, cur_result->timestamp)
1232 || (zeropad_ts && match_datestamp(ds->datestamp, zeropad_ts))) &&
1233 (!ds->write_timestamp || *ds->write_timestamp== '\0'
1234 || match_datestamp(ds->write_timestamp, cur_result->write_timestamp)
1235 || (zeropad_w_ts && match_datestamp(ds->write_timestamp, zeropad_w_ts))) &&
1236 (!ds->level || *ds->level== '\0' || match_level(ds->level, level_str)) &&
1237 (!ok || !strcmp(cur_result->status, "OK")) &&
1238 (!ok || !strcmp(cur_result->dump_status, "OK"))) {
1240 find_result_t *curmatch = alloc(SIZEOF(find_result_t));
1241 memcpy(curmatch, cur_result, SIZEOF(find_result_t));
1243 curmatch->timestamp = stralloc(cur_result->timestamp);
1244 curmatch->write_timestamp = stralloc(cur_result->write_timestamp);
1245 curmatch->hostname = stralloc(cur_result->hostname);
1246 curmatch->diskname = stralloc(cur_result->diskname);
1247 curmatch->level = cur_result->level;
1248 curmatch->label = cur_result->label? stralloc(cur_result->label) : NULL;
1249 curmatch->filenum = cur_result->filenum;
1250 curmatch->status = stralloc(cur_result->status);
1251 curmatch->dump_status = stralloc(cur_result->dump_status);
1252 curmatch->message = stralloc(cur_result->message);
1253 curmatch->partnum = cur_result->partnum;
1254 curmatch->totalparts = cur_result->totalparts;
1256 curmatch->next = matches;
1270 find_result_t *output_find,
1276 find_result_t *output_find_result;
1278 for(output_find_result=output_find;
1280 output_find_result=output_find_result->next) {
1281 if( !strcmp(output_find_result->hostname, hostname) &&
1282 !strcmp(output_find_result->diskname, diskname) &&
1283 !strcmp(output_find_result->timestamp, datestamp) &&
1284 output_find_result->level == level) {
1286 return output_find_result;