1/*
2 * Copyright (c) 2009-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::NDMP"
23%include "amglue/amglue.swg"
24%include "exception.i"
25
26%include "Amanda/NDMP.pod"
27
28%{
29#include "ndmpconnobj.h"
30#include "glib-util.h"
31%}
32
33/* initialize glib, and in particular GType */
34%init %{
35    glib_init();
36%}
37
38/* supporting typemaps */
39
40/* treat all enums in this file as regular UV's - no need for BigInt */
41%{
42typedef guint ndmp_enum;
43%}
44
45/* Any enumeration, input */
46%typemap(in) ndmp_enum "$1 = SvIV($input);";
47
48/* Any enumeration, output argument */
49%typemap(in,numinputs=0) ndmp_enum * (int temp) "$1 = &temp; temp = 0;";
50%typemap(argout) ndmp_enum * {
51    if (argvi >= items) {
52	EXTEND(sp,1);
53    }
54
55    $result = sv_newmortal();
56    sv_setuv($result, (UV)(*$1));
57    argvi++;
58}
59
60/* gsize, output argument */
61%typemap(in,numinputs=0) gsize * (gsize temp) "$1 = &temp; temp = 0;"
62%typemap(argout) gsize * {
63    if (argvi >= items) {
64	EXTEND(sp,1);
65    }
66
67    SP += argvi; PUTBACK;
68    $result = sv_2mortal(amglue_newSVu64(*$1));
69    SP -= argvi; argvi++;
70}
71
72/* guint64, output argument */
73%typemap(in,numinputs=0) guint64 * (guint64 temp) "$1 = &temp; temp = 0;"
74%typemap(argout) guint64 * {
75    if (argvi >= items) {
76	EXTEND(sp,1);
77    }
78
79    SP += argvi; PUTBACK;
80    $result = sv_2mortal(amglue_newSVu64(*$1));
81    SP -= argvi; argvi++;
82}
83
84/* guint, output argument */
85%typemap(in,numinputs=0) guint * (guint temp) "$1 = &temp; temp = 0;"
86%typemap(argout) guint * {
87    if (argvi >= items) {
88	EXTEND(sp,1);
89    }
90
91    SP += argvi; PUTBACK;
92    $result = sv_2mortal(amglue_newSVu64(*$1));
93    SP -= argvi; argvi++;
94}
95
96typedef struct {
97    /* methods */
98    %extend {
99	/* constructor */
100	NDMPConnection(
101		gchar *hostname,
102		gint port,
103		gchar *username,
104		gchar *password,
105		gchar *auth) {
106	    return ndmp_connection_new(
107		    hostname, port, username, password, auth);
108	}
109
110	~NDMPConnection() {
111	    g_object_unref(self);
112	}
113
114	/* error handling */
115
116	int
117	err_code() {
118	    return ndmp_connection_err_code(self);
119	}
120
121	%newobject err_msg;
122	gchar *
123	err_msg() {
124	    return ndmp_connection_err_msg(self);
125	}
126
127	void
128	set_verbose(gboolean verbose) {
129	    ndmp_connection_set_verbose(self, verbose);
130	}
131
132	/* operations */
133
134	gboolean
135	scsi_open(gchar *device) {
136	    return ndmp_connection_scsi_open(
137		    self,
138		    device);
139	}
140
141	gboolean
142	scsi_close() {
143	    return ndmp_connection_scsi_close(self);
144	}
145
146	/* NOTE: this method is wrapped with a more perlish interface; see below */
147
148	/* handle cdb */
149	%typemap(in) (gpointer cdb, gsize cdb_len) {
150	    /* cdb */
151	    int alloc = SWIG_OLDOBJ;
152	    SWIG_AsCharPtrAndSize($input, (char **)&$1, &$2, &alloc);
153	    if ($2) $2--; /* strip trailing NUL byte */
154	}
155
156	/* handle dataout and its response */
157	%typemap(in,numinputs=1)
158	    (gpointer dataout, gsize dataout_len, gsize *actual_dataout_len)
159	    (gsize dataout_len) {
160	    /* dataout */
161
162	    /* handle the actual input here */
163	    int alloc = SWIG_OLDOBJ;
164	    SWIG_AsCharPtrAndSize($input, (char **)&$1, &$2, &alloc);
165	    if ($2) $2--; /* strip trailing NUL byte */
166	    /* set up for argout typemap, below */
167	    dataout_len = 0;
168	    $3 = &dataout_len;
169	}
170	%typemap(argout)
171	    (gpointer dataout, gsize dataout_len, gsize *actual_dataout_len) {
172	    if (argvi >= items) {
173		EXTEND(sp,1);
174	    }
175
176	    SP += argvi; PUTBACK;
177	    $result = sv_2mortal(amglue_newSVu64(*$3));
178	    SP -= argvi; argvi++;
179	}
180
181	/* handle datain and its response */
182	%typemap(in,numinputs=1)
183	    (gpointer datain, gsize datain_max_len, gsize *actual_datain_len)
184	    (gpointer datain_buf, gsize actual_datain_len) {
185	    /* datain */
186	    gsize max_size = amglue_SvU64($input);
187	    $2 = max_size;
188	    if (max_size) {
189		$1 = g_malloc(max_size);
190	    } else {
191		$1 = NULL;
192	    }
193	    actual_datain_len = 0;
194	    $3 = &actual_datain_len;
195	}
196	%typemap(argout)
197	    (gpointer datain, gsize datain_max_len, gsize *actual_datain_len) {
198	    if (argvi >= items) {
199		EXTEND(sp,1);
200	    }
201
202	    /* convert the value, even if it's NULL */
203	    $result = SWIG_FromCharPtrAndSize($1, *$3);
204	    argvi++;
205	    if ($1) g_free($1);
206	}
207
208	/* handle status */
209	%typemap(in,numinputs=0) (guint8 *status) (guint8 temp) "$1 = &temp;";
210	%typemap(argout) (guint8 *status) {
211	    if (argvi >= items) {
212		EXTEND(sp,1);
213	    }
214
215	    $result = sv_newmortal();
216	    sv_setuv($result, (UV)(*$1));
217	    argvi++;
218	}
219
220	/* handle ext_status */
221	%typemap(in,numinputs=0)
222	    (gpointer ext_sense, gsize ext_sense_max_len, gsize *actual_ext_sense_len)
223	    (guint8 ext_sense_buf[128], gsize actual_ext_sense_len) {
224	    $1 = ext_sense_buf;
225	    $2 = sizeof(ext_sense_buf); /* always allocate 128 bytes for sense */
226	    actual_ext_sense_len = 0;
227	    $3 = &actual_ext_sense_len;
228	}
229	%typemap(argout)
230	    (gpointer ext_sense, gsize ext_sense_max_len, gsize *actual_ext_sense_len) {
231	    if (argvi >= items) {
232		EXTEND(sp,1);
233	    }
234
235	    $result = SWIG_FromCharPtrAndSize($1, *$3);
236	    argvi++;
237	}
238
239	gboolean
240	scsi_execute_cdb_C(
241		ndmp_enum flags,
242		guint32 timeout,
243		gpointer cdb,
244		gsize cdb_len,
245		gpointer dataout,
246		gsize dataout_len,
247		gsize *actual_dataout_len,
248		gpointer datain,
249		gsize datain_max_len,
250		gsize *actual_datain_len,
251		guint8 *status,
252		gpointer ext_sense,
253		gsize ext_sense_max_len,
254		gsize *actual_ext_sense_len
255		) {
256	    return ndmp_connection_scsi_execute_cdb(
257		    self,
258		    flags,
259		    timeout,
260		    cdb,
261		    cdb_len,
262		    dataout,
263		    dataout_len,
264		    actual_dataout_len,
265		    datain,
266		    datain_max_len,
267		    actual_datain_len,
268		    status,
269		    ext_sense,
270		    ext_sense_max_len,
271		    actual_ext_sense_len
272		    );
273	}
274
275	gboolean
276	tape_open(
277		gchar *device,
278		ndmp_enum mode) {
279	    return ndmp_connection_tape_open(
280		    self,
281		    device,
282		    mode);
283	}
284
285	gboolean
286	tape_close() {
287	    return ndmp_connection_tape_close(self);
288	}
289
290	gboolean
291	tape_mtio(
292		ndmp_enum tape_op,
293		gint count,
294		guint *resid) {
295	    return ndmp_connection_tape_mtio(
296		    self,
297		    tape_op,
298		    count,
299		    resid);
300	}
301
302	%typemap(in) (gpointer buf, guint64 len) {
303	    int alloc = SWIG_OLDOBJ;
304	    size_t len_tmp; /* use a temporary with the right type */
305	    SWIG_AsCharPtrAndSize($input, (char **)&$1, &len_tmp, &alloc);
306	    if (len_tmp) len_tmp--; /* strip trailing NUL byte */
307	    $2 = len_tmp;
308	}
309	gboolean
310	tape_write(
311		gpointer buf,
312		guint64 len,
313		guint64 *count) {
314	    return ndmp_connection_tape_write(
315		    self,
316		    buf,
317		    len,
318		    count);
319	}
320
321	%typemap(in,numinputs=1)
322	    (gpointer buf, guint64 count, guint64 *out_count)
323	    (guint64 out_count) {
324	    $2 = amglue_SvU64($input);
325	    $1 = $2?g_malloc($2):NULL;
326	    out_count = 0;
327	    $3 = &out_count;
328	}
329	%typemap(argout)
330	    (gpointer buf, guint64 count, guint64 *out_count) {
331	    if (argvi >= items) {
332		EXTEND(sp,1);
333	    }
334
335	    /* convert the value, even if it's NULL */
336	    $result = SWIG_FromCharPtrAndSize($1, *$3);
337	    argvi++;
338	    if ($1) g_free($1);
339	}
340	gboolean
341	tape_read(
342		gpointer buf,
343		guint64 count,
344		guint64 *out_count) {
345	    return ndmp_connection_tape_read(
346		    self,
347		    buf,
348		    count,
349		    out_count);
350	}
351
352	gboolean
353	tape_get_state(
354		guint64 *blocksize,
355		guint64 *file_num,
356		guint64 *blockno) {
357	    return ndmp_connection_tape_get_state(
358		    self,
359		    blocksize,
360		    file_num,
361		    blockno);
362	}
363
364	/* mover interface is not yet SWIGged */
365    };
366} NDMPConnection;
367
368/* perlish wrappers */
369%perlcode %{
370package Amanda::NDMP::NDMPConnection;
371
372sub scsi_execute_cdb {
373    my $self = shift;
374    my %params = @_;
375
376    die "no 'flags' parameter'" unless defined $params{'flags'};
377    die "no 'timeout' parameter'" unless defined $params{'timeout'};
378    die "no 'cdb' parameter'" unless defined $params{'cdb'};
379    if ($params{'flags'} & $Amanda::NDMP::NDMP9_SCSI_DATA_DIR_IN) {
380	die "no 'datain_len' parameter'" unless defined $params{'datain_len'};
381    } else {
382	$params{'datain_len'} = 0;
383    }
384    if ($params{'flags'} & $Amanda::NDMP::NDMP9_SCSI_DATA_DIR_OUT) {
385	die "no 'dataout' parameter'" unless defined $params{'dataout'};
386    } else {
387	$params{'dataout'} = undef;
388    }
389
390    my ($ok, $dataout_len, $datain, $status, $ext_sense) =
391	$self->scsi_execute_cdb_C(
392	    $params{'flags'}, $params{'timeout'},
393	    $params{'cdb'}, $params{'dataout'},
394	    $params{'datain_len'});
395
396    return 0 unless ($ok);
397
398    my %result = (
399	status => $status,
400	ext_sense => $ext_sense);
401    if ($params{'flags'} & $Amanda::NDMP::NDMP9_SCSI_DATA_DIR_IN) {
402	$result{'datain'} = $datain;
403    }
404    if ($params{'flags'} & $Amanda::NDMP::NDMP9_SCSI_DATA_DIR_OUT) {
405	$result{'dataout_len'} = $dataout_len;
406    }
407    return \%result;
408}
409
410package Amanda::NDMP;
411%}
412
413/* selected NDMP constants; note that the "NDMP9_" prfix is required */
414
415amglue_add_flag_tag_fns(scsi_data_dir);
416amglue_add_constant_short(NDMP9_SCSI_DATA_DIR_NONE, "NDMP9_SCSI_DATA_DIR_NONE", scsi_data_dir);
417amglue_add_constant_short(NDMP9_SCSI_DATA_DIR_IN, "NDMP9_SCSI_DATA_DIR_IN", scsi_data_dir);
418amglue_add_constant_short(NDMP9_SCSI_DATA_DIR_OUT, "NDMP9_SCSI_DATA_DIR_OUT", scsi_data_dir);
419amglue_copy_to_tag(scsi_data_dir, constants);
420
421amglue_add_flag_tag_fns(tape_open_mode);
422amglue_add_constant_short(NDMP9_TAPE_READ_MODE, "NDMP9_TAPE_READ_MODE", tape_open_mode);
423amglue_add_constant_short(NDMP9_TAPE_RDWR_MODE, "NDMP9_TAPE_RDRW_MODE", tape_open_mode);
424amglue_add_constant_short(NDMP9_TAPE_RAW_MODE, "NDMP9_TAPE_RAW_MODE", tape_open_mode);
425amglue_copy_to_tag(tape_open_mode, constants);
426
427amglue_add_flag_tag_fns(tape_mtio_op);
428amglue_add_constant_short(NDMP9_MTIO_FSF, "NDMP9_MTIO_FSF", tape_mtio_op);
429amglue_add_constant_short(NDMP9_MTIO_BSF, "NDMP9_MTIO_BSF", tape_mtio_op);
430amglue_add_constant_short(NDMP9_MTIO_FSR, "NDMP9_MTIO_FSR", tape_mtio_op);
431amglue_add_constant_short(NDMP9_MTIO_BSR, "NDMP9_MTIO_BSR", tape_mtio_op);
432amglue_add_constant_short(NDMP9_MTIO_REW, "NDMP9_MTIO_REW", tape_mtio_op);
433amglue_add_constant_short(NDMP9_MTIO_EOF, "NDMP9_MTIO_EOF", tape_mtio_op);
434amglue_add_constant_short(NDMP9_MTIO_OFF, "NDMP9_MTIO_OFF", tape_mtio_op);
435amglue_copy_to_tag(tape_mtio_op, constants);
436
437amglue_add_flag_tag_fns(mover_mode);
438amglue_add_constant_short(NDMP9_MOVER_MODE_READ, "NDMP9_MOVER_MODE_READ", mover_mode);
439amglue_add_constant_short(NDMP9_MOVER_MODE_WRITE, "NDMP9_MOVER_MODE_WRITE", mover_mode);
440amglue_copy_to_tag(mover_mode, constants);
441
442amglue_add_flag_tag_fns(addr_type);
443amglue_add_constant_short(NDMP9_ADDR_LOCAL, "NDMP9_ADDR_LOCAL", addr_type);
444amglue_add_constant_short(NDMP9_ADDR_TCP, "NDMP9_ADDR_TCP", addr_type);
445amglue_add_constant_short(NDMP9_ADDR_AS_CONNECTED, "NDMP9_ADDR_AS_CONNECTED", addr_type);
446amglue_copy_to_tag(addr_type, constants);
447
448amglue_add_flag_tag_fns(mover_state);
449amglue_add_constant_short(NDMP9_MOVER_STATE_IDLE, "NDMP9_MOVER_STATE_IDLE", mover_state);
450amglue_add_constant_short(NDMP9_MOVER_STATE_LISTEN, "NDMP9_MOVER_STATE_LISTEN", mover_state);
451amglue_add_constant_short(NDMP9_MOVER_STATE_ACTIVE, "NDMP9_MOVER_STATE_ACTIVE", mover_state);
452amglue_add_constant_short(NDMP9_MOVER_STATE_PAUSED, "NDMP9_MOVER_STATE_PAUSED", mover_state);
453amglue_add_constant_short(NDMP9_MOVER_STATE_HALTED, "NDMP9_MOVER_STATE_HALTED", mover_state);
454amglue_add_constant_short(NDMP9_MOVER_STATE_STANDBY, "NDMP9_MOVER_STATE_STANDBY", mover_state);
455amglue_copy_to_tag(mover_state, constants);
456
457amglue_add_flag_tag_fns(data_halt_reason);
458amglue_add_constant_short(NDMP9_DATA_HALT_NA, "NDMP9_DATA_HALT_NA", data_halt_reason);
459amglue_add_constant_short(NDMP9_DATA_HALT_SUCCESSFUL, "NDMP9_DATA_HALT_SUCCESSFUL", data_halt_reason);
460amglue_add_constant_short(NDMP9_DATA_HALT_ABORTED, "NDMP9_DATA_HALT_ABORTED", data_halt_reason);
461amglue_add_constant_short(NDMP9_DATA_HALT_INTERNAL_ERROR, "NDMP9_DATA_HALT_INTERNAL_ERROR", data_halt_reason);
462amglue_add_constant_short(NDMP9_DATA_HALT_CONNECT_ERROR, "NDMP9_DATA_HALT_CONNECT_ERROR", data_halt_reason);
463amglue_copy_to_tag(data_halt_reason, constants);
464
465amglue_add_flag_tag_fns(mover_halt_reason);
466amglue_add_constant_short(NDMP9_MOVER_HALT_NA, "NDMP9_MOVER_HALT_NA", mover_halt_reason);
467amglue_add_constant_short(NDMP9_MOVER_HALT_CONNECT_CLOSED, "NDMP9_MOVER_HALT_CONNECT_CLOSED", mover_halt_reason);
468amglue_add_constant_short(NDMP9_MOVER_HALT_ABORTED, "NDMP9_MOVER_HALT_ABORTED", mover_halt_reason);
469amglue_add_constant_short(NDMP9_MOVER_HALT_INTERNAL_ERROR, "NDMP9_MOVER_HALT_INTERNAL_ERROR", mover_halt_reason);
470amglue_add_constant_short(NDMP9_MOVER_HALT_CONNECT_ERROR, "NDMP9_MOVER_HALT_CONNECT_ERROR", mover_halt_reason);
471amglue_copy_to_tag(mover_halt_reason, constants);
472
473amglue_add_flag_tag_fns(mover_pause_reason);
474amglue_add_constant_short(NDMP9_MOVER_PAUSE_NA, "NDMP9_MOVER_PAUSE_NA", mover_pause_reason);
475amglue_add_constant_short(NDMP9_MOVER_PAUSE_EOM, "NDMP9_MOVER_PAUSE_EOM", mover_pause_reason);
476amglue_add_constant_short(NDMP9_MOVER_PAUSE_EOF, "NDMP9_MOVER_PAUSE_EOF", mover_pause_reason);
477amglue_add_constant_short(NDMP9_MOVER_PAUSE_SEEK, "NDMP9_MOVER_PAUSE_SEEK", mover_pause_reason);
478amglue_add_constant_short(NDMP9_MOVER_PAUSE_MEDIA_ERROR, "NDMP9_MOVER_PAUSE_MEDIA_ERROR", mover_pause_reason);
479amglue_add_constant_short(NDMP9_MOVER_PAUSE_EOW, "NDMP9_MOVER_PAUSE_EOW", mover_pause_reason);
480amglue_copy_to_tag(mover_pause_reason, constants);
481