2 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
22 %module "Amanda::Device"
23 %include "amglue/amglue.swg"
24 %include "exception.i"
25 %import "Amanda/Header.swg";
27 %include "Amanda/Device.pod"
32 #include "fileheader.h"
33 #include "glib-util.h"
34 #include "simpleprng.h"
36 #include "sockaddr-util.h"
40 /* Initialize the Device API on load */
46 /* Utility functions for typemaps, below */
48 /* return a new, mortal SV corresponding to the given GValue
50 * @param value: the value to convert
51 * @returns: a new, mortal SV
54 set_sv_from_gvalue(GValue *value)
56 GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
59 /* complex reference types */
60 switch (fundamental) {
62 return sv_2mortal(amglue_newSVi64(g_value_get_long(value)));
65 return sv_2mortal(amglue_newSVu64(g_value_get_ulong(value)));
68 return sv_2mortal(amglue_newSVi64(g_value_get_int64(value)));
71 return sv_2mortal(amglue_newSVu64(g_value_get_uint64(value)));
74 /* simple types that can be constructed with sv_set*v */
76 switch (fundamental) {
78 sv_setiv(sv, g_value_get_char(value));
82 sv_setuv(sv, g_value_get_uchar(value));
86 sv_setiv(sv, g_value_get_boolean(value));
90 sv_setiv(sv, g_value_get_int(value));
94 sv_setuv(sv, g_value_get_uint(value));
98 sv_setnv(sv, g_value_get_float(value));
102 sv_setnv(sv, g_value_get_double(value));
106 sv_setpv(sv, g_value_get_string(value));
110 sv_setiv(sv, g_value_get_enum(value));
114 sv_setiv(sv, g_value_get_flags(value));
120 case G_TYPE_INTERFACE:
123 warn("Unsupported fundamental property type #%d", (int)fundamental);
124 sv_setsv(sv, &PL_sv_undef);
131 /* Given an SV and an initialized GValue, set the GValue to the value
132 * represented by the SV. The GValue's type must already be set.
134 * For basic corresponding types (string -> string, integer -> integer),
135 * the translation is straightforward. However, if the GValue is not a
136 * string, but the SV has a string value, then g_value_set_from_string will
137 * be used to parse the string.
139 * @param sv: SV to convert
140 * @param value: (input/output) destination
141 * @returns: TRUE on success
144 set_gvalue_from_sv(SV *sv, GValue *value)
146 GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value));
148 /* if we got a string, use g_value_set_from_string to parse any funny
149 * values or suffixes */
151 if (g_value_set_from_string(value, SvPV_nolen(sv)))
155 /* otherwise, handle numeric types with SvIV, SvNV, or the amglue_* functions */
156 switch (fundamental) {
158 g_value_set_boolean(value, SvIV(sv));
162 g_value_set_char(value, amglue_SvI8(sv));
166 g_value_set_uchar(value, amglue_SvU8(sv));
170 g_value_set_int(value, amglue_SvI32(sv));
174 g_value_set_uint(value, amglue_SvU32(sv));
178 g_value_set_int64(value, amglue_SvI64(sv));
182 g_value_set_uint64(value, amglue_SvU64(sv));
186 g_value_set_int64(value, amglue_SvI64(sv));
190 g_value_set_uint64(value, amglue_SvU64(sv));
194 g_value_set_float(value, SvNV(sv));
198 g_value_set_double(value, SvNV(sv));
202 g_value_set_enum(value, SvIV(sv));
206 g_value_set_flags(value, SvIV(sv));
210 /* for anything else, let perl stringify it for us and try parsing it */
211 return g_value_set_from_string(value, SvPV_nolen(sv));
218 * DirectTCPConnection object
221 typedef struct DirectTCPConnection {
223 ~DirectTCPConnection() {
224 g_object_unref(self);
229 return directtcp_connection_close(self);
232 } DirectTCPConnection;
235 * Device struct, %extend-ed into a Perl class
238 %name(unaliased_name) extern char *device_unaliased_name(char *);
240 typedef struct Device {
245 Device(char *device_name) {
246 return device_open(device_name);
250 g_object_unref(self);
254 configure(gboolean use_global_config) {
255 return device_configure(self, use_global_config);
260 return device_error(self);
265 return device_status_error(self);
270 return device_error_or_status(self);
275 return device_read_label(self);
279 start(DeviceAccessMode mode, char *label, char *timestamp) {
280 return device_start(self, mode, label, timestamp);
285 return device_finish(self);
290 return device_get_bytes_read(self);
294 get_bytes_written() {
295 return device_get_bytes_written(self);
299 start_file(dumpfile_t *jobInfo) {
300 return device_start_file(self, jobInfo);
304 write_block(guint size, gpointer data) {
305 return device_write_block(self, size, data);
310 return device_finish_file(self);
314 seek_file(guint file) {
315 return device_seek_file(self, file);
319 seek_block(guint64 block) {
320 return device_seek_block(self, block);
324 read_block(gpointer buffer, int *size) {
325 return device_read_block(self, buffer, size);
330 return device_erase(self);
335 return device_eject(self);
339 directtcp_supported() {
340 return device_directtcp_supported(self);
344 listen(gboolean for_writing, DirectTCPAddr **addrs) {
345 /* ensure that the addresses are empty if there was an error */
346 if (!device_listen(self, for_writing, addrs))
351 use_connection(DirectTCPConnection *conn) {
352 return device_use_connection(self, conn);
355 %typemap(out) const GSList * {
358 /* Count the DeviceProperties */
359 EXTEND(SP, g_slist_length($1)); /* make room for return values */
361 /* Note that we set $result several times. the nature of
362 * SWIG's wrapping is such that incrementing argvi points
363 * $result to the next location in perl's argument stack.
366 for (iter = $1; iter; iter = g_slist_next(iter)) {
367 DeviceProperty *prop = iter->data;
369 SV *rv = newRV_noinc((SV *)hash);
371 hv_store(hash, "name", 4,
372 newSVpv(prop->base->name, 0), 0);
373 hv_store(hash, "description", 11,
374 newSVpv(prop->base->description, 0), 0);
375 hv_store(hash, "access", 6,
376 newSViv(prop->access), 0);
377 $result = sv_2mortal(rv);
381 const GSList * property_list(void) {
382 return device_property_get_list(self);
385 %typemap(out) const GSList *; /* remove typemap */
387 /* A typemap to convert a property name to a DevicePropertyBase. */
388 %typemap(in) DevicePropertyBase * {
392 pname = SvPV_nolen($input);
395 $1 = (DevicePropertyBase *)device_property_get_by_name(pname);
400 /* A typemap to convert the GValue in property_get to a return value. The
401 * (in) typemap sets up storage for the parameters, while the (argout) converts
402 * them to a perl SV. */
403 %typemap(in,numinputs=0) (GValue *out_val, PropertySurety *surety,
404 PropertySource *source, gboolean *val_found)
406 PropertySurety surety,
407 PropertySource source,
409 memset(&val, 0, sizeof(val));
411 if (GIMME_V == G_ARRAY) {
417 %typemap(argout) (GValue *out_val, PropertySurety *surety,
418 PropertySource *source, gboolean *val_found) {
419 /* if the result is valid */
421 /* move data from $1 to $result, somehow, being careful to
422 * save the perl stack while doing so */
423 SP += argvi; PUTBACK;
424 $result = set_sv_from_gvalue($1);
425 SPAGAIN; SP -= argvi; argvi++;
427 /* free any memory for the GValue */
430 if (GIMME_V == G_ARRAY) {
431 $result = newSViv(*$2);
433 $result = newSViv(*$3);
437 /* otherwise, return nothing */
441 property_get(DevicePropertyBase *pbase, GValue *out_val, PropertySurety *surety,
442 PropertySource *source, gboolean *val_found) {
444 *val_found = device_property_get_ex(self, pbase->ID, out_val, surety, source);
450 /* delete typemaps */
451 %typemap(in) (GValue *out_val, gboolean *val_found);
452 %typemap(argout) (GValue *out_val, gboolean *val_found);
454 /* We cheat a little bit here and just pass the native Perl type in to
455 * the function. This is the easiest way to make sure we know the property
456 * information (in particular, its type) before trying to convert the SV. */
457 %typemap(in) SV *sv "$1 = $input;"
460 property_set(DevicePropertyBase *pbase, SV *sv) {
465 memset(&gval, 0, sizeof(gval));
466 g_value_init(&gval, pbase->type);
467 if (!set_gvalue_from_sv(sv, &gval))
470 if (!device_property_set(self, pbase->ID, &gval))
473 g_value_unset(&gval);
476 g_value_unset(&gval);
482 property_set_ex(DevicePropertyBase *pbase, SV *sv,
483 PropertySurety surety, PropertySource source) {
485 memset(&gval, 0, sizeof(gval));
486 g_value_init(&gval, pbase->type);
487 if (!set_gvalue_from_sv(sv, &gval))
490 if (!device_property_set_ex(self, pbase->ID, &gval, surety, source))
493 g_value_unset(&gval);
496 g_value_unset(&gval);
500 gboolean recycle_file(guint filenum) {
501 return device_recycle_file(self, filenum);
504 /* accessor functions */
506 int file(void) { return self->file; }
507 guint64 block(void) { return self->block; }
508 gboolean in_file(void) { return self->in_file; }
509 char * device_name(void) { return self->device_name; }
510 DeviceAccessMode access_mode(void) { return self->access_mode; }
511 gboolean is_eof(void) { return self->is_eof; }
512 gboolean is_eom(void) { return self->is_eom; }
513 char * volume_label(void) { return self->volume_label; }
514 char * volume_time(void) { return self->volume_time; }
515 DeviceStatusFlags status(void) { return self->status; }
516 gsize min_block_size(void) { return self->min_block_size; }
517 gsize max_block_size(void) { return self->max_block_size; }
518 gsize block_size(void) { return self->block_size; }
519 gsize header_block_size(void) { return self->header_block_size; }
520 dumpfile_t *volume_header(void) { return self->volume_header; }
525 /* An alternate constructor for RAIT devices */
526 %typemap(in) GSList *child_devices {
530 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
531 SWIG_exception(SWIG_TypeError, "Expected an arrayref");
533 av = (AV *)SvRV($input);
537 for (i = 0; i <= len; i++) {
538 SV **elt = av_fetch(av, i, 0);
541 if (elt && !SvOK(*elt)) {
542 $1 = g_slist_append($1, NULL); /* 'undef' => NULL */
543 } else if (!elt || SWIG_ConvertPtr(*elt, (void **)&d, $descriptor(Device *), 0) == -1) {
544 SWIG_exception(SWIG_TypeError, "array member is not a Device");
546 $1 = g_slist_append($1, d);
550 %typemap(freearg) GSList *child_devices {
553 %newobject rait_device_open_from_children;
554 Device *rait_device_open_from_children(GSList *child_devices);
556 sub new_rait_from_children {
557 my $class = shift; # strip the $class from the arguments
558 return rait_device_open_from_children([@_]);
563 * Utilities for installchecks (not described in POD)
568 /* write LENGTH bytes of random data to FILENAME, seeded with SEED */
570 write_random_to_device(guint32 seed, size_t length, Device *device) {
571 simpleprng_state_t prng;
573 gsize block_size = device->block_size;
574 g_assert(block_size < G_MAXUINT);
576 buf = g_malloc(block_size);
577 simpleprng_seed(&prng, seed);
580 size_t to_write = min(block_size, length);
582 simpleprng_fill_buffer(&prng, buf, to_write);
583 if (!device_write_block(device, (guint)block_size, buf)) {
594 /* read LENGTH bytes of random data from FILENAME verifying it against
595 * a PRNG seeded with SEED. Sends any error messages to stderr.
598 verify_random_from_device(guint32 seed, size_t length, Device *device) {
599 simpleprng_state_t prng;
600 char *buf = NULL; /* first device_read_block will get the size */
603 simpleprng_seed(&prng, seed);
607 int size = block_size;
609 bytes_read = device_read_block(device, buf, &size);
610 if (bytes_read == 0 && size > block_size) {
613 buf = g_malloc(block_size);
616 if (bytes_read == -1) {
617 if (device->status == DEVICE_STATUS_SUCCESS) {
618 g_assert(device->is_eof);
619 g_debug("verify_random_from_device got unexpected EOF");
625 bytes_read = min(bytes_read, length);
627 if (!simpleprng_verify_buffer(&prng, buf, bytes_read))
630 length -= bytes_read;
646 amglue_add_flag_tag_fns(DeviceAccessMode);
647 amglue_add_constant_short(ACCESS_NULL, "NULL", DeviceAccessMode);
648 amglue_add_constant_short(ACCESS_READ, "READ", DeviceAccessMode);
649 amglue_add_constant_short(ACCESS_WRITE, "WRITE", DeviceAccessMode);
650 amglue_add_constant_short(ACCESS_APPEND, "APPEND", DeviceAccessMode);
652 /* (this is really a macro, but SWIG will Do The Right Thing */
653 gboolean IS_WRITABLE_ACCESS_MODE(DeviceAccessMode mode);
654 amglue_export_tag(DeviceAccessMode, IS_WRITABLE_ACCESS_MODE);
655 amglue_copy_to_tag(DeviceAccessMode, constants);
657 amglue_add_flag_tag_fns(DeviceStatusFlags);
658 amglue_add_constant_short(DEVICE_STATUS_SUCCESS, "SUCCESS", DeviceStatusFlags);
659 amglue_add_constant_short(DEVICE_STATUS_DEVICE_ERROR, "DEVICE_ERROR", DeviceStatusFlags);
660 amglue_add_constant_short(DEVICE_STATUS_DEVICE_BUSY, "DEVICE_BUSY", DeviceStatusFlags);
661 amglue_add_constant_short(DEVICE_STATUS_VOLUME_MISSING, "VOLUME_MISSING", DeviceStatusFlags);
662 amglue_add_constant_short(DEVICE_STATUS_VOLUME_UNLABELED, "VOLUME_UNLABELED", DeviceStatusFlags);
663 amglue_add_constant_short(DEVICE_STATUS_VOLUME_ERROR, "VOLUME_ERROR", DeviceStatusFlags);
664 amglue_add_constant_noshort(DEVICE_STATUS_FLAGS_MAX, DeviceStatusFlags);
665 amglue_copy_to_tag(DeviceStatusFlags, constants);
667 amglue_add_flag_tag_fns(PropertyPhaseFlags);
668 amglue_add_constant_short(PROPERTY_PHASE_BEFORE_START, "BEFORE_START", PropertyPhaseFlags);
669 amglue_add_constant_short(PROPERTY_PHASE_BETWEEN_FILE_WRITE, "BETWEEN_FILE_WRITE", PropertyPhaseFlags);
670 amglue_add_constant_short(PROPERTY_PHASE_INSIDE_FILE_WRITE, "INSIDE_FILE_WRITE", PropertyPhaseFlags);
671 amglue_add_constant_short(PROPERTY_PHASE_BETWEEN_FILE_READ, "BETWEEN_FILE_READ", PropertyPhaseFlags);
672 amglue_add_constant_short(PROPERTY_PHASE_INSIDE_FILE_READ, "INSIDE_FILE_READ", PropertyPhaseFlags);
673 amglue_add_constant_noshort(PROPERTY_PHASE_MAX, PropertyPhaseFlags);
674 amglue_add_constant_noshort(PROPERTY_PHASE_MASK, PropertyPhaseFlags);
675 amglue_add_constant_noshort(PROPERTY_PHASE_SHIFT, PropertyPhaseFlags);
676 amglue_copy_to_tag(PropertyPhaseFlags, constants);
678 amglue_add_flag_tag_fns(PropertyAccessFlags);
679 amglue_add_constant_short(PROPERTY_ACCESS_GET_BEFORE_START,
680 "GET_BEFORE_START", PropertyAccessFlags);
681 amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE,
682 "GET_BETWEEN_FILE_WRITE", PropertyAccessFlags);
683 amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE,
684 "GET_INSIDE_FILE_WRITE", PropertyAccessFlags);
685 amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_READ,
686 "GET_BETWEEN_FILE_READ", PropertyAccessFlags);
687 amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_READ,
688 "GET_INSIDE_FILE_READ", PropertyAccessFlags);
689 amglue_add_constant_short(PROPERTY_ACCESS_SET_BEFORE_START,
690 "SET_BEFORE_START", PropertyAccessFlags);
691 amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE,
692 "SET_BETWEEN_FILE_WRITE", PropertyAccessFlags);
693 amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE,
694 "SET_INSIDE_FILE_WRITE", PropertyAccessFlags);
695 amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_READ,
696 "SET_BETWEEN_FILE_READ", PropertyAccessFlags);
697 amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_READ,
698 "SET_INSIDE_FILE_READ", PropertyAccessFlags);
699 amglue_add_constant_noshort(PROPERTY_ACCESS_GET_MASK, PropertyAccessFlags);
700 amglue_add_constant_noshort(PROPERTY_ACCESS_SET_MASK, PropertyAccessFlags);
701 amglue_copy_to_tag(PropertyAccessFlags, constants);
703 amglue_add_enum_tag_fns(ConcurrencyParadigm);
704 amglue_add_constant_short(CONCURRENCY_PARADIGM_EXCLUSIVE, "EXCLUSIVE", ConcurrencyParadigm);
705 amglue_add_constant_short(CONCURRENCY_PARADIGM_SHARED_READ, "SHARED_READ", ConcurrencyParadigm);
706 amglue_add_constant_short(CONCURRENCY_PARADIGM_RANDOM_ACCESS, "RANDOM_ACCESS", ConcurrencyParadigm);
707 amglue_copy_to_tag(ConcurrencyParadigm, constants);
709 amglue_add_enum_tag_fns(StreamingRequirement);
710 amglue_add_constant_short(STREAMING_REQUIREMENT_NONE, "NONE", StreamingRequirement);
711 amglue_add_constant_short(STREAMING_REQUIREMENT_DESIRED, "DESIRED", StreamingRequirement);
712 amglue_add_constant_short(STREAMING_REQUIREMENT_REQUIRED, "REQUIRED", StreamingRequirement);
713 amglue_copy_to_tag(StreamingRequirement, constants);
715 amglue_add_enum_tag_fns(MediaAccessMode);
716 amglue_add_constant_short(MEDIA_ACCESS_MODE_READ_ONLY, "READ_ONLY", MediaAccessMode);
717 amglue_add_constant_short(MEDIA_ACCESS_MODE_WORM, "WORM", MediaAccessMode);
718 amglue_add_constant_short(MEDIA_ACCESS_MODE_READ_WRITE, "READ_WRITE", MediaAccessMode);
719 amglue_add_constant_short(MEDIA_ACCESS_MODE_WRITE_ONLY, "WRITE_ONLY", MediaAccessMode);
720 amglue_copy_to_tag(MediaAccessMode, constants);
722 amglue_add_flag_tag_fns(PropertySurety);
723 amglue_add_constant_short(PROPERTY_SURETY_BAD, "SURETY_BAD", PropertySurety);
724 amglue_add_constant_short(PROPERTY_SURETY_GOOD, "SURETY_GOOD", PropertySurety);
725 amglue_copy_to_tag(PropertySurety, constants);
727 amglue_add_flag_tag_fns(PropertySource);
728 amglue_add_constant_short(PROPERTY_SOURCE_DEFAULT, "SOURCE_DEFAULT", PropertySource);
729 amglue_add_constant_short(PROPERTY_SOURCE_DETECTED, "SOURCE_DETECTED", PropertySource);
730 amglue_add_constant_short(PROPERTY_SOURCE_USER, "SOURCE_USER", PropertySource);
731 amglue_copy_to_tag(PropertySource, constants);
735 # SWIG produces a sub-package for the Device "class", in this case named
736 # Amanda::Device::Device. For user convenience, we allow Amanda::Device->new(..) to
737 # do the same thing. This is a wrapper function, and not just a typeglob assignment,
738 # because we want to get the right blessing.
741 Amanda::Device::Device->new(@_);