2 * Copyright (c) 2007-2012 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
21 %module "Amanda::Device"
22 %include "amglue/amglue.swg"
23 %include "exception.i"
24 %import "Amanda/Header.swg";
26 %include "Amanda/Device.pod"
31 #include "fileheader.h"
32 #include "glib-util.h"
33 #include "simpleprng.h"
35 #include "sockaddr-util.h"
39 /* Initialize the Device API on load */
45 /* Utility functions for typemaps, below */
47 /* return a new, mortal SV corresponding to the given GValue
49 * @param value: the value to convert
50 * @returns: a new, mortal SV
53 set_sv_from_gvalue(GValue *value)
55 GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
58 /* complex reference types */
59 switch (fundamental) {
61 return sv_2mortal(amglue_newSVi64(g_value_get_long(value)));
64 return sv_2mortal(amglue_newSVu64(g_value_get_ulong(value)));
67 return sv_2mortal(amglue_newSVi64(g_value_get_int64(value)));
70 return sv_2mortal(amglue_newSVu64(g_value_get_uint64(value)));
73 /* simple types that can be constructed with sv_set*v */
75 switch (fundamental) {
77 sv_setiv(sv, g_value_get_char(value));
81 sv_setuv(sv, g_value_get_uchar(value));
85 sv_setiv(sv, g_value_get_boolean(value));
89 sv_setiv(sv, g_value_get_int(value));
93 sv_setuv(sv, g_value_get_uint(value));
97 sv_setnv(sv, g_value_get_float(value));
101 sv_setnv(sv, g_value_get_double(value));
105 sv_setpv(sv, g_value_get_string(value));
109 sv_setiv(sv, g_value_get_enum(value));
113 sv_setiv(sv, g_value_get_flags(value));
119 case G_TYPE_INTERFACE:
122 warn("Unsupported fundamental property type #%d", (int)fundamental);
123 sv_setsv(sv, &PL_sv_undef);
130 /* Given an SV and an initialized GValue, set the GValue to the value
131 * represented by the SV. The GValue's type must already be set.
133 * For basic corresponding types (string -> string, integer -> integer),
134 * the translation is straightforward. However, if the GValue is not a
135 * string, but the SV has a string value, then g_value_set_from_string will
136 * be used to parse the string.
138 * @param sv: SV to convert
139 * @param value: (input/output) destination
140 * @returns: TRUE on success
143 set_gvalue_from_sv(SV *sv, GValue *value)
145 GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
147 /* if we got a string, use g_value_set_from_string to parse any funny
148 * values or suffixes */
150 if (g_value_set_from_string(value, SvPV_nolen(sv)))
154 /* otherwise, handle numeric types with SvIV, SvNV, or the amglue_* functions */
155 switch (fundamental) {
157 g_value_set_boolean(value, SvIV(sv));
161 g_value_set_char(value, amglue_SvI8(sv));
165 g_value_set_uchar(value, amglue_SvU8(sv));
169 g_value_set_int(value, amglue_SvI32(sv));
173 g_value_set_uint(value, amglue_SvU32(sv));
177 g_value_set_int64(value, amglue_SvI64(sv));
181 g_value_set_uint64(value, amglue_SvU64(sv));
185 g_value_set_int64(value, amglue_SvI64(sv));
189 g_value_set_uint64(value, amglue_SvU64(sv));
193 g_value_set_float(value, SvNV(sv));
197 g_value_set_double(value, SvNV(sv));
201 g_value_set_enum(value, SvIV(sv));
205 g_value_set_flags(value, SvIV(sv));
209 /* for anything else, let perl stringify it for us and try parsing it */
210 return g_value_set_from_string(value, SvPV_nolen(sv));
217 * DirectTCPConnection object
220 typedef struct DirectTCPConnection {
222 ~DirectTCPConnection() {
223 g_object_unref(self);
228 return directtcp_connection_close(self);
231 } DirectTCPConnection;
234 * Device struct, %extend-ed into a Perl class
237 %name(unaliased_name) extern char *device_unaliased_name(char *);
239 typedef struct Device {
244 Device(char *device_name) {
245 return device_open(device_name);
249 g_object_unref(self);
253 configure(gboolean use_global_config) {
254 return device_configure(self, use_global_config);
259 return device_error(self);
264 return device_status_error(self);
269 return device_error_or_status(self);
274 return device_read_label(self);
278 start(DeviceAccessMode mode, char *label, char *timestamp) {
279 return device_start(self, mode, label, timestamp);
284 return device_finish(self);
289 return device_get_bytes_read(self);
293 get_bytes_written() {
294 return device_get_bytes_written(self);
298 start_file(dumpfile_t *jobInfo) {
299 return device_start_file(self, jobInfo);
303 write_block(guint size, gpointer data) {
304 return device_write_block(self, size, data);
309 return device_finish_file(self);
313 seek_file(guint file) {
314 return device_seek_file(self, file);
318 seek_block(guint64 block) {
319 return device_seek_block(self, block);
323 read_block(gpointer buffer, int *size) {
324 return device_read_block(self, buffer, size);
329 return device_erase(self);
334 return device_eject(self);
338 directtcp_supported() {
339 return device_directtcp_supported(self);
343 listen(gboolean for_writing, DirectTCPAddr **addrs) {
344 /* ensure that the addresses are empty if there was an error */
345 if (!device_listen(self, for_writing, addrs))
349 %newobject accept; /* connection is already ref'd, so we own it */
350 DirectTCPConnection *
352 DirectTCPConnection *conn = NULL;
355 rv = device_accept(self, &conn, NULL, NULL);
357 /* conn is ref'd for our convenience, but we don't want it */
358 g_object_unref(conn);
364 %newobject accept_with_cond; /* connection is already ref'd, so we own it */
365 DirectTCPConnection *
366 accept_with_cond(GMutex *abort_mutex, GCond *abort_cond) {
367 DirectTCPConnection *conn = NULL;
370 rv = device_accept_with_cond(self, &conn, abort_mutex, abort_cond);
372 /* conn is ref'd for our convenience, but we don't want it */
373 g_object_unref(conn);
379 %newobject connect; /* connection is already ref'd, so we own it */
380 DirectTCPConnection *
381 connect(gboolean for_writing, DirectTCPAddr *addrs) {
382 DirectTCPConnection *conn = NULL;
385 rv = device_connect(self, for_writing, addrs, &conn, NULL, NULL);
387 /* conn is ref'd for our convenience, but we don't want it */
388 g_object_unref(conn);
394 %newobject connect_with_cond; /* connection is already ref'd, so we own it */
395 DirectTCPConnection *
396 connect_with_cond(gboolean for_writing, DirectTCPAddr *addrs,
397 GMutex *abort_mutex, GCond *abort_cond) {
398 DirectTCPConnection *conn = NULL;
401 rv = device_connect_with_cond(self, for_writing, addrs, &conn,
402 abort_mutex, abort_cond);
404 /* conn is ref'd for our convenience, but we don't want it */
405 g_object_unref(conn);
412 use_connection(DirectTCPConnection *conn) {
413 return device_use_connection(self, conn);
416 %typemap(in,numinputs=0) guint64 *actual_size (guint64 sz) {
420 %typemap(argout) guint64 *actual_size {
421 SP += argvi; PUTBACK;
422 $result = sv_2mortal(amglue_newSVu64(*$1));
423 SPAGAIN; SP -= argvi; argvi++;
426 write_from_connection(guint64 size, guint64 *actual_size) {
427 return device_write_from_connection(self, size, actual_size);
431 read_to_connection(guint64 size, guint64 *actual_size) {
432 return device_read_to_connection(self, size, actual_size);
435 %typemap(out) const GSList * {
438 /* Count the DeviceProperties */
439 EXTEND(SP, g_slist_length($1)); /* make room for return values */
441 /* Note that we set $result several times. the nature of
442 * SWIG's wrapping is such that incrementing argvi points
443 * $result to the next location in perl's argument stack.
446 for (iter = $1; iter; iter = g_slist_next(iter)) {
447 DeviceProperty *prop = iter->data;
449 SV *rv = newRV_noinc((SV *)hash);
451 hv_store(hash, "name", 4,
452 newSVpv(prop->base->name, 0), 0);
453 hv_store(hash, "description", 11,
454 newSVpv(prop->base->description, 0), 0);
455 hv_store(hash, "access", 6,
456 newSViv(prop->access), 0);
457 $result = sv_2mortal(rv);
461 const GSList * property_list(void) {
462 return device_property_get_list(self);
465 %typemap(out) const GSList *; /* remove typemap */
467 /* A typemap to convert a property name to a DevicePropertyBase. */
468 %typemap(in) DevicePropertyBase * {
472 pname = SvPV_nolen($input);
475 $1 = (DevicePropertyBase *)device_property_get_by_name(pname);
480 /* A typemap to convert the GValue in property_get to a return value. The
481 * (in) typemap sets up storage for the parameters, while the (argout) converts
482 * them to a perl SV. */
483 %typemap(in,numinputs=0) (GValue *out_val, PropertySurety *surety,
484 PropertySource *source, gboolean *val_found)
486 PropertySurety surety,
487 PropertySource source,
489 memset(&val, 0, sizeof(val));
491 if (GIMME_V == G_ARRAY) {
497 %typemap(argout) (GValue *out_val, PropertySurety *surety,
498 PropertySource *source, gboolean *val_found) {
499 /* if the result is valid */
501 /* move data from $1 to $result, somehow, being careful to
502 * save the perl stack while doing so */
503 SP += argvi; PUTBACK;
504 $result = set_sv_from_gvalue($1);
505 SPAGAIN; SP -= argvi; argvi++;
507 /* free any memory for the GValue */
510 if (GIMME_V == G_ARRAY) {
511 $result = newSViv(*$2);
513 $result = newSViv(*$3);
517 /* otherwise, return nothing */
521 property_get(DevicePropertyBase *pbase, GValue *out_val, PropertySurety *surety,
522 PropertySource *source, gboolean *val_found) {
524 *val_found = device_property_get_ex(self, pbase->ID, out_val, surety, source);
530 /* delete typemaps */
531 %typemap(in) (GValue *out_val, gboolean *val_found);
532 %typemap(argout) (GValue *out_val, gboolean *val_found);
534 /* We cheat a little bit here and just pass the native Perl type in to
535 * the function. This is the easiest way to make sure we know the property
536 * information (in particular, its type) before trying to convert the SV. */
537 %typemap(in) SV *sv "$1 = $input;"
540 property_set(DevicePropertyBase *pbase, SV *sv) {
545 memset(&gval, 0, sizeof(gval));
546 g_value_init(&gval, pbase->type);
547 if (!set_gvalue_from_sv(sv, &gval))
550 if (!device_property_set(self, pbase->ID, &gval))
553 g_value_unset(&gval);
556 g_value_unset(&gval);
562 property_set_ex(DevicePropertyBase *pbase, SV *sv,
563 PropertySurety surety, PropertySource source) {
565 memset(&gval, 0, sizeof(gval));
566 g_value_init(&gval, pbase->type);
567 if (!set_gvalue_from_sv(sv, &gval))
570 if (!device_property_set_ex(self, pbase->ID, &gval, surety, source))
573 g_value_unset(&gval);
576 g_value_unset(&gval);
580 gboolean recycle_file(guint filenum) {
581 return device_recycle_file(self, filenum);
584 /* accessor functions */
586 int file(void) { return self->file; }
587 guint64 block(void) { return self->block; }
588 gboolean in_file(void) { return self->in_file; }
589 char * device_name(void) { return self->device_name; }
590 DeviceAccessMode access_mode(void) { return self->access_mode; }
591 gboolean is_eof(void) { return self->is_eof; }
592 gboolean is_eom(void) { return self->is_eom; }
593 char * volume_label(void) { return self->volume_label; }
594 char * volume_time(void) { return self->volume_time; }
595 DeviceStatusFlags status(void) { return self->status; }
596 gsize min_block_size(void) { return self->min_block_size; }
597 gsize max_block_size(void) { return self->max_block_size; }
598 gsize block_size(void) { return self->block_size; }
599 gsize header_block_size(void) { return self->header_block_size; }
600 dumpfile_t *volume_header(void) { return self->volume_header; }
605 /* An alternate constructor for RAIT devices */
606 %typemap(in) GSList *child_devices {
610 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
611 SWIG_exception(SWIG_TypeError, "Expected an arrayref");
613 av = (AV *)SvRV($input);
617 for (i = 0; i <= len; i++) {
618 SV **elt = av_fetch(av, i, 0);
621 if (elt && !SvOK(*elt)) {
622 $1 = g_slist_append($1, NULL); /* 'undef' => NULL */
623 } else if (!elt || SWIG_ConvertPtr(*elt, (void **)&d, $descriptor(Device *), 0) == -1) {
624 SWIG_exception(SWIG_TypeError, "array member is not a Device");
626 $1 = g_slist_append($1, d);
630 %typemap(freearg) GSList *child_devices {
633 %newobject rait_device_open_from_children;
634 Device *rait_device_open_from_children(GSList *child_devices);
636 sub new_rait_from_children {
637 my $class = shift; # strip the $class from the arguments
638 return rait_device_open_from_children([@_]);
643 * Utilities for installchecks (not described in POD)
648 /* write LENGTH bytes of random data to FILENAME, seeded with SEED */
650 write_random_to_device(guint32 seed, size_t length, Device *device) {
651 simpleprng_state_t prng;
653 gsize block_size = device->block_size;
654 g_assert(block_size < G_MAXUINT);
656 buf = g_malloc(block_size);
657 simpleprng_seed(&prng, seed);
660 size_t to_write = min(block_size, length);
662 simpleprng_fill_buffer(&prng, buf, to_write);
663 if (!device_write_block(device, (guint)block_size, buf)) {
674 /* read LENGTH bytes of random data from FILENAME verifying it against
675 * a PRNG seeded with SEED. Sends any error messages to stderr.
678 verify_random_from_device(guint32 seed, size_t length, Device *device) {
679 simpleprng_state_t prng;
680 char *buf = NULL; /* first device_read_block will get the size */
683 simpleprng_seed(&prng, seed);
687 int size = block_size;
689 bytes_read = device_read_block(device, buf, &size);
690 if (bytes_read == 0 && size > block_size) {
693 buf = g_malloc(block_size);
696 if (bytes_read == -1) {
697 if (device->status == DEVICE_STATUS_SUCCESS) {
698 g_assert(device->is_eof);
699 g_debug("verify_random_from_device got unexpected EOF");
705 bytes_read = min(bytes_read, length);
707 if (!simpleprng_verify_buffer(&prng, buf, bytes_read))
710 length -= bytes_read;
726 amglue_add_flag_tag_fns(DeviceAccessMode);
727 amglue_add_constant_short(ACCESS_NULL, "NULL", DeviceAccessMode);
728 amglue_add_constant_short(ACCESS_READ, "READ", DeviceAccessMode);
729 amglue_add_constant_short(ACCESS_WRITE, "WRITE", DeviceAccessMode);
730 amglue_add_constant_short(ACCESS_APPEND, "APPEND", DeviceAccessMode);
732 /* (this is really a macro, but SWIG will Do The Right Thing */
733 gboolean IS_WRITABLE_ACCESS_MODE(DeviceAccessMode mode);
734 amglue_export_tag(DeviceAccessMode, IS_WRITABLE_ACCESS_MODE);
735 amglue_copy_to_tag(DeviceAccessMode, constants);
737 amglue_add_flag_tag_fns(DeviceStatusFlags);
738 amglue_add_constant_short(DEVICE_STATUS_SUCCESS, "SUCCESS", DeviceStatusFlags);
739 amglue_add_constant_short(DEVICE_STATUS_DEVICE_ERROR, "DEVICE_ERROR", DeviceStatusFlags);
740 amglue_add_constant_short(DEVICE_STATUS_DEVICE_BUSY, "DEVICE_BUSY", DeviceStatusFlags);
741 amglue_add_constant_short(DEVICE_STATUS_VOLUME_MISSING, "VOLUME_MISSING", DeviceStatusFlags);
742 amglue_add_constant_short(DEVICE_STATUS_VOLUME_UNLABELED, "VOLUME_UNLABELED", DeviceStatusFlags);
743 amglue_add_constant_short(DEVICE_STATUS_VOLUME_ERROR, "VOLUME_ERROR", DeviceStatusFlags);
744 amglue_add_constant_noshort(DEVICE_STATUS_FLAGS_MAX, DeviceStatusFlags);
745 amglue_copy_to_tag(DeviceStatusFlags, constants);
747 amglue_add_flag_tag_fns(PropertyPhaseFlags);
748 amglue_add_constant_short(PROPERTY_PHASE_BEFORE_START, "BEFORE_START", PropertyPhaseFlags);
749 amglue_add_constant_short(PROPERTY_PHASE_BETWEEN_FILE_WRITE, "BETWEEN_FILE_WRITE", PropertyPhaseFlags);
750 amglue_add_constant_short(PROPERTY_PHASE_INSIDE_FILE_WRITE, "INSIDE_FILE_WRITE", PropertyPhaseFlags);
751 amglue_add_constant_short(PROPERTY_PHASE_BETWEEN_FILE_READ, "BETWEEN_FILE_READ", PropertyPhaseFlags);
752 amglue_add_constant_short(PROPERTY_PHASE_INSIDE_FILE_READ, "INSIDE_FILE_READ", PropertyPhaseFlags);
753 amglue_add_constant_noshort(PROPERTY_PHASE_MAX, PropertyPhaseFlags);
754 amglue_add_constant_noshort(PROPERTY_PHASE_MASK, PropertyPhaseFlags);
755 amglue_add_constant_noshort(PROPERTY_PHASE_SHIFT, PropertyPhaseFlags);
756 amglue_copy_to_tag(PropertyPhaseFlags, constants);
758 amglue_add_flag_tag_fns(PropertyAccessFlags);
759 amglue_add_constant_short(PROPERTY_ACCESS_GET_BEFORE_START,
760 "GET_BEFORE_START", PropertyAccessFlags);
761 amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE,
762 "GET_BETWEEN_FILE_WRITE", PropertyAccessFlags);
763 amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE,
764 "GET_INSIDE_FILE_WRITE", PropertyAccessFlags);
765 amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_READ,
766 "GET_BETWEEN_FILE_READ", PropertyAccessFlags);
767 amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_READ,
768 "GET_INSIDE_FILE_READ", PropertyAccessFlags);
769 amglue_add_constant_short(PROPERTY_ACCESS_SET_BEFORE_START,
770 "SET_BEFORE_START", PropertyAccessFlags);
771 amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE,
772 "SET_BETWEEN_FILE_WRITE", PropertyAccessFlags);
773 amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE,
774 "SET_INSIDE_FILE_WRITE", PropertyAccessFlags);
775 amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_READ,
776 "SET_BETWEEN_FILE_READ", PropertyAccessFlags);
777 amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_READ,
778 "SET_INSIDE_FILE_READ", PropertyAccessFlags);
779 amglue_add_constant_noshort(PROPERTY_ACCESS_GET_MASK, PropertyAccessFlags);
780 amglue_add_constant_noshort(PROPERTY_ACCESS_SET_MASK, PropertyAccessFlags);
781 amglue_copy_to_tag(PropertyAccessFlags, constants);
783 amglue_add_enum_tag_fns(ConcurrencyParadigm);
784 amglue_add_constant_short(CONCURRENCY_PARADIGM_EXCLUSIVE, "EXCLUSIVE", ConcurrencyParadigm);
785 amglue_add_constant_short(CONCURRENCY_PARADIGM_SHARED_READ, "SHARED_READ", ConcurrencyParadigm);
786 amglue_add_constant_short(CONCURRENCY_PARADIGM_RANDOM_ACCESS, "RANDOM_ACCESS", ConcurrencyParadigm);
787 amglue_copy_to_tag(ConcurrencyParadigm, constants);
789 amglue_add_enum_tag_fns(StreamingRequirement);
790 amglue_add_constant_short(STREAMING_REQUIREMENT_NONE, "NONE", StreamingRequirement);
791 amglue_add_constant_short(STREAMING_REQUIREMENT_DESIRED, "DESIRED", StreamingRequirement);
792 amglue_add_constant_short(STREAMING_REQUIREMENT_REQUIRED, "REQUIRED", StreamingRequirement);
793 amglue_copy_to_tag(StreamingRequirement, constants);
795 amglue_add_enum_tag_fns(MediaAccessMode);
796 amglue_add_constant_short(MEDIA_ACCESS_MODE_READ_ONLY, "READ_ONLY", MediaAccessMode);
797 amglue_add_constant_short(MEDIA_ACCESS_MODE_WORM, "WORM", MediaAccessMode);
798 amglue_add_constant_short(MEDIA_ACCESS_MODE_READ_WRITE, "READ_WRITE", MediaAccessMode);
799 amglue_add_constant_short(MEDIA_ACCESS_MODE_WRITE_ONLY, "WRITE_ONLY", MediaAccessMode);
800 amglue_copy_to_tag(MediaAccessMode, constants);
802 amglue_add_flag_tag_fns(PropertySurety);
803 amglue_add_constant_short(PROPERTY_SURETY_BAD, "SURETY_BAD", PropertySurety);
804 amglue_add_constant_short(PROPERTY_SURETY_GOOD, "SURETY_GOOD", PropertySurety);
805 amglue_copy_to_tag(PropertySurety, constants);
807 amglue_add_flag_tag_fns(PropertySource);
808 amglue_add_constant_short(PROPERTY_SOURCE_DEFAULT, "SOURCE_DEFAULT", PropertySource);
809 amglue_add_constant_short(PROPERTY_SOURCE_DETECTED, "SOURCE_DETECTED", PropertySource);
810 amglue_add_constant_short(PROPERTY_SOURCE_USER, "SOURCE_USER", PropertySource);
811 amglue_copy_to_tag(PropertySource, constants);
815 # SWIG produces a sub-package for the Device "class", in this case named
816 # Amanda::Device::Device. For user convenience, we allow Amanda::Device->new(..) to
817 # do the same thing. This is a wrapper function, and not just a typeglob assignment,
818 # because we want to get the right blessing.
821 Amanda::Device::Device->new(@_);