#include "version.h"
#include "clock.h"
#include "restore.h"
+#include "cmdline.h"
#include "changer.h"
-#include "tapeio.h"
#include "conffile.h"
#include "logfile.h"
#include "amfeatures.h"
#include "stream.h"
#include "amandad.h"
+#include "server_util.h"
+
+#define amidxtaped_debug(i,x) do { \
+ if ((i) <= debug_amidxtaped) { \
+ dbprintf(x); \
+ } \
+} while (0)
#define TIMEOUT 30
static char *pgm = "amidxtaped"; /* in case argv[0] is not set */
extern char *rst_conf_logfile;
-extern char *config_dir;
static int get_lock = 0;
static int from_amandad;
static g_option_t *g_options = NULL;
static int ctlfdin, ctlfdout, datafdout;
static char *amandad_auth = NULL;
+static FILE *cmdin, *cmdout;
-static char *get_client_line(void);
+static char *get_client_line(FILE *in);
static void check_security_buffer(char *);
static char *get_client_line_fd(int);
/* get a line from client - line terminated by \r\n */
static char *
-get_client_line(void)
+get_client_line(FILE *in)
{
static char *line = NULL;
char *part = NULL;
amfree(line);
while(1) {
- if((part = agets(stdin)) == NULL) {
+ if((part = agets(in)) == 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: EOF reached\n", debug_prefix_time(NULL)));
+ dbprintf(_("EOF reached\n"));
}
if(line) {
- dbprintf(("%s: unprocessed input:\n", debug_prefix_time(NULL)));
- dbprintf(("-----\n"));
- dbprintf(("%s\n", line));
- dbprintf(("-----\n"));
+ dbprintf(_("s: unprocessed input:\n"));
+ dbprintf("-----\n");
+ dbprintf("%s\n", line);
+ dbprintf("-----\n");
}
amfree(line);
amfree(part);
*/
strappend(line, "\n");
}
- dbprintf(("%s: > %s\n", debug_prefix_time(NULL), line));
+ dbprintf("> %s\n", line);
return line;
}
/* Keep looping if failure is temporary */
continue;
}
- dbprintf(("%s: Control pipe read error - %s\n",
- pgm, strerror(errno)));
+ dbprintf(_("%s: Control pipe read error - %s\n"),
+ pgm, strerror(errno));
break;
}
line_size *= 2;
line = realloc(line, line_size);
if (line == NULL) {
- error("Memory reallocation failure");
+ error(_("Memory reallocation failure"));
/*NOTREACHED*/
}
s = &line[len];
check_security_buffer(
char * buffer)
{
- socklen_t i;
+ socklen_t_equiv i;
struct sockaddr_in addr;
char *s, *fp, ch;
char *errstr = NULL;
- dbprintf(("%s: check_security_buffer(buffer='%s')\n",
- debug_prefix(NULL), buffer));
+ dbprintf(_("check_security_buffer(buffer='%s')\n"), buffer);
i = SIZEOF(addr);
if (getpeername(0, (struct sockaddr *)&addr, &i) == -1) {
- error("getpeername: %s", strerror(errno));
+ error(_("getpeername: %s"), strerror(errno));
/*NOTREACHED*/
}
if ((addr.sin_family != (sa_family_t)AF_INET)
|| (ntohs(addr.sin_port) == 20)) {
- error("connection rejected from %s family %d port %d",
+ error(_("connection rejected from %s family %d port %d"),
inet_ntoa(addr.sin_addr), addr.sin_family, htons(addr.sin_port));
/*NOTREACHED*/
}
skip_whitespace(s, ch);
if (ch == '\0') {
- error("cannot parse SECURITY line");
+ error(_("cannot parse SECURITY line"));
/*NOTREACHED*/
}
fp = s-1;
skip_non_whitespace(s, ch);
s[-1] = '\0';
if (strcmp(fp, "SECURITY") != 0) {
- error("cannot parse SECURITY line");
+ error(_("cannot parse SECURITY line"));
/*NOTREACHED*/
}
skip_whitespace(s, ch);
- if (!check_security(&addr, s-1, 0, &errstr)) {
- error("security check failed: %s", errstr);
+ if (!check_security((sockaddr_union *)&addr, s-1, 0, &errstr)) {
+ error(_("security check failed: %s"), errstr);
/*NOTREACHED*/
}
}
char *buf = NULL;
int data_sock = -1;
in_port_t data_port = (in_port_t)-1;
- socklen_t socklen;
+ socklen_t_equiv socklen;
struct sockaddr_in addr;
- match_list_t *match_list;
+ GSList *dumpspecs;
tapelist_t *tapes = NULL;
char *their_feature_string = NULL;
rst_flags_t *rst_flags;
int use_changer = 0;
- FILE *prompt_stream = NULL;
int re_end;
char *re_config = NULL;
char *conf_tapetype;
tapetype_t *tape;
char *line;
+ char *tapedev;
+ dumpspec_t *ds;
+
+ /*
+ * 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, 4);
safe_cd();
safe_fd(-1, 0);
}
-#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 */
-
/* initialize */
/* close stderr first so that debug file becomes it - amrestore
chats to stderr, which we don't want going to client */
(void)close(STDERR_FILENO);
dbopen(DBG_SUBDIR_SERVER);
startclock();
- dbprintf(("%s: version %s\n", pgm, version()));
-#ifdef DEBUG_CODE
- if(dbfd() != -1 && dbfd() != STDERR_FILENO)
- {
- if(dup2(dbfd(),STDERR_FILENO) != STDERR_FILENO)
- {
- perror("amidxtaped can't redirect stderr to the debug file");
- dbprintf(("%s: can't redirect stderr to the debug file\n",
- debug_prefix_time(NULL)));
- return 1;
- }
- }
-#else
- if ((i = open("/dev/null", O_WRONLY)) == -1 ||
- (i != STDERR_FILENO &&
- (dup2(i, STDERR_FILENO) != STDERR_FILENO ||
- close(i) != 0))) {
- perror("amidxtaped can't redirect stderr");
- return 1;
- }
-#endif
+ dbprintf(_("%s: version %s\n"), pgm, version());
+ debug_dup_stderr_to_debug();
if (! (argc >= 1 && argv != NULL && 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"));
}
if(from_amandad == 0) {
socklen = SIZEOF(addr);
if (getpeername(0, (struct sockaddr *)&addr, &socklen) == -1) {
- error("getpeername: %s", strerror(errno));
+ error(_("getpeername: %s"), strerror(errno));
/*NOTREACHED*/
}
if ((addr.sin_family != (sa_family_t)AF_INET)
|| (ntohs(addr.sin_port) == 20)) {
- error("connection rejected from %s family %d port %d",
+ error(_("connection rejected from %s family %d port %d"),
inet_ntoa(addr.sin_addr), addr.sin_family,
htons(addr.sin_port));
/*NOTREACHED*/
/* do the security thing */
amfree(buf);
- buf = stralloc(get_client_line());
+ fflush(stdout);
+ cmdout = stdout;
+ cmdin = stdin;
+ buf = stralloc(get_client_line(cmdin));
check_security_buffer(buf);
}
else {
/* 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)
+ error(_("ERROR recover program sent multiple OPTIONS"));
g_options = parse_g_options(line+8, 1);
if(!g_options->hostname) {
g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
if(amandad_auth && g_options->auth) {
if(strcasecmp(amandad_auth, g_options->auth) != 0) {
- printf("ERROR recover program ask for auth=%s while amidxtaped is configured for '%s'\n",
+ g_printf(_("ERROR recover program ask for auth=%s while amidxtaped is configured for '%s'\n"),
g_options->auth, amandad_auth);
- error("ERROR recover program ask for auth=%s while amidxtaped is configured for '%s'",
+ error(_("ERROR recover program ask for auth=%s while amidxtaped is configured for '%s'"),
g_options->auth, amandad_auth);
/*NOTREACHED*/
}
}
/* send the REP packet */
- printf("CONNECT CTL %d DATA %d\n", DATA_FD_OFFSET, DATA_FD_OFFSET+1);
- printf("\n");
+ g_printf("CONNECT CTL %d DATA %d\n", DATA_FD_OFFSET, DATA_FD_OFFSET+1);
+ g_printf("\n");
fflush(stdout);
- fflush(stdin);
- if ((dup2(ctlfdout, fileno(stdout)) < 0)
- || (dup2(ctlfdin, fileno(stdin)) < 0)) {
- error("amandad: Failed to setup stdin or stdout");
+ fclose(stdin);
+ fclose(stdout);
+ cmdout = fdopen(ctlfdout, "a");
+ if (!cmdout) {
+ error(_("amidxtaped: Can't fdopen(ctlfdout): %s"), strerror(errno));
+ /*NOTREACHED*/
+ }
+ cmdin = fdopen(ctlfdin, "r");
+ if (!cmdin) {
+ error(_("amidxtaped: Can't fdopen(ctlfdin): %s"), strerror(errno));
/*NOTREACHED*/
}
}
- /* get the number of arguments */
- match_list = alloc(SIZEOF(match_list_t));
- match_list->next = NULL;
- match_list->hostname = "";
- match_list->datestamp = "";
- match_list->level = "";
- match_list->diskname = "";
-
+ ds = dumpspec_new(NULL, NULL, NULL, NULL);
for (re_end = 0; re_end == 0; ) {
+ char *s, ch;
amfree(buf);
- buf = stralloc(get_client_line());
- if(strncmp(buf, "LABEL=", 6) == 0) {
- tapes = unmarshal_tapelist_str(buf+6);
+ buf = stralloc(get_client_line(cmdin));
+ s = buf;
+ if(strncmp_const_skip(buf, "LABEL=", s, ch) == 0) {
+ tapes = unmarshal_tapelist_str(s);
}
- else if(strncmp(buf, "FSF=", 4) == 0) {
- rst_flags->fsf = OFF_T_ATOI(buf + 4);
+ else if(strncmp_const_skip(buf, "FSF=", s, ch) == 0) {
+ rst_flags->fsf = OFF_T_ATOI(s);
}
- else if(strncmp(buf, "HEADER", 6) == 0) {
+ else if(strncmp_const_skip(buf, "HEADER", s, ch) == 0) {
rst_flags->headers = 1;
}
- else if(strncmp(buf, "FEATURES=", 9) == 0) {
+ else if(strncmp_const_skip(buf, "FEATURES=", s, ch) == 0) {
char *our_feature_string = NULL;
- their_feature_string = stralloc(buf+9);
+ their_feature_string = stralloc(s);
am_release_feature_set(their_features);
their_features = am_string_to_feature(their_feature_string);
amfree(their_feature_string);
our_feature_string = am_feature_to_string(our_features);
if(from_amandad == 1)
- printf("FEATURES=%s\r\n", our_feature_string);
+ g_fprintf(cmdout,"FEATURES=%s\r\n", our_feature_string);
else
- printf("%s", our_feature_string);
- fflush(stdout);
+ g_fprintf(cmdout,"%s", our_feature_string);
+ fflush(cmdout);
amfree(our_feature_string);
}
- else if(strncmp(buf, "DEVICE=", 7) == 0) {
- rst_flags->alt_tapedev= stralloc(buf+7);
+ else if(strncmp_const_skip(buf, "DEVICE=", s, ch) == 0) {
+ rst_flags->alt_tapedev= stralloc(s);
}
- else if(strncmp(buf, "HOST=", 5) == 0) {
- match_list->hostname = stralloc(buf+5);
+ else if(strncmp_const_skip(buf, "HOST=", s, ch) == 0) {
+ if (ds->host) {
+ dbprintf(_("WARNING: HOST appeared twice in client request.\n"));
+ amfree(ds->host);
+ }
+ ds->host = stralloc(s);
}
- else if(strncmp(buf, "DISK=", 5) == 0) {
- match_list->diskname = stralloc(buf+5);
+ else if(strncmp_const_skip(buf, "DISK=", s, ch) == 0) {
+ if (ds->disk) {
+ dbprintf(_("WARNING: DISK appeared twice in client request.\n"));
+ amfree(ds->disk);
+ }
+ ds->disk = stralloc(s);
}
- else if(strncmp(buf, "DATESTAMP=", 10) == 0) {
- match_list->datestamp = stralloc(buf+10);
+ else if(strncmp_const_skip(buf, "DATESTAMP=", s, ch) == 0) {
+ if (ds->datestamp) {
+ dbprintf(_("WARNING: DATESTAMP appeared twice in client request.\n"));
+ amfree(ds->datestamp);
+ }
+ ds->datestamp = stralloc(s);
}
- else if(strncmp(buf, "END", 3) == 0) {
+ else if(strncmp_const(buf, "END") == 0) {
re_end = 1;
}
- else if(strncmp(buf, "CONFIG=", 7) == 0) {
- re_config = stralloc(buf+7);
+ else if(strncmp_const_skip(buf, "CONFIG=", s, ch) == 0) {
+ re_config = stralloc(s);
+ if(strlen(re_config) == 0)
+ amfree(re_config);
}
else if(buf[0] != '\0' && buf[0] >= '0' && buf[0] <= '9') {
-/* XXX does nothing? amrestore_nargs = atoi(buf); */
re_end = 1;
}
}
amfree(buf);
- if(!tapes && rst_flags->alt_tapedev){
- dbprintf(("%s: Looks like we're restoring from a holding file...\n", debug_prefix_time(NULL)));
- tapes = unmarshal_tapelist_str(rst_flags->alt_tapedev);
- tapes->isafile = 1;
- amfree(rst_flags->alt_tapedev);
- rst_flags->alt_tapedev = NULL;
- }
-
if(re_config) {
- char *conffile;
- config_dir = vstralloc(CONFIG_DIR, "/", re_config, "/", NULL);
- conffile = stralloc2(config_dir, CONFFILE_NAME);
- if (read_conffile(conffile)) {
- dbprintf(("%s: config '%s' not found\n",
- debug_prefix_time(NULL), re_config));
- amfree(re_config);
- re_config = NULL;
- }
- amfree(conffile);
+ config_init(CONFIG_INIT_EXPLICIT_NAME, re_config);
+ dbrename(re_config, DBG_SUBDIR_SERVER);
+ } else {
+ config_init(0, NULL);
+ }
- dbrename(config_name, DBG_SUBDIR_SERVER);
+ if (config_errors(NULL) >= CFGERR_ERRORS) {
+ g_critical(_("errors processing config file"));
}
+ check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
+
if(tapes &&
(!rst_flags->alt_tapedev ||
(re_config && ( strcmp(rst_flags->alt_tapedev,
getconf_str(CNF_TPCHANGER)) == 0 ) ) ) ) {
/* We need certain options, if restoring from more than one tape */
if(tapes->next && !am_has_feature(their_features, fe_recover_splits)) {
- error("%s: Client must support split dumps to restore requested data.", get_pname());
+ error(_("Client must support split dumps to restore requested data."));
/*NOTREACHED*/
}
- dbprintf(("%s: Restoring from changer, checking labels\n", get_pname()));
+ dbprintf(_("Restoring from changer, checking labels\n"));
rst_flags->check_labels = 1;
use_changer = 1;
}
+ /* build the dumpspec list from our single dumpspec */
+ dumpspecs = g_slist_append(NULL, (gpointer)ds);
+ ds = NULL;
+
+ if(!tapes && rst_flags->alt_tapedev){
+ dbprintf(_("Looks like we're restoring from a holding file...\n"));
+ tapes = unmarshal_tapelist_str(rst_flags->alt_tapedev);
+ tapes->isafile = 1;
+ amfree(rst_flags->alt_tapedev);
+ rst_flags->alt_tapedev = NULL;
+ use_changer = FALSE;
+ }
+
+ tapedev = getconf_str(CNF_TAPEDEV);
/* If we'll be stepping on the tape server's devices, lock them. */
if(re_config &&
- (use_changer || (rst_flags->alt_tapedev &&
- strcmp(rst_flags->alt_tapedev,
- getconf_str(CNF_TAPEDEV)) == 0) ) ) {
- dbprintf(("%s: Locking devices\n", get_pname()));
+ (use_changer || (rst_flags->alt_tapedev && tapedev &&
+ strcmp(rst_flags->alt_tapedev, tapedev) == 0) ) ) {
+ dbprintf(_("Locking devices\n"));
parent_pid = getpid();
atexit(cleanup);
get_lock = lock_logfile();
}
+ if (get_lock)
+ log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
/* Init the tape changer */
if(tapes && use_changer && changer_init() == 0) {
- dbprintf(("%s: No changer available\n", debug_prefix_time(NULL)));
+ dbprintf(_("No changer available\n"));
}
/* Read the default block size from the tape type */
if(am_has_feature(their_features, fe_recover_splits)) {
if(from_amandad == 1) {
rst_flags->pipe_to_fd = datafdout;
- prompt_stream = stdout;
}
else {
int data_fd;
char *buf;
- dbprintf(("%s: Client understands split dumpfiles\n",get_pname()));
+ dbprintf(_("Client understands split dumpfiles\n"));
- if((data_sock = stream_server(&data_port, STREAM_BUFSIZE,
+ if((data_sock = stream_server(AF_INET, &data_port, STREAM_BUFSIZE,
STREAM_BUFSIZE, 0)) < 0){
- error("%s: could not create data socket: %s", get_pname(),
- strerror(errno));
+ error(_("could not create data socket: %s"), strerror(errno));
/*NOTREACHED*/
}
- dbprintf(("%s: Local port %d set aside for data\n", get_pname(), data_port));
+ dbprintf(_("Local port %d set aside for data\n"), data_port);
/* tell client where to connect */
- printf("CONNECT %hu\n", (unsigned short)data_port);
+ g_printf(_("CONNECT %hu\n"), (unsigned short)data_port);
fflush(stdout);
if((data_fd = stream_accept(data_sock, TIMEOUT, STREAM_BUFSIZE,
STREAM_BUFSIZE)) < 0){
- error("stream_accept failed for client data connection: %s\n",
+ error(_("stream_accept failed for client data connection: %s\n"),
strerror(errno));
/*NOTREACHED*/
}
check_security_buffer(buf);
rst_flags->pipe_to_fd = data_fd;
- prompt_stream = stdout;
}
}
else {
rst_flags->pipe_to_fd = fileno(stdout);
- prompt_stream = stderr;
+ cmdout = stderr;
}
- dbprintf(("%s: Sending output to file descriptor %d\n",
- get_pname(), rst_flags->pipe_to_fd));
+ dbprintf(_("Sending output to file descriptor %d\n"), rst_flags->pipe_to_fd);
+ tapedev = getconf_str(CNF_TAPEDEV);
if(get_lock == 0 &&
re_config &&
- (use_changer || (rst_flags->alt_tapedev &&
- strcmp(rst_flags->alt_tapedev,
- getconf_str(CNF_TAPEDEV)) == 0) ) ) {
- send_message(prompt_stream, rst_flags, their_features,
- "%s exists: amdump or amflush is already running, "
- "or you must run amcleanup",
- rst_conf_logfile);
- error("%s exists: amdump or amflush is already running, "
- "or you must run amcleanup",
- rst_conf_logfile);
+ (use_changer || (rst_flags->alt_tapedev && tapedev &&
+ strcmp(rst_flags->alt_tapedev, tapedev) == 0) ) ) {
+ char *process_name = get_master_process(rst_conf_logfile);
+ send_message(cmdout, rst_flags, their_features,
+ _("%s exists: %s is already running, "
+ "or you must run amcleanup"),
+ rst_conf_logfile, process_name);
+ error(_("%s exists: %s is already running, "
+ "or you must run amcleanup"),
+ rst_conf_logfile, process_name);
}
/* make sure our restore flags aren't crazy */
if (check_rst_flags(rst_flags) == -1) {
if (rst_flags->pipe_to_fd != -1)
aclose(rst_flags->pipe_to_fd);
- send_message(prompt_stream, rst_flags, their_features,
- "restore flags are crazy");
+ send_message(cmdout, rst_flags, their_features,
+ _("restore flags are crazy"));
exit(1);
}
/* actual restoration */
- search_tapes(prompt_stream, use_changer, tapes, match_list, rst_flags,
+ search_tapes(cmdout, cmdin, use_changer, tapes, dumpspecs, rst_flags,
their_features);
- dbprintf(("%s: Restoration finished\n", debug_prefix_time(NULL)));
+ dbprintf(_("Restoration finished\n"));
/* cleanup */
if(rst_flags->pipe_to_fd != -1) aclose(rst_flags->pipe_to_fd);
amfree(rst_flags->alt_tapedev);
amfree(rst_flags);
- amfree(match_list->hostname);
- amfree(match_list->diskname);
- amfree(match_list->datestamp);
- amfree(match_list);
- amfree(config_dir);
+ dumpspec_list_free(dumpspecs);
amfree(re_config);
dbclose();
return 0;
static void
cleanup(void)
{
- if(parent_pid == getpid()) {
- if(get_lock) unlink(rst_conf_logfile);
+ if (parent_pid == getpid()) {
+ if (get_lock) {
+ log_add(L_INFO, "pid-done %ld\n", (long)getpid());
+ unlink(rst_conf_logfile);
+ }
}
}