capture uncaptured change
[debian/amanda] / server-src / amindexd.c
index 34587d46eda991f76be13c0259de05df1cdf3f19..951151bfd42bd39ac716cac90fb1522d8fae0f67 100644 (file)
@@ -24,7 +24,7 @@
  * file named AUTHORS, in the root directory of this distribution.
  */
 /*
- * $Id: amindexd.c,v 1.106.2.2 2006/09/27 12:04:09 martinea Exp $
+ * $Id: amindexd.c,v 1.106 2006/07/25 18:27:57 martinea Exp $
  *
  * This is the server daemon part of the index client/server system.
  * It is assumed that this is launched from inetd instead of being
 #include "tapefile.h"
 #include "util.h"
 #include "amandad.h"
+#include "pipespawn.h"
 
 #include <grp.h>
 
+#define amindexd_debug(i,x) do {       \
+       if ((i) <= debug_amindexd) {    \
+           dbprintf(x);                \
+       }                               \
+} while (0)
+
 typedef struct REMOVE_ITEM
 {
     char *filename;
@@ -67,7 +74,6 @@ typedef struct REMOVE_ITEM
 /* state */
 static int from_amandad;
 static char local_hostname[MAX_HOSTNAME_LENGTH+1];     /* me! */
-static char *remote_hostname = NULL;                   /* the client */
 static char *dump_hostname = NULL;             /* machine we are restoring */
 static char *disk_name;                                /* disk we are restoring */
 char *qdisk_name = NULL;                       /* disk we are restoring */
@@ -75,7 +81,6 @@ static char *target_date = NULL;
 static disklist_t disk_list;                   /* all disks in cur config */
 static find_result_t *output_find = NULL;
 static g_option_t *g_options = NULL;
-static int cmdfdin, cmdfdout;
 
 static int amindexd_debug = 0;
 
@@ -101,7 +106,7 @@ static void lreply(int, char *, ...)
     __attribute__ ((format (printf, 2, 3)));
 static void fast_lreply(int, char *, ...)
     __attribute__ ((format (printf, 2, 3)));
-static int is_dump_host_valid(char *);
+static am_host_t *is_dump_host_valid(char *);
 static int is_disk_valid(char *);
 static int is_config_valid(char *);
 static int build_disk_table(void);
@@ -114,6 +119,11 @@ static int tapedev_is(void);
 static int are_dumps_compressed(void);
 static char *amindexd_nicedate (char *datestamp);
 static int cmp_date (const char *date1, const char *date2);
+static char *clean_backslash(char *line);
+static char *get_index_name(char *dump_hostname, char *hostname,
+                           char *diskname, char *timestamps, int level);
+static int get_index_dir(char *dump_hostname, char *hostname, char *diskname);
+
 int main(int, char **);
 
 static REMOVE_ITEM *
