Example #1
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_overwrites_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_overwrites(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_overwrite(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_overwrite(cfg_ovr, "conf", optarg);
		break;

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

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

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

	    case 'o':
		add_config_overwrite_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_overwrites(cfg_ovr);
    config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
		getconf_str(CNF_CONF));
    reapply_config_overwrites();

    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;
}
Example #2
0
void dumpfile_free(dumpfile_t* info) {
    dumpfile_free_data(info);
    amfree(info);
}
Example #3
0
/*
 * Prints the contents of the file structure.
 */
char *
summarize_header(
    const dumpfile_t *	file)
{
    char *qdisk;
    GString *summ;

    switch(file->type) {
    case F_EMPTY:
	return g_strdup(_("EMPTY file"));

    case F_UNKNOWN:
	return g_strdup(_("UNKNOWN file"));

    default:
    case F_WEIRD:
	return g_strdup(_("WEIRD file"));

    case F_TAPESTART:
	return g_strdup_printf(_("start of tape: date %s label %s"),
	       file->datestamp, file->name);

    case F_NOOP:
	return g_strdup(_("NOOP file"));

    case F_DUMPFILE:
    case F_CONT_DUMPFILE:
	qdisk = quote_string(file->disk);
	summ = g_string_new("");
        g_string_printf(summ, "%s: date %s host %s disk %s lev %d comp %s",
	    filetype2str(file->type), file->datestamp, file->name,
	    qdisk, file->dumplevel,
	    file->compressed? file->comp_suffix : "N");
	amfree(qdisk);
	goto add_suffixes;

    case F_SPLIT_DUMPFILE: {
	char totalparts[NUM_STR_SIZE*2];
        if(file->totalparts > 0)
            g_snprintf(totalparts, sizeof(totalparts), "%d", file->totalparts);
        else
	    g_snprintf(totalparts, sizeof(totalparts), "UNKNOWN");
	qdisk = quote_string(file->disk);
        summ = g_string_new("");
        g_string_printf(summ, "split dumpfile: date %s host %s disk %s"
		      " part %d/%s lev %d comp %s",
                      file->datestamp, file->name, qdisk, file->partnum,
                      totalparts, file->dumplevel,
		      file->compressed? file->comp_suffix : "N");
	amfree(qdisk);
        goto add_suffixes;
    }

    add_suffixes:
	if (*file->program)
	    g_string_append_printf(summ, " program %s", file->program);
	if (g_str_equal(file->encrypt_suffix, "enc"))
	    g_string_append_printf(summ, " crypt %s", file->encrypt_suffix);
	if (*file->srvcompprog)
	    g_string_append_printf(summ, " server_custom_compress %s", file->srvcompprog);
	if (*file->clntcompprog)
	    g_string_append_printf(summ, " client_custom_compress %s", file->clntcompprog);
	if (*file->srv_encrypt)
	    g_string_append_printf(summ, " server_encrypt %s", file->srv_encrypt);
	if (*file->clnt_encrypt)
	    g_string_append_printf(summ, " client_encrypt %s", file->clnt_encrypt);
	if (*file->srv_decrypt_opt)
	    g_string_append_printf(summ, " server_decrypt_option %s", file->srv_decrypt_opt);
	if (*file->clnt_decrypt_opt)
	    g_string_append_printf(summ, " client_decrypt_option %s", file->clnt_decrypt_opt);
	return g_string_free(summ, FALSE);

    case F_TAPEEND:
	return g_strdup_printf("end of tape: date %s", file->datestamp);
	break;
    }
}
Example #4
0
void
set_disk(
    char *	dsk,
    char *	mtpt)
{
    char *cmd = NULL;
    char *qdsk;
    char *uqdsk;
    char *uqmtpt = NULL;

    if (is_extract_list_nonempty())
    {
	g_printf(_("Must clear extract list before changing disk\n"));
	return;
    }

    /* if mount point specified, check it is valid */
    if (mtpt != NULL) {
	uqmtpt = unquote_string(mtpt);
	if (*mtpt != '/') {
	    g_printf(_("Mount point \"%s\" invalid - must start with /\n"), uqmtpt);
	    amfree(uqmtpt);
	    return;
	}
    }

    clear_dir_list();
    uqdsk = unquote_string(dsk);
    qdsk = quote_string(uqdsk);
    cmd = g_strconcat("DISK ", qdsk, NULL);
    amfree(qdsk);
    if (converse(cmd) == -1)
	exit(1);
    amfree(cmd);

    if (!server_happy()) {
	amfree(uqmtpt);
	amfree(uqdsk);
	return;
    }

    g_free(disk_name);
    disk_name = g_strdup(uqdsk);
    if (mtpt == NULL)
    {
	/* mount point not specified */
	if (*uqdsk == '/')
	{
	    /* disk specified by mount point, hence use it */
	    g_free(mount_point);
	    mount_point = g_strdup(uqdsk);
	}
	else
	{
	    /* device name given, use '/' because nothing better */
	    g_free(mount_point);
	    mount_point = g_strdup("/");
	}
    }
    else
    {
	/* mount point specified */
	g_free(mount_point);
	mount_point = g_strdup(uqmtpt);
    }

    /* set the working directory to the mount point */
    /* there is the possibility that there are no index records for the
       disk for the given date, hence setting the directory to the
       mount point will fail. Preempt this by checking first so we can write
       a more informative message. */
    if (exchange("OISD /") == -1)
	exit(1);
    if (server_happy())
    {
	g_free(disk_path);
	g_free(disk_tpath);
	disk_path = g_strdup("/");
	disk_tpath = g_strdup("/");
	suck_dir_list_from_server();	/* get list of directory contents */
    }
    else
    {
	g_printf(_("No index records for disk for specified date\n"));
	g_printf(_("If date correct, notify system administrator\n"));
	g_free(disk_path);
	g_free(disk_tpath);
	disk_path = g_strdup("/");
	disk_tpath = g_strdup("/");
	clear_dir_list();
    }
    amfree(uqmtpt);
    amfree(uqdsk);

    if (am_has_feature(indexsrv_features, fe_amindexd_DLE)) {
	char *dle_str;
	char *errmsg = NULL;

	cmd = g_strdup("DLE");
	if (exchange(cmd) == -1)
	    exit(1);
	amfree(cmd);

	if (!server_happy())
	    return;

	dle_str = reply_line();
	if (BSTRNCMP(dle_str+4, "NODLE") == 0) {
	    dump_dle = NULL;
	} else {
	    dle_str = unquote_string(dle_str+4);
	    dump_dle = amxml_parse_node_CHAR(dle_str, &errmsg);
	    amfree(dle_str);
	    /* Should print the error */
	    amfree(errmsg);
	}
    }
}
Example #5
0
void
set_host(
    const char *host)
{
    char *cmd = NULL;
    struct hostent *hp = NULL;
    char **hostp;
    int found_host = 0;
    char *uqhost = unquote_string(host);

    if (is_extract_list_nonempty())
    {
	g_printf(_("Must clear extract list before changing host\n"));
	amfree(uqhost);
	return;
    }

    /*
     * The idea here is to try as many permutations of the hostname
     * as we can imagine.  The server will reject anything it doesn't
     * recognize.
     */

    cmd = g_strconcat("HOST ", uqhost, NULL);
    if (converse(cmd) == -1)
	exit(1);
    if (server_happy()) {
	found_host = 1;
	host = uqhost;
	uqhost = NULL;
    }

    /*
     * Try converting the given host to a fully qualified, canonical
     * name.
     */
    if (!found_host && !server_warning()) {
	if ((hp = gethostbyname(uqhost)) != NULL) {
	    host = hp->h_name;
	    g_printf(_("Trying host %s ...\n"), host);
	    g_free(cmd);
	    cmd = g_strconcat("HOST ", host, NULL);
	    if (converse(cmd) == -1)
		exit(1);
	    if(server_happy())
		found_host = 1;
	}
    }

    /*
     * Since we have them, try any CNAMEs that were traversed from uqhost
     * to the canonical name (this assumes gethostbyname was called above)
     */
    if (!found_host && !server_warning()) {
	if (hp) {
	    for (hostp = hp->h_aliases; (host = *hostp) != NULL; hostp++)
	    {
		g_printf(_("Trying host %s ...\n"), host);
		g_free(cmd);
		cmd = g_strconcat("HOST ", host, NULL);
		if (converse(cmd) == -1)
		    exit(1);
		if(server_happy())
		{
		    found_host = 1;
		    break;
		}
	    }
	}
    }

    /* Try looking up the canonical name of the host */
    if (!found_host && !server_warning()) {
	char *canonname;
	int result;

	result = resolve_hostname(uqhost, 0, NULL, &canonname);
	if (result == 0 && canonname) {
	    host = canonname;
	    g_printf(_("Trying host %s ...\n"), host);
	    g_free(cmd);
	    cmd = g_strconcat("HOST ", host, NULL);
	    if (converse(cmd) == -1)
		exit(1);
	    if(server_happy())
		found_host = 1;
	}
    }

    if(found_host) {
	g_free(dump_hostname);
	dump_hostname = g_strdup(host);
	amfree(disk_name);
	amfree(mount_point);
	amfree(disk_path);
	amfree(disk_tpath);
	clear_dir_list();
    }
    amfree(cmd);
    amfree(uqhost);
}
Example #6
0
int
main(
    int		argc,
    char **	argv)
{
    int c;
    char *command;
    application_argument_t argument;

#ifdef STAR
    star_path = g_strdup(STAR);
#else
    star_path = NULL;
#endif
    star_tardumps = g_strdup("/etc/tardumps");
    star_dle_tardumps = 0;
    star_onefilesystem = 1;
    star_sparse = 1;
    star_acl = 1;
    star_directory = NULL;

    /* initialize */

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

    if (argc < 2) {
	printf("ERROR no command given to amstar\n");
	error(_("No command given to amstar"));
    }

    /* drop root privileges */
    if (!set_root_privs(0)) {
	if (strcmp(argv[1], "selfcheck") == 0) {
	    printf("ERROR amstar must be run setuid root\n");
	}
	error(_("amstar must be run setuid root"));
    }

    safe_fd(3, 2);

    set_pname("amstar");

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

#if defined(USE_DBMALLOC)
    malloc_size_1 = malloc_inuse(&malloc_hist_1);
#endif

    add_amanda_log_handler(amanda_log_stderr);
    add_amanda_log_handler(amanda_log_syslog);
    dbopen(DBG_SUBDIR_CLIENT);
    startclock();
    dbprintf(_("version %s\n"), VERSION);

    config_init(CONFIG_INIT_CLIENT, NULL);

    //check_running_as(RUNNING_AS_DUMPUSER_PREFERRED);
    //root for amrecover
    //RUNNING_AS_CLIENT_LOGIN from selfcheck, sendsize, sendbackup

    /* parse argument */
    command = argv[1];

    argument.config     = NULL;
    argument.host       = NULL;
    argument.message    = 0;
    argument.collection = 0;
    argument.calcsize   = 0;
    argument.level      = NULL;
    argument.command_options = NULL;
    init_dle(&argument.dle);

    opterr = 0;
    while (1) {
	int option_index = 0;
    	c = getopt_long (argc, argv, "", long_options, &option_index);
	if (c == -1)
	    break;

	switch (c) {
	case 1: if (optarg) {
		    amfree(argument.config);
		    argument.config = g_strdup(optarg);
		}
		break;
	case 2: if (optarg) {
		    amfree(argument.host);
		    argument.host = g_strdup(optarg);
		}
		break;
	case 3: if (optarg) {
		    amfree(argument.dle.disk);
		    argument.dle.disk = g_strdup(optarg);
		}
		break;
	case 4: if (optarg) {
		    amfree(argument.dle.device);
		    argument.dle.device = g_strdup(optarg);
		}
		break;
	case 5: if (optarg) {
		    argument.level = g_slist_append(argument.level,
						GINT_TO_POINTER(atoi(optarg)));
		}
		break;
	case 6: argument.dle.create_index = 1;
		break;
	case 7: argument.message = 1;
		break;
	case 8: argument.collection = 1;
		break;
	case 9: argument.dle.record = 1;
		break;
	case 10: if (optarg) {
		     amfree(star_path);
		     star_path = g_strdup(optarg);
		 }
		 break;
	case 11: if (optarg) {
		     amfree(star_tardumps);
		     star_tardumps = g_strdup(optarg);
		 }
		 break;
	case 12: if (optarg && strcasecmp(optarg, "NO") == 0)
		     star_dle_tardumps = 0;
		 else if (optarg && strcasecmp(optarg, "YES") == 0)
		     star_dle_tardumps = 1;
		 else if (strcasecmp(command, "selfcheck") == 0)
		     printf(_("ERROR [%s: bad STAR-DLE-TARDUMP property value (%s)]\n"), get_pname(), optarg);
		 break;
	case 13: if (optarg && strcasecmp(optarg, "YES") != 0) {
		     /* This option is required to be YES */
		     /* star_onefilesystem = 0; */
		 }
		 break;
	case 14: if (optarg && strcasecmp(optarg, "NO") == 0)
		     star_sparse = 0;
		 else if (optarg && strcasecmp(optarg, "YES") == 0)
		     star_sparse = 1;
		 else if (strcasecmp(command, "selfcheck") == 0)
		     printf(_("ERROR [%s: bad SPARSE property value (%s)]\n"), get_pname(), optarg);
		 break;
	case 15: argument.calcsize = 1;
		 break;
        case 16: if (optarg)
                     normal_message =
                         g_slist_append(normal_message, optarg);
                 break;
        case 17: if (optarg)
                     ignore_message =
                         g_slist_append(ignore_message, optarg);
                 break;
        case 18: if (optarg)
                     strange_message =
                         g_slist_append(strange_message, optarg);
                 break;
	case 19: if (optarg)
		     argument.dle.include_list =
			 append_sl(argument.dle.include_list, optarg);
		 break;
	case 20: if (optarg)
		     argument.dle.exclude_list =
			 append_sl(argument.dle.exclude_list, optarg);
		 break;
	case 21: if (optarg) {
		     amfree(star_directory);
		     star_directory = g_strdup(optarg);
		 }
		 break;
	case 22: if (optarg)
		     argument.command_options =
			g_slist_append(argument.command_options,
				       g_strdup(optarg));
		 break;
	case 23: if (optarg)
		     argument.dle.exclude_file =
			 append_sl(argument.dle.exclude_file, optarg);
		 break;
	case 24: if (optarg && strcasecmp(optarg, "NO") == 0)
		     star_acl = 0;
		 else if (optarg && strcasecmp(optarg, "YES") == 0)
		     star_acl = 1;
		 else if (strcasecmp(command, "selfcheck") == 0)
		     printf(_("ERROR [%s: bad ACL property value (%s)]\n"), get_pname(), optarg);
		 break;
	case ':':
	case '?':
		break;
	}
    }

    if (!argument.dle.disk && argument.dle.device)
	argument.dle.disk = g_strdup(argument.dle.device);
    if (!argument.dle.device && argument.dle.disk)
	argument.dle.device = g_strdup(argument.dle.disk);

    argument.argc = argc - optind;
    argument.argv = argv + optind;

    if (argument.config) {
	/* overlay this configuration on the existing (nameless) configuration */
	config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
		    argument.config);
	dbrename(get_config_name(), DBG_SUBDIR_CLIENT);

    }

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

    re_table = build_re_table(init_re_table, normal_message, ignore_message,
			      strange_message);

    if (strcmp(command, "support") == 0) {
	amstar_support(&argument);
    } else if (strcmp(command, "selfcheck") == 0) {
	amstar_selfcheck(&argument);
    } else if (strcmp(command, "estimate") == 0) {
	amstar_estimate(&argument);
    } else if (strcmp(command, "backup") == 0) {
	amstar_backup(&argument);
    } else if (strcmp(command, "restore") == 0) {
	amstar_restore(&argument);
    } else if (strcmp(command, "validate") == 0) {
	amstar_validate(&argument);
    } else {
	fprintf(stderr, "Unknown command `%s'.\n", command);
	exit (1);
    }
    return 0;
}
Example #7
0
static void
amstar_backup(
    application_argument_t *argument)
{
    int        dumpin;
    char      *cmd = NULL;
    char      *qdisk;
    char       line[32768];
    amregex_t *rp;
    off_t      dump_size = -1;
    char      *type;
    char       startchr;
    GPtrArray *argv_ptr;
    int        starpid;
    int        dataf = 1;
    int        mesgf = 3;
    int        indexf = 4;
    int        outf;
    FILE      *mesgstream;
    FILE      *indexstream = NULL;
    FILE      *outstream;
    int        level;
    regex_t    regex_root;
    regex_t    regex_dir;
    regex_t    regex_file;
    regex_t    regex_special;
    regex_t    regex_symbolic;
    regex_t    regex_hard;

    mesgstream = fdopen(mesgf, "w");
    if (!mesgstream) {
	error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno));
    }

    if (!argument->level) {
	fprintf(mesgstream, "? No level argument\n");
	error(_("No level argument"));
    }
    if (!argument->dle.disk) {
	fprintf(mesgstream, "? No disk argument\n");
	error(_("No disk argument"));
    }
    if (!argument->dle.device) {
	fprintf(mesgstream, "? No device argument\n");
	error(_("No device argument"));
    }

    if (argument->dle.include_list &&
	argument->dle.include_list->nb_element >= 0) {
	fprintf(mesgstream, "? include-list not supported for backup\n");
    }

    level = GPOINTER_TO_INT(argument->level->data);

    qdisk = quote_string(argument->dle.disk);

    argv_ptr = amstar_build_argv(argument, level, CMD_BACKUP);

    cmd = g_strdup(star_path);

    starpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
			 &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);

    g_ptr_array_free_full(argv_ptr);
    /* close the write ends of the pipes */
    aclose(dumpin);
    aclose(dataf);
    if (argument->dle.create_index) {
	indexstream = fdopen(indexf, "w");
	if (!indexstream) {
	    error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
	}
    }
    outstream = fdopen(outf, "r");
    if (!outstream) {
	error(_("error outstream(%d): %s\n"), outf, strerror(errno));
    }

    regcomp(&regex_root, "^a \\.\\/ directory$", REG_EXTENDED|REG_NEWLINE);
    regcomp(&regex_dir, "^a (.*) directory$", REG_EXTENDED|REG_NEWLINE);
    regcomp(&regex_file, "^a (.*) (.*) bytes", REG_EXTENDED|REG_NEWLINE);
    regcomp(&regex_special, "^a (.*) special", REG_EXTENDED|REG_NEWLINE);
    regcomp(&regex_symbolic, "^a (.*) symbolic", REG_EXTENDED|REG_NEWLINE);
    regcomp(&regex_hard, "^a (.*) link to", REG_EXTENDED|REG_NEWLINE);

    while ((fgets(line, sizeof(line), outstream)) != NULL) {
	regmatch_t regmatch[3];

	if (strlen(line) > 0 && line[strlen(line)-1] == '\n') {
	    /* remove trailling \n */
	    line[strlen(line)-1] = '\0';
	}

	if (regexec(&regex_root, line, 1, regmatch, 0) == 0) {
	    if (argument->dle.create_index)
		fprintf(indexstream, "%s\n", "/");
	    continue;
	}

	if (regexec(&regex_dir, line, 3, regmatch, 0) == 0) {
	    if (argument->dle.create_index && regmatch[1].rm_so == 2) {
		line[regmatch[1].rm_eo+1]='\0';
		fprintf(indexstream, "/%s\n", &line[regmatch[1].rm_so]);
	    }
	    continue;
	}

	if (regexec(&regex_file, line, 3, regmatch, 0) == 0 ||
	    regexec(&regex_special, line, 3, regmatch, 0) == 0 ||
	    regexec(&regex_symbolic, line, 3, regmatch, 0) == 0 ||
	    regexec(&regex_hard, line, 3, regmatch, 0) == 0) {
	    if (argument->dle.create_index && regmatch[1].rm_so == 2) {
		line[regmatch[1].rm_eo]='\0';
		fprintf(indexstream, "/%s\n", &line[regmatch[1].rm_so]);
	    }
	    continue;
	}

	for (rp = re_table; rp->regex != NULL; rp++) {
	    if (match(rp->regex, line)) {
		break;
	    }
	}
	if (rp->typ == DMP_SIZE) {
	    dump_size = (off_t)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
	}
	switch (rp->typ) {
	    case DMP_IGNORE:
		continue;
	    case DMP_NORMAL:
		type = "normal";
		startchr = '|';
		break;
	    case DMP_STRANGE:
		type = "strange";
		startchr = '?';
		break;
	    case DMP_SIZE:
		type = "size";
		startchr = '|';
		break;
	    case DMP_ERROR:
		type = "error";
		startchr = '?';
		break;
	    default:
		type = "unknown";
		startchr = '!';
		break;
	}
	dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line);
	fprintf(mesgstream,"%c %s\n", startchr, line);
    }
    fclose(outstream);

    regfree(&regex_root);
    regfree(&regex_dir);
    regfree(&regex_file);
    regfree(&regex_special);
    regfree(&regex_symbolic);
    regfree(&regex_hard);

    dbprintf(_("gnutar: %s: pid %ld\n"), cmd, (long)starpid);

    dbprintf("sendbackup: size %lld\n", (long long)dump_size);
    fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
    dbprintf("sendbackup: end\n");
    fprintf(mesgstream, "sendbackup: end\n");

    fclose(mesgstream);
    if (argument->dle.create_index)
	fclose(indexstream);

    amfree(qdisk);
    amfree(cmd);
}
Example #8
0
int
main(
    int		argc,
    char **	argv)
{
    int foreground;
    int batch;
    int redirect;
    char **datearg = NULL;
    int nb_datearg = 0;
    char *conf_diskfile;
    char *conf_tapelist;
    char *conf_logfile;
    int conf_usetimestamps;
    disklist_t diskq;
    disk_t *dp;
    pid_t pid;
    pid_t driver_pid, reporter_pid;
    amwait_t exitcode;
    int opt;
    GSList *holding_list=NULL, *holding_file;
    int driver_pipe[2];
    char date_string[100];
    char date_string_standard[100];
    time_t today;
    char *errstr;
    struct tm *tm;
    char *tapedev;
    char *tpchanger;
    char *qdisk, *qhname;
    GSList *datestamp_list = NULL;
    config_overrides_t *cfg_ovr;
    char **config_options;
    find_result_t *holding_files;
    disklist_t holding_disklist = { NULL, NULL };
    gboolean exact_match = FALSE;

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

    safe_fd(-1, 0);
    safe_cd();

    set_pname("amflush");

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

    dbopen(DBG_SUBDIR_SERVER);

    add_amanda_log_handler(amanda_log_stderr);
    foreground = 0;
    batch = 0;
    redirect = 1;

    /* process arguments */

    cfg_ovr = new_config_overrides(argc/2);
    while((opt = getopt_long(argc, argv, "bfso:D:", long_options, NULL)) != EOF) {
	switch(opt) {
	case 1  : printf("amflush-%s\n", VERSION);
		  return(0);
		  break;
	case 2  : exact_match = TRUE;
		  break;
	case 'b': batch = 1;
		  break;
	case 'f': foreground = 1;
		  break;
	case 's': redirect = 0;
		  break;
	case 'o': add_config_override_opt(cfg_ovr, optarg);
		  break;
	case 'D': if (datearg == NULL)
		      datearg = g_malloc(21*sizeof(char *));
		  if(nb_datearg == 20) {
		      g_fprintf(stderr,_("maximum of 20 -D arguments.\n"));
		      exit(1);
		  }
		  datearg[nb_datearg++] = g_strdup(optarg);
		  datearg[nb_datearg] = NULL;
		  break;
	}
    }
    argc -= optind, argv += optind;

    if(!foreground && !redirect) {
	g_fprintf(stderr,_("Can't redirect to stdout/stderr if not in forground.\n"));
	exit(1);
    }

    if(argc < 1) {
	error(_("Usage: amflush [-b] [-f] [-s] [-D date]* [--exact-match] [-o configoption]* <confdir> [host [disk]* ]*"));
	/*NOTREACHED*/
    }

    set_config_overrides(cfg_ovr);
    config_init(CONFIG_INIT_EXPLICIT_NAME,
		argv[0]);

    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);

    /* load DLEs from the holding disk, in case there's anything to flush there */
    search_holding_disk(&holding_files, &holding_disklist);
    /* note that the dumps are added to the global disklist, so we need not
     * consult holding_files or holding_disklist after this.  The holding-only
     * dumps will be filtered properly by match_disklist, setting the dp->todo
     * flag appropriately. */

    errstr = match_disklist(&diskq, exact_match, argc-1, argv+1);
    if (errstr) {
	g_printf(_("%s"),errstr);
	amfree(errstr);
    }

    conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST));
    if(read_tapelist(conf_tapelist)) {
	error(_("could not load tapelist \"%s\""), conf_tapelist);
	/*NOTREACHED*/
    }
    amfree(conf_tapelist);

    conf_usetimestamps = getconf_boolean(CNF_USETIMESTAMPS);

    amflush_datestamp = get_datestamp_from_time(0);
    if(conf_usetimestamps == 0) {
	amflush_timestamp = g_strdup(amflush_datestamp);
    }
    else {
	amflush_timestamp = get_timestamp_from_time(0);
    }

    conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
    conf_logfile = g_strjoin(NULL, conf_logdir, "/log", NULL);
    if (access(conf_logfile, F_OK) == 0) {
	run_amcleanup(get_config_name());
    }
    if (access(conf_logfile, F_OK) == 0) {
	char *process_name = get_master_process(conf_logfile);
	error(_("%s exists: %s is already running, or you must run amcleanup"), conf_logfile, process_name);
	/*NOTREACHED*/
    }

    driver_program = g_strjoin(NULL, amlibexecdir, "/", "driver", NULL);
    reporter_program = g_strjoin(NULL, sbindir, "/", "amreport", NULL);
    logroll_program = g_strjoin(NULL, amlibexecdir, "/", "amlogroll", NULL);

    tapedev = getconf_str(CNF_TAPEDEV);
    tpchanger = getconf_str(CNF_TPCHANGER);
    if (tapedev == NULL && tpchanger == NULL) {
	error(_("No tapedev or tpchanger specified"));
    }

    /* if dates were specified (-D), then use match_datestamp
     * against the list of all datestamps to turn that list
     * into a set of existing datestamps (basically, evaluate the
     * expressions into actual datestamps) */
    if(datearg) {
	GSList *all_datestamps;
	GSList *datestamp;
	int i, ok;

	all_datestamps = holding_get_all_datestamps();
	for(datestamp = all_datestamps; datestamp != NULL; datestamp = datestamp->next) {
	    ok = 0;
	    for(i=0; i<nb_datearg && ok==0; i++) {
		ok = match_datestamp(datearg[i], (char *)datestamp->data);
	    }
	    if (ok)
		datestamp_list = g_slist_insert_sorted(datestamp_list,
		    g_strdup((char *)datestamp->data),
		    g_compare_strings);
	}
	slist_free_full(all_datestamps, g_free);
    }
    else {
	/* otherwise, in batch mode, use all datestamps */
	if(batch) {
	    datestamp_list = holding_get_all_datestamps();
	}
	/* or allow the user to pick datestamps */
	else {
	    datestamp_list = pick_datestamp();
	}
    }

    if(!datestamp_list) {
	g_printf(_("Could not find any Amanda directories to flush.\n"));
	exit(1);
    }

    holding_list = holding_get_files_for_flush(datestamp_list);
    if (holding_list == NULL) {
	g_printf(_("Could not find any valid dump image, check directory.\n"));
	exit(1);
    }

    if (access(conf_logfile, F_OK) == 0) {
	char *process_name = get_master_process(conf_logfile);
	error(_("%s exists: someone started %s"), conf_logfile, process_name);
	/*NOTREACHED*/
    }
    log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());

    if(!batch) confirm(datestamp_list);

    for(dp = diskq.head; dp != NULL; dp = dp->next) {
	if(dp->todo) {
	    /* is it holding_list */
	    for (holding_file=holding_list; holding_file != NULL;
					    holding_file = holding_file->next) {
		dumpfile_t file;
		holding_file_get_dumpfile((char *)holding_file->data, &file);
		if (g_str_equal(dp->host->hostname, file.name) &&
		    g_str_equal(dp->name, file.disk)) {
		    char *qname;
		    qname = quote_string(dp->name);
		    log_add(L_DISK, "%s %s", dp->host->hostname, qname);
		    amfree(qname);
		}
	    }
	}
    }

    if(!foreground) { /* write it before redirecting stdout */
	puts(_("Running in background, you can log off now."));
	puts(_("You'll get mail when amflush is finished."));
    }

    if(redirect) redirect_stderr();

    if(!foreground) detach();

    add_amanda_log_handler(amanda_log_stderr);
    add_amanda_log_handler(amanda_log_trace_log);
    today = time(NULL);
    tm = localtime(&today);
    if (tm) {
	strftime(date_string, 100, "%a %b %e %H:%M:%S %Z %Y", tm);
	strftime(date_string_standard, 100, "%Y-%m-%d %H:%M:%S %Z", tm);
    } else {
	error(_("BAD DATE")); /* should never happen */
    }
    g_fprintf(stderr, _("amflush: start at %s\n"), date_string);
    g_fprintf(stderr, _("amflush: datestamp %s\n"), amflush_timestamp);
    g_fprintf(stderr, _("amflush: starttime %s\n"), amflush_timestamp);
    g_fprintf(stderr, _("amflush: starttime-locale-independent %s\n"),
	      date_string_standard);
    log_add(L_START, _("date %s"), amflush_timestamp);

    /* START DRIVER */
    if(pipe(driver_pipe) == -1) {
	error(_("error [opening pipe to driver: %s]"), strerror(errno));
	/*NOTREACHED*/
    }
    if((driver_pid = fork()) == 0) {
	/*
	 * This is the child process.
	 */
	dup2(driver_pipe[0], 0);
	close(driver_pipe[1]);
	config_options = get_config_options(3);
	config_options[0] = "driver";
	config_options[1] = get_config_name();
	config_options[2] = "nodump";
	safe_fd(-1, 0);
	execve(driver_program, config_options, safe_env());
	error(_("cannot exec %s: %s"), driver_program, strerror(errno));
	/*NOTREACHED*/
    } else if(driver_pid == -1) {
	error(_("cannot fork for %s: %s"), driver_program, strerror(errno));
	/*NOTREACHED*/
    }
    driver_stream = fdopen(driver_pipe[1], "w");
    if (!driver_stream) {
	error(_("Can't fdopen: %s"), strerror(errno));
	/*NOTREACHED*/
    }

    g_fprintf(driver_stream, "DATE %s\n", amflush_timestamp);
    for(holding_file=holding_list; holding_file != NULL;
				   holding_file = holding_file->next) {
	dumpfile_t file;
	holding_file_get_dumpfile((char *)holding_file->data, &file);

	if (holding_file_size((char *)holding_file->data, 1) <= 0) {
	    g_debug("%s is empty - ignoring", (char *)holding_file->data);
	    log_add(L_INFO, "%s: removing file with no data.",
		    (char *)holding_file->data);
	    holding_file_unlink((char *)holding_file->data);
	    dumpfile_free_data(&file);
	    continue;
	}

	/* search_holding_disk should have already ensured that every
	 * holding dumpfile has an entry in the dynamic disklist */
	dp = lookup_disk(file.name, file.disk);
	assert(dp != NULL);

	/* but match_disklist may have indicated we should not flush it */
	if (dp->todo == 0) continue;

	qdisk = quote_string(file.disk);
	qhname = quote_string((char *)holding_file->data);
	g_fprintf(stderr,
		"FLUSH %s %s %s %d %s\n",
		file.name,
		qdisk,
		file.datestamp,
		file.dumplevel,
		qhname);

	g_debug("flushing '%s'", (char *)holding_file->data);
	g_fprintf(driver_stream,
		"FLUSH %s %s %s %d %s\n",
		file.name,
		qdisk,
		file.datestamp,
		file.dumplevel,
		qhname);
	amfree(qdisk);
	amfree(qhname);
	dumpfile_free_data(&file);
    }
    g_fprintf(stderr, "ENDFLUSH\n"); fflush(stderr);
    g_fprintf(driver_stream, "ENDFLUSH\n"); fflush(driver_stream);
    fclose(driver_stream);

    /* WAIT DRIVER */
    while(1) {
	if((pid = wait(&exitcode)) == -1) {
	    if(errno == EINTR) {
		continue;
	    } else {
		error(_("wait for %s: %s"), driver_program, strerror(errno));
		/*NOTREACHED*/
	    }
	} else if (pid == driver_pid) {
	    break;
	}
    }

    slist_free_full(datestamp_list, g_free);
    datestamp_list = NULL;
    slist_free_full(holding_list, g_free);
    holding_list = NULL;

    if(redirect) { /* rename errfile */
	char *errfile, *errfilex, *nerrfilex, number[100];
	int tapecycle;
	int maxdays, days;
		
	struct stat stat_buf;

	errfile = g_strjoin(NULL, conf_logdir, "/amflush", NULL);
	errfilex = NULL;
	nerrfilex = NULL;
	tapecycle = getconf_int(CNF_TAPECYCLE);
	maxdays = tapecycle + 2;
	days = 1;
	/* First, find out the last existing errfile,           */
	/* to avoid ``infinite'' loops if tapecycle is infinite */

	g_snprintf(number,100,"%d",days);
	g_free(errfilex);
	errfilex = g_strconcat(errfile, ".", number, NULL);
	while ( days < maxdays && stat(errfilex,&stat_buf)==0) {
	    days++;
	    g_snprintf(number,100,"%d",days);
	    g_free(errfilex);
	    errfilex = g_strconcat(errfile, ".", number, NULL);
	}
	g_snprintf(number,100,"%d",days);
	g_free(errfilex);
	errfilex = g_strconcat(errfile, ".", number, NULL);
	nerrfilex = NULL;
	while (days > 1) {
	    amfree(nerrfilex);
	    nerrfilex = errfilex;
	    days--;
	    g_snprintf(number,100,"%d",days);
	    errfilex = g_strjoin(NULL, errfile, ".", number, NULL);
	    if (rename(errfilex, nerrfilex) != 0) {
		error(_("cannot rename \"%s\" to \"%s\": %s"),
		      errfilex, nerrfilex, strerror(errno));
	        /*NOTREACHED*/
	    }
	}
	g_free(errfilex);
	errfilex = g_strconcat(errfile, ".1", NULL);
	if (rename(errfile,errfilex) != 0) {
	    error(_("cannot rename \"%s\" to \"%s\": %s"),
		  errfilex, nerrfilex, strerror(errno));
	    /*NOTREACHED*/
	}
	amfree(errfile);
	amfree(errfilex);
	amfree(nerrfilex);
    }

    /*
     * Have amreport generate report and send mail.  Note that we do
     * not bother checking the exit status.  If it does not work, it
     * can be rerun.
     */

    if((reporter_pid = fork()) == 0) {
	/*
	 * This is the child process.
	 */
	config_options = get_config_options(3);
	config_options[0] = "amreport";
	config_options[1] = get_config_name();
        config_options[2] = "--from-amdump";
	safe_fd(-1, 0);
	execve(reporter_program, config_options, safe_env());
	error(_("cannot exec %s: %s"), reporter_program, strerror(errno));
	/*NOTREACHED*/
    } else if(reporter_pid == -1) {
	error(_("cannot fork for %s: %s"), reporter_program, strerror(errno));
	/*NOTREACHED*/
    }
    while(1) {
	if((pid = wait(&exitcode)) == -1) {
	    if(errno == EINTR) {
		continue;
	    } else {
		error(_("wait for %s: %s"), reporter_program, strerror(errno));
		/*NOTREACHED*/
	    }
	} else if (pid == reporter_pid) {
	    break;
	}
    }

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

    /*
     * Call amlogroll to rename the log file to its datestamped version.
     * Since we exec at this point, our exit code will be that of amlogroll.
     */
    config_options = get_config_options(2);
    config_options[0] = "amlogroll";
    config_options[1] = get_config_name();
    safe_fd(-1, 0);
    execve(logroll_program, config_options, safe_env());
    error(_("cannot exec %s: %s"), logroll_program, strerror(errno));
    /*NOTREACHED*/
    return 0;				/* keep the compiler happy */
}
Example #9
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 */
}
Example #10
0
static int
changer_command(
     char *cmd,
     char *arg)
{
    int exitcode = 0;
    char *cmdstr = NULL;

    amfree(changer_resultstr);

    if (!start_chg_glue()) {
	exitcode = 2;
	goto failed;
    }

    cmdstr = vstralloc(cmd,
		       arg ? " " : "",
		       arg ? arg : "",
		       "\n",
		       NULL);

    g_debug("changer: >> %s %s", cmd, arg? arg : "");

    /* write the command to chg_glue */
    if (full_write(tpchanger_stdin, cmdstr, strlen(cmdstr)) != strlen(cmdstr)) {
        changer_resultstr = g_strdup("<error> chg-glue exited unexpectedly");
	exitcode = 2;
	goto failed;
    }

    /* read the first line of the response */
    changer_resultstr = areads(tpchanger_stdout);
    if (!changer_resultstr || !*changer_resultstr) {
        changer_resultstr = g_strdup("<error> unexpected EOF");
        exitcode = 2;
        goto failed;
    }
    g_debug("changer: << %s", changer_resultstr);

    if (strncmp_const(changer_resultstr, "EXITSTATUS ") != 0) {
	report_bad_resultstr(cmd);
	exitcode = 2;
	goto failed;
    }
    exitcode = atoi(changer_resultstr + strlen("EXITSTATUS "));

    /* and the second */
    changer_resultstr = areads(tpchanger_stdout);
    if (!changer_resultstr) {
        changer_resultstr = g_strdup("<error> unexpected EOF");
        exitcode = 2;
        goto failed;
    }
    g_debug("changer: << %s", changer_resultstr);

failed:
    if (exitcode != 0) {
	g_debug("changer: ERROR %s", changer_resultstr);
    }

    amfree(cmdstr);

    return exitcode;
}
Example #11
0
/* Allow the user to select a set of datestamps from those in
 * holding disks.  The result can be passed to
 * holding_get_files_for_flush.  If less than two dates are
 * available, then no user interaction takes place.
 *
 * @returns: a new GSList listing the selected datestamps
 */
