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