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