Imported Upstream version 3.3.2
[debian/amanda] / server-src / dumper.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 /* $Id: dumper.c,v 1.190 2006/08/30 19:53:57 martinea Exp $
27  *
28  * requests remote amandad processes to dump filesystems
29  */
30 #include "amanda.h"
31 #include "amindex.h"
32 #include "arglist.h"
33 #include "clock.h"
34 #include "conffile.h"
35 #include "event.h"
36 #include "logfile.h"
37 #include "packet.h"
38 #include "protocol.h"
39 #include "security.h"
40 #include "stream.h"
41 #include "fileheader.h"
42 #include "amfeatures.h"
43 #include "server_util.h"
44 #include "util.h"
45 #include "timestamp.h"
46 #include "amxml.h"
47
48 #define dumper_debug(i,x) do {          \
49         if ((i) <= debug_dumper) {      \
50             dbprintf(x);                \
51         }                               \
52 } while (0)
53
54 #ifndef SEEK_SET
55 #define SEEK_SET 0
56 #endif
57
58 #ifndef SEEK_CUR
59 #define SEEK_CUR 1
60 #endif
61
62 #define CONNECT_TIMEOUT 5*60
63
64 #define STARTUP_TIMEOUT 60
65
66 struct databuf {
67     int fd;                     /* file to flush to */
68     char *buf;
69     char *datain;               /* data buffer markers */
70     char *dataout;
71     char *datalimit;
72     pid_t compresspid;          /* valid if fd is pipe to compress */
73     pid_t encryptpid;           /* valid if fd is pipe to encrypt */
74 };
75
76 struct databuf *g_databuf = NULL;
77
78 typedef struct filter_s {
79     int             fd;
80     char           *name;
81     char           *buffer;
82     gint64          first;           /* first byte used */
83     gint64          size;            /* number of byte use in the buffer */
84     gint64          allocated_size ; /* allocated size of the buffer     */
85     event_handle_t *event;
86 } filter_t;
87
88 static char *handle = NULL;
89
90 static char *errstr = NULL;
91 static off_t dumpbytes;
92 static off_t dumpsize, headersize, origsize;
93
94 static comp_t srvcompress = COMP_NONE;
95 char *srvcompprog = NULL;
96 char *clntcompprog = NULL;
97
98 static encrypt_t srvencrypt = ENCRYPT_NONE;
99 char *srv_encrypt = NULL;
100 char *clnt_encrypt = NULL;
101 char *srv_decrypt_opt = NULL;
102 char *clnt_decrypt_opt = NULL;
103 static kencrypt_type dumper_kencrypt;
104
105 static FILE *errf = NULL;
106 static char *hostname = NULL;
107 am_feature_t *their_features = NULL;
108 static char *diskname = NULL;
109 static char *qdiskname = NULL, *b64disk;
110 static char *device = NULL, *b64device;
111 static char *options = NULL;
112 static char *progname = NULL;
113 static char *amandad_path=NULL;
114 static char *client_username=NULL;
115 static char *client_port=NULL;
116 static char *ssh_keys=NULL;
117 static char *auth=NULL;
118 static data_path_t data_path=DATA_PATH_AMANDA;
119 static char *dataport_list = NULL;
120 static int level;
121 static char *dumpdate = NULL;
122 static char *dumper_timestamp = NULL;
123 static time_t conf_dtimeout;
124 static int indexfderror;
125 static int set_datafd;
126 static char *dle_str = NULL;
127 static char *errfname = NULL;
128 static int   errf_lines = 0;
129 static int   max_warnings = 0;
130
131 static dumpfile_t file;
132
133 static struct {
134     const char *name;
135     security_stream_t *fd;
136 } streams[] = {
137 #define DATAFD  0
138     { "DATA", NULL },
139 #define MESGFD  1
140     { "MESG", NULL },
141 #define INDEXFD 2
142     { "INDEX", NULL },
143 };
144 #define NSTREAMS        (int)(sizeof(streams) / sizeof(streams[0]))
145
146 static am_feature_t *our_features = NULL;
147 static char *our_feature_string = NULL;
148
149 /* buffer to keep partial line from the MESG stream */
150 static struct {
151     char *buf;          /* buffer holding msg data */
152     size_t size;        /* size of alloced buffer */
153 } msg = { NULL, 0 };
154
155
156 /* local functions */
157 int             main(int, char **);
158 static int      do_dump(struct databuf *);
159 static void     check_options(char *);
160 static void     xml_check_options(char *optionstr);
161 static void     finish_tapeheader(dumpfile_t *);
162 static ssize_t  write_tapeheader(int, dumpfile_t *);
163 static void     databuf_init(struct databuf *, int);
164 static int      databuf_write(struct databuf *, const void *, size_t);
165 static int      databuf_flush(struct databuf *);
166 static void     process_dumpeof(void);
167 static void     process_dumpline(const char *);
168 static void     add_msg_data(const char *, size_t);
169 static void     parse_info_line(char *);
170 static int      log_msgout(logtype_t);
171 static char *   dumper_get_security_conf (char *, void *);
172
173 static int      runcompress(int, pid_t *, comp_t, char *);
174 static int      runencrypt(int, pid_t *,  encrypt_t);
175
176 static void     sendbackup_response(void *, pkt_t *, security_handle_t *);
177 static int      startup_dump(const char *, const char *, const char *, int,
178                         const char *, const char *, const char *,
179                         const char *, const char *, const char *,
180                         const char *, const char *);
181 static void     stop_dump(void);
182
183 static void     read_indexfd(void *, void *, ssize_t);
184 static void     read_datafd(void *, void *, ssize_t);
185 static void     read_mesgfd(void *, void *, ssize_t);
186 static void     timeout(time_t);
187 static void     timeout_callback(void *);
188
189 static void
190 check_options(
191     char *options)
192 {
193   char *compmode = NULL;
194   char *compend  = NULL;
195   char *encryptmode = NULL;
196   char *encryptend = NULL;
197   char *decryptmode = NULL;
198   char *decryptend = NULL;
199
200     /* parse the compression option */
201     if (strstr(options, "srvcomp-best;") != NULL) 
202       srvcompress = COMP_BEST;
203     else if (strstr(options, "srvcomp-fast;") != NULL)
204       srvcompress = COMP_FAST;
205     else if ((compmode = strstr(options, "srvcomp-cust=")) != NULL) {
206         compend = strchr(compmode, ';');
207         if (compend ) {
208             srvcompress = COMP_SERVER_CUST;
209             *compend = '\0';
210             srvcompprog = stralloc(compmode + strlen("srvcomp-cust="));
211             *compend = ';';
212         }
213     } else if ((compmode = strstr(options, "comp-cust=")) != NULL) {
214         compend = strchr(compmode, ';');
215         if (compend) {
216             srvcompress = COMP_CUST;
217             *compend = '\0';
218             clntcompprog = stralloc(compmode + strlen("comp-cust="));
219             *compend = ';';
220         }
221     }
222     else {
223       srvcompress = COMP_NONE;
224     }
225     
226
227     /* now parse the encryption option */
228     if ((encryptmode = strstr(options, "encrypt-serv-cust=")) != NULL) {
229       encryptend = strchr(encryptmode, ';');
230       if (encryptend) {
231             srvencrypt = ENCRYPT_SERV_CUST;
232             *encryptend = '\0';
233             srv_encrypt = stralloc(encryptmode + strlen("encrypt-serv-cust="));
234             *encryptend = ';';
235       }
236     } else if ((encryptmode = strstr(options, "encrypt-cust=")) != NULL) {
237       encryptend = strchr(encryptmode, ';');
238       if (encryptend) {
239             srvencrypt = ENCRYPT_CUST;
240             *encryptend = '\0';
241             clnt_encrypt = stralloc(encryptmode + strlen("encrypt-cust="));
242             *encryptend = ';';
243       }
244     } else {
245       srvencrypt = ENCRYPT_NONE;
246     }
247     /* get the decryption option parameter */
248     if ((decryptmode = strstr(options, "server-decrypt-option=")) != NULL) {
249       decryptend = strchr(decryptmode, ';');
250       if (decryptend) {
251         *decryptend = '\0';
252         srv_decrypt_opt = stralloc(decryptmode + strlen("server-decrypt-option="));
253         *decryptend = ';';
254       }
255     } else if ((decryptmode = strstr(options, "client-decrypt-option=")) != NULL) {
256       decryptend = strchr(decryptmode, ';');
257       if (decryptend) {
258         *decryptend = '\0';
259         clnt_decrypt_opt = stralloc(decryptmode + strlen("client-decrypt-option="));
260         *decryptend = ';';
261       }
262     }
263
264     if (strstr(options, "kencrypt;") != NULL) {
265         dumper_kencrypt = KENCRYPT_WILL_DO;
266     } else {
267         dumper_kencrypt = KENCRYPT_NONE;
268     }
269 }
270
271
272 static void
273 xml_check_options(
274     char *optionstr)
275 {
276     char *o, *oo;
277     char *errmsg = NULL;
278     dle_t *dle;
279
280     o = oo = vstralloc("<dle>", strchr(optionstr,'<'), "</dle>", NULL);
281
282     dle = amxml_parse_node_CHAR(o, &errmsg);
283     if (dle == NULL) {
284         error("amxml_parse_node_CHAR failed: %s\n", errmsg);
285     }
286
287     if (dle->compress == COMP_SERVER_FAST) {
288         srvcompress = COMP_FAST;
289     } else if (dle->compress == COMP_SERVER_BEST) {
290         srvcompress = COMP_BEST;
291     } else if (dle->compress == COMP_SERVER_CUST) {
292         srvcompress = COMP_SERVER_CUST;
293         srvcompprog = g_strdup(dle->compprog);
294     } else if (dle->compress == COMP_CUST) {
295         srvcompress = COMP_CUST;
296         clntcompprog = g_strdup(dle->compprog);
297     } else {
298         srvcompress = COMP_NONE;
299     }
300
301     if (dle->encrypt == ENCRYPT_CUST) {
302         srvencrypt = ENCRYPT_CUST;
303         clnt_encrypt = g_strdup(dle->clnt_encrypt);
304         clnt_decrypt_opt = g_strdup(dle->clnt_decrypt_opt);
305     } else if (dle->encrypt == ENCRYPT_SERV_CUST) {
306         srvencrypt = ENCRYPT_SERV_CUST;
307         srv_encrypt = g_strdup(dle->srv_encrypt);
308         srv_decrypt_opt = g_strdup(dle->srv_decrypt_opt);
309     } else {
310         srvencrypt = ENCRYPT_NONE;
311     }
312     free_dle(dle);
313     amfree(o);
314 }
315
316
317 int
318 main(
319     int         argc,
320     char **     argv)
321 {
322     static struct databuf db;
323     struct cmdargs *cmdargs = NULL;
324     int outfd = -1;
325     int rc;
326     in_port_t header_port;
327     char *q = NULL;
328     int a;
329     int res;
330     config_overrides_t *cfg_ovr = NULL;
331     char *cfg_opt = NULL;
332     int dumper_setuid;
333
334     if (argc > 1 && argv && argv[1] && g_str_equal(argv[1], "--version")) {
335         printf("dumper-%s\n", VERSION);
336         return (0);
337     }
338
339     /*
340      * Configure program for internationalization:
341      *   1) Only set the message locale for now.
342      *   2) Set textdomain for all amanda related programs to "amanda"
343      *      We don't want to be forced to support dozens of message catalogs.
344      */  
345     setlocale(LC_MESSAGES, "C");
346     textdomain("amanda"); 
347
348     /* drop root privileges */
349     dumper_setuid = set_root_privs(0);
350
351     safe_fd(-1, 0);
352
353     set_pname("dumper");
354
355     dbopen(DBG_SUBDIR_SERVER);
356
357     /* Don't die when child closes pipe */
358     signal(SIGPIPE, SIG_IGN);
359
360     add_amanda_log_handler(amanda_log_stderr);
361     add_amanda_log_handler(amanda_log_trace_log);
362
363     cfg_ovr = extract_commandline_config_overrides(&argc, &argv);
364     if (argc > 1)
365         cfg_opt = argv[1];
366     set_config_overrides(cfg_ovr);
367     config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt);
368
369     if (!dumper_setuid) {
370         error(_("dumper must be run setuid root"));
371     }
372
373     if (config_errors(NULL) >= CFGERR_ERRORS) {
374         g_critical(_("errors processing config file"));
375     }
376
377     safe_cd(); /* do this *after* config_init() */
378
379     check_running_as(RUNNING_AS_ROOT | RUNNING_AS_UID_ONLY);
380
381     dbrename(get_config_name(), DBG_SUBDIR_SERVER);
382
383     our_features = am_init_feature_set();
384     our_feature_string = am_feature_to_string(our_features);
385
386     log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid());
387     g_fprintf(stderr,
388             _("%s: pid %ld executable %s version %s\n"),
389             get_pname(), (long) getpid(),
390             argv[0], VERSION);
391     fflush(stderr);
392
393     /* now, make sure we are a valid user */
394
395     signal(SIGPIPE, SIG_IGN);
396
397     conf_dtimeout = (time_t)getconf_int(CNF_DTIMEOUT);
398
399     protocol_init();
400
401     do {
402         if (cmdargs)
403             free_cmdargs(cmdargs);
404         cmdargs = getcmd();
405
406         amfree(errstr);
407         switch(cmdargs->cmd) {
408         case START:
409             if(cmdargs->argc <  2)
410                 error(_("error [dumper START: not enough args: timestamp]"));
411             dumper_timestamp = newstralloc(dumper_timestamp, cmdargs->argv[1]);
412             break;
413
414         case ABORT:
415             break;
416
417         case QUIT:
418             break;
419
420         case PORT_DUMP:
421             /*
422              * PORT-DUMP
423              *   handle
424              *   port
425              *   host
426              *   features
427              *   disk
428              *   device
429              *   level
430              *   dumpdate
431              *   progname
432              *   amandad_path
433              *   client_username
434              *   client_port
435              *   ssh_keys
436              *   security_driver
437              *   data_path
438              *   dataport_list
439              *   options
440              */
441             a = 1; /* skip "PORT-DUMP" */
442
443             if(a >= cmdargs->argc) {
444                 error(_("error [dumper PORT-DUMP: not enough args: handle]"));
445                 /*NOTREACHED*/
446             }
447             handle = newstralloc(handle, cmdargs->argv[a++]);
448
449             if(a >= cmdargs->argc) {
450                 error(_("error [dumper PORT-DUMP: not enough args: port]"));
451                 /*NOTREACHED*/
452             }
453             header_port = (in_port_t)atoi(cmdargs->argv[a++]);
454
455             if(a >= cmdargs->argc) {
456                 error(_("error [dumper PORT-DUMP: not enough args: hostname]"));
457                 /*NOTREACHED*/
458             }
459             hostname = newstralloc(hostname, cmdargs->argv[a++]);
460
461             if(a >= cmdargs->argc) {
462                 error(_("error [dumper PORT-DUMP: not enough args: features]"));
463                 /*NOTREACHED*/
464             }
465             am_release_feature_set(their_features);
466             their_features = am_string_to_feature(cmdargs->argv[a++]);
467
468             if(a >= cmdargs->argc) {
469                 error(_("error [dumper PORT-DUMP: not enough args: diskname]"));
470                 /*NOTREACHED*/
471             }
472             diskname = newstralloc(diskname, cmdargs->argv[a++]);
473             if (qdiskname != NULL)
474                 amfree(qdiskname);
475             qdiskname = quote_string(diskname);
476             b64disk = amxml_format_tag("disk", diskname);
477
478             if(a >= cmdargs->argc) {
479                 error(_("error [dumper PORT-DUMP: not enough args: device]"));
480                 /*NOTREACHED*/
481             }
482             device = newstralloc(device, cmdargs->argv[a++]);
483             b64device = amxml_format_tag("diskdevice", device);
484             if(strcmp(device,"NODEVICE") == 0)
485                 amfree(device);
486
487             if(a >= cmdargs->argc) {
488                 error(_("error [dumper PORT-DUMP: not enough args: level]"));
489                 /*NOTREACHED*/
490             }
491             level = atoi(cmdargs->argv[a++]);
492
493             if(a >= cmdargs->argc) {
494                 error(_("error [dumper PORT-DUMP: not enough args: dumpdate]"));
495                 /*NOTREACHED*/
496             }
497             dumpdate = newstralloc(dumpdate, cmdargs->argv[a++]);
498
499             if(a >= cmdargs->argc) {
500                 error(_("error [dumper PORT-DUMP: not enough args: program]"));
501                 /*NOTREACHED*/
502             }
503             progname = newstralloc(progname, cmdargs->argv[a++]);
504
505             if(a >= cmdargs->argc) {
506                 error(_("error [dumper PORT-DUMP: not enough args: amandad_path]"));
507                 /*NOTREACHED*/
508             }
509             amandad_path = newstralloc(amandad_path, cmdargs->argv[a++]);
510
511             if(a >= cmdargs->argc) {
512                 error(_("error [dumper PORT-DUMP: not enough args: client_username]"));
513             }
514             client_username = newstralloc(client_username, cmdargs->argv[a++]);
515
516             if(a >= cmdargs->argc) {
517                 error(_("error [dumper PORT-DUMP: not enough args: client_port]"));
518             }
519             client_port = newstralloc(client_port, cmdargs->argv[a++]);
520
521             if(a >= cmdargs->argc) {
522                 error(_("error [dumper PORT-DUMP: not enough args: ssh_keys]"));
523             }
524             ssh_keys = newstralloc(ssh_keys, cmdargs->argv[a++]);
525
526             if(a >= cmdargs->argc) {
527                 error(_("error [dumper PORT-DUMP: not enough args: auth]"));
528             }
529             auth = newstralloc(auth, cmdargs->argv[a++]);
530
531             if(a >= cmdargs->argc) {
532                 error(_("error [dumper PORT-DUMP: not enough args: data_path]"));
533             }
534             data_path = data_path_from_string(cmdargs->argv[a++]);
535
536             if(a >= cmdargs->argc) {
537                 error(_("error [dumper PORT-DUMP: not enough args: dataport_list]"));
538             }
539             dataport_list = newstralloc(dataport_list, cmdargs->argv[a++]);
540
541             if(a >= cmdargs->argc) {
542                 error(_("error [dumper PORT-DUMP: not enough args: max_warnings]"));
543             }
544             max_warnings = atoi(cmdargs->argv[a++]);
545
546             if(a >= cmdargs->argc) {
547                 error(_("error [dumper PORT-DUMP: not enough args: options]"));
548             }
549             options = newstralloc(options, cmdargs->argv[a++]);
550
551             if(a != cmdargs->argc) {
552                 error(_("error [dumper PORT-DUMP: too many args: %d != %d]"),
553                       cmdargs->argc, a);
554                 /*NOTREACHED*/
555             }
556
557             /* Double-check that 'localhost' resolves properly */
558             if ((res = resolve_hostname("localhost", 0, NULL, NULL) != 0)) {
559                 errstr = newvstrallocf(errstr,
560                                      _("could not resolve localhost: %s"),
561                                      gai_strerror(res));
562                 q = quote_string(errstr);
563                 putresult(FAILED, "%s %s\n", handle, q);
564                 log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname,
565                         dumper_timestamp, level, errstr);
566                 amfree(q);
567                 break;
568             }
569
570             /* connect outf to chunker/taper port */
571
572             g_debug(_("Sending header to localhost:%d\n"), header_port);
573             outfd = stream_client("localhost", header_port,
574                                   STREAM_BUFSIZE, 0, NULL, 0);
575             if (outfd == -1) {
576                 
577                 errstr = newvstrallocf(errstr, _("port open: %s"),
578                                       strerror(errno));
579                 q = quote_string(errstr);
580                 putresult(FAILED, "%s %s\n", handle, q);
581                 log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname,
582                         dumper_timestamp, level, errstr);
583                 amfree(q);
584                 break;
585             }
586             databuf_init(&db, outfd);
587             g_databuf = &db;
588
589             if (am_has_feature(their_features, fe_req_xml))
590                 xml_check_options(options); /* note: modifies globals */
591             else
592                 check_options(options); /* note: modifies globals */
593
594             rc = startup_dump(hostname,
595                               diskname,
596                               device,
597                               level,
598                               dumpdate,
599                               progname,
600                               amandad_path,
601                               client_username,
602                               client_port,
603                               ssh_keys,
604                               auth,
605                               options);
606             if (rc != 0) {
607                 q = quote_string(errstr);
608                 putresult(rc == 2? FAILED : TRYAGAIN, "%s %s\n",
609                     handle, q);
610                 if (rc == 2)
611                     log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname,
612                         dumper_timestamp, level, errstr);
613                 amfree(q);
614             } else {
615                 do_dump(&db);
616                 /* try to clean up any defunct processes, since Amanda doesn't
617                    wait() for them explicitly */
618                 while(waitpid(-1, NULL, WNOHANG)> 0);
619             }
620
621             amfree(amandad_path);
622             amfree(client_username);
623             amfree(client_port);
624             amfree(device);
625             amfree(b64device);
626             amfree(qdiskname);
627             amfree(b64disk);
628
629             break;
630
631         default:
632             if(cmdargs->argc >= 1) {
633                 q = quote_string(cmdargs->argv[0]);
634             } else {
635                 q = stralloc(_("(no input?)"));
636             }
637             putresult(BAD_COMMAND, "%s\n", q);
638             amfree(q);
639             break;
640         }
641
642         if (outfd != -1)
643             aclose(outfd);
644     } while(cmdargs->cmd != QUIT);
645     free_cmdargs(cmdargs);
646
647     log_add(L_INFO, "pid-done %ld", (long)getpid());
648
649     am_release_feature_set(our_features);
650     amfree(our_feature_string);
651     amfree(errstr);
652     amfree(dumper_timestamp);
653     amfree(handle);
654     amfree(hostname);
655     amfree(qdiskname);
656     amfree(diskname);
657     amfree(device);
658     amfree(dumpdate);
659     amfree(progname);
660     amfree(srvcompprog);
661     amfree(clntcompprog);
662     amfree(srv_encrypt);
663     amfree(clnt_encrypt);
664     amfree(srv_decrypt_opt);
665     amfree(clnt_decrypt_opt);
666     amfree(options);
667
668     dbclose();
669     return (0); /* exit */
670 }
671
672
673 /*
674  * Initialize a databuf.  Takes a writeable file descriptor.
675  */
676 static void
677 databuf_init(
678     struct databuf *    db,
679     int                 fd)
680 {
681
682     db->fd = fd;
683     db->datain = db->dataout = db->datalimit = NULL;
684     db->compresspid = -1;
685     db->encryptpid = -1;
686 }
687
688
689 /*
690  * Updates the buffer pointer for the input data buffer.  The buffer is
691  * written regardless of how much data is present, since we know we
692  * are writing to a socket (to chunker) and there is no need to maintain
693  * any boundaries.
694  */
695 static int
696 databuf_write(
697     struct databuf *    db,
698     const void *        buf,
699     size_t              size)
700 {
701     db->buf = (char *)buf;
702     db->datain = db->datalimit = db->buf + size;
703     db->dataout = db->buf;
704     return databuf_flush(db);
705 }
706
707 /*
708  * Write out the buffer to chunker.
709  */
710 static int
711 databuf_flush(
712     struct databuf *    db)
713 {
714     size_t written;
715     char *m;
716
717     /*
718      * If there's no data, do nothing.
719      */
720     if (db->dataout >= db->datain) {
721         return 0;
722     }
723
724     /*
725      * Write out the buffer
726      */
727     written = full_write(db->fd, db->dataout,
728                         (size_t)(db->datain - db->dataout));
729     if (written > 0) {
730         db->dataout += written;
731         dumpbytes += (off_t)written;
732     }
733     if (dumpbytes >= (off_t)1024) {
734         dumpsize += (dumpbytes / (off_t)1024);
735         dumpbytes %= (off_t)1024;
736     }
737     if (written == 0) {
738         int save_errno = errno;
739         m = vstrallocf(_("data write: %s"), strerror(save_errno));
740         amfree(errstr);
741         errstr = quote_string(m);
742         amfree(m);
743         errno = save_errno;
744         return -1;
745     }
746     db->datain = db->dataout = db->buf;
747     return 0;
748 }
749
750 static int dump_result;
751 static int status;
752 #define GOT_INFO_ENDLINE        (1 << 0)
753 #define GOT_SIZELINE            (1 << 1)
754 #define GOT_ENDLINE             (1 << 2)
755 #define HEADER_DONE             (1 << 3)
756
757
758 static void
759 process_dumpeof(void)
760 {
761     /* process any partial line in msgbuf? !!! */
762     add_msg_data(NULL, 0);
763     if(!ISSET(status, GOT_SIZELINE) && dump_result < 2) {
764         /* make a note if there isn't already a failure */
765         g_fprintf(errf,
766                 _("? %s: strange [missing size line from sendbackup]\n"),
767                 get_pname());
768         if(errstr == NULL) {
769             errstr = stralloc(_("missing size line from sendbackup"));
770         }
771         dump_result = max(dump_result, 2);
772     }
773
774     if(!ISSET(status, GOT_ENDLINE) && dump_result < 2) {
775         g_fprintf(errf,
776                 _("? %s: strange [missing end line from sendbackup]\n"),
777                 get_pname());
778         if(errstr == NULL) {
779             errstr = stralloc(_("missing end line from sendbackup"));
780         }
781         dump_result = max(dump_result, 2);
782     }
783 }
784
785 /*
786  * Parse an information line from the client.
787  * We ignore unknown parameters and only remember the last
788  * of any duplicates.
789  */
790 static void
791 parse_info_line(
792     char *str)
793 {
794     static const struct {
795         const char *name;
796         char *value;
797         size_t len;
798     } fields[] = {
799         { "BACKUP", file.program, SIZEOF(file.program) },
800         { "APPLICATION", file.application, SIZEOF(file.application) },
801         { "RECOVER_CMD", file.recover_cmd, SIZEOF(file.recover_cmd) },
802         { "COMPRESS_SUFFIX", file.comp_suffix, SIZEOF(file.comp_suffix) },
803         { "SERVER_CUSTOM_COMPRESS", file.srvcompprog, SIZEOF(file.srvcompprog) },
804         { "CLIENT_CUSTOM_COMPRESS", file.clntcompprog, SIZEOF(file.clntcompprog) },
805         { "SERVER_ENCRYPT", file.srv_encrypt, SIZEOF(file.srv_encrypt) },
806         { "CLIENT_ENCRYPT", file.clnt_encrypt, SIZEOF(file.clnt_encrypt) },
807         { "SERVER_DECRYPT_OPTION", file.srv_decrypt_opt, SIZEOF(file.srv_decrypt_opt) },
808         { "CLIENT_DECRYPT_OPTION", file.clnt_decrypt_opt, SIZEOF(file.clnt_decrypt_opt) }
809     };
810     char *name, *value;
811     size_t i;
812
813     if (strcmp(str, "end") == 0) {
814         SET(status, GOT_INFO_ENDLINE);
815         return;
816     }
817
818     name = strtok(str, "=");
819     if (name == NULL)
820         return;
821     value = strtok(NULL, "");
822     if (value == NULL)
823         return;
824
825     for (i = 0; i < SIZEOF(fields) / SIZEOF(fields[0]); i++) {
826         if (strcmp(name, fields[i].name) == 0) {
827             strncpy(fields[i].value, value, fields[i].len - 1);
828             fields[i].value[fields[i].len - 1] = '\0';
829             break;
830         }
831     }
832 }
833
834 static void
835 process_dumpline(
836     const char *        str)
837 {
838     char *buf, *tok;
839
840     buf = stralloc(str);
841
842     switch (*buf) {
843     case '|':
844         /* normal backup output line */
845         break;
846     case '?':
847         /* sendbackup detected something strange */
848         dump_result = max(dump_result, 1);
849         break;
850     case 's':
851         /* a sendbackup line, just check them all since there are only 5 */
852         tok = strtok(buf, " ");
853         if (tok == NULL || strcmp(tok, "sendbackup:") != 0)
854             goto bad_line;
855
856         tok = strtok(NULL, " ");
857         if (tok == NULL)
858             goto bad_line;
859
860         if (strcmp(tok, "start") == 0) {
861             break;
862         }
863
864         if (strcmp(tok, "size") == 0) {
865             tok = strtok(NULL, "");
866             if (tok != NULL) {
867                 origsize = OFF_T_ATOI(tok);
868                 SET(status, GOT_SIZELINE);
869             }
870             break;
871         }
872
873         if (strcmp(tok, "no-op") == 0) {
874             amfree(buf);
875             return;
876         }
877
878         if (strcmp(tok, "end") == 0) {
879             SET(status, GOT_ENDLINE);
880             break;
881         }
882
883         if (strcmp(tok, "warning") == 0) {
884             dump_result = max(dump_result, 1);
885             break;
886         }
887
888         if (strcmp(tok, "error") == 0) {
889             SET(status, GOT_ENDLINE);
890             dump_result = max(dump_result, 2);
891
892             tok = strtok(NULL, "");
893             if (!errstr) { /* report first error line */
894                 if (tok == NULL || *tok != '[') {
895                     errstr = newvstrallocf(errstr, _("bad remote error: %s"),
896                                            str);
897                 } else {
898                     char *enderr;
899
900                     tok++;      /* skip over '[' */
901                     if ((enderr = strchr(tok, ']')) != NULL)
902                         *enderr = '\0';
903                     errstr = newstralloc(errstr, tok);
904                 }
905             }
906             break;
907         }
908
909         if (strcmp(tok, "info") == 0) {
910             tok = strtok(NULL, "");
911             if (tok != NULL)
912                 parse_info_line(tok);
913             break;
914         }
915         /* else we fall through to bad line */
916     default:
917 bad_line:
918         /* prefix with ?? */
919         g_fprintf(errf, "??");
920         dump_result = max(dump_result, 1);
921         break;
922     }
923     g_fprintf(errf, "%s\n", str);
924     errf_lines++;
925     amfree(buf);
926 }
927
928 static void
929 add_msg_data(
930     const char *        str,
931     size_t              len)
932 {
933     char *line, *ch;
934     size_t buflen;
935
936     if (msg.buf != NULL)
937         buflen = strlen(msg.buf);
938     else
939         buflen = 0;
940
941     /*
942      * If our argument is NULL, then we need to flush out any remaining
943      * bits and return.
944      */
945     if (str == NULL) {
946         if (buflen == 0)
947             return;
948         g_fprintf(errf,_("? %s: error [partial line in msgbuf: %zu bytes]\n"),
949             get_pname(), buflen);
950         g_fprintf(errf,_("? %s: error [partial line in msgbuf: \"%s\"]\n"),
951             get_pname(), msg.buf);
952         msg.buf[0] = '\0';
953         return;
954     }
955
956     /*
957      * Expand the buffer if it can't hold the new contents.
958      */
959     if ((buflen + len + 1) > msg.size) {
960         char *newbuf;
961         size_t newsize;
962
963 /* round up to next y, where y is a power of 2 */
964 #define ROUND(x, y)     (((x) + (y) - 1) & ~((y) - 1))
965
966         newsize = ROUND(buflen + (ssize_t)len + 1, 256);
967         newbuf = alloc(newsize);
968
969         if (msg.buf != NULL) {
970             strncpy(newbuf, msg.buf, newsize);
971             amfree(msg.buf);
972         } else
973             newbuf[0] = '\0';
974         msg.buf = newbuf;
975         msg.size = newsize;
976     }
977
978     /*
979      * If there was a partial line from the last call, then
980      * append the new data to the end.
981      */
982     strncat(msg.buf, str, len);
983
984     /*
985      * Process all lines in the buffer
986      * scanning line for unqouted newline.
987      */
988     for (ch = line = msg.buf; *ch != '\0'; ch++) {
989         if (*ch == '\n') {
990             /*
991              * Found a newline.  Terminate and process line.
992              */
993             *ch = '\0';
994             process_dumpline(line);
995             line = ch + 1;
996         }
997     }
998
999     /*
1000      * If we did not process all of the data, move it to the front
1001      * of the buffer so it is there next time.
1002      */
1003     if (*line != '\0') {
1004         buflen = strlen(line);
1005         memmove(msg.buf, line, (size_t)buflen + 1);
1006     } else {
1007         msg.buf[0] = '\0';
1008     }
1009 }
1010
1011
1012 static int
1013 log_msgout(
1014     logtype_t   typ)
1015 {
1016     char *line;
1017     int   count = 0;
1018     int   to_unlink = 1;
1019
1020     fflush(errf);
1021     if (fseeko(errf, 0L, SEEK_SET) < 0) {
1022         dbprintf(_("log_msgout: warning - seek failed: %s\n"), strerror(errno));
1023     }
1024     while ((line = agets(errf)) != NULL) {
1025         if (max_warnings > 0 && errf_lines >= max_warnings && count >= max_warnings) {
1026             log_add(typ, "Look in the '%s' file for full error messages", errfname);
1027             to_unlink = 0;
1028             break;
1029         }
1030         if (line[0] != '\0') {
1031                 log_add(typ, "%s", line);
1032         }
1033         amfree(line);
1034         count++;
1035     }
1036     amfree(line);
1037
1038     return to_unlink;
1039 }
1040
1041 /* ------------- */
1042
1043 /*
1044  * Fill in the rest of the tape header
1045  */
1046 static void
1047 finish_tapeheader(
1048     dumpfile_t *file)
1049 {
1050
1051     assert(ISSET(status, HEADER_DONE));
1052
1053     file->type = F_DUMPFILE;
1054     strncpy(file->datestamp, dumper_timestamp, sizeof(file->datestamp) - 1);
1055     strncpy(file->name, hostname, SIZEOF(file->name) - 1);
1056     strncpy(file->disk, diskname, SIZEOF(file->disk) - 1);
1057     file->dumplevel = level;
1058     file->blocksize = DISK_BLOCK_BYTES;
1059
1060     /*
1061      * If we're doing the compression here, we need to override what
1062      * sendbackup told us the compression was.
1063      */
1064     if (srvcompress != COMP_NONE) {
1065         file->compressed = 1;
1066 #ifndef UNCOMPRESS_OPT
1067 #define UNCOMPRESS_OPT  ""
1068 #endif
1069         if (srvcompress == COMP_SERVER_CUST) {
1070             g_snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
1071                      " %s %s |", srvcompprog, "-d");
1072             strncpy(file->comp_suffix, "cust", SIZEOF(file->comp_suffix) - 1);
1073             file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
1074             strncpy(file->srvcompprog, srvcompprog, SIZEOF(file->srvcompprog) - 1);
1075             file->srvcompprog[SIZEOF(file->srvcompprog) - 1] = '\0';
1076         } else if ( srvcompress == COMP_CUST ) {
1077             g_snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
1078                      " %s %s |", clntcompprog, "-d");
1079             strncpy(file->comp_suffix, "cust", SIZEOF(file->comp_suffix) - 1);
1080             file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
1081             strncpy(file->clntcompprog, clntcompprog, SIZEOF(file->clntcompprog));
1082             file->clntcompprog[SIZEOF(file->clntcompprog) - 1] = '\0';
1083         } else {
1084             g_snprintf(file->uncompress_cmd, SIZEOF(file->uncompress_cmd),
1085                 " %s %s |", UNCOMPRESS_PATH, UNCOMPRESS_OPT);
1086             strncpy(file->comp_suffix, COMPRESS_SUFFIX,SIZEOF(file->comp_suffix) - 1);
1087             file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
1088         }
1089     } else {
1090         if (file->comp_suffix[0] == '\0') {
1091             file->compressed = 0;
1092             assert(SIZEOF(file->comp_suffix) >= 2);
1093             strncpy(file->comp_suffix, "N", SIZEOF(file->comp_suffix) - 1);
1094             file->comp_suffix[SIZEOF(file->comp_suffix) - 1] = '\0';
1095         } else {
1096             file->compressed = 1;
1097         }
1098     }
1099     /* take care of the encryption header here */
1100     if (srvencrypt != ENCRYPT_NONE) {
1101       file->encrypted= 1;
1102       if (srvencrypt == ENCRYPT_SERV_CUST) {
1103         if (srv_decrypt_opt) {
1104           g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
1105                    " %s %s |", srv_encrypt, srv_decrypt_opt); 
1106           strncpy(file->srv_decrypt_opt, srv_decrypt_opt, SIZEOF(file->srv_decrypt_opt) - 1);
1107           file->srv_decrypt_opt[SIZEOF(file->srv_decrypt_opt) - 1] = '\0';
1108         } else {
1109           g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
1110                    " %s |", srv_encrypt); 
1111           file->srv_decrypt_opt[0] = '\0';
1112         }
1113         strncpy(file->encrypt_suffix, "enc", SIZEOF(file->encrypt_suffix) - 1);
1114         file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0';
1115         strncpy(file->srv_encrypt, srv_encrypt, SIZEOF(file->srv_encrypt) - 1);
1116         file->srv_encrypt[SIZEOF(file->srv_encrypt) - 1] = '\0';
1117       } else if ( srvencrypt == ENCRYPT_CUST ) {
1118         if (clnt_decrypt_opt) {
1119           g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
1120                    " %s %s |", clnt_encrypt, clnt_decrypt_opt);
1121           strncpy(file->clnt_decrypt_opt, clnt_decrypt_opt,
1122                   SIZEOF(file->clnt_decrypt_opt));
1123           file->clnt_decrypt_opt[SIZEOF(file->clnt_decrypt_opt) - 1] = '\0';
1124         } else {
1125           g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
1126                    " %s |", clnt_encrypt);
1127           file->clnt_decrypt_opt[0] = '\0';
1128         }
1129         g_snprintf(file->decrypt_cmd, SIZEOF(file->decrypt_cmd),
1130                  " %s %s |", clnt_encrypt, clnt_decrypt_opt);
1131         strncpy(file->encrypt_suffix, "enc", SIZEOF(file->encrypt_suffix) - 1);
1132         file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0';
1133         strncpy(file->clnt_encrypt, clnt_encrypt, SIZEOF(file->clnt_encrypt) - 1);
1134         file->clnt_encrypt[SIZEOF(file->clnt_encrypt) - 1] = '\0';
1135       }
1136     } else {
1137       if (file->encrypt_suffix[0] == '\0') {
1138         file->encrypted = 0;
1139         assert(SIZEOF(file->encrypt_suffix) >= 2);
1140         strncpy(file->encrypt_suffix, "N", SIZEOF(file->encrypt_suffix) - 1);
1141         file->encrypt_suffix[SIZEOF(file->encrypt_suffix) - 1] = '\0';
1142       } else {
1143         file->encrypted= 1;
1144       }
1145     }
1146     if (dle_str)
1147         file->dle_str = stralloc(dle_str);
1148     else
1149         file->dle_str = NULL;
1150 }
1151
1152 /*
1153  * Send an Amanda dump header to the output file.
1154  */
1155 static ssize_t
1156 write_tapeheader(
1157     int         outfd,
1158     dumpfile_t *file)
1159 {
1160     char * buffer;
1161     size_t written;
1162
1163     if (debug_dumper > 1)
1164         dump_dumpfile_t(file);
1165     buffer = build_header(file, NULL, DISK_BLOCK_BYTES);
1166     if (!buffer) /* this shouldn't happen */
1167         error(_("header does not fit in %zd bytes"), (size_t)DISK_BLOCK_BYTES);
1168
1169     written = full_write(outfd, buffer, DISK_BLOCK_BYTES);
1170     amfree(buffer);
1171     if(written == DISK_BLOCK_BYTES)
1172         return 0;
1173
1174     return -1;
1175 }
1176
1177 int indexout = -1;
1178
1179 static int
1180 do_dump(
1181     struct databuf *db)
1182 {
1183     char *indexfile_tmp = NULL;
1184     char *indexfile_real = NULL;
1185     char level_str[NUM_STR_SIZE];
1186     char *time_str;
1187     char *fn;
1188     char *q;
1189     times_t runtime;
1190     double dumptime;    /* Time dump took in secs */
1191     pid_t indexpid = -1;
1192     char *m;
1193     int to_unlink = 1;
1194
1195     startclock();
1196
1197     if (msg.buf) msg.buf[0] = '\0';     /* reset msg buffer */
1198     status = 0;
1199     dump_result = 0;
1200     dumpbytes = dumpsize = headersize = origsize = (off_t)0;
1201     fh_init(&file);
1202
1203     g_snprintf(level_str, SIZEOF(level_str), "%d", level);
1204     time_str = get_timestamp_from_time(0);
1205     fn = sanitise_filename(diskname);
1206     errf_lines = 0;
1207     errfname = newvstralloc(errfname,
1208                             AMANDA_DBGDIR,
1209                             "/log.error", NULL);
1210     mkdir(errfname, 0700);
1211     errfname = newvstralloc(errfname,
1212                             AMANDA_DBGDIR,
1213                             "/log.error/", hostname,
1214                             ".", fn,
1215                             ".", level_str,
1216                             ".", time_str,
1217                             ".errout",
1218                             NULL);
1219     amfree(fn);
1220     amfree(time_str);
1221     if((errf = fopen(errfname, "w+")) == NULL) {
1222         errstr = newvstrallocf(errstr, "errfile open \"%s\": %s",
1223                               errfname, strerror(errno));
1224         amfree(errfname);
1225         goto failed;
1226     }
1227
1228     if (streams[INDEXFD].fd != NULL) {
1229         indexfile_real = getindexfname(hostname, diskname, dumper_timestamp, level);
1230         indexfile_tmp = stralloc2(indexfile_real, ".tmp");
1231
1232         if (mkpdir(indexfile_tmp, 0755, (uid_t)-1, (gid_t)-1) == -1) {
1233            errstr = newvstrallocf(errstr,
1234                                  _("err create %s: %s"),
1235                                  indexfile_tmp,
1236                                  strerror(errno));
1237            amfree(indexfile_real);
1238            amfree(indexfile_tmp);
1239            goto failed;
1240         }
1241         indexout = open(indexfile_tmp, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1242         if (indexout == -1) {
1243             errstr = newvstrallocf(errstr, _("err open %s: %s"),
1244                         indexfile_tmp, strerror(errno));
1245             goto failed;
1246         } else {
1247             if (runcompress(indexout, &indexpid, COMP_BEST, "index compress") < 0) {
1248                 aclose(indexout);
1249                 goto failed;
1250             }
1251         }
1252         indexfderror = 0;
1253         /*
1254          * Schedule the indexfd for relaying to the index file
1255          */
1256         security_stream_read(streams[INDEXFD].fd, read_indexfd, &indexout);
1257     }
1258
1259     /*
1260      * We only need to process messages initially.  Once we have done
1261      * the header, we will start processing data too.
1262      */
1263     security_stream_read(streams[MESGFD].fd, read_mesgfd, db);
1264     set_datafd = 0;
1265
1266     /*
1267      * Setup a read timeout
1268      */
1269     timeout(conf_dtimeout);
1270
1271     /*
1272      * Start the event loop.  This will exit when all three events
1273      * (read the mesgfd, read the datafd, and timeout) are removed.
1274      */
1275     event_loop(0);
1276
1277     if (!ISSET(status, HEADER_DONE)) {
1278         dump_result = max(dump_result, 2);
1279         if (!errstr) errstr = stralloc(_("got no header information"));
1280     }
1281
1282     dumpsize -= headersize;             /* don't count the header */
1283     if (dumpsize <= (off_t)0 && data_path == DATA_PATH_AMANDA) {
1284         dumpsize = (off_t)0;
1285         dump_result = max(dump_result, 2);
1286         if (!errstr) errstr = stralloc(_("got no data"));
1287     }
1288
1289     if (data_path == DATA_PATH_DIRECTTCP) {
1290         dumpsize = origsize;
1291     }
1292
1293     if (!ISSET(status, HEADER_DONE)) {
1294         dump_result = max(dump_result, 2);
1295         if (!errstr) errstr = stralloc(_("got no header information"));
1296     }
1297
1298     if (dumpsize == 0 && data_path == DATA_PATH_AMANDA) {
1299         dump_result = max(dump_result, 2);
1300         if (!errstr) errstr = stralloc(_("got no data"));
1301     }
1302
1303     if (indexfile_tmp) {
1304         amwait_t index_status;
1305
1306         /*@i@*/ aclose(indexout);
1307         waitpid(indexpid,&index_status,0);
1308         log_add(L_INFO, "pid-done %ld", (long)indexpid);
1309         if (rename(indexfile_tmp, indexfile_real) != 0) {
1310             log_add(L_WARNING, _("could not rename \"%s\" to \"%s\": %s"),
1311                     indexfile_tmp, indexfile_real, strerror(errno));
1312         }
1313         amfree(indexfile_tmp);
1314         amfree(indexfile_real);
1315     }
1316
1317     /* copy the header in a file on the index dir */
1318     {
1319         FILE *a;
1320         char *s;
1321         char *f = getheaderfname(hostname, diskname, dumper_timestamp, level);
1322         a = fopen(f,"w");
1323         if (a) {
1324             s = build_header(&file, NULL, DISK_BLOCK_BYTES);
1325             fprintf(a,"%s", s);
1326             g_free(s);
1327             fclose(a);
1328         }
1329         g_free(f);
1330     }
1331
1332     if (db->compresspid != -1 && dump_result < 2) {
1333         amwait_t  wait_status;
1334         char *errmsg = NULL;
1335
1336         waitpid(db->compresspid, &wait_status, 0);
1337         if (WIFSIGNALED(wait_status)) {
1338             errmsg = g_strdup_printf(_("%s terminated with signal %d"),
1339                                      "compress", WTERMSIG(wait_status));
1340         } else if (WIFEXITED(wait_status)) {
1341             if (WEXITSTATUS(wait_status) != 0) {
1342                 errmsg = g_strdup_printf(_("%s exited with status %d"),
1343                                          "compress", WEXITSTATUS(wait_status));
1344             }
1345         } else {
1346             errmsg = g_strdup_printf(_("%s got bad exit"),
1347                                      "compress");
1348         }
1349         if (errmsg) {
1350             g_fprintf(errf, _("? %s\n"), errmsg);
1351             g_debug("%s", errmsg);
1352             dump_result = max(dump_result, 2);
1353             if (!errstr)
1354                 errstr = errmsg;
1355             else
1356                 g_free(errmsg);
1357         }
1358         log_add(L_INFO, "pid-done %ld", (long)db->compresspid);
1359         db->compresspid = -1;
1360     }
1361
1362     if (db->encryptpid != -1 && dump_result < 2) {
1363         amwait_t  wait_status;
1364         char *errmsg = NULL;
1365
1366         waitpid(db->encryptpid, &wait_status, 0);
1367         if (WIFSIGNALED(wait_status)) {
1368             errmsg = g_strdup_printf(_("%s terminated with signal %d"),
1369                                      "encrypt", WTERMSIG(wait_status));
1370         } else if (WIFEXITED(wait_status)) {
1371             if (WEXITSTATUS(wait_status) != 0) {
1372                 errmsg = g_strdup_printf(_("%s exited with status %d"),
1373                                          "encrypt", WEXITSTATUS(wait_status));
1374             }
1375         } else {
1376             errmsg = g_strdup_printf(_("%s got bad exit"),
1377                                      "encrypt");
1378         }
1379         if (errmsg) {
1380             g_fprintf(errf, _("? %s\n"), errmsg);
1381             g_debug("%s", errmsg);
1382             dump_result = max(dump_result, 2);
1383             if (!errstr)
1384                 errstr = errmsg;
1385             else
1386                 g_free(errmsg);
1387         }
1388         log_add(L_INFO, "pid-done %ld", (long)db->encryptpid);
1389         db->encryptpid  = -1;
1390     }
1391
1392     if (dump_result > 1)
1393         goto failed;
1394
1395     runtime = stopclock();
1396     dumptime = g_timeval_to_double(runtime);
1397
1398     amfree(errstr);
1399     errstr = alloc(128);
1400     g_snprintf(errstr, 128, _("sec %s kb %lld kps %3.1lf orig-kb %lld"),
1401         walltime_str(runtime),
1402         (long long)dumpsize,
1403         (isnormal(dumptime) ? ((double)dumpsize / (double)dumptime) : 0.0),
1404         (long long)origsize);
1405     m = vstrallocf("[%s]", errstr);
1406     q = quote_string(m);
1407     amfree(m);
1408     putresult(DONE, _("%s %lld %lld %lu %s\n"), handle,
1409                 (long long)origsize,
1410                 (long long)dumpsize,
1411                 (unsigned long)((double)dumptime+0.5), q);
1412     amfree(q);
1413
1414     switch(dump_result) {
1415     case 0:
1416         log_add(L_SUCCESS, "%s %s %s %d [%s]", hostname, qdiskname, dumper_timestamp, level, errstr);
1417
1418         break;
1419
1420     case 1:
1421         log_start_multiline();
1422         log_add(L_STRANGE, "%s %s %d [%s]", hostname, qdiskname, level, errstr);
1423         to_unlink = log_msgout(L_STRANGE);
1424         log_end_multiline();
1425
1426         break;
1427     }
1428
1429     if (errf)
1430         afclose(errf);
1431     if (errfname) {
1432         if (to_unlink)
1433             unlink(errfname);
1434         amfree(errfname);
1435     }
1436
1437     if (data_path == DATA_PATH_AMANDA)
1438         aclose(db->fd);
1439
1440     amfree(errstr);
1441     dumpfile_free_data(&file);
1442
1443     return 1;
1444
1445 failed:
1446     m = vstrallocf("[%s]", errstr);
1447     q = quote_string(m);
1448     putresult(FAILED, "%s %s\n", handle, q);
1449     amfree(q);
1450     amfree(m);
1451
1452     aclose(db->fd);
1453     /* kill all child process */
1454     if (db->compresspid != -1) {
1455         g_fprintf(stderr,_("%s: kill compress command\n"),get_pname());
1456         if (kill(db->compresspid, SIGTERM) < 0) {
1457             if (errno != ESRCH) {
1458                 g_fprintf(stderr,_("%s: can't kill compress command: %s\n"), 
1459                     get_pname(), strerror(errno));
1460             } else {
1461                 log_add(L_INFO, "pid-done %ld", (long)db->compresspid);
1462             }
1463         }
1464         else {
1465             waitpid(db->compresspid,NULL,0);
1466             log_add(L_INFO, "pid-done %ld", (long)db->compresspid);
1467         }
1468     }
1469
1470     if (db->encryptpid != -1) {
1471         g_fprintf(stderr,_("%s: kill encrypt command\n"),get_pname());
1472         if (kill(db->encryptpid, SIGTERM) < 0) {
1473             if (errno != ESRCH) {
1474                 g_fprintf(stderr,_("%s: can't kill encrypt command: %s\n"), 
1475                     get_pname(), strerror(errno));
1476             } else {
1477                 log_add(L_INFO, "pid-done %ld", (long)db->encryptpid);
1478             }
1479         }
1480         else {
1481             waitpid(db->encryptpid,NULL,0);
1482             log_add(L_INFO, "pid-done %ld", (long)db->encryptpid);
1483         }
1484     }
1485
1486     if (indexpid != -1) {
1487         g_fprintf(stderr,_("%s: kill index command\n"),get_pname());
1488         if (kill(indexpid, SIGTERM) < 0) {
1489             if (errno != ESRCH) {
1490                 g_fprintf(stderr,_("%s: can't kill index command: %s\n"), 
1491                     get_pname(),strerror(errno));
1492             } else {
1493                 log_add(L_INFO, "pid-done %ld", (long)indexpid);
1494             }
1495         }
1496         else {
1497             waitpid(indexpid,NULL,0);
1498             log_add(L_INFO, "pid-done %ld", (long)indexpid);
1499         }
1500     }
1501
1502     log_start_multiline();
1503     log_add(L_FAIL, _("%s %s %s %d [%s]"), hostname, qdiskname, dumper_timestamp,
1504             level, errstr);
1505     if (errf) {
1506         to_unlink = log_msgout(L_FAIL);
1507     }
1508     log_end_multiline();
1509
1510     if (errf)
1511         afclose(errf);
1512     if (errfname) {
1513         if (to_unlink)
1514             unlink(errfname);
1515         amfree(errfname);
1516     }
1517
1518     if (indexfile_tmp) {
1519         unlink(indexfile_tmp);
1520         amfree(indexfile_tmp);
1521         amfree(indexfile_real);
1522     }
1523
1524     amfree(errstr);
1525     dumpfile_free_data(&file);
1526
1527     return 0;
1528 }
1529
1530 /*
1531  * Callback for reads on the mesgfd stream
1532  */
1533 static void
1534 read_mesgfd(
1535     void *      cookie,
1536     void *      buf,
1537     ssize_t     size)
1538 {
1539     struct databuf *db = cookie;
1540
1541     assert(db != NULL);
1542
1543     switch (size) {
1544     case -1:
1545         errstr = newvstrallocf(errstr, _("mesg read: %s"),
1546             security_stream_geterror(streams[MESGFD].fd));
1547         dump_result = 2;
1548         stop_dump();
1549         return;
1550
1551     case 0:
1552         /*
1553          * EOF.  Just shut down the mesg stream.
1554          */
1555         process_dumpeof();
1556         security_stream_close(streams[MESGFD].fd);
1557         streams[MESGFD].fd = NULL;
1558         /*
1559          * If the data fd and index fd has also shut down, then we're done.
1560          */
1561         if ((set_datafd == 0 || streams[DATAFD].fd == NULL) && 
1562             streams[INDEXFD].fd == NULL)
1563             stop_dump();
1564         return;
1565
1566     default:
1567         assert(buf != NULL);
1568         add_msg_data(buf, (size_t)size);
1569         security_stream_read(streams[MESGFD].fd, read_mesgfd, cookie);
1570         break;
1571     }
1572
1573     if (ISSET(status, GOT_INFO_ENDLINE) && !ISSET(status, HEADER_DONE)) {
1574         /* Use the first in the dataport_list */
1575         in_port_t data_port;
1576         char *data_host = dataport_list;
1577         char *s;
1578
1579         s = strchr(dataport_list, ',');
1580         if (s) *s = '\0';  /* use first data_port */
1581         s = strrchr(dataport_list, ':');
1582         *s = '\0';
1583         s++;
1584         data_port = atoi(s);
1585
1586         SET(status, HEADER_DONE);
1587         /* time to do the header */
1588         finish_tapeheader(&file);
1589         if (write_tapeheader(db->fd, &file)) {
1590             errstr = newvstrallocf(errstr, _("write_tapeheader: %s"), 
1591                                   strerror(errno));
1592             dump_result = 2;
1593             stop_dump();
1594             return;
1595         }
1596         aclose(db->fd);
1597         if (data_path == DATA_PATH_AMANDA) {
1598             g_debug(_("Sending data to %s:%d\n"), data_host, data_port);
1599             db->fd = stream_client(data_host, data_port,
1600                                    STREAM_BUFSIZE, 0, NULL, 0);
1601             if (db->fd == -1) {
1602                 errstr = newvstrallocf(errstr,
1603                                        _("Can't open data output stream: %s"),
1604                                        strerror(errno));
1605                 dump_result = 2;
1606                 stop_dump();
1607                 return;
1608             }
1609         }
1610
1611         dumpsize += (off_t)DISK_BLOCK_KB;
1612         headersize += (off_t)DISK_BLOCK_KB;
1613
1614         if (srvencrypt == ENCRYPT_SERV_CUST) {
1615             if (runencrypt(db->fd, &db->encryptpid, srvencrypt) < 0) {
1616                 dump_result = 2;
1617                 stop_dump();
1618                 return;
1619             }
1620         }
1621         /*
1622          * Now, setup the compress for the data output, and start
1623          * reading the datafd.
1624          */
1625         if ((srvcompress != COMP_NONE) && (srvcompress != COMP_CUST)) {
1626             if (runcompress(db->fd, &db->compresspid, srvcompress, "data compress") < 0) {
1627                 dump_result = 2;
1628                 stop_dump();
1629                 return;
1630             }
1631         }
1632         security_stream_read(streams[DATAFD].fd, read_datafd, db);
1633         set_datafd = 1;
1634     }
1635
1636     /*
1637      * Reset the timeout for future reads
1638      */
1639     timeout(conf_dtimeout);
1640 }
1641
1642 /*
1643  * Callback for reads on the datafd stream
1644  */
1645 static void
1646 read_datafd(
1647     void *      cookie,
1648     void *      buf,
1649     ssize_t     size)
1650 {
1651     struct databuf *db = cookie;
1652
1653     assert(db != NULL);
1654
1655     /*
1656      * The read failed.  Error out
1657      */
1658     if (size < 0) {
1659         errstr = newvstrallocf(errstr, _("data read: %s"),
1660             security_stream_geterror(streams[DATAFD].fd));
1661         dump_result = 2;
1662         aclose(db->fd);
1663         stop_dump();
1664         return;
1665     }
1666
1667     /* The header had better be written at this point */
1668     assert(ISSET(status, HEADER_DONE));
1669
1670     /*
1671      * EOF.  Stop and return.
1672      */
1673     if (size == 0) {
1674         databuf_flush(db);
1675         if (dumpbytes != (off_t)0) {
1676             dumpsize += (off_t)1;
1677         }
1678         security_stream_close(streams[DATAFD].fd);
1679         streams[DATAFD].fd = NULL;
1680         aclose(db->fd);
1681         /*
1682          * If the mesg fd and index fd has also shut down, then we're done.
1683          */
1684         if (streams[MESGFD].fd == NULL && streams[INDEXFD].fd == NULL)
1685             stop_dump();
1686         return;
1687     }
1688
1689     /*
1690      * We read something.  Add it to the databuf and reschedule for
1691      * more data.
1692      */
1693     assert(buf != NULL);
1694     if (databuf_write(db, buf, (size_t)size) < 0) {
1695         int save_errno = errno;
1696         errstr = newvstrallocf(errstr, _("data write: %s"), strerror(save_errno));
1697         dump_result = 2;
1698         stop_dump();
1699         return;
1700     }
1701
1702     /*
1703      * Reset the timeout for future reads
1704      */
1705     timeout(conf_dtimeout);
1706
1707     security_stream_read(streams[DATAFD].fd, read_datafd, cookie);
1708 }
1709
1710 /*
1711  * Callback for reads on the index stream
1712  */
1713 static void
1714 read_indexfd(
1715     void *      cookie,
1716     void *      buf,
1717     ssize_t     size)
1718 {
1719     int fd;
1720
1721     assert(cookie != NULL);
1722     fd = *(int *)cookie;
1723
1724     if (size < 0) {
1725         errstr = newvstrallocf(errstr, _("index read: %s"),
1726             security_stream_geterror(streams[INDEXFD].fd));
1727         dump_result = 2;
1728         stop_dump();
1729         return;
1730     }
1731
1732     /*
1733      * EOF.  Stop and return.
1734      */
1735     if (size == 0) {
1736         security_stream_close(streams[INDEXFD].fd);
1737         streams[INDEXFD].fd = NULL;
1738         /*
1739          * If the mesg fd has also shut down, then we're done.
1740          */
1741         if ((set_datafd == 0 || streams[DATAFD].fd == NULL) &&
1742              streams[MESGFD].fd == NULL)
1743             stop_dump();
1744         aclose(indexout);
1745         return;
1746     }
1747
1748     assert(buf != NULL);
1749
1750     /*
1751      * We ignore error while writing to the index file.
1752      */
1753     if (full_write(fd, buf, (size_t)size) < (size_t)size) {
1754         /* Ignore error, but schedule another read. */
1755         if(indexfderror == 0) {
1756             indexfderror = 1;
1757             log_add(L_INFO, _("Index corrupted for %s:%s"), hostname, qdiskname);
1758         }
1759     }
1760     security_stream_read(streams[INDEXFD].fd, read_indexfd, cookie);
1761 }
1762
1763 static void
1764 handle_filter_stderr(
1765     void *cookie)
1766 {
1767     filter_t *filter = cookie;
1768     ssize_t   nread;
1769     char     *b, *p;
1770     gint64    len;
1771
1772     event_release(filter->event);
1773
1774     if (filter->buffer == NULL) {
1775         /* allocate initial buffer */
1776         filter->buffer = g_malloc(2048);
1777         filter->first = 0;
1778         filter->size = 0;
1779         filter->allocated_size = 2048;
1780     } else if (filter->first > 0) {
1781         if (filter->allocated_size - filter->size - filter->first < 1024) {
1782             memmove(filter->buffer, filter->buffer + filter->first,
1783                                     filter->size);
1784             filter->first = 0;
1785         }
1786     } else if (filter->allocated_size - filter->size < 1024) {
1787         /* double the size of the buffer */
1788         filter->allocated_size *= 2;
1789         filter->buffer = g_realloc(filter->buffer, filter->allocated_size);
1790     }
1791
1792     nread = read(filter->fd, filter->buffer + filter->first + filter->size,
1793                              filter->allocated_size - filter->first - filter->size - 2);
1794
1795     if (nread <= 0) {
1796         aclose(filter->fd);
1797         if (filter->size > 0 && filter->buffer[filter->first + filter->size - 1] != '\n') {
1798             /* Add a '\n' at end of buffer */
1799             filter->buffer[filter->first + filter->size] = '\n';
1800             filter->size++;
1801         }
1802     } else {
1803         filter->size += nread;
1804     }
1805
1806     /* process all complete lines */
1807     b = filter->buffer + filter->first;
1808     filter->buffer[filter->first + filter->size] = '\0';
1809     while (b < filter->buffer + filter->first + filter->size &&
1810            (p = strchr(b, '\n')) != NULL) {
1811         *p = '\0';
1812         g_fprintf(errf, _("? %s: %s\n"), filter->name, b);
1813         if (errstr == NULL) {
1814             errstr = stralloc(b);
1815         }
1816         len = p - b + 1;
1817         filter->first += len;
1818         filter->size -= len;
1819         b = p + 1;
1820         dump_result = max(dump_result, 1);
1821     }
1822
1823     if (nread <= 0) {
1824         g_free(filter->buffer);
1825         g_free(filter);
1826     } else {
1827         filter->event = event_register((event_id_t)filter->fd, EV_READFD,
1828                                        handle_filter_stderr, filter);
1829     }
1830 }
1831
1832 /*
1833  * Startup a timeout in the event handler.  If the arg is 0,
1834  * then remove the timeout.
1835  */
1836 static void
1837 timeout(
1838     time_t seconds)
1839 {
1840     static event_handle_t *ev_timeout = NULL;
1841
1842     /*
1843      * First, remove a timeout if one is active.
1844      */
1845     if (ev_timeout != NULL) {
1846         event_release(ev_timeout);
1847         ev_timeout = NULL;
1848     }
1849
1850     /*
1851      * Now, schedule a new one if 'seconds' is greater than 0
1852      */
1853     if (seconds > 0)
1854         ev_timeout = event_register((event_id_t)seconds, EV_TIME, timeout_callback, NULL);
1855 }
1856
1857 /*
1858  * This is the callback for timeout().  If this is reached, then we
1859  * have a data timeout.
1860  */
1861 static void
1862 timeout_callback(
1863     void *      unused)
1864 {
1865     (void)unused;       /* Quiet unused parameter warning */
1866
1867     assert(unused == NULL);
1868     errstr = newstralloc(errstr, _("data timeout"));
1869     dump_result = 2;
1870     stop_dump();
1871 }
1872
1873 /*
1874  * This is called when everything needs to shut down so event_loop()
1875  * will exit.
1876  */
1877 static void
1878 stop_dump(void)
1879 {
1880     int             i;
1881     struct cmdargs *cmdargs = NULL;
1882
1883     /* Check if I have a pending ABORT command */
1884     cmdargs = get_pending_cmd();
1885     if (cmdargs) {
1886         if (cmdargs->cmd != ABORT) {
1887             error(_("beurk %d"), cmdargs->cmd);
1888         }
1889         amfree(errstr);
1890         errstr = stralloc(cmdargs->argv[1]);
1891         free_cmdargs(cmdargs);
1892     }
1893
1894     for (i = 0; i < NSTREAMS; i++) {
1895         if (streams[i].fd != NULL) {
1896             security_stream_close(streams[i].fd);
1897             streams[i].fd = NULL;
1898         }
1899     }
1900     aclose(indexout);
1901     aclose(g_databuf->fd);
1902     timeout(0);
1903 }
1904
1905
1906 /*
1907  * Runs compress with the first arg as its stdout.  Returns
1908  * 0 on success or negative if error, and it's pid via the second
1909  * argument.  The outfd arg is dup2'd to the pipe to the compress
1910  * process.
1911  */
1912 static int
1913 runcompress(
1914     int         outfd,
1915     pid_t *     pid,
1916     comp_t      comptype,
1917     char       *name)
1918 {
1919     int outpipe[2], rval;
1920     int errpipe[2];
1921     filter_t *filter;
1922
1923     assert(outfd >= 0);
1924     assert(pid != NULL);
1925
1926     /* outpipe[0] is pipe's stdin, outpipe[1] is stdout. */
1927     if (pipe(outpipe) < 0) {
1928         errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno));
1929         return (-1);
1930     }
1931
1932     /* errpipe[0] is pipe's output, outpipe[1] is input. */
1933     if (pipe(errpipe) < 0) {
1934         errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno));
1935         return (-1);
1936     }
1937
1938     if (comptype != COMP_SERVER_CUST) {
1939         g_debug("execute: %s %s", COMPRESS_PATH,
1940                 comptype == COMP_BEST ? COMPRESS_BEST_OPT : COMPRESS_FAST_OPT);
1941     } else {
1942         g_debug("execute: %s", srvcompprog);
1943     }
1944     switch (*pid = fork()) {
1945     case -1:
1946         errstr = newvstrallocf(errstr, _("couldn't fork: %s"), strerror(errno));
1947         aclose(outpipe[0]);
1948         aclose(outpipe[1]);
1949         aclose(errpipe[0]);
1950         aclose(errpipe[1]);
1951         return (-1);
1952     default:
1953         rval = dup2(outpipe[1], outfd);
1954         if (rval < 0)
1955             errstr = newvstrallocf(errstr, _("couldn't dup2: %s"), strerror(errno));
1956         aclose(outpipe[1]);
1957         aclose(outpipe[0]);
1958         aclose(errpipe[1]);
1959         filter = g_new0(filter_t, 1);
1960         filter->fd = errpipe[0];
1961         filter->name = name;
1962         filter->buffer = NULL;
1963         filter->size = 0;
1964         filter->allocated_size = 0;
1965         filter->event = event_register((event_id_t)filter->fd, EV_READFD,
1966                                        handle_filter_stderr, filter);
1967         return (rval);
1968     case 0:
1969         close(outpipe[1]);
1970         close(errpipe[0]);
1971         if (dup2(outpipe[0], 0) < 0) {
1972             error(_("err dup2 in: %s"), strerror(errno));
1973             /*NOTREACHED*/
1974         }
1975         if (dup2(outfd, 1) == -1) {
1976             error(_("err dup2 out: %s"), strerror(errno));
1977             /*NOTREACHED*/
1978         }
1979         if (dup2(errpipe[1], 2) == -1) {
1980             error(_("err dup2 err: %s"), strerror(errno));
1981             /*NOTREACHED*/
1982         }
1983         if (comptype != COMP_SERVER_CUST) {
1984             char *base = stralloc(COMPRESS_PATH);
1985             log_add(L_INFO, "%s pid %ld", basename(base), (long)getpid());
1986             amfree(base);
1987             safe_fd(-1, 0);
1988             set_root_privs(-1);
1989             execlp(COMPRESS_PATH, COMPRESS_PATH, (  comptype == COMP_BEST ?
1990                 COMPRESS_BEST_OPT : COMPRESS_FAST_OPT), (char *)NULL);
1991             error(_("error: couldn't exec %s: %s"), COMPRESS_PATH, strerror(errno));
1992             /*NOTREACHED*/
1993         } else if (*srvcompprog) {
1994             char *base = stralloc(srvcompprog);
1995             log_add(L_INFO, "%s pid %ld", basename(base), (long)getpid());
1996             amfree(base);
1997             safe_fd(-1, 0);
1998             set_root_privs(-1);
1999             execlp(srvcompprog, srvcompprog, (char *)0);
2000             error(_("error: couldn't exec server custom compression '%s'.\n"), srvcompprog);
2001             /*NOTREACHED*/
2002         }
2003     }
2004     /*NOTREACHED*/
2005     return (-1);
2006 }
2007
2008 /*
2009  * Runs encrypt with the first arg as its stdout.  Returns
2010  * 0 on success or negative if error, and it's pid via the second
2011  * argument.  The outfd arg is dup2'd to the pipe to the encrypt
2012  * process.
2013  */
2014 static int
2015 runencrypt(
2016     int         outfd,
2017     pid_t *     pid,
2018     encrypt_t   encrypttype)
2019 {
2020     int outpipe[2], rval;
2021     int errpipe[2];
2022     filter_t *filter;
2023
2024     assert(outfd >= 0);
2025     assert(pid != NULL);
2026
2027     /* outpipe[0] is pipe's stdin, outpipe[1] is stdout. */
2028     if (pipe(outpipe) < 0) {
2029         errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno));
2030         return (-1);
2031     }
2032
2033     /* errpipe[0] is pipe's output, outpipe[1] is input. */
2034     if (pipe(errpipe) < 0) {
2035         errstr = newvstrallocf(errstr, _("pipe: %s"), strerror(errno));
2036         return (-1);
2037     }
2038
2039     g_debug("execute: %s", srv_encrypt);
2040     switch (*pid = fork()) {
2041     case -1:
2042         errstr = newvstrallocf(errstr, _("couldn't fork: %s"), strerror(errno));
2043         aclose(outpipe[0]);
2044         aclose(outpipe[1]);
2045         aclose(errpipe[0]);
2046         aclose(errpipe[1]);
2047         return (-1);
2048     default: {
2049         char *base;
2050         rval = dup2(outpipe[1], outfd);
2051         if (rval < 0)
2052             errstr = newvstrallocf(errstr, _("couldn't dup2: %s"), strerror(errno));
2053         aclose(outpipe[1]);
2054         aclose(outpipe[0]);
2055         aclose(errpipe[1]);
2056         filter = g_new0(filter_t, 1);
2057         filter->fd = errpipe[0];
2058         base = g_strdup(srv_encrypt);
2059         filter->name = g_strdup(basename(base));
2060         amfree(base);
2061         filter->buffer = NULL;
2062         filter->size = 0;
2063         filter->allocated_size = 0;
2064         filter->event = event_register((event_id_t)filter->fd, EV_READFD,
2065                                        handle_filter_stderr, filter);
2066         return (rval);
2067         }
2068     case 0: {
2069         char *base;
2070         if (dup2(outpipe[0], 0) < 0) {
2071             error(_("err dup2 in: %s"), strerror(errno));
2072             /*NOTREACHED*/
2073         }
2074         if (dup2(outfd, 1) < 0 ) {
2075             error(_("err dup2 out: %s"), strerror(errno));
2076             /*NOTREACHED*/
2077         }
2078         if (dup2(errpipe[1], 2) == -1) {
2079             error(_("err dup2 err: %s"), strerror(errno));
2080             /*NOTREACHED*/
2081         }
2082         close(errpipe[0]);
2083         base = stralloc(srv_encrypt);
2084         log_add(L_INFO, "%s pid %ld", basename(base), (long)getpid());
2085         amfree(base);
2086         safe_fd(-1, 0);
2087         if ((encrypttype == ENCRYPT_SERV_CUST) && *srv_encrypt) {
2088             set_root_privs(-1);
2089             execlp(srv_encrypt, srv_encrypt, (char *)0);
2090             error(_("error: couldn't exec server custom encryption '%s'.\n"), srv_encrypt);
2091             /*NOTREACHED*/
2092         }
2093         }
2094     }
2095     /*NOTREACHED*/
2096     return (-1);
2097 }
2098
2099
2100 /* -------------------- */
2101
2102 static void
2103 sendbackup_response(
2104     void *              datap,
2105     pkt_t *             pkt,
2106     security_handle_t * sech)
2107 {
2108     int ports[NSTREAMS], *response_error = datap, i;
2109     char *p;
2110     char *tok;
2111     char *extra;
2112
2113     assert(response_error != NULL);
2114     assert(sech != NULL);
2115
2116     security_close_connection(sech, hostname);
2117
2118     if (pkt == NULL) {
2119         errstr = newvstrallocf(errstr, _("[request failed: %s]"),
2120             security_geterror(sech));
2121         *response_error = 1;
2122         return;
2123     }
2124
2125     extra = NULL;
2126     memset(ports, 0, SIZEOF(ports));
2127     if (pkt->type == P_NAK) {
2128 #if defined(PACKET_DEBUG)
2129         g_fprintf(stderr, _("got nak response:\n----\n%s\n----\n\n"), pkt->body);
2130 #endif
2131
2132         tok = strtok(pkt->body, " ");
2133         if (tok == NULL || strcmp(tok, "ERROR") != 0)
2134             goto bad_nak;
2135
2136         tok = strtok(NULL, "\n");
2137         if (tok != NULL) {
2138             errstr = newvstrallocf(errstr, "NAK: %s", tok);
2139             *response_error = 1;
2140         } else {
2141 bad_nak:
2142             errstr = newvstrallocf(errstr, "request NAK");
2143             *response_error = 2;
2144         }
2145         return;
2146     }
2147
2148     if (pkt->type != P_REP) {
2149         errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"),
2150             pkt_type2str(pkt->type), pkt->body);
2151         *response_error = 1;
2152         return;
2153     }
2154
2155     dbprintf(_("got response:\n----\n%s\n----\n\n"), pkt->body);
2156
2157     for(i = 0; i < NSTREAMS; i++) {
2158         ports[i] = -1;
2159         streams[i].fd = NULL;
2160     }
2161
2162     p = pkt->body;
2163     while((tok = strtok(p, " \n")) != NULL) {
2164         p = NULL;
2165
2166         /*
2167          * Error response packets have "ERROR" followed by the error message
2168          * followed by a newline.
2169          */
2170         if (strcmp(tok, "ERROR") == 0) {
2171             tok = strtok(NULL, "\n");
2172             if (tok == NULL)
2173                 tok = _("[bogus error packet]");
2174             errstr = newvstrallocf(errstr, "%s", tok);
2175             *response_error = 2;
2176             return;
2177         }
2178
2179         /*
2180          * Regular packets have CONNECT followed by three streams
2181          */
2182         if (strcmp(tok, "CONNECT") == 0) {
2183
2184             /*
2185              * Parse the three stream specifiers out of the packet.
2186              */
2187             for (i = 0; i < NSTREAMS; i++) {
2188                 tok = strtok(NULL, " ");
2189                 if (tok == NULL || strcmp(tok, streams[i].name) != 0) {
2190                     extra = vstrallocf(
2191                                 _("CONNECT token is \"%s\": expected \"%s\""),
2192                                 tok ? tok : "(null)",
2193                                 streams[i].name);
2194                     goto parse_error;
2195                 }
2196                 tok = strtok(NULL, " \n");
2197                 if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
2198                     extra = vstrallocf(
2199                         _("CONNECT %s token is \"%s\": expected a port number"),
2200                         streams[i].name, tok ? tok : "(null)");
2201                     goto parse_error;
2202                 }
2203             }
2204             continue;
2205         }
2206
2207         /*
2208          * OPTIONS [options string] '\n'
2209          */
2210         if (strcmp(tok, "OPTIONS") == 0) {
2211             tok = strtok(NULL, "\n");
2212             if (tok == NULL) {
2213                 extra = vstrallocf(_("OPTIONS token is missing"));
2214                 goto parse_error;
2215             }
2216
2217             while((p = strchr(tok, ';')) != NULL) {
2218                 char ch;
2219                 *p++ = '\0';
2220                 if(strncmp_const_skip(tok, "features=", tok, ch) == 0) {
2221                     char *u = strchr(tok, ';');
2222                     ch = ch;
2223                     if (u)
2224                        *u = '\0';
2225                     am_release_feature_set(their_features);
2226                     if((their_features = am_string_to_feature(tok)) == NULL) {
2227                         errstr = newvstrallocf(errstr,
2228                                               _("OPTIONS: bad features value: %s"),
2229                                               tok);
2230                         goto parse_error;
2231                     }
2232                     if (u)
2233                        *u = ';';
2234                 }
2235                 tok = p;
2236             }
2237             continue;
2238         }
2239
2240         extra = vstrallocf(_("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""),
2241                           tok ? tok : "(null)");
2242         goto parse_error;
2243     }
2244
2245     if (dumper_kencrypt == KENCRYPT_WILL_DO)
2246         dumper_kencrypt = KENCRYPT_YES;
2247
2248     /*
2249      * Connect the streams to their remote ports
2250      */
2251     for (i = 0; i < NSTREAMS; i++) {
2252         if (ports[i] == -1)
2253             continue;
2254         streams[i].fd = security_stream_client(sech, ports[i]);
2255         if (streams[i].fd == NULL) {
2256             errstr = newvstrallocf(errstr,
2257                 _("[could not connect %s stream: %s]"),
2258                 streams[i].name,
2259                 security_geterror(sech));
2260             goto connect_error;
2261         }
2262     }
2263
2264     /*
2265      * Authenticate the streams
2266      */
2267     for (i = 0; i < NSTREAMS; i++) {
2268         if (streams[i].fd == NULL)
2269             continue;
2270         if (security_stream_auth(streams[i].fd) < 0) {
2271             errstr = newvstrallocf(errstr,
2272                 _("[could not authenticate %s stream: %s]"),
2273                 streams[i].name, 
2274                 security_stream_geterror(streams[i].fd));
2275             goto connect_error;
2276         }
2277     }
2278
2279     /*
2280      * The MESGFD and DATAFD streams are mandatory.  If we didn't get
2281      * them, complain.
2282      */
2283     if (streams[MESGFD].fd == NULL || streams[DATAFD].fd == NULL) {
2284         errstr = newvstrallocf(errstr, _("[couldn't open MESG or INDEX streams]"));
2285         goto connect_error;
2286     }
2287
2288     /* everything worked */
2289     *response_error = 0;
2290     return;
2291
2292 parse_error:
2293     errstr = newvstrallocf(errstr,
2294                           _("[parse of reply message failed: %s]"),
2295                           extra ? extra : _("(no additional information)"));
2296     amfree(extra);
2297     *response_error = 2;
2298     return;
2299
2300 connect_error:
2301     stop_dump();
2302     *response_error = 1;
2303 }
2304
2305 static char *
2306 dumper_get_security_conf(
2307     char *      string,
2308     void *      arg)
2309 {
2310         (void)arg;      /* Quiet unused parameter warning */
2311
2312         if(!string || !*string)
2313                 return(NULL);
2314
2315         if(strcmp(string, "krb5principal")==0) {
2316                 return(getconf_str(CNF_KRB5PRINCIPAL));
2317         } else if(strcmp(string, "krb5keytab")==0) {
2318                 return(getconf_str(CNF_KRB5KEYTAB));
2319         } else if(strcmp(string, "amandad_path")==0) {
2320                 return (amandad_path);
2321         } else if(strcmp(string, "client_username")==0) {
2322                 return (client_username);
2323         } else if(strcmp(string, "client_port")==0) {
2324                 return (client_port);
2325         } else if(strcmp(string, "ssh_keys")==0) {
2326                 return (ssh_keys);
2327         } else if(strcmp(string, "kencrypt")==0) {
2328                 if (dumper_kencrypt == KENCRYPT_YES)
2329                     return ("yes");
2330                 else
2331                     return (NULL);
2332         }
2333         return(NULL);
2334 }
2335
2336 static int
2337 startup_dump(
2338     const char *hostname,
2339     const char *disk,
2340     const char *device,
2341     int         level,
2342     const char *dumpdate,
2343     const char *progname,
2344     const char *amandad_path,
2345     const char *client_username,
2346     const char *client_port,
2347     const char *ssh_keys,
2348     const char *auth,
2349     const char *options)
2350 {
2351     char level_string[NUM_STR_SIZE];
2352     char *req = NULL;
2353     int response_error;
2354     const security_driver_t *secdrv;
2355     char *application_api;
2356     int has_features;
2357     int has_hostname;
2358     int has_device;
2359     int has_config;
2360
2361     (void)disk;                 /* Quiet unused parameter warning */
2362     (void)amandad_path;         /* Quiet unused parameter warning */
2363     (void)client_username;      /* Quiet unused parameter warning */
2364     (void)client_port;          /* Quiet unused parameter warning */
2365     (void)ssh_keys;             /* Quiet unused parameter warning */
2366     (void)auth;                 /* Quiet unused parameter warning */
2367
2368     has_features = am_has_feature(their_features, fe_req_options_features);
2369     has_hostname = am_has_feature(their_features, fe_req_options_hostname);
2370     has_config   = am_has_feature(their_features, fe_req_options_config);
2371     has_device   = am_has_feature(their_features, fe_sendbackup_req_device);
2372
2373     /*
2374      * Default to bsd authentication if none specified.  This is gross.
2375      *
2376      * Options really need to be pre-parsed into some sort of structure
2377      * much earlier, and then flattened out again before transmission.
2378      */
2379
2380     g_snprintf(level_string, SIZEOF(level_string), "%d", level);
2381     if(strcmp(progname, "DUMP") == 0
2382        || strcmp(progname, "GNUTAR") == 0) {
2383         application_api = "";
2384     } else {
2385         application_api = "BACKUP ";
2386     }
2387     req = vstralloc("SERVICE sendbackup\n",
2388                     "OPTIONS ",
2389                     has_features ? "features=" : "",
2390                     has_features ? our_feature_string : "",
2391                     has_features ? ";" : "",
2392                     has_hostname ? "hostname=" : "",
2393                     has_hostname ? hostname : "",
2394                     has_hostname ? ";" : "",
2395                     has_config   ? "config=" : "",
2396                     has_config   ? get_config_name() : "",
2397                     has_config   ? ";" : "",
2398                     "\n",
2399                     NULL);
2400
2401     amfree(dle_str);
2402     if (am_has_feature(their_features, fe_req_xml)) {
2403         char *p = NULL;
2404         char *pclean;
2405         vstrextend(&p, "<dle>\n", NULL);
2406         if (*application_api != '\0') {
2407             vstrextend(&p, "  <program>APPLICATION</program>\n", NULL);
2408         } else {
2409             vstrextend(&p, "  <program>", progname, "</program>\n", NULL);
2410         }
2411         vstrextend(&p, "  ", b64disk, "\n", NULL);
2412         if (device && has_device) {
2413             vstrextend(&p, "  ", b64device, "\n",
2414                        NULL);
2415         }
2416         vstrextend(&p, "  <level>", level_string, "</level>\n", NULL);
2417         vstrextend(&p, options+1, "</dle>\n", NULL);
2418         pclean = clean_dle_str_for_client(p, their_features);
2419         vstrextend(&req, pclean, NULL);
2420         amfree(pclean);
2421         dle_str = p;
2422     } else if (*application_api != '\0') {
2423         errstr = newvstrallocf(errstr,
2424                 _("[does not support application-api]"));
2425         amfree(req);
2426         return 2;
2427     } else {
2428         if (auth == NULL) {
2429             auth = "BSD";
2430         }
2431         vstrextend(&req,
2432                    progname,
2433                    " ", qdiskname,
2434                    " ", device && has_device ? device : "",
2435                    " ", level_string,
2436                    " ", dumpdate,
2437                    " OPTIONS ", options,
2438                    "\n",
2439                    NULL);
2440     }
2441
2442     dbprintf(_("send request:\n----\n%s\n----\n\n"), req);
2443     secdrv = security_getdriver(auth);
2444     if (secdrv == NULL) {
2445         errstr = newvstrallocf(errstr,
2446                 _("[could not find security driver '%s']"), auth);
2447         amfree(req);
2448         return 2;
2449     }
2450
2451     protocol_sendreq(hostname, secdrv, dumper_get_security_conf, req,
2452         STARTUP_TIMEOUT, sendbackup_response, &response_error);
2453
2454     amfree(req);
2455
2456     protocol_run();
2457     return (response_error);
2458 }