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