1/* 2 * Copyright (c) 2007-2013 Zmanda, Inc. All Rights Reserved. 3 * 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. 8 * 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 12 * for more details. 13 * 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 17 * 18 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300 19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com 20 */ 21 22%module "Amanda::Device" 23%include "amglue/amglue.swg" 24%include "exception.i" 25%import "Amanda/Header.swg"; 26 27%include "Amanda/Device.pod" 28 29%{ 30#include "device.h" 31#include "property.h" 32#include "fileheader.h" 33#include "glib-util.h" 34#include "simpleprng.h" 35#include "amanda.h" 36#include "sockaddr-util.h" 37%} 38 39%init %{ 40 /* Initialize the Device API on load */ 41 device_api_init(); 42%} 43 44%{ 45 46/* Utility functions for typemaps, below */ 47 48/* return a new, mortal SV corresponding to the given GValue 49 * 50 * @param value: the value to convert 51 * @returns: a new, mortal SV 52 */ 53static SV * 54set_sv_from_gvalue(GValue *value) 55{ 56 GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value)); 57 SV *sv = NULL; 58 59 /* complex reference types */ 60 switch (fundamental) { 61 case G_TYPE_LONG: 62 return sv_2mortal(amglue_newSVi64(g_value_get_long(value))); 63 64 case G_TYPE_ULONG: 65 return sv_2mortal(amglue_newSVu64(g_value_get_ulong(value))); 66 67 case G_TYPE_INT64: 68 return sv_2mortal(amglue_newSVi64(g_value_get_int64(value))); 69 70 case G_TYPE_UINT64: 71 return sv_2mortal(amglue_newSVu64(g_value_get_uint64(value))); 72 } 73 74 /* simple types that can be constructed with sv_set*v */ 75 sv = sv_newmortal(); 76 switch (fundamental) { 77 case G_TYPE_CHAR: 78 sv_setiv(sv, g_value_get_char(value)); 79 break; 80 81 case G_TYPE_UCHAR: 82 sv_setuv(sv, g_value_get_uchar(value)); 83 break; 84 85 case G_TYPE_BOOLEAN: 86 sv_setiv(sv, g_value_get_boolean(value)); 87 break; 88 89 case G_TYPE_INT: 90 sv_setiv(sv, g_value_get_int(value)); 91 break; 92 93 case G_TYPE_UINT: 94 sv_setuv(sv, g_value_get_uint(value)); 95 break; 96 97 case G_TYPE_FLOAT: 98 sv_setnv(sv, g_value_get_float(value)); 99 break; 100 101 case G_TYPE_DOUBLE: 102 sv_setnv(sv, g_value_get_double(value)); 103 break; 104 105 case G_TYPE_STRING: 106 sv_setpv(sv, g_value_get_string(value)); 107 break; 108 109 case G_TYPE_ENUM: 110 sv_setiv(sv, g_value_get_enum(value)); 111 break; 112 113 case G_TYPE_FLAGS: 114 sv_setiv(sv, g_value_get_flags(value)); 115 break; 116 117 /* Unsupported */ 118 default: 119 case G_TYPE_POINTER: 120 case G_TYPE_INTERFACE: 121 case G_TYPE_OBJECT: 122 case G_TYPE_PARAM: 123 warn("Unsupported fundamental property type #%d", (int)fundamental); 124 sv_setsv(sv, &PL_sv_undef); 125 break; 126 } 127 128 return sv; 129} 130 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. 133 * 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. 138 * 139 * @param sv: SV to convert 140 * @param value: (input/output) destination 141 * @returns: TRUE on success 142 */ 143static gboolean 144set_gvalue_from_sv(SV *sv, GValue *value) 145{ 146 GType fundamental = G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value)); 147 148 /* if we got a string, use g_value_set_from_string to parse any funny 149 * values or suffixes */ 150 if (SvPOK(sv)) { 151 if (g_value_set_from_string(value, SvPV_nolen(sv))) 152 return TRUE; 153 } 154 155 /* otherwise, handle numeric types with SvIV, SvNV, or the amglue_* functions */ 156 switch (fundamental) { 157 case G_TYPE_BOOLEAN: 158 g_value_set_boolean(value, SvIV(sv)); 159 return TRUE; 160 161 case G_TYPE_CHAR: 162 g_value_set_char(value, amglue_SvI8(sv)); 163 return TRUE; 164 165 case G_TYPE_UCHAR: 166 g_value_set_uchar(value, amglue_SvU8(sv)); 167 return TRUE; 168 169 case G_TYPE_INT: 170 g_value_set_int(value, amglue_SvI32(sv)); 171 return TRUE; 172 173 case G_TYPE_UINT: 174 g_value_set_uint(value, amglue_SvU32(sv)); 175 return TRUE; 176 177 case G_TYPE_LONG: 178 g_value_set_int64(value, amglue_SvI64(sv)); 179 return TRUE; 180 181 case G_TYPE_ULONG: 182 g_value_set_uint64(value, amglue_SvU64(sv)); 183 return TRUE; 184 185 case G_TYPE_INT64: 186 g_value_set_int64(value, amglue_SvI64(sv)); 187 return TRUE; 188 189 case G_TYPE_UINT64: 190 g_value_set_uint64(value, amglue_SvU64(sv)); 191 return TRUE; 192 193 case G_TYPE_FLOAT: 194 g_value_set_float(value, SvNV(sv)); 195 return TRUE; 196 197 case G_TYPE_DOUBLE: 198 g_value_set_double(value, SvNV(sv)); 199 return TRUE; 200 201 case G_TYPE_ENUM: 202 g_value_set_enum(value, SvIV(sv)); 203 return TRUE; 204 205 case G_TYPE_FLAGS: 206 g_value_set_flags(value, SvIV(sv)); 207 return TRUE; 208 209 default: 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)); 212 } 213} 214 215%} 216 217/* 218 * DirectTCPConnection object 219 */ 220 221typedef struct { 222 %extend { 223 ~DirectTCPConnection() { 224 g_object_unref(self); 225 }; 226 227 %newobject close; 228 char *close() { 229 return directtcp_connection_close(self); 230 } 231 }; 232} DirectTCPConnection; 233 234/* 235 * Device struct, %extend-ed into a Perl class 236 */ 237 238%name(unaliased_name) extern char *device_unaliased_name(char *); 239 240typedef struct { 241 242 /* methods */ 243 %extend { 244 /* constructor */ 245 Device(char *device_name) { 246 return device_open(device_name); 247 } 248 249 ~Device() { 250 g_object_unref(self); 251 } 252 253 gboolean 254 configure(gboolean use_global_config) { 255 return device_configure(self, use_global_config); 256 } 257 258 char * 259 error() { 260 return device_error(self); 261 } 262 263 char * 264 status_error() { 265 return device_status_error(self); 266 } 267 268 char * 269 error_or_status() { 270 return device_error_or_status(self); 271 } 272 273 DeviceStatusFlags 274 read_label() { 275 return device_read_label(self); 276 } 277 278 gboolean 279 start(DeviceAccessMode mode, char *label, char *timestamp) { 280 return device_start(self, mode, label, timestamp); 281 } 282 283 gboolean 284 finish() { 285 return device_finish(self); 286 } 287 288 guint64 289 get_bytes_read() { 290 return device_get_bytes_read(self); 291 } 292 293 guint64 294 get_bytes_written() { 295 return device_get_bytes_written(self); 296 } 297 298 gboolean 299 start_file(dumpfile_t *jobInfo) { 300 return device_start_file(self, jobInfo); 301 } 302 303 gboolean 304 write_block(guint size, gpointer data) { 305 return device_write_block(self, size, data); 306 } 307 308 gboolean 309 finish_file() { 310 return device_finish_file(self); 311 } 312 313 dumpfile_t* 314 seek_file(guint file) { 315 return device_seek_file(self, file); 316 } 317 318 gboolean 319 seek_block(guint64 block) { 320 return device_seek_block(self, block); 321 } 322 323 int 324 read_block(gpointer buffer, int *size) { 325 return device_read_block(self, buffer, size); 326 } 327 328 gboolean 329 erase() { 330 return device_erase(self); 331 } 332 333 gboolean 334 eject() { 335 return device_eject(self); 336 } 337 338 gboolean 339 directtcp_supported() { 340 return device_directtcp_supported(self); 341 } 342 343 void 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)) 347 *addrs = NULL; 348 } 349 350 gboolean 351 use_connection(DirectTCPConnection *conn) { 352 return device_use_connection(self, conn); 353 } 354 355 gboolean 356 allow_take_scribe_from() { 357 return device_allow_take_scribe_from(self); 358 } 359 360 %typemap(out) const GSList * { 361 GSList *iter; 362 363 /* Count the DeviceProperties */ 364 EXTEND(SP, g_slist_length($1)); /* make room for return values */ 365 366 /* Note that we set $result several times. the nature of 367 * SWIG's wrapping is such that incrementing argvi points 368 * $result to the next location in perl's argument stack. 369 */ 370 371 for (iter = $1; iter; iter = g_slist_next(iter)) { 372 DeviceProperty *prop = iter->data; 373 HV *hash = newHV(); 374 SV *rv = newRV_noinc((SV *)hash); 375 376 hv_store(hash, "name", 4, 377 newSVpv(prop->base->name, 0), 0); 378 hv_store(hash, "description", 11, 379 newSVpv(prop->base->description, 0), 0); 380 hv_store(hash, "access", 6, 381 newSViv(prop->access), 0); 382 $result = sv_2mortal(rv); 383 argvi++; 384 } 385 } 386 const GSList * property_list(void) { 387 return device_property_get_list(self); 388 } 389 390 %typemap(out) const GSList *; /* remove typemap */ 391 392 /* A typemap to convert a property name to a DevicePropertyBase. */ 393 %typemap(in) DevicePropertyBase * { 394 char *pname = NULL; 395 396 if (SvPOK($input)) 397 pname = SvPV_nolen($input); 398 399 if (pname) 400 $1 = (DevicePropertyBase *)device_property_get_by_name(pname); 401 else 402 $1 = NULL; 403 } 404 405 /* A typemap to convert the GValue in property_get to a return value. The 406 * (in) typemap sets up storage for the parameters, while the (argout) converts 407 * them to a perl SV. */ 408 %typemap(in,numinputs=0) (GValue *out_val, PropertySurety *surety, 409 PropertySource *source, gboolean *val_found) 410 (GValue val, 411 PropertySurety surety, 412 PropertySource source, 413 gboolean found) { 414 memset(&val, 0, sizeof(val)); 415 $1 = &val; 416 if (GIMME_V == G_ARRAY) { 417 $2 = &surety; 418 $3 = &source; 419 } 420 $4 = &found; 421 } 422 %typemap(argout) (GValue *out_val, PropertySurety *surety, 423 PropertySource *source, gboolean *val_found) { 424 /* if the result is valid */ 425 if (*$4) { 426 /* move data from $1 to $result, somehow, being careful to 427 * save the perl stack while doing so */ 428 SP += argvi; PUTBACK; 429 $result = set_sv_from_gvalue($1); 430 SPAGAIN; SP -= argvi; argvi++; 431 432 /* free any memory for the GValue */ 433 g_value_unset($1); 434 435 if (GIMME_V == G_ARRAY) { 436 $result = newSViv(*$2); 437 argvi++; 438 $result = newSViv(*$3); 439 argvi++; 440 } 441 } 442 /* otherwise, return nothing */ 443 } 444 445 void 446 property_get(DevicePropertyBase *pbase, GValue *out_val, PropertySurety *surety, 447 PropertySource *source, gboolean *val_found) { 448 if (pbase) { 449 *val_found = device_property_get_ex(self, pbase->ID, out_val, surety, source); 450 } else { 451 *val_found = FALSE; 452 } 453 } 454 455 /* delete typemaps */ 456 %typemap(in) (GValue *out_val, gboolean *val_found); 457 %typemap(argout) (GValue *out_val, gboolean *val_found); 458 459 /* We cheat a little bit here and just pass the native Perl type in to 460 * the function. This is the easiest way to make sure we know the property 461 * information (in particular, its type) before trying to convert the SV. */ 462 %typemap(in) SV *sv "$1 = $input;" 463 464 gboolean 465 property_set(DevicePropertyBase *pbase, SV *sv) { 466 GValue gval; 467 468 if (!pbase) 469 goto fail; 470 memset(&gval, 0, sizeof(gval)); 471 g_value_init(&gval, pbase->type); 472 if (!set_gvalue_from_sv(sv, &gval)) 473 goto failunset; 474 475 if (!device_property_set(self, pbase->ID, &gval)) 476 goto failunset; 477 478 g_value_unset(&gval); 479 return TRUE; 480 failunset: 481 g_value_unset(&gval); 482 fail: 483 return FALSE; 484 } 485 486 gboolean 487 property_set_ex(DevicePropertyBase *pbase, SV *sv, 488 PropertySurety surety, PropertySource source) { 489 GValue gval; 490 memset(&gval, 0, sizeof(gval)); 491 g_value_init(&gval, pbase->type); 492 if (!set_gvalue_from_sv(sv, &gval)) 493 goto fail; 494 495 if (!device_property_set_ex(self, pbase->ID, &gval, surety, source)) 496 goto fail; 497 498 g_value_unset(&gval); 499 return TRUE; 500 fail: 501 g_value_unset(&gval); 502 return FALSE; 503 } 504 505 gboolean recycle_file(guint filenum) { 506 return device_recycle_file(self, filenum); 507 } 508 509 /* accessor functions */ 510 511 int file(void) { return self->file; } 512 guint64 block(void) { return self->block; } 513 gboolean in_file(void) { return self->in_file; } 514 char * device_name(void) { return self->device_name; } 515 DeviceAccessMode access_mode(void) { return self->access_mode; } 516 gboolean is_eof(void) { return self->is_eof; } 517 gboolean is_eom(void) { return self->is_eom; } 518 char * volume_label(void) { return self->volume_label; } 519 char * volume_time(void) { return self->volume_time; } 520 DeviceStatusFlags status(void) { return self->status; } 521 gsize min_block_size(void) { return self->min_block_size; } 522 gsize max_block_size(void) { return self->max_block_size; } 523 gsize block_size(void) { return self->block_size; } 524 gsize header_block_size(void) { return self->header_block_size; } 525 dumpfile_t *volume_header(void) { return self->volume_header; } 526 }; 527 528} Device; 529 530/* An alternate constructor for RAIT devices */ 531%typemap(in) GSList *child_devices { 532 AV *av; 533 int i, len; 534 535 if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) { 536 SWIG_exception(SWIG_TypeError, "Expected an arrayref"); 537 } 538 av = (AV *)SvRV($input); 539 540 $1 = NULL; 541 len = av_len(av); 542 for (i = 0; i <= len; i++) { 543 SV **elt = av_fetch(av, i, 0); 544 Device *d; 545 546 if (elt && !SvOK(*elt)) { 547 $1 = g_slist_append($1, NULL); /* 'undef' => NULL */ 548 } else if (!elt || SWIG_ConvertPtr(*elt, (void **)&d, $descriptor(Device *), 0) == -1) { 549 SWIG_exception(SWIG_TypeError, "array member is not a Device"); 550 } else { 551 $1 = g_slist_append($1, d); 552 } 553 } 554} 555%typemap(freearg) GSList *child_devices { 556 g_slist_free($1); 557} 558%newobject rait_device_open_from_children; 559Device *rait_device_open_from_children(GSList *child_devices); 560%perlcode %{ 561sub new_rait_from_children { 562 my $class = shift; # strip the $class from the arguments 563 return rait_device_open_from_children([@_]); 564} 565%} 566 567/* 568 * Utilities for installchecks (not described in POD) 569 */ 570 571%inline %{ 572 573/* write LENGTH bytes of random data to FILENAME, seeded with SEED */ 574gboolean 575write_random_to_device(guint32 seed, size_t length, Device *device) { 576 simpleprng_state_t prng; 577 char *buf; 578 gsize block_size = device->block_size; 579 g_assert(block_size < G_MAXUINT); 580 581 buf = g_malloc(block_size); 582 simpleprng_seed(&prng, seed); 583 584 while (length) { 585 size_t to_write = min(block_size, length); 586 587 simpleprng_fill_buffer(&prng, buf, to_write); 588 if (!device_write_block(device, (guint)block_size, buf)) { 589 g_free(buf); 590 return FALSE; 591 } 592 length -= to_write; 593 } 594 595 g_free(buf); 596 return TRUE; 597} 598 599/* read LENGTH bytes of random data from FILENAME verifying it against 600 * a PRNG seeded with SEED. Sends any error messages to stderr. 601 */ 602gboolean 603verify_random_from_device(guint32 seed, size_t length, Device *device) { 604 simpleprng_state_t prng; 605 char *buf = NULL; /* first device_read_block will get the size */ 606 int block_size = 0; 607 608 simpleprng_seed(&prng, seed); 609 610 while (length) { 611 int bytes_read; 612 int size = block_size; 613 614 bytes_read = device_read_block(device, buf, &size); 615 if (bytes_read == 0 && size > block_size) { 616 g_free(buf); 617 block_size = size; 618 buf = g_malloc(block_size); 619 continue; 620 } 621 if (bytes_read == -1) { 622 if (device->status == DEVICE_STATUS_SUCCESS) { 623 g_assert(device->is_eof); 624 g_debug("verify_random_from_device got unexpected EOF"); 625 } 626 goto error; 627 } 628 629 /* strip padding */ 630 bytes_read = min(bytes_read, length); 631 632 if (!simpleprng_verify_buffer(&prng, buf, bytes_read)) 633 goto error; 634 635 length -= bytes_read; 636 } 637 638 g_free(buf); 639 return TRUE; 640 641error: 642 g_free(buf); 643 return FALSE; 644} 645%} 646 647/* 648 * Constants 649 */ 650 651amglue_add_flag_tag_fns(DeviceAccessMode); 652amglue_add_constant_short(ACCESS_NULL, "NULL", DeviceAccessMode); 653amglue_add_constant_short(ACCESS_READ, "READ", DeviceAccessMode); 654amglue_add_constant_short(ACCESS_WRITE, "WRITE", DeviceAccessMode); 655amglue_add_constant_short(ACCESS_APPEND, "APPEND", DeviceAccessMode); 656 657/* (this is really a macro, but SWIG will Do The Right Thing */ 658gboolean IS_WRITABLE_ACCESS_MODE(DeviceAccessMode mode); 659amglue_export_tag(DeviceAccessMode, IS_WRITABLE_ACCESS_MODE); 660amglue_copy_to_tag(DeviceAccessMode, constants); 661 662amglue_add_flag_tag_fns(DeviceStatusFlags); 663amglue_add_constant_short(DEVICE_STATUS_SUCCESS, "SUCCESS", DeviceStatusFlags); 664amglue_add_constant_short(DEVICE_STATUS_DEVICE_ERROR, "DEVICE_ERROR", DeviceStatusFlags); 665amglue_add_constant_short(DEVICE_STATUS_DEVICE_BUSY, "DEVICE_BUSY", DeviceStatusFlags); 666amglue_add_constant_short(DEVICE_STATUS_VOLUME_MISSING, "VOLUME_MISSING", DeviceStatusFlags); 667amglue_add_constant_short(DEVICE_STATUS_VOLUME_UNLABELED, "VOLUME_UNLABELED", DeviceStatusFlags); 668amglue_add_constant_short(DEVICE_STATUS_VOLUME_ERROR, "VOLUME_ERROR", DeviceStatusFlags); 669amglue_add_constant_noshort(DEVICE_STATUS_FLAGS_MAX, DeviceStatusFlags); 670amglue_copy_to_tag(DeviceStatusFlags, constants); 671 672amglue_add_flag_tag_fns(PropertyPhaseFlags); 673amglue_add_constant_short(PROPERTY_PHASE_BEFORE_START, "BEFORE_START", PropertyPhaseFlags); 674amglue_add_constant_short(PROPERTY_PHASE_BETWEEN_FILE_WRITE, "BETWEEN_FILE_WRITE", PropertyPhaseFlags); 675amglue_add_constant_short(PROPERTY_PHASE_INSIDE_FILE_WRITE, "INSIDE_FILE_WRITE", PropertyPhaseFlags); 676amglue_add_constant_short(PROPERTY_PHASE_BETWEEN_FILE_READ, "BETWEEN_FILE_READ", PropertyPhaseFlags); 677amglue_add_constant_short(PROPERTY_PHASE_INSIDE_FILE_READ, "INSIDE_FILE_READ", PropertyPhaseFlags); 678amglue_add_constant_noshort(PROPERTY_PHASE_MAX, PropertyPhaseFlags); 679amglue_add_constant_noshort(PROPERTY_PHASE_MASK, PropertyPhaseFlags); 680amglue_add_constant_noshort(PROPERTY_PHASE_SHIFT, PropertyPhaseFlags); 681amglue_copy_to_tag(PropertyPhaseFlags, constants); 682 683amglue_add_flag_tag_fns(PropertyAccessFlags); 684amglue_add_constant_short(PROPERTY_ACCESS_GET_BEFORE_START, 685 "GET_BEFORE_START", PropertyAccessFlags); 686amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_WRITE, 687 "GET_BETWEEN_FILE_WRITE", PropertyAccessFlags); 688amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_WRITE, 689 "GET_INSIDE_FILE_WRITE", PropertyAccessFlags); 690amglue_add_constant_short(PROPERTY_ACCESS_GET_BETWEEN_FILE_READ, 691 "GET_BETWEEN_FILE_READ", PropertyAccessFlags); 692amglue_add_constant_short(PROPERTY_ACCESS_GET_INSIDE_FILE_READ, 693 "GET_INSIDE_FILE_READ", PropertyAccessFlags); 694amglue_add_constant_short(PROPERTY_ACCESS_SET_BEFORE_START, 695 "SET_BEFORE_START", PropertyAccessFlags); 696amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_WRITE, 697 "SET_BETWEEN_FILE_WRITE", PropertyAccessFlags); 698amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE, 699 "SET_INSIDE_FILE_WRITE", PropertyAccessFlags); 700amglue_add_constant_short(PROPERTY_ACCESS_SET_BETWEEN_FILE_READ, 701 "SET_BETWEEN_FILE_READ", PropertyAccessFlags); 702amglue_add_constant_short(PROPERTY_ACCESS_SET_INSIDE_FILE_READ, 703 "SET_INSIDE_FILE_READ", PropertyAccessFlags); 704amglue_add_constant_noshort(PROPERTY_ACCESS_GET_MASK, PropertyAccessFlags); 705amglue_add_constant_noshort(PROPERTY_ACCESS_SET_MASK, PropertyAccessFlags); 706amglue_copy_to_tag(PropertyAccessFlags, constants); 707 708amglue_add_enum_tag_fns(ConcurrencyParadigm); 709amglue_add_constant_short(CONCURRENCY_PARADIGM_EXCLUSIVE, "EXCLUSIVE", ConcurrencyParadigm); 710amglue_add_constant_short(CONCURRENCY_PARADIGM_SHARED_READ, "SHARED_READ", ConcurrencyParadigm); 711amglue_add_constant_short(CONCURRENCY_PARADIGM_RANDOM_ACCESS, "RANDOM_ACCESS", ConcurrencyParadigm); 712amglue_copy_to_tag(ConcurrencyParadigm, constants); 713 714amglue_add_enum_tag_fns(StreamingRequirement); 715amglue_add_constant_short(STREAMING_REQUIREMENT_NONE, "NONE", StreamingRequirement); 716amglue_add_constant_short(STREAMING_REQUIREMENT_DESIRED, "DESIRED", StreamingRequirement); 717amglue_add_constant_short(STREAMING_REQUIREMENT_REQUIRED, "REQUIRED", StreamingRequirement); 718amglue_copy_to_tag(StreamingRequirement, constants); 719 720amglue_add_enum_tag_fns(MediaAccessMode); 721amglue_add_constant_short(MEDIA_ACCESS_MODE_READ_ONLY, "READ_ONLY", MediaAccessMode); 722amglue_add_constant_short(MEDIA_ACCESS_MODE_WORM, "WORM", MediaAccessMode); 723amglue_add_constant_short(MEDIA_ACCESS_MODE_READ_WRITE, "READ_WRITE", MediaAccessMode); 724amglue_add_constant_short(MEDIA_ACCESS_MODE_WRITE_ONLY, "WRITE_ONLY", MediaAccessMode); 725amglue_copy_to_tag(MediaAccessMode, constants); 726 727amglue_add_flag_tag_fns(PropertySurety); 728amglue_add_constant_short(PROPERTY_SURETY_BAD, "SURETY_BAD", PropertySurety); 729amglue_add_constant_short(PROPERTY_SURETY_GOOD, "SURETY_GOOD", PropertySurety); 730amglue_copy_to_tag(PropertySurety, constants); 731 732amglue_add_flag_tag_fns(PropertySource); 733amglue_add_constant_short(PROPERTY_SOURCE_DEFAULT, "SOURCE_DEFAULT", PropertySource); 734amglue_add_constant_short(PROPERTY_SOURCE_DETECTED, "SOURCE_DETECTED", PropertySource); 735amglue_add_constant_short(PROPERTY_SOURCE_USER, "SOURCE_USER", PropertySource); 736amglue_copy_to_tag(PropertySource, constants); 737 738%perlcode %{ 739 740# SWIG produces a sub-package for the Device "class", in this case named 741# Amanda::Device::Device. For user convenience, we allow Amanda::Device->new(..) to 742# do the same thing. This is a wrapper function, and not just a typeglob assignment, 743# because we want to get the right blessing. 744sub new { 745 my $pkg = shift; 746 Amanda::Device::Device->new(@_); 747} 748%} 749