X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=server-src%2Famindexd.c;h=2e09bfe3c1b55f1126e9eded3cf33b21b3aa535a;hb=cd0b924f27312d57bd42f6c4fae2b795139e2d0b;hp=493a8089c2c7138f641d07b28a5a5478ffa5b943;hpb=34197d9f46a5f4e944378cbb65fca32ee0eec7b9;p=debian%2Famanda diff --git a/server-src/amindexd.c b/server-src/amindexd.c index 493a808..2e09bfe 100644 --- a/server-src/amindexd.c +++ b/server-src/amindexd.c @@ -24,7 +24,7 @@ * file named AUTHORS, in the root directory of this distribution. */ /* - * $Id: amindexd.c,v 1.106.2.9 2007/02/07 15:23:45 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 @@ -45,20 +45,27 @@ #include "diskfile.h" #include "arglist.h" #include "clock.h" -#include "version.h" +#include "match.h" #include "amindex.h" #include "disk_history.h" #include "list_dir.h" #include "logfile.h" -#include "token.h" #include "find.h" #include "tapefile.h" #include "util.h" #include "amandad.h" #include "pipespawn.h" +#include "sockaddr-util.h" +#include "amxml.h" #include +#define DBG(i, ...) do { \ + if ((i) <= debug_amindexd) { \ + g_debug(__VA_ARGS__); \ + } \ +} while (0) + typedef struct REMOVE_ITEM { char *filename; @@ -68,7 +75,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 */ @@ -76,7 +82,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; @@ -86,9 +91,10 @@ static REMOVE_ITEM *uncompress_remove = NULL; static am_feature_t *our_features = NULL; static am_feature_t *their_features = NULL; +static int get_pid_status(int pid, char *program, GPtrArray **emsg); static REMOVE_ITEM *remove_files(REMOVE_ITEM *); -static char *uncompress_file(char *, char **); -static int process_ls_dump(char *, DUMP_ITEM *, int, char **); +static char *uncompress_file(char *, GPtrArray **); +static int process_ls_dump(char *, DUMP_ITEM *, int, GPtrArray **); static size_t reply_buffer_size = 1; static char *reply_buffer = NULL; @@ -96,15 +102,13 @@ static char *amandad_auth = NULL; static FILE *cmdin; static FILE *cmdout; -static void reply(int, char *, ...) - __attribute__ ((format (printf, 2, 3))); -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 void reply_ptr_array(int, GPtrArray *); +static void reply(int, char *, ...) G_GNUC_PRINTF(2, 3); +static void lreply(int, char *, ...) G_GNUC_PRINTF(2, 3); +static void fast_lreply(int, char *, ...) G_GNUC_PRINTF(2, 3); +static am_host_t *is_dump_host_valid(char *); static int is_disk_valid(char *); -static int is_config_valid(char *); +static int check_and_load_config(char *); static int build_disk_table(void); static int disk_history_list(void); static int is_dir_valid_opaque(char *); @@ -115,9 +119,52 @@ 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 int +get_pid_status( + int pid, + char *program, + GPtrArray **emsg) +{ + int status; + amwait_t wait_status; + char *msg; + int result = 1; + + status = waitpid(pid, &wait_status, 0); + if (status < 0) { + msg = vstrallocf( + _("%s (%d) returned negative value: %s"), + program, pid, strerror(errno)); + dbprintf("%s\n", msg); + g_ptr_array_add(*emsg, msg); + result = 0; + } else { + if (!WIFEXITED(wait_status)) { + msg = vstrallocf( + _("%s exited with signal %d"), + program, WTERMSIG(wait_status)); + dbprintf("%s\n", msg); + g_ptr_array_add(*emsg, msg); + result = 0; + } else if (WEXITSTATUS(wait_status) != 0) { + msg = vstrallocf( + _("%s exited with status %d"), + program, WEXITSTATUS(wait_status)); + dbprintf("%s\n", msg); + g_ptr_array_add(*emsg, msg); + result = 0; + } + } + return result; +} + static REMOVE_ITEM * remove_files( REMOVE_ITEM *remove) @@ -125,8 +172,7 @@ remove_files( REMOVE_ITEM *prev; while(remove) { - dbprintf(("%s: removing index file: %s\n", - debug_prefix_time(NULL), remove->filename)); + dbprintf(_("removing index file: %s\n"), remove->filename); unlink(remove->filename); amfree(remove->filename); prev = remove; @@ -138,8 +184,8 @@ remove_files( static char * uncompress_file( - char * filename_gz, - char ** emsg) + char *filename_gz, + GPtrArray **emsg) { char *cmd = NULL; char *filename = NULL; @@ -150,14 +196,21 @@ uncompress_file( int pipe_to_sort; int indexfd; int nullfd; - int debugfd; - int debugnullfd; + int uncompress_errfd; + int sort_errfd; char line[STR_SIZE]; FILE *pipe_stream; pid_t pid_gzip; pid_t pid_sort; - amwait_t wait_status; - + pid_t pid_index; + int status; + char *msg; + gpointer *p; + gpointer *p_last; + GPtrArray *uncompress_err; + GPtrArray *sort_err; + FILE *uncompress_err_stream; + FILE *sort_err_stream; filename = stralloc(filename_gz); len = strlen(filename); @@ -177,12 +230,10 @@ uncompress_file( * Check that compressed file exists manually. */ if (stat(filename_gz, &statbuf) < 0) { - *emsg = newvstralloc(*emsg, "Compressed file '", - filename_gz, - "' is inaccessable: ", - strerror(errno), - NULL); - dbprintf(("%s\n",*emsg)); + msg = vstrallocf(_("Compressed file '%s' is inaccessable: %s"), + filename_gz, strerror(errno)); + dbprintf("%s\n", msg); + g_ptr_array_add(*emsg, msg); amfree(filename); return NULL; } @@ -193,97 +244,140 @@ uncompress_file( # define PARAM_UNCOMPRESS_OPT skip_argument #endif - 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)); + msg = vstrallocf(_("Can't open '%s' for writting: %s"), + filename, strerror(errno)); + dbprintf("%s\n", msg); + g_ptr_array_add(*emsg, msg); amfree(filename); + aclose(nullfd); return NULL; } + /* just use our stderr directly for the pipe's stderr; in + * main() we send stderr to the debug file, or /dev/null + * if debugging is disabled */ + /* start the uncompress process */ putenv(stralloc("LC_ALL=C")); - pid_gzip = pipespawn(UNCOMPRESS_PATH, STDOUT_PIPE, - &nullfd, &pipe_from_gzip, &debugfd, + pid_gzip = pipespawn(UNCOMPRESS_PATH, STDOUT_PIPE|STDERR_PIPE, 0, + &nullfd, &pipe_from_gzip, &uncompress_errfd, 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)); + msg = vstrallocf(_("Can't fdopen pipe from gzip: %s"), + strerror(errno)); + dbprintf("%s\n", msg); + g_ptr_array_add(*emsg, msg); amfree(filename); + aclose(indexfd); return NULL; } /* start the sort process */ - pid_sort = pipespawn(SORT_PATH, STDIN_PIPE, - &pipe_to_sort, &indexfd, &debugfd, + putenv(stralloc("LC_ALL=C")); + pid_sort = pipespawn(SORT_PATH, STDIN_PIPE|STDERR_PIPE, 0, + &pipe_to_sort, &indexfd, &sort_errfd, SORT_PATH, NULL); - if (debugnullfd == 1) - aclose(debugfd); aclose(indexfd); + /* start a subprocess */ /* 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)); + pid_index = fork(); + switch (pid_index) { + case -1: + msg = vstrallocf( + _("fork error: %s"), + strerror(errno)); + dbprintf("%s\n", msg); + g_ptr_array_add(*emsg, msg); + unlink(filename); + amfree(filename); + default: break; + case 0: + while (fgets(line, STR_SIZE, pipe_stream) != NULL) { + if (line[0] != '\0') { + if (strchr(line,'/')) { + full_write(pipe_to_sort,line,strlen(line)); + } } } + exit(0); } 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))); + + uncompress_err_stream = fdopen(uncompress_errfd, "r"); + uncompress_err = g_ptr_array_new(); + while (fgets(line, sizeof(line), uncompress_err_stream) != NULL) { + if (line[strlen(line)-1] == '\n') + line[strlen(line)-1] = '\0'; + g_ptr_array_add(uncompress_err, vstrallocf(" %s", line)); + dbprintf("Uncompress: %s\n", line); + } + fclose(uncompress_err_stream); + + sort_err_stream = fdopen(sort_errfd, "r"); + sort_err = g_ptr_array_new(); + while (fgets(line, sizeof(line), sort_err_stream) != NULL) { + if (line[strlen(line)-1] == '\n') + line[strlen(line)-1] = '\0'; + g_ptr_array_add(sort_err, vstrallocf(" %s", line)); + dbprintf("Sort: %s\n", line); + } + fclose(sort_err_stream); + + status = get_pid_status(pid_gzip, UNCOMPRESS_PATH, emsg); + if (status == 0 && filename) { + unlink(filename); + amfree(filename); + } + if (uncompress_err->len > 0) { + p_last = uncompress_err->pdata + uncompress_err->len; + for (p = uncompress_err->pdata; p < p_last ;p++) { + g_ptr_array_add(*emsg, (char *)*p); } } - 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))); + g_ptr_array_free(uncompress_err, TRUE); + + status = get_pid_status(pid_index, "index", emsg); + if (status == 0 && filename) { + unlink(filename); + amfree(filename); + } + + status = get_pid_status(pid_sort, SORT_PATH, emsg); + if (status == 0 && filename) { + unlink(filename); + amfree(filename); + } + if (sort_err->len > 0) { + p_last = sort_err->pdata + sort_err->len; + for (p = sort_err->pdata; p < p_last ;p++) { + g_ptr_array_add(*emsg, (char *)*p); } } + g_ptr_array_free(sort_err, TRUE); /* add at beginning */ - remove_file = (REMOVE_ITEM *)alloc(SIZEOF(REMOVE_ITEM)); - remove_file->filename = stralloc(filename); - remove_file->next = uncompress_remove; - uncompress_remove = remove_file; + if (filename) { + remove_file = (REMOVE_ITEM *)alloc(SIZEOF(REMOVE_ITEM)); + remove_file->filename = stralloc(filename); + remove_file->next = uncompress_remove; + uncompress_remove = remove_file; + } + } else if(!S_ISREG((stat_filename.st_mode))) { - amfree(*emsg); - *emsg = vstralloc("\"", filename, "\" is not a regular file", NULL); + msg = vstrallocf(_("\"%s\" is not a regular file"), filename); + dbprintf("%s\n", msg); + g_ptr_array_add(*emsg, msg); errno = -1; amfree(filename); amfree(cmd); @@ -300,10 +394,9 @@ process_ls_dump( char * dir, DUMP_ITEM * dump_item, int recursive, - char ** emsg) + GPtrArray **emsg) { - char line[STR_SIZE]; - char *old_line = NULL; + char line[STR_SIZE], old_line[STR_SIZE]; char *filename = NULL; char *filename_gz; char *dir_slash = NULL; @@ -311,22 +404,23 @@ process_ls_dump( char *s; int ch; size_t len_dir_slash; - struct stat statbuf; + old_line[0] = '\0'; if (strcmp(dir, "/") == 0) { dir_slash = stralloc(dir); } else { dir_slash = stralloc2(dir, "/"); } - filename_gz = getindexfname(dump_hostname, disk_name, dump_item->date, - dump_item->level); - if (stat(filename_gz, &statbuf) < 0 && errno == ENOENT) { + filename_gz = get_index_name(dump_hostname, dump_item->hostname, disk_name, + dump_item->date, dump_item->level); + if (filename_gz == NULL) { + g_ptr_array_add(*emsg, stralloc(_("index file not found"))); amfree(filename_gz); - filename_gz = getoldindexfname(dump_hostname, disk_name, - dump_item->date, dump_item->level); + return -1; } - if((filename = uncompress_file(filename_gz, emsg)) == NULL) { + filename = uncompress_file(filename_gz, emsg); + if(filename == NULL) { amfree(filename_gz); amfree(dir_slash); return -1; @@ -334,9 +428,9 @@ process_ls_dump( amfree(filename_gz); if((fp = fopen(filename,"r"))==0) { - amfree(*emsg); - *emsg = stralloc(strerror(errno)); + g_ptr_array_add(*emsg, vstrallocf("%s", strerror(errno))); amfree(dir_slash); + amfree(filename); return -1; } @@ -357,21 +451,37 @@ process_ls_dump( } s[-1] = '\0'; } - if(old_line == NULL || strcmp(line, old_line) != 0) { + if(strcmp(line, old_line) != 0) { add_dir_list_item(dump_item, line); - amfree(old_line); - old_line = stralloc(line); + strcpy(old_line, line); } } } } afclose(fp); - /*@i@*/ amfree(old_line); amfree(filename); amfree(dir_slash); return 0; } +static void +reply_ptr_array( + int n, + GPtrArray *emsg) +{ + gpointer *p; + + if (emsg->len == 0) + return; + + p = emsg->pdata; + while (p != emsg->pdata + emsg->len -1) { + fast_lreply(n, "%s", (char *)*p); + p++; + } + reply(n, "%s", (char *)*p); +} + /* send a 1 line reply to the client */ printf_arglist_function1(static void reply, int, n, char *, fmt) { @@ -383,7 +493,7 @@ printf_arglist_function1(static void reply, int, n, char *, fmt) while(1) { arglist_start(args, fmt); - len = vsnprintf(reply_buffer, reply_buffer_size, fmt, args); + len = g_vsnprintf(reply_buffer, reply_buffer_size, fmt, args); arglist_end(args); if (len > -1 && (size_t)len < reply_buffer_size-1) @@ -394,21 +504,19 @@ printf_arglist_function1(static void reply, int, n, char *, fmt) reply_buffer = alloc(reply_buffer_size); } - if (fprintf(cmdout,"%03d %s\r\n", n, reply_buffer) < 0) + if (g_fprintf(cmdout,"%03d %s\r\n", n, reply_buffer) < 0) { - dbprintf(("%s: ! error %d (%s) in printf\n", - debug_prefix_time(NULL), errno, strerror(errno))); + dbprintf(_("! error %d (%s) in printf\n"), errno, strerror(errno)); uncompress_remove = remove_files(uncompress_remove); exit(1); } if (fflush(cmdout) != 0) { - dbprintf(("%s: ! error %d (%s) in fflush\n", - debug_prefix_time(NULL), errno, strerror(errno))); + dbprintf(_("! error %d (%s) in fflush\n"), errno, strerror(errno)); uncompress_remove = remove_files(uncompress_remove); exit(1); } - dbprintf(("%s: < %03d %s\n", debug_prefix_time(NULL), n, reply_buffer)); + dbprintf(_("< %03d %s\n"), n, reply_buffer); } /* send one line of a multi-line response */ @@ -422,7 +530,7 @@ printf_arglist_function1(static void lreply, int, n, char *, fmt) while(1) { arglist_start(args, fmt); - len = vsnprintf(reply_buffer, reply_buffer_size, fmt, args); + len = g_vsnprintf(reply_buffer, reply_buffer_size, fmt, args); arglist_end(args); if (len > -1 && (size_t)len < reply_buffer_size-1) @@ -433,22 +541,22 @@ printf_arglist_function1(static void lreply, int, n, char *, fmt) reply_buffer = alloc(reply_buffer_size); } - if (fprintf(cmdout,"%03d-%s\r\n", n, reply_buffer) < 0) + if (g_fprintf(cmdout,"%03d-%s\r\n", n, reply_buffer) < 0) { - dbprintf(("%s: ! error %d (%s) in printf\n", - debug_prefix_time(NULL), errno, strerror(errno))); + dbprintf(_("! error %d (%s) in printf\n"), + errno, strerror(errno)); uncompress_remove = remove_files(uncompress_remove); exit(1); } if (fflush(cmdout) != 0) { - dbprintf(("%s: ! error %d (%s) in fflush\n", - debug_prefix_time(NULL), errno, strerror(errno))); + dbprintf(_("! error %d (%s) in fflush\n"), + errno, strerror(errno)); uncompress_remove = remove_files(uncompress_remove); exit(1); } - dbprintf(("%s: < %03d-%s\n", debug_prefix_time(NULL), n, reply_buffer)); + dbprintf("< %03d-%s\n", n, reply_buffer); } @@ -463,7 +571,7 @@ printf_arglist_function1(static void fast_lreply, int, n, char *, fmt) while(1) { arglist_start(args, fmt); - len = vsnprintf(reply_buffer, reply_buffer_size, fmt, args); + len = g_vsnprintf(reply_buffer, reply_buffer_size, fmt, args); arglist_end(args); if (len > -1 && (size_t)len < reply_buffer_size-1) @@ -474,15 +582,15 @@ printf_arglist_function1(static void fast_lreply, int, n, char *, fmt) reply_buffer = alloc(reply_buffer_size); } - if (fprintf(cmdout,"%03d-%s\r\n", n, reply_buffer) < 0) + if (g_fprintf(cmdout,"%03d-%s\r\n", n, reply_buffer) < 0) { - dbprintf(("%s: ! error %d (%s) in printf\n", - debug_prefix_time(NULL), errno, strerror(errno))); + dbprintf(_("! error %d (%s) in printf\n"), + errno, strerror(errno)); uncompress_remove = remove_files(uncompress_remove); exit(1); } - dbprintf(("%s: < %03d-%s\n", debug_prefix_time(NULL), n, reply_buffer)); + DBG(2, "< %03d-%s", n, reply_buffer); } /* see if hostname is valid */ @@ -490,99 +598,154 @@ 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; - - if (config_name == NULL) { - reply(501, "Must set config before setting host."); - return -1; - } + am_host_t *ihost; + disk_t *diskp; -#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; + if (get_config_name() == NULL) { + reply(501, _("Must set config before setting host.")); + return NULL; } -#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; + reply(501, _("Host %s is not in your disklist."), host); + 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; } +static gboolean +is_disk_allowed( + disk_t *disk) +{ + dumptype_t *dt = disk->config; + host_limit_t *rl = NULL; + char *peer; + char *dle_hostname; + GSList *iter; + + /* get the config: either for the DLE or the global config */ + if (dt) { + if (dumptype_seen(dt, DUMPTYPE_RECOVERY_LIMIT)) { + g_debug("using recovery limit from DLE"); + rl = dumptype_get_recovery_limit(dt); + } + } + if (!rl) { + if (getconf_seen(CNF_RECOVERY_LIMIT)) { + g_debug("using global recovery limit"); + rl = getconf_recovery_limit(CNF_RECOVERY_LIMIT); + } + } + if (!rl) { + g_debug("no recovery limit found; allowing access"); + return TRUE; + } + + peer = getenv("AMANDA_AUTHENTICATED_PEER"); + if (!peer || !*peer) { + g_warning("DLE has a recovery-limit, but no authenticated peer name is " + "available; rejecting"); + return FALSE; + } + + /* check same-host */ + dle_hostname = disk->host? disk->host->hostname : NULL; + if (rl->same_host && dle_hostname) { + if (0 == g_ascii_strcasecmp(peer, dle_hostname)) { + g_debug("peer matched same-host ('%s')", dle_hostname); + return TRUE; + } + } + + /* check server */ + if (rl->server) { + char myhostname[MAX_HOSTNAME_LENGTH+1]; + if (gethostname(myhostname, MAX_HOSTNAME_LENGTH) == 0) { + myhostname[MAX_HOSTNAME_LENGTH] = '\0'; + g_debug("server hostname: %s", myhostname); + if (0 == g_ascii_strcasecmp(peer, myhostname)) { + g_debug("peer matched server ('%s')", myhostname); + return TRUE; + } + } + } + + /* check the match list */ + for (iter = rl->match_pats; iter; iter = iter->next) { + char *pat = iter->data; + if (match_host(pat, peer)) + return TRUE; + } + + g_warning("peer '%s' does not match any of the recovery-limit restrictions; rejecting", + peer); + + return FALSE; +} + static int is_disk_valid( char *disk) { - char *fn; - struct stat dir_stat; disk_t *idisk; char *qdisk; - if (config_name == NULL) { - reply(501, "Must set config,host before setting disk."); + if (get_config_name() == NULL) { + reply(501, _("Must set config,host before setting disk.")); return -1; } else if (dump_hostname == NULL) { - reply(501, "Must set host before setting disk."); + reply(501, _("Must set host before setting disk.")); return -1; } - /* check that the config actually handles that disk */ + /* check that the config actually handles that disk, and that recovery-limit allows it */ idisk = lookup_disk(dump_hostname, disk); - if(idisk == NULL) { + if(idisk == NULL || !is_disk_allowed(idisk)) { qdisk = quote_string(disk); - reply(501, "Disk %s:%s is not in your disklist.", dump_hostname, qdisk); + reply(501, _("Disk %s:%s is not in the server's disklist."), dump_hostname, qdisk); amfree(qdisk); return -1; } /* 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); + reply(501, _("No index records for disk: %s. Invalid?"), qdisk); amfree(qdisk); return -1; } - amfree(fn); return 0; } static int -is_config_valid( +check_and_load_config( char * config) { - char *conffile; char *conf_diskfile; char *conf_tapelist; char *conf_indexdir; @@ -590,58 +753,46 @@ is_config_valid( /* check that the config actually exists */ if (config == NULL) { - reply(501, "Must set config first."); + reply(501, _("Must set config first.")); return -1; } - /* read conffile */ - conffile = stralloc2(config_dir, CONFFILE_NAME); - if (read_conffile(conffile)) { - reply(501, "Could not read config file %s!", conffile); - amfree(conffile); + /* (re-)initialize configuration with the new config name */ + config_init(CONFIG_INIT_EXPLICIT_NAME, config); + if (config_errors(NULL) >= CFGERR_ERRORS) { + reply(501, _("Could not read config file for %s!"), config); return -1; } - amfree(conffile); - conf_diskfile = getconf_str(CNF_DISKFILE); - if (*conf_diskfile == '/') { - conf_diskfile = stralloc(conf_diskfile); - } else { - conf_diskfile = stralloc2(config_dir, conf_diskfile); - } - if (read_diskfile(conf_diskfile, &disk_list) < 0) { - reply(501, "Could not read disk file %s!", conf_diskfile); - amfree(conf_diskfile); + check_running_as(RUNNING_AS_DUMPUSER_PREFERRED); + + conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); + read_diskfile(conf_diskfile, &disk_list); + amfree(conf_diskfile); + if (config_errors(NULL) >= CFGERR_ERRORS) { + reply(501, _("Could not read disk file %s!"), conf_diskfile); return -1; } - amfree(conf_diskfile); - conf_tapelist = getconf_str(CNF_TAPELIST); - if (*conf_tapelist == '/') { - conf_tapelist = stralloc(conf_tapelist); - } else { - conf_tapelist = stralloc2(config_dir, conf_tapelist); - } + conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST)); if(read_tapelist(conf_tapelist)) { - reply(501, "Could not read tapelist file %s!", conf_tapelist); + reply(501, _("Could not read tapelist file %s!"), conf_tapelist); amfree(conf_tapelist); return -1; } amfree(conf_tapelist); - dbrename(config, DBG_SUBDIR_SERVER); + dbrename(get_config_name(), DBG_SUBDIR_SERVER); - output_find = find_dump(1, &disk_list); - sort_find_result("DLKHpB", &output_find); + output_find = find_dump(&disk_list); + /* the 'w' here sorts by write timestamp, so that the first instance of + * any particular datestamp/host/disk/level/part that we see is the one + * written earlier */ + sort_find_result("DLKHpwB", &output_find); - conf_indexdir = getconf_str(CNF_INDEXDIR); - if(*conf_indexdir == '/') { - conf_indexdir = stralloc(conf_indexdir); - } else { - conf_indexdir = stralloc2(config_dir, conf_indexdir); - } + conf_indexdir = config_dir_relative(getconf_str(CNF_INDEXDIR)); if (stat (conf_indexdir, &dir_stat) != 0 || !S_ISDIR(dir_stat.st_mode)) { - reply(501, "Index directory %s does not exist", conf_indexdir); + reply(501, _("Index directory %s does not exist"), conf_indexdir); amfree(conf_indexdir); return -1; } @@ -661,16 +812,16 @@ build_disk_table(void) int last_partnum; find_result_t *find_output; - if (config_name == NULL) { - reply(590, "Must set config,host,disk before building disk table"); + if (get_config_name() == NULL) { + reply(590, _("Must set config,host,disk before building disk table")); return -1; } else if (dump_hostname == NULL) { - reply(590, "Must set host,disk before building disk table"); + reply(590, _("Must set host,disk before building disk table")); return -1; } else if (disk_name == NULL) { - reply(590, "Must set disk before building disk table"); + reply(590, _("Must set disk before building disk table")); return -1; } @@ -683,12 +834,9 @@ build_disk_table(void) find_output != NULL; find_output = find_output->next) { if(strcasecmp(dump_hostname, find_output->hostname) == 0 && - strcmp(disk_name , find_output->diskname) == 0 && - strcmp("OK" , find_output->status) == 0) { - int partnum = -1; - if(strcmp("--", find_output->partnum)){ - partnum = atoi(find_output->partnum); - } + strcmp(disk_name , find_output->diskname) == 0 && + strcmp("OK" , find_output->status) == 0 && + strcmp("OK" , find_output->dump_status) == 0) { /* * The sort order puts holding disk entries first. We want to * use them if at all possible, so ignore any other entries @@ -698,23 +846,34 @@ build_disk_table(void) if(last_timestamp && strcmp(find_output->timestamp, last_timestamp) == 0 && find_output->level == last_level && - partnum == last_partnum && last_filenum == 0) { + last_filenum == 0) { + continue; + } + /* ignore duplicate partnum */ + if(last_timestamp && + strcmp(find_output->timestamp, last_timestamp) == 0 && + find_output->level == last_level && + find_output->partnum == last_partnum) { continue; } last_timestamp = find_output->timestamp; last_filenum = find_output->filenum; last_level = find_output->level; - last_partnum = partnum; + last_partnum = find_output->partnum; date = amindexd_nicedate(find_output->timestamp); - add_dump(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, + add_dump(find_output->hostname, date, find_output->level, + find_output->label, find_output->filenum, + find_output->partnum, find_output->totalparts); + dbprintf("- %s %d %s %lld %d %d\n", + date, find_output->level, find_output->label, - (OFF_T_FMT_TYPE)find_output->filenum, - partnum)); + (long long)find_output->filenum, + find_output->partnum, find_output->totalparts); } } + + clean_dump(); + return 0; } @@ -725,21 +884,21 @@ disk_history_list(void) DUMP_ITEM *item; char date[20]; - if (config_name == NULL) { - reply(502, "Must set config,host,disk before listing history"); + if (get_config_name() == NULL) { + reply(502, _("Must set config,host,disk before listing history")); return -1; } else if (dump_hostname == NULL) { - reply(502, "Must set host,disk before listing history"); + reply(502, _("Must set host,disk before listing history")); return -1; } else if (disk_name == NULL) { - reply(502, "Must set disk before listing history"); + reply(502, _("Must set disk before listing history")); return -1; } - lreply(200, " Dump history for config \"%s\" host \"%s\" disk %s", - config_name, dump_hostname, qdisk_name); + lreply(200, _(" Dump history for config \"%s\" host \"%s\" disk %s"), + get_config_name(), dump_hostname, qdisk_name); for (item=first_dump(); item!=NULL; item=next_dump(item)){ char *tapelist_str = marshal_tapelist(item->tapes, 1); @@ -753,14 +912,14 @@ disk_history_list(void) lreply(201, " %s %d %s", date, item->level, tapelist_str); } else{ - lreply(201, " %s %d %s " OFF_T_FMT, date, item->level, - tapelist_str, (OFF_T_FMT_TYPE)item->file); + lreply(201, " %s %d %s %lld", date, item->level, + tapelist_str, (long long)item->file); } amfree(tapelist_str); } - reply(200, "Dump history for config \"%s\" host \"%s\" disk %s", - config_name, dump_hostname, qdisk_name); + reply(200, _("Dump history for config \"%s\" host \"%s\" disk %s"), + get_config_name(), dump_hostname, qdisk_name); return 0; } @@ -783,25 +942,24 @@ is_dir_valid_opaque( char *filename_gz = NULL; char *filename = NULL; size_t ldir_len; - static char *emsg = NULL; + GPtrArray *emsg = NULL; - if (config_name == NULL || dump_hostname == NULL || disk_name == NULL) { - reply(502, "Must set config,host,disk before asking about directories"); + if (get_config_name() == NULL || dump_hostname == NULL || disk_name == NULL) { + reply(502, _("Must set config,host,disk before asking about directories")); return -1; } else if (dump_hostname == NULL) { - reply(502, "Must set host,disk before asking about directories"); + reply(502, _("Must set host,disk before asking about directories")); return -1; } else if (disk_name == NULL) { - reply(502, "Must set disk before asking about directories"); + reply(502, _("Must set disk before asking about directories")); return -1; } else if (target_date == NULL) { - reply(502, "Must set date before asking about directories"); + 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) @@ -810,7 +968,7 @@ is_dir_valid_opaque( if (item == NULL) { /* no dump for given date */ - reply(500, "No dumps available on or before date \"%s\"", target_date); + reply(500, _("No dumps available on or before date \"%s\""), target_date); return -1; } @@ -825,19 +983,26 @@ 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; + } + emsg = g_ptr_array_new(); if((filename = uncompress_file(filename_gz, &emsg)) == NULL) { - reply(599, "System error %s", emsg); + reply_ptr_array(599, emsg); amfree(filename_gz); - amfree(emsg); + g_ptr_array_free_full(emsg); amfree(ldir); return -1; } + g_ptr_array_free_full(emsg); amfree(filename_gz); - dbprintf(("%s: f %s\n", debug_prefix_time(NULL), filename)); + dbprintf("f %s\n", filename); if ((fp = fopen(filename, "r")) == NULL) { - reply(599, "System error %s", strerror(errno)); + reply(599, _("System error: %s"), strerror(errno)); amfree(filename); amfree(ldir); return -1; @@ -866,7 +1031,7 @@ is_dir_valid_opaque( amfree(filename); amfree(ldir); - reply(500, "\"%s\" is an invalid directory", dir); + reply(500, _("\"%s\" is an invalid directory"), dir); return -1; } @@ -878,7 +1043,7 @@ opaque_ls( DUMP_ITEM *dump_item; DIR_ITEM *dir_item; int level, last_level; - static char *emsg = NULL; + GPtrArray *emsg = NULL; am_feature_e marshall_feature; if (recursive) { @@ -889,20 +1054,20 @@ opaque_ls( clear_dir_list(); - if (config_name == NULL) { - reply(502, "Must set config,host,disk before listing a directory"); + if (get_config_name() == NULL) { + reply(502, _("Must set config,host,disk before listing a directory")); return -1; } else if (dump_hostname == NULL) { - reply(502, "Must set host,disk before listing a directory"); + reply(502, _("Must set host,disk before listing a directory")); return -1; } else if (disk_name == NULL) { - reply(502, "Must set disk before listing a directory"); + reply(502, _("Must set disk before listing a directory")); return -1; } else if (target_date == NULL) { - reply(502, "Must set date before listing a directory"); + reply(502, _("Must set date before listing a directory")); return -1; } @@ -914,14 +1079,15 @@ opaque_ls( if (dump_item == NULL) { /* no dump for given date */ - reply(500, "No dumps available on or before date \"%s\"", target_date); + reply(500, _("No dumps available on or before date \"%s\""), target_date); return -1; } /* get data from that dump */ + emsg = g_ptr_array_new(); if (process_ls_dump(dir, dump_item, recursive, &emsg) == -1) { - reply(599, "System error %s", emsg); - amfree(emsg); + reply_ptr_array(599, emsg); + g_ptr_array_free_full(emsg); return -1; } @@ -933,16 +1099,17 @@ opaque_ls( { last_level = dump_item->level; if (process_ls_dump(dir, dump_item, recursive, &emsg) == -1) { - reply(599, "System error %s", emsg); - amfree(emsg); + reply_ptr_array(599, emsg); + g_ptr_array_free_full(emsg); return -1; } } } + g_ptr_array_free_full(emsg); /* return the information to the caller */ - lreply(200, " Opaque list of %s", dir); - for(level=0; level<=9; level++) { + lreply(200, _(" Opaque list of %s"), dir); + for(level=0; level < DUMP_LEVELS; level++) { for (dir_item = get_dir_list(); dir_item != NULL; dir_item = dir_item->next) { @@ -950,8 +1117,8 @@ opaque_ls( if (!am_has_feature(their_features, marshall_feature) && (num_entries(dir_item->dump->tapes) > 1 || dir_item->dump->tapes->numfiles > 1)) { - fast_lreply(501, " ERROR: Split dumps not supported" - " with old version of amrecover."); + fast_lreply(501, _(" ERROR: Split dumps not supported" + " with old version of amrecover.")); break; } else { @@ -960,7 +1127,7 @@ opaque_ls( } } } - reply(200, " Opaque list of %s", dir); + reply(200, _(" Opaque list of %s"), dir); clear_dir_list(); return 0; @@ -971,8 +1138,9 @@ void opaque_ls_one( am_feature_e marshall_feature, int recursive) { - char date[20]; - char *tapelist_str; + char date[20]; + char *tapelist_str; + char *qtapelist_str; char *qpath; if (am_has_feature(their_features, marshall_feature)) { @@ -981,6 +1149,11 @@ void opaque_ls_one( tapelist_str = dir_item->dump->tapes->label; } + if (am_has_feature(their_features, fe_amindexd_quote_label)) { + qtapelist_str = quote_string(tapelist_str); + } else { + qtapelist_str = stralloc(tapelist_str); + } strncpy(date, dir_item->dump->date, 20); date[19] = '\0'; if(!am_has_feature(their_features,fe_amrecover_timestamp)) @@ -991,23 +1164,24 @@ void opaque_ls_one( fe_amindexd_fileno_in_OLSD)) || (recursive && am_has_feature(their_features, fe_amindexd_fileno_in_ORLD))) { - fast_lreply(201, " %s %d %s " OFF_T_FMT " %s", + fast_lreply(201, " %s %d %s %lld %s", date, dir_item->dump->level, - tapelist_str, - (OFF_T_FMT_TYPE)dir_item->dump->file, + qtapelist_str, + (long long)dir_item->dump->file, qpath); } else { fast_lreply(201, " %s %d %s %s", date, dir_item->dump->level, - tapelist_str, qpath); + qtapelist_str, qpath); } amfree(qpath); if(am_has_feature(their_features, marshall_feature)) { amfree(tapelist_str); } + amfree(qtapelist_str); } /* @@ -1021,39 +1195,36 @@ tapedev_is(void) char *result; /* check state okay to do this */ - if (config_name == NULL) { - reply(501, "Must set config before asking about tapedev."); + if (get_config_name() == NULL) { + reply(501, _("Must set config before asking about tapedev.")); return -1; } /* use amrecover_changer if possible */ if ((result = getconf_str(CNF_AMRECOVER_CHANGER)) != NULL && *result != '\0') { - dbprintf(("%s: tapedev_is amrecover_changer: %s\n", - debug_prefix_time(NULL), result)); - reply(200, result); + dbprintf(_("tapedev_is amrecover_changer: %s\n"), result); + reply(200, "%s", result); return 0; } /* use changer if possible */ if ((result = getconf_str(CNF_TPCHANGER)) != NULL && *result != '\0') { - dbprintf(("%s: tapedev_is tpchanger: %s\n", - debug_prefix_time(NULL), result)); - reply(200, result); + dbprintf(_("tapedev_is tpchanger: %s\n"), result); + reply(200, "%s", result); return 0; } /* get tapedev value */ if ((result = getconf_str(CNF_TAPEDEV)) != NULL && *result != '\0') { - dbprintf(("%s: tapedev_is tapedev: %s\n", - debug_prefix_time(NULL), result)); - reply(200, result); + dbprintf(_("tapedev_is tapedev: %s\n"), result); + reply(200, "%s", result); return 0; } - dbprintf(("%s: No tapedev or tpchanger in config site.\n", - debug_prefix_time(NULL))); - reply(501, "Tapedev or tpchanger not set in config file."); + dbprintf(_("No tapedev or tpchanger in config site.\n")); + + reply(501, _("Tapedev or tpchanger not set in config file.")); return -1; } @@ -1065,16 +1236,16 @@ are_dumps_compressed(void) disk_t *diskp; /* check state okay to do this */ - if (config_name == NULL) { - reply(501, "Must set config,host,disk name before asking about dumps."); + if (get_config_name() == NULL) { + reply(501, _("Must set config,host,disk name before asking about dumps.")); return -1; } else if (dump_hostname == NULL) { - reply(501, "Must set host,disk name before asking about dumps."); + reply(501, _("Must set host,disk name before asking about dumps.")); return -1; } else if (disk_name == NULL) { - reply(501, "Must set disk name before asking about dumps."); + reply(501, _("Must set disk name before asking about dumps.")); return -1; } @@ -1087,7 +1258,7 @@ are_dumps_compressed(void) } if (diskp == NULL) { - reply(501, "Couldn't find host/disk in disk file."); + reply(501, _("Couldn't find host/disk in disk file.")); return -1; } @@ -1106,20 +1277,31 @@ 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; + socklen_t_equiv socklen; + sockaddr_union 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]; + char *cfg_opt = NULL; + + /* + * 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(DATA_FD_OFFSET, 2); + openbsd_fd_inform(); safe_cd(); /* @@ -1141,43 +1323,18 @@ main( /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); -#ifdef FORCE_USERID - - /* we'd rather not run as root */ - - if(geteuid() == 0) { - if(client_uid == (uid_t) -1) { - error("error [cannot find user %s in passwd file]\n", CLIENT_LOGIN); - /*NOTREACHED*/ - } - - /*@ignore@*/ - initgroups(CLIENT_LOGIN, client_gid); - /*@end@*/ - setgid(client_gid); - setuid(client_uid); - } - -#endif /* FORCE_USERID */ - dbopen(DBG_SUBDIR_SERVER); - dbprintf(("%s: version %s\n", get_pname(), version())); + dbprintf(_("version %s\n"), VERSION); if(argv == NULL) { error("argv == NULL\n"); } if (! (argc >= 1 && argv[0] != NULL)) { - dbprintf(("%s: WARNING: argv[0] not defined: check inetd.conf\n", - debug_prefix_time(NULL))); + dbprintf(_("WARNING: argv[0] not defined: check inetd.conf\n")); } - { - int db_fd = dbfd(); - if(db_fd != -1) { - dup2(db_fd, 2); - } - } + debug_dup_stderr_to_debug(); /* initialize */ @@ -1202,18 +1359,17 @@ main( } else { from_amandad = 0; - safe_fd(-1, 0); + safe_fd(dbfd(), 1); } if (argc > 0) { - config_name = stralloc(*argv); - config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL); + cfg_opt = *argv; argc--; argv++; } if(gethostname(local_hostname, SIZEOF(local_hostname)-1) == -1) { - error("gethostname: %s", strerror(errno)); + error(_("gethostname: %s"), strerror(errno)); /*NOTREACHED*/ } local_hostname[SIZEOF(local_hostname)-1] = '\0'; @@ -1226,61 +1382,36 @@ 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)); - } - 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*/ + 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*/ + } } - 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) { + if (g_options != NULL) { + dbprintf(_("REQ packet specified multiple OPTIONS.\n")); + free_g_options(g_options); + } g_options = parse_g_options(line+8, 1); if(!g_options->hostname) { g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1); @@ -1293,30 +1424,30 @@ main( if(amandad_auth && g_options->auth) { if(strcasecmp(amandad_auth, g_options->auth) != 0) { - printf("ERROR recover program ask for auth=%s while amindexd is configured for '%s'\n", + g_printf(_("ERROR recover program ask for auth=%s while amindexd is configured for '%s'\n"), g_options->auth, amandad_auth); - error("amindexd: ERROR recover program ask for auth=%s while amindexd is configured for '%s'", + error(_("amindexd: ERROR recover program ask for auth=%s while amindexd is configured for '%s'"), g_options->auth, amandad_auth); /*NOTREACHED*/ } } /* send the REP packet */ - printf("CONNECT MESG %d\n", DATA_FD_OFFSET); - printf("\n"); + g_printf("CONNECT MESG %d\n", DATA_FD_OFFSET); + g_printf("\n"); fflush(stdin); fflush(stdout); 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*/ } } @@ -1330,12 +1461,12 @@ main( our_features = am_init_feature_set(); their_features = am_set_default_feature_set(); - if (config_name != NULL && is_config_valid(config_name) != -1) { + if (cfg_opt != NULL && check_and_load_config(cfg_opt) != -1) { /* load the config */ return 1; } - reply(220, "%s AMANDA index server (%s) ready.", local_hostname, - version()); + reply(220, _("%s AMANDA index server (%s) ready."), local_hostname, + VERSION); user_validated = from_amandad; @@ -1346,18 +1477,15 @@ main( while(1) { if((part = agets(cmdin)) == NULL) { if(errno != 0) { - dbprintf(("%s: ? read error: %s\n", - debug_prefix_time(NULL), strerror(errno))); + dbprintf(_("? read error: %s\n"), strerror(errno)); } else { - dbprintf(("%s: ? unexpected EOF\n", - debug_prefix_time(NULL))); + dbprintf(_("? unexpected EOF\n")); } if(line) { - dbprintf(("%s: ? unprocessed input:\n", - debug_prefix_time(NULL))); - dbprintf(("-----\n")); - dbprintf(("? %s\n", line)); - dbprintf(("-----\n")); + dbprintf(_("? unprocessed input:\n")); + dbprintf("-----\n"); + dbprintf("? %s\n", line); + dbprintf("-----\n"); } amfree(line); amfree(part); @@ -1383,7 +1511,7 @@ main( strappend(line, "\n"); } - dbprintf(("%s: > %s\n", debug_prefix_time(NULL), line)); + dbprintf("> %s\n", line); if (arg != NULL) amfree(arg); @@ -1392,7 +1520,7 @@ main( skip_whitespace(s, ch); if(ch == '\0') { - reply(500, "Command not recognised/incorrect: %s", line); + reply(500, _("Command not recognised/incorrect: %s"), line); amfree(line); continue; } @@ -1413,17 +1541,20 @@ 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( + (sockaddr_union *)&his_addr, + arg, 0, &errstr); if(user_validated) { - reply(200, "Access OK"); + reply(200, _("Access OK")); amfree(line); continue; } } if (!user_validated) { /* don't tell client the reason, just log it to debug log */ - reply(500, "Access not allowed"); + reply(500, _("Access not allowed")); if (errstr) { - dbprintf(("%s: %s\n", debug_prefix_time(NULL), errstr)); + dbprintf("%s\n", errstr); } break; } @@ -1432,12 +1563,13 @@ 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); - reply(200, "Dump host set to %s.", dump_hostname); + 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 */ } @@ -1448,11 +1580,11 @@ main( int nbhost = 0, found = 0; s[-1] = '\0'; - if (config_name == NULL) { - reply(501, "Must set config before listhost"); + if (get_config_name() == NULL) { + reply(501, _("Must set config before listhost")); } else { - lreply(200, " List hosts for config %s", config_name); + lreply(200, _(" List hosts for config %s"), get_config_name()); for (disk = disk_list.head; disk!=NULL; disk = disk->next) { found = 0; for (diskdup = disk_list.head; diskdup!=disk; diskdup = diskdup->next) { @@ -1467,10 +1599,10 @@ main( } } if(nbhost > 0) { - reply(200, " List hosts for config %s", config_name); + reply(200, _(" List hosts for config %s"), get_config_name()); } else { - reply(200, "No hosts for config %s", config_name); + reply(200, _("No hosts for config %s"), get_config_name()); } } s[-1] = (char)ch; @@ -1480,27 +1612,82 @@ main( disk_name = newstralloc(disk_name, arg); qdisk_name = quote_string(disk_name); if (build_disk_table() != -1) { - reply(200, "Disk set to %s.", qdisk_name); + reply(200, _("Disk set to %s."), qdisk_name); } } s[-1] = (char)ch; + } else if (strcmp(cmd, "DLE") == 0) { + disk_t *dp; + char *optionstr; + char *b64disk; + char *l, *ql; + + dp = lookup_disk(dump_hostname, disk_name); + if (dp->line == 0) { + reply(200, "NODLE"); + } else { + GPtrArray *errarray; + guint i; + + b64disk = amxml_format_tag("disk", dp->name); + dp->host->features = their_features; + errarray = validate_optionstr(dp); + if (errarray->len > 0) { + for (i=0; i < errarray->len; i++) { + g_debug(_("ERROR: %s:%s %s"), + dump_hostname, disk_name, + (char *)g_ptr_array_index(errarray, i)); + } + g_ptr_array_free(errarray, TRUE); + reply(200, "NODLE"); + } else { + optionstr = xml_optionstr(dp, 0); + l = vstralloc("\n", + " ", dp->program, "\n", NULL); + if (dp->application) { + application_t *application; + char *xml_app; + + application = lookup_application(dp->application); + g_assert(application != NULL); + xml_app = xml_application(dp, application, + their_features); + vstrextend(&l, xml_app, NULL); + amfree(xml_app); + } + vstrextend(&l, " ", b64disk, "\n", NULL); + if (dp->device) { + char *b64device = amxml_format_tag("diskdevice", + dp->device); + vstrextend(&l, " ", b64device, "\n", NULL); + amfree(b64device); + } + vstrextend(&l, optionstr, "\n", NULL); + ql = quote_string(l); + reply(200, "%s", ql); + amfree(optionstr); + amfree(l); + amfree(ql); + amfree(b64disk); + } + } } else if (strcmp(cmd, "LISTDISK") == 0) { char *qname; disk_t *disk; int nbdisk = 0; s[-1] = '\0'; - if (config_name == NULL) { - reply(501, "Must set config, host before listdisk"); + if (get_config_name() == NULL) { + reply(501, _("Must set config, host before listdisk")); } else if (dump_hostname == NULL) { - reply(501, "Must set host before listdisk"); + reply(501, _("Must set host before listdisk")); } else if(arg) { - lreply(200, " List of disk for device %s on host %s", arg, + lreply(200, _(" List of disk for device %s on host %s"), arg, 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); @@ -1510,18 +1697,18 @@ main( } } if(nbdisk > 0) { - reply(200, "List of disk for device %s on host %s", arg, + reply(200, _("List of disk for device %s on host %s"), arg, dump_hostname); } else { - reply(200, "No disk for device %s on host %s", arg, + reply(200, _("No disk for device %s on host %s"), arg, dump_hostname); } } else { - lreply(200, " List of disk for host %s", dump_hostname); + 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); @@ -1529,28 +1716,21 @@ main( } } if(nbdisk > 0) { - reply(200, "List of disk for host %s", dump_hostname); + reply(200, _("List of disk for host %s"), dump_hostname); } else { - reply(200, "No disk for host %s", dump_hostname); + reply(200, _("No disk for host %s"), dump_hostname); } } s[-1] = (char)ch; } else if (strcmp(cmd, "SCNF") == 0 && arg) { s[-1] = '\0'; - amfree(config_name); - amfree(config_dir); - config_name = newstralloc(config_name, arg); - config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL); - if (is_config_valid(arg) != -1) { + if (check_and_load_config(arg) != -1) { /* try to load the new config */ amfree(dump_hostname); /* invalidate any value */ amfree(qdisk_name); /* invalidate any value */ amfree(disk_name); /* invalidate any value */ - reply(200, "Config set to %s.", config_name); - } else { - amfree(config_name); - amfree(config_dir); - } + reply(200, _("Config set to %s."), get_config_name()); + } /* check_and_load_config replies with any failure messages */ s[-1] = (char)ch; } else if (strcmp(cmd, "FEATURES") == 0 && arg) { char *our_feature_string = NULL; @@ -1562,6 +1742,10 @@ main( our_feature_string = am_feature_to_string(our_features); their_feature_string = newstralloc(their_feature_string, arg); their_features = am_string_to_feature(their_feature_string); + if (!their_features) { + g_warning("Invalid client feature set '%s'", their_feature_string); + their_features = am_set_default_feature_set(); + } reply(200, "FEATURES %s", our_feature_string); amfree(our_feature_string); amfree(their_feature_string); @@ -1569,13 +1753,13 @@ main( } else if (strcmp(cmd, "DATE") == 0 && arg) { s[-1] = '\0'; target_date = newstralloc(target_date, arg); - reply(200, "Working date set to %s.", target_date); + reply(200, _("Working date set to %s."), target_date); s[-1] = (char)ch; } else if (strcmp(cmd, "DHST") == 0) { (void)disk_history_list(); } else if (strcmp(cmd, "OISD") == 0 && arg) { if (is_dir_valid_opaque(arg) != -1) { - reply(200, "\"%s\" is a valid directory", arg); + reply(200, _("\"%s\" is a valid directory"), arg); } } else if (strcmp(cmd, "OLSD") == 0 && arg) { (void)opaque_ls(arg,0); @@ -1587,7 +1771,7 @@ main( (void)are_dumps_compressed(); } else { *cmd_undo = cmd_undo_ch; /* restore the command line */ - reply(500, "Command not recognised/incorrect: %s", cmd); + reply(500, _("Command not recognised/incorrect: %s"), cmd); } amfree(line); } @@ -1595,7 +1779,7 @@ main( uncompress_remove = remove_files(uncompress_remove); free_find_result(&output_find); - reply(200, "Good bye."); + reply(200, _("Good bye.")); dbclose(); return 0; } @@ -1618,7 +1802,7 @@ amindexd_nicedate( day = numdate % 100; if(strlen(datestamp) <= 8) { - snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d", + g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d", year, month, day); } else { @@ -1629,7 +1813,7 @@ amindexd_nicedate( minutes = (numtime / 100) % 100; seconds = numtime % 100; - snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d-%02d-%02d-%02d", + g_snprintf(nice, SIZEOF(nice), "%4d-%02d-%02d-%02d-%02d-%02d", year, month, day, hours, minutes, seconds); } @@ -1644,37 +1828,131 @@ cmp_date( return strncmp(date1, date2, strlen(date2)); } -static char * -clean_backslash( - char *line) +static int +get_index_dir( + char *dump_hostname, + char *hostname, + char *diskname) { - 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++; + 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; } - } else { - *p++ = *s++; } + 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); } - *p = '\0'; + 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); - return line; + 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; }