Example #1
0
/* 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);
}
Example #2
0
/* 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;
}
Example #3
0
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 */
}