Exemplo n.º 1
0
int
main(
    int		argc,
    char **	argv)
{
    static struct databuf db;
    struct cmdargs *cmdargs;
    int infd;
    char *q = NULL;
    char *filename = NULL;
    off_t chunksize, use;
    times_t runtime;
    am_feature_t *their_features = NULL;
    int a;
    config_overrides_t *cfg_ovr = NULL;
    char *cfg_opt = NULL;
    char *m;

    /*
     * Configure program for internationalization:
     *   1) Only set the message locale for now.
     *   2) Set textdomain for all amanda related programs to "amanda"
     *      We don't want to be forced to support dozens of message catalogs.
     */
    setlocale(LC_MESSAGES, "C");
    textdomain("amanda");

    safe_fd(-1, 0);

    set_pname("chunker");

    dbopen(DBG_SUBDIR_SERVER);

    /* Don't die when child closes pipe */
    signal(SIGPIPE, SIG_IGN);

    add_amanda_log_handler(amanda_log_stderr);
    add_amanda_log_handler(amanda_log_trace_log);

    cfg_ovr = extract_commandline_config_overrides(&argc, &argv);

    if (argc > 1)
        cfg_opt = argv[1];

    config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
    apply_config_overrides(cfg_ovr);

    if (config_errors(NULL) >= CFGERR_WARNINGS) {
        config_print_errors();
        if (config_errors(NULL) >= CFGERR_ERRORS) {
            g_critical(_("errors processing config file"));
        }
    }

    safe_cd(); /* do this *after* config_init() */

    check_running_as(RUNNING_AS_DUMPUSER);

    dbrename(get_config_name(), DBG_SUBDIR_SERVER);

    log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
    g_fprintf(stderr,
              _("%s: pid %ld executable %s version %s\n"),
              get_pname(), (long) getpid(),
              argv[0], VERSION);
    fflush(stderr);

    /* now, make sure we are a valid user */

    signal(SIGPIPE, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);

    cmdargs = getcmd();
    if(cmdargs->cmd == START) {
        if(cmdargs->argc <= 1)
            error(_("error [dumper START: not enough args: timestamp]"));
        chunker_timestamp = newstralloc(chunker_timestamp, cmdargs->argv[1]);
    }
    else {
        log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
        error(_("Didn't get START command"));
    }

    /*    do {*/
    cmdargs = getcmd();

    switch(cmdargs->cmd) {
    case QUIT:
        break;

    case PORT_WRITE:
        /*
         * PORT-WRITE
         *   handle
         *   filename
         *   host
         *   features
         *   disk
         *   level
         *   dumpdate
         *   chunksize
         *   progname
         *   use
         *   options
         */
        a = 1;

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: handle]"));
            /*NOTREACHED*/
        }
        handle = newstralloc(handle, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: filename]"));
            /*NOTREACHED*/
        }
        filename = newstralloc(filename, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: hostname]"));
            /*NOTREACHED*/
        }
        hostname = newstralloc(hostname, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: features]"));
            /*NOTREACHED*/
        }
        am_release_feature_set(their_features);
        their_features = am_string_to_feature(cmdargs->argv[a++]);
        if (!their_features) {
            error(_("error [chunker PORT-WRITE: invalid feature string]"));
            /*NOTREACHED*/
        }

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: diskname]"));
            /*NOTREACHED*/
        }
        diskname = newstralloc(diskname, cmdargs->argv[a++]);
        if (qdiskname)
            amfree(qdiskname);
        qdiskname = quote_string(diskname); /* qdiskname is a global */

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: level]"));
            /*NOTREACHED*/
        }
        level = atoi(cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: dumpdate]"));
            /*NOTREACHED*/
        }
        dumpdate = newstralloc(dumpdate, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: chunksize]"));
            /*NOTREACHED*/
        }
        chunksize = OFF_T_ATOI(cmdargs->argv[a++]);
        chunksize = am_floor(chunksize, (off_t)DISK_BLOCK_KB);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: progname]"));
            /*NOTREACHED*/
        }
        progname = newstralloc(progname, cmdargs->argv[a++]);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: use]"));
            /*NOTREACHED*/
        }
        use = am_floor(OFF_T_ATOI(cmdargs->argv[a++]), DISK_BLOCK_KB);

        if(a >= cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: not enough args: options]"));
            /*NOTREACHED*/
        }
        options = newstralloc(options, cmdargs->argv[a++]);

        if(a != cmdargs->argc) {
            error(_("error [chunker PORT-WRITE: too many args: %d != %d]"),
                  cmdargs->argc, a);
            /*NOTREACHED*/
        }

        if((infd = startup_chunker(filename, use, chunksize, &db)) < 0) {
            q = quote_string(vstrallocf(_("[chunker startup failed: %s]"), errstr));
            putresult(TRYAGAIN, "%s %s\n", handle, q);
            error("startup_chunker failed: %s", errstr);
        }
        command_in_transit = NULL;
        if(infd >= 0 && do_chunk(infd, &db)) {
            char kb_str[NUM_STR_SIZE];
            char kps_str[NUM_STR_SIZE];
            double rt;

            runtime = stopclock();
            rt = g_timeval_to_double(runtime);
            g_snprintf(kb_str, SIZEOF(kb_str), "%lld",
                       (long long)(dumpsize - (off_t)headersize));
            g_snprintf(kps_str, SIZEOF(kps_str), "%3.1lf",
                       isnormal(rt) ? (double)dumpsize / rt : 0.0);
            errstr = newvstrallocf(errstr, "sec %s kb %s kps %s",
                                   walltime_str(runtime), kb_str, kps_str);
            m = vstrallocf("[%s]", errstr);
            q = quote_string(m);
            amfree(m);
            if(command_in_transit != NULL) {
                cmdargs = command_in_transit;
                command_in_transit = NULL;
            } else {
                cmdargs = getcmd();
            }
            switch(cmdargs->cmd) {
            case DONE:
                putresult(DONE, "%s %lld %s\n", handle,
                          (long long)(dumpsize - (off_t)headersize), q);
                log_add(L_SUCCESS, "%s %s %s %d [%s]",
                        hostname, qdiskname, chunker_timestamp, level, errstr);
                break;
            case BOGUS:
            case TRYAGAIN:
            case FAILED:
            case ABORT_FINISHED:
                if(dumpsize > (off_t)DISK_BLOCK_KB) {
                    putresult(PARTIAL, "%s %lld %s\n", handle,
                              (long long)(dumpsize - (off_t)headersize),
                              q);
                    log_add(L_PARTIAL, "%s %s %s %d [%s]",
                            hostname, qdiskname, chunker_timestamp, level, errstr);
                }
                else {
                    errstr = newvstrallocf(errstr,
                                           _("dumper returned %s"), cmdstr[cmdargs->cmd]);
                    amfree(q);
                    m = vstrallocf("[%s]",errstr);
                    q = quote_string(m);
                    amfree(m);
                    putresult(FAILED, "%s %s\n", handle, q);
                    log_add(L_FAIL, "%s %s %s %d [%s]",
                            hostname, qdiskname, chunker_timestamp, level, errstr);
                }
            default:
                break;
            }
            amfree(q);
        } else if(infd != -2) {
            if(q == NULL) {
                m = vstrallocf("[%s]", errstr);
                q = quote_string(m);
                amfree(m);
            }
            if(!abort_pending) {
                putresult(FAILED, "%s %s\n", handle, q);
            }
            log_add(L_FAIL, "%s %s %s %d [%s]",
                    hostname, qdiskname, chunker_timestamp, level, errstr);
            amfree(q);
        }
        amfree(filename);
        amfree(db.filename);
        break;

    default:
        if(cmdargs->argc >= 1) {
            q = quote_string(cmdargs->argv[0]);
        } else {
            q = stralloc(_("(no input?)"));
        }
        putresult(BAD_COMMAND, "%s\n", q);
        amfree(q);
        break;
    }

    /*    } while(cmdargs->cmd != QUIT); */

    log_add(L_INFO, "pid-done %ld", (long)getpid());

    amfree(errstr);
    amfree(chunker_timestamp);
    amfree(handle);
    amfree(hostname);
    amfree(diskname);
    amfree(qdiskname);
    amfree(dumpdate);
    amfree(progname);
    amfree(options);
    free_cmdargs(cmdargs);
    if (command_in_transit)
        free_cmdargs(command_in_transit);
    am_release_feature_set(their_features);
    their_features = NULL;

    dbclose();

    return (0); /* exit */
}
Exemplo n.º 2
0
int
main(
    int		argc,
    char **	argv)
{
    extern int optind;
    int opt;
    GSList *dumpspecs = NULL;
    int fd;
    tapelist_t *needed_tapes = NULL;
    char *e;
    rst_flags_t *rst_flags;
    int minimum_arguments;
    config_overrides_t *cfg_ovr = NULL;
    disklist_t diskq;
    char * conf_diskfile = NULL;
    am_feature_t *our_features = am_init_feature_set();

    /*
     * 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"); 

    set_pname("amfetchdump");

    /* Don't die when child closes pipe */
    signal(SIGPIPE, SIG_IGN);

    dbopen(DBG_SUBDIR_SERVER);

    add_amanda_log_handler(amanda_log_stderr);
    error_exit_status = 2;

    rst_flags = new_rst_flags();
    rst_flags->wait_tape_prompt = 1;

    /* handle options */
    cfg_ovr = new_config_overrides(argc/2);
    while( (opt = getopt_long(argc, argv, "alht:scCpb:nwi:d:O:o:", long_options, NULL)) != -1) {
	switch(opt) {
	case 0:
	    switch (loptions) {
		case 1:
		    rst_flags->headers = 1;
		    if (strcmp(optarg, "-") == 0)
			rst_flags->header_to_fd = STDOUT_FILENO;
		    else
			rst_flags->header_to_fd = atoi(optarg);
		    if (fcntl(rst_flags->header_to_fd, F_GETFL, NULL) == -1) {
			error(_("fd %d: %s\n"), rst_flags->header_to_fd,
			      strerror(errno));
		    }
		    break;
		case 2:
		    rst_flags->headers = 1;
		    rst_flags->header_to_fd = open(optarg,
						 O_WRONLY | O_CREAT | O_TRUNC,
						 S_IRUSR | S_IWUSR);
		    if (rst_flags->header_to_fd == -1) {
			error(_("Can't create '%s': %s\n"), optarg,
			      strerror(errno));
		    }
		    break;
	    }
	    break;
	case 'b':
            rst_flags->blocksize = (ssize_t)strtol(optarg, &e, 10);
            if(*e == 'k' || *e == 'K') {
	        rst_flags->blocksize *= 1024;
	    } else if(*e == 'm' || *e == 'M') {
	        rst_flags->blocksize *= 1024 * 1024;
	    } else if(*e != '\0') {
	        error(_("invalid blocksize value \"%s\""), optarg);
		/*NOTREACHED*/
	    }
	    if(rst_flags->blocksize < DISK_BLOCK_BYTES) {
	        error(_("minimum block size is %dk"), DISK_BLOCK_BYTES / 1024);
		/*NOTREACHED*/
	    }
	    break;
	case 'c': rst_flags->compress = 1; break;
	case 'O': rst_flags->restore_dir = stralloc(optarg) ; break;
	case 'd': rst_flags->alt_tapedev = stralloc(optarg) ; break;
	case 'C':
	    rst_flags->compress = 1;
	    rst_flags->comp_type = COMPRESS_BEST_OPT;
	    break;
	case 'p': rst_flags->pipe_to_fd = STDOUT_FILENO; break;
	case 's': rst_flags->fsf = (off_t)0; break;
	case 'l': rst_flags->leave_comp = 1; break;
	case 'i': rst_flags->inventory_log = stralloc(optarg); break;
	case 'n': rst_flags->inline_assemble = 0; break;
	case 'w': rst_flags->delay_assemble = 1; break;
	case 'a': rst_flags->wait_tape_prompt = 0; break;
	case 'h': rst_flags->headers = 1; break;
	case 'o': add_config_override_opt(cfg_ovr, optarg); break;
	default:
	    usage();
	    /*NOTREACHED*/
	}
    }

    for(fd = 3; fd < (int)FD_SETSIZE; fd++) {
	if (fd != debug_fd() &&
	    fd != rst_flags->pipe_to_fd &&
	    fd != rst_flags->header_to_fd) {
	    /*
	     * Make sure nobody spoofs us with a lot of extra open files
	     * that would cause a successful open to get a very high file
	     * descriptor, which in turn might be used as an index into
	     * an array (e.g. an fd_set).
	     */
	    close(fd);
	}
    }

    /* Check some flags that affect inventorying */
    if(rst_flags->inventory_log){
	if(rst_flags->inline_assemble) rst_flags->delay_assemble = 1;
	rst_flags->inline_assemble = 0;
	rst_flags->leave_comp = 1;
	if(rst_flags->compress){
	    error(_("Cannot force compression when doing inventory/search"));
	    /*NOTREACHED*/
	}
	g_fprintf(stderr, _("Doing inventory/search, dumps will not be uncompressed or assembled on-the-fly.\n"));
    }
    else{
	if(rst_flags->delay_assemble){
	    g_fprintf(stderr, _("Using -w, split dumpfiles will *not* be automatically uncompressed.\n"));
	}
    }

    /* make sure our options all make sense otherwise */
    if(check_rst_flags(rst_flags) == -1) {
    	usage();
	/*NOTREACHED*/
    }

    if (rst_flags->inventory_log) {
        minimum_arguments = 1;
    } else {
        minimum_arguments = 2;
    }
 
    if(argc - optind < minimum_arguments) {
	usage();
	/*NOTREACHED*/
    }

    config_init(CONFIG_INIT_EXPLICIT_NAME, argv[optind++]);
    apply_config_overrides(cfg_ovr);

    conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
    read_diskfile(conf_diskfile, &diskq);
    amfree(conf_diskfile);

    if (config_errors(NULL) >= CFGERR_WARNINGS) {
	config_print_errors();
	if (config_errors(NULL) >= CFGERR_ERRORS) {
	    g_critical(_("errors processing config file"));
	}
    }

    check_running_as(RUNNING_AS_DUMPUSER);

    dbrename(get_config_name(), DBG_SUBDIR_SERVER);

    dumpspecs = cmdline_parse_dumpspecs(argc - optind, argv + optind,
					CMDLINE_PARSE_DATESTAMP |
					CMDLINE_PARSE_LEVEL |
					CMDLINE_EMPTY_TO_WILDCARD);

    /*
     * We've been told explicitly to go and search through the tapes the hard
     * way.
     */
    if(rst_flags->inventory_log){
	g_fprintf(stderr, _("Beginning tape-by-tape search.\n"));
	search_tapes(stderr, stdin, rst_flags->alt_tapedev == NULL,
                     NULL, dumpspecs, rst_flags, our_features);
	dbclose();
	exit(0);
    }


    /* Decide what tapes we'll need */
    needed_tapes = list_needed_tapes(dumpspecs,
				     rst_flags->pipe_to_fd == STDOUT_FILENO,
				     &diskq);

    parent_pid = getpid();
    atexit(cleanup);
    get_lock = lock_logfile(); /* config is loaded, should be ok here */
    if(get_lock == 0) {
	char *process_name = get_master_process(rst_conf_logfile);
	error(_("%s exists: %s is already running, or you must run amcleanup"), rst_conf_logfile, process_name);
    }
    log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
    search_tapes(NULL, stdin, rst_flags->alt_tapedev == NULL,
                 needed_tapes, dumpspecs, rst_flags, our_features);
    cleanup();

    dumpspec_list_free(dumpspecs);

    if(rst_flags->inline_assemble || rst_flags->delay_assemble)
	flush_open_outputs(1, NULL);
    else flush_open_outputs(0, NULL);

    free_disklist(&diskq);
    free_rst_flags(rst_flags);

    dbclose();

    return(0);
}
Exemplo n.º 3
0
int
main(
    int		argc,
    char **	argv)
{
    int i;
    time_t timer;
    char *lineread = NULL;
    struct sigaction act, oact;
    extern char *optarg;
    extern int optind;
    char *line = NULL;
    const security_driver_t *secdrv;
    char *req = NULL;
    int response_error;
    struct tm *tm;
    config_overrides_t *cfg_ovr;

    /*
     * Configure program for internationalization:
     *   1) Only set the message locale for now.
     *   2) Set textdomain for all amanda related programs to "amanda"
     *      We don't want to be forced to support dozens of message catalogs.
     */  
    setlocale(LC_MESSAGES, "C");
    textdomain("amanda"); 

    safe_fd(-1, 0);

    set_pname("amrecover");

    /* Don't die when child closes pipe */
    signal(SIGPIPE, SIG_IGN);

    dbopen(DBG_SUBDIR_CLIENT);

    localhost = alloc(MAX_HOSTNAME_LENGTH+1);
    if (gethostname(localhost, MAX_HOSTNAME_LENGTH) != 0) {
	error(_("cannot determine local host name\n"));
	/*NOTREACHED*/
    }
    localhost[MAX_HOSTNAME_LENGTH] = '\0';

    /* load the base client configuration */
    config_init(CONFIG_INIT_CLIENT, NULL);

    if (config_errors(NULL) >= CFGERR_WARNINGS) {
	config_print_errors();
	if (config_errors(NULL) >= CFGERR_ERRORS) {
	    g_critical(_("errors processing config file"));
	}
    }

    /* treat amrecover-specific command line options as the equivalent
     * -o command-line options to set configuration values */
    cfg_ovr = new_config_overrides(argc/2);

    /* If the first argument is not an option flag, then we assume
     * it is a configuration name to match the syntax of the other
     * Amanda utilities. */
    if (argc > 1 && argv[1][0] != '-') {
	add_config_override(cfg_ovr, "conf", argv[1]);

	/* remove that option from the command line */
	argv[1] = argv[0];
	argv++; argc--;
    }

    /* now parse regular command-line '-' options */
    while ((i = getopt(argc, argv, "o:C:s:t:d:U")) != EOF) {
	switch (i) {
	    case 'C':
		add_config_override(cfg_ovr, "conf", optarg);
		break;

	    case 's':
		add_config_override(cfg_ovr, "index_server", optarg);
		break;

	    case 't':
		add_config_override(cfg_ovr, "tape_server", optarg);
		break;

	    case 'd':
		add_config_override(cfg_ovr, "tapedev", optarg);
		break;

	    case 'o':
		add_config_override_opt(cfg_ovr, optarg);
		break;

	    case 'U':
	    case '?':
		(void)g_printf(USAGE);
		return 0;
	}
    }
    if (optind != argc) {
	(void)g_fprintf(stderr, USAGE);
	exit(1);
    }

    /* and now try to load the configuration named in that file */
    apply_config_overrides(cfg_ovr);
    config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
		getconf_str(CNF_CONF));
    reapply_config_overrides();

    check_running_as(RUNNING_AS_ROOT);

    dbrename(get_config_name(), DBG_SUBDIR_CLIENT);

    our_features = am_init_feature_set();
    our_features_string = am_feature_to_string(our_features);

    server_name = NULL;
    if (getconf_seen(CNF_INDEX_SERVER) == -2) { /* command line argument */
	server_name = getconf_str(CNF_INDEX_SERVER);
    }
    if (!server_name) {
	server_name = getenv("AMANDA_SERVER");
	if (server_name) {
	    g_printf(_("Using index server from environment AMANDA_SERVER (%s)\n"), server_name);
	}
    }
    if (!server_name) {
	server_name = getconf_str(CNF_INDEX_SERVER);
    }
    if (!server_name) {
	error(_("No index server set"));
	/*NOTREACHED*/
    }
    server_name = stralloc(server_name);

    tape_server_name = NULL;
    if (getconf_seen(CNF_TAPE_SERVER) == -2) { /* command line argument */
	tape_server_name = getconf_str(CNF_TAPE_SERVER);
    }
    if (!tape_server_name) {
	tape_server_name = getenv("AMANDA_TAPE_SERVER");
	if (!tape_server_name) {
	    tape_server_name = getenv("AMANDA_TAPESERVER");
	    if (tape_server_name) {
		g_printf(_("Using tape server from environment AMANDA_TAPESERVER (%s)\n"), tape_server_name);
	    }
	} else {
	    g_printf(_("Using tape server from environment AMANDA_TAPE_SERVER (%s)\n"), tape_server_name);
	}
    }
    if (!tape_server_name) {
	tape_server_name = getconf_str(CNF_TAPE_SERVER);
    }
    if (!tape_server_name) {
	error(_("No tape server set"));
	/*NOTREACHED*/
    }
    tape_server_name = stralloc(tape_server_name);

    amfree(tape_device_name);
    tape_device_name = getconf_str(CNF_TAPEDEV);
    if (!tape_device_name ||
	strlen(tape_device_name) == 0 ||
	!getconf_seen(CNF_TAPEDEV)) {
	tape_device_name = NULL;
    } else {
	tape_device_name = stralloc(tape_device_name);
    }

    authopt = stralloc(getconf_str(CNF_AUTH));


    amfree(disk_name);
    amfree(mount_point);
    amfree(disk_path);
    dump_date[0] = '\0';

    /* Don't die when child closes pipe */
    signal(SIGPIPE, SIG_IGN);

    /* set up signal handler */
    act.sa_handler = sigint_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if (sigaction(SIGINT, &act, &oact) != 0) {
	error(_("error setting signal handler: %s"), strerror(errno));
	/*NOTREACHED*/
    }

    protocol_init();

    /* We assume that amindexd support fe_amindexd_options_features */
    /*                             and fe_amindexd_options_auth     */
    /* We should send a noop to really know                         */
    req = vstrallocf("SERVICE amindexd\n"
		    "OPTIONS features=%s;auth=%s;\n",
		    our_features_string, authopt);

    secdrv = security_getdriver(authopt);
    if (secdrv == NULL) {
	error(_("no '%s' security driver available for host '%s'"),
	    authopt, server_name);
	/*NOTREACHED*/
    }

    protocol_sendreq(server_name, secdrv, generic_client_get_security_conf,
		     req, STARTUP_TIMEOUT, amindexd_response, &response_error);

    amfree(req);
    protocol_run();

    g_printf(_("AMRECOVER Version %s. Contacting server on %s ...\n"),
	   VERSION, server_name);

    if(response_error != 0) {
	g_fprintf(stderr,"%s\n",errstr);
	exit(1);
    }

    /* get server's banner */
    if (grab_reply(1) == -1) {
        aclose(server_socket);
	exit(1);
    }
    if (!server_happy()) {
	dbclose();
	aclose(server_socket);
	exit(1);
    }

    /* try to get the features from the server */
    {
	char *their_feature_string = NULL;

	indexsrv_features = NULL;

	line = vstrallocf("FEATURES %s", our_features_string);
	if(exchange(line) == 0) {
	    their_feature_string = stralloc(server_line+13);
	    indexsrv_features = am_string_to_feature(their_feature_string);
	    if (!indexsrv_features)
		g_printf(_("Bad feature string from server: %s"), their_feature_string);
	}
	if (!indexsrv_features)
	    indexsrv_features = am_set_default_feature_set();

	amfree(their_feature_string);
	amfree(line);
    }

    /* set the date of extraction to be today */
    (void)time(&timer);
    tm = localtime(&timer);
    if (tm) 
	strftime(dump_date, sizeof(dump_date), "%Y-%m-%d", tm);
    else
	error(_("BAD DATE"));

    g_printf(_("Setting restore date to today (%s)\n"), dump_date);
    line = vstrallocf("DATE %s", dump_date);
    if (converse(line) == -1) {
        aclose(server_socket);
	exit(1);
    }
    amfree(line);

    line = vstrallocf("SCNF %s", get_config_name());
    if (converse(line) == -1) {
        aclose(server_socket);
	exit(1);
    }
    amfree(line);

    if (server_happy()) {
	/* set host we are restoring to this host by default */
	amfree(dump_hostname);
	set_host(localhost);
	if (dump_hostname)
	    g_printf(_("Use the setdisk command to choose dump disk to recover\n"));
	else
	    g_printf(_("Use the sethost command to choose a host to recover\n"));

    }

    quit_prog = 0;
    do {
	if ((lineread = readline("amrecover> ")) == NULL) {
	    clearerr(stdin);
	    putchar('\n');
	    break;
	}
	if (lineread[0] != '\0') 
	{
	    add_history(lineread);
	    dbprintf(_("user command: '%s'\n"), lineread);
	    process_line(lineread);	/* act on line's content */
	}
	amfree(lineread);
    } while (!quit_prog);

    dbclose();

    aclose(server_socket);
    return 0;
}