diff --git a/acinclude.m4 b/acinclude.m4 index dd2a137539..8509253412 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -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 index 0000000000..7f615ad334 --- /dev/null +++ b/src/cf/swig.m4 @@ -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) +]) diff --git a/src/libuafs/Makefile.common.in b/src/libuafs/Makefile.common.in index dfa10b4ece..165aa02872 100644 --- a/src/libuafs/Makefile.common.in +++ b/src/libuafs/Makefile.common.in @@ -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 index 0000000000..bf6ce41853 --- /dev/null +++ b/src/libuafs/ukernel_swig.i @@ -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 +#include + +#include +#include +#include +#include +#include +%} + +%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);