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