Add AFS::ukernel libuafs perl bindings
authorAndrew Deason <adeason@sinenomine.net>
Fri, 14 Aug 2009 21:32:54 +0000 (16:32 -0500)
committerDerrick Brashear <shadow@dementia.org>
Sat, 9 Jul 2011 05:20:06 +0000 (22:20 -0700)
Add the SWIG-generated AFS::ukernel perl module, which provides perl
bindings to libuafs calls.

Change-Id: I5ce480944a8c97cbca72c80e79fc40c0edb0962f
Reviewed-on: http://gerrit.openafs.org/2048
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

acinclude.m4
src/cf/swig.m4 [new file with mode: 0644]
src/libuafs/Makefile.common.in
src/libuafs/ukernel_swig.i [new file with mode: 0644]

index dd2a137..8509253 100644 (file)
@@ -1680,6 +1680,7 @@ AC_SUBST(DOCBOOK_STYLESHEETS)
 
 OPENAFS_OSCONF
 OPENAFS_FUSE
+OPENAFS_SWIG
 
 TOP_SRCDIR="${srcdir}/src"
 dnl
diff --git a/src/cf/swig.m4 b/src/cf/swig.m4
new file mode 100644 (file)
index 0000000..7f615ad
--- /dev/null
@@ -0,0 +1,11 @@
+dnl SWIG Autoconf glue. Build with SWIG-derived language bindings if SWIG
+dnl is available; if it's not, don't build the extra language bindings.
+
+AC_DEFUN([OPENAFS_SWIG],
+[AC_CHECK_PROG([SWIG], [swig], [swig])
+LIBUAFS_BUILD_PERL=
+if test "x$SWIG" = "xswig" ; then
+       LIBUAFS_BUILD_PERL=LIBUAFS_BUILD_PERL
+fi
+AC_SUBST(LIBUAFS_BUILD_PERL)
+])
index dfa10b4..165aa02 100644 (file)
@@ -14,11 +14,16 @@ UOBJ        =../UAFS
 PICOBJ  =../UAFS.pic
 JUAFS  =../JUAFS
 WEBOBJ=../AFSWEB
+PERLUAFS = PERLUAFS
 AFS    =../afs
 RX     =../rx
 AFSINT=../afsint
 LIB    =../lib
 NS_INCL =SRC/../afsweb/netscape_includes
+SWIG_PERL_CFLAGS = -fPIC $(shell perl -MExtUtils::Embed -e ccopts)
+SWIG_PERL_LDFLAGS = -fPIC $(shell perl -MExtUtils::Embed -e ldopts)
+SWIG = @SWIG@
+LIBUAFS_BUILD_PERL = @LIBUAFS_BUILD_PERL@
 
 TOP_OBJ_AUTH = ${TOP_OBJDIR}/src/auth
 TOP_OBJ_FSINT = ${TOP_OBJDIR}/src/fsint
@@ -58,7 +63,7 @@ COMMON_INCLUDE = -I. -I.. -I../nfs \
 # Build rules - CC and CFLAGS are defined in system specific MakefileProtos.
 
 all: ${TOP_LIBDIR}/$(LIBJUAFS) ${TOP_LIBDIR}/$(LIBUAFS) \
-       ${TOP_LIBDIR}/libuafs_pic.a linktest
+       ${TOP_LIBDIR}/libuafs_pic.a linktest @LIBUAFS_BUILD_PERL@
 
 ${TOP_LIBDIR}/$(LIBAFSWEB): AFSWEB/$(LIBAFSWEB)
        ${INSTALL_DATA} $? $@
@@ -75,11 +80,17 @@ ${TOP_LIBDIR}/libuafs_pic.a: UAFS.pic/libuafs_pic.a
 ${TOP_LIBDIR}/$(LIBJUAFS): JUAFS/$(LIBJUAFS)
        ${INSTALL_DATA} $? $@
 
-${TOP_LIBDIR}/perl/AFS/ukernel.so: PERLUAFS/ukernel.so
-       ${INSTALL_DATA} $? $@
+setup_perllib:
+       ${INSTALL} -d ${TOP_LIBDIR}/perl
+       ${INSTALL} -d ${TOP_LIBDIR}/perl/AFS
 
-${TOP_LIBDIR}/perl/AFS/ukernel.pm: PERLUAFS/ukernel.pm
-       ${INSTALL_DATA} $? $@
+${TOP_LIBDIR}/perl/ukernel.so: setup_perllib PERLUAFS/ukernel.so
+       ${INSTALL_DATA} PERLUAFS/ukernel.so $@
+
+${TOP_LIBDIR}/perl/AFS/ukernel.pm: setup_perllib PERLUAFS/ukernel.pm
+       ${INSTALL_DATA} PERLUAFS/ukernel.pm $@
+
+LIBUAFS_BUILD_PERL: ${TOP_LIBDIR}/perl/ukernel.so ${TOP_LIBDIR}/perl/AFS/ukernel.pm
 
 webinstall: all \
        ${TOP_LIBDIR}/$(LIBAFSWEB) \
@@ -2007,23 +2018,50 @@ $(JUAFS)/xdr_mem.o: $(TOP_SRC_RX)/xdr_mem.c
 $(JUAFS)/xdr_len.o: $(TOP_SRC_RX)/xdr_len.c
        $(CRULE1)
 
+$(PERLUAFS)/ukernel.pm: $(PERLUAFS)/ukernel_swig_perl.c
+$(PERLUAFS)/ukernel_swig_perl.c: ${srcdir}/ukernel_swig.i
+       mkdir -p $(PERLUAFS)
+       $(SWIG) -perl5 -o $@ ${srcdir}/ukernel_swig.i
+
+$(PERLUAFS)/ukernel_swig_perl.o: $(PERLUAFS)/ukernel_swig_perl.c
+       ${CC} -c ${CPPFLAGS} ${UAFS_CFLAGS} $(SWIG_PERL_CFLAGS) \
+               $(COMMON_INCLUDE) -DUKERNEL $(SHLIB_CFLAGS) -o $@ \
+               $(PERLUAFS)/ukernel_swig_perl.c
+
+$(PERLUAFS)/ukernel.so: $(PERLUAFS)/ukernel_swig_perl.o UAFS.pic/libuafs_pic.a
+       ${TOP_OBJDIR}/src/config/shlib-build -d $(srcdir) -p -f $@ -- \
+               $(SWIG_PERL_LDFLAGS) $(LDFLAGS) \
+               $(PERLUAFS)/ukernel_swig_perl.o \
+               UAFS.pic/libuafs_pic.a ${TOP_LIBDIR}/libcmd_pic.a \
+               ${TOP_LIBDIR}/libafsutil_pic.a $(LDFLAGS_roken) \
+               $(LDFLAGS_hcrypto) $(LIB_hcrypto) $(LIB_roken) $(LIB_crypt) \
+               $(XLIBS)
+
 clean:
-       -$(RM) -rf UAFS* JUAFS* AFSWEB* nsapi afsd afs afsint config rx
+       -$(RM) -rf UAFS* JUAFS* AFSWEB* PERLUAFS nsapi afsd afs afsint config rx
        -$(RM) -f  h net netinet rpc ufs machine inet nfs sys linktest $(AFS_OS_CLEAN)
 
 
-install: UAFS/$(LIBUAFS) JUAFS/$(LIBJUAFS) UAFS.pic/libuafs_pic.a
+install: UAFS/$(LIBUAFS) JUAFS/$(LIBJUAFS) UAFS.pic/libuafs_pic.a \
+               @LIBUAFS_BUILD_PERL@
        ${INSTALL} -d ${DESTDIR}${libdir}
        ${INSTALL_DATA} UAFS/$(LIBUAFS) ${DESTDIR}${libdir}/$(LIBUAFS)
        ${INSTALL_DATA} JUAFS/$(LIBJUAFS) ${DESTDIR}${libdir}/$(LIBJUAFS)
        ${INSTALL_DATA} UAFS.pic/libuafs_pic.a ${DESTDIR}${libdir}/libuafs_pic.a
+       if [ "x$(LIBUAFS_BUILD_PERL)" != "x" ] ; then \
+               ${INSTALL} -d ${DESTDIR}${libdir}/perl; \
+               ${INSTALL} -d ${DESTDIR}${libdir}/perl/AFS; \
+               ${INSTALL_DATA} PERLUAFS/ukernel.so ${DESTDIR}${libdir}/perl/ukernel.so; \
+               ${INSTALL_DATA} PERLUAFS/ukernel.pm ${DESTDIR}${libdir}/perl/AFS/ukernel.pm; \
+       fi;
 
 dest: $(TOP_INCDIR)/afs/param.h $(TOP_INCDIR)/afs/stds.h \
                $(TOP_INCDIR)/afs/afs_sysnames.h \
                $(TOP_INCDIR)/afs/afs_stats.h \
                $(TOP_SRCDIR)/afs/sysincludes.h \
                $(TOP_SRCDIR)/afs/UKERNEL/afs_usrops.h \
-               UAFS/$(LIBUAFS) JUAFS/$(LIBJUAFS) UAFS.pic/libuafs_pic.a
+               UAFS/$(LIBUAFS) JUAFS/$(LIBJUAFS) UAFS.pic/libuafs_pic.a \
+               @LIBUAFS_BUILD_PERL@
        ${INSTALL} -d ${DEST}/root.perf/include/afs
        ${INSTALL} -d ${DEST}/root.perf/lib
        ${INSTALL_DATA} $(TOP_INCDIR)/afs/param.h \
@@ -2041,6 +2079,12 @@ dest: $(TOP_INCDIR)/afs/param.h $(TOP_INCDIR)/afs/stds.h \
        ${INSTALL_DATA} UAFS/$(LIBUAFS) ${DEST}/root.perf/lib/$(LIBUAFS)
        ${INSTALL_DATA} JUAFS/$(LIBJUAFS) ${DEST}/root.perf/lib/$(LIBJUAFS)
        ${INSTALL_DATA} UAFS.pic/libuafs_pic.a ${DEST}/root.perf/lib/libuafs_pic.a
+       if [ "x$(LIBUAFS_BUILD_PERL)" != "x" ] ; then \
+               ${INSTALL} -d ${DEST}/root.perf/lib/perl; \
+               ${INSTALL} -d ${DEST}/root.perf/lib/perl/AFS; \
+               ${INSTALL_DATA} PERLUAFS/ukernel.so ${DEST}/root.perf/lib/perl/ukernel.so; \
+               ${INSTALL_DATA} PERLUAFS/ukernel.pm ${DEST}/root.perf/lib/perl/AFS/ukernel.pm; \
+       fi;
 
 #
 # Common directory and other build targets
diff --git a/src/libuafs/ukernel_swig.i b/src/libuafs/ukernel_swig.i
new file mode 100644 (file)
index 0000000..bf6ce41
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2010, Sine Nomine Associates.
+ * All Rights Reserved.
+ *
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
+ */
+
+/*
+ * libuafs SWIG interface file
+ *
+ * This file specifies the libuafs interfaces for SWIG, which can then be
+ * used to easily create libuafs bindings to other languages such as Perl.
+ *
+ * For each language you want a binding for, there are two typemaps you
+ * must define for that language, since SWIG does not handle them natively.
+ * These are the 'in' typemap for READBUF and LENGTH, and the 'argout'
+ * typemap for READBUF. Search this file for 'perl5' to see existing ones
+ * for the Perl 5 bindings.
+ */
+
+%module "AFS::ukernel"
+
+%{
+#include <afsconfig.h>
+#include <afs/param.h>
+
+#include <afs/afsutil.h>
+#include <afs/sysincludes.h>
+#include <afs_usrops.h>
+#include <afs/cmd.h>
+#include <afs/afs_args.h>
+%}
+
+%include "typemaps.i";
+
+%apply long { off_t };
+
+%rename (uafs_ParseArgs) swig_uafs_ParseArgs;
+%inline %{
+/* SWIG doesn't handle argv-like string arrays too well, so instead have
+ * a wrapper to convert a single string of all arguments into an argv-like
+ * array. Conveniently, libcmd can do this.
+ *
+ * We could instead do this with SWIG typemaps, but writing this little
+ * function instead is much more language-neutral. With typemaps, we'd have
+ * to write the converting code for each target language.
+ */
+extern int
+swig_uafs_ParseArgs(char *line)
+{
+    char *argv[1024];
+    int argc;
+    int code;
+
+    code = cmd_ParseLine(line, argv, &argc, sizeof(argv)/sizeof(argv[0]));
+    if (code) {
+        afs_com_err("AFS::ukernel", code, "parsing line: '%s'", line);
+        return code;
+    }
+
+    code = uafs_ParseArgs(argc, argv);
+
+    cmd_FreeArgv(argv);
+
+    return code;
+}
+%}
+extern int uafs_Setup(const char *mount);
+extern int uafs_Run(void);
+
+/*
+ * Define typemaps for binary read buffers. SWIG natively handles
+ * NUL-terminated strings, but uafs_read could have NULs in the middle of the
+ * string, so we need these typemaps to pay attention to the string length.
+ *
+ * (Reading in a binary buffer from e.g. uafs_write is already handled natively
+ * by SWIG. Fancy that.)
+ */
+%typemap(in, numinputs=1, perl5) (char *READBUF, int LENGTH) {
+    if (!SvIOK($input)) {
+        SWIG_croak("expected an integer");
+    }
+    $2 = SvIV($input);
+    Newx($1, $2, char);
+}
+%typemap(argout, numinputs=1, perl5) char *READBUF {
+    /* some logic here copied from typemaps.i and/or SWIG itself, since I'm not
+     * a perl dev */
+
+    if (argvi >= items) {
+        EXTEND(sp, 1);
+    }
+
+    /* 'result' is the return value from the actual C function call; we assume
+     * it is an int that represents how many bytes of data were actually read into
+     * the buffer if nonnegative */
+    if (result < 0) {
+        $result = &PL_sv_undef;
+    } else {
+        $result = sv_2mortal(newSVpvn($1, result));
+    }
+
+    Safefree($1);
+    argvi++;
+}
+
+extern int uafs_mkdir(char *path, int mode);
+extern int uafs_chdir(char *path);
+extern int uafs_open(char *path, int flags, int mode=0);
+extern int uafs_creat(char *path, int mode);
+extern int uafs_write(int fd, char *STRING, int LENGTH);
+extern int uafs_pwrite(int fd, char *STRING, int LENGTH, off_t offset);
+extern int uafs_read(int fd, char *READBUF, int LENGTH);
+extern int uafs_pread(int fd, char *READBUF, int LENGTH, off_t offset);
+extern int uafs_fsync(int fd);
+extern int uafs_close(int fd);
+
+%{
+#define STAT_TYPE long
+#define STAT_ARGS        \
+    STAT_TYPE *adev,     \
+    STAT_TYPE *aino,     \
+    STAT_TYPE *amode,    \
+    STAT_TYPE *anlink,   \
+    STAT_TYPE *auid,     \
+    STAT_TYPE *agid,     \
+    STAT_TYPE *ardev,    \
+    STAT_TYPE *asize,    \
+    STAT_TYPE *aatime,   \
+    STAT_TYPE *amtime,   \
+    STAT_TYPE *actime,   \
+    STAT_TYPE *ablksize, \
+    STAT_TYPE *ablocks
+
+#define STAT_COPYFROM(st) do {   \
+    *adev     = (st).st_dev;     \
+    *aino     = (st).st_ino;     \
+    *amode    = (st).st_mode;    \
+    *anlink   = (st).st_nlink;   \
+    *auid     = (st).st_uid;     \
+    *agid     = (st).st_gid;     \
+    *ardev    = (st).st_rdev;    \
+    *asize    = (st).st_size;    \
+    *aatime   = (st).st_atime;   \
+    *amtime   = (st).st_mtime;   \
+    *actime   = (st).st_ctime;   \
+    *ablksize = (st).st_blksize; \
+    *ablocks  = (st).st_blocks;  \
+} while (0)
+
+int
+swig_uafs_stat(char *path, STAT_ARGS)
+{
+    int code;
+    struct stat st;
+    code = uafs_stat(path, &st);
+    if (code == 0) {
+        STAT_COPYFROM(st);
+    }
+    return code;
+}
+int
+swig_uafs_lstat(char *path, STAT_ARGS)
+{
+    int code;
+    struct stat st;
+    code = uafs_lstat(path, &st);
+    if (code == 0) {
+        STAT_COPYFROM(st);
+    }
+    return code;
+}
+int
+swig_uafs_fstat(int fd, STAT_ARGS)
+{
+    int code;
+    struct stat st;
+    code = uafs_fstat(fd, &st);
+    if (code == 0) {
+        STAT_COPYFROM(st);
+    }
+    return code;
+}
+
+#undef STAT_TYPE
+#undef STAT_ARGS
+#undef STAT_COPYFROM
+%}
+
+%define STAT_TYPE
+long
+%enddef
+%define STAT_OUT_ARGS
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT,
+STAT_TYPE *OUTPUT
+%enddef
+
+%rename (uafs_stat) swig_uafs_stat;
+%rename (uafs_lstat) swig_uafs_lstat;
+%rename (uafs_fstat) swig_uafs_fstat;
+
+extern int swig_uafs_stat(char *path, STAT_OUT_ARGS);
+extern int swig_uafs_lstat(char *path, STAT_OUT_ARGS);
+extern int swig_uafs_fstat(int fd, STAT_OUT_ARGS);
+
+extern int uafs_truncate(char *path, int len);
+extern int uafs_ftruncate(int fd, int len);
+extern int uafs_lseek(int fd, int offset, int whence);
+extern int uafs_chmod(char *path, int mode);
+extern int uafs_fchmod(int fd, int mode);
+extern int uafs_symlink(char *target, char *source);
+extern int uafs_unlink(char *path);
+extern int uafs_rmdir(char *path);
+extern int uafs_readlink(char *path, char *READBUF, int LENGTH);
+extern int uafs_link(char *existing, char *new);
+extern int uafs_rename(char *old, char *new);
+
+extern usr_DIR *uafs_opendir(char *path);
+
+%rename (uafs_readdir) swig_uafs_readdir;
+%{
+/*
+ * Language-neutral wrapper for uafs_readdir. Since the language won't know
+ * what to do with a struct usr_dirent, we could either make a SWIG typemap, or
+ * define a wrapper with multiple return arguments. Making a typemap is
+ * language-specific, so we define a wrapper, and let the typemaps.i library
+ * worry about the language-specific parts of getting multiple return values.
+ */
+char *
+swig_uafs_readdir(usr_DIR *dirp, unsigned long *d_ino, unsigned long *d_off, unsigned short *d_reclen)
+{
+    struct usr_dirent *dentry;
+
+    dentry = uafs_readdir(dirp);
+    if (!dentry) {
+        *d_ino = *d_off = *d_reclen = 0;
+        return NULL;
+    }
+
+    *d_ino = dentry->d_ino;
+    *d_off = dentry->d_off;
+    *d_reclen = dentry->d_reclen;
+
+    return strdup(dentry->d_name);
+}
+%}
+
+extern char * swig_uafs_readdir(usr_DIR *dirp, unsigned long *OUTPUT, unsigned long *OUTPUT, unsigned short *OUTPUT);
+extern int uafs_closedir(usr_DIR * dirp);
+extern void uafs_SetRxPort(int);
+extern void uafs_Shutdown(void);