static GSList *
pick_datestamp(void)
{
    GSList *datestamp_list;
    GSList *r_datestamp_list = NULL;
    GSList *ds;
    char **datestamps = NULL;
    int i;
    char *answer = NULL;
    char *a = NULL;
    int ch = 0;
    char max_char = '\0', chupper = '\0';

    datestamp_list = holding_get_all_datestamps();

    if(g_slist_length(datestamp_list) < 2) {
	return datestamp_list;
    } else {
	datestamps = g_malloc(g_slist_length(datestamp_list) * sizeof(char *));
	for(ds = datestamp_list, i=0; ds != NULL; ds = ds->next,i++) {
	    datestamps[i] = (char *)ds->data; /* borrowing reference */
	}

	while(1) {
	    puts(_("\nMultiple Amanda runs in holding disks; please pick one by letter:"));
	    for(ds = datestamp_list, max_char = 'A';
		ds != NULL && max_char <= 'Z';
		ds = ds->next, max_char++) {
		g_printf("  %c. %s\n", max_char, (char *)ds->data);
	    }
	    max_char--;
	    g_printf(_("Select datestamps to flush [A..%c or <enter> for all]: "), max_char);
	    fflush(stdout); fflush(stderr);
	    amfree(answer);
	    if ((answer = agets(stdin)) == NULL) {
		clearerr(stdin);
		continue;
	    }

	    if (*answer == '\0' || strncasecmp(answer, "ALL", 3) == 0) {
		break;
	    }

	    a = answer;
	    while ((ch = *a++) != '\0') {
		if (!g_ascii_isspace(ch))
		    break;
	    }

	    /* rewrite the selected list into r_datestamp_list, then copy it over
	     * to datestamp_list */
	    do {
		if (g_ascii_isspace(ch) || ch == ',') {
		    continue;
		}
		chupper = (char)toupper(ch);
		if (chupper < 'A' || chupper > max_char) {
		    slist_free_full(r_datestamp_list, g_free);
		    r_datestamp_list = NULL;
		    break;
		}
		r_datestamp_list = g_slist_append(r_datestamp_list,
					   g_strdup(datestamps[chupper - 'A']));
	    } while ((ch = *a++) != '\0');
	    if (r_datestamp_list && ch == '\0') {
		slist_free_full(datestamp_list, g_free);
		datestamp_list = r_datestamp_list;
		break;
	    }
	}
    }
    amfree(datestamps); /* references in this array are borrowed */
    amfree(answer);

    return datestamp_list;
}
Example #12
0
static int
start_chg_glue(void)
{
    int stdin_pipe[2] = { -1, -1 };
    int stdout_pipe[2] = { -1, -1 };
    char *chg_glue = NULL;
    char **config_options = NULL;
    char *cmdline = NULL;

    /* is it already running? */
    if (tpchanger_pid != -1)
	return 1;

    if (pipe(stdin_pipe) == -1 || pipe(stdout_pipe) == -1) {
	changer_resultstr = vstrallocf(
			_("<error> could not make pipe: %s"), strerror(errno));
	goto error;
    }

    config_options = get_config_options(2);
    config_options[0] = g_strdup("chg-glue");
    config_options[1] = g_strdup(get_config_name());
    chg_glue = g_strdup_printf("%s/chg-glue", amlibexecdir);

    cmdline = g_strjoinv(" ", config_options);
    g_debug("invoking %s: %s", chg_glue, cmdline);
    amfree(cmdline);

    switch(tpchanger_pid = fork()) {
    case -1:
	changer_resultstr = vstrallocf(
			_("<error> could not fork: %s"), strerror(errno));
	goto error;

    case 0:
	debug_dup_stderr_to_debug();
	if(dup2(stdin_pipe[0], 0) == -1) {
	    changer_resultstr = vstrallocf(
			_("<error> could not dup2: %s\n"), strerror(errno));
	    goto child_err;
	}

	if(dup2(stdout_pipe[1], 1) == -1) {
	    changer_resultstr = vstrallocf(
			_("<error> could not dup2: %s\n"), strerror(errno));
	    goto child_err;
	}

	safe_fd(-1, 0);
	execv(chg_glue, config_options);
	changer_resultstr = vstrallocf(
			_("<error> could not exec \"%s\": %s\n"), chg_glue, strerror(errno));

child_err:
	(void)full_write(stdout_pipe[1], changer_resultstr, strlen(changer_resultstr));
	exit(1);

    default:
	aclose(stdin_pipe[0]);
	aclose(stdout_pipe[1]);

	g_strfreev(config_options);
	amfree(chg_glue);
	amfree(cmdline);

	tpchanger_stdout = stdout_pipe[0];
	tpchanger_stdin = stdin_pipe[1];

	return 1;
    }

error:
    amfree(chg_glue);
    amfree(cmdline);
    aclose(stdin_pipe[0]);
    aclose(stdin_pipe[1]);
    aclose(stdout_pipe[0]);
    aclose(stdout_pipe[1]);

    return 0;
}
Example #13
0
int
start_amandates(
    char *amandates_file,
    int	  open_readwrite)
{
    int rc, level = 0;
    long ldate = 0L;
    char *line;
    char *name;
    char *s;
    int ch;
    char *qname;

    if (amandates_file == NULL) {
	errno = 0;
	return 0;
    }

    /* clean up from previous invocation */

    if(amdf != NULL)
	finish_amandates();
    if(amandates_list != NULL)
	free_amandates();
    amfree(g_amandates_file);

    /* initialize state */

    updated = 0;
    readonly = !open_readwrite;
    amdf = NULL;
    amandates_list = NULL;
    g_amandates_file = g_strdup(amandates_file);
    /* open the file */

//    if (access(amandates_file,F_OK))
//	/* not yet existing */
//	if ( (rc = open(amandates_file,(O_CREAT|O_RDWR),0644)) != -1 )
//	    /* open/create successfull */
//	    aclose(rc);

    if (open_readwrite)
	amdf = fopen(amandates_file, "r+");
    else
	amdf = fopen(amandates_file, "r");

    /* create it if we need to */
    if (amdf == NULL) {
	if (errno == ENOENT) {
	    amdf = fopen(amandates_file, "w+");
	}
    }
    if (amdf == NULL) {
	// errno is set
	return 0;
    }

    if(open_readwrite)
	rc = amflock(fileno(amdf), amandates_file);
    else
	rc = amroflock(fileno(amdf), amandates_file);

    if(rc == -1) {
	error(_("could not lock %s: %s"), amandates_file, strerror(errno));
	/*NOTREACHED*/
    }

    for(; (line = agets(amdf)) != NULL; free(line)) {
	if (line[0] == '\0')
	    continue;
	s = line;
	ch = *s++;

	skip_whitespace(s, ch);
	if(ch == '\0') {
	    continue;				/* no name field */
	}
	qname = s - 1;
	skip_quoted_string(s, ch);
	s[-1] = '\0';				/* terminate the name */
	name = unquote_string(qname);

	skip_whitespace(s, ch);
	if(ch == '\0' || sscanf(s - 1, "%d %ld", &level, &ldate) != 2) {
	    amfree(name);
	    continue;				/* no more fields */
	}

	if(level < 0 || level >= DUMP_LEVELS) {
	    amfree(name);
	    continue;
	}

	enter_record(name, level, (time_t) ldate);
	amfree(name);
    }

    if(ferror(amdf)) {
	error(_("reading %s: %s"), amandates_file, strerror(errno));
	/*NOTREACHED*/
    }

    updated = 0;	/* reset updated flag */
    return 1;
}
Example #14
0
static void
amindexd_response(
    void *datap,
    pkt_t *pkt,
    security_handle_t *sech)
{
    int ports[NSTREAMS], *response_error = datap, i;
    char *p;
    char *tok;
    char *extra = NULL;

    assert(response_error != NULL);
    assert(sech != NULL);

    if (pkt == NULL) {
	errstr = newvstrallocf(errstr, _("[request failed: %s]"),
			     security_geterror(sech));
	*response_error = 1;
	return;
    }

    if (pkt->type == P_NAK) {
#if defined(PACKET_DEBUG)
	dbprintf(_("got nak response:\n----\n%s\n----\n\n"), pkt->body);
#endif

	tok = strtok(pkt->body, " ");
	if (tok == NULL || strcmp(tok, "ERROR") != 0)
	    goto bad_nak;

	tok = strtok(NULL, "\n");
	if (tok != NULL) {
	    errstr = newvstrallocf(errstr, "NAK: %s", tok);
	    *response_error = 1;
	} else {
bad_nak:
	    errstr = newvstrallocf(errstr, _("request NAK"));
	    *response_error = 2;
	}
	return;
    }

    if (pkt->type != P_REP) {
	errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"),
			      pkt_type2str(pkt->type), pkt->body);
	*response_error = 1;
	return;
    }

