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.6.2.4.4.2.2.5.2.1 2004/02/02 20:29:12 martinea Exp $
30 * controlling process for the Amanda backup system
39 void find P((int argc, char **argv));
40 int find_match P((char *host, char *disk));
41 int search_logfile P((find_result_t **output_find, char *label, int datestamp, int datestamp_aux, char *logfile));
42 void search_holding_disk P((find_result_t **output_find));
43 char *find_nicedate P((int datestamp));
45 static char *find_sort_order = NULL;
46 int dynamic_disklist = 0;
47 disklist_t* find_diskqp = NULL;
49 find_result_t *find_dump(dyna_disklist, diskqp)
53 char *conf_logdir, *logfile = NULL;
54 int tape, maxtape, seq, logs;
56 find_result_t *output_find = NULL;
58 dynamic_disklist = dyna_disklist;
60 conf_logdir = getconf_str(CNF_LOGDIR);
61 if (*conf_logdir == '/') {
62 conf_logdir = stralloc(conf_logdir);
64 conf_logdir = stralloc2(config_dir, conf_logdir);
66 maxtape = lookup_nb_tape();
68 for(tape = 1; tape <= maxtape; tape++) {
69 char ds_str[NUM_STR_SIZE];
71 tp = lookup_tapepos(tape);
72 if(tp == NULL) continue;
73 ap_snprintf(ds_str, sizeof(ds_str), "%d", tp->datestamp);
75 /* search log files */
79 /* new-style log.<date>.<seq> */
81 for(seq = 0; 1; seq++) {
82 char seq_str[NUM_STR_SIZE];
84 ap_snprintf(seq_str, sizeof(seq_str), "%d", seq);
85 logfile = newvstralloc(logfile,
86 conf_logdir, "/log.", ds_str, ".", seq_str, NULL);
87 if(access(logfile, R_OK) != 0) break;
88 logs += search_logfile(&output_find, tp->label, tp->datestamp, seq, logfile);
91 /* search old-style amflush log, if any */
93 logfile = newvstralloc(logfile,
94 conf_logdir, "/log.", ds_str, ".amflush", NULL);
95 if(access(logfile,R_OK) == 0) {
96 logs += search_logfile(&output_find, tp->label, tp->datestamp, 1000, logfile);
99 /* search old-style main log, if any */
101 logfile = newvstralloc(logfile, conf_logdir, "/log.", ds_str, NULL);
102 if(access(logfile,R_OK) == 0) {
103 logs += search_logfile(&output_find, tp->label, tp->datestamp, -1, logfile);
105 if(logs == 0 && tp->datestamp != 0)
106 printf("Warning: no log files found for tape %s written %s\n",
107 tp->label, find_nicedate(tp->datestamp));
112 search_holding_disk(&output_find);
118 char *conf_logdir, *logfile = NULL;
119 int tape, maxtape, seq, logs;
121 char **output_find_log = NULL;
124 conf_logdir = getconf_str(CNF_LOGDIR);
125 if (*conf_logdir == '/') {
126 conf_logdir = stralloc(conf_logdir);
128 conf_logdir = stralloc2(config_dir, conf_logdir);
130 maxtape = lookup_nb_tape();
132 output_find_log = alloc((maxtape*5+10) * sizeof(char *));
133 current_log = output_find_log;
135 for(tape = 1; tape <= maxtape; tape++) {
136 char ds_str[NUM_STR_SIZE];
138 tp = lookup_tapepos(tape);
139 if(tp == NULL) continue;
140 ap_snprintf(ds_str, sizeof(ds_str), "%d", tp->datestamp);
142 /* search log files */
146 /* new-style log.<date>.<seq> */
148 for(seq = 0; 1; seq++) {
149 char seq_str[NUM_STR_SIZE];
151 ap_snprintf(seq_str, sizeof(seq_str), "%d", seq);
152 logfile = newvstralloc(logfile,
153 conf_logdir, "/log.", ds_str, ".", seq_str, NULL);
154 if(access(logfile, R_OK) != 0) break;
155 if( search_logfile(NULL, tp->label, tp->datestamp, seq, logfile)) {
156 *current_log = vstralloc("log.", ds_str, ".", seq_str, NULL);
163 /* search old-style amflush log, if any */
165 logfile = newvstralloc(logfile,
166 conf_logdir, "/log.", ds_str, ".amflush", NULL);
167 if(access(logfile,R_OK) == 0) {
168 if( search_logfile(NULL, tp->label, tp->datestamp, 1000, logfile)) {
169 *current_log = vstralloc("log.", ds_str, ".amflush", NULL);
175 /* search old-style main log, if any */
177 logfile = newvstralloc(logfile, conf_logdir, "/log.", ds_str, NULL);
178 if(access(logfile,R_OK) == 0) {
179 if(search_logfile(NULL, tp->label, tp->datestamp, -1, logfile)) {
180 *current_log = vstralloc("log.", ds_str, NULL);
185 if(logs == 0 && tp->datestamp != 0)
186 printf("Warning: no log files found for tape %s written %s\n",
187 tp->label, find_nicedate(tp->datestamp));
192 return(output_find_log);
195 void search_holding_disk(output_find)
196 find_result_t **output_find;
198 holdingdisk_t *hdisk;
201 char *sdirname = NULL;
202 char *destname = NULL;
203 char *hostname = NULL;
204 char *diskname = NULL;
206 struct dirent *entry;
210 holding_list = pick_all_datestamp(1);
212 for(hdisk = getconf_holdingdisks(); hdisk != NULL; hdisk = hdisk->next) {
213 for(dir = holding_list->first; dir != NULL; dir = dir->next) {
214 sdirname = newvstralloc(sdirname,
215 hdisk->diskdir, "/", dir->name,
217 if((workdir = opendir(sdirname)) == NULL) {
221 while((entry = readdir(workdir)) != NULL) {
222 if(is_dot_or_dotdot(entry->d_name)) {
225 destname = newvstralloc(destname,
226 sdirname, "/", entry->d_name,
228 if(is_emptyfile(destname)) {
233 if(get_amanda_names(destname, &hostname, &diskname, &level) != F_DUMPFILE) {
236 if(level < 0 || level > 9)
242 if((dp = lookup_disk(hostname, diskname)))
244 if((s = strrchr(hostname,'.')) == NULL)
252 if(find_match(hostname,diskname)) {
253 find_result_t *new_output_find =
254 alloc(sizeof(find_result_t));
255 new_output_find->next=*output_find;
256 if(strlen(dir->name) == 8) {
257 new_output_find->datestamp=atoi(dir->name);
258 new_output_find->timestamp=stralloc2(dir->name, "000000");
260 else if(strlen(dir->name) == 14) {
261 char *name = stralloc(dir->name);
263 new_output_find->datestamp=atoi(name);
264 new_output_find->timestamp=stralloc(dir->name);
270 new_output_find->datestamp_aux=1001;
271 new_output_find->hostname=hostname;
273 new_output_find->diskname=diskname;
275 new_output_find->level=level;
276 new_output_find->label=stralloc(destname);
277 new_output_find->filenum=0;
278 new_output_find->status=stralloc("OK");
279 *output_find=new_output_find;
285 free_sl(holding_list);
293 static int find_compare(i1, j1)
298 find_result_t **i = (find_result_t **)i1;
299 find_result_t **j = (find_result_t **)j1;
301 int nb_compare=strlen(find_sort_order);
304 for(k=0;k<nb_compare;k++) {
305 switch (find_sort_order[k]) {
306 case 'h' : compare=strcmp((*i)->hostname,(*j)->hostname);
308 case 'H' : compare=strcmp((*j)->hostname,(*i)->hostname);
310 case 'k' : compare=strcmp((*i)->diskname,(*j)->diskname);
312 case 'K' : compare=strcmp((*j)->diskname,(*i)->diskname);
314 case 'd' : compare=(*i)->datestamp - (*j)->datestamp;
316 compare = (*i)->datestamp_aux - (*j)->datestamp_aux;
318 case 'D' : compare=(*j)->datestamp - (*i)->datestamp;
320 compare = (*j)->datestamp_aux - (*i)->datestamp_aux;
322 case 'l' : compare=(*j)->level - (*i)->level;
324 case 'L' : compare=(*i)->level - (*j)->level;
326 case 'b' : compare=strcmp((*i)->label,(*j)->label);
328 case 'B' : compare=strcmp((*j)->label,(*i)->label);
337 void sort_find_result(sort_order, output_find)
339 find_result_t **output_find;
341 find_result_t *output_find_result;
342 find_result_t **array_find_result = NULL;
346 find_sort_order = sort_order;
347 /* qsort core dump if nothing to sort */
348 if(*output_find==NULL)
351 /* How many result */
352 for(output_find_result=*output_find;
354 output_find_result=output_find_result->next) {
358 /* put the list in an array */
359 array_find_result=alloc(nb_result * sizeof(find_result_t *));
360 for(output_find_result=*output_find,no_result=0;
362 output_find_result=output_find_result->next,no_result++) {
363 array_find_result[no_result]=output_find_result;
367 qsort(array_find_result,nb_result,sizeof(find_result_t *),
370 /* put the sorted result in the list */
372 no_result<nb_result-1; no_result++) {
373 array_find_result[no_result]->next = array_find_result[no_result+1];
375 array_find_result[nb_result-1]->next=NULL;
376 *output_find=array_find_result[0];
377 amfree(array_find_result);
380 void print_find_result(output_find)
381 find_result_t *output_find;
383 find_result_t *output_find_result;
384 int max_len_datestamp = 4;
385 int max_len_hostname = 4;
386 int max_len_diskname = 4;
387 int max_len_level = 2;
388 int max_len_label =12;
389 int max_len_filenum = 4;
390 int max_len_status = 6;
393 for(output_find_result=output_find;
395 output_find_result=output_find_result->next) {
397 len=strlen(find_nicedate(output_find_result->datestamp));
398 if(len>max_len_datestamp) max_len_datestamp=len;
400 len=strlen(output_find_result->hostname);
401 if(len>max_len_hostname) max_len_hostname=len;
403 len=strlen(output_find_result->diskname);
404 if(len>max_len_diskname) max_len_diskname=len;
406 len=strlen(output_find_result->label);
407 if(len>max_len_label) max_len_label=len;
409 len=strlen(output_find_result->status);
410 if(len>max_len_status) max_len_status=len;
414 * Since status is the rightmost field, we zap the maximum length
415 * because it is not needed. The code is left in place in case
416 * another column is added later.
420 if(output_find==NULL) {
421 printf("\nNo dump to list\n");
424 printf("\ndate%*s host%*s disk%*s lv%*s tape or file%*s file%*s status\n",
425 max_len_datestamp-4,"",
426 max_len_hostname-4 ,"",
427 max_len_diskname-4 ,"",
429 max_len_label-12 ,"",
430 max_len_filenum-4 ,"");
431 for(output_find_result=output_find;
433 output_find_result=output_find_result->next) {
435 printf("%-*s %-*s %-*s %*d %-*s %*d %-*s\n",
437 find_nicedate(output_find_result->datestamp),
438 max_len_hostname, output_find_result->hostname,
439 max_len_diskname, output_find_result->diskname,
440 max_len_level, output_find_result->level,
441 max_len_label, output_find_result->label,
442 max_len_filenum, output_find_result->filenum,
443 max_len_status, output_find_result->status);
448 void free_find_result(output_find)
449 find_result_t **output_find;
451 find_result_t *output_find_result, *prev;
454 for(output_find_result=*output_find;
456 output_find_result=output_find_result->next) {
457 if(prev != NULL) amfree(prev);
458 amfree(output_find_result->hostname);
459 amfree(output_find_result->diskname);
460 amfree(output_find_result->label);
461 amfree(output_find_result->status);
462 prev = output_find_result;
464 if(prev != NULL) amfree(prev);
468 int find_match(host, disk)
471 disk_t *dp = lookup_disk(host,disk);
472 return (dp && dp->todo);
475 char *find_nicedate(datestamp)
478 static char nice[20];
479 int year, month, day;
481 year = datestamp / 10000;
482 month = (datestamp / 100) % 100;
483 day = datestamp % 100;
485 ap_snprintf(nice, sizeof(nice), "%4d-%02d-%02d", year, month, day);
490 static int parse_taper_datestamp_log(logline, datestamp, label)
501 skip_whitespace(s, ch);
505 #define sc "datestamp"
506 if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
513 skip_whitespace(s, ch);
514 if(ch == '\0' || sscanf(s - 1, "%d", datestamp) != 1) {
519 skip_whitespace(s, ch);
524 if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
531 skip_whitespace(s, ch);
536 skip_non_whitespace(s, ch);
542 /* if output_find is NULL */
543 /* return 1 if this is the logfile for this label */
544 /* return 0 if this is not the logfile for this label */
546 /* add to output_find all the dump for this label */
547 /* return the number of dump added. */
548 int search_logfile(output_find, label, datestamp, datestamp_aux, logfile)
549 find_result_t **output_find;
550 char *label, *logfile;
551 int datestamp, datestamp_aux;
554 char *host, *host_undo;
555 char *disk, *disk_undo;
559 int level, filenum, ck_datestamp, tapematch;
560 int passlabel, ck_datestamp2;
565 if((logf = fopen(logfile, "r")) == NULL)
566 error("could not open logfile %s: %s", logfile, strerror(errno));
568 /* check that this log file corresponds to the right tape */
570 while(!tapematch && get_logline(logf)) {
571 if(curlog == L_START && curprog == P_TAPER) {
572 if(parse_taper_datestamp_log(curstr,
573 &ck_datestamp, &ck_label) == 0) {
574 printf("strange log line \"start taper %s\"\n", curstr);
575 } else if(ck_datestamp == datestamp
576 && strcmp(ck_label, label) == 0) {
582 if(output_find == NULL) {
597 while(get_logline(logf) && passlabel) {
598 if(curlog == L_SUCCESS && curprog == P_TAPER && passlabel) filenum++;
599 if(curlog == L_START && curprog == P_TAPER) {
600 if(parse_taper_datestamp_log(curstr,
601 &ck_datestamp2, &ck_label) == 0) {
602 printf("strange log line \"start taper %s\"\n", curstr);
603 } else if (strcmp(ck_label, label)) {
604 passlabel = !passlabel;
607 if(curlog == L_SUCCESS || curlog == L_FAIL) {
611 skip_whitespace(s, ch);
613 printf("strange log line \"%s\"\n", curstr);
617 skip_non_whitespace(s, ch);
621 skip_whitespace(s, ch);
623 printf("strange log line \"%s\"\n", curstr);
627 skip_non_whitespace(s, ch);
631 skip_whitespace(s, ch);
632 if(ch == '\0' || sscanf(s - 1, "%d", &datestampI) != 1) {
633 printf("strange log line \"%s\"\n", curstr);
638 if(datestampI < 100) { /* old log didn't have datestamp */
640 datestampI = datestamp;
643 skip_whitespace(s, ch);
644 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
645 printf("strange log line \"%s\"\n", curstr);
651 skip_whitespace(s, ch);
653 printf("strange log line \"%s\"\n", curstr);
657 if((s = strchr(s, '\n')) != NULL) {
661 dp = lookup_disk(host,disk);
663 if (dynamic_disklist == 0) {
666 dp = add_disk(host, disk);
667 enqueue_disk(find_diskqp , dp);
669 if(find_match(host, disk)) {
670 if(curprog == P_TAPER) {
671 find_result_t *new_output_find =
672 (find_result_t *)alloc(sizeof(find_result_t));
673 new_output_find->next=*output_find;
674 new_output_find->datestamp=datestampI;
675 new_output_find->timestamp = alloc(15);
676 ap_snprintf(new_output_find->timestamp, 15, "%d000000", datestampI);
677 new_output_find->datestamp_aux=datestamp_aux;
678 new_output_find->hostname=stralloc(host);
679 new_output_find->diskname=stralloc(disk);
680 new_output_find->level=level;
681 new_output_find->label=stralloc(label);
682 new_output_find->filenum=filenum;
683 if(curlog == L_SUCCESS)
684 new_output_find->status=stralloc("OK");
686 new_output_find->status=stralloc(rest);
687 *output_find=new_output_find;
689 else if(curlog == L_FAIL) { /* print other failures too */
690 find_result_t *new_output_find =
691 (find_result_t *)alloc(sizeof(find_result_t));
692 new_output_find->next=*output_find;
693 new_output_find->datestamp=datestamp;
694 new_output_find->datestamp_aux=datestamp_aux;
695 new_output_find->timestamp = alloc(15);
696 ap_snprintf(new_output_find->timestamp, 15, "%d000000", datestamp);
697 new_output_find->hostname=stralloc(host);
698 new_output_find->diskname=stralloc(disk);
699 new_output_find->level=level;
700 new_output_find->label=stralloc("---");
701 new_output_find->filenum=0;
702 new_output_find->status=vstralloc(
704 program_str[(int)curprog],
708 *output_find=new_output_find;
717 find_result_t *dump_exist(output_find, hostname, diskname, datestamp, level)
718 find_result_t *output_find;
724 find_result_t *output_find_result;
726 for(output_find_result=output_find;
728 output_find_result=output_find_result->next) {
729 if( !strcmp(output_find_result->hostname, hostname) &&
730 !strcmp(output_find_result->diskname, diskname) &&
731 output_find_result->datestamp == datestamp &&
732 output_find_result->level == level) {
734 return output_find_result;