/* We call this when we can't find a tape to write data to. This could happen with the first (or only) part of a file, but it could also happen with an intermediate part of a split dump. dump_bytes is 0 if this is the first part of a dump. */ static void bail_no_volume( dump_info_t *dump_info, char *errmsg) { char *errstr; if (errmsg) errstr = quote_string(errmsg); else errstr = quote_string("no new tape"); if (dump_info->total_bytes > 0) { /* Second or later part of a split dump, so PARTIAL message. */ double dump_time = g_timeval_to_double(dump_info->total_time); guint64 dump_kbytes = dump_info->total_bytes / 1024; double dump_kbps = get_kbps(dump_kbytes, dump_time); putresult(PARTIAL, "%s INPUT-GOOD TAPE-ERROR " "\"[sec %f kb %ju kps %f]\" \"\" %s\n", dump_info->handle, dump_time, (uintmax_t)dump_kbytes, dump_kbps, errstr); put_partial_log(dump_info, dump_time, dump_kbytes, errstr); } else { char * qdiskname = quote_string(dump_info->diskname); putresult(FAILED, "%s INPUT-GOOD TAPE-ERROR \"\" %s\n", dump_info->handle, errstr); log_add(L_FAIL, "%s %s %s %d %s", dump_info->hostname, qdiskname, dump_info->timestamp, dump_info->level, errstr); amfree(qdiskname); } amfree(errstr); }
/* Figure out what to do after a part attempt. Returns TRUE if another attempt should proceed for this dump; FALSE if we are done. */ static gboolean finish_part_attempt(taper_state_t * taper_state, dump_info_t * dump_info, queue_result_flags queue_result, GTimeVal run_time, guint64 run_bytes) { double part_time = g_timeval_to_double(run_time); guint64 part_kbytes = run_bytes / 1024; double part_kbps = get_kbps((double)run_bytes / 1024.0, part_time); char * qdiskname = quote_string(dump_info->diskname); if (queue_result == QUEUE_SUCCESS) { dump_info->total_time = timesadd(run_time, dump_info->total_time); dump_info->total_bytes += run_bytes; log_add(L_PART, "%s %d %s %s %s %d/%d %d [sec %f kb %ju kps %f]", taper_state->device->volume_label, taper_state->device->file, dump_info->hostname, qdiskname, dump_info->timestamp, dump_info->current_part, taper_source_predict_parts(dump_info->source), dump_info->level, part_time, (uintmax_t)part_kbytes, part_kbps); putresult(PARTDONE, "%s %s %d %ju \"[sec %f kb %ju kps %f]\"\n", dump_info->handle, taper_state->device->volume_label, taper_state->device->file, (uintmax_t)part_kbytes, part_time, (uintmax_t)part_kbytes, part_kbps); taper_state->total_bytes += run_bytes; if (taper_source_get_end_of_data(dump_info->source)) { cmd_t result_cmd; logtype_t result_log; double dump_time = g_timeval_to_double(dump_info->total_time); guint64 dump_kbytes = dump_info->total_bytes / 1024; double dump_kbps = get_kbps((double)dump_info->total_bytes / 1024.0, dump_time); find_completion_tags(dump_info, &result_cmd, &result_log); g_object_unref(dump_info->source); dump_info->source = NULL; log_add(result_log, "%s %s %s %d %d [sec %f kb %ju kps %f]", dump_info->hostname, qdiskname, dump_info->timestamp, dump_info->current_part, dump_info->level, dump_time, (uintmax_t)dump_kbytes, dump_kbps); putresult(result_cmd, "%s INPUT-GOOD TAPE-GOOD " "\"[sec %f kb %ju kps %f]\" \"\" \"\"\n", dump_info->handle, dump_time, (uintmax_t)dump_kbytes, dump_kbps); amfree(qdiskname); return FALSE; } else if (taper_source_get_end_of_part(dump_info->source)) { taper_source_start_new_part(dump_info->source); dump_info->current_part ++; amfree(qdiskname); return TRUE; } /* If we didn't read EOF or EOP, then an error occured. But we read QUEUE_SUCCESS, so something is b0rked. */ g_assert_not_reached(); } else { char * volume_label = strdup(taper_state->device->volume_label); int file_number = taper_state->device->file; double dump_time, dump_kbps; guint64 dump_kbytes; char *producer_errstr = quote_string( taper_source_get_errmsg(dump_info->source)); char *consumer_errstr = quote_string( device_error(taper_state->device)); log_add(L_PARTPARTIAL, "%s %d %s %s %s %d/%d %d [sec %f kb %ju kps %f] %s", volume_label, file_number, dump_info->hostname, qdiskname, dump_info->timestamp, dump_info->current_part, taper_source_predict_parts(dump_info->source), dump_info->level, part_time, (uintmax_t)part_kbytes, part_kbps, consumer_errstr); log_add(L_INFO, "tape %s kb %lld fm %d [OK]\n", volume_label, (long long)((taper_state->total_bytes+(off_t)1023) / (off_t)1024), taper_state->device->file); /* A problem occured. */ if (queue_result & QUEUE_CONSUMER_ERROR) { /* Make a note if this was EOM (we treat EOM the same as any other error, * so it's just for debugging purposes */ if (taper_state->device->is_eof) g_debug("device %s ran out of space", taper_state->device->device_name); /* Close the device. */ device_finish(taper_state->device); g_object_unref(taper_state->device); taper_state->device = NULL; } amfree(volume_label); if ((queue_result & QUEUE_CONSUMER_ERROR) && (!(queue_result & QUEUE_PRODUCER_ERROR)) && taper_source_seek_to_part_start(dump_info->source)) { /* It is recoverable. */ log_add(L_INFO, "Will request retry of failed split part."); if (find_and_label_new_tape(taper_state, dump_info)) { /* dump_info->current_part is unchanged. */ amfree(qdiskname); return TRUE; } } dump_time = g_timeval_to_double(dump_info->total_time); dump_kbytes = dump_info->total_bytes / 1024; dump_kbps = get_kbps((double)dump_info->total_bytes / 1024.0, dump_time); putresult(PARTIAL, "%s INPUT-%s TAPE-%s " "\"[sec %f kb %ju kps %f]\" %s %s\n", dump_info->handle, (queue_result & QUEUE_PRODUCER_ERROR) ? "ERROR" : "GOOD", (queue_result & QUEUE_CONSUMER_ERROR) ? "ERROR" : "GOOD", dump_time, (uintmax_t)dump_kbytes, dump_kbps, producer_errstr, consumer_errstr); if (queue_result & QUEUE_CONSUMER_ERROR) { put_partial_log(dump_info, dump_time, dump_kbytes, consumer_errstr); } else { put_partial_log(dump_info, dump_time, dump_kbytes, producer_errstr); } amfree(producer_errstr); amfree(consumer_errstr); } amfree(qdiskname); return FALSE; }
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 */ }