int copy_file( char *dst, char *src, char **errmsg) { int infd, outfd; int save_errno; size_t nb; char buf[32768]; char *quoted; if ((infd = open(src, O_RDONLY)) == -1) { save_errno = errno; quoted = quote_string(src); *errmsg = vstrallocf(_("Can't open file '%s' for reading: %s"), quoted, strerror(save_errno)); amfree(quoted); return -1; } if ((outfd = open(dst, O_WRONLY|O_CREAT, 0600)) == -1) { save_errno = errno; quoted = quote_string(dst); *errmsg = vstrallocf(_("Can't open file '%s' for writting: %s"), quoted, strerror(save_errno)); amfree(quoted); close(infd); return -1; } while((nb=read(infd, &buf, SIZEOF(buf))) > 0) { if(full_write(outfd,&buf,nb) < nb) { save_errno = errno; quoted = quote_string(dst); *errmsg = vstrallocf(_("Error writing to '%s': %s"), quoted, strerror(save_errno)); amfree(quoted); close(infd); close(outfd); return -1; } } if (errno != 0) { save_errno = errno; quoted = quote_string(src); *errmsg = vstrallocf(_("Error reading from '%s': %s"), quoted, strerror(save_errno)); amfree(quoted); close(infd); close(outfd); return -1; } close(infd); close(outfd); return 0; }
static int report_bad_resultstr(char *cmd) { char *s; s = vstrallocf(_("<error> badly formed result from changer command %s: \"%s\""), cmd, changer_resultstr); amfree(changer_resultstr); changer_resultstr = s; return 2; }
static char *quote_heredoc( char *text, char *delimiter_prefix) { char *delimiter = stralloc(delimiter_prefix); int delimiter_n = 0; int delimiter_len = strlen(delimiter); char *quoted; /* keep picking delimiters until we find one that's not a line in TEXT */ while (1) { char *line = text; char *c = text; gboolean found_delimiter = FALSE; while (1) { if (*c == '\n' || *c == '\0') { int linelen = c - line; if (linelen == delimiter_len && 0 == strncmp(line, delimiter, linelen)) { found_delimiter = TRUE; break; } line = c+1; } if (!*c) break; c++; } if (!found_delimiter) break; delimiter = newvstrallocf(delimiter, "%s%d", delimiter_prefix, ++delimiter_n); delimiter_len = strlen(delimiter); } /* we have a delimiter .. now use it */ quoted = vstrallocf("<<%s\n%s\n%s", delimiter, text, delimiter); amfree(delimiter); return quoted; }
char * xmsg_repr( XMsg *msg) { if (!msg) return "(nil)"; /* better safe than sorry */ /* this just shows the "header" fields for now */ if (!msg->repr) { char *typ = NULL; switch (msg->type) { case XMSG_INFO: typ = "INFO"; break; case XMSG_ERROR: typ = "ERROR"; break; case XMSG_DONE: typ = "DONE"; break; case XMSG_CANCEL: typ = "CANCEL"; break; case XMSG_PART_DONE: typ = "PART_DONE"; break; case XMSG_READY: typ = "READY"; break; default: typ = "**UNKNOWN**"; break; } msg->repr = vstrallocf("<XMsg@%p type=XMSG_%s elt=%s version=%d>", msg, typ, xfer_element_repr(msg->elt), msg->version); } return msg->repr; }
char * _str_exit_status( char *subject, amwait_t status) { if (WIFEXITED(status)) { int exitstatus = WEXITSTATUS(status); if (exitstatus == 0) return vstrallocf(_("%s exited normally"), subject); else return vstrallocf(_("%s exited with status %d"), subject, exitstatus); } if (WIFSIGNALED(status)) { int signal = WTERMSIG(status); #ifdef WCOREDUMP if (WCOREDUMP(status)) return vstrallocf(_("%s exited after receiving signal %d (core dumped)"), subject, signal); else #endif return vstrallocf(_("%s exited after receiving signal %d"), subject, signal); } if (WIFSTOPPED(status)) { int signal = WSTOPSIG(status); return vstrallocf(_("%s stopped temporarily after receiving signal %d"), subject, signal); } #ifdef WIFCONTINUED if (WIFCONTINUED(status)) { return vstrallocf(_("%s was resumed"), subject); } #endif return vstrallocf(_("%s exited in unknown circumstances"), subject); }
static void amgtar_backup( application_argument_t *argument) { int dumpin; char *cmd = NULL; char *qdisk; char *incrname; char line[32768]; amregex_t *rp; off_t dump_size = -1; char *type; char startchr; int dataf = 1; int mesgf = 3; int indexf = 4; int outf; FILE *mesgstream; FILE *indexstream = NULL; FILE *outstream; char *errmsg = NULL; amwait_t wait_status; GPtrArray *argv_ptr; int tarpid; mesgstream = fdopen(mesgf, "w"); if (!mesgstream) { error(_("error mesgstream(%d): %s\n"), mesgf, strerror(errno)); } if (!gnutar_path) { error(_("GNUTAR-PATH not defined")); } if (!gnutar_listdir) { error(_("GNUTAR-LISTDIR not defined")); } if (!argument->level) { fprintf(mesgstream, "? No level argument\n"); error(_("No level argument")); } if (!argument->dle.disk) { fprintf(mesgstream, "? No disk argument\n"); error(_("No disk argument")); } if (!argument->dle.device) { fprintf(mesgstream, "? No device argument\n"); error(_("No device argument")); } qdisk = quote_string(argument->dle.disk); incrname = amgtar_get_incrname(argument, GPOINTER_TO_INT(argument->level->data)); cmd = stralloc(gnutar_path); argv_ptr = amgtar_build_argv(argument, incrname, CMD_BACKUP); tarpid = pipespawnv(cmd, STDIN_PIPE|STDERR_PIPE, 1, &dumpin, &dataf, &outf, (char **)argv_ptr->pdata); /* close the write ends of the pipes */ aclose(dumpin); aclose(dataf); if (argument->dle.create_index) { indexstream = fdopen(indexf, "w"); if (!indexstream) { error(_("error indexstream(%d): %s\n"), indexf, strerror(errno)); } } outstream = fdopen(outf, "r"); if (!outstream) { error(_("error outstream(%d): %s\n"), outf, strerror(errno)); } while (fgets(line, sizeof(line), outstream) != NULL) { if (line[strlen(line)-1] == '\n') /* remove trailling \n */ line[strlen(line)-1] = '\0'; if (*line == '.' && *(line+1) == '/') { /* filename */ if (argument->dle.create_index) { fprintf(indexstream, "%s\n", &line[1]); /* remove . */ } } else { /* message */ for(rp = re_table; rp->regex != NULL; rp++) { if(match(rp->regex, line)) { break; } } if(rp->typ == DMP_SIZE) { dump_size = (long)((the_num(line, rp->field)* rp->scale+1023.0)/1024.0); } switch(rp->typ) { case DMP_NORMAL: type = "normal"; startchr = '|'; break; case DMP_IGNORE: continue; case DMP_STRANGE: type = "strange"; startchr = '?'; break; case DMP_SIZE: type = "size"; startchr = '|'; break; case DMP_ERROR: type = "error"; startchr = '?'; break; default: type = "unknown"; startchr = '!'; break; } dbprintf("%3d: %7s(%c): %s\n", rp->srcline, type, startchr, line); fprintf(mesgstream,"%c %s\n", startchr, line); } } waitpid(tarpid, &wait_status, 0); if (WIFSIGNALED(wait_status)) { errmsg = vstrallocf(_("%s terminated with signal %d: see %s"), cmd, WTERMSIG(wait_status), dbfn()); } else if (WIFEXITED(wait_status)) { if (exit_value[WEXITSTATUS(wait_status)] == 1) { errmsg = vstrallocf(_("%s exited with status %d: see %s"), cmd, WEXITSTATUS(wait_status), dbfn()); } else { /* Normal exit */ } } else { errmsg = vstrallocf(_("%s got bad exit: see %s"), cmd, dbfn()); } dbprintf(_("after %s %s wait\n"), cmd, qdisk); dbprintf(_("amgtar: %s: pid %ld\n"), cmd, (long)tarpid); if (errmsg) { dbprintf("%s", errmsg); g_fprintf(mesgstream, "sendbackup: error [%s]\n", errmsg); } if (!errmsg && incrname && strlen(incrname) > 4) { char *nodotnew; nodotnew = stralloc(incrname); nodotnew[strlen(nodotnew)-4] = '\0'; if (rename(incrname, nodotnew)) { dbprintf(_("%s: warning [renaming %s to %s: %s]\n"), get_pname(), incrname, nodotnew, strerror(errno)); g_fprintf(mesgstream, _("? warning [renaming %s to %s: %s]\n"), incrname, nodotnew, strerror(errno)); } amfree(nodotnew); } dbprintf("sendbackup: size %lld\n", (long long)dump_size); fprintf(mesgstream, "sendbackup: size %lld\n", (long long)dump_size); dbprintf("sendbackup: end\n"); fprintf(mesgstream, "sendbackup: end\n"); if (argument->dle.create_index) fclose(indexstream); fclose(mesgstream); amfree(incrname); amfree(qdisk); amfree(cmd); g_ptr_array_free_full(argv_ptr); }
static void amgtar_estimate( application_argument_t *argument) { char *incrname = NULL; GPtrArray *argv_ptr; char *cmd = NULL; int nullfd = -1; int pipefd = -1; FILE *dumpout = NULL; off_t size = -1; char line[32768]; char *errmsg = NULL; char *qerrmsg = NULL; char *qdisk; amwait_t wait_status; int tarpid; amregex_t *rp; times_t start_time; int level; GSList *levels; if (!argument->level) { fprintf(stderr, "ERROR No level argument\n"); error(_("No level argument")); } if (!argument->dle.disk) { fprintf(stderr, "ERROR No disk argument\n"); error(_("No disk argument")); } if (!argument->dle.device) { fprintf(stderr, "ERROR No device argument\n"); error(_("No device argument")); } qdisk = quote_string(argument->dle.disk); if (argument->calcsize) { char *dirname; char *file_exclude; char *file_include; int nb_exclude; int nb_include; if (gnutar_directory) { dirname = gnutar_directory; } else { dirname = amname_to_dirname(argument->dle.device); } amgtar_build_exinclude(&argument->dle, 1, &nb_exclude, &file_exclude, &nb_include, &file_include); run_calcsize(argument->config, "GNUTAR", argument->dle.disk, dirname, argument->level, file_exclude, file_include); return; } if (!gnutar_path) { errmsg = vstrallocf(_("GNUTAR-PATH not defined")); goto common_error; } if (!gnutar_listdir) { errmsg = vstrallocf(_("GNUTAR-LISTDIR not defined")); goto common_error; } for (levels = argument->level; levels != NULL; levels = levels->next) { level = GPOINTER_TO_INT(levels->data); incrname = amgtar_get_incrname(argument, level); cmd = stralloc(gnutar_path); argv_ptr = amgtar_build_argv(argument, incrname, CMD_ESTIMATE); start_time = curclock(); if ((nullfd = open("/dev/null", O_RDWR)) == -1) { errmsg = vstrallocf(_("Cannot access /dev/null : %s"), strerror(errno)); goto common_exit; } tarpid = pipespawnv(cmd, STDERR_PIPE, 1, &nullfd, &nullfd, &pipefd, (char **)argv_ptr->pdata); dumpout = fdopen(pipefd,"r"); if (!dumpout) { error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } size = (off_t)-1; while (size < 0 && (fgets(line, sizeof(line), dumpout) != NULL)) { if (line[strlen(line)-1] == '\n') /* remove trailling \n */ line[strlen(line)-1] = '\0'; if (line[0] == '\0') continue; dbprintf("%s\n", line); /* check for size match */ /*@ignore@*/ for(rp = re_table; rp->regex != NULL; rp++) { if(match(rp->regex, line)) { if (rp->typ == DMP_SIZE) { size = ((the_num(line, rp->field)*rp->scale+1023.0)/1024.0); if(size < 0.0) size = 1.0; /* found on NeXT -- sigh */ } break; } } /*@end@*/ } while (fgets(line, sizeof(line), dumpout) != NULL) { dbprintf("%s", line); } dbprintf(".....\n"); dbprintf(_("estimate time for %s level %d: %s\n"), qdisk, level, walltime_str(timessub(curclock(), start_time))); if(size == (off_t)-1) { errmsg = vstrallocf(_("no size line match in %s output"), cmd); dbprintf(_("%s for %s\n"), errmsg, qdisk); dbprintf(".....\n"); } else if(size == (off_t)0 && argument->level == 0) { dbprintf(_("possible %s problem -- is \"%s\" really empty?\n"), cmd, argument->dle.disk); dbprintf(".....\n"); } dbprintf(_("estimate size for %s level %d: %lld KB\n"), qdisk, level, (long long)size); kill(-tarpid, SIGTERM); dbprintf(_("waiting for %s \"%s\" child\n"), cmd, qdisk); waitpid(tarpid, &wait_status, 0); if (WIFSIGNALED(wait_status)) { errmsg = vstrallocf(_("%s terminated with signal %d: see %s"), cmd, WTERMSIG(wait_status), dbfn()); } else if (WIFEXITED(wait_status)) { if (exit_value[WEXITSTATUS(wait_status)] == 1) { errmsg = vstrallocf(_("%s exited with status %d: see %s"), cmd, WEXITSTATUS(wait_status), dbfn()); } else { /* Normal exit */ } } else { errmsg = vstrallocf(_("%s got bad exit: see %s"), cmd, dbfn()); } dbprintf(_("after %s %s wait\n"), cmd, qdisk); common_exit: if (errmsg) { dbprintf("%s", errmsg); fprintf(stdout, "ERROR %s\n", errmsg); } if (incrname) { unlink(incrname); } g_ptr_array_free_full(argv_ptr); amfree(cmd); aclose(nullfd); afclose(dumpout); fprintf(stdout, "%d %lld 1\n", level, (long long)size); } amfree(qdisk); return; common_error: qerrmsg = quote_string(errmsg); amfree(qdisk); dbprintf("%s", errmsg); fprintf(stdout, "ERROR %s\n", qerrmsg); amfree(errmsg); amfree(qerrmsg); return; }
int check_status( pid_t pid, amwait_t w, int mesgfd) { char *thiserr = NULL; char *str, *strX; int ret, sig, rc; str = childstr(pid); if(WIFSIGNALED(w)) { ret = 0; rc = sig = WTERMSIG(w); } else { sig = 0; rc = ret = WEXITSTATUS(w); } if(pid == indexpid) { /* * Treat an index failure (other than signal) as a "STRANGE" * rather than an error so the dump goes ahead and gets processed * but the failure is noted. */ if(ret != 0) { fdprintf(mesgfd, _("? index %s returned %d\n"), str, ret); rc = 0; } indexpid = -1; strX = "index"; } else if(pid == comppid) { /* * compress returns 2 sometimes, but it is ok. */ #ifndef HAVE_GZIP if(ret == 2) { rc = 0; } #endif comppid = -1; strX = "compress"; } else if(pid == dumppid && tarpid == -1) { /* * Ultrix dump returns 1 sometimes, but it is ok. */ #ifdef DUMP_RETURNS_1 if(ret == 1) { rc = 0; } #endif dumppid = -1; strX = "dump"; } else if(pid == tarpid) { if (ret == 1) { rc = 0; } /* * tar bitches about active filesystems, but we do not care. */ #ifdef IGNORE_TAR_ERRORS if(ret == 2) { rc = 0; } #endif dumppid = tarpid = -1; strX = "dump"; } else if(pid == application_api_pid) { strX = "Application"; } else { strX = "unknown"; } if(rc == 0) { return 0; /* normal exit */ } if(ret == 0) { thiserr = vstrallocf(_("%s (%d) %s got signal %d"), strX, (int)pid, str, sig); } else { thiserr = vstrallocf(_("%s (%d) %s returned %d"), strX, (int)pid, str, ret); } fdprintf(mesgfd, "? %s\n", thiserr); if(errorstr) { errorstr = newvstrallocf(errorstr, "%s, %s", errorstr, thiserr); amfree(thiserr); } else { errorstr = thiserr; thiserr = NULL; } return 1; }
int main( int argc, char ** argv) { int interactive = 0; int level = 0; int mesgpipe[2]; dle_t *dle = NULL; char *dumpdate, *stroptions; char *qdisk = NULL; char *qamdevice = NULL; char *line = NULL; char *err_extra = NULL; char *s; int i; int ch; GSList *errlist; FILE *mesgstream; level_t *alevel; /* 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 for config errors comes later) */ 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); } qdisk = NULL; dumpdate = NULL; stroptions = NULL; 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(get_config_name(), DBG_SUBDIR_CLIENT); } /* check for any config errors now */ if (config_errors(&errlist) >= CFGERR_ERRORS) { char *errstr = config_errors_to_error_string(errlist); g_printf("%s\n", errstr); dbclose(); return 1; } if (am_has_feature(g_options->features, fe_req_xml)) { break; } continue; } if (dle && dle->program != NULL) { err_extra = _("multiple requests"); goto err; } dbprintf(_(" sendbackup req: <%s>\n"), line); dle = alloc_dle(); 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 */ } dle->program = s - 1; skip_non_whitespace(s, ch); s[-1] = '\0'; if (strcmp(dle->program, "APPLICATION")==0) { dle->program_is_application_api=1; skip_whitespace(s, ch); /* find dumper name */ if (ch == '\0') { goto err; /* no program */ } dle->program = s - 1; skip_non_whitespace(s, ch); s[-1] = '\0'; } dle->program = stralloc(dle->program); skip_whitespace(s, ch); /* find the disk name */ if(ch == '\0') { err_extra = _("no disk name"); goto err; /* no disk name */ } amfree(qdisk); qdisk = s - 1; ch = *qdisk; skip_quoted_string(s, ch); s[-1] = '\0'; qdisk = stralloc(qdisk); dle->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(qamdevice); qamdevice = s - 1; ch = *qamdevice; skip_quoted_string(s, ch); s[-1] = '\0'; qamdevice = stralloc(qamdevice); dle->device = unquote_string(qamdevice); skip_whitespace(s, ch); /* find level number */ } else { dle->device = stralloc(dle->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); alevel = g_new0(level_t, 1); alevel->level = level; dle->levellist = g_slist_append(dle->levellist, alevel); 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) { g_printf(_("ERROR [Missing OPTIONS line in sendbackup input]\n")); error(_("Missing OPTIONS line in sendbackup input\n")); /*NOTREACHED*/ } if (am_has_feature(g_options->features, fe_req_xml)) { char *errmsg = NULL; dle = amxml_parse_node_FILE(stdin, &errmsg); if (errmsg) { err_extra = errmsg; goto err; } if (!dle) { err_extra = _("One DLE required"); goto err; } else if (dle->next) { err_extra = _("Only one DLE allowed"); goto err; } qdisk = quote_string(dle->disk); if (dle->device == NULL) dle->device = stralloc(dle->disk); qamdevice = quote_string(dle->device); dumpdate = stralloc("NODATE"); stroptions = stralloc(""); } else { parse_options(stroptions, dle, g_options->features, 0); } gdle = dle; if (dle->program == NULL || dle->disk == NULL || dle->device == NULL || dle->levellist == NULL || dumpdate == NULL) { err_extra = _("no valid sendbackup request"); goto err; } if (g_slist_length(dle->levellist) != 1) { err_extra = _("Too many level"); goto err; } alevel = (level_t *)dle->levellist->data; level = alevel->level; dbprintf(_(" Parsed request as: program `%s'\n"), dle->program); 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 (dle->program_is_application_api==1) { /* check that the application_api exist */ } else { for(i = 0; programs[i]; i++) { if (strcmp(programs[i]->name, dle->program) == 0) { break; } } if (programs[i] == NULL) { dbprintf(_("ERROR [%s: unknown program %s]\n"), get_pname(), dle->program); error(_("ERROR [%s: unknown program %s]"), get_pname(), dle->program); /*NOTREACHED*/ } program = programs[i]; } if(!interactive) { datafd = DATA_FD_OFFSET + 0; mesgfd = DATA_FD_OFFSET + 2; indexfd = DATA_FD_OFFSET + 4; } if (!dle->create_index) indexfd = -1; if (dle->auth && amandad_auth) { if(strcasecmp(dle->auth, amandad_auth) != 0) { g_printf(_("ERROR [client configured for auth=%s while server requested '%s']\n"), amandad_auth, dle->auth); exit(-1); } } if (dle->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); } 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 || (dle->create_index && indexfd == -1)) { dbclose(); exit(1); } } mesgstream = fdopen(mesgfd,"w"); run_client_scripts(EXECUTE_ON_PRE_DLE_BACKUP, g_options, dle, mesgstream); fflush(mesgstream); if (dle->program_is_application_api==1) { guint j; char *cmd=NULL; GPtrArray *argv_ptr; char levelstr[20]; backup_support_option_t *bsu; char *compopt = NULL; char *encryptopt = skip_argument; int compout, dumpout; GSList *scriptlist; script_t *script; time_t cur_dumptime; int result; GPtrArray *errarray; int errfd[2]; FILE *dumperr; /* apply client-side encryption here */ if ( dle->encrypt == ENCRYPT_CUST ) { encpid = pipespawn(dle->clnt_encrypt, STDIN_PIPE, 0, &compout, &datafd, &mesgfd, dle->clnt_encrypt, encryptopt, NULL); dbprintf(_("encrypt: pid %ld: %s\n"), (long)encpid, dle->clnt_encrypt); } else { compout = datafd; encpid = -1; } /* now do the client-side compression */ if(dle->compress == COMP_FAST || dle->compress == COMP_BEST) { compopt = skip_argument; #if defined(COMPRESS_BEST_OPT) && defined(COMPRESS_FAST_OPT) if(dle->compress == COMP_BEST) { compopt = COMPRESS_BEST_OPT; } else { compopt = COMPRESS_FAST_OPT; } #endif comppid = pipespawn(COMPRESS_PATH, STDIN_PIPE, 0, &dumpout, &compout, &mesgfd, COMPRESS_PATH, compopt, NULL); dbprintf(_("gnutar: pid %ld: %s"), (long)comppid, COMPRESS_PATH); if(compopt != skip_argument) { dbprintf(_("pid %ld: %s %s\n"), (long)comppid, COMPRESS_PATH, compopt); } else { dbprintf(_("pid %ld: %s\n"), (long)comppid, COMPRESS_PATH); } } else if (dle->compress == COMP_CUST) { compopt = skip_argument; comppid = pipespawn(dle->compprog, STDIN_PIPE, 0, &dumpout, &compout, &mesgfd, dle->compprog, compopt, NULL); if(compopt != skip_argument) { dbprintf(_("pid %ld: %s %s\n"), (long)comppid, dle->compprog, compopt); } else { dbprintf(_("pid %ld: %s\n"), (long)comppid, dle->compprog); } } else { dumpout = compout; comppid = -1; } cur_dumptime = time(0); bsu = backup_support_option(dle->program, g_options, dle->disk, dle->device, &errarray); if (!bsu) { char *errmsg; char *qerrmsg; guint i; for (i=0; i < errarray->len; i++) { errmsg = g_ptr_array_index(errarray, i); qerrmsg = quote_string(errmsg); fdprintf(mesgfd, _("sendbackup: error [Application '%s': %s]\n"), dle->program, errmsg); dbprintf("aa: %s\n",qerrmsg); amfree(qerrmsg); } if (i == 0) { /* no errarray */ errmsg = vstrallocf(_("Can't execute application '%s'"), dle->program); qerrmsg = quote_string(errmsg); fdprintf(mesgfd, _("sendbackup: error [%s]\n"), errmsg); dbprintf(_("ERROR %s\n"), qerrmsg); amfree(qerrmsg); amfree(errmsg); } return 0; } if (pipe(errfd) < 0) { char *errmsg; char *qerrmsg; errmsg = vstrallocf(_("Application '%s': can't create pipe"), dle->program); qerrmsg = quote_string(errmsg); fdprintf(mesgfd, _("sendbackup: error [%s]\n"), errmsg); dbprintf(_("ERROR %s\n"), qerrmsg); amfree(qerrmsg); amfree(errmsg); return 0; } switch(application_api_pid=fork()) { case 0: argv_ptr = g_ptr_array_new(); cmd = vstralloc(APPLICATION_DIR, "/", dle->program, NULL); g_ptr_array_add(argv_ptr, stralloc(dle->program)); g_ptr_array_add(argv_ptr, stralloc("backup")); if (bsu->message_line == 1) { g_ptr_array_add(argv_ptr, stralloc("--message")); g_ptr_array_add(argv_ptr, stralloc("line")); } if (g_options->config && bsu->config == 1) { g_ptr_array_add(argv_ptr, stralloc("--config")); g_ptr_array_add(argv_ptr, stralloc(g_options->config)); } if (g_options->hostname && bsu->host == 1) { g_ptr_array_add(argv_ptr, stralloc("--host")); g_ptr_array_add(argv_ptr, stralloc(g_options->hostname)); } if (dle->disk && bsu->disk == 1) { g_ptr_array_add(argv_ptr, stralloc("--disk")); g_ptr_array_add(argv_ptr, stralloc(dle->disk)); } g_ptr_array_add(argv_ptr, stralloc("--device")); g_ptr_array_add(argv_ptr, stralloc(dle->device)); if (level <= bsu->max_level) { g_ptr_array_add(argv_ptr, stralloc("--level")); g_snprintf(levelstr,19,"%d",level); g_ptr_array_add(argv_ptr, stralloc(levelstr)); } if (indexfd != -1 && bsu->index_line == 1) { g_ptr_array_add(argv_ptr, stralloc("--index")); g_ptr_array_add(argv_ptr, stralloc("line")); } if (dle->record && bsu->record == 1) { g_ptr_array_add(argv_ptr, stralloc("--record")); } application_property_add_to_argv(argv_ptr, dle, bsu); for (scriptlist = dle->scriptlist; scriptlist != NULL; scriptlist = scriptlist->next) { script = (script_t *)scriptlist->data; if (script->result && script->result->proplist) { property_add_to_argv(argv_ptr, script->result->proplist); } } g_ptr_array_add(argv_ptr, NULL); dbprintf(_("%s: running \"%s\n"), get_pname(), cmd); for (j = 1; j < argv_ptr->len - 1; j++) dbprintf(" %s\n", (char *)g_ptr_array_index(argv_ptr,j)); dbprintf(_("\"\n")); if(dup2(dumpout, 1) == -1) { error(_("Can't dup2: %s"),strerror(errno)); /*NOTREACHED*/ } if (dup2(errfd[1], 2) == -1) { error(_("Can't dup2: %s"),strerror(errno)); /*NOTREACHED*/ } if(dup2(mesgfd, 3) == -1) { error(_("Can't dup2: %s"),strerror(errno)); /*NOTREACHED*/ } if(indexfd > 0) { if(dup2(indexfd, 4) == -1) { error(_("Can't dup2: %s"),strerror(errno)); /*NOTREACHED*/ } fcntl(indexfd, F_SETFD, 0); } application_api_info_tapeheader(mesgfd, dle->program, dle); if (indexfd != 0) { safe_fd(3, 2); } else { safe_fd(3, 1); } execve(cmd, (char **)argv_ptr->pdata, safe_env()); exit(1); break; default: break; case -1: error(_("%s: fork returned: %s"), get_pname(), strerror(errno)); } close(errfd[1]); dumperr = fdopen(errfd[0],"r"); if (!dumperr) { error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } result = 0; while ((line = agets(dumperr)) != NULL) { if (strlen(line) > 0) { fdprintf(mesgfd, "sendbackup: error [%s]\n", line); dbprintf("error: %s\n", line); result = 1; } amfree(line); } result |= check_result(mesgfd); if (result == 0) { char *amandates_file; amandates_file = getconf_str(CNF_AMANDATES); if(start_amandates(amandates_file, 1)) { amandates_updateone(dle->disk, level, cur_dumptime); finish_amandates(); free_amandates(); } else { if (GPOINTER_TO_INT(dle->estimatelist->data) == ES_CALCSIZE && bsu->calcsize) { error(_("error [opening %s for writing: %s]"), amandates_file, strerror(errno)); } else { g_debug(_("non-fatal error opening '%s' for writing: %s]"), amandates_file, strerror(errno)); } } } amfree(bsu); } 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); error(_("error [opening mesg pipe: %s]"), s); } program->start_backup(dle, g_options->hostname, datafd, mesgpipe[1], indexfd); dbprintf(_("Started backup\n")); parse_backup_messages(dle, mesgpipe[0]); dbprintf(_("Parsed backup messages\n")); } run_client_scripts(EXECUTE_ON_POST_DLE_BACKUP, g_options, dle, mesgstream); fflush(mesgstream); amfree(qdisk); amfree(qamdevice); amfree(dumpdate); amfree(stroptions); amfree(our_feature_string); am_release_feature_set(our_features); our_features = NULL; free_g_options(g_options); dbclose(); return 0; err: if (err_extra) { g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET '%s'\n"), err_extra); dbprintf(_("REQ packet is bogus: %s\n"), err_extra); } else { g_printf(_("ERROR FORMAT ERROR IN REQUEST PACKET\n")); dbprintf(_("REQ packet is bogus\n")); } amfree(qdisk); amfree(qamdevice); amfree(dumpdate); amfree(stroptions); amfree(our_feature_string); dbclose(); return 1; }
static int do_chunk( int infd, struct databuf * db) { size_t nread; char header_buf[DISK_BLOCK_BYTES]; startclock(); dumpsize = dumpbytes = filesize = (off_t)0; headersize = 0; memset(header_buf, 0, sizeof(header_buf)); /* * The first thing we should receive is the file header, which we * need to save into "file", as well as write out. Later, the * chunk code will rewrite it. */ nread = full_read(infd, header_buf, SIZEOF(header_buf)); if (nread != sizeof(header_buf)) { if(errno != 0) { errstr = vstrallocf(_("cannot read header: %s"), strerror(errno)); } else { errstr = vstrallocf(_("cannot read header: got %zd bytes instead of %zd"), nread, sizeof(header_buf)); } return 0; } parse_file_header(header_buf, &file, (size_t)nread); if(write_tapeheader(db->fd, &file)) { int save_errno = errno; char *m = vstrallocf(_("write_tapeheader file %s: %s"), db->filename, strerror(errno)); errstr = quote_string(m); amfree(m); if(save_errno == ENOSPC) { putresult(NO_ROOM, "%s %lld\n", handle, (long long)(db->use+db->split_size-dumpsize)); } return 0; } dumpsize += (off_t)DISK_BLOCK_KB; filesize = (off_t)DISK_BLOCK_KB; headersize += DISK_BLOCK_KB; /* * We've written the file header. Now, just write data until the * end. */ while ((nread = full_read(infd, db->buf, (size_t)(db->datalimit - db->datain))) > 0) { db->datain += nread; while(db->dataout < db->datain) { if(!databuf_flush(db)) { return 0; } } } while(db->dataout < db->datain) { if(!databuf_flush(db)) { return 0; } } if(dumpbytes > (off_t)0) { dumpsize += (off_t)1; /* count partial final KByte */ filesize += (off_t)1; } return 1; }
/* * Returns a file descriptor to the incoming port * on success, or -1 on error. */ static int startup_chunker( char * filename, off_t use, off_t chunksize, struct databuf * db) { int infd, outfd; char *tmp_filename, *pc; in_port_t data_port; int data_socket; int result; struct addrinfo *res; data_port = 0; if ((result = resolve_hostname("localhost", 0, &res, NULL) != 0)) { errstr = newvstrallocf(errstr, _("could not resolve localhost: %s"), gai_strerror(result)); return -1; } data_socket = stream_server(res->ai_family, &data_port, 0, STREAM_BUFSIZE, 0); if (res) freeaddrinfo(res); if(data_socket < 0) { errstr = vstrallocf(_("error creating stream server: %s"), strerror(errno)); return -1; } putresult(PORT, "%d\n", data_port); infd = stream_accept(data_socket, CONNECT_TIMEOUT, 0, STREAM_BUFSIZE); aclose(data_socket); if(infd == -1) { errstr = vstrallocf(_("error accepting stream: %s"), strerror(errno)); return -1; } tmp_filename = vstralloc(filename, ".tmp", NULL); pc = strrchr(tmp_filename, '/'); g_assert(pc != NULL); *pc = '\0'; mkholdingdir(tmp_filename); *pc = '/'; if ((outfd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) { int save_errno = errno; char *m = vstrallocf(_("holding file \"%s\": %s"), tmp_filename, strerror(errno)); errstr = quote_string(m); amfree(m); amfree(tmp_filename); aclose(infd); if(save_errno == ENOSPC) { putresult(NO_ROOM, "%s %lld\n", handle, (long long)use); return -2; } else { return -1; } } amfree(tmp_filename); databuf_init(db, outfd, filename, use, chunksize); db->filename_seq++; return infd; }
int main( int argc, char ** argv) { static struct databuf db; struct cmdargs *cmdargs; int infd; char *q = NULL; char *filename = NULL; off_t chunksize, use; times_t runtime; am_feature_t *their_features = NULL; int a; config_overrides_t *cfg_ovr = NULL; char *cfg_opt = NULL; char *m; /* * 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(-1, 0); set_pname("chunker"); dbopen(DBG_SUBDIR_SERVER); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); add_amanda_log_handler(amanda_log_stderr); add_amanda_log_handler(amanda_log_trace_log); cfg_ovr = extract_commandline_config_overrides(&argc, &argv); if (argc > 1) cfg_opt = argv[1]; config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, cfg_opt); apply_config_overrides(cfg_ovr); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } safe_cd(); /* do this *after* config_init() */ check_running_as(RUNNING_AS_DUMPUSER); dbrename(get_config_name(), DBG_SUBDIR_SERVER); log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid()); g_fprintf(stderr, _("%s: pid %ld executable %s version %s\n"), get_pname(), (long) getpid(), argv[0], VERSION); fflush(stderr); /* now, make sure we are a valid user */ signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); cmdargs = getcmd(); if(cmdargs->cmd == START) { if(cmdargs->argc <= 1) error(_("error [dumper START: not enough args: timestamp]")); chunker_timestamp = newstralloc(chunker_timestamp, cmdargs->argv[1]); } else { log_add(L_INFO, "%s pid %ld", get_pname(), (long)getpid()); error(_("Didn't get START command")); } /* do {*/ cmdargs = getcmd(); switch(cmdargs->cmd) { case QUIT: break; case PORT_WRITE: /* * PORT-WRITE * handle * filename * host * features * disk * level * dumpdate * chunksize * progname * use * options */ a = 1; if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: handle]")); /*NOTREACHED*/ } handle = newstralloc(handle, cmdargs->argv[a++]); if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: filename]")); /*NOTREACHED*/ } filename = newstralloc(filename, cmdargs->argv[a++]); if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: hostname]")); /*NOTREACHED*/ } hostname = newstralloc(hostname, cmdargs->argv[a++]); if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: features]")); /*NOTREACHED*/ } am_release_feature_set(their_features); their_features = am_string_to_feature(cmdargs->argv[a++]); if (!their_features) { error(_("error [chunker PORT-WRITE: invalid feature string]")); /*NOTREACHED*/ } if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: diskname]")); /*NOTREACHED*/ } diskname = newstralloc(diskname, cmdargs->argv[a++]); if (qdiskname) amfree(qdiskname); qdiskname = quote_string(diskname); /* qdiskname is a global */ if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: level]")); /*NOTREACHED*/ } level = atoi(cmdargs->argv[a++]); if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: dumpdate]")); /*NOTREACHED*/ } dumpdate = newstralloc(dumpdate, cmdargs->argv[a++]); if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: chunksize]")); /*NOTREACHED*/ } chunksize = OFF_T_ATOI(cmdargs->argv[a++]); chunksize = am_floor(chunksize, (off_t)DISK_BLOCK_KB); if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: progname]")); /*NOTREACHED*/ } progname = newstralloc(progname, cmdargs->argv[a++]); if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: use]")); /*NOTREACHED*/ } use = am_floor(OFF_T_ATOI(cmdargs->argv[a++]), DISK_BLOCK_KB); if(a >= cmdargs->argc) { error(_("error [chunker PORT-WRITE: not enough args: options]")); /*NOTREACHED*/ } options = newstralloc(options, cmdargs->argv[a++]); if(a != cmdargs->argc) { error(_("error [chunker PORT-WRITE: too many args: %d != %d]"), cmdargs->argc, a); /*NOTREACHED*/ } if((infd = startup_chunker(filename, use, chunksize, &db)) < 0) { q = quote_string(vstrallocf(_("[chunker startup failed: %s]"), errstr)); putresult(TRYAGAIN, "%s %s\n", handle, q); error("startup_chunker failed: %s", errstr); } command_in_transit = NULL; if(infd >= 0 && do_chunk(infd, &db)) { char kb_str[NUM_STR_SIZE]; char kps_str[NUM_STR_SIZE]; double rt; runtime = stopclock(); rt = g_timeval_to_double(runtime); g_snprintf(kb_str, SIZEOF(kb_str), "%lld", (long long)(dumpsize - (off_t)headersize)); g_snprintf(kps_str, SIZEOF(kps_str), "%3.1lf", isnormal(rt) ? (double)dumpsize / rt : 0.0); errstr = newvstrallocf(errstr, "sec %s kb %s kps %s", walltime_str(runtime), kb_str, kps_str); m = vstrallocf("[%s]", errstr); q = quote_string(m); amfree(m); if(command_in_transit != NULL) { cmdargs = command_in_transit; command_in_transit = NULL; } else { cmdargs = getcmd(); } switch(cmdargs->cmd) { case DONE: putresult(DONE, "%s %lld %s\n", handle, (long long)(dumpsize - (off_t)headersize), q); log_add(L_SUCCESS, "%s %s %s %d [%s]", hostname, qdiskname, chunker_timestamp, level, errstr); break; case BOGUS: case TRYAGAIN: case FAILED: case ABORT_FINISHED: if(dumpsize > (off_t)DISK_BLOCK_KB) { putresult(PARTIAL, "%s %lld %s\n", handle, (long long)(dumpsize - (off_t)headersize), q); log_add(L_PARTIAL, "%s %s %s %d [%s]", hostname, qdiskname, chunker_timestamp, level, errstr); } else { errstr = newvstrallocf(errstr, _("dumper returned %s"), cmdstr[cmdargs->cmd]); amfree(q); m = vstrallocf("[%s]",errstr); q = quote_string(m); amfree(m); putresult(FAILED, "%s %s\n", handle, q); log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname, chunker_timestamp, level, errstr); } default: break; } amfree(q); } else if(infd != -2) { if(q == NULL) { m = vstrallocf("[%s]", errstr); q = quote_string(m); amfree(m); } if(!abort_pending) { putresult(FAILED, "%s %s\n", handle, q); } log_add(L_FAIL, "%s %s %s %d [%s]", hostname, qdiskname, chunker_timestamp, level, errstr); amfree(q); } amfree(filename); amfree(db.filename); break; default: if(cmdargs->argc >= 1) { q = quote_string(cmdargs->argv[0]); } else { q = stralloc(_("(no input?)")); } putresult(BAD_COMMAND, "%s\n", q); amfree(q); break; } /* } while(cmdargs->cmd != QUIT); */ log_add(L_INFO, "pid-done %ld", (long)getpid()); amfree(errstr); amfree(chunker_timestamp); amfree(handle); amfree(hostname); amfree(diskname); amfree(qdiskname); amfree(dumpdate); amfree(progname); amfree(options); free_cmdargs(cmdargs); if (command_in_transit) free_cmdargs(command_in_transit); am_release_feature_set(their_features); their_features = NULL; dbclose(); return (0); /* exit */ }
static int start_chg_glue(void) { int stdin_pipe[2] = { -1, -1 }; int stdout_pipe[2] = { -1, -1 }; char *chg_glue = NULL; char **config_options = NULL; char *cmdline = NULL; /* is it already running? */ if (tpchanger_pid != -1) return 1; if (pipe(stdin_pipe) == -1 || pipe(stdout_pipe) == -1) { changer_resultstr = vstrallocf( _("<error> could not make pipe: %s"), strerror(errno)); goto error; } config_options = get_config_options(2); config_options[0] = g_strdup("chg-glue"); config_options[1] = g_strdup(get_config_name()); chg_glue = g_strdup_printf("%s/chg-glue", amlibexecdir); cmdline = g_strjoinv(" ", config_options); g_debug("invoking %s: %s", chg_glue, cmdline); amfree(cmdline); switch(tpchanger_pid = fork()) { case -1: changer_resultstr = vstrallocf( _("<error> could not fork: %s"), strerror(errno)); goto error; case 0: debug_dup_stderr_to_debug(); if(dup2(stdin_pipe[0], 0) == -1) { changer_resultstr = vstrallocf( _("<error> could not dup2: %s\n"), strerror(errno)); goto child_err; } if(dup2(stdout_pipe[1], 1) == -1) { changer_resultstr = vstrallocf( _("<error> could not dup2: %s\n"), strerror(errno)); goto child_err; } safe_fd(-1, 0); execv(chg_glue, config_options); changer_resultstr = vstrallocf( _("<error> could not exec \"%s\": %s\n"), chg_glue, strerror(errno)); child_err: (void)full_write(stdout_pipe[1], changer_resultstr, strlen(changer_resultstr)); exit(1); default: aclose(stdin_pipe[0]); aclose(stdout_pipe[1]); g_strfreev(config_options); amfree(chg_glue); amfree(cmdline); tpchanger_stdout = stdout_pipe[0]; tpchanger_stdin = stdin_pipe[1]; return 1; } error: amfree(chg_glue); amfree(cmdline); aclose(stdin_pipe[0]); aclose(stdin_pipe[1]); aclose(stdout_pipe[0]); aclose(stdout_pipe[1]); return 0; }
static void amindexd_response( void *datap, pkt_t *pkt, security_handle_t *sech) { int ports[NSTREAMS], *response_error = datap, i; char *p; char *tok; char *extra = NULL; assert(response_error != NULL); assert(sech != NULL); if (pkt == NULL) { errstr = newvstrallocf(errstr, _("[request failed: %s]"), security_geterror(sech)); *response_error = 1; return; } if (pkt->type == P_NAK) { #if defined(PACKET_DEBUG) dbprintf(_("got nak response:\n----\n%s\n----\n\n"), pkt->body); #endif tok = strtok(pkt->body, " "); if (tok == NULL || strcmp(tok, "ERROR") != 0) goto bad_nak; tok = strtok(NULL, "\n"); if (tok != NULL) { errstr = newvstrallocf(errstr, "NAK: %s", tok); *response_error = 1; } else { bad_nak: errstr = newvstrallocf(errstr, _("request NAK")); *response_error = 2; } return; } if (pkt->type != P_REP) { errstr = newvstrallocf(errstr, _("received strange packet type %s: %s"), pkt_type2str(pkt->type), pkt->body); *response_error = 1; return; } #if defined(PACKET_DEBUG) g_fprintf(stderr, _("got response:\n----\n%s\n----\n\n"), pkt->body); #endif for(i = 0; i < NSTREAMS; i++) { ports[i] = -1; streams[i].fd = NULL; } p = pkt->body; while((tok = strtok(p, " \n")) != NULL) { p = NULL; /* * Error response packets have "ERROR" followed by the error message * followed by a newline. */ if (strcmp(tok, "ERROR") == 0) { tok = strtok(NULL, "\n"); if (tok == NULL) { errstr = newvstrallocf(errstr, _("[bogus error packet]")); } else { errstr = newvstrallocf(errstr, "%s", tok); } *response_error = 2; return; } /* * Regular packets have CONNECT followed by three streams */ if (strcmp(tok, "CONNECT") == 0) { /* * Parse the three stream specifiers out of the packet. */ for (i = 0; i < NSTREAMS; i++) { tok = strtok(NULL, " "); if (tok == NULL || strcmp(tok, streams[i].name) != 0) { extra = vstrallocf( _("CONNECT token is \"%s\": expected \"%s\""), tok ? tok : _("(null)"), streams[i].name); goto parse_error; } tok = strtok(NULL, " \n"); if (tok == NULL || sscanf(tok, "%d", &ports[i]) != 1) { extra = vstrallocf( _("CONNECT %s token is \"%s\" expected a port number"), streams[i].name, tok ? tok : _("(null)")); goto parse_error; } } continue; } /* * OPTIONS [options string] '\n' */ if (strcmp(tok, "OPTIONS") == 0) { tok = strtok(NULL, "\n"); if (tok == NULL) { extra = vstrallocf(_("OPTIONS token is missing")); goto parse_error; } #if 0 tok_end = tok + strlen(tok); while((p = strchr(tok, ';')) != NULL) { *p++ = '\0'; if(strncmp_const(tok, "features=") == 0) { tok += SIZEOF("features=") - 1; am_release_feature_set(their_features); if((their_features = am_string_to_feature(tok)) == NULL) { errstr = newvstrallocf(errstr, _("OPTIONS: bad features value: %s"), tok); goto parse_error; } } tok = p; } #endif continue; } #if 0 extra = vstrallocf(_("next token is \"%s\": expected \"CONNECT\", \"ERROR\" or \"OPTIONS\""), tok ? tok : _("(null)")); goto parse_error; #endif } /* * Connect the streams to their remote ports */ for (i = 0; i < NSTREAMS; i++) { /*@i@*/ if (ports[i] == -1) continue; streams[i].fd = security_stream_client(sech, ports[i]); if (streams[i].fd == NULL) { errstr = newvstrallocf(errstr, _("[could not connect %s stream: %s]"), streams[i].name, security_geterror(sech)); goto connect_error; } } /* * Authenticate the streams */ for (i = 0; i < NSTREAMS; i++) { if (streams[i].fd == NULL) continue; if (security_stream_auth(streams[i].fd) < 0) { errstr = newvstrallocf(errstr, _("[could not authenticate %s stream: %s]"), streams[i].name, security_stream_geterror(streams[i].fd)); goto connect_error; } } /* * The MESGFD and DATAFD streams are mandatory. If we didn't get * them, complain. */ if (streams[MESGFD].fd == NULL) { errstr = newvstrallocf(errstr, _("[couldn't open MESG streams]")); goto connect_error; } /* everything worked */ *response_error = 0; amindexd_alive = 1; return; parse_error: errstr = newvstrallocf(errstr, _("[parse of reply message failed: %s]"), extra ? extra : _("(no additional information)")); amfree(extra); *response_error = 2; return; connect_error: stop_amindexd(); *response_error = 1; }
int main( int argc, char ** argv) { int i; time_t timer; char *lineread = NULL; struct sigaction act, oact; extern char *optarg; extern int optind; char *line = NULL; const security_driver_t *secdrv; char *req = NULL; int response_error; struct tm *tm; config_overwrites_t *cfg_ovr; /* * 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(-1, 0); set_pname("amrecover"); /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); dbopen(DBG_SUBDIR_CLIENT); localhost = alloc(MAX_HOSTNAME_LENGTH+1); if (gethostname(localhost, MAX_HOSTNAME_LENGTH) != 0) { error(_("cannot determine local host name\n")); /*NOTREACHED*/ } localhost[MAX_HOSTNAME_LENGTH] = '\0'; /* load the base client configuration */ config_init(CONFIG_INIT_CLIENT, NULL); if (config_errors(NULL) >= CFGERR_WARNINGS) { config_print_errors(); if (config_errors(NULL) >= CFGERR_ERRORS) { g_critical(_("errors processing config file")); } } /* treat amrecover-specific command line options as the equivalent * -o command-line options to set configuration values */ cfg_ovr = new_config_overwrites(argc/2); /* If the first argument is not an option flag, then we assume * it is a configuration name to match the syntax of the other * Amanda utilities. */ if (argc > 1 && argv[1][0] != '-') { add_config_overwrite(cfg_ovr, "conf", argv[1]); /* remove that option from the command line */ argv[1] = argv[0]; argv++; argc--; } /* now parse regular command-line '-' options */ while ((i = getopt(argc, argv, "o:C:s:t:d:U")) != EOF) { switch (i) { case 'C': add_config_overwrite(cfg_ovr, "conf", optarg); break; case 's': add_config_overwrite(cfg_ovr, "index_server", optarg); break; case 't': add_config_overwrite(cfg_ovr, "tape_server", optarg); break; case 'd': add_config_overwrite(cfg_ovr, "tapedev", optarg); break; case 'o': add_config_overwrite_opt(cfg_ovr, optarg); break; case 'U': case '?': (void)g_printf(USAGE); return 0; } } if (optind != argc) { (void)g_fprintf(stderr, USAGE); exit(1); } /* and now try to load the configuration named in that file */ apply_config_overwrites(cfg_ovr); config_init(CONFIG_INIT_CLIENT | CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_OVERLAY, getconf_str(CNF_CONF)); reapply_config_overwrites(); check_running_as(RUNNING_AS_ROOT); dbrename(get_config_name(), DBG_SUBDIR_CLIENT); our_features = am_init_feature_set(); our_features_string = am_feature_to_string(our_features); server_name = NULL; if (getconf_seen(CNF_INDEX_SERVER) == -2) { /* command line argument */ server_name = getconf_str(CNF_INDEX_SERVER); } if (!server_name) { server_name = getenv("AMANDA_SERVER"); if (server_name) { g_printf(_("Using index server from environment AMANDA_SERVER (%s)\n"), server_name); } } if (!server_name) { server_name = getconf_str(CNF_INDEX_SERVER); } if (!server_name) { error(_("No index server set")); /*NOTREACHED*/ } server_name = stralloc(server_name); tape_server_name = NULL; if (getconf_seen(CNF_TAPE_SERVER) == -2) { /* command line argument */ tape_server_name = getconf_str(CNF_TAPE_SERVER); } if (!tape_server_name) { tape_server_name = getenv("AMANDA_TAPE_SERVER"); if (!tape_server_name) { tape_server_name = getenv("AMANDA_TAPESERVER"); if (tape_server_name) { g_printf(_("Using tape server from environment AMANDA_TAPESERVER (%s)\n"), tape_server_name); } } else { g_printf(_("Using tape server from environment AMANDA_TAPE_SERVER (%s)\n"), tape_server_name); } } if (!tape_server_name) { tape_server_name = getconf_str(CNF_TAPE_SERVER); } if (!tape_server_name) { error(_("No tape server set")); /*NOTREACHED*/ } tape_server_name = stralloc(tape_server_name); amfree(tape_device_name); tape_device_name = getconf_str(CNF_TAPEDEV); if (!tape_device_name || strlen(tape_device_name) == 0 || !getconf_seen(CNF_TAPEDEV)) { tape_device_name = NULL; } else { tape_device_name = stralloc(tape_device_name); } authopt = stralloc(getconf_str(CNF_AUTH)); amfree(disk_name); amfree(mount_point); amfree(disk_path); dump_date[0] = '\0'; /* Don't die when child closes pipe */ signal(SIGPIPE, SIG_IGN); /* set up signal handler */ act.sa_handler = sigint_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGINT, &act, &oact) != 0) { error(_("error setting signal handler: %s"), strerror(errno)); /*NOTREACHED*/ } protocol_init(); /* We assume that amindexd support fe_amindexd_options_features */ /* and fe_amindexd_options_auth */ /* We should send a noop to really know */ req = vstrallocf("SERVICE amindexd\n" "OPTIONS features=%s;auth=%s;\n", our_features_string, authopt); secdrv = security_getdriver(authopt); if (secdrv == NULL) { error(_("no '%s' security driver available for host '%s'"), authopt, server_name); /*NOTREACHED*/ } protocol_sendreq(server_name, secdrv, generic_client_get_security_conf, req, STARTUP_TIMEOUT, amindexd_response, &response_error); amfree(req); protocol_run(); g_printf(_("AMRECOVER Version %s. Contacting server on %s ...\n"), version(), server_name); if(response_error != 0) { g_fprintf(stderr,"%s\n",errstr); exit(1); } /* get server's banner */ if (grab_reply(1) == -1) { aclose(server_socket); exit(1); } if (!server_happy()) { dbclose(); aclose(server_socket); exit(1); } /* try to get the features from the server */ { char *their_feature_string = NULL; indexsrv_features = NULL; line = vstrallocf("FEATURES %s", our_features_string); if(exchange(line) == 0) { their_feature_string = stralloc(server_line+13); indexsrv_features = am_string_to_feature(their_feature_string); if (!indexsrv_features) g_printf(_("Bad feature string from server: %s"), their_feature_string); } if (!indexsrv_features) indexsrv_features = am_set_default_feature_set(); amfree(their_feature_string); amfree(line); } /* set the date of extraction to be today */ (void)time(&timer); tm = localtime(&timer); if (tm) strftime(dump_date, sizeof(dump_date), "%Y-%m-%d", tm); else error(_("BAD DATE")); g_printf(_("Setting restore date to today (%s)\n"), dump_date); line = vstrallocf("DATE %s", dump_date); if (converse(line) == -1) { aclose(server_socket); exit(1); } amfree(line); line = vstrallocf("SCNF %s", get_config_name()); if (converse(line) == -1) { aclose(server_socket); exit(1); } amfree(line); if (server_happy()) { /* set host we are restoring to this host by default */ amfree(dump_hostname); set_host(localhost); if (dump_hostname) g_printf(_("Use the setdisk command to choose dump disk to recover\n")); else g_printf(_("Use the sethost command to choose a host to recover\n")); } quit_prog = 0; do { if ((lineread = readline("amrecover> ")) == NULL) { clearerr(stdin); putchar('\n'); break; } if (lineread[0] != '\0') { add_history(lineread); dbprintf(_("user command: '%s'\n"), lineread); process_line(lineread); /* act on line's content */ } amfree(lineread); } while (!quit_prog); dbclose(); aclose(server_socket); return 0; }
/* * check ~/.k5amandahosts to see if this principal is allowed in. If it's * hardcoded, then we don't check the realm */ static char * krb5_checkuser( char * host, char * name, char * realm) { #ifdef AMANDA_PRINCIPAL if(strcmp(name, AMANDA_PRINCIPAL) == 0) { return(NULL); } else { return(vstrallocf(_("does not match compiled in default"))); } #else struct passwd *pwd; char *ptmp; char *result = _("generic error"); /* default is to not permit */ FILE *fp = NULL; struct stat sbuf; uid_t localuid; char *line = NULL; char *filehost = NULL, *fileuser = NULL, *filerealm = NULL; assert( host != NULL); assert( name != NULL); if((pwd = getpwnam(CLIENT_LOGIN)) == NULL) { result = vstrallocf(_("can not find user %s"), CLIENT_LOGIN); } localuid = pwd->pw_uid; #ifdef USE_AMANDAHOSTS ptmp = stralloc2(pwd->pw_dir, "/.k5amandahosts"); #else ptmp = stralloc2(pwd->pw_dir, "/.k5login"); #endif if(!ptmp) { result = vstrallocf(_("could not find home directory for %s"), CLIENT_LOGIN); goto common_exit; } /* * check to see if the ptmp file does nto exist. */ if(access(ptmp, R_OK) == -1 && errno == ENOENT) { /* * in this case we check to see if the principal matches * the destination user mimicing the .k5login functionality. */ if(strcmp(name, CLIENT_LOGIN) != 0) { result = vstrallocf(_("%s does not match %s"), name, CLIENT_LOGIN); return result; } result = NULL; goto common_exit; } auth_debug(1, _("opening ptmp: %s\n"), (ptmp)?ptmp: "NULL!"); if((fp = fopen(ptmp, "r")) == NULL) { result = vstrallocf(_("can not open %s"), ptmp); return result; } auth_debug(1, _("opened ptmp\n")); if (fstat(fileno(fp), &sbuf) != 0) { result = vstrallocf(_("cannot fstat %s: %s"), ptmp, strerror(errno)); goto common_exit; } if (sbuf.st_uid != localuid) { result = vstrallocf(_("%s is owned by %ld, should be %ld"), ptmp, (long)sbuf.st_uid, (long)localuid); goto common_exit; } if ((sbuf.st_mode & 077) != 0) { result = vstrallocf( _("%s: incorrect permissions; file must be accessible only by its owner"), ptmp); goto common_exit; } while ((line = agets(fp)) != NULL) { if (line[0] == '\0') { amfree(line); continue; } /* if there's more than one column, then it's the host */ if( (filehost = strtok(line, " \t")) == NULL) { amfree(line); continue; } /* * if there's only one entry, then it's a username and we have * no hostname. (so the principal is allowed from anywhere. */ if((fileuser = strtok(NULL, " \t")) == NULL) { fileuser = filehost; filehost = NULL; } if(filehost && strcmp(filehost, host) != 0) { amfree(line); continue; } else { auth_debug(1, _("found a host match\n")); } if( (filerealm = strchr(fileuser, '@')) != NULL) { *filerealm++ = '\0'; } /* * we have a match. We're going to be a little bit insecure * and indicate that the principal is correct but the realm is * not if that's the case. Technically we should say nothing * and let the user figure it out, but it's helpful for debugging. * You likely only get this far if you've turned on cross-realm auth * anyway... */ auth_debug(1, _("comparing %s %s\n"), fileuser, name); if(strcmp(fileuser, name) == 0) { auth_debug(1, _("found a match!\n")); if(realm && filerealm && (strcmp(realm, filerealm)!=0)) { amfree(line); continue; } result = NULL; amfree(line); goto common_exit; } amfree(line); } result = vstrallocf(_("no match in %s"), ptmp); common_exit: afclose(fp); return(result); #endif /* AMANDA_PRINCIPAL */ }
/* * Get a ticket granting ticket and stuff it in the cache */ static const char * get_tgt( char * keytab_name, char * principal_name) { krb5_context context; krb5_error_code ret; krb5_principal client = NULL, server = NULL; krb5_creds creds; krb5_keytab keytab; krb5_ccache ccache; krb5_timestamp now; #ifdef KRB5_HEIMDAL_INCLUDES krb5_data tgtname = { KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; #else krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; #endif static char *error = NULL; if (error != NULL) { amfree(error); error = NULL; } if ((ret = krb5_init_context(&context)) != 0) { error = vstrallocf(_("error initializing krb5 context: %s"), error_message(ret)); return (error); } /*krb5_init_ets(context);*/ if(!keytab_name) { error = vstrallocf(_("error -- no krb5 keytab defined")); return(error); } if(!principal_name) { error = vstrallocf(_("error -- no krb5 principal defined")); return(error); } /* * Resolve keytab file into a keytab object */ if ((ret = krb5_kt_resolve(context, keytab_name, &keytab)) != 0) { error = vstrallocf(_("error resolving keytab %s: %s"), keytab_name, error_message(ret)); return (error); } /* * Resolve the amanda service held in the keytab into a principal * object */ ret = krb5_parse_name(context, principal_name, &client); if (ret != 0) { error = vstrallocf(_("error parsing %s: %s"), principal_name, error_message(ret)); return (error); } #ifdef KRB5_HEIMDAL_INCLUDES ret = krb5_build_principal_ext(context, &server, krb5_realm_length(*krb5_princ_realm(context, client)), krb5_realm_data(*krb5_princ_realm(context, client)), tgtname.length, tgtname.data, krb5_realm_length(*krb5_princ_realm(context, client)), krb5_realm_data(*krb5_princ_realm(context, client)), 0); #else ret = krb5_build_principal_ext(context, &server, krb5_princ_realm(context, client)->length, krb5_princ_realm(context, client)->data, tgtname.length, tgtname.data, krb5_princ_realm(context, client)->length, krb5_princ_realm(context, client)->data, 0); #endif if (ret != 0) { error = vstrallocf(_("error while building server name: %s"), error_message(ret)); return (error); } ret = krb5_timeofday(context, &now); if (ret != 0) { error = vstrallocf(_("error getting time of day: %s"), error_message(ret)); return (error); } memset(&creds, 0, SIZEOF(creds)); creds.times.starttime = 0; creds.times.endtime = now + AMANDA_TKT_LIFETIME; creds.client = client; creds.server = server; /* * Get a ticket for the service, using the keytab */ ret = krb5_get_in_tkt_with_keytab(context, 0, NULL, NULL, NULL, keytab, 0, &creds, 0); if (ret != 0) { error = vstrallocf(_("error getting ticket for %s: %s"), principal_name, error_message(ret)); goto cleanup2; } if ((ret = krb5_cc_default(context, &ccache)) != 0) { error = vstrallocf(_("error initializing ccache: %s"), error_message(ret)); goto cleanup; } if ((ret = krb5_cc_initialize(context, ccache, client)) != 0) { error = vstrallocf(_("error initializing ccache: %s"), error_message(ret)); goto cleanup; } if ((ret = krb5_cc_store_cred(context, ccache, &creds)) != 0) { error = vstrallocf(_("error storing creds in ccache: %s"), error_message(ret)); /* FALLTHROUGH */ } krb5_cc_close(context, ccache); cleanup: krb5_free_cred_contents(context, &creds); cleanup2: #if 0 krb5_free_principal(context, client); krb5_free_principal(context, server); #endif krb5_free_context(context); return (error); }
/* * Write out the buffer to the backing file */ static int databuf_flush( struct databuf * db) { struct cmdargs *cmdargs = NULL; int rc = 1; size_t size_to_write; size_t written; off_t left_in_chunk; char *arg_filename = NULL; char *new_filename = NULL; char *tmp_filename = NULL; char sequence[NUM_STR_SIZE]; int newfd; filetype_t save_type; char *q; int a; char *pc; /* * If there's no data, do nothing. */ if (db->dataout >= db->datain) { goto common_exit; } /* * See if we need to split this file. */ while (db->split_size > (off_t)0 && dumpsize >= db->split_size) { if( db->use == (off_t)0 ) { /* * Probably no more space on this disk. Request some more. */ putresult(RQ_MORE_DISK, "%s\n", handle); cmdargs = getcmd(); if(command_in_transit == NULL && (cmdargs->cmd == DONE || cmdargs->cmd == TRYAGAIN || cmdargs->cmd == FAILED)) { command_in_transit = cmdargs; cmdargs = getcmd(); } if(cmdargs->cmd == CONTINUE) { /* * CONTINUE * serial * filename * chunksize * use */ a = 2; /* skip CONTINUE and serial */ if(a >= cmdargs->argc) { error(_("error [chunker CONTINUE: not enough args: filename]")); /*NOTREACHED*/ } arg_filename = newstralloc(arg_filename, cmdargs->argv[a++]); if(a >= cmdargs->argc) { error(_("error [chunker CONTINUE: not enough args: chunksize]")); /*NOTREACHED*/ } db->chunk_size = OFF_T_ATOI(cmdargs->argv[a++]); db->chunk_size = am_floor(db->chunk_size, (off_t)DISK_BLOCK_KB); if(a >= cmdargs->argc) { error(_("error [chunker CONTINUE: not enough args: use]")); /*NOTREACHED*/ } db->use = OFF_T_ATOI(cmdargs->argv[a++]); if(a != cmdargs->argc) { error(_("error [chunker CONTINUE: too many args: %d != %d]"), cmdargs->argc, a); /*NOTREACHED*/ } if(strcmp(db->filename, arg_filename) == 0) { /* * Same disk, so use what room is left up to the * next chunk boundary or the amount we were given, * whichever is less. */ left_in_chunk = db->chunk_size - filesize; if(left_in_chunk > db->use) { db->split_size += db->use; db->use = (off_t)0; } else { db->split_size += left_in_chunk; db->use -= left_in_chunk; } if(left_in_chunk > (off_t)0) { /* * We still have space in this chunk. */ break; } } else { /* * Different disk, so use new file. */ db->filename = newstralloc(db->filename, arg_filename); } } else if(cmdargs->cmd == ABORT) { abort_pending = 1; errstr = newstralloc(errstr, cmdargs->argv[1]); putresult(ABORT_FINISHED, "%s\n", handle); rc = 0; goto common_exit; } else { if(cmdargs->argc >= 1) { q = quote_string(cmdargs->argv[0]); } else { q = stralloc(_("(no input?)")); } error(_("error [bad command after RQ-MORE-DISK: \"%s\"]"), q); /*NOTREACHED*/ } } /* * Time to use another file. */ /* * First, open the new chunk file, and give it a new header * that has no cont_filename pointer. */ g_snprintf(sequence, SIZEOF(sequence), "%d", db->filename_seq); new_filename = newvstralloc(new_filename, db->filename, ".", sequence, NULL); tmp_filename = newvstralloc(tmp_filename, new_filename, ".tmp", NULL); pc = strrchr(tmp_filename, '/'); g_assert(pc != NULL); /* Only a problem if db->filename has no /. */ *pc = '\0'; mkholdingdir(tmp_filename); *pc = '/'; newfd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600); if (newfd == -1) { int save_errno = errno; char *m; if(save_errno == ENOSPC) { putresult(NO_ROOM, "%s %lld\n", handle, (long long)(db->use+db->split_size-dumpsize)); db->use = (off_t)0; /* force RQ_MORE_DISK */ db->split_size = dumpsize; continue; } m = vstrallocf(_("creating chunk holding file \"%s\": %s"), tmp_filename, strerror(errno)); errstr = quote_string(m); amfree(m); aclose(db->fd); rc = 0; goto common_exit; } save_type = file.type; file.type = F_CONT_DUMPFILE; file.cont_filename[0] = '\0'; if(write_tapeheader(newfd, &file)) { int save_errno = errno; char *m; aclose(newfd); if(save_errno == ENOSPC) { putresult(NO_ROOM, "%s %lld\n", handle, (long long)(db->use+db->split_size-dumpsize)); db->use = (off_t)0; /* force RQ_MORE DISK */ db->split_size = dumpsize; continue; } m = vstrallocf(_("write_tapeheader file %s: %s"), tmp_filename, strerror(errno)); errstr = quote_string(m); amfree(m); rc = 0; goto common_exit; } /* * Now, update the header of the current file to point * to the next chunk, and then close it. */ if (lseek(db->fd, (off_t)0, SEEK_SET) < (off_t)0) { char *m = vstrallocf(_("lseek holding file %s: %s"), db->filename, strerror(errno)); errstr = quote_string(m); amfree(m); aclose(newfd); rc = 0; goto common_exit; } file.type = save_type; strncpy(file.cont_filename, new_filename, SIZEOF(file.cont_filename)); file.cont_filename[SIZEOF(file.cont_filename)-1] = '\0'; if(write_tapeheader(db->fd, &file)) { char * m = vstrallocf(_("write_tapeheader file \"%s\": %s"), db->filename, strerror(errno)); errstr = quote_string(m); amfree(m); aclose(newfd); unlink(tmp_filename); rc = 0; goto common_exit; } file.type = F_CONT_DUMPFILE; /* * Now shift the file descriptor. */ aclose(db->fd); db->fd = newfd; newfd = -1; /* * Update when we need to chunk again */ if(db->use <= (off_t)DISK_BLOCK_KB) { /* * Cheat and use one more block than allowed so we can make * some progress. */ db->split_size += (off_t)(2 * DISK_BLOCK_KB); db->use = (off_t)0; } else if(db->chunk_size > db->use) { db->split_size += db->use; db->use = (off_t)0; } else { db->split_size += db->chunk_size; db->use -= db->chunk_size; } amfree(tmp_filename); amfree(new_filename); dumpsize += (off_t)DISK_BLOCK_KB; filesize = (off_t)DISK_BLOCK_KB; headersize += DISK_BLOCK_KB; db->filename_seq++; } /* * Write out the buffer */ size_to_write = (size_t)(db->datain - db->dataout); written = full_write(db->fd, db->dataout, size_to_write); if (written > 0) { db->dataout += written; dumpbytes += (off_t)written; } dumpsize += (dumpbytes / (off_t)1024); filesize += (dumpbytes / (off_t)1024); dumpbytes %= 1024; if (written < size_to_write) { if (errno != ENOSPC) { char *m = vstrallocf(_("data write: %s"), strerror(errno)); errstr = quote_string(m); amfree(m); rc = 0; goto common_exit; } /* * NO-ROOM is informational only. Later, RQ_MORE_DISK will be * issued to use another holding disk. */ putresult(NO_ROOM, "%s %lld\n", handle, (long long)(db->use+db->split_size-dumpsize)); db->use = (off_t)0; /* force RQ_MORE_DISK */ db->split_size = dumpsize; goto common_exit; } if (db->datain == db->dataout) { /* * We flushed the whole buffer so reset to use it all. */ db->datain = db->dataout = db->buf; } common_exit: if (cmdargs) free_cmdargs(cmdargs); amfree(new_filename); /*@i@*/ amfree(tmp_filename); amfree(arg_filename); return rc; }