add bug closure to changelog
[debian/amanda] / application-src / amgtar.c
index 947a986ed25e28eb2d4a69c103e5ccbac5edbeb9..47103ad45a466f0f248ce5ce47944e0c518b851b 100644 (file)
@@ -57,6 +57,7 @@
  * EXIT-HANDLING   (1=GOOD 2=BAD)
  * TAR-BLOCKSIZE   (default does not add --blocking-factor option,
  *                  using tar's default)
+ * VERBOSE
  */
 
 #include "amanda.h"
@@ -120,6 +121,8 @@ typedef struct application_argument_s {
     dle_t      dle;
     int        argc;
     char     **argv;
+    int        verbose;
+    int        ignore_zeros;
 } application_argument_t;
 
 enum { CMD_ESTIMATE, CMD_BACKUP };
@@ -135,8 +138,10 @@ static void amgtar_build_exinclude(dle_t *dle, int verbose,
                                   int *nb_include, char **file_include);
 static char *amgtar_get_incrname(application_argument_t *argument, int level,
                                 FILE *mesgstream, int command);
+static void check_no_check_device(void);
 static GPtrArray *amgtar_build_argv(application_argument_t *argument,
-                               char *incrname, int command);
+                               char *incrname, char **file_exclude,
+                               char **file_include, int command);
 static char *gnutar_path;
 static char *gnutar_listdir;
 static char *gnutar_directory;
@@ -190,6 +195,8 @@ static struct option long_options[] = {
     {"command-options" , 1, NULL, 33},
     {"include-list-glob", 1, NULL, 34},
     {"exclude-list-glob", 1, NULL, 35},
+    {"verbose"          , 1, NULL, 36},
+    {"ignore-zeros"     , 1, NULL, 37},
     {NULL, 0, NULL, 0}
 };
 
