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 2004/01/14 12:59:12 martinea 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 for(fd = 3; fd < FD_SETSIZE; fd++) {
161 * Make sure nobody spoofs us with a lot of extra open files
162 * that would cause an open we do to get a very high file
163 * descriptor, which in turn might be used as an index into
164 * an array (e.g. an fd_set).
167 if (fd != KEY_PIPE) /* XXX interface needs to be fixed */
174 set_pname("sendbackup");
176 malloc_size_1 = malloc_inuse(&malloc_hist_1);
178 interactive = (argc > 1 && strcmp(argv[1],"-t") == 0);
179 erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
182 dbprintf(("%s: version %s\n", argv[0], version()));
184 our_features = am_init_feature_set();
185 our_feature_string = am_feature_to_string(our_features);
189 * In interactive (debug) mode, the backup data is sent to
190 * /dev/null and none of the network connections back to driver
191 * programs on the tape host are set up. The index service is
192 * run and goes to stdout.
194 fprintf(stderr, "%s: running in interactive test mode\n", get_pname());
204 /* parse dump request */
206 for(; (line = agets(stdin)) != NULL; free(line)) {
208 fprintf(stderr, "%s> ", get_pname());
211 #define sc "OPTIONS "
212 if(strncmp(line, sc, sizeof(sc)-1) == 0) {
214 g_options = parse_g_options(line+8, 1);
215 if(!g_options->hostname) {
216 g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1);
217 gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH);
218 g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0';
224 err_extra = "multiple requests";
231 skip_whitespace(s, ch); /* find the program name */
233 err_extra = "no program name";
234 goto err; /* no program name */
237 skip_non_whitespace(s, ch);
239 prog = stralloc(prog);
241 skip_whitespace(s, ch); /* find the disk name */
243 err_extra = "no disk name";
244 goto err; /* no disk name */
248 skip_non_whitespace(s, ch);
250 disk = stralloc(disk);
252 skip_whitespace(s, ch); /* find the device or level */
254 err_extra = "bad level";
258 if(!isdigit((int)s[-1])) {
261 skip_non_whitespace(s, ch);
263 amdevice = stralloc(amdevice);
264 skip_whitespace(s, ch); /* find level number */
267 amdevice = stralloc(disk);
270 /* find the level number */
271 if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) {
272 err_extra = "bad level";
273 goto err; /* bad level */
277 skip_whitespace(s, ch); /* find the dump date */
279 err_extra = "no dumpdate";
280 goto err; /* no dumpdate */
284 skip_non_whitespace(s, ch);
286 dumpdate = stralloc(dumpdate);
288 skip_whitespace(s, ch); /* find the options keyword */
290 err_extra = "no options";
291 goto err; /* no options */
293 #define sc "OPTIONS "
294 if(strncmp(s - 1, sc, sizeof(sc)-1) != 0) {
295 err_extra = "no OPTIONS keyword";
296 goto err; /* no options */
301 skip_whitespace(s, ch); /* find the options string */
303 err_extra = "bad options string";
304 goto err; /* no options */
307 stroptions = stralloc(s - 1);
311 dbprintf((" parsed request as: program `%s'\n", prog));
312 dbprintf((" disk `%s'\n", disk));
313 dbprintf((" device `%s'\n", amdevice));
314 dbprintf((" level %d\n", level));
315 dbprintf((" since %s\n", dumpdate));
316 dbprintf((" options `%s'\n", stroptions));
318 for(i = 0; programs[i] != NULL; i++) {
319 if (strcmp(programs[i]->name, prog) == 0) {
323 if (programs[i] == NULL) {
324 error("ERROR [%s: unknown program %s]", get_pname(), prog);
326 program = programs[i];
328 options = parse_options(stroptions, disk, amdevice, g_options->features, 0);
331 /* modification by BIS@BBN 4/25/2003:
332 * with the option processing changes in amanda 2.4.4, must change
333 * the conditional from krb4_auth to options->krb4_auth */
334 if(options->krb4_auth) {
335 if(read(KEY_PIPE, session_key, sizeof session_key)
336 != sizeof session_key) {
337 error("ERROR [%s: could not read session key]", get_pname());
343 data_socket = stream_server(&data_port, STREAM_BUFSIZE, -1);
344 if(data_socket < 0) {
345 error("ERROR [%s: could not create data socket: %s]",
346 get_pname(), strerror(errno));
348 mesg_socket = stream_server(&mesg_port, -1, -1);
349 if(mesg_socket < 0) {
350 error("ERROR [%s: could not create mesg socket: %s]",
351 get_pname(), strerror(errno));
354 if (!interactive && options->createindex) {
355 index_socket = stream_server(&index_port, -1, -1);
356 if(index_socket < 0) {
357 error("ERROR [%s: could not create index socket: %s]",
358 get_pname(), strerror(errno));
364 printf("CONNECT DATA %d MESG %d INDEX %d\n",
365 data_port, mesg_port, index_port);
367 if(am_has_feature(g_options->features, fe_rep_options_features)) {
368 printf("features=%s;", our_feature_string);
370 if(am_has_feature(g_options->features, fe_rep_options_hostname)) {
371 printf("hostname=%s;", g_options->hostname);
373 if(am_has_feature(g_options->features, fe_rep_options_sendbackup_options)) {
374 printf("%s", optionstr(options));
378 freopen("/dev/null", "w", stdout);
380 if (options->createindex)
381 dbprintf(("%s: waiting for connect on %d, then %d, then %d\n",
382 debug_prefix_time(NULL), data_port, mesg_port, index_port));
384 dbprintf(("%s: waiting for connect on %d, then %d\n",
385 debug_prefix_time(NULL), data_port, mesg_port));
388 if((dataf = open("/dev/null", O_RDWR)) < 0) {
389 error("ERROR [%s: open of /dev/null for debug data stream: %s]",
390 get_pname(), strerror(errno));
394 dataf = stream_accept(data_socket, TIMEOUT, -1, -1);
396 dbprintf(("%s: timeout on data port %d\n",
397 debug_prefix_time(NULL), data_port));
399 mesgf = stream_accept(mesg_socket, TIMEOUT, -1, -1);
401 dbprintf(("%s: timeout on mesg port %d\n",
402 debug_prefix_time(NULL), mesg_port));
407 } else if (options->createindex) {
408 indexf = stream_accept(index_socket, TIMEOUT, -1, -1);
410 dbprintf(("%s: timeout on index port %d\n",
411 debug_prefix_time(NULL), index_port));
416 if(dataf == -1 || mesgf == -1 || (options->createindex && indexf == -1)) {
422 dbprintf(("%s: got all connections\n", debug_prefix_time(NULL)));
426 /* modification by BIS@BBN 4/25/2003:
427 * with the option processing changes in amanda 2.4.4, must change
428 * the conditional from krb4_auth to options->krb4_auth */
429 if (options->krb4_auth) {
430 if(kerberos_handshake(dataf, session_key) == 0) {
431 dbprintf(("%s: kerberos_handshake on data socket failed\n",
432 debug_prefix_time(NULL)));
436 dbprintf(("%s: kerberos_handshake on data socket succeeded\n",
437 debug_prefix_time(NULL)));
441 if(kerberos_handshake(mesgf, session_key) == 0) {
442 dbprintf(("%s: kerberos_handshake on mesg socket failed\n",
443 debug_prefix_time(NULL)));
447 dbprintf(("%s: kerberos_handshake on mesg socket succeeded\n",
448 debug_prefix_time(NULL)));
452 dbprintf(("%s: kerberos handshakes succeeded!\n",
453 debug_prefix_time(NULL)));
459 /* redirect stderr */
460 if(dup2(mesgf, 2) == -1) {
461 dbprintf(("%s: error redirecting stderr: %s\n",
462 debug_prefix(NULL), strerror(errno)));
468 if(pipe(mesgpipe) == -1) {
469 error("error [opening mesg pipe: %s]", strerror(errno));
472 program->start_backup(g_options->hostname, disk, amdevice, level, dumpdate,
473 dataf, mesgpipe[1], indexf);
474 parse_backup_messages(mesgpipe[0]);
481 amfree(our_feature_string);
482 am_release_feature_set(our_features);
484 am_release_feature_set(g_options->features);
485 g_options->features = NULL;
486 amfree(g_options->hostname);
487 amfree(g_options->str);
492 malloc_size_2 = malloc_inuse(&malloc_hist_2);
494 if(malloc_size_1 != malloc_size_2) {
495 malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
501 printf("FORMAT ERROR IN REQUEST PACKET\n");
502 dbprintf(("%s: REQ packet is bogus%s%s\n",
503 debug_prefix_time(NULL),
504 err_extra ? ": " : "",
505 err_extra ? err_extra : ""));
513 * Returns a string for a child process. Checks the saved dump and
514 * compress pids to see which it is.
517 if(pid == dumppid) return program->backup_name;
518 if(pid == comppid) return "compress";
519 if(pid == encpid) return "kencrypt";
520 if(pid == indexpid) return "index";
525 int check_status(pid, w)
529 * Determine if the child return status really indicates an error.
530 * If so, add the error message to the error string; more than one
531 * child can have an error.
534 char *thiserr = NULL;
537 char number[NUM_STR_SIZE];
543 rc = sig = WTERMSIG(w);
546 rc = ret = WEXITSTATUS(w);
549 if(pid == indexpid) {
551 * Treat an index failure (other than signal) as a "STRANGE"
552 * rather than an error so the dump goes ahead and gets processed
553 * but the failure is noted.
556 fprintf(stderr, "? %s returned %d\n", str, ret);
564 * compress returns 2 sometimes, but it is ok.
572 #ifdef DUMP_RETURNS_1
573 if(pid == dumppid && tarpid == -1) {
575 * Ultrix dump returns 1 sometimes, but it is ok.
583 #ifdef IGNORE_TAR_ERRORS
586 * tar bitches about active filesystems, but we do not care.
595 return 0; /* normal exit */
599 ap_snprintf(number, sizeof(number), "%d", sig);
600 thiserr = vstralloc(str, " got signal ", number, NULL);
602 ap_snprintf(number, sizeof(number), "%d", ret);
603 thiserr = vstralloc(str, " returned ", number, NULL);
607 strappend(errorstr, ", ");
608 strappend(errorstr, thiserr);
618 /* Send header info to the message file.
620 void write_tapeheader()
622 fprintf(stderr, "%s: info BACKUP=%s\n", get_pname(), program->backup_name);
624 fprintf(stderr, "%s: info RECOVER_CMD=", get_pname());
625 if (options->compress == COMPR_FAST || options->compress == COMPR_BEST)
626 fprintf(stderr, "%s %s |", UNCOMPRESS_PATH,
627 #ifdef UNCOMPRESS_OPT
634 fprintf(stderr, "%s -f... -\n", program->restore_name);
636 if (options->compress == COMPR_FAST || options->compress == COMPR_BEST)
637 fprintf(stderr, "%s: info COMPRESS_SUFFIX=%s\n",
638 get_pname(), COMPRESS_SUFFIX);
640 fprintf(stderr, "%s: info end\n", get_pname());
643 int pipefork(func, fname, stdinfd, stdoutfd, stderrfd)
644 void (*func) P((void));
647 int stdoutfd, stderrfd;
651 dbprintf(("%s: forking function %s in pipeline\n",
652 debug_prefix_time(NULL), fname));
654 if(pipe(inpipe) == -1) {
655 error("error [open pipe to %s: %s]", fname, strerror(errno));
658 switch(pid = fork()) {
660 error("error [fork %s: %s]", fname, strerror(errno));
661 default: /* parent process */
662 aclose(inpipe[0]); /* close input side of pipe */
663 *stdinfd = inpipe[1];
665 case 0: /* child process */
666 aclose(inpipe[1]); /* close output side of pipe */
668 if(dup2(inpipe[0], 0) == -1) {
669 error("error [dup2 0 %s: dup2 in: %s]", fname, strerror(errno));
671 if(dup2(stdoutfd, 1) == -1) {
672 error("error [dup2 1 %s: dup2 out: %s]", fname, strerror(errno));
674 if(dup2(stderrfd, 2) == -1) {
675 error("error [dup2 2 %s: dup2 err: %s]", fname, strerror(errno));
685 void parse_backup_messages(mesgin)
695 for(; (line = areads(mesgin)) != NULL; free(line)) {
696 process_dumpline(line);
700 error("error [read mesg pipe: %s]", strerror(errno));
703 while((wpid = wait(&retstat)) != -1) {
704 if(check_status(wpid, retstat)) goterror = 1;
708 error("error [%s]", errorstr);
709 } else if(dump_size == -1) {
710 error("error [no backup size line]");
713 program->end_backup(goterror);
715 fprintf(stderr, "%s: size %ld\n", get_pname(), dump_size);
716 fprintf(stderr, "%s: end\n", get_pname());
720 double first_num P((char *str));
722 double first_num(str)
725 * Returns the value of the first integer in a string.
733 while(ch && !isdigit(ch)) ch = *str++;
735 while(isdigit(ch) || ch == '.') ch = *str++;
742 static void process_dumpline(str)
749 for(rp = program->re_table; rp->regex != NULL; rp++) {
750 if(match(rp->regex, str)) {
754 if(rp->typ == DMP_SIZE) {
755 dump_size = (long)((first_num(str) * rp->scale + 1023.0)/1024.0);
776 * Should never get here.
782 dbprintf(("%s: %3d: %7s(%c): %s\n",
783 debug_prefix_time(NULL),
788 fprintf(stderr, "%c %s\n", startchr, str);
792 /* start_index. Creates an index file from the output of dump/tar.
793 It arranges that input is the fd to be written by the dump process.
794 If createindex is not enabled, it does nothing. If it is not, a
795 new process will be created that tees input both to a pipe whose
796 read fd is dup2'ed input and to a program that outputs an index
799 make sure that the chat from restore doesn't go to stderr cause
800 this goes back to amanda which doesn't expect to see it
801 (2>/dev/null should do it)
803 Originally by Alan M. McIvor, 13 April 1996
805 Adapted by Alexandre Oliva, 1 May 1997
807 This program owes a lot to tee.c from GNU sh-utils and dumptee.c
808 from the DeeJay backup package.
812 static volatile int index_finished = 0;
814 static void index_closed(sig)
820 void save_fd(fd, min)
825 while (*fd >= 0 && *fd < min) {
826 int newfd = dup(*fd);
828 dbprintf(("%s: unable to save file descriptor [%s]\n",
829 debug_prefix(NULL), strerror(errno)));
833 dbprintf(("%s: dupped file descriptor %i to %i\n",
834 debug_prefix(NULL), origfd, *fd));
837 void start_index(createindex, input, mesg, index, cmd)
838 int createindex, input, mesg, index;
841 struct sigaction act, oact;
849 if (pipe(pipefd) != 0) {
850 error("creating index pipe: %s", strerror(errno));
853 switch(indexpid = fork()) {
855 error("forking index tee process: %s", strerror(errno));
859 if (dup2(pipefd[1], input) == -1) {
860 error("dup'ping index tee output: %s", strerror(errno));
869 /* now in a child process */
870 save_fd(&pipefd[0], 4);
878 for(index = 4; index < FD_SETSIZE; index++) {
879 if (index != dbfd()) {
884 /* set up a signal handler for SIGPIPE for when the pipe is finished
885 creating the index file */
886 /* at that point we obviously want to stop writing to it */
887 act.sa_handler = index_closed;
888 sigemptyset(&act.sa_mask);
890 if (sigaction(SIGPIPE, &act, &oact) != 0) {
891 error("couldn't set index SIGPIPE handler [%s]", strerror(errno));
894 if ((pipe_fp = popen(cmd, "w")) == NULL) {
895 error("couldn't start index creator [%s]", strerror(errno));
898 dbprintf(("%s: started index creator: \"%s\"\n",
899 debug_prefix_time(NULL), cmd));
901 char buffer[BUFSIZ], *ptr;
906 bytes_read = read(0, buffer, sizeof(buffer));
907 if ((bytes_read < 0) && (errno == EINTR))
910 if (bytes_read < 0) {
911 error("index tee cannot read [%s]", strerror(errno));
915 break; /* finished */
917 /* write the stuff to the subprocess */
920 while (bytes_read > bytes_written && !index_finished) {
921 just_written = write(fileno(pipe_fp), ptr, bytes_read - bytes_written);
922 if (just_written < 0) {
923 /* the signal handler may have assigned to index_finished
924 * just as we waited for write() to complete. */
925 if (!index_finished) {
926 dbprintf(("%s: index tee cannot write to index creator [%s]\n",
927 debug_prefix_time(NULL), strerror(errno)));
931 bytes_written += just_written;
936 /* write the stuff to stdout, ensuring none lost when interrupt
940 while (bytes_read > bytes_written) {
941 just_written = write(3, ptr, bytes_read - bytes_written);
942 if ((just_written < 0) && (errno == EINTR))
944 if (just_written < 0) {
945 error("index tee cannot write [%s]", strerror(errno));
947 bytes_written += just_written;
956 /* check the exit code of the pipe and moan if not 0 */
957 if ((exitcode = pclose(pipe_fp)) != 0) {
958 dbprintf(("%s: index pipe returned %d\n",
959 debug_prefix_time(NULL), exitcode));
961 dbprintf(("%s: index created successfully\n", debug_prefix_time(NULL)));
968 extern backup_program_t dump_program, gnutar_program;
970 backup_program_t *programs[] = {
971 &dump_program, &gnutar_program, NULL
975 #include "sendbackup-krb4.c"