nspluginwrapper-1.1.2

Taken from lp:~ubuntu-dev/nspluginwrapper/upstream.
This commit is contained in:
David Benjamin 2011-03-05 23:10:51 -05:00
parent 10bbf2f098
commit 199cf054f2
25 changed files with 1959 additions and 166 deletions

137
ChangeLog
View File

@ -1,3 +1,140 @@
2008-10-12 16:01 Gwenole Beauchesne <gb.public@free.fr>
* README: Mention the standalone plugins player.
2008-10-12 15:59 Gwenole Beauchesne <gb.public@free.fr>
* README, src/npw-config.c: Update doc for nspluginwrapper
-n|--native flag.
2008-10-12 15:21 Gwenole Beauchesne <gb.public@free.fr>
* NEWS, nspluginwrapper.spec: Updates for 1.1.2 release.
2008-10-12 15:19 Gwenole Beauchesne <gb.public@free.fr>
* README: Flash Player 10 release candidate also works.
2008-10-12 15:05 Gwenole Beauchesne <gb.public@free.fr>
* Makefile, configure, src/npw-config.c: Add support for Open
Solaris (2008.05).
2008-10-12 15:04 Gwenole Beauchesne <gb.public@free.fr>
* src/npw-viewer.sh: Fix architecture detection on Solaris/i386.
2008-10-12 15:03 Gwenole Beauchesne <gb.public@free.fr>
* src/npw-config.c: Allow wrapping of native plugins through the
-n|--native option.
2008-10-12 15:00 Gwenole Beauchesne <gb.public@free.fr>
* src/npw-config-template.h: Try to guess Solaris binaries with
.SUNW_version sections.
2008-10-12 13:55 Gwenole Beauchesne <gb.public@free.fr>
* Makefile, utils/install.sh: Add install program.
2008-10-12 08:31 Gwenole Beauchesne <gb.public@free.fr>
* configure: Fix build on NetBSD 3.1.
2008-10-12 08:22 Gwenole Beauchesne <gb.public@free.fr>
* configure, src/rpc.c: Fix calculation of sockaddr_un length.
2008-10-06 21:55 Gwenole Beauchesne <gb.public@free.fr>
* configure, src/rpc.c: Make it possible to define the maximum of
time (in seconds) to wait for the plugin to connect. This can be
set both at configure-time (--rpc-init-timeout) or at run-time
(NPW_INIT_TIMEOUT) (Initial patch by Geraint North).
2008-10-06 21:25 Gwenole Beauchesne <gb.public@free.fr>
* configure: Detect ARM (Geraint North).
2008-10-05 21:45 Gwenole Beauchesne <gb.public@free.fr>
* src/npruntime.c, src/npw-viewer.c, src/npw-wrapper.c: Revert rev
647 (renaming of g_rpc_connection to g_npn_connection).
2008-10-05 21:43 Gwenole Beauchesne <gb.public@free.fr>
* src/rpc.c: Handle possible _rpc_dispatch_until() errors in
rpc_method_invoke().
2008-10-05 21:39 Gwenole Beauchesne <gb.public@free.fr>
* TODO, src/npruntime.c, src/npw-viewer.c, src/npw-wrapper.c,
src/rpc.c, tests/test-rpc-concurrent.c, tests/test-rpc-nested.c,
tests/test-rpc-types.c: Rework RPC code to cope with concurrent
rpc_method_invoke(). This function is now atomic. That is,
method id and its arguments are marshalled in one shot, there is
no intermediate wait for MSG_ACK.
Notable change also includes the fact that optimization for
no-argument or no-return value cases is now gone. i.e. each
rpc_method_invoke() shall have an rpc_method_get_args() on the
other side, even if there is no arg passed. Besides, each
rpc_method_wait_for_reply() shall have an
rpc_method_send_reply() on the other side, even if the function
normally doesn't return anything.
This optimization could be brought back into V3 protocol
specification. Current revision is now V2.5.
2008-10-05 21:03 Gwenole Beauchesne <gb.public@free.fr>
* tests/test-rpc-common.c: Cleaner exit code path.
2008-10-05 16:32 Gwenole Beauchesne <gb.public@free.fr>
* tests/test-rpc-concurrent.c: Error out early for invalid message
types.
2008-10-05 16:27 Gwenole Beauchesne <gb.public@free.fr>
* tests/test-rpc-concurrent.c: Default to silent mode and 5000
messages.
2008-10-05 16:08 Gwenole Beauchesne <gb.public@free.fr>
* Makefile, tests/test-rpc-common.c, tests/test-rpc-common.h,
tests/test-rpc-concurrent.c, tests/test-rpc-nested.c,
tests/test-rpc-types.c: Add tests for new RPC implementation.
2008-10-04 13:31 Gwenole Beauchesne <gb.public@free.fr>
* lsb-build/headers/glib-2.0/glib.h,
lsb-build/stub_libs/libglib-2.0.c: Add basic GSlice support
thunks.
2008-10-04 13:30 Gwenole Beauchesne <gb.public@free.fr>
* src/utils.c, src/utils.h: Add npw_asprintf().
2008-10-04 08:02 Gwenole Beauchesne <gb.public@free.fr>
* src/npruntime.c, src/npw-viewer.c, src/npw-wrapper.c: Rename
g_rpc_connection to g_npn_connection.
2008-09-29 22:03 Gwenole Beauchesne <gb.public@free.fr>
* src/npw-rpc.c, src/npw-viewer.c: Fix X visual marshaling (Flash
10, initial patch by Martin Stransky).
2008-07-07 19:37 Gwenole Beauchesne <gb.public@free.fr>
* nspluginwrapper.spec: Bump version for development.
2008-07-06 20:59 Gwenole Beauchesne <gb.public@free.fr>
* ChangeLog: Generated by svn2cl.
2008-07-06 20:55 Gwenole Beauchesne <gb.public@free.fr>
* nspluginwrapper.spec: Add libnoxshm.so to filelist.

View File

