+ break;
+
+ case PARTIAL: /* PARTIAL <handle> INPUT-* TAPE-* <stat mess> <input err mesg> <tape err mesg>*/
+ case DONE: /* DONE <handle> INPUT-GOOD TAPE-GOOD <stat mess> <input err mesg> <tape err mesg> */
+ if(result_argc != 7) {
+ error(_("error: [taper PARTIAL result_argc != 7: %d"), result_argc);
+ /*NOTREACHED*/
+ }
+
+ dp = serial2disk(result_argv[1]);
+ taper = sched(dp)->taper;
+ assert(dp == taper->disk);
+ if (!taper->dumper)
+ free_serial(result_argv[1]);
+
+ qname = quote_string(dp->name);
+ g_printf(_("driver: finished-cmd time %s taper wrote %s:%s\n"),
+ walltime_str(curclock()), dp->host->hostname, qname);
+ fflush(stdout);
+
+ if (strcmp(result_argv[2], "INPUT-ERROR") == 0) {
+ taper->input_error = newstralloc(taper->input_error, result_argv[5]);
+ } else if (strcmp(result_argv[2], "INPUT-GOOD") != 0) {
+ taper->tape_error = newstralloc(taper->tape_error,
+ _("Taper protocol error"));
+ taper->result = FAILED;
+ log_add(L_FAIL, _("%s %s %s %d [%s]"),
+ dp->host->hostname, qname, sched(dp)->datestamp,
+ sched(dp)->level, taper->tape_error);
+ amfree(qname);
+ break;
+ }
+ if (strcmp(result_argv[3], "TAPE-ERROR") == 0) {
+ taper->state &= ~TAPER_STATE_TAPE_STARTED;
+ taper->tape_error = newstralloc(taper->tape_error, result_argv[6]);
+ } else if (strcmp(result_argv[3], "TAPE-GOOD") != 0) {
+ taper->state &= ~TAPER_STATE_TAPE_STARTED;
+ taper->tape_error = newstralloc(taper->tape_error,
+ _("Taper protocol error"));
+ taper->result = FAILED;
+ log_add(L_FAIL, _("%s %s %s %d [%s]"),
+ dp->host->hostname, qname, sched(dp)->datestamp,
+ sched(dp)->level, taper->tape_error);
+ amfree(qname);
+ break;
+ }
+
+ s = strstr(result_argv[4], " kb ");
+ if (s) {
+ s += 4;
+ sched(dp)->dumpsize = atol(s);
+ }
+
+ taper->result = cmd;
+ amfree(qname);
+
+ break;
+
+ case PARTDONE: /* PARTDONE <handle> <label> <fileno> <kbytes> <stat> */
+ dp = serial2disk(result_argv[1]);
+ taper = sched(dp)->taper;
+ assert(dp == taper->disk);
+ if (result_argc != 6) {
+ error(_("error [taper PARTDONE result_argc != 6: %d]"),
+ result_argc);
+ /*NOTREACHED*/
+ }
+ if (!taper->first_label) {
+ amfree(taper->first_label);
+ taper->first_label = stralloc(result_argv[2]);
+ taper->first_fileno = OFF_T_ATOI(result_argv[3]);
+ }
+ taper->written += OFF_T_ATOI(result_argv[4]);
+ if (taper->written > sched(taper->disk)->act_size)
+ sched(taper->disk)->act_size = taper->written;
+
+ partsize = 0;
+ s = strstr(result_argv[5], " kb ");
+ if (s) {
+ s += 4;
+ partsize = atol(s);
+ }
+ taper->left -= partsize;
+
+ break;
+
+ case REQUEST_NEW_TAPE: /* REQUEST-NEW-TAPE <handle> */
+ if (result_argc != 2) {
+ error(_("error [taper REQUEST_NEW_TAPE result_argc != 2: %d]"),
+ result_argc);
+ /*NOTREACHED*/
+ }
+
+ dp = serial2disk(result_argv[1]);
+ taper = sched(dp)->taper;
+ taper->state &= ~TAPER_STATE_TAPE_STARTED;
+ taper->state |= TAPER_STATE_TAPE_REQUESTED;
+
+ start_some_dumps(&runq);
+ startaflush();
+ break;
+
+ case NEW_TAPE: /* NEW-TAPE <handle> <label> */
+ if (result_argc != 3) {
+ error(_("error [taper NEW_TAPE result_argc != 3: %d]"),
+ result_argc);
+ /*NOTREACHED*/
+ }
+
+ nb_sent_new_tape--;
+ taper_nb_scan_volume--;
+ dp = serial2disk(result_argv[1]);
+ taper = sched(dp)->taper;
+ /* Update our tape counter and reset taper->left */
+ current_tape++;
+ taper->left = tape_length;
+ taper->state &= ~TAPER_STATE_WAIT_NEW_TAPE;
+ taper->state |= TAPER_STATE_TAPE_STARTED;
+ last_started_taper = NULL;
+
+ /* start a new worker */
+ for (i = 0; i < conf_taper_parallel_write ; i++) {
+ taper1 = &tapetable[i];
+ if (need_degraded == 0 &&
+ taper1->state == TAPER_STATE_DEFAULT) {
+ taper1->state = TAPER_STATE_INIT;
+ if (taper_nb_wait_reply == 0) {
+ taper_ev_read = event_register(taper_fd, EV_READFD,
+ handle_taper_result, NULL);
+ }
+ taper_nb_wait_reply++;
+ taper_nb_scan_volume++;
+ taper_cmd(START_TAPER, NULL, taper1->name, 0,
+ driver_timestamp);
+ break;
+ }
+ }
+ break;
+
+ case NO_NEW_TAPE: /* NO-NEW-TAPE <handle> */
+ if (result_argc != 2) {
+ error(_("error [taper NO_NEW_TAPE result_argc != 2: %d]"),
+ result_argc);
+ /*NOTREACHED*/
+ }
+ nb_sent_new_tape--;
+ taper_nb_scan_volume--;
+ dp = serial2disk(result_argv[1]);
+ taper = sched(dp)->taper;
+ taper->state |= TAPER_STATE_DONE;
+ last_started_taper = NULL;
+ start_degraded_mode(&runq);
+ break;
+
+ case DUMPER_STATUS: /* DUMPER-STATUS <handle> */
+ if (result_argc != 2) {
+ error(_("error [taper DUMPER_STATUS result_argc != 2: %d]"),
+ result_argc);
+ /*NOTREACHED*/
+ }
+ dp = serial2disk(result_argv[1]);
+ taper = sched(dp)->taper;
+ if (taper->dumper->result == LAST_TOK) {
+ taper->sendresult = 1;
+ } else {
+ if( taper->dumper->result == DONE) {
+ taper_cmd(DONE, dp, NULL, 0, NULL);
+ } else {
+ taper_cmd(FAILED, dp, NULL, 0, NULL);
+ }
+ }
+ break;
+
+ case TAPE_ERROR: /* TAPE-ERROR <name> <err mess> */
+ taper_started = 1;
+ if (strcmp(result_argv[1], "SETUP") == 0) {
+ taper_nb_wait_reply = 0;
+ taper_nb_scan_volume = 0;
+ } else {
+ taper = taper_from_name(result_argv[1]);
+ taper->state = TAPER_STATE_DONE;
+ fflush(stdout);
+ q = quote_string(result_argv[2]);
+ log_add(L_WARNING, _("Taper error: %s"), q);
+ amfree(q);
+ if (taper) {
+ taper->tape_error = newstralloc(taper->tape_error,
+ result_argv[2]);
+ }
+
+ taper_nb_wait_reply--;
+ taper_nb_scan_volume--;
+ }
+ if (taper_nb_wait_reply == 0) {
+ event_release(taper_ev_read);
+ taper_ev_read = NULL;
+ }
+ need_degraded = 1;
+ if (schedule_done && !degraded_mode) {
+ start_degraded_mode(&runq);
+ }
+ start_some_dumps(&runq);
+ break;
+
+ case PORT: /* PORT <name> <handle> <port> <dataport_list> */
+ dp = serial2disk(result_argv[2]);
+ taper = sched(dp)->taper;
+ dumper = sched(dp)->dumper;
+ dumper->output_port = atoi(result_argv[3]);
+ amfree(dp->dataport_list);
+ dp->dataport_list = stralloc(result_argv[4]);
+
+ amfree(taper->input_error);
+ amfree(taper->tape_error);
+ amfree(taper->first_label);
+ taper->written = 0;
+ taper->state |= TAPER_STATE_DUMP_TO_TAPE;
+
+ if (dp->host->pre_script == 0) {
+ for (dp1=dp->host->disks; dp1 != NULL; dp1 = dp1->hostnext) {
+ run_server_scripts(EXECUTE_ON_PRE_HOST_BACKUP,
+ get_config_name(), dp1, -1);
+ }
+ dp->host->pre_script = 1;
+ }
+ run_server_scripts(EXECUTE_ON_PRE_DLE_BACKUP,
+ get_config_name(), dp,
+ sched(dp)->level);
+ /* tell the dumper to dump to a port */
+ dumper_cmd(dumper, PORT_DUMP, dp, NULL);
+ dp->host->start_t = time(NULL) + 15;
+ amfree(dp->dataport_list);
+
+ taper->state |= TAPER_STATE_DUMP_TO_TAPE;
+
+ dumper->ev_read = event_register(dumper->fd, EV_READFD,
+ handle_dumper_result, dumper);
+ break;
+
+ case BOGUS:
+ log_add(L_WARNING, _("Taper protocol error"));
+ /*
+ * Since we received a taper error, we can't send anything more
+ * to the taper. Go into degraded mode to try to get everthing
+ * onto disk. Later, these dumps can be flushed to a new tape.
+ * The tape queue is zapped so that it appears empty in future
+ * checks. If there are dumps waiting for diskspace to be freed,
+ * cancel one.
+ */
+ if(!nodump) {
+ log_add(L_WARNING,
+ _("going into degraded mode because of taper component error."));
+ }
+
+ for (taper = tapetable;
+ taper < tapetable + conf_taper_parallel_write;
+ taper++) {
+ if (taper && taper->disk && taper->result != LAST_TOK) {
+ taper->tape_error = newstralloc(taper->tape_error,"BOGUS");
+ taper->result = cmd;
+ if (taper->dumper) {
+ if (taper->dumper->result != LAST_TOK) {
+ // Dumper already returned it's result
+ dumper_taper_result(taper->disk);
+ }
+ } else {
+ file_taper_result(taper->disk);
+ }
+ }
+
+ }
+ taper = NULL;
+
+ if(taper_ev_read != NULL) {
+ event_release(taper_ev_read);
+ taper_ev_read = NULL;
+ taper_nb_wait_reply = 0;
+ }
+ start_degraded_mode(&runq);
+ tapeq.head = tapeq.tail = NULL;
+ aclose(taper_fd);
+
+ break;
+
+ default:
+ error(_("driver received unexpected token (%s) from taper"),
+ cmdstr[cmd]);
+ /*NOTREACHED*/