#if defined(PACKET_DEBUG)
    g_fprintf(stderr, _("got response:\n----\n%s\n----\n\n"), pkt->body);
#endif

    for(i = 0; i < NSTREAMS; i++) {
        ports[i] = -1;
        streams[i].fd = NULL;
    }

    p = pkt->body;
    while((tok = strtok(p, " \n")) != NULL) {
	p = NULL;

	/*
	 * Error response packets have "ERROR" followed by the error message
	 * followed by a newline.
	 */
	if (strcmp(tok, "ERROR") == 0) {
	    tok = strtok(NULL, "\n");
	    if (tok == NULL) {
	        errstr = newvstrallocf(errstr, _("[bogus error packet]"));
	    } else {
		errstr = newvstrallocf(errstr, "%s", tok);
	    }
	    *response_error = 2;
	    return;
	}


        /*
         * Regular packets have CONNECT followed by three streams
         */
        if (strcmp(tok, "CONNECT") == 0) {

	    /*
	     * Parse the three stream specifiers out of the packet.
	     */
	    for (i = 0; i < NSTREAMS; i++) {
		tok = strtok(NULL, " ");
		if (tok == NULL || strcmp(tok, streams[i].name) != 0) {
		    extra = vstrallocf(
			   _("CONNECT token is \"%s\": expected \"%s\""),
			   tok ? tok : _("(null)"), streams[i].name);
		    goto parse_error;
		}
		tok = strtok(NULL, " \n");
		if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
		    extra = vstrallocf(
			   _("CONNECT %s token is \"%s\" expected a port number"),
			   streams[i].name, tok ? tok : _("(null)"));
		    goto parse_error;
		}
	    }
	    continue;
	}

	/*
	 * OPTIONS [options string] '\n'
	 */
	if (strcmp(tok, "OPTIONS") == 0) {
	    tok = strtok(NULL, "\n");
	    if (tok == NULL) {
		extra = vstrallocf(_("OPTIONS token is missing"));
		goto parse_error;
	    }
#if 0
	    tok_end = tok + strlen(tok);
	    while((p = strchr(tok, ';')) != NULL) {
		*p++ = '\0';
		if(strncmp_const(tok, "features=") == 0) {
		    tok += SIZEOF("features=") - 1;
		    am_release_feature_set(their_features);
		    if((their_features = am_string_to_feature(tok)) == NULL) {
			errstr = newvstrallocf(errstr,
				      _("OPTIONS: bad features value: %s"),
				      tok);
			goto parse_error;
		    }
		}
		tok = p;
	    }
#endif
	    continue;
	}
#if 0
	extra = vstrallocf(_("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""), tok ? tok : _("(null)"));
	goto parse_error;
#endif
    }

    /*
     * Connect the streams to their remote ports
     */
    for (i = 0; i < NSTREAMS; i++) {
/*@i@*/	if (ports[i] == -1)
	    continue;
	streams[i].fd = security_stream_client(sech, ports[i]);
	if (streams[i].fd == NULL) {
	    errstr = newvstrallocf(errstr,
			_("[could not connect %s stream: %s]"),
			streams[i].name, security_geterror(sech));
	    goto connect_error;
	}
    }
    /*
     * Authenticate the streams
     */
    for (i = 0; i < NSTREAMS; i++) {
	if (streams[i].fd == NULL)
	    continue;
	if (security_stream_auth(streams[i].fd) < 0) {
	    errstr = newvstrallocf(errstr,
		_("[could not authenticate %s stream: %s]"),
		streams[i].name, security_stream_geterror(streams[i].fd));
	    goto connect_error;
	}
    }

    /*
     * The MESGFD and DATAFD streams are mandatory.  If we didn't get
     * them, complain.
     */
    if (streams[MESGFD].fd == NULL) {
        errstr = newvstrallocf(errstr, _("[couldn't open MESG streams]"));
        goto connect_error;
    }

    /* everything worked */
    *response_error = 0;
    amindexd_alive = 1;
    return;

parse_error:
    errstr = newvstrallocf(errstr,
			  _("[parse of reply message failed: %s]"),
			  extra ? extra : _("(no additional information)"));
    amfree(extra);
    *response_error = 2;
    return;

connect_error:
    stop_amindexd();
    *response_error = 1;
}
Example #15
0
/* WARNING: Function accesses globals find_diskqp, curlog, curlog, curstr,
 * dynamic_disklist */