@ -1,4 +1,3 @@
#!/bin/sh
#
# nspluginwrapper Makefile (C) 2005-2008 Gwenole Beauchesne
#
@ -31,12 +30,26 @@ ifeq ($(SNAPSHOT),1)
VERSION_SUFFIX = -$(SVNDATE)
endif
ifeq ($(INSTALL),)
INSTALL = install
ifneq (,$(findstring $(OS),solaris))
INSTALL = $(SRC_PATH)/utils/install.sh
endif
endif
ifeq ($(ALLOW_STRIP), yes)
STRIP_OPT = -s
endif
LN_S = ln -sf
ifeq ($(LD_soname),)
LD_soname = -soname
ifeq ($(TARGET_OS),solaris)
LD_soname = -h
endif
endif
ifneq (,$(findstring $(OS),linux))
libdl_LDFLAGS = -ldl
endif
@ -46,6 +59,10 @@ ifeq ($(OS),dragonfly)
libpthread_LDFLAGS = -pthread
endif
ifneq (,$(findstring $(OS),solaris))
libsocket_LDFLAGS = -lsocket -lnsl
endif
PIC_CFLAGS = -fPIC
DSO_LDFLAGS = -shared
ifeq ($(COMPILER),xlc)
@ -90,7 +107,7 @@ npwrapper_RAWSRCS = npw-wrapper.c npw-rpc.c rpc.c debug.c utils.c npruntime.c
npwrapper_SOURCES = $(npwrapper_RAWSRCS:%.c=$(SRC_PATH)/src/%.c)
npwrapper_OBJECTS = $(npwrapper_RAWSRCS:%.c=npwrapper-%.os)
npwrapper_CFLAGS = $(CFLAGS) $(X_CFLAGS) $(MOZILLA_CFLAGS) $(GLIB_CFLAGS)
npwrapper_LDFLAGS = $(X_LDFLAGS) $(libpthread_LDFLAGS)
npwrapper_LDFLAGS = $(X_LDFLAGS) $(libpthread_LDFLAGS) $(libsocket_LDFLAGS)
npwrapper_LDFLAGS += $(GLIB_LDFLAGS)
npviewer_PROGRAM = npviewer.bin
@ -110,25 +127,28 @@ npviewer_LDFLAGS = $(GTK_LDFLAGS) $(X_LDFLAGS)
endif
npviewer_CFLAGS += $(MOZILLA_CFLAGS)
npviewer_LDFLAGS += $(libdl_LDFLAGS) $(libpthread_LDFLAGS) -lgthread-2.0
ifeq ($(TARGET_ARCH),i386)
ifeq ($(TARGET_OS):$(TARGET_ARCH),linux:i386)
npviewer_MAPFILE = $(SRC_PATH)/src/npw-viewer.map
endif
ifneq ($(npviewer_MAPFILE),)
npviewer_LDFLAGS += -Wl,--export-dynamic
npviewer_LDFLAGS += -Wl,--version-script,$(npviewer_MAPFILE)
endif
ifeq ($(OS):$(TARGET_ARCH),linux:i386)
ifeq ($(TARGET_OS):$(TARGET_ARCH),linux:i386)
npviewer_SOURCES += $(SRC_PATH)/src/cxxabi-compat.cpp
npviewer_OBJECTS += npviewer-cxxabi-compat.o
npviewer_LDFLAGS += -lsupc++
endif
ifeq ($(TARGET_OS):$(TARGET_ARCH),solaris:i386)
npviewer_LDFLAGS += $(libsocket_LDFLAGS)
endif
npplayer_PROGRAM = npplayer
npplayer_SOURCES = npw-player.c debug.c rpc.c utils.c glibcurl.c gtk2xtbin.c $(tidy_SOURCES)
npplayer_OBJECTS = $(npplayer_SOURCES:%.c=npplayer-%.o)
npplayer_CFLAGS = $(GTK_CFLAGS) $(MOZILLA_CFLAGS) $(CURL_CFLAGS) $(X_CFLAGS)
npplayer_LDFLAGS = $(GTK_LDFLAGS) $(CURL_LDFLAGS) $(X_LDFLAGS)
npplayer_LDFLAGS += -lgthread-2.0 $(libpthread_LDFLAGS)
npplayer_LDFLAGS += -lgthread-2.0 $(libpthread_LDFLAGS) $(libsocket_LDFLAGS)
libxpcom_LIBRARY = libxpcom.so
libxpcom_RAWSRCS = libxpcom.c debug.c
@ -166,6 +186,18 @@ nploader_PROGRAM = npviewer
nploader_RAWSRCS = npw-viewer.sh
nploader_SOURCES = $(nploader_RAWSRCS:%.sh=$(SRC_PATH)/src/%.sh)
test_rpc_RAWSRCS = test-rpc-common.c debug.c rpc.c
test_rpc_client_OBJECTS = $(test_rpc_RAWSRCS:%.c=%-client.o)
test_rpc_server_OBJECTS = $(test_rpc_RAWSRCS:%.c=%-server.o)
test_rpc_client_CPPFLAGS = $(CPPFLAGS) -I$(SRC_PATH)/src -DBUILD_CLIENT -DNPW_COMPONENT_NAME="\"Client\""
test_rpc_server_CPPFLAGS = $(CPPFLAGS) -I$(SRC_PATH)/src -DBUILD_SERVER -DNPW_COMPONENT_NAME="\"Server\""
test_rpc_CFLAGS = -I$(SRC_PATH)/src $(GLIB_CFLAGS)
test_rpc_LDFLAGS = $(GLIB_LDFLAGS) $(libpthread_LDFLAGS) $(libsocket_LDFLAGS)
test_rpc_RAWPROGS = test-rpc-types test-rpc-nested test-rpc-concurrent
test_rpc_PROGRAMS = \
$(test_rpc_RAWPROGS:%=%-client) \
$(test_rpc_RAWPROGS:%=%-server)
CPPFLAGS = -I. -I$(SRC_PATH)
TARGETS = $(npconfig_PROGRAM)
TARGETS += $(nploader_PROGRAM)
@ -178,6 +210,7 @@ endif
ifeq ($(build_player),yes)
TARGETS += $(npplayer_PROGRAM)
endif
TARGETS += $(test_rpc_PROGRAMS)
archivedir = files/
SRCARCHIVE = $(PACKAGE)-$(VERSION)$(VERSION_SUFFIX).tar
@ -191,6 +224,7 @@ FILES += $(wildcard src/*.h)
FILES += $(wildcard src/*.sh)
FILES += $(wildcard src/*.map)
FILES += $(wildcard tests/*.html)
FILES += $(wildcard tests/*.c tests/*.h)
FILES += $(wildcard npapi/*.h npapi/nspr/*.h npapi/nspr/obsolete/*.h)
FILES += $(LSB_TOP_DIR)/headers/core_filelist
FILES += $(addprefix $(LSB_TOP_DIR)/headers/,$(shell cat $(LSB_TOP_DIR)/headers/core_filelist))
@ -254,14 +288,14 @@ ifneq ($(ARCH),$(ARCH_32))
endif
ifeq ($(build_player),yes)
install.player: $(npplayer_PROGRAM)
install -m 755 $(STRIP_OPT) $(npplayer_PROGRAM) $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npplayer_PROGRAM)
$(INSTALL) -m 755 $(STRIP_OPT) $(npplayer_PROGRAM) $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npplayer_PROGRAM)
mkdir -p $(DESTDIR)$(bindir)
$(LN_S) $(pkglibdir)/$(ARCH)/$(OS)/$(npplayer_PROGRAM) $(DESTDIR)$(bindir)/nspluginplayer
else
install.player:
endif
install.wrapper: $(npwrapper_LIBRARY)
install -m 755 $(STRIP_OPT) $(npwrapper_LIBRARY) $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npwrapper_LIBRARY)
$(INSTALL) -m 755 $(STRIP_OPT) $(npwrapper_LIBRARY) $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npwrapper_LIBRARY)
ifeq ($(build_viewer),yes)
install.viewer: install.viewer.bin install.viewer.glue
install.libxpcom: do.install.libxpcom
@ -272,7 +306,7 @@ install.libxpcom:
install.libnoxshm:
endif
install.viewer.bin: $(npviewer_PROGRAM)
install -m 755 $(STRIP_OPT) $(npviewer_PROGRAM) $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(npviewer_PROGRAM)
$(INSTALL) -m 755 $(STRIP_OPT) $(npviewer_PROGRAM) $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(npviewer_PROGRAM)
install.viewer.glue::
p=$(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(npviewer_PROGRAM:%.bin=%); \
echo "#!/bin/sh" > $$p; \
@ -281,17 +315,17 @@ install.viewer.glue::
echo ". $(pkglibdir)/noarch/$(nploader_PROGRAM)" >> $$p; \
chmod 755 $$p
do.install.libxpcom: $(libxpcom_LIBRARY)
install -m 755 $(STRIP_OPT) $(libxpcom_LIBRARY) $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(libxpcom_LIBRARY)
$(INSTALL) -m 755 $(STRIP_OPT) $(libxpcom_LIBRARY) $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(libxpcom_LIBRARY)
do.install.libnoxshm: $(libnoxshm_LIBRARY)
install -m 755 $(STRIP_OPT) $(libnoxshm_LIBRARY) $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(libnoxshm_LIBRARY)
$(INSTALL) -m 755 $(STRIP_OPT) $(libnoxshm_LIBRARY) $(DESTDIR)$(pkglibdir)/$(ARCH_32)/$(TARGET_OS)/$(libnoxshm_LIBRARY)
install.config: $(npconfig_PROGRAM)
install -m 755 $(STRIP_OPT) $(npconfig_PROGRAM) $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npconfig_PROGRAM)
$(INSTALL) -m 755 $(STRIP_OPT) $(npconfig_PROGRAM) $(DESTDIR)$(pkglibdir)/$(ARCH)/$(OS)/$(npconfig_PROGRAM)
mkdir -p $(DESTDIR)$(bindir)
$(LN_S) $(pkglibdir)/$(ARCH)/$(OS)/$(npconfig_PROGRAM) $(DESTDIR)$(bindir)/nspluginwrapper
install.loader: $(nploader_PROGRAM)
install -m 755 $(nploader_PROGRAM) $(DESTDIR)$(pkglibdir)/noarch/$(nploader_PROGRAM)
$(INSTALL) -m 755 $(nploader_PROGRAM) $(DESTDIR)$(pkglibdir)/noarch/$(nploader_PROGRAM)
install.mkruntime: $(SRC_PATH)/utils/mkruntime.sh
install -m 755 $< $(DESTDIR)$(pkglibdir)/noarch/mkruntime
$(INSTALL) -m 755 $< $(DESTDIR)$(pkglibdir)/noarch/mkruntime
$(archivedir)::
[ -d $(archivedir) ] || mkdir $(archivedir) > /dev/null 2>&1
@ -357,13 +391,13 @@ npplayer-%.o: $(SRC_PATH)/src/tidy/%.c
$(CC) $(CFLAGS) -o $@ -c $< $(CPPFLAGS) $(npplayer_CFLAGS) -DBUILD_PLAYER
$(libxpcom_LIBRARY): $(libxpcom_OBJECTS) $(LSB_OBJ_DIR) $(LSB_LIBS)
$(CC) $(LDFLAGS_32) $(DSO_LDFLAGS) -o $@ $(libxpcom_OBJECTS) $(libxpcom_LDFLAGS) -Wl,--soname,libxpcom.so
$(CC) $(LDFLAGS_32) $(DSO_LDFLAGS) -o $@ $(libxpcom_OBJECTS) $(libxpcom_LDFLAGS) -Wl,$(LD_soname),libxpcom.so
libxpcom-%.o: $(SRC_PATH)/src/%.c
$(CC) $(CFLAGS_32) -o $@ -c $< $(CPPFLAGS) $(libxpcom_CFLAGS) -DBUILD_XPCOM
$(libnoxshm_LIBRARY): $(libnoxshm_OBJECTS) $(LSB_OBJ_DIR) $(LSB_LIBS)
$(CC) $(LDFLAGS_32) $(DSO_LDFLAGS) -o $@ $(libnoxshm_OBJECTS) $(libnoxshm_LDFLAGS) -Wl,--soname,libnoxshm.so
$(CC) $(LDFLAGS_32) $(DSO_LDFLAGS) -o $@ $(libnoxshm_OBJECTS) $(libnoxshm_LDFLAGS) -Wl,$(LD_soname),libnoxshm.so
libnoxshm-%.o: $(SRC_PATH)/src/%.c
$(CC) $(CFLAGS_32) -o $@ -c $< $(CPPFLAGS) $(libnoxshm_CFLAGS)
@ -398,3 +432,16 @@ $(LSB_OBJ_DIR)/%.so: $(LSB_OBJ_DIR)/%.o
$(CC) $(LDFLAGS_32) -nostdlib $(DSO_LDFLAGS) $< -o $@ \
-Wl,--version-script,$(patsubst $(LSB_OBJ_DIR)/%.o,$(LSB_SRC_DIR)/%.Version,$<) \
-Wl,-soname,`grep "$(patsubst $(LSB_OBJ_DIR)/%.o,%,$<) " $(LSB_SRC_DIR)/LibNameMap.txt | cut -f2 -d' '`
test-rpc-%-client: test-rpc-%-client.o $(test_rpc_client_OBJECTS)
$(CC) -o $@ $< $(test_rpc_client_OBJECTS) $(test_rpc_LDFLAGS)
test-rpc-%-client.o: $(SRC_PATH)/tests/test-rpc-%.c
$(CC) -o $@ -c $< $(test_rpc_client_CPPFLAGS) $(test_rpc_CFLAGS)
%-client.o: $(SRC_PATH)/src/%.c
$(CC) -o $@ -c $< $(test_rpc_client_CPPFLAGS) $(test_rpc_CFLAGS)
test-rpc-%-server: test-rpc-%-server.o $(test_rpc_server_OBJECTS)
$(CC) -o $@ $< $(test_rpc_server_OBJECTS) $(test_rpc_LDFLAGS)
test-rpc-%-server.o: $(SRC_PATH)/tests/test-rpc-%.c
$(CC) -o $@ -c $< $(test_rpc_server_CPPFLAGS) $(test_rpc_CFLAGS)
%-server.o: $(SRC_PATH)/src/%.c
$(CC) -o $@ -c $< $(test_rpc_server_CPPFLAGS) $(test_rpc_CFLAGS)

9
NEWS
View File

@ -1,6 +1,13 @@
nspluginwrapper NEWS -- history of user-visible changes. 2008-07-06
nspluginwrapper NEWS -- history of user-visible changes. 2008-10-12
Copyright (C) 2005-2008 Gwenole Beauchesne
Version 1.1.2 (BETA) - 12.Oct.2008
* Add support for Open Solaris hosts
* Add support for ARM targets (Geraint North)
* Fix support for windowless plugins (Flash Player 10 rc)
* Fix various bugs in RPC code (crashes and concurrent messaging)
* Allow wrapping of native plugins through the -n|--native option
Version 1.1.0 (BETA) - 06.Jul.2008
* Add support for windowless plugins (Flash Player 10 beta 2)
* Add standalone plugins player (nspluginplayer)

7
README
View File

@ -20,6 +20,10 @@ compatible plugins. It makes it possible to use 32-bit x86 plugins
like Adobe Flash Player on other platforms like Linux/x86_64, *BSD and
even Linux/ppc.
nspluginwrapper also provides a standalone plugins player. This
programs makes it possible to execute plugins without an actual
browser.
Quick build notes
-----------------
@ -57,6 +61,7 @@ You can manually install/remove/update plugins with "nspluginwrapper".
-h --help print this message
-a --auto set automatic mode for plugins discovery
-n --native allow native plugin(s) to be wrapped
-l --list list plugins currently installed
-u --update update plugin(s) currently installed
-i --install [FILE(S)] install plugin(s)
@ -78,7 +83,7 @@ The following plugins work reasonnably well:
- DejaVu Libre 3.5.14
- Flash Player 7.0
- Flash Player 9.0.124
- Flash Player 10.0 (beta 2)
- Flash Player 10.0 (beta 2, rc)
- Linux J2K 0.0.2
- Mplayerplug-in 2.80
- Mplayerplug-in 3.25

1
TODO
View File

@ -19,6 +19,7 @@
* Split toolkit specific code (npviewer-{x11,gtk,win}.c)
* Use winelib + override win32 socket to support AF_UNIX (Linux "native")
- RPC
* RPC_MESSAGE_FAILURE handling is broken
* Need a way to differenciate array of pointers or array of values
=> RPC_TYPE_DYNAMIC (allocate space), RPC_TYPE_STATIC (assumes data alloc'ed?)
=> Rearrange RPC message type descriptors

49
configure vendored
View File

@ -35,7 +35,11 @@ host_os=`uname -s | tr '[A-Z]' '[a-z]'`
host_cpu=`uname -m`
target_os="linux"
target_cpu="i386"
rpc_init_timeout=5
case "$host_cpu" in
arm*)
host_cpu="arm"
;;
i386|i486|i586|i686|i86pc|BePC)
host_cpu="i386"
;;
@ -61,7 +65,11 @@ x86_64|amd64)
host_cpu="unknown"
;;
esac
bigendian="no"
case "$host_os" in
sunos*)
host_os="solaris"
;;
esac
# find source path
# XXX: we assume an absolute path is given when launching configure,
@ -130,6 +138,9 @@ case "$opt" in
--with-cxx=*)
cxx=`echo $opt | cut -d '=' -f 2`
;;
--rpc-init-timeout=*)
rpc_init_timeout=`echo $opt | cut -d '=' -f 2`
;;
esac
done
@ -231,6 +242,24 @@ if $cc -Werror $TMPC -o $TMPE >/dev/null 2>&1; then
fi
rm -f $TMPC $TMPE
# check for sockaddr_un::sun_len member
cat > $TMPC << EOF
#include <sys/types.h>
#include <sys/un.h>
int main(void) {
struct sockaddr_un addr;
addr.sun_len = 0;
return 0;
}
EOF
has_sockaddr_un_sun_len=no
if $cc -Werror $TMPC -o $TMPE >/dev/null 2>&1; then
if $TMPE; then
has_sockaddr_un_sun_len=yes
fi
fi
rm -f $TMPC $TMPE
# check for egrep program
if echo a | (grep -E '(a|b)') >/dev/null 2>&1; then
EGREP='grep -E'
@ -448,6 +477,7 @@ int main(int argc, char ** argv){
}
EOF
bigendian="no"
if $cc -o $TMPE $TMPC 2>/dev/null ; then
$TMPE && bigendian="yes"
else
@ -560,6 +590,7 @@ echo " --with-lib64=NAME use NAME as the 64-bit library dir name [$li
echo " --with-x11-prefix=PREFIX use PREFIX as the X11 base dir [autodetect]"
echo " --with-cc=CC use C compiler CC [$cc]"
echo " --with-cxx=CXX use C++ compiler CXX [$cxx]"
echo " --rpc-init-timeout=VALUE wait VALUE seconds for the plugin to connect [$rpc_init_timeout]"
echo ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@ -582,6 +613,7 @@ echo "host CPU $host_cpu"
echo "host big endian $bigendian"
echo "target OS $target_os"
echo "target CPU $target_cpu"
echo "rpc init timeout $rpc_init_timeout secs"
config_mak="config-host.mak"
echo "# Automatically generated by configure - do not modify" > $config_mak
@ -621,6 +653,10 @@ elif test "$host_os" = "netbsd"; then
echo "OS=netbsd" >> $config_mak
echo "#define HOST_NETBSD 1" >> $config_h
echo "#define HOST_OS \"netbsd\"" >> $config_h
elif test "$host_os" = "solaris"; then
echo "OS=solaris" >> $config_mak
echo "#define HOST_SOLARIS 1" >> $config_h
echo "#define HOST_OS \"solaris\"" >> $config_h
else
echo "Unsupported OS"
exit 1
@ -653,6 +689,10 @@ elif test "$host_cpu" = "ia64" ; then
echo "ARCH=ia64" >> $config_mak
echo "#define HOST_IA64 1" >> $config_h
echo "#define HOST_ARCH \"ia64\"" >> $config_h
elif test "$host_cpu" = "arm" ; then
echo "ARCH=arm" >> $config_mak
echo "#define HOST_ARM 1" >> $config_h
echo "#define HOST_ARCH \"arm\"" >> $config_h
else
echo "Unsupported CPU"
exit 1
@ -703,6 +743,8 @@ fi
echo "pkglibdir=$pkglibdir" >> $config_mak
echo "#define NPW_LIBDIR \"$pkglibdir\"" >> $config_h
echo "#define RPC_INIT_TIMEOUT $rpc_init_timeout" >> $config_h
if test "$has_visibility_attribute" = "yes"; then
echo "#define attribute_hidden __attribute__((visibility(\"hidden\")))" >> $config_h
echo "#define attribute_protected __attribute__((visibility(\"protected\")))" >> $config_h
@ -715,6 +757,11 @@ if test "$has_initfini_array" = "yes"; then
else
echo "#undef HAVE_INITFINI_ARRAY" >> $config_h
fi
if test "$has_sockaddr_un_sun_len" = "yes"; then
echo "#define HAVE_SOCKADDR_UN_SUN_LEN 1" >> $config_h
else
echo "#undef HAVE_SOCKADDR_UN_SUN_LEN" >> $config_h
fi
if test "$libc_provides_ssp" = "yes"; then
echo "#define TARGET_LIBC_PROVIDES_SSP 1" >> $config_h
else

View File

@ -3290,6 +3290,18 @@ extern "C" {
extern GDate *g_date_new(void);
extern void g_thread_init_with_errorcheck_mutexes(GThreadFunctions *);
extern void g_thread_init(GThreadFunctions *);
extern gpointer g_slice_alloc (gsize block_size) G_GNUC_MALLOC;
extern gpointer g_slice_alloc0 (gsize block_size) G_GNUC_MALLOC;
extern void g_slice_free1 (gsize block_size, gpointer mem_block);
#define g_slice_new(type) \
((type*) g_slice_alloc (sizeof (type)))
#define g_slice_new0(type) \
((type*) g_slice_alloc0 (sizeof (type)))
#define g_slice_free(type, mem) do { \
if (1) g_slice_free1 (sizeof (type), (mem)); \
else (void) ((type*) 0 == (mem)); \
} while (0)
#ifdef __cplusplus
}
#endif

View File

@ -830,6 +830,9 @@ void g_vprintf() {} ;
void g_vsnprintf() {} ;
void g_vsprintf() {} ;
void glib_check_version() {} ;
void g_slice_alloc() {} ;
void g_slice_alloc0() {} ;
void g_slice_free1() {} ;
__asm__(".globl g_ascii_table; .pushsection .data; .type g_ascii_table,@object; .size g_ascii_table, 4; g_ascii_table: .long 0; .popsection");
__asm__(".globl g_child_watch_funcs; .pushsection .data; .type g_child_watch_funcs,@object; .size g_child_watch_funcs, 24; g_child_watch_funcs: .long 0; .popsection");
__asm__(".globl g_idle_funcs; .pushsection .data; .type g_idle_funcs,@object; .size g_idle_funcs, 24; g_idle_funcs: .long 0; .popsection");

View File

@ -1,7 +1,7 @@
%define name nspluginwrapper
%define version 1.1.0
%define version 1.1.2
%define release 1
#define svndate 20080706
#define svndate 20081012
# define 32-bit arch of multiarch platforms
%define arch_32 %{nil}
@ -192,6 +192,13 @@ fi
%endif
%changelog
* Sun Oct 12 2008 Gwenole Beauchesne <gb.public@free.fr> 1.1.2-1
- add support for Open Solaris hosts
- add support for ARM targets (Geraint North)
- fix support for windowless plugins (Flash Player 10 rc)
- fix various bugs in RPC code (crashes and concurrent messaging)
- allow wrapping of native plugins through the -n|--native option
* Sun Jul 6 2008 Gwenole Beauchesne <gb.public@free.fr> 1.1.0-1
- add support for windowless plugins (Flash Player 10 beta 2)
- add standalone plugins player (nspluginplayer)

View File

@ -78,7 +78,7 @@ int npclass_handle_Invalidate(rpc_connection_t *connection)
D(bug(" done\n"));
}
return RPC_ERROR_NO_ERROR;
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
void npclass_invoke_Invalidate(NPObject *npobj)

View File

@ -92,25 +92,6 @@ static bool FUNC(is_elf_plugin_fd)(int fd, NPW_PluginInfo *out_plugin_info)
if (ehdr.e_version != EV_CURRENT)
return false;
if (out_plugin_info) {
const char *target_arch = "";
switch (ehdr.e_machine) {
case EM_386: target_arch = "i386"; break;
case EM_X86_64: target_arch = "x86_64"; break;
case EM_SPARC: target_arch = "sparc"; break;
case EM_PPC: target_arch = "ppc"; break;
case EM_PPC64: target_arch = "ppc64"; break;
}
strcpy(out_plugin_info->target_arch, target_arch);
const char *target_os = "";
switch (ehdr.e_ident[EI_OSABI]) {
case ELFOSABI_LINUX: target_os = "linux"; break;
case ELFOSABI_SOLARIS: target_os = "solaris"; break;
case ELFOSABI_FREEBSD: target_os = "freebsd"; break;
}
strcpy(out_plugin_info->target_os, target_os);
}
ElfW(Shdr) *shdr = (ElfW(Shdr) *)load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(*shdr));
if (do_swap) {
for (i = 0; i < ehdr.e_shnum; i++)
@ -163,6 +144,40 @@ static bool FUNC(is_elf_plugin_fd)(int fd, NPW_PluginInfo *out_plugin_info)
ret = (nb_np_syms == 3) && !is_wrapper_plugin;
done:
if (out_plugin_info) {
const char *target_arch = NULL;
switch (ehdr.e_machine) {
case EM_386: target_arch = "i386"; break;
case EM_X86_64: target_arch = "x86_64"; break;
case EM_SPARC: target_arch = "sparc"; break;
case EM_PPC: target_arch = "ppc"; break;
case EM_PPC64: target_arch = "ppc64"; break;
}
if (target_arch == NULL)
target_arch = "";
strcpy(out_plugin_info->target_arch, target_arch);
const char *target_os = NULL;
switch (ehdr.e_ident[EI_OSABI]) {
case ELFOSABI_LINUX: target_os = "linux"; break;
case ELFOSABI_SOLARIS: target_os = "solaris"; break;
case ELFOSABI_FREEBSD: target_os = "freebsd"; break;
}
if (target_os == NULL) {
for (i = 0; i < ehdr.e_shnum; i++) {
ElfW(Shdr) *sec = &shdr[i];
if ((sec->sh_type == 0x6ffffffd /* SHT_SUNW_verdef */ || sec->sh_type == 0x6ffffffe /*SHT_SUNW_verneed*/)
&& strcmp(sdata[ehdr.e_shstrndx] + sec->sh_name, ".SUNW_version") == 0) {
target_os = "solaris";
break;
}
}
if (target_os == NULL)
target_os = "";
}
strcpy(out_plugin_info->target_os, target_os);
}
for (i = 0; i < ehdr.e_shnum; i++)
free(sdata[i]);
free(sdata);

