2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1999 University of Maryland at College Park
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.
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.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
26 /* $Id: dumper.c,v 1.170 2006/03/22 15:10:52 martinea Exp $
28 * requests remote amandad processes to dump filesystems
43 #include "fileheader.h"
44 #include "amfeatures.h"
45 #include "server_util.h"
56 #define CONNECT_TIMEOUT 5*60
58 #define STARTUP_TIMEOUT 60
61 int fd; /* file to flush to */
63 char *datain; /* data buffer markers */
66 pid_t compresspid; /* valid if fd is pipe to compress */
67 pid_t encryptpid; /* valid if fd is pipe to encrypt */
70 static char *handle = NULL;
72 static char *errstr = NULL;
73 static long dumpbytes;
74 static long dumpsize, headersize, origsize;
76 static comp_t srvcompress = COMP_NONE;
77 char *srvcompprog = NULL;
78 char *clntcompprog = NULL;
80 static encrypt_t srvencrypt = ENCRYPT_NONE;
81 char *srv_encrypt = NULL;
82 char *clnt_encrypt = NULL;
83 char *srv_decrypt_opt = NULL;
84 char *clnt_decrypt_opt = NULL;
86 static FILE *errf = NULL;
87 static char *hostname = NULL;
88 am_feature_t *their_features = NULL;
89 static char *diskname = NULL;
90 static char *device = NULL;
91 static char *options = NULL;
92 static char *progname = NULL;
94 static char *dumpdate = NULL;
95 static char *datestamp;
96 static int conf_dtimeout;
97 static int indexfderror;
99 static dumpfile_t file;
103 security_stream_t *fd;
112 #define NSTREAMS (sizeof(streams) / sizeof(streams[0]))
114 static am_feature_t *our_features = NULL;
115 static char *our_feature_string = NULL;
117 /* local functions */
118 int main P((int, char **));
119 static int do_dump P((struct databuf *));
120 static void check_options P((char *));
121 static void finish_tapeheader P((dumpfile_t *));
122 static int write_tapeheader P((int, dumpfile_t *));
123 static void databuf_init P((struct databuf *, int));
124 static int databuf_write P((struct databuf *, const void *, int));
125 static int databuf_flush P((struct databuf *));
126 static void process_dumpeof P((void));
127 static void process_dumpline P((const char *));
128 static void add_msg_data P((const char *, size_t));
129 static void parse_info_line P((char *));
130 static void log_msgout P((logtype_t));
132 static int runcompress P((int, pid_t *, comp_t));
133 static int runencrypt P((int, pid_t *, encrypt_t));
135 static void sendbackup_response P((void *, pkt_t *, security_handle_t *));
136 static int startup_dump P((const char *, const char *, const char *, int,
137 const char *, const char *, const char *));
138 static void stop_dump P((void));
140 static void read_indexfd P((void *, void *, ssize_t));
141 static void read_datafd P((void *, void *, ssize_t));
142 static void read_mesgfd P((void *, void *, ssize_t));
143 static void timeout P((int));
144 static void timeout_callback P((void *));
147 check_options(options)
150 char *compmode = NULL;
151 char *compend = NULL;
152 char *encryptmode = NULL;
153 char *encryptend = NULL;
154 char *decryptmode = NULL;
155 char *decryptend = NULL;
157 /* parse the compression option */
158 if (strstr(options, "srvcomp-best;") != NULL)
159 srvcompress = COMP_BEST;
160 else if (strstr(options, "srvcomp-fast;") != NULL)
161 srvcompress = COMP_FAST;
162 else if ((compmode = strstr(options, "srvcomp-cust=")) != NULL) {
163 compend = strchr(compmode, ';');
165 srvcompress = COMP_SERV_CUST;
167 srvcompprog = stralloc(compmode + strlen("srvcomp-cust="));
170 } else if ((compmode = strstr(options, "comp-cust=")) != NULL) {
171 compend = strchr(compmode, ';');
173 srvcompress = COMP_CUST;
175 clntcompprog = stralloc(compmode + strlen("comp-cust="));
180 srvcompress = COMP_NONE;
184 /* now parse the encryption option */
185 if ((encryptmode = strstr(options, "encrypt-serv-cust=")) != NULL) {
186 encryptend = strchr(encryptmode, ';');
188 srvencrypt = ENCRYPT_SERV_CUST;
190 srv_encrypt = stralloc(encryptmode + strlen("encrypt-serv-cust="));
193 } else if ((encryptmode = strstr(options, "encrypt-cust=")) != NULL) {
194 encryptend = strchr(encryptmode, ';');
196 srvencrypt = ENCRYPT_CUST;
198 clnt_encrypt = stralloc(encryptmode + strlen("encrypt-cust="));
202 srvencrypt = ENCRYPT_NONE;
204 /* get the decryption option parameter */
205 if ((decryptmode = strstr(options, "server-decrypt-option=")) != NULL) {
206 decryptend = strchr(decryptmode, ';');
209 srv_decrypt_opt = stralloc(decryptmode + strlen("server-decrypt-option="));
212 } else if ((decryptmode = strstr(options, "client-decrypt-option=")) != NULL) {
213 decryptend = strchr(decryptmode, ';');
216 clnt_decrypt_opt = stralloc(decryptmode + strlen("client-decrypt-option="));
224 main(main_argc, main_argv)
228 static struct databuf db;
229 struct cmdargs cmdargs;
233 unsigned long malloc_hist_1, malloc_size_1;
234 unsigned long malloc_hist_2, malloc_size_2;
243 /* Don't die when child closes pipe */
244 signal(SIGPIPE, SIG_IGN);
246 malloc_size_1 = malloc_inuse(&malloc_hist_1);
248 erroutput_type = (ERR_AMANDALOG|ERR_INTERACTIVE);
249 set_logerror(logerror);
252 config_name = stralloc(main_argv[1]);
253 config_dir = vstralloc(CONFIG_DIR, "/", config_name, "/", NULL);
255 char my_cwd[STR_SIZE];
257 if (getcwd(my_cwd, sizeof(my_cwd)) == NULL) {
258 error("cannot determine current working directory");
260 config_dir = stralloc2(my_cwd, "/");
261 if ((config_name = strrchr(my_cwd, '/')) != NULL) {
262 config_name = stralloc(config_name + 1);
268 our_features = am_init_feature_set();
269 our_feature_string = am_feature_to_string(our_features);
271 conffile = stralloc2(config_dir, CONFFILE_NAME);
272 if(read_conffile(conffile)) {
273 error("errors processing config file \"%s\"", conffile);
278 * Make our effective uid nonprivlidged, but keep our real uid as root
279 * in case we need to get back (to bind privlidged ports, etc).
282 uid_t ruid = getuid();
287 #if defined BSD_SECURITY && !defined SSH_SECURITY
288 else error("must be run setuid root to communicate correctly");
292 "%s: pid %ld executable %s version %s\n",
293 get_pname(), (long) getpid(),
294 main_argv[0], version());
297 /* now, make sure we are a valid user */
299 if (getpwuid(getuid()) == NULL)
300 error("can't get login name for my uid %ld", (long)getuid());
302 signal(SIGPIPE, SIG_IGN);
304 datestamp = construct_datestamp(NULL);
305 conf_dtimeout = getconf_int(CNF_DTIMEOUT);
310 cmd = getcmd(&cmdargs);
330 cmdargs.argc++; /* true count of args */
333 if(a >= cmdargs.argc) {
334 error("error [dumper PORT-DUMP: not enough args: handle]");
336 handle = newstralloc(handle, cmdargs.argv[a++]);
338 if(a >= cmdargs.argc) {
339 error("error [dumper PORT-DUMP: not enough args: handle]");
341 taper_port = atoi(cmdargs.argv[a++]);
343 if(a >= cmdargs.argc) {
344 error("error [dumper PORT-DUMP: not enough args: handle]");
346 hostname = newstralloc(hostname, cmdargs.argv[a++]);
348 if(a >= cmdargs.argc) {
349 error("error [dumper PORT-DUMP: not enough args: features]");
351 am_release_feature_set(their_features);
352 their_features = am_string_to_feature(cmdargs.argv[a++]);
354 if(a >= cmdargs.argc) {
355 error("error [dumper PORT-DUMP: not enough args: handle]");
357 diskname = newstralloc(diskname, cmdargs.argv[a++]);
359 if(a >= cmdargs.argc) {
360 error("error [dumper PORT-DUMP: not enough args: handle]");
362 device = newstralloc(device, cmdargs.argv[a++]);
363 if(strcmp(device,"NODEVICE") == 0) amfree(device);
365 if(a >= cmdargs.argc) {
366 error("error [dumper PORT-DUMP: not enough args: handle]");
368 level = atoi(cmdargs.argv[a++]);
370 if(a >= cmdargs.argc) {
371 error("error [dumper PORT-DUMP: not enough args: handle]");
373 dumpdate = newstralloc(dumpdate, cmdargs.argv[a++]);
375 if(a >= cmdargs.argc) {
376 error("error [dumper PORT-DUMP: not enough args: handle]");
378 progname = newstralloc(progname, cmdargs.argv[a++]);
380 if(a >= cmdargs.argc) {
381 error("error [dumper PORT-DUMP: not enough args: handle]");
383 options = newstralloc(options, cmdargs.argv[a++]);
385 if(a != cmdargs.argc) {
386 error("error [dumper PORT-DUMP: too many args: %d != %d]",
390 /* connect outf to taper port */
392 outfd = stream_client("localhost", taper_port,
393 STREAM_BUFSIZE, -1, NULL, 0);
395 q = squotef("[taper port open: %s]", strerror(errno));
396 putresult(FAILED, "%s %s\n", handle, q);
400 databuf_init(&db, outfd);
402 check_options(options);
404 rc = startup_dump(hostname,
413 putresult(rc == 2? FAILED : TRYAGAIN, "%s %s\n",
416 log_add(L_FAIL, "%s %s %s %d [%s]", hostname, diskname,
417 datestamp, level, errstr);
426 if(cmdargs.argc >= 1) {
427 q = squote(cmdargs.argv[1]);
428 } else if(cmdargs.argc >= 0) {
429 q = squote(cmdargs.argv[0]);
431 q = stralloc("(no input?)");
433 putresult(BAD_COMMAND, "%s\n", q);
440 } while(cmd != QUIT);
451 amfree(clntcompprog);
453 amfree(clnt_encrypt);
454 amfree(srv_decrypt_opt);
455 amfree(clnt_decrypt_opt);
460 malloc_size_2 = malloc_inuse(&malloc_hist_2);
462 if (malloc_size_1 != malloc_size_2)
463 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
470 * Initialize a databuf. Takes a writeable file descriptor.
479 db->datain = db->dataout = db->datalimit = NULL;
480 db->compresspid = -1;
486 * Updates the buffer pointer for the input data buffer. The buffer is
487 * written regardless of how much data is present, since we know we
488 * are writing to a socket (to chunker) and there is no need to maintain
492 databuf_write(db, buf, size)
497 db->buf = (char *)buf;
498 db->datain = db->datalimit = db->buf + size;
499 db->dataout = db->buf;
500 return databuf_flush(db);
504 * Write out the buffer to chunker.
513 * If there's no data, do nothing.
515 if (db->dataout >= db->datain) {
520 * Write out the buffer
522 written = fullwrite(db->fd, db->dataout, db->datain - db->dataout);
524 db->dataout += written;
525 dumpbytes += written;
527 if (dumpbytes >= 1024) {
528 dumpsize += (dumpbytes / 1024);
532 errstr = squotef("data write: %s", strerror(errno));
535 db->datain = db->dataout = db->buf;
539 static int dump_result;
541 #define GOT_INFO_ENDLINE (1 << 0)
542 #define GOT_SIZELINE (1 << 1)
543 #define GOT_ENDLINE (1 << 2)
544 #define HEADER_DONE (1 << 3)
550 /* process any partial line in msgbuf? !!! */
551 add_msg_data(NULL, 0);
552 if(!ISSET(status, GOT_SIZELINE) && dump_result < 2) {
553 /* make a note if there isn't already a failure */
555 "? %s: strange [missing size line from sendbackup]\n",
558 errstr = stralloc("missing size line from sendbackup");
560 dump_result = max(dump_result, 2);
563 if(!ISSET(status, GOT_ENDLINE) && dump_result < 2) {
565 "? %s: strange [missing end line from sendbackup]\n",
568 errstr = stralloc("missing end line from sendbackup");
570 dump_result = max(dump_result, 2);
575 * Parse an information line from the client.
576 * We ignore unknown parameters and only remember the last
583 static const struct {
588 { "BACKUP", file.program, sizeof(file.program) },
589 { "RECOVER_CMD", file.recover_cmd, sizeof(file.recover_cmd) },
590 { "COMPRESS_SUFFIX", file.comp_suffix, sizeof(file.comp_suffix) },
591 { "SERVER_CUSTOM_COMPRESS", file.srvcompprog, sizeof(file.srvcompprog) },
592 { "CLIENT_CUSTOM_COMPRESS", file.clntcompprog, sizeof(file.clntcompprog) },
593 { "SERVER_ENCRYPT", file.srv_encrypt, sizeof(file.srv_encrypt) },
594 { "CLIENT_ENCRYPT", file.clnt_encrypt, sizeof(file.clnt_encrypt) },
595 { "SERVER_DECRYPT_OPTION", file.srv_decrypt_opt, sizeof(file.srv_decrypt_opt) },
596 { "CLIENT_DECRYPT_OPTION", file.clnt_decrypt_opt, sizeof(file.clnt_decrypt_opt) }
601 if (strcmp(str, "end") == 0) {
602 SET(status, GOT_INFO_ENDLINE);
606 name = strtok(str, "=");
609 value = strtok(NULL, "");
613 for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) {
614 if (strcmp(name, fields[i].name) == 0) {
615 strncpy(fields[i].value, value, fields[i].len - 1);
616 fields[i].value[fields[i].len - 1] = '\0';
623 process_dumpline(str)
632 /* normal backup output line */
635 /* sendbackup detected something strange */
636 dump_result = max(dump_result, 1);
639 /* a sendbackup line, just check them all since there are only 5 */
640 tok = strtok(buf, " ");
641 if (tok == NULL || strcmp(tok, "sendbackup:") != 0)
644 tok = strtok(NULL, " ");
648 if (strcmp(tok, "start") == 0)
651 if (strcmp(tok, "size") == 0) {
652 tok = strtok(NULL, "");
654 origsize = (long)atof(tok);
655 SET(status, GOT_SIZELINE);
660 if (strcmp(tok, "end") == 0) {
661 SET(status, GOT_ENDLINE);
665 if (strcmp(tok, "warning") == 0) {
666 dump_result = max(dump_result, 1);
670 if (strcmp(tok, "error") == 0) {
671 SET(status, GOT_ENDLINE);
672 dump_result = max(dump_result, 2);
674 tok = strtok(NULL, "");
675 if (tok == NULL || *tok != '[') {
676 errstr = newvstralloc(errstr, "bad remote error: ", str, NULL);
680 tok++; /* skip over '[' */
681 if ((enderr = strchr(tok, ']')) != NULL)
683 errstr = newstralloc(errstr, tok);
688 if (strcmp(tok, "info") == 0) {
689 tok = strtok(NULL, "");
691 parse_info_line(tok);
694 /* else we fall through to bad line */
699 dump_result = max(dump_result, 1);
702 fprintf(errf, "%s\n", str);
707 add_msg_data(str, len)
712 char *buf; /* buffer holding msg data */
713 size_t size; /* size of alloced buffer */
719 buflen = strlen(msg.buf);
724 * If our argument is NULL, then we need to flush out any remaining
730 fprintf(errf,"? %s: error [partial line in msgbuf: %ld bytes]\n",
731 get_pname(), (long)buflen);
732 fprintf(errf,"? %s: error [partial line in msgbuf: \"%s\"]\n",
733 get_pname(), msg.buf);
739 * Expand the buffer if it can't hold the new contents.
741 if (buflen + len + 1 > msg.size) {
745 /* round up to next y, where y is a power of 2 */
746 #define ROUND(x, y) (((x) + (y) - 1) & ~((y) - 1))
748 newsize = ROUND(buflen + len + 1, 256);
749 newbuf = alloc(newsize);
751 if (msg.buf != NULL) {
752 strcpy(newbuf, msg.buf);
761 * If there was a partial line from the last call, then
762 * append the new data to the end.
764 strncat(msg.buf, str, len);
767 * Process all lines in the buffer
769 for (line = msg.buf;;) {
771 * If there's no newline, then we've only got a partial line.
772 * We go back for more.
774 if ((nl = strchr(line, '\n')) == NULL)
777 process_dumpline(line);
782 * If we did not process all of the data, move it to the front
783 * of the buffer so it is there next time.
786 buflen = strlen(line);
787 memmove(msg.buf, line, buflen + 1);
801 (void) fseek(errf, 0L, SEEK_SET);
802 while ((line = agets(errf)) != NULL) {
803 log_add(typ, "%s", line);
813 * Fill in the rest of the tape header
816 finish_tapeheader(file)
820 assert(ISSET(status, HEADER_DONE));
822 file->type = F_DUMPFILE;
823 strncpy(file->datestamp, datestamp, sizeof(file->datestamp) - 1);
824 strncpy(file->name, hostname, sizeof(file->name) - 1);
825 strncpy(file->disk, diskname, sizeof(file->disk) - 1);
826 file->dumplevel = level;
829 * If we're doing the compression here, we need to override what
830 * sendbackup told us the compression was.
832 if (srvcompress != COMP_NONE) {
833 file->compressed = 1;
834 #ifndef UNCOMPRESS_OPT
835 #define UNCOMPRESS_OPT ""
837 if (srvcompress == COMP_SERV_CUST) {
838 snprintf(file->uncompress_cmd, sizeof(file->uncompress_cmd),
839 " %s %s |", srvcompprog, "-d");
840 strcpy(file->comp_suffix, "cust");
841 strncpy(file->srvcompprog, srvcompprog, sizeof(file->srvcompprog));
842 file->srvcompprog[sizeof(file->srvcompprog)-1] = '\0';
843 } else if ( srvcompress == COMP_CUST ) {
844 snprintf(file->uncompress_cmd, sizeof(file->uncompress_cmd),
845 " %s %s |", clntcompprog, "-d");
846 strcpy(file->comp_suffix, "cust");
847 strncpy(file->clntcompprog, clntcompprog, sizeof(file->clntcompprog));
848 file->clntcompprog[sizeof(file->clntcompprog)-1] = '\0';
850 snprintf(file->uncompress_cmd, sizeof(file->uncompress_cmd),
851 " %s %s |", UNCOMPRESS_PATH, UNCOMPRESS_OPT);
852 strncpy(file->comp_suffix, COMPRESS_SUFFIX,sizeof(file->comp_suffix)-1);
853 file->comp_suffix[sizeof(file->comp_suffix)-1] = '\0';
856 if (file->comp_suffix[0] == '\0') {
857 file->compressed = 0;
858 assert(sizeof(file->comp_suffix) >= 2);
859 strcpy(file->comp_suffix, "N");
861 file->compressed = 1;
864 /* take care of the encryption header here */
865 if (srvencrypt != ENCRYPT_NONE) {
867 if (srvencrypt == ENCRYPT_SERV_CUST) {
868 snprintf(file->decrypt_cmd, sizeof(file->decrypt_cmd),
869 " %s %s |", srv_encrypt, srv_decrypt_opt);
870 strcpy(file->encrypt_suffix, "enc");
871 strncpy(file->srv_encrypt, srv_encrypt, sizeof(file->srv_encrypt));
872 file->srv_encrypt[sizeof(file->srv_encrypt)-1] = '\0';
873 strncpy(file->srv_decrypt_opt, srv_decrypt_opt, sizeof(file->srv_decrypt_opt));
874 file->srv_decrypt_opt[sizeof(file->srv_decrypt_opt)-1] = '\0';
875 } else if ( srvencrypt == ENCRYPT_CUST ) {
876 snprintf(file->decrypt_cmd, sizeof(file->decrypt_cmd),
877 " %s %s |", clnt_encrypt, clnt_decrypt_opt);
878 strcpy(file->encrypt_suffix, "enc");
879 strncpy(file->clnt_encrypt, clnt_encrypt, sizeof(file->clnt_encrypt));
880 file->clnt_encrypt[sizeof(file->clnt_encrypt)-1] = '\0';
881 strncpy(file->clnt_decrypt_opt, clnt_decrypt_opt, sizeof(file->clnt_decrypt_opt));
882 file->clnt_decrypt_opt[sizeof(file->clnt_decrypt_opt)-1] = '\0';
885 if (file->encrypt_suffix[0] == '\0') {
887 assert(sizeof(file->encrypt_suffix) >= 2);
888 strcpy(file->encrypt_suffix, "N");
896 * Send an Amanda dump header to the output file.
899 write_tapeheader(outfd, file)
903 char buffer[DISK_BLOCK_BYTES];
906 build_header(buffer, file, sizeof(buffer));
908 written = write(outfd, buffer, sizeof(buffer));
909 if(written == sizeof(buffer)) return 0;
910 if(written < 0) return written;
919 char *indexfile_tmp = NULL;
920 char *indexfile_real = NULL;
921 char level_str[NUM_STR_SIZE];
925 double dumptime; /* Time dump took in secs */
926 char *errfname = NULL;
932 dumpbytes = dumpsize = headersize = origsize = dump_result = 0;
936 snprintf(level_str, sizeof(level_str), "%d", level);
937 fn = sanitise_filename(diskname);
938 errfname = newvstralloc(errfname,
946 if((errf = fopen(errfname, "w+")) == NULL) {
947 errstr = newvstralloc(errstr,
948 "errfile open \"", errfname, "\": ",
954 unlink(errfname); /* so it goes away on close */
957 if (streams[INDEXFD].fd != NULL) {
958 indexfile_real = getindexfname(hostname, diskname, datestamp, level);
959 indexfile_tmp = stralloc2(indexfile_real, ".tmp");
961 if (mkpdir(indexfile_tmp, 02755, (uid_t)-1, (gid_t)-1) == -1) {
962 errstr = newvstralloc(errstr,
968 amfree(indexfile_real);
969 amfree(indexfile_tmp);
972 indexout = open(indexfile_tmp, O_WRONLY | O_CREAT | O_TRUNC, 0600);
973 if (indexout == -1) {
974 errstr = newvstralloc(errstr, "err open ", indexfile_tmp, ": ",
975 strerror(errno), NULL);
978 if (runcompress(indexout, &indexpid, COMP_BEST) < 0) {
985 * Schedule the indexfd for relaying to the index file
987 security_stream_read(streams[INDEXFD].fd, read_indexfd, &indexout);
991 * We only need to process messages initially. Once we have done
992 * the header, we will start processing data too.
994 security_stream_read(streams[MESGFD].fd, read_mesgfd, db);
997 * Setup a read timeout
999 timeout(conf_dtimeout);
1002 * Start the event loop. This will exit when all three events
1003 * (read the mesgfd, read the datafd, and timeout) are removed.
1007 if (dump_result > 1)
1010 runtime = stopclock();
1011 dumptime = runtime.r.tv_sec + runtime.r.tv_usec/1000000.0;
1013 dumpsize -= headersize; /* don't count the header */
1014 if (dumpsize < 0) dumpsize = 0; /* XXX - maybe this should be fatal? */
1017 errstr = alloc(128);
1018 snprintf(errstr, 128, "sec %s kb %ld kps %3.1f orig-kb %ld",
1019 walltime_str(runtime), dumpsize,
1020 dumptime ? dumpsize / dumptime : 0.0, origsize);
1021 q = squotef("[%s]", errstr);
1022 putresult(DONE, "%s %ld %ld %ld %s\n", handle, origsize, dumpsize,
1023 (long)(dumptime+0.5), q);
1026 switch(dump_result) {
1028 log_add(L_SUCCESS, "%s %s %s %d [%s]", hostname, diskname, datestamp, level, errstr);
1033 log_start_multiline();
1034 log_add(L_STRANGE, "%s %s %d [%s]", hostname, diskname, level, errstr);
1035 log_msgout(L_STRANGE);
1036 log_end_multiline();
1041 if (errf) afclose(errf);
1044 if (indexfile_tmp) {
1045 amwait_t index_status;
1048 waitpid(indexpid,&index_status,0);
1049 if (rename(indexfile_tmp, indexfile_real) != 0) {
1050 log_add(L_WARNING, "could not rename \"%s\" to \"%s\": %s",
1051 indexfile_tmp, indexfile_real, strerror(errno));
1053 amfree(indexfile_tmp);
1054 amfree(indexfile_real);
1057 if(db->compresspid != -1) {
1058 waitpid(db->compresspid,NULL,0);
1060 if(db->encryptpid != -1) {
1061 waitpid(db->encryptpid,NULL,0);
1069 q = squotef("[%s]", errstr);
1070 putresult(FAILED, "%s %s\n", handle, q);
1074 /* kill all child process */
1075 if (db->compresspid != -1) {
1076 fprintf(stderr,"%s: kill compress command\n",get_pname());
1077 if (kill(db->compresspid, SIGTERM) < 0) {
1079 fprintf(stderr,"%s: can't kill compress command: %s\n",
1080 get_pname(), strerror(errno));
1083 waitpid(db->compresspid,NULL,0);
1087 if (db->encryptpid != -1) {
1088 fprintf(stderr,"%s: kill encrypt command\n",get_pname());
1089 if (kill(db->encryptpid, SIGTERM) < 0) {
1091 fprintf(stderr,"%s: can't kill encrypt command: %s\n",
1092 get_pname(), strerror(errno));
1095 waitpid(db->encryptpid,NULL,0);
1099 if (indexpid != -1) {
1100 fprintf(stderr,"%s: kill index command\n",get_pname());
1101 if (kill(indexpid, SIGTERM) < 0) {
1103 fprintf(stderr,"%s: can't kill index command: %s\n",
1104 get_pname(),strerror(errno));
1107 waitpid(indexpid,NULL,0);
1111 log_start_multiline();
1112 log_add(L_FAIL, "%s %s %s %d [%s]", hostname, diskname, datestamp,
1117 log_end_multiline();
1119 if (errf) afclose(errf);
1121 if (indexfile_tmp) {
1122 unlink(indexfile_tmp);
1123 amfree(indexfile_tmp);
1124 amfree(indexfile_real);
1131 * Callback for reads on the mesgfd stream
1134 read_mesgfd(cookie, buf, size)
1138 struct databuf *db = cookie;
1144 errstr = newstralloc2(errstr, "mesg read: ",
1145 security_stream_geterror(streams[MESGFD].fd));
1151 * EOF. Just shut down the mesg stream.
1154 security_stream_close(streams[MESGFD].fd);
1155 streams[MESGFD].fd = NULL;
1157 * If the data fd and index fd has also shut down, then we're done.
1159 if (streams[DATAFD].fd == NULL && streams[INDEXFD].fd == NULL)
1163 assert(buf != NULL);
1164 add_msg_data(buf, size);
1165 security_stream_read(streams[MESGFD].fd, read_mesgfd, cookie);
1170 * Reset the timeout for future reads
1172 timeout(conf_dtimeout);
1174 if (ISSET(status, GOT_INFO_ENDLINE) && !ISSET(status, HEADER_DONE)) {
1175 SET(status, HEADER_DONE);
1176 /* time to do the header */
1177 finish_tapeheader(&file);
1178 if (write_tapeheader(db->fd, &file)) {
1179 errstr = newstralloc2(errstr, "write_tapeheader: ",
1185 dumpsize += DISK_BLOCK_KB;
1186 headersize += DISK_BLOCK_KB;
1188 if (srvencrypt == ENCRYPT_SERV_CUST) {
1189 if (runencrypt(db->fd, &db->encryptpid, srvencrypt) < 0) {
1196 * Now, setup the compress for the data output, and start
1197 * reading the datafd.
1199 if ((srvcompress != COMP_NONE) && (srvcompress != COMP_CUST)) {
1200 if (runcompress(db->fd, &db->compresspid, srvcompress) < 0) {
1206 security_stream_read(streams[DATAFD].fd, read_datafd, db);
1211 * Callback for reads on the datafd stream
1214 read_datafd(cookie, buf, size)
1218 struct databuf *db = cookie;
1223 * The read failed. Error out
1226 errstr = newstralloc2(errstr, "data read: ",
1227 security_stream_geterror(streams[DATAFD].fd));
1234 * Reset the timeout for future reads
1236 timeout(conf_dtimeout);
1238 /* The header had better be written at this point */
1239 assert(ISSET(status, HEADER_DONE));
1242 * EOF. Stop and return.
1249 security_stream_close(streams[DATAFD].fd);
1250 streams[DATAFD].fd = NULL;
1252 * If the mesg fd and index fd has also shut down, then we're done.
1254 if (streams[MESGFD].fd == NULL && streams[INDEXFD].fd == NULL)
1260 * We read something. Add it to the databuf and reschedule for
1263 assert(buf != NULL);
1264 if (databuf_write(db, buf, size) < 0) {
1265 errstr = newstralloc2(errstr, "data write: ", strerror(errno));
1270 security_stream_read(streams[DATAFD].fd, read_datafd, cookie);
1274 * Callback for reads on the index stream
1277 read_indexfd(cookie, buf, size)
1283 assert(cookie != NULL);
1284 fd = *(int *)cookie;
1287 errstr = newstralloc2(errstr, "index read: ",
1288 security_stream_geterror(streams[INDEXFD].fd));
1295 * EOF. Stop and return.
1298 security_stream_close(streams[INDEXFD].fd);
1299 streams[INDEXFD].fd = NULL;
1301 * If the mesg fd has also shut down, then we're done.
1303 if (streams[DATAFD].fd == NULL && streams[MESGFD].fd == NULL)
1308 assert(buf != NULL);
1311 * We ignore error while writing to the index file.
1313 if (fullwrite(fd, buf, size) < 0) {
1314 /* Ignore error, but schedule another read. */
1315 if(indexfderror == 0) {
1317 log_add(L_INFO, "Index corrupted for %s:%s", hostname, diskname);
1320 security_stream_read(streams[INDEXFD].fd, read_indexfd, cookie);
1324 * Startup a timeout in the event handler. If the arg is 0,
1325 * then remove the timeout.
1331 static event_handle_t *ev_timeout = NULL;
1334 * First, remove a timeout if one is active.
1336 if (ev_timeout != NULL) {
1337 event_release(ev_timeout);
1342 * Now, schedule a new one if 'seconds' is greater than 0
1345 ev_timeout = event_register(seconds, EV_TIME, timeout_callback, NULL);
1349 * This is the callback for timeout(). If this is reached, then we
1350 * have a data timeout.
1353 timeout_callback(unused)
1356 assert(unused == NULL);
1357 errstr = newstralloc(errstr, "data timeout");
1363 * This is called when everything needs to shut down so event_loop()
1371 for (i = 0; i < NSTREAMS; i++) {
1372 if (streams[i].fd != NULL) {
1373 security_stream_close(streams[i].fd);
1374 streams[i].fd = NULL;
1382 * Runs compress with the first arg as its stdout. Returns
1383 * 0 on success or negative if error, and it's pid via the second
1384 * argument. The outfd arg is dup2'd to the pipe to the compress
1388 runcompress(outfd, pid, comptype)
1393 int outpipe[2], rval;
1396 assert(pid != NULL);
1398 /* outpipe[0] is pipe's stdin, outpipe[1] is stdout. */
1399 if (pipe(outpipe) < 0) {
1400 errstr = newstralloc2(errstr, "pipe: ", strerror(errno));
1404 switch (*pid = fork()) {
1406 errstr = newstralloc2(errstr, "couldn't fork: ", strerror(errno));
1411 rval = dup2(outpipe[1], outfd);
1413 errstr = newstralloc2(errstr, "couldn't dup2: ", strerror(errno));
1418 if (dup2(outpipe[0], 0) < 0)
1419 error("err dup2 in: %s", strerror(errno));
1420 if (dup2(outfd, 1) == -1)
1421 error("err dup2 out: %s", strerror(errno));
1423 if (comptype != COMP_SERV_CUST) {
1424 execlp(COMPRESS_PATH, COMPRESS_PATH, ( comptype == COMP_BEST ?
1425 COMPRESS_BEST_OPT : COMPRESS_FAST_OPT), NULL);
1426 error("error: couldn't exec %s: %s", COMPRESS_PATH, strerror(errno));
1427 } else if (*srvcompprog) {
1428 execlp(srvcompprog, srvcompprog, (char *)0);
1429 error("error: couldn't exec server custom filter%s.\n", srvcompprog);
1437 * Runs encrypt with the first arg as its stdout. Returns
1438 * 0 on success or negative if error, and it's pid via the second
1439 * argument. The outfd arg is dup2'd to the pipe to the encrypt
1443 runencrypt(outfd, pid, encrypttype)
1446 encrypt_t encrypttype;
1448 int outpipe[2], rval;
1451 assert(pid != NULL);
1453 /* outpipe[0] is pipe's stdin, outpipe[1] is stdout. */
1454 if (pipe(outpipe) < 0) {
1455 errstr = newstralloc2(errstr, "pipe: ", strerror(errno));
1459 switch (*pid = fork()) {
1461 errstr = newstralloc2(errstr, "couldn't fork: ", strerror(errno));
1466 rval = dup2(outpipe[1], outfd);
1468 errstr = newstralloc2(errstr, "couldn't dup2: ", strerror(errno));
1473 if (dup2(outpipe[0], 0) < 0)
1474 error("err dup2 in: %s", strerror(errno));
1475 if (dup2(outfd, 1) < 0 )
1476 error("err dup2 out: %s", strerror(errno));
1478 if ((encrypttype == ENCRYPT_SERV_CUST) && *srv_encrypt) {
1479 execlp(srv_encrypt, srv_encrypt, (char *)0);
1480 error("error: couldn't exec server encryption%s.\n", srv_encrypt);
1488 /* -------------------- */
1491 sendbackup_response(datap, pkt, sech)
1494 security_handle_t *sech;
1496 int ports[NSTREAMS], *response_error = datap, i;
1502 assert(response_error != NULL);
1503 assert(sech != NULL);
1506 errstr = newvstralloc(errstr, "[request failed: ",
1507 security_geterror(sech), "]", NULL);
1508 *response_error = 1;
1512 if (pkt->type == P_NAK) {
1513 #if defined(PACKET_DEBUG)
1514 fprintf(stderr, "got nak response:\n----\n%s\n----\n\n", pkt->body);
1517 tok = strtok(pkt->body, " ");
1518 if (tok == NULL || strcmp(tok, "ERROR") != 0)
1521 tok = strtok(NULL, "\n");
1523 errstr = newvstralloc(errstr, "NAK: ", tok, NULL);
1524 *response_error = 1;
1527 errstr = newstralloc(errstr, "request NAK");
1528 *response_error = 2;
1533 if (pkt->type != P_REP) {
1534 errstr = newvstralloc(errstr, "received strange packet type ",
1535 pkt_type2str(pkt->type), ": ", pkt->body, NULL);
1536 *response_error = 1;
1540 #if defined(PACKET_DEBUG)
1541 fprintf(stderr, "got response:\n----\n%s\n----\n\n", pkt->body);
1544 for(i = 0; i < NSTREAMS; i++) {
1546 streams[i].fd = NULL;
1550 while((tok = strtok(p, " \n")) != NULL) {
1554 * Error response packets have "ERROR" followed by the error message
1555 * followed by a newline.
1557 if (strcmp(tok, "ERROR") == 0) {
1558 tok = strtok(NULL, "\n");
1560 tok = "[bogus error packet]";
1561 errstr = newstralloc(errstr, tok);
1562 *response_error = 2;
1567 * Regular packets have CONNECT followed by three streams
1569 if (strcmp(tok, "CONNECT") == 0) {
1572 * Parse the three stream specifiers out of the packet.
1574 for (i = 0; i < NSTREAMS; i++) {
1575 tok = strtok(NULL, " ");
1576 if (tok == NULL || strcmp(tok, streams[i].name) != 0) {
1577 extra = vstralloc("CONNECT token is \"",
1578 tok ? tok : "(null)",
1585 tok = strtok(NULL, " \n");
1586 if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) {
1587 extra = vstralloc("CONNECT ",
1590 tok ? tok : "(null)",
1591 "\": expected a port number",
1600 * OPTIONS [options string] '\n'
1602 if (strcmp(tok, "OPTIONS") == 0) {
1603 tok = strtok(NULL, "\n");
1605 extra = stralloc("OPTIONS token is missing");
1608 tok_end = tok + strlen(tok);
1610 while((p = strchr(tok, ';')) != NULL) {
1612 #define sc "features="
1613 if(strncmp(tok, sc, sizeof(sc)-1) == 0) {
1614 tok += sizeof(sc) - 1;
1616 am_release_feature_set(their_features);
1617 if((their_features = am_string_to_feature(tok)) == NULL) {
1618 errstr = newvstralloc(errstr,
1619 "OPTIONS: bad features value: ",
1630 extra = vstralloc("next token is \"",
1631 tok ? tok : "(null)",
1632 "\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\"",
1638 * Connect the streams to their remote ports
1640 for (i = 0; i < NSTREAMS; i++) {
1643 streams[i].fd = security_stream_client(sech, ports[i]);
1644 if (streams[i].fd == NULL) {
1645 errstr = newvstralloc(errstr,
1646 "[could not connect ", streams[i].name, " stream: ",
1647 security_geterror(sech), "]", NULL);
1653 * Authenticate the streams
1655 for (i = 0; i < NSTREAMS; i++) {
1656 if (streams[i].fd == NULL)
1658 #ifdef KRB4_SECURITY
1660 * XXX krb4 historically never authenticated the index stream!
1661 * We need to reproduce this lossage here to preserve compatibility
1663 * It is wrong to delve into sech, but we have no choice here.
1665 if (strcasecmp(sech->driver->name, "krb4") != 0 && i == INDEXFD)
1668 if (security_stream_auth(streams[i].fd) < 0) {
1669 errstr = newvstralloc(errstr,
1670 "[could not authenticate ", streams[i].name, " stream: ",
1671 security_stream_geterror(streams[i].fd), "]", NULL);
1677 * The MESGFD and DATAFD streams are mandatory. If we didn't get
1680 if (streams[MESGFD].fd == NULL || streams[DATAFD].fd == NULL) {
1681 errstr = newstralloc(errstr, "[couldn't open MESG or INDEX streams]");
1685 /* everything worked */
1686 *response_error = 0;
1690 errstr = newvstralloc(errstr,
1691 "[parse of reply message failed: ",
1692 extra ? extra : "(no additional information)",
1696 *response_error = 2;
1701 *response_error = 1;
1705 startup_dump(hostname, disk, device, level, dumpdate, progname, options)
1706 const char *hostname, *disk, *device, *dumpdate, *progname, *options;
1709 char level_string[NUM_STR_SIZE];
1711 char *authopt, *endauthopt, authoptbuf[64];
1713 const security_driver_t *secdrv;
1716 int has_features = am_has_feature(their_features, fe_req_options_features);
1717 int has_hostname = am_has_feature(their_features, fe_req_options_hostname);
1718 int has_device = am_has_feature(their_features, fe_sendbackup_req_device);
1721 * Default to bsd authentication if none specified. This is gross.
1723 * Options really need to be pre-parsed into some sort of structure
1724 * much earlier, and then flattened out again before transmission.
1726 if ((authopt = strstr(options, "auth=")) == NULL
1727 || (endauthopt = strchr(authopt, ';')) == NULL
1728 || (sizeof(authoptbuf) - 1 < endauthopt - authopt)) {
1731 authopt += strlen("auth=");
1732 strncpy(authoptbuf, authopt, endauthopt - authopt);
1733 authoptbuf[endauthopt - authopt] = '\0';
1734 authopt = authoptbuf;
1737 snprintf(level_string, sizeof(level_string), "%d", level);
1738 if(strncmp(progname, "DUMP", 4) == 0
1739 || strncmp(progname, "GNUTAR", 6) == 0) {
1742 dumper_api = "DUMPER ";
1744 req = vstralloc("SERVICE sendbackup\n",
1746 has_features ? "features=" : "",
1747 has_features ? our_feature_string : "",
1748 has_features ? ";" : "",
1749 has_hostname ? "hostname=" : "",
1750 has_hostname ? hostname : "",
1751 has_hostname ? ";" : "",
1753 dumper_api, progname,
1755 " ", device && has_device ? device : "",
1758 " OPTIONS ", options,
1759 /* compat: if auth=krb4, send krb4-auth */
1760 (strcasecmp(authopt, "krb4") ? "" : "krb4-auth"),
1764 secdrv = security_getdriver(authopt);
1765 if (secdrv == NULL) {
1766 error("no '%s' security driver available for host '%s'",
1770 protocol_sendreq(hostname, secdrv, generic_get_security_conf, req,
1771 STARTUP_TIMEOUT, sendbackup_response, &response_error);
1776 return (response_error);