gboolean
search_logfile(
    find_result_t **output_find,
    const char *label,
    const char *passed_datestamp,
    const char *logfile,
    disklist_t * dynamic_disklist)
{
    FILE *logf;
    char *host = NULL;
    char *disk = NULL, *qdisk, *disk_undo;
    char *date = NULL, *date_undo;
    int  partnum;
    int  totalparts;
    int  maxparts = -1;
    char *number;
    int fileno;
    char *current_label;
    char *current_storage;
    char *rest, *rest_undo;
    char *ck_label=NULL;
    char *ck_storage=NULL;
    int level = 0;
    off_t filenum;
    char *ck_datestamp=NULL;
    char *datestamp;
    char *s;
    int ch;
    disk_t *dp;
    GHashTable* valid_label;
    GHashTable* part_by_dle;
    find_result_t *part_find;
    find_result_t *a_part_find;
    gboolean right_label = FALSE;
    gboolean found_something = FALSE;
    double sec;
    off_t kb;
    off_t bytes;
    off_t orig_kb;
    int   taper_part = 0;
    crc_t crc1, crc2, crc3;
    crc_t native_crc;
    crc_t client_crc;
    crc_t server_crc;

    g_return_val_if_fail(output_find != NULL, 0);
    g_return_val_if_fail(logfile != NULL, 0);

    current_label = g_strdup("");
    current_storage = g_strdup("");
    if (string_chunk == NULL) {
	string_chunk = g_string_chunk_new(32768);
    }
    valid_label = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
    part_by_dle = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
    datestamp = g_strdup(passed_datestamp);

    if((logf = fopen(logfile, "r")) == NULL) {
	error(_("could not open logfile %s: %s"), logfile, strerror(errno));
	/*NOTREACHED*/
    }

    filenum = (off_t)0;
    while(get_logline(logf)) {
	if (curlog == L_START && curprog == P_TAPER) {
	    amfree(ck_label);
	    amfree(ck_storage);
	    ck_datestamp = NULL;
	    if(parse_taper_datestamp_log(curstr, &ck_datestamp,
                                         &ck_label, &ck_storage) == 0) {
		g_printf(_("strange log line in %s \"start taper %s\"\n"),
                         logfile, curstr);
                continue;
	    }
            if (datestamp != NULL) {
                if (!g_str_equal(datestamp, ck_datestamp)) {
                    g_printf(_("Log file %s stamped %s, expecting %s!\n"),
                             logfile, ck_datestamp, datestamp);
		    amfree(ck_label);
                    break;
                }
            }

            right_label = volume_matches(label, ck_label, ck_datestamp);
	    if (right_label && ck_label) {
		g_hash_table_insert(valid_label, g_strdup(ck_label),
				    GINT_TO_POINTER(1));
	    }
	    if (label && datestamp && right_label) {
		found_something = TRUE;
	    }
            amfree(current_label);
            current_label = ck_label;
	    ck_label = NULL;
            amfree(current_storage);
            current_storage = ck_storage;
	    ck_storage = NULL;
            if (datestamp == NULL) {
                datestamp = g_strdup(ck_datestamp);
            }
	    filenum = (off_t)0;
	}
	if (!datestamp)
	    continue;
	if (right_label &&
	    (curlog == L_SUCCESS ||
	     curlog == L_CHUNK || curlog == L_PART || curlog == L_PARTPARTIAL) &&
	    curprog == P_TAPER) {
	    filenum++;
	} else if (right_label && curlog == L_PARTIAL && curprog == P_TAPER &&
		   taper_part == 0) {
	    filenum++;
	}
	partnum = -1;
	totalparts = -1;
	if (curlog == L_SUCCESS || curlog == L_CHUNKSUCCESS ||
	    curlog == L_DONE    || curlog == L_FAIL ||
	    curlog == L_CHUNK   || curlog == L_PART || curlog == L_PARTIAL ||
	    curlog == L_PARTPARTIAL ) {
	    s = curstr;
	    ch = *s++;

	    skip_whitespace(s, ch);
	    if(ch == '\0') {
		g_printf(_("strange log line in %s \"%s\"\n"),
		    logfile, curstr);
		continue;
	    }

	    if (curlog == L_PART || curlog == L_PARTPARTIAL ||
		curlog == L_DONE || curlog == L_FAIL || curlog == L_PARTIAL) {
		char *part_storage;
		char *qpart_storage = s - 1;
		char *part_label;
		char *qnext_string;
		char *next_string;
		taper_part++;
		skip_quoted_string(s, ch);
		s[-1] = '\0';

		part_storage = unquote_string(qpart_storage);
		if (strncmp(part_storage, "ST:", 3) == 0) {
		    char *ps = part_storage;
		    part_storage = g_strdup(ps+3);
		    g_free(ps);
		    skip_whitespace(s, ch);
		    qnext_string = s - 1;
		    skip_quoted_string(s, ch);
		    s[-1] = '\0';
		    next_string = unquote_string(qnext_string);
		} else {
		    next_string = part_storage;
		    part_storage = g_strdup(get_config_name());
		}

		if (curlog == L_PART || curlog == L_PARTPARTIAL) {
		    part_label = next_string;
		    if (!g_hash_table_lookup(valid_label, part_label)) {
			amfree(part_label);
			amfree(part_storage);
			continue;
		    }
		    amfree(current_label);
		    current_label = part_label;
		    amfree(current_storage);
		    current_storage = part_storage;

		    skip_whitespace(s, ch);
		    if (ch == '\0') {
			g_printf("strange log line in %s \"%s\"\n",
			   logfile, curstr);
			continue;
		    }

		    number = s - 1;
		    skip_non_whitespace(s, ch);
		    s[-1] = '\0';
		    fileno = atoi(number);
		    filenum = fileno;
		    if (filenum == 0)
			continue;

		    skip_whitespace(s, ch);
		    if(ch == '\0') {
			g_printf("strange log line in %s \"%s\"\n",
			   logfile, curstr);
			continue;
		    }
		    amfree(host);
		    host = s - 1;
		    skip_non_whitespace(s, ch);
		    s[-1] = '\0';
		    host = g_strdup(host);
		} else {
		    amfree(part_storage);
		    amfree(host);
		    host = next_string;
		}
	    } else {
		taper_part = 0;
		    amfree(host);
		host = s - 1;
		skip_non_whitespace(s, ch);
		s[-1] = '\0';
		host = g_strdup(host);
	    }

	    skip_whitespace(s, ch);
	    if(ch == '\0') {
		g_printf(_("strange log line in %s \"%s\"\n"),
		    logfile, curstr);
		continue;
	    }
	    qdisk = s - 1;
	    skip_quoted_string(s, ch);
	    disk_undo = s - 1;
	    *disk_undo = '\0';
	    amfree(disk);
	    disk = unquote_string(qdisk);

	    skip_whitespace(s, ch);
	    if(ch == '\0') {
		g_printf(_("strange log line in %s \"%s\"\n"),
                         logfile, curstr);
		amfree(disk);
		continue;
	    }
	    amfree(date);
	    date = s - 1;
	    skip_non_whitespace(s, ch);
	    date_undo = s - 1;
	    *date_undo = '\0';
	    date = g_strdup(date);

	    if(strlen(date) < 3) { /* old log didn't have datestamp */
		level = atoi(date);
		date = g_strdup(datestamp);
		partnum = 1;
		totalparts = 1;
	    } else {
		if (curprog == P_TAPER &&
			(curlog == L_CHUNK || curlog == L_PART ||
			 curlog == L_PARTPARTIAL || curlog == L_PARTIAL ||
			 curlog == L_DONE)) {
		    char *s1, ch1;
		    skip_whitespace(s, ch);
		    number = s - 1;
		    skip_non_whitespace(s, ch);
		    s1 = &s[-1];
		    ch1 = *s1;
		    skip_whitespace(s, ch);
		    if (*(s-1) != '[') {
			*s1 = ch1;
			sscanf(number, "%d/%d", &partnum, &totalparts);
			if (partnum > maxparts)
			    maxparts = partnum;
			if (totalparts > maxparts)
			    maxparts = totalparts;
		    } else { /* nparts is not in all PARTIAL lines */
			partnum = 1;
			totalparts = 1;
			s = number + 1;
		    }
		} else {
		    skip_whitespace(s, ch);
		}
		if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
		    g_printf(_("Fstrange log line in %s \"%s\"\n"),
		    logfile, s-1);
		    amfree(disk);
		    continue;
		}
		skip_integer(s, ch);
	    }

	    skip_whitespace(s, ch);
	    if(ch == '\0') {
		g_printf(_("strange log line in %s \"%s\"\n"),
		    logfile, curstr);
		amfree(disk);
		continue;
	    }
	    rest = s - 1;
	    skip_non_whitespace(s, ch);
	    rest_undo = s - 1;
	    *rest_undo = '\0';
	    crc1.crc = 0;
	    crc1.size = 0;
	    crc2.crc = 0;
	    crc2.size = 0;
	    crc3.crc = 0;
	    crc3.size = 0;
	    if (curlog == L_DONE) {
		if (!g_str_equal(rest, "[sec")) {
		    // CRC
		    parse_crc(rest, &crc1);
		    skip_whitespace(s, ch);
		    rest = s - 1;
		    skip_non_whitespace(s, ch);
		    rest_undo = s - 1;
		    *rest_undo = '\0';
		}
		if (!g_str_equal(rest, "[sec")) {
		    // CRC
		    parse_crc(rest, &crc2);
		    skip_whitespace(s, ch);
		    rest = s - 1;
		    skip_non_whitespace(s, ch);
		    rest_undo = s - 1;
		    *rest_undo = '\0';
		}
		if (!g_str_equal(rest, "[sec")) {
		    // CRC
		    parse_crc(rest, &crc3);
		    skip_whitespace(s, ch);
		    rest = s - 1;
		    skip_non_whitespace(s, ch);
		    rest_undo = s - 1;
		    *rest_undo = '\0';
		}
	    }
	    native_crc.crc = 0;
	    native_crc.size = 0;
	    client_crc.crc = 0;
	    client_crc.size = 0;
	    server_crc.crc = 0;
	    server_crc.size = 0;
	    if (curprog == P_DUMPER) {
		native_crc = crc1;
		client_crc = crc2;
	    } else if (curprog == P_CHUNKER) {
		server_crc = crc1;
	    } else if (curprog == P_TAPER) {
		native_crc = crc1;
		client_crc = crc2;
		server_crc = crc3;
	    }
	    if (g_str_equal(rest, "[sec")) {
		skip_whitespace(s, ch);
		if(ch == '\0') {
		    g_printf(_("strange log line in %s \"%s\"\n"),
			     logfile, curstr);
		    amfree(disk);
		    continue;
		}
		sec = atof(s - 1);
		skip_non_whitespace(s, ch);
		skip_whitespace(s, ch);
		rest = s - 1;
		skip_non_whitespace(s, ch);
		rest_undo = s - 1;
		*rest_undo = '\0';
		if (!g_str_equal(rest, "kb") &&
		    !g_str_equal(rest, "bytes")) {
		    g_printf(_("Bstrange log line in %s \"%s\"\n"),
			     logfile, curstr);
		    amfree(disk);
		    continue;
		}

		skip_whitespace(s, ch);
		if (ch == '\0') {
		     g_printf(_("strange log line in %s \"%s\"\n"),
			      logfile, curstr);
		     amfree(disk);
		     continue;
		}
		if (g_str_equal(rest, "kb")) {
		    kb = atof(s - 1);
		    bytes = 0;
		} else {
		    bytes = atof(s - 1);
		    kb = bytes / 1024;
		}
		skip_non_whitespace(s, ch);
		skip_whitespace(s, ch);
		rest = s - 1;
		skip_non_whitespace(s, ch);
		rest_undo = s - 1;
		*rest_undo = '\0';
		if (!g_str_equal(rest, "kps")) {
		    g_printf(_("Cstrange log line in %s \"%s\"\n"),
			     logfile, curstr);
		    amfree(disk);
		    continue;
		}

		skip_whitespace(s, ch);
		if (ch == '\0') {
		    g_printf(_("strange log line in %s \"%s\"\n"),
			     logfile, curstr);
		    amfree(disk);
		    continue;
		}
		/* kps = atof(s - 1); */
		skip_non_whitespace(s, ch);
		skip_whitespace(s, ch);
		rest = s - 1;
		skip_non_whitespace(s, ch);
		rest_undo = s - 1;
		*rest_undo = '\0';
		if (!g_str_equal(rest, "orig-kb")) {
		    orig_kb = 0;
		} else {

		    skip_whitespace(s, ch);
		    if(ch == '\0') {
			g_printf(_("strange log line in %s \"%s\"\n"),
				 logfile, curstr);
			amfree(disk);
			continue;
		    }
		    orig_kb = atof(s - 1);
		}
	    } else {
		sec = 0;
		kb = 0;
		bytes = 0;
		orig_kb = 0;
		*rest_undo = ' ';
	    }

	    if (g_str_has_prefix(rest, "error")) rest += 6;
	    if (g_str_has_prefix(rest, "config")) rest += 7;

	    dp = lookup_disk(host,disk);
	    if ( dp == NULL ) {
		if (dynamic_disklist == NULL) {
		    amfree(disk);
		    continue;
		}
		add_disk(dynamic_disklist, host, disk);
	    }
            if (find_match(host, disk)) {
		if(curprog == P_TAPER) {
		    char *key = g_strdup_printf(
					"HOST:%s DISK:%s: DATE:%s LEVEL:%d",
					host, disk, date, level);
		    find_result_t *new_output_find = g_new0(find_result_t, 1);
		    part_find = g_hash_table_lookup(part_by_dle, key);
		    maxparts = partnum;
		    if (maxparts < totalparts)
			maxparts = totalparts;
		    for (a_part_find = part_find;
			 a_part_find;
			 a_part_find = a_part_find->next) {
			if (maxparts < a_part_find->partnum)
			    maxparts = a_part_find->partnum;
			if (maxparts < a_part_find->totalparts)
			    maxparts = a_part_find->totalparts;
		    }
		    new_output_find->timestamp = g_string_chunk_insert_const(string_chunk, date);
		    new_output_find->write_timestamp = g_string_chunk_insert_const(string_chunk, datestamp);
		    new_output_find->hostname=g_string_chunk_insert_const(string_chunk, host);
		    new_output_find->diskname=g_string_chunk_insert_const(string_chunk, disk);
		    new_output_find->level=level;
		    new_output_find->partnum = partnum;
		    new_output_find->totalparts = totalparts;
		    new_output_find->label=g_string_chunk_insert_const(string_chunk, current_label);
		    if (current_storage) {
			new_output_find->storage=g_string_chunk_insert_const(string_chunk, current_storage);
		    }
		    new_output_find->status=NULL;
		    new_output_find->dump_status=NULL;
		    new_output_find->message="";
		    new_output_find->filenum=filenum;
		    new_output_find->sec=sec;
		    new_output_find->kb=kb;
		    new_output_find->bytes=bytes;
		    new_output_find->orig_kb=orig_kb;
		    new_output_find->next=NULL;
		    new_output_find->native_crc = native_crc;
		    new_output_find->client_crc = client_crc;
		    new_output_find->server_crc = server_crc;
		    if (curlog == L_SUCCESS) {
			new_output_find->status = "OK";
			new_output_find->dump_status = "OK";
			new_output_find->next = *output_find;
			new_output_find->partnum = 1; /* L_SUCCESS is pre-splitting */
			*output_find = new_output_find;
                        found_something = TRUE;
		    } else if (curlog == L_CHUNKSUCCESS || curlog == L_DONE ||
			       curlog == L_PARTIAL      || curlog == L_FAIL) {
			/* result line */
			if (curlog == L_PARTIAL || curlog == L_FAIL) {
			    /* set dump_status of each part */
			    for (a_part_find = part_find;
				 a_part_find;
				 a_part_find = a_part_find->next) {
				if (curlog == L_PARTIAL)
				    a_part_find->dump_status = "PARTIAL";
				else {
				    a_part_find->dump_status = "FAIL";
				    a_part_find->message = g_string_chunk_insert_const(string_chunk, rest);
				}
			    }
			} else {
			    if (maxparts > -1) { /* format with part */
				/* must check if all part are there */
				int num_part = maxparts;
				for (a_part_find = part_find;
				     a_part_find;
				     a_part_find = a_part_find->next) {
				    if (a_part_find->partnum == num_part &&
					g_str_equal(a_part_find->status, "OK"))
					num_part--;
			        }
				/* set dump_status of each part */
				for (a_part_find = part_find;
				     a_part_find;
				     a_part_find = a_part_find->next) {
				    if (num_part == 0) {
					a_part_find->dump_status = "OK";
				    } else {
					a_part_find->dump_status = "FAIL";
					a_part_find->message =
						g_string_chunk_insert_const(string_chunk, "Missing part");
				    }
				}
			    }
			}
			if (curlog == L_DONE) {
			    for (a_part_find = part_find;
				 a_part_find;
			         a_part_find = a_part_find->next) {
				if (a_part_find->totalparts == -1) {
				    a_part_find->totalparts = maxparts;
				}
				if (a_part_find->orig_kb == 0) {
				    a_part_find->orig_kb = orig_kb;
				}
				a_part_find->native_crc = native_crc;
				a_part_find->client_crc = client_crc;
				a_part_find->server_crc = server_crc;
			    }
			}
			if (part_find) { /* find last element */
			    for (a_part_find = part_find;
				 a_part_find->next != NULL;
				 a_part_find=a_part_find->next) {
			    }
			    /* merge part_find to *output_find */
			    a_part_find->next = *output_find;
			    *output_find = part_find;
			    part_find = NULL;
			    maxparts = -1;
                            found_something = TRUE;
			    g_hash_table_remove(part_by_dle, key);
			}
			free_find_result(&new_output_find);
		    } else { /* part line */
			if (curlog == L_PART || curlog == L_CHUNK) {
			    new_output_find->status = "OK";
			    new_output_find->dump_status = "OK";
			} else { /* PARTPARTIAL */
			    new_output_find->status = "PARTIAL";
			    new_output_find->dump_status = "PARTIAL";
			}
			/* Add to part_find list */
			if (part_find) {
			    new_output_find->next = part_find;
			    part_find = new_output_find;
			} else {
			    new_output_find->next = NULL;
			    part_find = new_output_find;
			}
			g_hash_table_insert(part_by_dle, g_strdup(key),
					    part_find);
			found_something = TRUE;
		    }
		    amfree(key);
		}
		else if(curlog == L_FAIL) {
		    char *status_failed;
		    /* print other failures too -- this is a hack to ensure that failures which
		     * did not make it to tape are also listed in the output of 'amadmin x find';
		     * users that do not want this information (e.g., Amanda::DB::Catalog) should
		     * filter dumps with a NULL label. */
		    find_result_t *new_output_find = g_new0(find_result_t, 1);
		    new_output_find->next = *output_find;
		    new_output_find->timestamp = g_string_chunk_insert_const(string_chunk, date);
		    new_output_find->write_timestamp = g_string_chunk_insert_const(string_chunk, "00000000000000"); /* dump was not written.. */
		    new_output_find->hostname=g_string_chunk_insert_const(string_chunk, host);
		    new_output_find->diskname=g_string_chunk_insert_const(string_chunk, disk);
		    if (current_storage != NULL) {
			new_output_find->storage=g_string_chunk_insert_const(string_chunk, current_storage);
		    }
		    new_output_find->level=level;
		    new_output_find->label=NULL;
		    new_output_find->partnum=partnum;
		    new_output_find->totalparts=totalparts;
		    new_output_find->filenum=0;
		    new_output_find->sec=sec;
		    new_output_find->kb=kb;
		    new_output_find->bytes=bytes;
		    new_output_find->orig_kb=orig_kb;
		    status_failed = g_strjoin(NULL, 
			 "FAILED (",
			 program_str[(int)curprog],
			 ") ",
			 rest,
			 NULL);
		    new_output_find->status = g_string_chunk_insert_const(string_chunk, status_failed);
		    amfree(status_failed);
		    new_output_find->dump_status="";
		    new_output_find->message="";
		    *output_find=new_output_find;
                    found_something = TRUE;
		    maxparts = -1;
		}
	    }
	}
    }
    amfree(host);
    amfree(date);
    amfree(disk);

    g_hash_table_destroy(valid_label);
    g_hash_table_destroy(part_by_dle);
    afclose(logf);
    amfree(datestamp);
    amfree(current_label);
    amfree(current_storage);
    amfree(disk);

    return found_something;
}
Example #16
0
/*
 * Returns a file descriptor to the incoming port
 * on success, or -1 on error.
 */
static int
startup_chunker(
    char *		filename,
    off_t		use,
    off_t		chunksize,
    struct databuf *	db)
{
    int infd, outfd;
    char *tmp_filename, *pc;
    in_port_t data_port;
    int data_socket;
    int result;
    struct addrinfo *res;