View File

@ -41,6 +41,7 @@
static bool g_auto = false;
static bool g_verbose = false;
static bool g_allow_native = false;
static const char NPW_CONFIG[] = "nspluginwrapper";
static void error(const char *format, ...)
@ -140,6 +141,14 @@ static const char *get_system_mozilla_plugin_dir(void)
};
dirs = netbsd_dirs;
}
#elif defined(__sun__)
{
static const char *solaris_dirs[] = {
LIBDIR "/firefox/plugins",
"/usr/sfw/" LIB "/mozilla/plugins",
};
dirs = solaris_dirs;
}
#elif defined(__linux__)
if (access("/etc/SuSE-release", F_OK) == 0) {
static const char *suse_dirs[] = {
@ -227,6 +236,9 @@ static const char **get_mozilla_plugin_dirs(void)
"/usr/pkg/lib/RealPlayer/mozilla",
"/usr/pkg/Acrobat5/Browsers/intellinux",
"/usr/pkg/Acrobat7/Browser/intellinux",
#endif
#if defined(__sun__)
"/usr/sfw/lib/mozilla/plugins",
#endif
};
@ -504,7 +516,8 @@ static int detect_plugin_viewer(const char *filename, NPW_PluginInfo *out_plugin
target_os_table[0] = NULL;
// don't wrap plugins for host OS/ARCH
if (out_plugin_info
if (!g_allow_native
&& out_plugin_info
&& out_plugin_info->target_arch && strcmp(out_plugin_info->target_arch, HOST_ARCH) == 0
&& out_plugin_info->target_os && strcmp(out_plugin_info->target_os, HOST_OS) == 0)
return EXIT_VIEWER_NATIVE;
@ -968,6 +981,7 @@ static void print_usage(void)
printf(" -h --help print this message\n");
printf(" -v --verbose flag: set verbose mode\n");
printf(" -a --auto flag: set automatic mode for plugins discovery\n");
printf(" -n --native flag: allow native plugin(s) to be wrapped\n");
printf(" -l --list list plugins currently installed\n");
printf(" -u --update update plugin(s) currently installed\n");
printf(" -i --install [FILE(S)] install plugin(s)\n");
@ -993,6 +1007,12 @@ static int process_auto(int argc, char *argv[])
return 0;
}
static int process_native(int argc, char *argv[])
{
g_allow_native = true;
return 0;
}
static int process_list(int argvc, char *argv[])
{
const char **plugin_dirs = get_mozilla_plugin_dirs();
@ -1110,6 +1130,7 @@ int main(int argc, char *argv[])
{ 'h', "help", process_help, 1 },
{ 'v', "verbose", process_verbose, 0 },
{ 'a', "auto", process_auto, 0 },
{ 'n', "native", process_native, 0 },
{ 'l', "list", process_list, 1 },
{ 'u', "update", process_update, 1 },
{ 'i', "install", process_install, 1 },

View File

@ -381,7 +381,7 @@ static int do_send_NPSetWindowCallbackStruct(rpc_message_t *message, void *p_val
return error;
if ((error = rpc_message_send_int32(message, ws_info->type)) < 0)
return error;
if ((error = rpc_message_send_uint32(message, XVisualIDFromVisual(ws_info->visual))) < 0)
if ((error = rpc_message_send_uint32(message, ws_info->visual ? XVisualIDFromVisual(ws_info->visual) : 0)) < 0)
return error;
if ((error = rpc_message_send_uint32(message, ws_info->colormap)) < 0)
return error;

View File

@ -358,7 +358,11 @@ static int create_window_attributes(NPSetWindowCallbackStruct *ws_info)
{
if (ws_info == NULL)
return -1;
GdkVisual *gdk_visual = gdkx_visual_get((uintptr_t)ws_info->visual);
GdkVisual *gdk_visual;
if (ws_info->visual)
gdk_visual = gdkx_visual_get((uintptr_t)ws_info->visual);
else
gdk_visual = gdk_visual_get_system();
if (gdk_visual == NULL) {
npw_printf("ERROR: could not reconstruct XVisual from visualID\n");
return -2;
@ -2248,6 +2252,12 @@ static int handle_NP_GetMIMEDescription(rpc_connection_t *connection)
{
D(bug("handle_NP_GetMIMEDescription\n"));
int error = rpc_method_get_args(connection, RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NP_GetMIMEDescription() get args", error);
return error;
}
char *str = g_NP_GetMIMEDescription();
return rpc_method_send_reply(connection, RPC_TYPE_STRING, str, RPC_TYPE_INVALID);
}
@ -2414,6 +2424,12 @@ static int handle_NP_Shutdown(rpc_connection_t *connection)
{
D(bug("handle_NP_Shutdown\n"));
int error = rpc_method_get_args(connection, RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NP_Shutdown() get args", error);
return error;
}
NPError ret = g_NP_Shutdown();
return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID);
}
@ -2731,7 +2747,7 @@ static int handle_NPP_URLNotify(rpc_connection_t *connection)
if (url)
free(url);
return RPC_ERROR_NO_ERROR;
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
// NPP_NewStream
@ -2980,7 +2996,7 @@ static int handle_NPP_StreamAsFile(rpc_connection_t *connection)
if (fname)
free(fname);
return RPC_ERROR_NO_ERROR;
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
// NPP_Print
@ -2998,7 +3014,8 @@ g_NPP_Print(NPP instance, NPPrint *printInfo)
D(bug(" done\n"));
}
static void invoke_NPN_PrintData(PluginInstance *plugin, uint32_t platform_print_id, NPPrintData *printData)
static void
invoke_NPN_PrintData(PluginInstance *plugin, uint32_t platform_print_id, NPPrintData *printData)
{
if (printData == NULL)
return;

View File

@ -27,7 +27,7 @@ export LD_LIBRARY_PATH=$NPW_VIEWER_DIR
NPW_USE_XSHM=${NPW_USE_XSHM:-yes}
case $ARCH in
i?86)
i?86|i86pc)
ARCH=i386
;;
amd64)

View File

@ -243,6 +243,12 @@ static int handle_NPN_UserAgent(rpc_connection_t *connection)
{
D(bug("handle_NPN_UserAgent\n"));
int error = rpc_method_get_args(connection, RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_UserAgent() get args", error);
return error;
}
const char *user_agent = g_NPN_UserAgent(NULL);
return rpc_method_send_reply(connection, RPC_TYPE_STRING, user_agent, RPC_TYPE_INVALID);
}
@ -270,7 +276,7 @@ static int handle_NPN_Status(rpc_connection_t *connection)
mozilla_funcs.status(instance, message);
if (message)
free(message);
return RPC_ERROR_NO_ERROR;
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
// NPN_GetValue
@ -390,7 +396,7 @@ static int handle_NPN_InvalidateRect(rpc_connection_t *connection)
g_NPN_InvalidateRect(instance, &invalidRect);
return RPC_ERROR_NO_ERROR;
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
// NPN_GetURL
@ -591,7 +597,7 @@ static int handle_NPN_PrintData(rpc_connection_t *connection)
if (fwrite(printData.data, printData.size, 1, platformPrint->fp) != 1)
return RPC_ERROR_ERRNO_SET;
return RPC_ERROR_NO_ERROR;
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
// NPN_RequestRead
@ -831,7 +837,7 @@ static int handle_NPN_PushPopupsEnabledState(rpc_connection_t *connection)
g_NPN_PushPopupsEnabledState(instance, enabled);
return RPC_ERROR_NO_ERROR;
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
// NPN_PopPopupsEnabledState
@ -861,7 +867,7 @@ static int handle_NPN_PopPopupsEnabledState(rpc_connection_t *connection)
g_NPN_PopPopupsEnabledState(instance);
return RPC_ERROR_NO_ERROR;
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
// NPN_CreateObject
@ -1171,7 +1177,7 @@ static int handle_NPN_SetException(rpc_connection_t *connection)
// XXX memory leak (message)
return RPC_ERROR_NO_ERROR;
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
// NPN_GetStringIdentifier

248
src/rpc.c
View File

@ -33,6 +33,7 @@
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
@ -64,7 +65,14 @@
#endif
// Define the maximum amount of time (in seconds) to wait for a message
#ifndef RPC_MESSAGE_TIMEOUT
#define RPC_MESSAGE_TIMEOUT 30
#endif
// Define the maximum amount of time (in seconds) to wait for plugin connection
#ifndef RPC_INIT_TIMEOUT
#define RPC_INIT_TIMEOUT 5
#endif
/* ====================================================================== */
@ -179,6 +187,27 @@ static inline int rpc_message_timeout(void)
return timeout;
}
// Returns the maximum amount of time (in seconds) to wait for plugin connection
static int _rpc_init_timeout(void)
{
int timeout = 0;
const char *timeout_str = getenv("NPW_INIT_TIMEOUT");
if (timeout_str)
timeout = atoi(timeout_str);
if (timeout <= 0)
timeout = RPC_INIT_TIMEOUT;
D(bug("RPC message timeout set to %d sec\n", timeout));
return timeout;
}
static inline int rpc_init_timeout(void)
{
static int timeout = -1;
if (timeout < 0)
timeout = _rpc_init_timeout();
return timeout;
}
// Returns a string describing the error code passed in the argument ERROR
const char *rpc_strerror(int error)
{
@ -487,6 +516,16 @@ static inline int rpc_error(rpc_connection_t *connection, int error)
return error;
}
#if DEBUG
static inline int rpc_error_debug(rpc_connection_t *connection, int error, const char *filename, int line)
{
npw_printf("ERROR: RPC error %d caught at %s:%d\n", error, filename, line);
return rpc_error(connection, error);
}
#define rpc_error(connection, error) \
rpc_error_debug(connection, error, __FILE__, __LINE__)
#endif
// Returns socket fd or -1 if invalid connection
int rpc_socket(rpc_connection_t *connection)
{
@ -586,7 +625,10 @@ rpc_connection_t *rpc_init_server(const char *ident)
connection->socket_path = NULL;
addr_len = _rpc_socket_path(&connection->socket_path, ident);
memcpy(&addr.sun_path[0], connection->socket_path, addr_len);
addr_len += sizeof(struct sockaddr_un) - sizeof(addr.sun_path);
addr_len += offsetof(struct sockaddr_un, sun_path); /* though POSIX says size of the actual sockaddr structure */
#ifdef HAVE_SOCKADDR_UN_SUN_LEN
addr.sun_len = addr_len;
#endif
if (bind(connection->server_socket, (struct sockaddr *)&addr, addr_len) < 0) {
perror("server bind");
@ -649,11 +691,14 @@ rpc_connection_t *rpc_init_client(const char *ident)
connection->socket_path = NULL;
addr_len = _rpc_socket_path(&connection->socket_path, ident);
memcpy(&addr.sun_path[0], connection->socket_path, addr_len);
addr_len += sizeof(struct sockaddr_un) - sizeof(addr.sun_path);
addr_len += offsetof(struct sockaddr_un, sun_path); /* though POSIX says size of the actual sockaddr structure */
#ifdef HAVE_SOCKADDR_UN_SUN_LEN
addr.sun_len = addr_len;
#endif
// Wait at most 5 seconds for server to initialize
// Wait at most RPC_INIT_TIMEOUT seconds for server to initialize
const int N_CONNECT_WAIT_DELAY = 10;
int n_connect_attempts = 5000 / N_CONNECT_WAIT_DELAY;
int n_connect_attempts = (rpc_init_timeout() * 1000) / N_CONNECT_WAIT_DELAY;
if (n_connect_attempts == 0)
n_connect_attempts = 1;
while (n_connect_attempts > 0) {
@ -1441,7 +1486,7 @@ static inline rpc_method_callback_t rpc_lookup_callback(rpc_connection_t *connec
// Dispatch message received in the server loop
static int _rpc_dispatch(rpc_connection_t *connection, rpc_message_t *message)
{
// wait: <invoke> (body: <method-id> MESSAGE_END
// recv: <invoke> (body: <method-id> MESSAGE_END
D(bug("receiving message\n"));
int32_t method;
int error = rpc_message_recv_int32(message, &method);
@ -1455,14 +1500,6 @@ static int _rpc_dispatch(rpc_connection_t *connection, rpc_message_t *message)
return RPC_ERROR_MESSAGE_TYPE_INVALID;
D(bug(" -- message received [%d]\n", method));
// send: MESSAGE_ACK
error = rpc_message_send_int32(message, RPC_MESSAGE_ACK);
if (error != RPC_ERROR_NO_ERROR)
return error;
error = rpc_message_flush(message);
if (error != RPC_ERROR_NO_ERROR)
return error;
// call: <method>
rpc_method_callback_t callback = rpc_lookup_callback(connection, method);
if (callback)
@ -1472,37 +1509,35 @@ static int _rpc_dispatch(rpc_connection_t *connection, rpc_message_t *message)
if (error != RPC_ERROR_NO_ERROR) {
int error_code = error;
// send: MESSAGE_FAILURE <error-code>
error = rpc_message_send_int32(message, RPC_MESSAGE_FAILURE);
if (error != RPC_ERROR_NO_ERROR)
return error;
error = rpc_message_send_int32(message, error_code);
if (error != RPC_ERROR_NO_ERROR)
return error;
error = rpc_message_flush(message);
if (error != RPC_ERROR_NO_ERROR)
return error;
// send: MESSAGE_FAILURE <error-code> ("high-level" error codes only)
switch (error) {
case RPC_ERROR_GENERIC:
case RPC_ERROR_ERRNO_SET:
case RPC_ERROR_NO_MEMORY:
error = rpc_message_send_int32(message, RPC_MESSAGE_FAILURE);
if (error != RPC_ERROR_NO_ERROR)
return error;
error = rpc_message_send_int32(message, error_code);
if (error != RPC_ERROR_NO_ERROR)
return error;
error = rpc_message_flush(message);
if (error != RPC_ERROR_NO_ERROR)
return error;
break;
}
return error_code;
}
// send: MESSAGE_ACK
error = rpc_message_send_int32(message, RPC_MESSAGE_ACK);
if (error != RPC_ERROR_NO_ERROR)
return error;
error = rpc_message_flush(message);
if (error != RPC_ERROR_NO_ERROR)
return error;
return method;
}
int rpc_dispatch(rpc_connection_t *connection)
{
int32_t msg_tag;
rpc_message_t message;
rpc_message_init(&message, connection);
// wait: <invoke> (header: MESSAGE_START)
int32_t msg_tag;
// recv: <invoke> (header: MESSAGE_START)
int error = rpc_message_recv_int32(&message, &msg_tag);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
@ -1515,6 +1550,35 @@ int rpc_dispatch(rpc_connection_t *connection)
return method;
}
// Dispatch pending remote calls until we get MSG_TAG
static int _rpc_dispatch_until(rpc_connection_t *connection, rpc_message_t *message, int32_t expected_msg_tag)
{
if (expected_msg_tag) {
for (;;) {
int32_t msg_tag;
int error = rpc_message_recv_int32(message, &msg_tag);
if (error != RPC_ERROR_NO_ERROR)
return error;
if (msg_tag == expected_msg_tag)
break;
if (msg_tag != RPC_MESSAGE_START)
return RPC_ERROR_MESSAGE_TYPE_INVALID;
if ((error = _rpc_dispatch(connection, message)) < 0)
return error;
}
}
else {
for (;;) {
int ret = _rpc_wait_dispatch(connection, 0);
if (ret == 0)
break;
if (ret < 0 || (ret = rpc_dispatch(connection)) < 0)
return ret;
}
}
return RPC_ERROR_NO_ERROR;
}
/* ====================================================================== */
/* === Method Callbacks Handling === */
@ -1603,16 +1667,12 @@ int rpc_method_invoke(rpc_connection_t *connection, int method, ...)
rpc_message_init(&message, connection);
// call: rpc_dispatch() (pending remote calls)
for (;;) {
int ret = _rpc_wait_dispatch(connection, 0);
if (ret == 0)
break;
if (ret < 0 || (ret = rpc_dispatch(connection)) < 0)
return ret;
}
int error = _rpc_dispatch_until(connection, &message, 0);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
// send: <invoke> = MESSAGE_START <method-id> MESSAGE_END
int error = rpc_message_send_int32(&message, RPC_MESSAGE_START);
error = rpc_message_send_int32(&message, RPC_MESSAGE_START);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
error = rpc_message_send_int32(&message, method);
@ -1625,14 +1685,6 @@ int rpc_method_invoke(rpc_connection_t *connection, int method, ...)
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
// wait: MESSAGE_ACK
int32_t msg_tag;
error = rpc_message_recv_int32(&message, &msg_tag);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
if (msg_tag != RPC_MESSAGE_ACK)
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
// send optional arguments
va_list args;
va_start(args, method);
@ -1649,15 +1701,15 @@ int rpc_method_invoke(rpc_connection_t *connection, int method, ...)
error = rpc_message_flush(&message);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
// wait: MESSAGE_ACK
error = rpc_message_recv_int32(&message, &msg_tag);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
if (msg_tag != RPC_MESSAGE_ACK)
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
}
// wait: MESSAGE_ACK
error = _rpc_dispatch_until(connection, &message, RPC_MESSAGE_ACK);
if (error == RPC_ERROR_ERRNO_SET)
perror("rpc_method_invoke");
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
return RPC_ERROR_NO_ERROR;
}
@ -1674,7 +1726,11 @@ int rpc_method_get_args(rpc_connection_t *connection, ...)
rpc_message_t message;
rpc_message_init(&message, connection);
// wait: <method-args>
// we can't have pending calls here because the method invocation
// message and its arguments are atomic (i.e. they are sent right
// away, no wait for ACK)
// recv: <method-args>
va_list args;
va_start(args, connection);
int error = rpc_message_recv_args(&message, args);
@ -1704,76 +1760,42 @@ int rpc_method_wait_for_reply(rpc_connection_t *connection, ...)
return RPC_ERROR_CONNECTION_CLOSED;
int error;
int32_t msg_tag;
rpc_message_t message;
rpc_message_init(&message, connection);
// call: rpc_dispatch() (pending remote calls)
int32_t msg_tag;
bool done = false;
while (!done) {
error = rpc_message_recv_int32(&message, &msg_tag);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
switch (msg_tag) {
case RPC_MESSAGE_START:
if ((error = _rpc_dispatch(connection, &message)) < 0)
return rpc_error(connection, error);
break;
case RPC_MESSAGE_REPLY:
case RPC_MESSAGE_ACK:
done = true;
break;
case RPC_MESSAGE_FAILURE:
{
// wait: <error-code>
int32_t error_code;
error = rpc_message_recv_int32(&message, &error_code);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
// return other-side error code
return rpc_error(connection, error_code);
}
default:
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
}
}
// recv: MESSAGE_REPLY
error = _rpc_dispatch_until(connection, &message, RPC_MESSAGE_REPLY);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
// receive optional arguments
va_list args;
va_start(args, connection);
int type = va_arg(args, int);
va_end(args);
if (type != RPC_TYPE_INVALID) {
// wait: <reply>
if (msg_tag != RPC_MESSAGE_REPLY)
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
// recv: [ <method-args> ]
va_start(args, connection);
error = rpc_message_recv_args(&message, args);
va_end(args);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
error = rpc_message_recv_int32(&message, &msg_tag);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
if (msg_tag != RPC_MESSAGE_END)
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
// send: MESSAGE_ACK
error = rpc_message_send_int32(&message, RPC_MESSAGE_ACK);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
error = rpc_message_flush(&message);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
// wait: MESSAGE_ACK (prepare for final ACK)
error = rpc_message_recv_int32(&message, &msg_tag);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
}
// recv: MESSAGE_END
error = rpc_message_recv_int32(&message, &msg_tag);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
if (msg_tag != RPC_MESSAGE_END)
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
// wait: MESSAGE_ACK
error = rpc_message_recv_int32(&message, &msg_tag);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
if (msg_tag != RPC_MESSAGE_ACK)
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
@ -1810,13 +1832,13 @@ int rpc_method_send_reply(rpc_connection_t *connection, ...)
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
// wait: MESSAGE_ACK
int32_t msg_tag;
error = rpc_message_recv_int32(&message, &msg_tag);
// send: MESSAGE_ACK
error = rpc_message_send_int32(&message, RPC_MESSAGE_ACK);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
error = rpc_message_flush(&message);
if (error != RPC_ERROR_NO_ERROR)
return rpc_error(connection, error);
if (msg_tag != RPC_MESSAGE_ACK)
return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID);
return RPC_ERROR_NO_ERROR;
}

View File

@ -196,6 +196,25 @@ const char *npw_strerror(int error)
return "Unknown error";
}
char *npw_asprintf(const char *format, ...)
{
va_list args;
va_start(args, format);
int alen = vsnprintf(NULL, 0, format, args);
va_end(args);
char *str = malloc(alen+1);
if (str == NULL)
return NULL;
va_start(args, format);
int rlen = vsnprintf(str, alen+1, format, args);
va_end(args);
if (rlen != alen) {
free(str);
return NULL;
}
return str;
}
/* ====================================================================== */
/* === Test Program === */

View File

@ -42,6 +42,7 @@ extern const char *string_of_NPStreamType(int stype) attribute_hidden;
// Misc utility functions
extern void npw_perror(const char *prefix, int error) attribute_hidden;
extern const char *npw_strerror(int error) attribute_hidden;
extern char *npw_asprintf(const char *format, ...) attribute_hidden;
#ifdef __cplusplus
}

318
tests/test-rpc-common.c Normal file
View File

@ -0,0 +1,318 @@
/*
* test-rpc-common.c - Common RPC test code
*
* nspluginwrapper (C) 2005-2008 Gwenole Beauchesne
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "sysdeps.h"
#include "test-rpc-common.h"
#include <signal.h>
#define DEBUG 1
#include "debug.h"
#ifdef BUILD_WRAPPER
#define BUILD_CLIENT 1
#endif
#ifdef BUILD_VIEWER
#define BUILD_SERVER 1
#endif
typedef struct _RPCTest RPCTest;
struct _RPCTest
{
RPCTestFuncs funcs;
gpointer user_data;
};
static RPCTest g_test;
static rpc_connection_t *g_connection;
static const gchar *g_connection_path;
static GMainLoop *g_main_loop;
static GPid g_child_pid;
static guint g_child_watch_id;
static guint g_source_id;
static gint g_exit_status;
void
rpc_test_set_funcs (const RPCTestFuncs *funcs, gpointer user_data)
{
g_test.user_data = user_data;
if (funcs && funcs->pre_dispatch_hook)
g_test.funcs.pre_dispatch_hook = funcs->pre_dispatch_hook;
if (funcs && funcs->post_dispatch_hook)
g_test.funcs.post_dispatch_hook = funcs->post_dispatch_hook;
}
rpc_connection_t *
rpc_test_get_connection (void)
{
return g_connection;
}
#ifdef BUILD_CLIENT
static void
child_exited_cb (GPid pid, gint status, gpointer user_data)
{
g_print ("child_exited_cb(), pid %d, status %d\n", pid, status);
if (status)
g_exit_status = status;
g_main_loop_quit (g_main_loop);
if (g_child_watch_id)
g_source_remove (g_child_watch_id);
g_spawn_close_pid (pid);
}
static void
kill_child_now (void)
{
if (g_child_watch_id)
g_source_remove (g_child_watch_id);
if (g_child_pid)
{
g_spawn_close_pid (g_child_pid);
kill (g_child_pid, SIGTERM);
}
}
static void
urgent_exit_sig (int sig)
{
kill_child_now ();
}
#endif
#ifdef BUILD_SERVER
static gboolean
rpc_event_prepare (GSource *source, gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean
rpc_event_check (GSource *source)
{
return rpc_wait_dispatch (g_connection, 0) > 0;
}
static gboolean
rpc_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
{
gint rc;
if (g_test.funcs.pre_dispatch_hook)
{
if (!g_test.funcs.pre_dispatch_hook (g_test.user_data))
return TRUE;
}
rc = rpc_dispatch (g_connection);
if (g_test.funcs.post_dispatch_hook)
g_test.funcs.post_dispatch_hook (g_test.user_data);
return rc != RPC_ERROR_CONNECTION_CLOSED;
}
typedef gboolean (*GSourcePrepare) (GSource *, gint *);
typedef gboolean (*GSourceCheckFunc) (GSource *);
typedef gboolean (*GSourceDispatchFunc) (GSource *, GSourceFunc, gpointer);
typedef void (*GSourceFinalizeFunc) (GSource *);
static GSourceFuncs rpc_event_funcs =
{
rpc_event_prepare,
rpc_event_check,
rpc_event_dispatch,
(GSourceFinalizeFunc)g_free,
(GSourceFunc)NULL,
(GSourceDummyMarshal)NULL
};
#endif
static gboolean
rpc_test_execute_cb (gpointer user_data)
{
int rc = RPC_TEST_EXECUTE_SUCCESS;
if (rpc_test_execute)
rc = rpc_test_execute (g_test.user_data);
g_assert ((rc & ~RPC_TEST_EXECUTE_DONT_QUIT) == RPC_TEST_EXECUTE_SUCCESS);
#ifdef BUILD_CLIENT
if ((rc & RPC_TEST_EXECUTE_DONT_QUIT) == 0)
rpc_test_exit_full (0);
#endif
return FALSE;
}
static gchar **
clone_args (gchar **args)
{
gchar **new_args;
gint i, n, rc = 0;
if ((new_args = g_strdupv (args)) == NULL)
g_error ("could not duplicate the program arguments");
n = g_strv_length (new_args);
#ifdef BUILD_CLIENT
/* first arg was path to server program, skip it */
g_assert (n >= 2);
g_free (new_args[1]);
for (i = 1; i < n - 1; i++)
new_args[i] = new_args[i + 1];
new_args[i] = NULL;
#endif
return new_args;
}
static void
rpc_test_init_invoke (gchar **program_args)
{
gchar **args = NULL;
gint n, rc = 0;
if ((args = clone_args (program_args)) == NULL)
g_error ("could not clone program arguments");
n = g_strv_length (args);
if (rpc_test_init)
rc = rpc_test_init (n, args);
g_strfreev (args);
g_assert (rc == 0);
g_timeout_add (0, rpc_test_execute_cb, NULL);
}
void
rpc_test_exit (int status)
{
if (status)
g_exit_status = status;
if (g_source_id)
g_source_remove (g_source_id);
if (g_connection)
rpc_exit (g_connection);
g_main_loop_quit (g_main_loop);
}
void
rpc_test_exit_full (int status)
{
#ifdef BUILD_CLIENT
/* Tell server to quit, don't expect any reply from him */
rpc_method_invoke (g_connection,
RPC_TEST_METHOD_EXIT,
RPC_TYPE_INT32, status,
RPC_TYPE_INVALID);
#endif
rpc_test_exit (status);
}
static int
handle_rpc_test_exit (rpc_connection_t *connection)
{
int error;
gint32 status;
error = rpc_method_get_args (connection,
RPC_TYPE_INT32, &status,
RPC_TYPE_INVALID);
if (error == RPC_ERROR_NO_ERROR)
rpc_test_exit (status);
return error;
}
int
main (int argc, char *argv[])
{
if (rpc_test_get_connection_path)
g_connection_path = rpc_test_get_connection_path ();
else
g_connection_path = NPW_CONNECTION_PATH "/Test.RPC";
#ifdef BUILD_CLIENT
gchar **child_args;
if (argc < 2)
g_error ("no server program provided on command line");
signal (SIGSEGV, urgent_exit_sig);
signal (SIGBUS, urgent_exit_sig);
signal (SIGINT, urgent_exit_sig);
signal (SIGABRT, urgent_exit_sig);
if ((child_args = clone_args (argv)) == NULL)
g_error ("could not create server program arguments\n");
g_free (child_args[0]);
child_args[0] = g_strdup (argv[1]);
if (!g_spawn_async (NULL,
child_args,
NULL,
G_SPAWN_DO_NOT_REAP_CHILD,
NULL,
NULL,
&g_child_pid,
NULL))
g_error ("could not start server program '%s'", child_args[0]);
g_strfreev (child_args);
if ((g_connection = rpc_init_client (g_connection_path)) == NULL)
g_error ("failed to initialize RPC client connection");
#endif
#ifdef BUILD_SERVER
if ((g_connection = rpc_init_server (g_connection_path)) == NULL)
g_error ("failed to initialize RPC server connection");
GSource *rpc_source;
GPollFD rpc_event_poll_fd;
if ((rpc_source = g_source_new (&rpc_event_funcs, sizeof (GSource))) == NULL)
g_error ("failed to initialize RPC source");
g_source_id = g_source_attach (rpc_source, NULL);
memset (&rpc_event_poll_fd, 0, sizeof (rpc_event_poll_fd));
rpc_event_poll_fd.fd = rpc_listen_socket (g_connection);
rpc_event_poll_fd.events = G_IO_IN;
rpc_event_poll_fd.revents = 0;
g_source_add_poll (rpc_source, &rpc_event_poll_fd);
#endif
static const rpc_method_descriptor_t vtable[] = {
{ RPC_TEST_METHOD_EXIT, handle_rpc_test_exit }
};
if (rpc_connection_add_method_descriptor (g_connection, &vtable[0]) < 0)
g_error ("could not add method descriptor for TEST_RPC_METHOD_EXIT");
g_main_loop = g_main_loop_new (NULL, TRUE);
#ifdef BUILD_CLIENT
g_child_watch_id = g_child_watch_add (g_child_pid, child_exited_cb, NULL);
#endif
rpc_test_init_invoke (argv);
g_main_loop_run (g_main_loop);
return g_exit_status;
}

