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