    data_port = 0;
    if ((result = resolve_hostname("localhost", 0, &res, NULL) != 0)) {
        errstr = newvstrallocf(errstr, _("could not resolve localhost: %s"),
                               gai_strerror(result));
        return -1;
    }
    data_socket = stream_server(res->ai_family, &data_port, 0,
                                STREAM_BUFSIZE, 0);
    if (res) freeaddrinfo(res);

    if(data_socket < 0) {
        errstr = vstrallocf(_("error creating stream server: %s"), strerror(errno));
        return -1;
    }

    putresult(PORT, "%d\n", data_port);

    infd = stream_accept(data_socket, CONNECT_TIMEOUT, 0, STREAM_BUFSIZE);
    aclose(data_socket);
    if(infd == -1) {
        errstr = vstrallocf(_("error accepting stream: %s"), strerror(errno));
        return -1;
    }

    tmp_filename = vstralloc(filename, ".tmp", NULL);
    pc = strrchr(tmp_filename, '/');
    g_assert(pc != NULL);
    *pc = '\0';
    mkholdingdir(tmp_filename);
    *pc = '/';
    if ((outfd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) {
        int save_errno = errno;
        char *m = vstrallocf(_("holding file \"%s\": %s"),
                             tmp_filename,
                             strerror(errno));

        errstr = quote_string(m);
        amfree(m);
        amfree(tmp_filename);
        aclose(infd);
        if(save_errno == ENOSPC) {
            putresult(NO_ROOM, "%s %lld\n",
                      handle, (long long)use);
            return -2;
        } else {
            return -1;
        }
    }
    amfree(tmp_filename);
    databuf_init(db, outfd, filename, use, chunksize);
    db->filename_seq++;
    return infd;
}
Example #17
0
int
main(
    int		argc,
    char **	argv)
{
    int ch;
    char *exitstr;
    amwait_t status;

    if (argc > 1 && argv[1] && g_str_equal(argv[1], "--version")) {
	printf("killpgrp-%s\n", VERSION);
	return (0);
    }

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

    safe_fd(-1, 0);
    safe_cd();

    set_pname("killpgrp");

    dbopen(DBG_SUBDIR_CLIENT);
    config_init(CONFIG_INIT_CLIENT|CONFIG_INIT_GLOBAL, NULL);

    if (argc < 2) {
	error("Need at least 2 arguments\n");
	/*NOTREACHED*/
    }
    dbprintf(_("version %s\n"), VERSION);
    dbprintf(_("config: %s\n"), argv[1]);
    if (!g_str_equal(argv[1], "NOCONFIG"))
	dbrename(argv[1], DBG_SUBDIR_CLIENT);

#ifdef WANT_SETUID_CLIENT
    check_running_as(RUNNING_AS_CLIENT_LOGIN | RUNNING_AS_UID_ONLY);
    if (!become_root()) {
	error(_("error [%s could not become root (is the setuid bit set?)]\n"), get_pname());
	/*NOTREACHED*/
    }
#else
    check_running_as(RUNNING_AS_CLIENT_LOGIN);
#endif

    if (AM_GETPGRP() != getpid()) {
	error(_("error [must be the process group leader]"));
	/*NOTREACHED*/
    }

    signal(SIGTERM, term_kill_soft);

    /* Consume any extranious input */
    do {
	ch = getchar();
	/* wait until EOF */
    } while (ch != EOF);

    term_kill_soft(0);

    for(;;) {
	if (wait(&status) != -1)
	    break;
	if (errno != EINTR) {
	    error(_("error [wait() failed: %s]"), strerror(errno));
	    /*NOTREACHED*/
	}
    }
    exitstr = str_exit_status("child", status);
    dbprintf("%s\n", exitstr);
    amfree(exitstr);

    /*@ignore@*/
    return WIFEXITED(status)?WEXITSTATUS(status):1;
    /*@end@*/
}
Example #18
0
static int
do_chunk(
    int			infd,
    struct databuf *	db)
{
    size_t nread;
    char header_buf[DISK_BLOCK_BYTES];

    startclock();

    dumpsize = dumpbytes = filesize = (off_t)0;
    headersize = 0;
    memset(header_buf, 0, sizeof(header_buf));

    /*
     * The first thing we should receive is the file header, which we
     * need to save into "file", as well as write out.  Later, the
     * chunk code will rewrite it.
     */
    nread = full_read(infd, header_buf, SIZEOF(header_buf));
    if (nread != sizeof(header_buf)) {
        if(errno != 0) {
            errstr = vstrallocf(_("cannot read header: %s"), strerror(errno));
        } else {
            errstr = vstrallocf(_("cannot read header: got %zd bytes instead of %zd"),
                                nread, sizeof(header_buf));
        }
        return 0;
    }
    parse_file_header(header_buf, &file, (size_t)nread);
    if(write_tapeheader(db->fd, &file)) {
        int save_errno = errno;
        char *m = vstrallocf(_("write_tapeheader file %s: %s"),
                             db->filename, strerror(errno));
        errstr = quote_string(m);
        amfree(m);
        if(save_errno == ENOSPC) {
            putresult(NO_ROOM, "%s %lld\n", handle,
                      (long long)(db->use+db->split_size-dumpsize));
        }
        return 0;
    }
    dumpsize += (off_t)DISK_BLOCK_KB;
    filesize = (off_t)DISK_BLOCK_KB;
    headersize += DISK_BLOCK_KB;

    /*
     * We've written the file header.  Now, just write data until the
     * end.
     */
    while ((nread = full_read(infd, db->buf,
                              (size_t)(db->datalimit - db->datain))) > 0) {
        db->datain += nread;
        while(db->dataout < db->datain) {
            if(!databuf_flush(db)) {
                return 0;
            }
        }
    }
    while(db->dataout < db->datain) {
        if(!databuf_flush(db)) {
            return 0;
        }
    }
    if(dumpbytes > (off_t)0) {
        dumpsize += (off_t)1;			/* count partial final KByte */
        filesize += (off_t)1;
    }
    return 1;
}
Example #19
0
static void
amstar_estimate(
    application_argument_t *argument)
{
    GPtrArray  *argv_ptr;
    char       *cmd = NULL;
    int         nullfd;
    int         pipefd;
    FILE       *dumpout = NULL;
    off_t       size = -1;
    char        line[32768];
    char       *errmsg = NULL;
    char       *qerrmsg;
    char       *qdisk;
    amwait_t    wait_status;
    int         starpid;
    amregex_t  *rp;
    times_t     start_time;
    int         level = 0;
    GSList     *levels = NULL;

    if (!argument->level) {
	fprintf(stderr, "ERROR No level argument\n");
	error(_("No level argument"));
    }
    if (!argument->dle.disk) {
	fprintf(stderr, "ERROR No disk argument\n");
	error(_("No disk argument"));
    }
    if (!argument->dle.device) {
	fprintf(stderr, "ERROR No device argument\n");
	error(_("No device argument"));
    }

    if (argument->dle.include_list &&
	argument->dle.include_list->nb_element >= 0) {
	fprintf(stderr, "ERROR include-list not supported for backup\n");
    }

    if (check_device(argument) == 0) {
	return;
    }

    if (argument->calcsize) {
	char *dirname;

	if (star_directory) {
	    dirname = star_directory;
	} else {
	    dirname = argument->dle.device;
	}
	run_calcsize(argument->config, "STAR", argument->dle.disk, dirname,
		     argument->level, NULL, NULL);
	return;
    }

    qdisk = quote_string(argument->dle.disk);
    if (!star_path) {
	errmsg = g_strdup(_("STAR-PATH not defined"));
	goto common_error;
    }
    cmd = g_strdup(star_path);

    start_time = curclock();

    for (levels = argument->level; levels != NULL; levels = levels->next) {
	level = GPOINTER_TO_INT(levels->data);
	argv_ptr = amstar_build_argv(argument, level, CMD_ESTIMATE);

	if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
	    errmsg = g_strdup_printf(_("Cannot access /dev/null : %s"),
				strerror(errno));
	    goto common_error;
	}

	starpid = pipespawnv(cmd, STDERR_PIPE, 1,
			     &nullfd, &nullfd, &pipefd,
			     (char **)argv_ptr->pdata);

	dumpout = fdopen(pipefd,"r");
	if (!dumpout) {
	    errmsg = g_strdup_printf(_("Can't fdopen: %s"), strerror(errno));
	    aclose(nullfd);
	    goto common_error;
	}

	size = (off_t)-1;
	while (size < 0 && (fgets(line, sizeof(line), dumpout)) != NULL) {
	    if (strlen(line) > 0 && line[strlen(line)-1] == '\n') {
		/* remove trailling \n */
		line[strlen(line)-1] = '\0';
	    }
	    if (line[0] == '\0')
		continue;
	    dbprintf("%s\n", line);
	    /* check for size match */
	    /*@ignore@*/
	    for(rp = re_table; rp->regex != NULL; rp++) {
		if(match(rp->regex, line)) {
		    if (rp->typ == DMP_SIZE) {
			size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0);
			if(size < 0.0)
			    size = 1.0;             /* found on NeXT -- sigh */
		    }
		    break;
		}
	    }
	    /*@end@*/
	}

	while ((fgets(line, sizeof(line), dumpout)) != NULL) {
	    dbprintf("%s", line);
	}

	dbprintf(".....\n");
	dbprintf(_("estimate time for %s level %d: %s\n"),
		 qdisk,
		 level,
		 walltime_str(timessub(curclock(), start_time)));
	if(size == (off_t)-1) {
	    errmsg = g_strdup_printf(_("no size line match in %s output"),
				cmd);
	    dbprintf(_("%s for %s\n"), errmsg, qdisk);
	    dbprintf(".....\n");
	    qerrmsg = quote_string(errmsg);
	    fprintf(stdout, "ERROR %s\n", qerrmsg);
	    amfree(errmsg);
	    amfree(qerrmsg);
	} else if(size == (off_t)0 && argument->level == 0) {
	    dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"),
		     cmd, argument->dle.disk);
	    dbprintf(".....\n");
	}
	dbprintf(_("estimate size for %s level %d: %lld KB\n"),
		 qdisk,
		 level,
		 (long long)size);

	kill(-starpid, SIGTERM);

	dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk);
	waitpid(starpid, &wait_status, 0);
	if (WIFSIGNALED(wait_status)) {
	    amfree(errmsg);
	    errmsg = g_strdup_printf(_("%s terminated with signal %d: see %s"),
				cmd, WTERMSIG(wait_status), dbfn());
	    dbprintf(_("%s for %s\n"), errmsg, qdisk);
	    dbprintf(".....\n");
	    qerrmsg = quote_string(errmsg);
	    fprintf(stdout, "ERROR %s\n", qerrmsg);
	    amfree(errmsg);
	    amfree(qerrmsg);
	} else if (WIFEXITED(wait_status)) {
	    if (WEXITSTATUS(wait_status) != 0) {
		amfree(errmsg);
		errmsg = g_strdup_printf(_("%s exited with status %d: see %s"),
				    cmd, WEXITSTATUS(wait_status), dbfn());
		dbprintf(_("%s for %s\n"), errmsg, qdisk);
		dbprintf(".....\n");
		qerrmsg = quote_string(errmsg);
		fprintf(stdout, "ERROR %s\n", qerrmsg);
		amfree(errmsg);
		amfree(qerrmsg);
	    } else {
		/* Normal exit */
	    }
	} else {
	    amfree(errmsg);
	    errmsg = g_strdup_printf(_("%s got bad exit: see %s"), cmd, dbfn());
	    dbprintf(_("%s for %s\n"), errmsg, qdisk);
	    dbprintf(".....\n");
	    qerrmsg = quote_string(errmsg);
	    fprintf(stdout, "ERROR %s\n", qerrmsg);
	    amfree(errmsg);
	    amfree(qerrmsg);
	}
	dbprintf(_("after %s %s wait\n"), cmd, qdisk);

	g_ptr_array_free_full(argv_ptr);

	aclose(nullfd);
	afclose(dumpout);

	fprintf(stdout, "%d %lld 1\n", level, (long long)size);
    }
    amfree(qdisk);
    amfree(cmd);
    return;

common_error:
    dbprintf("%s\n", errmsg);
    qerrmsg = quote_string(errmsg);
    amfree(qdisk);
    dbprintf("%s", errmsg);
    fprintf(stdout, "ERROR %s\n", qerrmsg);
    amfree(errmsg);
    amfree(qerrmsg);
    amfree(cmd);
}
Example #20
0
/*
 * Write out the buffer to the backing file
 */
static int
databuf_flush(
    struct databuf *	db)
{
    struct cmdargs *cmdargs = NULL;
    int rc = 1;
    size_t size_to_write;
    size_t written;
    off_t left_in_chunk;
    char *arg_filename = NULL;
    char *new_filename = NULL;
    char *tmp_filename = NULL;
    char sequence[NUM_STR_SIZE];
    int newfd;
    filetype_t save_type;
    char *q;
    int a;
    char *pc;

    /*
     * If there's no data, do nothing.
     */
    if (db->dataout >= db->datain) {
        goto common_exit;
    }

