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