@@ -292,6 +299,7 @@ main(
 #else
     gnutar_path = NULL;
 #endif
+    gnutar_listdir = NULL;
     gnutar_directory = NULL;
     gnutar_onefilesystem = 1;
     gnutar_atimepreserve = 1;
@@ -353,6 +361,7 @@ main(
     /* parse argument */
     command = argv[1];
 
+    gnutar_listdir = stralloc(getconf_str(CNF_GNUTAR_LIST_DIR));
     argument.config     = NULL;
     argument.host       = NULL;
     argument.message    = 0;
@@ -363,7 +372,10 @@ main(
     argument.command_options = NULL;
     argument.include_list_glob = NULL;
     argument.exclude_list_glob = NULL;
+    argument.verbose = 0;
+    argument.ignore_zeros = 1;
     init_dle(&argument.dle);
+    argument.dle.record = 0;
 
     while (1) {
        int option_index = 0;
@@ -490,6 +502,12 @@ main(
        case 35: if (optarg)
                     argument.exclude_list_glob = stralloc(optarg);
                 break;
+       case 36: if (optarg  && strcasecmp(optarg, "YES") == 0)
+                    argument.verbose = 1;
+                break;
+       case 37: if (strcasecmp(optarg, "YES") != 0)
+                    argument.ignore_zeros = 0;
+                break;
        case ':':
        case '?':
                break;
@@ -538,7 +556,6 @@ main(
        }
     }
 
-    gnutar_listdir = getconf_str(CNF_GNUTAR_LIST_DIR);
     if (strlen(gnutar_listdir) == 0)
        gnutar_listdir = NULL;
 
@@ -628,11 +645,37 @@ static void
 amgtar_selfcheck(
     application_argument_t *argument)
 {
+    if (argument->dle.disk) {
+       char *qdisk = quote_string(argument->dle.disk);
+       fprintf(stdout, "OK disk %s\n", qdisk);
+       amfree(qdisk);
+    }
+
+    printf("OK amgtar version %s\n", VERSION);
     amgtar_build_exinclude(&argument->dle, 1, NULL, NULL, NULL, NULL);
 
     printf("OK amgtar\n");
     if (gnutar_path) {
-       check_file(gnutar_path, X_OK);
+       if (check_file(gnutar_path, X_OK)) {
+           char *gtar_version;
+           GPtrArray *argv_ptr = g_ptr_array_new();
+
+           g_ptr_array_add(argv_ptr, gnutar_path);
+           g_ptr_array_add(argv_ptr, "--version");
+           g_ptr_array_add(argv_ptr, NULL);
+
+           gtar_version = get_first_line(argv_ptr);
+           if (gtar_version) {
+               char *gv;
+               for (gv = gtar_version; *gv && !g_ascii_isdigit(*gv); gv++);
+               printf("OK amgtar gtar-version %s\n", gv);
+           } else {
+               printf(_("ERROR [Can't get %s version]\n"), gnutar_path);
+           }
+
+           g_ptr_array_free(argv_ptr, TRUE);
+           amfree(gtar_version);
+       }
     } else {
        printf(_("ERROR [GNUTAR program not available]\n"));
     }
@@ -646,11 +689,6 @@ amgtar_selfcheck(
        printf(_("ERROR [No GNUTAR-LISTDIR]\n"));
     }
 
-    if (argument->dle.disk) {
-       char *qdisk = quote_string(argument->dle.disk);
-       fprintf(stdout, "OK %s\n", qdisk);
-       amfree(qdisk);
-    }
     if (gnutar_directory) {
        check_dir(gnutar_directory, R_OK);
     } else if (argument->dle.device) {
@@ -686,6 +724,8 @@ amgtar_estimate(
     times_t    start_time;
     int        level;
     GSList    *levels;
+    char      *file_exclude;
+    char      *file_include;
 
     if (!argument->level) {
         fprintf(stderr, "ERROR No level argument\n");
@@ -704,15 +744,13 @@ amgtar_estimate(
 
     if (argument->calcsize) {
        char *dirname;
-       char *file_exclude;
-       char *file_include;
        int   nb_exclude;
        int   nb_include;
 
        if (gnutar_directory) {
            dirname = gnutar_directory;
        } else {
-           dirname = amname_to_dirname(argument->dle.device);
+           dirname = argument->dle.device;
        }
        amgtar_build_exinclude(&argument->dle, 1,
                               &nb_exclude, &file_exclude,
@@ -720,6 +758,13 @@ amgtar_estimate(
 
        run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname,
                     argument->level, file_exclude, file_include);
+
+       if (argument->verbose == 0) {
+           if (file_exclude)
+               unlink(file_exclude);
+           if (file_include)
+               unlink(file_include);
+        }
        return;
     }
 
@@ -737,7 +782,8 @@ amgtar_estimate(
        level = GPOINTER_TO_INT(levels->data);
        incrname = amgtar_get_incrname(argument, level, stdout, CMD_ESTIMATE);
        cmd = stralloc(gnutar_path);
-       argv_ptr = amgtar_build_argv(argument, incrname, CMD_ESTIMATE);
+       argv_ptr = amgtar_build_argv(argument, incrname, &file_exclude,
+                                    &file_include, CMD_ESTIMATE);
 
        start_time = curclock();
 
@@ -831,6 +877,14 @@ common_exit:
        if (incrname) {
            unlink(incrname);
        }
+
+       if (argument->verbose == 0) {
+           if (file_exclude)
+               unlink(file_exclude);
+           if (file_include)
+               unlink(file_include);
+        }
+
        g_ptr_array_free_full(argv_ptr);
        amfree(cmd);
 
@@ -876,6 +930,8 @@ amgtar_backup(
     amwait_t   wait_status;
     GPtrArray *argv_ptr;
     int        tarpid;
+    char      *file_exclude;
+    char      *file_include;
 
     mesgstream = fdopen(mesgf, "w");
     if (!mesgstream) {
@@ -908,7 +964,8 @@ amgtar_backup(
                                   GPOINTER_TO_INT(argument->level->data),
                                   mesgstream, CMD_BACKUP);
     cmd = stralloc(gnutar_path);
-    argv_ptr = amgtar_build_argv(argument, incrname, CMD_BACKUP);
+    argv_ptr = amgtar_build_argv(argument, incrname, &file_exclude,
+                                &file_include, CMD_BACKUP);
 
     tarpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1,
                        &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
@@ -941,7 +998,7 @@ amgtar_backup(
                }
            }
            if(rp->typ == DMP_SIZE) {
-               dump_size = (long)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
+               dump_size = (off_t)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0);
            }
            switch(rp->typ) {
            case DMP_NORMAL:
@@ -995,16 +1052,25 @@ amgtar_backup(
     }
 
     if (!errmsg && incrname && strlen(incrname) > 4) {
-       char *nodotnew;
-       nodotnew = stralloc(incrname);
-       nodotnew[strlen(nodotnew)-4] = '\0';
-       if (rename(incrname, nodotnew)) {
-           dbprintf(_("%s: warning [renaming %s to %s: %s]\n"),
-                    get_pname(), incrname, nodotnew, strerror(errno));
-           g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"),
-                     incrname, nodotnew, strerror(errno));
+       if (argument->dle.record) {
+           char *nodotnew;
+           nodotnew = stralloc(incrname);
+           nodotnew[strlen(nodotnew)-4] = '\0';
+           if (rename(incrname, nodotnew)) {
+               dbprintf(_("%s: warning [renaming %s to %s: %s]\n"),
+                        get_pname(), incrname, nodotnew, strerror(errno));
+               g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"),
+                         incrname, nodotnew, strerror(errno));
+           }
+           amfree(nodotnew);
+       } else {
+           if (unlink(incrname) == -1) {
+               dbprintf(_("%s: warning [unlink %s: %s]\n"),
+                        get_pname(), incrname, strerror(errno));
+               g_fprintf(mesgstream, _("? warning [unlink %s: %s]\n"),
+                         incrname, strerror(errno));
+           }
        }
-       amfree(nodotnew);
     }
 
     dbprintf("sendbackup: size %lld\n", (long long)dump_size);
@@ -1017,6 +1083,13 @@ amgtar_backup(
 
     fclose(mesgstream);
 
+    if (argument->verbose == 0) {
+       if (file_exclude)
+           unlink(file_exclude);
+       if (file_include)
+           unlink(file_include);
+    }
+
     amfree(incrname);
     amfree(qdisk);
     amfree(cmd);
@@ -1032,6 +1105,9 @@ amgtar_restore(
     char      **env;
     int         j;
     char       *e;
+    char       *include_filename = NULL;
+    char       *exclude_filename = NULL;
+    int         tarpid;
 
     if (!gnutar_path) {
        error(_("GNUTAR-PATH not defined"));
@@ -1048,6 +1124,14 @@ amgtar_restore(
        g_ptr_array_add(argv_ptr, stralloc("--selinux"));
     if (gnutar_xattrs)
        g_ptr_array_add(argv_ptr, stralloc("--xattrs"));
+    /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
+    if (argument->ignore_zeros) {
+       g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
+    }
+    if (argument->tar_blocksize) {
+       g_ptr_array_add(argv_ptr, stralloc("--blocking-factor"));
+       g_ptr_array_add(argv_ptr, stralloc(argument->tar_blocksize));
+    }
     g_ptr_array_add(argv_ptr, stralloc("-xpGvf"));
     g_ptr_array_add(argv_ptr, stralloc("-"));
     if (gnutar_directory) {
@@ -1073,7 +1157,6 @@ amgtar_restore(
        argument->dle.exclude_list->nb_element == 1) {
        FILE      *exclude;
        char      *sdisk;
-       char      *filename;
        int        in_argv;
        int        entry_in_exclude = 0;
        char       line[2*PATH_MAX];
@@ -1082,12 +1165,12 @@ amgtar_restore(
        if (argument->dle.disk) {
            sdisk = sanitise_filename(argument->dle.disk);
        } else {
-           sdisk = g_strdup_printf("installcheck-exclude-%d", getpid());
+           sdisk = g_strdup_printf("no_dle-%d", getpid());
        }
-       filename = vstralloc(AMANDA_TMPDIR, "/", "exclude-", sdisk,  NULL);
+       exclude_filename= vstralloc(AMANDA_TMPDIR, "/", "exclude-", sdisk,  NULL);
        exclude_list = fopen(argument->dle.exclude_list->first->name, "r");
 
-       exclude = fopen(filename, "w");
+       exclude = fopen(exclude_filename, "w");
        while (fgets(line, 2*PATH_MAX, exclude_list)) {
            char *escaped;
            line[strlen(line)-1] = '\0'; /* remove '\n' */
@@ -1103,7 +1186,7 @@ amgtar_restore(
        }
        fclose(exclude);
        g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
-       g_ptr_array_add(argv_ptr, filename);
+       g_ptr_array_add(argv_ptr, exclude_filename);
     }
 
     if (argument->exclude_list_glob) {
@@ -1115,7 +1198,6 @@ amgtar_restore(
        GPtrArray *argv_include = g_ptr_array_new();
        FILE      *include;
        char      *sdisk;
-       char      *filename;
        int        in_argv;
        guint      i;
        int        entry_in_include = 0;
@@ -1123,10 +1205,10 @@ amgtar_restore(
        if (argument->dle.disk) {
            sdisk = sanitise_filename(argument->dle.disk);
        } else {
-           sdisk = g_strdup_printf("installcheck-include-%d", getpid());
+           sdisk = g_strdup_printf("no_dle-%d", getpid());
        }
-       filename = vstralloc(AMANDA_TMPDIR, "/", "include-", sdisk,  NULL);
-       include = fopen(filename, "w");
+       include_filename = vstralloc(AMANDA_TMPDIR, "/", "include-", sdisk,  NULL);
+       include = fopen(include_filename, "w");
        if (argument->dle.include_list &&
            argument->dle.include_list->nb_element == 1) {
            char line[2*PATH_MAX];
@@ -1159,7 +1241,7 @@ amgtar_restore(
 
        if (entry_in_include) {
            g_ptr_array_add(argv_ptr, stralloc("--files-from"));
-           g_ptr_array_add(argv_ptr, filename);
+           g_ptr_array_add(argv_ptr, include_filename);
        }
 
        if (argument->include_list_glob) {
@@ -1174,11 +1256,27 @@ amgtar_restore(
     g_ptr_array_add(argv_ptr, NULL);
 
     debug_executing(argv_ptr);
-    env = safe_env();
-    become_root();
-    execve(cmd, (char **)argv_ptr->pdata, env);
-    e = strerror(errno);
-    error(_("error [exec %s: %s]"), cmd, e);
+
+    tarpid = fork();
+    switch (tarpid) {
+    case -1: error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
+    case 0:
+       env = safe_env();
+       become_root();
+       execve(cmd, (char **)argv_ptr->pdata, env);
+       e = strerror(errno);
+       error(_("error [exec %s: %s]"), cmd, e);
+       break;
+    default: break;
+    }
+
+    waitpid(tarpid, NULL, 0);
+    if (argument->verbose == 0) {
+       if (exclude_filename)
+           unlink(exclude_filename);
+       if (include_filename)
+           unlink(include_filename);
+    }
 }
 
 static void
@@ -1199,6 +1297,8 @@ amgtar_validate(
 
     cmd = stralloc(gnutar_path);
     g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
+    /* ignore trailing zero blocks on input (this was the default until tar-1.21) */
+    g_ptr_array_add(argv_ptr, stralloc("--ignore-zeros"));
     g_ptr_array_add(argv_ptr, stralloc("-tf"));
     g_ptr_array_add(argv_ptr, stralloc("-"));
     g_ptr_array_add(argv_ptr, NULL);
@@ -1364,28 +1464,64 @@ amgtar_get_incrname(
     return incrname;
 }
 
+static void
+check_no_check_device(void)
+{
+    if (gnutar_checkdevice == 0) {
+       GPtrArray *argv_ptr = g_ptr_array_new();
+       int dumpin;
+       int dataf;
+       int outf;
+       int size;
+       char buf[32768];
+
+       g_ptr_array_add(argv_ptr, gnutar_path);
+       g_ptr_array_add(argv_ptr, "-x");
+       g_ptr_array_add(argv_ptr, "--no-check-device");
+       g_ptr_array_add(argv_ptr, "-f");
+       g_ptr_array_add(argv_ptr, "-");
+       g_ptr_array_add(argv_ptr, NULL);
+
+       pipespawnv(gnutar_path, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
+                            &dumpin, &dataf, &outf, (char **)argv_ptr->pdata);
+       aclose(dumpin);
+       aclose(dataf);
+       size = read(outf, buf, 32767);
+       if (size > 0) {
+           buf[size] = '\0';
+           if (strstr(buf, "--no-check-device")) {
+               g_debug("disabling --no-check-device since '%s' doesn't support it", gnutar_path);
+               gnutar_checkdevice = 1;
+           }
+       }
+       aclose(outf);
+       g_ptr_array_free(argv_ptr, TRUE);
+    }
+}
+
 GPtrArray *amgtar_build_argv(
     application_argument_t *argument,
-    char *incrname,
-    int   command)
+    char  *incrname,
+    char **file_exclude,
+    char **file_include,
+    int    command)
 {
     int    nb_exclude;
     int    nb_include;
-    char  *file_exclude;
-    char  *file_include;
     char  *dirname;
     char   tmppath[PATH_MAX];
     GPtrArray *argv_ptr = g_ptr_array_new();
     GSList    *copt;
 
+    check_no_check_device();
     amgtar_build_exinclude(&argument->dle, 1,
-                          &nb_exclude, &file_exclude,
-                          &nb_include, &file_include);
+                          &nb_exclude, file_exclude,
+                          &nb_include, file_include);
 
     if (gnutar_directory) {
        dirname = gnutar_directory;
     } else {
-       dirname = amname_to_dirname(argument->dle.device);
+       dirname = argument->dle.device;
     }
 
     g_ptr_array_add(argv_ptr, stralloc(gnutar_path));
@@ -1431,14 +1567,14 @@ GPtrArray *amgtar_build_argv(
        g_ptr_array_add(argv_ptr, stralloc((char *)copt->data));
     }
 
-    if(file_exclude) {
+    if (*file_exclude) {
        g_ptr_array_add(argv_ptr, stralloc("--exclude-from"));
-       g_ptr_array_add(argv_ptr, stralloc(file_exclude));
+       g_ptr_array_add(argv_ptr, stralloc(*file_exclude));
     }
 
-    if(file_include) {
+    if (*file_include) {
        g_ptr_array_add(argv_ptr, stralloc("--files-from"));
-       g_ptr_array_add(argv_ptr, stralloc(file_include));
+       g_ptr_array_add(argv_ptr, stralloc(*file_include));
     }
     else {
        g_ptr_array_add(argv_ptr, stralloc("."));