/*
* Amanda, The Advanced Maryland Automatic Network Disk Archiver
* Copyright (c) 1991-1998 University of Maryland at College Park
* Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
* Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved.
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of U.M. not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. U.M. makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Authors: the Amanda Development Team. Its members are listed in a
* file named AUTHORS, in the root directory of this distribution.
*/
/*
* $Id: amstar.c 8888 2007-10-02 13:40:42Z martineau $
*
* send estimated backup sizes using dump
*/
/* PROPERTY:
*
* STAR-PATH (default STAR)
* STAR-TARDUMP
* STAR-DLE-TARDUMP
* ONE-FILE-SYSTEM
* SPARSE
* NORMAL
* IGNORE
* STRANGE
* INCLUDE-LIST (for restore only)
* EXCLUDE-FILE
* EXCLUDE-LIST
* TARGET
*/
#include "amanda.h"
#include "match.h"
#include "pipespawn.h"
#include "amfeatures.h"
#include "amandates.h"
#include "clock.h"
#include "amutil.h"
#include "getfsent.h"
#include "client_util.h"
#include "conffile.h"
#include "getopt.h"
#include "sendbackup.h"
#include "security-file.h"
#include "ammessage.h"
#include "event.h"
int debug_application = 1;
#define application_debug(i, ...) do { \
if ((i) <= debug_application) { \
dbprintf(__VA_ARGS__); \
} \
} while (0)
static amregex_t init_re_table[] = {
/* tar prints the size in bytes */
AM_SIZE_RE("star: [0-9][0-9]* blocks", 10240, 1),
AM_NORMAL_RE("^could not open conf file"),
AM_NORMAL_RE("^Type of this level "),
AM_NORMAL_RE("^Date of this level "),
AM_NORMAL_RE("^Date of last level "),
AM_NORMAL_RE("^Dump record level "),
AM_NORMAL_RE("^Throughput"),
AM_NORMAL_RE("^.*is sparse$"),
#ifdef IGNORE_TAR_ERRORS
AM_NORMAL_RE("^.*shrunk*$"),
AM_NORMAL_RE("^.*changed size.*$"),
AM_NORMAL_RE("^.*Cannot listxattr for.*$"),
AM_NORMAL_RE("^.Cannot: stat .*$"),
AM_NORMAL_RE("^.Missing links .*$"),
AM_NORMAL_RE("^.Cannot get xattr.*$"),
AM_NORMAL_RE("^.Cannot.*acl.*$"),
#endif
AM_NORMAL_RE("^star: dumped [0-9][0-9]* (tar )?files"),
AM_NORMAL_RE("^.*The following problems occurred during .* processing.*$"),
AM_NORMAL_RE("^.*Processed all possible files, despite earlier errors.*$"),
AM_NORMAL_RE("^.*not written due to problems during backup.*$"),
AM_STRANGE_RE("^Perform a level 0 dump first.*$"),
AM_ERROR_RE("amstar: error"),
/* catch-all: DMP_STRANGE is returned for all other lines */
AM_STRANGE_RE(NULL)
};
static amregex_t *re_table;
/* local functions */
int main(int argc, char **argv);
typedef struct application_argument_s {
char *config;
char *host;
int message;
int collection;
int calcsize;
GSList *level;
GSList *command_options;
dle_t dle;
int argc;
char **argv;
} application_argument_t;
enum { CMD_ESTIMATE, CMD_BACKUP };
static void amstar_support(application_argument_t *argument);
static void amstar_selfcheck(application_argument_t *argument);
static void amstar_estimate(application_argument_t *argument);
static void amstar_backup(application_argument_t *argument);
static void amstar_restore(application_argument_t *argument);
static void amstar_validate(application_argument_t *argument);
static void amstar_index(application_argument_t *argument);
static GPtrArray *amstar_build_argv(char *star_realpath,
application_argument_t *argument,
int level,
int command,
FILE *mesgstream);
static int check_device(application_argument_t *argument);
static char *command;
static char *star_path;
static char *star_tardumps;
static int star_dle_tardumps;
static int star_onefilesystem;
static int star_sparse;
static int star_acl;
static char *star_target;
static GSList *normal_message = NULL;
static GSList *ignore_message = NULL;
static GSList *strange_message = NULL;
static FILE *mesgstream = NULL;
static int amstar_exit_value = 0;
static struct option long_options[] = {
{"config" , 1, NULL, 1},
{"host" , 1, NULL, 2},
{"disk" , 1, NULL, 3},
{"device" , 1, NULL, 4},
{"level" , 1, NULL, 5},
{"index" , 1, NULL, 6},
{"message" , 1, NULL, 7},
{"collection" , 0, NULL, 8},
{"record" , 0, NULL, 9},
{"star-path" , 1, NULL, 10},
{"star-tardump" , 1, NULL, 11},
{"star-dle-tardump", 1, NULL, 12},
{"one-file-system" , 1, NULL, 13},
{"sparse" , 1, NULL, 14},
{"calcsize" , 0, NULL, 15},
{"normal" , 1, NULL, 16},
{"ignore" , 1, NULL, 17},
{"strange" , 1, NULL, 18},
{"include-list" , 1, NULL, 19},
{"exclude-list" , 1, NULL, 20},
{"directory" , 1, NULL, 21},
{"command-options" , 1, NULL, 22},
{"exclude-file" , 1, NULL, 23},
{"acl" , 1, NULL, 24},
{"include-file" , 1, NULL, 25},
{"target" , 1, NULL, 26},
{ NULL, 0, NULL, 0}
};
typedef struct filter_s {
int fd;
char *name;
char *buffer;
gint64 first; /* first byte used */
gint64 size; /* number of byte use in the buffer */
gint64 allocated_size; /* allocated size of the buffer */
event_handle_t *event;
int out;
} filter_t;
static void read_fd(int fd, char *name, event_fn_t fn);
static void read_text(void *cookie);
static void
read_fd(
int fd,
char *name,
event_fn_t fn)
{
filter_t *filter = g_new0(filter_t, 1);
filter->fd = fd;
filter->name = g_strdup(name);
filter->event = event_create((event_id_t)filter->fd, EV_READFD,
fn, filter);
event_activate(filter->event);
}
static void
read_text(
void *cookie)
{
filter_t *filter = cookie;
char *line;
char *p;
ssize_t nread;
int len;
if (filter->buffer == NULL) {
/* allocate initial buffer */
filter->buffer = g_malloc(32768);
filter->first = 0;
filter->size = 0;
filter->allocated_size = 32768;
} else if (filter->first > 0) {
if (filter->allocated_size - filter->size - filter->first < 1024) {
memmove(filter->buffer, filter->buffer + filter->first,
filter->size);
filter->first = 0;
}
} else if (filter->allocated_size - filter->size < 1024) {
/* double the size of the buffer */
filter->allocated_size *= 2;
filter->buffer = g_realloc(filter->buffer, filter->allocated_size);
}
nread = read(filter->fd, filter->buffer + filter->first + filter->size,
filter->allocated_size - filter->first - filter->size - 2);
if (nread <= 0) {
event_release(filter->event);
aclose(filter->fd);
if (filter->size > 0 && filter->buffer[filter->first + filter->size - 1] != '\n') {
/* Add a '\n' at end of buffer */
filter->buffer[filter->first + filter->size] = '\n';
filter->size++;
}
} else {
filter->size += nread;
}
/* process all complete lines */
line = filter->buffer + filter->first;
line[filter->size] = '\0';
while (line < filter->buffer + filter->first + filter->size &&
(p = strchr(line, '\n')) != NULL) {
*p = '\0';
if (g_str_equal(filter->name, "restore stdout")) {
g_fprintf(stdout, "%s\n", line);
} else if (g_str_equal(filter->name, "restore stderr")) {
if (!match("^star: [0-9]* blocks?", line)) {
g_fprintf(stderr, "%s\n", line);
}
} else if (g_str_equal(filter->name, "validate stdout")) {
g_fprintf(stdout, "%s\n", line);
} else if (g_str_equal(filter->name, "validate stderr")) {
if (!match("^star: [0-9]* blocks?", line)) {
g_fprintf(stderr, "%s\n", line);
}
} else {
g_debug("unknown: %s", line);
}
len = p - line + 1;
filter->first += len;
filter->size -= len;
line = p + 1;
}
if (nread <= 0) {
g_free(filter->name);
g_free(filter->buffer);
g_free(filter);
}
}
static message_t *
amstar_print_message(
message_t *message)
{
if (strcasecmp(command, "selfcheck") == 0) {
return print_message(message);
}
if (message_get_severity(message) <= MSG_INFO) {
if (g_str_equal(command, "estimate")) {
fprintf(stdout, "OK %s\n", get_message(message));
} else if (g_str_equal(command, "backup")) {
fprintf(mesgstream, "| %s\n", get_message(message));
} else {
fprintf(stdout, "%s\n", get_message(message));
}
} else {
amstar_exit_value = 1;
if (g_str_equal(command, "estimate")) {
fprintf(stdout, "ERROR %s\n", get_message(message));
} else if (g_str_equal(command, "backup")) {
fprintf(mesgstream, "sendbackup: error [%s]\n", get_message(message));
} else {
fprintf(stdout, "%s\n", get_message(message));
}
}
return message;
}
int
main(
int argc,
char ** argv)
{
int c;
application_argument_t argument;
char *star_sparse_value = NULL;
char *star_acl_value = NULL;
#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_target = NULL;
glib_init();
/* 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 (g_str_equal(argv[1], "selfcheck")) {
printf("ERROR amstar must be run setuid root\n");
}
error(_("amstar must be run setuid root"));
}
safe_fd(3, 2);
set_pname("amstar");
set_pcomponent("application");
set_pmodule("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|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.level = NULL;
argument.command_options = NULL;
init_dle(&argument.dle);
argument.dle.record = 0;
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: amfree(star_sparse_value);
star_sparse_value = g_strdup(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_target);
star_target = 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: amfree(star_acl_value);
star_acl_value = g_strdup(optarg);
break;
case 25: if (optarg)
argument.dle.include_file =
append_sl(argument.dle.include_file, optarg);
break;
case 26: if (optarg) {
amfree(star_target);
star_target = g_strdup(optarg);
}
break;
case ':':
case '?':
break;
}
}
if (g_str_equal(command, "backup")) {
mesgstream = fdopen(3, "w");
if (!mesgstream) {
error(_("error mesgstream(%d): %s\n"), 3, strerror(errno));
}
}
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 (star_sparse_value) {
if (strcasecmp(star_sparse_value, "NO") == 0) {
star_sparse = 0;
} else if (strcasecmp(star_sparse_value, "YES") == 0) {
star_sparse = 1;
} else {
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701008, MSG_ERROR, 4,
"value", star_sparse_value,
"disk", argument.dle.disk,
"device", argument.dle.device,
"hostname", argument.host)));
}
}
if (star_acl_value) {
if (strcasecmp(star_acl_value, "NO") == 0){
star_acl = 0;
} else if (strcasecmp(star_acl_value, "YES") == 0){
star_acl = 1;
} else {
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701009, MSG_ERROR, 4,
"value", star_acl_value,
"disk", argument.dle.disk,
"device", argument.dle.device,
"hostname", argument.host)));
}
}
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 (g_str_equal(command, "support")) {
amstar_support(&argument);
} else if (g_str_equal(command, "selfcheck")) {
amstar_selfcheck(&argument);
} else if (g_str_equal(command, "estimate")) {
amstar_estimate(&argument);
} else if (g_str_equal(command, "backup")) {
amstar_backup(&argument);
} else if (g_str_equal(command, "restore")) {
amstar_restore(&argument);
} else if (g_str_equal(command, "validate")) {
amstar_validate(&argument);
} else if (g_str_equal(command, "index")) {
amstar_index(&argument);
} else {
fprintf(stderr, "Unknown command `%s'.\n", command);
exit (1);
}
dbclose();
return amstar_exit_value;
}
static char *validate_command_options(
application_argument_t *argument)
{
GSList *copt;
for (copt = argument->command_options; copt != NULL; copt = copt->next) {
char *opt = (char *)copt->data;
if (g_str_has_prefix(opt, "--compress-command")) {
return opt;
}
}
return NULL;
}
static void
amstar_support(
application_argument_t *argument)
{
(void)argument;
fprintf(stdout, "CONFIG YES\n");
fprintf(stdout, "HOST YES\n");
fprintf(stdout, "DISK YES\n");
fprintf(stdout, "MAX-LEVEL 9\n");
fprintf(stdout, "INDEX-LINE YES\n");
fprintf(stdout, "INDEX-XML NO\n");
fprintf(stdout, "MESSAGE-LINE YES\n");
fprintf(stdout, "MESSAGE-SELFCHECK-JSON YES\n");
fprintf(stdout, "MESSAGE-XML NO\n");
fprintf(stdout, "RECORD YES\n");
fprintf(stdout, "INCLUDE-FILE YES\n");
fprintf(stdout, "INCLUDE-LIST YES\n");
fprintf(stdout, "EXCLUDE-FILE YES\n");
fprintf(stdout, "EXCLUDE-LIST YES\n");
fprintf(stdout, "COLLECTION NO\n");
fprintf(stdout, "MULTI-ESTIMATE YES\n");
fprintf(stdout, "CALCSIZE YES\n");
fprintf(stdout, "CLIENT-ESTIMATE YES\n");
}
static void
amstar_selfcheck(
application_argument_t *argument)
{
char *option;
if (argument->dle.disk) {
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701000, MSG_INFO, 3,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host)));
}
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701001, MSG_INFO, 4,
"version", VERSION,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host)));
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701004, MSG_INFO, 3,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host)));
if (argument->dle.device) {
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701019, MSG_INFO, 4,
"directory", star_target,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host)));
}
if (star_target) {
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701018, MSG_INFO, 4,
"directory", star_target,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host)));
}
if (((argument->dle.include_list &&
argument->dle.include_list->nb_element >= 0) ||
(argument->dle.include_file &&
argument->dle.include_file->nb_element >= 0)) &&
((argument->dle.exclude_list &&
argument->dle.exclude_list->nb_element >= 0) ||
(argument->dle.exclude_file &&
argument->dle.exclude_file->nb_element >= 0))) {
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701017, MSG_ERROR, 3,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host)));
}
if ((option = validate_command_options(argument))) {
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701014, MSG_ERROR, 4,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host,
"command-options", option)));
}
if (star_path) {
char *star_realpath = NULL;
message_t *message;
if ((message = check_exec_for_suid_message("STAR_PATH", star_path, &star_realpath))) {
delete_message(amstar_print_message(message));
} else {
message = amstar_print_message(check_file_message(star_path, X_OK));
if (message && message_get_severity(message) <= MSG_INFO) {
char *star_version;
GPtrArray *argv_ptr = g_ptr_array_new();
g_ptr_array_add(argv_ptr, star_realpath);
g_ptr_array_add(argv_ptr, "--version");
g_ptr_array_add(argv_ptr, NULL);
star_version = get_first_line(argv_ptr);
if (star_version) {
char *sv, *sv1;
for (sv = star_version; *sv && !g_ascii_isdigit(*sv); sv++);
for (sv1 = sv; *sv1 && *sv1 != ' '; sv1++);
*sv1 = '\0';
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701002, MSG_INFO, 4,
"star-version", sv,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host)));
} else {
printf(_("ERROR Can't get %s version\n"), star_path);
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701003, MSG_INFO, 4,
"star-path", star_path,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host)));
}
g_ptr_array_free(argv_ptr, TRUE);
amfree(star_version);
}
if (message)
delete_message(message);
}
if (star_realpath)
g_free(star_realpath);
} else {
delete_message(amstar_print_message(build_message(
AMANDA_FILE, __LINE__, 3701005, MSG_ERROR, 3,
"disk", argument->dle.disk,
"device", argument->dle.device,
"hostname", argument->host)));
}
delete_message(amstar_print_message(check_file_message(star_tardumps, W_OK)));
if (argument->calcsize) {
char *calcsize = g_strjoin(NULL, amlibexecdir, "/", "calcsize", NULL);
delete_message(amstar_print_message(check_file_message(calcsize, X_OK)));
delete_message(amstar_print_message(check_suid_message(calcsize)));
amfree(calcsize);
}
{
char *amandates_file;
amandates_file = getconf_str(CNF_AMANDATES);
delete_message(amstar_print_message(check_file_message(amandates_file, R_OK|W_OK)));
}
set_root_privs(1);
if (argument->dle.device) {
delete_message(amstar_print_message(check_dir_message(argument->dle.device, R_OK)));
}
set_root_privs(0);
}
static void
amstar_estimate(
application_argument_t *argument)
{
GPtrArray *argv_ptr;
int nullfd;
int pipefd;
FILE *dumpout = NULL;
off_t size = -1;
char line[32768];
char *errmsg = NULL;
char *qerrmsg;
char *qdisk = NULL;
amwait_t wait_status;
int starpid;
amregex_t *rp;
times_t start_time;
int level = 0;
GSList *levels = NULL;
char *option;
char *star_realpath = NULL;
message_t *message;
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 ((option = validate_command_options(argument))) {
fprintf(stdout, "ERROR Invalid '%s' COMMAND-OPTIONS\n", option);
error("Invalid '%s' COMMAND-OPTIONS", option);
}
if (argument->calcsize) {
char *dirname;
if (star_target) {
dirname = star_target;
} 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;
}
if ((message = check_exec_for_suid_message("STAR_PATH", star_path, &star_realpath))) {
errmsg = g_strdup(get_message(message));
delete_message(message);
goto common_error;
}
if ((message = check_file_message(star_tardumps, W_OK))) {
if (message_get_severity(message) > MSG_INFO) {
errmsg = g_strdup(get_message(message));
delete_message(message);
goto common_error;
}
delete_message(message);
}
start_time = curclock();
qdisk = quote_string(argument->dle.disk);
for (levels = argument->level; levels != NULL; levels = levels->next) {
level = GPOINTER_TO_INT(levels->data);
argv_ptr = amstar_build_argv(star_realpath, argument, level, CMD_ESTIMATE, NULL);
if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
errmsg = g_strdup_printf(_("Cannot access /dev/null : %s"),
strerror(errno));
goto common_error;
}
starpid = pipespawnv(star_realpath, 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"),
star_realpath);
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"),
star_realpath, argument->dle.disk);
dbprintf(".....\n");
}
dbprintf(_("estimate size for %s level %d: %lld KB\n"),
qdisk,
level,
(long long)size);
(void)kill(-starpid, SIGTERM);
dbprintf(_("waiting for %s \"%s\" child\n"), star_realpath, qdisk);
waitpid(starpid, &wait_status, 0);
if (WIFSIGNALED(wait_status)) {
amfree(errmsg);
errmsg = g_strdup_printf(_("%s terminated with signal %d: see %s"),
star_realpath, 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"),
star_realpath, 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"), star_realpath, 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"), star_realpath, 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(star_realpath);
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(star_realpath);
}
static void
amstar_backup(
application_argument_t *argument)
{
int dumpin;
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 indexf = 4;
int outf;
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;
char *option;
char *star_realpath = NULL;
message_t *message;
if (!argument->level) {
fprintf(mesgstream, "sendbackup: error [No level argument]\n");
error(_("No level argument"));
}
if (!argument->dle.disk) {
fprintf(mesgstream, "sendbackup: error [No disk argument]\n");
error(_("No disk argument"));
}
if (!argument->dle.device) {
fprintf(mesgstream, "sendbackup: error [No device argument]\n");
error(_("No device argument"));
}
if ((message = check_exec_for_suid_message("STAR_PATH", star_path, &star_realpath))) {
fprintf(mesgstream, "sendbackup: error [%s]", get_message(message));
exit(1);
}
if ((message = check_file_message(star_tardumps, W_OK))) {
if (message_get_severity(message) > MSG_INFO) {
fprintf(mesgstream, "sendbackup: error [%s]", get_message(message));
delete_message(message);
exit(1);
}
delete_message(message);
}
if ((option = validate_command_options(argument))) {
fprintf(mesgstream, "sendbackup: error [Invalid '%s' COMMAND-OPTIONS]\n", option);
exit(1);
}
if (argument->dle.include_list &&
argument->dle.include_list->nb_element >= 0) {
fprintf(mesgstream, "sendbackup: error [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(star_realpath, argument, level, CMD_BACKUP, mesgstream);
starpid = pipespawnv(star_realpath, 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) {
fprintf(mesgstream, "sendbackup: error [error indexstream(%d): %s]\n", indexf, strerror(errno));
error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
}
}
outstream = fdopen(outf, "r");
if (!outstream) {
fprintf(mesgstream, "sendbackup: error [error outstream(%d): %s]\n", outf, strerror(errno));
error(_("error outstream(%d): %s\n"), outf, strerror(errno));
}
regcomp(®ex_root, "^a \\.\\/ directory$", REG_EXTENDED|REG_NEWLINE);
regcomp(®ex_dir, "^a (.*) directory$", REG_EXTENDED|REG_NEWLINE);
regcomp(®ex_file, "^a (.*) (.*) bytes", REG_EXTENDED|REG_NEWLINE);
regcomp(®ex_special, "^a (.*) special", REG_EXTENDED|REG_NEWLINE);
regcomp(®ex_symbolic, "^a (.*) symbolic", REG_EXTENDED|REG_NEWLINE);
regcomp(®ex_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(®ex_root, line, 1, regmatch, 0) == 0) {
if (argument->dle.create_index)
fprintf(indexstream, "%s\n", "/");
continue;
}
if (regexec(®ex_dir, 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;
}
if (regexec(®ex_file, line, 3, regmatch, 0) == 0 ||
regexec(®ex_special, line, 3, regmatch, 0) == 0 ||
regexec(®ex_symbolic, line, 3, regmatch, 0) == 0 ||
regexec(®ex_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(®ex_root);
regfree(®ex_dir);
regfree(®ex_file);
regfree(®ex_special);
regfree(®ex_symbolic);
regfree(®ex_hard);
dbprintf(_("gnutar: %s: pid %ld\n"), star_realpath, (long)starpid);
dbprintf("sendbackup: size %lld\n", (long long)dump_size);
fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size);
fclose(mesgstream);
if (argument->dle.create_index)
fclose(indexstream);
amfree(qdisk);
amfree(star_realpath);
}
static void
amstar_restore(
application_argument_t *argument)
{
GPtrArray *argv_ptr = g_ptr_array_new();
int j;
char *star_realpath = NULL;
message_t *message;
int datain = 0;
int outf;
int errf;
int star_pid;
amwait_t wait_status;
char *errmsg = NULL;
if (!star_path) {
error(_("STAR-PATH not defined"));
}
if ((message = check_exec_for_suid_message("STAR_PATH", star_path, &star_realpath))) {
fprintf(stderr, "%s\n", get_message(message));
delete_message(message);
exit(1);
}
if (!security_allow_to_restore()) {
error("The user is not allowed to restore files");
}
g_ptr_array_add(argv_ptr, g_strdup(star_realpath));
if (star_target) {
struct stat stat_buf;
if(stat(star_target, &stat_buf) != 0) {
fprintf(stderr,"can not stat directory %s: %s\n", star_target, strerror(errno));
exit(1);
}
if (!S_ISDIR(stat_buf.st_mode)) {
fprintf(stderr,"%s is not a directory\n", star_target);
exit(1);
}
if (access(star_target, W_OK) != 0 ) {
fprintf(stderr, "Can't write to %s: %s\n", star_target, strerror(errno));
exit(1);
}
g_ptr_array_add(argv_ptr, g_strdup("-C"));
g_ptr_array_add(argv_ptr, g_strdup(star_target));
}
g_ptr_array_add(argv_ptr, g_strdup("-x"));
g_ptr_array_add(argv_ptr, g_strdup("-v"));
g_ptr_array_add(argv_ptr, g_strdup("-xattr"));
g_ptr_array_add(argv_ptr, g_strdup("-acl"));
g_ptr_array_add(argv_ptr, g_strdup("errctl=WARN|SAMEFILE|SETTIME|DIFF|SETACL|SETXATTR|SETMODE|BADACL *"));
g_ptr_array_add(argv_ptr, g_strdup("-no-fifo"));
g_ptr_array_add(argv_ptr, g_strdup("-f"));
g_ptr_array_add(argv_ptr, g_strdup("-"));
if (argument->dle.exclude_list &&
argument->dle.exclude_list->nb_element == 1) {
g_ptr_array_add(argv_ptr, g_strdup("-exclude-from"));
g_ptr_array_add(argv_ptr,
g_strdup(argument->dle.exclude_list->first->name));
}
if (argument->dle.include_list &&
argument->dle.include_list->nb_element == 1) {
FILE *include_list = fopen(argument->dle.include_list->first->name, "r");
if (include_list) {
char line[2*PATH_MAX+2];
while (fgets(line, 2*PATH_MAX, include_list)) {
line[strlen(line)-1] = '\0'; /* remove '\n' */
if (g_str_has_prefix(line, "./"))
g_ptr_array_add(argv_ptr, g_strdup(line+2)); /* remove ./ */
else if (!g_str_equal(line, "."))
g_ptr_array_add(argv_ptr, g_strdup(line));
}
fclose(include_list);
}
}
for (j=1; j< argument->argc; j++) {
if (g_str_has_prefix(argument->argv[j], "./"))
g_ptr_array_add(argv_ptr, g_strdup(argument->argv[j]+2));/*remove ./ */
else if (!g_str_equal(argument->argv[j], "."))
g_ptr_array_add(argv_ptr, g_strdup(argument->argv[j]));
}
g_ptr_array_add(argv_ptr, NULL);
debug_executing(argv_ptr);
star_pid = pipespawnv(star_realpath, STDOUT_PIPE|STDERR_PIPE, 1,
&datain, &outf, &errf, (char **)argv_ptr->pdata);
aclose(datain);
read_fd(outf, "restore stdout", &read_text);
read_fd(errf, "restore stderr", &read_text);
event_loop(0);
waitpid(star_pid, &wait_status, 0);
if (WIFSIGNALED(wait_status)) {
errmsg = g_strdup_printf(_("%s terminated with signal %d: see %s"),
star_path, WTERMSIG(wait_status), dbfn());
amstar_exit_value = 1;
} else if (WIFEXITED(wait_status)) {
if (WEXITSTATUS(wait_status) != 0) {
errmsg = g_strdup_printf(_("%s exited with status %d: see %s"),
star_path, WEXITSTATUS(wait_status), dbfn());
amstar_exit_value = 1;
} else {
/* Normal exit */
}
} else {
errmsg = g_strdup_printf(_("%s got bad exit: see %s"),
star_path, dbfn());
amstar_exit_value = 1;
}
if (errmsg) {
g_debug("%s", errmsg);
fprintf(stderr,"%s\n", errmsg);
}
g_ptr_array_free_full(argv_ptr);
return;
}
static void
amstar_validate(
application_argument_t *argument G_GNUC_UNUSED)
{
char *cmd;
GPtrArray *argv_ptr = g_ptr_array_new();
char buf[32768];
int datain = 0;
int outf;
int errf;
int star_pid;
amwait_t wait_status;
char *errmsg = NULL;
set_root_privs(-1);
if (!star_path) {
dbprintf("STAR-PATH not set; Piping to /dev/null\n");
fprintf(stderr,"STAR-PATH not set; Piping to /dev/null\n");
goto pipe_to_null;
}
cmd = g_strdup(star_path);
g_ptr_array_add(argv_ptr, g_strdup(star_path));
g_ptr_array_add(argv_ptr, g_strdup("-t"));
g_ptr_array_add(argv_ptr, g_strdup("-f"));
g_ptr_array_add(argv_ptr, g_strdup("-"));
g_ptr_array_add(argv_ptr, NULL);
debug_executing(argv_ptr);
star_pid = pipespawnv(cmd, STDOUT_PIPE|STDERR_PIPE, 0,
&datain, &outf, &errf, (char **)argv_ptr->pdata);
aclose(datain);
read_fd(outf, "validate stdout", &read_text);
read_fd(errf, "validate stderr", &read_text);
event_loop(0);
waitpid(star_pid, &wait_status, 0);
if (WIFSIGNALED(wait_status)) {
errmsg = g_strdup_printf(_("%s terminated with signal %d: see %s"),
star_path, WTERMSIG(wait_status), dbfn());
amstar_exit_value = 1;
} else if (WIFEXITED(wait_status)) {
if (WEXITSTATUS(wait_status) != 0) {
errmsg = g_strdup_printf(_("%s exited with status %d: see %s"),
star_path, WEXITSTATUS(wait_status), dbfn());
amstar_exit_value = 1;
} else {
/* Normal exit */
}
} else {
errmsg = g_strdup_printf(_("%s got bad exit: see %s"),
star_path, dbfn());
amstar_exit_value = 1;
}
if (errmsg) {
g_debug("%s", errmsg);
fprintf(stderr,"%s\n", errmsg);
}
g_ptr_array_free_full(argv_ptr);
return;
pipe_to_null:
while (read(0, buf, 32768) > 0) {
}
g_ptr_array_free_full(argv_ptr);
}
static void
amstar_index(
application_argument_t *argument G_GNUC_UNUSED)
{
char *cmd;
GPtrArray *argv_ptr = g_ptr_array_new();
int datain = 0;
int indexf;
int errf = 2;
pid_t tarpid;
FILE *indexstream;
char line[32768];
amwait_t wait_status;
char *errmsg = NULL;
if (!star_path) {
dbprintf("STAR-PATH not set; Piping to /dev/null\n");
fprintf(stderr,"STAR-PATH not set; Piping to /dev/null\n");
while (read(0, line, 32768) > 0) {
}
exit(1);
}
cmd = g_strdup(star_path);
g_ptr_array_add(argv_ptr, g_strdup(star_path));
g_ptr_array_add(argv_ptr, g_strdup("-t"));
g_ptr_array_add(argv_ptr, g_strdup("-f"));
g_ptr_array_add(argv_ptr, g_strdup("-"));
g_ptr_array_add(argv_ptr, NULL);
tarpid = pipespawnv(cmd, STDOUT_PIPE, 0,
&datain, &indexf, &errf, (char **)argv_ptr->pdata);
aclose(datain);
indexstream = fdopen(indexf, "r");
if (!indexstream) {
error(_("error indexstream(%d): %s\n"), indexf, strerror(errno));
}
while (fgets(line, sizeof(line), indexstream) != NULL) {
if (strlen(line) > 0 && line[strlen(line)-1] == '\n') {
/* remove trailling \n */
line[strlen(line)-1] = '\0';
}
if (*line == '.' && *(line+1) == '/') { /* filename */
fprintf(stdout, "%s\n", &line[1]); /* remove . */
}
}
fclose(indexstream);
waitpid(tarpid, &wait_status, 0);
if (WIFSIGNALED(wait_status)) {
errmsg = g_strdup_printf(_("%s terminated with signal %d: see %s"),
cmd, WTERMSIG(wait_status), dbfn());
} else if (WIFEXITED(wait_status)) {
if (WEXITSTATUS(wait_status) > 0) {
errmsg = g_strdup_printf(_("%s exited with status %d: see %s"),
cmd, WEXITSTATUS(wait_status), dbfn());
} else {
/* Normal exit */
}
} else {
errmsg = g_strdup_printf(_("%s got bad exit: see %s"),
cmd, dbfn());
}
dbprintf(_("amstar: %s: pid %ld\n"), cmd, (long)tarpid);
if (errmsg) {
dbprintf("%s", errmsg);
fprintf(stderr, "error [%s]\n", errmsg);
}
amfree(cmd);
}
static GPtrArray *amstar_build_argv(
char *star_realpath,
application_argument_t *argument,
int level,
int command,
FILE *mesgstream)
{
char *dirname;
char *fsname;
char levelstr[NUM_STR_SIZE+7];
GPtrArray *argv_ptr = g_ptr_array_new();
char *s;
char *tardumpfile;
GSList *copt;
if (star_target) {
dirname = star_target;
} else {
dirname = argument->dle.device;
}
fsname = g_strjoin(NULL, "fs-name=", dirname, NULL);
for (s = fsname; *s != '\0'; s++) {
if (iscntrl((int)*s))
*s = '-';
}
snprintf(levelstr, sizeof(levelstr), "-level=%d", level);
if (star_dle_tardumps) {
char *sdisk = sanitise_filename(argument->dle.disk);
tardumpfile = g_strjoin(NULL, star_tardumps, sdisk, NULL);
amfree(sdisk);
} else {
tardumpfile = g_strdup(star_tardumps);
}
g_ptr_array_add(argv_ptr, g_strdup(star_realpath));
g_ptr_array_add(argv_ptr, g_strdup("-c"));
g_ptr_array_add(argv_ptr, g_strdup("-f"));
if (command == CMD_ESTIMATE) {
g_ptr_array_add(argv_ptr, g_strdup("/dev/null"));
} else {
g_ptr_array_add(argv_ptr, g_strdup("-"));
}
g_ptr_array_add(argv_ptr, g_strdup("-C"));
#if defined(__CYGWIN__)
{
char tmppath[PATH_MAX];
cygwin_conv_to_full_posix_path(dirname, tmppath);
g_ptr_array_add(argv_ptr, g_strdup(tmppath));
}
#else
g_ptr_array_add(argv_ptr, g_strdup(dirname));
#endif
g_ptr_array_add(argv_ptr, g_strdup(fsname));
if (star_onefilesystem)
g_ptr_array_add(argv_ptr, g_strdup("-xdev"));
g_ptr_array_add(argv_ptr, g_strdup("-link-dirs"));
g_ptr_array_add(argv_ptr, g_strdup(levelstr));
g_ptr_array_add(argv_ptr, g_strconcat("tardumps=", tardumpfile, NULL));
if (command == CMD_BACKUP)
g_ptr_array_add(argv_ptr, g_strdup("-wtardumps"));
g_ptr_array_add(argv_ptr, g_strdup("-xattr"));
if (star_acl)
g_ptr_array_add(argv_ptr, g_strdup("-acl"));
g_ptr_array_add(argv_ptr, g_strdup("H=exustar"));
g_ptr_array_add(argv_ptr, g_strdup("errctl=WARN|SAMEFILE|DIFF|GROW|SHRINK|SPECIALFILE|GETXATTR|BADACL *"));
if (star_sparse)
g_ptr_array_add(argv_ptr, g_strdup("-sparse"));
g_ptr_array_add(argv_ptr, g_strdup("-dodesc"));
if (command == CMD_BACKUP && argument->dle.create_index)
g_ptr_array_add(argv_ptr, g_strdup("-v"));
if (((argument->dle.include_file &&
argument->dle.include_file->nb_element >= 1) ||
(argument->dle.include_list &&
argument->dle.include_list->nb_element >= 1)) &&
((argument->dle.exclude_file &&
argument->dle.exclude_file->nb_element >= 1) ||
(argument->dle.exclude_list &&
argument->dle.exclude_list->nb_element >= 1))) {
if (mesgstream && command == CMD_BACKUP) {
fprintf(mesgstream, "? include and exclude specified, disabling exclude\n");
}
free_sl(argument->dle.exclude_file);
argument->dle.exclude_file = NULL;
free_sl(argument->dle.exclude_list);
argument->dle.exclude_list = NULL;
}
if ((argument->dle.exclude_file &&
argument->dle.exclude_file->nb_element >= 1) ||
(argument->dle.exclude_list &&
argument->dle.exclude_list->nb_element >= 1)) {
g_ptr_array_add(argv_ptr, g_strdup("-match-tree"));
g_ptr_array_add(argv_ptr, g_strdup("-not"));
}
if (argument->dle.exclude_file &&
argument->dle.exclude_file->nb_element >= 1) {
sle_t *excl;
for (excl = argument->dle.exclude_file->first; excl != NULL;
excl = excl->next) {
char *ex;
if (strncmp(excl->name, "./", 2) == 0) {
ex = g_strdup_printf("pat=%s", excl->name+2);
} else {
ex = g_strdup_printf("pat=%s", excl->name);
}
g_ptr_array_add(argv_ptr, ex);
}
}
if (argument->dle.exclude_list &&
argument->dle.exclude_list->nb_element >= 1) {
sle_t *excl;
for (excl = argument->dle.exclude_list->first; excl != NULL;
excl = excl->next) {
char *exclname = fixup_relative(excl->name, argument->dle.device);
FILE *exclude;
char *aexc;
if ((exclude = fopen(exclname, "r")) != NULL) {
while ((aexc = pgets(exclude)) != NULL) {
if (aexc[0] != '\0') {
char *ex;
if (strncmp(aexc, "./", 2) == 0) {
ex = g_strdup_printf("pat=%s", aexc+2);
} else {
ex = g_strdup_printf("pat=%s", aexc);
}
g_ptr_array_add(argv_ptr, ex);
}
amfree(aexc);
}
fclose(exclude);
}
amfree(exclname);
}
}
if (argument->dle.include_file &&
argument->dle.include_file->nb_element >= 1) {
sle_t *excl;
for (excl = argument->dle.include_file->first; excl != NULL;
excl = excl->next) {
char *ex;
if (strncmp(excl->name, "./", 2) == 0) {
ex = g_strdup_printf("pat=%s", excl->name+2);
} else {
ex = g_strdup_printf("pat=%s", excl->name);
}
g_ptr_array_add(argv_ptr, ex);
}
}
if (argument->dle.include_list &&
argument->dle.include_list->nb_element >= 1) {
sle_t *excl;
for (excl = argument->dle.include_list->first; excl != NULL;
excl = excl->next) {
char *exclname = fixup_relative(excl->name, argument->dle.device);
FILE *include;
char *aexc;
if ((include = fopen(exclname, "r")) != NULL) {
while ((aexc = pgets(include)) != NULL) {
if (aexc[0] != '\0') {
char *ex;
if (strncmp(aexc, "./", 2) == 0) {
ex = g_strdup_printf("pat=%s", aexc+2);
} else {
ex = g_strdup_printf("pat=%s", aexc);
}
g_ptr_array_add(argv_ptr, ex);
}
amfree(aexc);
}
fclose(include);
}
amfree(exclname);
}
}
/* It is best to place command_options at the and of command line.
* For example '-find' option requires that it is the last option used.
* See: http://cdrecord.berlios.de/private/man/star/star.1.html
*/
for (copt = argument->command_options; copt != NULL; copt = copt->next) {
g_ptr_array_add(argv_ptr, g_strdup((char *)copt->data));
}
g_ptr_array_add(argv_ptr, g_strdup("."));
g_ptr_array_add(argv_ptr, NULL);
amfree(tardumpfile);
amfree(fsname);
return(argv_ptr);
}
static int
check_device(
application_argument_t *argument)
{
char *qdevice;
struct stat stat_buf;
qdevice = quote_string(argument->dle.device);
set_root_privs(1);
if (!stat(argument->dle.device, &stat_buf)) {
if (!S_ISDIR(stat_buf.st_mode)) {
set_root_privs(0);
g_fprintf(stderr, _("ERROR %s is not a directory\n"), qdevice);
amfree(qdevice);
return 0;
}
} else {
set_root_privs(0);
g_fprintf(stderr, _("ERROR can not stat %s: %s\n"), qdevice,
strerror(errno));
amfree(qdevice);
return 0;
}
if (access(argument->dle.device, R_OK|X_OK) == -1) {
set_root_privs(0);
g_fprintf(stderr, _("ERROR can not access %s: %s\n"),
argument->dle.device, strerror(errno));
amfree(qdevice);
return 0;
}
set_root_privs(0);
amfree(qdevice);
return 1;
}