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