📄 sendbackup.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1999 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Authors: the Amanda Development Team. Its members are listed in a * file named AUTHORS, in the root directory of this distribution. *//* * $Id: sendbackup.c,v 1.88 2006/07/25 18:27:56 martinea Exp $ * * common code for the sendbackup-* programs. */#include "amanda.h"#include "sendbackup.h"#include "clock.h"#include "pipespawn.h"#include "amfeatures.h"#include "amandad.h"#include "arglist.h"#include "getfsent.h"#include "version.h"#include "conffile.h"#define sendbackup_debug(i, ...) do { \ if ((i) <= debug_sendbackup) { \ dbprintf(__VA_LIST__); \ } \} while (0)#define TIMEOUT 30pid_t comppid = (pid_t)-1;pid_t dumppid = (pid_t)-1;pid_t tarpid = (pid_t)-1;pid_t encpid = (pid_t)-1;pid_t indexpid = (pid_t)-1;char *errorstr = NULL;int datafd;int mesgfd;int indexfd;option_t *options;g_option_t *g_options = NULL;long dump_size = -1;backup_program_t *program = NULL;static am_feature_t *our_features = NULL;static char *our_feature_string = NULL;static char *amandad_auth = NULL;/* local functions */int main(int argc, char **argv);char *optionstr(option_t *options);char *childstr(pid_t pid);int check_status(pid_t pid, amwait_t w);pid_t pipefork(void (*func)(void), char *fname, int *stdinfd, int stdoutfd, int stderrfd);void parse_backup_messages(int mesgin);static void process_dumpline(char *str);static void save_fd(int *, int);void backup_api_info_tapeheader(int mesgfd, char *prog, option_t *options);double the_num(char *str, int pos);char *optionstr( option_t * options){ static char *optstr = NULL; char *compress_opt; char *encrypt_opt; char *decrypt_opt; char *record_opt = ""; char *index_opt = ""; char *auth_opt; char *exclude_file_opt; char *exclude_list_opt; char *exc = NULL; sle_t *excl; if(options->compress == COMP_BEST) compress_opt = stralloc("compress-best;"); else if(options->compress == COMP_FAST) compress_opt = stralloc("compress-fast;"); else if(options->compress == COMP_SERVER_BEST) compress_opt = stralloc("srvcomp-best;"); else if(options->compress == COMP_SERVER_FAST) compress_opt = stralloc("srvcomp-fast;"); else if(options->compress == COMP_SERVER_CUST) compress_opt = vstralloc("srvcomp-cust=", options->srvcompprog, ";", NULL); else if(options->compress == COMP_CUST) compress_opt = vstralloc("comp-cust=", options->clntcompprog, ";", NULL); else compress_opt = stralloc(""); if(options->encrypt == ENCRYPT_CUST) { encrypt_opt = vstralloc("encrypt-cust=", options->clnt_encrypt, ";", NULL); if (options->clnt_decrypt_opt) decrypt_opt = vstralloc("client-decrypt-option=", options->clnt_decrypt_opt, ";", NULL); else decrypt_opt = stralloc(""); } else if(options->encrypt == ENCRYPT_SERV_CUST) { encrypt_opt = vstralloc("encrypt-serv-cust=", options->srv_encrypt, ";", NULL); if(options->srv_decrypt_opt) decrypt_opt = vstralloc("server-decrypt-option=", options->srv_decrypt_opt, ";", NULL); else decrypt_opt = stralloc(""); } else { encrypt_opt = stralloc(""); decrypt_opt = stralloc(""); } if(options->no_record) record_opt = "no-record;"; if(options->auth) auth_opt = vstralloc("auth=", options->auth, ";", NULL); else auth_opt = stralloc(""); if(options->createindex) index_opt = "index;"; exclude_file_opt = stralloc(""); if(options->exclude_file) { for(excl = options->exclude_file->first; excl != NULL; excl=excl->next){ exc = newvstralloc(exc, "exclude-file=", excl->name, ";", NULL); strappend(exclude_file_opt, exc); } } exclude_list_opt = stralloc(""); if(options->exclude_list) { for(excl = options->exclude_list->first; excl != NULL; excl=excl->next){ exc = newvstralloc(exc, "exclude-list=", excl->name, ";", NULL); strappend(exclude_list_opt, exc); } } amfree(exc); optstr = newvstralloc(optstr, compress_opt, encrypt_opt, decrypt_opt, record_opt, index_opt, auth_opt, exclude_file_opt, exclude_list_opt, NULL); amfree(compress_opt); amfree(encrypt_opt); amfree(decrypt_opt); amfree(auth_opt); amfree(exclude_file_opt); amfree(exclude_list_opt); return optstr;}intmain( int argc, char ** argv){ int interactive = 0; int level = 0; int mesgpipe[2]; char *prog, *dumpdate, *stroptions; int program_is_backup_api; char *disk = NULL; char *qdisk = NULL; char *amdevice = NULL; char *qamdevice = NULL; char *line = NULL; char *err_extra = NULL; char *s; int i; int ch; FILE *toolin; int status; /* initialize */ /* * Configure program for internationalization: * 1) Only set the message locale for now. * 2) Set textdomain for all amanda related programs to "amanda" * We don't want to be forced to support dozens of message catalogs. */ setlocale(LC_MESSAGES, "C"); textdomain("amanda"); safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2); safe_cd(); set_pname("sendbackup"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); /* Don't die when interrupt received */ signal(SIGINT, SIG_IGN); if(argc > 1 && strcmp(argv[1],"-t") == 0) { interactive = 1; argc--; argv++; } else { interactive = 0; } erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG); dbopen(DBG_SUBDIR_CLIENT); startclock(); dbprintf(_("Version %s\n"), version()); if(argc > 2 && strcmp(argv[1], "amandad") == 0) { amandad_auth = stralloc(argv[2]); } our_features = am_init_feature_set(); our_feature_string = am_feature_to_string(our_features); config_init(CONFIG_INIT_CLIENT, NULL); check_running_as(RUNNING_AS_CLIENT_LOGIN); if(interactive) { /* * In interactive (debug) mode, the backup data is sent to * /dev/null and none of the network connections back to driver * programs on the tape host are set up. The index service is * run and goes to stdout. */ g_fprintf(stderr, _("%s: running in interactive test mode\n"), get_pname()); fflush(stderr); } prog = NULL; disk = NULL; qdisk = NULL; amdevice = NULL; dumpdate = NULL; stroptions = NULL; program_is_backup_api=0; for(; (line = agets(stdin)) != NULL; free(line)) { if (line[0] == '\0') continue; if(interactive) { g_fprintf(stderr, "%s> ", get_pname()); fflush(stderr); } if(strncmp_const(line, "OPTIONS ") == 0) { g_options = parse_g_options(line+8, 1); if(!g_options->hostname) { g_options->hostname = alloc(MAX_HOSTNAME_LENGTH+1); gethostname(g_options->hostname, MAX_HOSTNAME_LENGTH); g_options->hostname[MAX_HOSTNAME_LENGTH] = '\0'; } if (g_options->config) { /* overlay this configuration on the existing (nameless) configuration */ config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY, g_options->config); dbrename(config_name, DBG_SUBDIR_CLIENT); } continue; } if (prog != NULL) { err_extra = _("multiple requests"); goto err; } dbprintf(_(" sendbackup req: <%s>\n"), line); s = line; ch = *s++; skip_whitespace(s, ch); /* find the program name */ if(ch == '\0') { err_extra = _("no program name"); goto err; /* no program name */ } prog = s - 1; skip_non_whitespace(s, ch); s[-1] = '\0'; if(strcmp(prog,"BACKUP")==0) { program_is_backup_api=1; skip_whitespace(s, ch); /* find dumper name */ if (ch == '\0') { goto err; /* no program */ } prog = s - 1; skip_non_whitespace(s, ch); s[-1] = '\0'; } prog = stralloc(prog); skip_whitespace(s, ch); /* find the disk name */ if(ch == '\0') { err_extra = _("no disk name"); goto err; /* no disk name */ } amfree(disk); amfree(qdisk); qdisk = s - 1; ch = *qdisk; skip_quoted_string(s, ch); s[-1] = '\0'; qdisk = stralloc(qdisk); disk = unquote_string(qdisk); skip_whitespace(s, ch); /* find the device or level */ if (ch == '\0') { err_extra = _("bad level"); goto err; } if(!isdigit((int)s[-1])) { amfree(amdevice); amfree(qamdevice); qamdevice = s - 1; ch = *qamdevice; skip_quoted_string(s, ch); s[-1] = '\0'; qamdevice = stralloc(qamdevice); amdevice = unquote_string(qamdevice); skip_whitespace(s, ch); /* find level number */ } else { amdevice = stralloc(disk); qamdevice = stralloc(qdisk); } /* find the level number */ if(ch == '\0' || sscanf(s - 1, "%d", &level) != 1) { err_extra = _("bad level"); goto err; /* bad level */ } skip_integer(s, ch); skip_whitespace(s, ch); /* find the dump date */ if(ch == '\0') { err_extra = _("no dumpdate"); goto err; /* no dumpdate */ } amfree(dumpdate); dumpdate = s - 1; skip_non_whitespace(s, ch); s[-1] = '\0'; dumpdate = stralloc(dumpdate); skip_whitespace(s, ch); /* find the options keyword */ if(ch == '\0') { err_extra = _("no options"); goto err; /* no options */ } if(strncmp_const_skip(s - 1, "OPTIONS ", s, ch) != 0) { err_extra = _("no OPTIONS keyword"); goto err; /* no options */ } skip_whitespace(s, ch); /* find the options string */ if(ch == '\0') { err_extra = _("bad options string"); goto err; /* no options */ } amfree(stroptions); stroptions = stralloc(s - 1); } amfree(line); if (g_options == NULL) { printf(_("ERROR [Missing OPTIONS line in sendbackup input]\n")); error(_("Missing OPTIONS line in sendbackup input\n")); /*NOTREACHED*/ } if (prog == NULL || disk == NULL || amdevice == NULL || dumpdate == NULL || stroptions == NULL) { err_extra = _("no valid sendbackup request"); goto err; } dbprintf(_(" Parsed request as: program `%s'\n"), prog); dbprintf(_(" disk `%s'\n"), qdisk); dbprintf(_(" device `%s'\n"), qamdevice); dbprintf(_(" level %d\n"), level); dbprintf(_(" since %s\n"), dumpdate); dbprintf(_(" options `%s'\n"), stroptions); if(program_is_backup_api==1) { /* check that the backup_api exist */ } else { for(i = 0; programs[i]; i++) { if (strcmp(programs[i]->name, prog) == 0) { break; } } if (programs[i] == NULL) { dbprintf(_("ERROR [%s: unknown program %s]\n"), get_pname(), prog); error(_("ERROR [%s: unknown program %s]"), get_pname(), prog); /*NOTREACHED*/ } program = programs[i]; } options = parse_options(stroptions, disk, amdevice, g_options->features, 0); if(!interactive) { datafd = DATA_FD_OFFSET + 0; mesgfd = DATA_FD_OFFSET + 2; indexfd = DATA_FD_OFFSET + 4; } if (!options->createindex) indexfd = -1; if(options->auth && amandad_auth) { if(strcasecmp(options->auth, amandad_auth) != 0) { g_printf(_("ERROR [client configured for auth=%s while server requested '%s']\n"), amandad_auth, options->auth); exit(-1); } } if (options->kencrypt) { g_printf("KENCRYPT\n"); } g_printf(_("CONNECT DATA %d MESG %d INDEX %d\n"), DATA_FD_OFFSET, DATA_FD_OFFSET+1, indexfd == -1 ? -1 : DATA_FD_OFFSET+2); g_printf(_("OPTIONS ")); if(am_has_feature(g_options->features, fe_rep_options_features)) { g_printf("features=%s;", our_feature_string); } if(am_has_feature(g_options->features, fe_rep_options_hostname)) { g_printf("hostname=%s;", g_options->hostname); } if(am_has_feature(g_options->features, fe_rep_options_sendbackup_options)) { g_printf("%s", optionstr(options)); } g_printf("\n"); fflush(stdout); if (freopen("/dev/null", "w", stdout) == NULL) { dbprintf(_("Error redirecting stdout to /dev/null: %s\n"), strerror(errno)); exit(1); } if(interactive) { if((datafd = open("/dev/null", O_RDWR)) < 0) { error(_("ERROR [open of /dev/null for debug data stream: %s]\n"), strerror(errno)); /*NOTREACHED*/ } mesgfd = 2; indexfd = 1; } if(!interactive) { if(datafd == -1 || mesgfd == -1 || (options->createindex && indexfd == -1)) { dbclose(); exit(1); } } if(program_is_backup_api==1) { pid_t backup_api_pid; int i, j; char *cmd=NULL; char *argvchild[20]; char levelstr[20]; int property_pipe[2]; backup_support_option_t *bsu; if (pipe(property_pipe) < 0) { error(_("Can't create pipe: %s"),strerror(errno)); /*NOTREACHED*/ } bsu = backup_support_option(prog, g_options, disk, amdevice); switch(backup_api_pid=fork()) { case 0: aclose(property_pipe[1]); if(dup2(property_pipe[0], 0) == -1) { error(_("Can't dup2: %s"),strerror(errno)); /*NOTREACHED*/ } if(dup2(datafd, 1) == -1) { error(_("Can't dup2: %s"),strerror(errno)); /*NOTREACHED*/ } if(dup2(mesgfd, 2) == -1) { error(_("Can't dup2: %s"),strerror(errno)); /*NOTREACHED*/ } if(indexfd != 0) { if(dup2(indexfd, 3) == -1) { error(_("Can't dup2: %s"),strerror(errno)); /*NOTREACHED*/ } fcntl(indexfd, F_SETFD, 0); fcntl(3, F_SETFD, 0); safe_fd(3, 1); } else { safe_fd(-1, 0); } cmd = vstralloc(DUMPER_DIR, "/", prog, NULL); i=0; argvchild[i++] = prog; argvchild[i++] = "backup"; if (bsu->message_line == 1) { argvchild[i++] = "--message"; argvchild[i++] = "line"; } if (g_options->config && bsu->config == 1) { argvchild[i++] = "--config"; argvchild[i++] = g_options->config; } if (g_options->hostname && bsu->host == 1) { argvchild[i++] = "--host"; argvchild[i++] = g_options->hostname; } if (disk && bsu->disk == 1) { argvchild[i++] = "--disk"; argvchild[i++] = disk; } argvchild[i++] = "--device"; argvchild[i++] = amdevice; if (level <= bsu->max_level) { argvchild[i++] = "--level"; g_snprintf(levelstr,19,"%d",level); argvchild[i++] = levelstr; } if (indexfd != 0 && bsu->index_line == 1) { argvchild[i++] = "--index"; argvchild[i++] = "line"; } if (!options->no_record && bsu->record == 1) { argvchild[i++] = "--record"; } argvchild[i] = NULL; dbprintf(_("%s: running \"%s"), get_pname(), cmd); for(j=1;j<i;j++) dbprintf(" %s",argvchild[j]); dbprintf(_("\"\n")); backup_api_info_tapeheader(mesgfd, prog, options); execve(cmd, argvchild, safe_env()); exit(1); break; default: aclose(property_pipe[0]); toolin = fdopen(property_pipe[1],"w"); if (!toolin) { error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } output_tool_property(toolin, options); fflush(toolin); fclose(toolin); break; case -1: error(_("%s: fork returned: %s"), get_pname(), strerror(errno)); } amfree(bsu); if (waitpid(backup_api_pid, &status, 0) < 0) { if (!WIFEXITED(status)) { dbprintf(_("Tool exited with signal %d"), WTERMSIG(status)); } else if (WEXITSTATUS(status) != 0) { dbprintf(_("Tool exited with status %d"), WEXITSTATUS(status)); } else { dbprintf(_("waitpid returned negative value")); } } } else { if(!interactive) { /* redirect stderr */ if(dup2(mesgfd, 2) == -1) { dbprintf(_("Error redirecting stderr to fd %d: %s\n"), mesgfd, strerror(errno)); dbclose(); exit(1); } } if(pipe(mesgpipe) == -1) { s = strerror(errno); dbprintf(_("error [opening mesg pipe: %s]\n"), s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -