Blob Blame History Raw
/*
 * Copyright (c) 2009-2012 Zmanda, Inc.  All Rights Reserved.
 * Copyright (c) 2013-2016 Carbonite, Inc.  All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * 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 General Public License
 * for more details.
 *
 * 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: Carbonite Inc., 756 N Pastoria Ave
 * Sunnyvale, CA 94085, or: http://www.zmanda.com
 */

%module "Amanda::NDMP"
%include "amglue/amglue.swg"
%include "exception.i"

%include "Amanda/NDMP.pod"

%{
#include "ndmpconnobj.h"
#include "glib-util.h"
%}

/* initialize glib, and in particular GType */
%init %{
    glib_init();
%}

/* supporting typemaps */

/* treat all enums in this file as regular UV's - no need for BigInt */
%{
typedef guint ndmp_enum;
%}

/* Any enumeration, input */
%typemap(in) ndmp_enum "$1 = SvIV($input);";

/* Any enumeration, output argument */
%typemap(in,numinputs=0) ndmp_enum * (int temp) "$1 = &temp; temp = 0;";
%typemap(argout) ndmp_enum * {
    if (argvi >= items) {
	EXTEND(sp,1);
    }

    $result = sv_newmortal();
    sv_setuv($result, (UV)(*$1));
    argvi++;
}

/* gsize, output argument */
%typemap(in,numinputs=0) gsize * (gsize temp) "$1 = &temp; temp = 0;"
%typemap(argout) gsize * {
    if (argvi >= items) {
	EXTEND(sp,1);
    }

    SP += argvi; PUTBACK;
    $result = sv_2mortal(amglue_newSVu64(*$1));
    SP -= argvi; argvi++;
}

/* guint64, output argument */
%typemap(in,numinputs=0) guint64 * (guint64 temp) "$1 = &temp; temp = 0;"
%typemap(argout) guint64 * {
    if (argvi >= items) {
	EXTEND(sp,1);
    }

    SP += argvi; PUTBACK;
    $result = sv_2mortal(amglue_newSVu64(*$1));
    SP -= argvi; argvi++;
}

/* guint, output argument */
%typemap(in,numinputs=0) guint * (guint temp) "$1 = &temp; temp = 0;"
%typemap(argout) guint * {
    if (argvi >= items) {
	EXTEND(sp,1);
    }

    SP += argvi; PUTBACK;
    $result = sv_2mortal(amglue_newSVu64(*$1));
    SP -= argvi; argvi++;
}

typedef struct {
    /* methods */
    %extend {
	/* constructor */
	NDMPConnection(
		gchar *hostname,
		gint port,
		gchar *username,
		gchar *password,
		gchar *auth) {
	    return ndmp_connection_new(
		    hostname, port, username, password, auth);
	}

	~NDMPConnection() {
	    g_object_unref(self);
	}

	/* error handling */

	int
	err_code() {
	    return ndmp_connection_err_code(self);
	}

	%newobject err_msg;
	gchar *
	err_msg() {
	    return ndmp_connection_err_msg(self);
	}

	void
	set_verbose(gboolean verbose) {
	    ndmp_connection_set_verbose(self, verbose);
	}

	/* operations */

	gboolean
	scsi_open(gchar *device) {
	    return ndmp_connection_scsi_open(
		    self,
		    device);
	}

	gboolean
	scsi_close() {
	    return ndmp_connection_scsi_close(self);
	}

	/* NOTE: this method is wrapped with a more perlish interface; see below */

	/* handle cdb */
	%typemap(in) (gpointer cdb, gsize cdb_len) {
	    /* cdb */
	    int g_malloc = SWIG_OLDOBJ;
	    SWIG_AsCharPtrAndSize($input, (char **)&$1, &$2, &g_malloc);
	    if ($2) $2--; /* strip trailing NUL byte */
	}

	/* handle dataout and its response */
	%typemap(in,numinputs=1)
	    (gpointer dataout, gsize dataout_len, gsize *actual_dataout_len)
	    (gsize dataout_len) {
	    /* dataout */

	    /* handle the actual input here */
	    int g_malloc = SWIG_OLDOBJ;
	    SWIG_AsCharPtrAndSize($input, (char **)&$1, &$2, &g_malloc);
	    if ($2) $2--; /* strip trailing NUL byte */
	    /* set up for argout typemap, below */
	    dataout_len = 0;
	    $3 = &dataout_len;
	}
	%typemap(argout)
	    (gpointer dataout, gsize dataout_len, gsize *actual_dataout_len) {
	    if (argvi >= items) {
		EXTEND(sp,1);
	    }

	    SP += argvi; PUTBACK;
	    $result = sv_2mortal(amglue_newSVu64(*$3));
	    SP -= argvi; argvi++;
	}

	/* handle datain and its response */
	%typemap(in,numinputs=1)
	    (gpointer datain, gsize datain_max_len, gsize *actual_datain_len)
	    (gpointer datain_buf, gsize actual_datain_len) {
	    /* datain */
	    gchar *err = NULL;
	    gsize max_size = amglue_SvU64($input, &err);
	    $2 = max_size;
	    if (max_size) {
		$1 = g_malloc(max_size);
	    } else {
		$1 = NULL;
	    }
	    actual_datain_len = 0;
	    $3 = &actual_datain_len;
	}
	%typemap(argout)
	    (gpointer datain, gsize datain_max_len, gsize *actual_datain_len) {
	    if (argvi >= items) {
		EXTEND(sp,1);
	    }

	    /* convert the value, even if it's NULL */
	    $result = SWIG_FromCharPtrAndSize($1, *$3);
	    argvi++;
	    if ($1) g_free($1);
	}

	/* handle status */
	%typemap(in,numinputs=0) (guint8 *status) (guint8 temp) "$1 = &temp;";
	%typemap(argout) (guint8 *status) {
	    if (argvi >= items) {
		EXTEND(sp,1);
	    }

	    $result = sv_newmortal();
	    sv_setuv($result, (UV)(*$1));
	    argvi++;
	}

	/* handle ext_status */
	%typemap(in,numinputs=0)
	    (gpointer ext_sense, gsize ext_sense_max_len, gsize *actual_ext_sense_len)
	    (guint8 ext_sense_buf[128], gsize actual_ext_sense_len) {
	    $1 = ext_sense_buf;
	    $2 = sizeof(ext_sense_buf); /* always allocate 128 bytes for sense */
	    actual_ext_sense_len = 0;
	    $3 = &actual_ext_sense_len;
	}
	%typemap(argout)
	    (gpointer ext_sense, gsize ext_sense_max_len, gsize *actual_ext_sense_len) {
	    if (argvi >= items) {
		EXTEND(sp,1);
	    }

	    $result = SWIG_FromCharPtrAndSize($1, *$3);
	    argvi++;
	}

	gboolean
	scsi_execute_cdb_C(
		ndmp_enum flags,
		guint32 timeout,
		gpointer cdb,
		gsize cdb_len,
		gpointer dataout,
		gsize dataout_len,
		gsize *actual_dataout_len,
		gpointer datain,
		gsize datain_max_len,
		gsize *actual_datain_len,
		guint8 *status,
		gpointer ext_sense,
		gsize ext_sense_max_len,
		gsize *actual_ext_sense_len
		) {
	    return ndmp_connection_scsi_execute_cdb(
		    self,
		    flags,
		    timeout,
		    cdb,
		    cdb_len,
		    dataout,
		    dataout_len,
		    actual_dataout_len,
		    datain,
		    datain_max_len,
		    actual_datain_len,
		    status,
		    ext_sense,
		    ext_sense_max_len,
		    actual_ext_sense_len
		    );
	}

	gboolean
	tape_open(
		gchar *device,
		ndmp_enum mode) {
	    return ndmp_connection_tape_open(
		    self,
		    device,
		    mode);
	}

	gboolean
	tape_close() {
	    return ndmp_connection_tape_close(self);
	}

	gboolean
	tape_mtio(
		ndmp_enum tape_op,
		gint count,
		guint *resid) {
	    return ndmp_connection_tape_mtio(
		    self,
		    tape_op,
		    count,
		    resid);
	}

	%typemap(in) (gpointer buf, guint64 len) {
	    int g_malloc = SWIG_OLDOBJ;
	    size_t len_tmp; /* use a temporary with the right type */
	    SWIG_AsCharPtrAndSize($input, (char **)&$1, &len_tmp, &g_malloc);
	    if (len_tmp) len_tmp--; /* strip trailing NUL byte */
	    $2 = len_tmp;
	}
	gboolean
	tape_write(
		gpointer buf,
		guint64 len,
		guint64 *count) {
	    return ndmp_connection_tape_write(
		    self,
		    buf,
		    len,
		    count);
	}

	%typemap(in,numinputs=1)
	    (gpointer buf, guint64 count, guint64 *out_count)
	    (guint64 out_count) {
	    gchar *err = NULL;
	    $2 = amglue_SvU64($input, &err);
	    $1 = $2?g_malloc($2):NULL;
	    out_count = 0;
	    $3 = &out_count;
	}
	%typemap(argout)
	    (gpointer buf, guint64 count, guint64 *out_count) {
	    if (argvi >= items) {
		EXTEND(sp,1);
	    }

	    /* convert the value, even if it's NULL */
	    $result = SWIG_FromCharPtrAndSize($1, *$3);
	    argvi++;
	    if ($1) g_free($1);
	}
	gboolean
	tape_read(
		gpointer buf,
		guint64 count,
		guint64 *out_count) {
	    return ndmp_connection_tape_read(
		    self,
		    buf,
		    count,
		    out_count);
	}

	gboolean
	tape_get_state(
		guint64 *blocksize,
		guint64 *file_num,
		guint64 *blockno) {
	    return ndmp_connection_tape_get_state(
		    self,
		    blocksize,
		    file_num,
		    blockno);
	}

	/* mover interface is not yet SWIGged */
    };
} NDMPConnection;

/* perlish wrappers */
%perlcode %{
package Amanda::NDMP::NDMPConnection;

sub scsi_execute_cdb {
    my $self = shift;
    my %params = @_;

    die "no 'flags' parameter'" unless defined $params{'flags'};
    die "no 'timeout' parameter'" unless defined $params{'timeout'};
    die "no 'cdb' parameter'" unless defined $params{'cdb'};
    if ($params{'flags'} & $Amanda::NDMP::NDMP9_SCSI_DATA_DIR_IN) {
	die "no 'datain_len' parameter'" unless defined $params{'datain_len'};
    } else {
	$params{'datain_len'} = 0;
    }
    if ($params{'flags'} & $Amanda::NDMP::NDMP9_SCSI_DATA_DIR_OUT) {
	die "no 'dataout' parameter'" unless defined $params{'dataout'};
    } else {
	$params{'dataout'} = undef;
    }

    my ($ok, $dataout_len, $datain, $status, $ext_sense) =
	$self->scsi_execute_cdb_C(
	    $params{'flags'}, $params{'timeout'},
	    $params{'cdb'}, $params{'dataout'},
	    $params{'datain_len'});

    return 0 unless ($ok);

    my %result = (
	status => $status,
	ext_sense => $ext_sense);
    if ($params{'flags'} & $Amanda::NDMP::NDMP9_SCSI_DATA_DIR_IN) {
	$result{'datain'} = $datain;
    }
    if ($params{'flags'} & $Amanda::NDMP::NDMP9_SCSI_DATA_DIR_OUT) {
	$result{'dataout_len'} = $dataout_len;
    }
    return \%result;
}

package Amanda::NDMP;
%}

/* selected NDMP constants; note that the "NDMP9_" prfix is required */

amglue_add_flag_tag_fns(scsi_data_dir);
amglue_add_constant_short(NDMP9_SCSI_DATA_DIR_NONE, "NDMP9_SCSI_DATA_DIR_NONE", scsi_data_dir);
amglue_add_constant_short(NDMP9_SCSI_DATA_DIR_IN, "NDMP9_SCSI_DATA_DIR_IN", scsi_data_dir);
amglue_add_constant_short(NDMP9_SCSI_DATA_DIR_OUT, "NDMP9_SCSI_DATA_DIR_OUT", scsi_data_dir);
amglue_copy_to_tag(scsi_data_dir, constants);

amglue_add_flag_tag_fns(tape_open_mode);
amglue_add_constant_short(NDMP9_TAPE_READ_MODE, "NDMP9_TAPE_READ_MODE", tape_open_mode);
amglue_add_constant_short(NDMP9_TAPE_RDWR_MODE, "NDMP9_TAPE_RDRW_MODE", tape_open_mode);
amglue_add_constant_short(NDMP9_TAPE_RAW_MODE, "NDMP9_TAPE_RAW_MODE", tape_open_mode);
amglue_copy_to_tag(tape_open_mode, constants);

amglue_add_flag_tag_fns(tape_mtio_op);
amglue_add_constant_short(NDMP9_MTIO_FSF, "NDMP9_MTIO_FSF", tape_mtio_op);
amglue_add_constant_short(NDMP9_MTIO_BSF, "NDMP9_MTIO_BSF", tape_mtio_op);
amglue_add_constant_short(NDMP9_MTIO_FSR, "NDMP9_MTIO_FSR", tape_mtio_op);
amglue_add_constant_short(NDMP9_MTIO_BSR, "NDMP9_MTIO_BSR", tape_mtio_op);
amglue_add_constant_short(NDMP9_MTIO_REW, "NDMP9_MTIO_REW", tape_mtio_op);
amglue_add_constant_short(NDMP9_MTIO_EOF, "NDMP9_MTIO_EOF", tape_mtio_op);
amglue_add_constant_short(NDMP9_MTIO_OFF, "NDMP9_MTIO_OFF", tape_mtio_op);
amglue_copy_to_tag(tape_mtio_op, constants);

amglue_add_flag_tag_fns(mover_mode);
amglue_add_constant_short(NDMP9_MOVER_MODE_READ, "NDMP9_MOVER_MODE_READ", mover_mode);
amglue_add_constant_short(NDMP9_MOVER_MODE_WRITE, "NDMP9_MOVER_MODE_WRITE", mover_mode);
amglue_copy_to_tag(mover_mode, constants);

amglue_add_flag_tag_fns(addr_type);
amglue_add_constant_short(NDMP9_ADDR_LOCAL, "NDMP9_ADDR_LOCAL", addr_type);
amglue_add_constant_short(NDMP9_ADDR_TCP, "NDMP9_ADDR_TCP", addr_type);
amglue_add_constant_short(NDMP9_ADDR_AS_CONNECTED, "NDMP9_ADDR_AS_CONNECTED", addr_type);
amglue_copy_to_tag(addr_type, constants);

amglue_add_flag_tag_fns(mover_state);
amglue_add_constant_short(NDMP9_MOVER_STATE_IDLE, "NDMP9_MOVER_STATE_IDLE", mover_state);
amglue_add_constant_short(NDMP9_MOVER_STATE_LISTEN, "NDMP9_MOVER_STATE_LISTEN", mover_state);
amglue_add_constant_short(NDMP9_MOVER_STATE_ACTIVE, "NDMP9_MOVER_STATE_ACTIVE", mover_state);
amglue_add_constant_short(NDMP9_MOVER_STATE_PAUSED, "NDMP9_MOVER_STATE_PAUSED", mover_state);
amglue_add_constant_short(NDMP9_MOVER_STATE_HALTED, "NDMP9_MOVER_STATE_HALTED", mover_state);
amglue_add_constant_short(NDMP9_MOVER_STATE_STANDBY, "NDMP9_MOVER_STATE_STANDBY", mover_state);
amglue_copy_to_tag(mover_state, constants);

amglue_add_flag_tag_fns(data_halt_reason);
amglue_add_constant_short(NDMP9_DATA_HALT_NA, "NDMP9_DATA_HALT_NA", data_halt_reason);
amglue_add_constant_short(NDMP9_DATA_HALT_SUCCESSFUL, "NDMP9_DATA_HALT_SUCCESSFUL", data_halt_reason);
amglue_add_constant_short(NDMP9_DATA_HALT_ABORTED, "NDMP9_DATA_HALT_ABORTED", data_halt_reason);
amglue_add_constant_short(NDMP9_DATA_HALT_INTERNAL_ERROR, "NDMP9_DATA_HALT_INTERNAL_ERROR", data_halt_reason);
amglue_add_constant_short(NDMP9_DATA_HALT_CONNECT_ERROR, "NDMP9_DATA_HALT_CONNECT_ERROR", data_halt_reason);
amglue_copy_to_tag(data_halt_reason, constants);

amglue_add_flag_tag_fns(mover_halt_reason);
amglue_add_constant_short(NDMP9_MOVER_HALT_NA, "NDMP9_MOVER_HALT_NA", mover_halt_reason);
amglue_add_constant_short(NDMP9_MOVER_HALT_CONNECT_CLOSED, "NDMP9_MOVER_HALT_CONNECT_CLOSED", mover_halt_reason);
amglue_add_constant_short(NDMP9_MOVER_HALT_ABORTED, "NDMP9_MOVER_HALT_ABORTED", mover_halt_reason);
amglue_add_constant_short(NDMP9_MOVER_HALT_INTERNAL_ERROR, "NDMP9_MOVER_HALT_INTERNAL_ERROR", mover_halt_reason);
amglue_add_constant_short(NDMP9_MOVER_HALT_CONNECT_ERROR, "NDMP9_MOVER_HALT_CONNECT_ERROR", mover_halt_reason);
amglue_copy_to_tag(mover_halt_reason, constants);

amglue_add_flag_tag_fns(mover_pause_reason);
amglue_add_constant_short(NDMP9_MOVER_PAUSE_NA, "NDMP9_MOVER_PAUSE_NA", mover_pause_reason);
amglue_add_constant_short(NDMP9_MOVER_PAUSE_EOM, "NDMP9_MOVER_PAUSE_EOM", mover_pause_reason);
amglue_add_constant_short(NDMP9_MOVER_PAUSE_EOF, "NDMP9_MOVER_PAUSE_EOF", mover_pause_reason);
amglue_add_constant_short(NDMP9_MOVER_PAUSE_SEEK, "NDMP9_MOVER_PAUSE_SEEK", mover_pause_reason);
amglue_add_constant_short(NDMP9_MOVER_PAUSE_MEDIA_ERROR, "NDMP9_MOVER_PAUSE_MEDIA_ERROR", mover_pause_reason);
amglue_add_constant_short(NDMP9_MOVER_PAUSE_EOW, "NDMP9_MOVER_PAUSE_EOW", mover_pause_reason);
amglue_copy_to_tag(mover_pause_reason, constants);