Imported Upstream version 3.3.3
[debian/amanda] / perl / Amanda / Device.swg
1 /*
2  * Copyright (c) 2007-2012 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  */
53 static SV *
54 set_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  */
143 static gboolean
144 set_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
221 typedef struct DirectTCPConnection {
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
240 typedef struct Device {
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         %typemap(out) const GSList * {
356             GSList *iter;
357
358             /* Count the DeviceProperties */
359             EXTEND(SP, g_slist_length($1)); /* make room for return values */
360
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.
364              */
365
366             for (iter = $1; iter; iter = g_slist_next(iter)) {
367                 DeviceProperty *prop = iter->data;
368                 HV *hash = newHV();
369                 SV *rv = newRV_noinc((SV *)hash);
370
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);
378                 argvi++;
379             }
380         }
381         const GSList * property_list(void) {
382             return device_property_get_list(self);
383         }
384
385         %typemap(out) const GSList *; /* remove typemap */
386
387         /* A typemap to convert a property name to a DevicePropertyBase. */
388         %typemap(in) DevicePropertyBase * {
389             char *pname = NULL;
390
391             if (SvPOK($input))
392                 pname = SvPV_nolen($input);
393
394             if (pname)
395                 $1 = (DevicePropertyBase *)device_property_get_by_name(pname);
396             else
397                 $1 = NULL;
398         }
399
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)
405                             (GValue val,
406                              PropertySurety surety,
407                              PropertySource source,
408                              gboolean found) {
409             memset(&val, 0, sizeof(val));
410             $1 = &val;
411             if (GIMME_V == G_ARRAY) {
412                 $2 = &surety;
413                 $3 = &source;
414             }
415             $4 = &found;
416         }
417         %typemap(argout) (GValue *out_val, PropertySurety *surety,
418                           PropertySource *source, gboolean *val_found) {
419             /* if the result is valid */
420             if (*$4) {
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++;
426
427                 /* free any memory for the GValue */
428                 g_value_unset($1);
429
430                 if (GIMME_V == G_ARRAY) {
431                     $result = newSViv(*$2);
432                     argvi++;
433                     $result = newSViv(*$3);
434                     argvi++;
435                 }
436             }
437             /* otherwise, return nothing */
438         }
439
440         void
441         property_get(DevicePropertyBase *pbase, GValue *out_val, PropertySurety *surety,
442                      PropertySource *source, gboolean *val_found) {
443             if (pbase) {
444                 *val_found = device_property_get_ex(self, pbase->ID, out_val, surety, source);
445             } else {
446                 *val_found = FALSE;
447             }
448         }
449
450         /* delete typemaps */
451         %typemap(in) (GValue *out_val, gboolean *val_found);
452         %typemap(argout) (GValue *out_val, gboolean *val_found);
453
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;"
458
459         gboolean
460         property_set(DevicePropertyBase *pbase, SV *sv) {
461             GValue gval;
462
463             if (!pbase)
464                 goto fail;
465             memset(&gval, 0, sizeof(gval));
466             g_value_init(&gval, pbase->type);
467             if (!set_gvalue_from_sv(sv, &gval))
468                 goto failunset;
469
470             if (!device_property_set(self, pbase->ID, &gval))
471                 goto failunset;
472
473             g_value_unset(&gval);
474             return TRUE;
475         failunset:
476             g_value_unset(&gval);
477         fail:
478             return FALSE;
479         }
480
481         gboolean
482         property_set_ex(DevicePropertyBase *pbase, SV *sv,
483                         PropertySurety surety, PropertySource source) {
484             GValue gval;
485             memset(&gval, 0, sizeof(gval));
486             g_value_init(&gval, pbase->type);
487             if (!set_gvalue_from_sv(sv, &gval))
488                 goto fail;
489
490             if (!device_property_set_ex(self, pbase->ID, &gval, surety, source))
491                 goto fail;
492
493             g_value_unset(&gval);
494             return TRUE;
495         fail:
496             g_value_unset(&gval);
497             return FALSE;
498         }
499
500         gboolean recycle_file(guint filenum) {
501             return device_recycle_file(self, filenum);
502         }
503
504         /* accessor functions */
505
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; }
521     };
522
523 } Device;
524
525 /* An alternate constructor for RAIT devices */
526 %typemap(in) GSList *child_devices {
527     AV *av;
528     int i, len;
529
530     if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV) {
531         SWIG_exception(SWIG_TypeError, "Expected an arrayref");
532     }
533     av = (AV *)SvRV($input);
534
535     $1 = NULL;
536     len = av_len(av);
537     for (i = 0; i <= len; i++) {
538         SV **elt = av_fetch(av, i, 0);
539         Device *d;
540
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");
545         } else {
546             $1 = g_slist_append($1, d);
547         }
548     }
549 }
550 %typemap(freearg) GSList *child_devices {
551     g_slist_free($1);
552 }
553 %newobject rait_device_open_from_children;
554 Device *rait_device_open_from_children(GSList *child_devices);
555 %perlcode %{
556 sub new_rait_from_children {
557     my $class = shift; # strip the $class from the arguments
558     return rait_device_open_from_children([@_]);
559 }
560 %}
561
562 /*
563  * Utilities for installchecks (not described in POD)
564  */
565
566 %inline %{
567
568 /* write LENGTH bytes of random data to FILENAME, seeded with SEED */
569 gboolean
570 write_random_to_device(guint32 seed, size_t length, Device *device) {
571     simpleprng_state_t prng;
572     char *buf;
573     gsize block_size = device->block_size;
574     g_assert(block_size < G_MAXUINT);
575
576     buf = g_malloc(block_size);
577     simpleprng_seed(&prng, seed);
578
579     while (length) {
580         size_t to_write = min(block_size, length);
581
582         simpleprng_fill_buffer(&prng, buf, to_write);
583         if (!device_write_block(device, (guint)block_size, buf)) {
584             g_free(buf);
585             return FALSE;
586         }
587         length -= to_write;
588     }
589
590     g_free(buf);
591     return TRUE;
592 }
593
594 /* read LENGTH bytes of random data from FILENAME verifying it against
595  * a PRNG seeded with SEED.  Sends any error messages to stderr.
596  */
597 gboolean
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 */
601     int block_size = 0;
602
603     simpleprng_seed(&prng, seed);
604
605     while (length) {
606         int bytes_read;
607         int size = block_size;
608
609         bytes_read = device_read_block(device, buf, &size);
610         if (bytes_read == 0 && size > block_size) {
611             g_free(buf);
612             block_size = size;
613             buf = g_malloc(block_size);
614             continue;
615         }
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");
620             }
621             goto error;
622         }
623
624         /* strip padding */
625         bytes_read = min(bytes_read, length);
626
627         if (!simpleprng_verify_buffer(&prng, buf, bytes_read))
628             goto error;
629
630         length -= bytes_read;
631     }
632
633     g_free(buf);
634     return TRUE;
635
636 error:
637     g_free(buf);
638     return FALSE;
639 }
640 %}
641
642 /*
643  * Constants
644  */
645
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);
651
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);
656
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);
666
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);
677
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);
702
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);
708
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);
714
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);
721
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);
726
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);
732
733 %perlcode %{
734
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.
739 sub new {
740     my $pkg = shift;
741     Amanda::Device::Device->new(@_);
742 }
743 %}