74
tests/test-rpc-common.h Normal file
View File

@ -0,0 +1,74 @@
/*
* test-rpc-common.h - Common RPC test code
*
* nspluginwrapper (C) 2005-2008 Gwenole Beauchesne
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef TEST_RPC_COMMON_H
#define TEST_RPC_COMMON_H
#include "rpc.h"
#include <glib.h>
enum
{
/* void rpc_test_exit (int status); */
RPC_TEST_METHOD_EXIT = 0,
};
enum
{
RPC_TEST_EXECUTE_SUCCESS = 0,
RPC_TEST_EXECUTE_FAILURE = 1,
RPC_TEST_EXECUTE_DONT_QUIT = 0x8000,
};
typedef struct _RPCTestFuncs RPCTestFuncs;
struct _RPCTestFuncs
{
gboolean (*pre_dispatch_hook) (gpointer user_data);
void (*post_dispatch_hook) (gpointer user_data);
};
void
rpc_test_set_funcs (const RPCTestFuncs *funcs, gpointer user_data);
rpc_connection_t *
rpc_test_get_connection (void);
/* IMPLEMENT: default is NPW_CONNECTION_PATH "/Test.RPC"; */
const gchar *
rpc_test_get_connection_path (void)
__attribute__((__weak__));
/* IMPLEMENT: default is return 0; */
int
rpc_test_init (int argc, char *argv[])
__attribute__((__weak__));
/* IMPLEMENT: default is return 0; */
int
rpc_test_execute (gpointer user_data)
__attribute__((__weak__));
void
rpc_test_exit (int status);
void
rpc_test_exit_full (int status);
#endif /* TEST_RPC_COMMON_H */

