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 2003/10/27 18:33:03 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 new_output_find->datestamp=atoi(dir->name);
257 new_output_find->datestamp_aux=1001;
258 new_output_find->hostname=hostname;
260 new_output_find->diskname=diskname;
262 new_output_find->level=level;
263 new_output_find->label=stralloc(destname);
264 new_output_find->filenum=0;
265 new_output_find->status=stralloc("OK");
266 *output_find=new_output_find;
272 free_sl(holding_list);
280 static int find_compare(i1, j1)
285 find_result_t **i = (find_result_t **)i1;
286 find_result_t **j = (find_result_t **)j1;
288 int nb_compare=strlen(find_sort_order);
291 for(k=0;k<nb_compare;k++) {
292 switch (find_sort_order[k]) {
293 case 'h' : compare=strcmp((*i)->hostname,(*j)->hostname);
295 case 'H' : compare=strcmp((*j)->hostname,(*i)->hostname);
297 case 'k' : compare=strcmp((*i)->diskname,(*j)->diskname);
299 case 'K' : compare=strcmp((*j)->diskname,(*i)->diskname);
301 case 'd' : compare=(*i)->datestamp - (*j)->datestamp;
303 compare = (*i)->datestamp_aux - (*j)->datestamp_aux;
305 case 'D' : compare=(*j)->datestamp - (*i)->datestamp;
307 compare = (*j)->datestamp_aux - (*i)->datestamp_aux;
309 case 'l' : compare=(*j)->level - (*i)->level;
311 case 'L' : compare=(*i)->level - (*j)->level;
313 case 'b' : compare=strcmp((*i)->label,(*j)->label);
315 case 'B' : compare=strcmp((*j)->label,(*i)->label);
324 void sort_find_result(sort_order, output_find)
326 find_result_t **output_find;
328 find_result_t *output_find_result;
329 find_result_t **array_find_result = NULL;
333 find_sort_order = sort_order;
334 /* qsort core dump if nothing to sort */
335 if(*output_find==NULL)
338 /* How many result */
339 for(output_find_result=*output_find;
341 output_find_result=output_find_result->next) {
345 /* put the list in an array */
346 array_find_result=alloc(nb_result * sizeof(find_result_t *));
347 for(output_find_result=*output_find,no_result=0;
349 output_find_result=output_find_result->next,no_result++) {
350 array_find_result[no_result]=output_find_result;
354 qsort(array_find_result,nb_result,sizeof(find_result_t *),
357 /* put the sorted result in the list */
359 no_result<nb_result-1; no_result++) {
360 array_find_result[no_result]->next = array_find_result[no_result+1];
362 array_find_result[nb_result-1]->next=NULL;
363 *output_find=array_find_result[0];
364 amfree(array_find_result);
367 void print_find_result(output_find)
368 find_result_t *output_find;
370 find_result_t *output_find_result;
371 int max_len_datestamp = 4;
372 int max_len_hostname = 4;
373 int max_len_diskname = 4;
374 int max_len_level = 2;
375 int max_len_label =12;
376 int max_len_filenum = 4;
377 int max_len_status = 6;
380 for(output_find_result=output_find;
382 output_find_result=output_find_result->next) {
384 len=strlen(find_nicedate(output_find_result->datestamp));
385 if(len>max_len_datestamp) max_len_datestamp=len;
387 len=strlen(output_find_result->hostname);
388 if(len>max_len_hostname) max_len_hostname=len;
390 len=strlen(output_find_result->diskname);
391 if(len>max_len_diskname) max_len_diskname=len;
393 len=strlen(output_find_result->label);
394 if(len>max_len_label) max_len_label=len;
396 len=strlen(output_find_result->status);
397 if(len>max_len_status) max_len_status=len;
401 * Since status is the rightmost field, we zap the maximum length
402 * because it is not needed. The code is left in place in case
403 * another column is added later.
407 if(output_find==NULL) {
408 printf("\nNo dump to list\n");
411 printf("\ndate%*s host%*s disk%*s lv%*s tape or file%*s file%*s status\n",
412 max_len_datestamp-4,"",
413 max_len_hostname-4 ,"",
414 max_len_diskname-4 ,"",
416 max_len_label-12 ,"",
417 max_len_filenum-4 ,"");
418 for(output_find_result=output_find;
420 output_find_result=output_find_result->next) {
422 printf("%-*s %-*s %-*s %*d %-*s %*d %-*s\n",
424 find_nicedate(output_find_result->datestamp),
425 max_len_hostname, output_find_result->hostname,
426 max_len_diskname, output_find_result->diskname,
427 max_len_level, output_find_result->level,
428 max_len_label, output_find_result->label,
429 max_len_filenum, output_find_result->filenum,
430 max_len_status, output_find_result->status);
435 void free_find_result(output_find)
436 find_result_t **output_find;
438 find_result_t *output_find_result, *prev;
441 for(output_find_result=*output_find;
443 output_find_result=output_find_result->next) {
444 if(prev != NULL) amfree(prev);
445 amfree(output_find_result->hostname);
446 amfree(output_find_result->diskname);
447 amfree(output_find_result->label);
448 amfree(output_find_result->status);
449 prev = output_find_result;
451 if(prev != NULL) amfree(prev);
455 int find_match(host, disk)
458 disk_t *dp = lookup_disk(host,disk);
459 return (dp && dp->todo);
462 char *find_nicedate(datestamp)
465 static char nice[20];
466 int year, month, day;
468 year = datestamp / 10000;
469 month = (datestamp / 100) % 100;
470 day = datestamp % 100;
472 ap_snprintf(nice, sizeof(nice), "%4d-%02d-%02d", year, month, day);
477 static int parse_taper_datestamp_log(logline, datestamp, label)
488 skip_whitespace(s, ch);
492 #define sc "datestamp"
493 if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
500 skip_whitespace(s, ch);
501 if(ch == '\0' || sscanf(s - 1, "%d", datestamp) != 1) {
506 skip_whitespace(s, ch);
511 if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
518 skip_whitespace(s, ch);
523 skip_non_whitespace(s, ch);
529 /* if output_find is NULL */
530 /* return 1 if this is the logfile for this label */
531 /* return 0 if this is not the logfile for this label */
533 /* add to output_find all the dump for this label */
534 /* return the number of dump added. */
535 int search_logfile(output_find, label, datestamp, datestamp_aux, logfile)
536 find_result_t **output_find;
537 char *label, *logfile;
538 int datestamp, datestamp_aux;
541 char *host, *host_undo;
542 char *disk, *disk_undo;
546 int level, filenum, ck_datestamp, tapematch;
547 int passlabel, ck_datestamp2;
552 if((logf = fopen(logfile, "r")) == NULL)
553 error("could not open logfile %s: %s", logfile, strerror(errno));
555 /* check that this log file corresponds to the right tape */
557 while(!tapematch && get_logline(logf)) {
558 if(curlog == L_START && curprog == P_TAPER) {
559 if(parse_taper_datestamp_log(curstr,
560 &ck_datestamp, &ck_label) == 0) {
561 printf("strange log line \"start taper %s\"\n", curstr);
562 } else if(ck_datestamp == datestamp
563 && strcmp(ck_label, label) == 0) {
569 if(output_find == NULL) {
584 while(get_logline(logf) && passlabel) {
585 if(curlog == L_SUCCESS && curprog == P_TAPER && passlabel) filenum++;
586 if(curlog == L_START && curprog == P_TAPER) {
587 if(parse_taper_datestamp_log(curstr,
588 &ck_datestamp2, &ck_label) == 0) {
589 printf("strange log line \"start taper %s\"\n", curstr);
590 } else if (strcmp(ck_label, label)) {
591 passlabel = !passlabel;
594 if(curlog == L_SUCCESS || curlog == L_FAIL) {
598 skip_whitespace(s, ch);
600 printf("strange log line \"%s\"\n", curstr);
604 skip_non_whitespace(s, ch);
608 skip_whitespace(s, ch);
610 printf("strange log line \"%s\"\n", curstr);
614 skip_non_whitespace(s, ch);
618 skip_whitespace(s, ch);
619 if(ch == '\0' || sscanf(s - 1, "%d", &datestampI) != 1) {
620 printf("strange log line \"%s\"\n", curstr);
625 if(datestampI < 100) { /* old log didn't have datestamp */
627 datestampI = datestamp;
630 skip_whitespace(s, ch);
631 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
632 printf("strange log line \"%s\"\n", curstr);
638 skip_whitespace(s, ch);
640 printf("strange log line \"%s\"\n", curstr);
644 if((s = strchr(s, '\n')) != NULL) {
648 dp = lookup_disk(host,disk);
650 if (dynamic_disklist == 0) {
653 dp = add_disk(host, disk);
654 enqueue_disk(find_diskqp , dp);
656 if(find_match(host, disk)) {
657 if(curprog == P_TAPER) {
658 find_result_t *new_output_find =
659 (find_result_t *)alloc(sizeof(find_result_t));
660 new_output_find->next=*output_find;
661 new_output_find->datestamp=datestampI;
662 new_output_find->datestamp_aux=datestamp_aux;
663 new_output_find->hostname=stralloc(host);
664 new_output_find->diskname=stralloc(disk);
665 new_output_find->level=level;
666 new_output_find->label=stralloc(label);
667 new_output_find->filenum=filenum;
668 if(curlog == L_SUCCESS)
669 new_output_find->status=stralloc("OK");
671 new_output_find->status=stralloc(rest);
672 *output_find=new_output_find;
674 else if(curlog == L_FAIL) { /* print other failures too */
675 find_result_t *new_output_find =
676 (find_result_t *)alloc(sizeof(find_result_t));
677 new_output_find->next=*output_find;
678 new_output_find->datestamp=datestamp;
679 new_output_find->datestamp_aux=datestamp_aux;
680 new_output_find->hostname=stralloc(host);
681 new_output_find->diskname=stralloc(disk);
682 new_output_find->level=level;
683 new_output_find->label=stralloc("---");
684 new_output_find->filenum=0;
685 new_output_find->status=vstralloc(
687 program_str[(int)curprog],
691 *output_find=new_output_find;
700 find_result_t *dump_exist(output_find, hostname, diskname, datestamp, level)
701 find_result_t *output_find;
707 find_result_t *output_find_result;
709 for(output_find_result=output_find;
711 output_find_result=output_find_result->next) {
712 if( !strcmp(output_find_result->hostname, hostname) &&
713 !strcmp(output_find_result->diskname, diskname) &&
714 output_find_result->datestamp == datestamp &&
715 output_find_result->level == level) {
717 return output_find_result;