    /*
     * See if we need to split this file.
     */
    while (db->split_size > (off_t)0 && dumpsize >= db->split_size) {
        if( db->use == (off_t)0 ) {
            /*
             * Probably no more space on this disk.  Request some more.
             */
            putresult(RQ_MORE_DISK, "%s\n", handle);
            cmdargs = getcmd();
            if(command_in_transit == NULL &&
                    (cmdargs->cmd == DONE || cmdargs->cmd == TRYAGAIN || cmdargs->cmd == FAILED)) {
                command_in_transit = cmdargs;
                cmdargs = getcmd();
            }
            if(cmdargs->cmd == CONTINUE) {
                /*
                 * CONTINUE
                 *   serial
                 *   filename
                 *   chunksize
                 *   use
                 */
                a = 2; /* skip CONTINUE and serial */

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

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

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

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

                if(strcmp(db->filename, arg_filename) == 0) {
                    /*
                     * Same disk, so use what room is left up to the
                     * next chunk boundary or the amount we were given,
                     * whichever is less.
                     */
                    left_in_chunk = db->chunk_size - filesize;
                    if(left_in_chunk > db->use) {
                        db->split_size += db->use;
                        db->use = (off_t)0;
                    } else {
                        db->split_size += left_in_chunk;
                        db->use -= left_in_chunk;
                    }
                    if(left_in_chunk > (off_t)0) {
                        /*
                         * We still have space in this chunk.
                         */
                        break;
                    }
                } else {
                    /*
                     * Different disk, so use new file.
                     */
                    db->filename = newstralloc(db->filename, arg_filename);
                }
            } else if(cmdargs->cmd == ABORT) {
                abort_pending = 1;
                errstr = newstralloc(errstr, cmdargs->argv[1]);
                putresult(ABORT_FINISHED, "%s\n", handle);
                rc = 0;
                goto common_exit;
            } else {
                if(cmdargs->argc >= 1) {
                    q = quote_string(cmdargs->argv[0]);
                } else {
                    q = stralloc(_("(no input?)"));
                }
                error(_("error [bad command after RQ-MORE-DISK: \"%s\"]"), q);
                /*NOTREACHED*/
            }
        }

        /*
         * Time to use another file.
         */

        /*
         * First, open the new chunk file, and give it a new header
         * that has no cont_filename pointer.
         */
        g_snprintf(sequence, SIZEOF(sequence), "%d", db->filename_seq);
        new_filename = newvstralloc(new_filename,
                                    db->filename,
                                    ".",
                                    sequence,
                                    NULL);
        tmp_filename = newvstralloc(tmp_filename,
                                    new_filename,
                                    ".tmp",
                                    NULL);
        pc = strrchr(tmp_filename, '/');
        g_assert(pc != NULL); /* Only a problem if db->filename has no /. */
        *pc = '\0';
        mkholdingdir(tmp_filename);
        *pc = '/';
        newfd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600);
        if (newfd == -1) {
            int save_errno = errno;
            char *m;

            if(save_errno == ENOSPC) {
                putresult(NO_ROOM, "%s %lld\n", handle,
                          (long long)(db->use+db->split_size-dumpsize));
                db->use = (off_t)0;			/* force RQ_MORE_DISK */
                db->split_size = dumpsize;
                continue;
            }
            m = vstrallocf(_("creating chunk holding file \"%s\": %s"),
                           tmp_filename,
                           strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            aclose(db->fd);
            rc = 0;
            goto common_exit;
        }
        save_type = file.type;
        file.type = F_CONT_DUMPFILE;
        file.cont_filename[0] = '\0';
        if(write_tapeheader(newfd, &file)) {
            int save_errno = errno;
            char *m;

            aclose(newfd);
            if(save_errno == ENOSPC) {
                putresult(NO_ROOM, "%s %lld\n", handle,
                          (long long)(db->use+db->split_size-dumpsize));
                db->use = (off_t)0;			/* force RQ_MORE DISK */
                db->split_size = dumpsize;
                continue;
            }
            m = vstrallocf(_("write_tapeheader file %s: %s"),
                           tmp_filename,
                           strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            rc = 0;
            goto common_exit;
        }

        /*
         * Now, update the header of the current file to point
         * to the next chunk, and then close it.
         */
        if (lseek(db->fd, (off_t)0, SEEK_SET) < (off_t)0) {
            char *m = vstrallocf(_("lseek holding file %s: %s"),
                                 db->filename,
                                 strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            aclose(newfd);
            rc = 0;
            goto common_exit;
        }

        file.type = save_type;
        strncpy(file.cont_filename, new_filename, SIZEOF(file.cont_filename));
        file.cont_filename[SIZEOF(file.cont_filename)-1] = '\0';
        if(write_tapeheader(db->fd, &file)) {
            char * m = vstrallocf(_("write_tapeheader file \"%s\": %s"),
                                  db->filename,
                                  strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            aclose(newfd);
            unlink(tmp_filename);
            rc = 0;
            goto common_exit;
        }
        file.type = F_CONT_DUMPFILE;

        /*
         * Now shift the file descriptor.
         */
        aclose(db->fd);
        db->fd = newfd;
        newfd = -1;

        /*
         * Update when we need to chunk again
         */
        if(db->use <= (off_t)DISK_BLOCK_KB) {
            /*
             * Cheat and use one more block than allowed so we can make
             * some progress.
             */
            db->split_size += (off_t)(2 * DISK_BLOCK_KB);
            db->use = (off_t)0;
        } else if(db->chunk_size > db->use) {
            db->split_size += db->use;
            db->use = (off_t)0;
        } else {
            db->split_size += db->chunk_size;
            db->use -= db->chunk_size;
        }


        amfree(tmp_filename);
        amfree(new_filename);
        dumpsize += (off_t)DISK_BLOCK_KB;
        filesize = (off_t)DISK_BLOCK_KB;
        headersize += DISK_BLOCK_KB;
        db->filename_seq++;
    }

    /*
     * Write out the buffer
     */
    size_to_write = (size_t)(db->datain - db->dataout);
    written = full_write(db->fd, db->dataout, size_to_write);
    if (written > 0) {
        db->dataout += written;
        dumpbytes += (off_t)written;
    }
    dumpsize += (dumpbytes / (off_t)1024);
    filesize += (dumpbytes / (off_t)1024);
    dumpbytes %= 1024;
    if (written < size_to_write) {
        if (errno != ENOSPC) {
            char *m = vstrallocf(_("data write: %s"), strerror(errno));
            errstr = quote_string(m);
            amfree(m);
            rc = 0;
            goto common_exit;
        }

        /*
         * NO-ROOM is informational only.  Later, RQ_MORE_DISK will be
         * issued to use another holding disk.
         */
        putresult(NO_ROOM, "%s %lld\n", handle,
                  (long long)(db->use+db->split_size-dumpsize));
        db->use = (off_t)0;				/* force RQ_MORE_DISK */
        db->split_size = dumpsize;
        goto common_exit;
    }
    if (db->datain == db->dataout) {
        /*
         * We flushed the whole buffer so reset to use it all.
         */
        db->datain = db->dataout = db->buf;
    }

common_exit:

    if (cmdargs)
        free_cmdargs(cmdargs);
    amfree(new_filename);
    /*@i@*/ amfree(tmp_filename);
    amfree(arg_filename);
    return rc;
}
Example #21
0
static void
bsd_connect(
    const char *	hostname,
    char *		(*conf_fn)(char *, void *),
    void		(*fn)(void *, security_handle_t *, security_status_t),
    void *		arg,
    void *		datap)
{
    struct sec_handle *bh;
    in_port_t port = 0;
    struct timeval sequence_time;
    int sequence;
    char *handle;
    int result;
    struct addrinfo *res, *res_addr;
    char *canonname;
    int result_bind;
    char *service;

    assert(hostname != NULL);

    (void)conf_fn;	/* Quiet unused parameter warning */
    (void)datap;        /* Quiet unused parameter warning */

    bh = g_new0(struct sec_handle, 1);
    bh->proto_handle=NULL;
    security_handleinit(&bh->sech, &bsd_security_driver);

    result = resolve_hostname(hostname, SOCK_DGRAM, &res, &canonname);
    if(result != 0) {
	dbprintf(_("resolve_hostname(%s): %s\n"), hostname, gai_strerror(result));
	security_seterror(&bh->sech, _("resolve_hostname(%s): %s\n"), hostname,
			  gai_strerror(result));
	(*fn)(arg, &bh->sech, S_ERROR);
	return;
    }
    if (canonname == NULL) {
	dbprintf(_("resolve_hostname(%s) did not return a canonical name\n"), hostname);
	security_seterror(&bh->sech,
	        _("resolve_hostname(%s) did not return a canonical name\n"), hostname);
	(*fn)(arg, &bh->sech, S_ERROR);
	if (res) freeaddrinfo(res);
	return;
    }
    if (res == NULL) {
	dbprintf(_("resolve_hostname(%s): no results\n"), hostname);
	security_seterror(&bh->sech,
	        _("resolve_hostname(%s): no results\n"), hostname);
	(*fn)(arg, &bh->sech, S_ERROR);
	amfree(canonname);
	return;
    }

    for (res_addr = res; res_addr != NULL; res_addr = res_addr->ai_next) {
#ifdef WORKING_IPV6
	/* IPv6 socket already bound */
	if (res_addr->ai_addr->sa_family == AF_INET6 && not_init6 == 0) {
	    break;
	}
	/*
	 * Only init the IPv6 socket once
	 */
	if (res_addr->ai_addr->sa_family == AF_INET6 && not_init6 == 1) {
	    uid_t euid;
	    dgram_zero(&netfd6.dgram);

	    euid = geteuid();
	    set_root_privs(1);
	    result_bind = dgram_bind(&netfd6.dgram,
				     res_addr->ai_addr->sa_family, &port);
	    set_root_privs(0);
	    if (result_bind != 0) {
		continue;
	    }
	    netfd6.handle = NULL;
	    netfd6.pkt.body = NULL;
	    netfd6.recv_security_ok = &bsd_recv_security_ok;
	    netfd6.prefix_packet = &bsd_prefix_packet;
	    /*
	     * We must have a reserved port.  Bomb if we didn't get one.
	     */
	    if (port >= IPPORT_RESERVED) {
		security_seterror(&bh->sech,
		    _("unable to bind to a reserved port (got port %u)"),
		    (unsigned int)port);
		(*fn)(arg, &bh->sech, S_ERROR);
		freeaddrinfo(res);
		amfree(canonname);
		return;
	    }
	    not_init6 = 0;
	    bh->udp = &netfd6;
	    break;
	}
#endif

	/* IPv4 socket already bound */
	if (res_addr->ai_addr->sa_family == AF_INET && not_init4 == 0) {
	    break;
	}

	/*
	 * Only init the IPv4 socket once
	 */
	if (res_addr->ai_addr->sa_family == AF_INET && not_init4 == 1) {
	    uid_t euid;
	    dgram_zero(&netfd4.dgram);

	    euid = geteuid();
	    set_root_privs(1);
	    result_bind = dgram_bind(&netfd4.dgram,
				     res_addr->ai_addr->sa_family, &port);
	    set_root_privs(0);
	    if (result_bind != 0) {
		continue;
	    }
	    netfd4.handle = NULL;
	    netfd4.pkt.body = NULL;
	    netfd4.recv_security_ok = &bsd_recv_security_ok;
	    netfd4.prefix_packet = &bsd_prefix_packet;
	    /*
	     * We must have a reserved port.  Bomb if we didn't get one.
	     */
	    if (port >= IPPORT_RESERVED) {
		security_seterror(&bh->sech,
		    "unable to bind to a reserved port (got port %u)",
		    (unsigned int)port);
		(*fn)(arg, &bh->sech, S_ERROR);
		freeaddrinfo(res);
		amfree(canonname);
		return;
	    }
	    not_init4 = 0;
	    bh->udp = &netfd4;
	    break;
	}
    }

    if (res_addr == NULL) {
	dbprintf(_("Can't bind a socket to connect to %s\n"), hostname);
	security_seterror(&bh->sech,
	        _("Can't bind a socket to connect to %s\n"), hostname);
	(*fn)(arg, &bh->sech, S_ERROR);
       amfree(canonname);
       return;
    }

#ifdef WORKING_IPV6
    if (res_addr->ai_addr->sa_family == AF_INET6)
	bh->udp = &netfd6;
    else
#endif
	bh->udp = &netfd4;

    auth_debug(1, _("Resolved hostname=%s\n"), canonname);

    if (conf_fn) {
        service = conf_fn("client_port", datap);
        if (!service || strlen(service) <= 1)
            service = "amanda";
    } else {
        service = "amanda";
    }
    port = find_port_for_service(service, "udp");
    if (port == 0) {
        security_seterror(&bh->sech, _("%s/udp unknown protocol"), service);
	(*fn)(arg, &bh->sech, S_ERROR);
        amfree(canonname);
	return;
    }

    amanda_gettimeofday(&sequence_time);
    sequence = (int)sequence_time.tv_sec ^ (int)sequence_time.tv_usec;
    handle=alloc(15);
    g_snprintf(handle, 14, "000-%08x",  (unsigned)newhandle++);
    if (udp_inithandle(bh->udp, bh, canonname,
	(sockaddr_union *)res_addr->ai_addr, port, handle, sequence) < 0) {
	(*fn)(arg, &bh->sech, S_ERROR);
	amfree(bh->hostname);
	amfree(bh);
    }
    else {
	(*fn)(arg, &bh->sech, S_OK);
    }
    amfree(handle);
    amfree(canonname);

    freeaddrinfo(res);
}
Example #22
0
static void
start_backup(
    dle_t      *dle,
    char       *host,
    int		dataf,
    int		mesgf,
    int		indexf)
{
    int dumpin, dumpout, compout;
    char *dumpkeys = NULL;
    char *device = NULL;
    char *fstype = NULL;
    char *cmd = NULL;
    char *cmdX = NULL;
    char *indexcmd = NULL;
    char level_str[NUM_STR_SIZE];
    char *compopt  = NULL;
    char *encryptopt = skip_argument;
    char *qdisk;
    char *config;
    am_level_t *alevel = (am_level_t *)dle->levellist->data;
    int      level  = alevel->level;

    g_snprintf(level_str, sizeof(level_str), "%d", level);

    qdisk = quote_string(dle->disk);
    dbprintf(_("start: %s:%s lev %d\n"), host, qdisk, level);

    g_fprintf(stderr, _("%s: start [%s:%s level %d]\n"),
	    get_pname(), host, qdisk, level);
    amfree(qdisk);

    /*  apply client-side encryption here */
    if (dle->encrypt == ENCRYPT_CUST ) {
        encpid = pipespawn(dle->clnt_encrypt, STDIN_PIPE, 0,
	                   &compout, &dataf, &mesgf,
	                   dle->clnt_encrypt, encryptopt, NULL);
        dbprintf(_("gnutar: pid %ld: %s\n"), (long)encpid, dle->clnt_encrypt);
    } else {
        compout = dataf;
        encpid = -1;
    }
    /*  now do the client-side compression */


    if(dle->compress == COMP_FAST || dle->compress == COMP_BEST) {
	compopt = skip_argument;

#if defined(COMPRESS_BEST_OPT) && defined(COMPRESS_FAST_OPT)
	if(dle->compress == COMP_BEST) {
	    compopt = COMPRESS_BEST_OPT;
	} else {
	    compopt = COMPRESS_FAST_OPT;
	}
#endif
	comppid = pipespawn(COMPRESS_PATH, STDIN_PIPE, 0,
			    &dumpout, &compout, &mesgf,
			    COMPRESS_PATH, compopt, NULL);
	dbprintf(_("dump: pid %ld: %s"), (long)comppid, COMPRESS_PATH);
	if(compopt != skip_argument) {
	    dbprintf(" %s", compopt);
	}
	dbprintf("\n");
     } else if (dle->compress == COMP_CUST) {
        compopt = skip_argument;
	comppid = pipespawn(dle->compprog, STDIN_PIPE, 0,
			    &dumpout, &compout, &mesgf,
			    dle->compprog, compopt, NULL);
	dbprintf(_("gnutar-cust: pid %ld: %s"),
		(long)comppid, dle->compprog);
	if(compopt != skip_argument) {
	    dbprintf(" %s", compopt);
	}
	dbprintf("\n");
    } else {
	dumpout = compout;
	comppid = -1;
    }

    /* invoke dump */
    device = amname_to_devname(dle->device);
    fstype = amname_to_fstype(dle->device);

    dbprintf(_("dumping device '%s' with '%s'\n"), device, fstype);

#if defined(USE_RUNDUMP) || !defined(DUMP)
    cmd = g_strjoin(NULL, amlibexecdir, "/", "rundump", NULL);
    cmdX = cmd;
    if (g_options->config)
	config = g_options->config;
    else
	config = "NOCONFIG";
#else
    cmd = g_strdup(DUMP);
    cmdX = skip_argument;
    config = skip_argument;
#endif

#ifndef AIX_BACKUP					/* { */
    /* normal dump */
#ifdef XFSDUMP						/* { */
#ifdef DUMP						/* { */
    if (g_str_equal(amname_to_fstype(dle->device), "xfs"))
#else							/* } { */
    if (1)
#endif							/* } */
    {
        char *progname;
        g_free(cmd);
        progname = cmd = g_strconcat(amlibexecdir, "/", "rundump", NULL);
	cmdX = cmd;
	if (g_options->config)
	    config = g_options->config;
	else
	    config = "NOCONFIG";

	program->backup_name  = XFSDUMP;
	program->restore_name = XFSRESTORE;

	indexcmd = g_strjoin(NULL, XFSRESTORE, " -t", " -v", " silent", " -",
	    " 2>/dev/null", " | sed", " -e", " \'s/^/\\//\'", NULL);

	info_tapeheader(dle);

	start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);

	dumpkeys = g_strdup(level_str);
	dumppid = pipespawn(progname, STDIN_PIPE, 0,
			    &dumpin, &dumpout, &mesgf,
			    cmdX, config,
			    "xfsdump",
			    !dle->record ? "-J" : skip_argument,
			    "-F",
			    "-l", dumpkeys,
			    "-",
			    device,
			    NULL);
    }
    else
#endif							/* } */
#ifdef VXDUMP						/* { */
#ifdef DUMP
    if (g_str_equal(amname_to_fstype(dle->device), "vxfs"))
#else
    if (1)
#endif
    {
char *progname;
#ifdef USE_RUNDUMP
        g_free(cmd);
        progname = cmd = g_strconcat(amlibexecdir, "/", "rundump", NULL);
	cmdX = cmd;
	if (g_options->config)
	    config = g_options->config;
	else
	    config = "NOCONFIG";
#else
	char *progname;
        g_free(cmd);
        progname = cmd = g_strdup(VXDUMP);
	cmdX = skip_argument;
	config = skip_argument;
#endif
	program->backup_name  = VXDUMP;
	program->restore_name = VXRESTORE;

	dumpkeys = g_strjoin(NULL, level_str,
			     !dle->record ? "" : "u",
			     "s",
			     "f",
			     NULL);

	indexcmd = g_strjoin(NULL, VXRESTORE,
			     " -tvf", " -",
			     " 2>/dev/null",
			     " | ",
			     LEAF_AND_DIRS,
			     NULL);
	info_tapeheader(dle);

	start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);

	dumppid = pipespawn(progname, STDIN_PIPE, 0,
			    &dumpin, &dumpout, &mesgf, 
			    cmdX, config,
			    "vxdump",
			    dumpkeys,
			    "1048576",
			    "-",
			    device,
			    NULL);
    }
    else
#endif							/* } */

#ifdef VDUMP						/* { */
#ifdef DUMP
    if (g_str_equal(amname_to_fstype(dle->device), "advfs"))
#else
    if (1)
#endif
    {
        g_free(cmd);
        cmd = g_strconcat(amlibexecdir, "/", "rundump", NULL);
	cmdX = cmd;
	if (g_options->config)
	    config = g_options->config;
	else
	    config = "NOCONFIG";
	g_free(device);
	device = g_strdup(amname_to_dirname(dle->device));
	program->backup_name  = VDUMP;
	program->restore_name = VRESTORE;

	dumpkeys = g_strjoin(NULL, level_str,
			     !dle->record ? "" : "u",
			     "b",
			     "f",
			     NULL);

	indexcmd = g_strjoin(NULL, VRESTORE,
			     " -tvf", " -",
			     " 2>/dev/null",
			     " | ",
			     "sed -e \'\n/^\\./ {\ns/^\\.//\ns/, [0-9]*$//\ns/^\\.//\ns/ @-> .*$//\nt\n}\nd\n\'",
			     NULL);
	info_tapeheader(dle);

	start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);

	dumppid = pipespawn(cmd, STDIN_PIPE, 0,
			    &dumpin, &dumpout, &mesgf, 
			    cmdX, config,
			    "vdump",
			    dumpkeys,
			    "60",
			    "-",
			    device,
			    NULL);
    }
    else
#endif							/* } */

    {
#ifndef RESTORE
#define RESTORE "restore"
#endif

#ifdef HAVE_HONOR_NODUMP
#  define PARAM_HONOR_NODUMP "h"
#else
#  define PARAM_HONOR_NODUMP ""
#endif

#ifdef __FreeBSD__
# if defined(__FreeBSD_version) && (__FreeBSD_version >= 500043)
#  define FREEBSD_EXTRA_KEYS "bL"
# else
#  define FREEBSD_EXTRA_KEYS "b"
# endif
#else
# define FREEBSD_EXTRA_KEYS ""
#endif

	dumpkeys = g_strjoin(NULL, level_str,
			     !dle->record ? "" : "u",
			     FREEBSD_EXTRA_KEYS,
			     "s",
			     PARAM_HONOR_NODUMP,
			     "f",
			     NULL);

	indexcmd = g_strjoin(NULL, RESTORE,
			     " -tvf", " -",
			     " 2>&1",
			     /* not to /dev/null because of DU's dump */
			     " | ",
			     LEAF_AND_DIRS,
			     NULL);
	info_tapeheader(dle);

	start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);

	dumppid = pipespawn(cmd, STDIN_PIPE, 0,
			    &dumpin, &dumpout, &mesgf, 
			    cmdX, config,
			    "dump",
			    dumpkeys,
#ifdef __FreeBSD__
			    "64",
#endif
			    "1048576",
#ifdef HAVE_HONOR_NODUMP
			    "0",
#endif
			    "-",
			    device,
			    NULL);
    }
#else							/* } { */
    /* AIX backup program */
    dumpkeys = g_strjoin(NULL, "-",
			 level_str,
			 !dle->record ? "" : "u",
			 "f",
			 NULL);

    indexcmd = g_strjoin(NULL, RESTORE,
			 " -B",
			 " -tvf", " -",
			 " 2>/dev/null",
			 " | ",
			 LEAF_AND_DIRS,
			 NULL);
    info_tapeheader(dle);

    start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);

    dumppid = pipespawn(cmd, STDIN_PIPE, 0,
			&dumpin, &dumpout, &mesgf,
			cmdX, config,
			"backup",
			dumpkeys,
			"-",
			device,
			NULL);
