main(
    int		argc,
    char **	argv)
{
    int c;
    char *command;
    application_argument_t argument;
    int i;
    char *gnutar_onefilesystem_value = NULL;
    char *gnutar_sparse_value = NULL;
    char *gnutar_atimepreserve_value = NULL;
    char *gnutar_checkdevice_value = NULL;
    char *gnutar_no_unquote_value = NULL;

#ifdef GNUTAR
    gnutar_path = g_strdup(GNUTAR);
#else
    gnutar_path = NULL;
#endif
    gnutar_listdir = NULL;
    gnutar_directory = NULL;
    gnutar_onefilesystem = 1;
    gnutar_atimepreserve = 1;
    gnutar_acls = 0;
    gnutar_selinux = 0;
    gnutar_xattrs = 0;
    gnutar_checkdevice = 1;
    gnutar_sparse = 1;
    gnutar_no_unquote = 0;
    exit_handling = 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 amgtar\n");
        error(_("No command given to amgtar"));
    }

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

    set_pname("amgtar");
    set_pcomponent("application");
    set_pmodule("amgtar");

    /* 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|CONFIG_INIT_GLOBAL, NULL);

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

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

    if (strcasecmp(command,"selfcheck") == 0) {
	fprintf(stdout, "MESSAGE JSON\n");
    }
    argument.config     = NULL;
    argument.host       = NULL;
    argument.message    = 0;
    argument.collection = 0;
    argument.calcsize   = 0;
    argument.tar_blocksize = NULL;
    argument.level      = NULL;
    argument.command_options = NULL;
    argument.include_list_glob = NULL;
    argument.exclude_list_glob = NULL;
    argument.verbose = 0;
    argument.ignore_zeros = 1;
    argument.amfeatures = NULL;
    argument.recover_dump_state_file = NULL;
    argument.dar        = FALSE;
    argument.state_stream = -1;
    init_dle(&argument.dle);
    argument.dle.record = 0;

    while (1) {
	int option_index = 0;
	c = getopt_long (argc, argv, "", long_options, &option_index);
	if (c == -1) {
	    break;
	}
	switch (c) {
	case 1: amfree(argument.config);
		argument.config = g_strdup(optarg);
		break;
	case 2: amfree(argument.host);
		argument.host = g_strdup(optarg);
		break;
	case 3: amfree(argument.dle.disk);
		argument.dle.disk = g_strdup(optarg);
		break;
	case 4: amfree(argument.dle.device);
		argument.dle.device = g_strdup(optarg);
		break;
	case 5: 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: amfree(gnutar_path);
		 gnutar_path = g_strdup(optarg);
		 break;
	case 11: amfree(gnutar_listdir);
		 gnutar_listdir = g_strdup(optarg);
		 break;
	case 12: if (strcasecmp(optarg, "NO") == 0)
		     gnutar_onefilesystem = 0;
		 else if (strcasecmp(optarg, "YES") == 0)
		     gnutar_onefilesystem = 1;
		 else if (strcasecmp(command, "selfcheck") == 0) {
		     gnutar_onefilesystem = 2;
		     gnutar_onefilesystem_value = g_strdup(optarg);
		 }
		 break;
	case 13: gnutar_sparse_set = 1;
		 if (strcasecmp(optarg, "NO") == 0)
		     gnutar_sparse = 0;
		 else if (strcasecmp(optarg, "YES") == 0)
		     gnutar_sparse = 1;
		 else if (strcasecmp(command, "selfcheck") == 0) {
		     gnutar_sparse = 2;
		     gnutar_sparse_value = g_strdup(optarg);
		 }
		 break;
	case 14: if (strcasecmp(optarg, "NO") == 0)
		     gnutar_atimepreserve = 0;
		 else if (strcasecmp(optarg, "YES") == 0)
		     gnutar_atimepreserve = 1;
		 else if (strcasecmp(command, "selfcheck") == 0) {
		     gnutar_atimepreserve = 2;
		     gnutar_atimepreserve_value = g_strdup(optarg);
		 }
		 break;
	case 15: if (strcasecmp(optarg, "NO") == 0)
		     gnutar_checkdevice = 0;
		 else if (strcasecmp(optarg, "YES") == 0)
		     gnutar_checkdevice = 1;
		 else if (strcasecmp(command, "selfcheck") == 0) {
		     gnutar_checkdevice = 2;
		     gnutar_checkdevice_value = g_strdup(optarg);
		 }
		 break;
	case 16: argument.dle.include_file =
			 append_sl(argument.dle.include_file, optarg);
		 break;
	case 17: argument.dle.include_list =
			 append_sl(argument.dle.include_list, optarg);
		 break;
	case 18: argument.dle.include_optional = 1;
		 break;
	case 19: argument.dle.exclude_file =
			 append_sl(argument.dle.exclude_file, optarg);
		 break;
	case 20: argument.dle.exclude_list =
			 append_sl(argument.dle.exclude_list, optarg);
		 break;
	case 21: argument.dle.exclude_optional = 1;
		 break;
	case 22: amfree(gnutar_directory);
		 gnutar_directory = g_strdup(optarg);
		 break;
	case 23: normal_message =
			 g_slist_append(normal_message, optarg);
		 break;
	case 24: ignore_message =
			 g_slist_append(ignore_message, optarg);
		 break;
	case 25: strange_message =
			 g_slist_append(strange_message, optarg);
		 break;
	case 26: amfree(exit_handling);
		 exit_handling = g_strdup(optarg);
		 break;
	case 27: argument.calcsize = 1;
		 break;
	case 28: amfree(argument.tar_blocksize);
		 argument.tar_blocksize = g_strdup(optarg);
		 break;
	case 29: if (strcasecmp(optarg, "NO") == 0)
		     gnutar_no_unquote = 0;
		 else if (strcasecmp(optarg, "YES") == 0)
		     gnutar_no_unquote = 1;
		 else if (strcasecmp(command, "selfcheck") == 0) {
		     gnutar_no_unquote = 2;
		     gnutar_no_unquote_value = g_strdup(optarg);
		 }
		 break;
        case 30: if (strcasecmp(optarg, "YES") == 0)
                   gnutar_acls = 1;
                 break;
        case 31: if (strcasecmp(optarg, "YES") == 0)
                   gnutar_selinux = 1;
                 break;
        case 32: if (strcasecmp(optarg, "YES") == 0)
                   gnutar_xattrs = 1;
                 break;
	case 33: argument.command_options =
			g_slist_append(argument.command_options,
				       g_strdup(optarg));
		 break;
	case 34: amfree(argument.include_list_glob);
		 argument.include_list_glob = g_strdup(optarg);
		 break;
	case 35: amfree(argument.exclude_list_glob);
		 argument.exclude_list_glob = g_strdup(optarg);
		 break;
	case 36: if (strcasecmp(optarg, "YES") == 0)
		     argument.verbose = 1;
		 break;
	case 37: if (strcasecmp(optarg, "YES") != 0)
		     argument.ignore_zeros = 0;
		 break;
	case 38: amfree(argument.amfeatures);
		 argument.amfeatures = am_string_to_feature(optarg);
		 break;
	case 39: amfree(argument.recover_dump_state_file);
		 argument.recover_dump_state_file = g_strdup(optarg);
		 break;
	case 40: if (strcasecmp(optarg, "NO") == 0)
		     argument.dar = FALSE;
		 else if (strcasecmp(optarg, "YES") == 0)
		     argument.dar = TRUE;
		 else if (strcasecmp(command, "selfcheck") == 0)
		     printf(_("ERROR [%s: bad DAR property value (%s)]\n"), get_pname(), optarg);
		 break;
	case 41: argument.state_stream = atoi(optarg);
		 break;
	case ':':
	case '?':
		break;
	}
    }

    if ((g_str_equal(command, "backup") ||
	 g_str_equal(command, "restore")) && argument.state_stream >= 0) {
	g_debug("state_stream: %d", argument.state_stream);
	safe_fd3(3, 2, dbfd(), argument.state_stream);
    } else {
	safe_fd2(3, 2, dbfd());
    }

    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);
    if (!argument.dle.disk && !argument.dle.device) {
	argument.dle.disk = g_strdup("no disk");
	argument.dle.device = g_strdup("no device");
    }
    if (!argument.host)
	argument.host = g_strdup("no host");

    if (gnutar_onefilesystem == 2) {
	delete_message(print_message(build_message(
			AMANDA_FILE, __LINE__, 3700007, MSG_ERROR, 4,
			"value", gnutar_onefilesystem_value,
			"disk", argument.dle.disk,
			"device", argument.dle.device,
			"hostname", argument.host)));
    }

    if (gnutar_sparse == 2) {
	delete_message(print_message(build_message(
			AMANDA_FILE, __LINE__, 3700008, MSG_ERROR, 4,
			"value", gnutar_sparse_value,
			"disk", argument.dle.disk,
			"device", argument.dle.device,
			"hostname", argument.host)));
    }

    if (gnutar_atimepreserve == 2) {
	delete_message(print_message(build_message(
			AMANDA_FILE, __LINE__, 3700009, MSG_ERROR, 4,
			"value", gnutar_atimepreserve_value,
			"disk", argument.dle.disk,
			"device", argument.dle.device,
			"hostname", argument.host)));
    }

    if (gnutar_checkdevice == 2) {
	delete_message(print_message(build_message(
			AMANDA_FILE, __LINE__, 3700010, MSG_ERROR, 4,
			"value", gnutar_checkdevice_value,
			"disk", argument.dle.disk,
			"device", argument.dle.device,
			"hostname", argument.host)));
    }

    if (gnutar_no_unquote == 2) {
	delete_message(print_message(build_message(
			AMANDA_FILE, __LINE__, 3700011, MSG_ERROR, 4,
			"value", gnutar_no_unquote_value,
			"disk", argument.dle.disk,
			"device", argument.dle.device,
			"hostname", argument.host)));
    }

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

    if (argument.config) {
	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"));
    }

    if (!gnutar_listdir) {
	gnutar_listdir = g_strdup(getconf_str(CNF_GNUTAR_LIST_DIR));
    }

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

    for(i=0;i<256;i++)
	exit_value[i] = 1; /* BAD  */
    exit_value[0] = 0;     /* GOOD */
    exit_value[1] = 0;     /* GOOD */
    if (exit_handling) {
	char *s = exit_handling;
	while (s) {
	    char *r = strchr(s, '=');
	    if (r) {
		int j = atoi(s);
		if (j >= 0 && j < 256) {
		    r++;
		    if (strncasecmp(r, "GOOD", 4) == 0) {
			exit_value[j] = 0;
		    }
		}
	    }
	    s = strchr(s+1, ' ');
	}
    }

    if (strlen(gnutar_listdir) == 0)
	amfree(gnutar_listdir);

    if (gnutar_path) {
	dbprintf("GNUTAR-PATH %s\n", gnutar_path);
    } else {
	dbprintf("GNUTAR-PATH is not set\n");
    }
    if (gnutar_listdir) {
	    dbprintf("GNUTAR-LISTDIR %s\n", gnutar_listdir);
    } else {
	dbprintf("GNUTAR-LISTDIR is not set\n");
    }
    if (gnutar_directory) {
	dbprintf("DIRECTORY %s\n", gnutar_directory);
    }
    dbprintf("ONE-FILE-SYSTEM %s\n", gnutar_onefilesystem? "yes":"no");
    dbprintf("SPARSE %s\n", gnutar_sparse? "yes":"no");
    dbprintf("NO-UNQUOTE %s\n", gnutar_no_unquote? "yes":"no");
    dbprintf("ATIME-PRESERVE %s\n", gnutar_atimepreserve? "yes":"no");
    dbprintf("ACLS %s\n", gnutar_acls? "yes":"no");
    dbprintf("SELINUX %s\n", gnutar_selinux? "yes":"no");
    dbprintf("XATTRS %s\n", gnutar_xattrs? "yes":"no");
    dbprintf("CHECK-DEVICE %s\n", gnutar_checkdevice? "yes":"no");
    {
	amregex_t *rp;
	for (rp = re_table; rp->regex != NULL; rp++) {
	    switch (rp->typ) {
		case DMP_NORMAL : dbprintf("NORMAL %s\n", rp->regex); break;
		case DMP_IGNORE : dbprintf("IGNORE %s\n", rp->regex); break;
		case DMP_STRANGE: dbprintf("STRANGE %s\n", rp->regex); break;
		case DMP_SIZE   : dbprintf("SIZE %s\n", rp->regex); break;
		case DMP_ERROR  : dbprintf("ERROR %s\n", rp->regex); break;
	    }
	}
    }

    if (g_str_equal(command, "support")) {
	amgtar_support(&argument);
    } else if (g_str_equal(command, "selfcheck")) {
	amgtar_selfcheck(&argument);
    } else if (g_str_equal(command, "estimate")) {
	amgtar_estimate(&argument);
    } else if (g_str_equal(command, "backup")) {
	amgtar_backup(&argument);
    } else if (g_str_equal(command, "restore")) {
	amgtar_restore(&argument);
    } else if (g_str_equal(command, "validate")) {
	amgtar_validate(&argument);
    } else if (g_str_equal(command, "index")) {
	amgtar_index(&argument);
    } else if (g_str_equal(command, "discover")) {
       amgtar_discover(&argument);
    } else {
	dbprintf("Unknown command `%s'.\n", command);
	fprintf(stderr, "Unknown command `%s'.\n", command);
	exit (1);
    }

    g_free(argument.config);
    g_free(argument.host);
    g_free(argument.dle.disk);
    g_free(argument.dle.device);
    g_free(argument.tar_blocksize);
    g_slist_free(argument.level);

    dbclose();

    return 0;
}