2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 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.
27 * $Id: sendbackup.c,v 1.44.2.9.4.4.2.16.2.1 2005/09/20 21:31:52 jrjackson Exp $
29 * common code for the sendbackup-* programs.
33 #include "sendbackup.h"
35 #include "pipespawn.h"
36 #include "amfeatures.h"
49 char *errorstr = NULL;
51 int data_socket, data_port, dataf;
52 int mesg_socket, mesg_port, mesgf;
53 int index_socket, index_port, indexf;
58 #include "sendbackup-krb4.h"
59 #else /* I'd tell you what this does */
60 #define NAUGHTY_BITS /* but then I'd have to kill you */
65 backup_program_t *program = NULL;
67 static am_feature_t *our_features = NULL;
68 static char *our_feature_string = NULL;
69 static g_option_t *g_options = NULL;
72 int main P((int argc, char **argv));
73 char *optionstr P((option_t *options));
74 char *childstr P((int pid));
75 int check_status P((int pid, amwait_t w));
77 int pipefork P((void (*func) P((void)), char *fname, int *stdinfd,
78 int stdoutfd, int stderrfd));
79 void parse_backup_messages P((int mesgin));
80 static void process_dumpline P((char *str));
83 char *optionstr(option_t *options)
85 static char *optstr = NULL;
86 char *compress_opt = "";
87 char *record_opt = "";
90 char *kencrypt_opt = "";
92 char *exclude_file_opt;
93 char *exclude_list_opt;
97 if(options->compress == COMPR_BEST)
98 compress_opt = "compress-best;";
99 else if(options->compress == COMPR_FAST)
100 compress_opt = "compress-fast;";
101 else if(options->compress == COMPR_SERVER_BEST)
102 compress_opt = "srvcomp-best;";
103 else if(options->compress == COMPR_SERVER_FAST)
104 compress_opt = "srvcomp-fast;";
105 if(options->no_record) record_opt = "no-record;";
106 if(options->bsd_auth) bsd_opt = "bsd-auth;";
108 if(options->krb4_auth) krb4_opt = "krb4-auth;";
109 if(options->kencrypt) kencrypt_opt = "kencrypt;";
111 if(options->createindex) index_opt = "index;";
113 exclude_file_opt = stralloc("");
114 if(options->exclude_file) {
115 for(excl = options->exclude_file->first; excl != NULL; excl=excl->next){
116 exc = newvstralloc(exc, "exclude-file=", excl->name, ";", NULL);
117 strappend(exclude_file_opt, exc);
120 exclude_list_opt = stralloc("");
121 if(options->exclude_list) {
122 for(excl = options->exclude_list->first; excl != NULL; excl=excl->next){
123 exc = newvstralloc(exc, "exclude-list=", excl->name, ";", NULL);
124 strappend(exclude_list_opt, exc);
127 optstr = newvstralloc(optstr,
146 int level, mesgpipe[2];
147 char *prog, *disk, *amdevice, *dumpdate, *stroptions;
149 char *err_extra = NULL;
153 unsigned long malloc_hist_1, malloc_size_1;
154 unsigned long malloc_hist_2, malloc_size_2;
159 safe_fd(KEY_PIPE, 1); /* XXX interface needs to be fixed */
166 set_pname("sendbackup");
168 malloc_size_1 = malloc_inuse(&malloc_hist_1);
170 interactive = (argc > 1 && strcmp(argv[1],"-t") == 0);
171 erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
174 dbprintf(("%s: version %s\n", argv[0], version()));
176 our_features = am_init_feature_set();
177 our_feature_string = am_feature_to_string(our_features);
181 * In interactive (debug) mode, the backup data is sent to
182 * /dev/null and none of the network connections back to driver
183 * programs on the tape host are set up. The index service is
184 * run and goes to stdout.
186 fprintf(stderr, "%s: running in interactive test mode\n", get_pname());
196 /* parse dump request */
198 for(; (line = agets(stdin)) != NULL; free(line)) {
200 fprintf(stderr, "%s> ", get_pname());
203 #define sc "OPTIONS "
204 if(strncmp(line, sc, sizeof(sc)-1) == 0) {
206 g_options = parse_g_options(line+8, 1);
207 if(!g_options->hostname) {
208 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
209 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
210 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
216 err_extra = "multiple requests";
223 skip_whitespace(s, ch); /* find the program name */
225 err_extra = "no program name";
226 goto err; /* no program name */
229 skip_non_whitespace(s, ch);
231 prog = stralloc(prog);
233 skip_whitespace(s, ch); /* find the disk name */
235 err_extra = "no disk name";
236 goto err; /* no disk name */
240 skip_non_whitespace(s, ch);
242 disk = stralloc(disk);
244 skip_whitespace(s, ch); /* find the device or level */
246 err_extra = "bad level";
250 if(!isdigit((int)s[-1])) {
253 skip_non_whitespace(s, ch);
255 amdevice = stralloc(amdevice);
256 skip_whitespace(s, ch); /* find level number */
259 amdevice = stralloc(disk);
262 /* find the level number */
263 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
264 err_extra = "bad level";
265 goto err; /* bad level */
269 skip_whitespace(s, ch); /* find the dump date */
271 err_extra = "no dumpdate";
272 goto err; /* no dumpdate */
276 skip_non_whitespace(s, ch);
278 dumpdate = stralloc(dumpdate);
280 skip_whitespace(s, ch); /* find the options keyword */
282 err_extra = "no options";
283 goto err; /* no options */
285 #define sc "OPTIONS "
286 if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
287 err_extra = "no OPTIONS keyword";
288 goto err; /* no options */
293 skip_whitespace(s, ch); /* find the options string */
295 err_extra = "bad options string";
296 goto err; /* no options */
299 stroptions = stralloc(s - 1);
303 dbprintf((" parsed request as: program `%s'\n", prog));
304 dbprintf((" disk `%s'\n", disk));
305 dbprintf((" device `%s'\n", amdevice));
306 dbprintf((" level %d\n", level));
307 dbprintf((" since %s\n", dumpdate));
308 dbprintf((" options `%s'\n", stroptions));
310 for(i = 0; programs[i] != NULL; i++) {
311 if (strcmp(programs[i]->name, prog) == 0) {
315 if (programs[i] == NULL) {
316 error("ERROR [%s: unknown program %s]", get_pname(), prog);
318 program = programs[i];
320 options = parse_options(stroptions, disk, amdevice, g_options->features, 0);
323 /* modification by BIS@BBN 4/25/2003:
324 * with the option processing changes in amanda 2.4.4, must change
325 * the conditional from krb4_auth to options->krb4_auth */
326 if(options->krb4_auth) {
327 if(read(KEY_PIPE, session_key, sizeof session_key)
328 != sizeof session_key) {
329 error("ERROR [%s: could not read session key]", get_pname());
335 data_socket = stream_server(&data_port, STREAM_BUFSIZE, -1);
336 if(data_socket < 0) {
337 error("ERROR [%s: could not create data socket: %s]",
338 get_pname(), strerror(errno));
340 mesg_socket = stream_server(&mesg_port, -1, -1);
341 if(mesg_socket < 0) {
342 error("ERROR [%s: could not create mesg socket: %s]",
343 get_pname(), strerror(errno));
346 if (!interactive && options->createindex) {
347 index_socket = stream_server(&index_port, -1, -1);
348 if(index_socket < 0) {
349 error("ERROR [%s: could not create index socket: %s]",
350 get_pname(), strerror(errno));
356 printf("CONNECT DATA %d MESG %d INDEX %d\n",
357 data_port, mesg_port, index_port);
359 if(am_has_feature(g_options->features, fe_rep_options_features)) {
360 printf("features=%s;", our_feature_string);
362 if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
363 printf("hostname=%s;", g_options->hostname);
365 if(am_has_feature(g_options->features, fe_rep_options_sendbackup_options)) {
366 printf("%s", optionstr(options));
370 freopen("/dev/null", "w", stdout);
372 if (options->createindex)
373 dbprintf(("%s: waiting for connect on %d, then %d, then %d\n",
374 debug_prefix_time(NULL), data_port, mesg_port, index_port));
376 dbprintf(("%s: waiting for connect on %d, then %d\n",
377 debug_prefix_time(NULL), data_port, mesg_port));
380 if((dataf = open("/dev/null", O_RDWR)) < 0) {
381 error("ERROR [%s: open of /dev/null for debug data stream: %s]",
382 get_pname(), strerror(errno));
386 dataf = stream_accept(data_socket, TIMEOUT, -1, -1);
388 dbprintf(("%s: timeout on data port %d\n",
389 debug_prefix_time(NULL), data_port));
391 mesgf = stream_accept(mesg_socket, TIMEOUT, -1, -1);
393 dbprintf(("%s: timeout on mesg port %d\n",
394 debug_prefix_time(NULL), mesg_port));
399 } else if (options->createindex) {
400 indexf = stream_accept(index_socket, TIMEOUT, -1, -1);
402 dbprintf(("%s: timeout on index port %d\n",
403 debug_prefix_time(NULL), index_port));
408 if(dataf == -1 || mesgf == -1 || (options->createindex && indexf == -1)) {
414 dbprintf(("%s: got all connections\n", debug_prefix_time(NULL)));
418 /* modification by BIS@BBN 4/25/2003:
419 * with the option processing changes in amanda 2.4.4, must change
420 * the conditional from krb4_auth to options->krb4_auth */
421 if (options->krb4_auth) {
422 if(kerberos_handshake(dataf, session_key) == 0) {
423 dbprintf(("%s: kerberos_handshake on data socket failed\n",
424 debug_prefix_time(NULL)));
428 dbprintf(("%s: kerberos_handshake on data socket succeeded\n",
429 debug_prefix_time(NULL)));
433 if(kerberos_handshake(mesgf, session_key) == 0) {
434 dbprintf(("%s: kerberos_handshake on mesg socket failed\n",
435 debug_prefix_time(NULL)));
439 dbprintf(("%s: kerberos_handshake on mesg socket succeeded\n",
440 debug_prefix_time(NULL)));
444 dbprintf(("%s: kerberos handshakes succeeded!\n",
445 debug_prefix_time(NULL)));
451 /* redirect stderr */
452 if(dup2(mesgf, 2) == -1) {
453 dbprintf(("%s: error redirecting stderr: %s\n",
454 debug_prefix(NULL), strerror(errno)));
460 if(pipe(mesgpipe) == -1) {
461 error("error [opening mesg pipe: %s]", strerror(errno));
464 program->start_backup(g_options->hostname, disk, amdevice, level, dumpdate,
465 dataf, mesgpipe[1], indexf);
466 parse_backup_messages(mesgpipe[0]);
473 amfree(our_feature_string);
474 am_release_feature_set(our_features);
476 am_release_feature_set(g_options->features);
477 g_options->features = NULL;
478 amfree(g_options->hostname);
479 amfree(g_options->str);
484 malloc_size_2 = malloc_inuse(&malloc_hist_2);
486 if(malloc_size_1 != malloc_size_2) {
487 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
493 printf("FORMAT ERROR IN REQUEST PACKET\n");
494 dbprintf(("%s: REQ packet is bogus%s%s\n",
495 debug_prefix_time(NULL),
496 err_extra ? ": " : "",
497 err_extra ? err_extra : ""));
505 * Returns a string for a child process. Checks the saved dump and
506 * compress pids to see which it is.
509 if(pid == dumppid) return program->backup_name;
510 if(pid == comppid) return "compress";
511 if(pid == encpid) return "kencrypt";
512 if(pid == indexpid) return "index";
517 int check_status(pid, w)
521 * Determine if the child return status really indicates an error.
522 * If so, add the error message to the error string; more than one
523 * child can have an error.
526 char *thiserr = NULL;
529 char number[NUM_STR_SIZE];
535 rc = sig = WTERMSIG(w);
538 rc = ret = WEXITSTATUS(w);
541 if(pid == indexpid) {
543 * Treat an index failure (other than signal) as a "STRANGE"
544 * rather than an error so the dump goes ahead and gets processed
545 * but the failure is noted.
548 fprintf(stderr, "? %s returned %d\n", str, ret);
556 * compress returns 2 sometimes, but it is ok.
564 #ifdef DUMP_RETURNS_1
565 if(pid == dumppid && tarpid == -1) {
567 * Ultrix dump returns 1 sometimes, but it is ok.
575 #ifdef IGNORE_TAR_ERRORS
578 * tar bitches about active filesystems, but we do not care.
587 return 0; /* normal exit */
591 ap_snprintf(number, sizeof(number), "%d", sig);
592 thiserr = vstralloc(str, " got signal ", number, NULL);
594 ap_snprintf(number, sizeof(number), "%d", ret);
595 thiserr = vstralloc(str, " returned ", number, NULL);
599 strappend(errorstr, ", ");
600 strappend(errorstr, thiserr);
610 /* Send header info to the message file.
612 void write_tapeheader()
614 fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
616 fprintf(stderr, "%s: info RECOVER_CMD=", get_pname());
617 if (options->compress == COMPR_FAST || options->compress == COMPR_BEST)
618 fprintf(stderr, "%s %s |", UNCOMPRESS_PATH,
619 #ifdef UNCOMPRESS_OPT
626 fprintf(stderr, "%s -f... -\n", program->restore_name);
628 if (options->compress == COMPR_FAST || options->compress == COMPR_BEST)
629 fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
630 get_pname(), COMPRESS_SUFFIX);
632 fprintf(stderr, "%s: info end\n", get_pname());
635 int pipefork(func, fname, stdinfd, stdoutfd, stderrfd)
636 void (*func) P((void));
639 int stdoutfd, stderrfd;
643 dbprintf(("%s: forking function %s in pipeline\n",
644 debug_prefix_time(NULL), fname));
646 if(pipe(inpipe) == -1) {
647 error("error [open pipe to %s: %s]", fname, strerror(errno));
650 switch(pid = fork()) {
652 error("error [fork %s: %s]", fname, strerror(errno));
653 default: /* parent process */
654 aclose(inpipe[0]); /* close input side of pipe */
655 *stdinfd = inpipe[1];
657 case 0: /* child process */
658 aclose(inpipe[1]); /* close output side of pipe */
660 if(dup2(inpipe[0], 0) == -1) {
661 error("error [dup2 0 %s: dup2 in: %s]", fname, strerror(errno));
663 if(dup2(stdoutfd, 1) == -1) {
664 error("error [dup2 1 %s: dup2 out: %s]", fname, strerror(errno));
666 if(dup2(stderrfd, 2) == -1) {
667 error("error [dup2 2 %s: dup2 err: %s]", fname, strerror(errno));
677 void parse_backup_messages(mesgin)
687 for(; (line = areads(mesgin)) != NULL; free(line)) {
688 process_dumpline(line);
692 error("error [read mesg pipe: %s]", strerror(errno));
695 while((wpid = wait(&retstat)) != -1) {
696 if(check_status(wpid, retstat)) goterror = 1;
700 error("error [%s]", errorstr);
701 } else if(dump_size == -1) {
702 error("error [no backup size line]");
705 program->end_backup(goterror);
707 fprintf(stderr, "%s: size %ld\n", get_pname(), dump_size);
708 fprintf(stderr, "%s: end\n", get_pname());
712 double first_num P((char *str));
714 double first_num(str)
717 * Returns the value of the first integer in a string.
725 while(ch && !isdigit(ch)) ch = *str++;
727 while(isdigit(ch) || ch == '.') ch = *str++;
734 static void process_dumpline(str)
741 for(rp = program->re_table; rp->regex != NULL; rp++) {
742 if(match(rp->regex, str)) {
746 if(rp->typ == DMP_SIZE) {
747 dump_size = (long)((first_num(str) * rp->scale + 1023.0)/1024.0);
768 * Should never get here.
774 dbprintf(("%s: %3d: %7s(%c): %s\n",
775 debug_prefix_time(NULL),
780 fprintf(stderr, "%c %s\n", startchr, str);
784 /* start_index. Creates an index file from the output of dump/tar.
785 It arranges that input is the fd to be written by the dump process.
786 If createindex is not enabled, it does nothing. If it is not, a
787 new process will be created that tees input both to a pipe whose
788 read fd is dup2'ed input and to a program that outputs an index
791 make sure that the chat from restore doesn't go to stderr cause
792 this goes back to amanda which doesn't expect to see it
793 (2>/dev/null should do it)
795 Originally by Alan M. McIvor, 13 April 1996
797 Adapted by Alexandre Oliva, 1 May 1997
799 This program owes a lot to tee.c from GNU sh-utils and dumptee.c
800 from the DeeJay backup package.
804 static volatile int index_finished = 0;
806 static void index_closed(sig)
812 void save_fd(fd, min)
817 while (*fd >= 0 && *fd < min) {
818 int newfd = dup(*fd);
820 dbprintf(("%s: unable to save file descriptor [%s]\n",
821 debug_prefix(NULL), strerror(errno)));
825 dbprintf(("%s: dupped file descriptor %i to %i\n",
826 debug_prefix(NULL), origfd, *fd));
829 void start_index(createindex, input, mesg, index, cmd)
830 int createindex, input, mesg, index;
833 struct sigaction act, oact;
841 if (pipe(pipefd) != 0) {
842 error("creating index pipe: %s", strerror(errno));
845 switch(indexpid = fork()) {
847 error("forking index tee process: %s", strerror(errno));
851 if (dup2(pipefd[1], input) == -1) {
852 error("dup'ping index tee output: %s", strerror(errno));
861 /* now in a child process */
862 save_fd(&pipefd[0], 4);
870 for(index = 4; index < FD_SETSIZE; index++) {
871 if (index != dbfd()) {
876 /* set up a signal handler for SIGPIPE for when the pipe is finished
877 creating the index file */
878 /* at that point we obviously want to stop writing to it */
879 act.sa_handler = index_closed;
880 sigemptyset(&act.sa_mask);
882 if (sigaction(SIGPIPE, &act, &oact) != 0) {
883 error("couldn't set index SIGPIPE handler [%s]", strerror(errno));
886 if ((pipe_fp = popen(cmd, "w")) == NULL) {
887 error("couldn't start index creator [%s]", strerror(errno));
890 dbprintf(("%s: started index creator: \"%s\"\n",
891 debug_prefix_time(NULL), cmd));
893 char buffer[BUFSIZ], *ptr;
898 bytes_read = read(0, buffer, sizeof(buffer));
899 if ((bytes_read < 0) && (errno == EINTR))
902 if (bytes_read < 0) {
903 error("index tee cannot read [%s]", strerror(errno));
907 break; /* finished */
909 /* write the stuff to the subprocess */
912 while (bytes_read > bytes_written && !index_finished) {
913 just_written = write(fileno(pipe_fp), ptr, bytes_read - bytes_written);
914 if (just_written < 0) {
915 /* the signal handler may have assigned to index_finished
916 * just as we waited for write() to complete. */
917 if (!index_finished) {
918 dbprintf(("%s: index tee cannot write to index creator [%s]\n",
919 debug_prefix_time(NULL), strerror(errno)));
923 bytes_written += just_written;
928 /* write the stuff to stdout, ensuring none lost when interrupt
932 while (bytes_read > bytes_written) {
933 just_written = write(3, ptr, bytes_read - bytes_written);
934 if ((just_written < 0) && (errno == EINTR))
936 if (just_written < 0) {
937 error("index tee cannot write [%s]", strerror(errno));
939 bytes_written += just_written;
948 /* check the exit code of the pipe and moan if not 0 */
949 if ((exitcode = pclose(pipe_fp)) != 0) {
950 dbprintf(("%s: index pipe returned %d\n",
951 debug_prefix_time(NULL), exitcode));
953 dbprintf(("%s: index created successfully\n", debug_prefix_time(NULL)));
960 extern backup_program_t dump_program, gnutar_program;
962 backup_program_t *programs[] = {
963 &dump_program, &gnutar_program, NULL
967 #include "sendbackup-krb4.c"