#endif							/* } */

    amfree(dumpkeys);
    amfree(fstype);
    amfree(device);
    amfree(cmd);
    amfree(indexcmd);

    /* close the write ends of the pipes */

    aclose(dumpin);
    aclose(dumpout);
    aclose(dataf);
    aclose(mesgf);
    if (dle->create_index)
	aclose(indexf);
}
Example #23
0
/* dir is relative to dir_path or absolute with mount_point */
int
set_directory(
    char *	dir,
    int		verbose)
{
    char *cmd = NULL;
    char *new_dir = NULL;
    char *qnew_dir;
    char *dp, *de;
    char *ldir = NULL;
    int   result;

    /* do nothing if "." */
    if(g_str_equal(dir, ".")) {
	show_directory();		/* say where we are */
	return 1;
	/*NOTREACHED*/
    }

    if (disk_name == NULL) {
	g_printf(_("Must select disk before setting directory\n"));
	return 0;
	/*NOTREACHED*/
    }

    ldir = g_strdup(dir);
    clean_pathname(ldir);

    /* convert directory into absolute path relative to disk mount point */
    if (ldir[0] == '/')
    {
	/* absolute path specified, must start with mount point */
	if (g_str_equal(mount_point, "/"))
	{
	    new_dir = g_strdup(ldir);
	}
	else
	{
	    if (strncmp(mount_point, ldir, strlen(mount_point)) != 0)
	    {
		g_printf(_("Invalid directory - Can't cd outside mount point \"%s\"\n"),
		       mount_point);
		amfree(ldir);
		return 0;
		/*NOTREACHED*/
	    }
	    new_dir = g_strdup(ldir+strlen(mount_point));
	    if (strlen(new_dir) == 0) {
		g_free(new_dir);
		new_dir = g_strdup("/");
					/* i.e. ldir == mount_point */
	    }
	}
    }
    else
    {
	new_dir = g_strdup(disk_path);
	dp = ldir;
	/* strip any leading ..s */
	while (g_str_has_prefix(dp, "../"))
	{
	    de = strrchr(new_dir, '/');	/* always at least 1 */
	    if (de == new_dir)
	    {
		/* at top of disk */
		*(de + 1) = '\0';
		dp = dp + 3;
	    }
	    else
	    {
		*de = '\0';
		dp = dp + 3;
	    }
	}
	if (g_str_equal(dp, "..")) {
	    if (g_str_equal(new_dir, "/")) {
		/* at top of disk */
		g_printf(_("Invalid directory - Can't cd outside mount point \"%s\"\n"),
		       mount_point);
		/*@ignore@*/
		amfree(new_dir);
		/*@end@*/
		amfree(ldir);
		return 0;
		/*NOTREACHED*/
	    }
	    de = strrchr(new_dir, '/');	/* always at least 1 */
	    if (de == new_dir)
	    {
		/* at top of disk */
		*(de+1) = '\0';
	    }
	    else
	    {
		*de = '\0';
 	    }
	} else {
	    /*@ignore@*/
	    if (!g_str_equal(new_dir, "/")) {
		strappend(new_dir, "/");
	    }
	    strappend(new_dir, ldir);
	    /*@end@*/
	}
    }

    qnew_dir = quote_string(new_dir);
    cmd = g_strconcat("OISD ", qnew_dir, NULL);
    amfree(qnew_dir);
    if (exchange(cmd) == -1) {
	exit(1);
	/*NOTREACHED*/
    }
    amfree(cmd);

    if (server_happy())
    {
	g_free(disk_path);
	g_free(disk_tpath);
	disk_path = g_strdup(new_dir);
	disk_tpath = translate_octal(g_strdup(disk_path));
	suck_dir_list_from_server();	/* get list of directory contents */
	if (verbose)
	    show_directory();		/* say where we moved to */
	result = 1;
    }
    else
    {
	g_printf(_("Invalid directory - %s\n"), dir);
	result = 0;
    }

    /*@ignore@*/
    amfree(new_dir);
    amfree(ldir);
    /*@end@*/

    return result;
}
Example #24
0
void
sort_find_result_with_storage(
    char *sort_order,
    char **storage_list,
    find_result_t **output_find)
{
    find_result_t *output_find_result;
    find_result_t **array_find_result = NULL;
    size_t nb_result=0;
    size_t no_result;
    int    i;
    identlist_t il;

    find_sort_order = sort_order;
    /* qsort core dump if nothing to sort */
    if(*output_find==NULL)
	return;

    /* How many result */
    for(output_find_result=*output_find;
	output_find_result;
	output_find_result=output_find_result->next) {
	nb_result++;
	if (!storage_list) {
	    for (i = 1, il = getconf_identlist(CNF_STORAGE); il != NULL;
		i++, il = il->next) {
		char *storage_n = il->data;
		if (g_str_equal(output_find_result->storage,
				storage_n)) {
		    output_find_result->storage_id = i;
		}
	    }
	} else {
	    char **storage_l;
	    for (i=1, storage_l = storage_list; *storage_l != NULL;
		 storage_l++, i++) {
		if (g_str_equal(output_find_result->storage, *storage_l)) {
		    output_find_result->storage_id = i;
		}
	    }
	}
    }

    /* put the list in an array */
    array_find_result=g_malloc(nb_result * sizeof(find_result_t *));
    for(output_find_result=*output_find,no_result=0;
	output_find_result;
	output_find_result=output_find_result->next,no_result++) {
	array_find_result[no_result]=output_find_result;
    }

    /* sort the array */
    qsort(array_find_result,nb_result,sizeof(find_result_t *),
	  find_compare);

    /* put the sorted result in the list */
    for(no_result=0;
	no_result<nb_result-1; no_result++) {
	array_find_result[no_result]->next = array_find_result[no_result+1];
    }
    array_find_result[nb_result-1]->next=NULL;
    *output_find=array_find_result[0];
    amfree(array_find_result);
}
Example #25
0
void dumpfile_free_data(dumpfile_t* info) {
    if (info) {
	amfree(info->dle_str);
    }
}
Example #26
0
void
print_find_result(
    find_result_t *output_find)
{
    find_result_t *output_find_result;
    int max_len_datestamp = 4;
    int max_len_hostname  = 4;
    int max_len_diskname  = 4;
    int max_len_level     = 2;
    int max_len_storage   = 7;
    int max_len_label     =12;
    int max_len_filenum   = 4;
    int max_len_part      = 4;
    int max_len_status    = 6;
    size_t len;

    for(output_find_result=output_find;
	output_find_result;
	output_find_result=output_find_result->next) {
	char *s;

	len=len_find_nicedate(output_find_result->timestamp);
	if((int)len > max_len_datestamp)
	    max_len_datestamp=(int)len;

	len=strlen(output_find_result->hostname);
	if((int)len > max_len_hostname)
	    max_len_hostname = (int)len;

	len = len_quote_string(output_find_result->diskname);
	if((int)len > max_len_diskname)
	    max_len_diskname = (int)len;

        if (output_find_result->label != NULL) {
	    len = len_quote_string(output_find_result->label);
            if((int)len > max_len_label)
                max_len_label = (int)len;
        }

        if (output_find_result->storage != NULL) {
	    len = len_quote_string(output_find_result->storage);
            if((int)len > max_len_storage)
                max_len_storage = (int)len;
        }

	len=strlen(output_find_result->status) + 1 + strlen(output_find_result->dump_status);
	if((int)len > max_len_status)
	    max_len_status = (int)len;

	s = g_strdup_printf("%d/%d", output_find_result->partnum,
				     output_find_result->totalparts);
	len=strlen(s);
	if((int)len > max_len_part)
	    max_len_part = (int)len;
	amfree(s);
    }

    /*
     * Since status is the rightmost field, we zap the maximum length
     * because it is not needed.  The code is left in place in case
     * another column is added later.
     */
    max_len_status = 1;

    if(output_find==NULL) {
	g_printf(_("\nNo dump to list\n"));
    }
    else {
	g_printf(_("\ndate%*s host%*s disk%*s lv%*s storage%*s tape or file%*s file%*s part%*s status\n"),
	       max_len_datestamp-4,"",
	       max_len_hostname-4 ,"",
	       max_len_diskname-4 ,"",
	       max_len_level-2    ,"",
	       max_len_storage-7  ,"",
	       max_len_label-12   ,"",
	       max_len_filenum-4  ,"",
	       max_len_part-4  ,"");
        for(output_find_result=output_find;
	        output_find_result;
	        output_find_result=output_find_result->next) {
	    char *qdiskname;
            char * formatted_label;
	    char *s;
	    char *status;

	    qdiskname = quote_string(output_find_result->diskname);
            if (output_find_result->label == NULL)
                formatted_label = g_strdup("");
	    else
		formatted_label = quote_string(output_find_result->label);

	    if (!g_str_equal(output_find_result->status, "OK") ||
		!g_str_equal(output_find_result->dump_status, "OK")) {
		status = g_strjoin(NULL, output_find_result->status, " ",
				   output_find_result->dump_status, NULL);
	    } else {
		status = g_strdup(output_find_result->status);
	    }

	    /*@ignore@*/
	    /* sec and kb are omitted here, for compatibility with the existing
	     * output from 'amadmin' */
	    s = g_strdup_printf("%d/%d", output_find_result->partnum,
					 output_find_result->totalparts);
	    g_printf("%-*s %-*s %-*s %*d %-*s %-*s %*lld %*s %s %s\n",
                     max_len_datestamp,
                     find_nicedate(output_find_result->timestamp),
                     max_len_hostname,  output_find_result->hostname,
                     max_len_diskname,  qdiskname,
                     max_len_level,     output_find_result->level,
                     max_len_storage,   output_find_result->storage,
                     max_len_label,     formatted_label,
                     max_len_filenum,   (long long)output_find_result->filenum,
                     max_len_part,      s,
                                        status,
					output_find_result->message
		    );
	    amfree(status);
	    amfree(s);
	    /*@end@*/
	    amfree(qdiskname);
	    amfree(formatted_label);
	}
    }
}
Example #27
0
char *
build_header(const dumpfile_t * file, size_t *size, size_t max_size)
{
    GString *rval, *split_data;
    char *qname;
    char *program;
    size_t min_size;

    min_size = size? *size : max_size;
    g_debug(_("Building type %s header of %zu-%zu bytes with name='%s' disk='%s' dumplevel=%d and blocksize=%zu"),
	    filetype2str(file->type), min_size, max_size,
	    file->name, file->disk, file->dumplevel, file->blocksize);

    rval = g_string_sized_new(min_size);
    split_data = g_string_sized_new(10);

    switch (file->type) {
    case F_TAPESTART:
	validate_nonempty_str(file->name, "name");
	validate_datestamp(file->datestamp);
        g_string_printf(rval,
                        "AMANDA: TAPESTART DATE %s TAPE %s\n\014\n",
                        file->datestamp, file->name);
	break;

    case F_SPLIT_DUMPFILE:
	validate_parts(file->partnum, file->totalparts);
        g_string_printf(split_data,
                        " part %d/%d ", file->partnum, file->totalparts);
        /* FALLTHROUGH */

    case F_CONT_DUMPFILE:
    case F_DUMPFILE :
	validate_nonempty_str(file->name, "name");
	validate_nonempty_str(file->program, "program");
	validate_datestamp(file->datestamp);
	validate_encrypt_suffix(file->encrypted, file->encrypt_suffix);
	qname = quote_string(file->disk);
	program = g_strdup(file->program);
	if (match("^.*[.][Ee][Xx][Ee]$", program)) {
		/* Trim ".exe" from program name */
		program[strlen(program) - strlen(".exe")] = '\0';
	}
        g_string_printf(rval, 
                        "AMANDA: %s %s %s %s %s lev %d comp %s program %s",
                        filetype2str(file->type),
                        file->datestamp, file->name, qname,
                        split_data->str,
                        file->dumplevel,
			file->compressed? file->comp_suffix : "N",
			program); 
	amfree(program);
	amfree(qname);

        /* only output crypt if it's enabled */
	if (file->encrypted) {
	    g_string_append_printf(rval, " crypt %s", file->encrypt_suffix);
	}

	validate_not_both(file->srvcompprog, file->clntcompprog,
			    "srvcompprog", "clntcompprog");
	if (*file->srvcompprog) {
	    validate_no_space(file->srvcompprog, "srvcompprog");
            g_string_append_printf(rval, " server_custom_compress %s",
                                   file->srvcompprog);
	} else if (*file->clntcompprog) {
	    validate_no_space(file->clntcompprog, "clntcompprog");
            g_string_append_printf(rval, " client_custom_compress %s",
                                   file->clntcompprog);
	}

	validate_not_both(file->srv_encrypt, file->clnt_encrypt,
			    "srv_encrypt", "clnt_encrypt");
	if (*file->srv_encrypt) {
	    validate_no_space(file->srv_encrypt, "srv_encrypt");
            g_string_append_printf(rval, " server_encrypt %s",
                                   file->srv_encrypt);
	} else if (*file->clnt_encrypt) {
	    validate_no_space(file->clnt_encrypt, "clnt_encrypt");
            g_string_append_printf(rval, " client_encrypt %s",
                                   file->clnt_encrypt);
	}

	validate_not_both(file->srv_decrypt_opt, file->clnt_decrypt_opt,
			    "srv_decrypt_opt", "clnt_decrypt_opt");
	if (*file->srv_decrypt_opt) {
	    validate_no_space(file->srv_decrypt_opt, "srv_decrypt_opt");
            g_string_append_printf(rval, " server_decrypt_option %s",
                                   file->srv_decrypt_opt);
        } else if (*file->clnt_decrypt_opt) {
            g_string_append_printf(rval, " client_decrypt_option %s",
                                   file->clnt_decrypt_opt);
	} 
        
        g_string_append_printf(rval, "\n");
        
	if (file->cont_filename[0] != '\0') {
            g_string_append_printf(rval, "CONT_FILENAME=%s\n",
                                   file->cont_filename);
	}
	if (file->application[0] != '\0') {
            g_string_append_printf(rval, "APPLICATION=%s\n", file->application);
	}
	if (file->is_partial != 0) {
            g_string_append_printf(rval, "PARTIAL=YES\n");
	}
	if (file->orig_size > 0) {
	    g_string_append_printf(rval, "ORIGSIZE=%jd\n",
					 (intmax_t)file->orig_size);
	}
	if (file->dle_str && strlen(file->dle_str) < max_size-2048) {
	    char *heredoc = quote_heredoc(file->dle_str, "ENDDLE");
	    g_string_append_printf(rval, "DLE=%s\n", heredoc);
	    amfree(heredoc);
	}
        
        g_string_append_printf(rval,
	    _("To restore, position tape at start of file and run:\n"));

        g_string_append_printf(rval, "\tdd if=<tape> ");
	if (file->blocksize)
	    g_string_append_printf(rval, "bs=%zuk ",
				   file->blocksize / 1024);
	g_string_append_printf(rval, "skip=1 | ");
	if (*file->recover_cmd) {
	    if (*file->decrypt_cmd) {
		validate_pipe_cmd(file->decrypt_cmd, "decrypt_cmd");
		g_string_append_printf(rval, "%s ", file->decrypt_cmd);
	    }
	    if (*file->uncompress_cmd) {
		validate_pipe_cmd(file->uncompress_cmd, "uncompress_cmd");
		g_string_append_printf(rval, "%s ", file->uncompress_cmd);
	    }
	    g_string_append_printf(rval, "%s ", file->recover_cmd);
	} else {
	    if (*file->uncompress_cmd || *file->decrypt_cmd)
		error("cannot specify uncompress_cmd or decrypt_cmd without recover_cmd\n");
	}
	/* \014 == ^L == form feed */
	g_string_append_printf(rval, "\n\014\n");
	break;

    case F_TAPEEND:
	validate_datestamp(file->datestamp);
        g_string_printf(rval, "AMANDA: TAPEEND DATE %s\n\014\n",
                        file->datestamp);
	break;

    case F_NOOP:
        g_string_printf(rval, "AMANDA: NOOP\n\014\n");
	break;

    case F_UNKNOWN:
    case F_EMPTY:
    case F_WEIRD:
    default:
	error(_("Invalid header type: %d (%s)"),
		file->type, filetype2str(file->type));
	/*NOTREACHED*/
    }
    
    g_string_free(split_data, TRUE);

    /* is it too big? */
    if (rval->len > max_size) {
	g_debug("header is larger than %zu bytes -- cannot create", max_size);
	g_string_free(rval, TRUE);
	return NULL;
    }

    /* Clear extra bytes. */
    if (rval->len < min_size) {
        bzero(rval->str + rval->len, rval->allocated_len - rval->len);
    }
    if (size) {
	*size = MAX(min_size, (size_t)rval->len);
    }
    return g_string_free(rval, FALSE);
}
Example #28
0
find_result_t * find_dump(disklist_t* diskqp) {
    char *conf_logdir, *logfile = NULL;
    int tape, maxtape, logs;
    unsigned seq;
    tape_t *tp;
    find_result_t *output_find = NULL;
    GHashTable *tape_seen = g_hash_table_new(g_str_hash, g_str_equal);

    if (string_chunk == NULL) {
	string_chunk = g_string_chunk_new(32768);
    }
    conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
    maxtape = lookup_nb_tape();

    for(tape = 1; tape <= maxtape; tape++) {

	tp = lookup_tapepos(tape);
	if(tp == NULL) continue;

	/* Do not search the log file if we already searched that datestamp */
	if (g_hash_table_lookup(tape_seen, tp->datestamp)) {
	    continue;
	}
	g_hash_table_insert(tape_seen, tp->datestamp, GINT_TO_POINTER(1));

	/* search log files */

	logs = 0;

	/* new-style log.<date>.<seq> */

	for(seq = 0; 1; seq++) {
	    char seq_str[NUM_STR_SIZE];

	    g_snprintf(seq_str, sizeof(seq_str), "%u", seq);
	    g_free(logfile);
	    logfile = g_strconcat(conf_logdir, "/log.", tp->datestamp, ".",
	        seq_str, NULL);
	    if(access(logfile, R_OK) != 0) break;
	    if (search_logfile(&output_find, NULL, tp->datestamp,
                               logfile, diskqp)) {
                logs ++;
            }
	}

	/* search old-style amflush log, if any */

	g_free(logfile);
	logfile = g_strconcat(conf_logdir, "/log.", tp->datestamp, ".amflush",
	    NULL);
	if(access(logfile,R_OK) == 0) {
	    if (search_logfile(&output_find, NULL, tp->datestamp,
                               logfile, diskqp)) {
                logs ++;
            }
        }
        
	/* search old-style main log, if any */

	g_free(logfile);
	logfile = g_strconcat(conf_logdir, "/log.", tp->datestamp, NULL);
	if(access(logfile,R_OK) == 0) {
	    if (search_logfile(&output_find, NULL, tp->datestamp,
                               logfile, diskqp)) {
                logs ++;
            }
	}
    }
    g_hash_table_destroy(tape_seen);
    amfree(logfile);
    amfree(conf_logdir);

    search_holding_disk(&output_find, diskqp);

    return(output_find);
}
Example #29
0
void
parse_file_header(
    const char *buffer,
    dumpfile_t *file,
    size_t	buflen)
{
    char *buf, *line, *tok, *line1;
    size_t lsize;
    char *uqname;
    int in_quotes;
    char *saveptr = NULL;

    /* put the buffer into a writable chunk of memory and nul-term it */
    buf = g_malloc(buflen + 1);
    memcpy(buf, buffer, buflen);
    buf[buflen] = '\0';
    fh_init(file); 

    /* extract the first unquoted line */
    in_quotes = 0;
    for (line = buf, lsize = 0; lsize < buflen; line++) {
	if ((*line == '\n') && !in_quotes)
	    break;

	if (*line == '"') {
	    in_quotes = !in_quotes;
	} else if ((*line == '\\') && (*(line + 1) == '"')) {
	    line++;
	    lsize++;
	}
	lsize++;
    }
    *line = '\0';
    line1 = g_malloc(lsize + 1);
    strncpy(line1, buf, lsize);
    line1[lsize] = '\0';
    *line = '\n';

    tok = strtok_r(line1, " ", &saveptr);
    if (tok == NULL) {
        g_debug("Empty amanda header: buflen=%zu lsize=%zu buf='%s'", buflen, lsize, buf);
	strange_header(file, buffer, buflen, _("<Non-empty line>"), tok);
	goto out;
    }

    if (!g_str_equal(tok, "NETDUMP:") && !g_str_equal(tok, "AMANDA:")) {
	amfree(buf);
	file->type = F_WEIRD;
	amfree(line1);
	return;
    }

    tok = strtok_r(NULL, " ", &saveptr);
    if (tok == NULL) {
	strange_header(file, buffer, buflen, _("<file type>"), tok);
	goto out;
    }
    file->type = str2filetype(tok);
    
    switch (file->type) {
    case F_TAPESTART:
	tok = strtok_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (!g_str_equal(tok, "DATE"))) {
	    strange_header(file, buffer, buflen, "DATE", tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<date stamp>"), tok);
	    goto out;
	}
	strncpy(file->datestamp, tok, sizeof(file->datestamp) - 1);
	file->datestamp[sizeof(file->datestamp) - 1] = '\0';

	tok = strtok_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (!g_str_equal(tok, "TAPE"))) {
	    strange_header(file, buffer, buflen, "TAPE", tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<file type>"), tok);
	    goto out;
	}
	strncpy(file->name, tok, sizeof(file->name) - 1);
	file->name[sizeof(file->name) - 1] = '\0';
	break;

    case F_DUMPFILE:
    case F_CONT_DUMPFILE:
    case F_SPLIT_DUMPFILE:
	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<date stamp>"), tok);
	    goto out;
	}
	strncpy(file->datestamp, tok, sizeof(file->datestamp) - 1);
	file->datestamp[sizeof(file->datestamp) - 1] = '\0';

	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<file name>"), tok);
	    goto out;
	}
	strncpy(file->name, tok, sizeof(file->name) - 1);
	file->name[sizeof(file->name) - 1] = '\0';

	tok = strquotedstr(&saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<disk name>"), tok);
	    goto out;
	}
	uqname = unquote_string(tok);
	strncpy(file->disk, uqname, sizeof(file->disk) - 1);
	file->disk[sizeof(file->disk) - 1] = '\0';
 	amfree(uqname);
	
	if(file->type == F_SPLIT_DUMPFILE) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL || !g_str_equal(tok, "part")) {
		strange_header(file, buffer, buflen, "part", tok);
		goto out;
	    }

	    tok = strtok_r(NULL, "/", &saveptr);
	    if ((tok == NULL) || (sscanf(tok, "%d", &file->partnum) != 1)) {
		strange_header(file, buffer, buflen, _("<part num param>"), tok);
		goto out;
	    }

	    /* If totalparts == -1, then the original dump was done in 
 	       streaming mode (no holding disk), thus we don't know how 
               many parts there are. */
	    tok = strtok_r(NULL, " ", &saveptr);
            if((tok == NULL) || (sscanf(tok, "%d", &file->totalparts) != 1)) {
		strange_header(file, buffer, buflen, _("<total parts param>"), tok);
		goto out;
	    }
	} else if (file->type == F_DUMPFILE) {
	    /* only one part in this dump, so call it partnum 1 */
	    file->partnum = 1;
	    file->totalparts = 1;
	} else {
	    file->partnum = 0;
	    file->totalparts = 0;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (!g_str_equal(tok, "lev"))) {
	    strange_header(file, buffer, buflen, "lev", tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (sscanf(tok, "%d", &file->dumplevel) != 1)) {
	    strange_header(file, buffer, buflen, _("<dump level param>"), tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if ((tok == NULL) || (!g_str_equal(tok, "comp"))) {
	    strange_header(file, buffer, buflen, "comp", tok);
	    goto out;
	}

	tok = strtok_r(NULL, " ", &saveptr);
	if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<comp param>"), tok);
	    goto out;
	}
	strncpy(file->comp_suffix, tok, sizeof(file->comp_suffix) - 1);

	file->compressed = (!g_str_equal(file->comp_suffix, "N"));
	if (file->compressed) {
	    /* compatibility with pre-2.2 amanda */
	    if (g_str_equal(file->comp_suffix, "C"))
		strncpy(file->comp_suffix, ".Z", sizeof(file->comp_suffix) - 1);
	} else {
	    strcpy(file->comp_suffix, "");
	}
	file->comp_suffix[sizeof(file->comp_suffix) - 1] = '\0';

	tok = strtok_r(NULL, " ", &saveptr);
        /* "program" is optional */
        if (tok == NULL || !g_str_equal(tok, "program")) {
	    break;
	}

        tok = strtok_r(NULL, " ", &saveptr);
        if (tok == NULL) {
	    strange_header(file, buffer, buflen, _("<program name>"), tok);
	    goto out;
	}
        strncpy(file->program, tok, sizeof(file->program) - 1);
	file->program[sizeof(file->program) - 1] = '\0';

	if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
             break;          /* reached the end of the buffer */

	/* encryption is optional */
	if (BSTRNCMP(tok, "crypt") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen, _("<crypt param>"), tok);
		goto out;
	    }
	    strncpy(file->encrypt_suffix, tok,
		    sizeof(file->encrypt_suffix) - 1);
	    file->encrypt_suffix[sizeof(file->encrypt_suffix) - 1] = '\0';
	    file->encrypted = 1;

	    /* for compatibility with who-knows-what, allow "comp N" to be
	     * equivalent to no compression */
	    if (0 == BSTRNCMP(file->encrypt_suffix, "N")) {
		file->encrypted = 0;
		strcpy(file->encrypt_suffix, "");
	    }

	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
		break;
	}

	/* "srvcompprog" is optional */
	if (BSTRNCMP(tok, "server_custom_compress") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<server custom compress param>"), tok);
		goto out;
	    }
	    strncpy(file->srvcompprog, tok, sizeof(file->srvcompprog) - 1);
	    file->srvcompprog[sizeof(file->srvcompprog) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
		break;      
	}

	/* "clntcompprog" is optional */
	if (BSTRNCMP(tok, "client_custom_compress") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<client custom compress param>"), tok);
		goto out;
	    }
	    strncpy(file->clntcompprog, tok, sizeof(file->clntcompprog) - 1);
	    file->clntcompprog[sizeof(file->clntcompprog) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL)
		break;
	}

	/* "srv_encrypt" is optional */
	if (BSTRNCMP(tok, "server_encrypt") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<server encrypt param>"), tok);
		goto out;
	    }
	    strncpy(file->srv_encrypt, tok, sizeof(file->srv_encrypt) - 1);
	    file->srv_encrypt[sizeof(file->srv_encrypt) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL) 
		break;
	}

	/* "clnt_encrypt" is optional */
	if (BSTRNCMP(tok, "client_encrypt") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<client encrypt param>"), tok);
		goto out;
	    }
	    strncpy(file->clnt_encrypt, tok, sizeof(file->clnt_encrypt) - 1);
	    file->clnt_encrypt[sizeof(file->clnt_encrypt) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL) 
		break;
	}

	/* "srv_decrypt_opt" is optional */
	if (BSTRNCMP(tok, "server_decrypt_option") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<server decrypt param>"), tok);
		goto out;
	    }
	    strncpy(file->srv_decrypt_opt, tok,
		    sizeof(file->srv_decrypt_opt) - 1);
	    file->srv_decrypt_opt[sizeof(file->srv_decrypt_opt) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL) 
		break;
	}

	/* "clnt_decrypt_opt" is optional */
	if (BSTRNCMP(tok, "client_decrypt_option") == 0) {
	    tok = strtok_r(NULL, " ", &saveptr);
	    if (tok == NULL) {
		strange_header(file, buffer, buflen,
				_("<client decrypt param>"), tok);
		goto out;
	    }
	    strncpy(file->clnt_decrypt_opt, tok,
		    sizeof(file->clnt_decrypt_opt) - 1);
	    file->clnt_decrypt_opt[sizeof(file->clnt_decrypt_opt) - 1] = '\0';
	    if ((tok = strtok_r(NULL, " ", &saveptr)) == NULL) 
		break;
	}
      break;
      

    case F_TAPEEND:
	tok = strtok_r(NULL, " ", &saveptr);
	/* DATE is optional */
	if (tok != NULL) {
	    if (g_str_equal(tok, "DATE")) {
		tok = strtok_r(NULL, " ", &saveptr);
		if(tok == NULL)
		    file->datestamp[0] = '\0';
		else {
		    strncpy(file->datestamp, tok, sizeof(file->datestamp) - 1);
		    file->datestamp[sizeof(file->datestamp) - 1] = '\0';
		}
	    } else {
		strange_header(file, buffer, buflen, _("<DATE>"), tok);
	   }
	} else {
	    file->datestamp[0] = '\0';
	}
	break;

    case F_NOOP:
	/* nothing follows */
	break;

    default:
	strange_header(file, buffer, buflen,
		_("TAPESTART|DUMPFILE|CONT_DUMPFILE|SPLIT_DUMPFILE|TAPEEND|NOOP"), tok);
	goto out;
    }

    (void)strtok_r(buf, "\n", &saveptr); /* this is the first line */
    /* iterate through the rest of the lines */
    while ((line = strtok_r(NULL, "\n", &saveptr)) != NULL) {
#define SC "CONT_FILENAME="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    strncpy(file->cont_filename, line,
		    sizeof(file->cont_filename) - 1);
	    file->cont_filename[sizeof(file->cont_filename) - 1] = '\0';
	    continue;
	}
