Imported Upstream version 3.3.0
[debian/amanda] / client-src / sendbackup.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.c,v 1.88 2006/07/25 18:27:56 martinea Exp $
28  *
29  * common code for the sendbackup-* programs.
30  */
31
32 #include "amanda.h"
33 #include "match.h"
34 #include "sendbackup.h"
35 #include "clock.h"
36 #include "pipespawn.h"
37 #include "amfeatures.h"
38 #include "arglist.h"
39 #include "getfsent.h"
40 #include "conffile.h"
41 #include "amandates.h"
42
43 #define sendbackup_debug(i, ...) do {   \
44         if ((i) <= debug_sendbackup) {  \
45             dbprintf(__VA_LIST__);      \
46         }                               \
47 } while (0)
48
49 #define TIMEOUT 30
50
51 pid_t comppid = (pid_t)-1;
52 pid_t dumppid = (pid_t)-1;
53 pid_t tarpid = (pid_t)-1;
54 pid_t encpid = (pid_t)-1;
55 pid_t indexpid = (pid_t)-1;
56 pid_t application_api_pid = (pid_t)-1;
57 char *errorstr = NULL;
58
59 int datafd;
60 int mesgfd;
61 int indexfd;
62
63 g_option_t *g_options = NULL;
64
65 long dump_size = -1;
66
67 backup_program_t *program = NULL;
68 dle_t *gdle = NULL;
69
70 static am_feature_t *our_features = NULL;
71 static char *our_feature_string = NULL;
72 static char *amandad_auth = NULL;
73
74 /* local functions */
75 int main(int argc, char **argv);
76 char *childstr(pid_t pid);
77 int check_status(pid_t pid, amwait_t w, int mesgfd);
78
79 pid_t pipefork(void (*func)(void), char *fname, int *stdinfd,
80                 int stdoutfd, int stderrfd);
81 int check_result(int mesgfd);
82 void parse_backup_messages(dle_t *dle, int mesgin);
83 static void process_dumpline(char *str);
84 static void save_fd(int *, int);
85 void application_api_info_tapeheader(int mesgfd, char *prog, dle_t *dle);
86
87 int fdprintf(int fd, char *format, ...) G_GNUC_PRINTF(2, 3);
88
89 int
90 fdprintf(
91     int   fd,
92     char *format,
93     ...)
94 {
95     va_list  argp;
96     char    *s;
97     int      r;
98
99     arglist_start(argp, format);
100     s = g_strdup_vprintf(format, argp);
101     arglist_end(argp);
102
103     r = full_write(fd, s, strlen(s));
104     amfree(s);
105     return r;
106 }
107
108 int
109 main(
110     int         argc,
111     char **     argv)
112 {
113     int interactive = 0;
114     int level = 0;
115     int mesgpipe[2];
116     dle_t *dle = NULL;
117     char *dumpdate, *stroptions;
118     char *qdisk = NULL;
119     char *qamdevice = NULL;
120     char *line = NULL;
121     char *err_extra = NULL;
122     char *s;
123     int i;
124     int ch;
125     GSList *errlist;
126     FILE   *mesgstream;
127     level_t *alevel;
128
129     /* initialize */
130     /*
131      * Configure program for internationalization:
132      *   1) Only set the message locale for now.
133      *   2) Set textdomain for all amanda related programs to "amanda"
134      *      We don't want to be forced to support dozens of message catalogs.
135      */  
136     setlocale(LC_MESSAGES, "C");
137     textdomain("amanda"); 
138
139     safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);
140     openbsd_fd_inform();
141
142     safe_cd();
143
144     set_pname("sendbackup");
145
146     /* Don't die when child closes pipe */
147     signal(SIGPIPE, SIG_IGN);
148
149     /* Don't die when interrupt received */
150     signal(SIGINT, SIG_IGN);
151
152     if(argc > 1 && strcmp(argv[1],"-t") == 0) {
153         interactive = 1;
154         argc--;
155         argv++;
156     } else {
157         interactive = 0;
158     }
159
160     add_amanda_log_handler(amanda_log_stderr);
161     add_amanda_log_handler(amanda_log_syslog);
162     dbopen(DBG_SUBDIR_CLIENT);
163     startclock();
164     dbprintf(_("Version %s\n"), VERSION);
165
166     if(argc > 2 && strcmp(argv[1], "amandad") == 0) {
167         amandad_auth = stralloc(argv[2]);
168     }
169
170     our_features = am_init_feature_set();
171     our_feature_string = am_feature_to_string(our_features);
172
173     config_init(CONFIG_INIT_CLIENT, NULL);
174     /* (check for config errors comes later) */
175
176     check_running_as(RUNNING_AS_CLIENT_LOGIN);
177
178     if(interactive) {
179         /*
180          * In interactive (debug) mode, the backup data is sent to
181          * /dev/null and none of the network connections back to driver
182          * programs on the tape host are set up.  The index service is
183          * run and goes to stdout.
184          */
185         g_fprintf(stderr, _("%s: running in interactive test mode\n"), get_pname());
186         fflush(stderr);
187     }
188
189     qdisk = NULL;
190     dumpdate = NULL;
191     stroptions = NULL;
192
193     for(; (line = agets(stdin)) != NULL; free(line)) {
194         if (line[0] == '\0')
195             continue;
196         if(interactive) {
197             g_fprintf(stderr, "%s> ", get_pname());
198             fflush(stderr);
199         }
200         if(strncmp_const(line, "OPTIONS ") == 0) {
201             g_options = parse_g_options(line+8, 1);
202             if(!g_options->hostname) {
203                 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
204                 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
205                 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
206             }
207
208             if (g_options->config) {
209                 /* overlay this configuration on the existing (nameless) configuration */
210                 config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY,
211                             g_options->config);
212
213                 dbrename(get_config_name(), DBG_SUBDIR_CLIENT);
214             }
215
216             /* check for any config errors now */
217             if (config_errors(&errlist) >= CFGERR_ERRORS) {
218                 char *errstr = config_errors_to_error_string(errlist);
219                 g_printf("%s\n", errstr);
220                 dbclose();
221                 return 1;
222             }
223
224             if (am_has_feature(g_options->features, fe_req_xml)) {
225                 break;
226             }
227             continue;
228         }
229
230         if (dle && dle->program != NULL) {
231             err_extra = _("multiple requests");
232             goto err;
233         }
234
235         dbprintf(_("  sendbackup req: <%s>\n"), line);
236         dle = alloc_dle();
237
238         s = line;
239         ch = *s++;
240
241         skip_whitespace(s, ch);                 /* find the program name */
242         if(ch == '\0') {
243             err_extra = _("no program name");
244             goto err;                           /* no program name */
245         }
246         dle->program = s - 1;
247         skip_non_whitespace(s, ch);
248         s[-1] = '\0';
249
250         if (strcmp(dle->program, "APPLICATION")==0) {
251             dle->program_is_application_api=1;
252             skip_whitespace(s, ch);             /* find dumper name */
253             if (ch == '\0') {
254                 goto err;                       /* no program */
255             }
256             dle->program = s - 1;
257             skip_non_whitespace(s, ch);
258             s[-1] = '\0';
259         }
260         dle->program = stralloc(dle->program);
261
262         skip_whitespace(s, ch);                 /* find the disk name */
263         if(ch == '\0') {
264             err_extra = _("no disk name");
265             goto err;                           /* no disk name */
266         }
267
268         amfree(qdisk);
269         qdisk = s - 1;
270         ch = *qdisk;
271         skip_quoted_string(s, ch);
272         s[-1] = '\0';
273         qdisk = stralloc(qdisk);
274         dle->disk = unquote_string(qdisk);
275
276         skip_whitespace(s, ch);                 /* find the device or level */
277         if (ch == '\0') {
278             err_extra = _("bad level");
279             goto err;
280         }
281
282         if(!isdigit((int)s[-1])) {
283             amfree(qamdevice);
284             qamdevice = s - 1;
285             ch = *qamdevice;
286             skip_quoted_string(s, ch);
287             s[-1] = '\0';
288             qamdevice = stralloc(qamdevice);
289             dle->device = unquote_string(qamdevice);
290             skip_whitespace(s, ch);             /* find level number */
291         }
292         else {
293             dle->device = stralloc(dle->disk);
294             qamdevice = stralloc(qdisk);
295         }
296                                                 /* find the level number */
297         if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
298             err_extra = _("bad level");
299             goto err;                           /* bad level */
300         }
301         skip_integer(s, ch);
302         alevel = g_new0(level_t, 1);
303         alevel->level = level;
304         dle->levellist = g_slist_append(dle->levellist, alevel);
305
306         skip_whitespace(s, ch);                 /* find the dump date */
307         if(ch == '\0') {
308             err_extra = _("no dumpdate");
309             goto err;                           /* no dumpdate */
310         }
311         amfree(dumpdate);
312         dumpdate = s - 1;
313         skip_non_whitespace(s, ch);
314         s[-1] = '\0';
315         dumpdate = stralloc(dumpdate);
316
317         skip_whitespace(s, ch);                 /* find the options keyword */
318         if(ch == '\0') {
319             err_extra = _("no options");
320             goto err;                           /* no options */
321         }
322         if(strncmp_const_skip(s - 1, "OPTIONS ", s, ch) != 0) {
323             err_extra = _("no OPTIONS keyword");
324             goto err;                           /* no options */
325         }
326         skip_whitespace(s, ch);                 /* find the options string */
327         if(ch == '\0') {
328             err_extra = _("bad options string");
329             goto err;                           /* no options */
330         }
331         amfree(stroptions);
332         stroptions = stralloc(s - 1);
333     }
334     amfree(line);
335     if (g_options == NULL) {
336         g_printf(_("ERROR [Missing OPTIONS line in sendbackup input]\n"));
337         error(_("Missing OPTIONS line in sendbackup input\n"));
338         /*NOTREACHED*/
339     }
340
341     if (am_has_feature(g_options->features, fe_req_xml)) {
342         char *errmsg = NULL;
343
344         dle = amxml_parse_node_FILE(stdin, &errmsg);
345         if (errmsg) {
346             err_extra = errmsg;
347             goto err;
348         }
349         if (!dle) {
350             err_extra = _("One DLE required");
351             goto err;
352         } else if (dle->next) {
353             err_extra = _("Only one DLE allowed");
354             goto err;
355         }
356
357         qdisk = quote_string(dle->disk);
358         if (dle->device == NULL)
359             dle->device = stralloc(dle->disk);
360         qamdevice = quote_string(dle->device);
361         dumpdate = stralloc("NODATE");
362         stroptions = stralloc("");
363     } else {
364         parse_options(stroptions, dle, g_options->features, 0);
365     }
366     gdle = dle;
367
368     if (dle->program   == NULL ||
369         dle->disk      == NULL ||
370         dle->device    == NULL ||
371         dle->levellist == NULL ||
372         dumpdate       == NULL) {
373         err_extra = _("no valid sendbackup request");
374         goto err;
375     }
376
377     if (g_slist_length(dle->levellist) != 1) {
378         err_extra = _("Too many level");
379         goto err;
380     }
381
382     alevel = (level_t *)dle->levellist->data;
383     level = alevel->level;
384     dbprintf(_("  Parsed request as: program `%s'\n"), dle->program);
385     dbprintf(_("                     disk `%s'\n"), qdisk);
386     dbprintf(_("                     device `%s'\n"), qamdevice);
387     dbprintf(_("                     level %d\n"), level);
388     dbprintf(_("                     since %s\n"), dumpdate);
389     dbprintf(_("                     options `%s'\n"), stroptions);
390     dbprintf(_("                     datapath `%s'\n"),
391                             data_path_to_string(dle->data_path));
392
393     if (dle->program_is_application_api==1) {
394         /* check that the application_api exist */
395     } else {
396         for(i = 0; programs[i]; i++) {
397             if (strcmp(programs[i]->name, dle->program) == 0) {
398                 break;
399             }
400         }
401         if (programs[i] == NULL) {
402             dbprintf(_("ERROR [%s: unknown program %s]\n"), get_pname(),
403                      dle->program);
404             error(_("ERROR [%s: unknown program %s]"), get_pname(),
405                   dle->program);
406             /*NOTREACHED*/
407         }
408         program = programs[i];
409     }
410
411     if(!interactive) {
412         datafd = DATA_FD_OFFSET + 0;
413         mesgfd = DATA_FD_OFFSET + 2;
414         indexfd = DATA_FD_OFFSET + 4;
415     }
416     if (!dle->create_index)
417         indexfd = -1;
418
419     if (dle->auth && amandad_auth) {
420         if(strcasecmp(dle->auth, amandad_auth) != 0) {
421             g_printf(_("ERROR [client configured for auth=%s while server requested '%s']\n"),
422                    amandad_auth, dle->auth);
423             exit(-1);
424         }
425     }
426
427     if (dle->kencrypt) {
428         g_printf("KENCRYPT\n");
429     }
430
431     g_printf(_("CONNECT DATA %d MESG %d INDEX %d\n"),
432            DATA_FD_OFFSET, DATA_FD_OFFSET+1,
433            indexfd == -1 ? -1 : DATA_FD_OFFSET+2);
434     g_printf(_("OPTIONS "));
435     if(am_has_feature(g_options->features, fe_rep_options_features)) {
436         g_printf("features=%s;", our_feature_string);
437     }
438     if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
439         g_printf("hostname=%s;", g_options->hostname);
440     }
441     if (!am_has_feature(g_options->features, fe_rep_options_features) &&
442         !am_has_feature(g_options->features, fe_rep_options_hostname)) {
443         g_printf(";");
444     }
445     g_printf("\n");
446     fflush(stdout);
447     if (freopen("/dev/null", "w", stdout) == NULL) {
448         dbprintf(_("Error redirecting stdout to /dev/null: %s\n"),
449                  strerror(errno));
450         exit(1);
451     }
452
453     if(interactive) {
454       if((datafd = open("/dev/null", O_RDWR)) < 0) {
455         error(_("ERROR [open of /dev/null for debug data stream: %s]\n"),
456                 strerror(errno));
457         /*NOTREACHED*/
458       }
459       mesgfd = 2;
460       indexfd = 1;
461     }
462
463     if(!interactive) {
464       if(datafd == -1 || mesgfd == -1 || (dle->create_index && indexfd == -1)) {
465         dbclose();
466         exit(1);
467       }
468     }
469
470     if (merge_dles_properties(dle, 1) == 0) {
471         g_debug("merge_dles_properties failed");
472         exit(1);
473     }
474     mesgstream = fdopen(mesgfd,"w");
475     run_client_scripts(EXECUTE_ON_PRE_DLE_BACKUP, g_options, dle, mesgstream);
476     fflush(mesgstream);
477
478     if (dle->program_is_application_api==1) {
479         guint j;
480         char *cmd=NULL;
481         GPtrArray *argv_ptr;
482         char levelstr[20];
483         backup_support_option_t *bsu;
484         char *compopt = NULL;
485         char *encryptopt = skip_argument;
486         int compout, dumpout;
487         GSList    *scriptlist;
488         script_t  *script;
489         time_t     cur_dumptime;
490         int        result;
491         GPtrArray *errarray;
492         int        errfd[2];
493         FILE      *dumperr;
494
495         /*  apply client-side encryption here */
496         if ( dle->encrypt == ENCRYPT_CUST ) {
497             encpid = pipespawn(dle->clnt_encrypt, STDIN_PIPE, 0,
498                                &compout, &datafd, &mesgfd,
499                                dle->clnt_encrypt, encryptopt, NULL);
500             dbprintf(_("encrypt: pid %ld: %s\n"), (long)encpid, dle->clnt_encrypt);
501         } else {
502             compout = datafd;
503             encpid = -1;
504         }
505
506         /*  now do the client-side compression */
507         if(dle->compress == COMP_FAST || dle->compress == COMP_BEST) {
508             compopt = skip_argument;
509 #if defined(COMPRESS_BEST_OPT) && defined(COMPRESS_FAST_OPT)
510             if(dle->compress == COMP_BEST) {
511                 compopt = COMPRESS_BEST_OPT;
512             } else {
513                 compopt = COMPRESS_FAST_OPT;
514             }
515 #endif
516             comppid = pipespawn(COMPRESS_PATH, STDIN_PIPE, 0,
517                                 &dumpout, &compout, &mesgfd,
518                                 COMPRESS_PATH, compopt, NULL);
519             if(compopt != skip_argument) {
520                 dbprintf(_("compress pid %ld: %s %s\n"),
521                          (long)comppid, COMPRESS_PATH, compopt);
522             } else {
523                 dbprintf(_("compress pid %ld: %s\n"), (long)comppid, COMPRESS_PATH);
524             }
525         } else if (dle->compress == COMP_CUST) {
526             compopt = skip_argument;
527             comppid = pipespawn(dle->compprog, STDIN_PIPE, 0,
528                                 &dumpout, &compout, &mesgfd,
529                                 dle->compprog, compopt, NULL);
530             if(compopt != skip_argument) {
531                 dbprintf(_("pid %ld: %s %s\n"),
532                          (long)comppid, dle->compprog, compopt);
533             } else {
534                 dbprintf(_("pid %ld: %s\n"), (long)comppid, dle->compprog);
535             }
536         } else {
537             dumpout = compout;
538             comppid = -1;
539         }
540
541         cur_dumptime = time(0);
542         bsu = backup_support_option(dle->program, g_options, dle->disk,
543                                     dle->device, &errarray);
544         if (!bsu) {
545             char  *errmsg;
546             char  *qerrmsg;
547             guint  i;
548             for (i=0; i < errarray->len; i++) {
549                 errmsg = g_ptr_array_index(errarray, i);
550                 qerrmsg = quote_string(errmsg);
551                 fdprintf(mesgfd,
552                           _("sendbackup: error [Application '%s': %s]\n"),
553                           dle->program, errmsg);
554                 dbprintf("aa: %s\n",qerrmsg);
555                 amfree(qerrmsg);
556             }
557             if (i == 0) { /* no errarray */
558                 errmsg = vstrallocf(_("Can't execute application '%s'"),
559                                     dle->program);
560                 qerrmsg = quote_string(errmsg);
561                 fdprintf(mesgfd, _("sendbackup: error [%s]\n"), errmsg);
562                 dbprintf(_("ERROR %s\n"), qerrmsg);
563                 amfree(qerrmsg);
564                 amfree(errmsg);
565             }
566             return 0;
567         }
568
569         if (pipe(errfd) < 0) {
570             char  *errmsg;
571             char  *qerrmsg;
572             errmsg = vstrallocf(_("Application '%s': can't create pipe"),
573                                     dle->program);
574             qerrmsg = quote_string(errmsg);
575             fdprintf(mesgfd, _("sendbackup: error [%s]\n"), errmsg);
576             dbprintf(_("ERROR %s\n"), qerrmsg);
577             amfree(qerrmsg);
578             amfree(errmsg);
579             return 0;
580         }
581
582         switch(application_api_pid=fork()) {
583         case 0:
584             argv_ptr = g_ptr_array_new();
585             cmd = vstralloc(APPLICATION_DIR, "/", dle->program, NULL);
586             g_ptr_array_add(argv_ptr, stralloc(dle->program));
587             g_ptr_array_add(argv_ptr, stralloc("backup"));
588             if (bsu->message_line == 1) {
589                 g_ptr_array_add(argv_ptr, stralloc("--message"));
590                 g_ptr_array_add(argv_ptr, stralloc("line"));
591             }
592             if (g_options->config && bsu->config == 1) {
593                 g_ptr_array_add(argv_ptr, stralloc("--config"));
594                 g_ptr_array_add(argv_ptr, stralloc(g_options->config));
595             }
596             if (g_options->hostname && bsu->host == 1) {
597                 g_ptr_array_add(argv_ptr, stralloc("--host"));
598                 g_ptr_array_add(argv_ptr, stralloc(g_options->hostname));
599             }
600             if (dle->disk && bsu->disk == 1) {
601                 g_ptr_array_add(argv_ptr, stralloc("--disk"));
602                 g_ptr_array_add(argv_ptr, stralloc(dle->disk));
603             }
604             g_ptr_array_add(argv_ptr, stralloc("--device"));
605             g_ptr_array_add(argv_ptr, stralloc(dle->device));
606             if (level <= bsu->max_level) {
607                 g_ptr_array_add(argv_ptr, stralloc("--level"));
608                 g_snprintf(levelstr,19,"%d",level);
609                 g_ptr_array_add(argv_ptr, stralloc(levelstr));
610             }
611             if (indexfd != -1 && bsu->index_line == 1) {
612                 g_ptr_array_add(argv_ptr, stralloc("--index"));
613                 g_ptr_array_add(argv_ptr, stralloc("line"));
614             }
615             if (dle->record && bsu->record == 1) {
616                 g_ptr_array_add(argv_ptr, stralloc("--record"));
617             }
618             application_property_add_to_argv(argv_ptr, dle, bsu,
619                                              g_options->features);
620
621             for (scriptlist = dle->scriptlist; scriptlist != NULL;
622                  scriptlist = scriptlist->next) {
623                 script = (script_t *)scriptlist->data;
624                 if (script->result && script->result->proplist) {
625                     property_add_to_argv(argv_ptr, script->result->proplist);
626                 }
627             }
628
629             g_ptr_array_add(argv_ptr, NULL);
630             dbprintf(_("%s: running \"%s\n"), get_pname(), cmd);
631             for (j = 1; j < argv_ptr->len - 1; j++)
632                 dbprintf(" %s\n", (char *)g_ptr_array_index(argv_ptr,j));
633             dbprintf(_("\"\n"));
634             if(dup2(dumpout, 1) == -1) {
635                 error(_("Can't dup2: %s"),strerror(errno));
636                 /*NOTREACHED*/
637             }
638             if (dup2(errfd[1], 2) == -1) {
639                 error(_("Can't dup2: %s"),strerror(errno));
640                 /*NOTREACHED*/
641             }
642             if(dup2(mesgfd, 3) == -1) {
643                 error(_("Can't dup2: %s"),strerror(errno));
644                 /*NOTREACHED*/
645             }
646             if(indexfd > 0) {
647                 if(dup2(indexfd, 4) == -1) {
648                     error(_("Can't dup2: %s"),strerror(errno));
649                     /*NOTREACHED*/
650                 }
651                 fcntl(indexfd, F_SETFD, 0);
652             }
653             application_api_info_tapeheader(mesgfd, dle->program, dle);
654             if (indexfd != 0) {
655                 safe_fd(3, 2);
656             } else {
657                 safe_fd(3, 1);
658             }
659             execve(cmd, (char **)argv_ptr->pdata, safe_env());
660             exit(1);
661             break;
662  
663         default:
664             break;
665         case -1:
666             error(_("%s: fork returned: %s"), get_pname(), strerror(errno));
667         }
668
669         close(errfd[1]);
670         dumperr = fdopen(errfd[0],"r");
671         if (!dumperr) {
672             error(_("Can't fdopen: %s"), strerror(errno));
673             /*NOTREACHED*/
674         }
675
676         result = 0;
677         while ((line = agets(dumperr)) != NULL) {
678             if (strlen(line) > 0) {
679                 fdprintf(mesgfd, "sendbackup: error [%s]\n", line);
680                 dbprintf("error: %s\n", line);
681                 result = 1;
682             }
683             amfree(line);
684         }
685
686         result |= check_result(mesgfd);
687         if (result == 0) {
688             char *amandates_file;
689
690             amandates_file = getconf_str(CNF_AMANDATES);
691             if(start_amandates(amandates_file, 1)) {
692                 amandates_updateone(dle->disk, level, cur_dumptime);
693                 finish_amandates();
694                 free_amandates();
695             } else {
696                 if (GPOINTER_TO_INT(dle->estimatelist->data) == ES_CALCSIZE &&
697                     bsu->calcsize) {
698                     error(_("error [opening %s for writing: %s]"),
699                           amandates_file, strerror(errno));
700                 } else {
701                     g_debug(_("non-fatal error opening '%s' for writing: %s]"),
702                             amandates_file, strerror(errno));
703                 }
704             }
705         }
706         amfree(bsu);
707      } else {
708         if(!interactive) {
709             /* redirect stderr */
710             if(dup2(mesgfd, 2) == -1) {
711                 dbprintf(_("Error redirecting stderr to fd %d: %s\n"),
712                          mesgfd, strerror(errno));
713                 dbclose();
714                 exit(1);
715             }
716         }
717  
718         if(pipe(mesgpipe) == -1) {
719             s = strerror(errno);
720             dbprintf(_("error [opening mesg pipe: %s]\n"), s);
721             error(_("error [opening mesg pipe: %s]"), s);
722         }
723
724         program->start_backup(dle, g_options->hostname,
725                               datafd, mesgpipe[1], indexfd);
726         dbprintf(_("Started backup\n"));
727         parse_backup_messages(dle, mesgpipe[0]);
728         dbprintf(_("Parsed backup messages\n"));
729     }
730
731     run_client_scripts(EXECUTE_ON_POST_DLE_BACKUP, g_options, dle, mesgstream);
732     fflush(mesgstream);
733
734     amfree(qdisk);
735     amfree(qamdevice);
736     amfree(dumpdate);
737     amfree(stroptions);
738     amfree(our_feature_string);
739     am_release_feature_set(our_features);
740     our_features = NULL;
741     free_g_options(g_options);
742
743     dbclose();
744
745     return 0;
746
747  err:
748     if (err_extra) {
749         g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET '%s'\n"), err_extra);
750         dbprintf(_("REQ packet is bogus: %s\n"), err_extra);
751     } else {
752         g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET\n"));
753         dbprintf(_("REQ packet is bogus\n"));
754     }
755
756     amfree(qdisk);
757     amfree(qamdevice);
758     amfree(dumpdate);
759     amfree(stroptions);
760     amfree(our_feature_string);
761
762     dbclose();
763     return 1;
764 }
765
766
767 /*
768  * Returns a string for a child process.  Checks the saved dump and
769  * compress pids to see which it is.
770  */
771
772 char *
773 childstr(
774     pid_t pid)
775 {
776     if(pid == dumppid) return program->backup_name;
777     if(pid == comppid) return "compress";
778     if(pid == encpid) return "encrypt";
779     if(pid == indexpid) return "index";
780     if(pid == application_api_pid) {
781         if (!gdle) {
782             dbprintf("gdle == NULL\n");
783             return "gdle == NULL";
784         }
785         return gdle->program;
786     }
787     return "unknown";
788 }
789
790
791 /*
792  * Determine if the child return status really indicates an error.
793  * If so, add the error message to the error string; more than one
794  * child can have an error.
795  */
796
797 int
798 check_status(
799     pid_t       pid,
800     amwait_t    w,
801     int         mesgfd)
802 {
803     char *thiserr = NULL;
804     char *str, *strX;
805     int ret, sig, rc;
806
807     str = childstr(pid);
808
809     if(WIFSIGNALED(w)) {
810         ret = 0;
811         rc = sig = WTERMSIG(w);
812     } else {
813         sig = 0;
814         rc = ret = WEXITSTATUS(w);
815     }
816
817     if(pid == indexpid) {
818         /*
819          * Treat an index failure (other than signal) as a "STRANGE"
820          * rather than an error so the dump goes ahead and gets processed
821          * but the failure is noted.
822          */
823         if(ret != 0) {
824             fdprintf(mesgfd, _("? index %s returned %d\n"), str, ret);
825             rc = 0;
826         }
827         indexpid = -1;
828         strX = "index";
829     } else if(pid == comppid) {
830         /*
831          * compress returns 2 sometimes, but it is ok.
832          */
833 #ifndef HAVE_GZIP
834         if(ret == 2) {
835             rc = 0;
836         }
837 #endif
838         comppid = -1;
839         strX = "compress";
840     } else if(pid == dumppid && tarpid == -1) {
841         /*
842          * Ultrix dump returns 1 sometimes, but it is ok.
843          */
844 #ifdef DUMP_RETURNS_1
845         if(ret == 1) {
846             rc = 0;
847         }
848 #endif
849         dumppid = -1;
850         strX = "dump";
851     } else if(pid == tarpid) {
852         if (ret == 1) {
853             rc = 0;
854         }
855         /*
856          * tar bitches about active filesystems, but we do not care.
857          */
858 #ifdef IGNORE_TAR_ERRORS
859         if(ret == 2) {
860             rc = 0;
861         }
862 #endif
863         dumppid = tarpid = -1;
864         strX = "dump";
865     } else if(pid == application_api_pid) {
866         strX = "Application";
867     } else {
868         strX = "unknown";
869     }
870
871     if(rc == 0) {
872         return 0;                               /* normal exit */
873     }
874
875     if(ret == 0) {
876         thiserr = vstrallocf(_("%s (%d) %s got signal %d"), strX, (int)pid, str,
877                              sig);
878     } else {
879         thiserr = vstrallocf(_("%s (%d) %s returned %d"), strX, (int)pid, str, ret);
880     }
881
882     fdprintf(mesgfd, "? %s\n", thiserr);
883
884     if(errorstr) {
885         errorstr =  newvstrallocf(errorstr, "%s, %s", errorstr, thiserr);
886         amfree(thiserr);
887     } else {
888         errorstr = thiserr;
889         thiserr = NULL;
890     }
891     return 1;
892 }
893
894
895 /*
896  *Send header info to the message file.
897  */
898 void
899 info_tapeheader(
900     dle_t *dle)
901 {
902     g_fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
903
904     g_fprintf(stderr, "%s: info RECOVER_CMD=", get_pname());
905     if (dle->compress == COMP_FAST || dle->compress == COMP_BEST)
906         g_fprintf(stderr, "%s %s |", UNCOMPRESS_PATH,
907 #ifdef UNCOMPRESS_OPT
908                 UNCOMPRESS_OPT
909 #else
910                 ""
911 #endif
912                 );
913
914     g_fprintf(stderr, "%s -xpGf - ...\n", program->restore_name);
915
916     if (dle->compress == COMP_FAST || dle->compress == COMP_BEST)
917         g_fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
918                         get_pname(), COMPRESS_SUFFIX);
919
920     g_fprintf(stderr, "%s: info end\n", get_pname());
921 }
922
923 void
924 application_api_info_tapeheader(
925     int       mesgfd,
926     char     *prog,
927     dle_t *dle)
928 {
929     char line[1024];
930
931     g_snprintf(line, 1024, "%s: info BACKUP=APPLICATION\n", get_pname());
932     if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
933         dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
934         return;
935     }
936
937     g_snprintf(line, 1024, "%s: info APPLICATION=%s\n", get_pname(), prog);
938     if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
939         dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
940         return;
941     }
942
943     g_snprintf(line, 1024, "%s: info RECOVER_CMD=", get_pname());
944     if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
945         dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
946         return;
947     }
948
949     if (dle->compress == COMP_FAST || dle->compress == COMP_BEST) {
950         g_snprintf(line, 1024, "%s %s |", UNCOMPRESS_PATH,
951 #ifdef UNCOMPRESS_OPT
952                  UNCOMPRESS_OPT
953 #else
954                  ""
955 #endif
956                  );
957         if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
958             dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
959             return;
960         }
961     }
962     g_snprintf(line, 1024, "%s/%s restore [./file-to-restore]+\n",
963                APPLICATION_DIR, prog);
964     if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
965         dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
966         return;
967     }
968
969     if (dle->compress) {
970         g_snprintf(line, 1024, "%s: info COMPRESS_SUFFIX=%s\n",
971                  get_pname(), COMPRESS_SUFFIX);
972         if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
973             dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
974             return;
975         }
976     }
977
978     g_snprintf(line, 1024, "%s: info end\n", get_pname());
979     if (full_write(mesgfd, line, strlen(line)) != strlen(line)) {
980         dbprintf(_("error writing to mesgfd socket: %s"), strerror(errno));
981         return;
982     }
983 }
984
985 pid_t
986 pipefork(
987     void        (*func)(void),
988     char *      fname,
989     int *       stdinfd,
990     int         stdoutfd,
991     int         stderrfd)
992 {
993     int inpipe[2];
994     pid_t pid;
995
996     dbprintf(_("Forking function %s in pipeline\n"), fname);
997
998     if(pipe(inpipe) == -1) {
999         error(_("error [open pipe to %s: %s]"), fname, strerror(errno));
1000         /*NOTREACHED*/
1001     }
1002
1003     switch(pid = fork()) {
1004     case -1:
1005         error(_("error [fork %s: %s]"), fname, strerror(errno));
1006         /*NOTREACHED*/
1007     default:    /* parent process */
1008         aclose(inpipe[0]);      /* close input side of pipe */
1009         *stdinfd = inpipe[1];
1010         break;
1011     case 0:             /* child process */
1012         aclose(inpipe[1]);      /* close output side of pipe */
1013
1014         if(dup2(inpipe[0], 0) == -1) {
1015             error(_("error [fork %s: dup2(%d, in): %s]"),
1016                   fname, inpipe[0], strerror(errno));
1017             /*NOTRACHED*/
1018         }
1019         if(dup2(stdoutfd, 1) == -1) {
1020             error(_("error [fork %s: dup2(%d, out): %s]"),
1021                   fname, stdoutfd, strerror(errno));
1022             /*NOTRACHED*/
1023         }
1024         if(dup2(stderrfd, 2) == -1) {
1025             error(_("error [fork %s: dup2(%d, err): %s]"),
1026                   fname, stderrfd, strerror(errno));
1027             /*NOTRACHED*/
1028         }
1029
1030         func();
1031         exit(0);
1032         /*NOTREACHED*/
1033     }
1034     return pid;
1035 }
1036
1037 int
1038 check_result(
1039     int mesgfd)
1040 {
1041     int goterror;
1042     pid_t wpid;
1043     amwait_t retstat;
1044
1045     goterror = 0;
1046
1047
1048     while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
1049         if(check_status(wpid, retstat, mesgfd)) goterror = 1;
1050     }
1051
1052     if (dumppid != -1) {
1053         sleep(5);
1054         while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
1055             if(check_status(wpid, retstat, mesgfd)) goterror = 1;
1056         }
1057     }
1058     if (dumppid != -1) {
1059         dbprintf(_("Sending SIGHUP to dump process %d\n"),
1060                   (int)dumppid);
1061         if(dumppid != -1) {
1062             if(kill(dumppid, SIGHUP) == -1) {
1063                 dbprintf(_("Can't send SIGHUP to %d: %s\n"),
1064                           (int)dumppid,
1065                           strerror(errno));
1066             }
1067         }
1068         sleep(5);
1069         while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
1070             if(check_status(wpid, retstat, mesgfd)) goterror = 1;
1071         }
1072     }
1073     if (dumppid != -1) {
1074         dbprintf(_("Sending SIGKILL to dump process %d\n"),
1075                   (int)dumppid);
1076         if(dumppid != -1) {
1077             if(kill(dumppid, SIGKILL) == -1) {
1078                 dbprintf(_("Can't send SIGKILL to %d: %s\n"),
1079                           (int)dumppid,
1080                           strerror(errno));
1081             }
1082         }
1083         sleep(5);
1084         while((wpid = waitpid((pid_t)-1, &retstat, WNOHANG)) > 0) {
1085             if(check_status(wpid, retstat, mesgfd)) goterror = 1;
1086         }
1087     }
1088
1089     return goterror;
1090 }
1091
1092 void
1093 parse_backup_messages(
1094     dle_t      *dle,
1095     int         mesgin)
1096 {
1097     int goterror;
1098     char *line;
1099
1100     amfree(errorstr);
1101
1102     for(; (line = areads(mesgin)) != NULL; free(line)) {
1103         process_dumpline(line);
1104     }
1105
1106     if(errno) {
1107         error(_("error [read mesg pipe: %s]"), strerror(errno));
1108         /*NOTREACHED*/
1109     }
1110
1111     goterror = check_result(mesgfd);
1112
1113     if(errorstr) {
1114         error(_("error [%s]"), errorstr);
1115         /*NOTREACHED*/
1116     } else if(dump_size == -1) {
1117         error(_("error [no backup size line]"));
1118         /*NOTREACHED*/
1119     }
1120
1121     program->end_backup(dle, goterror);
1122
1123     fdprintf(mesgfd, _("%s: size %ld\n"), get_pname(), dump_size);
1124     fdprintf(mesgfd, _("%s: end\n"), get_pname());
1125 }
1126
1127
1128 static void
1129 process_dumpline(
1130     char *      str)
1131 {
1132     amregex_t *rp;
1133     char *type;
1134     char startchr;
1135
1136     for(rp = program->re_table; rp->regex != NULL; rp++) {
1137         if(match(rp->regex, str)) {
1138             break;
1139         }
1140     }
1141     if(rp->typ == DMP_SIZE) {
1142         dump_size = (long)((the_num(str, rp->field)* rp->scale+1023.0)/1024.0);
1143     }
1144     switch(rp->typ) {
1145     case DMP_NORMAL:
1146         type = "normal";
1147         startchr = '|';
1148         break;
1149     case DMP_STRANGE:
1150         type = "strange";
1151         startchr = '?';
1152         break;
1153     case DMP_SIZE:
1154         type = "size";
1155         startchr = '|';
1156         break;
1157     case DMP_ERROR:
1158         type = "error";
1159         startchr = '?';
1160         break;
1161     default:
1162         /*
1163          * Should never get here.
1164          */
1165         type = "unknown";
1166         startchr = '!';
1167         break;
1168     }
1169     dbprintf("%3d: %7s(%c): %s\n",
1170               rp->srcline,
1171               type,
1172               startchr,
1173               str);
1174     fdprintf(mesgfd, "%c %s\n", startchr, str);
1175 }
1176
1177
1178 /*
1179  * start_index.  Creates an index file from the output of dump/tar.
1180  * It arranges that input is the fd to be written by the dump process.
1181  * If createindex is not enabled, it does nothing.  If it is not, a
1182  * new process will be created that tees input both to a pipe whose
1183  * read fd is dup2'ed input and to a program that outputs an index
1184  * file to `index'.
1185  *
1186  * make sure that the chat from restore doesn't go to stderr cause
1187  * this goes back to amanda which doesn't expect to see it
1188  * (2>/dev/null should do it)
1189  *
1190  * Originally by Alan M. McIvor, 13 April 1996
1191  *
1192  * Adapted by Alexandre Oliva, 1 May 1997
1193  *
1194  * This program owes a lot to tee.c from GNU sh-utils and dumptee.c
1195  * from the DeeJay backup package.
1196  */
1197
1198 static void
1199 save_fd(
1200     int *       fd,
1201     int         min)
1202 {
1203   int origfd = *fd;
1204
1205   while (*fd >= 0 && *fd < min) {
1206     int newfd = dup(*fd);
1207     if (newfd == -1)
1208       dbprintf(_("Unable to save file descriptor [%s]\n"), strerror(errno));
1209     *fd = newfd;
1210   }
1211   if (origfd != *fd)
1212     dbprintf(_("Dupped file descriptor %i to %i\n"), origfd, *fd);
1213 }
1214
1215 void
1216 start_index(
1217     int         createindex,
1218     int         input,
1219     int         mesg,
1220     int         index,
1221     char *      cmd)
1222 {
1223   int pipefd[2];
1224   FILE *pipe_fp;
1225   int exitcode;
1226
1227   if (!createindex)
1228     return;
1229
1230   if (pipe(pipefd) != 0) {
1231     error(_("creating index pipe: %s"), strerror(errno));
1232     /*NOTREACHED*/
1233   }
1234
1235   switch(indexpid = fork()) {
1236   case -1:
1237     error(_("forking index tee process: %s"), strerror(errno));
1238     /*NOTREACHED*/
1239
1240   default:
1241     aclose(pipefd[0]);
1242     if (dup2(pipefd[1], input) == -1) {
1243       error(_("dup'ping index tee output: %s"), strerror(errno));
1244       /*NOTREACHED*/
1245     }
1246     aclose(pipefd[1]);
1247     return;
1248
1249   case 0:
1250     break;
1251   }
1252
1253   /* now in a child process */
1254   save_fd(&pipefd[0], 4);
1255   save_fd(&index, 4);
1256   save_fd(&mesg, 4);
1257   save_fd(&input, 4);
1258   dup2(pipefd[0], 0);
1259   dup2(index, 1);
1260   dup2(mesg, 2);
1261   dup2(input, 3);
1262   for(index = 4; index < (int)FD_SETSIZE; index++) {
1263     if (index != dbfd()) {
1264       close(index);
1265     }
1266   }
1267
1268   if ((pipe_fp = popen(cmd, "w")) == NULL) {
1269     error(_("couldn't start index creator [%s]"), strerror(errno));
1270     /*NOTREACHED*/
1271   }
1272
1273   dbprintf(_("Started index creator: \"%s\"\n"), cmd);
1274   while(1) {
1275     char buffer[BUFSIZ], *ptr;
1276     ssize_t bytes_read;
1277     size_t bytes_written;
1278     size_t just_written;
1279
1280     do {
1281         bytes_read = read(0, buffer, SIZEOF(buffer));
1282     } while ((bytes_read < 0) && ((errno == EINTR) || (errno == EAGAIN)));
1283
1284     if (bytes_read < 0) {
1285       error(_("index tee cannot read [%s]"), strerror(errno));
1286       /*NOTREACHED*/
1287     }
1288
1289     if (bytes_read == 0)
1290       break; /* finished */
1291
1292     /* write the stuff to the subprocess */
1293     ptr = buffer;
1294     bytes_written = 0;
1295     just_written = full_write(fileno(pipe_fp), ptr, (size_t)bytes_read);
1296     if (just_written < (size_t)bytes_read) {
1297         /* 
1298          * just as we waited for write() to complete.
1299          */
1300         if (errno != EPIPE) {
1301             dbprintf(_("Index tee cannot write to index creator [%s]\n"),
1302                             strerror(errno));
1303         }
1304     } else {
1305         bytes_written += just_written;
1306         ptr += just_written;
1307     }
1308
1309     /* write the stuff to stdout, ensuring none lost when interrupt
1310        occurs */
1311     ptr = buffer;
1312     bytes_written = 0;
1313     just_written = full_write(3, ptr, bytes_read);
1314     if (just_written < (size_t)bytes_read) {
1315         error(_("index tee cannot write [%s]"), strerror(errno));
1316         /*NOTREACHED*/
1317     } else {
1318         bytes_written += just_written;
1319         ptr += just_written;
1320     }
1321   }
1322
1323   aclose(pipefd[1]);
1324
1325   /* finished */
1326   /* check the exit code of the pipe and moan if not 0 */
1327   if ((exitcode = pclose(pipe_fp)) != 0) {
1328     char *exitstr = str_exit_status("Index pipe", exitcode);
1329     dbprintf("%s\n", exitstr);
1330     amfree(exitstr);
1331   } else {
1332     dbprintf(_("Index created successfully\n"));
1333   }
1334   pipe_fp = NULL;
1335
1336   exit(exitcode);
1337 }
1338
1339 extern backup_program_t dump_program, gnutar_program;
1340
1341 backup_program_t *programs[] = {
1342   &dump_program, &gnutar_program, NULL
1343 };