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