X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=perl%2FAmanda%2FDevice.swg;fp=perl%2FAmanda%2FDevice.swg;h=d40031605f9bbb5955f3b74857ced43ba0212182;hb=538ae376635af705ebcd686f3b4b7b72a6652985;hp=b83d70b556590608ef984f093a3d79a752db722a;hpb=11425c69eb58b6103beb68adc13912735ba36975;p=debian%2Famanda diff --git a/perl/Amanda/Device.swg b/perl/Amanda/Device.swg index b83d70b..d400316 100644 --- a/perl/Amanda/Device.swg +++ b/perl/Amanda/Device.swg @@ -1,159 +1,38 @@ /* - * Copyright (c) Zmanda, Inc. All Rights Reserved. + * Copyright (c) 2007, 2008, 2009, 2010 Zmanda, Inc. All Rights Reserved. * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 2.1 - * as published by the Free Software Foundation. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. * - * This library is distributed in the hope that it will be useful, but + * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300 - * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com + * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300 + * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com */ %module "Amanda::Device" %include "amglue/amglue.swg" %include "exception.i" +%import "Amanda/Header.swg"; + +%include "Amanda/Device.pod" %{ #include "device.h" #include "property.h" #include "fileheader.h" -%} - -/* import dumptype_t, among others */ -%import "Amanda/Types.swg"; - -%perlcode %{ -=head1 NAME - -Amanda::Device - interact with Amanda data-storage devices - -=head1 SYNOPSIS - - use Amanda::Device qw( :constants ); - - my $dev = Amanda::Device->new($device_name); - if ($dev->read_label() == $DEVICE_STATUS_SUCCESS) { - print "Label on $device_name is '$dev->volume_label'\n"; - } - -See http://wiki.zmanda.com/index.php/Device_API for details on how Devices are used. - -=head1 API STATUS - -Stable - -=head1 Amanda::Device Objects - -See the wiki for descriptions of these functions. Note that C instance variables -are represented by accessor functions of the same name. - -=over - -=item C - -=item C - -=item C - -=item C - -=item C - -where C<$jobinfo> is a C (see L) - -=item C - -Note that Perl code is not expected to handle on-device data, so there -is currently no way to provide data to this function from Perl. This may -change in future revisions. - -=item C - -where C<$fd> is an integer file descriptor, not a filehandle - -=item C - -=item C - -=item C - -=item C - -=item C - -where C<$fd> is an integer file descriptor, not a filehandle - -Note that Perl code is not expected to handle on-device data, so there -is currently no way to access the data this function returns. This may -change in future revisions. - -=item C - -returns a list of properties, each represented as a hash: - - { 'access' => $access_flags, - 'name' => $property_name, - 'description' => $property_description } - -=item C - -returns the property, with the appropriate Perl type, or undef. In array -context, returns the list C<($value, $surety, $source)>. - -=item C - -=item C - -where C<$value> is of an appropriate type for the given property, C<$surety> is -a C<$PROPERTY_SURETY_*> constant, and C<$source> is a C<$PROPERTY_SOURCE_*> -constant. - -=item C - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=item C (accessor function) - -=back - -=head1 CONSTANTS - -This module defines a large number of constants. Again, consult the -wiki or C for the details on their meaning. These constants -are available from the package namespace (e.g., -C), or imported with the C<:constant> -import tag. - -=cut +#include "glib-util.h" +#include "simpleprng.h" +#include "amanda.h" +#include "sockaddr-util.h" %} %init %{ @@ -165,6 +44,11 @@ import tag. /* Utility functions for typemaps, below */ +/* return a new, mortal SV corresponding to the given GValue + * + * @param value: the value to convert + * @returns: a new, mortal SV + */ static SV * set_sv_from_gvalue(GValue *value) { @@ -174,44 +58,16 @@ set_sv_from_gvalue(GValue *value) /* complex reference types */ switch (fundamental) { case G_TYPE_LONG: - sv = sv_2mortal(amglue_newSVi64(g_value_get_long(value))); - break; + return sv_2mortal(amglue_newSVi64(g_value_get_long(value))); case G_TYPE_ULONG: - sv = sv_2mortal(amglue_newSVu64(g_value_get_ulong(value))); - break; + return sv_2mortal(amglue_newSVu64(g_value_get_ulong(value))); case G_TYPE_INT64: - sv = sv_2mortal(amglue_newSVi64(g_value_get_int64(value))); - break; + return sv_2mortal(amglue_newSVi64(g_value_get_int64(value))); case G_TYPE_UINT64: - sv = sv_2mortal(amglue_newSVu64(g_value_get_uint64(value))); - break; - - case G_TYPE_BOXED: { - GType boxed_type = G_VALUE_TYPE(value); - QualifiedSize qs; - HV *hv; - - if (boxed_type == QUALIFIED_SIZE_TYPE) { - qs = *(QualifiedSize*)(g_value_get_boxed(value)); - - /* build a hash */ - hv = (HV *)sv_2mortal((SV *)newHV()); - hv_store(hv, "accuracy", 8, newSViv(qs.accuracy), 0); - hv_store(hv, "bytes", 5, amglue_newSVi64(qs.bytes), 0); - - sv = newRV((SV *)hv); - return newRV((SV *)hv); - } else { - warn("Unsupported boxed property type #%d", (int)boxed_type); - - sv = sv_newmortal(); - sv_setsv(sv, &PL_sv_undef); - return sv; - } - } + return sv_2mortal(amglue_newSVu64(g_value_get_uint64(value))); } /* simple types that can be constructed with sv_set*v */ @@ -271,116 +127,114 @@ set_sv_from_gvalue(GValue *value) return sv; } +/* Given an SV and an initialized GValue, set the GValue to the value + * represented by the SV. The GValue's type must already be set. + * + * For basic corresponding types (string -> string, integer -> integer), + * the translation is straightforward. However, if the GValue is not a + * string, but the SV has a string value, then g_value_set_from_string will + * be used to parse the string. + * + * @param sv: SV to convert + * @param value: (input/output) destination + * @returns: TRUE on success + */ static gboolean set_gvalue_from_sv(SV *sv, GValue *value) { GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value)); - switch (fundamental) { - case G_TYPE_CHAR: - if (!SvIOK(sv)) return FALSE; - g_value_set_char(value, SvIV(sv)); - break; - case G_TYPE_UCHAR: - if (!SvIOK(sv)) return FALSE; - g_value_set_uchar(value, SvUV(sv)); - break; + /* if we got a string, use g_value_set_from_string to parse any funny + * values or suffixes */ + if (SvPOK(sv)) { + if (g_value_set_from_string(value, SvPV_nolen(sv))) + return TRUE; + } + /* otherwise, handle numeric types with SvIV, SvNV, or the amglue_* functions */ + switch (fundamental) { case G_TYPE_BOOLEAN: - if (!SvIOK(sv)) return FALSE; g_value_set_boolean(value, SvIV(sv)); - break; + return TRUE; + + case G_TYPE_CHAR: + g_value_set_char(value, amglue_SvI8(sv)); + return TRUE; + + case G_TYPE_UCHAR: + g_value_set_uchar(value, amglue_SvU8(sv)); + return TRUE; case G_TYPE_INT: g_value_set_int(value, amglue_SvI32(sv)); - break; + return TRUE; case G_TYPE_UINT: g_value_set_uint(value, amglue_SvU32(sv)); - break; + return TRUE; case G_TYPE_LONG: g_value_set_int64(value, amglue_SvI64(sv)); - break; + return TRUE; case G_TYPE_ULONG: g_value_set_uint64(value, amglue_SvU64(sv)); - break; + return TRUE; case G_TYPE_INT64: g_value_set_int64(value, amglue_SvI64(sv)); - break; + return TRUE; case G_TYPE_UINT64: g_value_set_uint64(value, amglue_SvU64(sv)); - break; + return TRUE; case G_TYPE_FLOAT: - if (!SvNOK(sv)) return FALSE; g_value_set_float(value, SvNV(sv)); - break; + return TRUE; case G_TYPE_DOUBLE: - if (!SvNOK(sv)) return FALSE; g_value_set_double(value, SvNV(sv)); - break; - - case G_TYPE_STRING: - if (!SvPOK(sv)) return FALSE; - g_value_set_string(value, SvPV_nolen(sv)); - break; + return TRUE; - case G_TYPE_ENUM: - if (!SvIOK(sv)) return FALSE; + case G_TYPE_ENUM: g_value_set_enum(value, SvIV(sv)); - break; + return TRUE; case G_TYPE_FLAGS: - if (!SvIOK(sv)) return FALSE; g_value_set_flags(value, SvIV(sv)); - break; + return TRUE; - /* Unsupported */ default: - case G_TYPE_POINTER: - case G_TYPE_INTERFACE: - case G_TYPE_BOXED: /* note: *getting* boxed values is supported */ - case G_TYPE_OBJECT: - case G_TYPE_PARAM: - return FALSE; + /* for anything else, let perl stringify it for us and try parsing it */ + return g_value_set_from_string(value, SvPV_nolen(sv)); } - - return TRUE; } %} /* - * Device struct, %extend-ed into a Perl class + * DirectTCPConnection object */ -typedef struct queue_fd_t { - /* Instance variables -- all readonly */ - %immutable; - int fd; - char *errmsg; - - %mutable; - - /* methods */ +typedef struct DirectTCPConnection { %extend { - /* constructor */ - queue_fd_t(int fd) { - return queue_fd_new(fd, NULL); - } + ~DirectTCPConnection() { + g_object_unref(self); + }; - /* destructor */ - ~queue_fd_t() { - amfree(self->errmsg); - g_free(self); + %newobject close; + char *close() { + return directtcp_connection_close(self); } - } -} queue_fd_t; + }; +} DirectTCPConnection; + +/* + * Device struct, %extend-ed into a Perl class + */ + +%name(unaliased_name) extern char *device_unaliased_name(char *); typedef struct Device { @@ -440,11 +294,6 @@ typedef struct Device { return device_write_block(self, size, data); } - gboolean - write_from_fd(queue_fd_t *queue_fd) { - return device_write_from_fd(self, queue_fd); - } - gboolean finish_file() { return device_finish_file(self); @@ -465,8 +314,80 @@ typedef struct Device { return device_read_block(self, buffer, size); } - gboolean read_to_fd(queue_fd_t *queue_fd) { - return device_read_to_fd(self, queue_fd); + gboolean + erase() { + return device_erase(self); + } + + gboolean + eject() { + return device_eject(self); + } + + gboolean + directtcp_supported() { + return device_directtcp_supported(self); + } + + void + listen(gboolean for_writing, DirectTCPAddr **addrs) { + /* ensure that the addresses are empty if there was an error */ + if (!device_listen(self, for_writing, addrs)) + *addrs = NULL; + } + + %newobject accept; /* connection is already ref'd, so we own it */ + DirectTCPConnection * + accept() { + DirectTCPConnection *conn = NULL; + gboolean rv; + + rv = device_accept(self, &conn, NULL, NULL); + if (!rv && conn) { + /* conn is ref'd for our convenience, but we don't want it */ + g_object_unref(conn); + conn = NULL; + } + return conn; + } + + %newobject connect; /* connection is already ref'd, so we own it */ + DirectTCPConnection * + connect(gboolean for_writing, DirectTCPAddr *addrs) { + DirectTCPConnection *conn = NULL; + gboolean rv; + + rv = device_connect(self, for_writing, addrs, &conn, NULL, NULL); + if (!rv && conn) { + /* conn is ref'd for our convenience, but we don't want it */ + g_object_unref(conn); + conn = NULL; + } + return conn; + } + + gboolean + use_connection(DirectTCPConnection *conn) { + return device_use_connection(self, conn); + } + + %typemap(in,numinputs=0) guint64 *actual_size (guint64 sz) { + sz = 0; + $1 = &sz; + } + %typemap(argout) guint64 *actual_size { + SP += argvi; PUTBACK; + $result = sv_2mortal(amglue_newSVu64(*$1)); + SPAGAIN; SP -= argvi; argvi++; + } + gboolean + write_from_connection(guint64 size, guint64 *actual_size) { + return device_write_from_connection(self, size, actual_size); + } + + gboolean + read_to_connection(guint64 size, guint64 *actual_size) { + return device_read_to_connection(self, size, actual_size); } %typemap(out) const GSList * { @@ -508,10 +429,10 @@ typedef struct Device { if (SvPOK($input)) pname = SvPV_nolen($input); - if (pname) $1 = (DevicePropertyBase *)device_property_get_by_name(pname); - if (!pname || !$1) { - SWIG_exception_fail(SWIG_ValueError, "Invalid property name"); - } + if (pname) + $1 = (DevicePropertyBase *)device_property_get_by_name(pname); + else + $1 = NULL; } /* A typemap to convert the GValue in property_get to a return value. The @@ -535,9 +456,11 @@ typedef struct Device { PropertySource *source, gboolean *val_found) { /* if the result is valid */ if (*$4) { - /* move data from $1 to $result, somehow */ + /* move data from $1 to $result, somehow, being careful to + * save the perl stack while doing so */ + SP += argvi; PUTBACK; $result = set_sv_from_gvalue($1); - argvi++; + SPAGAIN; SP -= argvi; argvi++; /* free any memory for the GValue */ g_value_unset($1); @@ -555,7 +478,11 @@ typedef struct Device { void property_get(DevicePropertyBase *pbase, GValue *out_val, PropertySurety *surety, PropertySource *source, gboolean *val_found) { - *val_found = device_property_get_ex(self, pbase->ID, out_val, surety, source); + if (pbase) { + *val_found = device_property_get_ex(self, pbase->ID, out_val, surety, source); + } else { + *val_found = FALSE; + } } /* delete typemaps */ @@ -570,18 +497,22 @@ typedef struct Device { gboolean property_set(DevicePropertyBase *pbase, SV *sv) { GValue gval; + + if (!pbase) + goto fail; memset(&gval, 0, sizeof(gval)); g_value_init(&gval, pbase->type); if (!set_gvalue_from_sv(sv, &gval)) - goto fail; + goto failunset; if (!device_property_set(self, pbase->ID, &gval)) - goto fail; + goto failunset; g_value_unset(&gval); return TRUE; - fail: + failunset: g_value_unset(&gval); + fail: return FALSE; } @@ -607,7 +538,7 @@ typedef struct Device { gboolean recycle_file(guint filenum) { return device_recycle_file(self, filenum); } - + /* accessor functions */ int file(void) { return self->file; } @@ -616,17 +547,136 @@ typedef struct Device { char * device_name(void) { return self->device_name; } DeviceAccessMode access_mode(void) { return self->access_mode; } gboolean is_eof(void) { return self->is_eof; } + gboolean is_eom(void) { return self->is_eom; } char * volume_label(void) { return self->volume_label; } char * volume_time(void) { return self->volume_time; } DeviceStatusFlags status(void) { return self->status; } gsize min_block_size(void) { return self->min_block_size; } gsize max_block_size(void) { return self->max_block_size; } gsize block_size(void) { return self->block_size; } + gsize header_block_size(void) { return self->header_block_size; } dumpfile_t *volume_header(void) { return self->volume_header; } }; } Device; +/* An alternate constructor for RAIT devices */ +%typemap(in) GSList *child_devices { + AV *av; + int i, len; + + if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) { + SWIG_exception(SWIG_TypeError, "Expected an arrayref"); + } + av = (AV *)SvRV($input); + + $1 = NULL; + len = av_len(av); + for (i = 0; i <= len; i++) { + SV **elt = av_fetch(av, i, 0); + Device *d; + + if (elt && !SvOK(*elt)) { + $1 = g_slist_append($1, NULL); /* 'undef' => NULL */ + } else if (!elt || SWIG_ConvertPtr(*elt, (void **)&d, $descriptor(Device *), 0) == -1) { + SWIG_exception(SWIG_TypeError, "array member is not a Device"); + } else { + $1 = g_slist_append($1, d); + } + } +} +%typemap(freearg) GSList *child_devices { + g_slist_free($1); +} +%newobject rait_device_open_from_children; +Device *rait_device_open_from_children(GSList *child_devices); +%perlcode %{ +sub new_rait_from_children { + my $class = shift; # strip the $class from the arguments + return rait_device_open_from_children([@_]); +} +%} + +/* + * Utilities for installchecks (not described in POD) + */ + +%inline %{ + +/* write LENGTH bytes of random data to FILENAME, seeded with SEED */ +gboolean +write_random_to_device(guint32 seed, size_t length, Device *device) { + simpleprng_state_t prng; + char *buf; + gsize block_size = device->block_size; + g_assert(block_size < G_MAXUINT); + + buf = g_malloc(block_size); + simpleprng_seed(&prng, seed); + + while (length) { + size_t to_write = min(block_size, length); + + simpleprng_fill_buffer(&prng, buf, to_write); + if (!device_write_block(device, (guint)block_size, buf)) { + g_free(buf); + return FALSE; + } + length -= to_write; + } + + g_free(buf); + return TRUE; +} + +/* read LENGTH bytes of random data from FILENAME verifying it against + * a PRNG seeded with SEED. Sends any error messages to stderr. + */ +gboolean +verify_random_from_device(guint32 seed, size_t length, Device *device) { + simpleprng_state_t prng; + char *buf = NULL; /* first device_read_block will get the size */ + int block_size = 0; + + simpleprng_seed(&prng, seed); + + while (length) { + int bytes_read; + int size = block_size; + + bytes_read = device_read_block(device, buf, &size); + if (bytes_read == 0 && size > block_size) { + g_free(buf); + block_size = size; + buf = g_malloc(block_size); + continue; + } + if (bytes_read == -1) { + if (device->status == DEVICE_STATUS_SUCCESS) { + g_assert(device->is_eof); + g_debug("verify_random_from_device got unexpected EOF"); + } + goto error; + } + + /* strip padding */ + bytes_read = min(bytes_read, length); + + if (!simpleprng_verify_buffer(&prng, buf, bytes_read)) + goto error; + + length -= bytes_read; + } + + g_free(buf); + return TRUE; + +error: + g_free(buf); + return FALSE; +} +%} + /* * Constants */ @@ -664,25 +714,25 @@ amglue_add_constant_noshort(PROPERTY_PHASE_SHIFT, PropertyPhaseFlags); amglue_copy_to_tag(PropertyPhaseFlags, constants); amglue_add_flag_tag_fns(PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_GET_BEFORE_START, +amglue_add_constant_short(PROPERTY_ACCESS_GET_BEFORE_START, "GET_BEFORE_START", PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE, +amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE, "GET_BETWEEN_FILE_WRITE", PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE, +amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE, "GET_INSIDE_FILE_WRITE", PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_READ, +amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_READ, "GET_BETWEEN_FILE_READ", PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_READ, +amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_READ, "GET_INSIDE_FILE_READ", PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_SET_BEFORE_START, +amglue_add_constant_short(PROPERTY_ACCESS_SET_BEFORE_START, "SET_BEFORE_START", PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE, +amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE, "SET_BETWEEN_FILE_WRITE", PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE, +amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE, "SET_INSIDE_FILE_WRITE", PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_READ, +amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_READ, "SET_BETWEEN_FILE_READ", PropertyAccessFlags); -amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_READ, +amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_READ, "SET_INSIDE_FILE_READ", PropertyAccessFlags); amglue_add_constant_noshort(PROPERTY_ACCESS_GET_MASK, PropertyAccessFlags); amglue_add_constant_noshort(PROPERTY_ACCESS_SET_MASK, PropertyAccessFlags); @@ -707,12 +757,6 @@ amglue_add_constant_short(MEDIA_ACCESS_MODE_READ_WRITE, "READ_WRITE", MediaAcces amglue_add_constant_short(MEDIA_ACCESS_MODE_WRITE_ONLY, "WRITE_ONLY", MediaAccessMode); amglue_copy_to_tag(MediaAccessMode, constants); -amglue_add_enum_tag_fns(SizeAccuracy); -amglue_add_constant_short(SIZE_ACCURACY_UNKNOWN, "UNKNOWN", SizeAccuracy); -amglue_add_constant_short(SIZE_ACCURACY_ESTIMATE, "ESTIMATE", SizeAccuracy); -amglue_add_constant_short(SIZE_ACCURACY_REAL, "REAL", SizeAccuracy); -amglue_copy_to_tag(SizeAccuracy, constants); - amglue_add_flag_tag_fns(PropertySurety); amglue_add_constant_short(PROPERTY_SURETY_BAD, "SURETY_BAD", PropertySurety); amglue_add_constant_short(PROPERTY_SURETY_GOOD, "SURETY_GOOD", PropertySurety); @@ -726,7 +770,7 @@ amglue_copy_to_tag(PropertySource, constants); %perlcode %{ -# SWIG produces a sub-package for the Device "class", in this case named +# SWIG produces a sub-package for the Device "class", in this case named # Amanda::Device::Device. For user convenience, we allow Amanda::Device->new(..) to # do the same thing. This is a wrapper function, and not just a typeglob assignment, # because we want to get the right blessing.