@@ -144,6 +154,18 @@ uncompress_file(
     struct stat stat_filename;
     int result;
     size_t len;
+    int pipe_from_gzip;
+    int pipe_to_sort;
+    int indexfd;
+    int nullfd;
+    int debugfd;
+    int debugnullfd;
+    char line[STR_SIZE];
+    FILE *pipe_stream;
+    pid_t pid_gzip;
+    pid_t pid_sort;
+    amwait_t  wait_status;
+
 
     filename = stralloc(filename_gz);
     len = strlen(filename);
@@ -173,26 +195,95 @@ uncompress_file(
            return NULL;
        }
 
-       cmd = vstralloc(UNCOMPRESS_PATH,
 #ifdef UNCOMPRESS_OPT
-                       " ", UNCOMPRESS_OPT,
+#  define PARAM_UNCOMPRESS_OPT UNCOMPRESS_OPT
+#else
+#  define PARAM_UNCOMPRESS_OPT skip_argument
 #endif
-                       " \'", filename_gz, "\'",
-                       " 2>/dev/null",
-                       " | (LC_ALL=C; export LC_ALL ; sort) ",
-                       " > ", "\'", filename, "\'",
-                       NULL);
-       dbprintf(("%s: uncompress command: %s\n",
-                 debug_prefix_time(NULL), cmd));
-       if (system(cmd) != 0) {
-           *emsg = newvstralloc(*emsg, "\"", cmd, "\" failed", NULL);
-           unlink(filename);
-           errno = -1;
+
+       debugfd = dbfd();
+       debugnullfd = 0;
+       if(debugfd < 0) {
+           debugfd = open("/dev/null", O_WRONLY);
+           debugnullfd = 1;
+       }
+
+       nullfd = open("/dev/null", O_RDONLY);
+       indexfd = open(filename,O_WRONLY|O_CREAT, 0600);
+       if (indexfd == -1) {
+           *emsg = newvstralloc(*emsg, "Can't open '",
+                                filename, "' for writting: ",
+                                strerror(errno),
+                                NULL);
+           dbprintf(("%s\n",*emsg));
+           amfree(filename);
+           return NULL;
+       }
+
+       /* start the uncompress process */
+       putenv(stralloc("LC_ALL=C"));
+       pid_gzip = pipespawn(UNCOMPRESS_PATH, STDOUT_PIPE,
+                            &nullfd, &pipe_from_gzip, &debugfd,
+                            UNCOMPRESS_PATH, PARAM_UNCOMPRESS_OPT,
+                            filename_gz, NULL);
+       aclose(nullfd);
+
+       pipe_stream = fdopen(pipe_from_gzip,"r");
+       if(pipe_stream == NULL) {
+           *emsg = newvstralloc(*emsg, "Can't fdopen pipe from gzip: ",
+                                strerror(errno),
+                                NULL);
+           dbprintf(("%s\n",*emsg));
            amfree(filename);
-           amfree(cmd);
            return NULL;
        }
 
+       /* start the sort process */
+       pid_sort = pipespawn(SORT_PATH, STDIN_PIPE,
+                            &pipe_to_sort, &indexfd, &debugfd,
+                            SORT_PATH, NULL);
+       if (debugnullfd == 1)
+           aclose(debugfd);
+       aclose(indexfd);
+
+       /* send all ouput from uncompress process to sort process */
+       /* clean the data with clean_backslash */
+       while (fgets(line, STR_SIZE, pipe_stream) != NULL) {
+           if (line[0] != '\0') {
+               if (index(line,'/')) {
+                   clean_backslash(line);
+                   fullwrite(pipe_to_sort,line,strlen(line));
+               }
+           }
+       }
+
+       fclose(pipe_stream);
+       aclose(pipe_to_sort);
+       if (waitpid(pid_gzip, &wait_status, 0) < 0) {
+           if (!WIFEXITED(wait_status)) {
+               dbprintf(("Uncompress exited with signal %d",
+                         WTERMSIG(wait_status)));
+           } else if (WEXITSTATUS(wait_status) != 0) {
+               dbprintf(("Uncompress exited with status %d",
+                         WEXITSTATUS(wait_status)));
+           } else {
+               dbprintf(("Uncompres returned negative value: %s",
+                         strerror(errno)));
+           }
+       }
+       if (waitpid(pid_sort, &wait_status, 0)) {
+           if (!WIFEXITED(wait_status)) {
+               dbprintf(("Sort exited with signal %d",
+                         WTERMSIG(wait_status)));
+           } else if (WEXITSTATUS(wait_status) != 0) {
+               dbprintf(("Sort exited with status %d",
+                         WEXITSTATUS(wait_status)));
+           } else {
+               dbprintf(("Sort returned negative value: %s",
+                         strerror(errno)));
+           }
+       }
+
        /* add at beginning */
        remove_file = (REMOVE_ITEM *)alloc(SIZEOF(REMOVE_ITEM));
        remove_file->filename = stralloc(filename);
@@ -219,7 +310,7 @@ process_ls_dump(
     int                recursive,
     char **    emsg)
 {
-    char *line = NULL;
+    char line[STR_SIZE];
     char *old_line = NULL;
     char *filename = NULL;
     char *filename_gz;
@@ -235,8 +326,13 @@ process_ls_dump(
        dir_slash = stralloc2(dir, "/");
     }
 
-    filename_gz = getindexfname(dump_hostname, disk_name, dump_item->date,
-                               dump_item->level);
+    filename_gz = get_index_name(dump_hostname, dump_item->hostname, disk_name,
+                                dump_item->date, dump_item->level);
+    if (filename_gz == NULL) {
+       *emsg = stralloc("index file not found");
+       amfree(filename_gz);
+       return -1;
+    }
     if((filename = uncompress_file(filename_gz, emsg)) == NULL) {
        amfree(filename_gz);
        amfree(dir_slash);
@@ -253,8 +349,10 @@ process_ls_dump(
 
     len_dir_slash=strlen(dir_slash);
 
-    while ((line = agets(fp)) != NULL) {
+    while (fgets(line, STR_SIZE, fp) != NULL) {
        if (line[0] != '\0') {
+           if(line[strlen(line)-1] == '\n')
+               line[strlen(line)-1] = '\0';
            if(strncmp(dir_slash, line, len_dir_slash) == 0) {
                if(!recursive) {
                    s = line + len_dir_slash;
@@ -269,12 +367,10 @@ process_ls_dump(
                if(old_line == NULL || strcmp(line, old_line) != 0) {
                    add_dir_list_item(dump_item, line);
                    amfree(old_line);
-                   old_line = line;
-                   line = NULL;
+                   old_line = stralloc(line);
                }
            }
        }
-       /*@i@*/ amfree(line);
     }
     afclose(fp);
     /*@i@*/ amfree(old_line);
@@ -401,49 +497,39 @@ printf_arglist_function1(static void fast_lreply, int, n, char *, fmt)
 /* also do a security check on the requested dump hostname */
 /* to restrict access to index records if required */
 /* return -1 if not okay */
-static int
+static am_host_t *
 is_dump_host_valid(
     char *     host)
 {
-    struct stat dir_stat;
-    char *fn;
-    am_host_t *ihost;
+    am_host_t   *ihost;
+    disk_t      *diskp;
 
     if (config_name == NULL) {
        reply(501, "Must set config before setting host.");
-       return -1;
+       return NULL;
     }
 
-#if 0
-    /* only let a client restore itself for now unless it is the server */
-    if (strcasecmp(remote_hostname, local_hostname) == 0)
-       return 0;
-    if (strcasecmp(remote_hostname, host) != 0)
-    {
-       reply(501,
-             "You don't have the necessary permissions to set dump host to %s.",
-             buf1);
-       return -1;
-    }
-#endif
-
     /* check that the config actually handles that host */
     ihost = lookup_host(host);
     if(ihost == NULL) {
        reply(501, "Host %s is not in your disklist.", host);
-       return -1;
+       return NULL;
     }
 
-    /* assume an index dir already */
-    fn = getindexfname(host, NULL, NULL, 0);
-    if (stat (fn, &dir_stat) != 0 || !S_ISDIR(dir_stat.st_mode)) {
-       reply(501, "No index records for host: %s. Have you enabled indexing?", host);
-       amfree(fn);
-       return -1;
+    /* check if an index dir exist */
+    if(get_index_dir(host, ihost->hostname, NULL)) {
+       return ihost;
     }
 
-    amfree(fn);
-    return 0;
+    /* check if an index dir exist for at least one DLE */
+    for(diskp = ihost->disks; diskp != NULL; diskp = diskp->hostnext) {
+       if (get_index_dir(diskp->hostname, NULL, NULL)) {
+           return ihost;
+       }
+    }
+
+    reply(501, "No index records for host: %s. Have you enabled indexing?", host);
+    return NULL;
 }
 
 
@@ -451,8 +537,6 @@ static int
 is_disk_valid(
     char *disk)
 {
-    char *fn;
-    struct stat dir_stat;
     disk_t *idisk;
     char *qdisk;
 
@@ -475,16 +559,13 @@ is_disk_valid(
     }
 
     /* assume an index dir already */
-    fn = getindexfname(dump_hostname, disk, NULL, 0);
-    if (stat (fn, &dir_stat) != 0 || !S_ISDIR(dir_stat.st_mode)) {
+    if (get_index_dir(dump_hostname, idisk->hostname, disk) == 0) {
        qdisk = quote_string(disk);
        reply(501, "No index records for disk: %s. Invalid?", qdisk);
-       amfree(fn);
        amfree(qdisk);
        return -1;
     }
 
-    amfree(fn);
     return 0;
 }
 
@@ -617,8 +698,8 @@ build_disk_table(void)
            last_level = find_output->level;
            last_partnum = partnum;
            date = amindexd_nicedate(find_output->timestamp);
-           add_dump(date, find_output->level, find_output->label, 
-                    find_output->filenum, partnum);
+           add_dump(find_output->hostname, date, find_output->level,
+                    find_output->label, find_output->filenum, partnum);
            dbprintf(("%s: - %s %d %s " OFF_T_FMT " %d\n",
                     debug_prefix_time(NULL), date, find_output->level, 
                     find_output->label,
@@ -687,7 +768,7 @@ is_dir_valid_opaque(
     char *dir)
 {
     DUMP_ITEM *item;
-    char *line = NULL;
+    char line[STR_SIZE];
     FILE *fp;
     int last_level;
     char *ldir = NULL;
@@ -712,7 +793,6 @@ is_dir_valid_opaque(
        reply(502, "Must set date before asking about directories");
        return -1;
     }
-
     /* scan through till we find first dump on or before date */
     for (item=first_dump(); item!=NULL; item=next_dump(item))
        if (cmp_date(item->date, target_date) <= 0)
@@ -736,8 +816,13 @@ is_dir_valid_opaque(
     do
     {
        amfree(filename);
-       filename_gz = getindexfname(dump_hostname, disk_name,
-                                   item->date, item->level);
+       filename_gz = get_index_name(dump_hostname, item->hostname, disk_name,
+                                    item->date, item->level);
+       if (filename_gz == NULL) {
+           reply(599, "index not found");
+           amfree(ldir);
+           return -1;
+       }
        if((filename = uncompress_file(filename_gz, &emsg)) == NULL) {
            reply(599, "System error %s", emsg);
            amfree(filename_gz);
@@ -753,15 +838,16 @@ is_dir_valid_opaque(
            amfree(ldir);
            return -1;
        }
-       for(; (line = agets(fp)) != NULL; free(line)) {
+       while (fgets(line, STR_SIZE, fp) != NULL) {
            if (line[0] == '\0')
                continue;
+           if(line[strlen(line)-1] == '\n')
+               line[strlen(line)-1] = '\0';
            if (strncmp(line, ldir, ldir_len) != 0) {
                continue;                       /* not found yet */
            }
            amfree(filename);
            amfree(ldir);
-           amfree(line);
            afclose(fp);
            return 0;
        }
@@ -961,9 +1047,9 @@ tapedev_is(void)
        return 0;
     }
 
-    dbprintf(("%s: No tapedev or changer in config site.\n",
+    dbprintf(("%s: No tapedev or tpchanger in config site.\n",
               debug_prefix_time(NULL)));
-    reply(501, "Tapedev or changer not set in config file.");
+    reply(501, "Tapedev or tpchanger not set in config file.");
     return -1;
 }
 
@@ -1016,18 +1102,18 @@ main(
     char **    argv)
 {
     char *line = NULL, *part = NULL;
-    char *s, *fp;
+    char *s;
     int ch;
     char *cmd_undo, cmd_undo_ch;
     socklen_t socklen;
-    struct sockaddr_in his_addr;
-    struct hostent *his_name;
+    struct sockaddr_storage his_addr;
     char *arg = NULL;
     char *cmd;
     size_t len;
     int user_validated = 0;
     char *errstr = NULL;
     char *pgm = "amindexd";            /* in case argv[0] is not set */
+    char his_hostname[MAX_HOSTNAME_LENGTH];
 
     safe_fd(DATA_FD_OFFSET, 2);
     safe_cd();
@@ -1112,7 +1198,7 @@ main(
     }
     else {
        from_amandad = 0;
-       safe_fd(-1, 0);
+       safe_fd(dbfd(), 1);
     }
 
     if (argc > 0) {
@@ -1136,61 +1222,32 @@ main(
 
 
     if(from_amandad == 0) {
-       if(amindexd_debug) {
-           /*
-            * Fake the remote address as the local address enough to get
-            * through the security check.
-            */
-           his_name = gethostbyname(local_hostname);
-           if(his_name == NULL) {
-               error("gethostbyname(%s) failed\n", local_hostname);
-                /*NOTREACHED*/
-           }
-           assert((sa_family_t)his_name->h_addrtype == (sa_family_t)AF_INET);
-           his_addr.sin_family = (sa_family_t)his_name->h_addrtype;
-           his_addr.sin_port = (in_port_t)htons(0);
-           memcpy((void *)&his_addr.sin_addr.s_addr,
-                  (void *)his_name->h_addr_list[0], 
-                   (size_t)his_name->h_length);
-       } else {
+       if(!amindexd_debug) {
            /* who are we talking to? */
            socklen = sizeof (his_addr);
            if (getpeername(0, (struct sockaddr *)&his_addr, &socklen) == -1)
                error("getpeername: %s", strerror(errno));
+
+           /* Try a reverse (IP->hostname) resolution, and fail if it does
+            * not work -- this is a basic security check */
+           if (getnameinfo((struct sockaddr *)&his_addr, SS_LEN(&his_addr),
+                           his_hostname, sizeof(his_hostname),
+                           NULL, 0,
+                           0)) {
+               error(_("getnameinfo(%s): hostname lookup failed"),
+                     str_sockaddr(&his_addr));
+               /*NOTREACHED*/
+           }
        }
-       if ((his_addr.sin_family != (sa_family_t)AF_INET)
-               || (ntohs(his_addr.sin_port) == 20)) {
-           error("connection rejected from %s family %d port %d",
-                 inet_ntoa(his_addr.sin_addr), his_addr.sin_family,
-                 htons(his_addr.sin_port));
-           /*NOTREACHED*/
-       }
-       if ((his_name = gethostbyaddr((char *)&(his_addr.sin_addr),
-                                     sizeof(his_addr.sin_addr),
-                                     AF_INET)) == NULL) {
-           error("gethostbyaddr(%s): hostname lookup failed",
-                 inet_ntoa(his_addr.sin_addr));
-           /*NOTREACHED*/
-       }
-       fp = s = stralloc(his_name->h_name);
-       ch = *s++;
-       while(ch && ch != '.') ch = *s++;
-       s[-1] = '\0';
-       remote_hostname = newstralloc(remote_hostname, fp);
-       s[-1] = (char)ch;
-       amfree(fp);
+
+       /* Set up the input and output FILEs */
        cmdout = stdout;
        cmdin = stdin;
     }
     else {
-       cmdfdout  = DATA_FD_OFFSET + 0;
-       cmdfdin   = DATA_FD_OFFSET + 1;
-
        /* read the REQ packet */
        for(; (line = agets(stdin)) != NULL; free(line)) {
-#define sc "OPTIONS "
-           if(strncmp(line, sc, sizeof(sc)-1) == 0) {
-#undef sc
+           if(strncmp_const(line, "OPTIONS ") == 0) {
                g_options = parse_g_options(line+8, 1);
                if(!g_options->hostname) {
                    g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
@@ -1218,15 +1275,15 @@ main(
        fclose(stdin);
        fclose(stdout);
        
-       cmdout = fdopen(cmdfdout, "a");
+       cmdout = fdopen(DATA_FD_OFFSET + 0, "a");
        if (!cmdout) {
-           error("amindexd: Can't fdopen(cmdfdout): %s", strerror(errno));
+           error(_("amindexd: Can't fdopen(%d): %s"), DATA_FD_OFFSET + 0, strerror(errno));
            /*NOTREACHED*/
        }
 
-       cmdin = fdopen(cmdfdin, "r");
+       cmdin = fdopen(DATA_FD_OFFSET + 1, "r");
        if (!cmdin) {
-           error("amindexd: Can't fdopen(cmdfdin): %s", strerror(errno));
+           error(_("amindexd: Can't fdopen(%d): %s"), DATA_FD_OFFSET + 1, strerror(errno));
            /*NOTREACHED*/
        }
     }
@@ -1323,7 +1380,10 @@ main(
 
        amfree(errstr);
        if (!user_validated && strcmp(cmd, "SECURITY") == 0 && arg) {
-           user_validated = check_security(&his_addr, arg, 0, &errstr);
+           user_validated = amindexd_debug ||
+                               check_security(
+                                       (struct sockaddr_storage *)&his_addr,
+                                       arg, 0, &errstr);
            if(user_validated) {
                reply(200, "Access OK");
                amfree(line);
@@ -1342,11 +1402,12 @@ main(
            amfree(line);
            break;
        } else if (strcmp(cmd, "HOST") == 0 && arg) {
+           am_host_t *lhost;
            /* set host we are restoring */
            s[-1] = '\0';
-           if (is_dump_host_valid(arg) != -1)
+           if ((lhost = is_dump_host_valid(arg)) != NULL)
            {
-               dump_hostname = newstralloc(dump_hostname, arg);
+               dump_hostname = newstralloc(dump_hostname, lhost->hostname);
                reply(200, "Dump host set to %s.", dump_hostname);
                amfree(qdisk_name);             /* invalidate any value */
                amfree(disk_name);              /* invalidate any value */
@@ -1410,7 +1471,7 @@ main(
                       dump_hostname);
                for (disk = disk_list.head; disk!=NULL; disk = disk->next) {
 
-                   if (strcmp(disk->host->hostname, dump_hostname) == 0 &&
+                   if (strcasecmp(disk->host->hostname, dump_hostname) == 0 &&
                      ((disk->device && strcmp(disk->device, arg) == 0) ||
                      (!disk->device && strcmp(disk->name, arg) == 0))) {
                        qname = quote_string(disk->name);
@@ -1431,7 +1492,7 @@ main(
            else {
                lreply(200, " List of disk for host %s", dump_hostname);
                for (disk = disk_list.head; disk!=NULL; disk = disk->next) {
-                   if(strcmp(disk->host->hostname, dump_hostname) == 0) {
+                   if(strcasecmp(disk->host->hostname, dump_hostname) == 0) {
                        qname = quote_string(disk->name);
                        fast_lreply(201, " %s", qname);
                        amfree(qname);
@@ -1553,3 +1614,168 @@ cmp_date(
 {
     return strncmp(date1, date2, strlen(date2));
 }
+
+static char *
+clean_backslash(
+    char *line)
+{
+    char *s = line, *s1, *s2;
+    char *p = line;
+    int i;
+
+    while(*s != '\0') {
+       if (*s == '\\') {
+           s++;
+           s1 = s+1;
+           s2 = s+2;
+           if (*s != '\0' && isdigit(*s) &&
+               *s1 != '\0' && isdigit(*s1) &&
+               *s2 != '\0' &&  isdigit(*s2)) {
+               /* this is \000, an octal value */
+               i = ((*s)-'0')*64 + ((*s1)-'0')*8 + ((*s2)-'0');
+               *p++ = i;
+               s += 3;
+           } else if (*s == '\\') { /* we remove one / */
+               *p++ = *s++;
+           } else { /* we keep the / */
+               *p++ = '\\';
+               *p++ = *s++;
+           }
+       } else {
+           *p++ = *s++;
+       }
+    }
+    *p = '\0';
+
+    return line;
+}
+
+
+static int
+get_index_dir(
+    char *dump_hostname,
+    char *hostname,
+    char *diskname)
+{
+    struct stat  dir_stat;
+    char        *fn;
+    char        *s;
+    char        *lower_hostname;
+
+    lower_hostname = stralloc(dump_hostname);
+    for(s=lower_hostname; *s != '\0'; s++)
+       *s = tolower(*s);
+
+    fn = getindexfname(dump_hostname, diskname, NULL, 0);
+    if (stat(fn, &dir_stat) == 0 && S_ISDIR(dir_stat.st_mode)) {
+       amfree(lower_hostname);
+       amfree(fn);
+       return 1;
+    }
+    amfree(fn);
+    if (hostname != NULL) {
+       fn = getindexfname(hostname, diskname, NULL, 0);
+       if (stat(fn, &dir_stat) == 0 && S_ISDIR(dir_stat.st_mode)) {
+           amfree(lower_hostname);
+           amfree(fn);
+           return 1;
+       }
+    }
+    amfree(fn);
+    fn = getindexfname(lower_hostname, diskname, NULL, 0);
+    if (stat(fn, &dir_stat) == 0 && S_ISDIR(dir_stat.st_mode)) {
+       amfree(lower_hostname);
+       amfree(fn);
+       return 1;
+    }
+    amfree(fn);
+    if(diskname != NULL) {
+       fn = getoldindexfname(dump_hostname, diskname, NULL, 0);
+       if (stat(fn, &dir_stat) == 0 && S_ISDIR(dir_stat.st_mode)) {
+           amfree(lower_hostname);
+           amfree(fn);
+           return 1;
+       }
+       amfree(fn);
+       if (hostname != NULL) {
+           fn = getoldindexfname(hostname, diskname, NULL, 0);
+           if (stat(fn, &dir_stat) == 0 && S_ISDIR(dir_stat.st_mode)) {
+               amfree(lower_hostname);
+               amfree(fn);
+               return 1;
+           }
+       }
+       amfree(fn);
+       fn = getoldindexfname(lower_hostname, diskname, NULL, 0);
+       if (stat(fn, &dir_stat) == 0 && S_ISDIR(dir_stat.st_mode)) {
+           amfree(lower_hostname);
+           amfree(fn);
+           return 1;
+       }
+       amfree(fn);
+    }
+    amfree(lower_hostname);
+    return -1;
+}
+
+static char *
+get_index_name(
+    char *dump_hostname,
+    char *hostname,
+    char *diskname,
+    char *timestamps,
+    int   level)
+{
+    struct stat  dir_stat;
+    char        *fn;
+    char        *s;
+    char        *lower_hostname;
+
+    lower_hostname = stralloc(dump_hostname);
+    for(s=lower_hostname; *s != '\0'; s++)
+       *s = tolower(*s);
+
+    fn = getindexfname(dump_hostname, diskname, timestamps, level);
+    if (stat(fn, &dir_stat) == 0 && S_ISREG(dir_stat.st_mode)) {
+       amfree(lower_hostname);
+       return fn;
+    }
+    amfree(fn);
+    if(hostname != NULL) {
+       fn = getindexfname(hostname, diskname, timestamps, level);
+       if (stat(fn, &dir_stat) == 0 && S_ISREG(dir_stat.st_mode)) {
+           amfree(lower_hostname);
+           return fn;
+       }
+    }
+    amfree(fn);
+    fn = getindexfname(lower_hostname, diskname, timestamps, level);
+    if (stat(fn, &dir_stat) == 0 && S_ISREG(dir_stat.st_mode)) {
+       amfree(lower_hostname);
+       return fn;
+    }
+    amfree(fn);
+    if(diskname != NULL) {
+       fn = getoldindexfname(dump_hostname, diskname, timestamps, level);
+       if (stat(fn, &dir_stat) == 0 && S_ISREG(dir_stat.st_mode)) {
+           amfree(lower_hostname);
+           return fn;
+       }
+       amfree(fn);
+       if(hostname != NULL) {
+           fn = getoldindexfname(hostname, diskname, timestamps, level);
+           if (stat(fn, &dir_stat) == 0 && S_ISREG(dir_stat.st_mode)) {
+               amfree(lower_hostname);
+               return fn;
+           }
+       }
+       amfree(fn);
+       fn = getoldindexfname(lower_hostname, diskname, timestamps, level);
+       if (stat(fn, &dir_stat) == 0 && S_ISREG(dir_stat.st_mode)) {
+           amfree(lower_hostname);
+           return fn;
+       }
+    }
+    amfree(lower_hostname);
+    return NULL;
+}