2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998, 2000 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
26 /* $Id: taper.c 6512 2007-05-24 17:00:24Z ian $
28 * moves files from holding disk to tape, or from a socket to tape
31 /* FIXME: This file needs to use gettext. */
41 #include "server_util.h"
44 #include "taperscan.h"
45 #include "taper-source.h"
46 #include "timestamp.h"
50 /* FIXME: This should not be here. */
51 #define CONNECT_TIMEOUT (2*60)
53 /* Use this instead of global variables, so that we are reentrant. */
56 char * driver_start_time;
58 char * next_tape_label;
59 char * next_tape_device;
60 taper_scan_tracker_t * taper_scan_tracker;
76 static gboolean label_new_tape(taper_state_t * state, dump_info_t * dump_info);
78 static void init_taper_state(taper_state_t* state) {
80 state->driver_start_time = NULL;
81 state->taper_scan_tracker = taper_scan_tracker_new();
84 static void cleanup(taper_state_t * state) {
85 amfree(state->driver_start_time);
86 amfree(state->next_tape_label);
87 amfree(state->next_tape_device);
88 taper_scan_tracker_free(state->taper_scan_tracker);
89 if (state->device != NULL) {
90 g_object_unref(state->device);
95 static void free_dump_info(dump_info_t * info) {
97 amfree(info->hostname);
98 amfree(info->diskname);
99 amfree(info->timestamp);
100 amfree(info->id_string);
101 if (info->source != NULL) {
102 g_object_unref(info->source);
107 /* Validate that a command has the proper number of arguments, and
108 print a meaningful error message if not. It returns only if the
109 check is successful. */
110 static void validate_args(cmd_t cmd, struct cmdargs * args,
114 for (i = 0; argnames[i] != NULL; i ++) {
115 if (i > args->argc) {
116 error("error [taper %s: not enough args: %s]",
117 cmdstr[cmd], argnames[i]);
120 if (i < args->argc) {
121 error("error [taper %s: Too many args: Got %d, expected %d.]",
122 cmdstr[cmd], args->argc, i);
126 /* Open a socket to the dumper. Returns TRUE if everything is happy, FALSE
128 static gboolean open_read_socket(dump_info_t * info, char * split_diskbuffer,
129 guint64 splitsize, guint64 fallback_splitsize) {
134 struct addrinfo *res;
136 if ((result = resolve_hostname("localhost", 0, &res, NULL) != 0)) {
139 int save_errno = errno;
140 char *qdiskname = quote_string(info->diskname);
142 m = vstralloc("[localhost resolve failure: ",
143 strerror(save_errno),
147 putresult(TAPE_ERROR, "%s %s\n", info->handle, q);
148 log_add(L_FAIL, "%s %s %s %d %s",
149 info->hostname, qdiskname, info->timestamp,
157 socket = stream_server(res->ai_family, &port, 0, STREAM_BUFSIZE, 0);
163 int save_errno = errno;
164 char *qdiskname = quote_string(info->diskname);
166 m = vstralloc("[port create failure: ",
167 strerror(save_errno),
171 putresult(TAPE_ERROR, "%s %s\n", info->handle, q);
172 log_add(L_FAIL, "%s %s %s %d %s",
173 info->hostname, qdiskname, info->timestamp,
181 putresult(PORT, "%d\n", port);
183 fd = stream_accept(socket, CONNECT_TIMEOUT, 0, STREAM_BUFSIZE);
187 int save_errno = errno;
188 char *qdiskname = quote_string(info->diskname);
189 m = vstralloc("[port connect failure: ",
190 strerror(save_errno),
194 putresult(TAPE_ERROR, "%s %s\n", info->handle, q);
195 log_add(L_FAIL, "%s %s %s %d %s",
196 info->hostname, qdiskname, info->timestamp,
207 info->source = taper_source_new(info->handle, PORT_WRITE, NULL, fd,
208 split_diskbuffer, splitsize,
210 /* FIXME: This should be handled properly. */
211 g_assert(info->source != NULL);
216 ConsumerFunctor next_consumer;
217 gpointer next_consumer_data;
218 guint64 bytes_written;
219 } CountingConsumerData;
221 /* A ConsumerFunctor. This consumer just passes its arguments on to a
222 second consumer, but counts the number of bytes successfully
224 static int counting_consumer(gpointer user_data, queue_buffer_t * buffer) {
226 CountingConsumerData * data = user_data;
228 result = data->next_consumer(data->next_consumer_data, buffer);
231 data->bytes_written += result;
237 static gboolean boolean_prolong(void * data) {
239 return TRUE; /* Do not interrupt. */
241 return *(gboolean*)data;
245 /* A (simpler) wrapper around taper_scan(). */
246 static gboolean simple_taper_scan(taper_state_t * state,
247 gboolean* prolong, char ** error_message) {
248 char ** label = &(state->next_tape_label);
249 char ** device = &(state->next_tape_device);
250 char *timestamp = NULL;
252 result = taper_scan(NULL, label, ×tamp, device,
253 state->taper_scan_tracker,
254 CHAR_taperscan_output_callback,
255 error_message, boolean_prolong, prolong);
256 if (prolong != NULL && !*prolong) {
257 g_fprintf(stderr, _("Cancelled taper scan.\n"));
259 } else if (result < 0) {
260 g_fprintf(stderr, _("Failed taper scan: %s\n"), (*error_message)?(*error_message):_("(no error message)"));
264 g_fprintf(stderr, _("taper: using label `%s' date `%s'\n"), *label,
265 state->driver_start_time);
268 _("Will write new label `%s' to new (previously non-amanda) tape"),
278 taper_state_t * state;
279 gboolean prolong; /* scan stops when this is FALSE. */
281 } tape_search_request_t;
283 /* A GThread that runs taper_scan. */
284 static gpointer tape_search_thread(gpointer data) {
285 tape_search_request_t * request = data;
287 if (request->state->next_tape_label != NULL &&
288 request->state->next_tape_device != NULL) {
289 return GINT_TO_POINTER(TRUE);
291 amfree(request->state->next_tape_label);
292 amfree(request->state->next_tape_device);
295 return GINT_TO_POINTER
296 (simple_taper_scan(request->state,
298 &(request->errmsg)));
301 static void log_taper_scan_errmsg(char * errmsg) {
310 log_add(L_WARNING,"%s", c1);
316 log_add(L_WARNING,"%s", c1);
320 /* If handle is NULL, then this function assumes that we are in startup mode.
321 * In that case it will wait for a command from driver. If handle is not NULL,
322 * this this function will ask for permission with REQUEST-NEW-TAPE. */
323 static gboolean find_new_tape(taper_state_t * state, dump_info_t * dump) {
324 GThread * tape_search = NULL;
325 tape_search_request_t search_request;
326 gboolean use_threads;
330 if (state->device != NULL) {
334 /* We save the value here in case it changes while we're running. */
335 use_threads = g_thread_supported();
337 search_request.state = state;
338 search_request.prolong = TRUE;
339 search_request.errmsg = NULL;
341 tape_search = g_thread_create(tape_search_thread,
342 &search_request, TRUE, NULL);
345 putresult(REQUEST_NEW_TAPE, "%s\n", dump->handle);
349 g_fprintf(stderr, "taper: Got odd message from driver, expected NEW-TAPE or NO-NEW-TAPE.\n");
352 gboolean search_result;
354 search_result = GPOINTER_TO_INT(g_thread_join(tape_search));
357 GPOINTER_TO_INT(tape_search_thread(&search_request));
360 /* We don't say NEW_TAPE until we actually write the label. */
361 amfree(search_request.errmsg);
364 putresult(NO_NEW_TAPE, "%s\n", dump->handle);
365 log_taper_scan_errmsg(search_request.errmsg);
370 search_request.prolong = FALSE;
372 g_thread_join(tape_search);
378 /* Returns TRUE if the old volume details are not the same as the new ones. */
379 static gboolean check_volume_changed(Device * device,
380 char * old_label, char * old_timestamp) {
381 /* If one is NULL and the other is not, something changed. */
382 if ((old_label == NULL) != (device->volume_label == NULL))
384 if ((old_timestamp == NULL) != (device->volume_time == NULL))
386 /* If details were not NULL and is now different, we have a difference. */
387 if (old_label != NULL && strcmp(old_label, device->volume_label) != 0)
389 if (old_timestamp != NULL &&
390 strcmp(old_timestamp, device->volume_time) != 0)
393 /* If we got here, everything is cool. */
399 taper_state_t *state)
401 char *tapelist_name = NULL;
402 char *tapelist_name_old = NULL;
404 tapelist_name = config_dir_relative(getconf_str(CNF_TAPELIST));
405 if (state->cur_tape == 0) {
406 tapelist_name_old = stralloc2(tapelist_name, ".yesterday");
408 char cur_str[NUM_STR_SIZE];
409 g_snprintf(cur_str, SIZEOF(cur_str), "%d", state->cur_tape - 1);
410 tapelist_name_old = vstralloc(tapelist_name,
411 ".today.", cur_str, NULL);
414 if (write_tapelist(tapelist_name_old)) {
415 error("could not write tapelist: %s", strerror(errno));
418 amfree(tapelist_name_old);
420 remove_tapelabel(state->device->volume_label);
421 add_tapelabel(state->driver_start_time,
422 state->device->volume_label);
423 if (write_tapelist(tapelist_name)) {
424 error("could not write tapelist: %s", strerror(errno));
427 amfree(tapelist_name);
430 /* Find and label a new tape, if one is not already open. Returns TRUE
431 * if a tape could be written. */
432 static gboolean find_and_label_new_tape(taper_state_t * state,
433 dump_info_t * dump_info) {
434 if (state->device != NULL) {
438 if (!find_new_tape(state, dump_info)) {
442 return label_new_tape(state, dump_info);
445 static gboolean label_new_tape(taper_state_t * state, dump_info_t * dump_info) {
446 char *old_volume_name = NULL;
447 char *old_volume_time = NULL;
448 tape_search_request_t request;
449 gboolean search_result;
450 ReadLabelStatusFlags status;
452 /* If we got here, it means that we have found a tape to label and
453 * have gotten permission from the driver to write it. But we
454 * still can say NO-NEW-TAPE if a problem shows up, and must still
455 * say NEW-TAPE if one doesn't. */
457 state->device = device_open(state->next_tape_device);
458 amfree(state->next_tape_device);
459 if (state->device == NULL)
462 device_set_startup_properties_from_config(state->device);
464 /* if we have an error, and are sure it isn't just an unlabeled volume,
465 * then skip this volume */
466 status = device_read_label(state->device);
467 if ((status & ~READ_LABEL_STATUS_VOLUME_UNLABELED) &&
468 !(status & READ_LABEL_STATUS_VOLUME_UNLABELED))
471 old_volume_name = g_strdup(state->device->volume_label);
472 old_volume_time = g_strdup(state->device->volume_time);
474 if (!device_start(state->device, ACCESS_WRITE, state->next_tape_label,
475 state->driver_start_time)) {
478 /* Something broke, see if we can tell if the volume was erased or
480 g_fprintf(stderr, "taper: Error writing label %s to device %s.\n",
481 state->next_tape_label, state->device->device_name);
483 if (!device_finish(state->device))
484 goto request_new_volume;
486 /* This time, if we can't read the label, assume we've overwritten
487 * the volume or otherwise corrupted it */
488 status = device_read_label(state->device);
489 if ((status & ~READ_LABEL_STATUS_VOLUME_UNLABELED) &&
490 !(status & READ_LABEL_STATUS_VOLUME_UNLABELED))
491 goto request_new_volume;
493 tape_used = check_volume_changed(state->device, old_volume_name,
496 goto request_new_volume;
502 amfree(old_volume_name);
503 amfree(old_volume_time);
504 amfree(state->next_tape_label);
506 update_tapelist(state);
509 log_add(L_START, "datestamp %s label %s tape %d",
510 state->driver_start_time, state->device->volume_label,
512 putresult(NEW_TAPE, "%s %s\n", dump_info->handle,
513 state->device->volume_label);
518 /* Tell the driver we overwrote this volume, even if it was empty, and request
521 g_object_unref(state->device);
522 state->device = NULL;
525 putresult(NEW_TAPE, "%s %s\n", dump_info->handle,
526 state->next_tape_label);
527 if (old_volume_name) {
528 log_add(L_WARNING, "Problem writing label '%s' to volume %s, "
529 "volume may be erased.\n",
530 state->next_tape_label, old_volume_name);
532 log_add(L_WARNING, "Problem writing label '%s' to new volume, "
533 "volume may be erased.\n", state->next_tape_label);
536 amfree(state->next_tape_label);
537 amfree(old_volume_name);
538 amfree(old_volume_time);
540 return find_and_label_new_tape(state, dump_info);
543 /* grab a new volume without talking to the driver again -- we do this if we're
544 * confident we didn't overwrite the last tape we got. */
546 g_object_unref(state->device);
547 state->device = NULL;
550 if (old_volume_name) {
551 log_add(L_WARNING, "Problem writing label '%s' to volume '%s', "
552 "old volume data intact\n",
553 state->next_tape_label, old_volume_name);
555 log_add(L_WARNING, "Problem writing label '%s' to new volume, "
556 "old volume data intact\n", state->next_tape_label);
559 amfree(state->next_tape_label);
560 amfree(old_volume_name);
561 amfree(old_volume_time);
563 request.state = state;
564 request.prolong = TRUE;
565 request.errmsg = NULL;
566 search_result = GPOINTER_TO_INT(tape_search_thread(&request));
568 amfree(request.errmsg);
569 return label_new_tape(state, dump_info);
571 /* Problem finding a new tape! */
572 log_taper_scan_errmsg(request.errmsg);
573 putresult(NO_NEW_TAPE, "%s\n", dump_info->handle);
577 /* Find out if the dump is PARTIAL or not, and set the proper driver
578 and logfile tags for the dump. */
579 static void find_completion_tags(dump_info_t * dump_info, /* IN */
580 cmd_t * result_cmd, /* OUT */
581 logtype_t * result_log /* OUT */) {
582 if (taper_source_is_partial(dump_info->source)) {
583 *result_cmd = PARTIAL;
584 *result_log = L_PARTIAL;
587 *result_log = L_DONE;
590 memcpy(intp, &buf[1], SIZEOF(int));
594 /* Put an L_PARTIAL message to the logfile. */
595 static void put_partial_log(dump_info_t * dump_info, double dump_time,
596 guint64 dump_kbytes) {
597 char * qdiskname = quote_string(dump_info->diskname);
599 log_add(L_PARTIAL, "%s %s %s %d %d [sec %f kb %ju kps %f] \"\"",
600 dump_info->hostname, qdiskname, dump_info->timestamp,
601 dump_info->current_part, dump_info->level, dump_time,
602 (uintmax_t)dump_kbytes, dump_kbytes / dump_time);
606 /* Figure out what to do after a part attempt. Returns TRUE if another
607 attempt should proceed for this dump; FALSE if we are done. */
608 static gboolean finish_part_attempt(taper_state_t * taper_state,
609 dump_info_t * dump_info,
610 queue_result_flags queue_result,
611 GTimeVal run_time, guint64 run_bytes) {
612 double part_time = g_timeval_to_double(run_time);
613 guint64 part_kbytes = run_bytes / 1024;
614 double part_kbps = run_bytes / (1024 * part_time);
616 char * qdiskname = quote_string(dump_info->diskname);
618 if (queue_result == QUEUE_SUCCESS) {
619 dump_info->total_time = timesadd(run_time, dump_info->total_time);
620 dump_info->total_bytes += run_bytes;
622 log_add(L_PART, "%s %d %s %s %s %d/%d %d [sec %f kb %ju kps %f]",
623 taper_state->device->volume_label,
624 taper_state->device->file, dump_info->hostname, qdiskname,
625 dump_info->timestamp, dump_info->current_part,
626 taper_source_predict_parts(dump_info->source),
627 dump_info->level, part_time, (uintmax_t)part_kbytes, part_kbps);
628 putresult(PARTDONE, "%s %s %d %ju \"[sec %f kb %ju kps %f]\"\n",
629 dump_info->handle, taper_state->device->volume_label,
630 taper_state->device->file, (uintmax_t)part_kbytes, part_time,
631 (uintmax_t)part_kbytes, part_kbps);
633 if (taper_source_get_end_of_data(dump_info->source)) {
635 logtype_t result_log;
636 double dump_time = g_timeval_to_double(dump_info->total_time);
637 guint64 dump_kbytes = dump_info->total_bytes / 1024;
638 double dump_kbps = dump_info->total_bytes / (1024 * dump_time);
640 find_completion_tags(dump_info, &result_cmd, &result_log);
642 g_object_unref(dump_info->source);
643 dump_info->source = NULL;
645 log_add(result_log, "%s %s %s %d %d [sec %f kb %ju kps %f]",
646 dump_info->hostname, qdiskname, dump_info->timestamp,
647 dump_info->current_part, dump_info->level, dump_time,
648 (uintmax_t)dump_kbytes, dump_kbps);
649 putresult(result_cmd, "%s INPUT-GOOD TAPE-GOOD "
650 "\"[sec %f kb %ju kps %f]\" \"\" \"\"\n",
651 dump_info->handle, dump_time, (uintmax_t)dump_kbytes,
656 } else if (taper_source_get_end_of_part(dump_info->source)) {
657 taper_source_start_new_part(dump_info->source);
658 dump_info->current_part ++;
662 /* If we didn't read EOF or EOP, then an error
663 occured. But we read QUEUE_SUCCESS, so something is
665 g_assert_not_reached();
667 char * volume_label = strdup(taper_state->device->volume_label);
668 int file_number = taper_state->device->file;
669 double dump_time, dump_kbps;
672 /* A problem occured. */
673 if (queue_result & QUEUE_CONSUMER_ERROR) {
674 /* Close the device. */
675 device_finish(taper_state->device);
676 g_object_unref(taper_state->device);
677 taper_state->device = NULL;
680 log_add(L_PARTPARTIAL,
681 "%s %d %s %s %s %d/%d %d [sec %f kb %ju kps %f] \"\"",
682 volume_label, file_number, dump_info->hostname, qdiskname,
683 dump_info->timestamp, dump_info->current_part,
684 taper_source_predict_parts(dump_info->source),
685 dump_info->level, part_time, (uintmax_t)part_kbytes, part_kbps);
686 amfree(volume_label);
688 if ((queue_result & QUEUE_CONSUMER_ERROR) &&
689 (!(queue_result & QUEUE_PRODUCER_ERROR)) &&
690 taper_source_seek_to_part_start(dump_info->source)) {
691 /* It is recoverable. */
692 log_add(L_INFO, "Will request retry of failed split part.");
693 if (find_and_label_new_tape(taper_state, dump_info)) {
694 /* dump_info->current_part is unchanged. */
700 dump_info->total_time = timesadd(run_time, dump_info->total_time);
701 dump_info->total_bytes += run_bytes;
702 dump_time = g_timeval_to_double(dump_info->total_time);
703 dump_kbytes = dump_info->total_bytes / 1024;
704 dump_kbps = dump_info->total_bytes / (1024 * dump_time);
707 "%s INPUT-%s TAPE-%s "
708 "\"[sec %f kb %ju kps %f]\" \"\" \"\"\n",
710 (queue_result & QUEUE_PRODUCER_ERROR) ? "ERROR" : "GOOD",
711 (queue_result & QUEUE_CONSUMER_ERROR) ? "ERROR" : "GOOD",
712 dump_time, (uintmax_t)dump_kbytes, dump_kbps);
713 put_partial_log(dump_info, dump_time, dump_kbytes);
720 /* Generate the actual header structure to write to tape. This means dropping
721 * bits related to the holding disk, and adding bits for split dumps. */
722 static dumpfile_t * munge_headers(dump_info_t * dump_info) {
726 rval = taper_source_get_first_header(dump_info->source);
732 rval->cont_filename[0] = '\0';
734 expected_splits = taper_source_predict_parts(dump_info->source);
736 if (expected_splits != 1) {
737 rval->type = F_SPLIT_DUMPFILE;
738 rval->partnum = dump_info->current_part;
739 rval->totalparts = expected_splits;
745 /* We call this when we can't find a tape to write data to. This could
746 happen with the first (or only) part of a file, but it could also
747 happen with an intermediate part of a split dump. dump_bytes
748 is 0 if this is the first part of a dump. */
749 static void bail_no_volume(dump_info_t * dump_info) {
750 if (dump_info->total_bytes > 0) {
751 /* Second or later part of a split dump, so PARTIAL message. */
752 double dump_time = g_timeval_to_double(dump_info->total_time);
753 guint64 dump_kbytes = dump_info->total_bytes / 1024;
754 double dump_kbps = dump_kbytes / dump_time;
756 "%s INPUT-GOOD TAPE-ERROR "
757 "\"[sec %f kb %ju kps %f]\" \"\" \"no new tape\"\n",
759 dump_time, (uintmax_t)dump_kbytes, dump_kbps);
760 put_partial_log(dump_info, dump_time, dump_kbytes);
762 char * qdiskname = quote_string(dump_info->diskname);
764 "%s INPUT-GOOD TAPE-ERROR \"\" \"No new tape.\"\n",
766 log_add(L_FAIL, "%s %s %s %d \"No new tape.\"",
767 dump_info->hostname, qdiskname, dump_info->timestamp,
773 /* Link up the TaperSource with the Device, including retries etc. */
774 static void run_device_output(taper_state_t * taper_state,
775 dump_info_t * dump_info) {
778 dump_info->current_part = 1;
779 dump_info->total_time.tv_sec = 0;
780 dump_info->total_time.tv_usec = 0;
781 dump_info->total_bytes = 0;
784 GTimeVal start_time, end_time, run_time;
785 StreamingRequirement streaming_mode;
786 queue_result_flags queue_result;
787 CountingConsumerData consumer_data;
788 dumpfile_t *this_header;
791 this_header = munge_headers(dump_info);
792 if (this_header == NULL) {
793 char * qdiskname = quote_string(dump_info->diskname);
795 "%s INPUT-ERROR TAPE-GOOD \"Failed reading dump header.\" \"\"\n",
797 log_add(L_FAIL, "%s %s %s %d \"Failed reading dump header.\"",
798 dump_info->hostname, qdiskname, dump_info->timestamp,
804 if (!find_and_label_new_tape(taper_state, dump_info)) {
805 bail_no_volume(dump_info);
810 if (!device_start_file(taper_state->device, this_header)) {
811 bail_no_volume(dump_info);
817 bzero(&val, sizeof(val));
818 if (!device_property_get(taper_state->device, PROPERTY_STREAMING, &val)
819 || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
820 g_fprintf(stderr, "taper: Couldn't get streaming type!\n");
821 streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
823 streaming_mode = g_value_get_enum(&val);
826 file_number = taper_state->device->file;
828 consumer_data.next_consumer = device_write_consumer;
829 consumer_data.next_consumer_data = taper_state->device;
830 consumer_data.bytes_written = 0;
832 g_get_current_time(&start_time);
834 if (getconf_seen(CNF_DEVICE_OUTPUT_BUFFER_SIZE)) {
835 max_memory = getconf_size(CNF_DEVICE_OUTPUT_BUFFER_SIZE);
836 if (getconf_seen(CNF_TAPEBUFS)) {
838 "Configuration directives 'device_output_buffer_size' "
840 "'tapebufs' are incompatible; using former.\n");
842 } else if (getconf_seen(CNF_TAPEBUFS)) {
843 max_memory = getconf_int(CNF_TAPEBUFS) *
844 device_write_max_size(taper_state->device);
847 max_memory = getconf_size(CNF_DEVICE_OUTPUT_BUFFER_SIZE);
850 queue_result = do_consumer_producer_queue_full
851 (taper_source_producer,
855 device_write_max_size(taper_state->device), max_memory,
858 g_get_current_time(&end_time);
859 run_time = timesub(end_time, start_time);
861 /* The device_write_consumer may have closed the file with a short
862 * write, so we only finish here if it needs it. */
863 if (taper_state->device->in_file &&
864 !device_finish_file(taper_state->device)) {
865 queue_result = queue_result | QUEUE_CONSUMER_ERROR;
868 if (!finish_part_attempt(taper_state, dump_info, queue_result,
869 run_time, consumer_data.bytes_written)) {
875 /* Handle a PORT_WRITE command. */
876 static void process_port_write(taper_state_t * state,
877 struct cmdargs * cmdargs) {
878 dump_info_t dump_state;
880 guint64 fallback_splitsize;
881 char * split_diskbuffer;
882 char * argnames[] = {"command", /* 1 */
889 "split_diskbuffer", /* 8 */
890 "fallback_splitsize", /* 9 */
893 validate_args(PORT_WRITE, cmdargs, argnames);
895 dump_state.handle = g_strdup(cmdargs->argv[2]);
896 dump_state.hostname = g_strdup(cmdargs->argv[3]);
897 dump_state.diskname = unquote_string(cmdargs->argv[4]);
900 dump_state.level = strtol(cmdargs->argv[5], NULL, 10);
902 error("error [taper PORT-WRITE: Invalid dump level %s]",
904 g_assert_not_reached();
907 dump_state.timestamp = strdup(cmdargs->argv[6]);
910 splitsize = g_ascii_strtoull(cmdargs->argv[7], NULL, 10);
912 error("error [taper PORT-WRITE: Invalid splitsize %s]",
914 g_assert_not_reached();
917 if (strcmp(cmdargs->argv[8], "NULL") == 0) {
918 split_diskbuffer = NULL;
920 split_diskbuffer = g_strdup(cmdargs->argv[8]);
924 fallback_splitsize = g_ascii_strtoull(cmdargs->argv[9], NULL, 10);
926 error("error [taper PORT-WRITE: Invalid fallback_splitsize %s]",
928 g_assert_not_reached();
931 dump_state.id_string = g_strdup_printf("%s:%s.%d", dump_state.hostname,
935 if (!open_read_socket(&dump_state, split_diskbuffer, splitsize,
936 fallback_splitsize)) {
937 free(split_diskbuffer);
940 free(split_diskbuffer);
942 run_device_output(state, &dump_state);
944 free_dump_info(&dump_state);
947 /* Handle a FILE_WRITE command. */
948 static void process_file_write(taper_state_t * state,
949 struct cmdargs * cmdargs) {
950 dump_info_t dump_state;
951 char * holding_disk_file;
953 char * argnames[] = {"command", /* 1 */
963 validate_args(FILE_WRITE, cmdargs, argnames);
965 dump_state.handle = g_strdup(cmdargs->argv[2]);
966 holding_disk_file = unquote_string(cmdargs->argv[3]);
967 dump_state.hostname = g_strdup(cmdargs->argv[4]);
968 dump_state.diskname = unquote_string(cmdargs->argv[5]);
971 dump_state.level = strtol(cmdargs->argv[6], NULL, 10);
973 error("error [taper FILE-WRITE: Invalid dump level %s]",
975 g_assert_not_reached();
978 dump_state.timestamp = strdup(cmdargs->argv[7]);
981 splitsize = g_ascii_strtoull(cmdargs->argv[8], NULL, 10);
983 error("error [taper FILE-WRITE: Invalid splitsize %s]",
985 g_assert_not_reached();
988 dump_state.id_string = g_strdup_printf("%s:%s.%d", dump_state.hostname,
992 dump_state.source = taper_source_new(dump_state.handle, FILE_WRITE,
993 holding_disk_file, -1,
994 NULL, splitsize, -1);
995 /* FIXME: This should be handled properly. */
996 g_assert(dump_state.source != NULL);
998 run_device_output(state, &dump_state);
1000 free_dump_info(&dump_state);
1001 amfree(holding_disk_file);
1004 /* Send QUITTING message to driver and associated logging. Always
1006 static gboolean send_quitting(taper_state_t * state) {
1007 putresult(QUITTING, "\n");
1008 g_fprintf(stderr,"taper: DONE\n");
1013 /* This function recieves the START_TAPER command from driver, and
1014 returns the attached timestamp. */
1015 static gboolean find_first_tape(taper_state_t * state) {
1017 /* Note: cmdargs.argv is never freed. In the entire Amanda codebase. */
1018 struct cmdargs cmdargs;
1019 tape_search_request_t search_request;
1020 GThread * tape_search = NULL;
1021 gboolean use_threads;
1023 /* We save the value here in case it changes while we're running. */
1024 use_threads = g_thread_supported();
1026 search_request.state = state;
1027 search_request.prolong = TRUE;
1028 search_request.errmsg = NULL;
1031 tape_search = g_thread_create(tape_search_thread,
1032 &search_request, TRUE, NULL);
1035 cmd = getcmd(&cmdargs);
1039 gboolean search_result;
1040 state->driver_start_time = strdup(cmdargs.argv[2]);
1042 search_result = GPOINTER_TO_INT(g_thread_join(tape_search));
1045 GPOINTER_TO_INT(tape_search_thread(&search_request));
1047 if (search_result) {
1048 putresult(TAPER_OK, "\n");
1050 putresult(TAPE_ERROR, "Could not find a tape to use.\n");
1051 log_add(L_ERROR, "no-tape [%s]", "Could not find a tape to use");
1052 if (search_request.errmsg != NULL) {
1054 c = c1 = search_request.errmsg;
1055 while (*c != '\0') {
1058 log_add(L_WARNING,"%s", c1);
1063 if (strlen(c1) > 1 )
1064 log_add(L_WARNING,"%s", c1);
1067 amfree(search_request.errmsg);
1071 search_request.prolong = FALSE;
1073 g_thread_join(tape_search);
1075 return send_quitting(state);
1077 error("error [file_reader_side cmd %d argc %d]", cmd, cmdargs.argc);
1080 g_assert_not_reached();
1083 /* In running mode (not startup mode), get a command from driver and
1085 static gboolean process_driver_command(taper_state_t * state) {
1087 struct cmdargs cmdargs;
1090 /* This will return QUIT if driver has died. */
1091 cmd = getcmd(&cmdargs);
1105 process_port_write(state, &cmdargs);
1120 process_file_write(state, &cmdargs);
1124 return send_quitting(state);
1126 if (cmdargs.argc >= 1) {
1127 q = squote(cmdargs.argv[1]);
1128 } else if (cmdargs.argc >= 0) {
1129 q = squote(cmdargs.argv[0]);
1131 q = stralloc("(no input?)");
1133 putresult(BAD_COMMAND, "%s\n", q);
1141 int main(int argc, char ** argv) {
1142 char * tapelist_name;
1144 taper_state_t state;
1145 config_overwrites_t *cfg_ovr = NULL;
1146 char *cfg_opt = NULL;
1149 * Configure program for internationalization:
1150 * 1) Only set the message locale for now.
1151 * 2) Set textdomain for all amanda related programs to "amanda"
1152 * We don't want to be forced to support dozens of message catalogs.
1154 setlocale(LC_MESSAGES, "C");
1155 textdomain("amanda");
1163 init_taper_state(&state);
1165 /* Don't die when child closes pipe */
1166 signal(SIGPIPE, SIG_IGN);
1168 g_fprintf(stderr, _("%s: pid %ld executable %s version %s\n"),
1169 get_pname(), (long) getpid(), argv[0], version());
1170 dbprintf(_("%s: pid %ld executable %s version %s\n"),
1171 get_pname(), (long) getpid(), argv[0], version());
1173 /* Process options */
1175 cfg_ovr = extract_commandline_config_overwrites(&argc, &argv);
1178 error("Too many arguments!\n");
1179 g_assert_not_reached();
1183 config_init(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD | CONFIG_INIT_FATAL,
1185 apply_config_overwrites(cfg_ovr);
1189 set_logerror(logerror);
1191 check_running_as(RUNNING_AS_DUMPUSER);
1193 dbrename(config_name, DBG_SUBDIR_SERVER);
1195 tapelist_name = config_dir_relative(getconf_str(CNF_TAPELIST));
1197 if (read_tapelist(tapelist_name) != 0) {
1198 error("could not load tapelist \"%s\"", tapelist_name);
1199 g_assert_not_reached();
1201 amfree(tapelist_name);
1203 have_changer = changer_init();
1204 if (have_changer < 0) {
1205 error("changer initialization failed: %s", strerror(errno));
1206 g_assert_not_reached();
1209 state.next_tape_label = NULL;
1210 state.next_tape_device = NULL;
1213 if (!find_first_tape(&state)) {
1214 return EXIT_SUCCESS;
1217 while (process_driver_command(&state));
1218 return EXIT_SUCCESS;