#undef SC

#define SC "PARTIAL="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    file->is_partial = !strcasecmp(line, "yes");
	    continue;
	}
#undef SC
#define SC "APPLICATION="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    strncpy(file->application, line,
		    sizeof(file->application) - 1);
	    file->application[sizeof(file->application) - 1] = '\0';
	    continue;
	}
#undef SC

#define SC "ORIGSIZE="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    file->orig_size = OFF_T_ATOI(line);
	}
#undef SC

#define SC "DLE="
	if (g_str_has_prefix(line, SC)) {
	    line += sizeof(SC) - 1;
	    amfree(file->dle_str);
	    file->dle_str = parse_heredoc(line, &saveptr);
	}
#undef SC

#define SC _("To restore, position tape at start of file and run:")
	if (g_str_has_prefix(line, SC))
	    continue;
#undef SC

#define SC "\tdd if=<tape> "
	if (g_str_has_prefix(line, SC)) {
	    char *cmd1, *cmd2, *cmd3=NULL;

	    /* skip over dd command */
	    if ((cmd1 = strchr(line, '|')) == NULL) {

	        strncpy(file->recover_cmd, "BUG\0",
		        sizeof(file->recover_cmd) - 1);
	        continue;
	    }
	    *cmd1++ = '\0';

	    /* block out first pipeline command */
	    if ((cmd2 = strchr(cmd1, '|')) != NULL) {
	      *cmd2++ = '\0';
	      if ((cmd3 = strchr(cmd2, '|')) != NULL)
		*cmd3++ = '\0';
	    }

	    /* clean up some extra spaces in various fields */
	    chomp(cmd1);
	    chomp(cmd2);
	    chomp(cmd3);

	    /* three cmds: decrypt    | uncompress | recover
	     * two   cmds: uncompress | recover
	     * XXX note that if there are two cmds, the first one 
	     * XXX could be either uncompress or decrypt. Since no
	     * XXX code actually call uncompress_cmd/decrypt_cmd, it's ok
	     * XXX for header information.
	     * one   cmds: recover
	     */

	    if ( cmd3 == NULL) {
	      if (cmd2 == NULL) {
		strncpy(file->recover_cmd, cmd1,
			sizeof(file->recover_cmd) - 1);
	      } else {
		g_snprintf(file->uncompress_cmd,
			 sizeof(file->uncompress_cmd), "%s |", cmd1);
		strncpy(file->recover_cmd, cmd2,
			sizeof(file->recover_cmd) - 1);
	      }
	    } else {    /* cmd3 presents:  decrypt | uncompress | recover */
	      g_snprintf(file->decrypt_cmd,
		       sizeof(file->decrypt_cmd), "%s |", cmd1);
	      g_snprintf(file->uncompress_cmd,
		       sizeof(file->uncompress_cmd), "%s |", cmd2);
	      strncpy(file->recover_cmd, cmd3,
		      sizeof(file->recover_cmd) - 1);
	    }
	    file->recover_cmd[sizeof(file->recover_cmd) - 1] = '\0';
	    file->uncompress_cmd[sizeof(file->uncompress_cmd) - 1] = '\0';
	    continue;
	}
#undef SC
	/* XXX complain about weird lines? */
    }

out:
    amfree(buf);
    amfree(line1);
}
Example #30
0
int
main(
    int		argc,
    char **	argv)
{
#ifdef GNUTAR
    int i;
    char *e;
    char *dbf;
    char *cmdline;
    GPtrArray *array = g_ptr_array_new();
    gchar **strings;
    char **new_argv;
    char **env;
#endif

    if (argc > 1 && argv[1] && g_str_equal(argv[1], "--version")) {
	printf("runtar-%s\n", VERSION);
	return (0);
    }

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

    safe_fd(-1, 0);
    safe_cd();

    set_pname("runtar");

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

    dbopen(DBG_SUBDIR_CLIENT);
    config_init(CONFIG_INIT_CLIENT|CONFIG_INIT_GLOBAL, NULL);

    if (argc < 3) {
	error(_("Need at least 3 arguments\n"));
	/*NOTREACHED*/
    }

    dbprintf(_("version %s\n"), VERSION);

    if (!g_str_equal(argv[3], "--create")) {
	error(_("Can only be used to create tar archives\n"));
	/*NOTREACHED*/
    }

#ifndef GNUTAR

    g_fprintf(stderr,_("gnutar not available on this system.\n"));
    dbprintf(_("%s: gnutar not available on this system.\n"), argv[0]);
    dbclose();
    return 1;

#else

    /*
     * Print out version information for tar.
     */
    do {
	FILE *	version_file;
	char	version_buf[80];

	if ((version_file = popen(GNUTAR " --version 2>&1", "r")) != NULL) {
	    if (fgets(version_buf, (int)sizeof(version_buf), version_file) != NULL) {
		dbprintf(_(GNUTAR " version: %s\n"), version_buf);
	    } else {
		if (ferror(version_file)) {
		    dbprintf(_(GNUTAR " version: Read failure: %s\n"), strerror(errno));
		} else {
		    dbprintf(_(GNUTAR " version: Read failure; EOF\n"));
		}
	    }
	} else {
	    dbprintf(_(GNUTAR " version: unavailable: %s\n"), strerror(errno));
	}
    } while(0);

#ifdef WANT_SETUID_CLIENT
    check_running_as(RUNNING_AS_CLIENT_LOGIN | RUNNING_AS_UID_ONLY);
    if (!become_root()) {
	error(_("error [%s could not become root (is the setuid bit set?)]\n"), get_pname());
	/*NOTREACHED*/
    }
#else
    check_running_as(RUNNING_AS_CLIENT_LOGIN);
#endif

    /* skip argv[0] */
    argc--;
    argv++;

    dbprintf(_("config: %s\n"), argv[0]);
    if (!g_str_equal(argv[0], "NOCONFIG"))
	dbrename(argv[0], DBG_SUBDIR_CLIENT);
    argc--;
    argv++;

    new_argv = g_new0(char *, argc+1);

    new_argv[0] = g_strdup_printf("%s", argv[0]);
    g_ptr_array_add(array, g_strdup(GNUTAR));
    for (i = 1; argv[i]; i++) {
        g_ptr_array_add(array, quote_string(argv[i]));
	new_argv[i] = g_strdup_printf("%s", argv[i]);
    }

    g_ptr_array_add(array, NULL);
    strings = (gchar **)g_ptr_array_free(array, FALSE);

    cmdline = g_strjoinv(" ", strings);
    g_strfreev(strings);

    dbprintf(_("running: %s\n"), cmdline);
    amfree(cmdline);

    dbf = dbfn();
    if (dbf) {
	dbf = g_strdup(dbf);
    }
    dbclose();

    env = safe_env();
    execve(GNUTAR, new_argv, env);
    free_env(env);

    e = strerror(errno);
    dbreopen(dbf, "more");
    amfree(dbf);
    dbprintf(_("execve of %s failed (%s)\n"), GNUTAR, e);
    dbclose();

    g_fprintf(stderr, _("runtar: could not exec %s: %s\n"), GNUTAR, e);
    return 1;
#endif
}