163
tests/test-rpc-concurrent.c Normal file
View File

@ -0,0 +1,163 @@
/*
* test-rpc-concurrent.c - Test concurrent RPC invoke
*
* nspluginwrapper (C) 2005-2008 Gwenole Beauchesne
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "sysdeps.h"
#include "test-rpc-common.h"
#include <string.h>
#define DEBUG 1
#include "debug.h"
#define RPC_TEST_USE_IDLE TRUE
enum
{
RPC_TEST_METHOD_PRINT = 1
};
static gboolean g_is_silent = TRUE;
static gint g_print_count = 5000;
static void
invoke_print (const gchar *str)
{
rpc_connection_t *connection;
int error;
connection = rpc_test_get_connection ();
g_assert (connection != NULL);
error = rpc_method_invoke (connection,
RPC_TEST_METHOD_PRINT,
RPC_TYPE_STRING, str,
RPC_TYPE_INVALID);
/* Error out early for invalid messages types.
The problem we are looking at is rpc_method_invoke() waiting for
the other side MSG_ACK prior to sending the arguments. Sometimes,
the other side sends a new message first (MSG_START). So, we get
a mismatch. */
g_assert (error != RPC_ERROR_MESSAGE_TYPE_INVALID);
g_assert (error == RPC_ERROR_NO_ERROR);
error = rpc_method_wait_for_reply (connection, RPC_TYPE_INVALID);
g_assert (error == RPC_ERROR_NO_ERROR);
}
static int
handle_print (rpc_connection_t *connection)
{
char *str;
int error;
error = rpc_method_get_args (connection,
RPC_TYPE_STRING, &str,
RPC_TYPE_INVALID);
g_assert (error == RPC_ERROR_NO_ERROR);
g_assert (str != NULL);
if (!g_is_silent)
npw_printf ("Got message from the other end: '%s'\n", str);
free (str);
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static inline void
print_msg (void)
{
invoke_print ("Hello from " NPW_COMPONENT_NAME);
}
static gboolean
invoke_print_cb (gpointer user_data)
{
print_msg ();
--g_print_count;
#ifdef BUILD_CLIENT
if (g_print_count == 0)
rpc_test_exit_full (0);
#endif
return g_print_count > 0;
}
int
rpc_test_init (int argc, char *argv[])
{
rpc_connection_t *connection;
for (int i = 1; i < argc; i++)
{
const gchar *arg = argv[i];
if (strcmp (arg, "--silent") == 0 || strcmp (arg, "-q") == 0)
g_is_silent = TRUE;
else if (strcmp (arg, "--verbose") == 0 || strcmp (arg, "-v") == 0)
g_is_silent = FALSE;
else if (strcmp (arg, "--count") == 0)
{
if (++i < argc)
{
unsigned long v = strtoul (argv[i], NULL, 10);
if (v > 0)
g_print_count = v;
}
}
else if (strcmp (arg, "--help") == 0)
{
g_print ("Usage: %s [--silent|--verbose] [--count COUNT]\n", argv[0]);
rpc_test_exit (0);
}
}
connection = rpc_test_get_connection ();
g_assert (connection != NULL);
static const rpc_method_descriptor_t vtable[] = {
{ RPC_TEST_METHOD_PRINT, handle_print },
};
if (rpc_connection_add_method_descriptor (connection, &vtable[0]) < 0)
g_error ("could not add method descriptors");
if (RPC_TEST_USE_IDLE)
{
/* XXX: we hope to trigger concurrent rpc_method_invoke() */
/* XXX: add a barrier to synchronize both processes? */
//g_idle_add (invoke_print_cb, NULL);
g_timeout_add (0, invoke_print_cb, NULL);
}
else
{
while (--g_print_count >= 0)
print_msg ();
}
return 0;
}
int
rpc_test_execute (gpointer user_data)
{
#ifdef BUILD_CLIENT
if (RPC_TEST_USE_IDLE)
return RPC_TEST_EXECUTE_SUCCESS|RPC_TEST_EXECUTE_DONT_QUIT;
#endif
return RPC_TEST_EXECUTE_SUCCESS;
}

116
tests/test-rpc-nested.c Normal file
View File

@ -0,0 +1,116 @@
/*
* test-rpc-nested.c - Test nested RPC invoke
*
* nspluginwrapper (C) 2005-2008 Gwenole Beauchesne
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "sysdeps.h"
#include "test-rpc-common.h"
#include <unistd.h>
#define DEBUG 1
#include "debug.h"
enum
{
RPC_TEST_METHOD_GET_PID = 1
};
static gint
get_remote_pid (void)
{
rpc_connection_t *connection;
int error;
gint32 pid;
connection = rpc_test_get_connection ();
g_assert (connection != NULL);
error = rpc_method_invoke (connection,
RPC_TEST_METHOD_GET_PID,
RPC_TYPE_INVALID);
g_assert (error == RPC_ERROR_NO_ERROR);
error = rpc_method_wait_for_reply (connection,
RPC_TYPE_INT32, &pid,
RPC_TYPE_INVALID);
g_assert (error == RPC_ERROR_NO_ERROR);
return pid;
}
static inline gint
get_local_pid (void)
{
return getpid ();
}
static inline gint
get_client_pid (void)
{
#ifdef BUILD_CLIENT
return get_local_pid ();
#endif
#ifdef BUILD_SERVER
return get_remote_pid ();
#endif
return -1;
}
static int
handle_get_pid (rpc_connection_t *connection)
{
gint pid;
int error;
error = rpc_method_get_args (connection, RPC_TYPE_INVALID);
g_assert (error == RPC_ERROR_NO_ERROR);
pid = get_client_pid ();
return rpc_method_send_reply (connection,
RPC_TYPE_INT32, pid,
RPC_TYPE_INVALID);
}
int
rpc_test_init (int argc, char *argv[])
{
rpc_connection_t *connection;
connection = rpc_test_get_connection ();
g_assert (connection != NULL);
static const rpc_method_descriptor_t vtable[] = {
{ RPC_TEST_METHOD_GET_PID, handle_get_pid },
};
if (rpc_connection_add_method_descriptor (connection, &vtable[0]) < 0)
g_error ("could not add method descriptors");
return 0;
}
int
rpc_test_execute (gpointer user_data)
{
#ifdef BUILD_CLIENT
gint pid = get_remote_pid ();
g_assert (pid == get_local_pid ());
#endif
return RPC_TEST_EXECUTE_SUCCESS;
}

504
tests/test-rpc-types.c Normal file
View File

@ -0,0 +1,504 @@
/*
* test-rpc-types.c - Test marshaling of common data types
*
* nspluginwrapper (C) 2005-2008 Gwenole Beauchesne
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "sysdeps.h"
#include "test-rpc-common.h"
#include "utils.h"
#include <stdarg.h>
#define DEBUG 1
#include "debug.h"
#define RPC_TEST_MAX_ARGS 32
enum
{
RPC_TEST_METHOD_VOID__VOID = 1,
RPC_TEST_METHOD_VOID__CHAR,
RPC_TEST_METHOD_VOID__CHARx10,
RPC_TEST_METHOD_VOID__BOOL,
RPC_TEST_METHOD_VOID__BOOLx10,
RPC_TEST_METHOD_VOID__INT32x10,
RPC_TEST_METHOD_VOID__UINT32x10,
RPC_TEST_METHOD_VOID__UINT64x10,
RPC_TEST_METHOD_VOID__DOUBLEx5,
RPC_TEST_METHOD_VOID__STRINGx3,
};
const gchar *
rpc_test_get_connection_path (void)
{
return NPW_CONNECTION_PATH "/Test.RPC.Types";
}
static void
rpc_test_signature (gboolean is_invoke, ...)
{
va_list args;
gint type, n_args;
gboolean was_array;
GString *str;
if ((str = g_string_new (NULL)) == NULL)
return;
n_args = 0;
was_array = FALSE;
va_start (args, is_invoke);
while ((type = va_arg (args, gint)) != RPC_TYPE_INVALID)
{
if (++n_args > 1 && !was_array)
g_string_append (str, ", ");
was_array = FALSE;
switch (type)
{
case RPC_TYPE_CHAR:
g_string_append (str, "char");
if (is_invoke)
va_arg (args, int);
break;
case RPC_TYPE_BOOLEAN:
g_string_append (str, "bool");
if (is_invoke)
va_arg (args, int);
break;
case RPC_TYPE_INT32:
g_string_append (str, "int32");
if (is_invoke)
va_arg (args, gint32);
break;
case RPC_TYPE_UINT32:
g_string_append (str, "uint32");
if (is_invoke)
va_arg (args, guint32);
break;
case RPC_TYPE_UINT64:
g_string_append (str, "uint64");
if (is_invoke)
va_arg (args, guint64);
break;
case RPC_TYPE_DOUBLE:
g_string_append (str, "double");
if (is_invoke)
va_arg (args, gdouble);
break;
case RPC_TYPE_STRING:
g_string_append (str, "string");
if (is_invoke)
va_arg (args, gchar *);
break;
case RPC_TYPE_ARRAY:
g_string_append (str, "array of");
was_array = TRUE;
break;
}
if (!is_invoke && type != RPC_TYPE_ARRAY)
va_arg (args, gpointer);
}
va_end (args);
if (n_args == 0)
g_string_append (str, "void");
g_print ("void f (%s)\n", str->str);
g_string_free (str, TRUE);
}
#define rpc_test_invoke(method, ...) do { \
int error; \
rpc_connection_t *connection; \
connection = rpc_test_get_connection (); \
rpc_test_signature (TRUE, __VA_ARGS__); \
error = rpc_method_invoke (connection, method, __VA_ARGS__); \
g_assert (error == RPC_ERROR_NO_ERROR); \
error = rpc_method_wait_for_reply (connection, RPC_TYPE_INVALID); \
g_assert (error == RPC_ERROR_NO_ERROR); \
} while (0)
#define rpc_test_get_args(connection, ...) do { \
int error; \
rpc_test_signature (FALSE, __VA_ARGS__); \
error = rpc_method_get_args (connection, __VA_ARGS__); \
g_assert (error == RPC_ERROR_NO_ERROR); \
} while (0)
#ifdef BUILD_SERVER
typedef union _RPCTestArg RPCTestArg;
union _RPCTestArg
{
gchar c;
guint b;
gint32 i;
guint32 u;
guint64 j;
gdouble d;
gchar *s;
};
static RPCTestArg g_args[RPC_TEST_MAX_ARGS];
static int
handle_VOID__VOID (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_INVALID);
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static int
handle_VOID__CHAR (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_CHAR, &g_args[0].c,
RPC_TYPE_INVALID);
g_assert (g_args[0].c == 'a');
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static int
handle_VOID__CHARx10 (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_CHAR, &g_args[0].c,
RPC_TYPE_CHAR, &g_args[1].c,
RPC_TYPE_CHAR, &g_args[2].c,
RPC_TYPE_CHAR, &g_args[3].c,
RPC_TYPE_CHAR, &g_args[4].c,
RPC_TYPE_CHAR, &g_args[5].c,
RPC_TYPE_CHAR, &g_args[6].c,
RPC_TYPE_CHAR, &g_args[7].c,
RPC_TYPE_CHAR, &g_args[8].c,
RPC_TYPE_CHAR, &g_args[9].c,
RPC_TYPE_INVALID);
g_assert (g_args[0].c == 'a');
g_assert (g_args[1].c == 'b');
g_assert (g_args[2].c == 'c');
g_assert (g_args[3].c == 'd');
g_assert (g_args[4].c == 'e');
g_assert (g_args[5].c == '1');
g_assert (g_args[6].c == '2');
g_assert (g_args[7].c == '3');
g_assert (g_args[8].c == '4');
g_assert (g_args[9].c == '5');
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static int
handle_VOID__BOOL (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_BOOLEAN, &g_args[0].b,
RPC_TYPE_INVALID);
g_assert (g_args[0].b == TRUE);
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static int
handle_VOID__BOOLx10 (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_BOOLEAN, &g_args[0].b,
RPC_TYPE_BOOLEAN, &g_args[1].b,
RPC_TYPE_BOOLEAN, &g_args[2].b,
RPC_TYPE_BOOLEAN, &g_args[3].b,
RPC_TYPE_BOOLEAN, &g_args[4].b,
RPC_TYPE_BOOLEAN, &g_args[5].b,
RPC_TYPE_BOOLEAN, &g_args[6].b,
RPC_TYPE_BOOLEAN, &g_args[7].b,
RPC_TYPE_BOOLEAN, &g_args[8].b,
RPC_TYPE_BOOLEAN, &g_args[9].b,
RPC_TYPE_INVALID);
g_assert (g_args[0].b == TRUE);
g_assert (g_args[1].b == FALSE);
g_assert (g_args[2].b == TRUE);
g_assert (g_args[3].b == FALSE);
g_assert (g_args[4].b == TRUE);
g_assert (g_args[5].b == FALSE);
g_assert (g_args[6].b == TRUE);
g_assert (g_args[7].b == FALSE);
g_assert (g_args[8].b == TRUE);
g_assert (g_args[9].b == FALSE);
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static int
handle_VOID__INT32x10 (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_INT32, &g_args[0].i,
RPC_TYPE_INT32, &g_args[1].i,
RPC_TYPE_INT32, &g_args[2].i,
RPC_TYPE_INT32, &g_args[3].i,
RPC_TYPE_INT32, &g_args[4].i,
RPC_TYPE_INT32, &g_args[5].i,
RPC_TYPE_INT32, &g_args[6].i,
RPC_TYPE_INT32, &g_args[7].i,
RPC_TYPE_INT32, &g_args[8].i,
RPC_TYPE_INT32, &g_args[9].i,
RPC_TYPE_INVALID);
g_assert (g_args[0].i == 0);
g_assert (g_args[1].i == 1);
g_assert (g_args[2].i == -1);
g_assert (g_args[3].i == 2);
g_assert (g_args[4].i == -2);
g_assert (g_args[5].i == G_MAXINT32);
g_assert (g_args[6].i == G_MININT32);
g_assert (g_args[7].i == G_MAXINT32 - 1);
g_assert (g_args[8].i == G_MININT32 + 1);
g_assert (g_args[9].i == 0);
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static int
handle_VOID__UINT32x10 (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_UINT32, &g_args[0].u,
RPC_TYPE_UINT32, &g_args[1].u,
RPC_TYPE_UINT32, &g_args[2].u,
RPC_TYPE_UINT32, &g_args[3].u,
RPC_TYPE_UINT32, &g_args[4].u,
RPC_TYPE_UINT32, &g_args[5].u,
RPC_TYPE_UINT32, &g_args[6].u,
RPC_TYPE_UINT32, &g_args[7].u,
RPC_TYPE_UINT32, &g_args[8].u,
RPC_TYPE_UINT32, &g_args[9].u,
RPC_TYPE_INVALID);
g_assert (g_args[0].u == 0);
g_assert (g_args[1].u == 1);
g_assert (g_args[2].u == 0xffffffff);
g_assert (g_args[3].u == 2);
g_assert (g_args[4].u == 0xfffffffe);
g_assert (g_args[5].u == G_MAXUINT32);
g_assert (g_args[6].u == G_MAXUINT32 - 1);
g_assert (g_args[7].u == 0x80000000);
g_assert (g_args[8].u == 0x80000001);
g_assert (g_args[9].u == 0);
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static int
handle_VOID__UINT64x10 (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_UINT64, &g_args[0].j,
RPC_TYPE_UINT64, &g_args[1].j,
RPC_TYPE_UINT64, &g_args[2].j,
RPC_TYPE_UINT64, &g_args[3].j,
RPC_TYPE_UINT64, &g_args[4].j,
RPC_TYPE_UINT64, &g_args[5].j,
RPC_TYPE_UINT64, &g_args[6].j,
RPC_TYPE_UINT64, &g_args[7].j,
RPC_TYPE_UINT64, &g_args[8].j,
RPC_TYPE_UINT64, &g_args[9].j,
RPC_TYPE_INVALID);
g_assert (g_args[0].j == 0);
g_assert (g_args[1].j == G_GINT64_CONSTANT (0x00000000000000ffU));
g_assert (g_args[2].j == G_GINT64_CONSTANT (0x000000000000ff00U));
g_assert (g_args[3].j == G_GINT64_CONSTANT (0x0000000000ff0000U));
g_assert (g_args[4].j == G_GINT64_CONSTANT (0x00000000ff000000U));
g_assert (g_args[5].j == G_GINT64_CONSTANT (0x000000ff00000000U));
g_assert (g_args[6].j == G_GINT64_CONSTANT (0x0000ff0000000000U));
g_assert (g_args[7].j == G_GINT64_CONSTANT (0x00ff000000000000U));
g_assert (g_args[8].j == G_GINT64_CONSTANT (0xff00000000000000U));
g_assert (g_args[9].j == G_GINT64_CONSTANT (0x0123456789abcdefU));
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static int
handle_VOID__DOUBLEx5 (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_DOUBLE, &g_args[0].d,
RPC_TYPE_DOUBLE, &g_args[1].d,
RPC_TYPE_DOUBLE, &g_args[2].d,
RPC_TYPE_DOUBLE, &g_args[3].d,
RPC_TYPE_DOUBLE, &g_args[4].d,
RPC_TYPE_INVALID);
g_assert (g_args[0].d == 0.0);
g_assert (g_args[1].d == 1.0);
g_assert (g_args[2].d == -1.0);
g_assert (g_args[3].d == 2.0);
g_assert (g_args[4].d == -2.0);
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
static int
handle_VOID__STRINGx3 (rpc_connection_t *connection)
{
rpc_test_get_args (connection,
RPC_TYPE_STRING, &g_args[0].s,
RPC_TYPE_STRING, &g_args[1].s,
RPC_TYPE_STRING, &g_args[2].s,
RPC_TYPE_INVALID);
g_assert (g_args[0].s && strcmp (g_args[0].s, "") == 0);
free (g_args[0].s);
g_assert (g_args[1].s && strcmp (g_args[1].s, "one") == 0);
free (g_args[1].s);
g_assert (g_args[2].s == NULL);
return rpc_method_send_reply (connection, RPC_TYPE_INVALID);
}
#endif
int
rpc_test_init (int argc, char *argv[])
{
#ifdef BUILD_SERVER
rpc_connection_t *connection;
static const rpc_method_descriptor_t vtable[] =
{
{ RPC_TEST_METHOD_VOID__VOID, handle_VOID__VOID },
{ RPC_TEST_METHOD_VOID__CHAR, handle_VOID__CHAR },
{ RPC_TEST_METHOD_VOID__CHARx10, handle_VOID__CHARx10 },
{ RPC_TEST_METHOD_VOID__BOOL, handle_VOID__BOOL },
{ RPC_TEST_METHOD_VOID__BOOLx10, handle_VOID__BOOLx10 },
{ RPC_TEST_METHOD_VOID__INT32x10, handle_VOID__INT32x10 },
{ RPC_TEST_METHOD_VOID__UINT32x10, handle_VOID__UINT32x10 },
{ RPC_TEST_METHOD_VOID__UINT64x10, handle_VOID__UINT64x10 },
{ RPC_TEST_METHOD_VOID__DOUBLEx5, handle_VOID__DOUBLEx5 },
{ RPC_TEST_METHOD_VOID__STRINGx3, handle_VOID__STRINGx3 },
};
connection = rpc_test_get_connection ();
g_assert (connection != NULL);
if (rpc_connection_add_method_descriptors(connection,
vtable,
G_N_ELEMENTS (vtable)) < 0)
g_error ("could not add method descriptors");
#endif
return 0;
}
int
rpc_test_execute (gpointer user_data)
{
#ifdef BUILD_CLIENT
rpc_test_invoke (RPC_TEST_METHOD_VOID__VOID,
RPC_TYPE_INVALID);
rpc_test_invoke (RPC_TEST_METHOD_VOID__CHAR,
RPC_TYPE_CHAR, 'a',
RPC_TYPE_INVALID);
rpc_test_invoke (RPC_TEST_METHOD_VOID__CHARx10,
RPC_TYPE_CHAR, 'a',
RPC_TYPE_CHAR, 'b',
RPC_TYPE_CHAR, 'c',
RPC_TYPE_CHAR, 'd',
RPC_TYPE_CHAR, 'e',
RPC_TYPE_CHAR, '1',
RPC_TYPE_CHAR, '2',
RPC_TYPE_CHAR, '3',
RPC_TYPE_CHAR, '4',
RPC_TYPE_CHAR, '5',
RPC_TYPE_INVALID);
rpc_test_invoke (RPC_TEST_METHOD_VOID__BOOL,
RPC_TYPE_BOOLEAN, TRUE,
RPC_TYPE_INVALID);
rpc_test_invoke (RPC_TEST_METHOD_VOID__BOOLx10,
RPC_TYPE_BOOLEAN, TRUE,
RPC_TYPE_BOOLEAN, FALSE,
RPC_TYPE_BOOLEAN, TRUE,
RPC_TYPE_BOOLEAN, FALSE,
RPC_TYPE_BOOLEAN, TRUE,
RPC_TYPE_BOOLEAN, FALSE,
RPC_TYPE_BOOLEAN, TRUE,
RPC_TYPE_BOOLEAN, FALSE,
RPC_TYPE_BOOLEAN, TRUE,
RPC_TYPE_BOOLEAN, FALSE,
RPC_TYPE_INVALID);
rpc_test_invoke (RPC_TEST_METHOD_VOID__INT32x10,
RPC_TYPE_INT32, 0,
RPC_TYPE_INT32, 1,
RPC_TYPE_INT32, -1,
RPC_TYPE_INT32, 2,
RPC_TYPE_INT32, -2,
RPC_TYPE_INT32, G_MAXINT32,
RPC_TYPE_INT32, G_MININT32,
RPC_TYPE_INT32, G_MAXINT32 - 1,
RPC_TYPE_INT32, G_MININT32 + 1,
RPC_TYPE_INT32, 0,
RPC_TYPE_INVALID);
rpc_test_invoke (RPC_TEST_METHOD_VOID__UINT32x10,
RPC_TYPE_UINT32, 0,
RPC_TYPE_UINT32, 1,
RPC_TYPE_UINT32, 0xffffffff,
RPC_TYPE_UINT32, 2,
RPC_TYPE_UINT32, 0xfffffffe,
RPC_TYPE_UINT32, G_MAXUINT32,
RPC_TYPE_UINT32, G_MAXUINT32 - 1,
RPC_TYPE_UINT32, 0x80000000,
RPC_TYPE_UINT32, 0x80000001,
RPC_TYPE_UINT32, 0,
RPC_TYPE_INVALID);
rpc_test_invoke (RPC_TEST_METHOD_VOID__UINT64x10,
RPC_TYPE_UINT64, 0,
RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x00000000000000ffU),
RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x000000000000ff00U),
RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x0000000000ff0000U),
RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x00000000ff000000U),
RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x000000ff00000000U),
RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x0000ff0000000000U),
RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x00ff000000000000U),
RPC_TYPE_UINT64, G_GINT64_CONSTANT (0xff00000000000000U),
RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x0123456789abcdefU),
RPC_TYPE_INVALID);
rpc_test_invoke (RPC_TEST_METHOD_VOID__DOUBLEx5,
RPC_TYPE_DOUBLE, 0.0,
RPC_TYPE_DOUBLE, 1.0,
RPC_TYPE_DOUBLE, -1.0,
RPC_TYPE_DOUBLE, 2.0,
RPC_TYPE_DOUBLE, -2.0,
RPC_TYPE_INVALID);
rpc_test_invoke (RPC_TEST_METHOD_VOID__STRINGx3,
RPC_TYPE_STRING, "",
RPC_TYPE_STRING, "one",
RPC_TYPE_STRING, NULL,
RPC_TYPE_INVALID);
#endif
return RPC_TEST_EXECUTE_SUCCESS;
}

251
utils/install.sh Executable file
View File

@ -0,0 +1,251 @@
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
transformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
:
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
chmodcmd=""
else
instcmd=$mkdirprog
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f "$src" ] || [ -d "$src" ]
then
:
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
:
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
:
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
:
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
:
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0