/* WARNING: Function accesses globals find_diskqp, curlog, curlog, curstr, * dynamic_disklist */ gboolean search_logfile( find_result_t **output_find, const char *label, const char *passed_datestamp, const char *logfile, disklist_t * dynamic_disklist) { FILE *logf; char *host, *host_undo; char *disk = NULL, *qdisk, *disk_undo; char *date, *date_undo; int partnum; int totalparts; int maxparts = -1; char *number; int fileno; char *current_label; char *rest, *rest_undo; char *ck_label=NULL; int level = 0; off_t filenum; char *ck_datestamp=NULL; char *datestamp; char *s; int ch; disk_t *dp; GHashTable* valid_label; GHashTable* part_by_dle; find_result_t *part_find; find_result_t *a_part_find; gboolean right_label = FALSE; gboolean found_something = FALSE; double sec; off_t kb; off_t bytes; off_t orig_kb; int taper_part = 0; g_return_val_if_fail(output_find != NULL, 0); g_return_val_if_fail(logfile != NULL, 0); current_label = g_strdup(""); if (string_chunk == NULL) { string_chunk = g_string_chunk_new(32768); } valid_label = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); part_by_dle = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); datestamp = g_strdup(passed_datestamp); if((logf = fopen(logfile, "r")) == NULL) { error(_("could not open logfile %s: %s"), logfile, strerror(errno)); /*NOTREACHED*/ } filenum = (off_t)0; while(get_logline(logf)) { if (curlog == L_START && curprog == P_TAPER) { amfree(ck_label); ck_datestamp = NULL; if(parse_taper_datestamp_log(curstr, &ck_datestamp, &ck_label) == 0) { g_printf(_("strange log line in %s \"start taper %s\"\n"), logfile, curstr); continue; } if (datestamp != NULL) { if (!g_str_equal(datestamp, ck_datestamp)) { g_printf(_("Log file %s stamped %s, expecting %s!\n"), logfile, ck_datestamp, datestamp); amfree(ck_label); break; } } right_label = volume_matches(label, ck_label, ck_datestamp); if (right_label && ck_label) { g_hash_table_insert(valid_label, g_strdup(ck_label), GINT_TO_POINTER(1)); } if (label && datestamp && right_label) { found_something = TRUE; } amfree(current_label); current_label = ck_label; ck_label = NULL; if (datestamp == NULL) { datestamp = g_strdup(ck_datestamp); } filenum = (off_t)0; } if (!datestamp) continue; if (right_label && (curlog == L_SUCCESS || curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTPARTIAL) && curprog == P_TAPER) { filenum++; } else if (right_label && curlog == L_PARTIAL && curprog == P_TAPER && taper_part == 0) { filenum++; } partnum = -1; totalparts = -1; if (curlog == L_SUCCESS || curlog == L_CHUNKSUCCESS || curlog == L_DONE || curlog == L_FAIL || curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTIAL || curlog == L_PARTPARTIAL ) { s = curstr; ch = *s++; skip_whitespace(s, ch); if(ch == '\0') { g_printf(_("strange log line in %s \"%s\"\n"), logfile, curstr); continue; } if (curlog == L_PART || curlog == L_PARTPARTIAL) { char *part_label; char *qpart_label = s - 1; taper_part++; skip_quoted_string(s, ch); s[-1] = '\0'; part_label = unquote_string(qpart_label); if (!g_hash_table_lookup(valid_label, part_label)) { amfree(part_label); continue; } amfree(current_label); current_label = part_label; skip_whitespace(s, ch); if(ch == '\0') { g_printf("strange log line in %s \"%s\"\n", logfile, curstr); continue; } number = s - 1; skip_non_whitespace(s, ch); s[-1] = '\0'; fileno = atoi(number); filenum = fileno; if (filenum == 0) continue; skip_whitespace(s, ch); if(ch == '\0') { g_printf("strange log line in %s \"%s\"\n", logfile, curstr); continue; } } else { taper_part = 0; } host = s - 1; skip_non_whitespace(s, ch); host_undo = s - 1; *host_undo = '\0'; skip_whitespace(s, ch); if(ch == '\0') { g_printf(_("strange log line in %s \"%s\"\n"), logfile, curstr); continue; } qdisk = s - 1; skip_quoted_string(s, ch); disk_undo = s - 1; *disk_undo = '\0'; disk = unquote_string(qdisk); skip_whitespace(s, ch); if(ch == '\0') { g_printf(_("strange log line in %s \"%s\"\n"), logfile, curstr); amfree(disk); continue; } date = s - 1; skip_non_whitespace(s, ch); date_undo = s - 1; *date_undo = '\0'; if(strlen(date) < 3) { /* old log didn't have datestamp */ level = atoi(date); date = datestamp; partnum = 1; totalparts = 1; } else { if (curprog == P_TAPER && (curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTPARTIAL || curlog == L_PARTIAL || curlog == L_DONE)) { char *s1, ch1; skip_whitespace(s, ch); number = s - 1; skip_non_whitespace(s, ch); s1 = &s[-1]; ch1 = *s1; skip_whitespace(s, ch); if (*(s-1) != '[') { *s1 = ch1; sscanf(number, "%d/%d", &partnum, &totalparts); if (partnum > maxparts) maxparts = partnum; if (totalparts > maxparts) maxparts = totalparts; } else { /* nparts is not in all PARTIAL lines */ partnum = 1; totalparts = 1; s = number + 1; } } else { skip_whitespace(s, ch); } if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) { g_printf(_("Fstrange log line in %s \"%s\"\n"), logfile, s-1); amfree(disk); continue; } skip_integer(s, ch); } skip_whitespace(s, ch); if(ch == '\0') { g_printf(_("strange log line in %s \"%s\"\n"), logfile, curstr); amfree(disk); continue; } rest = s - 1; skip_non_whitespace(s, ch); rest_undo = s - 1; *rest_undo = '\0'; if (g_str_equal(rest, "[sec")) { skip_whitespace(s, ch); if(ch == '\0') { g_printf(_("strange log line in %s \"%s\"\n"), logfile, curstr); amfree(disk); continue; } sec = atof(s - 1); skip_non_whitespace(s, ch); skip_whitespace(s, ch); rest = s - 1; skip_non_whitespace(s, ch); rest_undo = s - 1; *rest_undo = '\0'; if (!g_str_equal(rest, "kb") && !g_str_equal(rest, "bytes")) { g_printf(_("Bstrange log line in %s \"%s\"\n"), logfile, curstr); amfree(disk); continue; } skip_whitespace(s, ch); if (ch == '\0') { g_printf(_("strange log line in %s \"%s\"\n"), logfile, curstr); amfree(disk); continue; } if (g_str_equal(rest, "kb")) { kb = atof(s - 1); bytes = 0; } else { bytes = atof(s - 1); kb = bytes / 1024; } skip_non_whitespace(s, ch); skip_whitespace(s, ch); rest = s - 1; skip_non_whitespace(s, ch); rest_undo = s - 1; *rest_undo = '\0'; if (!g_str_equal(rest, "kps")) { g_printf(_("Cstrange log line in %s \"%s\"\n"), logfile, curstr); amfree(disk); continue; } skip_whitespace(s, ch); if (ch == '\0') { g_printf(_("strange log line in %s \"%s\"\n"), logfile, curstr); amfree(disk); continue; } /* kps = atof(s - 1); */ skip_non_whitespace(s, ch); skip_whitespace(s, ch); rest = s - 1; skip_non_whitespace(s, ch); rest_undo = s - 1; *rest_undo = '\0'; if (!g_str_equal(rest, "orig-kb")) { orig_kb = 0; } else { skip_whitespace(s, ch); if(ch == '\0') { g_printf(_("strange log line in %s \"%s\"\n"), logfile, curstr); amfree(disk); continue; } orig_kb = atof(s - 1); } } else { sec = 0; kb = 0; bytes = 0; orig_kb = 0; *rest_undo = ' '; } if (g_str_has_prefix(rest, "error")) rest += 6; if (g_str_has_prefix(rest, "config")) rest += 7; dp = lookup_disk(host,disk); if ( dp == NULL ) { if (dynamic_disklist == NULL) { amfree(disk); continue; } dp = add_disk(dynamic_disklist, host, disk); enqueue_disk(dynamic_disklist, dp); } if (find_match(host, disk)) { if(curprog == P_TAPER) { char *key = g_strdup_printf( "HOST:%s DISK:%s: DATE:%s LEVEL:%d", host, disk, date, level); find_result_t *new_output_find = g_new0(find_result_t, 1); part_find = g_hash_table_lookup(part_by_dle, key); maxparts = partnum; if (maxparts < totalparts) maxparts = totalparts; for (a_part_find = part_find; a_part_find; a_part_find = a_part_find->next) { if (maxparts < a_part_find->partnum) maxparts = a_part_find->partnum; if (maxparts < a_part_find->totalparts) maxparts = a_part_find->totalparts; } new_output_find->timestamp = g_string_chunk_insert_const(string_chunk, date); new_output_find->write_timestamp = g_string_chunk_insert_const(string_chunk, datestamp); new_output_find->hostname=g_string_chunk_insert_const(string_chunk, host); new_output_find->diskname=g_string_chunk_insert_const(string_chunk, disk); new_output_find->level=level; new_output_find->partnum = partnum; new_output_find->totalparts = totalparts; new_output_find->label=g_string_chunk_insert_const(string_chunk, current_label); new_output_find->status=NULL; new_output_find->dump_status=NULL; new_output_find->message=""; new_output_find->filenum=filenum; new_output_find->sec=sec; new_output_find->kb=kb; new_output_find->bytes=bytes; new_output_find->orig_kb=orig_kb; new_output_find->next=NULL; if (curlog == L_SUCCESS) { new_output_find->status = "OK"; new_output_find->dump_status = "OK"; new_output_find->next = *output_find; new_output_find->partnum = 1; /* L_SUCCESS is pre-splitting */ *output_find = new_output_find; found_something = TRUE; } else if (curlog == L_CHUNKSUCCESS || curlog == L_DONE || curlog == L_PARTIAL || curlog == L_FAIL) { /* result line */ if (curlog == L_PARTIAL || curlog == L_FAIL) { /* set dump_status of each part */ for (a_part_find = part_find; a_part_find; a_part_find = a_part_find->next) { if (curlog == L_PARTIAL) a_part_find->dump_status = "PARTIAL"; else { a_part_find->dump_status = "FAIL"; a_part_find->message = g_string_chunk_insert_const(string_chunk, rest); } } } else { if (maxparts > -1) { /* format with part */ /* must check if all part are there */ int num_part = maxparts; for (a_part_find = part_find; a_part_find; a_part_find = a_part_find->next) { if (a_part_find->partnum == num_part && g_str_equal(a_part_find->status, "OK")) num_part--; } /* set dump_status of each part */ for (a_part_find = part_find; a_part_find; a_part_find = a_part_find->next) { if (num_part == 0) { a_part_find->dump_status = "OK"; } else { a_part_find->dump_status = "FAIL"; a_part_find->message = g_string_chunk_insert_const(string_chunk, "Missing part"); } } } } if (curlog == L_DONE) { for (a_part_find = part_find; a_part_find; a_part_find = a_part_find->next) { if (a_part_find->totalparts == -1) { a_part_find->totalparts = maxparts; } if (a_part_find->orig_kb == 0) { a_part_find->orig_kb = orig_kb; } } } if (part_find) { /* find last element */ for (a_part_find = part_find; a_part_find->next != NULL; a_part_find=a_part_find->next) { } /* merge part_find to *output_find */ a_part_find->next = *output_find; *output_find = part_find; part_find = NULL; maxparts = -1; found_something = TRUE; g_hash_table_remove(part_by_dle, key); } free_find_result(&new_output_find); } else { /* part line */ if (curlog == L_PART || curlog == L_CHUNK) { new_output_find->status = "OK"; new_output_find->dump_status = "OK"; } else { /* PARTPARTIAL */ new_output_find->status = "PARTIAL"; new_output_find->dump_status = "PARTIAL"; } /* Add to part_find list */ if (part_find) { new_output_find->next = part_find; part_find = new_output_find; } else { new_output_find->next = NULL; part_find = new_output_find; } g_hash_table_insert(part_by_dle, g_strdup(key), part_find); found_something = TRUE; } amfree(key); } else if(curlog == L_FAIL) { char *status_failed; /* print other failures too -- this is a hack to ensure that failures which * did not make it to tape are also listed in the output of 'amadmin x find'; * users that do not want this information (e.g., Amanda::DB::Catalog) should * filter dumps with a NULL label. */ find_result_t *new_output_find = g_new0(find_result_t, 1); new_output_find->next = *output_find; new_output_find->timestamp = g_string_chunk_insert_const(string_chunk, date); new_output_find->write_timestamp = g_strdup("00000000000000"); /* dump was not written.. */ new_output_find->hostname=g_string_chunk_insert_const(string_chunk, host); new_output_find->diskname=g_string_chunk_insert_const(string_chunk, disk); new_output_find->level=level; new_output_find->label=NULL; new_output_find->partnum=partnum; new_output_find->totalparts=totalparts; new_output_find->filenum=0; new_output_find->sec=sec; new_output_find->kb=kb; new_output_find->bytes=bytes; new_output_find->orig_kb=orig_kb; status_failed = g_strjoin(NULL, "FAILED (", program_str[(int)curprog], ") ", rest, NULL); new_output_find->status = g_string_chunk_insert_const(string_chunk, status_failed); amfree(status_failed); new_output_find->dump_status=""; new_output_find->message=""; *output_find=new_output_find; found_something = TRUE; maxparts = -1; } } amfree(disk); } } g_hash_table_destroy(valid_label); afclose(logf); amfree(datestamp); amfree(current_label); amfree(disk); return found_something; }
int main( int argc, char ** argv) { GList *dlist; GList *dlist1; disk_t *diskp; disklist_t diskl; size_t i; char *conf_diskfile; char *conf_tapelist; char *conf_indexdir; find_result_t *output_find; time_t tmp_time; int amtrmidx_debug = 0; config_overrides_t *cfg_ovr = NULL; gboolean compress_index; gboolean sort_index; char *lock_file; file_lock *lock_index; if (argc > 1 && argv[1] && g_str_equal(argv[1], "--version")) { printf("amtrmidx-%s\n", VERSION); return (0); } /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(-1, 0); safe_cd(); set_pname("amtrmidx"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_SERVER); dbprintf(_("%s: version %s\n"), argv[0], VERSION); cfg_ovr = extract_commandline_config_overrides(&argc, &argv); if (argc > 1 && g_str_equal(argv[1], "-t")) { amtrmidx_debug = 1; argc--; argv++; } if (argc < 2) { g_fprintf(stderr, _("Usage: %s [-t] <config> [-o configoption]*\n"), argv[0]); return 1; } set_config_overrides(cfg_ovr); config_init_with_global(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, argv[1]); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); read_diskfile(conf_diskfile, &diskl); amfree(conf_diskfile); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); compress_index = getconf_boolean(CNF_COMPRESS_INDEX); sort_index = getconf_boolean(CNF_SORT_INDEX); output_find = find_dump(&diskl); conf_indexdir = config_dir_relative(getconf_str(CNF_INDEXDIR)); /* take a lock file to prevent concurent trim */ lock_file = g_strdup_printf("%s/%s", conf_indexdir, "lock"); lock_index = file_lock_new(lock_file); if (file_lock_lock_wr(lock_index) != 0) goto lock_failed; /* now go through the list of disks and find which have indexes */ time(&tmp_time); tmp_time -= 7*24*60*60; /* back one week */ for (dlist = diskl.head; dlist != NULL; dlist = dlist->next) { diskp = dlist->data; if (diskp->index) { char *indexdir, *qindexdir; DIR *d; struct dirent *f; char **names; size_t name_length; size_t name_count; char *host; char *disk, *qdisk; size_t len_date; disk_t *dp; GSList *matching_dp = NULL; /* get listing of indices, newest first */ host = sanitise_filename(diskp->host->hostname); disk = sanitise_filename(diskp->name); qdisk = quote_string(diskp->name); indexdir = g_strjoin(NULL, conf_indexdir, "/", host, "/", disk, "/", NULL); qindexdir = quote_string(indexdir); /* find all dles that use the same indexdir */ for (dlist1 = diskl.head; dlist1 != NULL; dlist1 = dlist1->next) { char *dp_host, *dp_disk; dp = dlist1->data; dp_host = sanitise_filename(dp->host->hostname); dp_disk = sanitise_filename(dp->name); if (g_str_equal(host, dp_host) && g_str_equal(disk, dp_disk)) { matching_dp = g_slist_append(matching_dp, dp); } amfree(dp_host); amfree(dp_disk); } dbprintf("%s %s -> %s\n", diskp->host->hostname, qdisk, qindexdir); amfree(qdisk); if ((d = opendir(indexdir)) == NULL) { dbprintf(_("could not open index directory %s\n"), qindexdir); amfree(host); amfree(disk); amfree(indexdir); amfree(qindexdir); g_slist_free(matching_dp); continue; } name_length = 100; names = (char **)g_malloc(name_length * sizeof(char *)); name_count = 0; while ((f = readdir(d)) != NULL) { size_t l; if(is_dot_or_dotdot(f->d_name)) { continue; } for(i = 0; i < sizeof("YYYYMMDDHHMMSS")-1; i++) { if(! isdigit((int)(f->d_name[i]))) { break; } } len_date = i; /* len_date=8 for YYYYMMDD */ /* len_date=14 for YYYYMMDDHHMMSS */ if((len_date != 8 && len_date != 14) || f->d_name[len_date] != '_' || ! isdigit((int)(f->d_name[len_date+1]))) { continue; /* not an index file */ } /* * Clear out old index temp files. */ l = strlen(f->d_name) - (sizeof(".tmp")-1); if ((l > (len_date + 1)) && (g_str_equal(f->d_name + l, ".tmp"))) { struct stat sbuf; char *path, *qpath; path = g_strconcat(indexdir, f->d_name, NULL); qpath = quote_string(path); if(lstat(path, &sbuf) != -1 && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((time_t)sbuf.st_mtime < tmp_time)) { dbprintf("rm %s\n", qpath); if(amtrmidx_debug == 0 && unlink(path) == -1) { dbprintf(_("Error removing %s: %s\n"), qpath, strerror(errno)); } } amfree(qpath); amfree(path); continue; } if(name_count >= name_length) { char **new_names; new_names = g_malloc((name_length * 2) * sizeof(char *)); memcpy(new_names, names, name_length * sizeof(char *)); amfree(names); names = new_names; name_length *= 2; } names[name_count++] = g_strdup(f->d_name); } closedir(d); qsort(names, name_count, sizeof(char *), sort_by_name_reversed); /* * Search for the first full dump past the minimum number * of index files to keep. */ for(i = 0; i < name_count; i++) { char *datestamp; int level; size_t len_date; int matching = 0; GSList *mdp; for(len_date = 0; len_date < sizeof("YYYYMMDDHHMMSS")-1; len_date++) { if(! isdigit((int)(names[i][len_date]))) { break; } } datestamp = g_strdup(names[i]); datestamp[len_date] = '\0'; if (sscanf(&names[i][len_date+1], "%d", &level) != 1) level = 0; for (mdp = matching_dp; mdp != NULL; mdp = mdp->next) { dp = mdp->data; if (dump_exist(output_find, dp->host->hostname, dp->name, datestamp, level)) { matching = 1; } } if (!matching) { struct stat sbuf; char *path, *qpath; path = g_strconcat(indexdir, names[i], NULL); qpath = quote_string(path); if(lstat(path, &sbuf) != -1 && ((sbuf.st_mode & S_IFMT) == S_IFREG) && ((time_t)sbuf.st_mtime < tmp_time)) { dbprintf("rm %s\n", qpath); if(amtrmidx_debug == 0 && unlink(path) == -1) { dbprintf(_("Error removing %s: %s\n"), qpath, strerror(errno)); } } amfree(qpath); amfree(path); } /* Did it require un/compression and/or sorting */ { char *orig_name = getindexfname(host, disk, datestamp, level); char *sorted_name = getindex_sorted_fname(host, disk, datestamp, level); char *sorted_gz_name = getindex_sorted_gz_fname(host, disk, datestamp, level); char *unsorted_name = getindex_unsorted_fname(host, disk, datestamp, level); char *unsorted_gz_name = getindex_unsorted_gz_fname(host, disk, datestamp, level); gboolean orig_exist = FALSE; gboolean sorted_exist = FALSE; gboolean sorted_gz_exist = FALSE; gboolean unsorted_exist = FALSE; gboolean unsorted_gz_exist = FALSE; int fd; int uncompress_err_fd = -1; int sort_err_fd = -1; int compress_err_fd = -1; pid_t uncompress_pid = -1; pid_t sort_pid = -1; pid_t compress_pid = -1; orig_exist = file_exists(orig_name); sorted_exist = file_exists(sorted_name); sorted_gz_exist = file_exists(sorted_gz_name); unsorted_exist = file_exists(unsorted_name); unsorted_gz_exist = file_exists(unsorted_gz_name); if (sort_index && compress_index) { if (!sorted_gz_exist) { if (sorted_exist) { // COMPRESS compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name); unlink(sorted_name); } else if (unsorted_exist) { // SORT AND COMPRESS sort_pid = run_sort(-1, &fd, &sort_err_fd, unsorted_name, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(unsorted_name); } else if (unsorted_gz_exist) { // UNCOMPRESS SORT AND COMPRESS uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL); sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS SORT AND COMPRESS uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL); sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL); compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name); unlink(orig_name); } } else { if (sorted_exist) { unlink(sorted_name); } if (unsorted_exist) { unlink(unsorted_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (sort_index && !compress_index) { if (!sorted_exist) { if (sorted_gz_exist) { // UNCOMPRESS uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name); unlink(sorted_gz_name); } else if (unsorted_exist) { // SORT sort_pid = run_sort(-1, NULL, &sort_err_fd, unsorted_name, sorted_name); unlink(unsorted_name); } else if (unsorted_gz_exist) { // UNCOMPRESS AND SORT uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL); sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS AND SORT uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL); sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name); unlink(orig_name); } } else { if (sorted_gz_exist) { unlink(sorted_gz_name); } if (unsorted_exist) { unlink(unsorted_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (!sort_index && compress_index) { if (!sorted_gz_exist && !unsorted_gz_exist) { if (sorted_exist) { // COMPRESS sorted compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name); unlink(sorted_name); } else if (unsorted_exist) { // COMPRESS unsorted compress_pid = run_compress(-1, NULL, &compress_err_fd, unsorted_name, unsorted_gz_name); unlink(unsorted_name); } else if (orig_exist) { // RENAME orig rename(orig_name, unsorted_gz_name); } } else { if (sorted_exist) { unlink(sorted_name); } if (unsorted_exist) { unlink(unsorted_name); } if (sorted_gz_exist && unsorted_gz_exist) { unlink(unsorted_gz_name); } } } else if (!sort_index && !compress_index) { if (!sorted_exist && !unsorted_exist) { if (sorted_gz_exist) { // UNCOMPRESS sorted uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name); unlink(sorted_gz_name); } else if (unsorted_gz_exist) { // UNCOMPRESS unsorted uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, unsorted_gz_name, unsorted_name); unlink(unsorted_gz_name); } else if (orig_exist) { // UNCOMPRESS orig uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, orig_name, unsorted_name); unlink(orig_name); } } else { if (sorted_gz_exist) { unlink(sorted_gz_name); } if (unsorted_gz_exist) { unlink(unsorted_gz_name); } if (sorted_exist && unsorted_exist) { unlink(unsorted_name); } } } if (uncompress_pid != -1) wait_process(uncompress_pid, uncompress_err_fd, "uncompress"); if (sort_pid != -1) wait_process(sort_pid, sort_err_fd, "sort"); if (compress_pid != -1) wait_process(compress_pid, compress_err_fd, "compress"); g_free(orig_name); g_free(sorted_name); g_free(sorted_gz_name); g_free(unsorted_name); g_free(unsorted_gz_name); } amfree(datestamp); amfree(names[i]); } g_slist_free(matching_dp); amfree(names); amfree(host); amfree(disk); amfree(indexdir); amfree(qindexdir); } } file_lock_unlock(lock_index); lock_failed: file_lock_free(lock_index); amfree(conf_indexdir); amfree(lock_file); free_find_result(&output_find); clear_tapelist(); free_disklist(&diskl); unload_disklist(); dbclose(); return 0; }
/* * Build the list of tapes we'll be wanting, and include data about the * files we want from said tapes while we're at it (the whole find_result * should do fine) */ tapelist_t * list_needed_tapes( GSList * dumpspecs, int only_one, disklist_t *diskqp) { GSList *needed_tapes = NULL; GSList *seen_dumps = NULL; GSList *iter, *iter2; find_result_t *alldumps = NULL; find_result_t *curmatch = NULL; find_result_t *matches = NULL; tapelist_t *tapes = NULL; int usage_order_counter = 0; char *conf_tapelist; /* Load the tape list */ conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { error(_("could not load tapelist \"%s\""), conf_tapelist); /*NOTREACHED*/ } amfree(conf_tapelist); /* Grab a find_output_t of all logged dumps */ alldumps = find_dump(diskqp); if(alldumps == NULL){ g_fprintf(stderr, _("No dump records found\n")); dbclose(); exit(1); } /* Compare all known dumps to our match list, note what we'll need */ matches = dumps_match_dumpspecs(alldumps, dumpspecs, 1); /* D = dump_timestamp, newest first * h = hostname * k = diskname * l = level * p = partnum * w = write_timestamp */ sort_find_result("Dhklpw", &matches); for(curmatch = matches; curmatch; curmatch = curmatch->next) { int havetape = 0; /* keep only first dump if only_one */ if (only_one && curmatch != matches && (strcmp(curmatch->hostname, matches->hostname) || strcmp(curmatch->diskname, matches->diskname) || strcmp(curmatch->timestamp, matches->timestamp) || curmatch->level != matches->level)) { continue; } if(strcmp("OK", curmatch->status)){ g_fprintf(stderr,_("Dump %s %s %s %d had status '%s', skipping\n"), curmatch->timestamp, curmatch->hostname, curmatch->diskname, curmatch->level, curmatch->status); continue; } for(iter = needed_tapes; iter; iter = iter->next) { needed_tape_t *curtape = iter->data; if (!strcmp(curtape->label, curmatch->label)) { int keep = 1; havetape = 1; for(iter2 = curtape->files; iter2; iter2 = iter2->next){ find_result_t *rsttemp = iter2->data; if(curmatch->filenum == rsttemp->filenum){ g_fprintf(stderr, _("Seeing multiple entries for tape " "%s file %lld, using most recent\n"), curtape->label, (long long)curmatch->filenum); keep = 0; } } if(!keep){ break; } curtape->isafile = (curmatch->filenum < 1); curtape->files = g_slist_prepend(curtape->files, curmatch); break; } } if (!havetape) { needed_tape_t *newtape = g_new0(needed_tape_t, 1); newtape->usage_order = usage_order_counter++; newtape->files = g_slist_prepend(newtape->files, curmatch); newtape->isafile = (curmatch->filenum < 1); newtape->label = curmatch->label; needed_tapes = g_slist_prepend(needed_tapes, newtape); } /* if(!havetape) */ } /* for(curmatch = matches ... */ if(g_slist_length(needed_tapes) == 0){ g_fprintf(stderr, _("No matching dumps found\n")); exit(1); /* NOTREACHED */ } /* sort the tapelist by tape write_timestamp */ needed_tapes = g_slist_sort(needed_tapes, sort_needed_tapes_by_write_timestamp); /* stick that list in a structure that librestore will understand, removing * files we have already seen in the process; this prefers the earliest written * copy of any dumps which are available on multiple tapes */ seen_dumps = NULL; for(iter = needed_tapes; iter; iter = iter->next) { needed_tape_t *curtape = iter->data; for(iter2 = curtape->files; iter2; iter2 = iter2->next) { find_result_t *curfind = iter2->data; find_result_t *prev; GSList *iter; int have_part; /* have we already seen this? */ have_part = 0; for (iter = seen_dumps; iter; iter = iter->next) { prev = iter->data; if (!strcmp(prev->partnum, curfind->partnum) && !strcmp(prev->hostname, curfind->hostname) && !strcmp(prev->diskname, curfind->diskname) && !strcmp(prev->timestamp, curfind->timestamp) && prev->level == curfind->level) { have_part = 1; break; } } if (!have_part) { seen_dumps = g_slist_prepend(seen_dumps, curfind); tapes = append_to_tapelist(tapes, curtape->label, curfind->filenum, -1, curtape->isafile); } } } /* free our resources */ for (iter = needed_tapes; iter; iter = iter->next) { needed_tape_t *curtape = iter->data; g_slist_free(curtape->files); g_free(curtape); } g_slist_free(seen_dumps); g_slist_free(needed_tapes); free_find_result(&matches); /* and we're done */ g_fprintf(stderr, _("%d tape(s) needed for restoration\n"), num_entries(tapes)); return(tapes); }