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