4439f308b12079c1fb4a0ae5441a55cdcc5b12be
[debian/amanda] / client-src / sendbackup-gnutar.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1999 University of Maryland at College Park
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of U.M. not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  U.M. makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as is"
14  * without express or implied warranty.
15  *
16  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  * Authors: the Amanda Development Team.  Its members are listed in a
24  * file named AUTHORS, in the root directory of this distribution.
25  */
26 /* 
27  * $Id: sendbackup-gnutar.c,v 1.98 2006/07/25 18:35:21 martinea Exp $
28  *
29  * send backup data using GNU tar
30  */
31
32 #include "amanda.h"
33 #include "sendbackup.h"
34 #include "amandates.h"
35 #include "clock.h"
36 #include "util.h"
37 #include "getfsent.h"                   /* for amname_to_dirname lookup */
38 #include "version.h"
39 #include "conffile.h"
40
41 #ifdef SAMBA_CLIENT
42 #include "findpass.h"
43 #endif
44
45 static amregex_t re_table[] = {
46   /* tar prints the size in bytes */
47   AM_SIZE_RE("^ *Total bytes written: [0-9][0-9]*", 1, 1),
48   AM_NORMAL_RE("^Elapsed time:"),
49   AM_NORMAL_RE("^Throughput"),
50
51   /* GNU tar 1.13.17 will print this warning when (not) backing up a
52      Unix named socket.  */
53   AM_NORMAL_RE(": socket ignored$"),
54
55   /* GNUTAR produces a few error messages when files are modified or
56      removed while it is running.  They may cause data to be lost, but
57      then they may not.  We shouldn't consider them NORMAL until
58      further investigation.  */
59 #ifdef IGNORE_TAR_ERRORS
60   AM_NORMAL_RE(": File .* shrunk by [0-9][0-9]* bytes, padding with zeros"),
61   AM_NORMAL_RE(": Cannot add file .*: No such file or directory$"),
62   AM_NORMAL_RE(": Error exit delayed from previous errors"),
63 #endif
64   
65   /* samba may produce these output messages */
66   AM_NORMAL_RE("^[Aa]dded interface"),
67   AM_NORMAL_RE("^session request to "),
68   AM_NORMAL_RE("^tar: dumped [0-9][0-9]* (tar )?files"),
69
70 #if SAMBA_VERSION < 2
71   AM_NORMAL_RE("^doing parameter"),
72   AM_NORMAL_RE("^pm_process\\(\\)"),
73   AM_NORMAL_RE("^adding IPC"),
74   AM_NORMAL_RE("^Opening"),
75   AM_NORMAL_RE("^Connect"),
76   AM_NORMAL_RE("^Domain="),
77   AM_NORMAL_RE("^max"),
78   AM_NORMAL_RE("^security="),
79   AM_NORMAL_RE("^capabilities"),
80   AM_NORMAL_RE("^Sec mode "),
81   AM_NORMAL_RE("^Got "),
82   AM_NORMAL_RE("^Chose protocol "),
83   AM_NORMAL_RE("^Server "),
84   AM_NORMAL_RE("^Timezone "),
85   AM_NORMAL_RE("^received"),
86   AM_NORMAL_RE("^FINDFIRST"),
87   AM_NORMAL_RE("^FINDNEXT"),
88   AM_NORMAL_RE("^dos_clean_name"),
89   AM_NORMAL_RE("^file"),
90   AM_NORMAL_RE("^getting file"),
91   AM_NORMAL_RE("^Rejected chained"),
92   AM_NORMAL_RE("^nread="),
93   AM_NORMAL_RE("^\\([0-9][0-9]* kb/s\\)"),
94   AM_NORMAL_RE("^\\([0-9][0-9]*\\.[0-9][0-9]* kb/s\\)"),
95   AM_NORMAL_RE("^[ \t]*[0-9][0-9]* \\([ \t]*[0-9][0-9]*\\.[0-9][0-9]* kb/s\\)"),
96   AM_NORMAL_RE("^[ \t]*directory "),
97   AM_NORMAL_RE("^load_client_codepage"),
98 #endif
99
100 #ifdef IGNORE_SMBCLIENT_ERRORS
101   /* This will cause amanda to ignore real errors, but that may be
102    * unavoidable when you're backing up system disks.  It seems to be
103    * a safe thing to do if you know what you're doing.  */
104   AM_NORMAL_RE("^ERRDOS - ERRbadshare opening remote file"),
105   AM_NORMAL_RE("^ERRDOS - ERRbadfile opening remote file"),
106   AM_NORMAL_RE("^ERRDOS - ERRnoaccess opening remote file"),
107   AM_NORMAL_RE("^ERRSRV - ERRaccess setting attributes on file"),
108   AM_NORMAL_RE("^ERRDOS - ERRnoaccess setting attributes on file"),
109 #endif
110
111 #if SAMBA_VERSION >= 2
112   /* Backup attempt of nonexisting directory */
113   AM_ERROR_RE("ERRDOS - ERRbadpath (Directory invalid.)"),
114   AM_NORMAL_RE("^Domain="),
115 #endif
116
117   /* catch-all: DMP_STRANGE is returned for all other lines */
118   AM_STRANGE_RE(NULL)
119 };
120
121 extern char *efile;
122
123 int cur_level;
124 char *cur_disk;
125 time_t cur_dumptime;
126
127 static char *gnutar_list_dir = NULL;
128 static char *incrname = NULL;
129 /*
130  *  doing similar to $ gtar | compression | encryption 
131  */
132 static void
133 start_backup(
134     dle_t      *dle,
135     char       *host,
136     int         dataf,
137     int         mesgf,
138     int         indexf)
139 {
140     char tmppath[PATH_MAX];
141     int dumpin, dumpout, compout;
142     char *cmd = NULL;
143     char *indexcmd = NULL;
144     char *dirname = NULL;
145     int l;
146     char dumptimestr[80] = "UNUSED";
147     struct tm *gmtm;
148     amandates_t *amdates = NULL;
149     time_t prev_dumptime = 0;
150     char *error_pn = NULL;
151     char *compopt  = NULL;
152     char *encryptopt = skip_argument;
153     char *tquoted;
154     char *fquoted;
155     char *qdisk;
156     int infd, outfd;
157     ssize_t nb;
158     char buf[32768];
159     char *amandates_file = NULL;
160
161     error_pn = stralloc2(get_pname(), "-smbclient");
162
163     qdisk = quote_string(dle->disk);
164     dbprintf(_("start: %s:%s lev %d\n"), host, qdisk, GPOINTER_TO_INT(dle->level->data));
165
166     g_fprintf(stderr, _("%s: start [%s:%s level %d]\n"),
167             get_pname(), host, qdisk, GPOINTER_TO_INT(dle->level->data));
168
169      /*  apply client-side encryption here */
170      if ( dle->encrypt == ENCRYPT_CUST ) {
171          encpid = pipespawn(dle->clnt_encrypt, STDIN_PIPE, 0, 
172                         &compout, &dataf, &mesgf, 
173                         dle->clnt_encrypt, encryptopt, NULL);
174          dbprintf(_("gnutar: pid %ld: %s\n"), (long)encpid, dle->clnt_encrypt);
175     } else {
176        compout = dataf;
177        encpid = -1;
178     } 
179      /*  now do the client-side compression */
180     if(dle->compress == COMP_FAST || dle->compress == COMP_BEST) {
181           compopt = skip_argument;
182 #if defined(COMPRESS_BEST_OPT) && defined(COMPRESS_FAST_OPT)
183         if(dle->compress == COMP_BEST) {
184             compopt = COMPRESS_BEST_OPT;
185         } else {
186             compopt = COMPRESS_FAST_OPT;
187         }
188 #endif
189         comppid = pipespawn(COMPRESS_PATH, STDIN_PIPE, 0,
190                             &dumpout, &compout, &mesgf,
191                             COMPRESS_PATH, compopt, NULL);
192         dbprintf(_("gnutar: pid %ld: %s"), (long)comppid, COMPRESS_PATH);
193         if(compopt != skip_argument) {
194             dbprintf(_("pid %ld: %s %s\n"),
195                         (long)comppid, COMPRESS_PATH, compopt);
196         } else {
197             dbprintf(_("pid %ld: %s\n"), (long)comppid, COMPRESS_PATH);
198         }
199      } else if (dle->compress == COMP_CUST) {
200         compopt = skip_argument;
201         comppid = pipespawn(dle->compprog, STDIN_PIPE, 0,
202                             &dumpout, &compout, &mesgf,
203                             dle->compprog, compopt, NULL);
204         if(compopt != skip_argument) {
205             dbprintf(_("pid %ld: %s %s\n"),
206                      (long)comppid, dle->compprog, compopt);
207         } else {
208             dbprintf(_("pid %ld: %s\n"), (long)comppid, dle->compprog);
209         }
210     } else {
211         dumpout = compout;
212         comppid = -1;
213     }
214
215     gnutar_list_dir = getconf_str(CNF_GNUTAR_LIST_DIR);
216     if (strlen(gnutar_list_dir) == 0)
217         gnutar_list_dir = NULL;
218
219 #ifdef SAMBA_CLIENT                                                     /* { */
220     if (dle->device[0] == '/' && dle->device[1]=='/')
221         amfree(incrname);
222     else
223 #endif                                                                  /* } */
224     if (gnutar_list_dir) {
225         char *basename = NULL;
226         char number[NUM_STR_SIZE];
227         char *inputname = NULL;
228         int baselevel;
229         char *sdisk = sanitise_filename(dle->disk);
230
231         basename = vstralloc(gnutar_list_dir,
232                              "/",
233                              host,
234                              sdisk,
235                              NULL);
236         amfree(sdisk);
237
238         g_snprintf(number, SIZEOF(number), "%d", GPOINTER_TO_INT(dle->level->data));
239         incrname = vstralloc(basename, "_", number, ".new", NULL);
240         unlink(incrname);
241
242         /*
243          * Open the listed incremental file from the previous level.  Search
244          * backward until one is found.  If none are found (which will also
245          * be true for a level 0), arrange to read from /dev/null.
246          */
247         baselevel = GPOINTER_TO_INT(dle->level->data);
248         infd = -1;
249         while (infd == -1) {
250             if (--baselevel >= 0) {
251                 g_snprintf(number, SIZEOF(number), "%d", baselevel);
252                 inputname = newvstralloc(inputname,
253                                          basename, "_", number, NULL);
254             } else {
255                 inputname = newstralloc(inputname, "/dev/null");
256             }
257             if ((infd = open(inputname, O_RDONLY)) == -1) {
258                 int save_errno = errno;
259                 char *qname = quote_string(inputname);
260
261                 dbprintf(_("gnutar: error opening '%s': %s\n"),
262                           qname,
263                           strerror(save_errno));
264                 if (baselevel < 0) {
265                     error(_("error [opening '%s': %s]"), qname, strerror(save_errno));
266                     /*NOTREACHED*/
267                 }
268                 amfree(qname);
269             }
270         }
271
272         /*
273          * Copy the previous listed incremental file to the new one.
274          */
275         if ((outfd = open(incrname, O_WRONLY|O_CREAT, 0600)) == -1) {
276             error(_("error [opening '%s': %s]"), incrname, strerror(errno));
277             /*NOTREACHED*/
278         }
279
280         while ((nb = read(infd, &buf, SIZEOF(buf))) > 0) {
281             if (full_write(outfd, &buf, (size_t)nb) < (size_t)nb) {
282                 error(_("error [writing to '%s': %s]"), incrname,
283                        strerror(errno));
284                 /*NOTREACHED*/
285             }
286         }
287
288         if (nb < 0) {
289             error(_("error [reading from '%s': %s]"), inputname, strerror(errno));
290             /*NOTREACHED*/
291         }
292
293         if (close(infd) != 0) {
294             error(_("error [closing '%s': %s]"), inputname, strerror(errno));
295             /*NOTREACHED*/
296         }
297         if (close(outfd) != 0) {
298             error(_("error [closing '%s': %s]"), incrname, strerror(errno));
299             /*NOTREACHED*/
300         }
301
302         tquoted = quote_string(incrname);
303         if(baselevel >= 0) {
304             fquoted = quote_string(inputname);
305             dbprintf(_("doing level %d dump as listed-incremental from '%s' to '%s'\n"),
306                      GPOINTER_TO_INT(dle->level->data), fquoted, tquoted);
307             amfree(fquoted);
308         } else {
309             dbprintf(_("doing level %d dump as listed-incremental to '%s'\n"),
310                      GPOINTER_TO_INT(dle->level->data), tquoted);
311         }
312         amfree(tquoted);
313         amfree(inputname);
314         amfree(basename);
315     } else {
316         /* no gnutar-listdir, so we're using amandates */
317
318         /* find previous dump time, failing completely if there's a problem */
319         amandates_file = getconf_str(CNF_AMANDATES);
320         if(!start_amandates(amandates_file, 0)) {
321             error(_("error [opening %s: %s]"), amandates_file, strerror(errno));
322             /*NOTREACHED*/
323         }
324
325         amdates = amandates_lookup(dle->disk);
326
327         prev_dumptime = EPOCH;
328         for(l = 0; l < GPOINTER_TO_INT(dle->level->data); l++) {
329             if(amdates->dates[l] > prev_dumptime)
330                 prev_dumptime = amdates->dates[l];
331         }
332
333         finish_amandates();
334         free_amandates();
335
336         gmtm = gmtime(&prev_dumptime);
337         g_snprintf(dumptimestr, SIZEOF(dumptimestr),
338                     "%04d-%02d-%02d %2d:%02d:%02d GMT",
339                     gmtm->tm_year + 1900, gmtm->tm_mon+1, gmtm->tm_mday,
340                     gmtm->tm_hour, gmtm->tm_min, gmtm->tm_sec);
341
342         dbprintf(_("gnutar: doing level %d dump from amandates-derived date: %s\n"),
343                   GPOINTER_TO_INT(dle->level->data), dumptimestr);
344     }
345
346     dirname = amname_to_dirname(dle->device);
347
348     cur_dumptime = time(0);
349     cur_level = GPOINTER_TO_INT(dle->level->data);
350     cur_disk = stralloc(dle->disk);
351 #ifdef GNUTAR
352 #  define PROGRAM_GNUTAR GNUTAR
353 #else
354 #  define PROGRAM_GNUTAR "tar"
355 #endif
356     indexcmd = vstralloc(
357                          PROGRAM_GNUTAR,
358                          " -tf", " -",
359                          " 2>/dev/null",
360                          " | sed", " -e",
361                          " \'s/^\\.//\'",
362                          NULL);
363
364 #ifdef SAMBA_CLIENT                                                     /* { */
365     /* Use sambatar if the disk to back up is a PC disk */
366     if (dle->device[0] == '/' && dle->device[1]=='/') {
367         char *sharename = NULL, *user_and_password = NULL, *domain = NULL;
368         char *share = NULL, *subdir = NULL;
369         char *pwtext = NULL;
370         char *taropt;
371         int passwdf = -1;
372         size_t lpass;
373         size_t pwtext_len;
374         char *pw_fd_env;
375
376         parsesharename(dle->device, &share, &subdir);
377         if (!share) {
378             amfree(share);
379             amfree(subdir);
380             set_pname(error_pn);
381             amfree(error_pn);
382             error(_("cannot parse disk entry %s for share/subdir"), qdisk);
383             /*NOTREACHED*/
384         }
385         if ((subdir) && (SAMBA_VERSION < 2)) {
386             amfree(share);
387             amfree(subdir);
388             set_pname(error_pn);
389             amfree(error_pn);
390             error(_("subdirectory specified for share %s but samba not v2 or better"), qdisk);
391             /*NOTREACHED*/
392         }
393         if ((user_and_password = findpass(share, &domain)) == NULL) {
394             if(domain) {
395                 memset(domain, '\0', strlen(domain));
396                 amfree(domain);
397             }
398             set_pname(error_pn);
399             amfree(error_pn);
400             error(_("error [invalid samba host or password not found?]"));
401             /*NOTREACHED*/
402         }
403         lpass = strlen(user_and_password);
404         if ((pwtext = strchr(user_and_password, '%')) == NULL) {
405             memset(user_and_password, '\0', lpass);
406             amfree(user_and_password);
407             if(domain) {
408                 memset(domain, '\0', strlen(domain));
409                 amfree(domain);
410             }
411             set_pname(error_pn);
412             amfree(error_pn);
413             error(_("password field not \'user%%pass\' for %s"), qdisk);
414             /*NOTREACHED*/
415         }
416         *pwtext++ = '\0';
417         pwtext_len = strlen(pwtext);
418         if ((sharename = makesharename(share, 0)) == 0) {
419             memset(user_and_password, '\0', lpass);
420             amfree(user_and_password);
421             if(domain) {
422                 memset(domain, '\0', strlen(domain));
423                 amfree(domain);
424             }
425             set_pname(error_pn);
426             amfree(error_pn);
427             error(_("error [can't make share name of %s]"), share);
428             /*NOTREACHED*/
429         }
430
431         taropt = stralloc("-T");
432         if(dle->exclude_file && dle->exclude_file->nb_element == 1) {
433             strappend(taropt, "X");
434         }
435 #if SAMBA_VERSION >= 2
436         strappend(taropt, "q");
437 #endif
438         strappend(taropt, "c");
439         if (GPOINTER_TO_INT(dle->level->data) != 0) {
440             strappend(taropt, "g");
441         } else if (dle->record) {
442             strappend(taropt, "a");
443         }
444
445         if (subdir) {
446             dbprintf(_("gnutar: backup of %s/%s\n"), sharename, subdir);
447         } else {
448             dbprintf(_("gnutar: backup of %s\n"), sharename);
449         }
450
451         program->backup_name = program->restore_name = SAMBA_CLIENT;
452         cmd = stralloc(program->backup_name);
453         info_tapeheader(dle);
454
455         start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);
456
457         if (pwtext_len > 0) {
458             pw_fd_env = "PASSWD_FD";
459         } else {
460             pw_fd_env = "dummy_PASSWD_FD";
461         }
462         dumppid = pipespawn(cmd, STDIN_PIPE|PASSWD_PIPE, 0,
463                             &dumpin, &dumpout, &mesgf,
464                             pw_fd_env, &passwdf,
465                             "smbclient",
466                             sharename,
467                             *user_and_password ? "-U" : skip_argument,
468                             *user_and_password ? user_and_password : skip_argument,
469                             "-E",
470                             domain ? "-W" : skip_argument,
471                             domain ? domain : skip_argument,
472 #if SAMBA_VERSION >= 2
473                             subdir ? "-D" : skip_argument,
474                             subdir ? subdir : skip_argument,
475 #endif
476                             "-d0",
477                             taropt,
478                             "-",
479                             dle->exclude_file && dle->exclude_file->nb_element == 1 ? dle->exclude_file->first->name : skip_argument,
480                             NULL);
481         if(domain) {
482             memset(domain, '\0', strlen(domain));
483             amfree(domain);
484         }
485         if(pwtext_len > 0 && full_write(passwdf, pwtext, pwtext_len) < pwtext_len) {
486             int save_errno = errno;
487
488             aclose(passwdf);
489             memset(user_and_password, '\0', lpass);
490             amfree(user_and_password);
491             set_pname(error_pn);
492             amfree(error_pn);
493             error(_("error [password write failed: %s]"), strerror(save_errno));
494             /*NOTREACHED*/
495         }
496         memset(user_and_password, '\0', lpass);
497         amfree(user_and_password);
498         aclose(passwdf);
499         amfree(sharename);
500         amfree(share);
501         amfree(subdir);
502         amfree(taropt);
503         tarpid = dumppid;
504     } else
505 #endif                  /*end of samba */
506     {
507
508         int nb_exclude = 0;
509         int nb_include = 0;
510         char **my_argv;
511         int i = 0;
512         char *file_exclude = NULL;
513         char *file_include = NULL;
514
515         if (dle->exclude_file) nb_exclude+=dle->exclude_file->nb_element;
516         if (dle->exclude_list) nb_exclude+=dle->exclude_list->nb_element;
517         if (dle->include_file) nb_include+=dle->include_file->nb_element;
518         if (dle->include_list) nb_include+=dle->include_list->nb_element;
519
520         if (nb_exclude > 0) file_exclude = build_exclude(dle, 0);
521         if (nb_include > 0) file_include = build_include(dle, 0);
522
523         my_argv = alloc(SIZEOF(char *) * (22 + (nb_exclude*2)+(nb_include*2)));
524
525         cmd = vstralloc(amlibexecdir, "/", "runtar", versionsuffix(), NULL);
526         info_tapeheader(dle);
527
528         start_index(dle->create_index, dumpout, mesgf, indexf, indexcmd);
529
530         my_argv[i++] = "runtar";
531         if (g_options->config)
532             my_argv[i++] = g_options->config;
533         else
534             my_argv[i++] = "NOCONFIG";
535 #ifdef GNUTAR
536         my_argv[i++] = GNUTAR;
537 #else
538         my_argv[i++] = "tar";
539 #endif
540         my_argv[i++] = "--create";
541         my_argv[i++] = "--file";
542         my_argv[i++] = "-";
543         my_argv[i++] = "--directory";
544         canonicalize_pathname(dirname, tmppath);
545         my_argv[i++] = tmppath;
546         my_argv[i++] = "--one-file-system";
547         if (gnutar_list_dir && incrname) {
548             my_argv[i++] = "--listed-incremental";
549             my_argv[i++] = incrname;
550         } else {
551             my_argv[i++] = "--incremental";
552             my_argv[i++] = "--newer";
553             my_argv[i++] = dumptimestr;
554         }
555 #ifdef ENABLE_GNUTAR_ATIME_PRESERVE
556         /* --atime-preserve causes gnutar to call
557          * utime() after reading files in order to
558          * adjust their atime.  However, utime()
559          * updates the file's ctime, so incremental
560          * dumps will think the file has changed. */
561         my_argv[i++] = "--atime-preserve";
562 #endif
563         my_argv[i++] = "--sparse";
564         my_argv[i++] = "--ignore-failed-read";
565         my_argv[i++] = "--totals";
566
567         if(file_exclude) {
568             my_argv[i++] = "--exclude-from";
569             my_argv[i++] = file_exclude;
570         }
571
572         if(file_include) {
573             my_argv[i++] = "--files-from";
574             my_argv[i++] = file_include;
575         }
576         else {
577             my_argv[i++] = ".";
578         }
579         my_argv[i++] = NULL;
580         dumppid = pipespawnv(cmd, STDIN_PIPE, 0,
581                              &dumpin, &dumpout, &mesgf, my_argv);
582         tarpid = dumppid;
583         amfree(file_exclude);
584         amfree(file_include);
585         amfree(my_argv);
586     }
587     dbprintf(_("gnutar: %s: pid %ld\n"), cmd, (long)dumppid);
588
589     amfree(qdisk);
590     amfree(dirname);
591     amfree(cmd);
592     amfree(indexcmd);
593     amfree(error_pn);
594
595     /* close the write ends of the pipes */
596
597     aclose(dumpin);
598     aclose(dumpout);
599     aclose(compout);
600     aclose(dataf);
601     aclose(mesgf);
602     if (dle->create_index)
603         aclose(indexf);
604 }
605
606 static void
607 end_backup(
608     dle_t      *dle,
609     int         goterror)
610 {
611     char *amandates_file = NULL;
612
613     if(dle->record && !goterror) {
614         if (incrname != NULL && strlen(incrname) > 4) {
615             char *nodotnew;
616         
617             nodotnew = stralloc(incrname);
618             nodotnew[strlen(nodotnew)-4] = '\0';
619             if (rename(incrname, nodotnew)) {
620                 g_fprintf(stderr, _("%s: warning [renaming %s to %s: %s]\n"), 
621                         get_pname(), incrname, nodotnew, strerror(errno));
622             }
623             amfree(nodotnew);
624             amfree(incrname);
625         }
626
627         /* update the amandates file */
628         amandates_file = getconf_str(CNF_AMANDATES);
629         if(start_amandates(amandates_file, 1)) {
630             amandates_updateone(cur_disk, cur_level, cur_dumptime);
631             finish_amandates();
632             free_amandates();
633         } else {
634             /* failure is only fatal if we didn't get a gnutar-listdir */
635             char *gnutar_list_dir = getconf_str(CNF_GNUTAR_LIST_DIR);
636             if (!gnutar_list_dir || !*gnutar_list_dir) {
637                 error(_("error [opening %s for writing: %s]"), amandates_file, strerror(errno));
638                 /* NOTREACHED */
639             } else {
640                 g_debug(_("non-fatal error opening '%s' for writing: %s]"),
641                         amandates_file, strerror(errno));
642             }
643         }
644     }
645 }
646
647 backup_program_t gnutar_program = {
648   "GNUTAR",
649 #ifdef GNUTAR
650   GNUTAR, GNUTAR,
651 #else
652   "gtar", "gtar",
653 #endif
654   re_table, start_backup, end_backup
655 };