2 * Copyright (c) 2009, 2010 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
24 #include "directtcp.h"
26 #include "ndmpconnobj.h"
29 * Type checking and casting macros
31 #define TYPE_NDMP_DEVICE (ndmp_device_get_type())
32 #define NDMP_DEVICE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), ndmp_device_get_type(), NdmpDevice)
33 #define NDMP_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), ndmp_device_get_type(), NdmpDevice const)
34 #define NDMP_DEVICE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), ndmp_device_get_type(), NdmpDeviceClass)
35 #define IS_NDMP_DEVICE(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), ndmp_device_get_type ())
36 #define NDMP_DEVICE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), ndmp_device_get_type(), NdmpDeviceClass)
37 static GType ndmp_device_get_type (void);
40 * Main object structure
43 typedef struct NdmpDevice_ NdmpDevice;
49 /* true if tape service is open on the NDMP server */
52 /* addresses the object is listening on, and how the connection
54 DirectTCPAddr *listen_addrs;
57 /* Current DirectTCPConnectionNDMP */
58 struct DirectTCPConnectionNDMP_ *directtcp_conn;
60 /* constructor parameters and properties */
63 gchar *ndmp_device_name;
68 gsize read_block_size;
75 typedef struct NdmpDeviceClass_ NdmpDeviceClass;
76 struct NdmpDeviceClass_ {
77 DeviceClass __parent__;
81 * A directtcp connection subclass representing a running mover on the other end of
82 * the given NDMP connection
85 #define TYPE_DIRECTTCP_CONNECTION_NDMP (directtcp_connection_ndmp_get_type())
86 #define DIRECTTCP_CONNECTION_NDMP(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), directtcp_connection_ndmp_get_type(), DirectTCPConnectionNDMP)
87 #define DIRECTTCP_CONNECTION_NDMP_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), directtcp_connection_ndmp_get_type(), DirectTCPConnectionNDMP const)
88 #define DIRECTTCP_CONNECTION_NDMP_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), directtcp_connection_ndmp_get_type(), DirectTCPConnectionNDMPClass)
89 #define IS_DIRECTTCP_CONNECTION_NDMP(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), directtcp_connection_ndmp_get_type ())
90 #define DIRECTTCP_CONNECTION_NDMP_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), directtcp_connection_ndmp_get_type(), DirectTCPConnectionNDMPClass)
91 GType directtcp_connection_ndmp_get_type(void);
93 typedef struct DirectTCPConnectionNDMP_ {
94 DirectTCPConnection __parent__;
96 /* NDMP connection controlling the mover */
99 /* mode for this operation */
100 ndmp9_mover_mode mode;
102 /* last reported mover position in the datastream */
104 } DirectTCPConnectionNDMP;
106 typedef struct DirectTCPConnectionNDMPClass_ {
107 DirectTCPConnectionClass __parent__;
108 } DirectTCPConnectionNDMPClass;
110 static DirectTCPConnectionNDMP *directtcp_connection_ndmp_new(
111 NDMPConnection *ndmp,
112 ndmp9_mover_mode mode);
115 * Constants and static data
118 #define NDMP_DEVICE_NAME "ndmp"
120 /* pointer to the class of our parent */
121 static DeviceClass *parent_class = NULL;
123 /* robust_write results */
126 ROBUST_WRITE_OK_LEOM,
127 ROBUST_WRITE_ERROR, /* device error already set */
128 ROBUST_WRITE_NO_SPACE
129 } robust_write_result;
132 * device-specific properties
135 /* Authentication information for NDMP agent. Both of these are strings. */
136 static DevicePropertyBase device_property_ndmp_username;
137 static DevicePropertyBase device_property_ndmp_password;
138 static DevicePropertyBase device_property_ndmp_auth;
139 #define PROPERTY_NDMP_USERNAME (device_property_ndmp_username.ID)
140 #define PROPERTY_NDMP_PASSWORD (device_property_ndmp_password.ID)
141 #define PROPERTY_NDMP_AUTH (device_property_ndmp_auth.ID)
148 void ndmp_device_register(void);
149 static void set_error_from_ndmp(NdmpDevice *self);
151 #define ndmp_device_read_size(self) \
152 (((NdmpDevice *)(self))->read_block_size? \
153 ((NdmpDevice *)(self))->read_block_size : ((Device *)(self))->block_size)
164 self->ndmp = ndmp_connection_new(
171 if (ndmp_connection_err_code(self->ndmp)) {
172 char *errmsg = ndmp_connection_err_msg(self->ndmp);
173 device_set_error(DEVICE(self),
174 g_strdup_printf("could not connect to ndmp-server '%s:%d': %s",
175 self->ndmp_hostname, self->ndmp_port, errmsg),
176 DEVICE_STATUS_DEVICE_ERROR);
177 g_object_unref(self->ndmp);
183 ndmp_connection_set_verbose(self->ndmp, TRUE);
185 self->tape_open = FALSE;
195 /* note that this does not send NDMP_TAPE_CLOSE, as it's used in error
198 g_object_unref(self->ndmp);
200 self->tape_open = FALSE;
208 guint64 file_num, blockno, blocksize;
210 /* if already open, stop now */
211 if (self->tape_open) {
215 if (!open_connection(self)) {
216 /* error message set by open_connection */
220 g_debug("opening tape device '%s' on NDMP server '%s:%d'",
221 self->ndmp_device_name, self->ndmp_hostname, self->ndmp_port);
223 /* send NDMP_TAPE_OPEN, using RAW mode so that it will open even with no tape */
224 if (!ndmp_connection_tape_open(self->ndmp,
225 self->ndmp_device_name, NDMP9_TAPE_RAW_MODE)) {
226 set_error_from_ndmp(self);
230 /* check that the block sizes match */
231 if (!ndmp_connection_tape_get_state(self->ndmp,
232 &blocksize, &file_num, &blockno)) {
233 set_error_from_ndmp(self);
236 if (blocksize != 0 && blocksize != DEVICE(self)->block_size) {
237 device_set_error(DEVICE(self),
238 g_strdup_printf("NDMP device has fixed block size %ju, but Amanda "
239 "device is configured with blocksize %ju", (uintmax_t)blocksize,
240 (uintmax_t)(DEVICE(self)->block_size)),
241 DEVICE_STATUS_DEVICE_ERROR);
244 self->tape_open = TRUE;
253 if (self->tape_open) {
254 g_debug("closing tape device '%s' on NDMP server '%s:%d'",
255 self->ndmp_device_name, self->ndmp_hostname, self->ndmp_port);
256 self->tape_open = FALSE; /* count it as closed even if there is an error */
257 if (!ndmp_connection_tape_close(self->ndmp)) {
258 set_error_from_ndmp(self);
269 ndmp9_tape_mtio_op tape_op)
273 if (!ndmp_connection_tape_mtio(self->ndmp, tape_op, 1, &resid)) {
274 set_error_from_ndmp(self);
279 device_set_error(DEVICE(self),
280 g_strdup_printf("NDMP MTIO operation %d did not complete", tape_op),
281 DEVICE_STATUS_DEVICE_ERROR);
287 /* get the tape state straight from the device; we try to track these things
288 * accurately in the device, but sometimes it's good to check. */
293 Device *dself = DEVICE(self);
294 guint64 file_num, blockno, blocksize;
296 if (!ndmp_connection_tape_get_state(self->ndmp,
297 &blocksize, &file_num, &blockno)) {
298 set_error_from_ndmp(self);
302 g_assert(file_num < INT_MAX);
303 dself->file = (int)file_num;
304 dself->block = blockno;
309 static robust_write_result
316 robust_write_result subresult;
318 if (!ndmp_connection_tape_write(self->ndmp, buf, count, &actual)) {
319 switch (ndmp_connection_err_code(self->ndmp)) {
321 /* We encountered PEOM; this only happens when the caller ignores
323 return ROBUST_WRITE_NO_SPACE;
326 /* We encountered LEOM; retry the write (which should succeed) */
327 subresult = robust_write(self, buf, count);
328 if (subresult != ROBUST_WRITE_OK)
330 g_debug("ndmp device hit logical EOM");
331 return ROBUST_WRITE_OK_LEOM;
334 set_error_from_ndmp(self);
335 return ROBUST_WRITE_ERROR;
339 g_assert(count == actual);
340 return ROBUST_WRITE_OK;
347 /* translate some error codes to the corresponding Device API status */
348 switch (ndmp_connection_err_code(self->ndmp)) {
349 case NDMP9_NO_TAPE_LOADED_ERR:
350 device_set_error(DEVICE(self),
351 g_strdup(_("no tape loaded")),
352 DEVICE_STATUS_VOLUME_MISSING);
355 case NDMP9_DEVICE_BUSY_ERR:
356 device_set_error(DEVICE(self),
357 g_strdup(_("device busy")),
358 DEVICE_STATUS_DEVICE_BUSY);
362 device_set_error(DEVICE(self),
363 g_strdup(_("IO error")),
364 DEVICE_STATUS_VOLUME_UNLABELED |
365 DEVICE_STATUS_VOLUME_ERROR |
366 DEVICE_STATUS_DEVICE_ERROR);
370 device_set_error(DEVICE(self),
371 ndmp_connection_err_msg(self->ndmp),
372 DEVICE_STATUS_DEVICE_ERROR);
375 close_connection(self);
379 * Virtual function overrides
383 ndmp_device_open_device(
389 NdmpDevice *self = NDMP_DEVICE(dself);
392 /* first, extract the various parts of the device_node:
393 * HOST[:PORT]@DEVICE */
394 colon = strchr(device_node, ':');
395 at = strchr(device_node, '@');
397 colon = NULL; /* :PORT only counts if it's before the device name */
399 device_set_error(dself,
400 g_strdup_printf("invalid ndmp device name '%s'", device_name),
401 DEVICE_STATUS_DEVICE_ERROR);
407 long port = strtol(colon+1, &p, 10);
409 if (port < 0 || port >= 65536 || p != at || (!port && EINVAL == errno)) {
410 device_set_error(dself,
411 g_strdup_printf("invalid ndmp port in device name '%s'",
413 DEVICE_STATUS_DEVICE_ERROR);
416 self->ndmp_port = (gint)port;
417 self->ndmp_hostname = g_strndup(device_node, colon-device_node);
419 self->ndmp_port = 0; /* (use ndmjob's default, 10000) */
420 self->ndmp_hostname = g_strndup(device_node, at-device_node);
422 self->ndmp_device_name = g_strdup(at+1);
424 if (parent_class->open_device) {
425 parent_class->open_device(dself, device_name, device_type, device_node);
429 static void ndmp_device_finalize(GObject * obj_self)
431 NdmpDevice *self = NDMP_DEVICE (obj_self);
433 if(G_OBJECT_CLASS(parent_class)->finalize)
434 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
436 (void)close_tape_agent(self); /* ignore any error */
438 if (self->directtcp_conn)
439 g_object_unref(self->directtcp_conn);
441 if (self->listen_addrs)
442 g_free(self->listen_addrs);
444 close_connection(self);
446 if (self->ndmp_hostname)
447 g_free(self->ndmp_hostname);
448 if (self->ndmp_device_name)
449 g_free(self->ndmp_device_name);
450 if (self->ndmp_username)
451 g_free(self->ndmp_username);
452 if (self->ndmp_password)
453 g_free(self->ndmp_password);
455 g_free(self->ndmp_auth);
458 static DeviceStatusFlags
459 ndmp_device_read_label(
462 NdmpDevice *self = NDMP_DEVICE(dself);
463 dumpfile_t *header = NULL;
465 guint64 buf_size = 0;
466 gsize read_block_size = 0;
468 amfree(dself->volume_label);
469 amfree(dself->volume_time);
470 dumpfile_free(dself->volume_header);
471 dself->volume_header = NULL;
473 if (device_in_error(self)) return dself->status;
475 if (!open_tape_agent(self)) {
476 /* error status was set by open_tape_agent */
477 return dself->status;
480 if (!single_ndmp_mtio(self, NDMP9_MTIO_REW)) {
481 /* error message, if any, is set by single_ndmp_mtio */
482 return dself->status;
485 /* read the tape header from the NDMP server */
487 read_block_size = ndmp_device_read_size(self);
488 buf = g_malloc(read_block_size);
489 if (!ndmp_connection_tape_read(self->ndmp,
494 /* handle known errors */
495 switch (ndmp_connection_err_code(self->ndmp)) {
496 case NDMP9_NO_TAPE_LOADED_ERR:
497 device_set_error(dself,
498 g_strdup(_("no tape loaded")),
499 DEVICE_STATUS_VOLUME_MISSING);
503 device_set_error(dself,
504 g_strdup(_("IO error reading tape label")),
505 DEVICE_STATUS_VOLUME_UNLABELED |
506 DEVICE_STATUS_VOLUME_ERROR |
507 DEVICE_STATUS_DEVICE_ERROR);
512 device_set_error(dself,
513 g_strdup(_("no tape label found")),
514 DEVICE_STATUS_VOLUME_UNLABELED);
515 header = dself->volume_header = g_new(dumpfile_t, 1);
520 set_error_from_ndmp(self);
525 header = dself->volume_header = g_new(dumpfile_t, 1);
527 parse_file_header(buf, header, buf_size);
532 if (dself->status != 0) {
533 /* error already set above */
534 return dself->status;
537 /* handle a "weird" label */
538 if (header->type != F_TAPESTART) {
539 device_set_error(dself,
540 stralloc(_("No tapestart header -- unlabeled device?")),
541 DEVICE_STATUS_VOLUME_UNLABELED);
542 return dself->status;
544 dself->volume_label = g_strdup(header->name);
545 dself->volume_time = g_strdup(header->datestamp);
546 /* dself->volume_header is already set */
548 /* note: connection is left open, as well as the tape device */
550 device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
552 return dself->status;
559 DeviceAccessMode mode,
563 NdmpDevice *self = NDMP_DEVICE(dself);
567 self = NDMP_DEVICE(dself);
569 if (device_in_error(self)) return FALSE;
571 if (!open_tape_agent(self)) {
572 /* error status was set by open_tape_agent */
576 if (mode != ACCESS_WRITE && dself->volume_label == NULL) {
577 if (ndmp_device_read_label(dself) != DEVICE_STATUS_SUCCESS)
578 /* the error was set by ndmp_device_read_label */
582 dself->access_mode = mode;
583 dself->in_file = FALSE;
585 if (!single_ndmp_mtio(self, NDMP9_MTIO_REW)) {
586 /* single_ndmp_mtio already set our error message */
590 /* Position the tape */
593 device_set_error(dself,
594 g_strdup("operation not supported"),
595 DEVICE_STATUS_DEVICE_ERROR);
604 header = make_tapestart_header(dself, label, timestamp);
605 g_assert(header != NULL);
607 header_buf = device_build_amanda_header(dself, header, NULL);
608 if (header_buf == NULL) {
609 device_set_error(dself,
610 stralloc(_("Tapestart header won't fit in a single block!")),
611 DEVICE_STATUS_DEVICE_ERROR);
612 dumpfile_free(header);
616 switch (robust_write(self, header_buf, dself->block_size)) {
617 case ROBUST_WRITE_OK_LEOM:
618 dself->is_eom = TRUE;
620 case ROBUST_WRITE_OK:
623 case ROBUST_WRITE_NO_SPACE:
624 /* this would be an odd error to see writing the tape label, but
626 device_set_error(dself,
627 stralloc(_("No space left on device")),
628 DEVICE_STATUS_VOLUME_ERROR);
629 dself->is_eom = TRUE;
632 case ROBUST_WRITE_ERROR:
633 /* error was set by robust_write or above */
634 dumpfile_free(header);
641 if (!single_ndmp_mtio(self, NDMP9_MTIO_EOF)) {
642 /* error was set by single_ndmp_mtio */
643 dumpfile_free(header);
647 dself->volume_label = newstralloc(dself->volume_label, label);
648 dself->volume_time = newstralloc(dself->volume_time, timestamp);
649 dumpfile_free(dself->volume_header);
650 dself->volume_header = header;
652 /* unset the VOLUME_UNLABELED flag, if it was set */
653 device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
658 g_assert_not_reached();
670 NdmpDevice *self = NDMP_DEVICE(dself);
671 rval = !device_in_error(dself);
673 /* we're not in a file anymore */
674 dself->access_mode = ACCESS_NULL;
676 if (!close_tape_agent(self)) {
677 /* error is set by close_tape_agent */
682 close_connection(self);
691 NdmpDevice *self = NDMP_DEVICE(dself);
692 if (device_in_error(dself)) return FALSE;
694 if (!single_ndmp_mtio(self, NDMP9_MTIO_OFF)) {
695 /* error was set by single_ndmp_mtio */
703 /* functions for writing */
706 ndmp_device_start_file(
710 NdmpDevice *self = NDMP_DEVICE(dself);
713 if (device_in_error(self)) return FALSE;
715 dself->is_eof = FALSE;
716 dself->is_eom = FALSE;
718 /* set the blocksize in the header properly */
719 header->blocksize = dself->block_size;
721 header_buf = device_build_amanda_header(dself, header, NULL);
722 if (header_buf == NULL) {
723 device_set_error(dself,
724 stralloc(_("Amanda file header won't fit in a single block!")),
725 DEVICE_STATUS_DEVICE_ERROR);
729 switch (robust_write(self, header_buf, dself->block_size)) {
730 case ROBUST_WRITE_OK_LEOM:
731 dself->is_eom = TRUE;
734 case ROBUST_WRITE_OK:
737 case ROBUST_WRITE_NO_SPACE:
738 /* this would be an odd error to see writing the tape label, but
740 device_set_error(dself,
741 stralloc(_("No space left on device")),
742 DEVICE_STATUS_VOLUME_ERROR);
743 dself->is_eom = TRUE;
746 case ROBUST_WRITE_ERROR:
747 /* error was set by robust_write or above */
753 /* arrange the file numbers correctly */
754 dself->in_file = TRUE;
755 if (!ndmp_get_state(self)) {
756 /* error already set by ndmp_get_state */
760 /* double-check that the tape agent gave us a non-bogus file number */
761 g_assert(dself->file > 0);
767 ndmp_device_write_block(
772 NdmpDevice *self = NDMP_DEVICE(dself);
773 gpointer replacement_buffer = NULL;
775 if (device_in_error(self)) return FALSE;
777 /* zero out to the end of a short block -- tape devices only write
779 if (size < dself->block_size) {
780 replacement_buffer = malloc(dself->block_size);
781 memcpy(replacement_buffer, data, size);
782 bzero(replacement_buffer+size, dself->block_size-size);
784 data = replacement_buffer;
785 size = dself->block_size;
788 switch (robust_write(self, data, size)) {
789 case ROBUST_WRITE_OK_LEOM:
790 dself->is_eom = TRUE;
793 case ROBUST_WRITE_OK:
796 case ROBUST_WRITE_NO_SPACE:
797 /* this would be an odd error to see writing the tape label, but
799 device_set_error(dself,
800 stralloc(_("No space left on device")),
801 DEVICE_STATUS_VOLUME_ERROR);
802 dself->is_eom = TRUE;
805 case ROBUST_WRITE_ERROR:
806 /* error was set by robust_write or above */
807 if (replacement_buffer) g_free(replacement_buffer);
813 if (replacement_buffer) g_free(replacement_buffer);
818 ndmp_device_finish_file(
821 NdmpDevice *self = NDMP_DEVICE(dself);
823 if (device_in_error(dself)) return FALSE;
825 /* we're not in a file anymore */
826 dself->in_file = FALSE;
828 if (!single_ndmp_mtio(self, NDMP9_MTIO_EOF)) {
829 /* error was set by single_ndmp_mtio */
830 dself->is_eom = TRUE;
837 /* functions for reading */
840 ndmp_device_seek_file(
844 NdmpDevice *self = NDMP_DEVICE(dself);
850 gsize read_block_size = 0;
852 if (device_in_error(dself)) return FALSE;
854 /* file 0 is the tape header, and isn't seekable as a distinct
855 * Device-API-level file */
857 device_set_error(dself,
858 g_strdup("cannot seek to file 0"),
859 DEVICE_STATUS_DEVICE_ERROR);
863 /* first, make sure the file and block numbers are correct */
864 if (!ndmp_get_state(self)) {
865 /* error already set by ndmp_get_state */
869 /* now calculate the file delta */
870 delta = file - dself->file;
873 /* Note that this algorithm will rewind to the beginning of
874 * the current part, too */
876 /* BSF *past* the filemark we want to seek to */
877 if (!ndmp_connection_tape_mtio(self->ndmp, NDMP9_MTIO_BSF, -delta + 1, &resid)) {
878 set_error_from_ndmp(self);
884 /* now we are on the BOT side of the filemark, but we want to be
885 * on the EOT side of it. An FSF will get us there.. */
886 if (!ndmp_connection_tape_mtio(self->ndmp, NDMP9_MTIO_FSF, 1, &resid)) {
887 set_error_from_ndmp(self);
893 device_set_error(dself,
894 g_strdup_printf("BSF operation failed to seek by %d files", resid),
895 DEVICE_STATUS_DEVICE_ERROR);
898 } else /* (delta > 0) */ {
899 if (!ndmp_connection_tape_mtio(self->ndmp, NDMP9_MTIO_FSF, delta, &resid)) {
900 set_error_from_ndmp(self);
904 /* if we didn't seek all the way there, then we're past the tapeend */
906 device_set_error(dself,
907 vstrallocf(_("Could not seek forward to file %d"), file),
908 DEVICE_STATUS_VOLUME_ERROR);
914 dself->in_file = TRUE;
918 /* now read the header */
919 read_block_size = ndmp_device_read_size(self);
920 buf = g_malloc(read_block_size);
921 if (!ndmp_connection_tape_read(self->ndmp,
922 buf, read_block_size, &buf_size)) {
923 switch (ndmp_connection_err_code(self->ndmp)) {
926 return make_tapeend_header();
929 set_error_from_ndmp(self);
935 header = g_new(dumpfile_t, 1);
937 parse_file_header(buf, header, buf_size);
944 ndmp_device_seek_block(
948 if (device_in_error(dself)) return FALSE;
950 dself->block = block;
952 device_set_error(dself, g_strdup("operation not supported"), DEVICE_STATUS_DEVICE_ERROR);
957 ndmp_device_read_block (Device * dself, gpointer data, int *size_req) {
958 NdmpDevice *self = NDMP_DEVICE(dself);
959 guint64 requested, actual;
960 gsize read_block_size = ndmp_device_read_size(self);
962 /* We checked the NDMP device's blocksize when the device was opened, which should
963 * catch any misalignent of server block size and Amanda block size */
965 g_assert(read_block_size < INT_MAX); /* check data type mismatch */
966 if (!data || *size_req < (int)(read_block_size)) {
967 *size_req = (int)(read_block_size);
971 requested = *size_req;
972 if (!ndmp_connection_tape_read(self->ndmp,
977 /* handle known errors */
978 switch (ndmp_connection_err_code(self->ndmp)) {
981 dself->is_eof = TRUE;
985 set_error_from_ndmp(self);
990 *size_req = (int)actual; /* cast is OK - requested size was < INT_MAX too */
998 gboolean for_writing,
999 DirectTCPAddr **addrs)
1001 NdmpDevice *self = NDMP_DEVICE(dself);
1003 if (device_in_error(self)) return FALSE;
1006 g_assert(!self->listen_addrs);
1008 if (!open_tape_agent(self)) {
1009 /* error message was set by open_tape_agent */
1013 /* first, set the window to an empty span so that the mover doesn't start
1014 * reading or writing data immediately. NDMJOB tends to reset the record
1015 * size periodically (in direct contradiction to the spec), so we reset it
1017 if (!ndmp_connection_mover_set_record_size(self->ndmp,
1018 DEVICE(self)->block_size)) {
1019 set_error_from_ndmp(self);
1023 if (!ndmp_connection_mover_set_window(self->ndmp, 0, 0)) {
1024 set_error_from_ndmp(self);
1028 /* then tell it to start listening */
1029 if (!ndmp_connection_mover_listen(self->ndmp,
1030 for_writing? NDMP9_MOVER_MODE_READ : NDMP9_MOVER_MODE_WRITE,
1033 set_error_from_ndmp(self);
1036 self->listen_addrs = *addrs;
1037 self->for_writing = for_writing;
1045 DirectTCPConnection **dtcpconn,
1046 ProlongProc prolong,
1047 gpointer prolong_data)
1049 NdmpDevice *self = NDMP_DEVICE(dself);
1050 ndmp9_mover_state state;
1051 guint64 bytes_moved;
1052 ndmp9_mover_mode mode;
1053 ndmp9_mover_pause_reason reason;
1054 guint64 seek_position;
1056 if (device_in_error(self)) return FALSE;
1058 g_assert(self->listen_addrs);
1062 /* TODO: support aborting this operation - maybe just always poll? */
1064 prolong_data = prolong_data;
1066 if (!self->for_writing) {
1067 /* when reading, we don't get any kind of notification that the
1068 * connection has been established, but we can't call NDMP_MOVER_READ
1069 * until the mover is active. So we have to poll, waiting for ACTIVE.
1071 gulong backoff = G_USEC_PER_SEC/20; /* 5 msec */
1073 if (!ndmp_connection_mover_get_state(self->ndmp,
1074 &state, &bytes_moved, NULL, NULL)) {
1075 set_error_from_ndmp(self);
1079 if (state != NDMP9_MOVER_STATE_LISTEN)
1082 /* back off a little bit to give the other side time to breathe,
1083 * but not more than one second */
1086 if (backoff > G_USEC_PER_SEC)
1087 backoff = G_USEC_PER_SEC;
1090 /* double-check state */
1091 if (state != NDMP9_MOVER_STATE_ACTIVE) {
1092 device_set_error(DEVICE(self),
1093 g_strdup("mover did not enter the ACTIVE state as expected"),
1094 DEVICE_STATUS_DEVICE_ERROR);
1098 /* now, we need to get this into the PAUSED state, since right now we
1099 * aren't allowed to perform any tape movement commands. So we issue a
1100 * MOVER_READ request for the whole darn image stream after setting the
1101 * usual empty window. Note that this means the whole dump will be read
1102 * in one MOVER_READ operation, even if it does not begin at the
1103 * beginning of a part. */
1104 if (!ndmp_connection_mover_read(self->ndmp, 0, G_MAXUINT64)) {
1105 set_error_from_ndmp(self);
1109 /* now we should expect a notice that the mover has paused */
1111 /* when writing, the mover will pause as soon as the first byte comes
1112 * in, so there's no need to do anything to trigger the pause. */
1115 /* NDMJOB sends NDMP9_MOVER_PAUSE_SEEK to indicate that it wants to write
1116 * outside the window, while the standard specifies .._EOW, instead. When
1117 * reading to a connection, we get the appropriate .._SEEK. It's easy
1118 * enough to handle both. */
1120 if (!ndmp_connection_wait_for_notify(self->ndmp,
1123 &reason, &seek_position)) {
1124 set_error_from_ndmp(self);
1128 if (reason != NDMP9_MOVER_PAUSE_SEEK && reason != NDMP9_MOVER_PAUSE_EOW) {
1129 device_set_error(DEVICE(self),
1130 g_strdup_printf("got NOTIFY_MOVER_PAUSED, but not because of EOW or SEEK"),
1131 DEVICE_STATUS_DEVICE_ERROR);
1135 g_free(self->listen_addrs);
1136 self->listen_addrs = NULL;
1138 if (self->for_writing)
1139 mode = NDMP9_MOVER_MODE_READ;
1141 mode = NDMP9_MOVER_MODE_WRITE;
1143 /* set up the new directtcp connection */
1144 if (self->directtcp_conn)
1145 g_object_unref(self->directtcp_conn);
1146 self->directtcp_conn =
1147 directtcp_connection_ndmp_new(self->ndmp, mode);
1148 *dtcpconn = DIRECTTCP_CONNECTION(self->directtcp_conn);
1150 /* reference it for the caller */
1151 g_object_ref(*dtcpconn);
1159 gboolean for_writing,
1160 DirectTCPAddr *addrs,
1161 DirectTCPConnection **dtcpconn,
1162 ProlongProc prolong,
1163 gpointer prolong_data)
1165 NdmpDevice *self = NDMP_DEVICE(dself);
1166 ndmp9_mover_mode mode;
1167 ndmp9_mover_pause_reason reason;
1168 guint64 seek_position;
1170 g_assert(!self->listen_addrs);
1173 self->for_writing = for_writing;
1175 /* TODO: support aborting this operation - maybe just always poll? */
1177 prolong_data = prolong_data;
1179 if (!open_tape_agent(self)) {
1180 /* error message was set by open_tape_agent */
1184 /* first, set the window to an empty span so that the mover doesn't start
1185 * reading or writing data immediately. NDMJOB tends to reset the record
1186 * size periodically (in direct contradiction to the spec), so we reset it
1188 if (!ndmp_connection_mover_set_record_size(self->ndmp,
1189 DEVICE(self)->block_size)) {
1190 set_error_from_ndmp(self);
1194 if (!ndmp_connection_mover_set_window(self->ndmp, 0, 0)) {
1195 set_error_from_ndmp(self);
1199 if (self->for_writing)
1200 mode = NDMP9_MOVER_MODE_READ;
1202 mode = NDMP9_MOVER_MODE_WRITE;
1204 if (!ndmp_connection_mover_connect(self->ndmp, mode, addrs)) {
1205 set_error_from_ndmp(self);
1209 if (!self->for_writing) {
1210 /* The agent is in the ACTIVE state, and will remain so until we tell
1211 * it to do something else. The thing we want to is for it to start
1212 * reading data from the tape, which will immediately trigger an EOW or
1214 if (!ndmp_connection_mover_read(self->ndmp, 0, G_MAXUINT64)) {
1215 set_error_from_ndmp(self);
1219 /* now we should expect a notice that the mover has paused */
1221 /* when writing, the mover will pause as soon as the first byte comes
1222 * in, so there's no need to do anything to trigger the pause. */
1225 /* NDMJOB sends NDMP9_MOVER_PAUSE_SEEK to indicate that it wants to write
1226 * outside the window, while the standard specifies .._EOW, instead. When
1227 * reading to a connection, we get the appropriate .._SEEK. It's easy
1228 * enough to handle both. */
1230 if (!ndmp_connection_wait_for_notify(self->ndmp,
1233 &reason, &seek_position)) {
1234 set_error_from_ndmp(self);
1238 if (reason != NDMP9_MOVER_PAUSE_SEEK && reason != NDMP9_MOVER_PAUSE_EOW) {
1239 device_set_error(DEVICE(self),
1240 g_strdup_printf("got NOTIFY_MOVER_PAUSED, but not because of EOW or SEEK"),
1241 DEVICE_STATUS_DEVICE_ERROR);
1245 if (self->listen_addrs) {
1246 g_free(self->listen_addrs);
1247 self->listen_addrs = NULL;
1250 /* set up the new directtcp connection */
1251 if (self->directtcp_conn)
1252 g_object_unref(self->directtcp_conn);
1253 self->directtcp_conn =
1254 directtcp_connection_ndmp_new(self->ndmp, mode);
1255 *dtcpconn = DIRECTTCP_CONNECTION(self->directtcp_conn);
1257 /* reference it for the caller */
1258 g_object_ref(*dtcpconn);
1264 write_from_connection_impl(
1267 guint64 *actual_size)
1269 NdmpDevice *self = NDMP_DEVICE(dself);
1270 DirectTCPConnectionNDMP *nconn = self->directtcp_conn;
1271 gboolean eom = FALSE, eof = FALSE, eow = FALSE;
1272 ndmp9_mover_state mover_state;
1273 ndmp9_mover_halt_reason halt_reason;
1274 ndmp9_mover_pause_reason pause_reason;
1275 guint64 bytes_moved_before, bytes_moved_after;
1278 if (device_in_error(self)) return FALSE;
1283 /* if this is false, then the caller did not use use_connection correctly */
1284 g_assert(self->directtcp_conn != NULL);
1285 g_assert(self->ndmp == nconn->ndmp);
1286 g_assert(nconn->mode == NDMP9_MOVER_MODE_READ);
1288 if (!ndmp_connection_mover_get_state(self->ndmp,
1289 &mover_state, &bytes_moved_before, NULL, NULL)) {
1290 set_error_from_ndmp(self);
1294 /* the mover had best be PAUSED right now */
1295 g_assert(mover_state == NDMP9_MOVER_STATE_PAUSED);
1297 if (!ndmp_connection_mover_set_window(self->ndmp,
1299 size? size : G_MAXUINT64 - nconn->offset)) {
1300 set_error_from_ndmp(self);
1304 if (!ndmp_connection_mover_continue(self->ndmp)) {
1305 set_error_from_ndmp(self);
1309 /* now wait for the mover to pause itself again, or halt on EOF or an error */
1310 if (!ndmp_connection_wait_for_notify(self->ndmp,
1313 &pause_reason, NULL)) {
1314 set_error_from_ndmp(self);
1320 switch (pause_reason) {
1321 case NDMP9_MOVER_PAUSE_EOM:
1325 /* ndmjob sends .._SEEK when it should send .._EOW, so deal with
1326 * both equivalently */
1327 case NDMP9_MOVER_PAUSE_EOW:
1328 case NDMP9_MOVER_PAUSE_SEEK:
1333 err = "got NOTIFY_MOVER_PAUSED, but not because of EOW or SEEK";
1336 } else if (halt_reason) {
1337 switch (halt_reason) {
1338 case NDMP9_MOVER_HALT_CONNECT_CLOSED:
1343 case NDMP9_MOVER_HALT_ABORTED:
1344 /* case NDMP9_MOVER_HALT_MEDIA_ERROR: <-- not in ndmjob */
1345 case NDMP9_MOVER_HALT_INTERNAL_ERROR:
1346 case NDMP9_MOVER_HALT_CONNECT_ERROR:
1347 err = "unexpected NDMP_NOTIFY_MOVER_HALTED";
1353 device_set_error(DEVICE(self),
1354 g_strdup_printf("waiting for accept: %s", err),
1355 DEVICE_STATUS_DEVICE_ERROR);
1359 /* no error, so the mover stopped due to one of EOM (volume out of space),
1360 * EOF (data connection is done), or EOW (maximum part size was written).
1361 * In any case, we want to know how many bytes were written. */
1363 if (!ndmp_connection_mover_get_state(self->ndmp,
1364 &mover_state, &bytes_moved_after, NULL, NULL)) {
1365 set_error_from_ndmp(self);
1368 size = bytes_moved_after - bytes_moved_before;
1369 nconn->offset += size;
1372 *actual_size = bytes_moved_after - bytes_moved_before;
1376 ; /* mover finished the whole part -- nothing to report! */
1378 DEVICE(self)->is_eof = TRUE;
1380 /* this is a *lossless* EOM, so no need to set error, but
1381 * we do need to figure out the actual size */
1382 DEVICE(self)->is_eom = TRUE;
1384 error("not reached");
1391 read_to_connection_impl(
1394 guint64 *actual_size)
1396 NdmpDevice *self = NDMP_DEVICE(dself);
1397 DirectTCPConnectionNDMP *nconn = self->directtcp_conn;
1398 gboolean eom = FALSE, eof = FALSE, eow = FALSE;
1399 ndmp9_mover_state mover_state;
1400 ndmp9_mover_halt_reason halt_reason;
1401 ndmp9_mover_pause_reason pause_reason;
1402 guint64 bytes_moved_before, bytes_moved_after;
1408 if (device_in_error(self)) return FALSE;
1410 /* if this is false, then the caller did not use use_connection correctly */
1411 g_assert(nconn != NULL);
1412 g_assert(self->ndmp == nconn->ndmp);
1413 g_assert(nconn->mode == NDMP9_MOVER_MODE_WRITE);
1415 if (!ndmp_connection_mover_get_state(self->ndmp,
1416 &mover_state, &bytes_moved_before, NULL, NULL)) {
1417 set_error_from_ndmp(self);
1421 /* the mover had best be PAUSED right now */
1422 g_assert(mover_state == NDMP9_MOVER_STATE_PAUSED);
1424 if (!ndmp_connection_mover_set_window(self->ndmp,
1426 size? size : G_MAXUINT64 - nconn->offset)) {
1427 set_error_from_ndmp(self);
1431 if (!ndmp_connection_mover_continue(self->ndmp)) {
1432 set_error_from_ndmp(self);
1436 /* now wait for the mover to pause itself again, or halt on EOF or an error */
1437 if (!ndmp_connection_wait_for_notify(self->ndmp,
1440 &pause_reason, NULL)) {
1441 set_error_from_ndmp(self);
1447 switch (pause_reason) {
1448 case NDMP9_MOVER_PAUSE_EOF:
1452 /* ndmjob sends .._SEEK when it should send .._EOW, so deal with
1453 * both equivalently */
1454 case NDMP9_MOVER_PAUSE_EOW:
1455 case NDMP9_MOVER_PAUSE_SEEK:
1460 err = "got NOTIFY_MOVER_PAUSED, but not because of EOW or SEEK";
1463 } else if (halt_reason) {
1464 switch (halt_reason) {
1465 case NDMP9_MOVER_HALT_CONNECT_CLOSED:
1470 case NDMP9_MOVER_HALT_ABORTED:
1471 /* case NDMP9_MOVER_HALT_MEDIA_ERROR: <-- not in ndmjob */
1472 case NDMP9_MOVER_HALT_INTERNAL_ERROR:
1473 case NDMP9_MOVER_HALT_CONNECT_ERROR:
1474 err = "unexpected NDMP_NOTIFY_MOVER_HALTED";
1480 device_set_error(DEVICE(self),
1481 g_strdup_printf("waiting for accept: %s", err),
1482 DEVICE_STATUS_DEVICE_ERROR);
1486 /* no error, so the mover stopped due to one of EOM (volume out of space),
1487 * EOF (data connection is done), or EOW (maximum part size was written).
1488 * In any case, we want to know how many bytes were written. */
1490 if (!ndmp_connection_mover_get_state(self->ndmp,
1491 &mover_state, &bytes_moved_after, NULL, NULL)) {
1492 set_error_from_ndmp(self);
1495 size = bytes_moved_after - bytes_moved_before;
1496 nconn->offset += size;
1499 *actual_size = bytes_moved_after - bytes_moved_before;
1503 ; /* mover finished the whole part -- nothing to report! */
1505 DEVICE(self)->is_eof = TRUE;
1507 /* this is a *lossless* EOM, so no need to set error, but
1508 * we do need to figure out the actual size */
1509 DEVICE(self)->is_eom = TRUE;
1511 error("not reached");
1518 use_connection_impl(
1520 DirectTCPConnection *conn)
1522 NdmpDevice *self = NDMP_DEVICE(dself);
1523 DirectTCPConnectionNDMP *nconn;
1525 /* the device_use_connection_impl wrapper already made sure we're in
1526 * ACCESS_NULL, but we may have opened the tape service already to read
1527 * a label - so close it to be sure */
1528 if (!close_tape_agent(self)) {
1529 /* error was already set by close_tape_agent */
1533 /* we had best not be listening when this is called */
1534 g_assert(!self->listen_addrs);
1536 if (!IS_DIRECTTCP_CONNECTION_NDMP(conn)) {
1537 device_set_error(DEVICE(self),
1538 g_strdup("existing DirectTCPConnection is not compatible with this device"),
1539 DEVICE_STATUS_DEVICE_ERROR);
1543 if (self->directtcp_conn)
1544 g_object_unref(self->directtcp_conn);
1545 self->directtcp_conn = nconn = DIRECTTCP_CONNECTION_NDMP(conn);
1546 g_object_ref(self->directtcp_conn);
1548 /* if this is a different connection, use it */
1549 if (nconn->ndmp != self->ndmp) {
1551 close_connection(self);
1552 self->ndmp = nconn->ndmp;
1553 g_object_ref(self->ndmp);
1564 ndmp_device_set_username_fn(Device *dself,
1565 DevicePropertyBase *base, GValue *val,
1566 PropertySurety surety, PropertySource source)
1568 NdmpDevice *self = NDMP_DEVICE(dself);
1570 amfree(self->ndmp_username);
1571 self->ndmp_username = g_value_dup_string(val);
1572 device_clear_volume_details(dself);
1574 return device_simple_property_set_fn(dself, base, val, surety, source);
1578 ndmp_device_set_password_fn(Device *dself,
1579 DevicePropertyBase *base, GValue *val,
1580 PropertySurety surety, PropertySource source)
1582 NdmpDevice *self = NDMP_DEVICE(dself);
1584 amfree(self->ndmp_password);
1585 self->ndmp_password = g_value_dup_string(val);
1586 device_clear_volume_details(dself);
1588 return device_simple_property_set_fn(dself, base, val, surety, source);
1592 ndmp_device_set_auth_fn(Device *dself,
1593 DevicePropertyBase *base, GValue *val,
1594 PropertySurety surety, PropertySource source)
1596 NdmpDevice *self = NDMP_DEVICE(dself);
1598 amfree(self->ndmp_auth);
1599 self->ndmp_auth = g_value_dup_string(val);
1600 device_clear_volume_details(dself);
1602 return device_simple_property_set_fn(dself, base, val, surety, source);
1606 ndmp_device_set_verbose_fn(Device *p_self, DevicePropertyBase *base,
1607 GValue *val, PropertySurety surety, PropertySource source)
1609 NdmpDevice *self = NDMP_DEVICE(p_self);
1611 self->verbose = g_value_get_boolean(val);
1613 /* if the connection is active, set up verbose logging or turn it off */
1615 ndmp_connection_set_verbose(self->ndmp, self->verbose);
1619 return device_simple_property_set_fn(p_self, base, val, surety, source);
1623 ndmp_device_set_read_block_size_fn(Device *p_self, DevicePropertyBase *base G_GNUC_UNUSED,
1624 GValue *val, PropertySurety surety, PropertySource source)
1626 NdmpDevice *self = NDMP_DEVICE(p_self);
1627 gsize read_block_size = g_value_get_uint(val);
1629 if (read_block_size != 0 &&
1630 ((gsize)read_block_size < p_self->block_size ||
1631 (gsize)read_block_size > p_self->max_block_size)) {
1632 device_set_error(p_self,
1633 g_strdup_printf("Error setting READ-BLOCk-SIZE property to '%zu', it must be between %zu and %zu", read_block_size, p_self->block_size, p_self->max_block_size),
1634 DEVICE_STATUS_DEVICE_ERROR);
1638 self->read_block_size = read_block_size;
1640 /* use the READ_BLOCK_SIZE, even if we're invoked to get the old READ_BUFFER_SIZE */
1641 return device_simple_property_set_fn(p_self, base,
1642 val, surety, source);
1646 ndmp_device_class_init(NdmpDeviceClass * c G_GNUC_UNUSED)
1648 GObjectClass *g_object_class = (GObjectClass*) c;
1649 DeviceClass *device_class = (DeviceClass *)c;
1651 parent_class = g_type_class_ref (TYPE_DEVICE);
1653 device_class->open_device = ndmp_device_open_device;
1654 device_class->read_label = ndmp_device_read_label;
1655 device_class->start = ndmp_device_start;
1656 device_class->finish = ndmp_device_finish;
1657 device_class->eject = ndmp_device_eject;
1659 device_class->start_file = ndmp_device_start_file;
1660 device_class->write_block = ndmp_device_write_block;
1661 device_class->finish_file = ndmp_device_finish_file;
1663 device_class->seek_file = ndmp_device_seek_file;
1664 device_class->seek_block = ndmp_device_seek_block;
1665 device_class->read_block = ndmp_device_read_block;
1667 device_class->directtcp_supported = TRUE;
1668 device_class->listen = listen_impl;
1669 device_class->accept = accept_impl;
1670 device_class->connect = connect_impl;
1671 device_class->write_from_connection = write_from_connection_impl;
1672 device_class->read_to_connection = read_to_connection_impl;
1673 device_class->use_connection = use_connection_impl;
1675 g_object_class->finalize = ndmp_device_finalize;
1677 device_class_register_property(device_class, PROPERTY_NDMP_USERNAME,
1678 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
1679 device_simple_property_get_fn,
1680 ndmp_device_set_username_fn);
1682 device_class_register_property(device_class, PROPERTY_NDMP_PASSWORD,
1683 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
1684 device_simple_property_get_fn,
1685 ndmp_device_set_password_fn);
1687 device_class_register_property(device_class, PROPERTY_NDMP_AUTH,
1688 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
1689 device_simple_property_get_fn,
1690 ndmp_device_set_auth_fn);
1692 device_class_register_property(device_class, PROPERTY_VERBOSE,
1693 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK,
1694 device_simple_property_get_fn,
1695 ndmp_device_set_verbose_fn);
1696 device_class_register_property(device_class, PROPERTY_READ_BLOCK_SIZE,
1697 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
1698 device_simple_property_get_fn,
1699 ndmp_device_set_read_block_size_fn);
1703 ndmp_device_init(NdmpDevice *self)
1705 Device *dself = DEVICE(self);
1708 /* begin unconnected */
1711 /* decent defaults */
1712 dself->block_size = 32768;
1713 dself->min_block_size = 32768;
1714 dself->max_block_size = SIZE_MAX;
1716 bzero(&response, sizeof(response));
1718 g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
1719 g_value_set_enum(&response, CONCURRENCY_PARADIGM_EXCLUSIVE);
1720 device_set_simple_property(dself, PROPERTY_CONCURRENCY,
1721 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
1722 g_value_unset(&response);
1724 g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
1725 g_value_set_enum(&response, STREAMING_REQUIREMENT_DESIRED);
1726 device_set_simple_property(dself, PROPERTY_STREAMING,
1727 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
1728 g_value_unset(&response);
1730 g_value_init(&response, G_TYPE_BOOLEAN);
1731 g_value_set_boolean(&response, FALSE);
1732 device_set_simple_property(dself, PROPERTY_APPENDABLE,
1733 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
1734 g_value_unset(&response);
1736 g_value_init(&response, G_TYPE_BOOLEAN);
1737 g_value_set_boolean(&response, FALSE);
1738 device_set_simple_property(dself, PROPERTY_PARTIAL_DELETION,
1739 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
1740 g_value_unset(&response);
1742 g_value_init(&response, G_TYPE_BOOLEAN);
1743 g_value_set_boolean(&response, FALSE);
1744 device_set_simple_property(dself, PROPERTY_FULL_DELETION,
1745 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
1746 g_value_unset(&response);
1748 g_value_init(&response, G_TYPE_BOOLEAN);
1749 g_value_set_boolean(&response, TRUE);
1750 device_set_simple_property(dself, PROPERTY_LEOM,
1751 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
1752 g_value_unset(&response);
1754 g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
1755 g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
1756 device_set_simple_property(dself, PROPERTY_MEDIUM_ACCESS_TYPE,
1757 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
1758 g_value_unset(&response);
1760 self->read_block_size = 0;
1761 g_value_init(&response, G_TYPE_UINT);
1762 g_value_set_uint(&response, self->read_block_size);
1763 device_set_simple_property(dself, PROPERTY_READ_BLOCK_SIZE,
1764 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DEFAULT);
1765 g_value_unset(&response);
1767 g_value_init(&response, G_TYPE_STRING);
1768 g_value_set_string(&response, "ndmp");
1769 device_set_simple_property(dself, PROPERTY_NDMP_USERNAME,
1770 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
1771 g_value_unset(&response);
1772 self->ndmp_username = g_strdup("ndmp");
1774 g_value_init(&response, G_TYPE_STRING);
1775 g_value_set_string(&response, "ndmp");
1776 device_set_simple_property(dself, PROPERTY_NDMP_PASSWORD,
1777 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
1778 g_value_unset(&response);
1779 self->ndmp_password = g_strdup("ndmp");
1781 g_value_init(&response, G_TYPE_STRING);
1782 g_value_set_string(&response, "md5");
1783 device_set_simple_property(dself, PROPERTY_NDMP_AUTH,
1784 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
1785 g_value_unset(&response);
1786 self->ndmp_auth = g_strdup("md5");
1791 ndmp_device_get_type(void)
1793 static GType type = 0;
1795 if G_UNLIKELY(type == 0) {
1796 static const GTypeInfo info = {
1797 sizeof (NdmpDeviceClass),
1798 (GBaseInitFunc) NULL,
1799 (GBaseFinalizeFunc) NULL,
1800 (GClassInitFunc) ndmp_device_class_init,
1801 (GClassFinalizeFunc) NULL,
1802 NULL /* class_data */,
1803 sizeof (NdmpDevice),
1804 0 /* n_preallocs */,
1805 (GInstanceInitFunc) ndmp_device_init,
1809 type = g_type_register_static (TYPE_DEVICE, "NdmpDevice", &info,
1817 ndmp_device_factory(
1823 g_assert(0 == strcmp(device_type, NDMP_DEVICE_NAME));
1824 rval = DEVICE(g_object_new(TYPE_NDMP_DEVICE, NULL));
1826 device_open_device(rval, device_name, device_type, device_node);
1831 ndmp_device_register(void)
1833 static const char * device_prefix_list[] = { NDMP_DEVICE_NAME, NULL };
1835 /* register the device itself */
1836 register_device(ndmp_device_factory, device_prefix_list);
1838 device_property_fill_and_register(&device_property_ndmp_username,
1839 G_TYPE_STRING, "ndmp_username",
1840 "Username for access to the NDMP agent");
1841 device_property_fill_and_register(&device_property_ndmp_password,
1842 G_TYPE_STRING, "ndmp_password",
1843 "Password for access to the NDMP agent");
1844 device_property_fill_and_register(&device_property_ndmp_auth,
1845 G_TYPE_STRING, "ndmp_auth",
1846 "Authentication method for the NDMP agent - md5 (default), text, none, or void");
1850 * DirectTCPConnectionNDMP implementation
1854 directtcp_connection_ndmp_close(DirectTCPConnection *dself)
1856 DirectTCPConnectionNDMP *self = DIRECTTCP_CONNECTION_NDMP(dself);
1858 ndmp9_mover_state state;
1859 guint64 bytes_moved;
1860 ndmp9_mover_halt_reason reason;
1861 gboolean expect_notif = FALSE;
1863 /* based on the current state, we may need to abort or stop the
1864 * mover before closing it */
1865 if (!ndmp_connection_mover_get_state(self->ndmp, &state,
1866 &bytes_moved, NULL, NULL)) {
1867 rv = ndmp_connection_err_msg(self->ndmp);
1872 case NDMP9_MOVER_STATE_HALTED:
1873 break; /* nothing to do but ndmp_mover_close, below */
1875 case NDMP9_MOVER_STATE_PAUSED:
1876 if (!ndmp_connection_mover_close(self->ndmp)) {
1877 rv = ndmp_connection_err_msg(self->ndmp);
1880 expect_notif = TRUE;
1883 case NDMP9_MOVER_STATE_ACTIVE:
1885 if (!ndmp_connection_mover_abort(self->ndmp)) {
1886 rv = ndmp_connection_err_msg(self->ndmp);
1889 expect_notif = TRUE;
1893 /* the spec isn't entirely clear that mover_close and mover_abort should
1894 * generate a NOTIF_MOVER_HALTED, but ndmjob does it */
1896 if (!ndmp_connection_wait_for_notify(self->ndmp,
1898 &reason, /* value is ignored.. */
1904 if (!ndmp_connection_mover_stop(self->ndmp)) {
1905 rv = ndmp_connection_err_msg(self->ndmp);
1911 g_object_unref(self->ndmp);
1919 directtcp_connection_ndmp_class_init(DirectTCPConnectionNDMPClass * c)
1921 DirectTCPConnectionClass *connc = (DirectTCPConnectionClass *)c;
1923 connc->close = directtcp_connection_ndmp_close;
1927 directtcp_connection_ndmp_get_type (void)
1929 static GType type = 0;
1931 if G_UNLIKELY(type == 0) {
1932 static const GTypeInfo info = {
1933 sizeof (DirectTCPConnectionNDMPClass),
1934 (GBaseInitFunc) NULL,
1935 (GBaseFinalizeFunc) NULL,
1936 (GClassInitFunc) directtcp_connection_ndmp_class_init,
1937 (GClassFinalizeFunc) NULL,
1938 NULL /* class_data */,
1939 sizeof (DirectTCPConnectionNDMP),
1940 0 /* n_preallocs */,
1941 (GInstanceInitFunc) NULL,
1945 type = g_type_register_static(TYPE_DIRECTTCP_CONNECTION,
1946 "DirectTCPConnectionNDMP", &info, (GTypeFlags)0);
1952 static DirectTCPConnectionNDMP *
1953 directtcp_connection_ndmp_new(
1954 NDMPConnection *ndmp,
1955 ndmp9_mover_mode mode)
1957 DirectTCPConnectionNDMP *dcn = DIRECTTCP_CONNECTION_NDMP(
1958 g_object_new(TYPE_DIRECTTCP_CONNECTION_NDMP, NULL));
1960 /* hang onto a copy of this NDMP connection */