summaryrefslogtreecommitdiff
Diffstat
-rw-r--r--.gitignore19
-rwxr-xr-xAndroid.mk244
-rw-r--r--CleanSpec.mk67
-rw-r--r--Makefile.flags2
-rw-r--r--README26
-rw-r--r--android/android.c96
-rw-r--r--android/libc/__set_errno.c43
-rwxr-xr-xandroid/libc/arch-arm/syscalls/swapoff.S19
-rwxr-xr-xandroid/libc/arch-arm/syscalls/swapon.S19
-rwxr-xr-xandroid/libc/arch-arm/syscalls/sysinfo.S19
-rw-r--r--android/libc/arch-mips/syscalls/swapoff.S22
-rw-r--r--android/libc/arch-mips/syscalls/swapon.S22
-rw-r--r--android/libc/arch-mips/syscalls/sysinfo.S22
-rw-r--r--android/libc/arch-x86/syscalls/swapoff.S31
-rw-r--r--android/libc/arch-x86/syscalls/swapon.S35
-rw-r--r--android/libc/arch-x86/syscalls/sysinfo.S31
-rw-r--r--android/libc/mktemp.c165
-rw-r--r--android/libc/pty.c118
-rw-r--r--android/librpc.sources43
-rw-r--r--android/librpc/auth_none.c137
-rw-r--r--android/librpc/auth_unix.c336
-rw-r--r--android/librpc/authunix_prot.c67
-rw-r--r--android/librpc/bindresvport.c95
-rw-r--r--android/librpc/clnt_generic.c215
-rw-r--r--android/librpc/clnt_perror.c435
-rw-r--r--android/librpc/clnt_raw.c248
-rw-r--r--android/librpc/clnt_simple.c164
-rw-r--r--android/librpc/clnt_tcp.c532
-rw-r--r--android/librpc/clnt_udp.c612
-rw-r--r--android/librpc/clnt_unix.c606
-rw-r--r--android/librpc/create_xid.c89
-rw-r--r--android/librpc/errqueue.h46
-rw-r--r--android/librpc/get_myaddress.c109
-rw-r--r--android/librpc/getrpcent.c349
-rw-r--r--android/librpc/getrpcport.c78
-rw-r--r--android/librpc/pm_getmaps.c84
-rw-r--r--android/librpc/pm_getport.c94
-rw-r--r--android/librpc/pmap_clnt.c176
-rw-r--r--android/librpc/pmap_prot.c56
-rw-r--r--android/librpc/pmap_prot2.c117
-rw-r--r--android/librpc/pmap_rmt.c440
-rw-r--r--android/librpc/rpc/auth.h232
-rw-r--r--android/librpc/rpc/auth_des.h117
-rw-r--r--android/librpc/rpc/auth_unix.h91
-rw-r--r--android/librpc/rpc/clnt.h433
-rw-r--r--android/librpc/rpc/des_crypt.h97
-rw-r--r--android/librpc/rpc/key_prot.h346
-rw-r--r--android/librpc/rpc/netdb.h79
-rw-r--r--android/librpc/rpc/pmap_clnt.h101
-rw-r--r--android/librpc/rpc/pmap_prot.h110
-rw-r--r--android/librpc/rpc/pmap_rmt.h71
-rw-r--r--android/librpc/rpc/rpc.h119
-rw-r--r--android/librpc/rpc/rpc_des.h72
-rw-r--r--android/librpc/rpc/rpc_msg.h206
-rw-r--r--android/librpc/rpc/svc.h330
-rw-r--r--android/librpc/rpc/svc_auth.h55
-rw-r--r--android/librpc/rpc/types.h134
-rw-r--r--android/librpc/rpc/xdr.h407
-rw-r--r--android/librpc/rpc_cmsg.c208
-rw-r--r--android/librpc/rpc_commondata.c47
-rw-r--r--android/librpc/rpc_dtablesize.c60
-rw-r--r--android/librpc/rpc_private.h55
-rw-r--r--android/librpc/rpc_prot.c285
-rw-r--r--android/librpc/rpc_thread.c166
-rw-r--r--android/librpc/svc.c506
-rw-r--r--android/librpc/svc_auth.c124
-rw-r--r--android/librpc/svc_authux.c159
-rw-r--r--android/librpc/svc_raw.c166
-rw-r--r--android/librpc/svc_run.c90
-rw-r--r--android/librpc/svc_simple.c197
-rw-r--r--android/librpc/svc_tcp.c428
-rw-r--r--android/librpc/svc_udp.c596
-rw-r--r--android/librpc/svc_unix.c536
-rw-r--r--android/librpc/xdr.c745
-rw-r--r--android/librpc/xdr_array.c171
-rw-r--r--android/librpc/xdr_float.c311
-rw-r--r--android/librpc/xdr_intXX_t.c203
-rw-r--r--android/librpc/xdr_mem.c237
-rw-r--r--android/librpc/xdr_rec.c646
-rw-r--r--android/librpc/xdr_reference.c147
-rw-r--r--android/librpc/xdr_stdio.c195
-rw-r--r--android/reboot.c57
-rw-r--r--android/regex/bb_regex.c5539
-rw-r--r--android/regex/bb_regex.h516
-rw-r--r--android/regex/cs_config.h239
-rw-r--r--android/selinux/android_selinux.h150
-rw-r--r--android/selinux/android_selinux_internal.h248
-rw-r--r--android/selinux/matchpathcon.c564
-rw-r--r--android/selinux/stubs.c39
-rw-r--r--applets/applets.c3
-rw-r--r--applets/usage_pod.c2
-rw-r--r--archival/cpio.c2
-rw-r--r--archival/gzip.c1
-rw-r--r--archival/libarchive/bz/blocksort.c2
-rw-r--r--archival/libarchive/data_extract_all.c5
-rw-r--r--archival/libarchive/data_extract_to_command.c4
-rw-r--r--archival/libarchive/decompress_gunzip.c5
-rw-r--r--archival/libarchive/unxz/xz_config.h4
-rw-r--r--busybox-full.config1093
-rw-r--r--busybox-full.links242
-rw-r--r--busybox-full.sources94
-rw-r--r--busybox-minimal.config1030
-rw-r--r--busybox-minimal.links184
-rw-r--r--busybox-minimal.sources51
-rw-r--r--configs/android_ndk_defconfig2
-rw-r--r--coreutils/cal.c2
-rw-r--r--coreutils/date.c1
-rw-r--r--coreutils/expand.c2
-rw-r--r--coreutils/expr.c4
-rw-r--r--coreutils/ls.c29
-rw-r--r--coreutils/od_bloaty.c2
-rw-r--r--coreutils/seq.c4
-rw-r--r--coreutils/sort.c2
-rw-r--r--coreutils/sync.c53
-rw-r--r--coreutils/tail.c4
-rw-r--r--coreutils/test.c2
-rw-r--r--coreutils/touch.c2
-rw-r--r--debianutils/mktemp.c10
-rw-r--r--e2fsprogs/tune2fs.c1
-rw-r--r--editors/awk.c14
-rw-r--r--editors/diff.c11
-rw-r--r--editors/patch.c4
-rw-r--r--editors/vi.c10
-rw-r--r--findutils/find.c8
-rw-r--r--include/.gitignore10
-rw-r--r--include/android.h96
-rw-r--r--include/bb_archive.h5
-rw-r--r--include/libbb.h101
-rw-r--r--include/platform.h2
-rw-r--r--include/xregex.h12
-rw-r--r--init/halt.c29
-rw-r--r--init/init.c5
-rw-r--r--libbb/appletlib.c2
-rw-r--r--libbb/bb_pwd.c27
-rw-r--r--libbb/dump.c4
-rw-r--r--libbb/fflush_stdout_and_exit.c4
-rw-r--r--libbb/fgets_str.c4
-rw-r--r--libbb/lineedit.c13
-rw-r--r--libbb/messages.c4
-rw-r--r--libbb/parse_config.c2
-rw-r--r--libbb/platform.c3
-rw-r--r--libbb/pw_encrypt_des.c2
-rw-r--r--libbb/pw_encrypt_sha.c4
-rw-r--r--libbb/rtc.c2
-rw-r--r--libbb/run_shell.c9
-rw-r--r--libbb/time.c6
-rw-r--r--libbb/udp_io.c8
-rw-r--r--libbb/unicode.c14
-rw-r--r--libbb/wfopen.c2
-rw-r--r--libbb/xfuncs_printf.c25
-rw-r--r--loginutils/addgroup.c2
-rw-r--r--loginutils/adduser.c2
-rw-r--r--loginutils/chpasswd.c2
-rw-r--r--loginutils/deluser.c2
-rw-r--r--loginutils/getty.c11
-rw-r--r--loginutils/login.c7
-rw-r--r--miscutils/adjtimex.c1
-rw-r--r--miscutils/crontab.c2
-rw-r--r--miscutils/devmem.c2
-rw-r--r--miscutils/fbsplash.c4
-rw-r--r--miscutils/fbsplash.cfg4
-rw-r--r--miscutils/flash_lock_unlock.c2
-rw-r--r--miscutils/flashcp.c2
-rw-r--r--miscutils/nandwrite.c4
-rw-r--r--miscutils/rx.c12
-rw-r--r--miscutils/strings.c4
-rw-r--r--miscutils/taskset.c6
-rw-r--r--miscutils/time.c1
-rw-r--r--networking/ftpgetput.c4
-rw-r--r--networking/hostname.c2
-rw-r--r--networking/ifconfig.c2
-rw-r--r--networking/inetd.c7
-rw-r--r--networking/interface.c2
-rw-r--r--networking/ipv6/icmp6.h346
-rw-r--r--networking/ipv6/ip6.h189
-rw-r--r--networking/libiproute/ipaddress.c12
-rw-r--r--networking/libiproute/iplink.c9
-rw-r--r--networking/libiproute/iproute.c2
-rw-r--r--networking/libiproute/libnetlink.c2
-rw-r--r--networking/libiproute/ll_proto.c2
-rw-r--r--networking/libiproute/utils.c4
-rw-r--r--networking/nc.c2
-rw-r--r--networking/nslookup.c55
-rw-r--r--networking/ntpd.c20
-rw-r--r--networking/ping.c4
-rw-r--r--networking/route.c10
-rw-r--r--networking/traceroute.c11
-rw-r--r--networking/udhcp/arpping.c2
-rw-r--r--networking/wget.c4
-rw-r--r--printutils/lpr.c2
-rw-r--r--procps/kill.c2
-rw-r--r--procps/lsof.c2
-rw-r--r--procps/mpstat.c18
-rw-r--r--procps/pstree.c2
-rw-r--r--procps/smemcap.c8
-rw-r--r--procps/sysctl.c2
-rw-r--r--procps/uptime.c2
-rw-r--r--scripts/Makefile.build3
-rw-r--r--scripts/kconfig/confdata.c6
-rwxr-xr-xscripts/update_config15
-rw-r--r--selinux/chcon.c5
-rw-r--r--selinux/matchpathcon.c5
-rw-r--r--selinux/setfiles.c10
-rw-r--r--shell/ash.c3437
-rw-r--r--shell/hush.c4
-rw-r--r--testsuite/date/date-works-12
-rw-r--r--testsuite/du/du-s-works2
-rw-r--r--testsuite/du/du-works2
-rw-r--r--testsuite/testing.sh7
-rw-r--r--util-linux/fdisk.c11
-rw-r--r--util-linux/fdisk_gpt.c6
-rw-r--r--util-linux/mkfs_ext2.c6
-rw-r--r--util-linux/more.c12
-rw-r--r--util-linux/mount.c16
-rw-r--r--util-linux/nsenter.c6
-rw-r--r--util-linux/rdate.c2
-rw-r--r--util-linux/swaponoff.c1
-rw-r--r--util-linux/umount.c8
-rw-r--r--util-linux/unshare.c4
-rw-r--r--util-linux/volume_id/get_devname.c6
-rw-r--r--util-linux/volume_id/util.c4
-rw-r--r--util-linux/volume_id/volume_id.c22
222 files changed, 28253 insertions, 2190 deletions
diff --git a/.gitignore b/.gitignore
index be1d461..37545bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ Config.in
# Never ignore these
#
!.gitignore
+!.config*
#
# Normal output
@@ -28,6 +29,7 @@ Config.in
*.orig
*.rej
/*.patch
+/.config.old
#
# debugging stuff
@@ -36,17 +38,6 @@ core
.gdb_history
.gdbinit
-#
-# testing output
-#
-/busybox.links
-/runtest-tempdir-links
-/testsuite/echo-ne
-
-#
-# cscope output
-#
-cscope.files
-cscope.in.out
-cscope.out
-cscope.po.out
+#ctags
+tags
+ctags
diff --git a/Android.mk b/Android.mk
new file mode 100755
index 0000000..46ce46e
--- a/dev/null
+++ b/Android.mk
@@ -0,0 +1,244 @@
+####busybox #######
+LOCAL_PATH := $(call my-dir)
+BB_PATH := $(LOCAL_PATH)
+
+# Bionic Branches Switches (GB/ICS/L)
+BIONIC_ICS := false
+BIONIC_L := true
+
+# Make a static library for regex.
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := android/regex/bb_regex.c
+LOCAL_C_INCLUDES := $(BB_PATH)/android/regex
+LOCAL_CFLAGS := -Wno-sign-compare
+LOCAL_MODULE := libclearsilverregex
+include $(BUILD_STATIC_LIBRARY)
+
+# Make a static library for RPC library (coming from uClibc).
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(shell cat $(BB_PATH)/android/librpc.sources)
+LOCAL_C_INCLUDES := $(BB_PATH)/android/librpc
+LOCAL_MODULE := libuclibcrpc
+LOCAL_CFLAGS += -fno-strict-aliasing
+ifeq ($(BIONIC_L),true)
+LOCAL_CFLAGS += -DBIONIC_ICS -DBIONIC_L
+endif
+include $(BUILD_STATIC_LIBRARY)
+
+#####################################################################
+
+# Execute make prepare for normal config & static lib (recovery)
+
+LOCAL_PATH := $(BB_PATH)
+include $(CLEAR_VARS)
+
+# Explicitly set an architecture specific CONFIG_CROSS_COMPILER_PREFIX
+ifneq ($(filter arm arm64,$(TARGET_ARCH)),)
+ BUSYBOX_CROSS_COMPILER_PREFIX := arm-linux-androideabi-
+endif
+ifneq ($(filter x86 x86_64,$(TARGET_ARCH)),)
+ BUSYBOX_CROSS_COMPILER_PREFIX := $(if $(filter x86_64,$(HOST_ARCH)),x86_64,i686)-linux-android-
+endif
+ifeq ($(TARGET_ARCH),mips)
+ BUSYBOX_CROSS_COMPILER_PREFIX := mipsel-linux-android-
+endif
+
+BB_PREPARE_FLAGS:=
+ifeq ($(HOST_OS),darwin)
+ BB_HOSTCC := $(ANDROID_BUILD_TOP)/prebuilts/gcc/darwin-x86/host/i686-apple-darwin-4.2.1/bin/i686-apple-darwin11-gcc
+ BB_PREPARE_FLAGS := HOSTCC=$(BB_HOSTCC)
+endif
+
+# On aosp (master), path is relative, not on cm (kitkat)
+bb_gen := $(abspath $(TARGET_OUT_INTERMEDIATES)/busybox)
+
+busybox_prepare_full := $(bb_gen)/full/.config
+$(busybox_prepare_full): $(BB_PATH)/busybox-full.config
+ @echo -e ${CL_YLW}"Prepare config for busybox binary"${CL_RST}
+ @rm -rf $(bb_gen)/full
+ @rm -f $(addsuffix /*.o, $(abspath $(call intermediates-dir-for,EXECUTABLES,busybox)))
+ @mkdir -p $(@D)
+ @cat $^ > $@ && echo "CONFIG_CROSS_COMPILER_PREFIX=\"$(BUSYBOX_CROSS_COMPILER_PREFIX)\"" >> $@
+ $(MAKE) -C $(BB_PATH) prepare O=$(@D) $(BB_PREPARE_FLAGS)
+
+busybox_prepare_minimal := $(bb_gen)/minimal/.config
+$(busybox_prepare_minimal): $(BB_PATH)/busybox-minimal.config
+ @echo -e ${CL_YLW}"Prepare config for libbusybox"${CL_RST}
+ @rm -rf $(bb_gen)/minimal
+ @rm -f $(addsuffix /*.o, $(abspath $(call intermediates-dir-for,STATIC_LIBRARIES,libbusybox)))
+ @mkdir -p $(@D)
+ @cat $^ > $@ && echo "CONFIG_CROSS_COMPILER_PREFIX=\"$(BUSYBOX_CROSS_COMPILER_PREFIX)\"" >> $@
+ $(MAKE) -C $(BB_PATH) prepare O=$(@D) $(BB_PREPARE_FLAGS)
+
+KERNEL_MODULES_DIR ?= /system/lib/modules
+BUSYBOX_CONFIG := minimal full
+$(BUSYBOX_CONFIG):
+ @echo -e ${CL_PFX}"prepare config for busybox $@ profile"${CL_RST}
+ @cd $(BB_PATH) && make clean
+ @cd $(BB_PATH) && git clean -f -- ./include-$@/
+ cp $(BB_PATH)/.config-$@ $(BB_PATH)/.config
+ cd $(BB_PATH) && make prepare
+ @#cp $(BB_PATH)/.config $(BB_PATH)/.config-$@
+ @mkdir -p $(BB_PATH)/include-$@
+ cp $(BB_PATH)/include/*.h $(BB_PATH)/include-$@/
+ @rm $(BB_PATH)/include/usage_compressed.h
+ @rm $(BB_PATH)/include/autoconf.h
+ @rm -f $(BB_PATH)/.config-old
+
+busybox_prepare: $(BUSYBOX_CONFIG)
+LOCAL_MODULE := busybox_prepare
+LOCAL_MODULE_TAGS := eng debug
+#include $(BUILD_STATIC_LIBRARY)
+
+#####################################################################
+
+LOCAL_PATH := $(BB_PATH)
+include $(CLEAR_VARS)
+
+KERNEL_MODULES_DIR ?= /system/lib/modules
+
+SUBMAKE := make -s -C $(BB_PATH) CC=$(CC)
+
+
+BUSYBOX_SRC_FILES = \
+ $(shell cat $(BB_PATH)/busybox-$(BUSYBOX_CONFIG).sources) \
+ android/libc/mktemp.c \
+ android/libc/pty.c \
+ android/android.c
+
+BUSYBOX_ASM_FILES =
+ifneq ($(BIONIC_L),true)
+ BUSYBOX_ASM_FILES += swapon.S swapoff.S sysinfo.S
+endif
+
+ifneq ($(filter arm x86 mips,$(TARGET_ARCH)),)
+ BUSYBOX_SRC_FILES += \
+ $(addprefix android/libc/arch-$(TARGET_ARCH)/syscalls/,$(BUSYBOX_ASM_FILES))
+endif
+
+BUSYBOX_C_INCLUDES = \
+ $(BB_PATH)/include $(BB_PATH)/libbb \
+ bionic/libc/private \
+ bionic/libm/include \
+ bionic/libc \
+ bionic/libm \
+ libc/kernel/common \
+ external/libselinux/include \
+ external/selinux/libsepol/include \
+ $(BB_PATH)/android/regex \
+ $(BB_PATH)/android/librpc
+
+BUSYBOX_CFLAGS = \
+ -Werror=implicit -Wno-clobbered \
+ -DNDEBUG \
+ -DANDROID \
+ -fno-strict-aliasing \
+ -fno-builtin-stpcpy \
+ -include $(bb_gen)/$(BUSYBOX_CONFIG)/include/autoconf.h \
+ -D'CONFIG_DEFAULT_MODULES_DIR="$(KERNEL_MODULES_DIR)"' \
+ -D'BB_VER="$(strip $(shell $(SUBMAKE) kernelversion)) $(BUSYBOX_SUFFIX)"' -DBB_BT=AUTOCONF_TIMESTAMP
+
+ifeq ($(BIONIC_L),true)
+ BUSYBOX_CFLAGS += -DBIONIC_L
+ BUSYBOX_AFLAGS += -DBIONIC_L
+ # include changes for ICS/JB/KK
+ BIONIC_ICS := true
+endif
+
+ifeq ($(BIONIC_ICS),true)
+ BUSYBOX_CFLAGS += -DBIONIC_ICS
+endif
+
+
+# Build the static lib for the recovery tool
+
+BUSYBOX_CONFIG:=minimal
+BUSYBOX_SUFFIX:=static
+LOCAL_SRC_FILES := $(BUSYBOX_SRC_FILES)
+LOCAL_C_INCLUDES := $(bb_gen)/minimal/include $(BUSYBOX_C_INCLUDES)
+LOCAL_CFLAGS := -Dmain=busybox_driver $(BUSYBOX_CFLAGS)
+LOCAL_CFLAGS += \
+ -DRECOVERY_VERSION \
+ -Dgetusershell=busybox_getusershell \
+ -Dsetusershell=busybox_setusershell \
+ -Dendusershell=busybox_endusershell \
+ -Dgetmntent=busybox_getmntent \
+ -Dgetmntent_r=busybox_getmntent_r \
+ -Dgenerate_uuid=busybox_generate_uuid
+LOCAL_ASFLAGS := $(BUSYBOX_AFLAGS)
+LOCAL_MODULE := libbusybox
+LOCAL_MODULE_TAGS := eng debug
+#$(LOCAL_MODULE): busybox_prepare
+LOCAL_STATIC_LIBRARIES := libcutils libc libm libselinux
+LOCAL_ADDITIONAL_DEPENDENCIES := $(busybox_prepare_minimal)
+include $(BUILD_STATIC_LIBRARY)
+
+
+# Bionic Busybox /system/xbin
+
+LOCAL_PATH := $(BB_PATH)
+include $(CLEAR_VARS)
+
+BUSYBOX_CONFIG:=full
+BUSYBOX_SUFFIX:=bionic
+LOCAL_SRC_FILES := $(BUSYBOX_SRC_FILES)
+LOCAL_C_INCLUDES := $(bb_gen)/full/include $(BUSYBOX_C_INCLUDES)
+LOCAL_CFLAGS := $(BUSYBOX_CFLAGS)
+LOCAL_ASFLAGS := $(BUSYBOX_AFLAGS)
+LOCAL_MODULE := busybox
+LOCAL_MODULE_TAGS := eng debug
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_SHARED_LIBRARIES := libc libcutils libm
+#$(LOCAL_MODULE): busybox_prepare
+LOCAL_STATIC_LIBRARIES += libclearsilverregex libuclibcrpc libselinux
+LOCAL_ADDITIONAL_DEPENDENCIES := $(busybox_prepare_full)
+include $(BUILD_EXECUTABLE)
+
+BUSYBOX_LINKS := $(shell cat $(BB_PATH)/busybox-$(BUSYBOX_CONFIG).links)
+# nc is provided by external/netcat
+exclude := nc which
+SYMLINKS := $(addprefix $(TARGET_OUT_OPTIONAL_EXECUTABLES)/,$(filter-out $(exclude),$(notdir $(BUSYBOX_LINKS))))
+$(SYMLINKS): BUSYBOX_BINARY := $(LOCAL_MODULE)
+$(SYMLINKS): $(LOCAL_INSTALLED_MODULE)
+ @echo -e ${CL_CYN}"Symlink:"${CL_RST}" $@ -> $(BUSYBOX_BINARY)"
+ @mkdir -p $(dir $@)
+ @rm -rf $@
+ $(hide) ln -sf $(BUSYBOX_BINARY) $@
+
+ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS)
+
+# We need this so that the installed files could be picked up based on the
+# local module name
+ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
+ $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(SYMLINKS)
+
+
+# Static Busybox
+
+LOCAL_PATH := $(BB_PATH)
+include $(CLEAR_VARS)
+
+BUSYBOX_CONFIG:=full
+BUSYBOX_SUFFIX:=static
+LOCAL_SRC_FILES := $(BUSYBOX_SRC_FILES)
+LOCAL_C_INCLUDES := $(bb_gen)/full/include $(BUSYBOX_C_INCLUDES)
+LOCAL_CFLAGS := $(BUSYBOX_CFLAGS)
+LOCAL_CFLAGS += \
+ -Dgetusershell=busybox_getusershell \
+ -Dsetusershell=busybox_setusershell \
+ -Dendusershell=busybox_endusershell \
+ -Dgetmntent=busybox_getmntent \
+ -Dgetmntent_r=busybox_getmntent_r \
+ -Dgenerate_uuid=busybox_generate_uuid
+LOCAL_ASFLAGS := $(BUSYBOX_AFLAGS)
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE := static_busybox
+LOCAL_MODULE_STEM := busybox
+LOCAL_MODULE_TAGS := optional
+LOCAL_STATIC_LIBRARIES := libclearsilverregex libc libcutils libm libuclibcrpc libselinux
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
+LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
+#$(LOCAL_MODULE): busybox_prepare
+LOCAL_ADDITIONAL_DEPENDENCIES := $(busybox_prepare_full)
+include $(BUILD_EXECUTABLE)
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..92152f4
--- a/dev/null
+++ b/CleanSpec.mk
@@ -0,0 +1,67 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# Note: this is not really required, but remember only the added lines
+# will be executed (see $OUT/clean_steps.mk value for the current line)
+
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/utilities/busybox)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/symbols/system/xbin/busybox)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/busybox_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbusybox_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/UTILITY_EXECUTABLES/static_busybox_intermediates)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/busybox)
+
+# remains from old build system */
+$(call add-clean-step, rm -f external/busybox/include/bbconfigopts.h)
+$(call add-clean-step, rm -f external/busybox/include/autoconf.h)
+$(call add-clean-step, rm -f external/busybox/include/applet_tables.h)
+$(call add-clean-step, rm -f external/busybox/include/applets.h)
+$(call add-clean-step, rm -f external/busybox/.config)
+
+# force prepare
+$(call add-clean-step, touch external/busybox/busybox-minimal.config)
+$(call add-clean-step, touch external/busybox/busybox-full.config)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
diff --git a/Makefile.flags b/Makefile.flags
index 65021de..89d599c 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -150,11 +150,13 @@ LDLIBS += pam pam_misc
endif
ifeq ($(CONFIG_SELINUX),y)
+ifeq ($(ANDROID_PRODUCT_OUT),) # Ignore pkgconfig on Android Builds
SELINUX_PC_MODULES = libselinux libsepol
$(eval $(call pkg_check_modules,SELINUX,$(SELINUX_PC_MODULES)))
CPPFLAGS += $(SELINUX_CFLAGS)
LDLIBS += $(if $(SELINUX_LIBS),$(SELINUX_LIBS:-l%=%),$(SELINUX_PC_MODULES:lib%=%))
endif
+endif
ifeq ($(CONFIG_EFENCE),y)
LDLIBS += efence
diff --git a/README b/README
index ada5935..ebdda73 100644
--- a/README
+++ b/README
@@ -1,6 +1,32 @@
Please see the LICENSE file for details on copying and usage.
Please refer to the INSTALL file for instructions on how to build.
+----------------
+Note about this Android Variant :
+
+WARNING : THIS IS A BIONIC VERSION OF BUSYBOX, DO NOT USE "make" IN THIS TREE
+
+This tree has multiple configurations (busybox and recovery lib),
+
+- lunch your device to prepare the environment
+- edit the wanted config profile (ie busybox-full.config)
+
+- type "mma" in external/busybox to build with the dependencies
+
+ Finally copy $OUT/obj/busybox/full/.config to the source tree without
+ the CONFIG_CROSS_COMPILER_PREFIX line! (to stay compatible with x86 targets)
+
+ bb_obj=$OUT/obj/busybox/full
+ cat $bb_obj/.config | grep -v CROSS_COMPILER_ > busybox-full.config
+
+ bb_obj=$OUT/obj/busybox/minimal
+ cat $bb_obj/.config | grep -v CROSS_COMPILER_ > busybox-minimal.config
+
+ If you add or remove some applets,
+ please also update busybox-<profile>.links and busybox-<profile>.sources
+
+----------------
+
What is busybox:
BusyBox combines tiny versions of many common UNIX utilities into a single
diff --git a/android/android.c b/android/android.c
new file mode 100644
index 0000000..62d25a8
--- a/dev/null
+++ b/android/android.c
@@ -0,0 +1,96 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * Android/bionic glue.
+ *
+ * Copyright (C) 2010 by Dylan Simon <dylan@dylex.net>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+
+#include <stdlib.h>
+#include "libbb.h"
+
+#ifndef BIONIC_ICS
+int clearenv(void)
+{
+ char **P = environ;
+
+ /* should never be NULL */
+ if (!environ)
+ environ = (char **)xzalloc(sizeof(char *));
+
+ if (P != NULL) {
+ for (; *P; ++P)
+ *P = NULL;
+ }
+ return 0;
+}
+#endif
+
+/* no /etc/shells anyway */
+char *getusershell() { return NULL; }
+void setusershell() {}
+void endusershell() {}
+
+struct mntent *getmntent_r(FILE *fp, struct mntent *mnt, char *buf, int buflen)
+{
+ char *tokp = NULL, *s;
+
+ do {
+ if (!fgets(buf, buflen, fp))
+ return NULL;
+ tokp = 0;
+ s = strtok_r(buf, " \t\n", &tokp);
+ } while (!s || *s == '#');
+
+ mnt->mnt_fsname = s;
+ mnt->mnt_freq = mnt->mnt_passno = 0;
+ if (!(mnt->mnt_dir = strtok_r(NULL, " \t\n", &tokp)))
+ return NULL;
+ if (!(mnt->mnt_type = strtok_r(NULL, " \t\n", &tokp)))
+ return NULL;
+ if (!(mnt->mnt_opts = strtok_r(NULL, " \t\n", &tokp)))
+ mnt->mnt_opts = "";
+ else if ((s = strtok_r(NULL, " \t\n", &tokp)))
+ {
+ mnt->mnt_freq = atoi(s);
+ if ((s = strtok_r(NULL, " \t\n", &tokp)))
+ mnt->mnt_passno = atoi(s);
+ }
+
+ return mnt;
+}
+
+/* override definition in bionic/stubs.c */
+struct mntent *getmntent(FILE *fp)
+{
+ static struct mntent mnt;
+ static char buf[256];
+ return getmntent_r(fp, &mnt, buf, 256);
+}
+
+/* not used anyway */
+int addmntent(FILE *fp UNUSED_PARAM, const struct mntent *mnt UNUSED_PARAM)
+{
+ errno = ENOENT;
+ return 1;
+}
+
+char *hasmntopt(const struct mntent *mnt, const char *opt)
+{
+ char *o = mnt->mnt_opts;
+ size_t l = strlen(opt);
+
+ while ((o = strstr(o, opt)) &&
+ ((o > mnt->mnt_opts && o[-1] != ',') ||
+ (o[l] != 0 && o[l] != ',' && o[l] != '=')));
+ return o;
+}
+
+/* declared in grp.h, but not necessary */
+#if !ENABLE_USE_BB_PWD_GRP
+int setpwent() { return 0; }
+void setgrent() {}
+void endgrent() {}
+#endif
+
diff --git a/android/libc/__set_errno.c b/android/libc/__set_errno.c
new file mode 100644
index 0000000..ed832e9
--- a/dev/null
+++ b/android/libc/__set_errno.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+
+#ifdef __LP64__
+
+/* __set_errno was mistakenly exposed in <errno.h> in the 32-bit NDK.
+ * but is no more present for 64-bit targets!
+ */
+
+long __set_errno(int n)
+{
+ errno = n;
+ return -1;
+}
+
+#endif
diff --git a/android/libc/arch-arm/syscalls/swapoff.S b/android/libc/arch-arm/syscalls/swapoff.S
new file mode 100755
index 0000000..7117295
--- a/dev/null
+++ b/android/libc/arch-arm/syscalls/swapoff.S
@@ -0,0 +1,19 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+
+ .text
+ .type swapoff, #function
+ .globl swapoff
+ .align 4
+ .fnstart
+
+swapoff:
+ .save {r4, r7}
+ stmfd sp!, {r4, r7}
+ ldr r7, =__NR_swapoff
+ swi #0
+ ldmfd sp!, {r4, r7}
+ movs r0, r0
+ bxpl lr
+ b __set_errno
+ .fnend
diff --git a/android/libc/arch-arm/syscalls/swapon.S b/android/libc/arch-arm/syscalls/swapon.S
new file mode 100755
index 0000000..fb86331
--- a/dev/null
+++ b/android/libc/arch-arm/syscalls/swapon.S
@@ -0,0 +1,19 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+
+ .text
+ .type swapon, #function
+ .globl swapon
+ .align 4
+ .fnstart
+
+swapon:
+ .save {r4, r7}
+ stmfd sp!, {r4, r7}
+ ldr r7, =__NR_swapon
+ swi #0
+ ldmfd sp!, {r4, r7}
+ movs r0, r0
+ bxpl lr
+ b __set_errno
+ .fnend
diff --git a/android/libc/arch-arm/syscalls/sysinfo.S b/android/libc/arch-arm/syscalls/sysinfo.S
new file mode 100755
index 0000000..3ffad4e
--- a/dev/null
+++ b/android/libc/arch-arm/syscalls/sysinfo.S
@@ -0,0 +1,19 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+
+ .text
+ .type sysinfo, #function
+ .globl sysinfo
+ .align 4
+ .fnstart
+
+sysinfo:
+ .save {r4, r7}
+ stmfd sp!, {r4, r7}
+ ldr r7, =__NR_sysinfo
+ swi #0
+ ldmfd sp!, {r4, r7}
+ movs r0, r0
+ bxpl lr
+ b __set_errno
+ .fnend
diff --git a/android/libc/arch-mips/syscalls/swapoff.S b/android/libc/arch-mips/syscalls/swapoff.S
new file mode 100644
index 0000000..5e851d5
--- a/dev/null
+++ b/android/libc/arch-mips/syscalls/swapoff.S
@@ -0,0 +1,22 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+ .text
+ .globl swapoff
+ .align 4
+ .ent swapoff
+
+swapoff:
+ .set noreorder
+ .cpload $t9
+ li $v0, (4000+115)
+ syscall
+ bnez $a3, 1f
+ move $a0, $v0
+ j $ra
+ nop
+1:
+ la $t9,__set_errno
+ j $t9
+ nop
+ .set reorder
+ .end swapoff
diff --git a/android/libc/arch-mips/syscalls/swapon.S b/android/libc/arch-mips/syscalls/swapon.S
new file mode 100644
index 0000000..f4d1b3d
--- a/dev/null
+++ b/android/libc/arch-mips/syscalls/swapon.S
@@ -0,0 +1,22 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+ .text
+ .globl swapon
+ .align 4
+ .ent swapon
+
+swapon:
+ .set noreorder
+ .cpload $t9
+ li $v0, (4000+87)
+ syscall
+ bnez $a3, 1f
+ move $a0, $v0
+ j $ra
+ nop
+1:
+ la $t9,__set_errno
+ j $t9
+ nop
+ .set reorder
+ .end swapon
diff --git a/android/libc/arch-mips/syscalls/sysinfo.S b/android/libc/arch-mips/syscalls/sysinfo.S
new file mode 100644
index 0000000..6f4580f
--- a/dev/null
+++ b/android/libc/arch-mips/syscalls/sysinfo.S
@@ -0,0 +1,22 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+ .text
+ .globl sysinfo
+ .align 4
+ .ent sysinfo
+
+sysinfo:
+ .set noreorder
+ .cpload $t9
+ li $v0, (4000+116)
+ syscall
+ bnez $a3, 1f
+ move $a0, $v0
+ j $ra
+ nop
+1:
+ la $t9,__set_errno
+ j $t9
+ nop
+ .set reorder
+ .end sysinfo
diff --git a/android/libc/arch-x86/syscalls/swapoff.S b/android/libc/arch-x86/syscalls/swapoff.S
new file mode 100644
index 0000000..5b4ee06
--- a/dev/null
+++ b/android/libc/arch-x86/syscalls/swapoff.S
@@ -0,0 +1,31 @@
+/* autogenerated by gensyscalls.py */
+
+#ifdef BIONIC_L
+# include <private/bionic_asm.h>
+#else
+# include <asm/unistd.h>
+# include <linux/err.h>
+# include <machine/asm.h>
+#endif
+
+ .text
+ .type swapoff, @function
+ .globl swapoff
+ .align 4
+
+swapoff:
+ pushl %ebx
+ mov 8(%esp), %ebx
+ movl $__NR_swapoff, %eax
+ int $0x80
+ cmpl $-MAX_ERRNO, %eax
+ jb 1f
+ negl %eax
+ pushl %eax
+ call __set_errno
+ addl $4, %esp
+ orl $-1, %eax
+1:
+ popl %ebx
+ ret
+
diff --git a/android/libc/arch-x86/syscalls/swapon.S b/android/libc/arch-x86/syscalls/swapon.S
new file mode 100644
index 0000000..957173e
--- a/dev/null
+++ b/android/libc/arch-x86/syscalls/swapon.S
@@ -0,0 +1,35 @@
+/* autogenerated by gensyscalls.py */
+
+#ifdef BIONIC_L
+# include <private/bionic_asm.h>
+#else
+# include <asm/unistd.h>
+# include <asm/unistd.h>
+# include <linux/err.h>
+# include <machine/asm.h>
+#endif
+
+ .text
+ .type swapon, @function
+ .globl swapon
+ .align 4
+
+swapon:
+ pushl %ebx
+ pushl %ecx
+ mov 12(%esp), %ebx
+ mov 16(%esp), %ecx
+ movl $__NR_swapon, %eax
+ int $0x80
+ cmpl $-MAX_ERRNO, %eax
+ jb 1f
+ negl %eax
+ pushl %eax
+ call __set_errno
+ addl $4, %esp
+ orl $-1, %eax
+1:
+ popl %ecx
+ popl %ebx
+ ret
+
diff --git a/android/libc/arch-x86/syscalls/sysinfo.S b/android/libc/arch-x86/syscalls/sysinfo.S
new file mode 100644
index 0000000..ea73dc0
--- a/dev/null
+++ b/android/libc/arch-x86/syscalls/sysinfo.S
@@ -0,0 +1,31 @@
+/* autogenerated by gensyscalls.py */
+
+#ifdef BIONIC_L
+# include <private/bionic_asm.h>
+#else
+# include <asm/unistd.h>
+# include <linux/err.h>
+# include <machine/asm.h>
+#endif
+
+ .text
+ .type sysinfo, @function
+ .globl sysinfo
+ .align 4
+
+sysinfo:
+ pushl %ebx
+ mov 8(%esp), %ebx
+ movl $__NR_sysinfo, %eax
+ int $0x80
+ cmpl $-MAX_ERRNO, %eax
+ jb 1f
+ negl %eax
+ pushl %eax
+ call __set_errno
+ addl $4, %esp
+ orl $-1, %eax
+1:
+ popl %ebx
+ ret
+
diff --git a/android/libc/mktemp.c b/android/libc/mktemp.c
new file mode 100644
index 0000000..0b2e933
--- a/dev/null
+++ b/android/libc/mktemp.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+extern u_int32_t arc4random_uniform(u_int32_t);
+#define _open open
+
+static int _gettemp(char *, int *, int, int);
+
+static const char padchar[] =
+"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static char *
+_mktemp(char *path)
+{
+ return (_gettemp(path, (int *)NULL, 0, 0) ? path : (char *)NULL);
+}
+
+char *
+bb_mktemp(char *path)
+{
+ return (_mktemp(path));
+}
+
+static int
+_gettemp(char *path, int *doopen, int domkdir, int slen)
+{
+ char *start, *trv, *suffp, *carryp;
+ char *pad;
+ struct stat sbuf;
+ int rval;
+ uint32_t rand;
+ char carrybuf[MAXPATHLEN];
+
+ if ((doopen != NULL && domkdir) || slen < 0) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ for (trv = path; *trv != '\0'; ++trv)
+ ;
+ if (trv - path >= MAXPATHLEN) {
+ errno = ENAMETOOLONG;
+ return (0);
+ }
+ trv -= slen;
+ suffp = trv;
+ --trv;
+ if (trv < path || NULL != strchr(suffp, '/')) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ /* Fill space with random characters */
+ while (trv >= path && *trv == 'X') {
+ rand = arc4random_uniform(sizeof(padchar) - 1);
+ *trv-- = padchar[rand];
+ }
+ start = trv + 1;
+
+ /* save first combination of random characters */
+ memcpy(carrybuf, start, suffp - start);
+
+ /*
+ * check the target directory.
+ */
+ if (doopen != NULL || domkdir) {
+ for (; trv > path; --trv) {
+ if (*trv == '/') {
+ *trv = '\0';
+ rval = stat(path, &sbuf);
+ *trv = '/';
+ if (rval != 0)
+ return (0);
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = ENOTDIR;
+ return (0);
+ }
+ break;
+ }
+ }
+ }
+
+ for (;;) {
+ if (doopen) {
+ if ((*doopen =
+ _open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
+ return (1);
+ if (errno != EEXIST)
+ return (0);
+ } else if (domkdir) {
+ if (mkdir(path, 0700) == 0)
+ return (1);
+ if (errno != EEXIST)
+ return (0);
+ } else if (lstat(path, &sbuf))
+ return (errno == ENOENT);
+
+ /* If we have a collision, cycle through the space of filenames */
+ for (trv = start, carryp = carrybuf;;) {
+ /* have we tried all possible permutations? */
+ if (trv == suffp)
+ return (0); /* yes - exit with EEXIST */
+ pad = strchr(padchar, *trv);
+ if (pad == NULL) {
+ /* this should never happen */
+ errno = EIO;
+ return (0);
+ }
+ /* increment character */
+ *trv = (*++pad == '\0') ? padchar[0] : *pad;
+ /* carry to next position? */
+ if (*trv == *carryp) {
+ /* increment position and loop */
+ ++trv;
+ ++carryp;
+ } else {
+ /* try with new name */
+ break;
+ }
+ }
+ }
+ /*NOTREACHED*/
+}
diff --git a/android/libc/pty.c b/android/libc/pty.c
new file mode 100644
index 0000000..2765221
--- a/dev/null
+++ b/android/libc/pty.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* #ifndef BIONIC_L (implementation was made after BIONIC_L (l-preview) */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+/* if this constant is not defined, we are
+ ttyname is not in bionic */
+#ifndef SPLICE_F_GIFT
+
+int posix_openpt(int flags) {
+ return open("/dev/ptmx", flags);
+}
+
+int getpt(void) {
+ return posix_openpt(O_RDWR|O_NOCTTY);
+}
+
+#ifndef __BIONIC__
+int grantpt(int) {
+ return 0;
+}
+#endif
+
+char* ptsname(int fd) {
+ static char buf[64];
+ return ptsname_r(fd, buf, sizeof(buf)) == 0 ? buf : NULL;
+}
+
+int ptsname_r(int fd, char* buf, size_t len) {
+ if (buf == NULL) {
+ errno = EINVAL;
+ return errno;
+ }
+
+ unsigned int pty_num;
+ if (ioctl(fd, TIOCGPTN, &pty_num) != 0) {
+ errno = ENOTTY;
+ return errno;
+ }
+
+ if (snprintf(buf, len, "/dev/pts/%u", pty_num) >= (int) len) {
+ errno = ERANGE;
+ return errno;
+ }
+
+ return 0;
+}
+
+int bb_ttyname_r(int fd, char* buf, size_t len) {
+ if (buf == NULL) {
+ errno = EINVAL;
+ return errno;
+ }
+
+ if (!isatty(fd)) {
+ return errno;
+ }
+
+ char path[64];
+ snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
+
+ ssize_t count = readlink(path, buf, len);
+ if (count == -1) {
+ return errno;
+ }
+ if ((size_t) (count) == len) {
+ errno = ERANGE;
+ return errno;
+ }
+ buf[count] = '\0';
+ return 0;
+}
+
+char* bb_ttyname(int fd) {
+ static char buf[64];
+ return bb_ttyname_r(fd, buf, sizeof(buf)) == 0 ? buf : NULL;
+}
+
+int unlockpt(int fd) {
+ int unlock = 0;
+ return ioctl(fd, TIOCSPTLCK, &unlock);
+}
+
+#endif
diff --git a/android/librpc.sources b/android/librpc.sources
new file mode 100644
index 0000000..f0da11f
--- a/dev/null
+++ b/android/librpc.sources
@@ -0,0 +1,43 @@
+android/librpc/auth_none.c
+android/librpc/auth_unix.c
+android/librpc/authunix_prot.c
+android/librpc/bindresvport.c
+android/librpc/clnt_generic.c
+android/librpc/clnt_perror.c
+android/librpc/clnt_raw.c
+android/librpc/clnt_simple.c
+android/librpc/clnt_tcp.c
+android/librpc/clnt_udp.c
+android/librpc/clnt_unix.c
+android/librpc/create_xid.c
+android/librpc/get_myaddress.c
+android/librpc/getrpcent.c
+android/librpc/getrpcport.c
+android/librpc/pmap_clnt.c
+android/librpc/pmap_prot2.c
+android/librpc/pmap_prot.c
+android/librpc/pmap_rmt.c
+android/librpc/pm_getmaps.c
+android/librpc/pm_getport.c
+android/librpc/rpc_cmsg.c
+android/librpc/rpc_commondata.c
+android/librpc/rpc_dtablesize.c
+android/librpc/rpc_prot.c
+android/librpc/rpc_thread.c
+android/librpc/svc_auth.c
+android/librpc/svc_authux.c
+android/librpc/svc.c
+android/librpc/svc_raw.c
+android/librpc/svc_run.c
+android/librpc/svc_simple.c
+android/librpc/svc_tcp.c
+android/librpc/svc_udp.c
+android/librpc/svc_unix.c
+android/librpc/xdr_array.c
+android/librpc/xdr.c
+android/librpc/xdr_float.c
+android/librpc/xdr_intXX_t.c
+android/librpc/xdr_mem.c
+android/librpc/xdr_rec.c
+android/librpc/xdr_reference.c
+android/librpc/xdr_stdio.c
diff --git a/android/librpc/auth_none.c b/android/librpc/auth_none.c
new file mode 100644
index 0000000..c48bbfe
--- a/dev/null
+++ b/android/librpc/auth_none.c
@@ -0,0 +1,137 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+/*
+ * auth_none.c
+ * Creates a client authentication handle for passing "null"
+ * credentials and verifiers to remote systems.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+#include "rpc_private.h"
+
+
+#define MAX_MARSHAL_SIZE 20
+
+/*
+ * Authenticator operations routines
+ */
+static void authnone_verf (AUTH *);
+static void authnone_destroy (AUTH *);
+static bool_t authnone_marshal (AUTH *, XDR *);
+static bool_t authnone_validate (AUTH *, struct opaque_auth *);
+static bool_t authnone_refresh (AUTH *);
+
+static const struct auth_ops ops = {
+ authnone_verf,
+ authnone_marshal,
+ authnone_validate,
+ authnone_refresh,
+ authnone_destroy
+};
+
+/* Internal data and routines */
+
+struct authnone_private_s {
+ AUTH no_client;
+ char marshalled_client[MAX_MARSHAL_SIZE];
+ u_int mcnt;
+};
+#ifdef __UCLIBC_HAS_THREADS__
+#define authnone_private (*(struct authnone_private_s **)&RPC_THREAD_VARIABLE(authnone_private_s))
+#else
+static struct authnone_private_s *authnone_private;
+#endif
+
+AUTH *
+authnone_create (void)
+{
+ struct authnone_private_s *ap;
+ XDR xdr_stream;
+ XDR *xdrs;
+
+ ap = (struct authnone_private_s *) authnone_private;
+ if (ap == NULL)
+ {
+ ap = (struct authnone_private_s *) calloc (1, sizeof (*ap));
+ if (ap == NULL)
+ return NULL;
+ authnone_private = ap;
+ }
+ if (!ap->mcnt)
+ {
+ ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth;
+ ap->no_client.ah_ops = (struct auth_ops *)&ops;
+ xdrs = &xdr_stream;
+ xdrmem_create (xdrs, ap->marshalled_client, (u_int) MAX_MARSHAL_SIZE,
+ XDR_ENCODE);
+ (void) xdr_opaque_auth (xdrs, &ap->no_client.ah_cred);
+ (void) xdr_opaque_auth (xdrs, &ap->no_client.ah_verf);
+ ap->mcnt = XDR_GETPOS (xdrs);
+ XDR_DESTROY (xdrs);
+ }
+ return (&ap->no_client);
+}
+libc_hidden_def(authnone_create)
+
+static bool_t
+authnone_marshal (AUTH *client attribute_unused, XDR *xdrs)
+{
+ struct authnone_private_s *ap;
+
+ ap = authnone_private;
+ if (ap == NULL)
+ return FALSE;
+ return (*xdrs->x_ops->x_putbytes) (xdrs, ap->marshalled_client, ap->mcnt);
+}
+
+static void
+authnone_verf (AUTH *auth attribute_unused)
+{
+}
+
+static bool_t
+authnone_validate (AUTH *auth attribute_unused, struct opaque_auth *oa attribute_unused)
+{
+ return TRUE;
+}
+
+static bool_t
+authnone_refresh (AUTH *auth attribute_unused)
+{
+ return FALSE;
+}
+
+static void
+authnone_destroy (AUTH *auth attribute_unused)
+{
+}
diff --git a/android/librpc/auth_unix.c b/android/librpc/auth_unix.c
new file mode 100644
index 0000000..1337214
--- a/dev/null
+++ b/android/librpc/auth_unix.c
@@ -0,0 +1,336 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+/*
+ * auth_unix.c, Implements UNIX style authentication parameters.
+ *
+ * The system is very weak. The client uses no encryption for it's
+ * credentials and only sends null verifiers. The server sends backs
+ * null verifiers or optionally a verifier that suggests a new short hand
+ * for the credentials.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+/*
+ * Unix authenticator operations vector
+ */
+static void authunix_nextverf (AUTH *);
+static bool_t authunix_marshal (AUTH *, XDR *);
+static bool_t authunix_validate (AUTH *, struct opaque_auth *);
+static bool_t authunix_refresh (AUTH *);
+static void authunix_destroy (AUTH *);
+
+static struct auth_ops auth_unix_ops = {
+ authunix_nextverf,
+ authunix_marshal,
+ authunix_validate,
+ authunix_refresh,
+ authunix_destroy
+};
+
+/*
+ * This struct is pointed to by the ah_private field of an auth_handle.
+ */
+struct audata {
+ struct opaque_auth au_origcred; /* original credentials */
+ struct opaque_auth au_shcred; /* short hand cred */
+ u_long au_shfaults; /* short hand cache faults */
+ char au_marshed[MAX_AUTH_BYTES];
+ u_int au_mpos; /* xdr pos at end of marshed */
+};
+#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private)
+
+static bool_t marshal_new_auth (AUTH *) internal_function;
+
+
+/*
+ * Create a unix style authenticator.
+ * Returns an auth handle with the given stuff in it.
+ */
+AUTH *
+authunix_create (char *machname, uid_t uid, gid_t gid, int len,
+ gid_t *aup_gids)
+{
+ struct authunix_parms aup;
+ char mymem[MAX_AUTH_BYTES];
+ struct timeval now;
+ XDR xdrs;
+ AUTH *auth;
+ struct audata *au;
+
+ /*
+ * Allocate and set up auth handle
+ */
+ auth = (AUTH *) mem_alloc (sizeof (*auth));
+ au = (struct audata *) mem_alloc (sizeof (*au));
+ if (auth == NULL || au == NULL)
+ {
+no_memory:
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s",
+ _("authunix_create: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("authunix_create: out of memory\n"), stderr);
+ mem_free (auth, sizeof (*auth));
+ mem_free (au, sizeof (*au));
+ return NULL;
+ }
+ auth->ah_ops = &auth_unix_ops;
+ auth->ah_private = (caddr_t) au;
+ auth->ah_verf = au->au_shcred = _null_auth;
+ au->au_shfaults = 0;
+
+ /*
+ * fill in param struct from the given params
+ */
+ (void) gettimeofday (&now, (struct timezone *) 0);
+ aup.aup_time = now.tv_sec;
+ aup.aup_machname = machname;
+ aup.aup_uid = uid;
+ aup.aup_gid = gid;
+ aup.aup_len = (u_int) len;
+ aup.aup_gids = aup_gids;
+
+ /*
+ * Serialize the parameters into origcred
+ */
+ xdrmem_create (&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
+ if (!xdr_authunix_parms (&xdrs, &aup))
+ abort ();
+ au->au_origcred.oa_length = len = XDR_GETPOS (&xdrs);
+ au->au_origcred.oa_flavor = AUTH_UNIX;
+ au->au_origcred.oa_base = mem_alloc ((u_int) len);
+ if (au->au_origcred.oa_base == NULL)
+ goto no_memory;
+ memcpy(au->au_origcred.oa_base, mymem, (u_int) len);
+
+ /*
+ * set auth handle to reflect new cred.
+ */
+ auth->ah_cred = au->au_origcred;
+ marshal_new_auth (auth);
+ return auth;
+}
+libc_hidden_def(authunix_create)
+
+/*
+ * Returns an auth handle with parameters determined by doing lots of
+ * syscalls.
+ */
+AUTH *
+authunix_create_default (void)
+{
+ int len;
+ char machname[MAX_MACHINE_NAME + 1];
+ uid_t uid;
+ gid_t gid;
+ int max_nr_groups = sysconf (_SC_NGROUPS_MAX);
+ gid_t *gids = NULL;
+ AUTH *ret_auth;
+
+ if (max_nr_groups) {
+ gids = (gid_t*)malloc(sizeof(*gids) * max_nr_groups);
+ if (gids == NULL)
+ abort ();
+ }
+
+ if (gethostname (machname, MAX_MACHINE_NAME) == -1)
+ abort ();
+ machname[MAX_MACHINE_NAME] = 0;
+ uid = geteuid ();
+ gid = getegid ();
+
+ if ((len = getgroups (max_nr_groups, gids)) < 0)
+ abort ();
+ /* This braindamaged Sun code forces us here to truncate the
+ list of groups to NGRPS members since the code in
+ authuxprot.c transforms a fixed array. Grrr. */
+ ret_auth = authunix_create (machname, uid, gid, MIN (NGRPS, len), gids);
+ free (gids);
+ return ret_auth;
+}
+libc_hidden_def(authunix_create_default)
+
+/*
+ * authunix operations
+ */
+
+static void
+authunix_nextverf (AUTH *auth attribute_unused)
+{
+ /* no action necessary */
+}
+
+static bool_t
+authunix_marshal (AUTH *auth, XDR *xdrs)
+{
+ struct audata *au = AUTH_PRIVATE (auth);
+
+ return XDR_PUTBYTES (xdrs, au->au_marshed, au->au_mpos);
+}
+
+static bool_t
+authunix_validate (AUTH *auth, struct opaque_auth *verf)
+{
+ struct audata *au;
+ XDR xdrs;
+
+ if (verf->oa_flavor == AUTH_SHORT)
+ {
+ au = AUTH_PRIVATE (auth);
+ xdrmem_create (&xdrs, verf->oa_base, verf->oa_length,
+ XDR_DECODE);
+
+ if (au->au_shcred.oa_base != NULL)
+ {
+ mem_free (au->au_shcred.oa_base,
+ au->au_shcred.oa_length);
+ au->au_shcred.oa_base = NULL;
+ }
+ if (xdr_opaque_auth (&xdrs, &au->au_shcred))
+ {
+ auth->ah_cred = au->au_shcred;
+ }
+ else
+ {
+ xdrs.x_op = XDR_FREE;
+ (void) xdr_opaque_auth (&xdrs, &au->au_shcred);
+ au->au_shcred.oa_base = NULL;
+ auth->ah_cred = au->au_origcred;
+ }
+ marshal_new_auth (auth);
+ }
+ return TRUE;
+}
+
+static bool_t
+authunix_refresh (AUTH *auth)
+{
+ struct audata *au = AUTH_PRIVATE (auth);
+ struct authunix_parms aup;
+ struct timeval now;
+ XDR xdrs;
+ int stat;
+
+ if (auth->ah_cred.oa_base == au->au_origcred.oa_base)
+ {
+ /* there is no hope. Punt */
+ return FALSE;
+ }
+ au->au_shfaults++;
+
+ /* first deserialize the creds back into a struct authunix_parms */
+ aup.aup_machname = NULL;
+ aup.aup_gids = (gid_t *) NULL;
+ xdrmem_create (&xdrs, au->au_origcred.oa_base,
+ au->au_origcred.oa_length, XDR_DECODE);
+ stat = xdr_authunix_parms (&xdrs, &aup);
+ if (!stat)
+ goto done;
+
+ /* update the time and serialize in place */
+ (void) gettimeofday (&now, (struct timezone *) 0);
+ aup.aup_time = now.tv_sec;
+ xdrs.x_op = XDR_ENCODE;
+ XDR_SETPOS (&xdrs, 0);
+ stat = xdr_authunix_parms (&xdrs, &aup);
+ if (!stat)
+ goto done;
+ auth->ah_cred = au->au_origcred;
+ marshal_new_auth (auth);
+done:
+ /* free the struct authunix_parms created by deserializing */
+ xdrs.x_op = XDR_FREE;
+ (void) xdr_authunix_parms (&xdrs, &aup);
+ XDR_DESTROY (&xdrs);
+ return stat;
+}
+
+static void
+authunix_destroy (AUTH *auth)
+{
+ struct audata *au = AUTH_PRIVATE (auth);
+
+ mem_free (au->au_origcred.oa_base, au->au_origcred.oa_length);
+
+ if (au->au_shcred.oa_base != NULL)
+ mem_free (au->au_shcred.oa_base, au->au_shcred.oa_length);
+
+ mem_free (auth->ah_private, sizeof (struct audata));
+
+ if (auth->ah_verf.oa_base != NULL)
+ mem_free (auth->ah_verf.oa_base, auth->ah_verf.oa_length);
+
+ mem_free ((caddr_t) auth, sizeof (*auth));
+}
+
+/*
+ * Marshals (pre-serializes) an auth struct.
+ * sets private data, au_marshed and au_mpos
+ */
+static bool_t
+internal_function
+marshal_new_auth (AUTH *auth)
+{
+ XDR xdr_stream;
+ XDR *xdrs = &xdr_stream;
+ struct audata *au = AUTH_PRIVATE (auth);
+
+ xdrmem_create (xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
+ if ((!xdr_opaque_auth (xdrs, &(auth->ah_cred))) ||
+ (!xdr_opaque_auth (xdrs, &(auth->ah_verf))))
+ perror (_("auth_none.c - Fatal marshalling problem"));
+ else
+ au->au_mpos = XDR_GETPOS (xdrs);
+
+ XDR_DESTROY (xdrs);
+
+ return TRUE;
+}
diff --git a/android/librpc/authunix_prot.c b/android/librpc/authunix_prot.c
new file mode 100644
index 0000000..2729900
--- a/dev/null
+++ b/android/librpc/authunix_prot.c
@@ -0,0 +1,67 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+/*
+ * authunix_prot.c
+ * XDR for UNIX style authentication parameters for RPC
+ */
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_unix.h>
+
+
+/*
+ * XDR for unix authentication parameters.
+ * Unfortunately, none of these can be declared const.
+ */
+bool_t
+xdr_authunix_parms (XDR * xdrs, struct authunix_parms *p)
+{
+ if (xdr_u_long (xdrs, &(p->aup_time))
+ && xdr_string (xdrs, &(p->aup_machname), MAX_MACHINE_NAME)
+ && (sizeof (uid_t) == sizeof (short int)
+ ? xdr_u_short (xdrs, (u_short *) & (p->aup_uid))
+ : xdr_u_int (xdrs, (u_int *) & (p->aup_uid)))
+ && (sizeof (gid_t) == sizeof (short int)
+ ? xdr_u_short (xdrs, (u_short *) & (p->aup_gid))
+ : xdr_u_int (xdrs, (u_int *) & (p->aup_gid)))
+ && xdr_array (xdrs, (caddr_t *) & (p->aup_gids),
+ & (p->aup_len), NGRPS, sizeof (gid_t),
+ (sizeof (gid_t) == sizeof (short int)
+ ? (xdrproc_t) xdr_u_short : (xdrproc_t) xdr_u_int)))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_authunix_parms)
diff --git a/android/librpc/bindresvport.c b/android/librpc/bindresvport.c
new file mode 100644
index 0000000..0181612
--- a/dev/null
+++ b/android/librpc/bindresvport.c
@@ -0,0 +1,95 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (c) 1987 by Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef ANDROID
+#include <rpc/types.h>
+extern long __set_errno(int n);
+#else
+#include <sys/types.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport (int sd, struct sockaddr_in *sin)
+{
+ int res;
+ static short port;
+ struct sockaddr_in myaddr;
+ int i;
+
+#define STARTPORT 600
+#define ENDPORT (IPPORT_RESERVED - 1)
+#define NPORTS (ENDPORT - STARTPORT + 1)
+
+ if (sin == (struct sockaddr_in *) 0)
+ {
+ sin = &myaddr;
+ memset (sin, 0, sizeof (*sin));
+ sin->sin_family = AF_INET;
+ }
+ else if (sin->sin_family != AF_INET)
+ {
+ __set_errno (EPFNOSUPPORT);
+ return -1;
+ }
+
+ if (port == 0)
+ {
+ port = (getpid () % NPORTS) + STARTPORT;
+ }
+ res = -1;
+ __set_errno (EADDRINUSE);
+
+ for (i = 0; i < NPORTS && res < 0 && errno == EADDRINUSE; ++i)
+ {
+ sin->sin_port = htons (port);
+ if (++port > ENDPORT)
+ {
+ port = STARTPORT;
+ }
+ res = bind(sd, (struct sockaddr *)sin, sizeof(struct sockaddr_in));
+ }
+
+ return res;
+}
+libc_hidden_def(bindresvport)
diff --git a/android/librpc/clnt_generic.c b/android/librpc/clnt_generic.c
new file mode 100644
index 0000000..274cd01
--- a/dev/null
+++ b/android/librpc/clnt_generic.c
@@ -0,0 +1,215 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <alloca.h>
+#include <errno.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#ifdef ANDROID
+int getprotobyname_r(
+ const char *name,
+ struct protoent *result_buf,
+ char *buf, size_t buflen,
+ struct protoent **result
+) {
+ char *official_name, *alias_name;
+ int protonum;
+
+ if (strcasecmp(name, "udp")) {
+ official_name = "udp";
+ alias_name = "UDP";
+ protonum = 17;
+ } else if (strcasecmp(name, "tcp")) {
+ official_name = "tcp";
+ alias_name = "TCP";
+ protonum = 6;
+ } else {
+ return errno = ENOENT;
+ }
+ if (buflen < sizeof("udp") + sizeof("UDP")
+ + 2*sizeof(result_buf->p_aliases[0]))
+ return ERANGE;
+ memcpy(buf, official_name, sizeof("udp"));
+ memcpy(buf + sizeof("udp"), alias_name, sizeof("UDP"));
+ result_buf->p_name = buf;
+ result_buf->p_aliases = (char **) (buf + sizeof("udp") + sizeof("UDP"));
+ result_buf->p_aliases[0] = buf + sizeof("udp");
+ result_buf->p_aliases[1] = 0;
+ result_buf->p_proto = protonum;
+ if (result)
+ *result = result_buf;
+ return 0;
+}
+#endif
+
+/*
+ * Generic client creation: takes (hostname, program-number, protocol) and
+ * returns client handle. Default options are set, which the user can
+ * change using the rpc equivalent of ioctl()'s.
+ */
+CLIENT *
+clnt_create (const char *hostname, u_long prog, u_long vers,
+ const char *proto)
+{
+ struct hostent hostbuf, *h;
+ size_t hstbuflen;
+ char *hsttmpbuf;
+ struct protoent protobuf, *p;
+ size_t prtbuflen;
+ char *prttmpbuf;
+ struct sockaddr_in sin;
+ struct sockaddr_un sun;
+ int sock;
+ struct timeval tv;
+ CLIENT *client;
+ int herr;
+
+ if (strcmp (proto, "unix") == 0)
+ {
+ memset ((char *)&sun, 0, sizeof (sun));
+ sun.sun_family = AF_UNIX;
+ strcpy (sun.sun_path, hostname);
+ sock = RPC_ANYSOCK;
+ client = clntunix_create (&sun, prog, vers, &sock, 0, 0);
+ if (client == NULL)
+ return NULL;
+#if 0
+ /* This is not wanted. This would disable the user from having
+ a timeout in the clnt_call() call. Only a call to cnlt_control()
+ by the user should set the timeout value. */
+ tv.tv_sec = 25;
+ tv.tv_usec = 0;
+ clnt_control (client, CLSET_TIMEOUT, (char *)&tv);
+#endif
+ return client;
+ }
+
+ hstbuflen = 1024;
+ hsttmpbuf = alloca (hstbuflen);
+ while (gethostbyname_r (hostname, &hostbuf, hsttmpbuf, hstbuflen,
+ &h, &herr) != 0
+ || h == NULL)
+ if (herr != NETDB_INTERNAL || errno != ERANGE)
+ {
+ get_rpc_createerr().cf_stat = RPC_UNKNOWNHOST;
+ return NULL;
+ }
+ else
+ {
+ /* Enlarge the buffer. */
+ hstbuflen *= 2;
+ hsttmpbuf = alloca (hstbuflen);
+ }
+
+ if (h->h_addrtype != AF_INET)
+ {
+ /*
+ * Only support INET for now
+ */
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = EAFNOSUPPORT;
+ return NULL;
+ }
+ sin.sin_family = h->h_addrtype;
+ sin.sin_port = 0;
+ memset (sin.sin_zero, 0, sizeof (sin.sin_zero));
+ memcpy ((char *) &sin.sin_addr, h->h_addr, h->h_length);
+
+ prtbuflen = 1024;
+ prttmpbuf = alloca (prtbuflen);
+ while (getprotobyname_r (proto, &protobuf, prttmpbuf, prtbuflen, &p) != 0
+ || p == NULL)
+ if (errno != ERANGE)
+ {
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+ ce->cf_stat = RPC_UNKNOWNPROTO;
+ ce->cf_error.re_errno = EPFNOSUPPORT;
+ return NULL;
+ }
+ else
+ {
+ /* Enlarge the buffer. */
+ prtbuflen *= 2;
+ prttmpbuf = alloca (prtbuflen);
+ }
+
+ sock = RPC_ANYSOCK;
+ switch (p->p_proto)
+ {
+ case IPPROTO_UDP:
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ client = clntudp_create (&sin, prog, vers, tv, &sock);
+ if (client == NULL)
+ {
+ return NULL;
+ }
+#if 0
+ /* This is not wanted. This would disable the user from having
+ a timeout in the clnt_call() call. Only a call to cnlt_control()
+ by the user should set the timeout value. */
+ tv.tv_sec = 25;
+ clnt_control (client, CLSET_TIMEOUT, (char *)&tv);
+#endif
+ break;
+ case IPPROTO_TCP:
+ client = clnttcp_create (&sin, prog, vers, &sock, 0, 0);
+ if (client == NULL)
+ {
+ return NULL;
+ }
+#if 0
+ /* This is not wanted. This would disable the user from having
+ a timeout in the clnt_call() call. Only a call to cnlt_control()
+ by the user should set the timeout value. */
+ tv.tv_sec = 25;
+ tv.tv_usec = 0;
+ clnt_control (client, CLSET_TIMEOUT, (char *)&tv);
+#endif
+ break;
+ default:
+ {
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = EPFNOSUPPORT;
+ }
+ return (NULL);
+ }
+ return client;
+}
diff --git a/android/librpc/clnt_perror.c b/android/librpc/clnt_perror.c
new file mode 100644
index 0000000..8dbae72
--- a/dev/null
+++ b/android/librpc/clnt_perror.c
@@ -0,0 +1,435 @@
+/* @(#)clnt_perror.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_perror.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <string.h>
+#include "rpc_private.h"
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+# include <libio/iolibio.h>
+# define fputs(s, f) _IO_fputs (s, f)
+#endif
+
+static char *auth_errmsg (enum auth_stat stat) internal_function;
+
+#ifdef __UCLIBC_HAS_THREADS__
+/*
+ * Making buf a preprocessor macro requires renaming the local
+ * buf variable in a few functions. Overriding a global variable
+ * with a local variable of the same name is a bad idea, anyway.
+ */
+#define buf (*(char **)&RPC_THREAD_VARIABLE(clnt_perr_buf_s))
+#else
+static char *buf;
+#endif
+
+static char *
+_buf (void)
+{
+ if (buf == NULL)
+ buf = (char *) malloc (256);
+ return buf;
+}
+
+struct rpc_errtab
+{
+ enum clnt_stat status;
+ unsigned int message_off;
+};
+
+static const char rpc_errstr[] =
+{
+#define RPC_SUCCESS_IDX 0
+ _("RPC: Success")
+ "\0"
+#define RPC_CANTENCODEARGS_IDX (RPC_SUCCESS_IDX + sizeof "RPC: Success")
+ _("RPC: Can't encode arguments")
+ "\0"
+#define RPC_CANTDECODERES_IDX (RPC_CANTENCODEARGS_IDX \
+ + sizeof "RPC: Can't encode arguments")
+ _("RPC: Can't decode result")
+ "\0"
+#define RPC_CANTSEND_IDX (RPC_CANTDECODERES_IDX \
+ + sizeof "RPC: Can't decode result")
+ _("RPC: Unable to send")
+ "\0"
+#define RPC_CANTRECV_IDX (RPC_CANTSEND_IDX \
+ + sizeof "RPC: Unable to send")
+ _("RPC: Unable to receive")
+ "\0"
+#define RPC_TIMEDOUT_IDX (RPC_CANTRECV_IDX \
+ + sizeof "RPC: Unable to receive")
+ _("RPC: Timed out")
+ "\0"
+#define RPC_VERSMISMATCH_IDX (RPC_TIMEDOUT_IDX \
+ + sizeof "RPC: Timed out")
+ _("RPC: Incompatible versions of RPC")
+ "\0"
+#define RPC_AUTHERROR_IDX (RPC_VERSMISMATCH_IDX \
+ + sizeof "RPC: Incompatible versions of RPC")
+ _("RPC: Authentication error")
+ "\0"
+#define RPC_PROGUNAVAIL_IDX (RPC_AUTHERROR_IDX \
+ + sizeof "RPC: Authentication error")
+ _("RPC: Program unavailable")
+ "\0"
+#define RPC_PROGVERSMISMATCH_IDX (RPC_PROGUNAVAIL_IDX \
+ + sizeof "RPC: Program unavailable")
+ _("RPC: Program/version mismatch")
+ "\0"
+#define RPC_PROCUNAVAIL_IDX (RPC_PROGVERSMISMATCH_IDX \
+ + sizeof "RPC: Program/version mismatch")
+ _("RPC: Procedure unavailable")
+ "\0"
+#define RPC_CANTDECODEARGS_IDX (RPC_PROCUNAVAIL_IDX \
+ + sizeof "RPC: Procedure unavailable")
+ _("RPC: Server can't decode arguments")
+ "\0"
+#define RPC_SYSTEMERROR_IDX (RPC_CANTDECODEARGS_IDX \
+ + sizeof "RPC: Server can't decode arguments")
+ _("RPC: Remote system error")
+ "\0"
+#define RPC_UNKNOWNHOST_IDX (RPC_SYSTEMERROR_IDX \
+ + sizeof "RPC: Remote system error")
+ _("RPC: Unknown host")
+ "\0"
+#define RPC_UNKNOWNPROTO_IDX (RPC_UNKNOWNHOST_IDX \
+ + sizeof "RPC: Unknown host")
+ _("RPC: Unknown protocol")
+ "\0"
+#define RPC_PMAPFAILURE_IDX (RPC_UNKNOWNPROTO_IDX \
+ + sizeof "RPC: Unknown protocol")
+ _("RPC: Port mapper failure")
+ "\0"
+#define RPC_PROGNOTREGISTERED_IDX (RPC_PMAPFAILURE_IDX \
+ + sizeof "RPC: Port mapper failure")
+ _("RPC: Program not registered")
+ "\0"
+#define RPC_FAILED_IDX (RPC_PROGNOTREGISTERED_IDX \
+ + sizeof "RPC: Program not registered")
+ _("RPC: Failed (unspecified error)")
+};
+
+static const struct rpc_errtab rpc_errlist[] =
+{
+ { RPC_SUCCESS, RPC_SUCCESS_IDX },
+ { RPC_CANTENCODEARGS, RPC_CANTENCODEARGS_IDX },
+ { RPC_CANTDECODERES, RPC_CANTDECODERES_IDX },
+ { RPC_CANTSEND, RPC_CANTSEND_IDX },
+ { RPC_CANTRECV, RPC_CANTRECV_IDX },
+ { RPC_TIMEDOUT, RPC_TIMEDOUT_IDX },
+ { RPC_VERSMISMATCH, RPC_VERSMISMATCH_IDX },
+ { RPC_AUTHERROR, RPC_AUTHERROR_IDX },
+ { RPC_PROGUNAVAIL, RPC_PROGUNAVAIL_IDX },
+ { RPC_PROGVERSMISMATCH, RPC_PROGVERSMISMATCH_IDX },
+ { RPC_PROCUNAVAIL, RPC_PROCUNAVAIL_IDX },
+ { RPC_CANTDECODEARGS, RPC_CANTDECODEARGS_IDX },
+ { RPC_SYSTEMERROR, RPC_SYSTEMERROR_IDX },
+ { RPC_UNKNOWNHOST, RPC_UNKNOWNHOST_IDX },
+ { RPC_UNKNOWNPROTO, RPC_UNKNOWNPROTO_IDX },
+ { RPC_PMAPFAILURE, RPC_PMAPFAILURE_IDX },
+ { RPC_PROGNOTREGISTERED, RPC_PROGNOTREGISTERED_IDX },
+ { RPC_FAILED, RPC_FAILED_IDX }
+};
+
+
+/*
+ * This interface for use by clntrpc
+ */
+char *
+clnt_sperrno (enum clnt_stat stat)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof (rpc_errlist) / sizeof (struct rpc_errtab); i++)
+ {
+ if (rpc_errlist[i].status == stat)
+ {
+ return (char*)_(rpc_errstr + rpc_errlist[i].message_off);
+ }
+ }
+ return _("RPC: (unknown error code)");
+}
+libc_hidden_def(clnt_sperrno)
+
+void
+clnt_perrno (enum clnt_stat num)
+{
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s", clnt_sperrno (num));
+ else
+#endif
+ (void) fputs (clnt_sperrno (num), stderr);
+}
+
+/*
+ * Print reply error info
+ */
+char *
+clnt_sperror (CLIENT * rpch, const char *msg)
+{
+ char chrbuf[1024];
+ struct rpc_err e;
+ char *err;
+ char *str = _buf ();
+ char *strstart = str;
+ int len;
+
+ if (str == NULL)
+ return NULL;
+ CLNT_GETERR (rpch, &e);
+
+ len = sprintf (str, "%s: ", msg);
+ str += len;
+
+ (void) strcpy(str, clnt_sperrno(e.re_status));
+ str += strlen(str);
+
+ switch (e.re_status)
+ {
+ case RPC_SUCCESS:
+ case RPC_CANTENCODEARGS:
+ case RPC_CANTDECODERES:
+ case RPC_TIMEDOUT:
+ case RPC_PROGUNAVAIL:
+ case RPC_PROCUNAVAIL:
+ case RPC_CANTDECODEARGS:
+ case RPC_SYSTEMERROR:
+ case RPC_UNKNOWNHOST:
+ case RPC_UNKNOWNPROTO:
+ case RPC_PMAPFAILURE:
+ case RPC_PROGNOTREGISTERED:
+ case RPC_FAILED:
+ break;
+
+ case RPC_CANTSEND:
+ case RPC_CANTRECV:
+ __glibc_strerror_r (e.re_errno, chrbuf, sizeof chrbuf);
+ len = sprintf (str, "; errno = %s", chrbuf);
+ str += len;
+ break;
+
+ case RPC_VERSMISMATCH:
+ len= sprintf (str, _("; low version = %lu, high version = %lu"),
+ e.re_vers.low, e.re_vers.high);
+ str += len;
+ break;
+
+ case RPC_AUTHERROR:
+ err = auth_errmsg (e.re_why);
+ (void) strcpy(str, _("; why = "));
+ str += strlen(str);
+
+ if (err != NULL)
+ {
+ (void) strcpy(str, err);
+ str += strlen(str);
+ }
+ else
+ {
+ len = sprintf (str, _("(unknown authentication error - %d)"),
+ (int) e.re_why);
+ str += len;
+ }
+ break;
+
+ case RPC_PROGVERSMISMATCH:
+ len = sprintf (str, _("; low version = %lu, high version = %lu"),
+ e.re_vers.low, e.re_vers.high);
+ str += len;
+ break;
+
+ default: /* unknown */
+ len = sprintf (str, "; s1 = %lu, s2 = %lu", e.re_lb.s1, e.re_lb.s2);
+ str += len;
+ break;
+ }
+ *str = '\n';
+ *++str = '\0';
+ return (strstart);
+}
+libc_hidden_def(clnt_sperror)
+
+void
+clnt_perror (CLIENT * rpch, const char *msg)
+{
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s", clnt_sperror (rpch, msg));
+ else
+#endif
+ (void) fputs (clnt_sperror (rpch, msg), stderr);
+}
+libc_hidden_def(clnt_perror)
+
+char *
+clnt_spcreateerror (const char *msg)
+{
+ char chrbuf[1024];
+ char *str = _buf ();
+ char *cp;
+ int len;
+ struct rpc_createerr *ce;
+
+ if (str == NULL)
+ return NULL;
+ ce = &get_rpc_createerr ();
+ len = sprintf (str, "%s: ", msg);
+ cp = str + len;
+ (void) strcpy(cp, clnt_sperrno (ce->cf_stat));
+ cp += strlen(cp);
+
+ switch (ce->cf_stat)
+ {
+ case RPC_PMAPFAILURE:
+ (void) strcpy(cp, " - ");
+ cp += strlen(cp);
+
+ (void) strcpy(cp, clnt_sperrno (ce->cf_error.re_status));
+ cp += strlen(cp);
+
+ break;
+
+ case RPC_SYSTEMERROR:
+ (void) strcpy(cp, " - ");
+ cp += strlen(cp);
+
+ __glibc_strerror_r (ce->cf_error.re_errno, chrbuf, sizeof chrbuf);
+ (void) strcpy(cp, chrbuf);
+ cp += strlen(cp);
+ break;
+ default:
+ break;
+ }
+ *cp = '\n';
+ *++cp = '\0';
+ return str;
+}
+libc_hidden_def(clnt_spcreateerror)
+
+void
+clnt_pcreateerror (const char *msg)
+{
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s", clnt_spcreateerror (msg));
+ else
+#endif
+ (void) fputs (clnt_spcreateerror (msg), stderr);
+}
+
+struct auth_errtab
+{
+ enum auth_stat status;
+ unsigned int message_off;
+};
+
+static const char auth_errstr[] =
+{
+#define AUTH_OK_IDX 0
+ _("Authentication OK")
+ "\0"
+#define AUTH_BADCRED_IDX (AUTH_OK_IDX + sizeof "Authentication OK")
+ _("Invalid client credential")
+ "\0"
+#define AUTH_REJECTEDCRED_IDX (AUTH_BADCRED_IDX \
+ + sizeof "Invalid client credential")
+ _("Server rejected credential")
+ "\0"
+#define AUTH_BADVERF_IDX (AUTH_REJECTEDCRED_IDX \
+ + sizeof "Server rejected credential")
+ _("Invalid client verifier")
+ "\0"
+#define AUTH_REJECTEDVERF_IDX (AUTH_BADVERF_IDX \
+ + sizeof "Invalid client verifier")
+ _("Server rejected verifier")
+ "\0"
+#define AUTH_TOOWEAK_IDX (AUTH_REJECTEDVERF_IDX \
+ + sizeof "Server rejected verifier")
+ _("Client credential too weak")
+ "\0"
+#define AUTH_INVALIDRESP_IDX (AUTH_TOOWEAK_IDX \
+ + sizeof "Client credential too weak")
+ _("Invalid server verifier")
+ "\0"
+#define AUTH_FAILED_IDX (AUTH_INVALIDRESP_IDX \
+ + sizeof "Invalid server verifier")
+ _("Failed (unspecified error)")
+};
+
+static const struct auth_errtab auth_errlist[] =
+{
+ { AUTH_OK, AUTH_OK_IDX },
+ { AUTH_BADCRED, AUTH_BADCRED_IDX },
+ { AUTH_REJECTEDCRED, AUTH_REJECTEDCRED_IDX },
+ { AUTH_BADVERF, AUTH_BADVERF_IDX },
+ { AUTH_REJECTEDVERF, AUTH_REJECTEDVERF_IDX },
+ { AUTH_TOOWEAK, AUTH_TOOWEAK_IDX },
+ { AUTH_INVALIDRESP, AUTH_INVALIDRESP_IDX },
+ { AUTH_FAILED, AUTH_FAILED_IDX }
+};
+
+static char *
+internal_function
+auth_errmsg (enum auth_stat stat)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof (auth_errlist) / sizeof (struct auth_errtab); i++)
+ {
+ if (auth_errlist[i].status == stat)
+ {
+ return (char*)_(auth_errstr + auth_errlist[i].message_off);
+ }
+ }
+ return NULL;
+}
+
+
+static void __attribute_used__
+free_mem (void)
+{
+ free (buf);
+}
diff --git a/android/librpc/clnt_raw.c b/android/librpc/clnt_raw.c
new file mode 100644
index 0000000..75dd982
--- a/dev/null
+++ b/android/librpc/clnt_raw.c
@@ -0,0 +1,248 @@
+/* @(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_raw.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * Memory based rpc for simple testing and timing.
+ * Interface to create an rpc client and server in the same process.
+ * This lets us simulate rpc and get round trip overhead, without
+ * any interference from the kernel.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+#include "rpc_private.h"
+#include <rpc/svc.h>
+#include <rpc/xdr.h>
+
+
+#define MCALL_MSG_SIZE 24
+
+/*
+ * This is the "network" we will be moving stuff over.
+ */
+struct clntraw_private_s
+ {
+ CLIENT client_object;
+ XDR xdr_stream;
+ char _raw_buf[UDPMSGSIZE];
+ char mashl_callmsg[MCALL_MSG_SIZE];
+ u_int mcnt;
+ };
+#ifdef __UCLIBC_HAS_THREADS__
+#define clntraw_private (*(struct clntraw_private_s **)&RPC_THREAD_VARIABLE(clntraw_private_s))
+#else
+static struct clntraw_private_s *clntraw_private;
+#endif
+
+static enum clnt_stat clntraw_call (CLIENT *, u_long, xdrproc_t, caddr_t,
+ xdrproc_t, caddr_t, struct timeval);
+static void clntraw_abort (void);
+static void clntraw_geterr (CLIENT *, struct rpc_err *);
+static bool_t clntraw_freeres (CLIENT *, xdrproc_t, caddr_t);
+static bool_t clntraw_control (CLIENT *, int, char *);
+static void clntraw_destroy (CLIENT *);
+
+static const struct clnt_ops client_ops =
+{
+ clntraw_call,
+ clntraw_abort,
+ clntraw_geterr,
+ clntraw_freeres,
+ clntraw_destroy,
+ clntraw_control
+};
+
+/*
+ * Create a client handle for memory based rpc.
+ */
+CLIENT *
+clntraw_create (u_long prog, u_long vers)
+{
+ struct clntraw_private_s *clp = clntraw_private;
+ struct rpc_msg call_msg;
+ XDR *xdrs = &clp->xdr_stream;
+ CLIENT *client = &clp->client_object;
+
+ if (clp == 0)
+ {
+ clp = (struct clntraw_private_s *) calloc (1, sizeof (*clp));
+ if (clp == 0)
+ return (0);
+ clntraw_private = clp;
+ }
+ /*
+ * pre-serialize the static part of the call msg and stash it away
+ */
+ call_msg.rm_direction = CALL;
+ call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ call_msg.rm_call.cb_prog = prog;
+ call_msg.rm_call.cb_vers = vers;
+ xdrmem_create (xdrs, clp->mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE);
+ if (!xdr_callhdr (xdrs, &call_msg))
+ {
+ perror (_ ("clnt_raw.c - Fatal header serialization error."));
+ }
+ clp->mcnt = XDR_GETPOS (xdrs);
+ XDR_DESTROY (xdrs);
+
+ /*
+ * Set xdrmem for client/server shared buffer
+ */
+ xdrmem_create (xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE);
+
+ /*
+ * create client handle
+ */
+ client->cl_ops = &client_ops;
+ client->cl_auth = authnone_create ();
+ return client;
+}
+
+static enum clnt_stat
+clntraw_call (CLIENT *h, u_long proc, xdrproc_t xargs, caddr_t argsp,
+ xdrproc_t xresults, caddr_t resultsp,
+ struct timeval timeout attribute_unused)
+{
+ struct clntraw_private_s *clp = clntraw_private;
+ XDR *xdrs = &clp->xdr_stream;
+ struct rpc_msg msg;
+ enum clnt_stat status;
+ struct rpc_err error;
+
+ if (clp == NULL)
+ return RPC_FAILED;
+call_again:
+ /*
+ * send request
+ */
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS (xdrs, 0);
+ ((struct rpc_msg *) clp->mashl_callmsg)->rm_xid++;
+ if ((!XDR_PUTBYTES (xdrs, clp->mashl_callmsg, clp->mcnt)) ||
+ (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
+ (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
+ (!(*xargs) (xdrs, argsp)))
+ {
+ return (RPC_CANTENCODEARGS);
+ }
+ (void) XDR_GETPOS (xdrs); /* called just to cause overhead */
+
+ /*
+ * We have to call server input routine here because this is
+ * all going on in one process. Yuk.
+ */
+ svc_getreq (1);
+
+ /*
+ * get results
+ */
+ xdrs->x_op = XDR_DECODE;
+ XDR_SETPOS (xdrs, 0);
+ msg.acpted_rply.ar_verf = _null_auth;
+ msg.acpted_rply.ar_results.where = resultsp;
+ msg.acpted_rply.ar_results.proc = xresults;
+ if (!xdr_replymsg (xdrs, &msg))
+ return RPC_CANTDECODERES;
+ _seterr_reply (&msg, &error);
+ status = error.re_status;
+
+ if (status == RPC_SUCCESS)
+ {
+ if (!AUTH_VALIDATE (h->cl_auth, &msg.acpted_rply.ar_verf))
+ {
+ status = RPC_AUTHERROR;
+ }
+ } /* end successful completion */
+ else
+ {
+ if (AUTH_REFRESH (h->cl_auth))
+ goto call_again;
+ } /* end of unsuccessful completion */
+
+ if (status == RPC_SUCCESS)
+ {
+ if (!AUTH_VALIDATE (h->cl_auth, &msg.acpted_rply.ar_verf))
+ {
+ status = RPC_AUTHERROR;
+ }
+ if (msg.acpted_rply.ar_verf.oa_base != NULL)
+ {
+ xdrs->x_op = XDR_FREE;
+ (void) xdr_opaque_auth (xdrs, &(msg.acpted_rply.ar_verf));
+ }
+ }
+
+ return status;
+}
+
+static void
+clntraw_geterr (CLIENT *cl attribute_unused, struct rpc_err *err attribute_unused)
+{
+}
+
+
+static bool_t
+clntraw_freeres (CLIENT *cl attribute_unused, xdrproc_t xdr_res, caddr_t res_ptr)
+{
+ struct clntraw_private_s *clp = clntraw_private;
+ XDR *xdrs = &clp->xdr_stream;
+ bool_t rval;
+
+ if (clp == NULL)
+ {
+ rval = (bool_t) RPC_FAILED;
+ return rval;
+ }
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_res) (xdrs, res_ptr);
+}
+
+static void
+clntraw_abort (void)
+{
+}
+
+static bool_t
+clntraw_control (CLIENT *cl attribute_unused, int i attribute_unused, char *c attribute_unused)
+{
+ return FALSE;
+}
+
+static void
+clntraw_destroy (CLIENT *cl attribute_unused)
+{
+}
diff --git a/android/librpc/clnt_simple.c b/android/librpc/clnt_simple.c
new file mode 100644
index 0000000..f66228a
--- a/dev/null
+++ b/android/librpc/clnt_simple.c
@@ -0,0 +1,164 @@
+/* @(#)clnt_simple.c 2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_simple.c
+ * Simplified front end to rpc.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <alloca.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "rpc_private.h"
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+
+
+struct callrpc_private_s
+ {
+ CLIENT *client;
+ int socket;
+ u_long oldprognum, oldversnum, valid;
+ char *oldhost;
+ };
+#ifdef __UCLIBC_HAS_THREADS__
+#define callrpc_private (*(struct callrpc_private_s **)&RPC_THREAD_VARIABLE(callrpc_private_s))
+#else
+static struct callrpc_private_s *callrpc_private;
+#endif
+
+int
+callrpc (const char *host, u_long prognum, u_long versnum, u_long procnum,
+ xdrproc_t inproc, const char *in, xdrproc_t outproc, char *out)
+{
+ struct callrpc_private_s *crp = callrpc_private;
+ struct sockaddr_in server_addr;
+ enum clnt_stat clnt_stat;
+ struct hostent hostbuf, *hp;
+ struct timeval timeout, tottimeout;
+
+ if (crp == 0)
+ {
+ crp = (struct callrpc_private_s *) calloc (1, sizeof (*crp));
+ if (crp == 0)
+ return 0;
+ callrpc_private = crp;
+ }
+ if (crp->oldhost == NULL)
+ {
+ crp->oldhost = malloc (256);
+ crp->oldhost[0] = 0;
+ crp->socket = RPC_ANYSOCK;
+ }
+ if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum
+ && strcmp (crp->oldhost, host) == 0)
+ {
+ /* reuse old client */
+ }
+ else
+ {
+ size_t buflen;
+ char *buffer;
+ int herr;
+
+ crp->valid = 0;
+ if (crp->socket != RPC_ANYSOCK)
+ {
+ (void) close (crp->socket);
+ crp->socket = RPC_ANYSOCK;
+ }
+ if (crp->client)
+ {
+ clnt_destroy (crp->client);
+ crp->client = NULL;
+ }
+
+ buflen = 1024;
+ buffer = alloca (buflen);
+ while (gethostbyname_r (host, &hostbuf, buffer, buflen,
+ &hp, &herr) != 0
+ || hp == NULL)
+ if (herr != NETDB_INTERNAL || errno != ERANGE)
+ return (int) RPC_UNKNOWNHOST;
+ else
+ {
+ /* Enlarge the buffer. */
+ buflen *= 2;
+ buffer = alloca (buflen);
+ }
+
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 5;
+ memcpy ((char *) &server_addr.sin_addr, hp->h_addr, hp->h_length);
+ server_addr.sin_family = AF_INET;
+ server_addr.sin_port = 0;
+ if ((crp->client = clntudp_create (&server_addr, (u_long) prognum,
+ (u_long) versnum, timeout, &crp->socket)) == NULL)
+ return (int) get_rpc_createerr().cf_stat;
+ crp->valid = 1;
+ crp->oldprognum = prognum;
+ crp->oldversnum = versnum;
+ (void) strncpy (crp->oldhost, host, 255);
+ crp->oldhost[255] = '\0';
+ }
+ tottimeout.tv_sec = 25;
+ tottimeout.tv_usec = 0;
+ clnt_stat = clnt_call (crp->client, procnum, inproc, (char *) in,
+ outproc, out, tottimeout);
+ /*
+ * if call failed, empty cache
+ */
+ if (clnt_stat != RPC_SUCCESS)
+ crp->valid = 0;
+ return (int) clnt_stat;
+}
+
+#ifdef __UCLIBC_HAS_THREADS__
+void attribute_hidden __rpc_thread_clnt_cleanup (void)
+{
+ struct callrpc_private_s *rcp = RPC_THREAD_VARIABLE(callrpc_private_s);
+
+ if (rcp) {
+ if (rcp->client)
+ CLNT_DESTROY (rcp->client);
+ free (rcp);
+ }
+}
+#endif /* __UCLIBC_HAS_THREADS__ */
diff --git a/android/librpc/clnt_tcp.c b/android/librpc/clnt_tcp.c
new file mode 100644
index 0000000..d8d7bb3
--- a/dev/null
+++ b/android/librpc/clnt_tcp.c
@@ -0,0 +1,532 @@
+/* @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * TCP based RPC supports 'batched calls'.
+ * A sequence of calls may be batched-up in a send buffer. The rpc call
+ * return immediately to the client even though the call was not necessarily
+ * sent. The batching occurs if the results' xdr routine is NULL (0) AND
+ * the rpc timeout value is zero (see clnt.h, rpc).
+ *
+ * Clients should NOT casually batch calls that in fact return results; that is,
+ * the server side should be aware that a call is batched and not produce any
+ * return message. Batched calls that produce many result messages can
+ * deadlock (netlock) the client and the server....
+ *
+ * Now go hang yourself.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <rpc/pmap_clnt.h>
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+extern u_long _create_xid (void) attribute_hidden;
+
+#define MCALL_MSG_SIZE 24
+
+struct ct_data
+ {
+ int ct_sock;
+ bool_t ct_closeit;
+ struct timeval ct_wait;
+ bool_t ct_waitset; /* wait set by clnt_control? */
+ struct sockaddr_in ct_addr;
+ struct rpc_err ct_error;
+ char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
+ u_int ct_mpos; /* pos after marshal */
+ XDR ct_xdrs;
+ };
+
+static int readtcp (char *, char *, int);
+static int writetcp (char *, char *, int);
+
+static enum clnt_stat clnttcp_call (CLIENT *, u_long, xdrproc_t, caddr_t,
+ xdrproc_t, caddr_t, struct timeval);
+static void clnttcp_abort (void);
+static void clnttcp_geterr (CLIENT *, struct rpc_err *);
+static bool_t clnttcp_freeres (CLIENT *, xdrproc_t, caddr_t);
+static bool_t clnttcp_control (CLIENT *, int, char *);
+static void clnttcp_destroy (CLIENT *);
+
+static const struct clnt_ops tcp_ops =
+{
+ clnttcp_call,
+ clnttcp_abort,
+ clnttcp_geterr,
+ clnttcp_freeres,
+ clnttcp_destroy,
+ clnttcp_control
+};
+
+/*
+ * Create a client handle for a tcp/ip connection.
+ * If *sockp<0, *sockp is set to a newly created TCP socket and it is
+ * connected to raddr. If *sockp non-negative then
+ * raddr is ignored. The rpc/tcp package does buffering
+ * similar to stdio, so the client must pick send and receive buffer sizes,];
+ * 0 => use the default.
+ * If raddr->sin_port is 0, then a binder on the remote machine is
+ * consulted for the right port number.
+ * NB: *sockp is copied into a private area.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
+ * something more useful.
+ */
+CLIENT *
+clnttcp_create (struct sockaddr_in *raddr, u_long prog, u_long vers,
+ int *sockp, u_int sendsz, u_int recvsz)
+{
+ CLIENT *h;
+ struct ct_data *ct;
+ struct rpc_msg call_msg;
+
+ h = (CLIENT *) mem_alloc (sizeof (*h));
+ ct = (struct ct_data *) mem_alloc (sizeof (*ct));
+ if (h == NULL || ct == NULL)
+ {
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s",
+ _("clnttcp_create: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("clnttcp_create: out of memory\n"), stderr);
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = ENOMEM;
+ goto fooy;
+ }
+
+ /*
+ * If no port number given ask the pmap for one
+ */
+ if (raddr->sin_port == 0)
+ {
+ u_short port;
+ if ((port = pmap_getport (raddr, prog, vers, IPPROTO_TCP)) == 0)
+ {
+ mem_free ((caddr_t) ct, sizeof (struct ct_data));
+ mem_free ((caddr_t) h, sizeof (CLIENT));
+ return ((CLIENT *) NULL);
+ }
+ raddr->sin_port = htons (port);
+ }
+
+ /*
+ * If no socket given, open one
+ */
+ if (*sockp < 0)
+ {
+ *sockp = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
+ if ((*sockp < 0)
+ || (connect (*sockp, (struct sockaddr *) raddr,
+ sizeof (*raddr)) < 0))
+ {
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = errno;
+ if (*sockp >= 0)
+ (void) close (*sockp);
+ goto fooy;
+ }
+ ct->ct_closeit = TRUE;
+ }
+ else
+ {
+ ct->ct_closeit = FALSE;
+ }
+
+ /*
+ * Set up private data struct
+ */
+ ct->ct_sock = *sockp;
+ ct->ct_wait.tv_usec = 0;
+ ct->ct_waitset = FALSE;
+ ct->ct_addr = *raddr;
+
+ /*
+ * Initialize call message
+ */
+ call_msg.rm_xid = _create_xid ();
+ call_msg.rm_direction = CALL;
+ call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ call_msg.rm_call.cb_prog = prog;
+ call_msg.rm_call.cb_vers = vers;
+
+ /*
+ * pre-serialize the static part of the call msg and stash it away
+ */
+ xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
+ XDR_ENCODE);
+ if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
+ {
+ if (ct->ct_closeit)
+ {
+ (void) close (*sockp);
+ }
+ goto fooy;
+ }
+ ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
+ XDR_DESTROY (&(ct->ct_xdrs));
+
+ /*
+ * Create a client handle which uses xdrrec for serialization
+ * and authnone for authentication.
+ */
+ xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
+ (caddr_t) ct, readtcp, writetcp);
+ h->cl_ops = &tcp_ops;
+ h->cl_private = (caddr_t) ct;
+ h->cl_auth = authnone_create ();
+ return h;
+
+fooy:
+ /*
+ * Something goofed, free stuff and barf
+ */
+ mem_free ((caddr_t) ct, sizeof (struct ct_data));
+ mem_free ((caddr_t) h, sizeof (CLIENT));
+ return ((CLIENT *) NULL);
+}
+libc_hidden_def(clnttcp_create)
+
+static enum clnt_stat
+clnttcp_call (CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr,
+ xdrproc_t xdr_results, caddr_t results_ptr,
+ struct timeval timeout)
+{
+ struct ct_data *ct = (struct ct_data *) h->cl_private;
+ XDR *xdrs = &(ct->ct_xdrs);
+ struct rpc_msg reply_msg;
+ u_long x_id;
+ u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
+ bool_t shipnow;
+ int refreshes = 2;
+
+ if (!ct->ct_waitset)
+ {
+ ct->ct_wait = timeout;
+ }
+
+ shipnow =
+ (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
+ && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
+
+call_again:
+ xdrs->x_op = XDR_ENCODE;
+ ct->ct_error.re_status = RPC_SUCCESS;
+ x_id = ntohl (--(*msg_x_id));
+ if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
+ (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
+ (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
+ (!(*xdr_args) (xdrs, args_ptr)))
+ {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status = RPC_CANTENCODEARGS;
+ (void) xdrrec_endofrecord (xdrs, TRUE);
+ return (ct->ct_error.re_status);
+ }
+ if (!xdrrec_endofrecord (xdrs, shipnow))
+ return ct->ct_error.re_status = RPC_CANTSEND;
+ if (!shipnow)
+ return RPC_SUCCESS;
+ /*
+ * Hack to provide rpc-based message passing
+ */
+ if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
+ {
+ return ct->ct_error.re_status = RPC_TIMEDOUT;
+ }
+
+
+ /*
+ * Keep receiving until we get a valid transaction id
+ */
+ xdrs->x_op = XDR_DECODE;
+ while (TRUE)
+ {
+ reply_msg.acpted_rply.ar_verf = _null_auth;
+ reply_msg.acpted_rply.ar_results.where = NULL;
+ reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+ if (!xdrrec_skiprecord (xdrs))
+ return (ct->ct_error.re_status);
+ /* now decode and validate the response header */
+ if (!xdr_replymsg (xdrs, &reply_msg))
+ {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ continue;
+ return ct->ct_error.re_status;
+ }
+ if ((u_int32_t) reply_msg.rm_xid == (u_int32_t) x_id)
+ break;
+ }
+
+ /*
+ * process header
+ */
+ _seterr_reply (&reply_msg, &(ct->ct_error));
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ {
+ if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
+ {
+ ct->ct_error.re_status = RPC_AUTHERROR;
+ ct->ct_error.re_why = AUTH_INVALIDRESP;
+ }
+ else if (!(*xdr_results) (xdrs, results_ptr))
+ {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status = RPC_CANTDECODERES;
+ }
+ /* free verifier ... */
+ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
+ {
+ xdrs->x_op = XDR_FREE;
+ (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
+ }
+ } /* end successful completion */
+ else
+ {
+ /* maybe our credentials need to be refreshed ... */
+ if (refreshes-- && AUTH_REFRESH (h->cl_auth))
+ goto call_again;
+ } /* end of unsuccessful completion */
+ return ct->ct_error.re_status;
+}
+
+static void
+clnttcp_geterr (CLIENT *h, struct rpc_err *errp)
+{
+ struct ct_data *ct =
+ (struct ct_data *) h->cl_private;
+
+ *errp = ct->ct_error;
+}
+
+static bool_t
+clnttcp_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
+{
+ struct ct_data *ct = (struct ct_data *) cl->cl_private;
+ XDR *xdrs = &(ct->ct_xdrs);
+
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_res) (xdrs, res_ptr);
+}
+
+static void
+clnttcp_abort (void)
+{
+}
+
+static bool_t
+clnttcp_control (CLIENT *cl, int request, char *info)
+{
+ struct ct_data *ct = (struct ct_data *) cl->cl_private;
+
+
+ switch (request)
+ {
+ case CLSET_FD_CLOSE:
+ ct->ct_closeit = TRUE;
+ break;
+ case CLSET_FD_NCLOSE:
+ ct->ct_closeit = FALSE;
+ break;
+ case CLSET_TIMEOUT:
+ ct->ct_wait = *(struct timeval *) info;
+ ct->ct_waitset = TRUE;
+ break;
+ case CLGET_TIMEOUT:
+ *(struct timeval *) info = ct->ct_wait;
+ break;
+ case CLGET_SERVER_ADDR:
+ *(struct sockaddr_in *) info = ct->ct_addr;
+ break;
+ case CLGET_FD:
+ *(int *)info = ct->ct_sock;
+ break;
+ case CLGET_XID:
+ /*
+ * use the knowledge that xid is the
+ * first element in the call structure *.
+ * This will get the xid of the PREVIOUS call
+ */
+ *(u_long *)info = ntohl (*(u_long *)ct->ct_mcall);
+ break;
+ case CLSET_XID:
+ /* This will set the xid of the NEXT call */
+ *(u_long *)ct->ct_mcall = htonl (*(u_long *)info - 1);
+ /* decrement by 1 as clnttcp_call() increments once */
+ break;
+ case CLGET_VERS:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the version number field is the fifth field from the
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_long *)info = ntohl (*(u_long *)(ct->ct_mcall +
+ 4 * BYTES_PER_XDR_UNIT));
+ break;
+ case CLSET_VERS:
+ *(u_long *)(ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
+ = htonl (*(u_long *)info);
+ break;
+ case CLGET_PROG:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the program number field is the field from the
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall +
+ 3 * BYTES_PER_XDR_UNIT));
+ break;
+ case CLSET_PROG:
+ *(u_long *)(ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
+ = htonl(*(u_long *)info);
+ break;
+ /* The following are only possible with TI-RPC */
+ case CLGET_RETRY_TIMEOUT:
+ case CLSET_RETRY_TIMEOUT:
+ case CLGET_SVC_ADDR:
+ case CLSET_SVC_ADDR:
+ case CLSET_PUSH_TIMOD:
+ case CLSET_POP_TIMOD:
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static void
+clnttcp_destroy (CLIENT *h)
+{
+ struct ct_data *ct =
+ (struct ct_data *) h->cl_private;
+
+ if (ct->ct_closeit)
+ {
+ (void) close (ct->ct_sock);
+ }
+ XDR_DESTROY (&(ct->ct_xdrs));
+ mem_free ((caddr_t) ct, sizeof (struct ct_data));
+ mem_free ((caddr_t) h, sizeof (CLIENT));
+}
+
+/*
+ * Interface between xdr serializer and tcp connection.
+ * Behaves like the system calls, read & write, but keeps some error state
+ * around for the rpc level.
+ */
+static int
+readtcp (char *ctptr, char *buf, int len)
+{
+ struct ct_data *ct = (struct ct_data *)ctptr;
+ struct pollfd fd;
+ int milliseconds = (ct->ct_wait.tv_sec * 1000) +
+ (ct->ct_wait.tv_usec / 1000);
+
+ if (len == 0)
+ return 0;
+
+ fd.fd = ct->ct_sock;
+ fd.events = POLLIN;
+ while (TRUE)
+ {
+ switch (poll(&fd, 1, milliseconds))
+ {
+ case 0:
+ ct->ct_error.re_status = RPC_TIMEDOUT;
+ return -1;
+
+ case -1:
+ if (errno == EINTR)
+ continue;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ ct->ct_error.re_errno = errno;
+ return -1;
+ }
+ break;
+ }
+ switch (len = read (ct->ct_sock, buf, len))
+ {
+
+ case 0:
+ /* premature eof */
+ ct->ct_error.re_errno = ECONNRESET;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ len = -1; /* it's really an error */
+ break;
+
+ case -1:
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ break;
+ }
+ return len;
+}
+
+static int
+writetcp (char *ctptr, char *buf, int len)
+{
+ int i, cnt;
+ struct ct_data *ct = (struct ct_data*)ctptr;
+
+ for (cnt = len; cnt > 0; cnt -= i, buf += i)
+ {
+ if ((i = write (ct->ct_sock, buf, cnt)) == -1)
+ {
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTSEND;
+ return -1;
+ }
+ }
+ return len;
+}
diff --git a/android/librpc/clnt_udp.c b/android/librpc/clnt_udp.c
new file mode 100644
index 0000000..71ffa55
--- a/dev/null
+++ b/android/librpc/clnt_udp.c
@@ -0,0 +1,612 @@
+/* @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * clnt_udp.c, Implements a UDP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpc/clnt.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <errno.h>
+#include <rpc/pmap_clnt.h>
+#include <net/if.h>
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+#ifdef IP_RECVERR
+#include "errqueue.h"
+#include <sys/uio.h>
+#endif
+
+/* CMSG_NXTHDR is using it */
+
+
+extern u_long _create_xid (void) attribute_hidden;
+
+/*
+ * UDP bases client side rpc operations
+ */
+static enum clnt_stat clntudp_call (CLIENT *, u_long, xdrproc_t, caddr_t,
+ xdrproc_t, caddr_t, struct timeval);
+static void clntudp_abort (void);
+static void clntudp_geterr (CLIENT *, struct rpc_err *);
+static bool_t clntudp_freeres (CLIENT *, xdrproc_t, caddr_t);
+static bool_t clntudp_control (CLIENT *, int, char *);
+static void clntudp_destroy (CLIENT *);
+
+static const struct clnt_ops udp_ops =
+{
+ clntudp_call,
+ clntudp_abort,
+ clntudp_geterr,
+ clntudp_freeres,
+ clntudp_destroy,
+ clntudp_control
+};
+
+/*
+ * Private data kept per client handle
+ */
+struct cu_data
+ {
+ int cu_sock;
+ bool_t cu_closeit;
+ struct sockaddr_in cu_raddr;
+ int cu_rlen;
+ struct timeval cu_wait;
+ struct timeval cu_total;
+ struct rpc_err cu_error;
+ XDR cu_outxdrs;
+ u_int cu_xdrpos;
+ u_int cu_sendsz;
+ char *cu_outbuf;
+ u_int cu_recvsz;
+ char cu_inbuf[1];
+ };
+
+/*
+ * Create a UDP based client handle.
+ * If *sockp<0, *sockp is set to a newly created UPD socket.
+ * If raddr->sin_port is 0 a binder on the remote machine
+ * is consulted for the correct port number.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is initialized to null authentication.
+ * Caller may wish to set this something more useful.
+ *
+ * wait is the amount of time used between retransmitting a call if
+ * no response has been heard; retransmission occurs until the actual
+ * rpc call times out.
+ *
+ * sendsz and recvsz are the maximum allowable packet sizes that can be
+ * sent and received.
+ */
+CLIENT *
+clntudp_bufcreate (struct sockaddr_in *raddr, u_long program, u_long version,
+ struct timeval wait, int *sockp, u_int sendsz,
+ u_int recvsz)
+{
+ CLIENT *cl;
+ struct cu_data *cu = NULL;
+ struct rpc_msg call_msg;
+
+ cl = (CLIENT *) mem_alloc (sizeof (CLIENT));
+ sendsz = ((sendsz + 3) / 4) * 4;
+ recvsz = ((recvsz + 3) / 4) * 4;
+ cu = (struct cu_data *) mem_alloc (sizeof (*cu) + sendsz + recvsz);
+ if (cl == NULL || cu == NULL)
+ {
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s",
+ _("clntudp_create: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("clntudp_create: out of memory\n"), stderr);
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = ENOMEM;
+ goto fooy;
+ }
+ cu->cu_outbuf = &cu->cu_inbuf[recvsz];
+
+ if (raddr->sin_port == 0)
+ {
+ u_short port;
+ if ((port =
+ pmap_getport (raddr, program, version, IPPROTO_UDP)) == 0)
+ {
+ goto fooy;
+ }
+ raddr->sin_port = htons (port);
+ }
+ cl->cl_ops = &udp_ops;
+ cl->cl_private = (caddr_t) cu;
+ cu->cu_raddr = *raddr;
+ cu->cu_rlen = sizeof (cu->cu_raddr);
+ cu->cu_wait = wait;
+ cu->cu_total.tv_sec = -1;
+ cu->cu_total.tv_usec = -1;
+ cu->cu_sendsz = sendsz;
+ cu->cu_recvsz = recvsz;
+ call_msg.rm_xid = _create_xid ();
+ call_msg.rm_direction = CALL;
+ call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ call_msg.rm_call.cb_prog = program;
+ call_msg.rm_call.cb_vers = version;
+ xdrmem_create (&(cu->cu_outxdrs), cu->cu_outbuf,
+ sendsz, XDR_ENCODE);
+ if (!xdr_callhdr (&(cu->cu_outxdrs), &call_msg))
+ {
+ goto fooy;
+ }
+ cu->cu_xdrpos = XDR_GETPOS (&(cu->cu_outxdrs));
+ if (*sockp < 0)
+ {
+ int dontblock = 1;
+
+ *sockp = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (*sockp < 0)
+ {
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = errno;
+ goto fooy;
+ }
+ /* attempt to bind to prov port */
+ (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
+ /* the sockets rpc controls are non-blocking */
+ (void) ioctl (*sockp, FIONBIO, (char *) &dontblock);
+#ifdef IP_RECVERR
+ {
+ int on = 1;
+ setsockopt(*sockp, SOL_IP, IP_RECVERR, &on, sizeof(on));
+ }
+#endif
+ cu->cu_closeit = TRUE;
+ }
+ else
+ {
+ cu->cu_closeit = FALSE;
+ }
+ cu->cu_sock = *sockp;
+ cl->cl_auth = authnone_create ();
+ return cl;
+fooy:
+ if (cu)
+ mem_free ((caddr_t) cu, sizeof (*cu) + sendsz + recvsz);
+ if (cl)
+ mem_free ((caddr_t) cl, sizeof (CLIENT));
+ return (CLIENT *) NULL;
+}
+libc_hidden_def(clntudp_bufcreate)
+
+CLIENT *
+clntudp_create (struct sockaddr_in *raddr, u_long program, u_long version, struct timeval wait, int *sockp)
+{
+
+ return clntudp_bufcreate (raddr, program, version, wait, sockp,
+ UDPMSGSIZE, UDPMSGSIZE);
+}
+libc_hidden_def(clntudp_create)
+
+static int
+is_network_up (int sock)
+{
+ struct ifconf ifc;
+ char buf[UDPMSGSIZE];
+ struct ifreq ifreq, *ifr;
+ int n;
+
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) == 0)
+ {
+ ifr = ifc.ifc_req;
+ for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++)
+ {
+ ifreq = *ifr;
+ if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0)
+ break;
+
+ if ((ifreq.ifr_flags & IFF_UP)
+ && ifr->ifr_addr.sa_family == AF_INET)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static enum clnt_stat
+clntudp_call (
+ CLIENT *cl, /* client handle */
+ u_long proc, /* procedure number */
+ xdrproc_t xargs, /* xdr routine for args */
+ caddr_t argsp, /* pointer to args */
+ xdrproc_t xresults, /* xdr routine for results */
+ caddr_t resultsp, /* pointer to results */
+ struct timeval utimeout /* seconds to wait before giving up */)
+{
+ struct cu_data *cu = (struct cu_data *) cl->cl_private;
+ XDR *xdrs;
+ int outlen = 0;
+ int inlen;
+ socklen_t fromlen;
+ struct pollfd fd;
+ int milliseconds = (cu->cu_wait.tv_sec * 1000) +
+ (cu->cu_wait.tv_usec / 1000);
+ struct sockaddr_in from;
+ struct rpc_msg reply_msg;
+ XDR reply_xdrs;
+ struct timeval time_waited;
+ bool_t ok;
+ int nrefreshes = 2; /* number of times to refresh cred */
+ struct timeval timeout;
+ int anyup; /* any network interface up */
+
+ if (cu->cu_total.tv_usec == -1)
+ {
+ timeout = utimeout; /* use supplied timeout */
+ }
+ else
+ {
+ timeout = cu->cu_total; /* use default timeout */
+ }
+
+ time_waited.tv_sec = 0;
+ time_waited.tv_usec = 0;
+call_again:
+ xdrs = &(cu->cu_outxdrs);
+ if (xargs == NULL)
+ goto get_reply;
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS (xdrs, cu->cu_xdrpos);
+ /*
+ * the transaction is the first thing in the out buffer
+ */
+ (*(uint32_t *) (cu->cu_outbuf))++;
+ if ((!XDR_PUTLONG (xdrs, (long *) &proc)) ||
+ (!AUTH_MARSHALL (cl->cl_auth, xdrs)) ||
+ (!(*xargs) (xdrs, argsp)))
+ return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
+ outlen = (int) XDR_GETPOS (xdrs);
+
+send_again:
+ if (sendto (cu->cu_sock, cu->cu_outbuf, outlen, 0,
+ (struct sockaddr *) &(cu->cu_raddr), cu->cu_rlen)
+ != outlen)
+ {
+ cu->cu_error.re_errno = errno;
+ return (cu->cu_error.re_status = RPC_CANTSEND);
+ }
+
+ /*
+ * Hack to provide rpc-based message passing
+ */
+ if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
+ {
+ return (cu->cu_error.re_status = RPC_TIMEDOUT);
+ }
+ get_reply:
+ /*
+ * sub-optimal code appears here because we have
+ * some clock time to spare while the packets are in flight.
+ * (We assume that this is actually only executed once.)
+ */
+ reply_msg.acpted_rply.ar_verf = _null_auth;
+ reply_msg.acpted_rply.ar_results.where = resultsp;
+ reply_msg.acpted_rply.ar_results.proc = xresults;
+ fd.fd = cu->cu_sock;
+ fd.events = POLLIN;
+ anyup = 0;
+ for (;;)
+ {
+ switch (poll (&fd, 1, milliseconds))
+ {
+
+ case 0:
+ if (anyup == 0)
+ {
+ anyup = is_network_up (cu->cu_sock);
+ if (!anyup)
+ return (cu->cu_error.re_status = RPC_CANTRECV);
+ }
+
+ time_waited.tv_sec += cu->cu_wait.tv_sec;
+ time_waited.tv_usec += cu->cu_wait.tv_usec;
+ while (time_waited.tv_usec >= 1000000)
+ {
+ time_waited.tv_sec++;
+ time_waited.tv_usec -= 1000000;
+ }
+ if ((time_waited.tv_sec < timeout.tv_sec) ||
+ ((time_waited.tv_sec == timeout.tv_sec) &&
+ (time_waited.tv_usec < timeout.tv_usec)))
+ goto send_again;
+ return (cu->cu_error.re_status = RPC_TIMEDOUT);
+
+ /*
+ * buggy in other cases because time_waited is not being
+ * updated.
+ */
+ case -1:
+ if (errno == EINTR)
+ continue;
+ cu->cu_error.re_errno = errno;
+ return (cu->cu_error.re_status = RPC_CANTRECV);
+ }
+#ifdef IP_RECVERR
+ if (fd.revents & POLLERR)
+ {
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct sock_extended_err *e;
+ struct sockaddr_in err_addr;
+ struct iovec iov;
+ char *cbuf = (char *) alloca (outlen + 256);
+ int ret;
+
+ iov.iov_base = cbuf + 256;
+ iov.iov_len = outlen;
+ msg.msg_name = (void *) &err_addr;
+ msg.msg_namelen = sizeof (err_addr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ msg.msg_control = cbuf;
+ msg.msg_controllen = 256;
+ ret = recvmsg (cu->cu_sock, &msg, MSG_ERRQUEUE);
+ if (ret >= 0
+ && memcmp (cbuf + 256, cu->cu_outbuf, ret) == 0
+ && (msg.msg_flags & MSG_ERRQUEUE)
+ && ((msg.msg_namelen == 0
+ && ret >= 12)
+ || (msg.msg_namelen == sizeof (err_addr)
+ && err_addr.sin_family == AF_INET
+ && memcmp (&err_addr.sin_addr, &cu->cu_raddr.sin_addr,
+ sizeof (err_addr.sin_addr)) == 0
+ && err_addr.sin_port == cu->cu_raddr.sin_port)))
+ for (cmsg = CMSG_FIRSTHDR (&msg); cmsg;
+ cmsg = CMSG_NXTHDR (&msg, cmsg))
+ if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
+ {
+ e = (struct sock_extended_err *) CMSG_DATA(cmsg);
+ cu->cu_error.re_errno = e->ee_errno;
+ return (cu->cu_error.re_status = RPC_CANTRECV);
+ }
+ }
+#endif
+ do
+ {
+ fromlen = sizeof (struct sockaddr);
+ inlen = recvfrom (cu->cu_sock, cu->cu_inbuf,
+ (int) cu->cu_recvsz, 0,
+ (struct sockaddr *) &from, &fromlen);
+ }
+ while (inlen < 0 && errno == EINTR);
+ if (inlen < 0)
+ {
+ if (errno == EWOULDBLOCK)
+ continue;
+ cu->cu_error.re_errno = errno;
+ return (cu->cu_error.re_status = RPC_CANTRECV);
+ }
+ if (inlen < 4)
+ continue;
+
+ /* see if reply transaction id matches sent id.
+ Don't do this if we only wait for a replay */
+ if (xargs != NULL
+ && (*((u_int32_t *) (cu->cu_inbuf))
+ != *((u_int32_t *) (cu->cu_outbuf))))
+ continue;
+ /* we now assume we have the proper reply */
+ break;
+ }
+
+ /*
+ * now decode and validate the response
+ */
+ xdrmem_create (&reply_xdrs, cu->cu_inbuf, (u_int) inlen, XDR_DECODE);
+ ok = xdr_replymsg (&reply_xdrs, &reply_msg);
+ /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
+ if (ok)
+ {
+ _seterr_reply (&reply_msg, &(cu->cu_error));
+ if (cu->cu_error.re_status == RPC_SUCCESS)
+ {
+ if (!AUTH_VALIDATE (cl->cl_auth,
+ &reply_msg.acpted_rply.ar_verf))
+ {
+ cu->cu_error.re_status = RPC_AUTHERROR;
+ cu->cu_error.re_why = AUTH_INVALIDRESP;
+ }
+ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
+ {
+ xdrs->x_op = XDR_FREE;
+ (void) xdr_opaque_auth (xdrs,
+ &(reply_msg.acpted_rply.ar_verf));
+ }
+ } /* end successful completion */
+ else
+ {
+ /* maybe our credentials need to be refreshed ... */
+ if (nrefreshes > 0 && AUTH_REFRESH (cl->cl_auth))
+ {
+ nrefreshes--;
+ goto call_again;
+ }
+ } /* end of unsuccessful completion */
+ } /* end of valid reply message */
+ else
+ {
+ cu->cu_error.re_status = RPC_CANTDECODERES;
+ }
+ return cu->cu_error.re_status;
+}
+
+static void
+clntudp_geterr (CLIENT *cl, struct rpc_err *errp)
+{
+ struct cu_data *cu = (struct cu_data *) cl->cl_private;
+
+ *errp = cu->cu_error;
+}
+
+
+static bool_t
+clntudp_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
+{
+ struct cu_data *cu = (struct cu_data *) cl->cl_private;
+ XDR *xdrs = &(cu->cu_outxdrs);
+
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_res) (xdrs, res_ptr);
+}
+
+static void
+clntudp_abort (void)
+{
+}
+
+static bool_t
+clntudp_control (CLIENT *cl, int request, char *info)
+{
+ struct cu_data *cu = (struct cu_data *) cl->cl_private;
+
+ switch (request)
+ {
+ case CLSET_FD_CLOSE:
+ cu->cu_closeit = TRUE;
+ break;
+ case CLSET_FD_NCLOSE:
+ cu->cu_closeit = FALSE;
+ break;
+ case CLSET_TIMEOUT:
+ cu->cu_total = *(struct timeval *) info;
+ break;
+ case CLGET_TIMEOUT:
+ *(struct timeval *) info = cu->cu_total;
+ break;
+ case CLSET_RETRY_TIMEOUT:
+ cu->cu_wait = *(struct timeval *) info;
+ break;
+ case CLGET_RETRY_TIMEOUT:
+ *(struct timeval *) info = cu->cu_wait;
+ break;
+ case CLGET_SERVER_ADDR:
+ *(struct sockaddr_in *) info = cu->cu_raddr;
+ break;
+ case CLGET_FD:
+ *(int *)info = cu->cu_sock;
+ break;
+ case CLGET_XID:
+ /*
+ * use the knowledge that xid is the
+ * first element in the call structure *.
+ * This will get the xid of the PREVIOUS call
+ */
+ *(u_long *)info = ntohl(*(u_long *)cu->cu_outbuf);
+ break;
+ case CLSET_XID:
+ /* This will set the xid of the NEXT call */
+ *(u_long *)cu->cu_outbuf = htonl(*(u_long *)info - 1);
+ /* decrement by 1 as clntudp_call() increments once */
+ break;
+ case CLGET_VERS:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the version number field is the fifth field from the
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf +
+ 4 * BYTES_PER_XDR_UNIT));
+ break;
+ case CLSET_VERS:
+ *(u_long *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT)
+ = htonl(*(u_long *)info);
+ break;
+ case CLGET_PROG:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the program number field is the field from the
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf +
+ 3 * BYTES_PER_XDR_UNIT));
+ break;
+ case CLSET_PROG:
+ *(u_long *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT)
+ = htonl(*(u_long *)info);
+ break;
+ /* The following are only possible with TI-RPC */
+ case CLGET_SVC_ADDR:
+ case CLSET_SVC_ADDR:
+ case CLSET_PUSH_TIMOD:
+ case CLSET_POP_TIMOD:
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+clntudp_destroy (CLIENT *cl)
+{
+ struct cu_data *cu = (struct cu_data *) cl->cl_private;
+
+ if (cu->cu_closeit)
+ {
+ (void) close (cu->cu_sock);
+ }
+ XDR_DESTROY (&(cu->cu_outxdrs));
+ mem_free ((caddr_t) cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz));
+ mem_free ((caddr_t) cl, sizeof (CLIENT));
+}
diff --git a/android/librpc/clnt_unix.c b/android/librpc/clnt_unix.c
new file mode 100644
index 0000000..daebf1b
--- a/dev/null
+++ b/android/librpc/clnt_unix.c
@@ -0,0 +1,606 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * clnt_unix.c, Implements a TCP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * TCP based RPC supports 'batched calls'.
+ * A sequence of calls may be batched-up in a send buffer. The rpc call
+ * return immediately to the client even though the call was not necessarily
+ * sent. The batching occurs if the results' xdr routine is NULL (0) AND
+ * the rpc timeout value is zero (see clnt.h, rpc).
+ *
+ * Clients should NOT casually batch calls that in fact return results; that is,
+ * the server side should be aware that a call is batched and not produce any
+ * return message. Batched calls that produce many result messages can
+ * deadlock (netlock) the client and the server....
+ *
+ * Now go hang yourself.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <rpc/pmap_clnt.h>
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+
+extern u_long _create_xid (void) attribute_hidden;
+
+#define MCALL_MSG_SIZE 24
+
+struct ct_data
+ {
+ int ct_sock;
+ bool_t ct_closeit;
+ struct timeval ct_wait;
+ bool_t ct_waitset; /* wait set by clnt_control? */
+ struct sockaddr_un ct_addr;
+ struct rpc_err ct_error;
+ char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
+ u_int ct_mpos; /* pos after marshal */
+ XDR ct_xdrs;
+ };
+
+static int readunix (char *, char *, int);
+static int writeunix (char *, char *, int);
+
+static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
+ xdrproc_t, caddr_t, struct timeval);
+static void clntunix_abort (void);
+static void clntunix_geterr (CLIENT *, struct rpc_err *);
+static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
+static bool_t clntunix_control (CLIENT *, int, char *);
+static void clntunix_destroy (CLIENT *);
+
+static const struct clnt_ops unix_ops =
+{
+ clntunix_call,
+ clntunix_abort,
+ clntunix_geterr,
+ clntunix_freeres,
+ clntunix_destroy,
+ clntunix_control
+};
+
+/*
+ * Create a client handle for a tcp/ip connection.
+ * If *sockp<0, *sockp is set to a newly created TCP socket and it is
+ * connected to raddr. If *sockp non-negative then
+ * raddr is ignored. The rpc/tcp package does buffering
+ * similar to stdio, so the client must pick send and receive buffer sizes,];
+ * 0 => use the default.
+ * If raddr->sin_port is 0, then a binder on the remote machine is
+ * consulted for the right port number.
+ * NB: *sockp is copied into a private area.
+ * NB: It is the clients responsibility to close *sockp.
+ * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this
+ * something more useful.
+ */
+CLIENT *
+clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
+ int *sockp, u_int sendsz, u_int recvsz)
+{
+ CLIENT *h;
+ struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
+ struct rpc_msg call_msg;
+ int len;
+
+ h = (CLIENT *) mem_alloc (sizeof (*h));
+ if (h == NULL || ct == NULL)
+ {
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s",
+ _("clntunix_create: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("clntunix_create: out of memory\n"), stderr);
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = ENOMEM;
+ goto fooy;
+ }
+
+ /*
+ * If no socket given, open one
+ */
+ if (*sockp < 0)
+ {
+ *sockp = socket (AF_UNIX, SOCK_STREAM, 0);
+ len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
+ if (*sockp < 0
+ || connect (*sockp, (struct sockaddr *) raddr, len) < 0)
+ {
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+ ce->cf_stat = RPC_SYSTEMERROR;
+ ce->cf_error.re_errno = errno;
+ if (*sockp != -1)
+ close (*sockp);
+ goto fooy;
+ }
+ ct->ct_closeit = TRUE;
+ }
+ else
+ {
+ ct->ct_closeit = FALSE;
+ }
+
+ /*
+ * Set up private data struct
+ */
+ ct->ct_sock = *sockp;
+ ct->ct_wait.tv_usec = 0;
+ ct->ct_waitset = FALSE;
+ ct->ct_addr = *raddr;
+
+ /*
+ * Initialize call message
+ */
+ call_msg.rm_xid = _create_xid ();
+ call_msg.rm_direction = CALL;
+ call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ call_msg.rm_call.cb_prog = prog;
+ call_msg.rm_call.cb_vers = vers;
+
+ /*
+ * pre-serialize the static part of the call msg and stash it away
+ */
+ xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
+ if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
+ {
+ if (ct->ct_closeit)
+ close (*sockp);
+ goto fooy;
+ }
+ ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
+ XDR_DESTROY (&(ct->ct_xdrs));
+
+ /*
+ * Create a client handle which uses xdrrec for serialization
+ * and authnone for authentication.
+ */
+ xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
+ (caddr_t) ct, readunix, writeunix);
+ h->cl_ops = &unix_ops;
+ h->cl_private = (caddr_t) ct;
+ h->cl_auth = authnone_create ();
+ return h;
+
+fooy:
+ /*
+ * Something goofed, free stuff and barf
+ */
+ mem_free ((caddr_t) ct, sizeof (struct ct_data));
+ mem_free ((caddr_t) h, sizeof (CLIENT));
+ return (CLIENT *) NULL;
+}
+libc_hidden_def(clntunix_create)
+
+static enum clnt_stat
+clntunix_call (CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr,
+ xdrproc_t xdr_results, caddr_t results_ptr,
+ struct timeval timeout)
+{
+ struct ct_data *ct = (struct ct_data *) h->cl_private;
+ XDR *xdrs = &(ct->ct_xdrs);
+ struct rpc_msg reply_msg;
+ u_long x_id;
+ u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall); /* yuk */
+ bool_t shipnow;
+ int refreshes = 2;
+
+ if (!ct->ct_waitset)
+ {
+ ct->ct_wait = timeout;
+ }
+
+ shipnow =
+ (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
+ && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
+
+call_again:
+ xdrs->x_op = XDR_ENCODE;
+ ct->ct_error.re_status = RPC_SUCCESS;
+ x_id = ntohl (--(*msg_x_id));
+ if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
+ (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
+ (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
+ (!(*xdr_args) (xdrs, args_ptr)))
+ {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status = RPC_CANTENCODEARGS;
+ (void) xdrrec_endofrecord (xdrs, TRUE);
+ return ct->ct_error.re_status;
+ }
+ if (!xdrrec_endofrecord (xdrs, shipnow))
+ return ct->ct_error.re_status = RPC_CANTSEND;
+ if (!shipnow)
+ return RPC_SUCCESS;
+ /*
+ * Hack to provide rpc-based message passing
+ */
+ if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
+ return ct->ct_error.re_status = RPC_TIMEDOUT;
+
+
+ /*
+ * Keep receiving until we get a valid transaction id
+ */
+ xdrs->x_op = XDR_DECODE;
+ while (TRUE)
+ {
+ reply_msg.acpted_rply.ar_verf = _null_auth;
+ reply_msg.acpted_rply.ar_results.where = NULL;
+ reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+ if (!xdrrec_skiprecord (xdrs))
+ return ct->ct_error.re_status;
+ /* now decode and validate the response header */
+ if (!xdr_replymsg (xdrs, &reply_msg))
+ {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ continue;
+ return ct->ct_error.re_status;
+ }
+ if (reply_msg.rm_xid == x_id)
+ break;
+ }
+
+ /*
+ * process header
+ */
+ _seterr_reply (&reply_msg, &(ct->ct_error));
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ {
+ if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
+ {
+ ct->ct_error.re_status = RPC_AUTHERROR;
+ ct->ct_error.re_why = AUTH_INVALIDRESP;
+ }
+ else if (!(*xdr_results) (xdrs, results_ptr))
+ {
+ if (ct->ct_error.re_status == RPC_SUCCESS)
+ ct->ct_error.re_status = RPC_CANTDECODERES;
+ }
+ /* free verifier ... */
+ if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
+ {
+ xdrs->x_op = XDR_FREE;
+ (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
+ }
+ } /* end successful completion */
+ else
+ {
+ /* maybe our credentials need to be refreshed ... */
+ if (refreshes-- && AUTH_REFRESH (h->cl_auth))
+ goto call_again;
+ } /* end of unsuccessful completion */
+ return ct->ct_error.re_status;
+}
+
+static void
+clntunix_geterr (CLIENT *h, struct rpc_err *errp)
+{
+ struct ct_data *ct = (struct ct_data *) h->cl_private;
+
+ *errp = ct->ct_error;
+}
+
+static bool_t
+clntunix_freeres (CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
+{
+ struct ct_data *ct = (struct ct_data *) cl->cl_private;
+ XDR *xdrs = &(ct->ct_xdrs);
+
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_res) (xdrs, res_ptr);
+}
+
+static void
+clntunix_abort (void)
+{
+}
+
+static bool_t
+clntunix_control (CLIENT *cl, int request, char *info)
+{
+ struct ct_data *ct = (struct ct_data *) cl->cl_private;
+
+
+ switch (request)
+ {
+ case CLSET_FD_CLOSE:
+ ct->ct_closeit = TRUE;
+ break;
+ case CLSET_FD_NCLOSE:
+ ct->ct_closeit = FALSE;
+ break;
+ case CLSET_TIMEOUT:
+ ct->ct_wait = *(struct timeval *) info;
+ break;
+ case CLGET_TIMEOUT:
+ *(struct timeval *) info = ct->ct_wait;
+ break;
+ case CLGET_SERVER_ADDR:
+ *(struct sockaddr_un *) info = ct->ct_addr;
+ break;
+ case CLGET_FD:
+ *(int *)info = ct->ct_sock;
+ break;
+ case CLGET_XID:
+ /*
+ * use the knowledge that xid is the
+ * first element in the call structure *.
+ * This will get the xid of the PREVIOUS call
+ */
+ *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
+ break;
+ case CLSET_XID:
+ /* This will set the xid of the NEXT call */
+ *(u_long *) ct->ct_mcall = htonl (*(u_long *)info - 1);
+ /* decrement by 1 as clntunix_call() increments once */
+ break;
+ case CLGET_VERS:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the version number field is the fifth field from the
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
+ + 4 * BYTES_PER_XDR_UNIT));
+ break;
+ case CLSET_VERS:
+ *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
+ = htonl (*(u_long *) info);
+ break;
+ case CLGET_PROG:
+ /*
+ * This RELIES on the information that, in the call body,
+ * the program number field is the field from the
+ * begining of the RPC header. MUST be changed if the
+ * call_struct is changed
+ */
+ *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
+ + 3 * BYTES_PER_XDR_UNIT));
+ break;
+ case CLSET_PROG:
+ *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
+ = htonl(*(u_long *) info);
+ break;
+ /* The following are only possible with TI-RPC */
+ case CLGET_RETRY_TIMEOUT:
+ case CLSET_RETRY_TIMEOUT:
+ case CLGET_SVC_ADDR:
+ case CLSET_SVC_ADDR:
+ case CLSET_PUSH_TIMOD:
+ case CLSET_POP_TIMOD:
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static void
+clntunix_destroy (CLIENT *h)
+{
+ struct ct_data *ct =
+ (struct ct_data *) h->cl_private;
+
+ if (ct->ct_closeit)
+ {
+ (void) close (ct->ct_sock);
+ }
+ XDR_DESTROY (&(ct->ct_xdrs));
+ mem_free ((caddr_t) ct, sizeof (struct ct_data));
+ mem_free ((caddr_t) h, sizeof (CLIENT));
+}
+
+static int
+__msgread (int sock, void *data, size_t cnt)
+{
+ struct iovec iov;
+ struct msghdr msg;
+#ifdef SCM_CREDENTIALS
+ /*static -why??*/ char cm[CMSG_SPACE(sizeof (struct ucred))];
+#endif
+ int len;
+
+ iov.iov_base = data;
+ iov.iov_len = cnt;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+#ifdef SCM_CREDENTIALS
+ msg.msg_control = (caddr_t) &cm;
+ msg.msg_controllen = CMSG_SPACE(sizeof (struct ucred));
+#endif
+ msg.msg_flags = 0;
+
+#ifdef SO_PASSCRED
+ {
+ int on = 1;
+ if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
+ return -1;
+ }
+#endif
+
+ restart:
+ len = recvmsg (sock, &msg, 0);
+ if (len >= 0)
+ {
+ if (msg.msg_flags & MSG_CTRUNC || len == 0)
+ return 0;
+ else
+ return len;
+ }
+ if (errno == EINTR)
+ goto restart;
+ return -1;
+}
+
+static int
+__msgwrite (int sock, void *data, size_t cnt)
+{
+#ifndef SCM_CREDENTIALS
+ /* We cannot implement this reliably. */
+ __set_errno (ENOSYS);
+ return -1;
+#else
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
+ struct ucred cred;
+ int len;
+
+ /* XXX I'm not sure, if gete?id() is always correct, or if we should use
+ get?id(). But since keyserv needs geteuid(), we have no other chance.
+ It would be much better, if the kernel could pass both to the server. */
+ cred.pid = getpid ();
+ cred.uid = geteuid ();
+ cred.gid = getegid ();
+
+ memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_CREDENTIALS;
+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
+
+ iov.iov_base = data;
+ iov.iov_len = cnt;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = cmsg;
+ msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
+ msg.msg_flags = 0;
+
+ restart:
+ len = sendmsg (sock, &msg, 0);
+ if (len >= 0)
+ return len;
+ if (errno == EINTR)
+ goto restart;
+ return -1;
+
+#endif
+}
+
+
+/*
+ * Interface between xdr serializer and unix connection.
+ * Behaves like the system calls, read & write, but keeps some error state
+ * around for the rpc level.
+ */
+static int
+readunix (char *ctptr, char *buf, int len)
+{
+ struct ct_data *ct = (struct ct_data *) ctptr;
+ struct pollfd fd;
+ int milliseconds = ((ct->ct_wait.tv_sec * 1000)
+ + (ct->ct_wait.tv_usec / 1000));
+
+ if (len == 0)
+ return 0;
+
+ fd.fd = ct->ct_sock;
+ fd.events = POLLIN;
+ while (TRUE)
+ {
+ switch (poll (&fd, 1, milliseconds))
+ {
+ case 0:
+ ct->ct_error.re_status = RPC_TIMEDOUT;
+ return -1;
+
+ case -1:
+ if (errno == EINTR)
+ continue;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ ct->ct_error.re_errno = errno;
+ return -1;
+ }
+ break;
+ }
+ switch (len = __msgread (ct->ct_sock, buf, len))
+ {
+
+ case 0:
+ /* premature eof */
+ ct->ct_error.re_errno = ECONNRESET;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ len = -1; /* it's really an error */
+ break;
+
+ case -1:
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTRECV;
+ break;
+ }
+ return len;
+}
+
+static int
+writeunix (char *ctptr, char *buf, int len)
+{
+ int i, cnt;
+ struct ct_data *ct = (struct ct_data *) ctptr;
+
+ for (cnt = len; cnt > 0; cnt -= i, buf += i)
+ {
+ if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
+ {
+ ct->ct_error.re_errno = errno;
+ ct->ct_error.re_status = RPC_CANTSEND;
+ return -1;
+ }
+ }
+ return len;
+}
diff --git a/android/librpc/create_xid.c b/android/librpc/create_xid.c
new file mode 100644
index 0000000..290b05e
--- a/dev/null
+++ b/android/librpc/create_xid.c
@@ -0,0 +1,89 @@
+/* Copyright (c) 1998, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <rpc/rpc.h>
+
+#ifdef ANDROID
+
+__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
+
+static int is_initialized;
+
+u_long _create_xid (void) attribute_hidden;
+u_long _create_xid (void)
+{
+ long res;
+
+ __UCLIBC_MUTEX_LOCK(mylock);
+
+ if (!is_initialized)
+ {
+ struct timeval now;
+
+ gettimeofday (&now, (struct timezone *) 0);
+ srand48(now.tv_sec ^ now.tv_usec);
+ is_initialized = 1;
+ }
+
+ res = lrand48();
+
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+
+ return res;
+}
+
+#else
+
+/* The RPC code is not threadsafe, but new code should be threadsafe. */
+
+#include <bits/uClibc_mutex.h>
+__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
+
+static smallint is_initialized;
+static struct drand48_data __rpc_lrand48_data;
+
+u_long _create_xid (void) attribute_hidden;
+u_long _create_xid (void)
+{
+ long res;
+
+ __UCLIBC_MUTEX_LOCK(mylock);
+
+ if (!is_initialized)
+ {
+ struct timeval now;
+
+ gettimeofday (&now, (struct timezone *) 0);
+ srand48_r (now.tv_sec ^ now.tv_usec, &__rpc_lrand48_data);
+ is_initialized = 1;
+ }
+
+ lrand48_r (&__rpc_lrand48_data, &res);
+
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+
+ return res;
+}
+#endif
diff --git a/android/librpc/errqueue.h b/android/librpc/errqueue.h
new file mode 100644
index 0000000..9ed6dc6
--- a/dev/null
+++ b/android/librpc/errqueue.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Linux version. */
+
+#ifndef _BITS_ERRQUEUE_H
+#define _BITS_ERRQUEUE_H 1
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+struct sock_extended_err
+ {
+ u_int32_t ee_errno;
+ u_int8_t ee_origin;
+ u_int8_t ee_type;
+ u_int8_t ee_code;
+ u_int8_t ee_pad;
+ u_int32_t ee_info;
+ u_int32_t ee_data;
+ };
+
+#define SO_EE_ORIGIN_NONE 0
+#define SO_EE_ORIGIN_LOCAL 1
+#define SO_EE_ORIGIN_ICMP 2
+#define SO_EE_ORIGIN_ICMP6 3
+
+#define SO_EE_OFFENDER(see) \
+ ((struct sockaddr *)(((struct sock_extended_err)(see))+1))
+
+#endif /* bits/errqueue.h */
diff --git a/android/librpc/get_myaddress.c b/android/librpc/get_myaddress.c
new file mode 100644
index 0000000..ab4ac33
--- a/dev/null
+++ b/android/librpc/get_myaddress.c
@@ -0,0 +1,109 @@
+/* @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)get_myaddress.c 1.4 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * get_myaddress.c
+ *
+ * Get client's IP address via ioctl. This avoids using the yellowpages.
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <rpc/types.h>
+#include <rpc/clnt.h>
+#include <rpc/pmap_prot.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+/* Order of following two #includes reversed by roland@gnu */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+/*
+ * don't use gethostbyname, which would invoke yellow pages
+ *
+ * Avoid loopback interfaces. We return information from a loopback
+ * interface only if there are no other possible interfaces.
+ */
+void
+get_myaddress (struct sockaddr_in *addr)
+{
+ int s;
+ char buf[BUFSIZ];
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ int len, loopback = 0;
+
+ if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ perror ("get_myaddress: socket");
+ exit (1);
+ }
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+ if (ioctl (s, SIOCGIFCONF, (char *) &ifc) < 0)
+ {
+ perror (_("get_myaddress: ioctl (get interface configuration)"));
+ exit (1);
+ }
+
+ again:
+ ifr = ifc.ifc_req;
+ for (len = ifc.ifc_len; len; len -= sizeof ifreq)
+ {
+ ifreq = *ifr;
+ if (ioctl (s, SIOCGIFFLAGS, (char *) &ifreq) < 0)
+ {
+ perror ("get_myaddress: ioctl");
+ exit (1);
+ }
+ if ((ifreq.ifr_flags & IFF_UP) && (ifr->ifr_addr.sa_family == AF_INET)
+ && (!(ifreq.ifr_flags & IFF_LOOPBACK) ||
+ (loopback == 1 && (ifreq.ifr_flags & IFF_LOOPBACK))))
+ {
+ *addr = *((struct sockaddr_in *) &ifr->ifr_addr);
+ addr->sin_port = htons (PMAPPORT);
+ close (s);
+ return;
+ }
+ ifr++;
+ }
+ if (loopback == 0)
+ {
+ loopback = 1;
+ goto again;
+ }
+ close (s);
+}
diff --git a/android/librpc/getrpcent.c b/android/librpc/getrpcent.c
new file mode 100644
index 0000000..82b2e43
--- a/dev/null
+++ b/android/librpc/getrpcent.c
@@ -0,0 +1,349 @@
+/* @(#)getrpcent.c 2.2 88/07/29 4.0 RPCSRC */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+
+/*
+ * Internet version.
+ */
+static struct rpcdata {
+ FILE *rpcf;
+ char *current;
+ int currentlen;
+ int stayopen;
+#define MAXALIASES 35
+ char *rpc_aliases[MAXALIASES];
+ struct rpcent rpc;
+ char line[BUFSIZ + 1];
+ char *domain;
+} *rpcdata;
+
+static const char RPCDB[] = "/etc/rpc";
+
+static struct rpcdata *_rpcdata(void)
+{
+ register struct rpcdata *d = rpcdata;
+
+ if (d == NULL) {
+ d = (struct rpcdata *) calloc(1, sizeof(struct rpcdata));
+
+ rpcdata = d;
+ }
+ return d;
+}
+
+void endrpcent(void)
+{
+ register struct rpcdata *d = _rpcdata();
+
+ if (d == NULL)
+ return;
+ if (d->stayopen)
+ return;
+ free(d->current);
+ d->current = NULL;
+ if (d->rpcf) {
+ fclose(d->rpcf);
+ d->rpcf = NULL;
+ }
+}
+libc_hidden_def(endrpcent)
+
+void setrpcent(int f)
+{
+ register struct rpcdata *d = _rpcdata();
+
+ if (d == NULL)
+ return;
+ if (d->rpcf == NULL)
+ d->rpcf = fopen(RPCDB, "r");
+ else
+ rewind(d->rpcf);
+ free(d->current);
+ d->current = NULL;
+ d->stayopen |= f;
+}
+libc_hidden_def(setrpcent)
+
+static struct rpcent *interpret(struct rpcdata *);
+
+static struct rpcent *__get_next_rpcent(struct rpcdata *d)
+{
+ if (fgets(d->line, BUFSIZ, d->rpcf) == NULL)
+ return NULL;
+ return interpret(d);
+}
+
+struct rpcent *getrpcent(void)
+{
+ register struct rpcdata *d = _rpcdata();
+
+ if (d == NULL)
+ return NULL;
+ if (d->rpcf == NULL && (d->rpcf = fopen(RPCDB, "r")) == NULL)
+ return NULL;
+ return __get_next_rpcent(d);
+}
+libc_hidden_def(getrpcent)
+
+struct rpcent *getrpcbynumber(register int number)
+{
+ register struct rpcdata *d = _rpcdata();
+ register struct rpcent *rpc;
+
+ if (d == NULL)
+ return NULL;
+ setrpcent(0);
+ while ((rpc = getrpcent())) {
+ if (rpc->r_number == number)
+ break;
+ }
+ endrpcent();
+ return rpc;
+}
+libc_hidden_def(getrpcbynumber)
+
+struct rpcent *getrpcbyname(const char *name)
+{
+ struct rpcent *rpc;
+ char **rp;
+
+ setrpcent(0);
+ while ((rpc = getrpcent())) {
+ if (strcmp(rpc->r_name, name) == 0)
+ return rpc;
+ for (rp = rpc->r_aliases; *rp != NULL; rp++) {
+ if (strcmp(*rp, name) == 0)
+ return rpc;
+ }
+ }
+ endrpcent();
+ return NULL;
+}
+libc_hidden_def(getrpcbyname)
+
+#ifdef __linux__
+static char *firstwhite(char *s)
+{
+ char *s1, *s2;
+
+ s1 = strchr(s, ' ');
+ s2 = strchr(s, '\t');
+ if (s1) {
+ if (s2)
+ return (s1 < s2) ? s1 : s2;
+ else
+ return s1;
+ } else
+ return s2;
+}
+#endif
+
+static struct rpcent *interpret(register struct rpcdata *d)
+{
+ char *p;
+ register char *cp, **q;
+
+ p = d->line;
+ d->line[strlen(p)-1] = '\n';
+ if (*p == '#')
+ return __get_next_rpcent(d);
+ cp = strchr(p, '#');
+ if (cp == NULL) {
+ cp = strchr(p, '\n');
+ if (cp == NULL)
+ return __get_next_rpcent(d);
+ }
+ *cp = '\0';
+#ifdef __linux__
+ if ((cp = firstwhite(p)))
+ *cp++ = 0;
+ else
+ return __get_next_rpcent(d);
+#else
+ cp = strchr(p, ' ');
+ if (cp == NULL) {
+ cp = strchr(p, '\t');
+ if (cp == NULL)
+ return __get_next_rpcent(d);
+ }
+ *cp++ = '\0';
+#endif
+ /* THIS STUFF IS INTERNET SPECIFIC */
+ d->rpc.r_name = d->line;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ d->rpc.r_number = atoi(cp);
+ q = d->rpc.r_aliases = d->rpc_aliases;
+#ifdef __linux__
+ if ((cp = firstwhite(cp)))
+ *cp++ = '\0';
+#else
+ cp = strchr(p, ' ');
+ if (cp != NULL)
+ *cp++ = '\0';
+ else {
+ cp = strchr(p, '\t');
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+#endif
+ while (cp && *cp) {
+ if (*cp == ' ' || *cp == '\t') {
+ cp++;
+ continue;
+ }
+ if (q < &(d->rpc_aliases[MAXALIASES - 1]))
+ *q++ = cp;
+#ifdef __linux__
+ if ((cp = firstwhite(cp)))
+ *cp++ = '\0';
+#else
+ cp = strchr(p, ' ');
+ if (cp != NULL)
+ *cp++ = '\0';
+ else {
+ cp = strchr(p, '\t');
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+#endif
+ }
+ *q = NULL;
+ return &d->rpc;
+}
+
+#if defined(__UCLIBC_HAS_REENTRANT_RPC__)
+
+#ifndef ANDROID
+#include <bits/uClibc_mutex.h>
+#endif
+__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
+
+
+static int __copy_rpcent(struct rpcent *r, struct rpcent *result_buf, char *buffer,
+ size_t buflen, struct rpcent **result)
+{
+ size_t i, s;
+
+ *result = NULL;
+
+ if (!r)
+ return ENOENT;
+
+ /* copy the struct from the shared mem */
+ memset(result_buf, 0x00, sizeof(*result_buf));
+ memset(buffer, 0x00, buflen);
+
+ result_buf->r_number = r->r_number;
+
+ /* copy the aliases ... need to not only copy the alias strings,
+ * but the array of pointers to the alias strings */
+ i = 0;
+ while (r->r_aliases[i++]) ;
+
+ s = i-- * sizeof(char*);
+ if (buflen < s)
+ goto err_out;
+ result_buf->r_aliases = (char**)buffer;
+ buffer += s;
+ buflen -= s;
+
+ while (i-- > 0) {
+ s = strlen(r->r_aliases[i]) + 1;
+ if (buflen < s)
+ goto err_out;
+ result_buf->r_aliases[i] = buffer;
+ buffer += s;
+ buflen -= s;
+ memcpy(result_buf->r_aliases[i], r->r_aliases[i], s);
+ }
+
+ /* copy the name */
+ i = strlen(r->r_name);
+ if (buflen <= i)
+ goto err_out;
+ result_buf->r_name = buffer;
+ memcpy(result_buf->r_name, r->r_name, i);
+
+ /* that was a hoot eh ? */
+ *result = result_buf;
+
+ return 0;
+err_out:
+ return ERANGE;
+}
+
+int getrpcbynumber_r(int number, struct rpcent *result_buf, char *buffer,
+ size_t buflen, struct rpcent **result)
+{
+ int ret;
+ __UCLIBC_MUTEX_LOCK(mylock);
+ ret = __copy_rpcent(getrpcbynumber(number), result_buf, buffer, buflen, result);
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+ return ret;
+}
+
+int getrpcbyname_r(const char *name, struct rpcent *result_buf, char *buffer,
+ size_t buflen, struct rpcent **result)
+{
+ int ret;
+ __UCLIBC_MUTEX_LOCK(mylock);
+ ret = __copy_rpcent(getrpcbyname(name), result_buf, buffer, buflen, result);
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+ return ret;
+}
+
+int getrpcent_r(struct rpcent *result_buf, char *buffer,
+ size_t buflen, struct rpcent **result)
+{
+ int ret;
+ __UCLIBC_MUTEX_LOCK(mylock);
+ ret = __copy_rpcent(getrpcent(), result_buf, buffer, buflen, result);
+ __UCLIBC_MUTEX_UNLOCK(mylock);
+ return ret;
+}
+
+#endif /* __UCLIBC_HAS_REENTRANT_RPC__ */
diff --git a/android/librpc/getrpcport.c b/android/librpc/getrpcport.c
new file mode 100644
index 0000000..9c4f443
--- a/dev/null
+++ b/android/librpc/getrpcport.c
@@ -0,0 +1,78 @@
+/* @(#)getrpcport.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)getrpcport.c 1.3 87/08/11 SMI";
+#endif
+
+/*
+ * Copyright (c) 1985 by Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <alloca.h>
+#include <errno.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/clnt.h>
+#include <rpc/pmap_clnt.h>
+#include <sys/socket.h>
+
+
+int
+getrpcport (const char *host, u_long prognum, u_long versnum, u_int proto)
+{
+ struct sockaddr_in addr;
+ struct hostent hostbuf, *hp;
+ size_t buflen;
+ char *buffer;
+ int herr;
+
+ buflen = 1024;
+ buffer = alloca (buflen);
+ while (gethostbyname_r (host, &hostbuf, buffer, buflen, &hp, &herr) != 0
+ || hp == NULL)
+ if (herr != NETDB_INTERNAL || errno != ERANGE)
+ return 0;
+ else
+ {
+ /* Enlarge the buffer. */
+ buflen *= 2;
+ buffer = alloca (buflen);
+ }
+
+ memcpy ((char *) &addr.sin_addr, hp->h_addr, hp->h_length);
+ addr.sin_family = AF_INET;
+ addr.sin_port = 0;
+ return pmap_getport (&addr, prognum, versnum, proto);
+}
diff --git a/android/librpc/pm_getmaps.c b/android/librpc/pm_getmaps.c
new file mode 100644
index 0000000..e7b97e6
--- a/dev/null
+++ b/android/librpc/pm_getmaps.c
@@ -0,0 +1,84 @@
+/* @(#)pmap_getmaps.c 2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_getmap.c
+ * Client interface to pmap rpc service.
+ * contains pmap_getmaps, which is only tcp service involved
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+
+
+/*
+ * Get a copy of the current port maps.
+ * Calls the pmap service remotely to do get the maps.
+ */
+struct pmaplist *
+pmap_getmaps (struct sockaddr_in *address)
+{
+ struct pmaplist *head = (struct pmaplist *) NULL;
+ int _socket = -1;
+ struct timeval minutetimeout;
+ CLIENT *client;
+
+ minutetimeout.tv_sec = 60;
+ minutetimeout.tv_usec = 0;
+ address->sin_port = htons (PMAPPORT);
+
+ /* Don't need a reserved port to get ports from the portmapper. */
+ client = clnttcp_create (address, PMAPPROG,
+ PMAPVERS, &_socket, 50, 500);
+ if (client != (CLIENT *) NULL)
+ {
+ if (CLNT_CALL (client, PMAPPROC_DUMP, (xdrproc_t)xdr_void, NULL,
+ (xdrproc_t)xdr_pmaplist, (caddr_t)&head,
+ minutetimeout) != RPC_SUCCESS)
+ {
+ clnt_perror (client, _("pmap_getmaps rpc problem"));
+ }
+ CLNT_DESTROY (client);
+ }
+ /* (void)__close(_socket); CLNT_DESTROY already closed it */
+ address->sin_port = 0;
+ return head;
+}
diff --git a/android/librpc/pm_getport.c b/android/librpc/pm_getport.c
new file mode 100644
index 0000000..8a42761
--- a/dev/null
+++ b/android/librpc/pm_getport.c
@@ -0,0 +1,94 @@
+/* @(#)pmap_getport.c 2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_getport.c
+ * Client interface to pmap rpc service.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <stdbool.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+
+
+static const struct timeval timeout =
+{5, 0};
+static const struct timeval tottimeout =
+{60, 0};
+
+/*
+ * Find the mapped port for program,version.
+ * Calls the pmap service remotely to do the lookup.
+ * Returns 0 if no map exists.
+ */
+u_short
+pmap_getport (struct sockaddr_in *address, u_long program, u_long version,
+ u_int protocol)
+{
+ u_short port = 0;
+ int _socket = -1;
+ CLIENT *client;
+ struct pmap parms;
+
+ address->sin_port = htons (PMAPPORT);
+ client = clntudp_bufcreate (address, PMAPPROG,
+ PMAPVERS, timeout, &_socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+ if (client != (CLIENT *) NULL)
+ {
+ struct rpc_createerr *ce = &get_rpc_createerr ();
+ parms.pm_prog = program;
+ parms.pm_vers = version;
+ parms.pm_prot = protocol;
+ parms.pm_port = 0; /* not needed or used */
+ if (CLNT_CALL (client, PMAPPROC_GETPORT, (xdrproc_t)xdr_pmap,
+ (caddr_t)&parms, (xdrproc_t)xdr_u_short,
+ (caddr_t)&port, tottimeout) != RPC_SUCCESS)
+ {
+ ce->cf_stat = RPC_PMAPFAILURE;
+ clnt_geterr (client, &ce->cf_error);
+ }
+ else if (port == 0)
+ {
+ ce->cf_stat = RPC_PROGNOTREGISTERED;
+ }
+ CLNT_DESTROY (client);
+ }
+ /* (void)__close(_socket); CLNT_DESTROY already closed it */
+ address->sin_port = 0;
+ return port;
+}
+libc_hidden_def(pmap_getport)
diff --git a/android/librpc/pmap_clnt.c b/android/librpc/pmap_clnt.c
new file mode 100644
index 0000000..c35a2e9
--- a/dev/null
+++ b/android/librpc/pmap_clnt.c
@@ -0,0 +1,176 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+/*
+ * pmap_clnt.c
+ * Client interface to pmap rpc service.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+
+
+/*
+ * Same as get_myaddress, but we try to use the loopback
+ * interface. portmap caches interfaces, and on DHCP clients,
+ * it could be that only loopback is started at this time.
+ */
+static bool_t
+__get_myaddress (struct sockaddr_in *addr)
+{
+ int s;
+ char buf[BUFSIZ];
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ int len, loopback = 1;
+
+ if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ perror ("__get_myaddress: socket");
+ exit (1);
+ }
+ ifc.ifc_len = sizeof (buf);
+ ifc.ifc_buf = buf;
+ if (ioctl (s, SIOCGIFCONF, (char *) &ifc) < 0)
+ {
+ perror (_("__get_myaddress: ioctl (get interface configuration)"));
+ exit (1);
+ }
+
+ again:
+ ifr = ifc.ifc_req;
+ for (len = ifc.ifc_len; len; len -= sizeof ifreq)
+ {
+ ifreq = *ifr;
+ if (ioctl (s, SIOCGIFFLAGS, (char *) &ifreq) < 0)
+ {
+ perror ("__get_myaddress: ioctl");
+ exit (1);
+ }
+ if ((ifreq.ifr_flags & IFF_UP) && (ifr->ifr_addr.sa_family == AF_INET)
+ && ((ifreq.ifr_flags & IFF_LOOPBACK) || (loopback == 0)))
+ {
+ *addr = *((struct sockaddr_in *) &ifr->ifr_addr);
+ addr->sin_port = htons (PMAPPORT);
+ close (s);
+ return TRUE;
+ }
+ ifr++;
+ }
+ if (loopback == 1)
+ {
+ loopback = 0;
+ goto again;
+ }
+ close (s);
+ return FALSE;
+}
+
+
+static const struct timeval timeout = {5, 0};
+static const struct timeval tottimeout = {60, 0};
+
+/*
+ * Set a mapping between program,version and port.
+ * Calls the pmap service remotely to do the mapping.
+ */
+bool_t
+pmap_set (u_long program, u_long version, int protocol, u_short port)
+{
+ struct sockaddr_in myaddress;
+ int _socket = -1;
+ CLIENT *client;
+ struct pmap parms;
+ bool_t rslt;
+
+ if (!__get_myaddress (&myaddress))
+ return FALSE;
+ client = clntudp_bufcreate (&myaddress, PMAPPROG, PMAPVERS,
+ timeout, &_socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+ if (client == (CLIENT *) NULL)
+ return (FALSE);
+ parms.pm_prog = program;
+ parms.pm_vers = version;
+ parms.pm_prot = protocol;
+ parms.pm_port = port;
+ if (CLNT_CALL (client, PMAPPROC_SET, (xdrproc_t)xdr_pmap, (caddr_t)&parms,
+ (xdrproc_t)xdr_bool, (caddr_t)&rslt,
+ tottimeout) != RPC_SUCCESS)
+ {
+ clnt_perror (client, _("Cannot register service"));
+ rslt = FALSE;
+ }
+ CLNT_DESTROY (client);
+ /* (void)close(_socket); CLNT_DESTROY closes it */
+ return rslt;
+}
+libc_hidden_def (pmap_set)
+
+/*
+ * Remove the mapping between program,version and port.
+ * Calls the pmap service remotely to do the un-mapping.
+ */
+bool_t
+pmap_unset (u_long program, u_long version)
+{
+ struct sockaddr_in myaddress;
+ int _socket = -1;
+ CLIENT *client;
+ struct pmap parms;
+ bool_t rslt;
+
+ if (!__get_myaddress (&myaddress))
+ return FALSE;
+ client = clntudp_bufcreate (&myaddress, PMAPPROG, PMAPVERS,
+ timeout, &_socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
+ if (client == (CLIENT *) NULL)
+ return FALSE;
+ parms.pm_prog = program;
+ parms.pm_vers = version;
+ parms.pm_port = parms.pm_prot = 0;
+ CLNT_CALL (client, PMAPPROC_UNSET, (xdrproc_t)xdr_pmap, (caddr_t)&parms,
+ (xdrproc_t)xdr_bool, (caddr_t)&rslt, tottimeout);
+ CLNT_DESTROY (client);
+ /* (void)close(_socket); CLNT_DESTROY already closed it */
+ return rslt;
+}
+libc_hidden_def (pmap_unset)
diff --git a/android/librpc/pmap_prot.c b/android/librpc/pmap_prot.c
new file mode 100644
index 0000000..342dbad
--- a/dev/null
+++ b/android/librpc/pmap_prot.c
@@ -0,0 +1,56 @@
+/* @(#)pmap_prot.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_prot.c
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/pmap_prot.h>
+
+
+bool_t
+xdr_pmap (XDR *xdrs, struct pmap *regs)
+{
+
+ if (xdr_u_long (xdrs, &regs->pm_prog) &&
+ xdr_u_long (xdrs, &regs->pm_vers) &&
+ xdr_u_long (xdrs, &regs->pm_prot))
+ return xdr_u_long (xdrs, &regs->pm_port);
+ return FALSE;
+}
+libc_hidden_def(xdr_pmap)
diff --git a/android/librpc/pmap_prot2.c b/android/librpc/pmap_prot2.c
new file mode 100644
index 0000000..f383757
--- a/dev/null
+++ b/android/librpc/pmap_prot2.c
@@ -0,0 +1,117 @@
+/* @(#)pmap_prot2.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_prot2.c
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/pmap_prot.h>
+
+
+/*
+ * What is going on with linked lists? (!)
+ * First recall the link list declaration from pmap_prot.h:
+ *
+ * struct pmaplist {
+ * struct pmap pml_map;
+ * struct pmaplist *pml_map;
+ * };
+ *
+ * Compare that declaration with a corresponding xdr declaration that
+ * is (a) pointer-less, and (b) recursive:
+ *
+ * typedef union switch (bool_t) {
+ *
+ * case TRUE: struct {
+ * struct pmap;
+ * pmaplist_t foo;
+ * };
+ *
+ * case FALSE: struct {};
+ * } pmaplist_t;
+ *
+ * Notice that the xdr declaration has no nxt pointer while
+ * the C declaration has no bool_t variable. The bool_t can be
+ * interpreted as ``more data follows me''; if FALSE then nothing
+ * follows this bool_t; if TRUE then the bool_t is followed by
+ * an actual struct pmap, and then (recursively) by the
+ * xdr union, pamplist_t.
+ *
+ * This could be implemented via the xdr_union primitive, though this
+ * would cause a one recursive call per element in the list. Rather than do
+ * that we can ``unwind'' the recursion
+ * into a while loop and do the union arms in-place.
+ *
+ * The head of the list is what the C programmer wishes to past around
+ * the net, yet is the data that the pointer points to which is interesting;
+ * this sounds like a job for xdr_reference!
+ */
+bool_t
+xdr_pmaplist (XDR *xdrs, struct pmaplist **rp)
+{
+ /*
+ * more_elements is pre-computed in case the direction is
+ * XDR_ENCODE or XDR_FREE. more_elements is overwritten by
+ * xdr_bool when the direction is XDR_DECODE.
+ */
+ bool_t more_elements;
+ int freeing = (xdrs->x_op == XDR_FREE);
+ struct pmaplist **next = NULL;
+
+ while (TRUE)
+ {
+ more_elements = (bool_t) (*rp != NULL);
+ if (!xdr_bool (xdrs, &more_elements))
+ return FALSE;
+ if (!more_elements)
+ return TRUE; /* we are done */
+ /*
+ * the unfortunate side effect of non-recursion is that in
+ * the case of freeing we must remember the next object
+ * before we free the current object ...
+ */
+ if (freeing)
+ next = &((*rp)->pml_next);
+ if (!xdr_reference (xdrs, (caddr_t *) rp,
+ (u_int) sizeof (struct pmaplist),
+ (xdrproc_t) xdr_pmap))
+ return FALSE;
+ rp = freeing ? next : &((*rp)->pml_next);
+ }
+}
+libc_hidden_def(xdr_pmaplist)
diff --git a/android/librpc/pmap_rmt.c b/android/librpc/pmap_rmt.c
new file mode 100644
index 0000000..e4dbd44
--- a/dev/null
+++ b/android/librpc/pmap_rmt.c
@@ -0,0 +1,440 @@
+/* @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * pmap_rmt.c
+ * Client interface to pmap rpc service.
+ * remote call and broadcast service
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_rmt.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <errno.h>
+#undef _POSIX_SOURCE /* Ultrix <sys/param.h> needs --roland@gnu */
+#include <sys/param.h> /* Ultrix needs before net/if --roland@gnu */
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#define MAX_BROADCAST_SIZE 1400
+
+#if defined(ANDROID) && !defined(BIONIC_L)
+static struct in_addr inet_makeaddr(in_addr_t net, in_addr_t host)
+{
+ struct in_addr a;
+
+ if (net <= 0x000000ff)
+ a.s_addr = (net << 24) | (host & 0x000000ff);
+ else if (net <= 0x0000ffff)
+ a.s_addr = (net << 16) | (host & 0x0000ffff);
+ else if (net <= 0x00ffffff)
+ a.s_addr = (net << 8) | (host & 0x00ffffff);
+ else
+ a.s_addr = net | host;
+ a.s_addr = htonl(a.s_addr);
+ return a;
+}
+static in_addr_t inet_netof(struct in_addr in)
+{
+ in_addr_t i = ntohl(in.s_addr);
+
+ if (i < 0x80000000)
+ return i >> 24;
+ if (i < 0xc0000000)
+ return i >> 16;
+ return i >> 8;
+}
+
+#endif
+
+
+extern u_long _create_xid (void) attribute_hidden;
+
+static const struct timeval timeout = {3, 0};
+
+/*
+ * pmapper remote-call-service interface.
+ * This routine is used to call the pmapper remote call service
+ * which will look up a service program in the port maps, and then
+ * remotely call that routine with the given parameters. This allows
+ * programs to do a lookup and call in one step.
+ */
+enum clnt_stat
+pmap_rmtcall (struct sockaddr_in *addr, u_long prog, u_long vers, u_long proc,
+ xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
+ struct timeval tout, u_long *port_ptr)
+{
+ int _socket = -1;
+ CLIENT *client;
+ struct rmtcallargs a;
+ struct rmtcallres r;
+ enum clnt_stat stat;
+
+ addr->sin_port = htons (PMAPPORT);
+ client = clntudp_create (addr, PMAPPROG, PMAPVERS, timeout, &_socket);
+ if (client != (CLIENT *) NULL)
+ {
+ a.prog = prog;
+ a.vers = vers;
+ a.proc = proc;
+ a.args_ptr = argsp;
+ a.xdr_args = xdrargs;
+ r.port_ptr = port_ptr;
+ r.results_ptr = resp;
+ r.xdr_results = xdrres;
+ stat = CLNT_CALL (client, PMAPPROC_CALLIT, (xdrproc_t)xdr_rmtcall_args,
+ (caddr_t)&a, (xdrproc_t)xdr_rmtcallres,
+ (caddr_t)&r, tout);
+ CLNT_DESTROY (client);
+ }
+ else
+ {
+ stat = RPC_FAILED;
+ }
+ /* (void)close(_socket); CLNT_DESTROY already closed it */
+ addr->sin_port = 0;
+ return stat;
+}
+
+
+/*
+ * XDR remote call arguments
+ * written for XDR_ENCODE direction only
+ */
+bool_t
+xdr_rmtcall_args (XDR *xdrs, struct rmtcallargs *cap)
+{
+ u_int lenposition, argposition, position;
+
+ if (xdr_u_long (xdrs, &(cap->prog)) &&
+ xdr_u_long (xdrs, &(cap->vers)) &&
+ xdr_u_long (xdrs, &(cap->proc)))
+ {
+ u_long dummy_arglen = 0;
+ lenposition = XDR_GETPOS (xdrs);
+ if (!xdr_u_long (xdrs, &dummy_arglen))
+ return FALSE;
+ argposition = XDR_GETPOS (xdrs);
+ if (!(*(cap->xdr_args)) (xdrs, cap->args_ptr))
+ return FALSE;
+ position = XDR_GETPOS (xdrs);
+ cap->arglen = (u_long) position - (u_long) argposition;
+ XDR_SETPOS (xdrs, lenposition);
+ if (!xdr_u_long (xdrs, &(cap->arglen)))
+ return FALSE;
+ XDR_SETPOS (xdrs, position);
+ return TRUE;
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_rmtcall_args)
+
+/*
+ * XDR remote call results
+ * written for XDR_DECODE direction only
+ */
+bool_t
+xdr_rmtcallres (XDR *xdrs, struct rmtcallres *crp)
+{
+ caddr_t port_ptr;
+
+ port_ptr = (caddr_t) crp->port_ptr;
+ if (xdr_reference (xdrs, &port_ptr, sizeof (u_long), (xdrproc_t) xdr_u_long)
+ && xdr_u_long (xdrs, &crp->resultslen))
+ {
+ crp->port_ptr = (u_long *) port_ptr;
+ return (*(crp->xdr_results)) (xdrs, crp->results_ptr);
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_rmtcallres)
+
+
+/*
+ * The following is kludged-up support for simple rpc broadcasts.
+ * Someday a large, complicated system will replace these trivial
+ * routines which only support udp/ip .
+ */
+
+static int
+internal_function
+getbroadcastnets (struct in_addr *addrs, int sock, char *buf)
+ /* int sock: any valid socket will do */
+ /* char *buf: why allocate more when we can use existing... */
+{
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ struct sockaddr_in *sin;
+ int n, i;
+
+ ifc.ifc_len = UDPMSGSIZE;
+ ifc.ifc_buf = buf;
+ if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0)
+ {
+ perror (_("broadcast: ioctl (get interface configuration)"));
+ return (0);
+ }
+ ifr = ifc.ifc_req;
+ for (i = 0, n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++)
+ {
+ ifreq = *ifr;
+ if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0)
+ {
+ perror (_("broadcast: ioctl (get interface flags)"));
+ continue;
+ }
+ if ((ifreq.ifr_flags & IFF_BROADCAST) &&
+ (ifreq.ifr_flags & IFF_UP) &&
+ ifr->ifr_addr.sa_family == AF_INET)
+ {
+ sin = (struct sockaddr_in *) &ifr->ifr_addr;
+#ifdef SIOCGIFBRDADDR /* 4.3BSD */
+ if (ioctl (sock, SIOCGIFBRDADDR, (char *) &ifreq) < 0)
+ {
+ addrs[i++] = inet_makeaddr (inet_netof
+ /* Changed to pass struct instead of s_addr member
+ by roland@gnu. */
+ (sin->sin_addr), INADDR_ANY);
+ }
+ else
+ {
+ addrs[i++] = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr;
+ }
+#else /* 4.2 BSD */
+ addrs[i++] = inet_makeaddr (inet_netof
+ (sin->sin_addr.s_addr), INADDR_ANY);
+#endif
+ }
+ }
+ return i;
+}
+
+
+enum clnt_stat
+clnt_broadcast (
+ u_long prog, /* program number */
+ u_long vers, /* version number */
+ u_long proc, /* procedure number */
+ xdrproc_t xargs, /* xdr routine for args */
+ caddr_t argsp, /* pointer to args */
+ xdrproc_t xresults, /* xdr routine for results */
+ caddr_t resultsp, /* pointer to results */
+ resultproc_t eachresult /* call with each result obtained */)
+{
+ enum clnt_stat stat = RPC_FAILED;
+ AUTH *unix_auth = authunix_create_default ();
+ XDR xdr_stream;
+ XDR *xdrs = &xdr_stream;
+ struct timeval t;
+ int outlen, inlen, nets;
+ socklen_t fromlen;
+ int sock;
+ int on = 1;
+ struct pollfd fd;
+ int milliseconds;
+ int i;
+ bool_t done = FALSE;
+ u_long xid;
+ u_long port;
+ struct in_addr addrs[20];
+ struct sockaddr_in baddr, raddr; /* broadcast and response addresses */
+ struct rmtcallargs a;
+ struct rmtcallres r;
+ struct rpc_msg msg;
+ char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE];
+
+ /*
+ * initialization: create a socket, a broadcast address, and
+ * preserialize the arguments into a send buffer.
+ */
+ if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ {
+ perror (_("Cannot create socket for broadcast rpc"));
+ stat = RPC_CANTSEND;
+ goto done_broad;
+ }
+#ifdef SO_BROADCAST
+ if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0)
+ {
+ perror (_("Cannot set socket option SO_BROADCAST"));
+ stat = RPC_CANTSEND;
+ goto done_broad;
+ }
+#endif /* def SO_BROADCAST */
+ fd.fd = sock;
+ fd.events = POLLIN;
+ nets = getbroadcastnets (addrs, sock, inbuf);
+ memset ((char *) &baddr, 0, sizeof (baddr));
+ baddr.sin_family = AF_INET;
+ baddr.sin_port = htons (PMAPPORT);
+ baddr.sin_addr.s_addr = htonl (INADDR_ANY);
+/* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */
+ msg.rm_xid = xid = _create_xid ();
+ t.tv_usec = 0;
+ msg.rm_direction = CALL;
+ msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ msg.rm_call.cb_prog = PMAPPROG;
+ msg.rm_call.cb_vers = PMAPVERS;
+ msg.rm_call.cb_proc = PMAPPROC_CALLIT;
+ msg.rm_call.cb_cred = unix_auth->ah_cred;
+ msg.rm_call.cb_verf = unix_auth->ah_verf;
+ a.prog = prog;
+ a.vers = vers;
+ a.proc = proc;
+ a.xdr_args = xargs;
+ a.args_ptr = argsp;
+ r.port_ptr = &port;
+ r.xdr_results = xresults;
+ r.results_ptr = resultsp;
+ xdrmem_create (xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE);
+ if ((!xdr_callmsg (xdrs, &msg)) || (!xdr_rmtcall_args (xdrs, &a)))
+ {
+ stat = RPC_CANTENCODEARGS;
+ goto done_broad;
+ }
+ outlen = (int) xdr_getpos (xdrs);
+ xdr_destroy (xdrs);
+ /*
+ * Basic loop: broadcast a packet and wait a while for response(s).
+ * The response timeout grows larger per iteration.
+ */
+ for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2)
+ {
+ for (i = 0; i < nets; i++)
+ {
+ baddr.sin_addr = addrs[i];
+ if (sendto (sock, outbuf, outlen, 0,
+ (struct sockaddr *) &baddr,
+ sizeof (struct sockaddr)) != outlen)
+ {
+ perror (_("Cannot send broadcast packet"));
+ stat = RPC_CANTSEND;
+ goto done_broad;
+ }
+ }
+ if (eachresult == NULL)
+ {
+ stat = RPC_SUCCESS;
+ goto done_broad;
+ }
+ recv_again:
+ msg.acpted_rply.ar_verf = _null_auth;
+ msg.acpted_rply.ar_results.where = (caddr_t) & r;
+ msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_rmtcallres;
+ milliseconds = t.tv_sec * 1000 + t.tv_usec / 1000;
+ switch (poll(&fd, 1, milliseconds))
+ {
+
+ case 0: /* timed out */
+ stat = RPC_TIMEDOUT;
+ continue;
+
+ case -1: /* some kind of error */
+ if (errno == EINTR)
+ goto recv_again;
+ perror (_("Broadcast poll problem"));
+ stat = RPC_CANTRECV;
+ goto done_broad;
+
+ } /* end of poll results switch */
+ try_again:
+ fromlen = sizeof (struct sockaddr);
+ inlen = recvfrom (sock, inbuf, UDPMSGSIZE, 0,
+ (struct sockaddr *) &raddr, &fromlen);
+ if (inlen < 0)
+ {
+ if (errno == EINTR)
+ goto try_again;
+ perror (_("Cannot receive reply to broadcast"));
+ stat = RPC_CANTRECV;
+ goto done_broad;
+ }
+ if ((size_t) inlen < sizeof (u_long))
+ goto recv_again;
+ /*
+ * see if reply transaction id matches sent id.
+ * If so, decode the results.
+ */
+ xdrmem_create (xdrs, inbuf, (u_int) inlen, XDR_DECODE);
+ if (xdr_replymsg (xdrs, &msg))
+ {
+ if (((u_int32_t) msg.rm_xid == (u_int32_t) xid) &&
+ (msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+ (msg.acpted_rply.ar_stat == SUCCESS))
+ {
+ raddr.sin_port = htons ((u_short) port);
+ done = (*eachresult) (resultsp, &raddr);
+ }
+ /* otherwise, we just ignore the errors ... */
+ }
+ else
+ {
+#ifdef notdef
+ /* some kind of deserialization problem ... */
+ if ((u_int32_t) msg.rm_xid == (u_int32_t) xid)
+ fprintf (stderr, "Broadcast deserialization problem");
+ /* otherwise, just random garbage */
+#endif
+ }
+ xdrs->x_op = XDR_FREE;
+ msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+ (void) xdr_replymsg (xdrs, &msg);
+ (void) (*xresults) (xdrs, resultsp);
+ xdr_destroy (xdrs);
+ if (done)
+ {
+ stat = RPC_SUCCESS;
+ goto done_broad;
+ }
+ else
+ {
+ goto recv_again;
+ }
+ }
+done_broad:
+ (void) close (sock);
+ AUTH_DESTROY (unix_auth);
+ return stat;
+}
diff --git a/android/librpc/rpc/auth.h b/android/librpc/rpc/auth.h
new file mode 100644
index 0000000..a156c56
--- a/dev/null
+++ b/android/librpc/rpc/auth.h
@@ -0,0 +1,232 @@
+/* @(#)auth.h 2.3 88/08/07 4.0 RPCSRC; from 1.17 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * auth.h, Authentication interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The data structures are completely opaque to the client. The client
+ * is required to pass a AUTH * to routines that create rpc
+ * "sessions".
+ */
+
+#ifndef _RPC_AUTH_H
+
+#define _RPC_AUTH_H 1
+#ifdef _LIBC
+/* Some adjustments to make the libc source from glibc
+ * compile more easily with uClibc... */
+#ifndef __FORCE_GLIBC
+#define __FORCE_GLIBC
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#define _(X) X
+#endif
+#include <features.h>
+#include <rpc/xdr.h>
+
+__BEGIN_DECLS
+
+#define MAX_AUTH_BYTES 400
+#define MAXNETNAMELEN 255 /* maximum length of network user's name */
+
+/*
+ * Status returned from authentication check
+ */
+enum auth_stat {
+ AUTH_OK=0,
+ /*
+ * failed at remote end
+ */
+ AUTH_BADCRED=1, /* bogus credentials (seal broken) */
+ AUTH_REJECTEDCRED=2, /* client should begin new session */
+ AUTH_BADVERF=3, /* bogus verifier (seal broken) */
+ AUTH_REJECTEDVERF=4, /* verifier expired or was replayed */
+ AUTH_TOOWEAK=5, /* rejected due to security reasons */
+ /*
+ * failed locally
+ */
+ AUTH_INVALIDRESP=6, /* bogus response verifier */
+ AUTH_FAILED=7 /* some unknown reason */
+};
+
+union des_block {
+ struct {
+ u_int32_t high;
+ u_int32_t low;
+ } key;
+ char c[8];
+};
+typedef union des_block des_block;
+extern bool_t xdr_des_block (XDR *__xdrs, des_block *__blkp) __THROW;
+
+/*
+ * Authentication info. Opaque to client.
+ */
+struct opaque_auth {
+ enum_t oa_flavor; /* flavor of auth */
+ caddr_t oa_base; /* address of more auth stuff */
+ u_int oa_length; /* not to exceed MAX_AUTH_BYTES */
+};
+
+/*
+ * Auth handle, interface to client side authenticators.
+ */
+typedef struct AUTH AUTH;
+struct AUTH {
+ struct opaque_auth ah_cred;
+ struct opaque_auth ah_verf;
+ union des_block ah_key;
+ struct auth_ops {
+ void (*ah_nextverf) (AUTH *);
+ int (*ah_marshal) (AUTH *, XDR *); /* nextverf & serialize */
+ int (*ah_validate) (AUTH *, struct opaque_auth *);
+ /* validate verifier */
+ int (*ah_refresh) (AUTH *); /* refresh credentials */
+ void (*ah_destroy) (AUTH *); /* destroy this structure */
+ } *ah_ops;
+ caddr_t ah_private;
+};
+
+
+/*
+ * Authentication ops.
+ * The ops and the auth handle provide the interface to the authenticators.
+ *
+ * AUTH *auth;
+ * XDR *xdrs;
+ * struct opaque_auth verf;
+ */
+#define AUTH_NEXTVERF(auth) \
+ ((*((auth)->ah_ops->ah_nextverf))(auth))
+#define auth_nextverf(auth) \
+ ((*((auth)->ah_ops->ah_nextverf))(auth))
+
+#define AUTH_MARSHALL(auth, xdrs) \
+ ((*((auth)->ah_ops->ah_marshal))(auth, xdrs))
+#define auth_marshall(auth, xdrs) \
+ ((*((auth)->ah_ops->ah_marshal))(auth, xdrs))
+
+#define AUTH_VALIDATE(auth, verfp) \
+ ((*((auth)->ah_ops->ah_validate))((auth), verfp))
+#define auth_validate(auth, verfp) \
+ ((*((auth)->ah_ops->ah_validate))((auth), verfp))
+
+#define AUTH_REFRESH(auth) \
+ ((*((auth)->ah_ops->ah_refresh))(auth))
+#define auth_refresh(auth) \
+ ((*((auth)->ah_ops->ah_refresh))(auth))
+
+#define AUTH_DESTROY(auth) \
+ ((*((auth)->ah_ops->ah_destroy))(auth))
+#define auth_destroy(auth) \
+ ((*((auth)->ah_ops->ah_destroy))(auth))
+
+
+extern struct opaque_auth _null_auth;
+
+
+/*
+ * These are the various implementations of client side authenticators.
+ */
+
+/*
+ * Unix style authentication
+ * AUTH *authunix_create(machname, uid, gid, len, aup_gids)
+ * char *machname;
+ * int uid;
+ * int gid;
+ * int len;
+ * int *aup_gids;
+ */
+extern AUTH *authunix_create (char *__machname, __uid_t __uid, __gid_t __gid,
+ int __len, __gid_t *__aup_gids);
+libc_hidden_proto(authunix_create)
+extern AUTH *authunix_create_default (void);
+libc_hidden_proto(authunix_create_default)
+extern AUTH *authnone_create (void) __THROW;
+libc_hidden_proto(authnone_create)
+#if 0
+extern AUTH *authdes_create (const char *__servername, u_int __window,
+ struct sockaddr *__syncaddr, des_block *__ckey)
+ __THROW;
+extern AUTH *authdes_pk_create (const char *, netobj *, u_int,
+ struct sockaddr *, des_block *) __THROW;
+#endif
+
+
+#define AUTH_NONE 0 /* no authentication */
+#define AUTH_NULL 0 /* backward compatibility */
+#define AUTH_SYS 1 /* unix style (uid, gids) */
+#define AUTH_UNIX AUTH_SYS
+#define AUTH_SHORT 2 /* short hand unix style */
+#define AUTH_DES 3 /* des style (encrypted timestamps) */
+#define AUTH_DH AUTH_DES /* Diffie-Hellman (this is DES) */
+#define AUTH_KERB 4 /* kerberos style */
+
+#if 0
+/*
+ * Netname manipulating functions
+ *
+ */
+extern int getnetname (char *) __THROW;
+extern int host2netname (char *, __const char *, __const char *) __THROW;
+extern int user2netname (char *, __const uid_t, __const char *) __THROW;
+extern int netname2user (__const char *, uid_t *, gid_t *, int *, gid_t *)
+ __THROW;
+extern int netname2host (__const char *, char *, __const int) __THROW;
+
+/*
+ *
+ * These routines interface to the keyserv daemon
+ *
+ */
+extern int key_decryptsession (char *, des_block *);
+extern int key_decryptsession_pk (char *, netobj *, des_block *);
+extern int key_encryptsession (char *, des_block *);
+extern int key_encryptsession_pk (char *, netobj *, des_block *);
+extern int key_gendes (des_block *);
+extern int key_setsecret (char *);
+extern int key_secretkey_is_set (void);
+extern int key_get_conv (char *, des_block *);
+#endif
+
+/*
+ * XDR an opaque authentication struct.
+ */
+extern bool_t xdr_opaque_auth (XDR *, struct opaque_auth *) __THROW;
+libc_hidden_proto(xdr_opaque_auth)
+
+__END_DECLS
+
+#endif /* rpc/auth.h */
diff --git a/android/librpc/rpc/auth_des.h b/android/librpc/rpc/auth_des.h
new file mode 100644
index 0000000..d51b7ce
--- a/dev/null
+++ b/android/librpc/rpc/auth_des.h
@@ -0,0 +1,117 @@
+/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _RPC_AUTH_DES_H
+#define _RPC_AUTH_DES_H 1
+
+#include <sys/cdefs.h>
+#include <rpc/auth.h>
+
+__BEGIN_DECLS
+
+#if 0
+/* There are two kinds of "names": fullnames and nicknames */
+enum authdes_namekind
+ {
+ ADN_FULLNAME,
+ ADN_NICKNAME
+ };
+
+/* A fullname contains the network name of the client,
+ a conversation key and the window */
+struct authdes_fullname
+ {
+ char *name; /* network name of client, up to MAXNETNAMELEN */
+ des_block key; /* conversation key */
+ uint32_t window; /* associated window */
+ };
+
+/* A credential */
+struct authdes_cred
+ {
+ enum authdes_namekind adc_namekind;
+ struct authdes_fullname adc_fullname;
+ uint32_t adc_nickname;
+ };
+#endif
+
+/* A timeval replacement for !32bit platforms */
+struct rpc_timeval
+ {
+ uint32_t tv_sec; /* Seconds. */
+ uint32_t tv_usec; /* Microseconds. */
+ };
+
+#if 0
+/* A des authentication verifier */
+struct authdes_verf
+ {
+ union
+ {
+ struct rpc_timeval adv_ctime; /* clear time */
+ des_block adv_xtime; /* crypt time */
+ }
+ adv_time_u;
+ uint32_t adv_int_u;
+ };
+
+/* des authentication verifier: client variety
+
+ adv_timestamp is the current time.
+ adv_winverf is the credential window + 1.
+ Both are encrypted using the conversation key. */
+#define adv_timestamp adv_time_u.adv_ctime
+#define adv_xtimestamp adv_time_u.adv_xtime
+#define adv_winverf adv_int_u
+
+/* des authentication verifier: server variety
+
+ adv_timeverf is the client's timestamp + client's window
+ adv_nickname is the server's nickname for the client.
+ adv_timeverf is encrypted using the conversation key. */
+#define adv_timeverf adv_time_u.adv_ctime
+#define adv_xtimeverf adv_time_u.adv_xtime
+#define adv_nickname adv_int_u
+
+/* Map a des credential into a unix cred. */
+extern int authdes_getucred (__const struct authdes_cred * __adc,
+ uid_t * __uid, gid_t * __gid,
+ short *__grouplen, gid_t * __groups) __THROW;
+
+/* Get the public key for NAME and place it in KEY. NAME can only be
+ up to MAXNETNAMELEN bytes long and the destination buffer KEY should
+ have HEXKEYBYTES + 1 bytes long to fit all characters from the key. */
+extern int getpublickey (__const char *__name, char *__key) __THROW;
+
+/* Get the secret key for NAME and place it in KEY. PASSWD is used to
+ decrypt the encrypted key stored in the database. NAME can only be
+ up to MAXNETNAMELEN bytes long and the destination buffer KEY
+ should have HEXKEYBYTES + 1 bytes long to fit all characters from
+ the key. */
+extern int getsecretkey (__const char *__name, char *__key,
+ __const char *__passwd) __THROW;
+#endif
+
+extern int rtime (struct sockaddr_in *__addrp, struct rpc_timeval *__timep,
+ struct rpc_timeval *__timeout) __THROW;
+libc_hidden_proto(rtime)
+
+__END_DECLS
+
+
+#endif /* rpc/auth_des.h */
diff --git a/android/librpc/rpc/auth_unix.h b/android/librpc/rpc/auth_unix.h
new file mode 100644
index 0000000..713fcb4
--- a/dev/null
+++ b/android/librpc/rpc/auth_unix.h
@@ -0,0 +1,91 @@
+/* @(#)auth_unix.h 2.2 88/07/29 4.0 RPCSRC; from 1.8 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/* @(#)auth_unix.h 1.5 86/07/16 SMI */
+
+/*
+ * auth_unix.h, Protocol for UNIX style authentication parameters for RPC
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+/*
+ * The system is very weak. The client uses no encryption for it
+ * credentials and only sends null verifiers. The server sends backs
+ * null verifiers or optionally a verifier that suggests a new short hand
+ * for the credentials.
+ */
+
+#ifndef _RPC_AUTH_UNIX_H
+#define _RPC_AUTH_UNIX_H 1
+
+#include <features.h>
+#include <sys/types.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <rpc/xdr.h>
+
+__BEGIN_DECLS
+
+/* The machine name is part of a credential; it may not exceed 255 bytes */
+#define MAX_MACHINE_NAME 255
+
+/* gids compose part of a credential; there may not be more than 16 of them */
+#define NGRPS 16
+
+/*
+ * Unix style credentials.
+ */
+struct authunix_parms
+ {
+ u_long aup_time;
+ char *aup_machname;
+ __uid_t aup_uid;
+ __gid_t aup_gid;
+ u_int aup_len;
+ __gid_t *aup_gids;
+ };
+
+extern bool_t xdr_authunix_parms (XDR *__xdrs, struct authunix_parms *__p)
+ __THROW;
+libc_hidden_proto(xdr_authunix_parms)
+
+/*
+ * If a response verifier has flavor AUTH_SHORT,
+ * then the body of the response verifier encapsulates the following structure;
+ * again it is serialized in the obvious fashion.
+ */
+struct short_hand_verf
+ {
+ struct opaque_auth new_cred;
+ };
+
+__END_DECLS
+
+#endif /* rpc/auth_unix.h */
diff --git a/android/librpc/rpc/clnt.h b/android/librpc/rpc/clnt.h
new file mode 100644
index 0000000..608c7e7
--- a/dev/null
+++ b/android/librpc/rpc/clnt.h
@@ -0,0 +1,433 @@
+/* @(#)clnt.h 2.1 88/07/29 4.0 RPCSRC; from 1.31 88/02/08 SMI*/
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * clnt.h - Client side remote procedure call interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_CLNT_H
+#define _RPC_CLNT_H 1
+
+#include <features.h>
+#include <sys/types.h>
+#include <rpc/types.h>
+#include <rpc/auth.h>
+#include <sys/un.h>
+
+__BEGIN_DECLS
+
+/*
+ * Rpc calls return an enum clnt_stat. This should be looked at more,
+ * since each implementation is required to live with this (implementation
+ * independent) list of errors.
+ */
+enum clnt_stat {
+ RPC_SUCCESS=0, /* call succeeded */
+ /*
+ * local errors
+ */
+ RPC_CANTENCODEARGS=1, /* can't encode arguments */
+ RPC_CANTDECODERES=2, /* can't decode results */
+ RPC_CANTSEND=3, /* failure in sending call */
+ RPC_CANTRECV=4, /* failure in receiving result */
+ RPC_TIMEDOUT=5, /* call timed out */
+ /*
+ * remote errors
+ */
+ RPC_VERSMISMATCH=6, /* rpc versions not compatible */
+ RPC_AUTHERROR=7, /* authentication error */
+ RPC_PROGUNAVAIL=8, /* program not available */
+ RPC_PROGVERSMISMATCH=9, /* program version mismatched */
+ RPC_PROCUNAVAIL=10, /* procedure unavailable */
+ RPC_CANTDECODEARGS=11, /* decode arguments error */
+ RPC_SYSTEMERROR=12, /* generic "other problem" */
+ RPC_NOBROADCAST = 21, /* Broadcasting not supported */
+ /*
+ * callrpc & clnt_create errors
+ */
+ RPC_UNKNOWNHOST=13, /* unknown host name */
+ RPC_UNKNOWNPROTO=17, /* unknown protocol */
+ RPC_UNKNOWNADDR = 19, /* Remote address unknown */
+
+ /*
+ * rpcbind errors
+ */
+ RPC_RPCBFAILURE=14, /* portmapper failed in its call */
+#define RPC_PMAPFAILURE RPC_RPCBFAILURE
+ RPC_PROGNOTREGISTERED=15, /* remote program is not registered */
+ RPC_N2AXLATEFAILURE = 22, /* Name to addr translation failed */
+ /*
+ * unspecified error
+ */
+ RPC_FAILED=16,
+ RPC_INTR=18,
+ RPC_TLIERROR=20,
+ RPC_UDERROR=23,
+ /*
+ * asynchronous errors
+ */
+ RPC_INPROGRESS = 24,
+ RPC_STALERACHANDLE = 25
+};
+
+
+/*
+ * Error info.
+ */
+struct rpc_err {
+ enum clnt_stat re_status;
+ union {
+ int RE_errno; /* related system error */
+ enum auth_stat RE_why; /* why the auth error occurred */
+ struct {
+ u_long low; /* lowest verion supported */
+ u_long high; /* highest verion supported */
+ } RE_vers;
+ struct { /* maybe meaningful if RPC_FAILED */
+ long s1;
+ long s2;
+ } RE_lb; /* life boot & debugging only */
+ } ru;
+#define re_errno ru.RE_errno
+#define re_why ru.RE_why
+#define re_vers ru.RE_vers
+#define re_lb ru.RE_lb
+};
+
+
+/*
+ * Client rpc handle.
+ * Created by individual implementations, see e.g. rpc_udp.c.
+ * Client is responsible for initializing auth, see e.g. auth_none.c.
+ */
+typedef struct CLIENT CLIENT;
+struct CLIENT {
+ AUTH *cl_auth; /* authenticator */
+ /* not sure whether non-const-ness is a part of the spec... if it is,
+ * enclose "const" in #ifdef _LIBC / #endif
+ * to make it effective only for libc compile */
+ const
+ struct clnt_ops {
+ enum clnt_stat (*cl_call) (CLIENT *, u_long, xdrproc_t, caddr_t, xdrproc_t,
+ caddr_t, struct timeval);
+ /* call remote procedure */
+ void (*cl_abort) (void); /* abort a call */
+ void (*cl_geterr) (CLIENT *, struct rpc_err *);
+ /* get specific error code */
+ bool_t (*cl_freeres) (CLIENT *, xdrproc_t, caddr_t);
+ /* frees results */
+ void (*cl_destroy) (CLIENT *); /* destroy this structure */
+ bool_t (*cl_control) (CLIENT *, int, char *);
+ /* the ioctl() of rpc */
+ } *cl_ops;
+ caddr_t cl_private; /* private stuff */
+};
+
+
+/*
+ * client side rpc interface ops
+ *
+ * Parameter types are:
+ *
+ */
+
+/*
+ * enum clnt_stat
+ * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout)
+ * CLIENT *rh;
+ * u_long proc;
+ * xdrproc_t xargs;
+ * caddr_t argsp;
+ * xdrproc_t xres;
+ * caddr_t resp;
+ * struct timeval timeout;
+ */
+#define CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs) \
+ ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs))
+#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \
+ ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs))
+
+/*
+ * void
+ * CLNT_ABORT(rh);
+ * CLIENT *rh;
+ */
+#define CLNT_ABORT(rh) ((*(rh)->cl_ops->cl_abort)(rh))
+#define clnt_abort(rh) ((*(rh)->cl_ops->cl_abort)(rh))
+
+/*
+ * struct rpc_err
+ * CLNT_GETERR(rh);
+ * CLIENT *rh;
+ */
+#define CLNT_GETERR(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp))
+#define clnt_geterr(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp))
+
+
+/*
+ * bool_t
+ * CLNT_FREERES(rh, xres, resp);
+ * CLIENT *rh;
+ * xdrproc_t xres;
+ * caddr_t resp;
+ */
+#define CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
+#define clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
+
+/*
+ * bool_t
+ * CLNT_CONTROL(cl, request, info)
+ * CLIENT *cl;
+ * u_int request;
+ * char *info;
+ */
+#define CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
+#define clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
+
+/*
+ * control operations that apply to all transports
+ *
+ * Note: options marked XXX are no-ops in this implementation of RPC.
+ * The are present in TI-RPC but can't be implemented here since they
+ * depend on the presence of STREAMS/TLI, which we don't have.
+ */
+#define CLSET_TIMEOUT 1 /* set timeout (timeval) */
+#define CLGET_TIMEOUT 2 /* get timeout (timeval) */
+#define CLGET_SERVER_ADDR 3 /* get server's address (sockaddr) */
+#define CLGET_FD 6 /* get connections file descriptor */
+#define CLGET_SVC_ADDR 7 /* get server's address (netbuf) XXX */
+#define CLSET_FD_CLOSE 8 /* close fd while clnt_destroy */
+#define CLSET_FD_NCLOSE 9 /* Do not close fd while clnt_destroy*/
+#define CLGET_XID 10 /* Get xid */
+#define CLSET_XID 11 /* Set xid */
+#define CLGET_VERS 12 /* Get version number */
+#define CLSET_VERS 13 /* Set version number */
+#define CLGET_PROG 14 /* Get program number */
+#define CLSET_PROG 15 /* Set program number */
+#define CLSET_SVC_ADDR 16 /* get server's address (netbuf) XXX */
+#define CLSET_PUSH_TIMOD 17 /* push timod if not already present XXX */
+#define CLSET_POP_TIMOD 18 /* pop timod XXX */
+/*
+ * Connectionless only control operations
+ */
+#define CLSET_RETRY_TIMEOUT 4 /* set retry timeout (timeval) */
+#define CLGET_RETRY_TIMEOUT 5 /* get retry timeout (timeval) */
+
+/*
+ * void
+ * CLNT_DESTROY(rh);
+ * CLIENT *rh;
+ */
+#define CLNT_DESTROY(rh) ((*(rh)->cl_ops->cl_destroy)(rh))
+#define clnt_destroy(rh) ((*(rh)->cl_ops->cl_destroy)(rh))
+
+
+/*
+ * RPCTEST is a test program which is accessible on every rpc
+ * transport/port. It is used for testing, performance evaluation,
+ * and network administration.
+ */
+
+#define RPCTEST_PROGRAM ((u_long)1)
+#define RPCTEST_VERSION ((u_long)1)
+#define RPCTEST_NULL_PROC ((u_long)2)
+#define RPCTEST_NULL_BATCH_PROC ((u_long)3)
+
+/*
+ * By convention, procedure 0 takes null arguments and returns them
+ */
+
+#define NULLPROC ((u_long)0)
+
+/*
+ * Below are the client handle creation routines for the various
+ * implementations of client side rpc. They can return NULL if a
+ * creation failure occurs.
+ */
+
+/*
+ * Memory based rpc (for speed check and testing)
+ * CLIENT *
+ * clntraw_create(prog, vers)
+ * u_long prog;
+ * u_long vers;
+ */
+extern CLIENT *clntraw_create (__const u_long __prog, __const u_long __vers)
+ __THROW;
+
+
+/*
+ * Generic client creation routine. Supported protocols are "udp", "tcp" and
+ * "unix"
+ * CLIENT *
+ * clnt_create(host, prog, vers, prot)
+ * char *host; -- hostname
+ * u_long prog; -- program number
+ * u_ong vers; -- version number
+ * char *prot; -- protocol
+ */
+extern CLIENT *clnt_create (__const char *__host, __const u_long __prog,
+ __const u_long __vers, __const char *__prot)
+ __THROW;
+
+
+/*
+ * TCP based rpc
+ * CLIENT *
+ * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
+ * struct sockaddr_in *raddr;
+ * u_long prog;
+ * u_long version;
+ * register int *sockp;
+ * u_int sendsz;
+ * u_int recvsz;
+ */
+extern CLIENT *clnttcp_create (struct sockaddr_in *__raddr, u_long __prog,
+ u_long __version, int *__sockp, u_int __sendsz,
+ u_int __recvsz) __THROW;
+libc_hidden_proto(clnttcp_create)
+
+/*
+ * UDP based rpc.
+ * CLIENT *
+ * clntudp_create(raddr, program, version, wait, sockp)
+ * struct sockaddr_in *raddr;
+ * u_long program;
+ * u_long version;
+ * struct timeval wait_resend;
+ * int *sockp;
+ *
+ * Same as above, but you specify max packet sizes.
+ * CLIENT *
+ * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
+ * struct sockaddr_in *raddr;
+ * u_long program;
+ * u_long version;
+ * struct timeval wait_resend;
+ * int *sockp;
+ * u_int sendsz;
+ * u_int recvsz;
+ */
+extern CLIENT *clntudp_create (struct sockaddr_in *__raddr, u_long __program,
+ u_long __version, struct timeval __wait_resend,
+ int *__sockp) __THROW;
+libc_hidden_proto(clntudp_create)
+extern CLIENT *clntudp_bufcreate (struct sockaddr_in *__raddr,
+ u_long __program, u_long __version,
+ struct timeval __wait_resend, int *__sockp,
+ u_int __sendsz, u_int __recvsz) __THROW;
+libc_hidden_proto(clntudp_bufcreate)
+
+
+/*
+ * AF_UNIX based rpc
+ * CLIENT *
+ * clntunix_create(raddr, prog, vers, sockp, sendsz, recvsz)
+ * struct sockaddr_un *raddr;
+ * u_long prog;
+ * u_long version;
+ * register int *sockp;
+ * u_int sendsz;
+ * u_int recvsz;
+ */
+extern CLIENT *clntunix_create (struct sockaddr_un *__raddr, u_long __program,
+ u_long __version, int *__sockp,
+ u_int __sendsz, u_int __recvsz) __THROW;
+libc_hidden_proto(clntunix_create)
+
+
+extern int callrpc (__const char *__host, __const u_long __prognum,
+ __const u_long __versnum, __const u_long __procnum,
+ __const xdrproc_t __inproc, __const char *__in,
+ __const xdrproc_t __outproc, char *__out) __THROW;
+extern int _rpc_dtablesize (void) __THROW;
+libc_hidden_proto(_rpc_dtablesize)
+
+/*
+ * Print why creation failed
+ */
+extern void clnt_pcreateerror (__const char *__msg); /* stderr */
+extern char *clnt_spcreateerror(__const char *__msg) __THROW; /* string */
+libc_hidden_proto(clnt_spcreateerror)
+
+/*
+ * Like clnt_perror(), but is more verbose in its output
+ */
+extern void clnt_perrno (enum clnt_stat __num); /* stderr */
+
+/*
+ * Print an English error message, given the client error code
+ */
+extern void clnt_perror (CLIENT *__clnt, __const char *__msg);
+ /* stderr */
+libc_hidden_proto(clnt_perror)
+extern char *clnt_sperror (CLIENT *__clnt, __const char *__msg) __THROW;
+ /* string */
+libc_hidden_proto(clnt_sperror)
+
+
+/*
+ * If a creation fails, the following allows the user to figure out why.
+ */
+struct rpc_createerr {
+ enum clnt_stat cf_stat;
+ struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */
+};
+
+extern struct rpc_createerr rpc_createerr;
+
+
+
+/*
+ * Copy error message to buffer.
+ */
+extern char *clnt_sperrno (enum clnt_stat __num) __THROW; /* string */
+libc_hidden_proto(clnt_sperrno)
+
+/*
+ * get the port number on the host for the rpc program,version and proto
+ */
+extern int getrpcport (__const char * __host, u_long __prognum,
+ u_long __versnum, u_int proto) __THROW;
+
+/*
+ * get the local host's IP address without consulting
+ * name service library functions
+ */
+extern void get_myaddress (struct sockaddr_in *) __THROW;
+
+#define UDPMSGSIZE 8800 /* rpc imposed limit on udp msg size */
+#define RPCSMALLMSGSIZE 400 /* a more reasonable packet size */
+
+__END_DECLS
+
+#endif /* rpc/clnt.h */
diff --git a/android/librpc/rpc/des_crypt.h b/android/librpc/rpc/des_crypt.h
new file mode 100644
index 0000000..6a65887
--- a/dev/null
+++ b/android/librpc/rpc/des_crypt.h
@@ -0,0 +1,97 @@
+/*
+ * @(#)des_crypt.h 2.1 88/08/11 4.0 RPCSRC; from 1.4 88/02/08 (C) 1986 SMI
+ *
+ * des_crypt.h, des library routine interface
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#ifndef __DES_CRYPT_H__
+#define __DES_CRYPT_H__ 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+#define DES_MAXDATA 8192 /* max bytes encrypted in one call */
+#define DES_DIRMASK (1 << 0)
+#define DES_ENCRYPT (0*DES_DIRMASK) /* Encrypt */
+#define DES_DECRYPT (1*DES_DIRMASK) /* Decrypt */
+
+
+#define DES_DEVMASK (1 << 1)
+#define DES_HW (0*DES_DEVMASK) /* Use hardware device */
+#define DES_SW (1*DES_DEVMASK) /* Use software device */
+
+
+#define DESERR_NONE 0 /* succeeded */
+#define DESERR_NOHWDEVICE 1 /* succeeded, but hw device not available */
+#define DESERR_HWERROR 2 /* failed, hardware/driver error */
+#define DESERR_BADPARAM 3 /* failed, bad parameter to call */
+
+#define DES_FAILED(err) \
+ ((err) > DESERR_NOHWDEVICE)
+
+/*
+ * cbc_crypt()
+ * ecb_crypt()
+ *
+ * Encrypt (or decrypt) len bytes of a buffer buf.
+ * The length must be a multiple of eight.
+ * The key should have odd parity in the low bit of each byte.
+ * ivec is the input vector, and is updated to the new one (cbc only).
+ * The mode is created by oring together the appropriate parameters.
+ * DESERR_NOHWDEVICE is returned if DES_HW was specified but
+ * there was no hardware to do it on (the data will still be
+ * encrypted though, in software).
+ */
+
+
+/*
+ * Cipher Block Chaining mode
+ */
+extern int cbc_crypt (char *__key, char *__buf, unsigned __len,
+ unsigned __mode, char *__ivec) __THROW;
+
+/*
+ * Electronic Code Book mode
+ */
+extern int ecb_crypt (char *__key, char *__buf, unsigned __len,
+ unsigned __mode) __THROW;
+
+/*
+ * Set des parity for a key.
+ * DES parity is odd and in the low bit of each byte
+ */
+extern void des_setparity (char *__key) __THROW;
+
+__END_DECLS
+
+#endif
diff --git a/android/librpc/rpc/key_prot.h b/android/librpc/rpc/key_prot.h
new file mode 100644
index 0000000..629e249
--- a/dev/null
+++ b/android/librpc/rpc/key_prot.h
@@ -0,0 +1,346 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _KEY_PROT_H_RPCGEN
+#define _KEY_PROT_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+#pragma ident "@(#)key_prot.x 1.7 94/04/29 SMI"
+#endif
+/* Copyright (c) 1990, 1991 Sun Microsystems, Inc. */
+
+/*
+ * Compiled from key_prot.x using rpcgen.
+ * DO NOT EDIT THIS FILE!
+ * This is NOT source code!
+ */
+#define PROOT 3
+#define HEXMODULUS "d4a0ba0250b6fd2ec626e7efd637df76c716e22d0944b88b"
+#define HEXKEYBYTES 48
+#define KEYSIZE 192
+#define KEYBYTES 24
+#define KEYCHECKSUMSIZE 16
+
+enum keystatus {
+ KEY_SUCCESS = 0,
+ KEY_NOSECRET = 1,
+ KEY_UNKNOWN = 2,
+ KEY_SYSTEMERR = 3,
+};
+typedef enum keystatus keystatus;
+#ifdef __cplusplus
+extern "C" bool_t xdr_keystatus(XDR *, keystatus*);
+#elif __STDC__
+extern bool_t xdr_keystatus(XDR *, keystatus*);
+#else /* Old Style C */
+bool_t xdr_keystatus();
+#endif /* Old Style C */
+
+
+typedef char keybuf[HEXKEYBYTES];
+#ifdef __cplusplus
+extern "C" bool_t xdr_keybuf(XDR *, keybuf);
+#elif __STDC__
+extern bool_t xdr_keybuf(XDR *, keybuf);
+#else /* Old Style C */
+bool_t xdr_keybuf();
+#endif /* Old Style C */
+
+
+typedef char *netnamestr;
+#ifdef __cplusplus
+extern "C" bool_t xdr_netnamestr(XDR *, netnamestr*);
+#elif __STDC__
+extern bool_t xdr_netnamestr(XDR *, netnamestr*);
+#else /* Old Style C */
+bool_t xdr_netnamestr();
+#endif /* Old Style C */
+
+
+struct cryptkeyarg {
+ netnamestr remotename;
+ des_block deskey;
+};
+typedef struct cryptkeyarg cryptkeyarg;
+#ifdef __cplusplus
+extern "C" bool_t xdr_cryptkeyarg(XDR *, cryptkeyarg*);
+#elif __STDC__
+extern bool_t xdr_cryptkeyarg(XDR *, cryptkeyarg*);
+#else /* Old Style C */
+bool_t xdr_cryptkeyarg();
+#endif /* Old Style C */
+
+
+struct cryptkeyarg2 {
+ netnamestr remotename;
+ netobj remotekey;
+ des_block deskey;
+};
+typedef struct cryptkeyarg2 cryptkeyarg2;
+#ifdef __cplusplus
+extern "C" bool_t xdr_cryptkeyarg2(XDR *, cryptkeyarg2*);
+#elif __STDC__
+extern bool_t xdr_cryptkeyarg2(XDR *, cryptkeyarg2*);
+#else /* Old Style C */
+bool_t xdr_cryptkeyarg2();
+#endif /* Old Style C */
+
+
+struct cryptkeyres {
+ keystatus status;
+ union {
+ des_block deskey;
+ } cryptkeyres_u;
+};
+typedef struct cryptkeyres cryptkeyres;
+#ifdef __cplusplus
+extern "C" bool_t xdr_cryptkeyres(XDR *, cryptkeyres*);
+#elif __STDC__
+extern bool_t xdr_cryptkeyres(XDR *, cryptkeyres*);
+#else /* Old Style C */
+bool_t xdr_cryptkeyres();
+#endif /* Old Style C */
+
+#define MAXGIDS 16
+
+struct unixcred {
+ u_int uid;
+ u_int gid;
+ struct {
+ u_int gids_len;
+ u_int *gids_val;
+ } gids;
+};
+typedef struct unixcred unixcred;
+#ifdef __cplusplus
+extern "C" bool_t xdr_unixcred(XDR *, unixcred*);
+#elif __STDC__
+extern bool_t xdr_unixcred(XDR *, unixcred*);
+#else /* Old Style C */
+bool_t xdr_unixcred();
+#endif /* Old Style C */
+
+
+struct getcredres {
+ keystatus status;
+ union {
+ unixcred cred;
+ } getcredres_u;
+};
+typedef struct getcredres getcredres;
+#ifdef __cplusplus
+extern "C" bool_t xdr_getcredres(XDR *, getcredres*);
+#elif __STDC__
+extern bool_t xdr_getcredres(XDR *, getcredres*);
+#else /* Old Style C */
+bool_t xdr_getcredres();
+#endif /* Old Style C */
+
+
+struct key_netstarg {
+ keybuf st_priv_key;
+ keybuf st_pub_key;
+ netnamestr st_netname;
+};
+typedef struct key_netstarg key_netstarg;
+#ifdef __cplusplus
+extern "C" bool_t xdr_key_netstarg(XDR *, key_netstarg*);
+#elif __STDC__
+extern bool_t xdr_key_netstarg(XDR *, key_netstarg*);
+#else /* Old Style C */
+bool_t xdr_key_netstarg();
+#endif /* Old Style C */
+
+
+struct key_netstres {
+ keystatus status;
+ union {
+ key_netstarg knet;
+ } key_netstres_u;
+};
+typedef struct key_netstres key_netstres;
+#ifdef __cplusplus
+extern "C" bool_t xdr_key_netstres(XDR *, key_netstres*);
+#elif __STDC__
+extern bool_t xdr_key_netstres(XDR *, key_netstres*);
+#else /* Old Style C */
+bool_t xdr_key_netstres();
+#endif /* Old Style C */
+
+
+#ifndef opaque
+#define opaque char
+#endif
+
+
+#define KEY_PROG ((u_long)100029)
+#define KEY_VERS ((u_long)1)
+
+#ifdef __cplusplus
+#define KEY_SET ((u_long)1)
+extern "C" keystatus * key_set_1(opaque *, CLIENT *);
+extern "C" keystatus * key_set_1_svc(opaque *, struct svc_req *);
+#define KEY_ENCRYPT ((u_long)2)
+extern "C" cryptkeyres * key_encrypt_1(cryptkeyarg *, CLIENT *);
+extern "C" cryptkeyres * key_encrypt_1_svc(cryptkeyarg *, struct svc_req *);
+#define KEY_DECRYPT ((u_long)3)
+extern "C" cryptkeyres * key_decrypt_1(cryptkeyarg *, CLIENT *);
+extern "C" cryptkeyres * key_decrypt_1_svc(cryptkeyarg *, struct svc_req *);
+#define KEY_GEN ((u_long)4)
+extern "C" des_block * key_gen_1(void *, CLIENT *);
+extern "C" des_block * key_gen_1_svc(void *, struct svc_req *);
+#define KEY_GETCRED ((u_long)5)
+extern "C" getcredres * key_getcred_1(netnamestr *, CLIENT *);
+extern "C" getcredres * key_getcred_1_svc(netnamestr *, struct svc_req *);
+
+#elif __STDC__
+#define KEY_SET ((u_long)1)
+extern keystatus * key_set_1(opaque *, CLIENT *);
+extern keystatus * key_set_1_svc(opaque *, struct svc_req *);
+#define KEY_ENCRYPT ((u_long)2)
+extern cryptkeyres * key_encrypt_1(cryptkeyarg *, CLIENT *);
+extern cryptkeyres * key_encrypt_1_svc(cryptkeyarg *, struct svc_req *);
+#define KEY_DECRYPT ((u_long)3)
+extern cryptkeyres * key_decrypt_1(cryptkeyarg *, CLIENT *);
+extern cryptkeyres * key_decrypt_1_svc(cryptkeyarg *, struct svc_req *);
+#define KEY_GEN ((u_long)4)
+extern des_block * key_gen_1(void *, CLIENT *);
+extern des_block * key_gen_1_svc(void *, struct svc_req *);
+#define KEY_GETCRED ((u_long)5)
+extern getcredres * key_getcred_1(netnamestr *, CLIENT *);
+extern getcredres * key_getcred_1_svc(netnamestr *, struct svc_req *);
+
+#else /* Old Style C */
+#define KEY_SET ((u_long)1)
+extern keystatus * key_set_1();
+extern keystatus * key_set_1_svc();
+#define KEY_ENCRYPT ((u_long)2)
+extern cryptkeyres * key_encrypt_1();
+extern cryptkeyres * key_encrypt_1_svc();
+#define KEY_DECRYPT ((u_long)3)
+extern cryptkeyres * key_decrypt_1();
+extern cryptkeyres * key_decrypt_1_svc();
+#define KEY_GEN ((u_long)4)
+extern des_block * key_gen_1();
+extern des_block * key_gen_1_svc();
+#define KEY_GETCRED ((u_long)5)
+extern getcredres * key_getcred_1();
+extern getcredres * key_getcred_1_svc();
+#endif /* Old Style C */
+#define KEY_VERS2 ((u_long)2)
+
+#ifdef __cplusplus
+extern "C" keystatus * key_set_2(opaque *, CLIENT *);
+extern "C" keystatus * key_set_2_svc(opaque *, struct svc_req *);
+extern "C" cryptkeyres * key_encrypt_2(cryptkeyarg *, CLIENT *);
+extern "C" cryptkeyres * key_encrypt_2_svc(cryptkeyarg *, struct svc_req *);
+extern "C" cryptkeyres * key_decrypt_2(cryptkeyarg *, CLIENT *);
+extern "C" cryptkeyres * key_decrypt_2_svc(cryptkeyarg *, struct svc_req *);
+extern "C" des_block * key_gen_2(void *, CLIENT *);
+extern "C" des_block * key_gen_2_svc(void *, struct svc_req *);
+extern "C" getcredres * key_getcred_2(netnamestr *, CLIENT *);
+extern "C" getcredres * key_getcred_2_svc(netnamestr *, struct svc_req *);
+#define KEY_ENCRYPT_PK ((u_long)6)
+extern "C" cryptkeyres * key_encrypt_pk_2(cryptkeyarg2 *, CLIENT *);
+extern "C" cryptkeyres * key_encrypt_pk_2_svc(cryptkeyarg2 *, struct svc_req *);
+#define KEY_DECRYPT_PK ((u_long)7)
+extern "C" cryptkeyres * key_decrypt_pk_2(cryptkeyarg2 *, CLIENT *);
+extern "C" cryptkeyres * key_decrypt_pk_2_svc(cryptkeyarg2 *, struct svc_req *);
+#define KEY_NET_PUT ((u_long)8)
+extern "C" keystatus * key_net_put_2(key_netstarg *, CLIENT *);
+extern "C" keystatus * key_net_put_2_svc(key_netstarg *, struct svc_req *);
+#define KEY_NET_GET ((u_long)9)
+extern "C" key_netstres * key_net_get_2(void *, CLIENT *);
+extern "C" key_netstres * key_net_get_2_svc(void *, struct svc_req *);
+#define KEY_GET_CONV ((u_long)10)
+extern "C" cryptkeyres * key_get_conv_2(opaque *, CLIENT *);
+extern "C" cryptkeyres * key_get_conv_2_svc(opaque *, struct svc_req *);
+
+#elif __STDC__
+extern keystatus * key_set_2(opaque *, CLIENT *);
+extern keystatus * key_set_2_svc(opaque *, struct svc_req *);
+extern cryptkeyres * key_encrypt_2(cryptkeyarg *, CLIENT *);
+extern cryptkeyres * key_encrypt_2_svc(cryptkeyarg *, struct svc_req *);
+extern cryptkeyres * key_decrypt_2(cryptkeyarg *, CLIENT *);
+extern cryptkeyres * key_decrypt_2_svc(cryptkeyarg *, struct svc_req *);
+extern des_block * key_gen_2(void *, CLIENT *);
+extern des_block * key_gen_2_svc(void *, struct svc_req *);
+extern getcredres * key_getcred_2(netnamestr *, CLIENT *);
+extern getcredres * key_getcred_2_svc(netnamestr *, struct svc_req *);
+#define KEY_ENCRYPT_PK ((u_long)6)
+extern cryptkeyres * key_encrypt_pk_2(cryptkeyarg2 *, CLIENT *);
+extern cryptkeyres * key_encrypt_pk_2_svc(cryptkeyarg2 *, struct svc_req *);
+#define KEY_DECRYPT_PK ((u_long)7)
+extern cryptkeyres * key_decrypt_pk_2(cryptkeyarg2 *, CLIENT *);
+extern cryptkeyres * key_decrypt_pk_2_svc(cryptkeyarg2 *, struct svc_req *);
+#define KEY_NET_PUT ((u_long)8)
+extern keystatus * key_net_put_2(key_netstarg *, CLIENT *);
+extern keystatus * key_net_put_2_svc(key_netstarg *, struct svc_req *);
+#define KEY_NET_GET ((u_long)9)
+extern key_netstres * key_net_get_2(void *, CLIENT *);
+extern key_netstres * key_net_get_2_svc(void *, struct svc_req *);
+#define KEY_GET_CONV ((u_long)10)
+extern cryptkeyres * key_get_conv_2(opaque *, CLIENT *);
+extern cryptkeyres * key_get_conv_2_svc(opaque *, struct svc_req *);
+
+#else /* Old Style C */
+extern keystatus * key_set_2();
+extern keystatus * key_set_2_svc();
+extern cryptkeyres * key_encrypt_2();
+extern cryptkeyres * key_encrypt_2_svc();
+extern cryptkeyres * key_decrypt_2();
+extern cryptkeyres * key_decrypt_2_svc();
+extern des_block * key_gen_2();
+extern des_block * key_gen_2_svc();
+extern getcredres * key_getcred_2();
+extern getcredres * key_getcred_2_svc();
+#define KEY_ENCRYPT_PK ((u_long)6)
+extern cryptkeyres * key_encrypt_pk_2();
+extern cryptkeyres * key_encrypt_pk_2_svc();
+#define KEY_DECRYPT_PK ((u_long)7)
+extern cryptkeyres * key_decrypt_pk_2();
+extern cryptkeyres * key_decrypt_pk_2_svc();
+#define KEY_NET_PUT ((u_long)8)
+extern keystatus * key_net_put_2();
+extern keystatus * key_net_put_2_svc();
+#define KEY_NET_GET ((u_long)9)
+extern key_netstres * key_net_get_2();
+extern key_netstres * key_net_get_2_svc();
+#define KEY_GET_CONV ((u_long)10)
+extern cryptkeyres * key_get_conv_2();
+extern cryptkeyres * key_get_conv_2_svc();
+#endif /* Old Style C */
+
+#endif /* !_KEY_PROT_H_RPCGEN */
diff --git a/android/librpc/rpc/netdb.h b/android/librpc/rpc/netdb.h
new file mode 100644
index 0000000..e9a6565
--- a/dev/null
+++ b/android/librpc/rpc/netdb.h
@@ -0,0 +1,79 @@
+/* @(#)netdb.h 2.1 88/07/29 3.9 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/* @(#)rpc.h 1.8 87/07/24 SMI */
+
+/* Cleaned up for GNU C library roland@gnu.ai.mit.edu:
+ added multiple inclusion protection and use of <sys/cdefs.h>.
+ In GNU this file is #include'd by <netdb.h>. */
+
+#ifndef _RPC_NETDB_H
+#define _RPC_NETDB_H 1
+
+#include <features.h>
+
+#define __need_size_t
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+struct rpcent
+{
+ char *r_name; /* Name of server for this rpc program. */
+ char **r_aliases; /* Alias list. */
+ int r_number; /* RPC program number. */
+};
+
+extern void setrpcent (int __stayopen) __THROW;
+libc_hidden_proto(setrpcent)
+extern void endrpcent (void) __THROW;
+libc_hidden_proto(endrpcent)
+extern struct rpcent *getrpcbyname (__const char *__name) __THROW;
+libc_hidden_proto(getrpcbyname)
+extern struct rpcent *getrpcbynumber (int __number) __THROW;
+libc_hidden_proto(getrpcbynumber)
+extern struct rpcent *getrpcent (void) __THROW;
+libc_hidden_proto(getrpcent)
+
+#if defined __USE_MISC && defined __UCLIBC_HAS_REENTRANT_RPC__
+extern int getrpcbyname_r (__const char *__name, struct rpcent *__result_buf,
+ char *__buffer, size_t __buflen,
+ struct rpcent **__result) __THROW;
+
+extern int getrpcbynumber_r (int __number, struct rpcent *__result_buf,
+ char *__buffer, size_t __buflen,
+ struct rpcent **__result) __THROW;
+
+extern int getrpcent_r (struct rpcent *__result_buf, char *__buffer,
+ size_t __buflen, struct rpcent **__result) __THROW;
+#endif
+
+__END_DECLS
+
+#endif /* rpc/netdb.h */
diff --git a/android/librpc/rpc/pmap_clnt.h b/android/librpc/rpc/pmap_clnt.h
new file mode 100644
index 0000000..f5e825d
--- a/dev/null
+++ b/android/librpc/rpc/pmap_clnt.h
@@ -0,0 +1,101 @@
+/* @(#)pmap_clnt.h 2.1 88/07/29 4.0 RPCSRC; from 1.11 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * pmap_clnt.h
+ * Supplies C routines to get to portmap services.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_PMAP_CLNT_H
+#define _RPC_PMAP_CLNT_H 1
+
+#include <features.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/clnt.h>
+
+__BEGIN_DECLS
+
+typedef bool_t (*resultproc_t) (caddr_t resp, struct sockaddr_in *raddr);
+
+/*
+ * Usage:
+ * success = pmap_set(program, version, protocol, port);
+ * success = pmap_unset(program, version);
+ * port = pmap_getport(address, program, version, protocol);
+ * head = pmap_getmaps(address);
+ * clnt_stat = pmap_rmtcall(address, program, version, procedure,
+ * xdrargs, argsp, xdrres, resp, tout, port_ptr)
+ * (works for udp only.)
+ * clnt_stat = clnt_broadcast(program, version, procedure,
+ * xdrargs, argsp, xdrres, resp, eachresult)
+ * (like pmap_rmtcall, except the call is broadcasted to all
+ * locally connected nets. For each valid response received,
+ * the procedure eachresult is called. Its form is:
+ * done = eachresult(resp, raddr)
+ * bool_t done;
+ * caddr_t resp;
+ * struct sockaddr_in raddr;
+ * where resp points to the results of the call and raddr is the
+ * address if the responder to the broadcast.
+ */
+
+extern bool_t pmap_set (__const u_long __program, __const u_long __vers,
+ int __protocol, u_short __port) __THROW;
+libc_hidden_proto(pmap_set)
+extern bool_t pmap_unset (__const u_long __program, __const u_long __vers)
+ __THROW;
+libc_hidden_proto(pmap_unset)
+extern struct pmaplist *pmap_getmaps (struct sockaddr_in *__address) __THROW;
+extern enum clnt_stat pmap_rmtcall (struct sockaddr_in *__addr,
+ __const u_long __prog,
+ __const u_long __vers,
+ __const u_long __proc,
+ xdrproc_t __xdrargs,
+ caddr_t __argsp, xdrproc_t __xdrres,
+ caddr_t __resp, struct timeval __tout,
+ u_long *__port_ptr) __THROW;
+extern enum clnt_stat clnt_broadcast (__const u_long __prog,
+ __const u_long __vers,
+ __const u_long __proc, xdrproc_t __xargs,
+ caddr_t __argsp, xdrproc_t __xresults,
+ caddr_t __resultsp,
+ resultproc_t __eachresult) __THROW;
+extern u_short pmap_getport (struct sockaddr_in *__address,
+ __const u_long __program,
+ __const u_long __version, u_int __protocol)
+ __THROW;
+libc_hidden_proto(pmap_getport)
+
+__END_DECLS
+
+#endif /* rpc/pmap_clnt.h */
diff --git a/android/librpc/rpc/pmap_prot.h b/android/librpc/rpc/pmap_prot.h
new file mode 100644
index 0000000..30b2670
--- a/dev/null
+++ b/android/librpc/rpc/pmap_prot.h
@@ -0,0 +1,110 @@
+/* @(#)pmap_prot.h 2.1 88/07/29 4.0 RPCSRC; from 1.14 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * pmap_prot.h
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_PMAP_PROT_H
+#define _RPC_PMAP_PROT_H 1
+
+#include <features.h>
+
+#include <rpc/xdr.h>
+
+__BEGIN_DECLS
+
+/* The following procedures are supported by the protocol:
+ *
+ * PMAPPROC_NULL() returns ()
+ * takes nothing, returns nothing
+ *
+ * PMAPPROC_SET(struct pmap) returns (bool_t)
+ * TRUE is success, FALSE is failure. Registers the tuple
+ * [prog, vers, prot, port].
+ *
+ * PMAPPROC_UNSET(struct pmap) returns (bool_t)
+ * TRUE is success, FALSE is failure. Un-registers pair
+ * [prog, vers]. prot and port are ignored.
+ *
+ * PMAPPROC_GETPORT(struct pmap) returns (long unsigned).
+ * 0 is failure. Otherwise returns the port number where the pair
+ * [prog, vers] is registered. It may lie!
+ *
+ * PMAPPROC_DUMP() RETURNS (struct pmaplist *)
+ *
+ * PMAPPROC_CALLIT(unsigned, unsigned, unsigned, string<>)
+ * RETURNS (port, string<>);
+ * usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs);
+ * Calls the procedure on the local machine. If it is not registered,
+ * this procedure is quite; ie it does not return error information!!!
+ * This procedure only is supported on rpc/udp and calls via
+ * rpc/udp. This routine only passes null authentication parameters.
+ * This file has no interface to xdr routines for PMAPPROC_CALLIT.
+ *
+ * The service supports remote procedure calls on udp/ip or tcp/ip socket 111.
+ */
+
+#define PMAPPORT ((u_short)111)
+#define PMAPPROG ((u_long)100000)
+#define PMAPVERS ((u_long)2)
+#define PMAPVERS_PROTO ((u_long)2)
+#define PMAPVERS_ORIG ((u_long)1)
+#define PMAPPROC_NULL ((u_long)0)
+#define PMAPPROC_SET ((u_long)1)
+#define PMAPPROC_UNSET ((u_long)2)
+#define PMAPPROC_GETPORT ((u_long)3)
+#define PMAPPROC_DUMP ((u_long)4)
+#define PMAPPROC_CALLIT ((u_long)5)
+
+struct pmap {
+ long unsigned pm_prog;
+ long unsigned pm_vers;
+ long unsigned pm_prot;
+ long unsigned pm_port;
+};
+
+extern bool_t xdr_pmap (XDR *__xdrs, struct pmap *__regs) __THROW;
+libc_hidden_proto(xdr_pmap)
+
+struct pmaplist {
+ struct pmap pml_map;
+ struct pmaplist *pml_next;
+};
+
+extern bool_t xdr_pmaplist (XDR *__xdrs, struct pmaplist **__rp) __THROW;
+libc_hidden_proto(xdr_pmaplist)
+
+__END_DECLS
+
+#endif /* rpc/pmap_prot.h */
diff --git a/android/librpc/rpc/pmap_rmt.h b/android/librpc/rpc/pmap_rmt.h
new file mode 100644
index 0000000..59b4f65
--- a/dev/null
+++ b/android/librpc/rpc/pmap_rmt.h
@@ -0,0 +1,71 @@
+/* @(#)pmap_rmt.h 2.1 88/07/29 4.0 RPCSRC; from 1.2 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * Structures and XDR routines for parameters to and replies from
+ * the portmapper remote-call-service.
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_PMAP_RMT_H
+#define _RPC_PMAP_RMT_H 1
+
+#include <features.h>
+#include <sys/types.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+__BEGIN_DECLS
+
+struct rmtcallargs {
+ u_long prog, vers, proc, arglen;
+ caddr_t args_ptr;
+ xdrproc_t xdr_args;
+};
+
+extern bool_t xdr_rmtcall_args (XDR *__xdrs, struct rmtcallargs *__crp)
+ __THROW;
+libc_hidden_proto(xdr_rmtcall_args)
+
+
+struct rmtcallres {
+ u_long *port_ptr;
+ u_long resultslen;
+ caddr_t results_ptr;
+ xdrproc_t xdr_results;
+};
+
+extern bool_t xdr_rmtcallres (XDR *__xdrs, struct rmtcallres *__crp) __THROW;
+libc_hidden_proto(xdr_rmtcallres)
+
+__END_DECLS
+
+#endif /* rpc/pmap_rmt.h */
diff --git a/android/librpc/rpc/rpc.h b/android/librpc/rpc/rpc.h
new file mode 100644
index 0000000..abcab9e
--- a/dev/null
+++ b/android/librpc/rpc/rpc.h
@@ -0,0 +1,119 @@
+/* @(#)rpc.h 2.3 88/08/10 4.0 RPCSRC; from 1.9 88/02/08 SMI */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * rpc.h, Just includes the billions of rpc header files necessary to
+ * do remote procedure calling.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_RPC_H
+#define _RPC_RPC_H 1
+
+#ifdef _LIBC
+/* Some adjustments to make the libc source from glibc
+ * compile more easily with uClibc... */
+#ifndef __FORCE_GLIBC
+#define __FORCE_GLIBC
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#define _(X) X
+#include <features.h>
+#endif
+
+#include <rpc/types.h> /* some typedefs */
+#include <netinet/in.h>
+
+/* external data representation interfaces */
+#include <rpc/xdr.h> /* generic (de)serializer */
+
+/* Client side only authentication */
+#include <rpc/auth.h> /* generic authenticator (client side) */
+
+/* Client side (mostly) remote procedure call */
+#include <rpc/clnt.h> /* generic rpc stuff */
+
+/* semi-private protocol headers */
+#include <rpc/rpc_msg.h> /* protocol for rpc messages */
+#include <rpc/auth_unix.h> /* protocol for unix style cred */
+#include <rpc/auth_des.h> /* protocol for des style cred */
+
+/* Server side only remote procedure callee */
+#include <rpc/svc.h> /* service manager and multiplexer */
+#include <rpc/svc_auth.h> /* service side authenticator */
+
+/*
+ * COMMENT OUT THE NEXT INCLUDE IF RUNNING ON SUN OS OR ON A VERSION
+ * OF UNIX BASED ON NFSSRC. These systems will already have the structures
+ * defined by <rpc/netdb.h> included in <netdb.h>.
+ */
+/* routines for parsing /etc/rpc */
+#include <rpc/netdb.h> /* structures and routines to parse /etc/rpc */
+
+__BEGIN_DECLS
+
+/* Global variables, protected for multi-threaded applications. */
+extern fd_set *__rpc_thread_svc_fdset (void) __attribute__ ((__const__));
+libc_hidden_proto(__rpc_thread_svc_fdset)
+#define svc_fdset (*__rpc_thread_svc_fdset ())
+
+extern struct rpc_createerr *__rpc_thread_createerr (void)
+ __attribute__ ((__const__));
+libc_hidden_proto(__rpc_thread_createerr)
+#define get_rpc_createerr() (*__rpc_thread_createerr ())
+/* The people who "engineered" RPC should bee punished for naming the
+ data structure and the variable the same. We cannot always define the
+ macro 'rpc_createerr' because this would prevent people from defining
+ object of type 'struct rpc_createerr'. So we leave it up to the user
+ to select transparent replacement also of this variable. */
+#ifdef _RPC_MT_VARS
+# define rpc_createerr (*__rpc_thread_createerr ())
+#endif
+
+extern struct pollfd **__rpc_thread_svc_pollfd (void)
+ __attribute__ ((__const__));
+libc_hidden_proto(__rpc_thread_svc_pollfd)
+#define svc_pollfd (*__rpc_thread_svc_pollfd ())
+
+extern int *__rpc_thread_svc_max_pollfd (void) __attribute__ ((__const__));
+libc_hidden_proto(__rpc_thread_svc_max_pollfd)
+#define svc_max_pollfd (*__rpc_thread_svc_max_pollfd ())
+
+extern bool_t xdr_accepted_reply (XDR *xdrs, struct accepted_reply *ar);
+libc_hidden_proto(xdr_accepted_reply)
+extern bool_t xdr_rejected_reply (XDR *xdrs, struct rejected_reply *rr);
+libc_hidden_proto(xdr_rejected_reply)
+
+__END_DECLS
+
+#endif /* rpc/rpc.h */
diff --git a/android/librpc/rpc/rpc_des.h b/android/librpc/rpc/rpc_des.h
new file mode 100644
index 0000000..96e5369
--- a/dev/null
+++ b/android/librpc/rpc/rpc_des.h
@@ -0,0 +1,72 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * Generic DES driver interface
+ * Keep this file hardware independent!
+ * Copyright (c) 1986 by Sun Microsystems, Inc.
+ */
+
+#ifndef _DES_H
+#define _DES_H
+
+#include <sys/types.h>
+
+#define DES_MAXLEN 65536 /* maximum # of bytes to encrypt */
+#define DES_QUICKLEN 16 /* maximum # of bytes to encrypt quickly */
+
+enum desdir
+ {
+ ENCRYPT, DECRYPT
+ };
+enum desmode
+ {
+ CBC, ECB
+ };
+
+/*
+ * parameters to ioctl call
+ */
+struct desparams
+ {
+ u_char des_key[8]; /* key (with low bit parity) */
+ enum desdir des_dir; /* direction */
+ enum desmode des_mode; /* mode */
+ u_char des_ivec[8]; /* input vector */
+ unsigned des_len; /* number of bytes to crypt */
+ union
+ {
+ u_char UDES_data[DES_QUICKLEN];
+ u_char *UDES_buf;
+ }
+ UDES;
+#define des_data UDES.UDES_data /* direct data here if quick */
+#define des_buf UDES.UDES_buf /* otherwise, pointer to data */
+ };
+
+#endif
diff --git a/android/librpc/rpc/rpc_msg.h b/android/librpc/rpc/rpc_msg.h
new file mode 100644
index 0000000..c848b39
--- a/dev/null
+++ b/android/librpc/rpc/rpc_msg.h
@@ -0,0 +1,206 @@
+/* @(#)rpc_msg.h 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/* @(#)rpc_msg.h 1.7 86/07/16 SMI */
+
+#ifndef _RPC_MSG_H
+#define _RPC_MSG_H 1
+
+#include <sys/cdefs.h>
+
+#include <rpc/xdr.h>
+#include <rpc/clnt.h>
+
+/*
+ * rpc_msg.h
+ * rpc message definition
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#define RPC_MSG_VERSION ((u_long) 2)
+#define RPC_SERVICE_PORT ((u_short) 2048)
+
+__BEGIN_DECLS
+
+/*
+ * Bottom up definition of an rpc message.
+ * NOTE: call and reply use the same overall struct but
+ * different parts of unions within it.
+ */
+
+enum msg_type {
+ CALL=0,
+ REPLY=1
+};
+
+enum reply_stat {
+ MSG_ACCEPTED=0,
+ MSG_DENIED=1
+};
+
+enum accept_stat {
+ SUCCESS=0,
+ PROG_UNAVAIL=1,
+ PROG_MISMATCH=2,
+ PROC_UNAVAIL=3,
+ GARBAGE_ARGS=4,
+ SYSTEM_ERR=5
+};
+
+enum reject_stat {
+ RPC_MISMATCH=0,
+ AUTH_ERROR=1
+};
+
+/*
+ * Reply part of an rpc exchange
+ */
+
+/*
+ * Reply to an rpc request that was accepted by the server.
+ * Note: there could be an error even though the request was
+ * accepted.
+ */
+struct accepted_reply {
+ struct opaque_auth ar_verf;
+ enum accept_stat ar_stat;
+ union {
+ struct {
+ u_long low;
+ u_long high;
+ } AR_versions;
+ struct {
+ caddr_t where;
+ xdrproc_t proc;
+ } AR_results;
+ /* and many other null cases */
+ } ru;
+#define ar_results ru.AR_results
+#define ar_vers ru.AR_versions
+};
+
+/*
+ * Reply to an rpc request that was rejected by the server.
+ */
+struct rejected_reply {
+ enum reject_stat rj_stat;
+ union {
+ struct {
+ u_long low;
+ u_long high;
+ } RJ_versions;
+ enum auth_stat RJ_why; /* why authentication did not work */
+ } ru;
+#define rj_vers ru.RJ_versions
+#define rj_why ru.RJ_why
+};
+
+/*
+ * Body of a reply to an rpc request.
+ */
+struct reply_body {
+ enum reply_stat rp_stat;
+ union {
+ struct accepted_reply RP_ar;
+ struct rejected_reply RP_dr;
+ } ru;
+#define rp_acpt ru.RP_ar
+#define rp_rjct ru.RP_dr
+};
+
+/*
+ * Body of an rpc request call.
+ */
+struct call_body {
+ u_long cb_rpcvers; /* must be equal to two */
+ u_long cb_prog;
+ u_long cb_vers;
+ u_long cb_proc;
+ struct opaque_auth cb_cred;
+ struct opaque_auth cb_verf; /* protocol specific - provided by client */
+};
+
+/*
+ * The rpc message
+ */
+struct rpc_msg {
+ u_long rm_xid;
+ enum msg_type rm_direction;
+ union {
+ struct call_body RM_cmb;
+ struct reply_body RM_rmb;
+ } ru;
+#define rm_call ru.RM_cmb
+#define rm_reply ru.RM_rmb
+};
+#define acpted_rply ru.RM_rmb.ru.RP_ar
+#define rjcted_rply ru.RM_rmb.ru.RP_dr
+
+
+/*
+ * XDR routine to handle a rpc message.
+ * xdr_callmsg(xdrs, cmsg)
+ * XDR *xdrs;
+ * struct rpc_msg *cmsg;
+ */
+extern bool_t xdr_callmsg (XDR *__xdrs, struct rpc_msg *__cmsg) __THROW;
+libc_hidden_proto(xdr_callmsg)
+
+/*
+ * XDR routine to pre-serialize the static part of a rpc message.
+ * xdr_callhdr(xdrs, cmsg)
+ * XDR *xdrs;
+ * struct rpc_msg *cmsg;
+ */
+extern bool_t xdr_callhdr (XDR *__xdrs, struct rpc_msg *__cmsg) __THROW;
+libc_hidden_proto(xdr_callhdr)
+
+/*
+ * XDR routine to handle a rpc reply.
+ * xdr_replymsg(xdrs, rmsg)
+ * XDR *xdrs;
+ * struct rpc_msg *rmsg;
+ */
+extern bool_t xdr_replymsg (XDR *__xdrs, struct rpc_msg *__rmsg) __THROW;
+libc_hidden_proto(xdr_replymsg)
+
+/*
+ * Fills in the error part of a reply message.
+ * _seterr_reply(msg, error)
+ * struct rpc_msg *msg;
+ * struct rpc_err *error;
+ */
+extern void _seterr_reply (struct rpc_msg *__msg, struct rpc_err *__error)
+ __THROW;
+libc_hidden_proto(_seterr_reply)
+
+__END_DECLS
+
+#endif /* rpc/rpc_msg.h */
diff --git a/android/librpc/rpc/svc.h b/android/librpc/rpc/svc.h
new file mode 100644
index 0000000..6898325
--- a/dev/null
+++ b/android/librpc/rpc/svc.h
@@ -0,0 +1,330 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * svc.h, Server-side remote procedure call interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_SVC_H
+#define _RPC_SVC_H 1
+
+#include <features.h>
+#include <rpc/rpc_msg.h>
+
+__BEGIN_DECLS
+
+/*
+ * This interface must manage two items concerning remote procedure calling:
+ *
+ * 1) An arbitrary number of transport connections upon which rpc requests
+ * are received. The two most notable transports are TCP and UDP; they are
+ * created and registered by routines in svc_tcp.c and svc_udp.c, respectively;
+ * they in turn call xprt_register and xprt_unregister.
+ *
+ * 2) An arbitrary number of locally registered services. Services are
+ * described by the following four data: program number, version number,
+ * "service dispatch" function, a transport handle, and a boolean that
+ * indicates whether or not the exported program should be registered with a
+ * local binder service; if true the program's number and version and the
+ * port number from the transport handle are registered with the binder.
+ * These data are registered with the rpc svc system via svc_register.
+ *
+ * A service's dispatch function is called whenever an rpc request comes in
+ * on a transport. The request's program and version numbers must match
+ * those of the registered service. The dispatch function is passed two
+ * parameters, struct svc_req * and SVCXPRT *, defined below.
+ */
+
+enum xprt_stat {
+ XPRT_DIED,
+ XPRT_MOREREQS,
+ XPRT_IDLE
+};
+
+/*
+ * Server side transport handle
+ */
+typedef struct SVCXPRT SVCXPRT;
+struct SVCXPRT {
+ int xp_sock;
+ u_short xp_port; /* associated port number */
+ const struct xp_ops {
+ bool_t (*xp_recv) (SVCXPRT *__xprt, struct rpc_msg *__msg);
+ /* receive incoming requests */
+ enum xprt_stat (*xp_stat) (SVCXPRT *__xprt);
+ /* get transport status */
+ bool_t (*xp_getargs) (SVCXPRT *__xprt, xdrproc_t __xdr_args,
+ caddr_t args_ptr); /* get arguments */
+ bool_t (*xp_reply) (SVCXPRT *__xprt, struct rpc_msg *__msg);
+ /* send reply */
+ bool_t (*xp_freeargs) (SVCXPRT *__xprt, xdrproc_t __xdr_args,
+ caddr_t args_ptr);
+ /* free mem allocated for args */
+ void (*xp_destroy) (SVCXPRT *__xprt);
+ /* destroy this struct */
+ } *xp_ops;
+ int xp_addrlen; /* length of remote address */
+ struct sockaddr_in xp_raddr; /* remote address */
+ struct opaque_auth xp_verf; /* raw response verifier */
+ caddr_t xp_p1; /* private */
+ caddr_t xp_p2; /* private */
+ char xp_pad [256]; /* padding, internal use */
+};
+
+/*
+ * Approved way of getting address of caller
+ */
+#define svc_getcaller(x) (&(x)->xp_raddr)
+
+/*
+ * Operations defined on an SVCXPRT handle
+ *
+ * SVCXPRT *xprt;
+ * struct rpc_msg *msg;
+ * xdrproc_t xargs;
+ * caddr_t argsp;
+ */
+#define SVC_RECV(xprt, msg) \
+ (*(xprt)->xp_ops->xp_recv)((xprt), (msg))
+#define svc_recv(xprt, msg) \
+ (*(xprt)->xp_ops->xp_recv)((xprt), (msg))
+
+#define SVC_STAT(xprt) \
+ (*(xprt)->xp_ops->xp_stat)(xprt)
+#define svc_stat(xprt) \
+ (*(xprt)->xp_ops->xp_stat)(xprt)
+
+#define SVC_GETARGS(xprt, xargs, argsp) \
+ (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
+#define svc_getargs(xprt, xargs, argsp) \
+ (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
+
+#define SVC_REPLY(xprt, msg) \
+ (*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
+#define svc_reply(xprt, msg) \
+ (*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
+
+#define SVC_FREEARGS(xprt, xargs, argsp) \
+ (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
+#define svc_freeargs(xprt, xargs, argsp) \
+ (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
+
+#define SVC_DESTROY(xprt) \
+ (*(xprt)->xp_ops->xp_destroy)(xprt)
+#define svc_destroy(xprt) \
+ (*(xprt)->xp_ops->xp_destroy)(xprt)
+
+
+/*
+ * Service request
+ */
+struct svc_req {
+ rpcprog_t rq_prog; /* service program number */
+ rpcvers_t rq_vers; /* service protocol version */
+ rpcproc_t rq_proc; /* the desired procedure */
+ struct opaque_auth rq_cred; /* raw creds from the wire */
+ caddr_t rq_clntcred; /* read only cooked cred */
+ SVCXPRT *rq_xprt; /* associated transport */
+};
+
+#ifndef __DISPATCH_FN_T
+#define __DISPATCH_FN_T
+typedef void (*__dispatch_fn_t) (struct svc_req*, SVCXPRT*);
+#endif
+
+/*
+ * Service registration
+ *
+ * svc_register(xprt, prog, vers, dispatch, protocol)
+ * SVCXPRT *xprt;
+ * rpcprog_t prog;
+ * rpcvers_t vers;
+ * void (*dispatch)(struct svc_req*, SVCXPRT*);
+ * rpcprot_t protocol; like TCP or UDP, zero means do not register
+ */
+extern bool_t svc_register (SVCXPRT *__xprt, rpcprog_t __prog,
+ rpcvers_t __vers, __dispatch_fn_t __dispatch,
+ rpcprot_t __protocol) __THROW;
+libc_hidden_proto(svc_register)
+
+/*
+ * Service un-registration
+ *
+ * svc_unregister(prog, vers)
+ * rpcprog_t prog;
+ * rpcvers_t vers;
+ */
+extern void svc_unregister (rpcprog_t __prog, rpcvers_t __vers) __THROW;
+libc_hidden_proto(svc_unregister)
+
+/*
+ * Transport registration.
+ *
+ * xprt_register(xprt)
+ * SVCXPRT *xprt;
+ */
+extern void xprt_register (SVCXPRT *__xprt) __THROW;
+libc_hidden_proto(xprt_register)
+
+/*
+ * Transport un-register
+ *
+ * xprt_unregister(xprt)
+ * SVCXPRT *xprt;
+ */
+extern void xprt_unregister (SVCXPRT *__xprt) __THROW;
+libc_hidden_proto(xprt_unregister)
+
+/*
+ * When the service routine is called, it must first check to see if it
+ * knows about the procedure; if not, it should call svcerr_noproc
+ * and return. If so, it should deserialize its arguments via
+ * SVC_GETARGS (defined above). If the deserialization does not work,
+ * svcerr_decode should be called followed by a return. Successful
+ * decoding of the arguments should be followed the execution of the
+ * procedure's code and a call to svc_sendreply.
+ *
+ * Also, if the service refuses to execute the procedure due to too-
+ * weak authentication parameters, svcerr_weakauth should be called.
+ * Note: do not confuse access-control failure with weak authentication!
+ *
+ * NB: In pure implementations of rpc, the caller always waits for a reply
+ * msg. This message is sent when svc_sendreply is called.
+ * Therefore pure service implementations should always call
+ * svc_sendreply even if the function logically returns void; use
+ * xdr.h - xdr_void for the xdr routine. HOWEVER, tcp based rpc allows
+ * for the abuse of pure rpc via batched calling or pipelining. In the
+ * case of a batched call, svc_sendreply should NOT be called since
+ * this would send a return message, which is what batching tries to avoid.
+ * It is the service/protocol writer's responsibility to know which calls are
+ * batched and which are not. Warning: responding to batch calls may
+ * deadlock the caller and server processes!
+ */
+
+extern bool_t svc_sendreply (SVCXPRT *xprt, xdrproc_t __xdr_results,
+ caddr_t __xdr_location) __THROW;
+libc_hidden_proto(svc_sendreply)
+
+extern void svcerr_decode (SVCXPRT *__xprt) __THROW;
+libc_hidden_proto(svcerr_decode)
+
+extern void svcerr_weakauth (SVCXPRT *__xprt) __THROW;
+
+extern void svcerr_noproc (SVCXPRT *__xprt) __THROW;
+
+extern void svcerr_progvers (SVCXPRT *__xprt, rpcvers_t __low_vers,
+ rpcvers_t __high_vers) __THROW;
+libc_hidden_proto(svcerr_progvers)
+
+extern void svcerr_auth (SVCXPRT *__xprt, enum auth_stat __why) __THROW;
+libc_hidden_proto(svcerr_auth)
+
+extern void svcerr_noprog (SVCXPRT *__xprt) __THROW;
+libc_hidden_proto(svcerr_noprog)
+
+extern void svcerr_systemerr (SVCXPRT *__xprt) __THROW;
+
+/*
+ * Lowest level dispatching -OR- who owns this process anyway.
+ * Somebody has to wait for incoming requests and then call the correct
+ * service routine. The routine svc_run does infinite waiting; i.e.,
+ * svc_run never returns.
+ * Since another (coexistent) package may wish to selectively wait for
+ * incoming calls or other events outside of the rpc architecture, the
+ * routine svc_getreq is provided. It must be passed readfds, the
+ * "in-place" results of a select system call (see select, section 2).
+ */
+
+/*
+ * Global keeper of rpc service descriptors in use
+ * dynamic; must be inspected before each call to select
+ */
+
+extern struct pollfd *svc_pollfd;
+extern int svc_max_pollfd;
+extern fd_set svc_fdset;
+#define svc_fds svc_fdset.fds_bits[0] /* compatibility */
+
+/*
+ * a small program implemented by the svc_rpc implementation itself;
+ * also see clnt.h for protocol numbers.
+ */
+extern void svc_getreq (int __rdfds) __THROW;
+libc_hidden_proto(svc_getreq)
+extern void svc_getreq_common (const int __fd) __THROW;
+libc_hidden_proto(svc_getreq_common)
+extern void svc_getreqset (fd_set *__readfds) __THROW;
+libc_hidden_proto(svc_getreqset)
+extern void svc_getreq_poll (struct pollfd *, const int) __THROW;
+libc_hidden_proto(svc_getreq_poll)
+extern void svc_exit (void) __THROW;
+extern void svc_run (void) __THROW;
+
+/*
+ * Socket to use on svcxxx_create call to get default socket
+ */
+#define RPC_ANYSOCK -1
+
+/*
+ * These are the existing service side transport implementations
+ */
+
+/*
+ * Memory based rpc for testing and timing.
+ */
+extern SVCXPRT *svcraw_create (void) __THROW;
+
+/*
+ * Udp based rpc.
+ */
+extern SVCXPRT *svcudp_create (int __sock) __THROW;
+libc_hidden_proto(svcudp_create)
+extern SVCXPRT *svcudp_bufcreate (int __sock, u_int __sendsz, u_int __recvsz)
+ __THROW;
+libc_hidden_proto(svcudp_bufcreate)
+
+/*
+ * Tcp based rpc.
+ */
+extern SVCXPRT *svctcp_create (int __sock, u_int __sendsize, u_int __recvsize)
+ __THROW;
+
+
+/*
+ * Unix based rpc.
+ */
+extern SVCXPRT *svcunix_create (int __sock, u_int __sendsize, u_int __recvsize,
+ char *__path) __THROW;
+
+
+__END_DECLS
+
+#endif /* rpc/svc.h */
diff --git a/android/librpc/rpc/svc_auth.h b/android/librpc/rpc/svc_auth.h
new file mode 100644
index 0000000..834e3c9
--- a/dev/null
+++ b/android/librpc/rpc/svc_auth.h
@@ -0,0 +1,55 @@
+/* @(#)svc_auth.h 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/* @(#)svc_auth.h 1.6 86/07/16 SMI */
+
+/*
+ * svc_auth.h, Service side of rpc authentication.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_SVC_AUTH_H
+#define _RPC_SVC_AUTH_H 1
+
+#include <features.h>
+#include <rpc/svc.h>
+
+__BEGIN_DECLS
+
+/*
+ * Server side authenticator
+ */
+extern enum auth_stat _authenticate (struct svc_req *__rqst,
+ struct rpc_msg *__msg) __THROW;
+libc_hidden_proto(_authenticate)
+
+__END_DECLS
+
+#endif /* rpc/svc_auth.h */
diff --git a/android/librpc/rpc/types.h b/android/librpc/rpc/types.h
new file mode 100644
index 0000000..68e9c65
--- a/dev/null
+++ b/android/librpc/rpc/types.h
@@ -0,0 +1,134 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/* fixincludes should not add extern "C" to this file */
+/*
+ * Rpc additions to <sys/types.h>
+ */
+#ifndef _RPC_TYPES_H
+#define _RPC_TYPES_H 1
+
+#ifdef _LIBC
+/* Some adjustments to make the libc source from glibc
+ * compile more easily with uClibc... */
+#ifndef __FORCE_GLIBC
+#define __FORCE_GLIBC
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#define _(X) X
+#endif
+#include <features.h>
+
+typedef int bool_t;
+typedef int enum_t;
+/* This needs to be changed to uint32_t in the future */
+typedef unsigned long rpcprog_t;
+typedef unsigned long rpcvers_t;
+typedef unsigned long rpcproc_t;
+typedef unsigned long rpcprot_t;
+typedef unsigned long rpcport_t;
+
+#define __dontcare__ -1
+
+#ifndef FALSE
+# define FALSE (0)
+#endif
+
+#ifndef TRUE
+# define TRUE (1)
+#endif
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+#include <stdlib.h> /* For malloc decl. */
+#define mem_alloc(bsize) malloc(bsize)
+#define mem_free(ptr, bsize) free(ptr)
+
+#ifndef makedev /* ie, we haven't already included it */
+#include <sys/types.h>
+#endif
+
+#ifdef ANDROID
+/* Compiling on android / bionic libc... */
+#include <sys/select.h>
+#include <sys/statfs.h>
+typedef signed long long quad_t;
+typedef unsigned long long u_quad_t;
+#define __THROW
+#define libc_hidden_proto(X)
+#define libc_hidden_def(X)
+#define internal_function
+#define attribute_hidden __attribute__((visibility("hidden")))
+#define attribute_unused __attribute__((__unused__))
+#define __attribute_used__ __attribute__((__used__))
+#define attribute_noreturn __attribute__((__noreturn__))
+#define _(X) X
+#define __glibc_strerror_r(A,B,C) strerror_r(A,B,C)
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#include <pthread.h>
+#define __UCLIBC_MUTEX_STATIC(ID, INIT) static pthread_mutex_t ID = INIT
+#define __UCLIBC_MUTEX_LOCK(ID) pthread_mutex_lock(&(ID))
+#define __UCLIBC_MUTEX_UNLOCK(ID) pthread_mutex_unlock(&(ID))
+#undef __UCLIBC_HAS_THREADS__
+#else
+#ifndef __u_char_defined
+typedef __u_char u_char;
+typedef __u_short u_short;
+typedef __u_int u_int;
+typedef __u_long u_long;
+typedef __quad_t quad_t;
+typedef __u_quad_t u_quad_t;
+typedef __fsid_t fsid_t;
+# define __u_char_defined
+#endif
+#ifndef __daddr_t_defined
+typedef __daddr_t daddr_t;
+typedef __caddr_t caddr_t;
+# define __daddr_t_defined
+#endif
+#endif
+
+#include <sys/time.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK (u_long)0x7F000001
+#endif
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#endif /* rpc/types.h */
diff --git a/android/librpc/rpc/xdr.h b/android/librpc/rpc/xdr.h
new file mode 100644
index 0000000..9981e3a
--- a/dev/null
+++ b/android/librpc/rpc/xdr.h
@@ -0,0 +1,407 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * xdr.h, External Data Representation Serialization Routines.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_XDR_H
+#define _RPC_XDR_H 1
+
+#ifdef _LIBC
+/* Some adjustments to make the libc source from glibc
+ * compile more easily with uClibc... */
+# ifndef __FORCE_GLIBC
+# define __FORCE_GLIBC
+# endif
+# define _(X) X
+#endif
+#include <features.h>
+#include <sys/types.h>
+#include <rpc/types.h>
+
+/* We need FILE. */
+#include <stdio.h>
+
+__BEGIN_DECLS
+
+/*
+ * XDR provides a conventional way for converting between C data
+ * types and an external bit-string representation. Library supplied
+ * routines provide for the conversion on built-in C data types. These
+ * routines and utility routines defined here are used to help implement
+ * a type encode/decode routine for each user-defined type.
+ *
+ * Each data type provides a single procedure which takes two arguments:
+ *
+ * bool_t
+ * xdrproc(xdrs, argresp)
+ * XDR *xdrs;
+ * <type> *argresp;
+ *
+ * xdrs is an instance of a XDR handle, to which or from which the data
+ * type is to be converted. argresp is a pointer to the structure to be
+ * converted. The XDR handle contains an operation field which indicates
+ * which of the operations (ENCODE, DECODE * or FREE) is to be performed.
+ *
+ * XDR_DECODE may allocate space if the pointer argresp is null. This
+ * data can be freed with the XDR_FREE operation.
+ *
+ * We write only one procedure per data type to make it easy
+ * to keep the encode and decode procedures for a data type consistent.
+ * In many cases the same code performs all operations on a user defined type,
+ * because all the hard work is done in the component type routines.
+ * decode as a series of calls on the nested data types.
+ */
+
+/*
+ * Xdr operations. XDR_ENCODE causes the type to be encoded into the
+ * stream. XDR_DECODE causes the type to be extracted from the stream.
+ * XDR_FREE can be used to release the space allocated by an XDR_DECODE
+ * request.
+ */
+enum xdr_op {
+ XDR_ENCODE = 0,
+ XDR_DECODE = 1,
+ XDR_FREE = 2
+};
+
+/*
+ * This is the number of bytes per unit of external data.
+ */
+#define BYTES_PER_XDR_UNIT (4)
+/*
+ * This only works if the above is a power of 2. But it's defined to be
+ * 4 by the appropriate RFCs. So it will work. And it's normally quicker
+ * than the old routine.
+ */
+#if 1
+#define RNDUP(x) (((x) + BYTES_PER_XDR_UNIT - 1) & ~(BYTES_PER_XDR_UNIT - 1))
+#else /* this is the old routine */
+#define RNDUP(x) ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \
+ * BYTES_PER_XDR_UNIT)
+#endif
+
+/*
+ * The XDR handle.
+ * Contains operation which is being applied to the stream,
+ * an operations vector for the particular implementation (e.g. see xdr_mem.c),
+ * and two private fields for the use of the particular implementation.
+ */
+typedef struct XDR XDR;
+struct XDR
+ {
+ enum xdr_op x_op; /* operation; fast additional param */
+ struct xdr_ops
+ {
+ bool_t (*x_getlong) (XDR *__xdrs, long *__lp);
+ /* get a long from underlying stream */
+ bool_t (*x_putlong) (XDR *__xdrs, __const long *__lp);
+ /* put a long to " */
+ bool_t (*x_getbytes) (XDR *__xdrs, caddr_t __addr, u_int __len);
+ /* get some bytes from " */
+ bool_t (*x_putbytes) (XDR *__xdrs, __const char *__addr, u_int __len);
+ /* put some bytes to " */
+ u_int (*x_getpostn) (__const XDR *__xdrs);
+ /* returns bytes off from beginning */
+ bool_t (*x_setpostn) (XDR *__xdrs, u_int __pos);
+ /* lets you reposition the stream */
+ int32_t *(*x_inline) (XDR *__xdrs, u_int __len);
+ /* buf quick ptr to buffered data */
+ void (*x_destroy) (XDR *__xdrs);
+ /* free privates of this xdr_stream */
+ bool_t (*x_getint32) (XDR *__xdrs, int32_t *__ip);
+ /* get a int from underlying stream */
+ bool_t (*x_putint32) (XDR *__xdrs, __const int32_t *__ip);
+ /* put a int to " */
+ }
+ *x_ops;
+ caddr_t x_public; /* users' data */
+ caddr_t x_private; /* pointer to private data */
+ caddr_t x_base; /* private used for position info */
+ u_int x_handy; /* extra private word */
+ };
+
+/*
+ * A xdrproc_t exists for each data type which is to be encoded or decoded.
+ *
+ * The second argument to the xdrproc_t is a pointer to an opaque pointer.
+ * The opaque pointer generally points to a structure of the data type
+ * to be decoded. If this pointer is 0, then the type routines should
+ * allocate dynamic storage of the appropriate size and return it.
+ * bool_t (*xdrproc_t)(XDR *, caddr_t *);
+ */
+typedef bool_t (*xdrproc_t) (XDR *, void *,...);
+
+
+/*
+ * Operations defined on a XDR handle
+ *
+ * XDR *xdrs;
+ * int32_t *int32p;
+ * long *longp;
+ * caddr_t addr;
+ * u_int len;
+ * u_int pos;
+ */
+#define XDR_GETINT32(xdrs, int32p) \
+ (*(xdrs)->x_ops->x_getint32)(xdrs, int32p)
+#define xdr_getint32(xdrs, int32p) \
+ (*(xdrs)->x_ops->x_getint32)(xdrs, int32p)
+
+#define XDR_PUTINT32(xdrs, int32p) \
+ (*(xdrs)->x_ops->x_putint32)(xdrs, int32p)
+#define xdr_putint32(xdrs, int32p) \
+ (*(xdrs)->x_ops->x_putint32)(xdrs, int32p)
+
+#define XDR_GETLONG(xdrs, longp) \
+ (*(xdrs)->x_ops->x_getlong)(xdrs, longp)
+#define xdr_getlong(xdrs, longp) \
+ (*(xdrs)->x_ops->x_getlong)(xdrs, longp)
+
+#define XDR_PUTLONG(xdrs, longp) \
+ (*(xdrs)->x_ops->x_putlong)(xdrs, longp)
+#define xdr_putlong(xdrs, longp) \
+ (*(xdrs)->x_ops->x_putlong)(xdrs, longp)
+
+#define XDR_GETBYTES(xdrs, addr, len) \
+ (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
+#define xdr_getbytes(xdrs, addr, len) \
+ (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
+
+#define XDR_PUTBYTES(xdrs, addr, len) \
+ (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
+#define xdr_putbytes(xdrs, addr, len) \
+ (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
+
+#define XDR_GETPOS(xdrs) \
+ (*(xdrs)->x_ops->x_getpostn)(xdrs)
+#define xdr_getpos(xdrs) \
+ (*(xdrs)->x_ops->x_getpostn)(xdrs)
+
+#define XDR_SETPOS(xdrs, pos) \
+ (*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
+#define xdr_setpos(xdrs, pos) \
+ (*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
+
+#define XDR_INLINE(xdrs, len) \
+ (*(xdrs)->x_ops->x_inline)(xdrs, len)
+#define xdr_inline(xdrs, len) \
+ (*(xdrs)->x_ops->x_inline)(xdrs, len)
+
+#define XDR_DESTROY(xdrs) \
+ do { \
+ if ((xdrs)->x_ops->x_destroy) \
+ (*(xdrs)->x_ops->x_destroy)(xdrs); \
+ } while (0)
+#define xdr_destroy(xdrs) \
+ do { \
+ if ((xdrs)->x_ops->x_destroy) \
+ (*(xdrs)->x_ops->x_destroy)(xdrs); \
+ } while (0)
+
+/*
+ * Support struct for discriminated unions.
+ * You create an array of xdrdiscrim structures, terminated with
+ * a entry with a null procedure pointer. The xdr_union routine gets
+ * the discriminant value and then searches the array of structures
+ * for a matching value. If a match is found the associated xdr routine
+ * is called to handle that part of the union. If there is
+ * no match, then a default routine may be called.
+ * If there is no match and no default routine it is an error.
+ */
+#define NULL_xdrproc_t ((xdrproc_t)0)
+struct xdr_discrim
+{
+ int value;
+ xdrproc_t proc;
+};
+
+/*
+ * Inline routines for fast encode/decode of primitive data types.
+ * Caveat emptor: these use single memory cycles to get the
+ * data from the underlying buffer, and will fail to operate
+ * properly if the data is not aligned. The standard way to use these
+ * is to say:
+ * if ((buf = XDR_INLINE(xdrs, count)) == NULL)
+ * return (FALSE);
+ * <<< macro calls >>>
+ * where ``count'' is the number of bytes of data occupied
+ * by the primitive data types.
+ *
+ * N.B. and frozen for all time: each data type here uses 4 bytes
+ * of external representation.
+ */
+
+#define IXDR_GET_INT32(buf) ((int32_t)ntohl((uint32_t)*(buf)++))
+#define IXDR_PUT_INT32(buf, v) (*(buf)++ = (int32_t)htonl((uint32_t)(v)))
+#define IXDR_GET_U_INT32(buf) ((uint32_t)IXDR_GET_INT32(buf))
+#define IXDR_PUT_U_INT32(buf, v) IXDR_PUT_INT32(buf, (int32_t)(v))
+
+/* WARNING: The IXDR_*_LONG defines are removed by Sun for new platforms
+ * and shouldn't be used any longer. Code which use this defines or longs
+ * in the RPC code will not work on 64bit Solaris platforms !
+ */
+#define IXDR_GET_LONG(buf) ((long)IXDR_GET_U_INT32(buf))
+#define IXDR_PUT_LONG(buf, v) ((long)IXDR_PUT_INT32(buf, (long)(v)))
+#define IXDR_GET_U_LONG(buf) ((u_long)IXDR_GET_LONG(buf))
+#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG(buf, (long)(v))
+
+
+#define IXDR_GET_BOOL(buf) ((bool_t)IXDR_GET_LONG(buf))
+#define IXDR_GET_ENUM(buf, t) ((t)IXDR_GET_LONG(buf))
+#define IXDR_GET_SHORT(buf) ((short)IXDR_GET_LONG(buf))
+#define IXDR_GET_U_SHORT(buf) ((u_short)IXDR_GET_LONG(buf))
+
+#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG(buf, (long)(v))
+#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG(buf, (long)(v))
+#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG(buf, (long)(v))
+#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG(buf, (long)(v))
+
+/*
+ * These are the "generic" xdr routines.
+ * None of these can have const applied because it's not possible to
+ * know whether the call is a read or a write to the passed parameter
+ * also, the XDR structure is always updated by some of these calls.
+ */
+extern bool_t xdr_void (void) __THROW;
+libc_hidden_proto(xdr_void)
+extern bool_t xdr_short (XDR *__xdrs, short *__sp) __THROW;
+libc_hidden_proto(xdr_short)
+extern bool_t xdr_u_short (XDR *__xdrs, u_short *__usp) __THROW;
+libc_hidden_proto(xdr_u_short)
+extern bool_t xdr_int (XDR *__xdrs, int *__ip) __THROW;
+libc_hidden_proto(xdr_int)
+extern bool_t xdr_u_int (XDR *__xdrs, u_int *__up) __THROW;
+libc_hidden_proto(xdr_u_int)
+extern bool_t xdr_long (XDR *__xdrs, long *__lp) __THROW;
+libc_hidden_proto(xdr_long)
+extern bool_t xdr_u_long (XDR *__xdrs, u_long *__ulp) __THROW;
+libc_hidden_proto(xdr_u_long)
+extern bool_t xdr_hyper (XDR *__xdrs, quad_t *__llp) __THROW;
+libc_hidden_proto(xdr_hyper)
+extern bool_t xdr_u_hyper (XDR *__xdrs, u_quad_t *__ullp) __THROW;
+libc_hidden_proto(xdr_u_hyper)
+extern bool_t xdr_longlong_t (XDR *__xdrs, quad_t *__llp) __THROW;
+extern bool_t xdr_u_longlong_t (XDR *__xdrs, u_quad_t *__ullp) __THROW;
+extern bool_t xdr_int8_t (XDR *__xdrs, int8_t *__ip) __THROW;
+extern bool_t xdr_uint8_t (XDR *__xdrs, uint8_t *__up) __THROW;
+extern bool_t xdr_int16_t (XDR *__xdrs, int16_t *__ip) __THROW;
+extern bool_t xdr_uint16_t (XDR *__xdrs, uint16_t *__up) __THROW;
+extern bool_t xdr_int32_t (XDR *__xdrs, int32_t *__ip) __THROW;
+extern bool_t xdr_uint32_t (XDR *__xdrs, uint32_t *__up) __THROW;
+extern bool_t xdr_int64_t (XDR *__xdrs, int64_t *__ip) __THROW;
+extern bool_t xdr_uint64_t (XDR *__xdrs, uint64_t *__up) __THROW;
+extern bool_t xdr_bool (XDR *__xdrs, bool_t *__bp) __THROW;
+libc_hidden_proto(xdr_bool)
+extern bool_t xdr_enum (XDR *__xdrs, enum_t *__ep) __THROW;
+libc_hidden_proto(xdr_enum)
+extern bool_t xdr_array (XDR * _xdrs, caddr_t *__addrp, u_int *__sizep,
+ u_int __maxsize, u_int __elsize, xdrproc_t __elproc)
+ __THROW;
+libc_hidden_proto(xdr_array)
+extern bool_t xdr_bytes (XDR *__xdrs, char **__cpp, u_int *__sizep,
+ u_int __maxsize) __THROW;
+libc_hidden_proto(xdr_bytes)
+extern bool_t xdr_opaque (XDR *__xdrs, caddr_t __cp, u_int __cnt) __THROW;
+libc_hidden_proto(xdr_opaque)
+extern bool_t xdr_string (XDR *__xdrs, char **__cpp, u_int __maxsize) __THROW;
+libc_hidden_proto(xdr_string)
+extern bool_t xdr_union (XDR *__xdrs, enum_t *__dscmp, char *__unp,
+ __const struct xdr_discrim *__choices,
+ xdrproc_t dfault) __THROW;
+libc_hidden_proto(xdr_union)
+extern bool_t xdr_char (XDR *__xdrs, char *__cp) __THROW;
+extern bool_t xdr_u_char (XDR *__xdrs, u_char *__cp) __THROW;
+extern bool_t xdr_vector (XDR *__xdrs, char *__basep, u_int __nelem,
+ u_int __elemsize, xdrproc_t __xdr_elem) __THROW;
+extern bool_t xdr_float (XDR *__xdrs, float *__fp) __THROW;
+extern bool_t xdr_double (XDR *__xdrs, double *__dp) __THROW;
+extern bool_t xdr_reference (XDR *__xdrs, caddr_t *__xpp, u_int __size,
+ xdrproc_t __proc) __THROW;
+libc_hidden_proto(xdr_reference)
+extern bool_t xdr_pointer (XDR *__xdrs, char **__objpp,
+ u_int __obj_size, xdrproc_t __xdr_obj) __THROW;
+extern bool_t xdr_wrapstring (XDR *__xdrs, char **__cpp) __THROW;
+extern u_long xdr_sizeof (xdrproc_t, void *) __THROW;
+
+/*
+ * Common opaque bytes objects used by many rpc protocols;
+ * declared here due to commonality.
+ */
+#define MAX_NETOBJ_SZ 1024
+struct netobj
+{
+ u_int n_len;
+ char *n_bytes;
+};
+typedef struct netobj netobj;
+extern bool_t xdr_netobj (XDR *__xdrs, struct netobj *__np) __THROW;
+
+/*
+ * These are the public routines for the various implementations of
+ * xdr streams.
+ */
+
+/* XDR using memory buffers */
+extern void xdrmem_create (XDR *__xdrs, __const caddr_t __addr,
+ u_int __size, enum xdr_op __xop) __THROW;
+libc_hidden_proto(xdrmem_create)
+
+/* XDR using stdio library */
+extern void xdrstdio_create (XDR *__xdrs, FILE *__file, enum xdr_op __xop)
+ __THROW;
+
+/* XDR pseudo records for tcp */
+extern void xdrrec_create (XDR *__xdrs, u_int __sendsize,
+ u_int __recvsize, caddr_t __tcp_handle,
+ int (*__readit) (char *, char *, int),
+ int (*__writeit) (char *, char *, int)) __THROW;
+libc_hidden_proto(xdrrec_create)
+
+/* make end of xdr record */
+extern bool_t xdrrec_endofrecord (XDR *__xdrs, bool_t __sendnow) __THROW;
+libc_hidden_proto(xdrrec_endofrecord)
+
+/* move to beginning of next record */
+extern bool_t xdrrec_skiprecord (XDR *__xdrs) __THROW;
+libc_hidden_proto(xdrrec_skiprecord)
+
+/* true if no more input */
+extern bool_t xdrrec_eof (XDR *__xdrs) __THROW;
+libc_hidden_proto(xdrrec_eof)
+
+/* free memory buffers for xdr */
+extern void xdr_free (xdrproc_t __proc, char *__objp) __THROW;
+
+__END_DECLS
+
+#endif /* rpc/xdr.h */
diff --git a/android/librpc/rpc_cmsg.c b/android/librpc/rpc_cmsg.c
new file mode 100644
index 0000000..a8c2573
--- a/dev/null
+++ b/android/librpc/rpc_cmsg.c
@@ -0,0 +1,208 @@
+/* @(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * rpc_callmsg.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <string.h>
+#include <sys/param.h>
+#include <rpc/rpc.h>
+
+
+/*
+ * XDR a call message
+ */
+bool_t
+xdr_callmsg (XDR *xdrs, struct rpc_msg *cmsg)
+{
+ int32_t *buf;
+ struct opaque_auth *oa;
+
+ if (xdrs->x_op == XDR_ENCODE)
+ {
+ if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES)
+ {
+ return (FALSE);
+ }
+ if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES)
+ {
+ return (FALSE);
+ }
+ buf = XDR_INLINE (xdrs, 8 * BYTES_PER_XDR_UNIT
+ + RNDUP (cmsg->rm_call.cb_cred.oa_length)
+ + 2 * BYTES_PER_XDR_UNIT
+ + RNDUP (cmsg->rm_call.cb_verf.oa_length));
+ if (buf != NULL)
+ {
+ IXDR_PUT_LONG (buf, cmsg->rm_xid);
+ IXDR_PUT_ENUM (buf, cmsg->rm_direction);
+ if (cmsg->rm_direction != CALL)
+ return FALSE;
+ IXDR_PUT_LONG (buf, cmsg->rm_call.cb_rpcvers);
+ if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION)
+ return FALSE;
+ IXDR_PUT_LONG (buf, cmsg->rm_call.cb_prog);
+ IXDR_PUT_LONG (buf, cmsg->rm_call.cb_vers);
+ IXDR_PUT_LONG (buf, cmsg->rm_call.cb_proc);
+ oa = &cmsg->rm_call.cb_cred;
+ IXDR_PUT_ENUM (buf, oa->oa_flavor);
+ IXDR_PUT_INT32 (buf, oa->oa_length);
+ if (oa->oa_length)
+ {
+ memcpy ((caddr_t) buf, oa->oa_base, oa->oa_length);
+ buf = (int32_t *) ((char *) buf + RNDUP (oa->oa_length));
+ }
+ oa = &cmsg->rm_call.cb_verf;
+ IXDR_PUT_ENUM (buf, oa->oa_flavor);
+ IXDR_PUT_INT32 (buf, oa->oa_length);
+ if (oa->oa_length)
+ {
+ memcpy ((caddr_t) buf, oa->oa_base, oa->oa_length);
+ /* no real need....
+ buf = (long *) ((char *) buf + RNDUP(oa->oa_length));
+ */
+ }
+ return TRUE;
+ }
+ }
+ if (xdrs->x_op == XDR_DECODE)
+ {
+ buf = XDR_INLINE (xdrs, 8 * BYTES_PER_XDR_UNIT);
+ if (buf != NULL)
+ {
+ cmsg->rm_xid = IXDR_GET_LONG (buf);
+ cmsg->rm_direction = IXDR_GET_ENUM (buf, enum msg_type);
+ if (cmsg->rm_direction != CALL)
+ {
+ return FALSE;
+ }
+ cmsg->rm_call.cb_rpcvers = IXDR_GET_LONG (buf);
+ if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION)
+ {
+ return FALSE;
+ }
+ cmsg->rm_call.cb_prog = IXDR_GET_LONG (buf);
+ cmsg->rm_call.cb_vers = IXDR_GET_LONG (buf);
+ cmsg->rm_call.cb_proc = IXDR_GET_LONG (buf);
+ oa = &cmsg->rm_call.cb_cred;
+ oa->oa_flavor = IXDR_GET_ENUM (buf, enum_t);
+ oa->oa_length = IXDR_GET_INT32 (buf);
+ if (oa->oa_length)
+ {
+ if (oa->oa_length > MAX_AUTH_BYTES)
+ return FALSE;
+ if (oa->oa_base == NULL)
+ {
+ oa->oa_base = (caddr_t)
+ mem_alloc (oa->oa_length);
+ }
+ buf = XDR_INLINE (xdrs, RNDUP (oa->oa_length));
+ if (buf == NULL)
+ {
+ if (xdr_opaque (xdrs, oa->oa_base,
+ oa->oa_length) == FALSE)
+ return FALSE;
+ }
+ else
+ {
+ memcpy (oa->oa_base, (caddr_t) buf, oa->oa_length);
+ /* no real need....
+ buf = (long *) ((char *) buf
+ + RNDUP(oa->oa_length));
+ */
+ }
+ }
+ oa = &cmsg->rm_call.cb_verf;
+ buf = XDR_INLINE (xdrs, 2 * BYTES_PER_XDR_UNIT);
+ if (buf == NULL)
+ {
+ if (xdr_enum (xdrs, &oa->oa_flavor) == FALSE ||
+ xdr_u_int (xdrs, &oa->oa_length) == FALSE)
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ oa->oa_flavor = IXDR_GET_ENUM (buf, enum_t);
+ oa->oa_length = IXDR_GET_INT32 (buf);
+ }
+ if (oa->oa_length)
+ {
+ if (oa->oa_length > MAX_AUTH_BYTES)
+ return FALSE;
+ if (oa->oa_base == NULL)
+ {
+ oa->oa_base = (caddr_t)
+ mem_alloc (oa->oa_length);
+ }
+ buf = XDR_INLINE (xdrs, RNDUP (oa->oa_length));
+ if (buf == NULL)
+ {
+ if (xdr_opaque (xdrs, oa->oa_base,
+ oa->oa_length) == FALSE)
+ return FALSE;
+ }
+ else
+ {
+ memcpy (oa->oa_base, (caddr_t) buf, oa->oa_length);
+ /* no real need...
+ buf = (long *) ((char *) buf
+ + RNDUP(oa->oa_length));
+ */
+ }
+ }
+ return TRUE;
+ }
+ }
+ if (
+ xdr_u_long (xdrs, &(cmsg->rm_xid)) &&
+ xdr_enum (xdrs, (enum_t *) & (cmsg->rm_direction)) &&
+ (cmsg->rm_direction == CALL) &&
+ xdr_u_long (xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+ (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
+ xdr_u_long (xdrs, &(cmsg->rm_call.cb_prog)) &&
+ xdr_u_long (xdrs, &(cmsg->rm_call.cb_vers)) &&
+ xdr_u_long (xdrs, &(cmsg->rm_call.cb_proc)) &&
+ xdr_opaque_auth (xdrs, &(cmsg->rm_call.cb_cred)))
+ return xdr_opaque_auth (xdrs, &(cmsg->rm_call.cb_verf));
+ return FALSE;
+}
+libc_hidden_def(xdr_callmsg)
diff --git a/android/librpc/rpc_commondata.c b/android/librpc/rpc_commondata.c
new file mode 100644
index 0000000..187d915
--- a/dev/null
+++ b/android/librpc/rpc_commondata.c
@@ -0,0 +1,47 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#include <rpc/rpc.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+
+#undef svc_fdset
+#undef rpc_createerr
+#undef svc_pollfd
+#undef svc_max_pollfd
+
+
+/*
+ * This file should only contain common data (global data) that is exported
+ * by public interfaces
+ */
+struct opaque_auth _null_auth;
+fd_set svc_fdset;
+struct rpc_createerr rpc_createerr;
+struct pollfd *svc_pollfd;
+int svc_max_pollfd;
diff --git a/android/librpc/rpc_dtablesize.c b/android/librpc/rpc_dtablesize.c
new file mode 100644
index 0000000..0bd3a1c
--- a/dev/null
+++ b/android/librpc/rpc_dtablesize.c
@@ -0,0 +1,60 @@
+/* @(#)rpc_dtablesize.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro";
+#endif
+
+#define __FORCE_GLIBC
+#define __USE_BSD
+#include <features.h>
+
+#include <unistd.h>
+#include <rpc/clnt.h>
+
+#ifdef BIONIC_L
+/* no more in unistd */
+extern int getdtablesize(void);
+#endif
+
+/*
+ * Cache the result of getdtablesize(), so we don't have to do an
+ * expensive system call every time.
+ */
+int
+_rpc_dtablesize(void)
+{
+ static int size;
+
+ if (size == 0)
+ size = getdtablesize ();
+
+ return size;
+}
+libc_hidden_def(_rpc_dtablesize)
diff --git a/android/librpc/rpc_private.h b/android/librpc/rpc_private.h
new file mode 100644
index 0000000..ede3ddf
--- a/dev/null
+++ b/android/librpc/rpc_private.h
@@ -0,0 +1,55 @@
+#ifndef _RPC_RPC_H
+#include <rpc/rpc.h>
+
+/* Now define the internal interfaces. */
+extern u_long _create_xid (void) attribute_hidden;
+
+
+/*
+ * Multi-threaded support
+ * Group all global and static variables into a single spot.
+ * This area is allocated on a per-thread basis
+ */
+#ifdef __UCLIBC_HAS_THREADS__
+#include <pthread.h>
+struct rpc_thread_variables {
+ fd_set svc_fdset_s; /* Global, rpc_common.c */
+ struct rpc_createerr rpc_createerr_s; /* Global, rpc_common.c */
+ struct pollfd *svc_pollfd_s; /* Global, rpc_common.c */
+ int svc_max_pollfd_s; /* Global, rpc_common.c */
+
+ void *authnone_private_s; /* auth_none.c */
+
+ void *clnt_perr_buf_s; /* clnt_perr.c */
+
+ void *clntraw_private_s; /* clnt_raw.c */
+
+ void *callrpc_private_s; /* clnt_simp.c */
+
+ void *key_call_private_s; /* key_call.c */
+
+ void *authdes_cache_s; /* svcauth_des.c */
+ void *authdes_lru_s; /* svcauth_des.c */
+
+ void *svc_xports_s; /* svc.c */
+ void *svc_head_s; /* svc.c */
+
+ void *svcraw_private_s; /* svc_raw.c */
+
+ void *svcsimple_proglst_s; /* svc_simple.c */
+ void *svcsimple_transp_s; /* svc_simple.c */
+};
+
+extern struct rpc_thread_variables *__rpc_thread_variables(void)
+ __attribute__ ((const)) attribute_hidden;
+extern void __rpc_thread_svc_cleanup (void) attribute_hidden;
+extern void __rpc_thread_clnt_cleanup (void) attribute_hidden;
+/*extern void __rpc_thread_key_cleanup (void) attribute_hidden;*/
+
+extern void __rpc_thread_destroy (void);
+
+#define RPC_THREAD_VARIABLE(x) (__rpc_thread_variables()->x)
+
+#endif /* __UCLIBC_HAS_THREADS__ */
+
+#endif
diff --git a/android/librpc/rpc_prot.c b/android/librpc/rpc_prot.c
new file mode 100644
index 0000000..bf55a3c
--- a/dev/null
+++ b/android/librpc/rpc_prot.c
@@ -0,0 +1,285 @@
+/* @(#)rpc_prot.c 2.3 88/08/07 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * rpc_prot.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * This set of routines implements the rpc message definition,
+ * its serializer and some common rpc utility routines.
+ * The routines are meant for various implementations of rpc -
+ * they are NOT for the rpc client or rpc service implementations!
+ * Because authentication stuff is easy and is part of rpc, the opaque
+ * routines are also in this program.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <sys/param.h>
+
+#include <rpc/rpc.h>
+
+
+/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
+
+/*
+ * XDR an opaque authentication struct
+ * (see auth.h)
+ */
+bool_t
+xdr_opaque_auth (XDR *xdrs, struct opaque_auth *ap)
+{
+
+ if (xdr_enum (xdrs, &(ap->oa_flavor)))
+ return xdr_bytes (xdrs, &ap->oa_base,
+ &ap->oa_length, MAX_AUTH_BYTES);
+ return FALSE;
+}
+libc_hidden_def(xdr_opaque_auth)
+
+/*
+ * XDR a DES block
+ */
+bool_t
+xdr_des_block (XDR *xdrs, des_block *blkp)
+{
+ return xdr_opaque (xdrs, (caddr_t) blkp, sizeof (des_block));
+}
+
+/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
+
+/*
+ * XDR the MSG_ACCEPTED part of a reply message union
+ */
+bool_t
+xdr_accepted_reply (XDR *xdrs, struct accepted_reply *ar)
+{
+ /* personalized union, rather than calling xdr_union */
+ if (!xdr_opaque_auth (xdrs, &(ar->ar_verf)))
+ return FALSE;
+ if (!xdr_enum (xdrs, (enum_t *) & (ar->ar_stat)))
+ return FALSE;
+ switch (ar->ar_stat)
+ {
+ case SUCCESS:
+ return ((*(ar->ar_results.proc)) (xdrs, ar->ar_results.where));
+ case PROG_MISMATCH:
+ if (!xdr_u_long (xdrs, &(ar->ar_vers.low)))
+ return FALSE;
+ return (xdr_u_long (xdrs, &(ar->ar_vers.high)));
+ default:
+ return TRUE;
+ }
+ return TRUE; /* TRUE => open ended set of problems */
+}
+libc_hidden_def(xdr_accepted_reply)
+
+/*
+ * XDR the MSG_DENIED part of a reply message union
+ */
+bool_t
+xdr_rejected_reply (XDR *xdrs, struct rejected_reply *rr)
+{
+ /* personalized union, rather than calling xdr_union */
+ if (!xdr_enum (xdrs, (enum_t *) & (rr->rj_stat)))
+ return FALSE;
+ switch (rr->rj_stat)
+ {
+ case RPC_MISMATCH:
+ if (!xdr_u_long (xdrs, &(rr->rj_vers.low)))
+ return FALSE;
+ return xdr_u_long (xdrs, &(rr->rj_vers.high));
+
+ case AUTH_ERROR:
+ return xdr_enum (xdrs, (enum_t *) & (rr->rj_why));
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_rejected_reply)
+
+static const struct xdr_discrim reply_dscrm[3] =
+{
+ {(int) MSG_ACCEPTED, (xdrproc_t) xdr_accepted_reply},
+ {(int) MSG_DENIED, (xdrproc_t) xdr_rejected_reply},
+ {__dontcare__, NULL_xdrproc_t}};
+
+/*
+ * XDR a reply message
+ */
+bool_t
+xdr_replymsg (XDR *xdrs, struct rpc_msg *rmsg)
+{
+ if (xdr_u_long (xdrs, &(rmsg->rm_xid)) &&
+ xdr_enum (xdrs, (enum_t *) & (rmsg->rm_direction)) &&
+ (rmsg->rm_direction == REPLY))
+ return xdr_union (xdrs, (enum_t *) & (rmsg->rm_reply.rp_stat),
+ (caddr_t) & (rmsg->rm_reply.ru), reply_dscrm,
+ NULL_xdrproc_t);
+ return FALSE;
+}
+libc_hidden_def(xdr_replymsg)
+
+
+/*
+ * Serializes the "static part" of a call message header.
+ * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
+ * The rm_xid is not really static, but the user can easily munge on the fly.
+ */
+bool_t
+xdr_callhdr (XDR *xdrs, struct rpc_msg *cmsg)
+{
+
+ cmsg->rm_direction = CALL;
+ cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ if (
+ (xdrs->x_op == XDR_ENCODE) &&
+ xdr_u_long (xdrs, &(cmsg->rm_xid)) &&
+ xdr_enum (xdrs, (enum_t *) & (cmsg->rm_direction)) &&
+ xdr_u_long (xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+ xdr_u_long (xdrs, &(cmsg->rm_call.cb_prog)))
+ return xdr_u_long (xdrs, &(cmsg->rm_call.cb_vers));
+ return FALSE;
+}
+libc_hidden_def(xdr_callhdr)
+
+/* ************************** Client utility routine ************* */
+
+static void
+accepted (enum accept_stat acpt_stat,
+ struct rpc_err *error)
+{
+ switch (acpt_stat)
+ {
+
+ case PROG_UNAVAIL:
+ error->re_status = RPC_PROGUNAVAIL;
+ return;
+
+ case PROG_MISMATCH:
+ error->re_status = RPC_PROGVERSMISMATCH;
+ return;
+
+ case PROC_UNAVAIL:
+ error->re_status = RPC_PROCUNAVAIL;
+ return;
+
+ case GARBAGE_ARGS:
+ error->re_status = RPC_CANTDECODEARGS;
+ return;
+
+ case SYSTEM_ERR:
+ error->re_status = RPC_SYSTEMERROR;
+ return;
+
+ case SUCCESS:
+ error->re_status = RPC_SUCCESS;
+ return;
+ }
+ /* something's wrong, but we don't know what ... */
+ error->re_status = RPC_FAILED;
+ error->re_lb.s1 = (long) MSG_ACCEPTED;
+ error->re_lb.s2 = (long) acpt_stat;
+}
+
+static void
+rejected (enum reject_stat rjct_stat,
+ struct rpc_err *error)
+{
+ switch (rjct_stat)
+ {
+ case RPC_MISMATCH:
+ error->re_status = RPC_VERSMISMATCH;
+ return;
+ case AUTH_ERROR:
+ error->re_status = RPC_AUTHERROR;
+ return;
+ default:
+ /* something's wrong, but we don't know what ... */
+ error->re_status = RPC_FAILED;
+ error->re_lb.s1 = (long) MSG_DENIED;
+ error->re_lb.s2 = (long) rjct_stat;
+ return;
+ }
+}
+
+/*
+ * given a reply message, fills in the error
+ */
+void
+_seterr_reply (struct rpc_msg *msg,
+ struct rpc_err *error)
+{
+ /* optimized for normal, SUCCESSful case */
+ switch (msg->rm_reply.rp_stat)
+ {
+ case MSG_ACCEPTED:
+ if (msg->acpted_rply.ar_stat == SUCCESS)
+ {
+ error->re_status = RPC_SUCCESS;
+ return;
+ };
+ accepted (msg->acpted_rply.ar_stat, error);
+ break;
+
+ case MSG_DENIED:
+ rejected (msg->rjcted_rply.rj_stat, error);
+ break;
+
+ default:
+ error->re_status = RPC_FAILED;
+ error->re_lb.s1 = (long) (msg->rm_reply.rp_stat);
+ break;
+ }
+ switch (error->re_status)
+ {
+
+ case RPC_VERSMISMATCH:
+ error->re_vers.low = msg->rjcted_rply.rj_vers.low;
+ error->re_vers.high = msg->rjcted_rply.rj_vers.high;
+ break;
+
+ case RPC_AUTHERROR:
+ error->re_why = msg->rjcted_rply.rj_why;
+ break;
+
+ case RPC_PROGVERSMISMATCH:
+ error->re_vers.low = msg->acpted_rply.ar_vers.low;
+ error->re_vers.high = msg->acpted_rply.ar_vers.high;
+ break;
+ default:
+ break;
+ }
+}
+libc_hidden_def(_seterr_reply)
diff --git a/android/librpc/rpc_thread.c b/android/librpc/rpc_thread.c
new file mode 100644
index 0000000..71303b2
--- a/dev/null
+++ b/android/librpc/rpc_thread.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
+ *
+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+#include <stdio.h>
+#include <assert.h>
+#include "rpc_private.h"
+
+
+#ifdef __UCLIBC_HAS_THREADS__
+
+#include <bits/libc-tsd.h>
+#include <bits/libc-lock.h>
+
+/* Variable used in non-threaded applications or for the first thread. */
+static struct rpc_thread_variables __libc_tsd_RPC_VARS_mem;
+__libc_tsd_define (, RPC_VARS)
+
+/*
+ * Task-variable destructor
+ */
+void
+__rpc_thread_destroy (void)
+{
+ struct rpc_thread_variables *tvp = __libc_tsd_get (RPC_VARS);
+
+ if (tvp != NULL && tvp != &__libc_tsd_RPC_VARS_mem) {
+ __rpc_thread_svc_cleanup ();
+ __rpc_thread_clnt_cleanup ();
+ /*__rpc_thread_key_cleanup (); */
+ free (tvp->authnone_private_s);
+ free (tvp->clnt_perr_buf_s);
+ free (tvp->clntraw_private_s);
+ free (tvp->svcraw_private_s);
+ free (tvp->authdes_cache_s);
+ free (tvp->authdes_lru_s);
+ free (tvp);
+ __libc_tsd_set (RPC_VARS, NULL);
+ }
+}
+
+/*
+ * Initialize RPC multi-threaded operation
+ */
+static void
+rpc_thread_multi (void)
+{
+ __libc_tsd_set (RPC_VARS, &__libc_tsd_RPC_VARS_mem);
+}
+
+
+struct rpc_thread_variables attribute_hidden *
+__rpc_thread_variables (void)
+{
+ __libc_once_define (static, once);
+ struct rpc_thread_variables *tvp;
+
+ tvp = __libc_tsd_get (RPC_VARS);
+ if (tvp == NULL) {
+ __libc_once (once, rpc_thread_multi);
+ tvp = __libc_tsd_get (RPC_VARS);
+ if (tvp == NULL) {
+ tvp = calloc (1, sizeof *tvp);
+ if (tvp != NULL)
+ __libc_tsd_set (RPC_VARS, tvp);
+ else
+ tvp = __libc_tsd_get (RPC_VARS);
+ }
+ }
+ return tvp;
+}
+
+
+/* Global variables If we're single-threaded, or if this is the first
+ thread using the variable, use the existing global variable. This
+ provides backwards compatability for existing applications which
+ dynamically link against this code. */
+#undef svc_fdset
+#undef rpc_createerr
+#undef svc_pollfd
+#undef svc_max_pollfd
+
+fd_set *
+__rpc_thread_svc_fdset (void)
+{
+ struct rpc_thread_variables *tvp;
+
+ tvp = __rpc_thread_variables ();
+ if (tvp == &__libc_tsd_RPC_VARS_mem)
+ return &svc_fdset;
+ return &tvp->svc_fdset_s;
+}
+
+struct rpc_createerr *
+__rpc_thread_createerr (void)
+{
+ struct rpc_thread_variables *tvp;
+
+ tvp = __rpc_thread_variables ();
+ if (tvp == &__libc_tsd_RPC_VARS_mem)
+ return &rpc_createerr;
+ return &tvp->rpc_createerr_s;
+}
+
+struct pollfd **
+__rpc_thread_svc_pollfd (void)
+{
+ struct rpc_thread_variables *tvp;
+
+ tvp = __rpc_thread_variables ();
+ if (tvp == &__libc_tsd_RPC_VARS_mem)
+ return &svc_pollfd;
+ return &tvp->svc_pollfd_s;
+}
+
+int *
+__rpc_thread_svc_max_pollfd (void)
+{
+ struct rpc_thread_variables *tvp;
+
+ tvp = __rpc_thread_variables ();
+ if (tvp == &__libc_tsd_RPC_VARS_mem)
+ return &svc_max_pollfd;
+ return &tvp->svc_max_pollfd_s;
+}
+#else
+
+#undef svc_fdset
+#undef rpc_createerr
+#undef svc_pollfd
+#undef svc_max_pollfd
+
+extern fd_set svc_fdset;
+fd_set * __rpc_thread_svc_fdset (void)
+{
+ return &(svc_fdset);
+}
+
+extern struct rpc_createerr rpc_createerr;
+struct rpc_createerr * __rpc_thread_createerr (void)
+{
+ return &(rpc_createerr);
+}
+
+extern struct pollfd *svc_pollfd;
+struct pollfd ** __rpc_thread_svc_pollfd (void)
+{
+ return &(svc_pollfd);
+}
+
+extern int svc_max_pollfd;
+int * __rpc_thread_svc_max_pollfd (void)
+{
+ return &(svc_max_pollfd);
+}
+
+#endif /* __UCLIBC_HAS_THREADS__ */
+
+libc_hidden_def(__rpc_thread_svc_fdset)
+libc_hidden_def(__rpc_thread_createerr)
+libc_hidden_def(__rpc_thread_svc_pollfd)
+libc_hidden_def(__rpc_thread_svc_max_pollfd)
diff --git a/android/librpc/svc.c b/android/librpc/svc.c
new file mode 100644
index 0000000..604b4a1
--- a/dev/null
+++ b/android/librpc/svc.c
@@ -0,0 +1,506 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * svc.c, Server-side remote procedure call interface.
+ *
+ * There are two sets of procedures here. The xprt routines are
+ * for handling transport handles. The svc routines handle the
+ * list of service routines.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <strings.h>
+#include <errno.h>
+#include <unistd.h>
+#include "rpc_private.h"
+#include <rpc/svc.h>
+#include <rpc/pmap_clnt.h>
+#include <sys/poll.h>
+
+/* used by svc_[max_]pollfd */
+/* used by svc_fdset */
+
+#ifdef __UCLIBC_HAS_THREADS__
+#define xports (*(SVCXPRT ***)&RPC_THREAD_VARIABLE(svc_xports_s))
+#else
+static SVCXPRT **xports;
+#endif
+
+#define NULL_SVC ((struct svc_callout *)0)
+#define RQCRED_SIZE 400 /* this size is excessive */
+
+/* The services list
+ Each entry represents a set of procedures (an rpc program).
+ The dispatch routine takes request structs and runs the
+ appropriate procedure. */
+struct svc_callout {
+ struct svc_callout *sc_next;
+ rpcprog_t sc_prog;
+ rpcvers_t sc_vers;
+ void (*sc_dispatch) (struct svc_req *, SVCXPRT *);
+};
+#ifdef __UCLIBC_HAS_THREADS__
+#define svc_head (*(struct svc_callout **)&RPC_THREAD_VARIABLE(svc_head_s))
+#else
+static struct svc_callout *svc_head;
+#endif
+
+/* *************** SVCXPRT related stuff **************** */
+
+/* Activate a transport handle. */
+void
+xprt_register (SVCXPRT *xprt)
+{
+ register int sock = xprt->xp_sock;
+ register int i;
+
+ if (xports == NULL)
+ {
+ xports = (SVCXPRT **) malloc (_rpc_dtablesize () * sizeof (SVCXPRT *));
+ if (xports == NULL) /* Don´t add handle */
+ return;
+ }
+
+ if (sock < _rpc_dtablesize ())
+ {
+ xports[sock] = xprt;
+ if (sock < FD_SETSIZE)
+ FD_SET (sock, &svc_fdset);
+
+ /* Check if we have an empty slot */
+ for (i = 0; i < svc_max_pollfd; ++i)
+ if (svc_pollfd[i].fd == -1)
+ {
+ svc_pollfd[i].fd = sock;
+ svc_pollfd[i].events = (POLLIN | POLLPRI |
+ POLLRDNORM | POLLRDBAND);
+ return;
+ }
+
+ ++svc_max_pollfd;
+ svc_pollfd = realloc (svc_pollfd,
+ sizeof (struct pollfd) * svc_max_pollfd);
+ if (svc_pollfd == NULL) /* Out of memory */
+ return;
+
+ svc_pollfd[svc_max_pollfd - 1].fd = sock;
+ svc_pollfd[svc_max_pollfd - 1].events = (POLLIN | POLLPRI |
+ POLLRDNORM | POLLRDBAND);
+ }
+}
+libc_hidden_def(xprt_register)
+
+/* De-activate a transport handle. */
+void
+xprt_unregister (SVCXPRT *xprt)
+{
+ register int sock = xprt->xp_sock;
+ register int i;
+
+ if ((sock < _rpc_dtablesize ()) && (xports[sock] == xprt))
+ {
+ xports[sock] = (SVCXPRT *) 0;
+
+ if (sock < FD_SETSIZE)
+ FD_CLR (sock, &svc_fdset);
+
+ for (i = 0; i < svc_max_pollfd; ++i)
+ if (svc_pollfd[i].fd == sock)
+ svc_pollfd[i].fd = -1;
+ }
+}
+libc_hidden_def(xprt_unregister)
+
+
+/* ********************** CALLOUT list related stuff ************* */
+
+/* Search the callout list for a program number, return the callout
+ struct. */
+static struct svc_callout *
+svc_find (rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev)
+{
+ register struct svc_callout *s, *p;
+
+ p = NULL_SVC;
+ for (s = svc_head; s != NULL_SVC; s = s->sc_next)
+ {
+ if ((s->sc_prog == prog) && (s->sc_vers == vers))
+ goto done;
+ p = s;
+ }
+done:
+ *prev = p;
+ return s;
+}
+
+/* Add a service program to the callout list.
+ The dispatch routine will be called when a rpc request for this
+ program number comes in. */
+bool_t
+svc_register (SVCXPRT * xprt, rpcprog_t prog, rpcvers_t vers,
+ void (*dispatch) (struct svc_req *, SVCXPRT *),
+ rpcproc_t protocol)
+{
+ struct svc_callout *prev;
+ register struct svc_callout *s;
+
+ if ((s = svc_find (prog, vers, &prev)) != NULL_SVC)
+ {
+ if (s->sc_dispatch == dispatch)
+ goto pmap_it; /* he is registering another xptr */
+ return FALSE;
+ }
+ s = (struct svc_callout *) mem_alloc (sizeof (struct svc_callout));
+ if (s == (struct svc_callout *) 0)
+ return FALSE;
+
+ s->sc_prog = prog;
+ s->sc_vers = vers;
+ s->sc_dispatch = dispatch;
+ s->sc_next = svc_head;
+ svc_head = s;
+
+pmap_it:
+ /* now register the information with the local binder service */
+ if (protocol)
+ return pmap_set (prog, vers, protocol, xprt->xp_port);
+
+ return TRUE;
+}
+libc_hidden_def(svc_register)
+
+/* Remove a service program from the callout list. */
+void
+svc_unregister (rpcprog_t prog, rpcvers_t vers)
+{
+ struct svc_callout *prev;
+ register struct svc_callout *s;
+
+ if ((s = svc_find (prog, vers, &prev)) == NULL_SVC)
+ return;
+
+ if (prev == NULL_SVC)
+ svc_head = s->sc_next;
+ else
+ prev->sc_next = s->sc_next;
+
+ s->sc_next = NULL_SVC;
+ mem_free ((char *) s, (u_int) sizeof (struct svc_callout));
+ /* now unregister the information with the local binder service */
+ pmap_unset (prog, vers);
+}
+libc_hidden_def(svc_unregister)
+
+/* ******************* REPLY GENERATION ROUTINES ************ */
+
+/* Send a reply to an rpc request */
+bool_t
+svc_sendreply (register SVCXPRT *xprt, xdrproc_t xdr_results,
+ caddr_t xdr_location)
+{
+ struct rpc_msg rply;
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = SUCCESS;
+ rply.acpted_rply.ar_results.where = xdr_location;
+ rply.acpted_rply.ar_results.proc = xdr_results;
+ return SVC_REPLY (xprt, &rply);
+}
+libc_hidden_def(svc_sendreply)
+
+/* No procedure error reply */
+void
+svcerr_noproc (register SVCXPRT *xprt)
+{
+ struct rpc_msg rply;
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = PROC_UNAVAIL;
+ SVC_REPLY (xprt, &rply);
+}
+
+/* Can't decode args error reply */
+void
+svcerr_decode (register SVCXPRT *xprt)
+{
+ struct rpc_msg rply;
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = GARBAGE_ARGS;
+ SVC_REPLY (xprt, &rply);
+}
+libc_hidden_def(svcerr_decode)
+
+/* Some system error */
+void
+svcerr_systemerr (register SVCXPRT *xprt)
+{
+ struct rpc_msg rply;
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = SYSTEM_ERR;
+ SVC_REPLY (xprt, &rply);
+}
+
+/* Authentication error reply */
+void
+svcerr_auth (SVCXPRT *xprt, enum auth_stat why)
+{
+ struct rpc_msg rply;
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_DENIED;
+ rply.rjcted_rply.rj_stat = AUTH_ERROR;
+ rply.rjcted_rply.rj_why = why;
+ SVC_REPLY (xprt, &rply);
+}
+libc_hidden_def(svcerr_auth)
+
+/* Auth too weak error reply */
+void
+svcerr_weakauth (SVCXPRT *xprt)
+{
+ svcerr_auth (xprt, AUTH_TOOWEAK);
+}
+
+/* Program unavailable error reply */
+void
+svcerr_noprog (register SVCXPRT *xprt)
+{
+ struct rpc_msg rply;
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = PROG_UNAVAIL;
+ SVC_REPLY (xprt, &rply);
+}
+libc_hidden_def(svcerr_noprog)
+
+/* Program version mismatch error reply */
+void
+svcerr_progvers (register SVCXPRT *xprt, rpcvers_t low_vers,
+ rpcvers_t high_vers)
+{
+ struct rpc_msg rply;
+
+ rply.rm_direction = REPLY;
+ rply.rm_reply.rp_stat = MSG_ACCEPTED;
+ rply.acpted_rply.ar_verf = xprt->xp_verf;
+ rply.acpted_rply.ar_stat = PROG_MISMATCH;
+ rply.acpted_rply.ar_vers.low = low_vers;
+ rply.acpted_rply.ar_vers.high = high_vers;
+ SVC_REPLY (xprt, &rply);
+}
+libc_hidden_def(svcerr_progvers)
+
+/* ******************* SERVER INPUT STUFF ******************* */
+
+/*
+ * Get server side input from some transport.
+ *
+ * Statement of authentication parameters management:
+ * This function owns and manages all authentication parameters, specifically
+ * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
+ * the "cooked" credentials (rqst->rq_clntcred).
+ * However, this function does not know the structure of the cooked
+ * credentials, so it make the following assumptions:
+ * a) the structure is contiguous (no pointers), and
+ * b) the cred structure size does not exceed RQCRED_SIZE bytes.
+ * In all events, all three parameters are freed upon exit from this routine.
+ * The storage is trivially management on the call stack in user land, but
+ * is mallocated in kernel land.
+ */
+
+void
+svc_getreq_common (const int fd)
+{
+ enum xprt_stat stat;
+ struct rpc_msg msg;
+ register SVCXPRT *xprt;
+ char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE];
+ msg.rm_call.cb_cred.oa_base = cred_area;
+ msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
+
+ xprt = xports[fd];
+ /* Do we control fd? */
+ if (xprt == NULL)
+ return;
+
+ /* now receive msgs from xprtprt (support batch calls) */
+ do
+ {
+ if (SVC_RECV (xprt, &msg))
+ {
+ /* now find the exported program and call it */
+ struct svc_callout *s;
+ struct svc_req r;
+ enum auth_stat why;
+ rpcvers_t low_vers;
+ rpcvers_t high_vers;
+ int prog_found;
+
+ r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
+ r.rq_xprt = xprt;
+ r.rq_prog = msg.rm_call.cb_prog;
+ r.rq_vers = msg.rm_call.cb_vers;
+ r.rq_proc = msg.rm_call.cb_proc;
+ r.rq_cred = msg.rm_call.cb_cred;
+
+ /* first authenticate the message */
+ /* Check for null flavor and bypass these calls if possible */
+
+ if (msg.rm_call.cb_cred.oa_flavor == AUTH_NULL)
+ {
+ r.rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
+ r.rq_xprt->xp_verf.oa_length = 0;
+ }
+ else if ((why = _authenticate (&r, &msg)) != AUTH_OK)
+ {
+ svcerr_auth (xprt, why);
+ goto call_done;
+ }
+
+ /* now match message with a registered service */
+ prog_found = FALSE;
+ low_vers = 0 - 1;
+ high_vers = 0;
+
+ for (s = svc_head; s != NULL_SVC; s = s->sc_next)
+ {
+ if (s->sc_prog == r.rq_prog)
+ {
+ if (s->sc_vers == r.rq_vers)
+ {
+ (*s->sc_dispatch) (&r, xprt);
+ goto call_done;
+ }
+ /* found correct version */
+ prog_found = TRUE;
+ if (s->sc_vers < low_vers)
+ low_vers = s->sc_vers;
+ if (s->sc_vers > high_vers)
+ high_vers = s->sc_vers;
+ }
+ /* found correct program */
+ }
+ /* if we got here, the program or version
+ is not served ... */
+ if (prog_found)
+ svcerr_progvers (xprt, low_vers, high_vers);
+ else
+ svcerr_noprog (xprt);
+ /* Fall through to ... */
+ }
+ call_done:
+ if ((stat = SVC_STAT (xprt)) == XPRT_DIED)
+ {
+ SVC_DESTROY (xprt);
+ break;
+ }
+ }
+ while (stat == XPRT_MOREREQS);
+}
+libc_hidden_def(svc_getreq_common)
+
+void
+svc_getreqset (fd_set *readfds)
+{
+ register u_int32_t mask;
+ register u_int32_t *maskp;
+ register int setsize;
+ register int sock;
+ register int bit;
+
+ setsize = _rpc_dtablesize ();
+ maskp = (u_int32_t *) readfds->fds_bits;
+ for (sock = 0; sock < setsize; sock += 32)
+ for (mask = *maskp++; (bit = ffs (mask)); mask ^= (1 << (bit - 1)))
+ svc_getreq_common (sock + bit - 1);
+}
+libc_hidden_def(svc_getreqset)
+
+void
+svc_getreq (int rdfds)
+{
+ fd_set readfds;
+
+ FD_ZERO (&readfds);
+ readfds.fds_bits[0] = rdfds;
+ svc_getreqset (&readfds);
+}
+libc_hidden_def(svc_getreq)
+
+void
+svc_getreq_poll (struct pollfd *pfdp, int pollretval)
+{
+ register int i;
+ register int fds_found;
+
+ for (i = fds_found = 0; i < svc_max_pollfd && fds_found < pollretval; ++i)
+ {
+ register struct pollfd *p = &pfdp[i];
+
+ if (p->fd != -1 && p->revents)
+ {
+ /* fd has input waiting */
+ ++fds_found;
+
+ if (p->revents & POLLNVAL)
+ xprt_unregister (xports[p->fd]);
+ else
+ svc_getreq_common (p->fd);
+ }
+ }
+}
+libc_hidden_def(svc_getreq_poll)
+
+#ifdef __UCLIBC_HAS_THREADS__
+
+void attribute_hidden __rpc_thread_svc_cleanup (void)
+{
+ struct svc_callout *svcp;
+
+ while ((svcp = svc_head) != NULL)
+ svc_unregister (svcp->sc_prog, svcp->sc_vers);
+}
+
+#endif /* __UCLIBC_HAS_THREADS__ */
diff --git a/android/librpc/svc_auth.c b/android/librpc/svc_auth.c
new file mode 100644
index 0000000..ae02a44
--- a/dev/null
+++ b/android/librpc/svc_auth.c
@@ -0,0 +1,124 @@
+/* @(#)svc_auth.c 2.4 88/08/15 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)svc_auth.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_auth.c, Server-side rpc authenticator interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <rpc/rpc.h>
+#include <rpc/svc.h>
+#include <rpc/svc_auth.h>
+
+/*
+ * svcauthsw is the bdevsw of server side authentication.
+ *
+ * Server side authenticators are called from authenticate by
+ * using the client auth struct flavor field to index into svcauthsw.
+ * The server auth flavors must implement a routine that looks
+ * like:
+ *
+ * enum auth_stat
+ * flavorx_auth(rqst, msg)
+ * register struct svc_req *rqst;
+ * register struct rpc_msg *msg;
+ *
+ */
+
+static enum auth_stat _svcauth_null (struct svc_req *, struct rpc_msg *);
+ /* no authentication */
+extern enum auth_stat _svcauth_unix (struct svc_req *, struct rpc_msg *);
+ /* unix style (uid, gids) */
+extern enum auth_stat _svcauth_short (struct svc_req *, struct rpc_msg *);
+ /* short hand unix style */
+#ifdef CONFIG_AUTH_DES
+extern enum auth_stat _svcauth_des (struct svc_req *, struct rpc_msg *);
+ /* des style */
+#endif
+
+static const struct
+ {
+ enum auth_stat (*authenticator) (struct svc_req *, struct rpc_msg *);
+ }
+svcauthsw[] =
+{
+ { _svcauth_null }, /* AUTH_NULL */
+ { _svcauth_unix }, /* AUTH_UNIX */
+ { _svcauth_short }, /* AUTH_SHORT */
+#ifdef CONFIG_AUTH_DES
+ { _svcauth_des } /* AUTH_DES */
+#endif
+};
+#define AUTH_MAX 3 /* HIGHEST AUTH NUMBER */
+
+
+/*
+ * The call rpc message, msg has been obtained from the wire. The msg contains
+ * the raw form of credentials and verifiers. authenticate returns AUTH_OK
+ * if the msg is successfully authenticated. If AUTH_OK then the routine also
+ * does the following things:
+ * set rqst->rq_xprt->verf to the appropriate response verifier;
+ * sets rqst->rq_client_cred to the "cooked" form of the credentials.
+ *
+ * NB: rqst->rq_cxprt->verf must be pre-allocated;
+ * its length is set appropriately.
+ *
+ * The caller still owns and is responsible for msg->u.cmb.cred and
+ * msg->u.cmb.verf. The authentication system retains ownership of
+ * rqst->rq_client_cred, the cooked credentials.
+ *
+ * There is an assumption that any flavour less than AUTH_NULL is
+ * invalid.
+ */
+enum auth_stat
+_authenticate (register struct svc_req *rqst, struct rpc_msg *msg)
+{
+ register int cred_flavor;
+
+ rqst->rq_cred = msg->rm_call.cb_cred;
+ rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
+ rqst->rq_xprt->xp_verf.oa_length = 0;
+ cred_flavor = rqst->rq_cred.oa_flavor;
+ if ((cred_flavor <= AUTH_MAX) && (cred_flavor >= AUTH_NULL))
+ return (*(svcauthsw[cred_flavor].authenticator)) (rqst, msg);
+
+ return AUTH_REJECTEDCRED;
+}
+libc_hidden_def(_authenticate)
+
+static enum auth_stat
+_svcauth_null (struct svc_req *rqst attribute_unused, struct rpc_msg *msg attribute_unused)
+{
+ return AUTH_OK;
+}
diff --git a/android/librpc/svc_authux.c b/android/librpc/svc_authux.c
new file mode 100644
index 0000000..03ec4d3
--- a/dev/null
+++ b/android/librpc/svc_authux.c
@@ -0,0 +1,159 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * svc_auth_unix.c
+ * Handles UNIX flavor authentication parameters on the service side of rpc.
+ * There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT.
+ * _svcauth_unix does full blown unix style uid,gid+gids auth,
+ * _svcauth_short uses a shorthand auth to index into a cache of longhand auths.
+ * Note: the shorthand has been gutted for efficiency.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/svc.h>
+
+
+/*
+ * Unix longhand authenticator
+ */
+enum auth_stat
+_svcauth_unix (struct svc_req *rqst, struct rpc_msg *msg) attribute_hidden;
+enum auth_stat
+_svcauth_unix (struct svc_req *rqst, struct rpc_msg *msg)
+{
+ enum auth_stat stat;
+ XDR xdrs;
+ struct authunix_parms *aup;
+ int32_t *buf;
+ struct area
+ {
+ struct authunix_parms area_aup;
+ char area_machname[MAX_MACHINE_NAME + 1];
+ gid_t area_gids[NGRPS];
+ }
+ *area;
+ u_int auth_len;
+ u_int str_len, gid_len;
+ u_int i;
+
+ area = (struct area *) rqst->rq_clntcred;
+ aup = &area->area_aup;
+ aup->aup_machname = area->area_machname;
+ aup->aup_gids = area->area_gids;
+ auth_len = (u_int) msg->rm_call.cb_cred.oa_length;
+ xdrmem_create (&xdrs, msg->rm_call.cb_cred.oa_base, auth_len, XDR_DECODE);
+ buf = XDR_INLINE (&xdrs, auth_len);
+ if (buf != NULL)
+ {
+ aup->aup_time = IXDR_GET_LONG (buf);
+ str_len = IXDR_GET_U_INT32 (buf);
+ if (str_len > MAX_MACHINE_NAME)
+ {
+ stat = AUTH_BADCRED;
+ goto done;
+ }
+ memcpy (aup->aup_machname, (caddr_t) buf, (u_int) str_len);
+ aup->aup_machname[str_len] = 0;
+ str_len = RNDUP (str_len);
+ buf = (int32_t *) ((char *) buf + str_len);
+ aup->aup_uid = IXDR_GET_LONG (buf);
+ aup->aup_gid = IXDR_GET_LONG (buf);
+ gid_len = IXDR_GET_U_INT32 (buf);
+ if (gid_len > NGRPS)
+ {
+ stat = AUTH_BADCRED;
+ goto done;
+ }
+ aup->aup_len = gid_len;
+ for (i = 0; i < gid_len; i++)
+ {
+ aup->aup_gids[i] = IXDR_GET_LONG (buf);
+ }
+ /*
+ * five is the smallest unix credentials structure -
+ * timestamp, hostname len (0), uid, gid, and gids len (0).
+ */
+ if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len)
+ {
+ (void) printf ("bad auth_len gid %d str %d auth %d\n",
+ gid_len, str_len, auth_len);
+ stat = AUTH_BADCRED;
+ goto done;
+ }
+ }
+ else if (!xdr_authunix_parms (&xdrs, aup))
+ {
+ xdrs.x_op = XDR_FREE;
+ (void) xdr_authunix_parms (&xdrs, aup);
+ stat = AUTH_BADCRED;
+ goto done;
+ }
+
+ /* get the verifier */
+ if ((u_int)msg->rm_call.cb_verf.oa_length)
+ {
+ rqst->rq_xprt->xp_verf.oa_flavor =
+ msg->rm_call.cb_verf.oa_flavor;
+ rqst->rq_xprt->xp_verf.oa_base =
+ msg->rm_call.cb_verf.oa_base;
+ rqst->rq_xprt->xp_verf.oa_length =
+ msg->rm_call.cb_verf.oa_length;
+ }
+ else
+ {
+ rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
+ rqst->rq_xprt->xp_verf.oa_length = 0;
+ }
+ stat = AUTH_OK;
+done:
+ XDR_DESTROY (&xdrs);
+ return stat;
+}
+
+
+/*
+ * Shorthand unix authenticator
+ * Looks up longhand in a cache.
+ */
+/*ARGSUSED */
+enum auth_stat
+_svcauth_short (struct svc_req *rqst attribute_unused, struct rpc_msg *msg attribute_unused) attribute_hidden;
+enum auth_stat
+_svcauth_short (struct svc_req *rqst attribute_unused, struct rpc_msg *msg attribute_unused)
+{
+ return AUTH_REJECTEDCRED;
+}
diff --git a/android/librpc/svc_raw.c b/android/librpc/svc_raw.c
new file mode 100644
index 0000000..f915a7d
--- a/dev/null
+++ b/android/librpc/svc_raw.c
@@ -0,0 +1,166 @@
+/* @(#)svc_raw.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)svc_raw.c 1.15 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_raw.c, This a toy for simple testing and timing.
+ * Interface to create an rpc client and server in the same UNIX process.
+ * This lets us simulate rpc and get rpc (round trip) overhead, without
+ * any interference from the kernel.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+#include "rpc_private.h"
+#include <rpc/svc.h>
+
+
+/*
+ * This is the "network" that we will be moving data over
+ */
+struct svcraw_private_s
+ {
+ char _raw_buf[UDPMSGSIZE];
+ SVCXPRT server;
+ XDR xdr_stream;
+ char verf_body[MAX_AUTH_BYTES];
+ };
+#ifdef __UCLIBC_HAS_THREADS__
+#define svcraw_private (*(struct svcraw_private_s **)&RPC_THREAD_VARIABLE(svcraw_private_s))
+#else
+static struct svcraw_private_s *svcraw_private;
+#endif
+
+static bool_t svcraw_recv (SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat svcraw_stat (SVCXPRT *);
+static bool_t svcraw_getargs (SVCXPRT *, xdrproc_t, caddr_t);
+static bool_t svcraw_reply (SVCXPRT *, struct rpc_msg *);
+static bool_t svcraw_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
+static void svcraw_destroy (SVCXPRT *);
+
+static struct xp_ops server_ops =
+{
+ svcraw_recv,
+ svcraw_stat,
+ svcraw_getargs,
+ svcraw_reply,
+ svcraw_freeargs,
+ svcraw_destroy
+};
+
+SVCXPRT *
+svcraw_create (void)
+{
+ struct svcraw_private_s *srp = svcraw_private;
+
+ if (srp == 0)
+ {
+ srp = (struct svcraw_private_s *) calloc (1, sizeof (*srp));
+ if (srp == 0)
+ return NULL;
+ }
+ srp->server.xp_sock = 0;
+ srp->server.xp_port = 0;
+ srp->server.xp_ops = &server_ops;
+ srp->server.xp_verf.oa_base = srp->verf_body;
+ xdrmem_create (&srp->xdr_stream, srp->_raw_buf, UDPMSGSIZE, XDR_FREE);
+ return &srp->server;
+}
+
+static enum xprt_stat
+svcraw_stat (SVCXPRT *xprt attribute_unused)
+{
+ return XPRT_IDLE;
+}
+
+static bool_t
+svcraw_recv (SVCXPRT *xprt attribute_unused, struct rpc_msg *msg)
+{
+ struct svcraw_private_s *srp = svcraw_private;
+ XDR *xdrs;
+
+ if (srp == 0)
+ return FALSE;
+ xdrs = &srp->xdr_stream;
+ xdrs->x_op = XDR_DECODE;
+ XDR_SETPOS (xdrs, 0);
+ if (!xdr_callmsg (xdrs, msg))
+ return FALSE;
+ return TRUE;
+}
+
+static bool_t
+svcraw_reply (SVCXPRT *xprt attribute_unused, struct rpc_msg *msg)
+{
+ struct svcraw_private_s *srp = svcraw_private;
+ XDR *xdrs;
+
+ if (srp == 0)
+ return FALSE;
+ xdrs = &srp->xdr_stream;
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS (xdrs, 0);
+ if (!xdr_replymsg (xdrs, msg))
+ return FALSE;
+ (void) XDR_GETPOS (xdrs); /* called just for overhead */
+ return TRUE;
+}
+
+static bool_t
+svcraw_getargs (SVCXPRT *xprt attribute_unused, xdrproc_t xdr_args, caddr_t args_ptr)
+{
+ struct svcraw_private_s *srp = svcraw_private;
+
+ if (srp == 0)
+ return FALSE;
+ return (*xdr_args) (&srp->xdr_stream, args_ptr);
+}
+
+static bool_t
+svcraw_freeargs (SVCXPRT *xprt attribute_unused, xdrproc_t xdr_args, caddr_t args_ptr)
+{
+ struct svcraw_private_s *srp = svcraw_private;
+ XDR *xdrs;
+
+ if (srp == 0)
+ return FALSE;
+ xdrs = &srp->xdr_stream;
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_args) (xdrs, args_ptr);
+}
+
+static void
+svcraw_destroy (SVCXPRT *xprt attribute_unused)
+{
+}
diff --git a/android/librpc/svc_run.c b/android/librpc/svc_run.c
new file mode 100644
index 0000000..1442cba
--- a/dev/null
+++ b/android/librpc/svc_run.c
@@ -0,0 +1,90 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+/*
+ * This is the rpc server side idle loop
+ * Wait for input, call server program.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <rpc/rpc.h>
+
+/* used by svc_[max_]pollfd */
+
+/* This function can be used as a signal handler to terminate the
+ server loop. */
+void
+svc_exit (void)
+{
+ free (svc_pollfd);
+ svc_pollfd = NULL;
+ svc_max_pollfd = 0;
+}
+
+void
+svc_run (void)
+{
+ int i;
+
+ for (;;)
+ {
+ struct pollfd *my_pollfd;
+
+ if (svc_max_pollfd == 0 && svc_pollfd == NULL)
+ return;
+
+ my_pollfd = malloc (sizeof (struct pollfd) * svc_max_pollfd);
+ for (i = 0; i < svc_max_pollfd; ++i)
+ {
+ my_pollfd[i].fd = svc_pollfd[i].fd;
+ my_pollfd[i].events = svc_pollfd[i].events;
+ my_pollfd[i].revents = 0;
+ }
+
+ switch (i = poll (my_pollfd, svc_max_pollfd, -1))
+ {
+ case -1:
+ free (my_pollfd);
+ if (errno == EINTR)
+ continue;
+ perror (_("svc_run: - poll failed"));
+ return;
+ case 0:
+ free (my_pollfd);
+ continue;
+ default:
+ svc_getreq_poll (my_pollfd, i);
+ free (my_pollfd);
+ }
+ }
+}
diff --git a/android/librpc/svc_simple.c b/android/librpc/svc_simple.c
new file mode 100644
index 0000000..dceb6ac
--- a/dev/null
+++ b/android/librpc/svc_simple.c
@@ -0,0 +1,197 @@
+/* @(#)svc_simple.c 2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)svc_simple.c 1.18 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_simple.c
+ * Simplified front end to rpc.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "rpc_private.h"
+#include <rpc/pmap_clnt.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+# include <libio/iolibio.h>
+# define fputs(s, f) _IO_fputs (s, f)
+#endif
+
+
+struct proglst_
+ {
+ char *(*p_progname) (char *);
+ int p_prognum;
+ int p_procnum;
+ xdrproc_t p_inproc, p_outproc;
+ struct proglst_ *p_nxt;
+ };
+#ifdef __UCLIBC_HAS_THREADS__
+#define proglst (*(struct proglst_ **)&RPC_THREAD_VARIABLE(svcsimple_proglst_s))
+#else
+static struct proglst_ *proglst;
+#endif
+
+
+static void universal (struct svc_req *rqstp, SVCXPRT *transp_s);
+#ifdef __UCLIBC_HAS_THREADS__
+#define transp (*(SVCXPRT **)&RPC_THREAD_VARIABLE(svcsimple_transp_s))
+#else
+static SVCXPRT *transp;
+#endif
+
+int registerrpc (u_long prognum, u_long versnum, u_long procnum,
+ char *(*progname) (char *), xdrproc_t inproc, xdrproc_t outproc);
+int
+registerrpc (u_long prognum, u_long versnum, u_long procnum,
+ char *(*progname) (char *), xdrproc_t inproc, xdrproc_t outproc)
+{
+ struct proglst_ *pl;
+ char *buf;
+
+ if (procnum == NULLPROC)
+ {
+
+ (void) asprintf (&buf, _("can't reassign procedure number %ld\n"),
+ NULLPROC);
+ goto err_out;
+ }
+ if (transp == 0)
+ {
+ transp = svcudp_create (RPC_ANYSOCK);
+ if (transp == NULL)
+ {
+ buf = strdup (_("couldn't create an rpc server\n"));
+ goto err_out;
+ }
+ }
+ (void) pmap_unset ((u_long) prognum, (u_long) versnum);
+ if (!svc_register (transp, (u_long) prognum, (u_long) versnum,
+ universal, IPPROTO_UDP))
+ {
+ (void) asprintf (&buf, _("couldn't register prog %ld vers %ld\n"),
+ prognum, versnum);
+ goto err_out;
+ }
+ pl = (struct proglst_ *) malloc (sizeof (struct proglst_));
+ if (pl == NULL)
+ {
+ buf = strdup (_("registerrpc: out of memory\n"));
+ goto err_out;
+ }
+ pl->p_progname = progname;
+ pl->p_prognum = prognum;
+ pl->p_procnum = procnum;
+ pl->p_inproc = inproc;
+ pl->p_outproc = outproc;
+ pl->p_nxt = proglst;
+ proglst = pl;
+ return 0;
+
+ err_out:
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) __fwprintf (stderr, L"%s", buf);
+ else
+#endif
+ (void) fputs (buf, stderr);
+ free (buf);
+ return -1;
+}
+
+static void
+universal (struct svc_req *rqstp, SVCXPRT *transp_l)
+{
+ int prog, proc;
+ char *outdata;
+ char xdrbuf[UDPMSGSIZE];
+ struct proglst_ *pl;
+ char *buf = NULL;
+
+ /*
+ * enforce "procnum 0 is echo" convention
+ */
+ if (rqstp->rq_proc == NULLPROC)
+ {
+ if (svc_sendreply (transp_l, (xdrproc_t)xdr_void, (char *) NULL) == FALSE)
+ {
+ write (STDERR_FILENO, "xxx\n", 4);
+ exit (1);
+ }
+ return;
+ }
+ prog = rqstp->rq_prog;
+ proc = rqstp->rq_proc;
+ for (pl = proglst; pl != NULL; pl = pl->p_nxt)
+ if (pl->p_prognum == prog && pl->p_procnum == proc)
+ {
+ /* decode arguments into a CLEAN buffer */
+ memset (xdrbuf, 0, sizeof (xdrbuf)); /* required ! */
+ if (!svc_getargs (transp_l, pl->p_inproc, xdrbuf))
+ {
+ svcerr_decode (transp_l);
+ return;
+ }
+ outdata = (*(pl->p_progname)) (xdrbuf);
+ if (outdata == NULL && pl->p_outproc != (xdrproc_t)xdr_void)
+ /* there was an error */
+ return;
+ if (!svc_sendreply (transp_l, pl->p_outproc, outdata))
+ {
+ (void) asprintf (&buf,
+ _("trouble replying to prog %d\n"),
+ pl->p_prognum);
+ exit (1);
+ }
+ /* free the decoded arguments */
+ (void) svc_freeargs (transp_l, pl->p_inproc, xdrbuf);
+ return;
+ }
+ (void) asprintf (&buf, _("never registered prog %d\n"), prog);
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", buf);
+ else
+#endif
+ fputs (buf, stderr);
+ free (buf);
+ exit (1);
+}
diff --git a/android/librpc/svc_tcp.c b/android/librpc/svc_tcp.c
new file mode 100644
index 0000000..363f203
--- a/dev/null
+++ b/android/librpc/svc_tcp.c
@@ -0,0 +1,428 @@
+/* @(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_tcp.c, Server side for TCP/IP based RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * Actually implements two flavors of transporter -
+ * a tcp rendezvouser (a listener and connection establisher)
+ * and a record/tcp stream.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+# include <libio/iolibio.h>
+# define fputs(s, f) _IO_fputs (s, f)
+#endif
+
+
+/*
+ * Ops vector for TCP/IP based rpc service handle
+ */
+static bool_t svctcp_recv (SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat svctcp_stat (SVCXPRT *);
+static bool_t svctcp_getargs (SVCXPRT *, xdrproc_t, caddr_t);
+static bool_t svctcp_reply (SVCXPRT *, struct rpc_msg *);
+static bool_t svctcp_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
+static void svctcp_destroy (SVCXPRT *);
+
+static const struct xp_ops svctcp_op =
+{
+ svctcp_recv,
+ svctcp_stat,
+ svctcp_getargs,
+ svctcp_reply,
+ svctcp_freeargs,
+ svctcp_destroy
+};
+
+/*
+ * Ops vector for TCP/IP rendezvous handler
+ */
+static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat rendezvous_stat (SVCXPRT *);
+static void svctcp_rendezvous_abort (void) attribute_noreturn;
+
+/* This function makes sure abort() relocation goes through PLT
+ and thus can be lazy bound. */
+static void
+svctcp_rendezvous_abort (void)
+{
+ abort ();
+};
+
+static const struct xp_ops svctcp_rendezvous_op =
+{
+ rendezvous_request,
+ rendezvous_stat,
+ (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svctcp_rendezvous_abort,
+ (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svctcp_rendezvous_abort,
+ (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svctcp_rendezvous_abort,
+ svctcp_destroy
+};
+
+static int readtcp (char*, char *, int);
+static int writetcp (char *, char *, int);
+static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
+
+struct tcp_rendezvous
+ { /* kept in xprt->xp_p1 */
+ u_int sendsize;
+ u_int recvsize;
+ };
+
+struct tcp_conn
+ { /* kept in xprt->xp_p1 */
+ enum xprt_stat strm_stat;
+ u_long x_id;
+ XDR xdrs;
+ char verf_body[MAX_AUTH_BYTES];
+ };
+
+/*
+ * Usage:
+ * xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
+ *
+ * Creates, registers, and returns a (rpc) tcp based transporter.
+ * Once *xprt is initialized, it is registered as a transporter
+ * see (svc.h, xprt_register). This routine returns
+ * a NULL if a problem occurred.
+ *
+ * If sock<0 then a socket is created, else sock is used.
+ * If the socket, sock is not bound to a port then svctcp_create
+ * binds it to an arbitrary port. The routine then starts a tcp
+ * listener on the socket's associated port. In any (successful) case,
+ * xprt->xp_sock is the registered socket number and xprt->xp_port is the
+ * associated port number.
+ *
+ * Since tcp streams do buffered io similar to stdio, the caller can specify
+ * how big the send and receive buffers are via the second and third parms;
+ * 0 => use the system default.
+ */
+SVCXPRT *
+svctcp_create (int sock, u_int sendsize, u_int recvsize)
+{
+ bool_t madesock = FALSE;
+ SVCXPRT *xprt;
+ struct tcp_rendezvous *r;
+ struct sockaddr_in addr;
+ socklen_t len = sizeof (struct sockaddr_in);
+
+ if (sock == RPC_ANYSOCK)
+ {
+ if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ {
+ perror (_("svc_tcp.c - tcp socket creation problem"));
+ return (SVCXPRT *) NULL;
+ }
+ madesock = TRUE;
+ }
+ memset ((char *) &addr, 0, sizeof (addr));
+ addr.sin_family = AF_INET;
+ if (bindresvport (sock, &addr))
+ {
+ addr.sin_port = 0;
+ (void) bind (sock, (struct sockaddr *) &addr, len);
+ }
+ if ((getsockname (sock, (struct sockaddr *) &addr, &len) != 0) ||
+ (listen (sock, 2) != 0))
+ {
+ perror (_("svc_tcp.c - cannot getsockname or listen"));
+ if (madesock)
+ (void) close (sock);
+ return (SVCXPRT *) NULL;
+ }
+ r = (struct tcp_rendezvous *) mem_alloc (sizeof (*r));
+ xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
+ if (r == NULL || xprt == NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) __fwprintf (stderr, L"%s", _("svctcp_create: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("svctcp_create: out of memory\n"), stderr);
+ mem_free (r, sizeof (*r));
+ mem_free (xprt, sizeof (SVCXPRT));
+ return NULL;
+ }
+ r->sendsize = sendsize;
+ r->recvsize = recvsize;
+ xprt->xp_p2 = NULL;
+ xprt->xp_p1 = (caddr_t) r;
+ xprt->xp_verf = _null_auth;
+ xprt->xp_ops = &svctcp_rendezvous_op;
+ xprt->xp_port = ntohs (addr.sin_port);
+ xprt->xp_sock = sock;
+ xprt_register (xprt);
+ return xprt;
+}
+
+/*
+ * Like svtcp_create(), except the routine takes any *open* UNIX file
+ * descriptor as its first input.
+ */
+SVCXPRT *
+svcfd_create (int fd, u_int sendsize, u_int recvsize);
+SVCXPRT *
+svcfd_create (int fd, u_int sendsize, u_int recvsize)
+{
+ return makefd_xprt (fd, sendsize, recvsize);
+}
+
+static SVCXPRT *
+internal_function
+makefd_xprt (int fd, u_int sendsize, u_int recvsize)
+{
+ SVCXPRT *xprt;
+ struct tcp_conn *cd;
+
+ xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
+ cd = (struct tcp_conn *) mem_alloc (sizeof (struct tcp_conn));
+ if (xprt == (SVCXPRT *) NULL || cd == NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) __fwprintf (stderr, L"%s",
+ _("svc_tcp: makefd_xprt: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("svc_tcp: makefd_xprt: out of memory\n"), stderr);
+ mem_free (xprt, sizeof (SVCXPRT));
+ mem_free (cd, sizeof (struct tcp_conn));
+ return NULL;
+ }
+ cd->strm_stat = XPRT_IDLE;
+ xdrrec_create (&(cd->xdrs), sendsize, recvsize,
+ (caddr_t) xprt, readtcp, writetcp);
+ xprt->xp_p2 = NULL;
+ xprt->xp_p1 = (caddr_t) cd;
+ xprt->xp_verf.oa_base = cd->verf_body;
+ xprt->xp_addrlen = 0;
+ xprt->xp_ops = &svctcp_op; /* truly deals with calls */
+ xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
+ xprt->xp_sock = fd;
+ xprt_register (xprt);
+ return xprt;
+}
+
+static bool_t
+rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg attribute_unused)
+{
+ int sock;
+ struct tcp_rendezvous *r;
+ struct sockaddr_in addr;
+ socklen_t len;
+
+ r = (struct tcp_rendezvous *) xprt->xp_p1;
+again:
+ len = sizeof (struct sockaddr_in);
+ if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
+ {
+ if (errno == EINTR)
+ goto again;
+ return FALSE;
+ }
+ /*
+ * make a new transporter (re-uses xprt)
+ */
+ xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
+ memcpy (&xprt->xp_raddr, &addr, sizeof (addr));
+ xprt->xp_addrlen = len;
+ return FALSE; /* there is never an rpc msg to be processed */
+}
+
+static enum xprt_stat
+rendezvous_stat (SVCXPRT *xprt attribute_unused)
+{
+ return XPRT_IDLE;
+}
+
+static void
+svctcp_destroy (SVCXPRT *xprt)
+{
+ struct tcp_conn *cd = (struct tcp_conn *) xprt->xp_p1;
+
+ xprt_unregister (xprt);
+ (void) close (xprt->xp_sock);
+ if (xprt->xp_port != 0)
+ {
+ /* a rendezvouser socket */
+ xprt->xp_port = 0;
+ }
+ else
+ {
+ /* an actual connection socket */
+ XDR_DESTROY (&(cd->xdrs));
+ }
+ mem_free ((caddr_t) cd, sizeof (struct tcp_conn));
+ mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
+}
+
+
+/*
+ * reads data from the tcp connection.
+ * any error is fatal and the connection is closed.
+ * (And a read of zero bytes is a half closed stream => error.)
+ */
+static int
+readtcp (char *xprtptr, char *buf, int len)
+{
+ SVCXPRT *xprt = (SVCXPRT *)xprtptr;
+ int sock = xprt->xp_sock;
+ int milliseconds = 35 * 1000;
+ struct pollfd pollfd;
+
+ do
+ {
+ pollfd.fd = sock;
+ pollfd.events = POLLIN;
+ switch (poll (&pollfd, 1, milliseconds))
+ {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ /*FALLTHROUGH*/
+ case 0:
+ goto fatal_err;
+ default:
+ if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
+ || (pollfd.revents & POLLNVAL))
+ goto fatal_err;
+ break;
+ }
+ }
+ while ((pollfd.revents & POLLIN) == 0);
+
+ if ((len = read (sock, buf, len)) > 0)
+ return len;
+
+ fatal_err:
+ ((struct tcp_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
+ return -1;
+}
+
+/*
+ * writes data to the tcp connection.
+ * Any error is fatal and the connection is closed.
+ */
+static int
+writetcp (char *xprtptr, char * buf, int len)
+{
+ SVCXPRT *xprt = (SVCXPRT *)xprtptr;
+ int i, cnt;
+
+ for (cnt = len; cnt > 0; cnt -= i, buf += i)
+ {
+ if ((i = write (xprt->xp_sock, buf, cnt)) < 0)
+ {
+ ((struct tcp_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
+ return -1;
+ }
+ }
+ return len;
+}
+
+static enum xprt_stat
+svctcp_stat (SVCXPRT *xprt)
+{
+ struct tcp_conn *cd =
+ (struct tcp_conn *) (xprt->xp_p1);
+
+ if (cd->strm_stat == XPRT_DIED)
+ return XPRT_DIED;
+ if (!xdrrec_eof (&(cd->xdrs)))
+ return XPRT_MOREREQS;
+ return XPRT_IDLE;
+}
+
+static bool_t
+svctcp_recv (SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct tcp_conn *cd = (struct tcp_conn *) (xprt->xp_p1);
+ XDR *xdrs = &(cd->xdrs);
+
+ xdrs->x_op = XDR_DECODE;
+ (void) xdrrec_skiprecord (xdrs);
+ if (xdr_callmsg (xdrs, msg))
+ {
+ cd->x_id = msg->rm_xid;
+ return TRUE;
+ }
+ cd->strm_stat = XPRT_DIED; /* XXXX */
+ return FALSE;
+}
+
+static bool_t
+svctcp_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
+{
+ return ((*xdr_args) (&(((struct tcp_conn *)
+ (xprt->xp_p1))->xdrs), args_ptr));
+}
+
+static bool_t
+svctcp_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
+{
+ XDR *xdrs = &(((struct tcp_conn *) (xprt->xp_p1))->xdrs);
+
+ xdrs->x_op = XDR_FREE;
+ return ((*xdr_args) (xdrs, args_ptr));
+}
+
+static bool_t
+svctcp_reply (SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct tcp_conn *cd = (struct tcp_conn *) (xprt->xp_p1);
+ XDR *xdrs = &(cd->xdrs);
+ bool_t stat;
+
+ xdrs->x_op = XDR_ENCODE;
+ msg->rm_xid = cd->x_id;
+ stat = xdr_replymsg (xdrs, msg);
+ (void) xdrrec_endofrecord (xdrs, TRUE);
+ return stat;
+}
diff --git a/android/librpc/svc_udp.c b/android/librpc/svc_udp.c
new file mode 100644
index 0000000..87015c6
--- a/dev/null
+++ b/android/librpc/svc_udp.c
@@ -0,0 +1,596 @@
+/* @(#)svc_udp.c 2.2 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * svc_udp.c,
+ * Server side for UDP/IP based RPC. (Does some caching in the hopes of
+ * achieving execute-at-most-once semantics.)
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#ifdef IP_PKTINFO
+#include <sys/uio.h>
+#endif
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+# include <libio/iolibio.h>
+# define fputs(s, f) _IO_fputs (s, f)
+#endif
+
+
+#define rpc_buffer(xprt) ((xprt)->xp_p1)
+#ifndef MAX
+#define MAX(a, b) ((a > b) ? a : b)
+#endif
+
+static bool_t svcudp_recv (SVCXPRT *, struct rpc_msg *);
+static bool_t svcudp_reply (SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat svcudp_stat (SVCXPRT *);
+static bool_t svcudp_getargs (SVCXPRT *, xdrproc_t, caddr_t);
+static bool_t svcudp_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
+static void svcudp_destroy (SVCXPRT *);
+
+static const struct xp_ops svcudp_op =
+{
+ svcudp_recv,
+ svcudp_stat,
+ svcudp_getargs,
+ svcudp_reply,
+ svcudp_freeargs,
+ svcudp_destroy
+};
+
+static int cache_get (SVCXPRT *, struct rpc_msg *, char **replyp,
+ u_long *replylenp);
+static void cache_set (SVCXPRT *xprt, u_long replylen);
+
+/*
+ * kept in xprt->xp_p2
+ */
+struct svcudp_data
+ {
+ u_int su_iosz; /* byte size of send.recv buffer */
+ u_long su_xid; /* transaction id */
+ XDR su_xdrs; /* XDR handle */
+ char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
+ char *su_cache; /* cached data, NULL if no cache */
+ };
+#define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2))
+
+/*
+ * Usage:
+ * xprt = svcudp_create(sock);
+ *
+ * If sock<0 then a socket is created, else sock is used.
+ * If the socket, sock is not bound to a port then svcudp_create
+ * binds it to an arbitrary port. In any (successful) case,
+ * xprt->xp_sock is the registered socket number and xprt->xp_port is the
+ * associated port number.
+ * Once *xprt is initialized, it is registered as a transporter;
+ * see (svc.h, xprt_register).
+ * The routines returns NULL if a problem occurred.
+ */
+SVCXPRT *
+svcudp_bufcreate (int sock, u_int sendsz, u_int recvsz)
+{
+ bool_t madesock = FALSE;
+ SVCXPRT *xprt;
+ struct svcudp_data *su;
+ struct sockaddr_in addr;
+ socklen_t len = sizeof (struct sockaddr_in);
+ int pad;
+ void *buf;
+
+ if (sock == RPC_ANYSOCK)
+ {
+ if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ {
+ perror (_("svcudp_create: socket creation problem"));
+ return (SVCXPRT *) NULL;
+ }
+ madesock = TRUE;
+ }
+ memset ((char *) &addr, 0, sizeof (addr));
+ addr.sin_family = AF_INET;
+ if (bindresvport (sock, &addr))
+ {
+ addr.sin_port = 0;
+ (void) bind (sock, (struct sockaddr *) &addr, len);
+ }
+ if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0)
+ {
+ perror (_("svcudp_create - cannot getsockname"));
+ if (madesock)
+ (void) close (sock);
+ return (SVCXPRT *) NULL;
+ }
+ xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
+ su = (struct svcudp_data *) mem_alloc (sizeof (*su));
+ buf = mem_alloc (((MAX (sendsz, recvsz) + 3) / 4) * 4);
+ if (xprt == NULL || su == NULL || buf == NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s", _("svcudp_create: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("svcudp_create: out of memory\n"), stderr);
+ mem_free (xprt, sizeof (SVCXPRT));
+ mem_free (su, sizeof (*su));
+ mem_free (buf, ((MAX (sendsz, recvsz) + 3) / 4) * 4);
+ return NULL;
+ }
+ su->su_iosz = ((MAX (sendsz, recvsz) + 3) / 4) * 4;
+ rpc_buffer (xprt) = buf;
+ xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_DECODE);
+ su->su_cache = NULL;
+ xprt->xp_p2 = (caddr_t) su;
+ xprt->xp_verf.oa_base = su->su_verfbody;
+ xprt->xp_ops = &svcudp_op;
+ xprt->xp_port = ntohs (addr.sin_port);
+ xprt->xp_sock = sock;
+
+#ifdef IP_PKTINFO
+ if ((sizeof (struct iovec) + sizeof (struct msghdr)
+ + sizeof(struct cmsghdr) + sizeof (struct in_pktinfo))
+ > sizeof (xprt->xp_pad))
+ {
+# ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s",
+ _("svcudp_create: xp_pad is too small for IP_PKTINFO\n"));
+ else
+# endif
+ (void) fputs (_("svcudp_create: xp_pad is too small for IP_PKTINFO\n"),
+ stderr);
+ return NULL;
+ }
+ pad = 1;
+ if (setsockopt (sock, SOL_IP, IP_PKTINFO, (void *) &pad,
+ sizeof (pad)) == 0)
+ /* Set the padding to all 1s. */
+ pad = 0xff;
+ else
+#endif
+ /* Clear the padding. */
+ pad = 0;
+ memset (&xprt->xp_pad [0], pad, sizeof (xprt->xp_pad));
+
+ xprt_register (xprt);
+ return xprt;
+}
+libc_hidden_def(svcudp_bufcreate)
+
+SVCXPRT *
+svcudp_create (int sock)
+{
+
+ return svcudp_bufcreate (sock, UDPMSGSIZE, UDPMSGSIZE);
+}
+libc_hidden_def(svcudp_create)
+
+static enum xprt_stat
+svcudp_stat (SVCXPRT *xprt attribute_unused)
+{
+
+ return XPRT_IDLE;
+}
+
+static bool_t
+svcudp_recv (SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct svcudp_data *su = su_data (xprt);
+ XDR *xdrs = &(su->su_xdrs);
+ int rlen;
+ char *reply;
+ u_long replylen;
+ socklen_t len;
+
+ /* It is very tricky when you have IP aliases. We want to make sure
+ that we are sending the packet from the IP address where the
+ incoming packet is addressed to. H.J. */
+#ifdef IP_PKTINFO
+ struct iovec *iovp;
+ struct msghdr *mesgp;
+#endif
+
+again:
+ /* FIXME -- should xp_addrlen be a size_t? */
+ len = (socklen_t) sizeof(struct sockaddr_in);
+#ifdef IP_PKTINFO
+ iovp = (struct iovec *) &xprt->xp_pad [0];
+ mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
+ if (mesgp->msg_iovlen)
+ {
+ iovp->iov_base = rpc_buffer (xprt);
+ iovp->iov_len = su->su_iosz;
+ mesgp->msg_iov = iovp;
+ mesgp->msg_iovlen = 1;
+ mesgp->msg_name = &(xprt->xp_raddr);
+ mesgp->msg_namelen = len;
+ mesgp->msg_control = &xprt->xp_pad [sizeof (struct iovec)
+ + sizeof (struct msghdr)];
+ mesgp->msg_controllen = sizeof(xprt->xp_pad)
+ - sizeof (struct iovec) - sizeof (struct msghdr);
+ rlen = recvmsg (xprt->xp_sock, mesgp, 0);
+ if (rlen >= 0)
+ len = mesgp->msg_namelen;
+ }
+ else
+#endif
+ rlen = recvfrom (xprt->xp_sock, rpc_buffer (xprt),
+ (int) su->su_iosz, 0,
+ (struct sockaddr *) &(xprt->xp_raddr), &len);
+ xprt->xp_addrlen = len;
+ if (rlen == -1 && errno == EINTR)
+ goto again;
+ if (rlen < 16) /* < 4 32-bit ints? */
+ return FALSE;
+ xdrs->x_op = XDR_DECODE;
+ XDR_SETPOS (xdrs, 0);
+ if (!xdr_callmsg (xdrs, msg))
+ return FALSE;
+ su->su_xid = msg->rm_xid;
+ if (su->su_cache != NULL)
+ {
+ if (cache_get (xprt, msg, &reply, &replylen))
+ {
+#ifdef IP_PKTINFO
+ if (mesgp->msg_iovlen)
+ {
+ iovp->iov_base = reply;
+ iovp->iov_len = replylen;
+ (void) sendmsg (xprt->xp_sock, mesgp, 0);
+ }
+ else
+#endif
+ (void) sendto (xprt->xp_sock, reply, (int) replylen, 0,
+ (struct sockaddr *) &xprt->xp_raddr, len);
+ return TRUE;
+ }
+ }
+ return TRUE;
+}
+
+static bool_t
+svcudp_reply (SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct svcudp_data *su = su_data (xprt);
+ XDR *xdrs = &(su->su_xdrs);
+ int slen, sent;
+ bool_t stat = FALSE;
+#ifdef IP_PKTINFO
+ struct iovec *iovp;
+ struct msghdr *mesgp;
+#endif
+
+ xdrs->x_op = XDR_ENCODE;
+ XDR_SETPOS (xdrs, 0);
+ msg->rm_xid = su->su_xid;
+ if (xdr_replymsg (xdrs, msg))
+ {
+ slen = (int) XDR_GETPOS (xdrs);
+#ifdef IP_PKTINFO
+ mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
+ if (mesgp->msg_iovlen)
+ {
+ iovp = (struct iovec *) &xprt->xp_pad [0];
+ iovp->iov_base = rpc_buffer (xprt);
+ iovp->iov_len = slen;
+ sent = sendmsg (xprt->xp_sock, mesgp, 0);
+ }
+ else
+#endif
+ sent = sendto (xprt->xp_sock, rpc_buffer (xprt), slen, 0,
+ (struct sockaddr *) &(xprt->xp_raddr),
+ xprt->xp_addrlen);
+ if (sent == slen)
+ {
+ stat = TRUE;
+ if (su->su_cache && slen >= 0)
+ {
+ cache_set (xprt, (u_long) slen);
+ }
+ }
+ }
+ return stat;
+}
+
+static bool_t
+svcudp_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
+{
+
+ return (*xdr_args) (&(su_data (xprt)->su_xdrs), args_ptr);
+}
+
+static bool_t
+svcudp_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
+{
+ XDR *xdrs = &(su_data (xprt)->su_xdrs);
+
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_args) (xdrs, args_ptr);
+}
+
+static void
+svcudp_destroy (SVCXPRT *xprt)
+{
+ struct svcudp_data *su = su_data (xprt);
+
+ xprt_unregister (xprt);
+ (void) close (xprt->xp_sock);
+ XDR_DESTROY (&(su->su_xdrs));
+ mem_free (rpc_buffer (xprt), su->su_iosz);
+ mem_free ((caddr_t) su, sizeof (struct svcudp_data));
+ mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
+}
+
+
+/***********this could be a separate file*********************/
+
+/*
+ * Fifo cache for udp server
+ * Copies pointers to reply buffers into fifo cache
+ * Buffers are sent again if retransmissions are detected.
+ */
+
+#define SPARSENESS 4 /* 75% sparse */
+
+#ifdef USE_IN_LIBIO
+# define CACHE_PERROR(msg) \
+ if (_IO_fwide (stderr, 0) > 0) \
+ (void) __fwprintf(stderr, L"%s\n", msg); \
+ else \
+ (void) fprintf(stderr, "%s\n", msg)
+#else
+# define CACHE_PERROR(msg) \
+ (void) fprintf(stderr,"%s\n", msg)
+#endif
+
+#define ALLOC(type, size) \
+ (type *) mem_alloc((unsigned) (sizeof(type) * (size)))
+
+#define BZERO(addr, type, size) \
+ memset((char *) addr, 0, sizeof(type) * (int) (size))
+
+/*
+ * An entry in the cache
+ */
+typedef struct cache_node *cache_ptr;
+struct cache_node
+ {
+ /*
+ * Index into cache is xid, proc, vers, prog and address
+ */
+ u_long cache_xid;
+ u_long cache_proc;
+ u_long cache_vers;
+ u_long cache_prog;
+ struct sockaddr_in cache_addr;
+ /*
+ * The cached reply and length
+ */
+ char *cache_reply;
+ u_long cache_replylen;
+ /*
+ * Next node on the list, if there is a collision
+ */
+ cache_ptr cache_next;
+ };
+
+
+
+/*
+ * The entire cache
+ */
+struct udp_cache
+ {
+ u_long uc_size; /* size of cache */
+ cache_ptr *uc_entries; /* hash table of entries in cache */
+ cache_ptr *uc_fifo; /* fifo list of entries in cache */
+ u_long uc_nextvictim; /* points to next victim in fifo list */
+ u_long uc_prog; /* saved program number */
+ u_long uc_vers; /* saved version number */
+ u_long uc_proc; /* saved procedure number */
+ struct sockaddr_in uc_addr; /* saved caller's address */
+ };
+
+
+/*
+ * the hashing function
+ */
+#define CACHE_LOC(transp, xid) \
+ (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))
+
+
+/*
+ * Enable use of the cache.
+ * Note: there is no disable.
+ */
+int svcudp_enablecache (SVCXPRT *transp, u_long size);
+int
+svcudp_enablecache (SVCXPRT *transp, u_long size)
+{
+ struct svcudp_data *su = su_data (transp);
+ struct udp_cache *uc;
+
+ if (su->su_cache != NULL)
+ {
+ CACHE_PERROR (_("enablecache: cache already enabled"));
+ return 0;
+ }
+ uc = ALLOC (struct udp_cache, 1);
+ if (uc == NULL)
+ {
+ CACHE_PERROR (_("enablecache: could not allocate cache"));
+ return 0;
+ }
+ uc->uc_size = size;
+ uc->uc_nextvictim = 0;
+ uc->uc_entries = ALLOC (cache_ptr, size * SPARSENESS);
+ if (uc->uc_entries == NULL)
+ {
+ CACHE_PERROR (_("enablecache: could not allocate cache data"));
+ return 0;
+ }
+ BZERO (uc->uc_entries, cache_ptr, size * SPARSENESS);
+ uc->uc_fifo = ALLOC (cache_ptr, size);
+ if (uc->uc_fifo == NULL)
+ {
+ CACHE_PERROR (_("enablecache: could not allocate cache fifo"));
+ return 0;
+ }
+ BZERO (uc->uc_fifo, cache_ptr, size);
+ su->su_cache = (char *) uc;
+ return 1;
+}
+
+
+/*
+ * Set an entry in the cache
+ */
+static void
+cache_set (SVCXPRT *xprt, u_long replylen)
+{
+ cache_ptr victim;
+ cache_ptr *vicp;
+ struct svcudp_data *su = su_data (xprt);
+ struct udp_cache *uc = (struct udp_cache *) su->su_cache;
+ u_int loc;
+ char *newbuf;
+
+ /*
+ * Find space for the new entry, either by
+ * reusing an old entry, or by mallocing a new one
+ */
+ victim = uc->uc_fifo[uc->uc_nextvictim];
+ if (victim != NULL)
+ {
+ loc = CACHE_LOC (xprt, victim->cache_xid);
+ for (vicp = &uc->uc_entries[loc];
+ *vicp != NULL && *vicp != victim;
+ vicp = &(*vicp)->cache_next)
+ ;
+ if (*vicp == NULL)
+ {
+ CACHE_PERROR (_("cache_set: victim not found"));
+ return;
+ }
+ *vicp = victim->cache_next; /* remote from cache */
+ newbuf = victim->cache_reply;
+ }
+ else
+ {
+ victim = ALLOC (struct cache_node, 1);
+ if (victim == NULL)
+ {
+ CACHE_PERROR (_("cache_set: victim alloc failed"));
+ return;
+ }
+ newbuf = mem_alloc (su->su_iosz);
+ if (newbuf == NULL)
+ {
+ CACHE_PERROR (_("cache_set: could not allocate new rpc_buffer"));
+ return;
+ }
+ }
+
+ /*
+ * Store it away
+ */
+ victim->cache_replylen = replylen;
+ victim->cache_reply = rpc_buffer (xprt);
+ rpc_buffer (xprt) = newbuf;
+ xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_ENCODE);
+ victim->cache_xid = su->su_xid;
+ victim->cache_proc = uc->uc_proc;
+ victim->cache_vers = uc->uc_vers;
+ victim->cache_prog = uc->uc_prog;
+ victim->cache_addr = uc->uc_addr;
+ loc = CACHE_LOC (xprt, victim->cache_xid);
+ victim->cache_next = uc->uc_entries[loc];
+ uc->uc_entries[loc] = victim;
+ uc->uc_fifo[uc->uc_nextvictim++] = victim;
+ uc->uc_nextvictim %= uc->uc_size;
+}
+
+/*
+ * Try to get an entry from the cache
+ * return 1 if found, 0 if not found
+ */
+static int
+cache_get (SVCXPRT *xprt, struct rpc_msg *msg, char **replyp, u_long *replylenp)
+{
+ u_int loc;
+ cache_ptr ent;
+ struct svcudp_data *su = su_data (xprt);
+ struct udp_cache *uc = (struct udp_cache *) su->su_cache;
+
+#define EQADDR(a1, a2) (memcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0)
+
+ loc = CACHE_LOC (xprt, su->su_xid);
+ for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next)
+ {
+ if (ent->cache_xid == su->su_xid &&
+ ent->cache_proc == uc->uc_proc &&
+ ent->cache_vers == uc->uc_vers &&
+ ent->cache_prog == uc->uc_prog &&
+ EQADDR (ent->cache_addr, uc->uc_addr))
+ {
+ *replyp = ent->cache_reply;
+ *replylenp = ent->cache_replylen;
+ return 1;
+ }
+ }
+ /*
+ * Failed to find entry
+ * Remember a few things so we can do a set later
+ */
+ uc->uc_proc = msg->rm_call.cb_proc;
+ uc->uc_vers = msg->rm_call.cb_vers;
+ uc->uc_prog = msg->rm_call.cb_prog;
+ memcpy (&uc->uc_addr, &xprt->xp_raddr, sizeof (uc->uc_addr));
+ return 0;
+}
diff --git a/android/librpc/svc_unix.c b/android/librpc/svc_unix.c
new file mode 100644
index 0000000..6185977
--- a/dev/null
+++ b/android/librpc/svc_unix.c
@@ -0,0 +1,536 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * svc_unix.c, Server side for TCP/IP based RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * Actually implements two flavors of transporter -
+ * a unix rendezvouser (a listener and connection establisher)
+ * and a record/unix stream.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/svc.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+
+/*
+ * Ops vector for AF_UNIX based rpc service handle
+ */
+static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat svcunix_stat (SVCXPRT *);
+static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
+static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
+static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
+static void svcunix_destroy (SVCXPRT *);
+
+static const struct xp_ops svcunix_op =
+{
+ svcunix_recv,
+ svcunix_stat,
+ svcunix_getargs,
+ svcunix_reply,
+ svcunix_freeargs,
+ svcunix_destroy
+};
+
+/*
+ * Ops vector for AF_UNIX rendezvous handler
+ */
+static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
+static enum xprt_stat rendezvous_stat (SVCXPRT *);
+static void svcunix_rendezvous_abort (void) attribute_noreturn;
+
+/* This function makes sure abort() relocation goes through PLT
+ and thus can be lazy bound. */
+static void
+svcunix_rendezvous_abort (void)
+{
+ abort ();
+};
+
+static const struct xp_ops svcunix_rendezvous_op =
+{
+ rendezvous_request,
+ rendezvous_stat,
+ (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
+ (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
+ (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
+ svcunix_destroy
+};
+
+static int readunix (char*, char *, int);
+static int writeunix (char *, char *, int);
+static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
+
+struct unix_rendezvous { /* kept in xprt->xp_p1 */
+ u_int sendsize;
+ u_int recvsize;
+};
+
+struct unix_conn { /* kept in xprt->xp_p1 */
+ enum xprt_stat strm_stat;
+ u_long x_id;
+ XDR xdrs;
+ char verf_body[MAX_AUTH_BYTES];
+};
+
+/*
+ * Usage:
+ * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
+ *
+ * Creates, registers, and returns a (rpc) unix based transporter.
+ * Once *xprt is initialized, it is registered as a transporter
+ * see (svc.h, xprt_register). This routine returns
+ * a NULL if a problem occurred.
+ *
+ * If sock<0 then a socket is created, else sock is used.
+ * If the socket, sock is not bound to a port then svcunix_create
+ * binds it to an arbitrary port. The routine then starts a unix
+ * listener on the socket's associated port. In any (successful) case,
+ * xprt->xp_sock is the registered socket number and xprt->xp_port is the
+ * associated port number.
+ *
+ * Since unix streams do buffered io similar to stdio, the caller can specify
+ * how big the send and receive buffers are via the second and third parms;
+ * 0 => use the system default.
+ */
+SVCXPRT *
+svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
+{
+ bool_t madesock = FALSE;
+ SVCXPRT *xprt;
+ struct unix_rendezvous *r;
+ struct sockaddr_un addr;
+ socklen_t len = sizeof (struct sockaddr_in);
+
+ if (sock == RPC_ANYSOCK)
+ {
+ if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ perror (_("svc_unix.c - AF_UNIX socket creation problem"));
+ return (SVCXPRT *) NULL;
+ }
+ madesock = TRUE;
+ }
+ memset (&addr, '\0', sizeof (addr));
+ addr.sun_family = AF_UNIX;
+ len = strlen (path) + 1;
+ memcpy (addr.sun_path, path, len);
+ len += sizeof (addr.sun_family);
+
+ bind (sock, (struct sockaddr *) &addr, len);
+
+ if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
+ || listen (sock, 2) != 0)
+ {
+ perror (_("svc_unix.c - cannot getsockname or listen"));
+ if (madesock)
+ close (sock);
+ return (SVCXPRT *) NULL;
+ }
+
+ r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
+ xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
+ if (r == NULL || xprt == NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ __fwprintf (stderr, L"%s", _("svcunix_create: out of memory\n"));
+ else
+#endif
+ fputs (_("svcunix_create: out of memory\n"), stderr);
+ mem_free (r, sizeof (*r));
+ mem_free (xprt, sizeof (SVCXPRT));
+ return NULL;
+ }
+ r->sendsize = sendsize;
+ r->recvsize = recvsize;
+ xprt->xp_p2 = NULL;
+ xprt->xp_p1 = (caddr_t) r;
+ xprt->xp_verf = _null_auth;
+ xprt->xp_ops = &svcunix_rendezvous_op;
+ xprt->xp_port = -1;
+ xprt->xp_sock = sock;
+ xprt_register (xprt);
+ return xprt;
+}
+
+/*
+ * Like svunix_create(), except the routine takes any *open* UNIX file
+ * descriptor as its first input.
+ */
+SVCXPRT *
+svcunixfd_create (int fd, u_int sendsize, u_int recvsize);
+SVCXPRT *
+svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
+{
+ return makefd_xprt (fd, sendsize, recvsize);
+}
+
+static SVCXPRT *
+internal_function
+makefd_xprt (int fd, u_int sendsize, u_int recvsize)
+{
+ SVCXPRT *xprt;
+ struct unix_conn *cd;
+
+ xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
+ cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
+ if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) __fwprintf (stderr, L"%s",
+ _("svc_unix: makefd_xprt: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
+ mem_free (xprt, sizeof (SVCXPRT));
+ mem_free (cd, sizeof (struct unix_conn));
+ return NULL;
+ }
+ cd->strm_stat = XPRT_IDLE;
+ xdrrec_create (&(cd->xdrs), sendsize, recvsize,
+ (caddr_t) xprt, readunix, writeunix);
+ xprt->xp_p2 = NULL;
+ xprt->xp_p1 = (caddr_t) cd;
+ xprt->xp_verf.oa_base = cd->verf_body;
+ xprt->xp_addrlen = 0;
+ xprt->xp_ops = &svcunix_op; /* truly deals with calls */
+ xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
+ xprt->xp_sock = fd;
+ xprt_register (xprt);
+ return xprt;
+}
+
+static bool_t
+rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg attribute_unused)
+{
+ int sock;
+ struct unix_rendezvous *r;
+ struct sockaddr_un addr;
+ struct sockaddr_in in_addr;
+ socklen_t len;
+
+ r = (struct unix_rendezvous *) xprt->xp_p1;
+again:
+ len = sizeof (struct sockaddr_un);
+ if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
+ {
+ if (errno == EINTR)
+ goto again;
+ return FALSE;
+ }
+ /*
+ * make a new transporter (re-uses xprt)
+ */
+ memset (&in_addr, '\0', sizeof (in_addr));
+ in_addr.sin_family = AF_UNIX;
+ xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
+ memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
+ xprt->xp_addrlen = len;
+ return FALSE; /* there is never an rpc msg to be processed */
+}
+
+static enum xprt_stat
+rendezvous_stat (SVCXPRT *xprt attribute_unused)
+{
+ return XPRT_IDLE;
+}
+
+static void
+svcunix_destroy (SVCXPRT *xprt)
+{
+ struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
+
+ xprt_unregister (xprt);
+ close (xprt->xp_sock);
+ if (xprt->xp_port != 0)
+ {
+ /* a rendezvouser socket */
+ xprt->xp_port = 0;
+ }
+ else
+ {
+ /* an actual connection socket */
+ XDR_DESTROY (&(cd->xdrs));
+ }
+ mem_free ((caddr_t) cd, sizeof (struct unix_conn));
+ mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
+}
+
+#ifdef SCM_CREDENTIALS
+struct cmessage {
+ struct cmsghdr cmsg;
+ struct ucred cmcred;
+ /* hack to make sure we have enough memory */
+ char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
+};
+
+/* XXX This is not thread safe, but since the main functions in svc.c
+ and the rpcgen generated *_svc functions for the daemon are also not
+ thread safe and uses static global variables, it doesn't matter. */
+static struct cmessage cm;
+#endif
+
+static int
+__msgread (int sock, void *data, size_t cnt)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ int len;
+
+ iov.iov_base = data;
+ iov.iov_len = cnt;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+#ifdef SCM_CREDENTIALS
+ msg.msg_control = (caddr_t) &cm;
+ msg.msg_controllen = sizeof (struct cmessage);
+#endif
+ msg.msg_flags = 0;
+
+#ifdef SO_PASSCRED
+ {
+ int on = 1;
+ if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
+ return -1;
+ }
+#endif
+
+ restart:
+ len = recvmsg (sock, &msg, 0);
+ if (len >= 0)
+ {
+ if (msg.msg_flags & MSG_CTRUNC || len == 0)
+ return 0;
+ else
+ return len;
+ }
+ if (errno == EINTR)
+ goto restart;
+ return -1;
+}
+
+static int
+__msgwrite (int sock, void *data, size_t cnt)
+{
+#ifndef SCM_CREDENTIALS
+ /* We cannot implement this reliably. */
+ __set_errno (ENOSYS);
+ return -1;
+#else
+ struct iovec iov;
+ struct msghdr msg;
+ struct cmsghdr *cmsg = &cm.cmsg;
+ struct ucred cred;
+ int len;
+
+ /* XXX I'm not sure, if gete?id() is always correct, or if we should use
+ get?id(). But since keyserv needs geteuid(), we have no other chance.
+ It would be much better, if the kernel could pass both to the server. */
+ cred.pid = getpid ();
+ cred.uid = geteuid ();
+ cred.gid = getegid ();
+
+ memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_CREDENTIALS;
+ cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
+
+ iov.iov_base = data;
+ iov.iov_len = cnt;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = cmsg;
+ msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
+ msg.msg_flags = 0;
+
+ restart:
+ len = sendmsg (sock, &msg, 0);
+ if (len >= 0)
+ return len;
+ if (errno == EINTR)
+ goto restart;
+ return -1;
+
+#endif
+}
+
+/*
+ * reads data from the unix connection.
+ * any error is fatal and the connection is closed.
+ * (And a read of zero bytes is a half closed stream => error.)
+ */
+static int
+readunix (char *xprtptr, char *buf, int len)
+{
+ SVCXPRT *xprt = (SVCXPRT *) xprtptr;
+ int sock = xprt->xp_sock;
+ int milliseconds = 35 * 1000;
+ struct pollfd pollfd;
+
+ do
+ {
+ pollfd.fd = sock;
+ pollfd.events = POLLIN;
+ switch (poll (&pollfd, 1, milliseconds))
+ {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ /*FALLTHROUGH*/
+ case 0:
+ goto fatal_err;
+ default:
+ if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
+ || (pollfd.revents & POLLNVAL))
+ goto fatal_err;
+ break;
+ }
+ }
+ while ((pollfd.revents & POLLIN) == 0);
+
+ if ((len = __msgread (sock, buf, len)) > 0)
+ return len;
+
+ fatal_err:
+ ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
+ return -1;
+}
+
+/*
+ * writes data to the unix connection.
+ * Any error is fatal and the connection is closed.
+ */
+static int
+writeunix (char *xprtptr, char * buf, int len)
+{
+ SVCXPRT *xprt = (SVCXPRT *) xprtptr;
+ int i, cnt;
+
+ for (cnt = len; cnt > 0; cnt -= i, buf += i)
+ {
+ if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
+ {
+ ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
+ return -1;
+ }
+ }
+ return len;
+}
+
+static enum xprt_stat
+svcunix_stat (SVCXPRT *xprt)
+{
+ struct unix_conn *cd =
+ (struct unix_conn *) (xprt->xp_p1);
+
+ if (cd->strm_stat == XPRT_DIED)
+ return XPRT_DIED;
+ if (!xdrrec_eof (&(cd->xdrs)))
+ return XPRT_MOREREQS;
+ return XPRT_IDLE;
+}
+
+static bool_t
+svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
+ XDR *xdrs = &(cd->xdrs);
+
+ xdrs->x_op = XDR_DECODE;
+ xdrrec_skiprecord (xdrs);
+ if (xdr_callmsg (xdrs, msg))
+ {
+ cd->x_id = msg->rm_xid;
+ /* set up verifiers */
+#ifdef SCM_CREDENTIALS
+ msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
+ msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
+ msg->rm_call.cb_verf.oa_length = sizeof (cm);
+#endif
+ return TRUE;
+ }
+ cd->strm_stat = XPRT_DIED; /* XXXX */
+ return FALSE;
+}
+
+static bool_t
+svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
+{
+ return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
+ args_ptr);
+}
+
+static bool_t
+svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
+{
+ XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
+
+ xdrs->x_op = XDR_FREE;
+ return (*xdr_args) (xdrs, args_ptr);
+}
+
+static bool_t
+svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
+{
+ struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
+ XDR *xdrs = &(cd->xdrs);
+ bool_t stat;
+
+ xdrs->x_op = XDR_ENCODE;
+ msg->rm_xid = cd->x_id;
+ stat = xdr_replymsg (xdrs, msg);
+ (void) xdrrec_endofrecord (xdrs, TRUE);
+ return stat;
+}
diff --git a/android/librpc/xdr.c b/android/librpc/xdr.c
new file mode 100644
index 0000000..bcf8901
--- a/dev/null
+++ b/android/librpc/xdr.c
@@ -0,0 +1,745 @@
+/* @(#)xdr.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)xdr.c 1.35 87/08/12";
+#endif
+
+/*
+ * xdr.c, Generic XDR routines implementation.
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ *
+ * These are the "generic" xdr routines used to serialize and de-serialize
+ * most common data items. See xdr.h for more info on the interface to
+ * xdr.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+
+/*
+ * constants specific to the xdr "protocol"
+ */
+#define XDR_FALSE ((long) 0)
+#define XDR_TRUE ((long) 1)
+#define LASTUNSIGNED ((u_int) 0-1)
+
+/*
+ * for unit alignment
+ */
+static const char xdr_zero[BYTES_PER_XDR_UNIT] = {0, 0, 0, 0};
+
+/*
+ * Free a data structure using XDR
+ * Not a filter, but a convenient utility nonetheless
+ */
+void
+xdr_free (xdrproc_t proc, char *objp)
+{
+ XDR x;
+
+ x.x_op = XDR_FREE;
+ (*proc) (&x, objp);
+}
+
+/*
+ * XDR nothing
+ */
+bool_t
+xdr_void (void)
+{
+ return TRUE;
+}
+libc_hidden_def(xdr_void)
+
+/*
+ * XDR long integers
+ * The definition of xdr_long() is kept for backward
+ * compatibility. Instead xdr_int() should be used.
+ */
+bool_t
+xdr_long (XDR *xdrs, long *lp)
+{
+ if (xdrs->x_op == XDR_ENCODE
+ && (sizeof (int32_t) == sizeof (long)
+ || (int32_t) *lp == *lp))
+ return XDR_PUTLONG (xdrs, lp);
+
+ if (xdrs->x_op == XDR_DECODE)
+ return XDR_GETLONG (xdrs, lp);
+
+ if (xdrs->x_op == XDR_FREE)
+ return TRUE;
+
+ return FALSE;
+}
+libc_hidden_def(xdr_long)
+
+/*
+ * XDR short integers
+ */
+bool_t
+xdr_short (XDR *xdrs, short *sp)
+{
+ long l;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ l = (long) *sp;
+ return XDR_PUTLONG (xdrs, &l);
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG (xdrs, &l))
+ {
+ return FALSE;
+ }
+ *sp = (short) l;
+ return TRUE;
+
+ case XDR_FREE:
+ return TRUE;
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_short)
+
+/*
+ * XDR integers
+ */
+bool_t
+xdr_int (XDR *xdrs, int *ip)
+{
+
+#if INT_MAX < LONG_MAX
+ long l;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ l = (long) *ip;
+ return XDR_PUTLONG (xdrs, &l);
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG (xdrs, &l))
+ {
+ return FALSE;
+ }
+ *ip = (int) l;
+ case XDR_FREE:
+ return TRUE;
+ }
+ return FALSE;
+#elif INT_MAX == LONG_MAX
+ return xdr_long (xdrs, (long *) ip);
+#elif INT_MAX == SHRT_MAX
+ return xdr_short (xdrs, (short *) ip);
+#else
+#error unexpected integer sizes in xdr_int()
+#endif
+}
+libc_hidden_def(xdr_int)
+
+/*
+ * XDR unsigned long integers
+ * The definition of xdr_u_long() is kept for backward
+ * compatibility. Instead xdr_u_int() should be used.
+ */
+bool_t
+xdr_u_long (XDR *xdrs, u_long *ulp)
+{
+ switch (xdrs->x_op)
+ {
+ case XDR_DECODE:
+ {
+ long int tmp;
+
+ if (XDR_GETLONG (xdrs, &tmp) == FALSE)
+ return FALSE;
+
+ *ulp = (uint32_t) tmp;
+ return TRUE;
+ }
+
+ case XDR_ENCODE:
+ if (sizeof (uint32_t) != sizeof (u_long)
+ && (uint32_t) *ulp != *ulp)
+ return FALSE;
+
+ return XDR_PUTLONG (xdrs, (long *) ulp);
+
+ case XDR_FREE:
+ return TRUE;
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_u_long)
+
+/*
+ * XDR unsigned integers
+ */
+bool_t
+xdr_u_int (XDR *xdrs, u_int *up)
+{
+#if UINT_MAX < ULONG_MAX
+ u_long l;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ l = (u_long) * up;
+ return XDR_PUTLONG (xdrs, (long *) &l);
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG (xdrs, (long *) &l))
+ {
+ return FALSE;
+ }
+ *up = (u_int) l;
+ case XDR_FREE:
+ return TRUE;
+ }
+ return FALSE;
+#elif UINT_MAX == ULONG_MAX
+ return xdr_u_long (xdrs, (u_long *) up);
+#elif UINT_MAX == USHRT_MAX
+ return xdr_short (xdrs, (short *) up);
+#else
+#error unexpected integer sizes in xdr_u_int()
+#endif
+}
+libc_hidden_def(xdr_u_int)
+
+/*
+ * XDR hyper integers
+ * same as xdr_u_hyper - open coded to save a proc call!
+ */
+bool_t
+xdr_hyper (XDR *xdrs, quad_t *llp)
+{
+ long t1;
+ unsigned long t2;
+
+ if (xdrs->x_op == XDR_ENCODE)
+ {
+ t1 = (long) ((*llp) >> 32);
+ t2 = (long) (*llp);
+ return (XDR_PUTLONG(xdrs, &t1) && XDR_PUTLONG(xdrs, (long *) &t2));
+ }
+
+ if (xdrs->x_op == XDR_DECODE)
+ {
+ if (!XDR_GETLONG(xdrs, &t1) || !XDR_GETLONG(xdrs, (long *) &t2))
+ return FALSE;
+ /* t2 must be unsigned for this to work */
+ *llp = ((quad_t) t1) << 32;
+ *llp |= t2;
+ return TRUE;
+ }
+
+ if (xdrs->x_op == XDR_FREE)
+ return TRUE;
+
+ return FALSE;
+}
+libc_hidden_def(xdr_hyper)
+
+
+/*
+ * XDR hyper integers
+ * same as xdr_hyper - open coded to save a proc call!
+ */
+bool_t
+xdr_u_hyper (XDR *xdrs, u_quad_t *ullp)
+{
+ unsigned long t1;
+ unsigned long t2;
+
+ if (xdrs->x_op == XDR_ENCODE)
+ {
+ t1 = (unsigned long) ((*ullp) >> 32);
+ t2 = (unsigned long) (*ullp);
+ return (XDR_PUTLONG(xdrs, (long *) &t1) && XDR_PUTLONG(xdrs, (long *) &t2));
+ }
+
+ if (xdrs->x_op == XDR_DECODE)
+ {
+ if (!XDR_GETLONG(xdrs, (long *) &t1) || !XDR_GETLONG(xdrs, (long *) &t2))
+ return FALSE;
+ *ullp = ((u_quad_t) t1) << 32;
+ *ullp |= t2;
+ return TRUE;
+ }
+
+ if (xdrs->x_op == XDR_FREE)
+ return TRUE;
+
+ return FALSE;
+}
+libc_hidden_def(xdr_u_hyper)
+
+bool_t
+xdr_longlong_t (XDR *xdrs, quad_t *llp)
+{
+ return xdr_hyper (xdrs, llp);
+}
+
+bool_t
+xdr_u_longlong_t (XDR *xdrs, u_quad_t *ullp)
+{
+ return xdr_u_hyper (xdrs, ullp);
+}
+
+/*
+ * XDR unsigned short integers
+ */
+bool_t
+xdr_u_short (XDR *xdrs, u_short *usp)
+{
+ u_long l;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ l = (u_long) * usp;
+ return XDR_PUTLONG (xdrs, (long *) &l);
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG (xdrs, (long *) &l))
+ {
+ return FALSE;
+ }
+ *usp = (u_short) l;
+ return TRUE;
+
+ case XDR_FREE:
+ return TRUE;
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_u_short)
+
+
+/*
+ * XDR a char
+ */
+bool_t
+xdr_char (XDR *xdrs, char *cp)
+{
+ int i;
+
+ i = (*cp);
+ if (!xdr_int (xdrs, &i))
+ {
+ return FALSE;
+ }
+ *cp = i;
+ return TRUE;
+}
+
+/*
+ * XDR an unsigned char
+ */
+bool_t
+xdr_u_char (XDR *xdrs, u_char *cp)
+{
+ u_int u;
+
+ u = (*cp);
+ if (!xdr_u_int (xdrs, &u))
+ {
+ return FALSE;
+ }
+ *cp = u;
+ return TRUE;
+}
+
+/*
+ * XDR booleans
+ */
+bool_t
+xdr_bool (XDR *xdrs, bool_t *bp)
+{
+ long lb;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ lb = *bp ? XDR_TRUE : XDR_FALSE;
+ return XDR_PUTLONG (xdrs, &lb);
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG (xdrs, &lb))
+ {
+ return FALSE;
+ }
+ *bp = (lb == XDR_FALSE) ? FALSE : TRUE;
+ return TRUE;
+
+ case XDR_FREE:
+ return TRUE;
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_bool)
+
+/*
+ * XDR enumerations
+ */
+bool_t
+xdr_enum (XDR *xdrs, enum_t *ep)
+{
+ enum sizecheck
+ {
+ SIZEVAL
+ }; /* used to find the size of an enum */
+
+ /*
+ * enums are treated as ints
+ */
+ if (sizeof (enum sizecheck) == 4)
+ {
+#if INT_MAX < LONG_MAX
+ long l;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ l = *ep;
+ return XDR_PUTLONG (xdrs, &l);
+
+ case XDR_DECODE:
+ if (!XDR_GETLONG (xdrs, &l))
+ {
+ return FALSE;
+ }
+ *ep = l;
+ case XDR_FREE:
+ return TRUE;
+
+ }
+ return FALSE;
+#else
+ return xdr_long (xdrs, (long *) ep);
+#endif
+ }
+ else if (sizeof (enum sizecheck) == sizeof (short))
+ {
+ return xdr_short (xdrs, (short *) ep);
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+libc_hidden_def(xdr_enum)
+
+/*
+ * XDR opaque data
+ * Allows the specification of a fixed size sequence of opaque bytes.
+ * cp points to the opaque object and cnt gives the byte length.
+ */
+bool_t
+xdr_opaque (XDR *xdrs, caddr_t cp, u_int cnt)
+{
+ u_int rndup;
+ static char crud[BYTES_PER_XDR_UNIT];
+
+ /*
+ * if no data we are done
+ */
+ if (cnt == 0)
+ return TRUE;
+
+ /*
+ * round byte count to full xdr units
+ */
+ rndup = cnt % BYTES_PER_XDR_UNIT;
+ if (rndup > 0)
+ rndup = BYTES_PER_XDR_UNIT - rndup;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_DECODE:
+ if (!XDR_GETBYTES (xdrs, cp, cnt))
+ {
+ return FALSE;
+ }
+ if (rndup == 0)
+ return TRUE;
+ return XDR_GETBYTES (xdrs, (caddr_t)crud, rndup);
+
+ case XDR_ENCODE:
+ if (!XDR_PUTBYTES (xdrs, cp, cnt))
+ {
+ return FALSE;
+ }
+ if (rndup == 0)
+ return TRUE;
+ return XDR_PUTBYTES (xdrs, xdr_zero, rndup);
+
+ case XDR_FREE:
+ return TRUE;
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_opaque)
+
+/*
+ * XDR counted bytes
+ * *cpp is a pointer to the bytes, *sizep is the count.
+ * If *cpp is NULL maxsize bytes are allocated
+ */
+bool_t
+xdr_bytes (XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
+{
+ char *sp = *cpp; /* sp is the actual string pointer */
+ u_int nodesize;
+
+ /*
+ * first deal with the length since xdr bytes are counted
+ */
+ if (!xdr_u_int (xdrs, sizep))
+ {
+ return FALSE;
+ }
+ nodesize = *sizep;
+ if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE))
+ {
+ return FALSE;
+ }
+
+ /*
+ * now deal with the actual bytes
+ */
+ switch (xdrs->x_op)
+ {
+ case XDR_DECODE:
+ if (nodesize == 0)
+ {
+ return TRUE;
+ }
+ if (sp == NULL)
+ {
+ *cpp = sp = (char *) mem_alloc (nodesize);
+ }
+ if (sp == NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s", _("xdr_bytes: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("xdr_bytes: out of memory\n"), stderr);
+ return FALSE;
+ }
+ /* fall into ... */
+
+ case XDR_ENCODE:
+ return xdr_opaque (xdrs, sp, nodesize);
+
+ case XDR_FREE:
+ if (sp != NULL)
+ {
+ mem_free (sp, nodesize);
+ *cpp = NULL;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_bytes)
+
+/*
+ * Implemented here due to commonality of the object.
+ */
+bool_t
+xdr_netobj (XDR *xdrs, struct netobj *np)
+{
+
+ return xdr_bytes (xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ);
+}
+
+/*
+ * XDR a discriminated union
+ * Support routine for discriminated unions.
+ * You create an array of xdrdiscrim structures, terminated with
+ * an entry with a null procedure pointer. The routine gets
+ * the discriminant value and then searches the array of xdrdiscrims
+ * looking for that value. It calls the procedure given in the xdrdiscrim
+ * to handle the discriminant. If there is no specific routine a default
+ * routine may be called.
+ * If there is no specific or default routine an error is returned.
+ */
+bool_t
+xdr_union (XDR *xdrs, enum_t *dscmp, char *unp, const struct xdr_discrim *choices, xdrproc_t dfault)
+{
+ enum_t dscm;
+
+ /*
+ * we deal with the discriminator; it's an enum
+ */
+ if (!xdr_enum (xdrs, dscmp))
+ {
+ return FALSE;
+ }
+ dscm = *dscmp;
+
+ /*
+ * search choices for a value that matches the discriminator.
+ * if we find one, execute the xdr routine for that value.
+ */
+ for (; choices->proc != NULL_xdrproc_t; choices++)
+ {
+ if (choices->value == dscm)
+ return (*(choices->proc)) (xdrs, unp, LASTUNSIGNED);
+ }
+
+ /*
+ * no match - execute the default xdr routine if there is one
+ */
+ return ((dfault == NULL_xdrproc_t) ? FALSE :
+ (*dfault) (xdrs, unp, LASTUNSIGNED));
+}
+libc_hidden_def(xdr_union)
+
+/*
+ * Non-portable xdr primitives.
+ * Care should be taken when moving these routines to new architectures.
+ */
+
+
+/*
+ * XDR null terminated ASCII strings
+ * xdr_string deals with "C strings" - arrays of bytes that are
+ * terminated by a NULL character. The parameter cpp references a
+ * pointer to storage; If the pointer is null, then the necessary
+ * storage is allocated. The last parameter is the max allowed length
+ * of the string as specified by a protocol.
+ */
+bool_t
+xdr_string (XDR *xdrs, char **cpp, u_int maxsize)
+{
+ char *sp = *cpp; /* sp is the actual string pointer */
+ u_int size;
+ u_int nodesize;
+
+ /*
+ * first deal with the length since xdr strings are counted-strings
+ */
+ switch (xdrs->x_op)
+ {
+ case XDR_FREE:
+ if (sp == NULL)
+ {
+ return TRUE; /* already free */
+ }
+ /* fall through... */
+ case XDR_ENCODE:
+ if (sp == NULL)
+ return FALSE;
+ size = strlen (sp);
+ break;
+ case XDR_DECODE:
+ break;
+ }
+ if (!xdr_u_int (xdrs, &size))
+ {
+ return FALSE;
+ }
+ if (size > maxsize)
+ {
+ return FALSE;
+ }
+ nodesize = size + 1;
+
+ /*
+ * now deal with the actual bytes
+ */
+ switch (xdrs->x_op)
+ {
+ case XDR_DECODE:
+ if (nodesize == 0)
+ {
+ return TRUE;
+ }
+ if (sp == NULL)
+ *cpp = sp = (char *) mem_alloc (nodesize);
+ if (sp == NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s",
+ _("xdr_string: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("xdr_string: out of memory\n"), stderr);
+ return FALSE;
+ }
+ sp[size] = 0;
+ /* fall into ... */
+
+ case XDR_ENCODE:
+ return xdr_opaque (xdrs, sp, size);
+
+ case XDR_FREE:
+ mem_free (sp, nodesize);
+ *cpp = NULL;
+ return TRUE;
+ }
+ return FALSE;
+}
+libc_hidden_def(xdr_string)
+
+/*
+ * Wrapper for xdr_string that can be called directly from
+ * routines like clnt_call
+ */
+bool_t
+xdr_wrapstring (XDR *xdrs, char **cpp)
+{
+ if (xdr_string (xdrs, cpp, LASTUNSIGNED))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/android/librpc/xdr_array.c b/android/librpc/xdr_array.c
new file mode 100644
index 0000000..61603ed
--- a/dev/null
+++ b/android/librpc/xdr_array.c
@@ -0,0 +1,171 @@
+/* @(#)xdr_array.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_array.c, Generic XDR routines implementation.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * arrays. See xdr.h for more info on the interface to xdr.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <limits.h>
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+#endif
+
+
+#define LASTUNSIGNED ((u_int)0-1)
+
+
+/*
+ * XDR an array of arbitrary elements
+ * *addrp is a pointer to the array, *sizep is the number of elements.
+ * If addrp is NULL (*sizep * elsize) bytes are allocated.
+ * elsize is the size (in bytes) of each element, and elproc is the
+ * xdr procedure to call to handle each element of the array.
+ */
+bool_t
+xdr_array (XDR *xdrs, caddr_t *addrp, u_int *sizep, u_int maxsize, u_int elsize, xdrproc_t elproc)
+{
+ u_int i;
+ caddr_t target = *addrp;
+ u_int c; /* the actual element count */
+ bool_t stat = TRUE;
+ u_int nodesize;
+
+ /* like strings, arrays are really counted arrays */
+ if (!xdr_u_int (xdrs, sizep))
+ {
+ return FALSE;
+ }
+ c = *sizep;
+ /*
+ * XXX: Let the overflow possibly happen with XDR_FREE because mem_free()
+ * doesn't actually use its second argument anyway.
+ */
+ if ((c > maxsize || c > UINT_MAX / elsize) && (xdrs->x_op != XDR_FREE))
+ {
+ return FALSE;
+ }
+ nodesize = c * elsize;
+
+ /*
+ * if we are deserializing, we may need to allocate an array.
+ * We also save time by checking for a null array if we are freeing.
+ */
+ if (target == NULL)
+ switch (xdrs->x_op)
+ {
+ case XDR_DECODE:
+ if (c == 0)
+ return TRUE;
+ *addrp = target = mem_alloc (nodesize);
+ if (target == NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s",
+ _("xdr_array: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("xdr_array: out of memory\n"), stderr);
+ return FALSE;
+ }
+ memset (target, 0, nodesize);
+ break;
+
+ case XDR_FREE:
+ return TRUE;
+ default:
+ break;
+ }
+
+ /*
+ * now we xdr each element of array
+ */
+ for (i = 0; (i < c) && stat; i++)
+ {
+ stat = (*elproc) (xdrs, target, LASTUNSIGNED);
+ target += elsize;
+ }
+
+ /*
+ * the array may need freeing
+ */
+ if (xdrs->x_op == XDR_FREE)
+ {
+ mem_free (*addrp, nodesize);
+ *addrp = NULL;
+ }
+ return stat;
+}
+libc_hidden_def(xdr_array)
+
+/*
+ * xdr_vector():
+ *
+ * XDR a fixed length array. Unlike variable-length arrays,
+ * the storage of fixed length arrays is static and unfreeable.
+ * > basep: base of the array
+ * > size: size of the array
+ * > elemsize: size of each element
+ * > xdr_elem: routine to XDR each element
+ */
+bool_t
+xdr_vector (XDR *xdrs, char *basep, u_int nelem, u_int elemsize,
+ xdrproc_t xdr_elem)
+{
+ u_int i;
+ char *elptr;
+
+ elptr = basep;
+ for (i = 0; i < nelem; i++)
+ {
+ if (!(*xdr_elem) (xdrs, elptr, LASTUNSIGNED))
+ {
+ return FALSE;
+ }
+ elptr += elemsize;
+ }
+ return TRUE;
+}
diff --git a/android/librpc/xdr_float.c b/android/librpc/xdr_float.c
new file mode 100644
index 0000000..3110cf7
--- a/dev/null
+++ b/android/librpc/xdr_float.c
@@ -0,0 +1,311 @@
+/* @(#)xdr_float.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro";
+#endif
+
+/*
+ * xdr_float.c, Generic XDR routines implementation.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These are the "floating point" xdr routines used to (de)serialize
+ * most common data items. See xdr.h for more info on the interface to
+ * xdr.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <endian.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+/*
+ * NB: Not portable.
+ * This routine works on Suns (Sky / 68000's) and Vaxen.
+ */
+
+#ifdef ANDROID
+/* is this correct??? */
+#define LSW (0)
+#else
+#define LSW (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
+#endif
+
+#ifdef vax
+
+/* What IEEE single precision floating point looks like on a Vax */
+struct ieee_single {
+ unsigned int mantissa: 23;
+ unsigned int exp : 8;
+ unsigned int sign : 1;
+};
+
+/* Vax single precision floating point */
+struct vax_single {
+ unsigned int mantissa1 : 7;
+ unsigned int exp : 8;
+ unsigned int sign : 1;
+ unsigned int mantissa2 : 16;
+};
+
+#define VAX_SNG_BIAS 0x81
+#define IEEE_SNG_BIAS 0x7f
+
+static struct sgl_limits {
+ struct vax_single s;
+ struct ieee_single ieee;
+} sgl_limits[2] = {
+ {{ 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */
+ { 0x0, 0xff, 0x0 }}, /* Max IEEE */
+ {{ 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */
+ { 0x0, 0x0, 0x0 }} /* Min IEEE */
+};
+#endif /* vax */
+
+bool_t
+xdr_float(XDR *xdrs, float *fp)
+{
+#ifdef vax
+ struct ieee_single is;
+ struct vax_single vs, *vsp;
+ struct sgl_limits *lim;
+ int i;
+#endif
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+#ifdef vax
+ vs = *((struct vax_single *)fp);
+ for (i = 0, lim = sgl_limits;
+ i < sizeof(sgl_limits)/sizeof(struct sgl_limits);
+ i++, lim++) {
+ if ((vs.mantissa2 == lim->s.mantissa2) &&
+ (vs.exp == lim->s.exp) &&
+ (vs.mantissa1 == lim->s.mantissa1)) {
+ is = lim->ieee;
+ goto shipit;
+ }
+ }
+ is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
+ is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
+ shipit:
+ is.sign = vs.sign;
+ return (XDR_PUTLONG(xdrs, (long *)&is));
+#else
+ if (sizeof(float) == sizeof(long))
+ return (XDR_PUTLONG(xdrs, (long *)fp));
+ else if (sizeof(float) == sizeof(int)) {
+ long tmp = *(int *)fp;
+ return (XDR_PUTLONG(xdrs, &tmp));
+ }
+ break;
+#endif
+
+ case XDR_DECODE:
+#ifdef vax
+ vsp = (struct vax_single *)fp;
+ if (!XDR_GETLONG(xdrs, (long *)&is))
+ return (FALSE);
+ for (i = 0, lim = sgl_limits;
+ i < sizeof(sgl_limits)/sizeof(struct sgl_limits);
+ i++, lim++) {
+ if ((is.exp == lim->ieee.exp) &&
+ (is.mantissa == lim->ieee.mantissa)) {
+ *vsp = lim->s;
+ goto doneit;
+ }
+ }
+ vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
+ vsp->mantissa2 = is.mantissa;
+ vsp->mantissa1 = (is.mantissa >> 16);
+ doneit:
+ vsp->sign = is.sign;
+ return (TRUE);
+#else
+ if (sizeof(float) == sizeof(long))
+ return (XDR_GETLONG(xdrs, (long *)fp));
+ else if (sizeof(float) == sizeof(int)) {
+ long tmp;
+ if (XDR_GETLONG(xdrs, &tmp)) {
+ *(int *)fp = tmp;
+ return (TRUE);
+ }
+ }
+ break;
+#endif
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+ * This routine works on Suns (Sky / 68000's) and Vaxen.
+ */
+
+#ifdef vax
+/* What IEEE double precision floating point looks like on a Vax */
+struct ieee_double {
+ unsigned int mantissa1 : 20;
+ unsigned int exp : 11;
+ unsigned int sign : 1;
+ unsigned int mantissa2 : 32;
+};
+
+/* Vax double precision floating point */
+struct vax_double {
+ unsigned int mantissa1 : 7;
+ unsigned int exp : 8;
+ unsigned int sign : 1;
+ unsigned int mantissa2 : 16;
+ unsigned int mantissa3 : 16;
+ unsigned int mantissa4 : 16;
+};
+
+#define VAX_DBL_BIAS 0x81
+#define IEEE_DBL_BIAS 0x3ff
+#define MASK(nbits) ((1 << nbits) - 1)
+
+static struct dbl_limits {
+ struct vax_double d;
+ struct ieee_double ieee;
+} dbl_limits[2] = {
+ {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff }, /* Max Vax */
+ { 0x0, 0x7ff, 0x0, 0x0 }}, /* Max IEEE */
+ {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* Min Vax */
+ { 0x0, 0x0, 0x0, 0x0 }} /* Min IEEE */
+};
+
+#endif /* vax */
+
+
+bool_t
+xdr_double(XDR *xdrs, double *dp)
+{
+#ifdef vax
+ struct ieee_double id;
+ struct vax_double vd;
+ register struct dbl_limits *lim;
+ int i;
+#endif
+
+ switch (xdrs->x_op) {
+
+ case XDR_ENCODE:
+#ifdef vax
+ vd = *((struct vax_double *)dp);
+ for (i = 0, lim = dbl_limits;
+ i < sizeof(dbl_limits)/sizeof(struct dbl_limits);
+ i++, lim++) {
+ if ((vd.mantissa4 == lim->d.mantissa4) &&
+ (vd.mantissa3 == lim->d.mantissa3) &&
+ (vd.mantissa2 == lim->d.mantissa2) &&
+ (vd.mantissa1 == lim->d.mantissa1) &&
+ (vd.exp == lim->d.exp)) {
+ id = lim->ieee;
+ goto shipit;
+ }
+ }
+ id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
+ id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
+ id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
+ (vd.mantissa3 << 13) |
+ ((vd.mantissa4 >> 3) & MASK(13));
+ shipit:
+ id.sign = vd.sign;
+ dp = (double *)&id;
+#endif
+ if (2*sizeof(long) == sizeof(double)) {
+ long *lp = (long *)dp;
+ return (XDR_PUTLONG(xdrs, lp+!LSW) &&
+ XDR_PUTLONG(xdrs, lp+LSW));
+ } else if (2*sizeof(int) == sizeof(double)) {
+ int *ip = (int *)dp;
+ long tmp[2];
+ tmp[0] = ip[!LSW];
+ tmp[1] = ip[LSW];
+ return (XDR_PUTLONG(xdrs, tmp) &&
+ XDR_PUTLONG(xdrs, tmp+1));
+ }
+ break;
+
+ case XDR_DECODE:
+#ifdef vax
+ lp = (long *)&id;
+ if (!XDR_GETLONG(xdrs, lp++) || !XDR_GETLONG(xdrs, lp))
+ return (FALSE);
+ for (i = 0, lim = dbl_limits;
+ i < sizeof(dbl_limits)/sizeof(struct dbl_limits);
+ i++, lim++) {
+ if ((id.mantissa2 == lim->ieee.mantissa2) &&
+ (id.mantissa1 == lim->ieee.mantissa1) &&
+ (id.exp == lim->ieee.exp)) {
+ vd = lim->d;
+ goto doneit;
+ }
+ }
+ vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
+ vd.mantissa1 = (id.mantissa1 >> 13);
+ vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
+ (id.mantissa2 >> 29);
+ vd.mantissa3 = (id.mantissa2 >> 13);
+ vd.mantissa4 = (id.mantissa2 << 3);
+ doneit:
+ vd.sign = id.sign;
+ *dp = *((double *)&vd);
+ return (TRUE);
+#else
+ if (2*sizeof(long) == sizeof(double)) {
+ long *lp = (long *)dp;
+ return (XDR_GETLONG(xdrs, lp+!LSW) &&
+ XDR_GETLONG(xdrs, lp+LSW));
+ } else if (2*sizeof(int) == sizeof(double)) {
+ int *ip = (int *)dp;
+ long tmp[2];
+ if (XDR_GETLONG(xdrs, tmp+!LSW) &&
+ XDR_GETLONG(xdrs, tmp+LSW)) {
+ ip[0] = tmp[0];
+ ip[1] = tmp[1];
+ return (TRUE);
+ }
+ }
+ break;
+#endif
+
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
diff --git a/android/librpc/xdr_intXX_t.c b/android/librpc/xdr_intXX_t.c
new file mode 100644
index 0000000..ff21775
--- a/dev/null
+++ b/android/librpc/xdr_intXX_t.c
@@ -0,0 +1,203 @@
+/* Copyright (c) 1998, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+/* XDR 64bit integers */
+bool_t
+xdr_int64_t (XDR *xdrs, int64_t *ip)
+{
+ int32_t t1;
+ /* This must be unsigned, otherwise we get problems with sign
+ extension in the DECODE case. */
+ uint32_t t2;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ t1 = (int32_t) ((*ip) >> 32);
+ t2 = (int32_t) (*ip);
+ return (XDR_PUTINT32(xdrs, &t1) && XDR_PUTINT32(xdrs, (int32_t *) &t2));
+ case XDR_DECODE:
+ if (!XDR_GETINT32(xdrs, &t1) || !XDR_GETINT32(xdrs, (int32_t *) &t2))
+ return FALSE;
+ *ip = ((int64_t) t1) << 32;
+ *ip |= t2;
+ return TRUE;
+ case XDR_FREE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* XDR 64bit unsigned integers */
+bool_t
+xdr_uint64_t (XDR *xdrs, uint64_t *uip)
+{
+ uint32_t t1;
+ uint32_t t2;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ t1 = (uint32_t) ((*uip) >> 32);
+ t2 = (uint32_t) (*uip);
+ return (XDR_PUTINT32 (xdrs, (int32_t *) &t1) &&
+ XDR_PUTINT32(xdrs, (int32_t *) &t2));
+ case XDR_DECODE:
+ if (!XDR_GETINT32(xdrs, (int32_t *) &t1) ||
+ !XDR_GETINT32(xdrs, (int32_t *) &t2))
+ return FALSE;
+ *uip = ((uint64_t) t1) << 32;
+ *uip |= t2;
+ return TRUE;
+ case XDR_FREE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* XDR 32bit integers */
+bool_t
+xdr_int32_t (XDR *xdrs, int32_t *lp)
+{
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ return XDR_PUTINT32 (xdrs, lp);
+ case XDR_DECODE:
+ return XDR_GETINT32 (xdrs, lp);
+ case XDR_FREE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* XDR 32bit unsigned integers */
+bool_t
+xdr_uint32_t (XDR *xdrs, uint32_t *ulp)
+{
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ return XDR_PUTINT32 (xdrs, (int32_t *) ulp);
+ case XDR_DECODE:
+ return XDR_GETINT32 (xdrs, (int32_t *) ulp);
+ case XDR_FREE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* XDR 16bit integers */
+bool_t
+xdr_int16_t (XDR *xdrs, int16_t *ip)
+{
+ int32_t t;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ t = (int32_t) *ip;
+ return XDR_PUTINT32 (xdrs, &t);
+ case XDR_DECODE:
+ if (!XDR_GETINT32 (xdrs, &t))
+ return FALSE;
+ *ip = (int16_t) t;
+ return TRUE;
+ case XDR_FREE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* XDR 16bit unsigned integers */
+bool_t
+xdr_uint16_t (XDR *xdrs, uint16_t *uip)
+{
+ uint32_t ut;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ ut = (uint32_t) *uip;
+ return XDR_PUTINT32 (xdrs, (int32_t *) &ut);
+ case XDR_DECODE:
+ if (!XDR_GETINT32 (xdrs, (int32_t *) &ut))
+ return FALSE;
+ *uip = (uint16_t) ut;
+ return TRUE;
+ case XDR_FREE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* XDR 8bit integers */
+bool_t
+xdr_int8_t (XDR *xdrs, int8_t *ip)
+{
+ int32_t t;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ t = (int32_t) *ip;
+ return XDR_PUTINT32 (xdrs, &t);
+ case XDR_DECODE:
+ if (!XDR_GETINT32 (xdrs, &t))
+ return FALSE;
+ *ip = (int8_t) t;
+ return TRUE;
+ case XDR_FREE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/* XDR 8bit unsigned integers */
+bool_t
+xdr_uint8_t (XDR *xdrs, uint8_t *uip)
+{
+ uint32_t ut;
+
+ switch (xdrs->x_op)
+ {
+ case XDR_ENCODE:
+ ut = (uint32_t) *uip;
+ return XDR_PUTINT32 (xdrs, (int32_t *) &ut);
+ case XDR_DECODE:
+ if (!XDR_GETINT32 (xdrs, (int32_t *) &ut))
+ return FALSE;
+ *uip = (uint8_t) ut;
+ return TRUE;
+ case XDR_FREE:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
diff --git a/android/librpc/xdr_mem.c b/android/librpc/xdr_mem.c
new file mode 100644
index 0000000..c58fc45
--- a/dev/null
+++ b/android/librpc/xdr_mem.c
@@ -0,0 +1,237 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * xdr_mem.h, XDR implementation using memory buffers.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * If you have some data to be interpreted as external data representation
+ * or to be converted to external data representation in a memory buffer,
+ * then this is the package for you.
+ *
+ */
+
+#include <features.h>
+#include <string.h>
+#include <limits.h>
+#include <rpc/rpc.h>
+
+
+static bool_t xdrmem_getlong (XDR *, long *);
+static bool_t xdrmem_putlong (XDR *, const long *);
+static bool_t xdrmem_getbytes (XDR *, caddr_t, u_int);
+static bool_t xdrmem_putbytes (XDR *, const char *, u_int);
+static u_int xdrmem_getpos (const XDR *);
+static bool_t xdrmem_setpos (XDR *, u_int);
+static int32_t *xdrmem_inline (XDR *, u_int);
+static void xdrmem_destroy (XDR *);
+static bool_t xdrmem_getint32 (XDR *, int32_t *);
+static bool_t xdrmem_putint32 (XDR *, const int32_t *);
+
+static const struct xdr_ops xdrmem_ops =
+{
+ xdrmem_getlong,
+ xdrmem_putlong,
+ xdrmem_getbytes,
+ xdrmem_putbytes,
+ xdrmem_getpos,
+ xdrmem_setpos,
+ xdrmem_inline,
+ xdrmem_destroy,
+ xdrmem_getint32,
+ xdrmem_putint32
+};
+
+/*
+ * The procedure xdrmem_create initializes a stream descriptor for a
+ * memory buffer.
+ */
+void
+xdrmem_create (XDR *xdrs, const caddr_t addr, u_int size, enum xdr_op op)
+{
+ xdrs->x_op = op;
+ /* We have to add the const since the `struct xdr_ops' in `struct XDR'
+ is not `const'. */
+ xdrs->x_ops = (struct xdr_ops *) &xdrmem_ops;
+ xdrs->x_private = xdrs->x_base = addr;
+ xdrs->x_handy = size;
+}
+libc_hidden_def(xdrmem_create)
+
+/*
+ * Nothing needs to be done for the memory case. The argument is clearly
+ * const.
+ */
+
+static void
+xdrmem_destroy (XDR *xdrs attribute_unused)
+{
+}
+
+/*
+ * Gets the next word from the memory referenced by xdrs and places it
+ * in the long pointed to by lp. It then increments the private word to
+ * point at the next element. Neither object pointed to is const
+ */
+static bool_t
+xdrmem_getlong (XDR *xdrs, long *lp)
+{
+ if (xdrs->x_handy < 4)
+ return FALSE;
+ xdrs->x_handy -= 4;
+ *lp = (int32_t) ntohl ((*((int32_t *) (xdrs->x_private))));
+ xdrs->x_private += 4;
+ return TRUE;
+}
+
+/*
+ * Puts the long pointed to by lp in the memory referenced by xdrs. It
+ * then increments the private word to point at the next element. The
+ * long pointed at is const
+ */
+static bool_t
+xdrmem_putlong (XDR *xdrs, const long *lp)
+{
+ if (xdrs->x_handy < 4)
+ return FALSE;
+ xdrs->x_handy -= 4;
+ *(int32_t *) xdrs->x_private = htonl (*lp);
+ xdrs->x_private += 4;
+ return TRUE;
+}
+
+/*
+ * Gets an unaligned number of bytes from the xdrs structure and writes them
+ * to the address passed in addr. Be very careful when calling this routine
+ * as it could leave the xdrs pointing to an unaligned structure which is not
+ * a good idea. None of the things pointed to are const.
+ */
+static bool_t
+xdrmem_getbytes (XDR *xdrs, caddr_t addr, u_int len)
+{
+ if (xdrs->x_handy < len)
+ return FALSE;
+ xdrs->x_handy -= len;
+ memcpy (addr, xdrs->x_private, len);
+ xdrs->x_private += len;
+ return TRUE;
+}
+
+/*
+ * The complementary function to the above. The same warnings apply about
+ * unaligned data. The source address is const.
+ */
+static bool_t
+xdrmem_putbytes (XDR *xdrs, const char *addr, u_int len)
+{
+ if (xdrs->x_handy < len)
+ return FALSE;
+ xdrs->x_handy -= len;
+ memcpy (xdrs->x_private, addr, len);
+ xdrs->x_private += len;
+ return TRUE;
+}
+
+/*
+ * Not sure what this one does. But it clearly doesn't modify the contents
+ * of xdrs. **FIXME** does this not assume u_int == u_long?
+ */
+static u_int
+xdrmem_getpos (const XDR *xdrs)
+{
+ return (u_long) xdrs->x_private - (u_long) xdrs->x_base;
+}
+
+/*
+ * xdrs modified
+ */
+static bool_t
+xdrmem_setpos (XDR *xdrs, u_int pos)
+{
+ caddr_t newaddr = xdrs->x_base + pos;
+ caddr_t lastaddr = xdrs->x_private + xdrs->x_handy;
+
+ if ((long) newaddr > (long) lastaddr
+ || (UINT_MAX < LONG_MAX
+ && (long) UINT_MAX < (long) lastaddr - (long) newaddr))
+ return FALSE;
+ xdrs->x_private = newaddr;
+ xdrs->x_handy = (long) lastaddr - (long) newaddr;
+ return TRUE;
+}
+
+/*
+ * xdrs modified
+ */
+static int32_t *
+xdrmem_inline (XDR *xdrs, u_int len)
+{
+ int32_t *buf = 0;
+
+ if (xdrs->x_handy >= len)
+ {
+ xdrs->x_handy -= len;
+ buf = (int32_t *) xdrs->x_private;
+ xdrs->x_private += len;
+ }
+ return buf;
+}
+
+/*
+ * Gets the next word from the memory referenced by xdrs and places it
+ * in the int pointed to by ip. It then increments the private word to
+ * point at the next element. Neither object pointed to is const
+ */
+static bool_t
+xdrmem_getint32 (XDR *xdrs, int32_t *ip)
+{
+ if (xdrs->x_handy < 4)
+ return FALSE;
+ xdrs->x_handy -= 4;
+ *ip = ntohl ((*((int32_t *) (xdrs->x_private))));
+ xdrs->x_private += 4;
+ return TRUE;
+}
+
+/*
+ * Puts the long pointed to by lp in the memory referenced by xdrs. It
+ * then increments the private word to point at the next element. The
+ * long pointed at is const
+ */
+static bool_t
+xdrmem_putint32 (XDR *xdrs, const int32_t *ip)
+{
+ if (xdrs->x_handy < 4)
+ return FALSE;
+ xdrs->x_handy -= 4;
+ *(int32_t *) xdrs->x_private = htonl (*ip);
+ xdrs->x_private += 4;
+ return TRUE;
+}
diff --git a/android/librpc/xdr_rec.c b/android/librpc/xdr_rec.c
new file mode 100644
index 0000000..d0123aa
--- a/dev/null
+++ b/android/librpc/xdr_rec.c
@@ -0,0 +1,646 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
+ * layer above tcp (for rpc's use).
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These routines interface XDRSTREAMS to a tcp/ip connection.
+ * There is a record marking layer between the xdr stream
+ * and the tcp transport level. A record is composed on one or more
+ * record fragments. A record fragment is a thirty-two bit header followed
+ * by n bytes of data, where n is contained in the header. The header
+ * is represented as a htonl(u_long). The high order bit encodes
+ * whether or not the fragment is the last fragment of the record
+ * (1 => fragment is last, 0 => more fragments to follow.
+ * The other 31 bits encode the byte length of the fragment.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+# include <libio/iolibio.h>
+# define fputs(s, f) _IO_fputs (s, f)
+#endif
+
+
+static bool_t xdrrec_getbytes (XDR *, caddr_t, u_int);
+static bool_t xdrrec_putbytes (XDR *, const char *, u_int);
+static bool_t xdrrec_getint32 (XDR *, int32_t *);
+static bool_t xdrrec_putint32 (XDR *, const int32_t *);
+#if ULONG_MAX != 0xffffffff
+static bool_t xdrrec_getlong (XDR *, long *);
+static bool_t xdrrec_putlong (XDR *, const long *);
+#endif
+static u_int xdrrec_getpos (const XDR *);
+static bool_t xdrrec_setpos (XDR *, u_int);
+static int32_t *xdrrec_inline (XDR *, u_int);
+static void xdrrec_destroy (XDR *);
+
+static const struct xdr_ops xdrrec_ops = {
+#if ULONG_MAX == 0xffffffff
+ (bool_t (*)(XDR *, long *)) xdrrec_getint32,
+ (bool_t (*)(XDR *, const long *)) xdrrec_putint32,
+#else
+ xdrrec_getlong,
+ xdrrec_putlong,
+#endif
+ xdrrec_getbytes,
+ xdrrec_putbytes,
+ xdrrec_getpos,
+ xdrrec_setpos,
+ xdrrec_inline,
+ xdrrec_destroy,
+ xdrrec_getint32,
+ xdrrec_putint32
+};
+
+/*
+ * A record is composed of one or more record fragments.
+ * A record fragment is a two-byte header followed by zero to
+ * 2**32-1 bytes. The header is treated as a long unsigned and is
+ * encode/decoded to the network via htonl/ntohl. The low order 31 bits
+ * are a byte count of the fragment. The highest order bit is a boolean:
+ * 1 => this fragment is the last fragment of the record,
+ * 0 => this fragment is followed by more fragment(s).
+ *
+ * The fragment/record machinery is not general; it is constructed to
+ * meet the needs of xdr and rpc based on tcp.
+ */
+
+#define LAST_FRAG (1UL << 31)
+
+typedef struct rec_strm
+ {
+ caddr_t tcp_handle;
+ caddr_t the_buffer;
+ /*
+ * out-going bits
+ */
+ int (*writeit) (char *, char *, int);
+ caddr_t out_base; /* output buffer (points to frag header) */
+ caddr_t out_finger; /* next output position */
+ caddr_t out_boundry; /* data cannot up to this address */
+ u_int32_t *frag_header; /* beginning of curren fragment */
+ bool_t frag_sent; /* true if buffer sent in middle of record */
+ /*
+ * in-coming bits
+ */
+ int (*readit) (char *, char *, int);
+ u_long in_size; /* fixed size of the input buffer */
+ caddr_t in_base;
+ caddr_t in_finger; /* location of next byte to be had */
+ caddr_t in_boundry; /* can read up to this location */
+ long fbtbc; /* fragment bytes to be consumed */
+ bool_t last_frag;
+ u_int sendsize;
+ u_int recvsize;
+ }
+RECSTREAM;
+
+static u_int fix_buf_size (u_int) internal_function;
+static bool_t skip_input_bytes (RECSTREAM *, long) internal_function;
+static bool_t flush_out (RECSTREAM *, bool_t) internal_function;
+static bool_t set_input_fragment (RECSTREAM *) internal_function;
+static bool_t get_input_bytes (RECSTREAM *, caddr_t, int) internal_function;
+
+/*
+ * Create an xdr handle for xdrrec
+ * xdrrec_create fills in xdrs. Sendsize and recvsize are
+ * send and recv buffer sizes (0 => use default).
+ * tcp_handle is an opaque handle that is passed as the first parameter to
+ * the procedures readit and writeit. Readit and writeit are read and
+ * write respectively. They are like the system
+ * calls expect that they take an opaque handle rather than an fd.
+ */
+void
+xdrrec_create (XDR *xdrs, u_int sendsize,
+ u_int recvsize, caddr_t tcp_handle,
+ int (*readit) (char *, char *, int),
+ int (*writeit) (char *, char *, int))
+{
+ RECSTREAM *rstrm = (RECSTREAM *) mem_alloc (sizeof (RECSTREAM));
+ caddr_t tmp;
+ char *buf;
+
+ sendsize = fix_buf_size (sendsize);
+ recvsize = fix_buf_size (recvsize);
+ buf = mem_alloc (sendsize + recvsize + BYTES_PER_XDR_UNIT);
+
+ if (rstrm == NULL || buf == NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s", _("xdrrec_create: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("xdrrec_create: out of memory\n"), stderr);
+ mem_free (rstrm, sizeof (RECSTREAM));
+ mem_free (buf, sendsize + recvsize + BYTES_PER_XDR_UNIT);
+ /*
+ * This is bad. Should rework xdrrec_create to
+ * return a handle, and in this case return NULL
+ */
+ return;
+ }
+ /*
+ * adjust sizes and allocate buffer quad byte aligned
+ */
+ rstrm->sendsize = sendsize;
+ rstrm->recvsize = recvsize;
+ rstrm->the_buffer = buf;
+ tmp = rstrm->the_buffer;
+ if ((size_t)tmp % BYTES_PER_XDR_UNIT)
+ tmp += BYTES_PER_XDR_UNIT - (size_t)tmp % BYTES_PER_XDR_UNIT;
+ rstrm->out_base = tmp;
+ rstrm->in_base = tmp + sendsize;
+ /*
+ * now the rest ...
+ */
+ /* We have to add the const since the `struct xdr_ops' in `struct XDR'
+ is not `const'. */
+ xdrs->x_ops = (struct xdr_ops *) &xdrrec_ops;
+ xdrs->x_private = (caddr_t) rstrm;
+ rstrm->tcp_handle = tcp_handle;
+ rstrm->readit = readit;
+ rstrm->writeit = writeit;
+ rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
+ rstrm->frag_header = (u_int32_t *) rstrm->out_base;
+ rstrm->out_finger += 4;
+ rstrm->out_boundry += sendsize;
+ rstrm->frag_sent = FALSE;
+ rstrm->in_size = recvsize;
+ rstrm->in_boundry = rstrm->in_base;
+ rstrm->in_finger = (rstrm->in_boundry += recvsize);
+ rstrm->fbtbc = 0;
+ rstrm->last_frag = TRUE;
+}
+libc_hidden_def(xdrrec_create)
+
+
+/*
+ * The routines defined below are the xdr ops which will go into the
+ * xdr handle filled in by xdrrec_create.
+ */
+
+static bool_t
+xdrrec_getint32 (XDR *xdrs, int32_t *ip)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+ int32_t *bufip = (int32_t *) rstrm->in_finger;
+ int32_t mylong;
+
+ /* first try the inline, fast case */
+ if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT &&
+ rstrm->in_boundry - (char *) bufip >= BYTES_PER_XDR_UNIT)
+ {
+ *ip = ntohl (*bufip);
+ rstrm->fbtbc -= BYTES_PER_XDR_UNIT;
+ rstrm->in_finger += BYTES_PER_XDR_UNIT;
+ }
+ else
+ {
+ if (!xdrrec_getbytes (xdrs, (caddr_t) &mylong,
+ BYTES_PER_XDR_UNIT))
+ return FALSE;
+ *ip = ntohl (mylong);
+ }
+ return TRUE;
+}
+
+#if ULONG_MAX != 0xffffffff
+static bool_t
+xdrrec_getlong (XDR *xdrs, long *lp)
+{
+ int32_t v;
+ bool_t r = xdrrec_getint32 (xdrs, &v);
+ *lp = v;
+ return r;
+}
+#endif
+
+static bool_t
+xdrrec_putint32 (XDR *xdrs, const int32_t *ip)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+ int32_t *dest_ip = (int32_t *) rstrm->out_finger;
+
+ if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry)
+ {
+ /*
+ * this case should almost never happen so the code is
+ * inefficient
+ */
+ rstrm->out_finger -= BYTES_PER_XDR_UNIT;
+ rstrm->frag_sent = TRUE;
+ if (!flush_out (rstrm, FALSE))
+ return FALSE;
+ dest_ip = (int32_t *) rstrm->out_finger;
+ rstrm->out_finger += BYTES_PER_XDR_UNIT;
+ }
+ *dest_ip = htonl (*ip);
+ return TRUE;
+}
+
+#if ULONG_MAX != 0xffffffff
+static bool_t
+xdrrec_putlong (XDR *xdrs, const long *lp)
+{
+ int32_t v = *lp;
+ return xdrrec_putint32 (xdrs, &v);
+}
+#endif
+
+static bool_t /* must manage buffers, fragments, and records */
+xdrrec_getbytes (XDR *xdrs, caddr_t addr, u_int len)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+ u_int current;
+
+ while (len > 0)
+ {
+ current = rstrm->fbtbc;
+ if (current == 0)
+ {
+ if (rstrm->last_frag)
+ return FALSE;
+ if (!set_input_fragment (rstrm))
+ return FALSE;
+ continue;
+ }
+ current = (len < current) ? len : current;
+ if (!get_input_bytes (rstrm, addr, current))
+ return FALSE;
+ addr += current;
+ rstrm->fbtbc -= current;
+ len -= current;
+ }
+ return TRUE;
+}
+
+static bool_t
+xdrrec_putbytes (XDR *xdrs, const char *addr, u_int len)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+ u_int current;
+
+ while (len > 0)
+ {
+ current = rstrm->out_boundry - rstrm->out_finger;
+ current = (len < current) ? len : current;
+ memcpy (rstrm->out_finger, addr, current);
+ rstrm->out_finger += current;
+ addr += current;
+ len -= current;
+ if (rstrm->out_finger == rstrm->out_boundry && len > 0)
+ {
+ rstrm->frag_sent = TRUE;
+ if (!flush_out (rstrm, FALSE))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static u_int
+xdrrec_getpos (const XDR *xdrs)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+ long pos;
+
+ pos = lseek ((int) (long) rstrm->tcp_handle, (long) 0, 1);
+ if (pos != -1)
+ switch (xdrs->x_op)
+ {
+
+ case XDR_ENCODE:
+ pos += rstrm->out_finger - rstrm->out_base;
+ break;
+
+ case XDR_DECODE:
+ pos -= rstrm->in_boundry - rstrm->in_finger;
+ break;
+
+ default:
+ pos = (u_int) - 1;
+ break;
+ }
+ return (u_int) pos;
+}
+
+static bool_t
+xdrrec_setpos (XDR *xdrs, u_int pos)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+ u_int currpos = xdrrec_getpos (xdrs);
+ int delta = currpos - pos;
+ caddr_t newpos;
+
+ if ((int) currpos != -1)
+ switch (xdrs->x_op)
+ {
+
+ case XDR_ENCODE:
+ newpos = rstrm->out_finger - delta;
+ if (newpos > (caddr_t) rstrm->frag_header &&
+ newpos < rstrm->out_boundry)
+ {
+ rstrm->out_finger = newpos;
+ return TRUE;
+ }
+ break;
+
+ case XDR_DECODE:
+ newpos = rstrm->in_finger - delta;
+ if ((delta < (int) (rstrm->fbtbc)) &&
+ (newpos <= rstrm->in_boundry) &&
+ (newpos >= rstrm->in_base))
+ {
+ rstrm->in_finger = newpos;
+ rstrm->fbtbc -= delta;
+ return TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+static int32_t *
+xdrrec_inline (XDR *xdrs, u_int len)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+ int32_t *buf = NULL;
+
+ switch (xdrs->x_op)
+ {
+
+ case XDR_ENCODE:
+ if ((rstrm->out_finger + len) <= rstrm->out_boundry)
+ {
+ buf = (int32_t *) rstrm->out_finger;
+ rstrm->out_finger += len;
+ }
+ break;
+
+ case XDR_DECODE:
+ if ((len <= (u_int) rstrm->fbtbc) &&
+ ((rstrm->in_finger + len) <= rstrm->in_boundry))
+ {
+ buf = (int32_t *) rstrm->in_finger;
+ rstrm->fbtbc -= len;
+ rstrm->in_finger += len;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return buf;
+}
+
+static void
+xdrrec_destroy (XDR *xdrs)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+
+ mem_free (rstrm->the_buffer,
+ rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
+ mem_free ((caddr_t) rstrm, sizeof (RECSTREAM));
+}
+
+/*
+ * Exported routines to manage xdr records
+ */
+
+/*
+ * Before reading (deserializing from the stream, one should always call
+ * this procedure to guarantee proper record alignment.
+ */
+bool_t
+xdrrec_skiprecord (XDR *xdrs)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+
+ while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
+ {
+ if (!skip_input_bytes (rstrm, rstrm->fbtbc))
+ return FALSE;
+ rstrm->fbtbc = 0;
+ if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
+ return FALSE;
+ }
+ rstrm->last_frag = FALSE;
+ return TRUE;
+}
+libc_hidden_def(xdrrec_skiprecord)
+
+/*
+ * Lookahead function.
+ * Returns TRUE iff there is no more input in the buffer
+ * after consuming the rest of the current record.
+ */
+bool_t
+xdrrec_eof (XDR *xdrs)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+
+ while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
+ {
+ if (!skip_input_bytes (rstrm, rstrm->fbtbc))
+ return TRUE;
+ rstrm->fbtbc = 0;
+ if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
+ return TRUE;
+ }
+ if (rstrm->in_finger == rstrm->in_boundry)
+ return TRUE;
+ return FALSE;
+}
+libc_hidden_def(xdrrec_eof)
+
+/*
+ * The client must tell the package when an end-of-record has occurred.
+ * The second parameter tells whether the record should be flushed to the
+ * (output) tcp stream. (This lets the package support batched or
+ * pipelined procedure calls.) TRUE => immediate flush to tcp connection.
+ */
+bool_t
+xdrrec_endofrecord (XDR *xdrs, bool_t sendnow)
+{
+ RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
+ u_long len; /* fragment length */
+
+ if (sendnow || rstrm->frag_sent
+ || rstrm->out_finger + BYTES_PER_XDR_UNIT >= rstrm->out_boundry)
+ {
+ rstrm->frag_sent = FALSE;
+ return flush_out (rstrm, TRUE);
+ }
+ len = (rstrm->out_finger - (char *) rstrm->frag_header
+ - BYTES_PER_XDR_UNIT);
+ *rstrm->frag_header = htonl ((u_long) len | LAST_FRAG);
+ rstrm->frag_header = (u_int32_t *) rstrm->out_finger;
+ rstrm->out_finger += BYTES_PER_XDR_UNIT;
+ return TRUE;
+}
+libc_hidden_def(xdrrec_endofrecord)
+
+/*
+ * Internal useful routines
+ */
+static bool_t
+internal_function
+flush_out (RECSTREAM *rstrm, bool_t eor)
+{
+ u_long eormask = (eor == TRUE) ? LAST_FRAG : 0;
+ u_long len = (rstrm->out_finger - (char *) rstrm->frag_header
+ - BYTES_PER_XDR_UNIT);
+
+ *rstrm->frag_header = htonl (len | eormask);
+ len = rstrm->out_finger - rstrm->out_base;
+ if ((*(rstrm->writeit)) (rstrm->tcp_handle, rstrm->out_base, (int) len)
+ != (int) len)
+ return FALSE;
+ rstrm->frag_header = (u_int32_t *) rstrm->out_base;
+ rstrm->out_finger = (caddr_t) rstrm->out_base + BYTES_PER_XDR_UNIT;
+ return TRUE;
+}
+
+static bool_t /* knows nothing about records! Only about input buffers */
+fill_input_buf (RECSTREAM *rstrm)
+{
+ caddr_t where;
+ size_t i;
+ int len;
+
+ where = rstrm->in_base;
+ i = (size_t) rstrm->in_boundry % BYTES_PER_XDR_UNIT;
+ where += i;
+ len = rstrm->in_size - i;
+ if ((len = (*(rstrm->readit)) (rstrm->tcp_handle, where, len)) == -1)
+ return FALSE;
+ rstrm->in_finger = where;
+ where += len;
+ rstrm->in_boundry = where;
+ return TRUE;
+}
+
+static bool_t /* knows nothing about records! Only about input buffers */
+internal_function
+get_input_bytes (RECSTREAM *rstrm, caddr_t addr, int len)
+{
+ int current;
+
+ while (len > 0)
+ {
+ current = rstrm->in_boundry - rstrm->in_finger;
+ if (current == 0)
+ {
+ if (!fill_input_buf (rstrm))
+ return FALSE;
+ continue;
+ }
+ current = (len < current) ? len : current;
+ memcpy (addr, rstrm->in_finger, current);
+ rstrm->in_finger += current;
+ addr += current;
+ len -= current;
+ }
+ return TRUE;
+}
+
+static bool_t /* next two bytes of the input stream are treated as a header */
+internal_function
+set_input_fragment (RECSTREAM *rstrm)
+{
+ uint32_t header;
+
+ if (! get_input_bytes (rstrm, (caddr_t)&header, BYTES_PER_XDR_UNIT))
+ return FALSE;
+ header = ntohl (header);
+ rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
+ /*
+ * Sanity check. Try not to accept wildly incorrect fragment
+ * sizes. Unfortunately, only a size of zero can be identified as
+ * 'wildely incorrect', and this only, if it is not the last
+ * fragment of a message. Ridiculously large fragment sizes may look
+ * wrong, but we don't have any way to be certain that they aren't
+ * what the client actually intended to send us. Many existing RPC
+ * implementations may sent a fragment of size zero as the last
+ * fragment of a message.
+ */
+ if (header == 0)
+ return FALSE;
+ rstrm->fbtbc = header & ~LAST_FRAG;
+ return TRUE;
+}
+
+static bool_t /* consumes input bytes; knows nothing about records! */
+internal_function
+skip_input_bytes (RECSTREAM *rstrm, long cnt)
+{
+ int current;
+
+ while (cnt > 0)
+ {
+ current = rstrm->in_boundry - rstrm->in_finger;
+ if (current == 0)
+ {
+ if (!fill_input_buf (rstrm))
+ return FALSE;
+ continue;
+ }
+ current = (cnt < current) ? cnt : current;
+ rstrm->in_finger += current;
+ cnt -= current;
+ }
+ return TRUE;
+}
+
+static u_int
+internal_function
+fix_buf_size (u_int s)
+{
+ if (s < 100)
+ s = 4000;
+ return RNDUP (s);
+}
diff --git a/android/librpc/xdr_reference.c b/android/librpc/xdr_reference.c
new file mode 100644
index 0000000..1c601fc
--- a/dev/null
+++ b/android/librpc/xdr_reference.c
@@ -0,0 +1,147 @@
+/* @(#)xdr_reference.c 2.1 88/07/29 4.0 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+#if 0
+static char sccsid[] = "@(#)xdr_reference.c 1.11 87/08/11 SMI";
+#endif
+
+/*
+ * xdr_reference.c, Generic XDR routines implementation.
+ *
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * "pointers". See xdr.h for more info on the interface to xdr.
+ */
+
+#define __FORCE_GLIBC
+#include <features.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+#ifdef USE_IN_LIBIO
+# include <wchar.h>
+# include <libio/iolibio.h>
+# define fputs(s, f) _IO_fputs (s, f)
+#endif
+
+
+#define LASTUNSIGNED ((u_int)0-1)
+
+/*
+ * XDR an indirect pointer
+ * xdr_reference is for recursively translating a structure that is
+ * referenced by a pointer inside the structure that is currently being
+ * translated. pp references a pointer to storage. If *pp is null
+ * the necessary storage is allocated.
+ * size is the size of the referneced structure.
+ * proc is the routine to handle the referenced structure.
+ */
+bool_t
+xdr_reference (XDR *xdrs, caddr_t *pp, u_int size, xdrproc_t proc)
+{
+ caddr_t loc = *pp;
+ bool_t stat;
+
+ if (loc == NULL)
+ switch (xdrs->x_op)
+ {
+ case XDR_FREE:
+ return TRUE;
+
+ case XDR_DECODE:
+ *pp = loc = (caddr_t) mem_alloc (size);
+ if (loc == NULL)
+ {
+#ifdef USE_IN_LIBIO
+ if (_IO_fwide (stderr, 0) > 0)
+ (void) fwprintf (stderr, L"%s",
+ _("xdr_reference: out of memory\n"));
+ else
+#endif
+ (void) fputs (_("xdr_reference: out of memory\n"), stderr);
+ return FALSE;
+ }
+ memset (loc, 0, (int) size);
+ break;
+ default:
+ break;
+ }
+
+ stat = (*proc) (xdrs, loc, LASTUNSIGNED);
+
+ if (xdrs->x_op == XDR_FREE)
+ {
+ mem_free (loc, size);
+ *pp = NULL;
+ }
+ return stat;
+}
+libc_hidden_def(xdr_reference)
+
+/*
+ * xdr_pointer():
+ *
+ * XDR a pointer to a possibly recursive data structure. This
+ * differs with xdr_reference in that it can serialize/deserialize
+ * trees correctly.
+ *
+ * What's sent is actually a union:
+ *
+ * union object_pointer switch (boolean b) {
+ * case TRUE: object_data data;
+ * case FALSE: void nothing;
+ * }
+ *
+ * > objpp: Pointer to the pointer to the object.
+ * > obj_size: size of the object.
+ * > xdr_obj: routine to XDR an object.
+ *
+ */
+bool_t
+xdr_pointer (XDR *xdrs, char **objpp, u_int obj_size, xdrproc_t xdr_obj)
+{
+
+ bool_t more_data;
+
+ more_data = (*objpp != NULL);
+ if (!xdr_bool (xdrs, &more_data))
+ {
+ return FALSE;
+ }
+ if (!more_data)
+ {
+ *objpp = NULL;
+ return TRUE;
+ }
+ return xdr_reference (xdrs, objpp, obj_size, xdr_obj);
+}
diff --git a/android/librpc/xdr_stdio.c b/android/librpc/xdr_stdio.c
new file mode 100644
index 0000000..a087c9c
--- a/dev/null
+++ b/android/librpc/xdr_stdio.c
@@ -0,0 +1,195 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/*
+ * xdr_stdio.c, XDR implementation on standard i/o file.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * This set of routines implements a XDR on a stdio stream.
+ * XDR_ENCODE serializes onto the stream, XDR_DECODE de-serializes
+ * from the stream.
+ */
+
+#include <rpc/types.h>
+#include <stdio.h>
+#include <rpc/xdr.h>
+
+#ifdef USE_IN_LIBIO
+# include <libio/iolibio.h>
+# define fflush(s) _IO_fflush (s)
+# define fread(p, m, n, s) _IO_fread (p, m, n, s)
+# define ftell(s) _IO_ftell (s)
+# define fwrite(p, m, n, s) _IO_fwrite (p, m, n, s)
+#endif
+
+
+static bool_t xdrstdio_getlong (XDR *, long *);
+static bool_t xdrstdio_putlong (XDR *, const long *);
+static bool_t xdrstdio_getbytes (XDR *, caddr_t, u_int);
+static bool_t xdrstdio_putbytes (XDR *, const char *, u_int);
+static u_int xdrstdio_getpos (const XDR *);
+static bool_t xdrstdio_setpos (XDR *, u_int);
+static int32_t *xdrstdio_inline (XDR *, u_int);
+static void xdrstdio_destroy (XDR *);
+static bool_t xdrstdio_getint32 (XDR *, int32_t *);
+static bool_t xdrstdio_putint32 (XDR *, const int32_t *);
+
+/*
+ * Ops vector for stdio type XDR
+ */
+static const struct xdr_ops xdrstdio_ops =
+{
+ xdrstdio_getlong, /* deserialize a long int */
+ xdrstdio_putlong, /* serialize a long int */
+ xdrstdio_getbytes, /* deserialize counted bytes */
+ xdrstdio_putbytes, /* serialize counted bytes */
+ xdrstdio_getpos, /* get offset in the stream */
+ xdrstdio_setpos, /* set offset in the stream */
+ xdrstdio_inline, /* prime stream for inline macros */
+ xdrstdio_destroy, /* destroy stream */
+ xdrstdio_getint32, /* deserialize a int */
+ xdrstdio_putint32 /* serialize a int */
+};
+
+/*
+ * Initialize a stdio xdr stream.
+ * Sets the xdr stream handle xdrs for use on the stream file.
+ * Operation flag is set to op.
+ */
+void
+xdrstdio_create (XDR *xdrs, FILE *file, enum xdr_op op)
+{
+ xdrs->x_op = op;
+ /* We have to add the const since the `struct xdr_ops' in `struct XDR'
+ is not `const'. */
+ xdrs->x_ops = (struct xdr_ops *) &xdrstdio_ops;
+ xdrs->x_private = (caddr_t) file;
+ xdrs->x_handy = 0;
+ xdrs->x_base = 0;
+}
+
+/*
+ * Destroy a stdio xdr stream.
+ * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create.
+ */
+static void
+xdrstdio_destroy (XDR *xdrs)
+{
+ (void) fflush ((FILE *) xdrs->x_private);
+ /* xx should we close the file ?? */
+};
+
+static bool_t
+xdrstdio_getlong (XDR *xdrs, long *lp)
+{
+ u_int32_t mycopy;
+
+ if (fread ((caddr_t) &mycopy, 4, 1, (FILE *) xdrs->x_private) != 1)
+ return FALSE;
+ *lp = (long) ntohl (mycopy);
+ return TRUE;
+}
+
+static bool_t
+xdrstdio_putlong (XDR *xdrs, const long *lp)
+{
+ int32_t mycopy = htonl ((u_int32_t) *lp);
+
+ if (fwrite ((caddr_t) &mycopy, 4, 1, (FILE *) xdrs->x_private) != 1)
+ return FALSE;
+ return TRUE;
+}
+
+static bool_t
+xdrstdio_getbytes (XDR *xdrs, const caddr_t addr, u_int len)
+{
+ if ((len != 0) && (fread (addr, (int) len, 1,
+ (FILE *) xdrs->x_private) != 1))
+ return FALSE;
+ return TRUE;
+}
+
+static bool_t
+xdrstdio_putbytes (XDR *xdrs, const char *addr, u_int len)
+{
+ if ((len != 0) && (fwrite (addr, (int) len, 1,
+ (FILE *) xdrs->x_private) != 1))
+ return FALSE;
+ return TRUE;
+}
+
+static u_int
+xdrstdio_getpos (const XDR *xdrs)
+{
+ return (u_int) ftell ((FILE *) xdrs->x_private);
+}
+
+static bool_t
+xdrstdio_setpos (XDR *xdrs, u_int pos)
+{
+ return fseek ((FILE *) xdrs->x_private, (long) pos, 0) < 0 ? FALSE : TRUE;
+}
+
+static int32_t *
+xdrstdio_inline (XDR *xdrs attribute_unused, u_int len attribute_unused)
+{
+ /*
+ * Must do some work to implement this: must insure
+ * enough data in the underlying stdio buffer,
+ * that the buffer is aligned so that we can indirect through a
+ * long *, and stuff this pointer in xdrs->x_buf. Doing
+ * a fread or fwrite to a scratch buffer would defeat
+ * most of the gains to be had here and require storage
+ * management on this buffer, so we don't do this.
+ */
+ return NULL;
+}
+
+static bool_t
+xdrstdio_getint32 (XDR *xdrs, int32_t *ip)
+{
+ int32_t mycopy;
+
+ if (fread ((caddr_t) &mycopy, 4, 1, (FILE *) xdrs->x_private) != 1)
+ return FALSE;
+ *ip = ntohl (mycopy);
+ return TRUE;
+}
+
+static bool_t
+xdrstdio_putint32 (XDR *xdrs, const int32_t *ip)
+{
+ int32_t mycopy = htonl (*ip);
+
+ ip = &mycopy;
+ if (fwrite ((caddr_t) ip, 4, 1, (FILE *) xdrs->x_private) != 1)
+ return FALSE;
+ return TRUE;
+}
diff --git a/android/reboot.c b/android/reboot.c
new file mode 100644
index 0000000..0bc50c0
--- a/dev/null
+++ b/android/reboot.c
@@ -0,0 +1,57 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cutils/properties.h>
+#include <cutils/android_reboot.h>
+#include <unistd.h>
+
+int reboot_main(int argc, char *argv[])
+{
+ int ret;
+ size_t prop_len;
+ char property_val[PROPERTY_VALUE_MAX];
+ const char *cmd = "reboot";
+ char *optarg = "";
+
+ opterr = 0;
+ do {
+ int c;
+
+ c = getopt(argc, argv, "p");
+
+ if (c == EOF) {
+ break;
+ }
+
+ switch (c) {
+ case 'p':
+ cmd = "shutdown";
+ break;
+ case '?':
+ fprintf(stderr, "usage: %s [-p] [rebootcommand]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ } while (1);
+
+ if(argc > optind + 1) {
+ fprintf(stderr, "%s: too many arguments\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (argc > optind)
+ optarg = argv[optind];
+
+ prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg);
+ if (prop_len >= sizeof(property_val)) {
+ fprintf(stderr, "reboot command too long: %s\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+
+ ret = property_set(ANDROID_RB_PROPERTY, property_val);
+ if(ret < 0) {
+ perror("reboot");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(stderr, "Done\n");
+ return 0;
+}
diff --git a/android/regex/bb_regex.c b/android/regex/bb_regex.c
new file mode 100644
index 0000000..682123c
--- a/dev/null
+++ b/android/regex/bb_regex.c
@@ -0,0 +1,5539 @@
+/* Extended regular expression matching and search library, version
+ 0.12. (Implements POSIX draft P10003.2/D11.2, except for
+ internationalization features.)
+
+ Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
+
+ 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, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined (_AIX) && !defined (REGEX_MALLOC)
+ #pragma alloca
+#endif
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#include "cs_config.h"
+
+#define os_random random
+#define HAVE_PTHREAD 1
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* We need this for `regex.h', and perhaps for the Emacs include files. */
+#include <sys/types.h>
+
+/* This is for other GNU distributions with internationalized messages. */
+#if HAVE_LIBINTL_H || defined (_LIBC)
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+#ifndef gettext_noop
+/* This define is so xgettext can find the internationalizable
+ strings. */
+#define gettext_noop(String) String
+#endif
+
+/* The `emacs' switch turns on certain matching commands
+ that make sense only in Emacs. */
+#ifdef emacs
+
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+
+#else /* not emacs */
+
+/* If we are not linking with Emacs proper,
+ we can't use the relocating allocator
+ even if config.h says that we can. */
+#undef REL_ALLOC
+
+#if defined (STDC_HEADERS) || defined (_LIBC)
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+
+/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow.
+ If nothing else has been done, use the method below. */
+#ifdef INHIBIT_STRING_HEADER
+#if !(defined (HAVE_BZERO) && defined (HAVE_BCOPY))
+#if !defined (bzero) && !defined (bcopy)
+#undef INHIBIT_STRING_HEADER
+#endif
+#endif
+#endif
+
+/* This is the normal way of making sure we have a bcopy and a bzero.
+ This is used in most programs--a few other programs avoid this
+ by defining INHIBIT_STRING_HEADER. */
+#ifndef INHIBIT_STRING_HEADER
+#if defined (HAVE_STRING_H) || defined (STDC_HEADERS) || defined (_LIBC)
+#include <string.h>
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+#endif
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset ((s), 0, (n))
+#endif
+#else
+#include <strings.h>
+#endif
+#endif
+
+/* Define the syntax stuff for \<, \>, etc. */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+ commands in re_match_2. */
+#ifndef Sword
+#define Sword 1
+#endif
+
+#ifdef SWITCH_ENUM_BUG
+#define SWITCH_ENUM_CAST(x) ((int)(x))
+#else
+#define SWITCH_ENUM_CAST(x) (x)
+#endif
+
+#ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+#else /* not SYNTAX_TABLE */
+
+/* How many characters in the character set. */
+#define CHAR_SET_SIZE 256
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void
+init_syntax_once ()
+{
+ register int c;
+ static int done = 0;
+
+ if (done)
+ return;
+
+ bzero (re_syntax_table, sizeof re_syntax_table);
+
+ for (c = 'a'; c <= 'z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = 'A'; c <= 'Z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = '0'; c <= '9'; c++)
+ re_syntax_table[c] = Sword;
+
+ re_syntax_table['_'] = Sword;
+
+ done = 1;
+}
+
+#endif /* not SYNTAX_TABLE */
+
+#define SYNTAX(c) re_syntax_table[c]
+
+#endif /* not emacs */
+
+/* Get the interface, including the syntax bits. */
+#include "bb_regex.h"
+
+/* isalpha etc. are used for the character classes. */
+#include <ctype.h>
+
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining IN_CTYPE_DOMAIN to 1 should let any compiler worth its salt
+ eliminate the && through constant folding." */
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+#define IN_CTYPE_DOMAIN(c) 1
+#else
+#define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+#ifdef isblank
+#define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c))
+#else
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+#define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c))
+#else
+#define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c))
+#endif
+
+#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
+#define ISDIGIT(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c))
+#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
+#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c))
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+ since ours (we hope) works properly with all combinations of
+ machines, compilers, `char' and `unsigned char' argument types.
+ (Per Bothner suggested the basic approach.) */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else /* not __STDC__ */
+/* As in Harbison and Steele. */
+#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+
+/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
+ use `alloca' instead of `malloc'. This is because using malloc in
+ re_search* or re_match* could cause memory leaks when C-g is used in
+ Emacs; also, malloc is slower and causes storage fragmentation. On
+ the other hand, malloc is more portable, and easier to debug.
+
+ Because we sometimes use alloca, some routines have to be macros,
+ not functions -- `alloca'-allocated space disappears at the end of the
+ function it is called in. */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE malloc
+#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+#define REGEX_FREE free
+
+#else /* not REGEX_MALLOC */
+
+/* Emacs already defines alloca, sometimes. */
+#ifndef alloca
+
+/* Make alloca work the best possible way. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not __GNUC__ or HAVE_ALLOCA_H */
+#if 0 /* It is a bad idea to declare alloca. We always cast the result. */
+#ifndef _AIX /* Already did AIX, up at the top. */
+char *alloca ();
+#endif /* not _AIX */
+#endif
+#endif /* not HAVE_ALLOCA_H */
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+#define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable. */
+#define REGEX_REALLOCATE(source, osize, nsize) \
+ (destination = (char *) alloca (nsize), \
+ bcopy (source, destination, osize), \
+ destination)
+
+/* No need to do anything to free, after alloca. */
+#define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */
+
+#endif /* not REGEX_MALLOC */
+
+/* Define how to allocate the failure stack. */
+
+#if defined (REL_ALLOC) && defined (REGEX_MALLOC)
+
+#define REGEX_ALLOCATE_STACK(size) \
+ r_alloc (&failure_stack_ptr, (size))
+#define REGEX_REALLOCATE_STACK(source, osize, nsize) \
+ r_re_alloc (&failure_stack_ptr, (nsize))
+#define REGEX_FREE_STACK(ptr) \
+ r_alloc_free (&failure_stack_ptr)
+
+#else /* not using relocating allocator */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE_STACK malloc
+#define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
+#define REGEX_FREE_STACK free
+
+#else /* not REGEX_MALLOC */
+
+#define REGEX_ALLOCATE_STACK alloca
+
+#define REGEX_REALLOCATE_STACK(source, osize, nsize) \
+ REGEX_REALLOCATE (source, osize, nsize)
+/* No need to explicitly free anything. */
+#define REGEX_FREE_STACK(arg)
+
+#endif /* not REGEX_MALLOC */
+#endif /* not using relocating allocator */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+ `string1' or just past its end. This works if PTR is NULL, which is
+ a good thing. */
+#define FIRST_STRING_P(ptr) \
+ (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail. */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define RETALLOC_IF(addr, n, t) \
+ if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits. */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+static int re_match_2_internal ();
+
+/* These are the command codes that appear in compiled regular
+ expressions. Some opcodes are followed by argument bytes. A
+ command code can specify any interpretation whatsoever for its
+ arguments. Zero bytes may appear in the compiled regular expression. */
+
+typedef enum
+{
+ no_op = 0,
+
+ /* Succeed right away--no more backtracking. */
+ succeed,
+
+ /* Followed by one byte giving n, then by n literal bytes. */
+ exactn,
+
+ /* Matches any (more or less) character. */
+ anychar,
+
+ /* Matches any one char belonging to specified set. First
+ following byte is number of bitmap bytes. Then come bytes
+ for a bitmap saying which chars are in. Bits in each byte
+ are ordered low-bit-first. A character is in the set if its
+ bit is 1. A character too large to have a bit in the map is
+ automatically not in the set. */
+ charset,
+
+ /* Same parameters as charset, but match any character that is
+ not one of those specified. */
+ charset_not,
+
+ /* Start remembering the text that is matched, for storing in a
+ register. Followed by one byte with the register number, in
+ the range 0 to one less than the pattern buffer's re_nsub
+ field. Then followed by one byte with the number of groups
+ inner to this one. (This last has to be part of the
+ start_memory only because we need it in the on_failure_jump
+ of re_match_2.) */
+ start_memory,
+
+ /* Stop remembering the text that is matched and store it in a
+ memory register. Followed by one byte with the register
+ number, in the range 0 to one less than `re_nsub' in the
+ pattern buffer, and one byte with the number of inner groups,
+ just like `start_memory'. (We need the number of inner
+ groups here because we don't have any easy way of finding the
+ corresponding start_memory when we're at a stop_memory.) */
+ stop_memory,
+
+ /* Match a duplicate of something remembered. Followed by one
+ byte containing the register number. */
+ duplicate,
+
+ /* Fail unless at beginning of line. */
+ begline,
+
+ /* Fail unless at end of line. */
+ endline,
+
+ /* Succeeds if at beginning of buffer (if emacs) or at beginning
+ of string to be matched (if not). */
+ begbuf,
+
+ /* Analogously, for end of buffer/string. */
+ endbuf,
+
+ /* Followed by two byte relative address to which to jump. */
+ jump,
+
+ /* Same as jump, but marks the end of an alternative. */
+ jump_past_alt,
+
+ /* Followed by two-byte relative address of place to resume at
+ in case of failure. */
+ on_failure_jump,
+
+ /* Like on_failure_jump, but pushes a placeholder instead of the
+ current string position when executed. */
+ on_failure_keep_string_jump,
+
+ /* Throw away latest failure point and then jump to following
+ two-byte relative address. */
+ pop_failure_jump,
+
+ /* Change to pop_failure_jump if know won't have to backtrack to
+ match; otherwise change to jump. This is used to jump
+ back to the beginning of a repeat. If what follows this jump
+ clearly won't match what the repeat does, such that we can be
+ sure that there is no use backtracking out of repetitions
+ already matched, then we change it to a pop_failure_jump.
+ Followed by two-byte address. */
+ maybe_pop_jump,
+
+ /* Jump to following two-byte address, and push a dummy failure
+ point. This failure point will be thrown away if an attempt
+ is made to use it for a failure. A `+' construct makes this
+ before the first repeat. Also used as an intermediary kind
+ of jump when compiling an alternative. */
+ dummy_failure_jump,
+
+ /* Push a dummy failure point and continue. Used at the end of
+ alternatives. */
+ push_dummy_failure,
+
+ /* Followed by two-byte relative address and two-byte number n.
+ After matching N times, jump to the address upon failure. */
+ succeed_n,
+
+ /* Followed by two-byte relative address, and two-byte number n.
+ Jump to the address N times, then fail. */
+ jump_n,
+
+ /* Set the following two-byte relative address to the
+ subsequent two-byte number. The address *includes* the two
+ bytes of number. */
+ set_number_at,
+
+ wordchar, /* Matches any word-constituent character. */
+ notwordchar, /* Matches any char that is not a word-constituent. */
+
+ wordbeg, /* Succeeds if at word beginning. */
+ wordend, /* Succeeds if at word end. */
+
+ wordbound, /* Succeeds if at a word boundary. */
+ notwordbound, /* Succeeds if not at a word boundary. */
+
+#ifdef emacs
+ before_dot, /* Succeeds if before point. */
+ at_dot, /* Succeeds if at point. */
+ after_dot, /* Succeeds if after point. */
+
+ /* Matches any character whose syntax is specified. Followed by
+ a byte which contains a syntax code, e.g., Sword. */
+ syntaxspec,
+
+ /* Matches any character whose syntax is not that specified. */
+ notsyntaxspec,
+#endif /* emacs */
+} re_opcode_t;
+
+/* Common operations on the compiled pattern. */
+
+/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
+
+#define STORE_NUMBER(destination, number) \
+ do { \
+ (destination)[0] = (number) & 0377; \
+ (destination)[1] = (number) >> 8; \
+ } while (0)
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+ the byte after where the number is stored. Therefore, DESTINATION
+ must be an lvalue. */
+
+#define STORE_NUMBER_AND_INCR(destination, number) \
+ do { \
+ STORE_NUMBER (destination, number); \
+ (destination) += 2; \
+ } while (0)
+
+/* Put into DESTINATION a number stored in two contiguous bytes starting
+ at SOURCE. */
+
+#define EXTRACT_NUMBER(destination, source) \
+ do { \
+ (destination) = *(source) & 0377; \
+ (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
+ } while (0)
+
+#ifdef DEBUG
+static void
+extract_number (dest, source)
+ int *dest;
+ unsigned char *source;
+{
+ int temp = SIGN_EXTEND_CHAR (*(source + 1));
+ *dest = *source & 0377;
+ *dest += temp << 8;
+}
+
+#ifndef EXTRACT_MACROS /* To debug the macros. */
+#undef EXTRACT_NUMBER
+#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+ SOURCE must be an lvalue. */
+
+#define EXTRACT_NUMBER_AND_INCR(destination, source) \
+ do { \
+ EXTRACT_NUMBER (destination, source); \
+ (source) += 2; \
+ } while (0)
+
+#ifdef DEBUG
+static void
+extract_number_and_incr (destination, source)
+ int *destination;
+ unsigned char **source;
+{
+ extract_number (destination, *source);
+ *source += 2;
+}
+
+#ifndef EXTRACT_MACROS
+#undef EXTRACT_NUMBER_AND_INCR
+#define EXTRACT_NUMBER_AND_INCR(dest, src) \
+ extract_number_and_incr (&dest, &src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+ it is doing (if the variable `debug' is nonzero). If linked with the
+ main program in `iregex.c', you can enter patterns and strings
+ interactively. And if linked with the main program in `main.c' and
+ the other test files, you can run the already-written tests. */
+
+#ifdef DEBUG
+
+/* We use standard I/O for debugging. */
+#include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging. */
+#include <assert.h>
+
+static int debug = 0;
+
+#define DEBUG_STATEMENT(e) e
+#define DEBUG_PRINT1(x) if (debug) printf (x)
+#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
+ if (debug) print_partial_compiled_pattern (s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
+ if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+/* Print the fastmap in human-readable form. */
+
+void
+print_fastmap (fastmap)
+ char *fastmap;
+{
+ unsigned was_a_range = 0;
+ unsigned i = 0;
+
+ while (i < (1 << BYTEWIDTH))
+ {
+ if (fastmap[i++])
+ {
+ was_a_range = 0;
+ putchar (i - 1);
+ while (i < (1 << BYTEWIDTH) && fastmap[i])
+ {
+ was_a_range = 1;
+ i++;
+ }
+ if (was_a_range)
+ {
+ printf ("-");
+ putchar (i - 1);
+ }
+ }
+ }
+ putchar ('\n');
+}
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+ the START pointer into it and ending just before the pointer END. */
+
+void
+print_partial_compiled_pattern (start, end)
+ unsigned char *start;
+ unsigned char *end;
+{
+ int mcnt, mcnt2;
+ unsigned char *p = start;
+ unsigned char *pend = end;
+
+ if (start == NULL)
+ {
+ printf ("(null)\n");
+ return;
+ }
+
+ /* Loop over pattern commands. */
+ while (p < pend)
+ {
+ printf ("%d:\t", p - start);
+
+ switch ((re_opcode_t) *p++)
+ {
+ case no_op:
+ printf ("/no_op");
+ break;
+
+ case exactn:
+ mcnt = *p++;
+ printf ("/exactn/%d", mcnt);
+ do
+ {
+ putchar ('/');
+ putchar (*p++);
+ }
+ while (--mcnt);
+ break;
+
+ case start_memory:
+ mcnt = *p++;
+ printf ("/start_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case stop_memory:
+ mcnt = *p++;
+ printf ("/stop_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case duplicate:
+ printf ("/duplicate/%d", *p++);
+ break;
+
+ case anychar:
+ printf ("/anychar");
+ break;
+
+ case charset:
+ case charset_not:
+ {
+ register int c, last = -100;
+ register int in_range = 0;
+
+ printf ("/charset [%s",
+ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+ assert (p + *p < pend);
+
+ for (c = 0; c < 256; c++)
+ if (c / 8 < *p
+ && (p[1 + (c/8)] & (1 << (c % 8))))
+ {
+ /* Are we starting a range? */
+ if (last + 1 == c && ! in_range)
+ {
+ putchar ('-');
+ in_range = 1;
+ }
+ /* Have we broken a range? */
+ else if (last + 1 != c && in_range)
+ {
+ putchar (last);
+ in_range = 0;
+ }
+
+ if (! in_range)
+ putchar (c);
+
+ last = c;
+ }
+
+ if (in_range)
+ putchar (last);
+
+ putchar (']');
+
+ p += 1 + *p;
+ }
+ break;
+
+ case begline:
+ printf ("/begline");
+ break;
+
+ case endline:
+ printf ("/endline");
+ break;
+
+ case on_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case on_failure_keep_string_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+ break;
+
+ case dummy_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/dummy_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case push_dummy_failure:
+ printf ("/push_dummy_failure");
+ break;
+
+ case maybe_pop_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/maybe_pop_jump to %d", p + mcnt - start);
+ break;
+
+ case pop_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/pop_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case jump_past_alt:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump_past_alt to %d", p + mcnt - start);
+ break;
+
+ case jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump to %d", p + mcnt - start);
+ break;
+
+ case succeed_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case jump_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case set_number_at:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/set_number_at location %d to %d", p + mcnt - start, mcnt2);
+ break;
+
+ case wordbound:
+ printf ("/wordbound");
+ break;
+
+ case notwordbound:
+ printf ("/notwordbound");
+ break;
+
+ case wordbeg:
+ printf ("/wordbeg");
+ break;
+
+ case wordend:
+ printf ("/wordend");
+
+#ifdef emacs
+ case before_dot:
+ printf ("/before_dot");
+ break;
+
+ case at_dot:
+ printf ("/at_dot");
+ break;
+
+ case after_dot:
+ printf ("/after_dot");
+ break;
+
+ case syntaxspec:
+ printf ("/syntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+
+ case notsyntaxspec:
+ printf ("/notsyntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+#endif /* emacs */
+
+ case wordchar:
+ printf ("/wordchar");
+ break;
+
+ case notwordchar:
+ printf ("/notwordchar");
+ break;
+
+ case begbuf:
+ printf ("/begbuf");
+ break;
+
+ case endbuf:
+ printf ("/endbuf");
+ break;
+
+ default:
+ printf ("?%d", *(p-1));
+ }
+
+ putchar ('\n');
+ }
+
+ printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+void
+print_compiled_pattern (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ unsigned char *buffer = bufp->buffer;
+
+ print_partial_compiled_pattern (buffer, buffer + bufp->used);
+ printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
+
+ if (bufp->fastmap_accurate && bufp->fastmap)
+ {
+ printf ("fastmap: ");
+ print_fastmap (bufp->fastmap);
+ }
+
+ printf ("re_nsub: %d\t", bufp->re_nsub);
+ printf ("regs_alloc: %d\t", bufp->regs_allocated);
+ printf ("can_be_null: %d\t", bufp->can_be_null);
+ printf ("newline_anchor: %d\n", bufp->newline_anchor);
+ printf ("no_sub: %d\t", bufp->no_sub);
+ printf ("not_bol: %d\t", bufp->not_bol);
+ printf ("not_eol: %d\t", bufp->not_eol);
+ printf ("syntax: %d\n", bufp->syntax);
+ /* Perhaps we should print the translate table? */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+ const char *where;
+ const char *string1;
+ const char *string2;
+ int size1;
+ int size2;
+{
+ unsigned this_char;
+
+ if (where == NULL)
+ printf ("(null)");
+ else
+ {
+ if (FIRST_STRING_P (where))
+ {
+ for (this_char = where - string1; this_char < size1; this_char++)
+ putchar (string1[this_char]);
+
+ where = string2;
+ }
+
+ for (this_char = where - string2; this_char < size2; this_char++)
+ putchar (string2[this_char]);
+ }
+}
+
+#else /* not DEBUG */
+
+#undef assert
+#define assert(e)
+
+#define DEBUG_STATEMENT(e)
+#define DEBUG_PRINT1(x)
+#define DEBUG_PRINT2(x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+
+/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
+ also be assigned to arbitrarily: each pattern buffer stores its own
+ syntax, so it can be changed between regex compilations. */
+/* This has no initializer because initialized variables in Emacs
+ become read-only after dumping. */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation. This provides
+ for compatibility for various utilities which historically have
+ different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit mask comprised of the various bits
+ defined in regex.h. We return the old syntax. */
+
+reg_syntax_t
+bb_re_set_syntax (syntax)
+ reg_syntax_t syntax;
+{
+ reg_syntax_t ret = re_syntax_options;
+
+ re_syntax_options = syntax;
+ return ret;
+}
+
+/* This table gives an error message for each of the error codes listed
+ in regex.h. Obviously the order here has to be same as there.
+ POSIX doesn't require that we do anything for REG_NOERROR,
+ but why not be nice? */
+
+static const char *re_error_msgid[] =
+ {
+ gettext_noop ("Success"), /* REG_NOERROR */
+ gettext_noop ("No match"), /* REG_NOMATCH */
+ gettext_noop ("Invalid regular expression"), /* REG_BADPAT */
+ gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */
+ gettext_noop ("Invalid character class name"), /* REG_ECTYPE */
+ gettext_noop ("Trailing backslash"), /* REG_EESCAPE */
+ gettext_noop ("Invalid back reference"), /* REG_ESUBREG */
+ gettext_noop ("Unmatched [ or [^"), /* REG_EBRACK */
+ gettext_noop ("Unmatched ( or \\("), /* REG_EPAREN */
+ gettext_noop ("Unmatched \\{"), /* REG_EBRACE */
+ gettext_noop ("Invalid content of \\{\\}"), /* REG_BADBR */
+ gettext_noop ("Invalid range end"), /* REG_ERANGE */
+ gettext_noop ("Memory exhausted"), /* REG_ESPACE */
+ gettext_noop ("Invalid preceding regular expression"), /* REG_BADRPT */
+ gettext_noop ("Premature end of regular expression"), /* REG_EEND */
+ gettext_noop ("Regular expression too big"), /* REG_ESIZE */
+ gettext_noop ("Unmatched ) or \\)"), /* REG_ERPAREN */
+ };
+
+/* Avoiding alloca during matching, to placate r_alloc. */
+
+/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
+ searching and matching functions should not call alloca. On some
+ systems, alloca is implemented in terms of malloc, and if we're
+ using the relocating allocator routines, then malloc could cause a
+ relocation, which might (if the strings being searched are in the
+ ralloc heap) shift the data out from underneath the regexp
+ routines.
+
+ Here's another reason to avoid allocation: Emacs
+ processes input from X in a signal handler; processing X input may
+ call malloc; if input arrives while a matching routine is calling
+ malloc, then we're scrod. But Emacs can't just block input while
+ calling matching routines; then we don't notice interrupts when
+ they come in. So, Emacs blocks input around all regexp calls
+ except the matching calls, which it leaves unprotected, in the
+ faith that they will not malloc. */
+
+/* Normally, this is fine. */
+#define MATCH_MAY_ALLOCATE
+
+/* When using GNU C, we are not REALLY using the C alloca, no matter
+ what config.h may say. So don't take precautions for it. */
+#ifdef __GNUC__
+#undef C_ALLOCA
+#endif
+
+/* The match routines may not allocate if (1) they would do it with malloc
+ and (2) it's not safe for them to use malloc.
+ Note that if REL_ALLOC is defined, matching would not use malloc for the
+ failure stack, but we would still use it for the register vectors;
+ so REL_ALLOC should not affect this. */
+#if (defined (C_ALLOCA) || defined (REGEX_MALLOC)) && defined (emacs)
+#undef MATCH_MAY_ALLOCATE
+#endif
+
+
+/* Failure stack declarations and macros; both re_compile_fastmap and
+ re_match_2 use a failure stack. These have to be macros because of
+ REGEX_ALLOCATE_STACK. */
+
+
+/* Number of failure points for which to initially allocate space
+ when matching. If this number is exceeded, we allocate more
+ space, so it is not a hard limit. */
+#ifndef INIT_FAILURE_ALLOC
+#define INIT_FAILURE_ALLOC 5
+#endif
+
+/* Roughly the maximum number of failure points on the stack. Would be
+ exactly that if always used MAX_FAILURE_ITEMS items each time we failed.
+ This is a variable only so users of regex can assign to it; we never
+ change it ourselves. */
+#if defined (MATCH_MAY_ALLOCATE)
+/* 4400 was enough to cause a crash on Alpha OSF/1,
+ whose default stack limit is 2mb. */
+int re_max_failures = 20000;
+#else
+int re_max_failures = 2000;
+#endif
+
+union fail_stack_elt
+{
+ unsigned char *pointer;
+ int integer;
+};
+
+typedef union fail_stack_elt fail_stack_elt_t;
+
+typedef struct
+{
+ fail_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} fail_stack_type;
+
+#define FAIL_STACK_EMPTY() (fail_stack.avail == 0)
+#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size)
+
+
+/* Define macros to initialize and free the failure stack.
+ Do `return -2' if the alloc fails. */
+
+#ifdef MATCH_MAY_ALLOCATE
+#define INIT_FAIL_STACK() \
+ do { \
+ fail_stack.stack = (fail_stack_elt_t *) \
+ REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
+ \
+ if (fail_stack.stack == NULL) \
+ return -2; \
+ \
+ fail_stack.size = INIT_FAILURE_ALLOC; \
+ fail_stack.avail = 0; \
+ } while (0)
+
+#define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack)
+#else
+#define INIT_FAIL_STACK() \
+ do { \
+ fail_stack.avail = 0; \
+ } while (0)
+
+#define RESET_FAIL_STACK()
+#endif
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+ Return 1 if succeeds, and 0 if either ran out of memory
+ allocating space for it or it was already too large.
+
+ REGEX_REALLOCATE_STACK requires `destination' be declared. */
+
+#define DOUBLE_FAIL_STACK(fail_stack) \
+ ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \
+ ? 0 \
+ : ((fail_stack).stack = (fail_stack_elt_t *) \
+ REGEX_REALLOCATE_STACK ((fail_stack).stack, \
+ (fail_stack).size * sizeof (fail_stack_elt_t), \
+ ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \
+ \
+ (fail_stack).stack == NULL \
+ ? 0 \
+ : ((fail_stack).size <<= 1, \
+ 1)))
+
+
+/* Push pointer POINTER on FAIL_STACK.
+ Return 1 if was able to do so and 0 if ran out of memory allocating
+ space to do so. */
+#define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \
+ ((FAIL_STACK_FULL () \
+ && !DOUBLE_FAIL_STACK (FAIL_STACK)) \
+ ? 0 \
+ : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \
+ 1))
+
+/* Push a pointer value onto the failure stack.
+ Assumes the variable `fail_stack'. Probably should only
+ be called from within `PUSH_FAILURE_POINT'. */
+#define PUSH_FAILURE_POINTER(item) \
+ fail_stack.stack[fail_stack.avail++].pointer = (unsigned char *) (item)
+
+/* This pushes an integer-valued item onto the failure stack.
+ Assumes the variable `fail_stack'. Probably should only
+ be called from within `PUSH_FAILURE_POINT'. */
+#define PUSH_FAILURE_INT(item) \
+ fail_stack.stack[fail_stack.avail++].integer = (item)
+
+/* Push a fail_stack_elt_t value onto the failure stack.
+ Assumes the variable `fail_stack'. Probably should only
+ be called from within `PUSH_FAILURE_POINT'. */
+#define PUSH_FAILURE_ELT(item) \
+ fail_stack.stack[fail_stack.avail++] = (item)
+
+/* These three POP... operations complement the three PUSH... operations.
+ All assume that `fail_stack' is nonempty. */
+#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer
+#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer
+#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging. */
+#ifdef DEBUG
+#define DEBUG_PUSH PUSH_FAILURE_INT
+#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT ()
+#else
+#define DEBUG_PUSH(item)
+#define DEBUG_POP(item_addr)
+#endif
+
+
+/* Push the information about the state we will need
+ if we ever fail back to it.
+
+ Requires variables fail_stack, regstart, regend, reg_info, and
+ num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be
+ declared.
+
+ Does `return FAILURE_CODE' if runs out of memory. */
+
+#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \
+ do { \
+ char *destination; \
+ /* Must be int, so when we don't save any registers, the arithmetic \
+ of 0 + -1 isn't done as unsigned. */ \
+ int this_reg; \
+ \
+ DEBUG_STATEMENT (failure_id++); \
+ DEBUG_STATEMENT (nfailure_points_pushed++); \
+ DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
+ DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\
+ DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\
+ \
+ DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \
+ DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \
+ \
+ /* Ensure we have enough space allocated for what we will push. */ \
+ while ((int) REMAINING_AVAIL_SLOTS < (int) NUM_FAILURE_ITEMS) \
+ { \
+ if (!DOUBLE_FAIL_STACK (fail_stack)) \
+ return failure_code; \
+ \
+ DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
+ (fail_stack).size); \
+ DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+ } \
+ \
+ /* Push the info, starting with the registers. */ \
+ DEBUG_PRINT1 ("\n"); \
+ \
+ if (1) \
+ for (this_reg = lowest_active_reg; \
+ this_reg <= (int) highest_active_reg; \
+ this_reg++) \
+ { \
+ DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
+ DEBUG_STATEMENT (num_regs_pushed++); \
+ \
+ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
+ PUSH_FAILURE_POINTER (regstart[this_reg]); \
+ \
+ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
+ PUSH_FAILURE_POINTER (regend[this_reg]); \
+ \
+ DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
+ DEBUG_PRINT2 (" match_null=%d", \
+ REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" matched_something=%d", \
+ MATCHED_SOMETHING (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" ever_matched=%d", \
+ EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
+ DEBUG_PRINT1 ("\n"); \
+ PUSH_FAILURE_ELT (reg_info[this_reg].word); \
+ } \
+ \
+ DEBUG_PRINT2(" Pushing low active reg: %d\n", lowest_active_reg); \
+ PUSH_FAILURE_INT (lowest_active_reg); \
+ \
+ DEBUG_PRINT2(" Pushing high active reg: %d\n", highest_active_reg);\
+ PUSH_FAILURE_INT (highest_active_reg); \
+ \
+ DEBUG_PRINT2(" Pushing pattern 0x%x: ", pattern_place); \
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \
+ PUSH_FAILURE_POINTER (pattern_place); \
+ \
+ DEBUG_PRINT2(" Pushing string 0x%x: `", string_place); \
+ DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \
+ size2); \
+ DEBUG_PRINT1("'\n"); \
+ PUSH_FAILURE_POINTER (string_place); \
+ \
+ DEBUG_PRINT2(" Pushing failure id: %u\n", failure_id); \
+ DEBUG_PUSH (failure_id); \
+ } while (0)
+
+/* This is the number of items that are pushed and popped on the stack
+ for each register. */
+#define NUM_REG_ITEMS 3
+
+/* Individual items aside from the registers. */
+#ifdef DEBUG
+#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */
+#else
+#define NUM_NONREG_ITEMS 4
+#endif
+
+/* We push at most this many items on the stack. */
+/* We used to use (num_regs - 1), which is the number of registers
+ this regexp will save; but that was changed to 5
+ to avoid stack overflow for a regexp with lots of parens. */
+#define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items. */
+#define NUM_FAILURE_ITEMS \
+ (((0 \
+ ? 0 : highest_active_reg - lowest_active_reg + 1) \
+ * NUM_REG_ITEMS) \
+ + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it. */
+#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+ We restore into the parameters, all of which should be lvalues:
+ STR -- the saved data position.
+ PAT -- the saved pattern position.
+ LOW_REG, HIGH_REG -- the highest and lowest active registers.
+ REGSTART, REGEND -- arrays of string positions.
+ REG_INFO -- array of information about each subexpression.
+
+ Also assumes the variables `fail_stack' and (if debugging), `bufp',
+ `pend', `string1', `size1', `string2', and `size2'. */
+
+#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{ \
+ DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \
+ int this_reg; \
+ const unsigned char *string_temp; \
+ \
+ assert (!FAIL_STACK_EMPTY ()); \
+ \
+ /* Remove failure points and point to how many regs pushed. */ \
+ DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \
+ DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \
+ DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \
+ \
+ assert ((int) fail_stack.avail >= (int) NUM_NONREG_ITEMS); \
+ \
+ DEBUG_POP (&failure_id); \
+ DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \
+ \
+ /* If the saved string location is NULL, it came from an \
+ on_failure_keep_string_jump opcode, and we want to throw away the \
+ saved NULL, thus retaining our current position in the string. */ \
+ string_temp = POP_FAILURE_POINTER (); \
+ if (string_temp != NULL) \
+ str = (const char *) string_temp; \
+ \
+ DEBUG_PRINT2 (" Popping string 0x%x: `", str); \
+ DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \
+ DEBUG_PRINT1 ("'\n"); \
+ \
+ pat = (unsigned char *) POP_FAILURE_POINTER (); \
+ DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \
+ \
+ /* Restore register info. */ \
+ high_reg = (unsigned) POP_FAILURE_INT (); \
+ DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \
+ \
+ low_reg = (unsigned) POP_FAILURE_INT (); \
+ DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \
+ \
+ if (1) \
+ for (this_reg = high_reg; this_reg >= (int) low_reg; this_reg--) \
+ { \
+ DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
+ \
+ reg_info[this_reg].word = POP_FAILURE_ELT (); \
+ DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
+ \
+ regend[this_reg] = (const char *) POP_FAILURE_POINTER (); \
+ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
+ \
+ regstart[this_reg] = (const char *) POP_FAILURE_POINTER (); \
+ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
+ } \
+ else \
+ { \
+ for (this_reg = highest_active_reg; this_reg > (int) high_reg; \
+ this_reg--) \
+ { \
+ reg_info[this_reg].word.integer = 0; \
+ regend[this_reg] = 0; \
+ regstart[this_reg] = 0; \
+ } \
+ highest_active_reg = high_reg; \
+ } \
+ \
+ set_regs_matched_done = 0; \
+ DEBUG_STATEMENT (nfailure_points_popped++); \
+} /* POP_FAILURE_POINT */
+
+
+
+/* Structure for per-register (a.k.a. per-group) information.
+ Other register information, such as the
+ starting and ending positions (which are addresses), and the list of
+ inner groups (which is a bits list) are maintained in separate
+ variables.
+
+ We are making a (strictly speaking) nonportable assumption here: that
+ the compiler will pack our bit fields into something that fits into
+ the type of `word', i.e., is something that fits into one item on the
+ failure stack. */
+
+typedef union
+{
+ fail_stack_elt_t word;
+ struct
+ {
+ /* This field is one if this group can match the empty string,
+ zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */
+#define MATCH_NULL_UNSET_VALUE 3
+ unsigned match_null_string_p : 2;
+ unsigned is_active : 1;
+ unsigned matched_something : 1;
+ unsigned ever_matched_something : 1;
+ } bits;
+} register_info_type;
+
+#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p)
+#define IS_ACTIVE(R) ((R).bits.is_active)
+#define MATCHED_SOMETHING(R) ((R).bits.matched_something)
+#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something)
+
+
+/* Call this when have matched a real character; it sets `matched' flags
+ for the subexpressions which we are currently inside. Also records
+ that those subexprs have matched. */
+#define SET_REGS_MATCHED() \
+ do \
+ { \
+ if (!set_regs_matched_done) \
+ { \
+ unsigned r; \
+ set_regs_matched_done = 1; \
+ for (r = lowest_active_reg; r <= highest_active_reg; r++) \
+ { \
+ MATCHED_SOMETHING (reg_info[r]) \
+ = EVER_MATCHED_SOMETHING (reg_info[r]) \
+ = 1; \
+ } \
+ } \
+ } \
+ while (0)
+
+/* Registers are set to a sentinel when they haven't yet matched. */
+static char reg_unset_dummy;
+#define REG_UNSET_VALUE (&reg_unset_dummy)
+#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+
+/* Subroutine declarations and macros for regex_compile. */
+
+static void store_op1 (), store_op2 ();
+static void insert_op1 (), insert_op2 ();
+static boolean at_begline_loc_p (), at_endline_loc_p ();
+static boolean group_in_compile_stack ();
+static reg_errcode_t compile_range ();
+
+/* Fetch the next character in the uncompiled pattern---translating it
+ if necessary. Also cast from a signed character in the constant
+ string passed to us by the user to an unsigned char that we can use
+ as an array index (in, e.g., `translate'). */
+#ifndef PATFETCH
+#define PATFETCH(c) \
+ do {if (p == pend) return REG_EEND; \
+ c = (unsigned char) *p++; \
+ if (translate) c = (unsigned char) translate[c]; \
+ } while (0)
+#endif
+
+/* Fetch the next character in the uncompiled pattern, with no
+ translation. */
+#define PATFETCH_RAW(c) \
+ do {if (p == pend) return REG_EEND; \
+ c = (unsigned char) *p++; \
+ } while (0)
+
+/* Go backwards one character in the pattern. */
+#define PATUNFETCH p--
+
+
+/* If `translate' is non-null, return translate[D], else just D. We
+ cast the subscript to translate because some data is declared as
+ `char *', to avoid warnings when a string constant is passed. But
+ when we use a character as a subscript we must make it unsigned. */
+#ifndef TRANSLATE
+#define TRANSLATE(d) \
+ (translate ? (char) translate[(unsigned char) (d)] : (d))
+#endif
+
+
+/* Macros for outputting the compiled pattern into `buffer'. */
+
+/* If the buffer isn't allocated when it comes in, use this. */
+#define INIT_BUF_SIZE 32
+
+/* Make sure we have at least N more bytes of space in buffer. */
+#define GET_BUFFER_SPACE(n) \
+ while (b - bufp->buffer + (n) > (int) bufp->allocated) \
+ EXTEND_BUFFER ()
+
+/* Make sure we have one more byte of buffer space and then add C to it. */
+#define BUF_PUSH(c) \
+ do { \
+ GET_BUFFER_SPACE (1); \
+ *b++ = (unsigned char) (c); \
+ } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2. */
+#define BUF_PUSH_2(c1, c2) \
+ do { \
+ GET_BUFFER_SPACE (2); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes. */
+#define BUF_PUSH_3(c1, c2, c3) \
+ do { \
+ GET_BUFFER_SPACE (3); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ *b++ = (unsigned char) (c3); \
+ } while (0)
+
+
+/* Store a jump with opcode OP at LOC to location TO. We store a
+ relative address offset by the three bytes the jump itself occupies. */
+#define STORE_JUMP(op, loc, to) \
+ store_op1 (op, loc, (to) - (loc) - 3)
+
+/* Likewise, for a two-argument jump. */
+#define STORE_JUMP2(op, loc, to, arg) \
+ store_op2 (op, loc, (to) - (loc) - 3, arg)
+
+/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */
+#define INSERT_JUMP(op, loc, to) \
+ insert_op1 (op, loc, (to) - (loc) - 3, b)
+
+/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */
+#define INSERT_JUMP2(op, loc, to, arg) \
+ insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
+
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+ into the pattern are two bytes long. So if 2^16 bytes turns out to
+ be too small, many things would have to change. */
+#define MAX_BUF_SIZE (1L << 16)
+
+
+/* Extend the buffer by twice its current size via realloc and
+ reset the pointers that pointed into the old block to point to the
+ correct places in the new one. If extending the buffer results in it
+ being larger than MAX_BUF_SIZE, then flag memory exhausted. */
+#define EXTEND_BUFFER() \
+ do { \
+ unsigned char *old_buffer = bufp->buffer; \
+ if (bufp->allocated == MAX_BUF_SIZE) \
+ return REG_ESIZE; \
+ bufp->allocated <<= 1; \
+ if (bufp->allocated > MAX_BUF_SIZE) \
+ bufp->allocated = MAX_BUF_SIZE; \
+ bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
+ if (bufp->buffer == NULL) \
+ return REG_ESPACE; \
+ /* If the buffer moved, move all the pointers into it. */ \
+ if (old_buffer != bufp->buffer) \
+ { \
+ b = (b - old_buffer) + bufp->buffer; \
+ begalt = (begalt - old_buffer) + bufp->buffer; \
+ if (fixup_alt_jump) \
+ fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
+ if (laststart) \
+ laststart = (laststart - old_buffer) + bufp->buffer; \
+ if (pending_exact) \
+ pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
+ } \
+ } while (0)
+
+
+/* Since we have one byte reserved for the register number argument to
+ {start,stop}_memory, the maximum number of groups we can report
+ things about is what fits in that byte. */
+#define MAX_REGNUM 255
+
+/* But patterns can have more than `MAX_REGNUM' registers. We just
+ ignore the excess. */
+typedef unsigned regnum_t;
+
+
+/* Macros for the compile stack. */
+
+/* Since offsets can go either forwards or backwards, this type needs to
+ be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */
+typedef int pattern_offset_t;
+
+typedef struct
+{
+ pattern_offset_t begalt_offset;
+ pattern_offset_t fixup_alt_jump;
+ pattern_offset_t inner_group_offset;
+ pattern_offset_t laststart_offset;
+ regnum_t regnum;
+} compile_stack_elt_t;
+
+
+typedef struct
+{
+ compile_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
+
+/* The next available element. */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list. */
+#define SET_LIST_BIT(c) \
+ (b[((unsigned char) (c)) / BYTEWIDTH] \
+ |= 1 << (((unsigned char) c) % BYTEWIDTH))
+
+
+/* Get the next unsigned number in the uncompiled pattern. */
+#define GET_UNSIGNED_NUMBER(num) \
+ { if (p != pend) \
+ { \
+ PATFETCH (c); \
+ while (ISDIGIT (c)) \
+ { \
+ if (num < 0) \
+ num = 0; \
+ num = num * 10 + c - '0'; \
+ if (p == pend) \
+ break; \
+ PATFETCH (c); \
+ } \
+ } \
+ }
+
+#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
+
+#define IS_CHAR_CLASS(string) \
+ (STREQ (string, "alpha") || STREQ (string, "upper") \
+ || STREQ (string, "lower") || STREQ (string, "digit") \
+ || STREQ (string, "alnum") || STREQ (string, "xdigit") \
+ || STREQ (string, "space") || STREQ (string, "print") \
+ || STREQ (string, "punct") || STREQ (string, "graph") \
+ || STREQ (string, "cntrl") || STREQ (string, "blank"))
+
+#ifndef MATCH_MAY_ALLOCATE
+
+/* If we cannot allocate large objects within re_match_2_internal,
+ we make the fail stack and register vectors global.
+ The fail stack, we grow to the maximum size when a regexp
+ is compiled.
+ The register vectors, we adjust in size each time we
+ compile a regexp, according to the number of registers it needs. */
+
+static fail_stack_type fail_stack;
+
+/* Size with which the following vectors are currently allocated.
+ That is so we can make them bigger as needed,
+ but never make them smaller. */
+static int regs_allocated_size;
+
+static const char ** regstart, ** regend;
+static const char ** old_regstart, ** old_regend;
+static const char **best_regstart, **best_regend;
+static register_info_type *reg_info;
+static const char **reg_dummy;
+static register_info_type *reg_info_dummy;
+
+/* Make the register vectors big enough for NUM_REGS registers,
+ but don't make them smaller. */
+
+static
+regex_grow_registers (num_regs)
+ int num_regs;
+{
+ if (num_regs > regs_allocated_size)
+ {
+ RETALLOC_IF (regstart, num_regs, const char *);
+ RETALLOC_IF (regend, num_regs, const char *);
+ RETALLOC_IF (old_regstart, num_regs, const char *);
+ RETALLOC_IF (old_regend, num_regs, const char *);
+ RETALLOC_IF (best_regstart, num_regs, const char *);
+ RETALLOC_IF (best_regend, num_regs, const char *);
+ RETALLOC_IF (reg_info, num_regs, register_info_type);
+ RETALLOC_IF (reg_dummy, num_regs, const char *);
+ RETALLOC_IF (reg_info_dummy, num_regs, register_info_type);
+
+ regs_allocated_size = num_regs;
+ }
+}
+
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+ Returns one of error codes defined in `regex.h', or zero for success.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate'
+ fields are set in BUFP on entry.
+
+ If it succeeds, results are put in BUFP (if it returns an error, the
+ contents of BUFP are undefined):
+ `buffer' is the compiled pattern;
+ `syntax' is set to SYNTAX;
+ `used' is set to the length of the compiled pattern;
+ `fastmap_accurate' is zero;
+ `re_nsub' is the number of subexpressions in PATTERN;
+ `not_bol' and `not_eol' are zero;
+
+ The `fastmap' and `newline_anchor' fields are neither
+ examined nor set. */
+
+/* Return, freeing storage we allocated. */
+#define FREE_STACK_RETURN(value) \
+ return (free (compile_stack.stack), value)
+
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+ const char *pattern;
+ int size;
+ reg_syntax_t syntax;
+ struct re_pattern_buffer *bufp;
+{
+ /* We fetch characters from PATTERN here. Even though PATTERN is
+ `char *' (i.e., signed), we declare these variables as unsigned, so
+ they can be reliably used as array indices. */
+ register unsigned char c, c1;
+
+ /* A random temporary spot in PATTERN. */
+ const char *p1;
+
+ /* Points to the end of the buffer, where we should append. */
+ register unsigned char *b;
+
+ /* Keeps track of unclosed groups. */
+ compile_stack_type compile_stack;
+
+ /* Points to the current (ending) position in the pattern. */
+ const char *p = pattern;
+ const char *pend = pattern + size;
+
+ /* How to translate the characters in the pattern. */
+ RE_TRANSLATE_TYPE translate = bufp->translate;
+
+ /* Address of the count-byte of the most recently inserted `exactn'
+ command. This makes it possible to tell if a new exact-match
+ character can be added to that command or if the character requires
+ a new `exactn' command. */
+ unsigned char *pending_exact = 0;
+
+ /* Address of start of the most recently finished expression.
+ This tells, e.g., postfix * where to find the start of its
+ operand. Reset at the beginning of groups and alternatives. */
+ unsigned char *laststart = 0;
+
+ /* Address of beginning of regexp, or inside of last group. */
+ unsigned char *begalt;
+
+ /* Place in the uncompiled pattern (i.e., the {) to
+ which to go back if the interval is invalid. */
+ const char *beg_interval;
+
+ /* Address of the place where a forward jump should go to the end of
+ the containing expression. Each alternative of an `or' -- except the
+ last -- ends with a forward jump of this sort. */
+ unsigned char *fixup_alt_jump = 0;
+
+ /* Counts open-groups as they are encountered. Remembered for the
+ matching close-group on the compile stack, so the same register
+ number is put in the stop_memory as the start_memory. */
+ regnum_t regnum = 0;
+
+#ifdef DEBUG
+ DEBUG_PRINT1 ("\nCompiling pattern: ");
+ if (debug)
+ {
+ unsigned debug_count;
+
+ for (debug_count = 0; debug_count < size; debug_count++)
+ putchar (pattern[debug_count]);
+ putchar ('\n');
+ }
+#endif /* DEBUG */
+
+ /* Initialize the compile stack. */
+ compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+ if (compile_stack.stack == NULL)
+ return REG_ESPACE;
+
+ compile_stack.size = INIT_COMPILE_STACK_SIZE;
+ compile_stack.avail = 0;
+
+ /* Initialize the pattern buffer. */
+ bufp->syntax = syntax;
+ bufp->fastmap_accurate = 0;
+ bufp->not_bol = bufp->not_eol = 0;
+
+ /* Set `used' to zero, so that if we return an error, the pattern
+ printer (for debugging) will think there's no pattern. We reset it
+ at the end. */
+ bufp->used = 0;
+
+ /* Always count groups, whether or not bufp->no_sub is set. */
+ bufp->re_nsub = 0;
+
+#if !defined (emacs) && !defined (SYNTAX_TABLE)
+ /* Initialize the syntax table. */
+ init_syntax_once ();
+#endif
+
+ if (bufp->allocated == 0)
+ {
+ if (bufp->buffer)
+ { /* If zero allocated, but buffer is non-null, try to realloc
+ enough space. This loses if buffer's address is bogus, but
+ that is the user's responsibility. */
+ RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
+ }
+ else
+ { /* Caller did not allocate a buffer. Do it for them. */
+ bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
+ }
+ if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE);
+
+ bufp->allocated = INIT_BUF_SIZE;
+ }
+
+ begalt = b = bufp->buffer;
+
+ /* Loop through the uncompiled pattern until we're at the end. */
+ while (p != pend)
+ {
+ PATFETCH (c);
+
+ switch (c)
+ {
+ case '^':
+ {
+ if ( /* If at start of pattern, it's an operator. */
+ p == pattern + 1
+ /* If context independent, it's an operator. */
+ || syntax & RE_CONTEXT_INDEP_ANCHORS
+ /* Otherwise, depends on what's come before. */
+ || at_begline_loc_p (pattern, p, syntax))
+ BUF_PUSH (begline);
+ else
+ goto normal_char;
+ }
+ break;
+
+
+ case '$':
+ {
+ if ( /* If at end of pattern, it's an operator. */
+ p == pend
+ /* If context independent, it's an operator. */
+ || syntax & RE_CONTEXT_INDEP_ANCHORS
+ /* Otherwise, depends on what's next. */
+ || at_endline_loc_p (p, pend, syntax))
+ BUF_PUSH (endline);
+ else
+ goto normal_char;
+ }
+ break;
+
+
+ case '+':
+ case '?':
+ if ((syntax & RE_BK_PLUS_QM)
+ || (syntax & RE_LIMITED_OPS))
+ goto normal_char;
+ handle_plus:
+ case '*':
+ /* If there is no previous pattern... */
+ if (!laststart)
+ {
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ FREE_STACK_RETURN (REG_BADRPT);
+ else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+ goto normal_char;
+ }
+
+ {
+ /* Are we optimizing this jump? */
+ boolean keep_string_p = false;
+
+ /* 1 means zero (many) matches is allowed. */
+ char zero_times_ok = 0, many_times_ok = 0;
+
+ /* If there is a sequence of repetition chars, collapse it
+ down to just one (the right one). We can't combine
+ interval operators with these because of, e.g., `a{2}*',
+ which should only match an even number of `a's. */
+
+ for (;;)
+ {
+ zero_times_ok |= c != '+';
+ many_times_ok |= c != '?';
+
+ if (p == pend)
+ break;
+
+ PATFETCH (c);
+
+ if (c == '*'
+ || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+ ;
+
+ else if (syntax & RE_BK_PLUS_QM && c == '\\')
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ PATFETCH (c1);
+ if (!(c1 == '+' || c1 == '?'))
+ {
+ PATUNFETCH;
+ PATUNFETCH;
+ break;
+ }
+
+ c = c1;
+ }
+ else
+ {
+ PATUNFETCH;
+ break;
+ }
+
+ /* If we get here, we found another repeat character. */
+ }
+
+ /* Star, etc. applied to an empty pattern is equivalent
+ to an empty pattern. */
+ if (!laststart)
+ break;
+
+ /* Now we know whether or not zero matches is allowed
+ and also whether or not two or more matches is allowed. */
+ if (many_times_ok)
+ { /* More than one repetition is allowed, so put in at the
+ end a backward relative jump from `b' to before the next
+ jump we're going to put in below (which jumps from
+ laststart to after this jump).
+
+ But if we are at the `*' in the exact sequence `.*\n',
+ insert an unconditional jump backwards to the .,
+ instead of the beginning of the loop. This way we only
+ push a failure point once, instead of every time
+ through the loop. */
+ assert (p - 1 > pattern);
+
+ /* Allocate the space for the jump. */
+ GET_BUFFER_SPACE (3);
+
+ /* We know we are not at the first character of the pattern,
+ because laststart was nonzero. And we've already
+ incremented `p', by the way, to be the character after
+ the `*'. Do we have to do something analogous here
+ for null bytes, because of RE_DOT_NOT_NULL? */
+ if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+ && zero_times_ok
+ && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+ && !(syntax & RE_DOT_NEWLINE))
+ { /* We have .*\n. */
+ STORE_JUMP (jump, b, laststart);
+ keep_string_p = true;
+ }
+ else
+ /* Anything else. */
+ STORE_JUMP (maybe_pop_jump, b, laststart - 3);
+
+ /* We've added more stuff to the buffer. */
+ b += 3;
+ }
+
+ /* On failure, jump from laststart to b + 3, which will be the
+ end of the buffer after this jump is inserted. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+ : on_failure_jump,
+ laststart, b + 3);
+ pending_exact = 0;
+ b += 3;
+
+ if (!zero_times_ok)
+ {
+ /* At least one repetition is required, so insert a
+ `dummy_failure_jump' before the initial
+ `on_failure_jump' instruction of the loop. This
+ effects a skip over that instruction the first time
+ we hit that loop. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
+ b += 3;
+ }
+ }
+ break;
+
+
+ case '.':
+ laststart = b;
+ BUF_PUSH (anychar);
+ break;
+
+
+ case '[':
+ {
+ boolean had_char_class = false;
+
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ /* Ensure that we have enough space to push a charset: the
+ opcode, the length count, and the bitset; 34 bytes in all. */
+ GET_BUFFER_SPACE (34);
+
+ laststart = b;
+
+ /* We test `*p == '^' twice, instead of using an if
+ statement, so we only need one BUF_PUSH. */
+ BUF_PUSH (*p == '^' ? charset_not : charset);
+ if (*p == '^')
+ p++;
+
+ /* Remember the first position in the bracket expression. */
+ p1 = p;
+
+ /* Push the number of bytes in the bitmap. */
+ BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* Clear the whole map. */
+ bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* charset_not matches newline according to a syntax bit. */
+ if ((re_opcode_t) b[-2] == charset_not
+ && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+ SET_LIST_BIT ('\n');
+
+ /* Read in characters and ranges, setting map bits. */
+ for (;;)
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ PATFETCH (c);
+
+ /* \ might escape characters inside [...] and [^...]. */
+ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ PATFETCH (c1);
+ SET_LIST_BIT (c1);
+ continue;
+ }
+
+ /* Could be the end of the bracket expression. If it's
+ not (i.e., when the bracket expression is `[]' so
+ far), the ']' character bit gets set way below. */
+ if (c == ']' && p != p1 + 1)
+ break;
+
+ /* Look ahead to see if it's a range when the last thing
+ was a character class. */
+ if (had_char_class && c == '-' && *p != ']')
+ FREE_STACK_RETURN (REG_ERANGE);
+
+ /* Look ahead to see if it's a range when the last thing
+ was a character: if this is a hyphen not at the
+ beginning or the end of a list, then it's the range
+ operator. */
+ if (c == '-'
+ && !(p - 2 >= pattern && p[-2] == '[')
+ && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+ && *p != ']')
+ {
+ reg_errcode_t ret
+ = compile_range (&p, pend, translate, syntax, b);
+ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+ }
+
+ else if (p[0] == '-' && p[1] != ']')
+ { /* This handles ranges made up of characters only. */
+ reg_errcode_t ret;
+
+ /* Move past the `-'. */
+ PATFETCH (c1);
+
+ ret = compile_range (&p, pend, translate, syntax, b);
+ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+ }
+
+ /* See if we're at the beginning of a possible character
+ class. */
+
+ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+ { /* Leave room for the null. */
+ char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+ PATFETCH (c);
+ c1 = 0;
+
+ /* If pattern is `[[:'. */
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ for (;;)
+ {
+ PATFETCH (c);
+ if (c == ':' || c == ']' || p == pend
+ || c1 == CHAR_CLASS_MAX_LENGTH)
+ break;
+ str[c1++] = c;
+ }
+ str[c1] = '\0';
+
+ /* If isn't a word bracketed by `[:' and:`]':
+ undo the ending character, the letters, and leave
+ the leading `:' and `[' (but set bits for them). */
+ if (c == ':' && *p == ']')
+ {
+ int ch;
+ boolean is_alnum = STREQ (str, "alnum");
+ boolean is_alpha = STREQ (str, "alpha");
+ boolean is_blank = STREQ (str, "blank");
+ boolean is_cntrl = STREQ (str, "cntrl");
+ boolean is_digit = STREQ (str, "digit");
+ boolean is_graph = STREQ (str, "graph");
+ boolean is_lower = STREQ (str, "lower");
+ boolean is_print = STREQ (str, "print");
+ boolean is_punct = STREQ (str, "punct");
+ boolean is_space = STREQ (str, "space");
+ boolean is_upper = STREQ (str, "upper");
+ boolean is_xdigit = STREQ (str, "xdigit");
+
+ if (!IS_CHAR_CLASS (str))
+ FREE_STACK_RETURN (REG_ECTYPE);
+
+ /* Throw away the ] at the end of the character
+ class. */
+ PATFETCH (c);
+
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+ {
+ int translated = TRANSLATE (ch);
+ /* This was split into 3 if's to
+ avoid an arbitrary limit in some compiler. */
+ if ( (is_alnum && ISALNUM (ch))
+ || (is_alpha && ISALPHA (ch))
+ || (is_blank && ISBLANK (ch))
+ || (is_cntrl && ISCNTRL (ch)))
+ SET_LIST_BIT (translated);
+ if ( (is_digit && ISDIGIT (ch))
+ || (is_graph && ISGRAPH (ch))
+ || (is_lower && ISLOWER (ch))
+ || (is_print && ISPRINT (ch)))
+ SET_LIST_BIT (translated);
+ if ( (is_punct && ISPUNCT (ch))
+ || (is_space && ISSPACE (ch))
+ || (is_upper && ISUPPER (ch))
+ || (is_xdigit && ISXDIGIT (ch)))
+ SET_LIST_BIT (translated);
+ }
+ had_char_class = true;
+ }
+ else
+ {
+ c1++;
+ while (c1--)
+ PATUNFETCH;
+ SET_LIST_BIT ('[');
+ SET_LIST_BIT (':');
+ had_char_class = false;
+ }
+ }
+ else
+ {
+ had_char_class = false;
+ SET_LIST_BIT (c);
+ }
+ }
+
+ /* Discard any (non)matching list bytes that are all 0 at the
+ end of the map. Decrease the map-length byte too. */
+ while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+ b[-1]--;
+ b += b[-1];
+ }
+ break;
+
+
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ goto handle_open;
+ else
+ goto normal_char;
+
+
+ case ')':
+ if (syntax & RE_NO_BK_PARENS)
+ goto handle_close;
+ else
+ goto normal_char;
+
+
+ case '\n':
+ if (syntax & RE_NEWLINE_ALT)
+ goto handle_alt;
+ else
+ goto normal_char;
+
+
+ case '|':
+ if (syntax & RE_NO_BK_VBAR)
+ goto handle_alt;
+ else
+ goto normal_char;
+
+
+ case '{':
+ if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
+ goto handle_interval;
+ else
+ goto normal_char;
+
+
+ case '\\':
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ /* Do not translate the character after the \, so that we can
+ distinguish, e.g., \B from \b, even if we normally would
+ translate, e.g., B to b. */
+ PATFETCH_RAW (c);
+
+ switch (c)
+ {
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ goto normal_backslash;
+
+ handle_open:
+ bufp->re_nsub++;
+ regnum++;
+
+ if (COMPILE_STACK_FULL)
+ {
+ RETALLOC (compile_stack.stack, compile_stack.size << 1,
+ compile_stack_elt_t);
+ if (compile_stack.stack == NULL) return REG_ESPACE;
+
+ compile_stack.size <<= 1;
+ }
+
+ /* These are the values to restore when we hit end of this
+ group. They are all relative offsets, so that if the
+ whole pattern moves because of realloc, they will still
+ be valid. */
+ COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+ COMPILE_STACK_TOP.fixup_alt_jump
+ = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+ COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+ COMPILE_STACK_TOP.regnum = regnum;
+
+ /* We will eventually replace the 0 with the number of
+ groups inner to this one. But do not push a
+ start_memory for groups beyond the last one we can
+ represent in the compiled pattern. */
+ if (regnum <= MAX_REGNUM)
+ {
+ COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+ BUF_PUSH_3 (start_memory, regnum, 0);
+ }
+
+ compile_stack.avail++;
+
+ fixup_alt_jump = 0;
+ laststart = 0;
+ begalt = b;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+ break;
+
+
+ case ')':
+ if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+ if (COMPILE_STACK_EMPTY)
+ {
+ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_backslash;
+ else
+ FREE_STACK_RETURN (REG_ERPAREN);
+ }
+
+ handle_close:
+ if (fixup_alt_jump)
+ { /* Push a dummy failure point at the end of the
+ alternative for a possible future
+ `pop_failure_jump' to pop. See comments at
+ `push_dummy_failure' in `re_match_2'. */
+ BUF_PUSH (push_dummy_failure);
+
+ /* We allocated space for this jump when we assigned
+ to `fixup_alt_jump', in the `handle_alt' case below. */
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
+ }
+
+ /* See similar code for backslashed left paren above. */
+ if (COMPILE_STACK_EMPTY)
+ {
+ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_char;
+ else
+ FREE_STACK_RETURN (REG_ERPAREN);
+ }
+
+ /* Since we just checked for an empty stack above, this
+ ``can't happen''. */
+ assert (compile_stack.avail != 0);
+ {
+ /* We don't just want to restore into `regnum', because
+ later groups should continue to be numbered higher,
+ as in `(ab)c(de)' -- the second group is #2. */
+ regnum_t this_group_regnum;
+
+ compile_stack.avail--;
+ begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
+ fixup_alt_jump
+ = COMPILE_STACK_TOP.fixup_alt_jump
+ ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
+ : 0;
+ laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
+ this_group_regnum = COMPILE_STACK_TOP.regnum;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+
+ /* We're at the end of the group, so now we know how many
+ groups were inside this one. */
+ if (this_group_regnum <= MAX_REGNUM)
+ {
+ unsigned char *inner_group_loc
+ = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
+
+ *inner_group_loc = regnum - this_group_regnum;
+ BUF_PUSH_3 (stop_memory, this_group_regnum,
+ regnum - this_group_regnum);
+ }
+ }
+ break;
+
+
+ case '|': /* `\|'. */
+ if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+ goto normal_backslash;
+ handle_alt:
+ if (syntax & RE_LIMITED_OPS)
+ goto normal_char;
+
+ /* Insert before the previous alternative a jump which
+ jumps to this alternative if the former fails. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (on_failure_jump, begalt, b + 6);
+ pending_exact = 0;
+ b += 3;
+
+ /* The alternative before this one has a jump after it
+ which gets executed if it gets matched. Adjust that
+ jump so it will jump to this alternative's analogous
+ jump (put in below, which in turn will jump to the next
+ (if any) alternative's such jump, etc.). The last such
+ jump jumps to the correct final destination. A picture:
+ _____ _____
+ | | | |
+ | v | v
+ a | b | c
+
+ If we are at `b', then fixup_alt_jump right now points to a
+ three-byte space after `a'. We'll put in the jump, set
+ fixup_alt_jump to right after `b', and leave behind three
+ bytes which we'll fill in when we get to after `c'. */
+
+ if (fixup_alt_jump)
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+ /* Mark and leave space for a jump after this alternative,
+ to be filled in later either by next alternative or
+ when know we're at the end of a series of alternatives. */
+ fixup_alt_jump = b;
+ GET_BUFFER_SPACE (3);
+ b += 3;
+
+ laststart = 0;
+ begalt = b;
+ break;
+
+
+ case '{':
+ /* If \{ is a literal. */
+ if (!(syntax & RE_INTERVALS)
+ /* If we're at `\{' and it's not the open-interval
+ operator. */
+ || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ || (p - 2 == pattern && p == pend))
+ goto normal_backslash;
+
+ handle_interval:
+ {
+ /* If got here, then the syntax allows intervals. */
+
+ /* At least (most) this many matches must be made. */
+ int lower_bound = -1, upper_bound = -1;
+
+ beg_interval = p - 1;
+
+ if (p == pend)
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ FREE_STACK_RETURN (REG_EBRACE);
+ }
+
+ GET_UNSIGNED_NUMBER (lower_bound);
+
+ if (c == ',')
+ {
+ GET_UNSIGNED_NUMBER (upper_bound);
+ if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+ }
+ else
+ /* Interval such as `{1}' => match exactly once. */
+ upper_bound = lower_bound;
+
+ if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+ || lower_bound > upper_bound)
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ FREE_STACK_RETURN (REG_BADBR);
+ }
+
+ if (!(syntax & RE_NO_BK_BRACES))
+ {
+ if (c != '\\') FREE_STACK_RETURN (REG_EBRACE);
+
+ PATFETCH (c);
+ }
+
+ if (c != '}')
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ FREE_STACK_RETURN (REG_BADBR);
+ }
+
+ /* We just parsed a valid interval. */
+
+ /* If it's invalid to have no preceding re. */
+ if (!laststart)
+ {
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ FREE_STACK_RETURN (REG_BADRPT);
+ else if (syntax & RE_CONTEXT_INDEP_OPS)
+ laststart = b;
+ else
+ goto unfetch_interval;
+ }
+
+ /* If the upper bound is zero, don't want to succeed at
+ all; jump from `laststart' to `b + 3', which will be
+ the end of the buffer after we insert the jump. */
+ if (upper_bound == 0)
+ {
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (jump, laststart, b + 3);
+ b += 3;
+ }
+
+ /* Otherwise, we have a nontrivial interval. When
+ we're all done, the pattern will look like:
+ set_number_at <jump count> <upper bound>
+ set_number_at <succeed_n count> <lower bound>
+ succeed_n <after jump addr> <succeed_n count>
+ <body of loop>
+ jump_n <succeed_n addr> <jump count>
+ (The upper bound and `jump_n' are omitted if
+ `upper_bound' is 1, though.) */
+ else
+ { /* If the upper bound is > 1, we need to insert
+ more at the end of the loop. */
+ unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+ GET_BUFFER_SPACE (nbytes);
+
+ /* Initialize lower bound of the `succeed_n', even
+ though it will be set during matching by its
+ attendant `set_number_at' (inserted next),
+ because `re_compile_fastmap' needs to know.
+ Jump to the `jump_n' we might insert below. */
+ INSERT_JUMP2 (succeed_n, laststart,
+ b + 5 + (upper_bound > 1) * 5,
+ lower_bound);
+ b += 5;
+
+ /* Code to initialize the lower bound. Insert
+ before the `succeed_n'. The `5' is the last two
+ bytes of this `set_number_at', plus 3 bytes of
+ the following `succeed_n'. */
+ insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+ b += 5;
+
+ if (upper_bound > 1)
+ { /* More than one repetition is allowed, so
+ append a backward jump to the `succeed_n'
+ that starts this interval.
+
+ When we've reached this during matching,
+ we'll have matched the interval once, so
+ jump back only `upper_bound - 1' times. */
+ STORE_JUMP2 (jump_n, b, laststart + 5,
+ upper_bound - 1);
+ b += 5;
+
+ /* The location we want to set is the second
+ parameter of the `jump_n'; that is `b-2' as
+ an absolute address. `laststart' will be
+ the `set_number_at' we're about to insert;
+ `laststart+3' the number to set, the source
+ for the relative address. But we are
+ inserting into the middle of the pattern --
+ so everything is getting moved up by 5.
+ Conclusion: (b - 2) - (laststart + 3) + 5,
+ i.e., b - laststart.
+
+ We insert this at the beginning of the loop
+ so that if we fail during matching, we'll
+ reinitialize the bounds. */
+ insert_op2 (set_number_at, laststart, b - laststart,
+ upper_bound - 1, b);
+ b += 5;
+ }
+ }
+ pending_exact = 0;
+ beg_interval = NULL;
+ }
+ break;
+
+ unfetch_interval:
+ /* If an invalid interval, match the characters as literals. */
+ assert (beg_interval);
+ p = beg_interval;
+ beg_interval = NULL;
+
+ /* normal_char and normal_backslash need `c'. */
+ PATFETCH (c);
+
+ if (!(syntax & RE_NO_BK_BRACES))
+ {
+ if (p > pattern && p[-1] == '\\')
+ goto normal_backslash;
+ }
+ goto normal_char;
+
+#ifdef emacs
+ /* There is no way to specify the before_dot and after_dot
+ operators. rms says this is ok. --karl */
+ case '=':
+ BUF_PUSH (at_dot);
+ break;
+
+ case 's':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+ break;
+
+ case 'S':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+ break;
+#endif /* emacs */
+
+
+ case 'w':
+ laststart = b;
+ BUF_PUSH (wordchar);
+ break;
+
+
+ case 'W':
+ laststart = b;
+ BUF_PUSH (notwordchar);
+ break;
+
+
+ case '<':
+ BUF_PUSH (wordbeg);
+ break;
+
+ case '>':
+ BUF_PUSH (wordend);
+ break;
+
+ case 'b':
+ BUF_PUSH (wordbound);
+ break;
+
+ case 'B':
+ BUF_PUSH (notwordbound);
+ break;
+
+ case '`':
+ BUF_PUSH (begbuf);
+ break;
+
+ case '\'':
+ BUF_PUSH (endbuf);
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ if (syntax & RE_NO_BK_REFS)
+ goto normal_char;
+
+ c1 = c - '0';
+
+ if (c1 > regnum)
+ FREE_STACK_RETURN (REG_ESUBREG);
+
+ /* Can't back reference to a subexpression if inside of it. */
+ if (group_in_compile_stack (compile_stack, c1))
+ goto normal_char;
+
+ laststart = b;
+ BUF_PUSH_2 (duplicate, c1);
+ break;
+
+
+ case '+':
+ case '?':
+ if (syntax & RE_BK_PLUS_QM)
+ goto handle_plus;
+ else
+ goto normal_backslash;
+
+ default:
+ normal_backslash:
+ /* You might think it would be useful for \ to mean
+ not to translate; but if we don't translate it
+ it will never match anything. */
+ c = TRANSLATE (c);
+ goto normal_char;
+ }
+ break;
+
+
+ default:
+ /* Expects the character in `c'. */
+ normal_char:
+ /* If no exactn currently being built. */
+ if (!pending_exact
+
+ /* If last exactn not at current position. */
+ || pending_exact + *pending_exact + 1 != b
+
+ /* We have only one byte following the exactn for the count. */
+ || *pending_exact == (1 << BYTEWIDTH) - 1
+
+ /* If followed by a repetition operator. */
+ || *p == '*' || *p == '^'
+ || ((syntax & RE_BK_PLUS_QM)
+ ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+ : (*p == '+' || *p == '?'))
+ || ((syntax & RE_INTERVALS)
+ && ((syntax & RE_NO_BK_BRACES)
+ ? *p == '{'
+ : (p[0] == '\\' && p[1] == '{'))))
+ {
+ /* Start building a new exactn. */
+
+ laststart = b;
+
+ BUF_PUSH_2 (exactn, 0);
+ pending_exact = b - 1;
+ }
+
+ BUF_PUSH (c);
+ (*pending_exact)++;
+ break;
+ } /* switch (c) */
+ } /* while p != pend */
+
+
+ /* Through the pattern now. */
+
+ if (fixup_alt_jump)
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+ if (!COMPILE_STACK_EMPTY)
+ FREE_STACK_RETURN (REG_EPAREN);
+
+ /* If we don't want backtracking, force success
+ the first time we reach the end of the compiled pattern. */
+ if (syntax & RE_NO_POSIX_BACKTRACKING)
+ BUF_PUSH (succeed);
+
+ free (compile_stack.stack);
+
+ /* We have succeeded; set the length of the buffer. */
+ bufp->used = b - bufp->buffer;
+
+#ifdef DEBUG
+ if (debug)
+ {
+ DEBUG_PRINT1 ("\nCompiled pattern: \n");
+ print_compiled_pattern (bufp);
+ }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+ /* Initialize the failure stack to the largest possible stack. This
+ isn't necessary unless we're trying to avoid calling alloca in
+ the search and match routines. */
+ {
+ int num_regs = bufp->re_nsub + 1;
+
+ /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+ is strictly greater than re_max_failures, the largest possible stack
+ is 2 * re_max_failures failure points. */
+ if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
+ {
+ fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+
+#ifdef emacs
+ if (! fail_stack.stack)
+ fail_stack.stack
+ = (fail_stack_elt_t *) xmalloc (fail_stack.size
+ * sizeof (fail_stack_elt_t));
+ else
+ fail_stack.stack
+ = (fail_stack_elt_t *) xrealloc (fail_stack.stack,
+ (fail_stack.size
+ * sizeof (fail_stack_elt_t)));
+#else /* not emacs */
+ if (! fail_stack.stack)
+ fail_stack.stack
+ = (fail_stack_elt_t *) malloc (fail_stack.size
+ * sizeof (fail_stack_elt_t));
+ else
+ fail_stack.stack
+ = (fail_stack_elt_t *) realloc (fail_stack.stack,
+ (fail_stack.size
+ * sizeof (fail_stack_elt_t)));
+#endif /* not emacs */
+ }
+
+ regex_grow_registers (num_regs);
+ }
+#endif /* not MATCH_MAY_ALLOCATE */
+
+ return REG_NOERROR;
+} /* regex_compile */
+
+/* Subroutines for `regex_compile'. */
+
+/* Store OP at LOC followed by two-byte integer parameter ARG. */
+
+static void
+store_op1 (op, loc, arg)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg;
+{
+ *loc = (unsigned char) op;
+ STORE_NUMBER (loc + 1, arg);
+}
+
+
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
+
+static void
+store_op2 (op, loc, arg1, arg2)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg1, arg2;
+{
+ *loc = (unsigned char) op;
+ STORE_NUMBER (loc + 1, arg1);
+ STORE_NUMBER (loc + 3, arg2);
+}
+
+
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+ for OP followed by two-byte integer parameter ARG. */
+
+static void
+insert_op1 (op, loc, arg, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg;
+ unsigned char *end;
+{
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 3;
+
+ while (pfrom != loc)
+ *--pto = *--pfrom;
+
+ store_op1 (op, loc, arg);
+}
+
+
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
+
+static void
+insert_op2 (op, loc, arg1, arg2, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg1, arg2;
+ unsigned char *end;
+{
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 5;
+
+ while (pfrom != loc)
+ *--pto = *--pfrom;
+
+ store_op2 (op, loc, arg1, arg2);
+}
+
+
+/* P points to just after a ^ in PATTERN. Return true if that ^ comes
+ after an alternative or a begin-subexpression. We assume there is at
+ least one character before the ^. */
+
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+ const char *pattern, *p;
+ reg_syntax_t syntax;
+{
+ const char *prev = p - 2;
+ boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+
+ return
+ /* After a subexpression? */
+ (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+ /* After an alternative? */
+ || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
+
+
+/* The dual of at_begline_loc_p. This one is for $. We assume there is
+ at least one character after the $, i.e., `P < PEND'. */
+
+static boolean
+at_endline_loc_p (p, pend, syntax)
+ const char *p, *pend;
+ int syntax;
+{
+ const char *next = p;
+ boolean next_backslash = *next == '\\';
+ const char *next_next = p + 1 < pend ? p + 1 : 0;
+
+ return
+ /* Before a subexpression? */
+ (syntax & RE_NO_BK_PARENS ? *next == ')'
+ : next_backslash && next_next && *next_next == ')')
+ /* Before an alternative? */
+ || (syntax & RE_NO_BK_VBAR ? *next == '|'
+ : next_backslash && next_next && *next_next == '|');
+}
+
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
+ false if it's not. */
+
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+ compile_stack_type compile_stack;
+ regnum_t regnum;
+{
+ int this_element;
+
+ for (this_element = compile_stack.avail - 1;
+ this_element >= 0;
+ this_element--)
+ if (compile_stack.stack[this_element].regnum == regnum)
+ return true;
+
+ return false;
+}
+
+
+/* Read the ending character of a range (in a bracket expression) from the
+ uncompiled pattern *P_PTR (which ends at PEND). We assume the
+ starting character is in `P[-2]'. (`P[-1]' is the character `-'.)
+ Then we set the translation of all bits between the starting and
+ ending characters (inclusive) in the compiled pattern B.
+
+ Return an error code.
+
+ We use these short variable names so we can use the same macros as
+ `regex_compile' itself. */
+
+static reg_errcode_t
+compile_range (p_ptr, pend, translate, syntax, b)
+ const char **p_ptr, *pend;
+ RE_TRANSLATE_TYPE translate;
+ reg_syntax_t syntax;
+ unsigned char *b;
+{
+ unsigned this_char;
+
+ const char *p = *p_ptr;
+ int range_start, range_end;
+
+ if (p == pend)
+ return REG_ERANGE;
+
+ /* Even though the pattern is a signed `char *', we need to fetch
+ with unsigned char *'s; if the high bit of the pattern character
+ is set, the range endpoints will be negative if we fetch using a
+ signed char *.
+
+ We also want to fetch the endpoints without translating them; the
+ appropriate translation is done in the bit-setting loop below. */
+ /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *. */
+ range_start = ((const unsigned char *) p)[-2];
+ range_end = ((const unsigned char *) p)[0];
+
+ /* Have to increment the pointer into the pattern string, so the
+ caller isn't still at the ending character. */
+ (*p_ptr)++;
+
+ /* If the start is after the end, the range is empty. */
+ if (range_start > range_end)
+ return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+ /* Here we see why `this_char' has to be larger than an `unsigned
+ char' -- the range is inclusive, so if `range_end' == 0xff
+ (assuming 8-bit characters), we would otherwise go into an infinite
+ loop, since all characters <= 0xff. */
+ for (this_char = range_start; this_char <= range_end; this_char++)
+ {
+ SET_LIST_BIT (TRANSLATE (this_char));
+ }
+
+ return REG_NOERROR;
+}
+
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+ BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
+ characters can start a string that matches the pattern. This fastmap
+ is used by re_search to skip quickly over impossible starting points.
+
+ The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+ area as BUFP->fastmap.
+
+ We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+ the pattern buffer.
+
+ Returns 0 if we succeed, -2 if an internal error. */
+
+int
+bb_re_compile_fastmap (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ int j, k;
+#ifdef MATCH_MAY_ALLOCATE
+ fail_stack_type fail_stack;
+#endif
+#ifndef REGEX_MALLOC
+ char *destination;
+#endif
+ /* We don't push any register information onto the failure stack. */
+ unsigned num_regs = 0;
+
+ register char *fastmap = bufp->fastmap;
+ unsigned char *pattern = bufp->buffer;
+ unsigned long size = bufp->used;
+ unsigned char *p = pattern;
+ register unsigned char *pend = pattern + size;
+
+ /* This holds the pointer to the failure stack, when
+ it is allocated relocatably. */
+#ifdef REL_ALLOC
+ fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+ /* Assume that each path through the pattern can be null until
+ proven otherwise. We set this false at the bottom of switch
+ statement, to which we get only if a particular path doesn't
+ match the empty string. */
+ boolean path_can_be_null = true;
+
+ /* We aren't doing a `succeed_n' to begin with. */
+ boolean succeed_n_p = false;
+
+ assert (fastmap != NULL && p != NULL);
+
+ INIT_FAIL_STACK ();
+ bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */
+ bufp->fastmap_accurate = 1; /* It will be when we're done. */
+ bufp->can_be_null = 0;
+
+ while (1)
+ {
+ if (p == pend || *p == succeed)
+ {
+ /* We have reached the (effective) end of pattern. */
+ if (!FAIL_STACK_EMPTY ())
+ {
+ bufp->can_be_null |= path_can_be_null;
+
+ /* Reset for next path. */
+ path_can_be_null = true;
+
+ p = fail_stack.stack[--fail_stack.avail].pointer;
+
+ continue;
+ }
+ else
+ break;
+ }
+
+ /* We should never be about to go beyond the end of the pattern. */
+ assert (p < pend);
+
+ switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+ {
+
+ /* I guess the idea here is to simply not bother with a fastmap
+ if a backreference is used, since it's too hard to figure out
+ the fastmap for the corresponding group. Setting
+ `can_be_null' stops `re_search_2' from using the fastmap, so
+ that is all we do. */
+ case duplicate:
+ bufp->can_be_null = 1;
+ goto done;
+
+
+ /* Following are the cases which match a character. These end
+ with `break'. */
+
+ case exactn:
+ fastmap[p[1]] = 1;
+ break;
+
+
+ case charset:
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+ fastmap[j] = 1;
+ break;
+
+
+ case charset_not:
+ /* Chars beyond end of map must be allowed. */
+ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+ fastmap[j] = 1;
+
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+ fastmap[j] = 1;
+ break;
+
+
+ case wordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == Sword)
+ fastmap[j] = 1;
+ break;
+
+
+ case notwordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != Sword)
+ fastmap[j] = 1;
+ break;
+
+
+ case anychar:
+ {
+ int fastmap_newline = fastmap['\n'];
+
+ /* `.' matches anything ... */
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ fastmap[j] = 1;
+
+ /* ... except perhaps newline. */
+ if (!(bufp->syntax & RE_DOT_NEWLINE))
+ fastmap['\n'] = fastmap_newline;
+
+ /* Return if we have already set `can_be_null'; if we have,
+ then the fastmap is irrelevant. Something's wrong here. */
+ else if (bufp->can_be_null)
+ goto done;
+
+ /* Otherwise, have to check alternative paths. */
+ break;
+ }
+
+#ifdef emacs
+ case syntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+
+
+ case notsyntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+
+
+ /* All cases after this match the empty string. These end with
+ `continue'. */
+
+
+ case before_dot:
+ case at_dot:
+ case after_dot:
+ continue;
+#endif /* emacs */
+
+
+ case no_op:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case wordbound:
+ case notwordbound:
+ case wordbeg:
+ case wordend:
+ case push_dummy_failure:
+ continue;
+
+
+ case jump_n:
+ case pop_failure_jump:
+ case maybe_pop_jump:
+ case jump:
+ case jump_past_alt:
+ case dummy_failure_jump:
+ EXTRACT_NUMBER_AND_INCR (j, p);
+ p += j;
+ if (j > 0)
+ continue;
+
+ /* Jump backward implies we just went through the body of a
+ loop and matched nothing. Opcode jumped to should be
+ `on_failure_jump' or `succeed_n'. Just treat it like an
+ ordinary jump. For a * loop, it has pushed its failure
+ point already; if so, discard that as redundant. */
+ if ((re_opcode_t) *p != on_failure_jump
+ && (re_opcode_t) *p != succeed_n)
+ continue;
+
+ p++;
+ EXTRACT_NUMBER_AND_INCR (j, p);
+ p += j;
+
+ /* If what's on the stack is where we are now, pop it. */
+ if (!FAIL_STACK_EMPTY ()
+ && fail_stack.stack[fail_stack.avail - 1].pointer == p)
+ fail_stack.avail--;
+
+ continue;
+
+
+ case on_failure_jump:
+ case on_failure_keep_string_jump:
+ handle_on_failure_jump:
+ EXTRACT_NUMBER_AND_INCR (j, p);
+
+ /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+ end of the pattern. We don't want to push such a point,
+ since when we restore it above, entering the switch will
+ increment `p' past the end of the pattern. We don't need
+ to push such a point since we obviously won't find any more
+ fastmap entries beyond `pend'. Such a pattern can match
+ the null string, though. */
+ if (p + j < pend)
+ {
+ if (!PUSH_PATTERN_OP (p + j, fail_stack))
+ {
+ RESET_FAIL_STACK ();
+ return -2;
+ }
+ }
+ else
+ bufp->can_be_null = 1;
+
+ if (succeed_n_p)
+ {
+ EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
+ succeed_n_p = false;
+ }
+
+ continue;
+
+
+ case succeed_n:
+ /* Get to the number of times to succeed. */
+ p += 2;
+
+ /* Increment p past the n for when k != 0. */
+ EXTRACT_NUMBER_AND_INCR (k, p);
+ if (k == 0)
+ {
+ p -= 4;
+ succeed_n_p = true; /* Spaghetti code alert. */
+ goto handle_on_failure_jump;
+ }
+ continue;
+
+
+ case set_number_at:
+ p += 4;
+ continue;
+
+
+ case start_memory:
+ case stop_memory:
+ p += 2;
+ continue;
+
+
+ default:
+ abort (); /* We have listed all the cases. */
+ } /* switch *p++ */
+
+ /* Getting here means we have found the possible starting
+ characters for one path of the pattern -- and that the empty
+ string does not match. We need not follow this path further.
+ Instead, look at the next alternative (remembered on the
+ stack), or quit if no more. The test at the top of the loop
+ does these things. */
+ path_can_be_null = false;
+ p = pend;
+ } /* while p */
+
+ /* Set `can_be_null' for the last path (also the first path, if the
+ pattern is empty). */
+ bufp->can_be_null |= path_can_be_null;
+
+ done:
+ RESET_FAIL_STACK ();
+ return 0;
+} /* re_compile_fastmap */
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
+ this memory for recording register information. STARTS and ENDS
+ must be allocated using the malloc library routine, and must each
+ be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+
+void
+bb_re_set_registers (bufp, regs, num_regs, starts, ends)
+ struct re_pattern_buffer *bufp;
+ struct re_registers *regs;
+ unsigned num_regs;
+ regoff_t *starts, *ends;
+{
+ if (num_regs)
+ {
+ bufp->regs_allocated = REGS_REALLOCATE;
+ regs->num_regs = num_regs;
+ regs->start = starts;
+ regs->end = ends;
+ }
+ else
+ {
+ bufp->regs_allocated = REGS_UNALLOCATED;
+ regs->num_regs = 0;
+ regs->start = regs->end = (regoff_t *) 0;
+ }
+}
+
+/* Searching routines. */
+
+/* Like re_search_2, below, but only one string is specified, and
+ doesn't let you say where to stop matching. */
+
+int
+bb_re_search (bufp, string, size, startpos, range, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int size, startpos, range;
+ struct re_registers *regs;
+{
+ return bb_re_search_2 (bufp, NULL, 0, string, size, startpos, range,
+ regs, size);
+}
+
+
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
+ virtual concatenation of STRING1 and STRING2, starting first at index
+ STARTPOS, then at STARTPOS + 1, and so on.
+
+ STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+
+ RANGE is how far to scan while trying to match. RANGE = 0 means try
+ only at STARTPOS; in general, the last start tried is STARTPOS +
+ RANGE.
+
+ In REGS, return the indices of the virtual concatenation of STRING1
+ and STRING2 that matched the entire BUFP->buffer and its contained
+ subexpressions.
+
+ Do not consider matching one past the index STOP in the virtual
+ concatenation of STRING1 and STRING2.
+
+ We return either the position in the strings at which the match was
+ found, -1 if no match, or -2 if error (such as failure
+ stack overflow). */
+
+int
+bb_re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int size1, size2;
+ int startpos;
+ int range;
+ struct re_registers *regs;
+ int stop;
+{
+ int val;
+ register char *fastmap = bufp->fastmap;
+ register RE_TRANSLATE_TYPE translate = bufp->translate;
+ int total_size = size1 + size2;
+ int endpos = startpos + range;
+ int anchored_start = 0;
+
+ /* Check for out-of-range STARTPOS. */
+ if (startpos < 0 || startpos > total_size)
+ return -1;
+
+ /* Fix up RANGE if it might eventually take us outside
+ the virtual concatenation of STRING1 and STRING2.
+ Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */
+ if (endpos < 0)
+ range = 0 - startpos;
+ else if (endpos > total_size)
+ range = total_size - startpos;
+
+ /* If the search isn't to be a backwards one, don't waste time in a
+ search for a pattern that must be anchored. */
+ if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
+ {
+ if (startpos > 0)
+ return -1;
+ else
+ range = 1;
+ }
+
+#ifdef emacs
+ /* In a forward search for something that starts with \=.
+ don't keep searching past point. */
+ if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0)
+ {
+ range = PT - startpos;
+ if (range <= 0)
+ return -1;
+ }
+#endif /* emacs */
+
+ /* Update the fastmap now if not correct already. */
+ if (fastmap && !bufp->fastmap_accurate)
+ if (bb_re_compile_fastmap (bufp) == -2)
+ return -2;
+
+ /* See whether the pattern is anchored. */
+ if (bufp->buffer[0] == begline)
+ anchored_start = 1;
+
+ /* Loop through the string, looking for a place to start matching. */
+ for (;;)
+ {
+ /* If the pattern is anchored,
+ skip quickly past places we cannot match.
+ We don't bother to treat startpos == 0 specially
+ because that case doesn't repeat. */
+ if (anchored_start && startpos > 0)
+ {
+ if (! (bufp->newline_anchor
+ && ((startpos <= size1 ? string1[startpos - 1]
+ : string2[startpos - size1 - 1])
+ == '\n')))
+ goto advance;
+ }
+
+ /* If a fastmap is supplied, skip quickly over characters that
+ cannot be the start of a match. If the pattern can match the
+ null string, however, we don't need to skip characters; we want
+ the first null string. */
+ if (fastmap && startpos < total_size && !bufp->can_be_null)
+ {
+ if (range > 0) /* Searching forwards. */
+ {
+ register const char *d;
+ register int lim = 0;
+ int irange = range;
+
+ if (startpos < size1 && startpos + range >= size1)
+ lim = range - (size1 - startpos);
+
+ d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+
+ /* Written out as an if-else to avoid testing `translate'
+ inside the loop. */
+ if (translate)
+ while (range > lim
+ && !fastmap[(unsigned char)
+ translate[(unsigned char) *d++]])
+ range--;
+ else
+ while (range > lim && !fastmap[(unsigned char) *d++])
+ range--;
+
+ startpos += irange - range;
+ }
+ else /* Searching backwards. */
+ {
+ register char c = (size1 == 0 || startpos >= size1
+ ? string2[startpos - size1]
+ : string1[startpos]);
+
+ if (!fastmap[(unsigned char) TRANSLATE (c)])
+ goto advance;
+ }
+ }
+
+ /* If can't match the null string, and that's all we have left, fail. */
+ if (range >= 0 && startpos == total_size && fastmap
+ && !bufp->can_be_null)
+ return -1;
+
+ val = re_match_2_internal (bufp, string1, size1, string2, size2,
+ startpos, regs, stop);
+#ifndef REGEX_MALLOC
+#ifdef C_ALLOCA
+ alloca (0);
+#endif
+#endif
+
+ if (val >= 0)
+ return startpos;
+
+ if (val == -2)
+ return -2;
+
+ advance:
+ if (!range)
+ break;
+ else if (range > 0)
+ {
+ range--;
+ startpos++;
+ }
+ else
+ {
+ range++;
+ startpos--;
+ }
+ }
+ return -1;
+} /* re_search_2 */
+
+/* Declarations and macros for re_match_2. */
+
+static int bcmp_translate ();
+static boolean alt_match_null_string_p (),
+ common_op_match_null_string_p (),
+ group_match_null_string_p ();
+
+/* This converts PTR, a pointer into one of the search strings `string1'
+ and `string2' into an offset from the beginning of that string. */
+#define POINTER_TO_OFFSET(ptr) \
+ (FIRST_STRING_P (ptr) \
+ ? ((regoff_t) ((ptr) - string1)) \
+ : ((regoff_t) ((ptr) - string2 + size1)))
+
+/* Macros for dealing with the split strings in re_match_2. */
+
+#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
+
+/* Call before fetching a character with *d. This switches over to
+ string2 if necessary. */
+#define PREFETCH() \
+ while (d == dend) \
+ { \
+ /* End of string2 => fail. */ \
+ if (dend == end_match_2) \
+ goto fail; \
+ /* End of string1 => advance to string2. */ \
+ d = string2; \
+ dend = end_match_2; \
+ }
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+ of `string1' and `string2'. If only one string, it's `string2'. */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)
+
+
+/* Test if D points to a character which is word-constituent. We have
+ two special cases to check for: if past the end of string1, look at
+ the first character in string2; and if before the beginning of
+ string2, look at the last character in string1. */
+#define WORDCHAR_P(d) \
+ (SYNTAX ((d) == end1 ? *string2 \
+ : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \
+ == Sword)
+
+/* Disabled due to a compiler bug -- see comment at case wordbound */
+#if 0
+/* Test if the character before D and the one at D differ with respect
+ to being word-constituent. */
+#define AT_WORD_BOUNDARY(d) \
+ (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \
+ || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+#endif
+
+/* Free everything we malloc. */
+#ifdef MATCH_MAY_ALLOCATE
+#define FREE_VAR(var) if (var) { REGEX_FREE (var); var = NULL; } else {}
+#define FREE_VARIABLES() \
+ do { \
+ REGEX_FREE_STACK (fail_stack.stack); \
+ FREE_VAR (regstart); \
+ FREE_VAR (regend); \
+ FREE_VAR (old_regstart); \
+ FREE_VAR (old_regend); \
+ FREE_VAR (best_regstart); \
+ FREE_VAR (best_regend); \
+ FREE_VAR (reg_info); \
+ FREE_VAR (reg_dummy); \
+ FREE_VAR (reg_info_dummy); \
+ } while (0)
+#else
+#define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* These values must meet several constraints. They must not be valid
+ register values; since we have a limit of 255 registers (because
+ we use only one byte in the pattern for the register number), we can
+ use numbers larger than 255. They must differ by 1, because of
+ NUM_FAILURE_ITEMS above. And the value for the lowest register must
+ be larger than the value for the highest register, so we do not try
+ to actually save any registers when none are active. */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+
+/* Matching routines. */
+
+#ifndef emacs /* Emacs never uses this. */
+/* re_match is like re_match_2 except it takes only a single string. */
+
+int
+bb_re_match (bufp, string, size, pos, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int size, pos;
+ struct re_registers *regs;
+{
+ int result = re_match_2_internal (bufp, NULL, 0, string, size,
+ pos, regs, size);
+ alloca (0);
+ return result;
+}
+#endif /* not emacs */
+
+
+/* re_match_2 matches the compiled pattern in BUFP against the
+ the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+ and SIZE2, respectively). We start matching at POS, and stop
+ matching at STOP.
+
+ If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+ store offsets for the substring each group matched in REGS. See the
+ documentation for exactly how many groups we fill.
+
+ We return -1 if no match, -2 if an internal error (such as the
+ failure stack overflowing). Otherwise, we return the length of the
+ matched substring. */
+
+int
+bb_re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int size1, size2;
+ int pos;
+ struct re_registers *regs;
+ int stop;
+{
+ int result = re_match_2_internal (bufp, string1, size1, string2, size2,
+ pos, regs, stop);
+ alloca (0);
+ return result;
+}
+
+/* This is a separate function so that we can force an alloca cleanup
+ afterwards. */
+static int
+re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int size1, size2;
+ int pos;
+ struct re_registers *regs;
+ int stop;
+{
+ /* General temporaries. */
+ int mcnt;
+ unsigned char *p1;
+
+ /* Just past the end of the corresponding string. */
+ const char *end1, *end2;
+
+ /* Pointers into string1 and string2, just past the last characters in
+ each to consider matching. */
+ const char *end_match_1, *end_match_2;
+
+ /* Where we are in the data, and the end of the current string. */
+ const char *d, *dend;
+
+ /* Where we are in the pattern, and the end of the pattern. */
+ unsigned char *p = bufp->buffer;
+ register unsigned char *pend = p + bufp->used;
+
+ /* Mark the opcode just after a start_memory, so we can test for an
+ empty subpattern when we get to the stop_memory. */
+ unsigned char *just_past_start_mem = 0;
+
+ /* We use this to map every character in the string. */
+ RE_TRANSLATE_TYPE translate = bufp->translate;
+
+ /* Failure point stack. Each place that can handle a failure further
+ down the line pushes a failure point on this stack. It consists of
+ restart, regend, and reg_info for all registers corresponding to
+ the subexpressions we're currently inside, plus the number of such
+ registers, and, finally, two char *'s. The first char * is where
+ to resume scanning the pattern; the second one is where to resume
+ scanning the strings. If the latter is zero, the failure point is
+ a ``dummy''; if a failure happens and the failure point is a dummy,
+ it gets discarded and the next next one is tried. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
+ fail_stack_type fail_stack;
+#endif
+#ifdef DEBUG
+ static unsigned failure_id = 0;
+ unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+#endif
+
+ /* This holds the pointer to the failure stack, when
+ it is allocated relocatably. */
+#ifdef REL_ALLOC
+ fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+ /* We fill all the registers internally, independent of what we
+ return, for use in backreferences. The number here includes
+ an element for register zero. */
+ unsigned num_regs = bufp->re_nsub + 1;
+
+ /* The currently active registers. */
+ unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+
+ /* Information on the contents of registers. These are pointers into
+ the input strings; they record just what was matched (on this
+ attempt) by a subexpression part of the pattern, that is, the
+ regnum-th regstart pointer points to where in the pattern we began
+ matching and the regnum-th regend points to right after where we
+ stopped matching the regnum-th subexpression. (The zeroth register
+ keeps track of what the whole pattern matches.) */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **regstart, **regend;
+#endif
+
+ /* If a group that's operated upon by a repetition operator fails to
+ match anything, then the register for its start will need to be
+ restored because it will have been set to wherever in the string we
+ are when we last see its open-group operator. Similarly for a
+ register's end. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **old_regstart, **old_regend;
+#endif
+
+ /* The is_active field of reg_info helps us keep track of which (possibly
+ nested) subexpressions we are currently in. The matched_something
+ field of reg_info[reg_num] helps us tell whether or not we have
+ matched any of the pattern so far this time through the reg_num-th
+ subexpression. These two fields get reset each time through any
+ loop their register is in. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
+ register_info_type *reg_info;
+#endif
+
+ /* The following record the register info as found in the above
+ variables when we find a match better than any we've seen before.
+ This happens as we backtrack through the failure points, which in
+ turn happens only if we have not yet matched the entire string. */
+ unsigned best_regs_set = false;
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **best_regstart, **best_regend;
+#endif
+
+ /* Logically, this is `best_regend[0]'. But we don't want to have to
+ allocate space for that if we're not allocating space for anything
+ else (see below). Also, we never need info about register 0 for
+ any of the other register vectors, and it seems rather a kludge to
+ treat `best_regend' differently than the rest. So we keep track of
+ the end of the best match so far in a separate variable. We
+ initialize this to NULL so that when we backtrack the first time
+ and need to test it, it's not garbage. */
+ const char *match_end = NULL;
+
+ /* This helps SET_REGS_MATCHED avoid doing redundant work. */
+ int set_regs_matched_done = 0;
+
+ /* Used when we pop values we don't care about. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **reg_dummy;
+ register_info_type *reg_info_dummy;
+#endif
+
+#ifdef DEBUG
+ /* Counts the total number of registers pushed. */
+ unsigned num_regs_pushed = 0;
+#endif
+
+ DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+
+ INIT_FAIL_STACK ();
+
+#ifdef MATCH_MAY_ALLOCATE
+ /* Do not bother to initialize all the register variables if there are
+ no groups in the pattern, as it takes a fair amount of time. If
+ there are groups, we include space for register 0 (the whole
+ pattern), even though we never use it, since it simplifies the
+ array indexing. We should fix this. */
+ if (bufp->re_nsub)
+ {
+ regstart = REGEX_TALLOC (num_regs, const char *);
+ regend = REGEX_TALLOC (num_regs, const char *);
+ old_regstart = REGEX_TALLOC (num_regs, const char *);
+ old_regend = REGEX_TALLOC (num_regs, const char *);
+ best_regstart = REGEX_TALLOC (num_regs, const char *);
+ best_regend = REGEX_TALLOC (num_regs, const char *);
+ reg_info = REGEX_TALLOC (num_regs, register_info_type);
+ reg_dummy = REGEX_TALLOC (num_regs, const char *);
+ reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
+
+ if (!(regstart && regend && old_regstart && old_regend && reg_info
+ && best_regstart && best_regend && reg_dummy && reg_info_dummy))
+ {
+ FREE_VARIABLES ();
+ return -2;
+ }
+ }
+ else
+ {
+ /* We must initialize all our variables to NULL, so that
+ `FREE_VARIABLES' doesn't try to free them. */
+ regstart = regend = old_regstart = old_regend = best_regstart
+ = best_regend = reg_dummy = NULL;
+ reg_info = reg_info_dummy = (register_info_type *) NULL;
+ }
+#endif /* MATCH_MAY_ALLOCATE */
+
+ /* The starting position is bogus. */
+ if (pos < 0 || pos > size1 + size2)
+ {
+ FREE_VARIABLES ();
+ return -1;
+ }
+
+ /* Initialize subexpression text positions to -1 to mark ones that no
+ start_memory/stop_memory has been seen for. Also initialize the
+ register information struct. */
+ for (mcnt = 1; mcnt < (int) num_regs; mcnt++)
+ {
+ regstart[mcnt] = regend[mcnt]
+ = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+
+ REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
+ IS_ACTIVE (reg_info[mcnt]) = 0;
+ MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+ EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+ }
+
+ /* We move `string1' into `string2' if the latter's empty -- but not if
+ `string1' is null. */
+ if (size2 == 0 && string1 != NULL)
+ {
+ string2 = string1;
+ size2 = size1;
+ string1 = 0;
+ size1 = 0;
+ }
+ end1 = string1 + size1;
+ end2 = string2 + size2;
+
+ /* Compute where to stop matching, within the two strings. */
+ if (stop <= size1)
+ {
+ end_match_1 = string1 + stop;
+ end_match_2 = string2;
+ }
+ else
+ {
+ end_match_1 = end1;
+ end_match_2 = string2 + stop - size1;
+ }
+
+ /* `p' scans through the pattern as `d' scans through the data.
+ `dend' is the end of the input string that `d' points within. `d'
+ is advanced into the following input string whenever necessary, but
+ this happens before fetching; therefore, at the beginning of the
+ loop, `d' can be pointing at the end of a string, but it cannot
+ equal `string2'. */
+ if (size1 > 0 && pos <= size1)
+ {
+ d = string1 + pos;
+ dend = end_match_1;
+ }
+ else
+ {
+ d = string2 + pos - size1;
+ dend = end_match_2;
+ }
+
+ DEBUG_PRINT1 ("The compiled pattern is: ");
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+ DEBUG_PRINT1 ("The string to match is: `");
+ DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+ DEBUG_PRINT1 ("'\n");
+
+ /* This loops over pattern commands. It exits by returning from the
+ function if the match is complete, or it drops through if the match
+ fails at this starting point in the input data. */
+ for (;;)
+ {
+ DEBUG_PRINT2 ("\n0x%x: ", p);
+
+ if (p == pend)
+ { /* End of pattern means we might have succeeded. */
+ DEBUG_PRINT1 ("end of pattern ... ");
+
+ /* If we haven't matched the entire string, and we want the
+ longest match, try backtracking. */
+ if (d != end_match_2)
+ {
+ /* 1 if this match ends in the same string (string1 or string2)
+ as the best previous match. */
+ boolean same_str_p = (FIRST_STRING_P (match_end)
+ == MATCHING_IN_FIRST_STRING);
+ /* 1 if this match is the best seen so far. */
+ boolean best_match_p;
+
+ /* AIX compiler got confused when this was combined
+ with the previous declaration. */
+ if (same_str_p)
+ best_match_p = d > match_end;
+ else
+ best_match_p = !MATCHING_IN_FIRST_STRING;
+
+ DEBUG_PRINT1 ("backtracking.\n");
+
+ if (!FAIL_STACK_EMPTY ())
+ { /* More failure points to try. */
+
+ /* If exceeds best match so far, save it. */
+ if (!best_regs_set || best_match_p)
+ {
+ best_regs_set = true;
+ match_end = d;
+
+ DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+
+ for (mcnt = 1; mcnt < (int) num_regs; mcnt++)
+ {
+ best_regstart[mcnt] = regstart[mcnt];
+ best_regend[mcnt] = regend[mcnt];
+ }
+ }
+ goto fail;
+ }
+
+ /* If no failure points, don't restore garbage. And if
+ last match is real best match, don't restore second
+ best one. */
+ else if (best_regs_set && !best_match_p)
+ {
+ restore_best_regs:
+ /* Restore best match. It may happen that `dend ==
+ end_match_1' while the restored d is in string2.
+ For example, the pattern `x.*y.*z' against the
+ strings `x-' and `y-z-', if the two strings are
+ not consecutive in memory. */
+ DEBUG_PRINT1 ("Restoring best registers.\n");
+
+ d = match_end;
+ dend = ((d >= string1 && d <= end1)
+ ? end_match_1 : end_match_2);
+
+ for (mcnt = 1; mcnt < (int) num_regs; mcnt++)
+ {
+ regstart[mcnt] = best_regstart[mcnt];
+ regend[mcnt] = best_regend[mcnt];
+ }
+ }
+ } /* d != end_match_2 */
+
+ succeed_label:
+ DEBUG_PRINT1 ("Accepting match.\n");
+
+ /* If caller wants register contents data back, do it. */
+ if (regs && !bufp->no_sub)
+ {
+ /* Have the register data arrays been allocated? */
+ if (bufp->regs_allocated == REGS_UNALLOCATED)
+ { /* No. So allocate them with malloc. We need one
+ extra element beyond `num_regs' for the `-1' marker
+ GNU code uses. */
+ regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+ regs->start = TALLOC (regs->num_regs, regoff_t);
+ regs->end = TALLOC (regs->num_regs, regoff_t);
+ if (regs->start == NULL || regs->end == NULL)
+ {
+ FREE_VARIABLES ();
+ return -2;
+ }
+ bufp->regs_allocated = REGS_REALLOCATE;
+ }
+ else if (bufp->regs_allocated == REGS_REALLOCATE)
+ { /* Yes. If we need more elements than were already
+ allocated, reallocate them. If we need fewer, just
+ leave it alone. */
+ if (regs->num_regs < num_regs + 1)
+ {
+ regs->num_regs = num_regs + 1;
+ RETALLOC (regs->start, regs->num_regs, regoff_t);
+ RETALLOC (regs->end, regs->num_regs, regoff_t);
+ if (regs->start == NULL || regs->end == NULL)
+ {
+ FREE_VARIABLES ();
+ return -2;
+ }
+ }
+ }
+ else
+ {
+ /* These braces fend off a "empty body in an else-statement"
+ warning under GCC when assert expands to nothing. */
+ assert (bufp->regs_allocated == REGS_FIXED);
+ }
+
+ /* Convert the pointer data in `regstart' and `regend' to
+ indices. Register zero has to be set differently,
+ since we haven't kept track of any info for it. */
+ if (regs->num_regs > 0)
+ {
+ regs->start[0] = pos;
+ regs->end[0] = (MATCHING_IN_FIRST_STRING
+ ? ((regoff_t) (d - string1))
+ : ((regoff_t) (d - string2 + size1)));
+ }
+
+ /* Go through the first `min (num_regs, regs->num_regs)'
+ registers, since that is all we initialized. */
+ for (mcnt = 1; mcnt < (int) MIN (num_regs, regs->num_regs); mcnt++)
+ {
+ if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+ regs->start[mcnt] = regs->end[mcnt] = -1;
+ else
+ {
+ regs->start[mcnt]
+ = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
+ regs->end[mcnt]
+ = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
+ }
+ }
+
+ /* If the regs structure we return has more elements than
+ were in the pattern, set the extra elements to -1. If
+ we (re)allocated the registers, this is the case,
+ because we always allocate enough to have at least one
+ -1 at the end. */
+ for (mcnt = num_regs; mcnt < (int) regs->num_regs; mcnt++)
+ regs->start[mcnt] = regs->end[mcnt] = -1;
+ } /* regs && !bufp->no_sub */
+
+ DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+ nfailure_points_pushed, nfailure_points_popped,
+ nfailure_points_pushed - nfailure_points_popped);
+ DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+ mcnt = d - pos - (MATCHING_IN_FIRST_STRING
+ ? string1
+ : string2 - size1);
+
+ DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+ FREE_VARIABLES ();
+ return mcnt;
+ }
+
+ /* Otherwise match next pattern command. */
+ switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+ {
+ /* Ignore these. Used to ignore the n of succeed_n's which
+ currently have n == 0. */
+ case no_op:
+ DEBUG_PRINT1 ("EXECUTING no_op.\n");
+ break;
+
+ case succeed:
+ DEBUG_PRINT1 ("EXECUTING succeed.\n");
+ goto succeed_label;
+
+ /* Match the next n pattern characters exactly. The following
+ byte in the pattern defines n, and the n bytes after that
+ are the characters to match. */
+ case exactn:
+ mcnt = *p++;
+ DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+ /* This is written out as an if-else so we don't waste time
+ testing `translate' inside the loop. */
+ if (translate)
+ {
+ do
+ {
+ PREFETCH ();
+ if ((unsigned char) translate[(unsigned char) *d++]
+ != (unsigned char) *p++)
+ goto fail;
+ }
+ while (--mcnt);
+ }
+ else
+ {
+ do
+ {
+ PREFETCH ();
+ if (*d++ != (char) *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ SET_REGS_MATCHED ();
+ break;
+
+
+ /* Match any character except possibly a newline or a null. */
+ case anychar:
+ DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+ PREFETCH ();
+
+ if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+ || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+ goto fail;
+
+ SET_REGS_MATCHED ();
+ DEBUG_PRINT2 (" Matched `%d'.\n", *d);
+ d++;
+ break;
+
+
+ case charset:
+ case charset_not:
+ {
+ register unsigned char c;
+ boolean not = (re_opcode_t) *(p - 1) == charset_not;
+
+ DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
+
+ PREFETCH ();
+ c = TRANSLATE (*d); /* The character to match. */
+
+ /* Cast to `unsigned' instead of `unsigned char' in case the
+ bit list is a full 32 bytes long. */
+ if (c < (unsigned) (*p * BYTEWIDTH)
+ && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ p += 1 + *p;
+
+ if (!not) goto fail;
+
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+ }
+
+
+ /* The beginning of a group is represented by start_memory.
+ The arguments are the register number in the next byte, and the
+ number of groups inner to this one in the next. The text
+ matched within the group is recorded (in the internal
+ registers data structure) under the register number. */
+ case start_memory:
+ DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
+
+ /* Find out if this group can match the empty string. */
+ p1 = p; /* To send to group_match_null_string_p. */
+
+ if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+ REG_MATCH_NULL_STRING_P (reg_info[*p])
+ = group_match_null_string_p (&p1, pend, reg_info);
+
+ /* Save the position in the string where we were the last time
+ we were at this open-group operator in case the group is
+ operated upon by a repetition operator, e.g., with `(a*)*b'
+ against `ab'; then we want to ignore where we are now in
+ the string in case this attempt to match fails. */
+ old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+ ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+ : regstart[*p];
+ DEBUG_PRINT2 (" old_regstart: %d\n",
+ POINTER_TO_OFFSET (old_regstart[*p]));
+
+ regstart[*p] = d;
+ DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
+ IS_ACTIVE (reg_info[*p]) = 1;
+ MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+ /* Clear this whenever we change the register activity status. */
+ set_regs_matched_done = 0;
+
+ /* This is the new highest active register. */
+ highest_active_reg = *p;
+
+ /* If nothing was active before, this is the new lowest active
+ register. */
+ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+ lowest_active_reg = *p;
+
+ /* Move past the register number and inner group count. */
+ p += 2;
+ just_past_start_mem = p;
+
+ break;
+
+
+ /* The stop_memory opcode represents the end of a group. Its
+ arguments are the same as start_memory's: the register
+ number, and the number of inner groups. */
+ case stop_memory:
+ DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
+
+ /* We need to save the string position the last time we were at
+ this close-group operator in case the group is operated
+ upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+ against `aba'; then we want to ignore where we are now in
+ the string in case this attempt to match fails. */
+ old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+ ? REG_UNSET (regend[*p]) ? d : regend[*p]
+ : regend[*p];
+ DEBUG_PRINT2 (" old_regend: %d\n",
+ POINTER_TO_OFFSET (old_regend[*p]));
+
+ regend[*p] = d;
+ DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
+
+ /* This register isn't active anymore. */
+ IS_ACTIVE (reg_info[*p]) = 0;
+
+ /* Clear this whenever we change the register activity status. */
+ set_regs_matched_done = 0;
+
+ /* If this was the only register active, nothing is active
+ anymore. */
+ if (lowest_active_reg == highest_active_reg)
+ {
+ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+ }
+ else
+ { /* We must scan for the new highest active register, since
+ it isn't necessarily one less than now: consider
+ (a(b)c(d(e)f)g). When group 3 ends, after the f), the
+ new highest active register is 1. */
+ unsigned char r = *p - 1;
+ while (r > 0 && !IS_ACTIVE (reg_info[r]))
+ r--;
+
+ /* If we end up at register zero, that means that we saved
+ the registers as the result of an `on_failure_jump', not
+ a `start_memory', and we jumped to past the innermost
+ `stop_memory'. For example, in ((.)*) we save
+ registers 1 and 2 as a result of the *, but when we pop
+ back to the second ), we are at the stop_memory 1.
+ Thus, nothing is active. */
+ if (r == 0)
+ {
+ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+ }
+ else
+ highest_active_reg = r;
+ }
+
+ /* If just failed to match something this time around with a
+ group that's operated on by a repetition operator, try to
+ force exit from the ``loop'', and restore the register
+ information for this group that we had before trying this
+ last match. */
+ if ((!MATCHED_SOMETHING (reg_info[*p])
+ || just_past_start_mem == p - 1)
+ && (p + 2) < pend)
+ {
+ boolean is_a_jump_n = false;
+
+ p1 = p + 2;
+ mcnt = 0;
+ switch ((re_opcode_t) *p1++)
+ {
+ case jump_n:
+ is_a_jump_n = true;
+ case pop_failure_jump:
+ case maybe_pop_jump:
+ case jump:
+ case dummy_failure_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if (is_a_jump_n)
+ p1 += 2;
+ break;
+
+ default:
+ /* do nothing */ ;
+ }
+ p1 += mcnt;
+
+ /* If the next operation is a jump backwards in the pattern
+ to an on_failure_jump right before the start_memory
+ corresponding to this stop_memory, exit from the loop
+ by forcing a failure after pushing on the stack the
+ on_failure_jump's jump in the pattern, and d. */
+ if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+ && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
+ {
+ /* If this group ever matched anything, then restore
+ what its registers were before trying this last
+ failed match, e.g., with `(a*)*b' against `ab' for
+ regstart[1], and, e.g., with `((a*)*(b*)*)*'
+ against `aba' for regend[3].
+
+ Also restore the registers for inner groups for,
+ e.g., `((a*)(b*))*' against `aba' (register 3 would
+ otherwise get trashed). */
+
+ if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+ {
+ unsigned r;
+
+ EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+ /* Restore this and inner groups' (if any) registers. */
+ for (r = *p; r < *p + *(p + 1); r++)
+ {
+ regstart[r] = old_regstart[r];
+
+ /* xx why this test? */
+ if (old_regend[r] >= regstart[r])
+ regend[r] = old_regend[r];
+ }
+ }
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+
+ goto fail;
+ }
+ }
+
+ /* Move past the register number and the inner group count. */
+ p += 2;
+ break;
+
+
+ /* \<digit> has been turned into a `duplicate' command which is
+ followed by the numeric value of <digit> as the register number. */
+ case duplicate:
+ {
+ register const char *d2, *dend2;
+ int regno = *p++; /* Get which register to match against. */
+ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+ /* Can't back reference a group which we've never matched. */
+ if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+ goto fail;
+
+ /* Where in input to try to start matching. */
+ d2 = regstart[regno];
+
+ /* Where to stop matching; if both the place to start and
+ the place to stop matching are in the same string, then
+ set to the place to stop, otherwise, for now have to use
+ the end of the first string. */
+
+ dend2 = ((FIRST_STRING_P (regstart[regno])
+ == FIRST_STRING_P (regend[regno]))
+ ? regend[regno] : end_match_1);
+ for (;;)
+ {
+ /* If necessary, advance to next segment in register
+ contents. */
+ while (d2 == dend2)
+ {
+ if (dend2 == end_match_2) break;
+ if (dend2 == regend[regno]) break;
+
+ /* End of string1 => advance to string2. */
+ d2 = string2;
+ dend2 = regend[regno];
+ }
+ /* At end of register contents => success */
+ if (d2 == dend2) break;
+
+ /* If necessary, advance to next segment in data. */
+ PREFETCH ();
+
+ /* How many characters left in this segment to match. */
+ mcnt = dend - d;
+
+ /* Want how many consecutive characters we can match in
+ one shot, so, if necessary, adjust the count. */
+ if (mcnt > dend2 - d2)
+ mcnt = dend2 - d2;
+
+ /* Compare that many; failure if mismatch, else move
+ past them. */
+ if (translate
+ ? bcmp_translate (d, d2, mcnt, translate)
+ : bcmp (d, d2, mcnt))
+ goto fail;
+ d += mcnt, d2 += mcnt;
+
+ /* Do this because we've match some characters. */
+ SET_REGS_MATCHED ();
+ }
+ }
+ break;
+
+
+ /* begline matches the empty string at the beginning of the string
+ (unless `not_bol' is set in `bufp'), and, if
+ `newline_anchor' is set, after newlines. */
+ case begline:
+ DEBUG_PRINT1 ("EXECUTING begline.\n");
+
+ if (AT_STRINGS_BEG (d))
+ {
+ if (!bufp->not_bol) break;
+ }
+ else if (d[-1] == '\n' && bufp->newline_anchor)
+ {
+ break;
+ }
+ /* In all other cases, we fail. */
+ goto fail;
+
+
+ /* endline is the dual of begline. */
+ case endline:
+ DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+ if (AT_STRINGS_END (d))
+ {
+ if (!bufp->not_eol) break;
+ }
+
+ /* We have to ``prefetch'' the next character. */
+ else if ((d == end1 ? *string2 : *d) == '\n'
+ && bufp->newline_anchor)
+ {
+ break;
+ }
+ goto fail;
+
+
+ /* Match at the very beginning of the data. */
+ case begbuf:
+ DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+ if (AT_STRINGS_BEG (d))
+ break;
+ goto fail;
+
+
+ /* Match at the very end of the data. */
+ case endbuf:
+ DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+ if (AT_STRINGS_END (d))
+ break;
+ goto fail;
+
+
+ /* on_failure_keep_string_jump is used to optimize `.*\n'. It
+ pushes NULL as the value for the string on the stack. Then
+ `pop_failure_point' will keep the current value for the
+ string, instead of restoring it. To see why, consider
+ matching `foo\nbar' against `.*\n'. The .* matches the foo;
+ then the . fails against the \n. But the next thing we want
+ to do is match the \n against the \n; if we restored the
+ string value, we would be back at the foo.
+
+ Because this is used only in specific cases, we don't need to
+ check all the things that `on_failure_jump' does, to make
+ sure the right things get saved on the stack. Hence we don't
+ share its code. The only reason to push anything on the
+ stack at all is that otherwise we would have to change
+ `anychar's code to do something besides goto fail in this
+ case; that seems worse than this. */
+ case on_failure_keep_string_jump:
+ DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+
+ PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+ break;
+
+
+ /* Uses of on_failure_jump:
+
+ Each alternative starts with an on_failure_jump that points
+ to the beginning of the next alternative. Each alternative
+ except the last ends with a jump that in effect jumps past
+ the rest of the alternatives. (They really jump to the
+ ending jump of the following alternative, because tensioning
+ these jumps is a hassle.)
+
+ Repeats start with an on_failure_jump that points past both
+ the repetition text and either the following jump or
+ pop_failure_jump back to this on_failure_jump. */
+ case on_failure_jump:
+ on_failure:
+ DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+
+ /* If this on_failure_jump comes right before a group (i.e.,
+ the original * applied to a group), save the information
+ for that group and all inner ones, so that if we fail back
+ to this point, the group's information will be correct.
+ For example, in \(a*\)*\1, we need the preceding group,
+ and in \(zz\(a*\)b*\)\2, we need the inner group. */
+
+ /* We can't use `p' to check ahead because we push
+ a failure point to `p + mcnt' after we do this. */
+ p1 = p;
+
+ /* We need to skip no_op's before we look for the
+ start_memory in case this on_failure_jump is happening as
+ the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+ against aba. */
+ while (p1 < pend && (re_opcode_t) *p1 == no_op)
+ p1++;
+
+ if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+ {
+ /* We have a new highest active register now. This will
+ get reset at the start_memory we are about to get to,
+ but we will have saved all the registers relevant to
+ this repetition op, as described above. */
+ highest_active_reg = *(p1 + 1) + *(p1 + 2);
+ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+ lowest_active_reg = *(p1 + 1);
+ }
+
+ DEBUG_PRINT1 (":\n");
+ PUSH_FAILURE_POINT (p + mcnt, d, -2);
+ break;
+
+
+ /* A smart repeat ends with `maybe_pop_jump'.
+ We change it to either `pop_failure_jump' or `jump'. */
+ case maybe_pop_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+ {
+ register unsigned char *p2 = p;
+
+ /* Compare the beginning of the repeat with what in the
+ pattern follows its end. If we can establish that there
+ is nothing that they would both match, i.e., that we
+ would have to backtrack because of (as in, e.g., `a*a')
+ then we can change to pop_failure_jump, because we'll
+ never have to backtrack.
+
+ This is not true in the case of alternatives: in
+ `(a|ab)*' we do need to backtrack to the `ab' alternative
+ (e.g., if the string was `ab'). But instead of trying to
+ detect that here, the alternative has put on a dummy
+ failure point which is what we will end up popping. */
+
+ /* Skip over open/close-group commands.
+ If what follows this loop is a ...+ construct,
+ look at what begins its body, since we will have to
+ match at least one of that. */
+ while (1)
+ {
+ if (p2 + 2 < pend
+ && ((re_opcode_t) *p2 == stop_memory
+ || (re_opcode_t) *p2 == start_memory))
+ p2 += 3;
+ else if (p2 + 6 < pend
+ && (re_opcode_t) *p2 == dummy_failure_jump)
+ p2 += 6;
+ else
+ break;
+ }
+
+ p1 = p + mcnt;
+ /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+ to the `maybe_finalize_jump' of this case. Examine what
+ follows. */
+
+ /* If we're at the end of the pattern, we can change. */
+ if (p2 == pend)
+ {
+ /* Consider what happens when matching ":\(.*\)"
+ against ":/". I don't really understand this code
+ yet. */
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1
+ (" End of pattern: change to `pop_failure_jump'.\n");
+ }
+
+ else if ((re_opcode_t) *p2 == exactn
+ || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+ {
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+
+ if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
+ c, p1[5]);
+ }
+
+ else if ((re_opcode_t) p1[3] == charset
+ || (re_opcode_t) p1[3] == charset_not)
+ {
+ int not = (re_opcode_t) p1[3] == charset_not;
+
+ if (c < (unsigned char) (p1[4] * BYTEWIDTH)
+ && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ /* `not' is equal to 1 if c would match, which means
+ that we can't change to pop_failure_jump. */
+ if (!not)
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ }
+ else if ((re_opcode_t) *p2 == charset)
+ {
+#ifdef DEBUG
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+#endif
+
+ if ((re_opcode_t) p1[3] == exactn
+ && ! ((int) p2[1] * BYTEWIDTH > (int) p1[5]
+ && (p2[2 + p1[5] / BYTEWIDTH]
+ & (1 << (p1[5] % BYTEWIDTH)))))
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
+ c, p1[5]);
+ }
+
+ else if ((re_opcode_t) p1[3] == charset_not)
+ {
+ int idx;
+ /* We win if the charset_not inside the loop
+ lists every character listed in the charset after. */
+ for (idx = 0; idx < (int) p2[1]; idx++)
+ if (! (p2[2 + idx] == 0
+ || (idx < (int) p1[4]
+ && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+ break;
+
+ if (idx == p2[1])
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ else if ((re_opcode_t) p1[3] == charset)
+ {
+ int idx;
+ /* We win if the charset inside the loop
+ has no overlap with the one after the loop. */
+ for (idx = 0;
+ idx < (int) p2[1] && idx < (int) p1[4];
+ idx++)
+ if ((p2[2 + idx] & p1[5 + idx]) != 0)
+ break;
+
+ if (idx == p2[1] || idx == p1[4])
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ }
+ }
+ p -= 2; /* Point at relative address again. */
+ if ((re_opcode_t) p[-1] != pop_failure_jump)
+ {
+ p[-1] = (unsigned char) jump;
+ DEBUG_PRINT1 (" Match => jump.\n");
+ goto unconditional_jump;
+ }
+ /* Note fall through. */
+
+
+ /* The end of a simple repeat has a pop_failure_jump back to
+ its matching on_failure_jump, where the latter will push a
+ failure point. The pop_failure_jump takes off failure
+ points put on by this pop_failure_jump's matching
+ on_failure_jump; we got through the pattern to here from the
+ matching on_failure_jump, so didn't fail. */
+ case pop_failure_jump:
+ {
+ /* We need to pass separate storage for the lowest and
+ highest registers, even though we don't care about the
+ actual values. Otherwise, we will restore only one
+ register from the stack, since lowest will == highest in
+ `pop_failure_point'. */
+ unsigned dummy_low_reg, dummy_high_reg;
+ unsigned char *pdummy;
+ const char *sdummy;
+
+ DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+ POP_FAILURE_POINT (sdummy, pdummy,
+ dummy_low_reg, dummy_high_reg,
+ reg_dummy, reg_dummy, reg_info_dummy);
+ }
+ /* Note fall through. */
+
+
+ /* Unconditionally jump (without popping any failure points). */
+ case jump:
+ unconditional_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
+ DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+ p += mcnt; /* Do the jump. */
+ DEBUG_PRINT2 ("(to 0x%x).\n", p);
+ break;
+
+
+ /* We need this opcode so we can detect where alternatives end
+ in `group_match_null_string_p' et al. */
+ case jump_past_alt:
+ DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+ goto unconditional_jump;
+
+
+ /* Normally, the on_failure_jump pushes a failure point, which
+ then gets popped at pop_failure_jump. We will end up at
+ pop_failure_jump, also, and with a pattern of, say, `a+', we
+ are skipping over the on_failure_jump, so we have to push
+ something meaningless for pop_failure_jump to pop. */
+ case dummy_failure_jump:
+ DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+ /* It doesn't matter what we push for the string here. What
+ the code at `fail' tests is the value for the pattern. */
+ PUSH_FAILURE_POINT (0, 0, -2);
+ goto unconditional_jump;
+
+
+ /* At the end of an alternative, we need to push a dummy failure
+ point in case we are followed by a `pop_failure_jump', because
+ we don't want the failure point for the alternative to be
+ popped. For example, matching `(a|ab)*' against `aab'
+ requires that we match the `ab' alternative. */
+ case push_dummy_failure:
+ DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+ /* See comments just above at `dummy_failure_jump' about the
+ two zeroes. */
+ PUSH_FAILURE_POINT (0, 0, -2);
+ break;
+
+ /* Have to succeed matching what follows at least n times.
+ After that, handle like `on_failure_jump'. */
+ case succeed_n:
+ EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+ assert (mcnt >= 0);
+ /* Originally, this is how many times we HAVE to succeed. */
+ if (mcnt > 0)
+ {
+ mcnt--;
+ p += 2;
+ STORE_NUMBER_AND_INCR (p, mcnt);
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt);
+ }
+ else if (mcnt == 0)
+ {
+ DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2);
+ p[2] = (unsigned char) no_op;
+ p[3] = (unsigned char) no_op;
+ goto on_failure;
+ }
+ break;
+
+ case jump_n:
+ EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+ /* Originally, this is how many times we CAN jump. */
+ if (mcnt)
+ {
+ mcnt--;
+ STORE_NUMBER (p + 2, mcnt);
+ goto unconditional_jump;
+ }
+ /* If don't have to jump any more, skip over the rest of command. */
+ else
+ p += 4;
+ break;
+
+ case set_number_at:
+ {
+ DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ p1 = p + mcnt;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
+ STORE_NUMBER (p1, mcnt);
+ break;
+ }
+
+#if 0
+ /* The DEC Alpha C compiler 3.x generates incorrect code for the
+ test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of
+ AT_WORD_BOUNDARY, so this code is disabled. Expanding the
+ macro and introducing temporary variables works around the bug. */
+
+ case wordbound:
+ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
+ break;
+ goto fail;
+
+ case notwordbound:
+ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
+ goto fail;
+ break;
+#else
+ case wordbound:
+ {
+ boolean prevchar, thischar;
+
+ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+ if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+ break;
+
+ prevchar = WORDCHAR_P (d - 1);
+ thischar = WORDCHAR_P (d);
+ if (prevchar != thischar)
+ break;
+ goto fail;
+ }
+
+ case notwordbound:
+ {
+ boolean prevchar, thischar;
+
+ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+ if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d))
+ goto fail;
+
+ prevchar = WORDCHAR_P (d - 1);
+ thischar = WORDCHAR_P (d);
+ if (prevchar != thischar)
+ goto fail;
+ break;
+ }
+#endif
+
+ case wordbeg:
+ DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+ if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+ break;
+ goto fail;
+
+ case wordend:
+ DEBUG_PRINT1 ("EXECUTING wordend.\n");
+ if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+ && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
+ break;
+ goto fail;
+
+#ifdef emacs
+ case before_dot:
+ DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) >= PT)
+ goto fail;
+ break;
+
+ case at_dot:
+ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) != PT)
+ goto fail;
+ break;
+
+ case after_dot:
+ DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) <= PT)
+ goto fail;
+ break;
+
+ case syntaxspec:
+ DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+ mcnt = *p++;
+ goto matchsyntax;
+
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+ mcnt = (int) Sword;
+ matchsyntax:
+ PREFETCH ();
+ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
+ d++;
+ if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+
+ case notsyntaxspec:
+ DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+ mcnt = *p++;
+ goto matchnotsyntax;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+ mcnt = (int) Sword;
+ matchnotsyntax:
+ PREFETCH ();
+ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
+ d++;
+ if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+
+#else /* not emacs */
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+ PREFETCH ();
+ if (!WORDCHAR_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+ PREFETCH ();
+ if (WORDCHAR_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+#endif /* not emacs */
+
+ default:
+ abort ();
+ }
+ continue; /* Successfully executed one pattern command; keep going. */
+
+
+ /* We goto here if a matching operation fails. */
+ fail:
+ if (!FAIL_STACK_EMPTY ())
+ { /* A restart point is known. Restore to that state. */
+ DEBUG_PRINT1 ("\nFAIL:\n");
+ POP_FAILURE_POINT (d, p,
+ lowest_active_reg, highest_active_reg,
+ regstart, regend, reg_info);
+
+ /* If this failure point is a dummy, try the next one. */
+ if (!p)
+ goto fail;
+
+ /* If we failed to the end of the pattern, don't examine *p. */
+ assert (p <= pend);
+ if (p < pend)
+ {
+ boolean is_a_jump_n = false;
+
+ /* If failed to a backwards jump that's part of a repetition
+ loop, need to pop this failure point and use the next one. */
+ switch ((re_opcode_t) *p)
+ {
+ case jump_n:
+ is_a_jump_n = true;
+ case maybe_pop_jump:
+ case pop_failure_jump:
+ case jump:
+ p1 = p + 1;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+
+ if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+ || (!is_a_jump_n
+ && (re_opcode_t) *p1 == on_failure_jump))
+ goto fail;
+ break;
+ default:
+ /* do nothing */ ;
+ }
+ }
+
+ if (d >= string1 && d <= end1)
+ dend = end_match_1;
+ }
+ else
+ break; /* Matching at this starting point really fails. */
+ } /* for (;;) */
+
+ if (best_regs_set)
+ goto restore_best_regs;
+
+ FREE_VARIABLES ();
+
+ return -1; /* Failure to match. */
+} /* re_match_2 */
+
+/* Subroutine definitions for re_match_2. */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+
+ Return true if the pattern up to the corresponding stop_memory can
+ match the empty string, and false otherwise.
+
+ If we find the matching stop_memory, sets P to point to one past its number.
+ Otherwise, sets P to an undefined byte less than or equal to END.
+
+ We don't handle duplicates properly (yet). */
+
+static boolean
+group_match_null_string_p (p, end, reg_info)
+ unsigned char **p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ /* Point to after the args to the start_memory. */
+ unsigned char *p1 = *p + 2;
+
+ while (p1 < end)
+ {
+ /* Skip over opcodes that can match nothing, and return true or
+ false, as appropriate, when we get to one that can't, or to the
+ matching stop_memory. */
+
+ switch ((re_opcode_t) *p1)
+ {
+ /* Could be either a loop or a series of alternatives. */
+ case on_failure_jump:
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+ /* If the next operation is not a jump backwards in the
+ pattern. */
+
+ if (mcnt >= 0)
+ {
+ /* Go through the on_failure_jumps of the alternatives,
+ seeing if any of the alternatives cannot match nothing.
+ The last alternative starts with only a jump,
+ whereas the rest start with on_failure_jump and end
+ with a jump, e.g., here is the pattern for `a|b|c':
+
+ /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+ /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+ /exactn/1/c
+
+ So, we have to first go through the first (n-1)
+ alternatives and then deal with the last one separately. */
+
+
+ /* Deal with the first (n-1) alternatives, which start
+ with an on_failure_jump (see above) that jumps to right
+ past a jump_past_alt. */
+
+ while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
+ {
+ /* `mcnt' holds how many bytes long the alternative
+ is, including the ending `jump_past_alt' and
+ its number. */
+
+ if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
+ reg_info))
+ return false;
+
+ /* Move to right after this alternative, including the
+ jump_past_alt. */
+ p1 += mcnt;
+
+ /* Break if it's the beginning of an n-th alternative
+ that doesn't begin with an on_failure_jump. */
+ if ((re_opcode_t) *p1 != on_failure_jump)
+ break;
+
+ /* Still have to check that it's not an n-th
+ alternative that starts with an on_failure_jump. */
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
+ {
+ /* Get to the beginning of the n-th alternative. */
+ p1 -= 3;
+ break;
+ }
+ }
+
+ /* Deal with the last alternative: go back and get number
+ of the `jump_past_alt' just before it. `mcnt' contains
+ the length of the alternative. */
+ EXTRACT_NUMBER (mcnt, p1 - 2);
+
+ if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+ return false;
+
+ p1 += mcnt; /* Get past the n-th alternative. */
+ } /* if mcnt > 0 */
+ break;
+
+
+ case stop_memory:
+ assert (p1[1] == **p);
+ *p = p1 + 2;
+ return true;
+
+
+ default:
+ if (!common_op_match_null_string_p (&p1, end, reg_info))
+ return false;
+ }
+ } /* while p1 < end */
+
+ return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+ It expects P to be the first byte of a single alternative and END one
+ byte past the last. The alternative can contain groups. */
+
+static boolean
+alt_match_null_string_p (p, end, reg_info)
+ unsigned char *p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ unsigned char *p1 = p;
+
+ while (p1 < end)
+ {
+ /* Skip over opcodes that can match nothing, and break when we get
+ to one that can't. */
+
+ switch ((re_opcode_t) *p1)
+ {
+ /* It's a loop. */
+ case on_failure_jump:
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+ break;
+
+ default:
+ if (!common_op_match_null_string_p (&p1, end, reg_info))
+ return false;
+ }
+ } /* while p1 < end */
+
+ return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+ alt_match_null_string_p.
+
+ Sets P to one after the op and its arguments, if any. */
+
+static boolean
+common_op_match_null_string_p (p, end, reg_info)
+ unsigned char **p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ boolean ret;
+ int reg_no;
+ unsigned char *p1 = *p;
+
+ switch ((re_opcode_t) *p1++)
+ {
+ case no_op:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case wordbeg:
+ case wordend:
+ case wordbound:
+ case notwordbound:
+#ifdef emacs
+ case before_dot:
+ case at_dot:
+ case after_dot:
+#endif
+ break;
+
+ case start_memory:
+ reg_no = *p1;
+ assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+ ret = group_match_null_string_p (&p1, end, reg_info);
+
+ /* Have to set this here in case we're checking a group which
+ contains a group and a back reference to it. */
+
+ if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+ REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+ if (!ret)
+ return false;
+ break;
+
+ /* If this is an optimized succeed_n for zero times, make the jump. */
+ case jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if (mcnt >= 0)
+ p1 += mcnt;
+ else
+ return false;
+ break;
+
+ case succeed_n:
+ /* Get to the number of times to succeed. */
+ p1 += 2;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+ if (mcnt == 0)
+ {
+ p1 -= 4;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+ }
+ else
+ return false;
+ break;
+
+ case duplicate:
+ if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+ return false;
+ break;
+
+ case set_number_at:
+ p1 += 4;
+
+ default:
+ /* All other opcodes mean we cannot match the empty string. */
+ return false;
+ }
+
+ *p = p1;
+ return true;
+} /* common_op_match_null_string_p */
+
+
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+ bytes; nonzero otherwise. */
+
+static int
+bcmp_translate (s1, s2, len, translate)
+ unsigned char *s1, *s2;
+ register int len;
+ RE_TRANSLATE_TYPE translate;
+{
+ register unsigned char *p1 = s1, *p2 = s2;
+ while (len)
+ {
+ if (translate[*p1++] != translate[*p2++]) return 1;
+ len--;
+ }
+ return 0;
+}
+
+/* Entry points for GNU code. */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+ compiles PATTERN (of length SIZE) and puts the result in BUFP.
+ Returns 0 if the pattern was valid, otherwise an error string.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+ are set in BUFP on entry.
+
+ We call regex_compile to do the actual compilation. */
+
+const char *
+bb_re_compile_pattern (pattern, length, bufp)
+ const char *pattern;
+ int length;
+ struct re_pattern_buffer *bufp;
+{
+ reg_errcode_t ret;
+
+ /* GNU code is written to assume at least RE_NREGS registers will be set
+ (and at least one extra will be -1). */
+ bufp->regs_allocated = REGS_UNALLOCATED;
+
+ /* And GNU code determines whether or not to get register information
+ by passing null for the REGS argument to re_match, etc., not by
+ setting no_sub. */
+ bufp->no_sub = 0;
+
+ /* Match anchors at newline. */
+ bufp->newline_anchor = 1;
+
+ ret = regex_compile (pattern, length, re_syntax_options, bufp);
+
+ if (!ret)
+ return NULL;
+ return gettext (re_error_msgid[(int) ret]);
+}
+
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#if defined (_REGEX_RE_COMP) || defined (_LIBC)
+
+/* BSD has one and only one pattern buffer. */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+#ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+ these names if they don't use our functions, and still use
+ regcomp/regexec below without link errors. */
+weak_function
+#endif
+bb_re_comp (s)
+ const char *s;
+{
+ reg_errcode_t ret;
+
+ if (!s)
+ {
+ if (!re_comp_buf.buffer)
+ return gettext ("No previous regular expression");
+ return 0;
+ }
+
+ if (!re_comp_buf.buffer)
+ {
+ re_comp_buf.buffer = (unsigned char *) malloc (200);
+ if (re_comp_buf.buffer == NULL)
+ return gettext (re_error_msgid[(int) REG_ESPACE]);
+ re_comp_buf.allocated = 200;
+
+ re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+ if (re_comp_buf.fastmap == NULL)
+ return gettext (re_error_msgid[(int) REG_ESPACE]);
+ }
+
+ /* Since `re_exec' always passes NULL for the `regs' argument, we
+ don't need to initialize the pattern buffer fields which affect it. */
+
+ /* Match anchors at newlines. */
+ re_comp_buf.newline_anchor = 1;
+
+ ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+
+ if (!ret)
+ return NULL;
+
+ /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
+ return (char *) gettext (re_error_msgid[(int) ret]);
+}
+
+
+int
+#ifdef _LIBC
+weak_function
+#endif
+bb_re_exec (s)
+ const char *s;
+{
+ const int len = strlen (s);
+ return
+ 0 <= bb_re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+#endif /* _REGEX_RE_COMP */
+
+/* POSIX.2 functions. Don't define these for Emacs. */
+
+#ifndef emacs
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+ PREG is a regex_t *. We do not expect any fields to be initialized,
+ since POSIX says we shouldn't. Thus, we set
+
+ `buffer' to the compiled pattern;
+ `used' to the length of the compiled pattern;
+ `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+ REG_EXTENDED bit in CFLAGS is set; otherwise, to
+ RE_SYNTAX_POSIX_BASIC;
+ `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+ `fastmap' and `fastmap_accurate' to zero;
+ `re_nsub' to the number of subexpressions in PATTERN.
+
+ PATTERN is the address of the pattern string.
+
+ CFLAGS is a series of bits which affect compilation.
+
+ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+ use POSIX basic syntax.
+
+ If REG_NEWLINE is set, then . and [^...] don't match newline.
+ Also, regexec will try a match beginning after every newline.
+
+ If REG_ICASE is set, then we considers upper- and lowercase
+ versions of letters to be equivalent when matching.
+
+ If REG_NOSUB is set, then when PREG is passed to regexec, that
+ routine will report only success or failure, and nothing about the
+ registers.
+
+ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
+ the return codes and their meanings.) */
+int
+#ifdef _LIBC
+weak_function
+#endif
+bb_regcomp (preg, pattern, cflags)
+ regex_t *preg;
+ const char *pattern;
+ int cflags;
+{
+ reg_errcode_t ret;
+ unsigned syntax
+ = (cflags & REG_EXTENDED) ?
+ RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+ /* regex_compile will allocate the space for the compiled pattern. */
+ preg->buffer = 0;
+ preg->allocated = 0;
+ preg->used = 0;
+
+ /* Don't bother to use a fastmap when searching. This simplifies the
+ REG_NEWLINE case: if we used a fastmap, we'd have to put all the
+ characters after newlines into the fastmap. This way, we just try
+ every character. */
+ preg->fastmap = 0;
+
+ if (cflags & REG_ICASE)
+ {
+ unsigned i;
+
+ preg->translate
+ = (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE
+ * sizeof (*(RE_TRANSLATE_TYPE)0));
+ if (preg->translate == NULL)
+ return (int) REG_ESPACE;
+
+ /* Map uppercase characters to corresponding lowercase ones. */
+ for (i = 0; i < CHAR_SET_SIZE; i++)
+ preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
+ }
+ else
+ preg->translate = NULL;
+
+ /* If REG_NEWLINE is set, newlines are treated differently. */
+ if (cflags & REG_NEWLINE)
+ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
+ syntax &= ~RE_DOT_NEWLINE;
+ syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+ /* It also changes the matching behavior. */
+ preg->newline_anchor = 1;
+ }
+ else
+ preg->newline_anchor = 0;
+
+ preg->no_sub = !!(cflags & REG_NOSUB);
+
+ /* POSIX says a null character in the pattern terminates it, so we
+ can use strlen here in compiling the pattern. */
+ ret = regex_compile (pattern, strlen (pattern), syntax, preg);
+
+ /* POSIX doesn't distinguish between an unmatched open-group and an
+ unmatched close-group: both are REG_EPAREN. */
+ if (ret == REG_ERPAREN) ret = REG_EPAREN;
+
+ return (int) ret;
+}
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+ string STRING.
+
+ If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+ `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
+ least NMATCH elements, and we set them to the offsets of the
+ corresponding matched substrings.
+
+ EFLAGS specifies `execution flags' which affect matching: if
+ REG_NOTBOL is set, then ^ does not match at the beginning of the
+ string; if REG_NOTEOL is set, then $ does not match at the end.
+
+ We return 0 if we find a match and REG_NOMATCH if not. */
+int
+#ifdef _LIBC
+weak_function
+#endif
+bb_regexec (preg, string, nmatch, pmatch, eflags)
+ const regex_t *preg;
+ const char *string;
+ size_t nmatch;
+ regmatch_t pmatch[];
+ int eflags;
+{
+ int ret;
+ struct re_registers regs;
+ regex_t private_preg;
+ int len = strlen (string);
+ boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+ private_preg = *preg;
+
+ private_preg.not_bol = !!(eflags & REG_NOTBOL);
+ private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+ /* The user has told us exactly how many registers to return
+ information about, via `nmatch'. We have to pass that on to the
+ matching routines. */
+ private_preg.regs_allocated = REGS_FIXED;
+
+ if (want_reg_info)
+ {
+ regs.num_regs = nmatch;
+ regs.start = TALLOC (nmatch, regoff_t);
+ regs.end = TALLOC (nmatch, regoff_t);
+ if (regs.start == NULL || regs.end == NULL)
+ return (int) REG_NOMATCH;
+ }
+
+ /* Perform the searching operation. */
+ ret = bb_re_search (&private_preg, string, len,
+ /* start: */ 0, /* range: */ len,
+ want_reg_info ? &regs : (struct re_registers *) 0);
+
+ /* Copy the register information to the POSIX structure. */
+ if (want_reg_info)
+ {
+ if (ret >= 0)
+ {
+ unsigned r;
+
+ for (r = 0; r < nmatch; r++)
+ {
+ pmatch[r].rm_so = regs.start[r];
+ pmatch[r].rm_eo = regs.end[r];
+ }
+ }
+
+ /* If we needed the temporary register info, free the space now. */
+ free (regs.start);
+ free (regs.end);
+ }
+
+ /* We want zero return to mean success, unlike `re_search'. */
+ return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
+size_t
+#ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+ these names if they don't use our functions, and still use
+ regcomp/regexec below without link errors. */
+weak_function
+#endif
+bb_regerror (errcode, preg, errbuf, errbuf_size)
+ int errcode;
+ const regex_t *preg;
+ char *errbuf;
+ size_t errbuf_size;
+{
+ const char *msg;
+ size_t msg_size;
+
+ if (errcode < 0
+ || errcode >= (sizeof (re_error_msgid) / sizeof (re_error_msgid[0])))
+ /* Only error codes returned by the rest of the code should be passed
+ to this routine. If we are given anything else, or if other regex
+ code generates an invalid error code, then the program has a bug.
+ Dump core so we can fix it. */
+ abort ();
+
+ msg = gettext (re_error_msgid[errcode]);
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (errbuf_size != 0)
+ {
+ if (msg_size > errbuf_size)
+ {
+ strncpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+ }
+ else
+ strcpy (errbuf, msg);
+ }
+
+ return msg_size;
+}
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+#ifdef _LIBC
+/* Make these definitions weak in libc, so POSIX programs can redefine
+ these names if they don't use our functions, and still use
+ regcomp/regexec below without link errors. */
+weak_function
+#endif
+bb_regfree (preg)
+ regex_t *preg;
+{
+ if (preg->buffer != NULL)
+ free (preg->buffer);
+ preg->buffer = NULL;
+
+ preg->allocated = 0;
+ preg->used = 0;
+
+ if (preg->fastmap != NULL)
+ free (preg->fastmap);
+ preg->fastmap = NULL;
+ preg->fastmap_accurate = 0;
+
+ if (preg->translate != NULL)
+ free (preg->translate);
+ preg->translate = NULL;
+}
+
+#endif /* not emacs */
diff --git a/android/regex/bb_regex.h b/android/regex/bb_regex.h
new file mode 100644
index 0000000..27a08ba
--- a/dev/null
+++ b/android/regex/bb_regex.h
@@ -0,0 +1,516 @@
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
+
+ Copyright (C) 1985, 89, 90, 91, 92, 93, 95 Free Software Foundation, Inc.
+
+ 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, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#if !defined (_POSIX_C_SOURCE) && !defined (_POSIX_SOURCE) && defined (VMS)
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+#include <stddef.h>
+#endif
+
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported. They are:
+ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+ If not set, then character classes are not supported. */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+ without further backtracking. */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* If this bit is set, do not process the GNU regex operators.
+ If not set, then the GNU regex operators are recognized. */
+#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
+
+/* If this bit is set, turn on internal regex debugging.
+ If not set, and debugging was on, turn it off.
+ This only works if regex.c is compiled -DDEBUG.
+ We define this bit always, so that all that's needed to turn on
+ debugging is to recompile regex.c; the calling code can always have
+ this bit set, and it won't affect anything in the normal case. */
+#define RE_DEBUG (RE_NO_GNU_OPS << 1)
+
+/* If this bit is set, a syntactically invalid interval is treated as
+ a string of ordinary characters. For example, the ERE 'a{1' is
+ treated as 'a\{1'. */
+#define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1)
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+#ifndef RE_TRANSLATE_TYPE
+#define RE_TRANSLATE_TYPE char *
+#endif
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ RE_TRANSLATE_TYPE translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+
+/* Declarations for routines. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t bb_re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *bb_re_compile_pattern
+ _RE_ARGS ((const char *pattern, int length,
+ struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int bb_re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int bb_re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int bb_re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int bb_re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int bb_re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, and must each be at least `NUM_REGS * sizeof
+ (regoff_t)' bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+extern void bb_re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+#ifdef _REGEX_RE_COMP
+/* 4.2 bsd compatibility. */
+extern char *bb_re_comp _RE_ARGS ((const char *));
+extern int bb_re_exec _RE_ARGS ((const char *));
+#endif
+
+/* POSIX compatibility. */
+extern int bb_regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int bb_regexec
+ _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags));
+extern size_t bb_regerror
+ _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size));
+extern void bb_regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/android/regex/cs_config.h b/android/regex/cs_config.h
new file mode 100644
index 0000000..7d14e2c
--- a/dev/null
+++ b/android/regex/cs_config.h
@@ -0,0 +1,239 @@
+/* cs_config.h. Generated by configure. */
+/* cs_config.h.in. Generated from configure.in by autoheader. */
+/*
+ * Copyright 2001-2004 Brandon Long
+ * All Rights Reserved.
+ *
+ * ClearSilver Templating System
+ *
+ * This code is made available under the terms of the ClearSilver License.
+ * http://www.clearsilver.net/license.hdf
+ *
+ */
+
+/*
+ * config file
+ */
+
+#ifndef __CS_CONFIG_H_
+#define __CS_CONFIG_H_ 1
+
+
+/* Enable support for HTML Compression (still must be enabled at run time) */
+#define HTML_COMPRESSION 1
+
+/* Enable support for X Remote CGI Debugging */
+/* #undef ENABLE_REMOTE_DEBUG */
+
+/********* SYSTEM CONFIG ***************************************************/
+/* autoconf/configure should figure all of these out for you */
+
+/* Does your system have the snprintf() call? */
+#define HAVE_SNPRINTF 1
+
+/* Does your system have the vsnprintf() call? */
+#define HAVE_VSNPRINTF 1
+
+/* Does your system have the strtok_r() call? */
+#define HAVE_STRTOK_R 1
+
+/* Does your system have the localtime_r() call? */
+#define HAVE_LOCALTIME_R 1
+
+/* Does your system have the gmtime_r() call? */
+#define HAVE_GMTIME_R 1
+
+/* Does your system have the mkstemp() call? */
+#define HAVE_MKSTEMP 1
+
+/* Does your system have regex.h */
+#define HAVE_REGEX 1
+
+/* Does your system have pthreads? */
+#undef HAVE_PTHREADS
+#define HAVE_PTHREADS 1
+
+/* Does your system have lockf ? */
+#define HAVE_LOCKF 1
+
+/* Does your system have Berkeley DB v2 ? */
+/* #undef HAVE_DB2 */
+
+/* Enable support for gettext message translation */
+/* #undef ENABLE_GETTEXT */
+
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if you have the `drand48' function. */
+#define HAVE_DRAND48 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#define HAVE_GMTIME_R 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the `localtime_r' function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mktime' function. */
+#define HAVE_MKTIME 1
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+/* #undef HAVE_NDIR_H */
+
+/* Define to 1 if you have the `putenv' function. */
+#define HAVE_PUTENV 1
+
+/* Define to 1 if you have the `rand' function. */
+#define HAVE_RAND 1
+
+/* Define to 1 if you have the `random' function. */
+#define HAVE_RANDOM 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strspn' function. */
+#define HAVE_STRSPN 1
+
+/* Define to 1 if you have the `strtod' function. */
+#define HAVE_STRTOD 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define to 1 if `tm_zone' is member of `struct tm'. */
+#define HAVE_STRUCT_TM_TM_ZONE 1
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use
+ `HAVE_STRUCT_TM_TM_ZONE' instead. */
+#ifndef __CYGWIN__
+#define HAVE_TM_ZONE 1
+#endif
+
+/* Define to 1 if you don't have `tm_zone' but do have the external array
+ `tzname'. */
+/* #undef HAVE_TZNAME */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <varargs.h> header file. */
+/* #undef HAVE_VARARGS_H */
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the `wait3' system call. Deprecated, you should no
+ longer depend upon `wait3'. */
+#define HAVE_WAIT3 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef mode_t */
+
+/* Define to `long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+#endif /* __CS_CONFIG_H_ */
diff --git a/android/selinux/android_selinux.h b/android/selinux/android_selinux.h
new file mode 100644
index 0000000..8a0cfb0
--- a/dev/null
+++ b/android/selinux/android_selinux.h
@@ -0,0 +1,150 @@
+#ifndef BB_ANDROID_SELINUX_H
+#define BB_ANDROID_SELINUX_H
+
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <selinux/android.h>
+
+/* Set the function used by matchpathcon_init when displaying
+ errors about the file_contexts configuration. If not set,
+ then this defaults to fprintf(stderr, fmt, ...). */
+extern void set_matchpathcon_printf(void (*f) (const char *fmt, ...));
+
+/* Set the function used by matchpathcon_init when checking the
+ validity of a context in the file contexts configuration. If not set,
+ then this defaults to a test based on security_check_context().
+ The function is also responsible for reporting any such error, and
+ may include the 'path' and 'lineno' in such error messages. */
+extern void set_matchpathcon_invalidcon(int (*f) (const char *path,
+ unsigned lineno,
+ char *context));
+
+/* Same as above, but also allows canonicalization of the context,
+ by changing *context to refer to the canonical form. If not set,
+ and invalidcon is also not set, then this defaults to calling
+ security_canonicalize_context(). */
+extern void set_matchpathcon_canoncon(int (*f) (const char *path,
+ unsigned lineno,
+ char **context));
+
+/* Set flags controlling operation of matchpathcon_init or matchpathcon. */
+#define MATCHPATHCON_BASEONLY 1 /* Only process the base file_contexts file. */
+#define MATCHPATHCON_NOTRANS 2 /* Do not perform any context translation. */
+#define MATCHPATHCON_VALIDATE 4 /* Validate/canonicalize contexts at init time. */
+extern void set_matchpathcon_flags(unsigned int flags);
+
+/* Load the file contexts configuration specified by 'path'
+ into memory for use by subsequent matchpathcon calls.
+ If 'path' is NULL, then load the active file contexts configuration,
+ i.e. the path returned by selinux_file_context_path().
+ Unless the MATCHPATHCON_BASEONLY flag has been set, this
+ function also checks for a 'path'.homedirs file and
+ a 'path'.local file and loads additional specifications
+ from them if present. */
+extern int matchpathcon_init(const char *path);
+
+/* Same as matchpathcon_init, but only load entries with
+ regexes that have stems that are prefixes of 'prefix'. */
+extern int matchpathcon_init_prefix(const char *path, const char *prefix);
+
+/* Free the memory allocated by matchpathcon_init. */
+extern void matchpathcon_fini(void);
+
+/* Resolve all of the symlinks and relative portions of a pathname, but NOT
+ * the final component (same a realpath() unless the final component is a
+ * symlink. Resolved path must be a path of size PATH_MAX + 1 */
+extern int realpath_not_final(const char *name, char *resolved_path);
+
+/* Match the specified pathname and mode against the file contexts
+ configuration and set *con to refer to the resulting context.
+ 'mode' can be 0 to disable mode matching.
+ Caller must free via freecon.
+ If matchpathcon_init has not already been called, then this function
+ will call it upon its first invocation with a NULL path. */
+extern int matchpathcon(const char *path,
+ mode_t mode, char ** con);
+
+/* Same as above, but return a specification index for
+ later use in a matchpathcon_filespec_add() call - see below. */
+extern int matchpathcon_index(const char *path,
+ mode_t mode, char ** con);
+
+/* Maintain an association between an inode and a specification index,
+ and check whether a conflicting specification is already associated
+ with the same inode (e.g. due to multiple hard links). If so, then
+ use the latter of the two specifications based on their order in the
+ file contexts configuration. Return the used specification index. */
+extern int matchpathcon_filespec_add(ino_t ino, int specind, const char *file);
+
+/* Destroy any inode associations that have been added, e.g. to restart
+ for a new filesystem. */
+extern void matchpathcon_filespec_destroy(void);
+
+/* Display statistics on the hash table usage for the associations. */
+extern void matchpathcon_filespec_eval(void);
+
+/* Check to see whether any specifications had no matches and report them.
+ The 'str' is used as a prefix for any warning messages. */
+extern void matchpathcon_checkmatches(char *str);
+
+/*
+ * Verify the context of the file 'path' against policy.
+ * Return 1 if match, 0 if not and -1 on error.
+ */
+extern int selinux_file_context_verify(const char *path, mode_t mode);
+
+/* Get the default security context for a user session for 'user'
+ spawned by 'fromcon' and set *newcon to refer to it. The context
+ will be one of those authorized by the policy, but the selection
+ of a default is subject to user customizable preferences.
+ If 'fromcon' is NULL, defaults to current context.
+ Returns 0 on success or -1 otherwise.
+ Caller must free via freecon. */
+extern int get_default_context(const char* user, const char* fromcon,
+ char ** newcon);
+
+/* Check a permission in the passwd class.
+ Return 0 if granted or -1 otherwise. */
+#define PASSWD__PASSWD 0x001UL
+#define PASSWD__CHFN 0x002UL
+#define PASSWD__CHSH 0x004UL
+#define PASSWD__ROOTOK 0x008UL
+#define PASSWD__CRONTAB 0x010UL
+extern int selinux_check_passwd_access(access_vector_t requested);
+
+#define lgetfilecon_raw(path, context) \
+ lgetfilecon(path, context)
+
+#define lsetfilecon_raw(path, scontext) \
+ lsetfilecon(path, scontext)
+
+#define selabel_lookup_raw(hnd, con, path, mode) \
+ selabel_lookup(hnd, con, path, mode)
+
+#define security_canonicalize_context_raw(context, newctx) \
+ security_canonicalize_context(context, newctx)
+
+#define getprevcon_raw(context) \
+ getprevcon(context)
+
+#define is_context_customizable(ctx) false
+
+#define selinux_log(type, ...) bb_error_msg(__VA_ARGS__)
+
+#define selinux_policy_root() "/sepolicy"
+
+static int selinux_getenforcemode(int *rc)
+{
+ if (rc) {
+ *rc = security_getenforce();
+ return 0;
+ }
+ return -1;
+}
+
+static const char *selinux_file_contexts_path()
+{
+ return "/file_contexts";
+}
+
+#endif /* BB_ANDROID_SELINUX_H */
diff --git a/android/selinux/android_selinux_internal.h b/android/selinux/android_selinux_internal.h
new file mode 100644
index 0000000..dd7b771
--- a/dev/null
+++ b/android/selinux/android_selinux_internal.h
@@ -0,0 +1,248 @@
+/*
+ * selinux_internal.h and label_internal.h definitions (libselinux)
+ *
+ */
+#ifndef _SELINUX_BB_INTERNAL_H
+#define _SELINUX_BB_INTERNAL_H 1
+
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <pthread.h>
+
+#ifdef SHARED
+# define hidden __attribute__ ((visibility ("hidden")))
+# define hidden_proto(fct) __hidden_proto (fct, fct##_internal)
+# define __hidden_proto(fct, internal) \
+ extern __typeof (fct) internal; \
+ extern __typeof (fct) fct __asm (#internal) hidden;
+# if defined(__alpha__) || defined(__mips__)
+# define hidden_def(fct) \
+ asm (".globl " #fct "\n" #fct " = " #fct "_internal");
+# else
+# define hidden_def(fct) \
+ asm (".globl " #fct "\n.set " #fct ", " #fct "_internal");
+#endif
+#else
+# define hidden
+# define hidden_proto(fct)
+# define hidden_def(fct)
+#endif
+
+hidden_proto(selinux_mkload_policy)
+ hidden_proto(fini_selinuxmnt)
+ hidden_proto(set_selinuxmnt)
+ hidden_proto(selinuxfs_exists)
+ hidden_proto(security_disable)
+ hidden_proto(security_policyvers)
+ hidden_proto(security_load_policy)
+ hidden_proto(security_get_boolean_active)
+ hidden_proto(security_get_boolean_names)
+ hidden_proto(security_set_boolean)
+ hidden_proto(security_commit_booleans)
+ hidden_proto(security_check_context)
+ hidden_proto(security_check_context_raw)
+ hidden_proto(security_canonicalize_context)
+ hidden_proto(security_canonicalize_context_raw)
+ hidden_proto(security_compute_av)
+ hidden_proto(security_compute_av_raw)
+ hidden_proto(security_compute_av_flags)
+ hidden_proto(security_compute_av_flags_raw)
+ hidden_proto(security_compute_user)
+ hidden_proto(security_compute_user_raw)
+ hidden_proto(security_compute_create)
+ hidden_proto(security_compute_create_raw)
+ hidden_proto(security_compute_create_name)
+ hidden_proto(security_compute_create_name_raw)
+ hidden_proto(security_compute_member_raw)
+ hidden_proto(security_compute_relabel_raw)
+ hidden_proto(is_selinux_enabled)
+ hidden_proto(is_selinux_mls_enabled)
+ hidden_proto(freecon)
+ hidden_proto(freeconary)
+ hidden_proto(getprevcon)
+ hidden_proto(getprevcon_raw)
+ hidden_proto(getcon)
+ hidden_proto(getcon_raw)
+ hidden_proto(setcon_raw)
+ hidden_proto(getpeercon_raw)
+ hidden_proto(getpidcon_raw)
+ hidden_proto(getexeccon_raw)
+ hidden_proto(getfilecon)
+ hidden_proto(getfilecon_raw)
+ hidden_proto(lgetfilecon_raw)
+ hidden_proto(fgetfilecon_raw)
+ hidden_proto(setfilecon_raw)
+ hidden_proto(lsetfilecon_raw)
+ hidden_proto(fsetfilecon_raw)
+ hidden_proto(setexeccon)
+ hidden_proto(setexeccon_raw)
+ hidden_proto(getfscreatecon_raw)
+ hidden_proto(getkeycreatecon_raw)
+ hidden_proto(getsockcreatecon_raw)
+ hidden_proto(setfscreatecon_raw)
+ hidden_proto(setkeycreatecon_raw)
+ hidden_proto(setsockcreatecon_raw)
+ hidden_proto(security_getenforce)
+ hidden_proto(security_setenforce)
+ hidden_proto(security_deny_unknown)
+ hidden_proto(selinux_boolean_sub)
+ hidden_proto(selinux_binary_policy_path)
+ hidden_proto(selinux_booleans_subs_path)
+ hidden_proto(selinux_default_context_path)
+ hidden_proto(selinux_securetty_types_path)
+ hidden_proto(selinux_failsafe_context_path)
+ hidden_proto(selinux_removable_context_path)
+ hidden_proto(selinux_virtual_domain_context_path)
+ hidden_proto(selinux_virtual_image_context_path)
+ hidden_proto(selinux_lxc_contexts_path)
+ hidden_proto(selinux_file_context_path)
+ hidden_proto(selinux_file_context_homedir_path)
+ hidden_proto(selinux_file_context_local_path)
+ hidden_proto(selinux_file_context_subs_dist_path)
+ hidden_proto(selinux_file_context_subs_path)
+ hidden_proto(selinux_netfilter_context_path)
+ hidden_proto(selinux_homedir_context_path)
+ hidden_proto(selinux_user_contexts_path)
+ hidden_proto(selinux_booleans_path)
+ hidden_proto(selinux_customizable_types_path)
+ hidden_proto(selinux_media_context_path)
+ hidden_proto(selinux_x_context_path)
+ hidden_proto(selinux_sepgsql_context_path)
+ hidden_proto(selinux_path)
+ hidden_proto(selinux_check_passwd_access)
+ hidden_proto(selinux_check_securetty_context)
+ hidden_proto(matchpathcon_init_prefix)
+ hidden_proto(selinux_users_path)
+ hidden_proto(selinux_usersconf_path);
+hidden_proto(selinux_translations_path);
+hidden_proto(selinux_colors_path);
+hidden_proto(selinux_getenforcemode);
+hidden_proto(selinux_getpolicytype);
+hidden_proto(selinux_raw_to_trans_context);
+hidden_proto(selinux_trans_to_raw_context);
+ hidden_proto(selinux_raw_context_to_color);
+hidden_proto(security_get_initial_context);
+hidden_proto(security_get_initial_context_raw);
+hidden_proto(selinux_reset_config);
+
+extern int load_setlocaldefs hidden;
+extern int require_seusers hidden;
+extern int selinux_page_size hidden;
+
+/* Make pthread_once optional */
+#pragma weak pthread_once
+#pragma weak pthread_key_create
+#pragma weak pthread_key_delete
+#pragma weak pthread_setspecific
+
+/* Call handler iff the first call. */
+#define __selinux_once(ONCE_CONTROL, INIT_FUNCTION) \
+ do { \
+ if (pthread_once != NULL) \
+ pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION)); \
+ else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) { \
+ INIT_FUNCTION (); \
+ (ONCE_CONTROL) = 2; \
+ } \
+ } while (0)
+
+/* Pthread key macros */
+#define __selinux_key_create(KEY, DESTRUCTOR) \
+ (pthread_key_create != NULL ? pthread_key_create(KEY, DESTRUCTOR) : -1)
+
+#define __selinux_key_delete(KEY) \
+ do { \
+ if (pthread_key_delete != NULL) \
+ pthread_key_delete(KEY); \
+ } while (0)
+
+#define __selinux_setspecific(KEY, VALUE) \
+ do { \
+ if (pthread_setspecific != NULL) \
+ pthread_setspecific(KEY, VALUE); \
+ } while (0)
+
+
+/*
+ * Installed backends
+ */
+int selabel_file_init(struct selabel_handle *rec, struct selinux_opt *opts,
+ unsigned nopts) hidden;
+int selabel_media_init(struct selabel_handle *rec, struct selinux_opt *opts,
+ unsigned nopts) hidden;
+int selabel_x_init(struct selabel_handle *rec, struct selinux_opt *opts,
+ unsigned nopts) hidden;
+int selabel_db_init(struct selabel_handle *rec,
+ struct selinux_opt *opts, unsigned nopts) hidden;
+int selabel_property_init(struct selabel_handle *rec,
+ struct selinux_opt *opts, unsigned nopts) hidden;
+
+/*
+ * Labeling internal structures
+ */
+struct selabel_sub {
+ char *src;
+ int slen;
+ char *dst;
+ struct selabel_sub *next;
+};
+
+extern struct selabel_sub *selabel_subs_init(const char *path,
+ struct selabel_sub *list);
+
+struct selabel_lookup_rec {
+ security_context_t ctx_raw;
+ security_context_t ctx_trans;
+ int validated;
+};
+
+struct selabel_handle {
+ /* arguments that were passed to selabel_open */
+ unsigned int backend;
+ int validating;
+
+ /* labeling operations */
+ struct selabel_lookup_rec *(*func_lookup) (struct selabel_handle *h,
+ const char *key, int type);
+ void (*func_close) (struct selabel_handle *h);
+ void (*func_stats) (struct selabel_handle *h);
+
+ /* supports backend-specific state information */
+ void *data;
+#if 0
+ /*
+ * The main spec file used. Note for file contexts the local and/or
+ * homedirs could also have been used to resolve a context.
+ */
+ char *spec_file;
+#endif
+ /* substitution support */
+ struct selabel_sub *subs;
+};
+
+/*
+ * Validation function
+ */
+extern int
+selabel_validate(struct selabel_handle *rec,
+ struct selabel_lookup_rec *contexts) hidden;
+
+/*
+ * Compatibility support
+ */
+extern int myprintf_compat;
+extern void __attribute__ ((format(printf, 1, 2)))
+(*myprintf) (const char *fmt,...);
+
+#define COMPAT_LOG(type, fmt...) if (myprintf_compat) \
+ myprintf(fmt); \
+ else \
+ selinux_log(type, fmt);
+
+extern int
+compat_validate(struct selabel_handle *rec,
+ struct selabel_lookup_rec *contexts,
+ const char *path, unsigned lineno) hidden;
+
+
+#endif // _SELINUX_BB_INTERNAL_H
diff --git a/android/selinux/matchpathcon.c b/android/selinux/matchpathcon.c
new file mode 100644
index 0000000..074c029
--- a/dev/null
+++ b/android/selinux/matchpathcon.c
@@ -0,0 +1,564 @@
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <selinux/android.h>
+
+#include "android_selinux.h"
+#include "android_selinux_internal.h"
+
+#include <libbb.h>
+
+static __thread struct selabel_handle *hnd = NULL;
+
+/*
+ * An array for mapping integers to contexts
+ */
+static __thread char **con_array;
+static __thread int con_array_size;
+static __thread int con_array_used;
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+static pthread_key_t destructor_key;
+static int destructor_key_initialized = 0;
+
+static int add_array_elt(char *con)
+{
+ if (con_array_size) {
+ while (con_array_used >= con_array_size) {
+ con_array_size *= 2;
+ con_array = (char **)realloc(con_array, sizeof(char*) *
+ con_array_size);
+ if (!con_array) {
+ con_array_size = con_array_used = 0;
+ return -1;
+ }
+ }
+ } else {
+ con_array_size = 1000;
+ con_array = (char **)malloc(sizeof(char*) * con_array_size);
+ if (!con_array) {
+ con_array_size = con_array_used = 0;
+ return -1;
+ }
+ }
+
+ con_array[con_array_used] = strdup(con);
+ if (!con_array[con_array_used])
+ return -1;
+ return con_array_used++;
+}
+
+static void free_array_elts(void)
+{
+ con_array_size = con_array_used = 0;
+ free(con_array);
+ con_array = NULL;
+}
+
+static void
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ default_printf(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+void
+#ifdef __GNUC__
+ __attribute__ ((format(printf, 1, 2)))
+#endif
+ (*myprintf) (const char *fmt,...) = &default_printf;
+int myprintf_compat = 0;
+
+void set_matchpathcon_printf(void (*f) (const char *fmt, ...))
+{
+ myprintf = f ? f : &default_printf;
+ myprintf_compat = 1;
+}
+
+static int (*myinvalidcon) (const char *p, unsigned l, char *c) = NULL;
+
+void set_matchpathcon_invalidcon(int (*f) (const char *p, unsigned l, char *c))
+{
+ myinvalidcon = f;
+}
+
+static int default_canoncon(const char *path, unsigned lineno, char **context)
+{
+ char *tmpcon;
+ if (security_canonicalize_context_raw(*context, &tmpcon) < 0) {
+ if (errno == ENOENT)
+ return 0;
+ if (lineno)
+ myprintf("%s: line %u has invalid context %s\n", path,
+ lineno, *context);
+ else
+ myprintf("%s: invalid context %s\n", path, *context);
+ return 1;
+ }
+ free(*context);
+ *context = tmpcon;
+ return 0;
+}
+
+static int (*mycanoncon) (const char *p, unsigned l, char **c) =
+ NULL;
+
+void set_matchpathcon_canoncon(int (*f) (const char *p, unsigned l, char **c))
+{
+ if (f)
+ mycanoncon = f;
+ else
+ mycanoncon = &default_canoncon;
+}
+
+static __thread struct selinux_opt options[SELABEL_NOPT];
+static __thread int notrans;
+
+void set_matchpathcon_flags(unsigned int flags)
+{
+ int i;
+ memset(options, 0, sizeof(options));
+ i = SELABEL_OPT_BASEONLY;
+ options[i].type = i;
+ options[i].value = (flags & MATCHPATHCON_BASEONLY) ? (char*)1 : NULL;
+ i = SELABEL_OPT_VALIDATE;
+ options[i].type = i;
+ options[i].value = (flags & MATCHPATHCON_VALIDATE) ? (char*)1 : NULL;
+ notrans = flags & MATCHPATHCON_NOTRANS;
+}
+
+/*
+ * An association between an inode and a
+ * specification.
+ */
+typedef struct file_spec {
+ ino_t ino; /* inode number */
+ int specind; /* index of specification in spec */
+ char *file; /* full pathname for diagnostic messages about conflicts */
+ struct file_spec *next; /* next association in hash bucket chain */
+} file_spec_t;
+
+/*
+ * The hash table of associations, hashed by inode number.
+ * Chaining is used for collisions, with elements ordered
+ * by inode number in each bucket. Each hash bucket has a dummy
+ * header.
+ */
+#define HASH_BITS 16
+#define HASH_BUCKETS (1 << HASH_BITS)
+#define HASH_MASK (HASH_BUCKETS-1)
+static file_spec_t *fl_head;
+
+/*
+ * Try to add an association between an inode and
+ * a specification. If there is already an association
+ * for the inode and it conflicts with this specification,
+ * then use the specification that occurs later in the
+ * specification array.
+ */
+int matchpathcon_filespec_add(ino_t ino, int specind, const char *file)
+{
+ file_spec_t *prevfl, *fl;
+ int h, ret;
+ struct stat sb;
+
+ if (!fl_head) {
+ fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS);
+ if (!fl_head)
+ goto oom;
+ memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS);
+ }
+
+ h = (ino + (ino >> HASH_BITS)) & HASH_MASK;
+ for (prevfl = &fl_head[h], fl = fl_head[h].next; fl;
+ prevfl = fl, fl = fl->next) {
+ if (ino == fl->ino) {
+ ret = lstat(fl->file, &sb);
+ if (ret < 0 || sb.st_ino != ino) {
+ fl->specind = specind;
+ free(fl->file);
+ fl->file = malloc(strlen(file) + 1);
+ if (!fl->file)
+ goto oom;
+ strcpy(fl->file, file);
+ return fl->specind;
+
+ }
+
+ if (!strcmp(con_array[fl->specind],
+ con_array[specind]))
+ return fl->specind;
+
+ myprintf
+ ("%s: conflicting specifications for %s and %s, using %s.\n",
+ __FUNCTION__, file, fl->file,
+ con_array[fl->specind]);
+ free(fl->file);
+ fl->file = malloc(strlen(file) + 1);
+ if (!fl->file)
+ goto oom;
+ strcpy(fl->file, file);
+ return fl->specind;
+ }
+
+ if (ino > fl->ino)
+ break;
+ }
+
+ fl = malloc(sizeof(file_spec_t));
+ if (!fl)
+ goto oom;
+ fl->ino = ino;
+ fl->specind = specind;
+ fl->file = malloc(strlen(file) + 1);
+ if (!fl->file)
+ goto oom_freefl;
+ strcpy(fl->file, file);
+ fl->next = prevfl->next;
+ prevfl->next = fl;
+ return fl->specind;
+ oom_freefl:
+ free(fl);
+ oom:
+ myprintf("%s: insufficient memory for file label entry for %s\n",
+ __FUNCTION__, file);
+ return -1;
+}
+
+/*
+ * Evaluate the association hash table distribution.
+ */
+void matchpathcon_filespec_eval(void)
+{
+ file_spec_t *fl;
+ int h, used, nel, len, longest;
+
+ if (!fl_head)
+ return;
+
+ used = 0;
+ longest = 0;
+ nel = 0;
+ for (h = 0; h < HASH_BUCKETS; h++) {
+ len = 0;
+ for (fl = fl_head[h].next; fl; fl = fl->next) {
+ len++;
+ }
+ if (len)
+ used++;
+ if (len > longest)
+ longest = len;
+ nel += len;
+ }
+
+ myprintf
+ ("%s: hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n",
+ __FUNCTION__, nel, used, HASH_BUCKETS, longest);
+}
+
+/*
+ * Destroy the association hash table.
+ */
+void matchpathcon_filespec_destroy(void)
+{
+ file_spec_t *fl, *tmp;
+ int h;
+
+ free_array_elts();
+
+ if (!fl_head)
+ return;
+
+ for (h = 0; h < HASH_BUCKETS; h++) {
+ fl = fl_head[h].next;
+ while (fl) {
+ tmp = fl;
+ fl = fl->next;
+ free(tmp->file);
+ free(tmp);
+ }
+ fl_head[h].next = NULL;
+ }
+ free(fl_head);
+ fl_head = NULL;
+}
+
+static void matchpathcon_thread_destructor(void __attribute__((unused)) *ptr)
+{
+ matchpathcon_fini();
+}
+
+void __attribute__((destructor)) matchpathcon_lib_destructor(void);
+
+void hidden __attribute__((destructor)) matchpathcon_lib_destructor(void)
+{
+ if (destructor_key_initialized)
+ __selinux_key_delete(destructor_key);
+}
+
+static void matchpathcon_init_once(void)
+{
+ if (__selinux_key_create(&destructor_key, matchpathcon_thread_destructor) == 0)
+ destructor_key_initialized = 1;
+}
+
+int matchpathcon_init_prefix(const char *path, const char *subset)
+{
+ if (!mycanoncon)
+ mycanoncon = default_canoncon;
+
+ __selinux_once(once, matchpathcon_init_once);
+ __selinux_setspecific(destructor_key, (void *)1);
+
+ options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET;
+ options[SELABEL_OPT_SUBSET].value = subset;
+ options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH;
+ options[SELABEL_OPT_PATH].value = path;
+
+ hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT);
+
+ return hnd ? 0 : -1;
+}
+
+hidden_def(matchpathcon_init_prefix)
+
+int matchpathcon_init(const char *path)
+{
+ return matchpathcon_init_prefix(path, NULL);
+}
+
+void matchpathcon_fini(void)
+{
+ free_array_elts();
+
+ if (hnd) {
+ selabel_close(hnd);
+ hnd = NULL;
+ }
+}
+
+/*
+ * We do not want to resolve a symlink to a real path if it is the final
+ * component of the name. Thus we split the pathname on the last "/" and
+ * determine a real path component of the first portion. We then have to
+ * copy the last part back on to get the final real path. Wheww.
+ */
+int realpath_not_final(const char *name, char *resolved_path)
+{
+ char *last_component;
+ char *tmp_path, *p;
+ size_t len = 0;
+ int rc = 0;
+
+ tmp_path = strdup(name);
+ if (!tmp_path) {
+ myprintf("symlink_realpath(%s) strdup() failed: %s\n",
+ name, strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ /* strip leading // */
+ while (tmp_path[len] && tmp_path[len] == '/' &&
+ tmp_path[len+1] && tmp_path[len+1] == '/') {
+ tmp_path++;
+ len++;
+ }
+ last_component = strrchr(tmp_path, '/');
+
+ if (last_component == tmp_path) {
+ last_component++;
+ p = strcpy(resolved_path, "");
+ } else if (last_component) {
+ *last_component = '\0';
+ last_component++;
+ p = realpath(tmp_path, resolved_path);
+ } else {
+ last_component = tmp_path;
+ p = realpath("./", resolved_path);
+ }
+
+ if (!p) {
+ myprintf("symlink_realpath(%s) realpath() failed: %s\n",
+ name, strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ len = strlen(p);
+ if (len + strlen(last_component) + 2 > PATH_MAX) {
+ myprintf("symlink_realpath(%s) failed: Filename too long \n",
+ name);
+ errno=ENAMETOOLONG;
+ rc = -1;
+ goto out;
+ }
+
+ resolved_path += len;
+ strcpy(resolved_path, "/");
+ resolved_path += 1;
+ strcpy(resolved_path, last_component);
+out:
+ free(tmp_path);
+ return rc;
+}
+
+int matchpathcon(const char *path, mode_t mode, char ** con)
+{
+ char stackpath[PATH_MAX + 1];
+ char *p = NULL;
+ int ret;
+
+ if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0))
+ return -1;
+
+ if (S_ISLNK(mode)) {
+ if (!realpath_not_final(path, stackpath))
+ path = stackpath;
+ } else {
+ p = realpath(path, stackpath);
+ if (p)
+ path = p;
+ }
+
+ ret = notrans ?
+ selabel_lookup_raw(hnd, con, path, mode) :
+ selabel_lookup(hnd, con, path, mode);
+
+ return ret;
+}
+
+int matchpathcon_index(const char *name, mode_t mode, char ** con)
+{
+ int i = matchpathcon(name, mode, con);
+
+ if (i < 0)
+ return -1;
+
+ return add_array_elt(*con);
+}
+
+void matchpathcon_checkmatches(char *str __attribute__((unused)))
+{
+ selabel_stats(hnd);
+}
+
+/* Compare two contexts to see if their differences are "significant",
+ * or whether the only difference is in the user. */
+int selinux_file_context_cmp(const char * a,
+ const char * b)
+{
+ char *rest_a, *rest_b; /* Rest of the context after the user */
+ if (!a && !b)
+ return 0;
+ if (!a)
+ return -1;
+ if (!b)
+ return 1;
+ rest_a = strchr((char *)a, ':');
+ rest_b = strchr((char *)b, ':');
+ if (!rest_a && !rest_b)
+ return 0;
+ if (!rest_a)
+ return -1;
+ if (!rest_b)
+ return 1;
+ return strcmp(rest_a, rest_b);
+}
+
+int selinux_file_context_verify(const char *path, mode_t mode)
+{
+ char * con = NULL;
+ char * fcontext = NULL;
+ int rc = 0;
+
+ rc = lgetfilecon_raw(path, &con);
+ if (rc == -1) {
+ if (errno != ENOTSUP)
+ return -1;
+ else
+ return 0;
+ }
+
+ if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0))
+ return -1;
+
+ if (selabel_lookup_raw(hnd, &fcontext, path, mode) != 0) {
+ if (errno != ENOENT)
+ rc = -1;
+ else
+ rc = 0;
+ } else {
+ /*
+ * Need to set errno to 0 as it can be set to ENOENT if the
+ * file_contexts.subs file does not exist (see selabel_open in
+ * label.c), thus causing confusion if errno is checked on return.
+ */
+ errno = 0;
+ rc = (selinux_file_context_cmp(fcontext, con) == 0);
+ }
+
+ freecon(con);
+ freecon(fcontext);
+ return rc;
+}
+
+int selinux_lsetfilecon_default(const char *path)
+{
+ struct stat st;
+ int rc = -1;
+ char * scontext = NULL;
+ if (lstat(path, &st) != 0)
+ return rc;
+
+ if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0))
+ return -1;
+
+ /* If there's an error determining the context, or it has none,
+ return to allow default context */
+ if (selabel_lookup_raw(hnd, &scontext, path, st.st_mode)) {
+ if (errno == ENOENT)
+ rc = 0;
+ } else {
+ rc = lsetfilecon_raw(path, scontext);
+ freecon(scontext);
+ }
+ return rc;
+}
+
+int compat_validate(struct selabel_handle *rec,
+ struct selabel_lookup_rec *contexts,
+ const char *path, unsigned lineno)
+{
+ int rc;
+ char **ctx = &contexts->ctx_raw;
+
+ if (myinvalidcon)
+ rc = myinvalidcon(path, lineno, *ctx);
+ else if (mycanoncon)
+ rc = mycanoncon(path, lineno, ctx);
+ else {
+ rc = selabel_validate(rec, contexts);
+ if (rc < 0) {
+ if (lineno) {
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: line %d has invalid context %s\n",
+ path, lineno, *ctx);
+ } else {
+ COMPAT_LOG(SELINUX_WARNING,
+ "%s: has invalid context %s\n", path, *ctx);
+ }
+ }
+ }
+
+ return rc ? -1 : 0;
+}
diff --git a/android/selinux/stubs.c b/android/selinux/stubs.c
new file mode 100644
index 0000000..c01bc57
--- a/dev/null
+++ b/android/selinux/stubs.c
@@ -0,0 +1,39 @@
+#include <libbb.h>
+#include <selinux/selinux.h>
+
+/* create a new context with user name (may be unsafe) */
+int get_default_context(const char* user,
+ const char* fromcon UNUSED_PARAM,
+ char ** newcon)
+{
+ char fmt[] = "u:r:%s:s0\0";
+ int len = strlen(user) + strlen(fmt);
+
+ *newcon = malloc(len);
+ if (!(*newcon))
+ return -1;
+ snprintf(*newcon, len, fmt, user);
+ return 0;
+}
+
+/* Compute a relabeling decision and set *newcon to refer to it.
+ Caller must free via freecon.
+ Stub not implemented in bionic, but declared in selinux.h */
+int security_compute_relabel(const char *scon UNUSED_PARAM,
+ const char *tcon,
+ security_class_t tclass UNUSED_PARAM,
+ char ** newcon)
+{
+ if (tcon)
+ *newcon = strdup(tcon);
+ if (!(*newcon))
+ return -1;
+ return 0;
+}
+
+/* Check a permission in the passwd class.
+ Return 0 if granted or -1 otherwise. */
+int selinux_check_passwd_access(access_vector_t requested UNUSED_PARAM)
+{
+ return 0;
+}
diff --git a/applets/applets.c b/applets/applets.c
index 98c2b44..c458a71 100644
--- a/applets/applets.c
+++ b/applets/applets.c
@@ -6,9 +6,8 @@
*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
-#include "busybox.h"
-
#if ENABLE_BUILD_LIBBUSYBOX
+#include "busybox.h"
int main(int argc UNUSED_PARAM, char **argv)
{
return lbb_main(argv);
diff --git a/applets/usage_pod.c b/applets/usage_pod.c
index ccc166a..9e6d3f0 100644
--- a/applets/usage_pod.c
+++ b/applets/usage_pod.c
@@ -71,7 +71,7 @@ int main(void)
} else {
printf(", ");
}
- printf(usage_array[i].aname);
+ printf("%s", usage_array[i].aname);
col += len2;
}
printf("\n\n");
diff --git a/archival/cpio.c b/archival/cpio.c
index 540218c..be98b42 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -508,7 +508,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
continue;
- if (archive_handle->cpio__blocks != (off_t)-1
+ if ((off_t)archive_handle->cpio__blocks != (off_t)-1
&& !(opt & OPT_QUIET)
) {
fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
diff --git a/archival/gzip.c b/archival/gzip.c
index 9e0bee8..1f0b70f 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -98,6 +98,7 @@ aa: 85.1% -- replaced with aa.gz
#include "libbb.h"
#include "bb_archive.h"
+#include <strings.h>
/* ===========================================================================
diff --git a/archival/libarchive/bz/blocksort.c b/archival/libarchive/bz/blocksort.c
index e600cb7..d329f44 100644
--- a/archival/libarchive/bz/blocksort.c
+++ b/archival/libarchive/bz/blocksort.c
@@ -828,7 +828,7 @@ void mainSort(EState* state,
int32_t vv;
/* bbox: was: int32_t h = 1; */
/* do h = 3 * h + 1; while (h <= 256); */
- uint32_t h = 364;
+ int32_t h = 364;
do {
/*h = h / 3;*/
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index bd034af..5d8e57a 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -20,6 +20,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
#if ENABLE_FEATURE_TAR_SELINUX
char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
+#ifdef __BIONIC__
+ matchpathcon_init(NULL);
+#endif
if (!sctx)
sctx = archive_handle->tar__sctx[PAX_GLOBAL];
if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
@@ -107,7 +110,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
bb_perror_msg_and_die("can't stat old file");
}
}
- else if (existing_sb.st_mtime >= file_header->mtime) {
+ else if ((time_t) existing_sb.st_mtime >= (time_t) file_header->mtime) {
if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
&& !S_ISDIR(file_header->mode)
) {
diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c
index 5d87693..3b7d1ea 100644
--- a/archival/libarchive/data_extract_to_command.c
+++ b/archival/libarchive/data_extract_to_command.c
@@ -38,7 +38,7 @@ static const char *const tar_var[] = {
static void xputenv(char *str)
{
if (putenv(str))
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
}
static void str2env(char *env[], int idx, const char *str)
@@ -63,7 +63,7 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
{
file_header_t *file_header = archive_handle->file_header;
-#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */
+#if ENABLE_FEATURE_TAR_SELINUX
char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
if (!sctx)
sctx = archive_handle->tar__sctx[PAX_GLOBAL];
diff --git a/archival/libarchive/decompress_gunzip.c b/archival/libarchive/decompress_gunzip.c
index c7fa5b5..b1d4989 100644
--- a/archival/libarchive/decompress_gunzip.c
+++ b/archival/libarchive/decompress_gunzip.c
@@ -256,7 +256,7 @@ static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current
while (*current < required) {
if (bytebuffer_offset >= bytebuffer_size) {
unsigned sz = bytebuffer_max - 4;
- if (to_read >= 0 && to_read < sz) /* unzip only */
+ if (to_read >= 0 && (unsigned) to_read < sz) /* unzip only */
sz = to_read;
/* Leave the first 4 bytes empty so we can always unwind the bitbuffer
* to the front of the bytebuffer */
@@ -413,7 +413,7 @@ static int huft_build(const unsigned *b, const unsigned n,
f -= *xp; /* else deduct codes from patterns */
}
}
- j = (w + j > eob_len && w < eob_len) ? eob_len - w : j; /* make EOB code end at table */
+ j = ((unsigned) (w + j) > eob_len && w >= 0 && (unsigned) w < eob_len) ? eob_len - w : j; /* make EOB code end at table */
z = 1 << j; /* table entries for j-bit table */
ws[htl+1] = w + j; /* set bits decoded in stack */
@@ -1007,7 +1007,6 @@ inflate_unzip_internal(STATE_PARAM transformer_state_t *xstate)
error_msg = "corrupted data";
if (setjmp(error_jmp)) {
/* Error from deep inside zip machinery */
- bb_error_msg(error_msg);
n = -1;
goto ret;
}
diff --git a/archival/libarchive/unxz/xz_config.h b/archival/libarchive/unxz/xz_config.h
index 187e1cb..29f3d29 100644
--- a/archival/libarchive/unxz/xz_config.h
+++ b/archival/libarchive/unxz/xz_config.h
@@ -47,6 +47,10 @@
* NOTE: System headers on GNU/Linux may #define this macro already,
* so if you want to change it, you need to #undef it first.
*/
+#ifdef __BIONIC__
+#undef __always_inline
+#endif
+
#ifndef __always_inline
# ifdef __GNUC__
# define __always_inline \
diff --git a/busybox-full.config b/busybox-full.config
new file mode 100644
index 0000000..8668d6d
--- a/dev/null
+++ b/busybox-full.config
@@ -0,0 +1,1093 @@
+#
+# Automatically generated make config: don't edit
+# Busybox version: 1.26.2
+# Thu May 18 16:36:09 2017
+#
+CONFIG_HAVE_DOT_CONFIG=y
+
+#
+# Busybox Settings
+#
+CONFIG_DESKTOP=y
+# CONFIG_EXTRA_COMPAT is not set
+# CONFIG_INCLUDE_SUSv2 is not set
+# CONFIG_USE_PORTABLE_CODE is not set
+CONFIG_PLATFORM_LINUX=y
+CONFIG_SHOW_USAGE=y
+CONFIG_FEATURE_VERBOSE_USAGE=y
+CONFIG_FEATURE_COMPRESS_USAGE=y
+CONFIG_BUSYBOX=y
+CONFIG_FEATURE_INSTALLER=y
+CONFIG_INSTALL_NO_USR=y
+# CONFIG_PAM is not set
+CONFIG_LONG_OPTS=y
+CONFIG_FEATURE_DEVPTS=y
+# CONFIG_FEATURE_CLEAN_UP is not set
+# CONFIG_FEATURE_UTMP is not set
+# CONFIG_FEATURE_WTMP is not set
+# CONFIG_FEATURE_PIDFILE is not set
+CONFIG_PID_FILE_PATH=""
+CONFIG_FEATURE_SUID=y
+# CONFIG_FEATURE_SUID_CONFIG is not set
+# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
+CONFIG_SELINUX=y
+# CONFIG_FEATURE_PREFER_APPLETS is not set
+CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe"
+CONFIG_FEATURE_SYSLOG=y
+CONFIG_FEATURE_HAVE_RPC=y
+
+#
+# Build Options
+#
+# CONFIG_STATIC is not set
+# CONFIG_PIE is not set
+# CONFIG_NOMMU is not set
+# CONFIG_BUILD_LIBBUSYBOX is not set
+# CONFIG_FEATURE_INDIVIDUAL is not set
+# CONFIG_FEATURE_SHARED_BUSYBOX is not set
+# CONFIG_LFS is not set
+CONFIG_CROSS_COMPILER_PREFIX=""
+CONFIG_SYSROOT=""
+CONFIG_EXTRA_CFLAGS="-Os -fno-short-enums -fgcse-after-reload -frerun-cse-after-loop -frename-registers"
+CONFIG_EXTRA_LDFLAGS=""
+CONFIG_EXTRA_LDLIBS=""
+
+#
+# Installation Options ("make install" behavior)
+#
+CONFIG_INSTALL_APPLET_SYMLINKS=y
+# CONFIG_INSTALL_APPLET_HARDLINKS is not set
+# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
+# CONFIG_INSTALL_APPLET_DONT is not set
+# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
+# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
+# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
+CONFIG_PREFIX="./_install"
+
+#
+# Debugging Options
+#
+# CONFIG_DEBUG is not set
+# CONFIG_DEBUG_PESSIMIZE is not set
+# CONFIG_DEBUG_SANITIZE is not set
+# CONFIG_UNIT_TEST is not set
+# CONFIG_WERROR is not set
+CONFIG_NO_DEBUG_LIB=y
+# CONFIG_DMALLOC is not set
+# CONFIG_EFENCE is not set
+
+#
+# Busybox Library Tuning
+#
+# CONFIG_FEATURE_USE_BSS_TAIL is not set
+CONFIG_FEATURE_RTMINMAX=y
+CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
+# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
+CONFIG_PASSWORD_MINLEN=6
+CONFIG_MD5_SMALL=1
+CONFIG_SHA3_SMALL=1
+# CONFIG_FEATURE_FAST_TOP is not set
+# CONFIG_FEATURE_ETC_NETWORKS is not set
+CONFIG_FEATURE_USE_TERMIOS=y
+CONFIG_FEATURE_EDITING=y
+CONFIG_FEATURE_EDITING_MAX_LEN=1024
+# CONFIG_FEATURE_EDITING_VI is not set
+CONFIG_FEATURE_EDITING_HISTORY=256
+CONFIG_FEATURE_EDITING_SAVEHISTORY=y
+# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
+CONFIG_FEATURE_REVERSE_SEARCH=y
+CONFIG_FEATURE_TAB_COMPLETION=y
+CONFIG_FEATURE_USERNAME_COMPLETION=y
+CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
+# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
+# CONFIG_LOCALE_SUPPORT is not set
+CONFIG_UNICODE_SUPPORT=y
+# CONFIG_UNICODE_USING_LOCALE is not set
+# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
+CONFIG_SUBST_WCHAR=63
+CONFIG_LAST_SUPPORTED_WCHAR=767
+# CONFIG_UNICODE_COMBINING_WCHARS is not set
+# CONFIG_UNICODE_WIDE_WCHARS is not set
+# CONFIG_UNICODE_BIDI_SUPPORT is not set
+# CONFIG_UNICODE_NEUTRAL_TABLE is not set
+# CONFIG_UNICODE_PRESERVE_BROKEN is not set
+CONFIG_FEATURE_NON_POSIX_CP=y
+# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
+CONFIG_FEATURE_USE_SENDFILE=y
+CONFIG_FEATURE_COPYBUF_KB=4
+CONFIG_FEATURE_SKIP_ROOTFS=y
+CONFIG_MONOTONIC_SYSCALL=y
+CONFIG_IOCTL_HEX2STR_ERROR=y
+CONFIG_FEATURE_HWIB=y
+
+#
+# Applets
+#
+
+#
+# Archival Utilities
+#
+CONFIG_FEATURE_SEAMLESS_XZ=y
+CONFIG_FEATURE_SEAMLESS_LZMA=y
+CONFIG_FEATURE_SEAMLESS_BZ2=y
+CONFIG_FEATURE_SEAMLESS_GZ=y
+# CONFIG_FEATURE_SEAMLESS_Z is not set
+# CONFIG_AR is not set
+# CONFIG_FEATURE_AR_LONG_FILENAMES is not set
+# CONFIG_FEATURE_AR_CREATE is not set
+CONFIG_UNCOMPRESS=y
+CONFIG_GUNZIP=y
+CONFIG_ZCAT=y
+CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y
+CONFIG_BUNZIP2=y
+CONFIG_BZCAT=y
+CONFIG_UNLZMA=y
+CONFIG_LZCAT=y
+CONFIG_LZMA=y
+CONFIG_FEATURE_LZMA_FAST=y
+CONFIG_UNXZ=y
+CONFIG_XZCAT=y
+CONFIG_XZ=y
+CONFIG_BZIP2=y
+CONFIG_CPIO=y
+CONFIG_FEATURE_CPIO_O=y
+CONFIG_FEATURE_CPIO_P=y
+# CONFIG_DPKG is not set
+# CONFIG_DPKG_DEB is not set
+CONFIG_GZIP=y
+CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
+CONFIG_GZIP_FAST=2
+# CONFIG_FEATURE_GZIP_LEVELS is not set
+CONFIG_LZOP=y
+CONFIG_UNLZOP=y
+CONFIG_LZOPCAT=y
+CONFIG_LZOP_COMPR_HIGH=y
+# CONFIG_RPM is not set
+# CONFIG_RPM2CPIO is not set
+CONFIG_TAR=y
+CONFIG_FEATURE_TAR_CREATE=y
+CONFIG_FEATURE_TAR_AUTODETECT=y
+CONFIG_FEATURE_TAR_FROM=y
+# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set
+# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
+CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
+CONFIG_FEATURE_TAR_LONG_OPTIONS=y
+CONFIG_FEATURE_TAR_TO_COMMAND=y
+CONFIG_FEATURE_TAR_UNAME_GNAME=y
+CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
+CONFIG_FEATURE_TAR_SELINUX=y
+CONFIG_UNZIP=y
+
+#
+# Coreutils
+#
+CONFIG_BASENAME=y
+CONFIG_CAL=y
+CONFIG_CAT=y
+CONFIG_CATV=y
+CONFIG_CHGRP=y
+CONFIG_CHMOD=y
+CONFIG_CHOWN=y
+CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y
+CONFIG_CHROOT=y
+# CONFIG_CKSUM is not set
+CONFIG_COMM=y
+CONFIG_CP=y
+CONFIG_FEATURE_CP_LONG_OPTIONS=y
+CONFIG_CUT=y
+CONFIG_DATE=y
+CONFIG_FEATURE_DATE_ISOFMT=y
+# CONFIG_FEATURE_DATE_NANO is not set
+CONFIG_FEATURE_DATE_COMPAT=y
+CONFIG_DD=y
+CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
+CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y
+CONFIG_FEATURE_DD_IBS_OBS=y
+CONFIG_FEATURE_DD_STATUS=y
+CONFIG_DF=y
+CONFIG_FEATURE_DF_FANCY=y
+CONFIG_DIRNAME=y
+CONFIG_DOS2UNIX=y
+CONFIG_UNIX2DOS=y
+CONFIG_DU=y
+CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
+CONFIG_ECHO=y
+CONFIG_FEATURE_FANCY_ECHO=y
+CONFIG_ENV=y
+CONFIG_FEATURE_ENV_LONG_OPTIONS=y
+CONFIG_EXPAND=y
+CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y
+CONFIG_UNEXPAND=y
+CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
+CONFIG_EXPR=y
+CONFIG_EXPR_MATH_SUPPORT_64=y
+CONFIG_FALSE=y
+CONFIG_FOLD=y
+CONFIG_FSYNC=y
+CONFIG_HEAD=y
+CONFIG_FEATURE_FANCY_HEAD=y
+# CONFIG_HOSTID is not set
+CONFIG_ID=y
+CONFIG_GROUPS=y
+CONFIG_INSTALL=y
+CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y
+CONFIG_LN=y
+# CONFIG_LOGNAME is not set
+CONFIG_LS=y
+CONFIG_FEATURE_LS_FILETYPES=y
+CONFIG_FEATURE_LS_FOLLOWLINKS=y
+CONFIG_FEATURE_LS_RECURSIVE=y
+CONFIG_FEATURE_LS_SORTFILES=y
+CONFIG_FEATURE_LS_TIMESTAMPS=y
+CONFIG_FEATURE_LS_USERNAME=y
+CONFIG_FEATURE_LS_COLOR=y
+# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
+CONFIG_MD5SUM=y
+CONFIG_SHA1SUM=y
+CONFIG_SHA256SUM=y
+CONFIG_SHA512SUM=y
+CONFIG_SHA3SUM=y
+
+#
+# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
+#
+CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
+CONFIG_MKDIR=y
+CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y
+CONFIG_MKFIFO=y
+CONFIG_MKNOD=y
+CONFIG_MV=y
+CONFIG_FEATURE_MV_LONG_OPTIONS=y
+CONFIG_NICE=y
+CONFIG_NOHUP=y
+CONFIG_OD=y
+CONFIG_PRINTENV=y
+CONFIG_PRINTF=y
+CONFIG_PWD=y
+CONFIG_READLINK=y
+CONFIG_FEATURE_READLINK_FOLLOW=y
+CONFIG_REALPATH=y
+CONFIG_RM=y
+CONFIG_RMDIR=y
+CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
+CONFIG_SEQ=y
+CONFIG_SHUF=y
+CONFIG_SLEEP=y
+CONFIG_FEATURE_FANCY_SLEEP=y
+CONFIG_FEATURE_FLOAT_SLEEP=y
+CONFIG_SORT=y
+CONFIG_FEATURE_SORT_BIG=y
+CONFIG_SPLIT=y
+CONFIG_FEATURE_SPLIT_FANCY=y
+CONFIG_STAT=y
+# CONFIG_FEATURE_STAT_FORMAT is not set
+CONFIG_FEATURE_STAT_FILESYSTEM=y
+CONFIG_STTY=y
+CONFIG_SUM=y
+CONFIG_SYNC=y
+CONFIG_FEATURE_SYNC_FANCY=y
+CONFIG_TAC=y
+CONFIG_TAIL=y
+CONFIG_FEATURE_FANCY_TAIL=y
+CONFIG_TEE=y
+CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
+CONFIG_TEST=y
+CONFIG_TEST1=y
+CONFIG_TEST2=y
+# CONFIG_FEATURE_TEST_64 is not set
+CONFIG_TOUCH=y
+# CONFIG_FEATURE_TOUCH_NODEREF is not set
+CONFIG_FEATURE_TOUCH_SUSV3=y
+CONFIG_TR=y
+CONFIG_FEATURE_TR_CLASSES=y
+# CONFIG_FEATURE_TR_EQUIV is not set
+CONFIG_TRUE=y
+CONFIG_TRUNCATE=y
+# CONFIG_TTY is not set
+CONFIG_UNAME=y
+CONFIG_UNAME_OSNAME="GNU/Linux"
+CONFIG_UNIQ=y
+CONFIG_UNLINK=y
+CONFIG_USLEEP=y
+CONFIG_UUDECODE=y
+CONFIG_BASE64=y
+CONFIG_UUENCODE=y
+CONFIG_WC=y
+CONFIG_FEATURE_WC_LARGE=y
+# CONFIG_WHO is not set
+# CONFIG_USERS is not set
+CONFIG_WHOAMI=y
+CONFIG_YES=y
+
+#
+# Common options
+#
+CONFIG_FEATURE_VERBOSE=y
+
+#
+# Common options for cp and mv
+#
+CONFIG_FEATURE_PRESERVE_HARDLINKS=y
+
+#
+# Common options for ls, more and telnet
+#
+CONFIG_FEATURE_AUTOWIDTH=y
+
+#
+# Common options for df, du, ls
+#
+CONFIG_FEATURE_HUMAN_READABLE=y
+
+#
+# Console Utilities
+#
+CONFIG_CHVT=y
+CONFIG_CLEAR=y
+CONFIG_DEALLOCVT=y
+# CONFIG_DUMPKMAP is not set
+CONFIG_FGCONSOLE=y
+# CONFIG_KBD_MODE is not set
+# CONFIG_LOADFONT is not set
+# CONFIG_SETFONT is not set
+# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
+CONFIG_DEFAULT_SETFONT_DIR=""
+# CONFIG_FEATURE_LOADFONT_PSF2 is not set
+# CONFIG_FEATURE_LOADFONT_RAW is not set
+# CONFIG_LOADKMAP is not set
+CONFIG_OPENVT=y
+CONFIG_RESET=y
+CONFIG_RESIZE=y
+# CONFIG_FEATURE_RESIZE_PRINT is not set
+CONFIG_SETCONSOLE=y
+# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
+CONFIG_SETKEYCODES=y
+# CONFIG_SETLOGCONS is not set
+# CONFIG_SHOWKEY is not set
+
+#
+# Debian Utilities
+#
+CONFIG_MKTEMP=y
+CONFIG_PIPE_PROGRESS=y
+CONFIG_RUN_PARTS=y
+CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y
+CONFIG_FEATURE_RUN_PARTS_FANCY=y
+# CONFIG_START_STOP_DAEMON is not set
+# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
+# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
+CONFIG_WHICH=y
+
+#
+# Editors
+#
+CONFIG_AWK=y
+CONFIG_FEATURE_AWK_LIBM=y
+CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
+CONFIG_CMP=y
+CONFIG_DIFF=y
+CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
+CONFIG_FEATURE_DIFF_DIR=y
+CONFIG_ED=y
+CONFIG_PATCH=y
+CONFIG_SED=y
+CONFIG_VI=y
+CONFIG_FEATURE_VI_MAX_LEN=256
+CONFIG_FEATURE_VI_8BIT=y
+CONFIG_FEATURE_VI_COLON=y
+CONFIG_FEATURE_VI_YANKMARK=y
+CONFIG_FEATURE_VI_SEARCH=y
+CONFIG_FEATURE_VI_REGEX_SEARCH=y
+CONFIG_FEATURE_VI_USE_SIGNALS=y
+CONFIG_FEATURE_VI_DOT_CMD=y
+CONFIG_FEATURE_VI_READONLY=y
+CONFIG_FEATURE_VI_SETOPTS=y
+CONFIG_FEATURE_VI_SET=y
+CONFIG_FEATURE_VI_WIN_RESIZE=y
+CONFIG_FEATURE_VI_ASK_TERMINAL=y
+CONFIG_FEATURE_VI_UNDO=y
+CONFIG_FEATURE_VI_UNDO_QUEUE=y
+CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
+CONFIG_FEATURE_ALLOW_EXEC=y
+
+#
+# Finding Utilities
+#
+CONFIG_FIND=y
+CONFIG_FEATURE_FIND_PRINT0=y
+CONFIG_FEATURE_FIND_MTIME=y
+CONFIG_FEATURE_FIND_MMIN=y
+CONFIG_FEATURE_FIND_PERM=y
+CONFIG_FEATURE_FIND_TYPE=y
+CONFIG_FEATURE_FIND_XDEV=y
+CONFIG_FEATURE_FIND_MAXDEPTH=y
+CONFIG_FEATURE_FIND_NEWER=y
+CONFIG_FEATURE_FIND_INUM=y
+CONFIG_FEATURE_FIND_EXEC=y
+CONFIG_FEATURE_FIND_EXEC_PLUS=y
+CONFIG_FEATURE_FIND_USER=y
+CONFIG_FEATURE_FIND_GROUP=y
+CONFIG_FEATURE_FIND_NOT=y
+CONFIG_FEATURE_FIND_DEPTH=y
+CONFIG_FEATURE_FIND_PAREN=y
+CONFIG_FEATURE_FIND_SIZE=y
+CONFIG_FEATURE_FIND_PRUNE=y
+CONFIG_FEATURE_FIND_DELETE=y
+CONFIG_FEATURE_FIND_PATH=y
+CONFIG_FEATURE_FIND_REGEX=y
+# CONFIG_FEATURE_FIND_CONTEXT is not set
+CONFIG_FEATURE_FIND_LINKS=y
+CONFIG_GREP=y
+CONFIG_EGREP=y
+CONFIG_FGREP=y
+CONFIG_FEATURE_GREP_CONTEXT=y
+CONFIG_XARGS=y
+CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
+CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
+CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
+CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
+CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y
+
+#
+# Init Utilities
+#
+# CONFIG_BOOTCHARTD is not set
+# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
+# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
+CONFIG_HALT=y
+CONFIG_POWEROFF=y
+CONFIG_REBOOT=y
+# CONFIG_FEATURE_CALL_TELINIT is not set
+CONFIG_TELINIT_PATH=""
+# CONFIG_INIT is not set
+CONFIG_LINUXRC=y
+# CONFIG_FEATURE_USE_INITTAB is not set
+# CONFIG_FEATURE_KILL_REMOVED is not set
+CONFIG_FEATURE_KILL_DELAY=0
+# CONFIG_FEATURE_INIT_SCTTY is not set
+# CONFIG_FEATURE_INIT_SYSLOG is not set
+# CONFIG_FEATURE_EXTRA_QUIET is not set
+# CONFIG_FEATURE_INIT_COREDUMPS is not set
+CONFIG_INIT_TERMINAL_TYPE=""
+CONFIG_FEATURE_INIT_MODIFY_CMDLINE=y
+CONFIG_MESG=y
+CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y
+
+#
+# Login/Password Management Utilities
+#
+# CONFIG_FEATURE_SHADOWPASSWDS is not set
+# CONFIG_USE_BB_PWD_GRP is not set
+# CONFIG_USE_BB_SHADOW is not set
+CONFIG_USE_BB_CRYPT=y
+CONFIG_USE_BB_CRYPT_SHA=y
+# CONFIG_ADD_SHELL is not set
+# CONFIG_REMOVE_SHELL is not set
+# CONFIG_ADDGROUP is not set
+# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
+# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
+# CONFIG_ADDUSER is not set
+# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
+# CONFIG_FEATURE_CHECK_NAMES is not set
+CONFIG_LAST_ID=0
+CONFIG_FIRST_SYSTEM_ID=0
+CONFIG_LAST_SYSTEM_ID=0
+# CONFIG_CHPASSWD is not set
+CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
+# CONFIG_CRYPTPW is not set
+CONFIG_MKPASSWD=y
+# CONFIG_DELUSER is not set
+# CONFIG_DELGROUP is not set
+# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
+# CONFIG_GETTY is not set
+# CONFIG_LOGIN is not set
+# CONFIG_LOGIN_SESSION_AS_CHILD is not set
+# CONFIG_LOGIN_SCRIPTS is not set
+# CONFIG_FEATURE_NOLOGIN is not set
+# CONFIG_FEATURE_SECURETTY is not set
+# CONFIG_PASSWD is not set
+# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
+# CONFIG_SU is not set
+# CONFIG_FEATURE_SU_SYSLOG is not set
+# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
+# CONFIG_SULOGIN is not set
+# CONFIG_VLOCK is not set
+
+#
+# Linux Ext2 FS Progs
+#
+CONFIG_CHATTR=y
+# CONFIG_FSCK is not set
+CONFIG_LSATTR=y
+CONFIG_TUNE2FS=y
+
+#
+# Linux Module Utilities
+#
+# CONFIG_MODPROBE_SMALL is not set
+CONFIG_DEPMOD=y
+CONFIG_INSMOD=y
+CONFIG_LSMOD=y
+CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT=y
+CONFIG_MODINFO=y
+# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set
+# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
+CONFIG_MODPROBE=y
+CONFIG_FEATURE_MODPROBE_BLACKLIST=y
+CONFIG_RMMOD=y
+
+#
+# Options common to multiple modutils
+#
+# CONFIG_FEATURE_2_4_MODULES is not set
+CONFIG_FEATURE_INSMOD_TRY_MMAP=y
+# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
+# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
+# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
+CONFIG_FEATURE_CHECK_TAINTED_MODULE=y
+CONFIG_FEATURE_MODUTILS_ALIAS=y
+CONFIG_FEATURE_MODUTILS_SYMBOLS=y
+CONFIG_DEFAULT_MODULES_DIR="/lib/modules"
+CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
+
+#
+# Linux System Utilities
+#
+# CONFIG_ACPID is not set
+# CONFIG_FEATURE_ACPID_COMPAT is not set
+CONFIG_BLKDISCARD=y
+CONFIG_BLKID=y
+CONFIG_FEATURE_BLKID_TYPE=y
+CONFIG_BLOCKDEV=y
+CONFIG_DMESG=y
+# CONFIG_FEATURE_DMESG_PRETTY is not set
+CONFIG_FATATTR=y
+CONFIG_FBSET=y
+CONFIG_FEATURE_FBSET_FANCY=y
+# CONFIG_FEATURE_FBSET_READMODE is not set
+# CONFIG_FDFORMAT is not set
+CONFIG_FDISK=y
+# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
+CONFIG_FEATURE_FDISK_WRITABLE=y
+# CONFIG_FEATURE_AIX_LABEL is not set
+# CONFIG_FEATURE_SGI_LABEL is not set
+# CONFIG_FEATURE_SUN_LABEL is not set
+# CONFIG_FEATURE_OSF_LABEL is not set
+CONFIG_FEATURE_GPT_LABEL=y
+CONFIG_FEATURE_FDISK_ADVANCED=y
+CONFIG_FINDFS=y
+CONFIG_FLOCK=y
+# CONFIG_FDFLUSH is not set
+CONFIG_FREERAMDISK=y
+# CONFIG_FSCK_MINIX is not set
+CONFIG_FSTRIM=y
+CONFIG_GETOPT=y
+CONFIG_FEATURE_GETOPT_LONG=y
+CONFIG_HEXDUMP=y
+CONFIG_FEATURE_HEXDUMP_REVERSE=y
+# CONFIG_HD is not set
+CONFIG_HWCLOCK=y
+# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
+# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
+# CONFIG_IPCRM is not set
+# CONFIG_IPCS is not set
+CONFIG_LOSETUP=y
+CONFIG_LSPCI=y
+CONFIG_LSUSB=y
+# CONFIG_MDEV is not set
+# CONFIG_FEATURE_MDEV_CONF is not set
+# CONFIG_FEATURE_MDEV_RENAME is not set
+# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
+# CONFIG_FEATURE_MDEV_EXEC is not set
+# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
+CONFIG_MKE2FS=y
+CONFIG_MKFS_EXT2=y
+# CONFIG_MKFS_MINIX is not set
+# CONFIG_FEATURE_MINIX2 is not set
+# CONFIG_MKFS_REISER is not set
+CONFIG_MKDOSFS=y
+CONFIG_MKFS_VFAT=y
+CONFIG_MKSWAP=y
+# CONFIG_FEATURE_MKSWAP_UUID is not set
+CONFIG_MORE=y
+CONFIG_MOUNT=y
+CONFIG_FEATURE_MOUNT_FAKE=y
+CONFIG_FEATURE_MOUNT_VERBOSE=y
+# CONFIG_FEATURE_MOUNT_HELPERS is not set
+CONFIG_FEATURE_MOUNT_LABEL=y
+CONFIG_FEATURE_MOUNT_NFS=y
+CONFIG_FEATURE_MOUNT_CIFS=y
+CONFIG_FEATURE_MOUNT_FLAGS=y
+CONFIG_FEATURE_MOUNT_FSTAB=y
+CONFIG_FEATURE_MOUNT_OTHERTAB=y
+CONFIG_NSENTER=y
+CONFIG_FEATURE_NSENTER_LONG_OPTS=y
+# CONFIG_PIVOT_ROOT is not set
+CONFIG_RDATE=y
+CONFIG_RDEV=y
+# CONFIG_READPROFILE is not set
+CONFIG_REV=y
+# CONFIG_RTCWAKE is not set
+# CONFIG_SCRIPT is not set
+# CONFIG_SCRIPTREPLAY is not set
+# CONFIG_SETARCH is not set
+CONFIG_LINUX32=y
+CONFIG_LINUX64=y
+CONFIG_SWAPON=y
+CONFIG_FEATURE_SWAPON_DISCARD=y
+CONFIG_FEATURE_SWAPON_PRI=y
+CONFIG_SWAPOFF=y
+CONFIG_SWITCH_ROOT=y
+CONFIG_UEVENT=y
+CONFIG_UMOUNT=y
+CONFIG_FEATURE_UMOUNT_ALL=y
+CONFIG_UNSHARE=y
+
+#
+# Common options for mount/umount
+#
+CONFIG_FEATURE_MOUNT_LOOP=y
+CONFIG_FEATURE_MOUNT_LOOP_CREATE=y
+# CONFIG_FEATURE_MTAB_SUPPORT is not set
+CONFIG_VOLUMEID=y
+
+#
+# Filesystem/Volume identification
+#
+CONFIG_FEATURE_VOLUMEID_BCACHE=y
+# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
+# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
+CONFIG_FEATURE_VOLUMEID_EXFAT=y
+CONFIG_FEATURE_VOLUMEID_EXT=y
+CONFIG_FEATURE_VOLUMEID_F2FS=y
+CONFIG_FEATURE_VOLUMEID_FAT=y
+# CONFIG_FEATURE_VOLUMEID_HFS is not set
+CONFIG_FEATURE_VOLUMEID_ISO9660=y
+# CONFIG_FEATURE_VOLUMEID_JFS is not set
+# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
+CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y
+# CONFIG_FEATURE_VOLUMEID_LUKS is not set
+# CONFIG_FEATURE_VOLUMEID_NILFS is not set
+CONFIG_FEATURE_VOLUMEID_NTFS=y
+# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
+# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
+# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
+CONFIG_FEATURE_VOLUMEID_SQUASHFS=y
+# CONFIG_FEATURE_VOLUMEID_SYSV is not set
+CONFIG_FEATURE_VOLUMEID_UBIFS=y
+# CONFIG_FEATURE_VOLUMEID_UDF is not set
+# CONFIG_FEATURE_VOLUMEID_XFS is not set
+
+#
+# Miscellaneous Utilities
+#
+CONFIG_ADJTIMEX=y
+CONFIG_BBCONFIG=y
+CONFIG_FEATURE_COMPRESS_BBCONFIG=y
+# CONFIG_BEEP is not set
+CONFIG_FEATURE_BEEP_FREQ=0
+CONFIG_FEATURE_BEEP_LENGTH_MS=0
+# CONFIG_CHAT is not set
+# CONFIG_FEATURE_CHAT_NOFAIL is not set
+# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
+# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
+# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
+# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
+# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
+# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
+# CONFIG_CHRT is not set
+# CONFIG_CONSPY is not set
+CONFIG_CROND=y
+CONFIG_FEATURE_CROND_D=y
+# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
+CONFIG_FEATURE_CROND_DIR="/etc"
+CONFIG_CRONTAB=y
+CONFIG_DC=y
+CONFIG_FEATURE_DC_LIBM=y
+# CONFIG_DEVFSD is not set
+# CONFIG_DEVFSD_MODLOAD is not set
+# CONFIG_DEVFSD_FG_NP is not set
+# CONFIG_DEVFSD_VERBOSE is not set
+# CONFIG_FEATURE_DEVFS is not set
+CONFIG_DEVMEM=y
+# CONFIG_EJECT is not set
+# CONFIG_FEATURE_EJECT_SCSI is not set
+CONFIG_FBSPLASH=y
+# CONFIG_FLASH_ERASEALL is not set
+CONFIG_FLASH_LOCK=y
+CONFIG_FLASH_UNLOCK=y
+CONFIG_FLASHCP=y
+# CONFIG_HDPARM is not set
+# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
+# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
+# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
+CONFIG_I2CGET=y
+CONFIG_I2CSET=y
+CONFIG_I2CDUMP=y
+CONFIG_I2CDETECT=y
+# CONFIG_INOTIFYD is not set
+CONFIG_IONICE=y
+# CONFIG_LAST is not set
+# CONFIG_FEATURE_LAST_FANCY is not set
+CONFIG_LESS=y
+CONFIG_FEATURE_LESS_MAXLINES=65536
+# CONFIG_FEATURE_LESS_BRACKETS is not set
+# CONFIG_FEATURE_LESS_FLAGS is not set
+CONFIG_FEATURE_LESS_TRUNCATE=y
+CONFIG_FEATURE_LESS_MARKS=y
+CONFIG_FEATURE_LESS_REGEXP=y
+CONFIG_FEATURE_LESS_WINCH=y
+CONFIG_FEATURE_LESS_ASK_TERMINAL=y
+# CONFIG_FEATURE_LESS_DASHCMD is not set
+# CONFIG_FEATURE_LESS_LINENUMS is not set
+# CONFIG_MAKEDEVS is not set
+# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
+# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
+CONFIG_MAN=y
+# CONFIG_MICROCOM is not set
+CONFIG_MOUNTPOINT=y
+# CONFIG_MT is not set
+CONFIG_NANDWRITE=y
+CONFIG_NANDDUMP=y
+# CONFIG_RAIDAUTORUN is not set
+# CONFIG_READAHEAD is not set
+# CONFIG_RFKILL is not set
+# CONFIG_RUNLEVEL is not set
+CONFIG_RX=y
+CONFIG_SETSERIAL=y
+CONFIG_SETSID=y
+CONFIG_STRINGS=y
+CONFIG_TASKSET=y
+CONFIG_FEATURE_TASKSET_FANCY=y
+CONFIG_TIME=y
+CONFIG_TIMEOUT=y
+CONFIG_TTYSIZE=y
+# CONFIG_UBIATTACH is not set
+# CONFIG_UBIDETACH is not set
+# CONFIG_UBIMKVOL is not set
+# CONFIG_UBIRMVOL is not set
+# CONFIG_UBIRSVOL is not set
+# CONFIG_UBIUPDATEVOL is not set
+CONFIG_UBIRENAME=y
+# CONFIG_VOLNAME is not set
+# CONFIG_WALL is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Networking Utilities
+#
+CONFIG_FEATURE_IPV6=y
+# CONFIG_FEATURE_UNIX_LOCAL is not set
+CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
+CONFIG_VERBOSE_RESOLUTION_ERRORS=y
+CONFIG_ARP=y
+# CONFIG_ARPING is not set
+CONFIG_BRCTL=y
+CONFIG_FEATURE_BRCTL_FANCY=y
+CONFIG_FEATURE_BRCTL_SHOW=y
+CONFIG_DNSD=y
+# CONFIG_ETHER_WAKE is not set
+# CONFIG_FTPD is not set
+# CONFIG_FEATURE_FTPD_WRITE is not set
+# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
+# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
+CONFIG_FTPGET=y
+CONFIG_FTPPUT=y
+CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y
+# CONFIG_HOSTNAME is not set
+CONFIG_DNSDOMAINNAME=y
+# CONFIG_HTTPD is not set
+# CONFIG_FEATURE_HTTPD_RANGES is not set
+# CONFIG_FEATURE_HTTPD_SETUID is not set
+# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
+# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
+# CONFIG_FEATURE_HTTPD_CGI is not set
+# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
+# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
+# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
+# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
+# CONFIG_FEATURE_HTTPD_PROXY is not set
+# CONFIG_FEATURE_HTTPD_GZIP is not set
+CONFIG_IFCONFIG=y
+CONFIG_FEATURE_IFCONFIG_STATUS=y
+# CONFIG_FEATURE_IFCONFIG_SLIP is not set
+# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
+CONFIG_FEATURE_IFCONFIG_HW=y
+# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
+# CONFIG_IFENSLAVE is not set
+# CONFIG_IFPLUGD is not set
+CONFIG_IFUP=y
+CONFIG_IFDOWN=y
+CONFIG_IFUPDOWN_IFSTATE_PATH=""
+# CONFIG_FEATURE_IFUPDOWN_IP is not set
+# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
+# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
+# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
+# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
+CONFIG_INETD=y
+CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
+CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y
+CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
+# CONFIG_FEATURE_INETD_RPC is not set
+CONFIG_IP=y
+# CONFIG_IPADDR is not set
+# CONFIG_IPLINK is not set
+# CONFIG_IPROUTE is not set
+# CONFIG_IPTUNNEL is not set
+# CONFIG_IPRULE is not set
+CONFIG_IPNEIGH=y
+CONFIG_FEATURE_IP_ADDRESS=y
+CONFIG_FEATURE_IP_LINK=y
+CONFIG_FEATURE_IP_ROUTE=y
+CONFIG_FEATURE_IP_ROUTE_DIR="/etc/iproute2"
+# CONFIG_FEATURE_IP_TUNNEL is not set
+CONFIG_FEATURE_IP_RULE=y
+CONFIG_FEATURE_IP_NEIGH=y
+# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
+# CONFIG_IPCALC is not set
+# CONFIG_FEATURE_IPCALC_FANCY is not set
+# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
+# CONFIG_FAKEIDENTD is not set
+# CONFIG_NAMEIF is not set
+# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
+CONFIG_NBDCLIENT=y
+CONFIG_NC=y
+CONFIG_NC_SERVER=y
+CONFIG_NC_EXTRA=y
+# CONFIG_NC_110_COMPAT is not set
+CONFIG_NETSTAT=y
+CONFIG_FEATURE_NETSTAT_WIDE=y
+CONFIG_FEATURE_NETSTAT_PRG=y
+CONFIG_NSLOOKUP=y
+CONFIG_NTPD=y
+# CONFIG_FEATURE_NTPD_SERVER is not set
+CONFIG_FEATURE_NTPD_CONF=y
+CONFIG_PING=y
+# CONFIG_PING6 is not set
+CONFIG_FEATURE_FANCY_PING=y
+# CONFIG_PSCAN is not set
+CONFIG_ROUTE=y
+# CONFIG_SLATTACH is not set
+# CONFIG_TCPSVD is not set
+# CONFIG_UDPSVD is not set
+CONFIG_TELNET=y
+CONFIG_FEATURE_TELNET_TTYPE=y
+# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
+CONFIG_TELNETD=y
+CONFIG_FEATURE_TELNETD_STANDALONE=y
+CONFIG_FEATURE_TELNETD_INETD_WAIT=y
+CONFIG_TFTP=y
+CONFIG_TFTPD=y
+
+#
+# Common options for tftp/tftpd
+#
+CONFIG_FEATURE_TFTP_GET=y
+CONFIG_FEATURE_TFTP_PUT=y
+# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
+# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
+# CONFIG_TFTP_DEBUG is not set
+CONFIG_TRACEROUTE=y
+# CONFIG_TRACEROUTE6 is not set
+CONFIG_FEATURE_TRACEROUTE_VERBOSE=y
+# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
+# CONFIG_TUNCTL is not set
+# CONFIG_FEATURE_TUNCTL_UG is not set
+# CONFIG_VCONFIG is not set
+CONFIG_WGET=y
+CONFIG_FEATURE_WGET_STATUSBAR=y
+CONFIG_FEATURE_WGET_AUTHENTICATION=y
+CONFIG_FEATURE_WGET_LONG_OPTIONS=y
+CONFIG_FEATURE_WGET_TIMEOUT=y
+CONFIG_FEATURE_WGET_OPENSSL=y
+CONFIG_FEATURE_WGET_SSL_HELPER=y
+# CONFIG_WHOIS is not set
+# CONFIG_ZCIP is not set
+# CONFIG_UDHCPC6 is not set
+# CONFIG_UDHCPD is not set
+# CONFIG_DHCPRELAY is not set
+# CONFIG_DUMPLEASES is not set
+# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
+# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
+CONFIG_DHCPD_LEASES_FILE=""
+# CONFIG_UDHCPC is not set
+# CONFIG_FEATURE_UDHCPC_ARPING is not set
+# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
+# CONFIG_FEATURE_UDHCP_PORT is not set
+CONFIG_UDHCP_DEBUG=0
+# CONFIG_FEATURE_UDHCP_RFC3397 is not set
+# CONFIG_FEATURE_UDHCP_8021Q is not set
+CONFIG_UDHCPC_DEFAULT_SCRIPT=""
+CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
+CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
+
+#
+# Print Utilities
+#
+# CONFIG_LPD is not set
+# CONFIG_LPR is not set
+# CONFIG_LPQ is not set
+
+#
+# Mail Utilities
+#
+# CONFIG_MAKEMIME is not set
+# CONFIG_POPMAILDIR is not set
+# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
+# CONFIG_REFORMIME is not set
+# CONFIG_FEATURE_REFORMIME_COMPAT is not set
+# CONFIG_SENDMAIL is not set
+CONFIG_FEATURE_MIME_CHARSET=""
+
+#
+# Process Utilities
+#
+CONFIG_FREE=y
+CONFIG_FUSER=y
+CONFIG_IOSTAT=y
+CONFIG_KILL=y
+CONFIG_KILLALL=y
+CONFIG_KILLALL5=y
+CONFIG_LSOF=y
+CONFIG_MPSTAT=y
+CONFIG_NMETER=y
+CONFIG_PGREP=y
+CONFIG_PKILL=y
+CONFIG_PIDOF=y
+CONFIG_FEATURE_PIDOF_SINGLE=y
+CONFIG_FEATURE_PIDOF_OMIT=y
+CONFIG_PMAP=y
+# CONFIG_POWERTOP is not set
+CONFIG_PS=y
+# CONFIG_FEATURE_PS_WIDE is not set
+# CONFIG_FEATURE_PS_LONG is not set
+CONFIG_FEATURE_PS_TIME=y
+CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y
+# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
+CONFIG_PSTREE=y
+CONFIG_PWDX=y
+CONFIG_RENICE=y
+CONFIG_SMEMCAP=y
+CONFIG_BB_SYSCTL=y
+CONFIG_TOP=y
+CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
+CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
+CONFIG_FEATURE_TOP_SMP_CPU=y
+CONFIG_FEATURE_TOP_DECIMALS=y
+CONFIG_FEATURE_TOP_SMP_PROCESS=y
+CONFIG_FEATURE_TOPMEM=y
+CONFIG_UPTIME=y
+# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
+CONFIG_WATCH=y
+CONFIG_FEATURE_SHOW_THREADS=y
+
+#
+# Runit Utilities
+#
+# CONFIG_CHPST is not set
+# CONFIG_SETUIDGID is not set
+# CONFIG_ENVUIDGID is not set
+# CONFIG_ENVDIR is not set
+# CONFIG_SOFTLIMIT is not set
+# CONFIG_RUNSV is not set
+# CONFIG_RUNSVDIR is not set
+# CONFIG_FEATURE_RUNSVDIR_LOG is not set
+# CONFIG_SV is not set
+CONFIG_SV_DEFAULT_SERVICE_DIR=""
+CONFIG_SVC=y
+# CONFIG_SVLOGD is not set
+
+#
+# SELinux Utilities
+#
+CONFIG_CHCON=y
+CONFIG_FEATURE_CHCON_LONG_OPTIONS=y
+CONFIG_GETENFORCE=y
+CONFIG_GETSEBOOL=y
+# CONFIG_LOAD_POLICY is not set
+CONFIG_MATCHPATHCON=y
+CONFIG_RUNCON=y
+CONFIG_FEATURE_RUNCON_LONG_OPTIONS=y
+CONFIG_SELINUXENABLED=y
+CONFIG_SESTATUS=y
+CONFIG_SETENFORCE=y
+CONFIG_SETFILES=y
+# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
+CONFIG_RESTORECON=y
+CONFIG_SETSEBOOL=y
+
+#
+# Shells
+#
+CONFIG_SH_IS_ASH=y
+# CONFIG_SH_IS_HUSH is not set
+# CONFIG_SH_IS_NONE is not set
+# CONFIG_BASH_IS_ASH is not set
+# CONFIG_BASH_IS_HUSH is not set
+CONFIG_BASH_IS_NONE=y
+CONFIG_ASH=y
+CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
+CONFIG_ASH_INTERNAL_GLOB=y
+CONFIG_ASH_RANDOM_SUPPORT=y
+CONFIG_ASH_EXPAND_PRMT=y
+CONFIG_ASH_BASH_COMPAT=y
+# CONFIG_ASH_IDLE_TIMEOUT is not set
+CONFIG_ASH_JOB_CONTROL=y
+CONFIG_ASH_ALIAS=y
+# CONFIG_ASH_GETOPTS is not set
+CONFIG_ASH_BUILTIN_ECHO=y
+CONFIG_ASH_BUILTIN_PRINTF=y
+CONFIG_ASH_BUILTIN_TEST=y
+CONFIG_ASH_HELP=y
+CONFIG_ASH_CMDCMD=y
+# CONFIG_ASH_MAIL is not set
+# CONFIG_CTTYHACK is not set
+# CONFIG_HUSH is not set
+# CONFIG_HUSH_BASH_COMPAT is not set
+# CONFIG_HUSH_BRACE_EXPANSION is not set
+# CONFIG_HUSH_HELP is not set
+# CONFIG_HUSH_INTERACTIVE is not set
+# CONFIG_HUSH_SAVEHISTORY is not set
+# CONFIG_HUSH_JOB is not set
+# CONFIG_HUSH_TICK is not set
+# CONFIG_HUSH_IF is not set
+# CONFIG_HUSH_LOOPS is not set
+# CONFIG_HUSH_CASE is not set
+# CONFIG_HUSH_FUNCTIONS is not set
+# CONFIG_HUSH_LOCAL is not set
+# CONFIG_HUSH_RANDOM_SUPPORT is not set
+# CONFIG_HUSH_EXPORT_N is not set
+# CONFIG_HUSH_MODE_X is not set
+# CONFIG_MSH is not set
+CONFIG_FEATURE_SH_MATH=y
+CONFIG_FEATURE_SH_MATH_64=y
+CONFIG_FEATURE_SH_EXTRA_QUIET=y
+# CONFIG_FEATURE_SH_STANDALONE is not set
+# CONFIG_FEATURE_SH_NOFORK is not set
+# CONFIG_FEATURE_SH_HISTFILESIZE is not set
+
+#
+# System Logging Utilities
+#
+# CONFIG_KLOGD is not set
+# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
+# CONFIG_LOGGER is not set
+# CONFIG_LOGREAD is not set
+# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
+# CONFIG_SYSLOGD is not set
+# CONFIG_FEATURE_ROTATE_LOGFILE is not set
+# CONFIG_FEATURE_REMOTE_LOG is not set
+# CONFIG_FEATURE_SYSLOGD_DUP is not set
+# CONFIG_FEATURE_SYSLOGD_CFG is not set
+CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
+# CONFIG_FEATURE_IPC_SYSLOG is not set
+CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
+# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/busybox-full.links b/busybox-full.links
new file mode 100644
index 0000000..e3e9f0c
--- a/dev/null
+++ b/busybox-full.links
@@ -0,0 +1,242 @@
+/bin/bunzip2
+/bin/bzcat
+/bin/date
+/bin/groups
+/bin/id
+/bin/touch
+/bin/base64
+/bin/patch
+/bin/vi
+/bin/find
+/bin/grep
+/bin/egrep
+/bin/fgrep
+/bin/xargs
+/sbin/halt
+/sbin/poweroff
+/sbin/reboot
+/bin/mesg
+/sbin/nandwrite
+/sbin/nanddump
+/bin/setserial
+/sbin/depmod
+/sbin/insmod
+/sbin/lsmod
+/sbin/modinfo
+/sbin/modprobe
+/sbin/rmmod
+/sbin/nbd-client
+/bin/ping
+/bin/iostat
+/bin/lsof
+/bin/mpstat
+/bin/pmap
+/bin/pstree
+/bin/pwdx
+/bin/ash
+/bin/sh
+/sbin/blockdev
+/bin/rev
+/bin/[
+/bin/[[
+/sbin/adjtimex
+/sbin/arp
+/bin/awk
+/bin/basename
+/bin/bbconfig
+/sbin/blkid
+/sbin/brctl
+/bin/bzip2
+/bin/cal
+/bin/cat
+/bin/catv
+/bin/chattr
+/bin/chcon
+/bin/chgrp
+/bin/chmod
+/bin/chown
+/sbin/chroot
+/bin/chvt
+/bin/clear
+/bin/cmp
+/bin/comm
+/bin/cp
+/bin/cpio
+/sbin/crond
+/bin/crontab
+/bin/cut
+/bin/dc
+/bin/dd
+/bin/deallocvt
+/sbin/devmem
+/bin/df
+/bin/diff
+/bin/dirname
+/bin/dmesg
+/sbin/dnsd
+/bin/dos2unix
+/bin/du
+/bin/echo
+/bin/ed
+/bin/env
+/bin/expand
+/bin/expr
+/bin/false
+/sbin/fbset
+/sbin/fbsplash
+/sbin/fdisk
+/bin/fgconsole
+/bin/findfs
+/sbin/flash_lock
+/sbin/flash_unlock
+/sbin/flashcp
+/bin/flock
+/bin/fold
+/bin/free
+/sbin/freeramdisk
+/sbin/fstrim
+/bin/fsync
+/bin/ftpget
+/bin/ftpput
+/bin/fuser
+/bin/getenforce
+/bin/getopt
+/bin/getsebool
+/bin/gunzip
+/bin/gzip
+/bin/head
+/bin/hexdump
+/sbin/hwclock
+/sbin/ifconfig
+/sbin/inetd
+/bin/install
+/bin/ionice
+/sbin/ip
+/bin/kill
+/bin/killall
+/sbin/killall5
+/bin/less
+/bin/ln
+/sbin/losetup
+/bin/ls
+/bin/lsattr
+/bin/lspci
+/bin/lsusb
+/bin/lzcat
+/bin/lzma
+/bin/lzop
+/bin/lzopcat
+/sbin/man
+/sbin/matchpathcon
+/bin/md5sum
+/bin/mkdir
+/sbin/mkdosfs
+/sbin/mke2fs
+/bin/mkfifo
+/sbin/mkfs.ext2
+/sbin/mkfs.vfat
+/bin/mknod
+/sbin/mkswap
+/bin/mktemp
+/bin/more
+/bin/mount
+/bin/mountpoint
+/bin/mv
+/bin/nc
+/bin/netstat
+/bin/nice
+/bin/nmeter
+/bin/nohup
+/bin/nslookup
+/sbin/ntpd
+/bin/od
+/bin/openvt
+/bin/pgrep
+/bin/pidof
+/bin/pipe_progress
+/bin/pkill
+/bin/printenv
+/bin/printf
+/bin/ps
+/bin/pwd
+/bin/rdate
+/sbin/rdev
+/bin/readlink
+/bin/realpath
+/bin/renice
+/bin/reset
+/bin/resize
+/sbin/restorecon
+/bin/rm
+/bin/rmdir
+/sbin/route
+/bin/runcon
+/bin/run-parts
+/bin/rx
+/bin/sed
+/sbin/selinuxenabled
+/bin/seq
+/sbin/sestatus
+/sbin/setconsole
+/sbin/setenforce
+/sbin/setfiles
+/bin/setkeycodes
+/sbin/setsebool
+/bin/setsid
+/bin/sha1sum
+/bin/sha3sum
+/bin/sha256sum
+/bin/sha512sum
+/bin/sleep
+/bin/smemcap
+/bin/sort
+/bin/split
+/bin/stat
+/bin/strings
+/bin/stty
+/bin/sum
+/sbin/swapoff
+/sbin/swapon
+/bin/sync
+/sbin/sysctl
+/bin/tac
+/bin/tail
+/bin/tar
+/bin/taskset
+/bin/tee
+/bin/telnet
+/sbin/telnetd
+/bin/test
+/bin/tftp
+/sbin/tftpd
+/bin/time
+/bin/timeout
+/bin/top
+/bin/tr
+/bin/traceroute
+/bin/true
+/bin/ttysize
+/sbin/tune2fs
+/bin/umount
+/bin/uname
+/bin/uncompress
+/bin/unexpand
+/bin/uniq
+/bin/unix2dos
+/bin/unxz
+/bin/unlzma
+/bin/unlzop
+/bin/unzip
+/bin/uptime
+/bin/usleep
+/bin/uudecode
+/bin/uuencode
+/bin/watch
+/bin/wc
+/bin/wget
+/bin/which
+/bin/whoami
+/bin/xzcat
+/bin/xz
+/bin/yes
+/bin/zcat
diff --git a/busybox-full.sources b/busybox-full.sources
new file mode 100644
index 0000000..307e78d
--- a/dev/null
+++ b/busybox-full.sources
@@ -0,0 +1,94 @@
+android/libc/__set_errno.c
+
+archival/bbunzip.c archival/bzip2.c archival/cpio.c archival/gzip.c
+archival/libarchive/lzo1x_1.c archival/libarchive/lzo1x_1o.c archival/libarchive/lzo1x_9x.c archival/libarchive/lzo1x_d.c archival/lzop.c
+archival/tar.c archival/unzip.c archival/libarchive/data_align.c
+archival/libarchive/data_extract_all.c archival/libarchive/data_extract_to_command.c archival/libarchive/data_extract_to_stdout.c
+archival/libarchive/data_skip.c archival/libarchive/decompress_bunzip2.c archival/libarchive/decompress_unlzma.c
+archival/libarchive/decompress_unxz.c archival/libarchive/decompress_gunzip.c archival/libarchive/decompress_uncompress.c
+archival/libarchive/filter_accept_all.c archival/libarchive/filter_accept_list.c archival/libarchive/filter_accept_reject_list.c
+archival/libarchive/find_list_entry.c archival/libarchive/get_header_cpio.c archival/libarchive/get_header_tar.c
+archival/libarchive/get_header_tar_bz2.c archival/libarchive/get_header_tar_gz.c archival/libarchive/get_header_tar_lzma.c
+archival/libarchive/header_list.c archival/libarchive/header_skip.c archival/libarchive/header_verbose_list.c
+archival/libarchive/init_handle.c archival/libarchive/open_transformer.c archival/libarchive/seek_by_jump.c archival/libarchive/seek_by_read.c
+archival/libarchive/common.c archival/libarchive/get_header_tar_xz.c archival/libarchive/unsafe_prefix.c
+
+console-tools/chvt.c console-tools/clear.c console-tools/deallocvt.c console-tools/fgconsole.c console-tools/openvt.c
+console-tools/reset.c console-tools/resize.c console-tools/setconsole.c console-tools/setkeycodes.c
+
+coreutils/basename.c coreutils/cal.c coreutils/cat.c coreutils/catv.c coreutils/chgrp.c coreutils/chmod.c coreutils/chown.c coreutils/chroot.c coreutils/cp.c coreutils/cut.c coreutils/date.c coreutils/dd.c coreutils/df.c coreutils/dirname.c coreutils/dos2unix.c coreutils/du.c coreutils/echo.c coreutils/env.c coreutils/expr.c coreutils/false.c coreutils/fold.c coreutils/head.c coreutils/id.c coreutils/install.c coreutils/ln.c coreutils/ls.c coreutils/md5_sha1_sum.c coreutils/mkdir.c coreutils/mkfifo.c coreutils/mknod.c coreutils/mv.c coreutils/nice.c coreutils/nohup.c coreutils/od.c coreutils/printenv.c coreutils/printf.c coreutils/pwd.c coreutils/readlink.c coreutils/realpath.c coreutils/rm.c coreutils/rmdir.c coreutils/seq.c coreutils/sleep.c coreutils/sort.c coreutils/split.c coreutils/stat.c coreutils/stty.c coreutils/sync.c coreutils/tac.c coreutils/tail.c coreutils/tee.c coreutils/test.c coreutils/test_ptr_hack.c coreutils/touch.c coreutils/tr.c coreutils/true.c coreutils/uname.c coreutils/uniq.c coreutils/usleep.c coreutils/uudecode.c coreutils/uuencode.c coreutils/wc.c coreutils/whoami.c coreutils/yes.c
+coreutils/libcoreutils/cp_mv_stat.c coreutils/libcoreutils/getopt_mk_fifo_nod.c
+coreutils/comm.c coreutils/expand.c coreutils/sum.c coreutils/fsync.c
+coreutils/shuf.c coreutils/truncate.c coreutils/unlink.c
+
+debianutils/mktemp.c debianutils/run_parts.c debianutils/which.c debianutils/pipe_progress.c
+
+editors/awk.c editors/cmp.c editors/diff.c editors/ed.c editors/patch.c editors/sed.c editors/vi.c
+e2fsprogs/e2fs_lib.c e2fsprogs/chattr.c e2fsprogs/lsattr.c e2fsprogs/tune2fs.c
+
+findutils/find.c findutils/grep.c findutils/xargs.c
+init/halt.c init/mesg.c init/init.c
+
+libbb/missing_syscalls.c
+libbb/appletlib.c libbb/ask_confirmation.c libbb/bb_askpass.c libbb/bb_do_delay.c libbb/bb_pwd.c libbb/bb_qsort.c libbb/bb_strtonum.c
+libbb/change_identity.c libbb/chomp.c libbb/compare_string_array.c libbb/concat_path_file.c libbb/concat_subpath_file.c libbb/copy_file.c libbb/copyfd.c
+libbb/crc32.c libbb/percent_decode.c libbb/default_error_retval.c libbb/device_open.c libbb/dump.c libbb/executable.c libbb/fclose_nonstdin.c
+libbb/fflush_stdout_and_exit.c libbb/fgets_str.c libbb/find_mount_point.c libbb/find_pid_by_name.c libbb/find_root_device.c libbb/full_write.c
+libbb/get_console.c libbb/get_cpu_count.c libbb/get_last_path_component.c libbb/get_line_from_file.c libbb/get_volsize.c
+libbb/getopt32.c libbb/getpty.c libbb/get_shell_name.c
+libbb/herror_msg.c libbb/human_readable.c libbb/inet_cksum.c libbb/inet_common.c libbb/inode_hash.c libbb/isdirectory.c
+libbb/kernel_version.c libbb/last_char_is.c libbb/lineedit.c libbb/lineedit_ptr_hack.c libbb/llist.c libbb/login.c libbb/loop.c
+libbb/make_directory.c libbb/makedev.c libbb/match_fstype.c libbb/hash_md5_sha.c libbb/bb_bswap_64.c libbb/messages.c libbb/mode_string.c libbb/mtab.c
+libbb/parse_config.c libbb/parse_mode.c libbb/perror_msg.c libbb/perror_nomsg.c libbb/perror_nomsg_and_die.c libbb/pidfile.c libbb/platform.c
+libbb/print_flags.c libbb/printable.c libbb/printable_string.c libbb/process_escape_sequence.c libbb/procps.c libbb/progress.c
+libbb/ptr_to_globals.c libbb/read.c libbb/read_key.c libbb/read_printf.c libbb/recursive_action.c libbb/remove_file.c libbb/rtc.c libbb/run_shell.c
+libbb/safe_gethostname.c libbb/safe_poll.c libbb/safe_strncpy.c libbb/safe_write.c libbb/setup_environment.c libbb/signals.c
+libbb/simplify_path.c libbb/single_argv.c libbb/skip_whitespace.c libbb/speed_table.c libbb/str_tolower.c libbb/strrstr.c
+libbb/time.c libbb/trim.c libbb/u_signal_names.c libbb/udp_io.c libbb/unicode.c libbb/uuencode.c
+libbb/vdprintf.c libbb/verror_msg.c libbb/vfork_daemon_rexec.c libbb/warn_ignoring_args.c libbb/wfopen.c libbb/wfopen_input.c
+libbb/write.c libbb/xatonum.c libbb/xconnect.c libbb/xfunc_die.c libbb/xfuncs.c libbb/xfuncs_printf.c
+libbb/xgetcwd.c libbb/xgethostbyname.c libbb/xreadlink.c libbb/xrealloc_vector.c libbb/xregcomp.c
+libbb/endofname.c libbb/in_ether.c libbb/nuke_str.c
+libbb/auto_string.c libbb/bbunit.c libbb/common_bufsiz.c libbb/logenv.c libbb/replace.c libbb/sysconf.c libbb/ubi.c
+libbb/pw_encrypt.c
+
+libpwdgrp/uidgid_get.c
+
+loginutils/cryptpw.c
+
+
+miscutils/adjtimex.c miscutils/bbconfig.c miscutils/crond.c miscutils/crontab.c miscutils/dc.c miscutils/devmem.c miscutils/fbsplash.c miscutils/flash_lock_unlock.c miscutils/flashcp.c miscutils/ionice.c miscutils/less.c miscutils/man.c miscutils/mountpoint.c miscutils/nandwrite.c miscutils/rx.c miscutils/setserial.c miscutils/setsid.c miscutils/strings.c miscutils/taskset.c miscutils/time.c miscutils/timeout.c miscutils/ttysize.c
+miscutils/i2c_tools.c miscutils/ubirename.c
+modutils/depmod.c modutils/insmod.c modutils/lsmod.c modutils/modinfo.c modutils/modprobe.c modutils/modutils.c modutils/rmmod.c
+networking/arp.c networking/brctl.c networking/dnsd.c networking/ftpgetput.c networking/ifconfig.c networking/inetd.c networking/interface.c networking/ip.c networking/nbd-client.c networking/nc.c networking/netstat.c networking/nslookup.c networking/ntpd.c networking/ping.c networking/route.c networking/telnet.c networking/telnetd.c networking/tftp.c networking/traceroute.c networking/wget.c
+networking/libiproute/ip_parse_common_args.c networking/libiproute/ipaddress.c networking/libiproute/iplink.c networking/libiproute/iproute.c networking/libiproute/iprule.c networking/libiproute/libnetlink.c networking/libiproute/ll_addr.c networking/libiproute/ll_map.c networking/libiproute/ll_proto.c networking/libiproute/ll_types.c networking/libiproute/rt_names.c networking/libiproute/rtm_map.c networking/libiproute/utils.c
+networking/libiproute/ipneigh.c
+networking/hostname.c networking/ifupdown.c
+
+procps/free.c procps/fuser.c procps/kill.c procps/pgrep.c procps/pidof.c procps/ps.c procps/renice.c procps/sysctl.c procps/top.c procps/uptime.c procps/watch.c
+procps/pmap.c procps/iostat.c procps/mpstat.c
+procps/lsof.c procps/nmeter.c procps/pstree.c procps/pwdx.c procps/smemcap.c
+
+shell/ash.c shell/ash_ptr_hack.c shell/math.c shell/random.c shell/shell_common.c
+
+libbb/selinux_common.c android/selinux/matchpathcon.c android/selinux/stubs.c
+selinux/chcon.c selinux/selinuxenabled.c
+selinux/getenforce.c selinux/sestatus.c selinux/setsebool.c
+selinux/getsebool.c selinux/runcon.c selinux/setenforce.c selinux/setfiles.c selinux/matchpathcon.c
+
+runit/sv.c
+
+util-linux/blkid.c util-linux/blockdev.c util-linux/dmesg.c util-linux/fdisk.c util-linux/findfs.c util-linux/flock.c
+util-linux/freeramdisk.c util-linux/fstrim.c util-linux/getopt.c
+util-linux/hexdump.c util-linux/hwclock.c util-linux/losetup.c util-linux/lspci.c util-linux/lsusb.c
+util-linux/mkfs_ext2.c util-linux/mkfs_vfat.c util-linux/mkswap.c
+util-linux/more.c util-linux/mount.c util-linux/rdate.c util-linux/rdev.c util-linux/rev.c
+util-linux/swaponoff.c util-linux/switch_root.c util-linux/umount.c
+
+util-linux/volume_id/get_devname.c util-linux/volume_id/volume_id.c util-linux/volume_id/util.c util-linux/volume_id/ext.c
+util-linux/volume_id/fat.c util-linux/volume_id/iso9660.c util-linux/volume_id/ntfs.c util-linux/volume_id/linux_swap.c
+util-linux/volume_id/exfat.c util-linux/volume_id/squashfs.c util-linux/volume_id/f2fs.c
+util-linux/volume_id/bcache.c util-linux/volume_id/ubifs.c
+
+util-linux/fbset.c util-linux/setarch.c util-linux/nsenter.c util-linux/unshare.c
+util-linux/blkdiscard.c util-linux/fatattr.c util-linux/uevent.c \ No newline at end of file
diff --git a/busybox-minimal.config b/busybox-minimal.config
new file mode 100644
index 0000000..979e56f
--- a/dev/null
+++ b/busybox-minimal.config
@@ -0,0 +1,1030 @@
+#
+# Automatically generated make config: don't edit
+# Busybox version: 1.22.1
+# Sun Jun 22 23:11:05 2014
+#
+CONFIG_HAVE_DOT_CONFIG=y
+
+#
+# Busybox Settings
+#
+
+#
+# General Configuration
+#
+# CONFIG_DESKTOP is not set
+# CONFIG_EXTRA_COMPAT is not set
+# CONFIG_INCLUDE_SUSv2 is not set
+# CONFIG_USE_PORTABLE_CODE is not set
+CONFIG_PLATFORM_LINUX=y
+CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
+# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
+CONFIG_SHOW_USAGE=y
+CONFIG_FEATURE_VERBOSE_USAGE=y
+CONFIG_FEATURE_COMPRESS_USAGE=y
+# CONFIG_FEATURE_INSTALLER is not set
+CONFIG_INSTALL_NO_USR=y
+# CONFIG_LOCALE_SUPPORT is not set
+CONFIG_UNICODE_SUPPORT=y
+# CONFIG_UNICODE_USING_LOCALE is not set
+# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
+CONFIG_SUBST_WCHAR=63
+CONFIG_LAST_SUPPORTED_WCHAR=0
+# CONFIG_UNICODE_COMBINING_WCHARS is not set
+CONFIG_UNICODE_WIDE_WCHARS=y
+# CONFIG_UNICODE_BIDI_SUPPORT is not set
+# CONFIG_UNICODE_NEUTRAL_TABLE is not set
+CONFIG_UNICODE_PRESERVE_BROKEN=y
+CONFIG_LONG_OPTS=y
+# CONFIG_FEATURE_DEVPTS is not set
+# CONFIG_FEATURE_CLEAN_UP is not set
+# CONFIG_FEATURE_UTMP is not set
+# CONFIG_FEATURE_WTMP is not set
+# CONFIG_FEATURE_PIDFILE is not set
+CONFIG_PID_FILE_PATH=""
+CONFIG_FEATURE_SUID=y
+# CONFIG_FEATURE_SUID_CONFIG is not set
+# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
+CONFIG_SELINUX=y
+# CONFIG_FEATURE_PREFER_APPLETS is not set
+CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe"
+# CONFIG_FEATURE_SYSLOG is not set
+# CONFIG_FEATURE_HAVE_RPC is not set
+
+#
+# Build Options
+#
+# CONFIG_STATIC is not set
+# CONFIG_PIE is not set
+# CONFIG_NOMMU is not set
+# CONFIG_BUILD_LIBBUSYBOX is not set
+# CONFIG_FEATURE_INDIVIDUAL is not set
+# CONFIG_FEATURE_SHARED_BUSYBOX is not set
+# CONFIG_LFS is not set
+CONFIG_LFS=y
+CONFIG_SYSROOT=""
+CONFIG_EXTRA_CFLAGS="-Os -fno-short-enums -fgcse-after-reload -frerun-cse-after-loop -frename-registers"
+CONFIG_EXTRA_LDFLAGS=""
+CONFIG_EXTRA_LDLIBS=""
+
+#
+# Debugging Options
+#
+# CONFIG_DEBUG is not set
+# CONFIG_DEBUG_PESSIMIZE is not set
+# CONFIG_WERROR is not set
+CONFIG_NO_DEBUG_LIB=y
+# CONFIG_DMALLOC is not set
+# CONFIG_EFENCE is not set
+
+#
+# Installation Options ("make install" behavior)
+#
+CONFIG_INSTALL_APPLET_SYMLINKS=y
+# CONFIG_INSTALL_APPLET_HARDLINKS is not set
+# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
+# CONFIG_INSTALL_APPLET_DONT is not set
+# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
+# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
+# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
+CONFIG_PREFIX="/system/xbin/bb"
+
+#
+# Busybox Library Tuning
+#
+# CONFIG_FEATURE_SYSTEMD is not set
+# CONFIG_FEATURE_RTMINMAX is not set
+CONFIG_PASSWORD_MINLEN=6
+CONFIG_MD5_SMALL=0
+CONFIG_SHA3_SMALL=1
+CONFIG_FEATURE_FAST_TOP=y
+# CONFIG_FEATURE_ETC_NETWORKS is not set
+CONFIG_FEATURE_USE_TERMIOS=y
+CONFIG_FEATURE_EDITING=y
+CONFIG_FEATURE_EDITING_MAX_LEN=1024
+CONFIG_FEATURE_EDITING_VI=y
+CONFIG_FEATURE_EDITING_HISTORY=256
+CONFIG_FEATURE_EDITING_SAVEHISTORY=y
+CONFIG_FEATURE_EDITING_SAVE_ON_EXIT=y
+CONFIG_FEATURE_REVERSE_SEARCH=y
+CONFIG_FEATURE_TAB_COMPLETION=y
+# CONFIG_FEATURE_USERNAME_COMPLETION is not set
+CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
+# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
+CONFIG_FEATURE_NON_POSIX_CP=y
+# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
+CONFIG_FEATURE_COPYBUF_KB=4
+CONFIG_FEATURE_SKIP_ROOTFS=y
+CONFIG_MONOTONIC_SYSCALL=y
+CONFIG_IOCTL_HEX2STR_ERROR=y
+# CONFIG_FEATURE_HWIB is not set
+
+#
+# Applets
+#
+
+#
+# Archival Utilities
+#
+# CONFIG_FEATURE_SEAMLESS_XZ is not set
+# CONFIG_FEATURE_SEAMLESS_LZMA is not set
+CONFIG_FEATURE_SEAMLESS_BZ2=y
+CONFIG_FEATURE_SEAMLESS_GZ=y
+# CONFIG_FEATURE_SEAMLESS_Z is not set
+# CONFIG_AR is not set
+# CONFIG_FEATURE_AR_LONG_FILENAMES is not set
+# CONFIG_FEATURE_AR_CREATE is not set
+# CONFIG_UNCOMPRESS is not set
+CONFIG_GUNZIP=y
+CONFIG_BUNZIP2=y
+CONFIG_UNLZMA=y
+# CONFIG_FEATURE_LZMA_FAST is not set
+# CONFIG_LZMA is not set
+CONFIG_UNXZ=y
+# CONFIG_XZ is not set
+CONFIG_BZIP2=y
+CONFIG_CPIO=y
+CONFIG_FEATURE_CPIO_O=y
+# CONFIG_FEATURE_CPIO_P is not set
+# CONFIG_DPKG is not set
+# CONFIG_DPKG_DEB is not set
+# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set
+CONFIG_GZIP=y
+CONFIG_FEATURE_GZIP_LONG_OPTIONS=y
+CONFIG_GZIP_FAST=2
+CONFIG_LZOP=y
+# CONFIG_LZOP_COMPR_HIGH is not set
+# CONFIG_RPM is not set
+# CONFIG_RPM2CPIO is not set
+CONFIG_TAR=y
+CONFIG_FEATURE_TAR_CREATE=y
+# CONFIG_FEATURE_TAR_AUTODETECT is not set
+CONFIG_FEATURE_TAR_FROM=y
+# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set
+# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
+CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
+CONFIG_FEATURE_TAR_LONG_OPTIONS=y
+# CONFIG_FEATURE_TAR_TO_COMMAND is not set
+# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
+CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y
+CONFIG_FEATURE_TAR_SELINUX=y
+CONFIG_UNZIP=y
+
+#
+# Coreutils
+#
+CONFIG_BASENAME=y
+CONFIG_CAT=y
+CONFIG_DATE=y
+CONFIG_FEATURE_DATE_ISOFMT=y
+# CONFIG_FEATURE_DATE_NANO is not set
+CONFIG_FEATURE_DATE_COMPAT=y
+# CONFIG_HOSTID is not set
+CONFIG_ID=y
+CONFIG_GROUPS=y
+CONFIG_TEST=y
+# CONFIG_FEATURE_TEST_64 is not set
+CONFIG_TOUCH=y
+# CONFIG_FEATURE_TOUCH_NODEREF is not set
+# CONFIG_FEATURE_TOUCH_SUSV3 is not set
+CONFIG_TR=y
+CONFIG_FEATURE_TR_CLASSES=y
+# CONFIG_FEATURE_TR_EQUIV is not set
+CONFIG_BASE64=y
+# CONFIG_WHO is not set
+# CONFIG_USERS is not set
+CONFIG_CAL=y
+CONFIG_CATV=y
+CONFIG_CHGRP=y
+CONFIG_CHMOD=y
+CONFIG_CHOWN=y
+CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y
+CONFIG_CHROOT=y
+# CONFIG_CKSUM is not set
+# CONFIG_COMM is not set
+CONFIG_CP=y
+CONFIG_FEATURE_CP_LONG_OPTIONS=y
+CONFIG_CUT=y
+CONFIG_DD=y
+CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
+CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y
+CONFIG_FEATURE_DD_IBS_OBS=y
+CONFIG_DF=y
+CONFIG_FEATURE_DF_FANCY=y
+CONFIG_DIRNAME=y
+CONFIG_DOS2UNIX=y
+CONFIG_UNIX2DOS=y
+CONFIG_DU=y
+CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
+CONFIG_ECHO=y
+CONFIG_FEATURE_FANCY_ECHO=y
+CONFIG_ENV=y
+# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set
+CONFIG_EXPAND=y
+# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set
+CONFIG_EXPR=y
+CONFIG_EXPR_MATH_SUPPORT_64=y
+CONFIG_FALSE=y
+CONFIG_FOLD=y
+# CONFIG_FSYNC is not set
+CONFIG_HEAD=y
+# CONFIG_FEATURE_FANCY_HEAD is not set
+CONFIG_INSTALL=y
+# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
+CONFIG_LN=y
+# CONFIG_LOGNAME is not set
+CONFIG_LS=y
+CONFIG_FEATURE_LS_FILETYPES=y
+CONFIG_FEATURE_LS_FOLLOWLINKS=y
+CONFIG_FEATURE_LS_RECURSIVE=y
+CONFIG_FEATURE_LS_SORTFILES=y
+CONFIG_FEATURE_LS_TIMESTAMPS=y
+CONFIG_FEATURE_LS_USERNAME=y
+CONFIG_FEATURE_LS_COLOR=y
+# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
+CONFIG_MD5SUM=y
+CONFIG_MKDIR=y
+# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set
+CONFIG_MKFIFO=y
+CONFIG_MKNOD=y
+CONFIG_MV=y
+# CONFIG_FEATURE_MV_LONG_OPTIONS is not set
+CONFIG_NICE=y
+CONFIG_NOHUP=y
+CONFIG_OD=y
+CONFIG_PRINTENV=y
+CONFIG_PRINTF=y
+CONFIG_PWD=y
+CONFIG_READLINK=y
+CONFIG_FEATURE_READLINK_FOLLOW=y
+CONFIG_REALPATH=y
+CONFIG_RM=y
+CONFIG_RMDIR=y
+CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y
+CONFIG_SEQ=y
+CONFIG_SHA1SUM=y
+CONFIG_SHA256SUM=y
+CONFIG_SHA512SUM=y
+# CONFIG_SHA3SUM is not set
+CONFIG_SLEEP=y
+CONFIG_FEATURE_FANCY_SLEEP=y
+CONFIG_FEATURE_FLOAT_SLEEP=y
+CONFIG_SORT=y
+# CONFIG_FEATURE_SORT_BIG is not set
+CONFIG_SPLIT=y
+# CONFIG_FEATURE_SPLIT_FANCY is not set
+CONFIG_STAT=y
+# CONFIG_FEATURE_STAT_FORMAT is not set
+CONFIG_STTY=y
+# CONFIG_SUM is not set
+CONFIG_SYNC=y
+CONFIG_TAC=y
+CONFIG_TAIL=y
+CONFIG_FEATURE_FANCY_TAIL=y
+CONFIG_TEE=y
+# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set
+CONFIG_TRUE=y
+# CONFIG_TTY is not set
+CONFIG_UNAME=y
+CONFIG_UNEXPAND=y
+CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y
+CONFIG_UNIQ=y
+CONFIG_USLEEP=y
+CONFIG_UUDECODE=y
+CONFIG_UUENCODE=y
+CONFIG_WC=y
+# CONFIG_FEATURE_WC_LARGE is not set
+CONFIG_WHOAMI=y
+CONFIG_YES=y
+
+#
+# Common options for cp and mv
+#
+CONFIG_FEATURE_PRESERVE_HARDLINKS=y
+
+#
+# Common options for ls, more and telnet
+#
+CONFIG_FEATURE_AUTOWIDTH=y
+
+#
+# Common options for df, du, ls
+#
+CONFIG_FEATURE_HUMAN_READABLE=y
+
+#
+# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum
+#
+CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
+
+#
+# Console Utilities
+#
+# CONFIG_CHVT is not set
+# CONFIG_FGCONSOLE is not set
+CONFIG_CLEAR=y
+# CONFIG_DEALLOCVT is not set
+# CONFIG_DUMPKMAP is not set
+# CONFIG_KBD_MODE is not set
+# CONFIG_LOADFONT is not set
+# CONFIG_LOADKMAP is not set
+# CONFIG_OPENVT is not set
+CONFIG_RESET=y
+CONFIG_RESIZE=y
+# CONFIG_FEATURE_RESIZE_PRINT is not set
+CONFIG_SETCONSOLE=y
+# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
+# CONFIG_SETFONT is not set
+# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
+CONFIG_DEFAULT_SETFONT_DIR=""
+# CONFIG_SETKEYCODES is not set
+# CONFIG_SETLOGCONS is not set
+# CONFIG_SHOWKEY is not set
+# CONFIG_FEATURE_LOADFONT_PSF2 is not set
+# CONFIG_FEATURE_LOADFONT_RAW is not set
+
+#
+# Debian Utilities
+#
+CONFIG_MKTEMP=y
+# CONFIG_PIPE_PROGRESS is not set
+CONFIG_RUN_PARTS=y
+# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
+CONFIG_FEATURE_RUN_PARTS_FANCY=y
+# CONFIG_START_STOP_DAEMON is not set
+# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
+# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
+CONFIG_WHICH=y
+
+#
+# Editors
+#
+CONFIG_AWK=y
+# CONFIG_FEATURE_AWK_LIBM is not set
+CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y
+CONFIG_CMP=y
+CONFIG_DIFF=y
+CONFIG_FEATURE_DIFF_LONG_OPTIONS=y
+CONFIG_FEATURE_DIFF_DIR=y
+# CONFIG_ED is not set
+CONFIG_PATCH=y
+CONFIG_SED=y
+# CONFIG_VI is not set
+CONFIG_FEATURE_VI_MAX_LEN=0
+# CONFIG_FEATURE_VI_8BIT is not set
+# CONFIG_FEATURE_VI_COLON is not set
+# CONFIG_FEATURE_VI_YANKMARK is not set
+# CONFIG_FEATURE_VI_SEARCH is not set
+# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
+# CONFIG_FEATURE_VI_USE_SIGNALS is not set
+# CONFIG_FEATURE_VI_DOT_CMD is not set
+# CONFIG_FEATURE_VI_READONLY is not set
+# CONFIG_FEATURE_VI_SETOPTS is not set
+# CONFIG_FEATURE_VI_SET is not set
+# CONFIG_FEATURE_VI_WIN_RESIZE is not set
+# CONFIG_FEATURE_VI_ASK_TERMINAL is not set
+CONFIG_FEATURE_ALLOW_EXEC=y
+
+#
+# Finding Utilities
+#
+CONFIG_FIND=y
+CONFIG_FEATURE_FIND_PRINT0=y
+CONFIG_FEATURE_FIND_MTIME=y
+CONFIG_FEATURE_FIND_MMIN=y
+CONFIG_FEATURE_FIND_PERM=y
+CONFIG_FEATURE_FIND_TYPE=y
+CONFIG_FEATURE_FIND_XDEV=y
+CONFIG_FEATURE_FIND_MAXDEPTH=y
+CONFIG_FEATURE_FIND_NEWER=y
+# CONFIG_FEATURE_FIND_INUM is not set
+CONFIG_FEATURE_FIND_EXEC=y
+CONFIG_FEATURE_FIND_USER=y
+CONFIG_FEATURE_FIND_GROUP=y
+CONFIG_FEATURE_FIND_NOT=y
+CONFIG_FEATURE_FIND_DEPTH=y
+CONFIG_FEATURE_FIND_PAREN=y
+CONFIG_FEATURE_FIND_SIZE=y
+CONFIG_FEATURE_FIND_PRUNE=y
+# CONFIG_FEATURE_FIND_DELETE is not set
+CONFIG_FEATURE_FIND_PATH=y
+CONFIG_FEATURE_FIND_REGEX=y
+# CONFIG_FEATURE_FIND_CONTEXT is not set
+# CONFIG_FEATURE_FIND_LINKS is not set
+CONFIG_GREP=y
+CONFIG_FEATURE_GREP_EGREP_ALIAS=y
+CONFIG_FEATURE_GREP_FGREP_ALIAS=y
+CONFIG_FEATURE_GREP_CONTEXT=y
+CONFIG_XARGS=y
+CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
+CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
+# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set
+CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
+
+#
+# Init Utilities
+#
+# CONFIG_BOOTCHARTD is not set
+# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
+# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
+# CONFIG_HALT is not set
+# CONFIG_FEATURE_CALL_TELINIT is not set
+CONFIG_TELINIT_PATH=""
+# CONFIG_INIT is not set
+# CONFIG_FEATURE_USE_INITTAB is not set
+# CONFIG_FEATURE_KILL_REMOVED is not set
+CONFIG_FEATURE_KILL_DELAY=0
+# CONFIG_FEATURE_INIT_SCTTY is not set
+# CONFIG_FEATURE_INIT_SYSLOG is not set
+# CONFIG_FEATURE_EXTRA_QUIET is not set
+# CONFIG_FEATURE_INIT_COREDUMPS is not set
+# CONFIG_FEATURE_INITRD is not set
+CONFIG_INIT_TERMINAL_TYPE=""
+# CONFIG_MESG is not set
+# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
+
+#
+# Login/Password Management Utilities
+#
+# CONFIG_ADD_SHELL is not set
+# CONFIG_REMOVE_SHELL is not set
+# CONFIG_FEATURE_SHADOWPASSWDS is not set
+# CONFIG_USE_BB_PWD_GRP is not set
+# CONFIG_USE_BB_SHADOW is not set
+CONFIG_USE_BB_CRYPT=y
+# CONFIG_USE_BB_CRYPT_SHA is not set
+# CONFIG_ADDUSER is not set
+# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
+# CONFIG_FEATURE_CHECK_NAMES is not set
+CONFIG_FIRST_SYSTEM_ID=0
+CONFIG_LAST_SYSTEM_ID=0
+# CONFIG_ADDGROUP is not set
+# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set
+# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
+# CONFIG_DELUSER is not set
+# CONFIG_DELGROUP is not set
+# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
+# CONFIG_GETTY is not set
+# CONFIG_LOGIN is not set
+# CONFIG_LOGIN_SESSION_AS_CHILD is not set
+# CONFIG_PAM is not set
+# CONFIG_LOGIN_SCRIPTS is not set
+# CONFIG_FEATURE_NOLOGIN is not set
+# CONFIG_FEATURE_SECURETTY is not set
+# CONFIG_PASSWD is not set
+# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
+# CONFIG_CRYPTPW is not set
+# CONFIG_CHPASSWD is not set
+CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
+# CONFIG_SU is not set
+# CONFIG_FEATURE_SU_SYSLOG is not set
+# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
+# CONFIG_SULOGIN is not set
+# CONFIG_VLOCK is not set
+
+#
+# Linux Ext2 FS Progs
+#
+CONFIG_CHATTR=y
+# CONFIG_FSCK is not set
+CONFIG_LSATTR=y
+CONFIG_TUNE2FS=y
+
+#
+# Linux Module Utilities
+#
+CONFIG_MODINFO=y
+CONFIG_MODPROBE_SMALL=y
+CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y
+# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
+# CONFIG_INSMOD is not set
+# CONFIG_RMMOD is not set
+# CONFIG_LSMOD is not set
+# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
+# CONFIG_MODPROBE is not set
+# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
+# CONFIG_DEPMOD is not set
+
+#
+# Options common to multiple modutils
+#
+# CONFIG_FEATURE_2_4_MODULES is not set
+CONFIG_FEATURE_INSMOD_TRY_MMAP=y
+# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
+# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
+# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
+# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
+# CONFIG_FEATURE_MODUTILS_ALIAS is not set
+# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
+CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
+
+#
+# Linux System Utilities
+#
+CONFIG_BLOCKDEV=y
+CONFIG_FSTRIM=y
+# CONFIG_MDEV is not set
+# CONFIG_FEATURE_MDEV_CONF is not set
+# CONFIG_FEATURE_MDEV_RENAME is not set
+# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
+# CONFIG_FEATURE_MDEV_EXEC is not set
+# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
+CONFIG_REV=y
+# CONFIG_ACPID is not set
+# CONFIG_FEATURE_ACPID_COMPAT is not set
+CONFIG_BLKID=y
+CONFIG_FEATURE_BLKID_TYPE=y
+CONFIG_DMESG=y
+# CONFIG_FEATURE_DMESG_PRETTY is not set
+CONFIG_FBSET=y
+CONFIG_FEATURE_FBSET_FANCY=y
+CONFIG_FEATURE_DMESG_COLOR=y
+# CONFIG_FEATURE_FBSET_READMODE is not set
+# CONFIG_FDFLUSH is not set
+# CONFIG_FDFORMAT is not set
+CONFIG_FDISK=y
+# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
+CONFIG_FEATURE_FDISK_WRITABLE=y
+# CONFIG_FEATURE_AIX_LABEL is not set
+# CONFIG_FEATURE_SGI_LABEL is not set
+# CONFIG_FEATURE_SUN_LABEL is not set
+# CONFIG_FEATURE_OSF_LABEL is not set
+# CONFIG_FEATURE_GPT_LABEL is not set
+# CONFIG_FEATURE_FDISK_ADVANCED is not set
+# CONFIG_FINDFS is not set
+# CONFIG_FLOCK is not set
+CONFIG_FREERAMDISK=y
+# CONFIG_FSCK_MINIX is not set
+CONFIG_MKFS_EXT2=y
+# CONFIG_MKFS_MINIX is not set
+# CONFIG_FEATURE_MINIX2 is not set
+# CONFIG_MKFS_REISER is not set
+CONFIG_MKFS_VFAT=y
+CONFIG_GETOPT=y
+# CONFIG_FEATURE_GETOPT_LONG is not set
+CONFIG_HEXDUMP=y
+# CONFIG_FEATURE_HEXDUMP_REVERSE is not set
+# CONFIG_HD is not set
+# CONFIG_HWCLOCK is not set
+# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set
+# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
+# CONFIG_IPCRM is not set
+# CONFIG_IPCS is not set
+CONFIG_LOSETUP=y
+CONFIG_LSPCI=y
+CONFIG_LSUSB=y
+CONFIG_MKSWAP=y
+# CONFIG_FEATURE_MKSWAP_UUID is not set
+CONFIG_MORE=y
+CONFIG_MOUNT=y
+# CONFIG_FEATURE_MOUNT_FAKE is not set
+# CONFIG_FEATURE_MOUNT_VERBOSE is not set
+# CONFIG_FEATURE_MOUNT_HELPERS is not set
+CONFIG_FEATURE_MOUNT_LABEL=y
+# CONFIG_FEATURE_MOUNT_NFS is not set
+CONFIG_FEATURE_MOUNT_CIFS=y
+CONFIG_FEATURE_MOUNT_FLAGS=y
+CONFIG_FEATURE_MOUNT_FSTAB=y
+# CONFIG_PIVOT_ROOT is not set
+# CONFIG_RDATE is not set
+CONFIG_RDEV=y
+# CONFIG_READPROFILE is not set
+# CONFIG_RTCWAKE is not set
+# CONFIG_SCRIPT is not set
+# CONFIG_SCRIPTREPLAY is not set
+# CONFIG_SETARCH is not set
+CONFIG_SWAPONOFF=y
+# CONFIG_FEATURE_SWAPON_PRI is not set
+# CONFIG_SWITCH_ROOT is not set
+CONFIG_UMOUNT=y
+# CONFIG_FEATURE_UMOUNT_ALL is not set
+
+#
+# Common options for mount/umount
+#
+CONFIG_FEATURE_MOUNT_LOOP=y
+# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
+# CONFIG_FEATURE_MTAB_SUPPORT is not set
+CONFIG_VOLUMEID=y
+
+#
+# Filesystem/Volume identification
+#
+# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
+# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
+CONFIG_FEATURE_VOLUMEID_EXFAT=y
+CONFIG_FEATURE_VOLUMEID_EXT=y
+CONFIG_FEATURE_VOLUMEID_F2FS=y
+CONFIG_FEATURE_VOLUMEID_FAT=y
+# CONFIG_FEATURE_VOLUMEID_HFS is not set
+CONFIG_FEATURE_VOLUMEID_ISO9660=y
+# CONFIG_FEATURE_VOLUMEID_JFS is not set
+# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
+CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y
+# CONFIG_FEATURE_VOLUMEID_LUKS is not set
+# CONFIG_FEATURE_VOLUMEID_NILFS is not set
+CONFIG_FEATURE_VOLUMEID_NTFS=y
+# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
+# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
+# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
+CONFIG_FEATURE_VOLUMEID_SQUASHFS=y
+# CONFIG_FEATURE_VOLUMEID_SYSV is not set
+# CONFIG_FEATURE_VOLUMEID_UDF is not set
+# CONFIG_FEATURE_VOLUMEID_XFS is not set
+
+#
+# Miscellaneous Utilities
+#
+# CONFIG_CONSPY is not set
+CONFIG_LESS=y
+CONFIG_FEATURE_LESS_MAXLINES=65536
+# CONFIG_FEATURE_LESS_BRACKETS is not set
+# CONFIG_FEATURE_LESS_FLAGS is not set
+CONFIG_FEATURE_LESS_MARKS=y
+CONFIG_FEATURE_LESS_REGEXP=y
+CONFIG_FEATURE_LESS_WINCH=y
+# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
+# CONFIG_FEATURE_LESS_DASHCMD is not set
+# CONFIG_FEATURE_LESS_LINENUMS is not set
+CONFIG_NANDWRITE=y
+CONFIG_NANDDUMP=y
+# CONFIG_RFKILL is not set
+CONFIG_SETSERIAL=y
+# CONFIG_UBIATTACH is not set
+# CONFIG_UBIDETACH is not set
+# CONFIG_UBIMKVOL is not set
+# CONFIG_UBIRMVOL is not set
+# CONFIG_UBIRSVOL is not set
+# CONFIG_UBIUPDATEVOL is not set
+# CONFIG_WALL is not set
+# CONFIG_ADJTIMEX is not set
+CONFIG_BBCONFIG=y
+CONFIG_FEATURE_COMPRESS_BBCONFIG=y
+# CONFIG_BEEP is not set
+CONFIG_FEATURE_BEEP_FREQ=0
+CONFIG_FEATURE_BEEP_LENGTH_MS=0
+# CONFIG_CHAT is not set
+# CONFIG_FEATURE_CHAT_NOFAIL is not set
+# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
+# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
+# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
+# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
+# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
+# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
+# CONFIG_CHRT is not set
+# CONFIG_CROND is not set
+# CONFIG_FEATURE_CROND_D is not set
+# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
+CONFIG_FEATURE_CROND_DIR=""
+# CONFIG_CRONTAB is not set
+CONFIG_DC=y
+# CONFIG_FEATURE_DC_LIBM is not set
+# CONFIG_DEVFSD is not set
+# CONFIG_DEVFSD_MODLOAD is not set
+# CONFIG_DEVFSD_FG_NP is not set
+# CONFIG_DEVFSD_VERBOSE is not set
+# CONFIG_FEATURE_DEVFS is not set
+CONFIG_DEVMEM=y
+# CONFIG_EJECT is not set
+# CONFIG_FEATURE_EJECT_SCSI is not set
+# CONFIG_FBSPLASH is not set
+# CONFIG_FLASHCP is not set
+# CONFIG_FLASH_LOCK is not set
+# CONFIG_FLASH_UNLOCK is not set
+# CONFIG_FLASH_ERASEALL is not set
+# CONFIG_IONICE is not set
+# CONFIG_INOTIFYD is not set
+# CONFIG_LAST is not set
+# CONFIG_FEATURE_LAST_SMALL is not set
+# CONFIG_FEATURE_LAST_FANCY is not set
+# CONFIG_HDPARM is not set
+# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
+# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
+# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
+CONFIG_MAKEDEVS=y
+# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
+CONFIG_FEATURE_MAKEDEVS_TABLE=y
+# CONFIG_MAN is not set
+# CONFIG_MICROCOM is not set
+CONFIG_MOUNTPOINT=y
+# CONFIG_MT is not set
+# CONFIG_RAIDAUTORUN is not set
+# CONFIG_READAHEAD is not set
+# CONFIG_RUNLEVEL is not set
+# CONFIG_RX is not set
+CONFIG_SETSID=y
+CONFIG_STRINGS=y
+# CONFIG_TASKSET is not set
+# CONFIG_FEATURE_TASKSET_FANCY is not set
+CONFIG_TIME=y
+# CONFIG_TIMEOUT is not set
+CONFIG_TTYSIZE=y
+# CONFIG_VOLNAME is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Networking Utilities
+#
+# CONFIG_NAMEIF is not set
+# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
+# CONFIG_NBDCLIENT is not set
+# CONFIG_NC is not set
+# CONFIG_NC_SERVER is not set
+# CONFIG_NC_EXTRA is not set
+# CONFIG_NC_110_COMPAT is not set
+# CONFIG_PING is not set
+# CONFIG_PING6 is not set
+# CONFIG_FEATURE_FANCY_PING is not set
+# CONFIG_WHOIS is not set
+# CONFIG_FEATURE_IPV6 is not set
+# CONFIG_FEATURE_UNIX_LOCAL is not set
+# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set
+# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
+# CONFIG_ARP is not set
+# CONFIG_ARPING is not set
+# CONFIG_BRCTL is not set
+# CONFIG_FEATURE_BRCTL_FANCY is not set
+# CONFIG_FEATURE_BRCTL_SHOW is not set
+# CONFIG_DNSD is not set
+# CONFIG_ETHER_WAKE is not set
+# CONFIG_FAKEIDENTD is not set
+# CONFIG_FTPD is not set
+# CONFIG_FEATURE_FTP_WRITE is not set
+# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
+# CONFIG_FTPGET is not set
+# CONFIG_FTPPUT is not set
+# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
+# CONFIG_HOSTNAME is not set
+# CONFIG_HTTPD is not set
+# CONFIG_FEATURE_HTTPD_RANGES is not set
+# CONFIG_FEATURE_HTTPD_USE_SENDFILE is not set
+# CONFIG_FEATURE_HTTPD_SETUID is not set
+# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
+# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
+# CONFIG_FEATURE_HTTPD_CGI is not set
+# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
+# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
+# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
+# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
+# CONFIG_FEATURE_HTTPD_PROXY is not set
+# CONFIG_FEATURE_HTTPD_GZIP is not set
+# CONFIG_IFCONFIG is not set
+# CONFIG_FEATURE_IFCONFIG_STATUS is not set
+# CONFIG_FEATURE_IFCONFIG_SLIP is not set
+# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
+# CONFIG_FEATURE_IFCONFIG_HW is not set
+# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set
+# CONFIG_IFENSLAVE is not set
+# CONFIG_IFPLUGD is not set
+# CONFIG_IFUPDOWN is not set
+CONFIG_IFUPDOWN_IFSTATE_PATH=""
+# CONFIG_FEATURE_IFUPDOWN_IP is not set
+# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set
+# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
+# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
+# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
+# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
+# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
+# CONFIG_INETD is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
+# CONFIG_FEATURE_INETD_RPC is not set
+# CONFIG_IP is not set
+# CONFIG_FEATURE_IP_ADDRESS is not set
+# CONFIG_FEATURE_IP_LINK is not set
+# CONFIG_FEATURE_IP_ROUTE is not set
+# CONFIG_FEATURE_IP_TUNNEL is not set
+# CONFIG_FEATURE_IP_RULE is not set
+# CONFIG_FEATURE_IP_SHORT_FORMS is not set
+# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
+# CONFIG_IPADDR is not set
+# CONFIG_IPLINK is not set
+# CONFIG_IPROUTE is not set
+# CONFIG_IPTUNNEL is not set
+# CONFIG_IPRULE is not set
+# CONFIG_IPCALC is not set
+# CONFIG_FEATURE_IPCALC_FANCY is not set
+# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
+# CONFIG_NETSTAT is not set
+# CONFIG_FEATURE_NETSTAT_WIDE is not set
+# CONFIG_FEATURE_NETSTAT_PRG is not set
+# CONFIG_NSLOOKUP is not set
+# CONFIG_NTPD is not set
+# CONFIG_FEATURE_NTPD_SERVER is not set
+# CONFIG_PSCAN is not set
+# CONFIG_ROUTE is not set
+# CONFIG_SLATTACH is not set
+# CONFIG_TCPSVD is not set
+# CONFIG_TELNET is not set
+# CONFIG_FEATURE_TELNET_TTYPE is not set
+# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
+# CONFIG_TELNETD is not set
+# CONFIG_FEATURE_TELNETD_STANDALONE is not set
+# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
+# CONFIG_TFTP is not set
+# CONFIG_TFTPD is not set
+# CONFIG_FEATURE_TFTP_GET is not set
+# CONFIG_FEATURE_TFTP_PUT is not set
+# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
+# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
+# CONFIG_TFTP_DEBUG is not set
+# CONFIG_TRACEROUTE is not set
+# CONFIG_TRACEROUTE6 is not set
+# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
+# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set
+# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
+# CONFIG_TUNCTL is not set
+# CONFIG_FEATURE_TUNCTL_UG is not set
+# CONFIG_UDHCPC6 is not set
+# CONFIG_UDHCPD is not set
+# CONFIG_DHCPRELAY is not set
+# CONFIG_DUMPLEASES is not set
+# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
+# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
+CONFIG_DHCPD_LEASES_FILE=""
+# CONFIG_UDHCPC is not set
+# CONFIG_FEATURE_UDHCPC_ARPING is not set
+# CONFIG_FEATURE_UDHCP_PORT is not set
+CONFIG_UDHCP_DEBUG=0
+# CONFIG_FEATURE_UDHCP_RFC3397 is not set
+# CONFIG_FEATURE_UDHCP_8021Q is not set
+CONFIG_UDHCPC_DEFAULT_SCRIPT=""
+CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
+CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
+# CONFIG_UDPSVD is not set
+# CONFIG_VCONFIG is not set
+# CONFIG_WGET is not set
+# CONFIG_FEATURE_WGET_STATUSBAR is not set
+# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
+# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set
+# CONFIG_FEATURE_WGET_TIMEOUT is not set
+# CONFIG_ZCIP is not set
+
+#
+# Print Utilities
+#
+# CONFIG_LPD is not set
+# CONFIG_LPR is not set
+# CONFIG_LPQ is not set
+
+#
+# Mail Utilities
+#
+# CONFIG_MAKEMIME is not set
+CONFIG_FEATURE_MIME_CHARSET=""
+# CONFIG_POPMAILDIR is not set
+# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
+# CONFIG_REFORMIME is not set
+# CONFIG_FEATURE_REFORMIME_COMPAT is not set
+# CONFIG_SENDMAIL is not set
+
+#
+# Process Utilities
+#
+# CONFIG_IOSTAT is not set
+CONFIG_LSOF=y
+# CONFIG_MPSTAT is not set
+# CONFIG_NMETER is not set
+# CONFIG_PMAP is not set
+# CONFIG_POWERTOP is not set
+CONFIG_PSTREE=y
+# CONFIG_PWDX is not set
+# CONFIG_SMEMCAP is not set
+CONFIG_TOP=y
+CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
+CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
+# CONFIG_FEATURE_TOP_SMP_CPU is not set
+CONFIG_FEATURE_TOP_DECIMALS=y
+# CONFIG_FEATURE_TOP_SMP_PROCESS is not set
+CONFIG_FEATURE_TOPMEM=y
+CONFIG_UPTIME=y
+# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
+CONFIG_FREE=y
+CONFIG_FUSER=y
+CONFIG_KILL=y
+CONFIG_KILLALL=y
+CONFIG_KILLALL5=y
+CONFIG_PGREP=y
+CONFIG_PIDOF=y
+CONFIG_FEATURE_PIDOF_SINGLE=y
+CONFIG_FEATURE_PIDOF_OMIT=y
+CONFIG_PKILL=y
+CONFIG_PS=y
+CONFIG_FEATURE_PS_WIDE=y
+CONFIG_FEATURE_PS_LONG=y
+# CONFIG_FEATURE_PS_TIME is not set
+# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
+# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
+CONFIG_RENICE=y
+CONFIG_BB_SYSCTL=y
+CONFIG_FEATURE_SHOW_THREADS=y
+CONFIG_WATCH=y
+
+#
+# Runit Utilities
+#
+# CONFIG_RUNSV is not set
+# CONFIG_RUNSVDIR is not set
+# CONFIG_FEATURE_RUNSVDIR_LOG is not set
+# CONFIG_SV is not set
+CONFIG_SV_DEFAULT_SERVICE_DIR=""
+# CONFIG_SVLOGD is not set
+# CONFIG_CHPST is not set
+# CONFIG_SETUIDGID is not set
+# CONFIG_ENVUIDGID is not set
+# CONFIG_ENVDIR is not set
+# CONFIG_SOFTLIMIT is not set
+
+#
+# SELinux Utilities
+#
+CONFIG_CHCON=y
+# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
+CONFIG_GETENFORCE=y
+CONFIG_GETSEBOOL=y
+# CONFIG_LOAD_POLICY is not set
+CONFIG_MATCHPATHCON=y
+CONFIG_RESTORECON=y
+# CONFIG_RUNCON is not set
+# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
+CONFIG_SELINUXENABLED=y
+CONFIG_SETENFORCE=y
+CONFIG_SETFILES=y
+# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
+CONFIG_SETSEBOOL=y
+CONFIG_SESTATUS=y
+
+#
+# Shells
+#
+CONFIG_ASH=y
+CONFIG_ASH_BASH_COMPAT=y
+# CONFIG_ASH_IDLE_TIMEOUT is not set
+CONFIG_ASH_JOB_CONTROL=y
+CONFIG_ASH_ALIAS=y
+CONFIG_ASH_GETOPTS=y
+CONFIG_ASH_BUILTIN_ECHO=y
+CONFIG_ASH_BUILTIN_PRINTF=y
+CONFIG_ASH_BUILTIN_TEST=y
+CONFIG_ASH_CMDCMD=y
+# CONFIG_ASH_MAIL is not set
+CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
+# CONFIG_ASH_RANDOM_SUPPORT is not set
+CONFIG_ASH_EXPAND_PRMT=y
+# CONFIG_CTTYHACK is not set
+# CONFIG_HUSH is not set
+# CONFIG_HUSH_BASH_COMPAT is not set
+# CONFIG_HUSH_BRACE_EXPANSION is not set
+# CONFIG_HUSH_HELP is not set
+# CONFIG_HUSH_INTERACTIVE is not set
+# CONFIG_HUSH_SAVEHISTORY is not set
+# CONFIG_HUSH_JOB is not set
+# CONFIG_HUSH_TICK is not set
+# CONFIG_HUSH_IF is not set
+# CONFIG_HUSH_LOOPS is not set
+# CONFIG_HUSH_CASE is not set
+# CONFIG_HUSH_FUNCTIONS is not set
+# CONFIG_HUSH_LOCAL is not set
+# CONFIG_HUSH_RANDOM_SUPPORT is not set
+# CONFIG_HUSH_EXPORT_N is not set
+# CONFIG_HUSH_MODE_X is not set
+# CONFIG_MSH is not set
+CONFIG_FEATURE_SH_IS_ASH=y
+# CONFIG_FEATURE_SH_IS_HUSH is not set
+# CONFIG_FEATURE_SH_IS_NONE is not set
+# CONFIG_FEATURE_BASH_IS_ASH is not set
+# CONFIG_FEATURE_BASH_IS_HUSH is not set
+CONFIG_FEATURE_BASH_IS_NONE=y
+CONFIG_SH_MATH_SUPPORT=y
+CONFIG_SH_MATH_SUPPORT_64=y
+CONFIG_FEATURE_SH_EXTRA_QUIET=y
+# CONFIG_FEATURE_SH_STANDALONE is not set
+# CONFIG_FEATURE_SH_NOFORK is not set
+# CONFIG_FEATURE_SH_HISTFILESIZE is not set
+
+#
+# System Logging Utilities
+#
+# CONFIG_SYSLOGD is not set
+# CONFIG_FEATURE_ROTATE_LOGFILE is not set
+# CONFIG_FEATURE_REMOTE_LOG is not set
+# CONFIG_FEATURE_SYSLOGD_DUP is not set
+# CONFIG_FEATURE_SYSLOGD_CFG is not set
+CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
+# CONFIG_FEATURE_IPC_SYSLOG is not set
+CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
+# CONFIG_LOGREAD is not set
+# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
+# CONFIG_FEATURE_KMSG_SYSLOG is not set
+# CONFIG_KLOGD is not set
+# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
+# CONFIG_LOGGER is not set
diff --git a/busybox-minimal.links b/busybox-minimal.links
new file mode 100644
index 0000000..e1df95c
--- a/dev/null
+++ b/busybox-minimal.links
@@ -0,0 +1,184 @@
+/bin/bunzip2
+/bin/bzcat
+/bin/date
+/bin/groups
+/bin/id
+/bin/touch
+/bin/base64
+/bin/patch
+/bin/find
+/bin/grep
+/bin/egrep
+/bin/fgrep
+/bin/xargs
+/sbin/nandwrite
+/sbin/nanddump
+/bin/setserial
+/sbin/modinfo
+/sbin/modprobe
+/sbin/depmod
+/sbin/insmod
+/sbin/lsmod
+/sbin/rmmod
+/bin/lsof
+/bin/pstree
+/bin/ash
+/bin/sh
+/sbin/blockdev
+/bin/rev
+/bin/[
+/bin/[[
+/bin/awk
+/bin/basename
+/bin/bbconfig
+/sbin/blkid
+/bin/bzip2
+/bin/cal
+/bin/cat
+/bin/catv
+/bin/chattr
+/bin/chcon
+/bin/chgrp
+/bin/chmod
+/bin/chown
+/sbin/chroot
+/bin/clear
+/bin/cmp
+/bin/cp
+/bin/cpio
+/bin/cut
+/bin/dc
+/bin/dd
+/sbin/devmem
+/bin/df
+/bin/diff
+/bin/dirname
+/bin/dmesg
+/bin/dos2unix
+/bin/du
+/bin/echo
+/bin/env
+/bin/expand
+/bin/expr
+/bin/false
+/sbin/fbset
+/sbin/fdisk
+/bin/fold
+/bin/free
+/sbin/freeramdisk
+/sbin/fstrim
+/bin/fuser
+/bin/getenforce
+/bin/getopt
+/bin/getsebool
+/bin/grep
+/bin/groups
+/bin/gunzip
+/bin/gzip
+/bin/head
+/bin/hexdump
+/bin/install
+/bin/kill
+/bin/killall
+/sbin/killall5
+/bin/less
+/bin/ln
+/sbin/losetup
+/bin/ls
+/bin/lsattr
+/bin/lspci
+/bin/lsusb
+/bin/lzcat
+/bin/lzop
+/bin/lzopcat
+/sbin/makedevs
+/sbin/matchpathcon
+/bin/md5sum
+/bin/mkdir
+/sbin/mkdosfs
+/sbin/mke2fs
+/bin/mkfifo
+/sbin/mkfs.ext2
+/sbin/mkfs.vfat
+/bin/mknod
+/sbin/mkswap
+/bin/mktemp
+/bin/more
+/bin/mount
+/bin/mountpoint
+/bin/mv
+/bin/nice
+/bin/nohup
+/bin/od
+/bin/pgrep
+/bin/pidof
+/bin/pkill
+/bin/printenv
+/bin/printf
+/bin/ps
+/bin/pwd
+/sbin/rdev
+/bin/readlink
+/bin/realpath
+/bin/renice
+/bin/reset
+/bin/resize
+/sbin/restorecon
+/bin/rev
+/bin/rm
+/bin/rmdir
+/bin/run-parts
+/bin/sed
+/sbin/selinuxenabled
+/bin/seq
+/sbin/sestatus
+/sbin/setconsole
+/sbin/setenforce
+/sbin/setfiles
+/bin/setsebool
+/bin/setserial
+/bin/setsid
+/bin/sha1sum
+/bin/sha256sum
+/bin/sha512sum
+/bin/sleep
+/bin/sort
+/bin/split
+/bin/stat
+/bin/strings
+/bin/stty
+/sbin/swapoff
+/sbin/swapon
+/bin/sync
+/sbin/sysctl
+/bin/tac
+/bin/tail
+/bin/tar
+/bin/tee
+/bin/test
+/bin/time
+/bin/top
+/bin/tr
+/bin/true
+/bin/ttysize
+/sbin/tune2fs
+/bin/umount
+/bin/uname
+/bin/unexpand
+/bin/uniq
+/bin/unix2dos
+/bin/unxz
+/bin/unlzma
+/bin/unlzop
+/bin/unzip
+/bin/uptime
+/bin/usleep
+/bin/uudecode
+/bin/uuencode
+/bin/watch
+/bin/wc
+/bin/which
+/bin/whoami
+/bin/xzcat
+/bin/yes
+/bin/zcat
diff --git a/busybox-minimal.sources b/busybox-minimal.sources
new file mode 100644
index 0000000..01da3e5
--- a/dev/null
+++ b/busybox-minimal.sources
@@ -0,0 +1,51 @@
+android/libc/__set_errno.c
+
+archival/bbunzip.c archival/bzip2.c archival/cpio.c archival/gzip.c archival/lzop.c archival/tar.c archival/unzip.c
+archival/libarchive/data_align.c archival/libarchive/data_extract_all.c archival/libarchive/data_extract_to_stdout.c archival/libarchive/data_skip.c archival/libarchive/decompress_bunzip2.c archival/libarchive/decompress_gunzip.c archival/libarchive/decompress_unlzma.c archival/libarchive/decompress_unxz.c archival/libarchive/filter_accept_all.c archival/libarchive/filter_accept_list.c archival/libarchive/filter_accept_reject_list.c archival/libarchive/find_list_entry.c archival/libarchive/get_header_cpio.c archival/libarchive/get_header_tar.c archival/libarchive/header_list.c archival/libarchive/header_skip.c archival/libarchive/header_verbose_list.c archival/libarchive/init_handle.c archival/libarchive/lzo1x_1.c archival/libarchive/lzo1x_1o.c archival/libarchive/lzo1x_d.c archival/libarchive/open_transformer.c archival/libarchive/seek_by_jump.c archival/libarchive/seek_by_read.c
+console-tools/clear.c console-tools/reset.c console-tools/resize.c console-tools/setconsole.c
+coreutils/basename.c coreutils/cal.c coreutils/cat.c coreutils/catv.c coreutils/chgrp.c coreutils/chmod.c coreutils/chown.c coreutils/chroot.c coreutils/cp.c coreutils/cut.c coreutils/date.c coreutils/dd.c coreutils/df.c coreutils/dirname.c coreutils/dos2unix.c coreutils/du.c coreutils/echo.c coreutils/env.c coreutils/expand.c coreutils/expr.c coreutils/false.c coreutils/fold.c coreutils/head.c coreutils/id.c coreutils/install.c coreutils/ln.c coreutils/ls.c coreutils/md5_sha1_sum.c coreutils/mkdir.c coreutils/mkfifo.c coreutils/mknod.c coreutils/mv.c coreutils/nice.c coreutils/nohup.c coreutils/od.c coreutils/printenv.c coreutils/printf.c coreutils/pwd.c coreutils/readlink.c coreutils/realpath.c coreutils/rm.c coreutils/rmdir.c coreutils/seq.c coreutils/sleep.c coreutils/sort.c coreutils/split.c coreutils/stat.c coreutils/stty.c coreutils/sync.c coreutils/tac.c coreutils/tail.c coreutils/tee.c coreutils/test.c coreutils/test_ptr_hack.c coreutils/touch.c coreutils/tr.c coreutils/true.c coreutils/uname.c coreutils/uniq.c coreutils/usleep.c coreutils/uudecode.c coreutils/uuencode.c coreutils/wc.c coreutils/whoami.c coreutils/yes.c
+coreutils/libcoreutils/cp_mv_stat.c coreutils/libcoreutils/getopt_mk_fifo_nod.c
+debianutils/mktemp.c debianutils/run_parts.c debianutils/which.c
+e2fsprogs/chattr.c e2fsprogs/e2fs_lib.c e2fsprogs/lsattr.c e2fsprogs/tune2fs.c
+editors/awk.c editors/cmp.c editors/diff.c editors/patch.c editors/sed.c
+findutils/find.c findutils/grep.c findutils/xargs.c
+
+libbb/missing_syscalls.c
+libbb/appletlib.c libbb/ask_confirmation.c libbb/bb_askpass.c libbb/bb_do_delay.c libbb/bb_pwd.c libbb/bb_qsort.c libbb/bb_strtonum.c
+libbb/change_identity.c libbb/chomp.c libbb/compare_string_array.c libbb/concat_path_file.c libbb/concat_subpath_file.c libbb/copy_file.c libbb/copyfd.c
+libbb/crc32.c libbb/default_error_retval.c libbb/device_open.c libbb/dump.c libbb/executable.c libbb/fclose_nonstdin.c
+libbb/fflush_stdout_and_exit.c libbb/fgets_str.c libbb/find_mount_point.c libbb/find_pid_by_name.c libbb/find_root_device.c libbb/full_write.c
+libbb/get_console.c libbb/get_last_path_component.c libbb/get_line_from_file.c libbb/get_shell_name.c libbb/endofname.c libbb/in_ether.c libbb/get_volsize.c
+libbb/getopt32.c libbb/getpty.c libbb/herror_msg.c libbb/human_readable.c libbb/inet_common.c libbb/inode_hash.c libbb/isdirectory.c
+libbb/kernel_version.c libbb/last_char_is.c libbb/lineedit.c libbb/lineedit_ptr_hack.c libbb/llist.c libbb/login.c libbb/loop.c
+libbb/make_directory.c libbb/makedev.c libbb/match_fstype.c libbb/hash_md5_sha.c libbb/bb_bswap_64.c libbb/messages.c libbb/mode_string.c libbb/mtab.c
+libbb/parse_config.c libbb/parse_mode.c libbb/perror_msg.c libbb/perror_nomsg.c libbb/perror_nomsg_and_die.c libbb/pidfile.c libbb/platform.c
+libbb/print_flags.c libbb/printable.c libbb/printable_string.c libbb/process_escape_sequence.c libbb/procps.c libbb/progress.c
+libbb/ptr_to_globals.c libbb/read.c libbb/read_key.c libbb/read_printf.c libbb/recursive_action.c libbb/remove_file.c libbb/run_shell.c
+libbb/safe_gethostname.c libbb/safe_poll.c libbb/safe_strncpy.c libbb/safe_write.c libbb/setup_environment.c libbb/signals.c
+libbb/simplify_path.c libbb/single_argv.c libbb/skip_whitespace.c libbb/speed_table.c libbb/str_tolower.c libbb/strrstr.c
+libbb/time.c libbb/trim.c libbb/u_signal_names.c libbb/udp_io.c libbb/uuencode.c
+libbb/vdprintf.c libbb/verror_msg.c libbb/vfork_daemon_rexec.c libbb/warn_ignoring_args.c libbb/wfopen.c
+libbb/wfopen_input.c libbb/write.c libbb/xatonum.c libbb/xconnect.c libbb/xfunc_die.c libbb/xfuncs.c libbb/xfuncs_printf.c
+libbb/xgetcwd.c libbb/xgethostbyname.c libbb/xreadlink.c libbb/xrealloc_vector.c libbb/xregcomp.c libbb/unicode.c
+
+libpwdgrp/uidgid_get.c
+
+
+miscutils/bbconfig.c miscutils/dc.c miscutils/devmem.c miscutils/less.c miscutils/makedevs.c miscutils/mountpoint.c miscutils/nandwrite.c miscutils/setserial.c miscutils/setsid.c miscutils/strings.c miscutils/time.c miscutils/ttysize.c
+modutils/modinfo.c modutils/modprobe-small.c modutils/modutils.c
+
+
+android/selinux/matchpathcon.c android/selinux/stubs.c
+libbb/selinux_common.c selinux/chcon.c selinux/selinuxenabled.c
+selinux/getenforce.c selinux/sestatus.c selinux/setsebool.c
+selinux/getsebool.c selinux/setenforce.c selinux/setfiles.c selinux/matchpathcon.c
+
+util-linux/blkid.c util-linux/blockdev.c util-linux/dmesg.c util-linux/fdisk.c util-linux/freeramdisk.c util-linux/fstrim.c util-linux/getopt.c
+util-linux/hexdump.c util-linux/losetup.c util-linux/lspci.c util-linux/lsusb.c util-linux/mkfs_ext2.c util-linux/mkfs_vfat.c util-linux/mkswap.c
+util-linux/more.c util-linux/mount.c util-linux/rdev.c util-linux/rev.c util-linux/swaponoff.c util-linux/switch_root.c util-linux/umount.c
+
+util-linux/volume_id/get_devname.c util-linux/volume_id/volume_id.c util-linux/volume_id/util.c util-linux/volume_id/ext.c
+util-linux/volume_id/fat.c util-linux/volume_id/iso9660.c util-linux/volume_id/ntfs.c util-linux/volume_id/linux_swap.c
+util-linux/volume_id/exfat.c util-linux/volume_id/squashfs.c util-linux/volume_id/f2fs.c
+
diff --git a/configs/android_ndk_defconfig b/configs/android_ndk_defconfig
index 716ec9a..bdcadc7 100644
--- a/configs/android_ndk_defconfig
+++ b/configs/android_ndk_defconfig
@@ -537,7 +537,7 @@ CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y
# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
# CONFIG_FEATURE_MODUTILS_ALIAS is not set
# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set
-CONFIG_DEFAULT_MODULES_DIR="/system/lib/modules"
+CONFIG_DEFAULT_MODULES_DIR="/lib/modules"
CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
#
diff --git a/coreutils/cal.c b/coreutils/cal.c
index af02608..4f5bbf7 100644
--- a/coreutils/cal.c
+++ b/coreutils/cal.c
@@ -334,7 +334,7 @@ static char *build_row(char *p, unsigned *dp)
col = 0;
do {
day = *dp++;
- if (day != SPACE) {
+ if (day != (unsigned) SPACE) {
if (julian) {
++p;
if (day >= 100) {
diff --git a/coreutils/date.c b/coreutils/date.c
index 9d4a7df..31b53d2 100644
--- a/coreutils/date.c
+++ b/coreutils/date.c
@@ -141,6 +141,7 @@
#if ENABLE_FEATURE_DATE_NANO
# include <sys/syscall.h>
#endif
+#include <android.h>
enum {
OPT_RFC2822 = (1 << 0), /* R */
diff --git a/coreutils/expand.c b/coreutils/expand.c
index bb59af4..466c11a 100644
--- a/coreutils/expand.c
+++ b/coreutils/expand.c
@@ -251,7 +251,7 @@ int expand_main(int argc UNUSED_PARAM, char **argv)
/* Now close stdin also */
/* (if we didn't read from it, it's a no-op) */
if (fclose(stdin))
- bb_perror_msg_and_die(bb_msg_standard_input);
+ bb_perror_msg_and_die("%s", bb_msg_standard_input);
fflush_stdout_and_exit(exit_status);
}
diff --git a/coreutils/expr.c b/coreutils/expr.c
index 5d2fbf2..55a19aa 100644
--- a/coreutils/expr.c
+++ b/coreutils/expr.c
@@ -341,8 +341,8 @@ static VALUE *eval6(void)
"quote\0""length\0""match\0""index\0""substr\0";
VALUE *r, *i1, *i2;
- VALUE *l = l; /* silence gcc */
- VALUE *v = v; /* silence gcc */
+ static VALUE *l = NULL;
+ static VALUE *v = NULL;
int key = *G.args ? index_in_strings(keywords, *G.args) + 1 : 0;
if (key == 0) /* not a keyword */
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 0f35c70..e7490ac 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -607,13 +607,28 @@ static NOINLINE unsigned display_single(const struct dnode *dn)
}
#if ENABLE_FEATURE_LS_USERNAME
else if (G.all_fmt & LIST_ID_NAME) {
- if (option_mask32 & OPT_g) {
- column += printf("%-8.8s ",
- get_cached_groupname(dn->dn_gid));
+ //extend user/group names to 12 char.
+ //if terminal has more than 88 cols (or -w 88 is set)
+ if (G_terminal_width >= 88) {
+ #define UGLONG_FMT "%-12.12s "
+ if (option_mask32 & OPT_g) {
+ column += printf(UGLONG_FMT,
+ get_cached_groupname(dn->dn_gid));
+ } else {
+ column += printf(UGLONG_FMT UGLONG_FMT,
+ get_cached_username(dn->dn_uid),
+ get_cached_groupname(dn->dn_gid));
+ }
} else {
- column += printf("%-8.8s %-8.8s ",
- get_cached_username(dn->dn_uid),
- get_cached_groupname(dn->dn_gid));
+ #define UGDEF_FMT "%-8.8s "
+ if (option_mask32 & OPT_g) {
+ column += printf(UGDEF_FMT,
+ get_cached_groupname(dn->dn_gid));
+ } else {
+ column += printf(UGDEF_FMT UGDEF_FMT,
+ get_cached_username(dn->dn_uid),
+ get_cached_groupname(dn->dn_gid));
+ }
}
}
#endif
@@ -735,7 +750,7 @@ static void display_files(struct dnode **dn, unsigned nfiles)
/* find the longest file name, use that as the column width */
for (i = 0; dn[i]; i++) {
int len = calc_name_len(dn[i]->name);
- if (column_width < len)
+ if ((int)column_width < len)
column_width = len;
}
column_width += 2 +
diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c
index f13bdfc..475fb3f 100644
--- a/coreutils/od_bloaty.c
+++ b/coreutils/od_bloaty.c
@@ -1385,7 +1385,7 @@ int od_main(int argc UNUSED_PARAM, char **argv)
dump(n_bytes_to_skip, end_offset);
if (fclose(stdin))
- bb_perror_msg_and_die(bb_msg_standard_input);
+ bb_perror_msg_and_die("%s", bb_msg_standard_input);
return G.exit_code;
}
diff --git a/coreutils/seq.c b/coreutils/seq.c
index ed4946b..7388f79 100644
--- a/coreutils/seq.c
+++ b/coreutils/seq.c
@@ -37,7 +37,7 @@ int seq_main(int argc, char **argv)
};
double first, last, increment, v;
unsigned n;
- unsigned width;
+ int width;
unsigned frac_part;
const char *sep, *opt_s = "\n";
unsigned opt;
@@ -79,7 +79,7 @@ int seq_main(int argc, char **argv)
while (1) {
char *dot = strchrnul(*argv, '.');
int w = (dot - *argv);
- int f = strlen(dot);
+ unsigned f = strlen(dot);
if (width < w)
width = w;
argv++;
diff --git a/coreutils/sort.c b/coreutils/sort.c
index 1ccce93..64b85e1 100644
--- a/coreutils/sort.c
+++ b/coreutils/sort.c
@@ -503,7 +503,7 @@ int sort_main(int argc UNUSED_PARAM, char **argv)
#if ENABLE_FEATURE_SORT_BIG
/* Open output file _after_ we read all input ones */
if (option_mask32 & FLAG_o)
- xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO);
+ xmove_fd(xopen3(str_o, O_WRONLY|O_CREAT|O_TRUNC, 0666), STDOUT_FILENO);
#endif
{
int ch = (option_mask32 & FLAG_z) ? '\0' : '\n';
diff --git a/coreutils/sync.c b/coreutils/sync.c
index 5e189f6..1a5aae5 100644
--- a/coreutils/sync.c
+++ b/coreutils/sync.c
@@ -45,59 +45,10 @@
int sync_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int sync_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM))
{
-#if !ENABLE_FEATURE_SYNC_FANCY
/* coreutils-6.9 compat */
bb_warn_ignoring_args(argv[1]);
- sync();
- return EXIT_SUCCESS;
-#else
- unsigned opts;
- int ret = EXIT_SUCCESS;
-
- enum {
- OPT_DATASYNC = (1 << 0),
- OPT_SYNCFS = (1 << 1),
- };
-
- opt_complementary = "d--f:f--d";
- opts = getopt32(argv, "df");
- argv += optind;
- /* Handle the no-argument case. */
- if (!argv[0])
- sync();
-
- while (*argv) {
- int fd = open_or_warn(*argv, O_RDONLY);
-
- if (fd < 0) {
- ret = EXIT_FAILURE;
- goto next;
- }
- if (opts & OPT_DATASYNC) {
- if (fdatasync(fd))
- goto err;
- goto do_close;
- }
- if (opts & OPT_SYNCFS) {
- /*
- * syncfs is documented to only fail with EBADF,
- * which can't happen here. So, no error checks.
- */
- syncfs(fd);
- goto do_close;
- }
- if (fsync(fd)) {
- err:
- bb_simple_perror_msg(*argv);
- ret = EXIT_FAILURE;
- }
- do_close:
- close(fd);
- next:
- ++argv;
- }
+ sync();
- return ret;
-#endif
+ return EXIT_SUCCESS;
}
diff --git a/coreutils/tail.c b/coreutils/tail.c
index 99f58dd..406edf8 100644
--- a/coreutils/tail.c
+++ b/coreutils/tail.c
@@ -119,8 +119,8 @@ int tail_main(int argc, char **argv)
char *tailbuf;
size_t tailbufsize;
- unsigned header_threshhold = 1;
- unsigned nfiles;
+ int header_threshhold = 1;
+ int nfiles;
int i, opt;
int *fds;
diff --git a/coreutils/test.c b/coreutils/test.c
index 288f665..2c1e624 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -645,7 +645,7 @@ static int test_eaccess(char *path, int mode)
static int filstat(char *nm, enum token mode)
{
struct stat s;
- unsigned i = i; /* gcc 3.x thinks it can be used uninitialized */
+ unsigned i = 0;
if (mode == FILSYM) {
#ifdef S_IFLNK
diff --git a/coreutils/touch.c b/coreutils/touch.c
index 92d5a71..7d58470 100644
--- a/coreutils/touch.c
+++ b/coreutils/touch.c
@@ -164,7 +164,7 @@ int touch_main(int argc UNUSED_PARAM, char **argv)
int result;
result = (
#if ENABLE_FEATURE_TOUCH_NODEREF
- (opts & OPT_h) ? lutimes :
+ (opts & OPT_h) ? utimes :
#endif
utimes)(*argv, (reference_file || date_str) ? timebuf : NULL);
if (result != 0) {
diff --git a/debianutils/mktemp.c b/debianutils/mktemp.c
index 6535369..8f9479f 100644
--- a/debianutils/mktemp.c
+++ b/debianutils/mktemp.c
@@ -52,7 +52,7 @@
//usage: "\n -p DIR Use DIR as a base directory (implies -t)"
//usage: "\n -u Do not create anything; print a name"
//usage: "\n"
-//usage: "\nBase directory is: -p DIR, else $TMPDIR, else /tmp"
+//usage: "\nBase directory is: -p DIR, else $TMPDIR, else /data/local/tmp"
//usage:
//usage:#define mktemp_example_usage
//usage: "$ mktemp /tmp/temp.XXXXXX\n"
@@ -62,6 +62,11 @@
#include "libbb.h"
+#ifdef __BIONIC__
+#include <android.h>
+#define mktemp(s) bb_mktemp(s)
+#endif
+
int mktemp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int mktemp_main(int argc UNUSED_PARAM, char **argv)
{
@@ -78,7 +83,7 @@ int mktemp_main(int argc UNUSED_PARAM, char **argv)
path = getenv("TMPDIR");
if (!path || path[0] == '\0')
- path = "/tmp";
+ path = "/data/local/tmp";
opt_complementary = "?1"; /* 1 argument max */
opts = getopt32(argv, "dqtp:u", &path);
@@ -103,6 +108,7 @@ int mktemp_main(int argc UNUSED_PARAM, char **argv)
if (opts & OPT_u) {
chp = mktemp(chp);
+ /*chp = mkstemp(chp);*/
if (chp[0] == '\0')
goto error;
} else if (opts & OPT_d) {
diff --git a/e2fsprogs/tune2fs.c b/e2fsprogs/tune2fs.c
index e9bad66..0485e82 100644
--- a/e2fsprogs/tune2fs.c
+++ b/e2fsprogs/tune2fs.c
@@ -88,6 +88,7 @@ int tune2fs_main(int argc UNUSED_PARAM, char **argv)
if (opts & OPT_C) {
int n = xatoi_range(str_C, 1, 0xfffe);
+ if (n == 0) n = 1;
STORE_LE(sb->s_mnt_count, (unsigned)n);
}
diff --git a/editors/awk.c b/editors/awk.c
index 685e8be..b1dfe9e 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -2094,7 +2094,7 @@ static char *awk_printf(node *n)
char *b = NULL;
char *fmt, *s, *f;
const char *s1;
- int i, j, incr, bsize;
+ int i, j, incr, bsize = 0;
char c, c1;
var *v, *arg;
@@ -2496,12 +2496,12 @@ static var *evaluate(node *op, var *res)
struct {
var *v;
const char *s;
- } L = L; /* for compiler */
+ } L = { NULL, NULL };
struct {
var *v;
const char *s;
- } R = R;
- double L_d = L_d;
+ } R = { NULL, NULL };
+ static double L_d;
uint32_t opinfo;
int opn;
node *op1;
@@ -2729,7 +2729,7 @@ static var *evaluate(node *op, var *res)
copyvar(v, arg);
v->type |= VF_CHILD;
v->x.parent = arg;
- if (++v - vbeg >= op->r.f->nargs)
+ if (++v - vbeg >= (int) op->r.f->nargs)
break;
}
@@ -2787,7 +2787,7 @@ static var *evaluate(node *op, var *res)
/* simple builtins */
case XC( OC_FBLTIN ): {
- double R_d = R_d; /* for compiler */
+ static double R_d;
switch (opn) {
case F_in:
@@ -3006,7 +3006,7 @@ static var *evaluate(node *op, var *res)
}
case XC( OC_COMPARE ): {
- int i = i; /* for compiler */
+ static int i;
double Ld;
if (is_numeric(L.v) && is_numeric(R.v)) {
diff --git a/editors/diff.c b/editors/diff.c
index 75229ad..b275a21 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -476,7 +476,7 @@ static NOINLINE int *create_J(FILE_and_pos_t ft[2], int nlen[2], off_t *ix[2])
for (i = 0; i < 2; i++) {
unsigned hash;
token_t tok;
- size_t sz = 100;
+ int sz = 100;
nfile[i] = xmalloc((sz + 3) * sizeof(nfile[i][0]));
/* ft gets here without the correct position, cant use seek_ft */
ft[i].ft_pos = 0;
@@ -735,7 +735,14 @@ static int diffreg(char *file[2])
* When we meet non-seekable file, we must make a temp copy.
*/
if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) {
- char name[] = "/tmp/difXXXXXX";
+ /* really should use $TMPDIR, but not usually set on android anyway
+ here with ifdef, android will use "/data/local/tmp/difXXXXXX"
+ */
+ char name[] =
+#ifdef __BIONIC__
+ "/data/local"
+#endif
+ "/tmp/difXXXXXX";
int fd_tmp = xmkstemp(name);
unlink(name);
diff --git a/editors/patch.c b/editors/patch.c
index 731a8c5..d297542 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -367,8 +367,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
int reverse, state = 0;
char *oldname = NULL, *newname = NULL;
char *opt_p, *opt_i;
- long oldlen = oldlen; /* for compiler */
- long newlen = newlen; /* for compiler */
+ long oldlen = 0;
+ long newlen = 0;
INIT_TT();
diff --git a/editors/vi.c b/editors/vi.c
index 38a4692..432fba8 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -185,7 +185,7 @@
#include "libbb.h"
/* Should be after libbb.h: on some systems regex.h needs sys/types.h: */
#if ENABLE_FEATURE_VI_REGEX_SEARCH
-# include <regex.h>
+# include "xregex.h"
#endif
/* the CRASHME code is unmaintained, and doesn't currently build */
@@ -310,7 +310,7 @@ struct globals {
int last_modified_count; // = -1;
int save_argc; // how many file names on cmd line
int cmdcnt; // repetition count
- unsigned rows, columns; // the terminal screen is this size
+ int rows, columns; // the terminal screen is this size
#if ENABLE_FEATURE_VI_ASK_TERMINAL
int get_rowcol_error;
#endif
@@ -747,7 +747,9 @@ static int init_text_buffer(char *fn)
#if ENABLE_FEATURE_VI_WIN_RESIZE
static int query_screen_dimensions(void)
{
- int err = get_terminal_width_height(STDIN_FILENO, &columns, &rows);
+ unsigned c, r;
+ int err = get_terminal_width_height(STDIN_FILENO, &c, &r);
+ columns = c; rows = r;
if (rows > MAX_SCR_ROWS)
rows = MAX_SCR_ROWS;
if (columns > MAX_SCR_COLS)
@@ -2472,7 +2474,7 @@ static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte
p += bias;
#if ENABLE_FEATURE_VI_YANKMARK
{
- int i;
+ unsigned i;
for (i = 0; i < ARRAY_SIZE(mark); i++)
if (mark[i])
mark[i] += bias;
diff --git a/findutils/find.c b/findutils/find.c
index 27698e5..4f976d5 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -388,7 +388,7 @@ IF_FEATURE_FIND_MMIN( ACTS(mmin, char mmin_char; unsigned mmin_mins;))
IF_FEATURE_FIND_NEWER( ACTS(newer, time_t newer_mtime;))
IF_FEATURE_FIND_INUM( ACTS(inum, ino_t inode_num;))
IF_FEATURE_FIND_USER( ACTS(user, uid_t uid;))
-IF_FEATURE_FIND_SIZE( ACTS(size, char size_char; off_t size;))
+IF_FEATURE_FIND_SIZE( ACTS(size, char size_char; filesize_t size;))
IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;))
IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;))
IF_FEATURE_FIND_PRUNE( ACTS(prune))
@@ -408,7 +408,7 @@ IF_FEATURE_FIND_EXEC( ACTS(exec,
)
))
IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;))
-IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;))
+IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; unsigned links_count;))
struct globals {
IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;)
@@ -580,7 +580,7 @@ ACTF(regex)
#if ENABLE_FEATURE_FIND_TYPE
ACTF(type)
{
- return ((statbuf->st_mode & S_IFMT) == ap->type_mask);
+ return ((statbuf->st_mode & S_IFMT) == (unsigned) ap->type_mask);
}
#endif
#if ENABLE_FEATURE_FIND_PERM
@@ -625,7 +625,7 @@ ACTF(mmin)
#if ENABLE_FEATURE_FIND_NEWER
ACTF(newer)
{
- return (ap->newer_mtime < statbuf->st_mtime);
+ return ((time_t) ap->newer_mtime < (time_t) statbuf->st_mtime);
}
#endif
#if ENABLE_FEATURE_FIND_INUM
diff --git a/include/.gitignore b/include/.gitignore
index 75afff9..50cf6de 100644
--- a/include/.gitignore
+++ b/include/.gitignore
@@ -1,11 +1 @@
/config
-
-/applets.h
-/applet_tables.h
-/autoconf.h
-/bbconfigopts_bz2.h
-/bbconfigopts.h
-/NUM_APPLETS.h
-/usage_compressed.h
-/usage.h
-/common_bufsiz.h*
diff --git a/include/android.h b/include/android.h
new file mode 100644
index 0000000..651f7df
--- a/dev/null
+++ b/include/android.h
@@ -0,0 +1,96 @@
+/* vi: set sw=4 ts=4: */
+/*
+ Copyright 2010, Dylan Simon
+
+ Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
+*/
+
+#ifndef BB_ANDROID_H
+#define BB_ANDROID_H 1
+
+/* for dirname, basename */
+#include <libgen.h>
+
+#if ENABLE_FEATURE_DC_LIBM
+# include <math.h>
+#endif
+
+/* lutimes doesnt exists in libc */
+#if ENABLE_FEATURE_TOUCH_NODEREF
+# define lutimes utimes
+#endif
+
+#define killpg_busybox(P, S) kill(-(P), S)
+
+#define setmntent fopen
+#define endmntent fclose
+
+/* defined in bionic/utmp.c */
+void endutent(void);
+
+/* defined in bionic/mktemp.c */
+char *mkdtemp(char *);
+char *bb_mktemp(char *);
+
+/* SYSCALLS */
+int stime(const time_t *);
+int swapon(const char *, int);
+int swapoff(const char *);
+int getsid(pid_t);
+
+#ifndef SYS_ioprio_set
+#define SYS_ioprio_set __NR_ioprio_set
+#define SYS_ioprio_get __NR_ioprio_get
+#endif
+
+/* XXX These need to be obtained from kernel headers. See b/9336527 */
+#define SWAP_FLAG_PREFER 0x8000
+#define SWAP_FLAG_PRIO_MASK 0x7fff
+#define SWAP_FLAG_PRIO_SHIFT 0
+#define SWAP_FLAG_DISCARD 0x10000
+
+/* local definition in libbb/xfuncs_printf.c */
+int fdprintf(int fd, const char *format, ...);
+
+/* local definitions in android/libc/pty.c */
+#include <fcntl.h>
+#ifndef SPLICE_F_GIFT
+/* if this constant is not defined,
+ ttyname is not in bionic */
+char* bb_ttyname(int);
+int bb_ttyname_r(int, char *, size_t);
+#define ttyname(n) bb_ttyname(n)
+#define ttyname_r(n,s,z) bb_ttyname_r(n,s,z)
+#else
+/* should be available in android M ? */
+extern char* ttyname(int);
+extern int ttyname_r(int, char *, size_t);
+#endif
+
+/* local definitions in android/android.c */
+char *getusershell(void);
+void setusershell(void);
+void endusershell(void);
+
+struct mntent;
+struct __sFILE;
+int addmntent(struct __sFILE *, const struct mntent *);
+struct mntent *getmntent_r(struct __sFILE *fp, struct mntent *mnt, char *buf, int buflen);
+char *hasmntopt(const struct mntent *, const char *);
+
+#define MNTOPT_NOAUTO "noauto"
+
+/* bionic's vfork is rather broken; for now a terrible bandaid: */
+#define vfork fork
+
+#if !defined(BIONIC_L) && !defined(BLOATCHECK)
+#define _SOCKLEN_T_DECLARED
+typedef int socklen_t;
+#endif
+
+/* wait3 was removed in android L */
+#ifdef BIONIC_L
+#define wait3(status, options, rusage) wait4(-1, status, options, rusage)
+#endif
+
+#endif
diff --git a/include/bb_archive.h b/include/bb_archive.h
index 2b9c5f0..7b43a29 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -129,6 +129,9 @@ typedef struct archive_handle_t {
#if ENABLE_RPM
#define ARCHIVE_REPLACE_VIA_RENAME (1 << 10)
#endif
+#if ENABLE_FEATURE_TAR_SELINUX
+#define ARCHIVE_STORE_SELINUX (1 << 15)
+#endif
/* POSIX tar Header Block, from POSIX 1003.1-1990 */
@@ -150,7 +153,7 @@ typedef struct tar_header_t { /* byte offset */
/* Normally it's defined as magic[6] followed by
* version[2], but we put them together to save code.
*/
- char magic[8]; /* 257-264 */
+ char magic[8]; /* 257-264 (magic 6 + version 2) */
char uname[32]; /* 265-296 */
char gname[32]; /* 297-328 */
char devmajor[8]; /* 329-336 */
diff --git a/include/libbb.h b/include/libbb.h
index abdc8c2..0fdddfc 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -12,7 +12,20 @@
#include "platform.h"
+#ifdef __BIONIC__
+/* work around "extern inline" (under std=gnu99) ctype definitions we don't use anyway */
+# ifdef NDEBUG
+# define NDEBUG_TMP NDEBUG
+# endif
+# undef NDEBUG
+# include <ctype.h>
+# ifdef NDEBUG_TMP
+# define NDEBUG NDEBUG_TMP
+# undef NDEBUG_TMP
+# endif
+#else
#include <ctype.h>
+#endif
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -62,10 +75,6 @@
# include <shadow.h>
# endif
#endif
-#if defined(ANDROID) || defined(__ANDROID__)
-# define endpwent() ((void)0)
-# define endgrent() ((void)0)
-#endif
#ifdef HAVE_MNTENT_H
# include <mntent.h>
#endif
@@ -81,8 +90,15 @@
#if ENABLE_SELINUX
# include <selinux/selinux.h>
# include <selinux/context.h>
+#ifdef __BIONIC__
+# include "android/selinux/android_selinux.h"
+# include <sepol/policydb/flask.h>
+#else
+# include <selinux/flask.h>
+# include <selinux/av_permissions.h>
#endif
-#if ENABLE_FEATURE_UTMP
+#endif
+/*#if ENABLE_FEATURE_UTMP
# if defined __UCLIBC__ && ( \
(UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 32) \
&& UCLIBC_VERSION < KERNEL_VERSION(0, 9, 34) \
@@ -92,7 +108,7 @@
) \
)
# include <utmpx.h>
-# elif defined __UCLIBC__
+# elif defined __UCLIBC__*/
# include <utmp.h>
# define utmpx utmp
# define setutxent setutent
@@ -104,14 +120,14 @@
# define utmpxname utmpname
# define updwtmpx updwtmp
# define _PATH_UTMPX _PATH_UTMP
-# else
+/*# else
# include <utmp.h>
-# include <utmpx.h>
+//# include <utmpx.h>
# if defined _PATH_UTMP && !defined _PATH_UTMPX
# define _PATH_UTMPX _PATH_UTMP
# endif
# endif
-#endif
+#endif*/
#if ENABLE_LOCALE_SUPPORT
# include <locale.h>
#else
@@ -195,6 +211,7 @@ int klogctl(int type, char *b, int len);
# undef fputc
# define fputc(c,stream) putc_unlocked(c,stream)
#endif
+
/* Above functions are required by POSIX.1-2008, below ones are extensions */
#ifdef HAVE_UNLOCKED_LINE_OPS
# undef fgets
@@ -288,12 +305,28 @@ typedef unsigned long uoff_t;
#endif
/* scary. better ideas? (but do *test* them first!) */
#define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1)))
+
+/* off_t is 32bits when it should be 64bits when LARGEFILE is defined. disable check, dangerously */
+#ifndef __BIONIC__
/* Users report bionic to use 32-bit off_t even if LARGEFILE support is requested.
* We misdetected that. Don't let it build:
*/
struct BUG_off_t_size_is_misdetected {
char BUG_off_t_size_is_misdetected[sizeof(off_t) == sizeof(uoff_t) ? 1 : -1];
};
+#endif
+
+#if defined(__BIONIC__) && !defined(__LP64__)
+/* bionic uses stat64 which has long long file sizes, whereas off_t is only long bits */
+typedef long long filesize_t;
+#define FILESIZE_FMT "ll"
+#if ENABLE_LFS
+#define lseek lseek64
+#endif /* ENABLE_LFS */
+#else
+typedef off_t filesize_t;
+#define FILESIZE_FMT OFF_FMT
+#endif
/* Some useful definitions */
#undef FALSE
@@ -535,7 +568,7 @@ int open_or_warn_stdin(const char *pathname) FAST_FUNC;
int xopen_stdin(const char *pathname) FAST_FUNC;
void xrename(const char *oldpath, const char *newpath) FAST_FUNC;
int rename_or_warn(const char *oldpath, const char *newpath) FAST_FUNC;
-off_t xlseek(int fd, off_t offset, int whence) FAST_FUNC;
+uoff_t xlseek(int fd, uoff_t offset, int whence) FAST_FUNC;
int xmkstemp(char *template) FAST_FUNC;
off_t fdlength(int fd) FAST_FUNC;
@@ -958,6 +991,8 @@ int get_uidgid(struct bb_uidgid_t*, const char*) FAST_FUNC;
void xget_uidgid(struct bb_uidgid_t*, const char*) FAST_FUNC;
/* chown-like handling of "user[:[group]" */
void parse_chown_usergroup_or_die(struct bb_uidgid_t *u, char *user_group) FAST_FUNC;
+struct passwd* safegetpwnam(const char *name) FAST_FUNC;
+struct passwd* safegetpwuid(uid_t uid) FAST_FUNC;
struct passwd* xgetpwnam(const char *name) FAST_FUNC;
struct group* xgetgrnam(const char *name) FAST_FUNC;
struct passwd* xgetpwuid(uid_t uid) FAST_FUNC;
@@ -1547,9 +1582,9 @@ typedef struct line_input_t {
int flags;
const char *path_lookup;
# if MAX_HISTORY
- int cnt_history;
- int cur_history;
- int max_history; /* must never be <= 0 */
+ unsigned cnt_history;
+ unsigned cur_history;
+ unsigned max_history; /* must never be <= 0 */
# if ENABLE_FEATURE_EDITING_SAVEHISTORY
/* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT:
* if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are
@@ -1847,7 +1882,11 @@ extern const char bb_busybox_exec_path[] ALIGN1;
* but I want to save a few bytes here */
extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */
#define bb_default_root_path (bb_PATH_root_path + sizeof("PATH"))
+#ifdef __BIONIC__
+#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin"))
+#else
#define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin"))
+#endif
extern const int const_int_0;
//extern const int const_int_1;
@@ -1875,18 +1914,43 @@ extern struct globals *const ptr_to_globals;
* use bb_default_login_shell and following defines.
* If you change LIBBB_DEFAULT_LOGIN_SHELL,
* don't forget to change increment constant. */
-#define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh"
extern const char bb_default_login_shell[] ALIGN1;
+
+#ifdef __BIONIC__
+/* Since android does not have the /bin path, unlike most unix systems,
+ * it needs an exception in the default shell path. */
+# define LIBBB_DEFAULT_LOGIN_SHELL "-/system/bin/sh"
+/* "/system/xbin/sh" */
+# define DEFAULT_SHELL (bb_default_login_shell+1)
+/* "sh" */
+# define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+13)
+
+#else
+# define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh"
/* "/bin/sh" */
-#define DEFAULT_SHELL (bb_default_login_shell+1)
+# define DEFAULT_SHELL (bb_default_login_shell+1)
/* "sh" */
-#define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6)
+# define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6)
+#endif
/* The following devices are the same on all systems. */
#define CURRENT_TTY "/dev/tty"
#define DEV_CONSOLE "/dev/console"
-#if defined(__FreeBSD_kernel__)
+#ifdef __BIONIC__
+# define CURRENT_VC CURRENT_TTY
+# define VC_1 "/dev/tty1"
+# define VC_2 "/dev/tty2"
+# define VC_3 "/dev/tty3"
+# define VC_4 "/dev/tty4"
+# define VC_5 "/dev/tty5"
+# define VC_FORMAT "/dev/tty%d"
+# define LOOP_FORMAT "/dev/block/loop%d"
+# define LOOP_NAMESIZE (sizeof("/dev/block/loop") + sizeof(int)*3 + 1)
+# define LOOP_NAME "/dev/block/loop"
+# define FB_0 "/dev/graphics/fb0"
+
+#elif defined(__FreeBSD_kernel__)
# define CURRENT_VC CURRENT_TTY
# define VC_1 "/dev/ttyv0"
# define VC_2 "/dev/ttyv1"
@@ -1928,7 +1992,8 @@ extern const char bb_default_login_shell[] ALIGN1;
# define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1)
# define LOOP_NAME "/dev/loop"
# define FB_0 "/dev/fb0"
-#endif
+
+#endif //Platform
#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0])))
diff --git a/include/platform.h b/include/platform.h
index c987d41..9d357a0 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -544,7 +544,7 @@ extern char *stpcpy(char *p, const char *to_add) FAST_FUNC;
#define mempcpy bb__mempcpy
static ALWAYS_INLINE void *mempcpy(void *dest, const void *src, size_t len)
{
- return memcpy(dest, src, len) + len;
+ return (char*)((uintptr_t)memcpy(dest, src, len) + len);
}
#endif
diff --git a/include/xregex.h b/include/xregex.h
index 5e5e6a2..62f438c 100644
--- a/include/xregex.h
+++ b/include/xregex.h
@@ -11,7 +11,19 @@
#ifndef BB_REGEX_H
#define BB_REGEX_H 1
+#if defined(ANDROID) && !defined(RECOVERY_VERSION)
+
+#include <bb_regex.h>
+#define regcomp bb_regcomp
+#define re_compile_pattern bb_re_compile_pattern
+#define re_search bb_re_search
+#define regexec bb_regexec
+#define regfree bb_regfree
+#define regerror bb_regerror
+
+#else
#include <regex.h>
+#endif
PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
diff --git a/init/halt.c b/init/halt.c
index b7fb108..8073103 100644
--- a/init/halt.c
+++ b/init/halt.c
@@ -83,6 +83,10 @@
#include "libbb.h"
#include "reboot.h"
+#ifdef __BIONIC__
+# include "android/reboot.c"
+#endif
+
#if ENABLE_FEATURE_WTMP
#include <sys/utsname.h>
@@ -152,6 +156,31 @@ int halt_main(int argc UNUSED_PARAM, char **argv)
if (!(flags & 2)) /* no -n */
sync();
+#ifdef __BIONIC__
+ char *mode[4];
+ int c = 1;
+ mode[0] = strdup("reboot");
+ mode[1] = mode[2] = mode[3] = NULL;
+ switch (which) {
+ case 0:
+ case 1:
+ //-p for halt
+ mode[1] = strdup("-p");
+ c=2;
+ break;
+ case 2:
+ //reboot
+ #ifdef CYANOGEN_LIBREBOOT
+ if (argc > 1) {
+ mode[1] = strdup(argv[1]);
+ c = 2;
+ }
+ #endif
+ break;
+ }
+ return reboot_main(c, mode);
+#endif
+
/* Perform action. */
rc = 1;
if (!(flags & 4)) { /* no -f */
diff --git a/init/init.c b/init/init.c
index 08cfa2f..055f2b4 100644
--- a/init/init.c
+++ b/init/init.c
@@ -1143,7 +1143,7 @@ int init_main(int argc UNUSED_PARAM, char **argv)
parse_inittab();
}
-#if ENABLE_SELINUX
+/*#if ENABLE_SELINUX
if (getenv("SELINUX_INIT") == NULL) {
int enforce = 0;
@@ -1151,13 +1151,12 @@ int init_main(int argc UNUSED_PARAM, char **argv)
if (selinux_init_load_policy(&enforce) == 0) {
BB_EXECVP(argv[0], argv);
} else if (enforce > 0) {
- /* SELinux in enforcing mode but load_policy failed */
message(L_CONSOLE, "can't load SELinux Policy. "
"Machine is in enforcing mode. Halting now.");
return EXIT_FAILURE;
}
}
-#endif
+#endif*/
if (ENABLE_FEATURE_INIT_MODIFY_CMDLINE) {
/* Make the command line just say "init" - that's all, nothing else */
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index ee8b4ec..966d3a8 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -732,7 +732,7 @@ static int busybox_main(char **argv)
full_write2_str(
"BusyBox is copyrighted by many authors between 1998-2015.\n"
"Licensed under GPLv2. See source distribution for detailed\n"
- "copyright notices.\n"
+ "copyright notices. Merged for bionic by tpruvot@github\n"
"\n"
"Usage: busybox [function [arguments]...]\n"
" or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n"
diff --git a/libbb/bb_pwd.c b/libbb/bb_pwd.c
index 4829b72..f51bfe9 100644
--- a/libbb/bb_pwd.c
+++ b/libbb/bb_pwd.c
@@ -15,9 +15,31 @@
* pointers to static data (getpwuid)
*/
-struct passwd* FAST_FUNC xgetpwnam(const char *name)
+struct passwd* FAST_FUNC safegetpwnam(const char *name)
{
struct passwd *pw = getpwnam(name);
+#ifdef __BIONIC__
+ if (pw && !pw->pw_passwd) {
+ pw->pw_passwd = "";
+ }
+#endif
+ return pw;
+}
+
+struct passwd* FAST_FUNC safegetpwuid(uid_t uid)
+{
+ struct passwd *pw = getpwuid(uid);
+#ifdef __BIONIC__
+ if (pw && !pw->pw_passwd) {
+ pw->pw_passwd = "";
+ }
+#endif
+ return pw;
+}
+
+struct passwd* FAST_FUNC xgetpwnam(const char *name)
+{
+ struct passwd *pw = safegetpwnam(name);
if (!pw)
bb_error_msg_and_die("unknown user %s", name);
return pw;
@@ -31,10 +53,9 @@ struct group* FAST_FUNC xgetgrnam(const char *name)
return gr;
}
-
struct passwd* FAST_FUNC xgetpwuid(uid_t uid)
{
- struct passwd *pw = getpwuid(uid);
+ struct passwd *pw = safegetpwuid(uid);
if (!pw)
bb_error_msg_and_die("unknown uid %u", (unsigned)uid);
return pw;
diff --git a/libbb/dump.c b/libbb/dump.c
index 154be5d..9bb7bb2 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -613,7 +613,7 @@ static void display(priv_dumper_t* dumper)
printf(pr->fmt, (char *) bp);
break;
case F_TEXT:
- printf(pr->fmt);
+ printf("%s", pr->fmt);
break;
case F_U:
conv_u(pr, bp);
@@ -663,7 +663,7 @@ static void display(priv_dumper_t* dumper)
printf(pr->fmt, (unsigned) dumper->eaddress);
break;
case F_TEXT:
- printf(pr->fmt);
+ printf("%s", pr->fmt);
break;
}
}
diff --git a/libbb/fflush_stdout_and_exit.c b/libbb/fflush_stdout_and_exit.c
index b4bed86..1d4d6e9 100644
--- a/libbb/fflush_stdout_and_exit.c
+++ b/libbb/fflush_stdout_and_exit.c
@@ -12,12 +12,14 @@
*/
#include "libbb.h"
+#include <strings.h>
+
void FAST_FUNC fflush_stdout_and_exit(int retval)
{
xfunc_error_retval = retval;
if (fflush(stdout))
- bb_perror_msg_and_die(bb_msg_standard_output);
+ bb_perror_msg_and_die("%s", bb_msg_standard_output);
/* In case we are in NOFORK applet. Do not exit() directly,
* but use xfunc_die() */
xfunc_die();
diff --git a/libbb/fgets_str.c b/libbb/fgets_str.c
index 89210a3..de99e5d 100644
--- a/libbb/fgets_str.c
+++ b/libbb/fgets_str.c
@@ -15,8 +15,8 @@ static char *xmalloc_fgets_internal(FILE *file, const char *terminating_string,
char *linebuf = NULL;
const int term_length = strlen(terminating_string);
int end_string_offset;
- int linebufsz = 0;
- int idx = 0;
+ size_t linebufsz = 0;
+ size_t idx = 0;
int ch;
size_t maxsz = *maxsz_p;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 31e3921..9908658 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -46,16 +46,17 @@
#include "busybox.h"
#include "NUM_APPLETS.h"
#include "unicode.h"
+#include "pwd_.h"
#ifndef _POSIX_VDISABLE
# define _POSIX_VDISABLE '\0'
#endif
-#ifdef TEST
-# define ENABLE_FEATURE_EDITING 0
-# define ENABLE_FEATURE_TAB_COMPLETION 0
+
+//# define ENABLE_FEATURE_EDITING 0
+//# define ENABLE_FEATURE_TAB_COMPLETION 0
# define ENABLE_FEATURE_USERNAME_COMPLETION 0
-#endif
+
/* Entire file (except TESTing part) sits inside this #if */
@@ -2334,7 +2335,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
/* new_settings.c_cc[VINTR] = _POSIX_VDISABLE; */
tcsetattr_stdin_TCSANOW(&new_settings);
-#if ENABLE_USERNAME_OR_HOMEDIR
+/*#if ENABLE_USERNAME_OR_HOMEDIR
{
struct passwd *entry;
@@ -2344,7 +2345,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
home_pwd_buf = xstrdup(entry->pw_dir);
}
}
-#endif
+#endif*/
#if 0
for (i = 0; i <= state->max_history; i++)
diff --git a/libbb/messages.c b/libbb/messages.c
index cb0836d..00d8b96 100644
--- a/libbb/messages.c
+++ b/libbb/messages.c
@@ -40,7 +40,11 @@ const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL;
/* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin,
* but I want to save a few bytes here. Check libbb.h before changing! */
const char bb_PATH_root_path[] ALIGN1 =
+#ifdef __BIONIC__
+ "PATH=/sbin" BB_ADDITIONAL_PATH; /* platform.h */
+#else
"PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH;
+#endif
//const int const_int_1 = 1;
diff --git a/libbb/parse_config.c b/libbb/parse_config.c
index 4084397..e18e2dc 100644
--- a/libbb/parse_config.c
+++ b/libbb/parse_config.c
@@ -122,7 +122,7 @@ static int get_line_with_continuation(parser_t *parser)
if (nlen <= 0)
break;
- if (parser->line_alloc < len + nlen + 1) {
+ if ((ssize_t)parser->line_alloc < len + nlen + 1) {
parser->line_alloc = len + nlen + 1;
line = parser->line = xrealloc(line, parser->line_alloc);
}
diff --git a/libbb/platform.c b/libbb/platform.c
index 03bbb79..04ef246 100644
--- a/libbb/platform.c
+++ b/libbb/platform.c
@@ -104,6 +104,9 @@ void* FAST_FUNC memrchr(const void *s, int c, size_t n)
#endif
#ifndef HAVE_MKDTEMP
+#ifdef __BIONIC__
+#define mktemp(s) bb_mktemp(s)
+#endif
/* This is now actually part of POSIX.1, but was only added in 2008 */
char* FAST_FUNC mkdtemp(char *template)
{
diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c
index c8e02dd..35326a5 100644
--- a/libbb/pw_encrypt_des.c
+++ b/libbb/pw_encrypt_des.c
@@ -598,7 +598,7 @@ do_des(struct des_ctx *ctx, /*uint32_t l_in, uint32_t r_in,*/ uint32_t *l_out, u
* l_in, r_in, l_out, and r_out are in pseudo-"big-endian" format.
*/
uint32_t l, r, *kl, *kr;
- uint32_t f = f; /* silence gcc */
+ static uint32_t f; /* silence gcc */
uint32_t r48l, r48r;
int round;
diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c
index 8aeaaca..e48b341 100644
--- a/libbb/pw_encrypt_sha.c
+++ b/libbb/pw_encrypt_sha.c
@@ -21,7 +21,7 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
void (*sha_begin)(void *ctx) FAST_FUNC;
void (*sha_hash)(void *ctx, const void *buffer, size_t len) FAST_FUNC;
void (*sha_end)(void *ctx, void *resbuf) FAST_FUNC;
- int _32or64;
+ unsigned _32or64;
char *result, *resptr;
@@ -152,7 +152,7 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
/* Start computation of S byte sequence. */
/* For every character in the password add the entire password. */
sha_begin(&alt_ctx);
- for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
+ for (cnt = 0; cnt < 16U + alt_result[0]; ++cnt)
sha_hash(&alt_ctx, salt_data, salt_len);
sha_end(&alt_ctx, temp_result);
diff --git a/libbb/rtc.c b/libbb/rtc.c
index c4117ba..488149d 100644
--- a/libbb/rtc.c
+++ b/libbb/rtc.c
@@ -93,7 +93,7 @@ void FAST_FUNC rtc_read_tm(struct tm *ptm, int fd)
time_t FAST_FUNC rtc_tm2time(struct tm *ptm, int utc)
{
- char *oldtz = oldtz; /* for compiler */
+ char *oldtz = NULL;
time_t t;
if (utc) {
diff --git a/libbb/run_shell.c b/libbb/run_shell.c
index b6b9360..93ab816 100644
--- a/libbb/run_shell.c
+++ b/libbb/run_shell.c
@@ -34,16 +34,18 @@
#endif
#if ENABLE_SELINUX
-static security_context_t current_sid;
+static security_context_t current_sid = NULL;
void FAST_FUNC renew_current_security_context(void)
{
- freecon(current_sid); /* Release old context */
+ if (current_sid)
+ freecon(current_sid); /* Release old context */
getcon(&current_sid); /* update */
}
void FAST_FUNC set_current_security_context(security_context_t sid)
{
- freecon(current_sid); /* Release old context */
+ if (current_sid)
+ freecon(current_sid); /* Release old context */
current_sid = sid;
}
@@ -77,6 +79,7 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char **additio
}
#if ENABLE_SELINUX
+ renew_current_security_context();
if (current_sid)
setexeccon(current_sid);
if (ENABLE_FEATURE_CLEAN_UP)
diff --git a/libbb/time.c b/libbb/time.c
index 82e6cb1..fa5ab43 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -161,15 +161,15 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
&end) >= 5) {
/* Adjust month from 1-12 to 0-11 */
ptm->tm_mon -= 1;
- if ((int)cur_year >= 50) { /* >= 1950 */
+ if (cur_year >= 50) { /* >= 1950 */
/* Adjust year: */
/* 1. Put it in the current century */
ptm->tm_year += (cur_year / 100) * 100;
/* 2. If too far in the past, +100 years */
- if (ptm->tm_year < cur_year - 50)
+ if (ptm->tm_year < (int) cur_year - 50)
ptm->tm_year += 100;
/* 3. If too far in the future, -100 years */
- if (ptm->tm_year > cur_year + 50)
+ if (ptm->tm_year > (int) cur_year + 50)
ptm->tm_year -= 100;
}
} else
diff --git a/libbb/udp_io.c b/libbb/udp_io.c
index 6e3ef48..d37a73b 100644
--- a/libbb/udp_io.c
+++ b/libbb/udp_io.c
@@ -8,6 +8,14 @@
*/
#include "libbb.h"
+#if defined(IPV6_PKTINFO) && defined(__BIONIC__) && !defined(BIONIC_ICS)
+// now included in Bionic ICS
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr; // src/dst IPv6 address
+ unsigned int ipi6_ifindex; // send/recv if index
+};
+#endif
+
/*
* This asks kernel to let us know dst addr/port of incoming packets
* We don't check for errors here. Not supported == won't be used
diff --git a/libbb/unicode.c b/libbb/unicode.c
index 9c4da50..6bdb666 100644
--- a/libbb/unicode.c
+++ b/libbb/unicode.c
@@ -14,6 +14,12 @@
uint8_t unicode_status;
#endif
+#ifdef __BIONIC__
+# define VOID
+#else
+# define VOID void
+#endif
+
/* This file is compiled only if UNICODE_SUPPORT is on.
* We check other options and decide whether to use libc support
* via locale, or use our own logic:
@@ -47,7 +53,7 @@ void FAST_FUNC reinit_unicode(const char *LANG)
unicode_status = (width == 1 ? UNICODE_ON : UNICODE_OFF);
}
-void FAST_FUNC init_unicode(void)
+void FAST_FUNC init_unicode(VOID)
{
/* Some people set only $LC_CTYPE, not $LC_ALL, because they want
* only Unicode to be activated on their system, not the whole
@@ -74,7 +80,7 @@ void FAST_FUNC reinit_unicode(const char *LANG)
unicode_status = UNICODE_ON;
}
-void FAST_FUNC init_unicode(void)
+void FAST_FUNC init_unicode(VOID)
{
if (unicode_status == UNICODE_UNKNOWN) {
char *s = getenv("LC_ALL");
@@ -227,6 +233,8 @@ size_t FAST_FUNC mbstowcs(wchar_t *dest, const char *src, size_t n)
{
size_t org_n = n;
+ if (!src) return 0;
+
if (unicode_status != UNICODE_ON) {
while (n) {
unsigned char c = *src++;
@@ -1026,9 +1034,11 @@ static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char
} else {
d = dst = xstrndup(src, width);
while (*d) {
+#if !ENABLE_UNICODE_PRESERVE_BROKEN /* Unicode checks are not working in 1.19.0 but can be displayed if not filtered */
unsigned char c = *d;
if (c < ' ' || c >= 0x7f)
*d = '?';
+#endif
d++;
}
}
diff --git a/libbb/wfopen.c b/libbb/wfopen.c
index 76dc8b8..115b091 100644
--- a/libbb/wfopen.c
+++ b/libbb/wfopen.c
@@ -43,7 +43,7 @@ static FILE* xfdopen_helper(unsigned fd_and_rw_bit)
{
FILE* fp = fdopen(fd_and_rw_bit >> 1, fd_and_rw_bit & 1 ? "w" : "r");
if (!fp)
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
return fp;
}
FILE* FAST_FUNC xfdopen_for_read(int fd)
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 1b11caf..2a20d53 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -37,7 +37,7 @@ void* FAST_FUNC malloc_or_warn(size_t size)
{
void *ptr = malloc(size);
if (ptr == NULL && size != 0)
- bb_error_msg(bb_msg_memory_exhausted);
+ bb_error_msg("%s", bb_msg_memory_exhausted);
return ptr;
}
@@ -46,7 +46,7 @@ void* FAST_FUNC xmalloc(size_t size)
{
void *ptr = malloc(size);
if (ptr == NULL && size != 0)
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
return ptr;
}
@@ -57,7 +57,7 @@ void* FAST_FUNC xrealloc(void *ptr, size_t size)
{
ptr = realloc(ptr, size);
if (ptr == NULL && size != 0)
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
return ptr;
}
#endif /* DMALLOC */
@@ -81,7 +81,7 @@ char* FAST_FUNC xstrdup(const char *s)
t = strdup(s);
if (t == NULL)
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
return t;
}
@@ -259,10 +259,10 @@ void FAST_FUNC xclose(int fd)
}
// Die with an error message if we can't lseek to the right spot.
-off_t FAST_FUNC xlseek(int fd, off_t offset, int whence)
+uoff_t FAST_FUNC xlseek(int fd, uoff_t offset, int whence)
{
- off_t off = lseek(fd, offset, whence);
- if (off == (off_t)-1) {
+ uoff_t off = lseek(fd, offset, whence);
+ if (off == (uoff_t)-1) {
if (whence == SEEK_SET)
bb_perror_msg_and_die("lseek(%"OFF_FMT"u)", offset);
bb_perror_msg_and_die("lseek");
@@ -329,14 +329,19 @@ char* FAST_FUNC xasprintf(const char *format, ...)
va_end(p);
if (r < 0)
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
return string_ptr;
}
void FAST_FUNC xsetenv(const char *key, const char *value)
{
+#ifdef __BIONIC__
+ /* on login, can be NULL, and should not be for bionic */
+ if (environ == NULL)
+ bb_error_msg_and_die("environment is not initialized");
+#endif
if (setenv(key, value, 1))
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
}
/* Handles "VAR=VAL" strings, even those which are part of environ
@@ -663,7 +668,7 @@ pid_t FAST_FUNC xfork(void)
pid_t pid;
pid = fork();
if (pid < 0) /* wtf? */
- bb_perror_msg_and_die("vfork"+1);
+ bb_perror_msg_and_die("%s", "vfork"+1);
return pid;
}
#endif
diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c
index 6b2fd7b..a7c5227 100644
--- a/loginutils/addgroup.c
+++ b/loginutils/addgroup.c
@@ -155,7 +155,7 @@ int addgroup_main(int argc UNUSED_PARAM, char **argv)
/* need to be root */
if (geteuid()) {
- bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ bb_error_msg_and_die("%s", bb_msg_perm_denied_are_you_root);
}
#if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS
applet_long_options = addgroup_longopts;
diff --git a/loginutils/adduser.c b/loginutils/adduser.c
index 608fb84..b9e46e7 100644
--- a/loginutils/adduser.c
+++ b/loginutils/adduser.c
@@ -212,7 +212,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv)
/* got root? */
if (geteuid()) {
- bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ bb_error_msg_and_die("%s", bb_msg_perm_denied_are_you_root);
}
pw.pw_gecos = (char *)"Linux User,,,";
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c
index 2d268be..fb7a241 100644
--- a/loginutils/chpasswd.c
+++ b/loginutils/chpasswd.c
@@ -59,7 +59,7 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv)
int opt;
if (getuid() != 0)
- bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ bb_error_msg_and_die("%s", bb_msg_perm_denied_are_you_root);
opt_complementary = "m--ec:e--mc:c--em";
IF_LONG_OPTS(applet_long_options = chpasswd_longopts;)
diff --git a/loginutils/deluser.c b/loginutils/deluser.c
index 7c3caf9..73fc1b8 100644
--- a/loginutils/deluser.c
+++ b/loginutils/deluser.c
@@ -76,7 +76,7 @@ int deluser_main(int argc, char **argv)
#endif
if (geteuid() != 0)
- bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ bb_error_msg_and_die("%s", bb_msg_perm_denied_are_you_root);
name = argv[1];
member = NULL;
diff --git a/loginutils/getty.c b/loginutils/getty.c
index 162c169..e5a2533 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -76,7 +76,12 @@ static FILE *dbf;
* and for line editing at the same time.
*/
#undef _PATH_LOGIN
+#ifdef __BIONIC__
+#define cfsetspeed(t,s) cfsetispeed(t,s)
+#define _PATH_LOGIN "/system/xbin/login"
+#else
#define _PATH_LOGIN "/bin/login"
+#endif
/* Displayed before the login prompt.
* If ISSUE is not defined, getty will never display the contents of the
@@ -116,7 +121,7 @@ struct globals {
//usage:#define getty_trivial_usage
//usage: "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]"
//usage:#define getty_full_usage "\n\n"
-//usage: "Open TTY, prompt for login name, then invoke /bin/login\n"
+//usage: "Open TTY, prompt for login name, then invoke /system/xbin/login\n"
//usage: "\n -h Enable hardware RTS/CTS flow control"
//usage: "\n -L Set CLOCAL (ignore Carrier Detect state)"
//usage: "\n -m Get baud rate from modem's CONNECT status message"
@@ -124,7 +129,7 @@ struct globals {
//usage: "\n -w Wait for CR or LF before sending /etc/issue"
//usage: "\n -i Don't display /etc/issue"
//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue"
-//usage: "\n -l LOGIN Invoke LOGIN instead of /bin/login"
+//usage: "\n -l LOGIN Invoke LOGIN instead of /system/xbin/login"
//usage: "\n -t SEC Terminate after SEC if no login name is read"
//usage: "\n -I INITSTR Send INITSTR before anything else"
//usage: "\n -H HOST Log HOST into the utmp file as the hostname"
@@ -522,7 +527,7 @@ static char *get_logname(void)
default:
if ((unsigned char)c < ' ') {
/* ignore garbage characters */
- } else if ((int)(bp - G.line_buf) < sizeof(G.line_buf) - 1) {
+ } else if ((int)(bp - G.line_buf) < (int)sizeof(G.line_buf) - 1) {
/* echo and store the character */
full_write(STDOUT_FILENO, &c, 1);
*bp++ = c;
diff --git a/loginutils/login.c b/loginutils/login.c
index 3ca8213..03ddadb 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -68,11 +68,13 @@
#if ENABLE_SELINUX
# include <selinux/selinux.h> /* for is_selinux_enabled() */
+#ifndef __BIONIC__
# include <selinux/get_context_list.h> /* for get_default_context() */
# /* from deprecated <selinux/flask.h>: */
# undef SECCLASS_CHR_FILE
# define SECCLASS_CHR_FILE 10
#endif
+#endif
#if ENABLE_PAM
/* PAM may include <locale.h>. We may need to undefine bbox's stub define: */
@@ -214,7 +216,8 @@ static void initselinux(char *username, char *full_tty,
bb_perror_msg_and_die("security_change_sid(%s) failed", full_tty);
}
if (setfilecon(full_tty, new_tty_sid) != 0) {
- bb_perror_msg_and_die("chsid(%s, %s) failed", full_tty, new_tty_sid);
+ if (strcmp(old_tty_sid, new_tty_sid))
+ bb_perror_msg_and_die("chsid(%s, %s) failed", full_tty, new_tty_sid);
}
}
#endif
@@ -493,7 +496,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
pam_strerror(pamh, pamret), pamret);
safe_strncpy(username, "UNKNOWN", sizeof(username));
#else /* not PAM */
- pw = getpwnam(username);
+ pw = safegetpwnam(username);
if (!pw) {
strcpy(username, "UNKNOWN");
goto fake_it;
diff --git a/miscutils/adjtimex.c b/miscutils/adjtimex.c
index 6355cc1..b4b54c4 100644
--- a/miscutils/adjtimex.c
+++ b/miscutils/adjtimex.c
@@ -36,6 +36,7 @@
#include "libbb.h"
#ifdef __BIONIC__
# include <linux/timex.h>
+extern int adjtimex (struct timex *);
#else
# include <sys/timex.h>
#endif
diff --git a/miscutils/crontab.c b/miscutils/crontab.c
index bcd4245..c6bece7 100644
--- a/miscutils/crontab.c
+++ b/miscutils/crontab.c
@@ -106,7 +106,7 @@ int crontab_main(int argc UNUSED_PARAM, char **argv)
if (sanitize_env_if_suid()) { /* Clears dangerous stuff, sets PATH */
/* Run by non-root */
if (opt_ler & (OPT_u|OPT_c))
- bb_error_msg_and_die(bb_msg_you_must_be_root);
+ bb_error_msg_and_die("%s", bb_msg_you_must_be_root);
}
if (opt_ler & OPT_u) {
diff --git a/miscutils/devmem.c b/miscutils/devmem.c
index aeb32b1..89c9abe 100644
--- a/miscutils/devmem.c
+++ b/miscutils/devmem.c
@@ -29,7 +29,7 @@ int devmem_main(int argc UNUSED_PARAM, char **argv)
{
void *map_base, *virt_addr;
uint64_t read_result;
- uint64_t writeval = writeval; /* for compiler */
+ uint64_t writeval = 0;
off_t target;
unsigned page_size, mapped_size, offset_in_page;
int fd;
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index fc6c9b9..1739a3e 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -488,7 +488,7 @@ int fbsplash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int fbsplash_main(int argc UNUSED_PARAM, char **argv)
{
const char *fb_device, *cfg_filename, *fifo_filename;
- FILE *fp = fp; // for compiler
+ FILE *fp = NULL;
char *num_buf;
unsigned num;
bool bCursorOff;
@@ -496,7 +496,7 @@ int fbsplash_main(int argc UNUSED_PARAM, char **argv)
INIT_G();
// parse command line options
- fb_device = "/dev/fb0";
+ fb_device = "/dev/graphics/fb0";
cfg_filename = NULL;
fifo_filename = NULL;
bCursorOff = 1 & getopt32(argv, "cs:d:i:f:",
diff --git a/miscutils/fbsplash.cfg b/miscutils/fbsplash.cfg
index b6cf607..1e93703 100644
--- a/miscutils/fbsplash.cfg
+++ b/miscutils/fbsplash.cfg
@@ -1,6 +1,6 @@
# progress bar position
-BAR_LEFT=170
-BAR_TOP=300
+BAR_LEFT=90
+BAR_TOP=70
BAR_WIDTH=300
BAR_HEIGHT=20
# progress bar color
diff --git a/miscutils/flash_lock_unlock.c b/miscutils/flash_lock_unlock.c
index 2f69864..a2e67b0 100644
--- a/miscutils/flash_lock_unlock.c
+++ b/miscutils/flash_lock_unlock.c
@@ -81,7 +81,7 @@ int flash_lock_unlock_main(int argc UNUSED_PARAM, char **argv)
sectors = info.size / info.erasesize;
} else {
// isn't this useless?
- unsigned long num = info.size / info.erasesize;
+ long num = info.size / info.erasesize;
if (sectors > num) {
bb_error_msg_and_die("%ld are too many "
"sectors, device only has "
diff --git a/miscutils/flashcp.c b/miscutils/flashcp.c
index 4bbc677..b27d75a 100644
--- a/miscutils/flashcp.c
+++ b/miscutils/flashcp.c
@@ -59,7 +59,7 @@ int flashcp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int flashcp_main(int argc UNUSED_PARAM, char **argv)
{
int fd_f, fd_d; /* input file and mtd device file descriptors */
- int i;
+ unsigned i;
uoff_t erase_count;
struct mtd_info_user mtd;
struct erase_info_user e;
diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c
index c95cbb2..395d01e 100644
--- a/miscutils/nandwrite.c
+++ b/miscutils/nandwrite.c
@@ -241,7 +241,7 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
*/
break;
}
- if (cnt < meminfo_writesize) {
+ if (cnt < (ssize_t) meminfo_writesize) {
if (IS_NANDDUMP)
bb_error_msg_and_die("short read");
if (!(opts & OPT_p))
@@ -260,7 +260,7 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv)
}
mtdoffset += meminfo_writesize;
- if (cnt < meminfo_writesize)
+ if (cnt < (ssize_t) meminfo_writesize)
break;
}
diff --git a/miscutils/rx.c b/miscutils/rx.c
index 660f66a..f794abe 100644
--- a/miscutils/rx.c
+++ b/miscutils/rx.c
@@ -95,7 +95,7 @@ static int receive(/*int read_fd, */int file_fd)
int blockNo, blockNoOnesCompl;
int cksum_or_crc;
int expected;
- int i, j;
+ unsigned i, j;
blockBegin = read_byte(timeout);
if (blockBegin < 0)
@@ -119,7 +119,7 @@ static int receive(/*int read_fd, */int file_fd)
}
/* Write previously received block */
errno = 0;
- if (full_write(file_fd, blockBuf, blockLength) != blockLength) {
+ if ((unsigned) full_write(file_fd, blockBuf, blockLength) != blockLength) {
bb_perror_msg(bb_msg_write_error);
goto fatal;
}
@@ -149,7 +149,7 @@ static int receive(/*int read_fd, */int file_fd)
if (blockNoOnesCompl < 0)
goto timeout;
- if (blockNo != (255 - blockNoOnesCompl)) {
+ if (blockNo != (int) (255 - blockNoOnesCompl)) {
bb_error_msg("bad block ones compl");
goto error;
}
@@ -172,14 +172,14 @@ static int receive(/*int read_fd, */int file_fd)
goto timeout;
}
- if (blockNo == ((wantBlockNo - 1) & 0xff)) {
+ if (blockNo == (int) ((wantBlockNo - 1) & 0xff)) {
/* a repeat of the last block is ok, just ignore it. */
/* this also ignores the initial block 0 which is */
- /* meta data. */
+ /* meta data. nt)*/
blockLength = 0;
goto next;
}
- if (blockNo != (wantBlockNo & 0xff)) {
+ if (blockNo != (int) (wantBlockNo & 0xff)) {
bb_error_msg("unexpected block no, 0x%08x, expecting 0x%08x", blockNo, wantBlockNo);
goto error;
}
diff --git a/miscutils/strings.c b/miscutils/strings.c
index 4d9bfe6..edd0e66 100644
--- a/miscutils/strings.c
+++ b/miscutils/strings.c
@@ -40,8 +40,8 @@
int strings_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int strings_main(int argc UNUSED_PARAM, char **argv)
{
- int n, c, status = EXIT_SUCCESS;
- unsigned count;
+ int c, status = EXIT_SUCCESS;
+ unsigned n, count;
off_t offset;
FILE *file;
char *string;
diff --git a/miscutils/taskset.c b/miscutils/taskset.c
index fb352ab..b0fcb2e 100644
--- a/miscutils/taskset.c
+++ b/miscutils/taskset.c
@@ -47,6 +47,10 @@
* -c/--cpu-list (specify CPUs via "1,3,5-7")
*/
+#ifdef BIONIC_ICS
+#define _GNU_SOURCE 1
+#endif
+
#include <sched.h>
#include "libbb.h"
@@ -107,7 +111,7 @@ int taskset_main(int argc UNUSED_PARAM, char **argv)
unsigned opt_p;
const char *current_new;
char *pid_str;
- char *aff = aff; /* for compiler */
+ char *aff = NULL;
/* NB: we mimic util-linux's taskset: -p does not take
* an argument, i.e., "-pN" is NOT valid, only "-p N"!
diff --git a/miscutils/time.c b/miscutils/time.c
index a73a837..23d18e1 100644
--- a/miscutils/time.c
+++ b/miscutils/time.c
@@ -28,6 +28,7 @@
#include "libbb.h"
#include <sys/resource.h> /* getrusage */
+#include <android.h>
/* Information on the resources used by a child process. */
typedef struct {
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 40a3271..49c5fd4 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -245,7 +245,7 @@ int ftp_receive(const char *local_path, char *server_path)
{
int fd_data;
int fd_local = -1;
- off_t beg_range = 0;
+ filesize_t beg_range = 0;
/* connect to the data socket */
fd_data = xconnect_ftpdata();
@@ -273,7 +273,7 @@ int ftp_receive(const char *local_path, char *server_path)
}
if (do_continue) {
- sprintf(buf, "REST %"OFF_FMT"u", beg_range);
+ sprintf(buf, "REST %"FILESIZE_FMT"u", beg_range);
if (ftpcmd(buf, NULL) != 350) {
do_continue = 0;
}
diff --git a/networking/hostname.c b/networking/hostname.c
index 04a051e..06d91f2 100644
--- a/networking/hostname.c
+++ b/networking/hostname.c
@@ -60,7 +60,7 @@ static void do_sethostname(char *s, int isfile)
config_close(parser);
} else if (sethostname(s, strlen(s))) {
// if (errno == EPERM)
-// bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+// bb_error_msg_and_die("%s", bb_msg_perm_denied_are_you_root);
bb_perror_msg_and_die("sethostname");
}
}
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index 9e16936..5fed60a 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -129,7 +129,7 @@
# define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
#endif
-#if ENABLE_FEATURE_IPV6
+#if ENABLE_FEATURE_IPV6 && !defined(BIONIC_ICS)
struct in6_ifreq {
struct in6_addr ifr6_addr;
uint32_t ifr6_prefixlen;
diff --git a/networking/inetd.c b/networking/inetd.c
index 4d0ab2e..d03a305 100644
--- a/networking/inetd.c
+++ b/networking/inetd.c
@@ -1195,7 +1195,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
struct sigaction sa, saved_pipe_handler;
servtab_t *sep, *sep2;
struct passwd *pwd;
- struct group *grp = grp; /* for compiler */
+ struct group *grp = NULL; /* for compiler */
int opt;
pid_t pid;
sigset_t omask;
@@ -1383,7 +1383,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
pid = vfork();
if (pid < 0) { /* fork error */
- bb_perror_msg("vfork"+1);
+ bb_perror_msg("%s", "vfork"+1);
sleep(1);
restore_sigmask(&omask);
maybe_close(new_udp_fd);
@@ -1440,7 +1440,6 @@ int inetd_main(int argc UNUSED_PARAM, char **argv)
int r;
close(new_udp_fd);
- dbg("closed new_udp_fd:%d\n", new_udp_fd);
lsa = xzalloc_lsa(sep->se_family);
/* peek at the packet and remember peer addr */
r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
@@ -1677,7 +1676,7 @@ static uint32_t machtime(void)
struct timeval tv;
gettimeofday(&tv, NULL);
- return htonl((uint32_t)(tv.tv_sec + 2208988800));
+ return htonl((uint32_t)(tv.tv_sec + 2208988800UL));
}
/* ARGSUSED */
static void FAST_FUNC machtime_stream(int s, servtab_t *sep UNUSED_PARAM)
diff --git a/networking/interface.c b/networking/interface.c
index c5c8f2c..9246132 100644
--- a/networking/interface.c
+++ b/networking/interface.c
@@ -54,7 +54,7 @@
#define _PATH_PROCNET_DEV "/proc/net/dev"
#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
-#ifdef HAVE_AFINET6
+#if defined(HAVE_AFINET6) && !defined(BIONIC_L)
# ifndef _LINUX_IN6_H
/*
* This is from linux/include/net/ipv6.h
diff --git a/networking/ipv6/icmp6.h b/networking/ipv6/icmp6.h
new file mode 100644
index 0000000..0cb1aa6
--- a/dev/null
+++ b/networking/ipv6/icmp6.h
@@ -0,0 +1,346 @@
+/* Copyright (C) 1991-1997,2000,2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _NETINET_ICMP6_H
+#define _NETINET_ICMP6_H 1
+
+#include <inttypes.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#define ICMP6_FILTER 1
+
+#define ICMP6_FILTER_BLOCK 1
+#define ICMP6_FILTER_PASS 2
+#define ICMP6_FILTER_BLOCKOTHERS 3
+#define ICMP6_FILTER_PASSONLY 4
+
+struct icmp6_filter
+ {
+ uint32_t icmp6_filt[8];
+ };
+
+struct icmp6_hdr
+ {
+ uint8_t icmp6_type; /* type field */
+ uint8_t icmp6_code; /* code field */
+ uint16_t icmp6_cksum; /* checksum field */
+ union
+ {
+ uint32_t icmp6_un_data32[1]; /* type-specific field */
+ uint16_t icmp6_un_data16[2]; /* type-specific field */
+ uint8_t icmp6_un_data8[4]; /* type-specific field */
+ } icmp6_dataun;
+ };
+
+#define icmp6_data32 icmp6_dataun.icmp6_un_data32
+#define icmp6_data16 icmp6_dataun.icmp6_un_data16
+#define icmp6_data8 icmp6_dataun.icmp6_un_data8
+#define icmp6_pptr icmp6_data32[0] /* parameter prob */
+#define icmp6_mtu icmp6_data32[0] /* packet too big */
+#define icmp6_id icmp6_data16[0] /* echo request/reply */
+#define icmp6_seq icmp6_data16[1] /* echo request/reply */
+#define icmp6_maxdelay icmp6_data16[0] /* mcast group membership */
+
+#define ICMP6_DST_UNREACH 1
+#define ICMP6_PACKET_TOO_BIG 2
+#define ICMP6_TIME_EXCEEDED 3
+#define ICMP6_PARAM_PROB 4
+
+#define ICMP6_INFOMSG_MASK 0x80 /* all informational messages */
+
+#define ICMP6_ECHO_REQUEST 128
+#define ICMP6_ECHO_REPLY 129
+#define MLD_LISTENER_QUERY 130
+#define MLD_LISTENER_REPORT 131
+#define MLD_LISTENER_REDUCTION 132
+
+#define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */
+#define ICMP6_DST_UNREACH_ADMIN 1 /* communication with destination */
+ /* administratively prohibited */
+#define ICMP6_DST_UNREACH_BEYONDSCOPE 2 /* beyond scope of source address */
+#define ICMP6_DST_UNREACH_ADDR 3 /* address unreachable */
+#define ICMP6_DST_UNREACH_NOPORT 4 /* bad port */
+
+#define ICMP6_TIME_EXCEED_TRANSIT 0 /* Hop Limit == 0 in transit */
+#define ICMP6_TIME_EXCEED_REASSEMBLY 1 /* Reassembly time out */
+
+#define ICMP6_PARAMPROB_HEADER 0 /* erroneous header field */
+#define ICMP6_PARAMPROB_NEXTHEADER 1 /* unrecognized Next Header */
+#define ICMP6_PARAMPROB_OPTION 2 /* unrecognized IPv6 option */
+
+#define ICMP6_FILTER_WILLPASS(type, filterp) \
+ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) == 0)
+
+#define ICMP6_FILTER_WILLBLOCK(type, filterp) \
+ ((((filterp)->icmp6_filt[(type) >> 5]) & (1 << ((type) & 31))) != 0)
+
+#define ICMP6_FILTER_SETPASS(type, filterp) \
+ ((((filterp)->icmp6_filt[(type) >> 5]) &= ~(1 << ((type) & 31))))
+
+#define ICMP6_FILTER_SETBLOCK(type, filterp) \
+ ((((filterp)->icmp6_filt[(type) >> 5]) |= (1 << ((type) & 31))))
+
+#define ICMP6_FILTER_SETPASSALL(filterp) \
+ memset (filterp, 0, sizeof (struct icmp6_filter));
+
+#define ICMP6_FILTER_SETBLOCKALL(filterp) \
+ memset (filterp, 0xFF, sizeof (struct icmp6_filter));
+
+#define ND_ROUTER_SOLICIT 133
+#define ND_ROUTER_ADVERT 134
+#define ND_NEIGHBOR_SOLICIT 135
+#define ND_NEIGHBOR_ADVERT 136
+#define ND_REDIRECT 137
+
+struct nd_router_solicit /* router solicitation */
+ {
+ struct icmp6_hdr nd_rs_hdr;
+ /* could be followed by options */
+ };
+
+#define nd_rs_type nd_rs_hdr.icmp6_type
+#define nd_rs_code nd_rs_hdr.icmp6_code
+#define nd_rs_cksum nd_rs_hdr.icmp6_cksum
+#define nd_rs_reserved nd_rs_hdr.icmp6_data32[0]
+
+struct nd_router_advert /* router advertisement */
+ {
+ struct icmp6_hdr nd_ra_hdr;
+ uint32_t nd_ra_reachable; /* reachable time */
+ uint32_t nd_ra_retransmit; /* retransmit timer */
+ /* could be followed by options */
+ };
+
+#define nd_ra_type nd_ra_hdr.icmp6_type
+#define nd_ra_code nd_ra_hdr.icmp6_code
+#define nd_ra_cksum nd_ra_hdr.icmp6_cksum
+#define nd_ra_curhoplimit nd_ra_hdr.icmp6_data8[0]
+#define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1]
+#define ND_RA_FLAG_MANAGED 0x80
+#define ND_RA_FLAG_OTHER 0x40
+#define ND_RA_FLAG_HOME_AGENT 0x20
+#define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1]
+
+struct nd_neighbor_solicit /* neighbor solicitation */
+ {
+ struct icmp6_hdr nd_ns_hdr;
+ struct in6_addr nd_ns_target; /* target address */
+ /* could be followed by options */
+ };
+
+#define nd_ns_type nd_ns_hdr.icmp6_type
+#define nd_ns_code nd_ns_hdr.icmp6_code
+#define nd_ns_cksum nd_ns_hdr.icmp6_cksum
+#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0]
+
+struct nd_neighbor_advert /* neighbor advertisement */
+ {
+ struct icmp6_hdr nd_na_hdr;
+ struct in6_addr nd_na_target; /* target address */
+ /* could be followed by options */
+ };
+
+#define nd_na_type nd_na_hdr.icmp6_type
+#define nd_na_code nd_na_hdr.icmp6_code
+#define nd_na_cksum nd_na_hdr.icmp6_cksum
+#define nd_na_flags_reserved nd_na_hdr.icmp6_data32[0]
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_NA_FLAG_ROUTER 0x80000000
+#define ND_NA_FLAG_SOLICITED 0x40000000
+#define ND_NA_FLAG_OVERRIDE 0x20000000
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+#define ND_NA_FLAG_ROUTER 0x00000080
+#define ND_NA_FLAG_SOLICITED 0x00000040
+#define ND_NA_FLAG_OVERRIDE 0x00000020
+#endif
+
+struct nd_redirect /* redirect */
+ {
+ struct icmp6_hdr nd_rd_hdr;
+ struct in6_addr nd_rd_target; /* target address */
+ struct in6_addr nd_rd_dst; /* destination address */
+ /* could be followed by options */
+ };
+
+#define nd_rd_type nd_rd_hdr.icmp6_type
+#define nd_rd_code nd_rd_hdr.icmp6_code
+#define nd_rd_cksum nd_rd_hdr.icmp6_cksum
+#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0]
+
+struct nd_opt_hdr /* Neighbor discovery option header */
+ {
+ uint8_t nd_opt_type;
+ uint8_t nd_opt_len; /* in units of 8 octets */
+ /* followed by option specific data */
+ };
+
+#define ND_OPT_SOURCE_LINKADDR 1
+#define ND_OPT_TARGET_LINKADDR 2
+#define ND_OPT_PREFIX_INFORMATION 3
+#define ND_OPT_REDIRECTED_HEADER 4
+#define ND_OPT_MTU 5
+#define ND_OPT_RTR_ADV_INTERVAL 7
+#define ND_OPT_HOME_AGENT_INFO 8
+
+struct nd_opt_prefix_info /* prefix information */
+ {
+ uint8_t nd_opt_pi_type;
+ uint8_t nd_opt_pi_len;
+ uint8_t nd_opt_pi_prefix_len;
+ uint8_t nd_opt_pi_flags_reserved;
+ uint32_t nd_opt_pi_valid_time;
+ uint32_t nd_opt_pi_preferred_time;
+ uint32_t nd_opt_pi_reserved2;
+ struct in6_addr nd_opt_pi_prefix;
+ };
+
+#define ND_OPT_PI_FLAG_ONLINK 0x80
+#define ND_OPT_PI_FLAG_AUTO 0x40
+#define ND_OPT_PI_FLAG_RADDR 0x20
+
+struct nd_opt_rd_hdr /* redirected header */
+ {
+ uint8_t nd_opt_rh_type;
+ uint8_t nd_opt_rh_len;
+ uint16_t nd_opt_rh_reserved1;
+ uint32_t nd_opt_rh_reserved2;
+ /* followed by IP header and data */
+ };
+
+struct nd_opt_mtu /* MTU option */
+ {
+ uint8_t nd_opt_mtu_type;
+ uint8_t nd_opt_mtu_len;
+ uint16_t nd_opt_mtu_reserved;
+ uint32_t nd_opt_mtu_mtu;
+ };
+
+struct mld_hdr
+ {
+ struct icmp6_hdr mld_icmp6_hdr;
+ struct in6_addr mld_addr; /* multicast address */
+ };
+
+#define mld_type mld_icmp6_hdr.icmp6_type
+#define mld_code mld_icmp6_hdr.icmp6_code
+#define mld_cksum mld_icmp6_hdr.icmp6_cksum
+#define mld_maxdelay mld_icmp6_hdr.icmp6_data16[0]
+#define mld_reserved mld_icmp6_hdr.icmp6_data16[1]
+
+#define ICMP6_ROUTER_RENUMBERING 138
+
+struct icmp6_router_renum /* router renumbering header */
+ {
+ struct icmp6_hdr rr_hdr;
+ uint8_t rr_segnum;
+ uint8_t rr_flags;
+ uint16_t rr_maxdelay;
+ uint32_t rr_reserved;
+ };
+
+#define rr_type rr_hdr.icmp6_type
+#define rr_code rr_hdr.icmp6_code
+#define rr_cksum rr_hdr.icmp6_cksum
+#define rr_seqnum rr_hdr.icmp6_data32[0]
+
+/* Router renumbering flags */
+#define ICMP6_RR_FLAGS_TEST 0x80
+#define ICMP6_RR_FLAGS_REQRESULT 0x40
+#define ICMP6_RR_FLAGS_FORCEAPPLY 0x20
+#define ICMP6_RR_FLAGS_SPECSITE 0x10
+#define ICMP6_RR_FLAGS_PREVDONE 0x08
+
+struct rr_pco_match /* match prefix part */
+ {
+ uint8_t rpm_code;
+ uint8_t rpm_len;
+ uint8_t rpm_ordinal;
+ uint8_t rpm_matchlen;
+ uint8_t rpm_minlen;
+ uint8_t rpm_maxlen;
+ uint16_t rpm_reserved;
+ struct in6_addr rpm_prefix;
+ };
+
+/* PCO code values */
+#define RPM_PCO_ADD 1
+#define RPM_PCO_CHANGE 2
+#define RPM_PCO_SETGLOBAL 3
+
+struct rr_pco_use /* use prefix part */
+ {
+ uint8_t rpu_uselen;
+ uint8_t rpu_keeplen;
+ uint8_t rpu_ramask;
+ uint8_t rpu_raflags;
+ uint32_t rpu_vltime;
+ uint32_t rpu_pltime;
+ uint32_t rpu_flags;
+ struct in6_addr rpu_prefix;
+ };
+
+#define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x20
+#define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x10
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80000000
+# define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40000000
+#elif BYTE_ORDER == LITTLE_ENDIAN
+# define ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80
+# define ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40
+#endif
+
+struct rr_result /* router renumbering result message */
+ {
+ uint16_t rrr_flags;
+ uint8_t rrr_ordinal;
+ uint8_t rrr_matchedlen;
+ uint32_t rrr_ifid;
+ struct in6_addr rrr_prefix;
+ };
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define ICMP6_RR_RESULT_FLAGS_OOB 0x0002
+# define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001
+#elif BYTE_ORDER == LITTLE_ENDIAN
+# define ICMP6_RR_RESULT_FLAGS_OOB 0x0200
+# define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100
+#endif
+
+/* Mobile IPv6 extension: Advertisement Interval. */
+struct nd_opt_adv_interval
+ {
+ uint8_t nd_opt_adv_interval_type;
+ uint8_t nd_opt_adv_interval_len;
+ uint16_t nd_opt_adv_interval_reserved;
+ uint32_t nd_opt_adv_interval_ival;
+ };
+
+/* Mobile IPv6 extension: Home Agent Info. */
+struct nd_opt_home_agent_info
+ {
+ uint8_t nd_opt_home_agent_info_type;
+ uint8_t nd_opt_home_agent_info_len;
+ uint16_t nd_opt_home_agent_info_reserved;
+ int16_t nd_opt_home_agent_info_preference;
+ uint16_t nd_opt_home_agent_info_lifetime;
+ };
+
+#endif /* netinet/icmpv6.h */
diff --git a/networking/ipv6/ip6.h b/networking/ipv6/ip6.h
new file mode 100644
index 0000000..bef2af2
--- a/dev/null
+++ b/networking/ipv6/ip6.h
@@ -0,0 +1,189 @@
+/* Copyright (C) 1991-1997, 2001, 2003, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _NETINET_IP6_H
+#define _NETINET_IP6_H 1
+
+#include <inttypes.h>
+#include <netinet/in.h>
+
+struct ip6_hdr
+ {
+ union
+ {
+ struct ip6_hdrctl
+ {
+ uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC,
+ 20 bits flow-ID */
+ uint16_t ip6_un1_plen; /* payload length */
+ uint8_t ip6_un1_nxt; /* next header */
+ uint8_t ip6_un1_hlim; /* hop limit */
+ } ip6_un1;
+ uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits tclass */
+ } ip6_ctlun;
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* destination address */
+ };
+
+#define ip6_vfc ip6_ctlun.ip6_un2_vfc
+#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
+#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
+#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+/* Generic extension header. */
+struct ip6_ext
+ {
+ uint8_t ip6e_nxt; /* next header. */
+ uint8_t ip6e_len; /* length in units of 8 octets. */
+ };
+
+/* Hop-by-Hop options header. */
+struct ip6_hbh
+ {
+ uint8_t ip6h_nxt; /* next header. */
+ uint8_t ip6h_len; /* length in units of 8 octets. */
+ /* followed by options */
+ };
+
+/* Destination options header */
+struct ip6_dest
+ {
+ uint8_t ip6d_nxt; /* next header */
+ uint8_t ip6d_len; /* length in units of 8 octets */
+ /* followed by options */
+ };
+
+/* Routing header */
+struct ip6_rthdr
+ {
+ uint8_t ip6r_nxt; /* next header */
+ uint8_t ip6r_len; /* length in units of 8 octets */
+ uint8_t ip6r_type; /* routing type */
+ uint8_t ip6r_segleft; /* segments left */
+ /* followed by routing type specific data */
+ };
+
+/* Type 0 Routing header */
+struct ip6_rthdr0
+ {
+ uint8_t ip6r0_nxt; /* next header */
+ uint8_t ip6r0_len; /* length in units of 8 octets */
+ uint8_t ip6r0_type; /* always zero */
+ uint8_t ip6r0_segleft; /* segments left */
+ uint8_t ip6r0_reserved; /* reserved field */
+ uint8_t ip6r0_slmap[3]; /* strict/loose bit map */
+ /* followed by up to 127 struct in6_addr */
+ struct in6_addr ip6r0_addr[0];
+ };
+
+/* Fragment header */
+struct ip6_frag
+ {
+ uint8_t ip6f_nxt; /* next header */
+ uint8_t ip6f_reserved; /* reserved field */
+ uint16_t ip6f_offlg; /* offset, reserved, and flag */
+ uint32_t ip6f_ident; /* identification */
+ };
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */
+# define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */
+# define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */
+#else /* BYTE_ORDER == LITTLE_ENDIAN */
+# define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */
+# define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */
+# define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */
+#endif
+
+/* IPv6 options */
+struct ip6_opt
+ {
+ uint8_t ip6o_type;
+ uint8_t ip6o_len;
+ };
+
+/* The high-order 3 bits of the option type define the behavior
+ * when processing an unknown option and whether or not the option
+ * content changes in flight.
+ */
+#define IP6OPT_TYPE(o) ((o) & 0xc0)
+#define IP6OPT_TYPE_SKIP 0x00
+#define IP6OPT_TYPE_DISCARD 0x40
+#define IP6OPT_TYPE_FORCEICMP 0x80
+#define IP6OPT_TYPE_ICMP 0xc0
+#define IP6OPT_TYPE_MUTABLE 0x20
+
+/* Special option types for padding. */
+#define IP6OPT_PAD1 0
+#define IP6OPT_PADN 1
+
+#define IP6OPT_JUMBO 0xc2
+#define IP6OPT_NSAP_ADDR 0xc3
+#define IP6OPT_TUNNEL_LIMIT 0x04
+#define IP6OPT_ROUTER_ALERT 0x05
+
+/* Jumbo Payload Option */
+struct ip6_opt_jumbo
+ {
+ uint8_t ip6oj_type;
+ uint8_t ip6oj_len;
+ uint8_t ip6oj_jumbo_len[4];
+ };
+#define IP6OPT_JUMBO_LEN 6
+
+/* NSAP Address Option */
+struct ip6_opt_nsap
+ {
+ uint8_t ip6on_type;
+ uint8_t ip6on_len;
+ uint8_t ip6on_src_nsap_len;
+ uint8_t ip6on_dst_nsap_len;
+ /* followed by source NSAP */
+ /* followed by destination NSAP */
+ };
+
+/* Tunnel Limit Option */
+struct ip6_opt_tunnel
+ {
+ uint8_t ip6ot_type;
+ uint8_t ip6ot_len;
+ uint8_t ip6ot_encap_limit;
+ };
+
+/* Router Alert Option */
+struct ip6_opt_router
+ {
+ uint8_t ip6or_type;
+ uint8_t ip6or_len;
+ uint8_t ip6or_value[2];
+ };
+
+/* Router alert values (in network byte order) */
+#if BYTE_ORDER == BIG_ENDIAN
+# define IP6_ALERT_MLD 0x0000
+# define IP6_ALERT_RSVP 0x0001
+# define IP6_ALERT_AN 0x0002
+#else /* BYTE_ORDER == LITTLE_ENDING */
+# define IP6_ALERT_MLD 0x0000
+# define IP6_ALERT_RSVP 0x0100
+# define IP6_ALERT_AN 0x0200
+#endif
+
+#endif /* netinet/ip6.h */
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index d9e0996..21465dc 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -236,7 +236,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
if (!rta_tb[IFA_ADDRESS])
rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];
- if (G_filter.ifindex && G_filter.ifindex != ifa->ifa_index)
+ if (G_filter.ifindex && G_filter.ifindex != (int) ifa->ifa_index)
return 0;
if ((G_filter.scope ^ ifa->ifa_scope) & G_filter.scopemask)
return 0;
@@ -264,7 +264,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM,
if (G_filter.flushb) {
struct nlmsghdr *fn;
- if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
+ if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > (unsigned) G_filter.flushe) {
if (flush_update())
return -1;
}
@@ -375,8 +375,8 @@ static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo)
continue;
if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifa)))
return -1;
- if (ifa->ifa_index != ifindex
- || (G_filter.family && G_filter.family != ifa->ifa_family)
+ if ((int) ifa->ifa_index != ifindex
+ || (G_filter.family && G_filter.family != (family_t) ifa->ifa_family)
) {
continue;
}
@@ -525,8 +525,8 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
struct nlmsghdr *n = &a->h;
struct ifaddrmsg *ifa = NLMSG_DATA(n);
- if (ifa->ifa_index != ifi->ifi_index
- || (G_filter.family && G_filter.family != ifa->ifa_family)
+ if ((int) ifa->ifa_index != (int) ifi->ifi_index
+ || (G_filter.family && G_filter.family != (family_t) ifa->ifa_family)
) {
continue;
}
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index ae3ef0c..29cf1ab 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -9,6 +9,7 @@
/*#include <net/if_packet.h> - not needed? */
#include <netpacket/packet.h>
#include <netinet/if_ether.h>
+#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include "ip_common.h" /* #include "libbb.h" is inside */
@@ -344,7 +345,7 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
};
int arg;
uint16_t id, proto;
- struct ifla_vlan_flags flags = {};
+ struct ifla_vlan_flags flags = { 0, 0 };
while (*argv) {
arg = index_in_substrings(keywords, *argv);
@@ -401,7 +402,7 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
#ifndef NLMSG_TAIL
#define NLMSG_TAIL(nmsg) \
- ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+ ((struct rtattr *) ((void *) ((nmsg) + NLMSG_ALIGN((nmsg)->nlmsg_len))))
#endif
/* Return value becomes exitcode. It's okay to not return at all */
static int do_add_or_delete(char **argv, const unsigned rtm)
@@ -484,10 +485,10 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
if (strcmp(type_str, "vlan") == 0)
vlan_parse_opt(argv, &req.n, sizeof(req));
- data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
+ data->rta_len = (NLMSG_TAIL(&req.n) - (data));
}
- linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
+ linkinfo->rta_len = (NLMSG_TAIL(&req.n) - (linkinfo));
}
if (rtm != RTM_NEWLINK) {
if (!dev_str)
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index 0f2b896..e28c67c 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
@@ -201,7 +201,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
return 0;
}
- if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) {
+ if ((int) (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len) > G_filter.flushe) {
if (flush_update())
xfunc_die();
}
diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c
index 7e0ff1b..a1a9fc1 100644
--- a/networking/libiproute/libnetlink.c
+++ b/networking/libiproute/libnetlink.c
@@ -138,7 +138,7 @@ static int rtnl_dump_filter(struct rtnl_handle *rth,
}
h = (struct nlmsghdr*)buf;
- while (NLMSG_OK(h, status)) {
+ while (NLMSG_OK(h, (unsigned) status)) {
int err;
if (nladdr.nl_pid != 0 ||
diff --git a/networking/libiproute/ll_proto.c b/networking/libiproute/ll_proto.c
index 4c32ae5..263ac78 100644
--- a/networking/libiproute/ll_proto.c
+++ b/networking/libiproute/ll_proto.c
@@ -13,6 +13,8 @@
#include "utils.h"
#include <netinet/if_ether.h>
+#include <linux/if_ether.h>
+
/* Please conditionalize exotic protocols on CONFIG_something */
diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c
index 42025bc..779c6a3 100644
--- a/networking/libiproute/utils.c
+++ b/networking/libiproute/utils.c
@@ -168,7 +168,7 @@ static void get_prefix_1(inet_prefix *dst, char *arg, int family)
netmask_pfx.family = AF_UNSPEC;
plen = bb_strtou(slash + 1, NULL, 0);
- if ((errno || plen > dst->bitlen)
+ if ((errno || plen > (unsigned) dst->bitlen)
&& get_addr_1(&netmask_pfx, slash + 1, family) != 0
) {
goto bad;
@@ -184,7 +184,7 @@ static void get_prefix_1(inet_prefix *dst, char *arg, int family)
for (plen = 0; mask; mask <<= 1)
++plen;
- if (plen > dst->bitlen)
+ if (plen > (unsigned) dst->bitlen)
goto bad;
/* dst->flags |= PREFIXLEN_SPECIFIED; */
}
diff --git a/networking/nc.c b/networking/nc.c
index 1b70434..50302d8 100644
--- a/networking/nc.c
+++ b/networking/nc.c
@@ -109,7 +109,7 @@ int nc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int nc_main(int argc, char **argv)
{
/* sfd sits _here_ only because of "repeat" option (-l -l). */
- int sfd = sfd; /* for gcc */
+ int sfd = 0;
int cfd = 0;
unsigned lport = 0;
IF_NOT_NC_SERVER(const) unsigned do_listen = 0;
diff --git a/networking/nslookup.c b/networking/nslookup.c
index 8e3c8fe..8be5f34 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -37,6 +37,31 @@
#include <resolv.h>
#include "libbb.h"
+#ifdef ANDROID
+# include <netinet/in.h>
+# if ENABLE_FEATURE_IPV6
+# include <netinet/in6.h>
+# endif
+# define ANDROID_CHANGES
+# ifdef BIONIC_L
+# include <arpa/nameser.h>
+# include <dns/include/resolv_private.h>
+# include <dns/resolv/res_private.h>
+# else
+# include <arpa_nameser.h>
+# include <private/resolv_private.h>
+# include <netbsd/resolv/res_private.h>
+# endif
+
+static struct __res_state res_st;
+struct __res_state * __res_state(void)
+{
+ return &res_st;
+}
+#endif
+
+#define EXT(res) ((&res)->_u._ext)
+
/*
* I'm only implementing non-interactive mode;
* I totally forgot nslookup even had an interactive mode.
@@ -126,13 +151,19 @@ static int print_host(const char *hostname, const char *header)
static void server_print(void)
{
char *server;
- struct sockaddr *sa;
+ struct sockaddr *sa = NULL;
#if ENABLE_FEATURE_IPV6
- sa = (struct sockaddr*)_res._u._ext.nsaddrs[0];
+# ifdef ANDROID
+ if (EXT(_res).ext)
+ sa = (struct sockaddr*) &EXT(_res).ext->nsaddrs[0];
+# else
+ sa = (struct sockaddr*)_res._u._ext.nsaddrs[0];
+# endif
+
if (!sa)
#endif
- sa = (struct sockaddr*)&_res.nsaddr_list[0];
+ sa = (struct sockaddr*) &_res.nsaddr_list[0];
server = xmalloc_sockaddr2dotted_noport(sa);
print_host(server, "Server:");
@@ -150,7 +181,7 @@ static void set_default_dns(const char *server)
if (!server)
return;
- /* NB: this works even with, say, "[::1]:5353"! :) */
+ /* NB: this works even with, say, "[::1]:53"! :) */
lsa = xhost2sockaddr(server, 53);
if (lsa->u.sa.sa_family == AF_INET) {
@@ -158,6 +189,7 @@ static void set_default_dns(const char *server)
/* struct copy */
_res.nsaddr_list[0] = lsa->u.sin;
}
+
#if ENABLE_FEATURE_IPV6
/* Hoped libc can cope with IPv4 address there too.
* No such luck, glibc 2.4 segfaults even with IPv6,
@@ -167,10 +199,18 @@ static void set_default_dns(const char *server)
// glibc neither SEGVs nor sends any dgrams with this
// (strace shows no socket ops):
//_res.nscount = 0;
- _res._u._ext.nscount = 1;
+ #ifdef ANDROID
+ if (EXT(_res).ext) {
+ EXT(_res).nscount = 1;
+ memcpy(&EXT(_res).ext->nsaddrs[0].sin6, &lsa->u.sin6,
+ sizeof(struct sockaddr_in6));
+ }
+ #else
/* store a pointer to part of malloc'ed lsa */
+ _res._u._ext.nscount = 1;
_res._u._ext.nsaddrs[0] = &lsa->u.sin6;
/* must not free(lsa)! */
+ #endif
}
#endif
}
@@ -189,6 +229,11 @@ int nslookup_main(int argc, char **argv)
/* initialize DNS structure _res used in printing the default
* name server and in the explicit name server option feature. */
res_init();
+
+#ifdef ANDROID
+ res_ninit(&_res);
+#endif
+
/* rfc2133 says this enables IPv6 lookups */
/* (but it also says "may be enabled in /etc/resolv.conf") */
/*_res.options |= RES_USE_INET6;*/
diff --git a/networking/ntpd.c b/networking/ntpd.c
index b7fa5dc..1532669 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -95,7 +95,13 @@
#include <math.h>
#include <netinet/ip.h> /* For IPTOS_LOWDELAY definition */
#include <sys/resource.h> /* setpriority */
+
+#ifdef __BIONIC__
+#include <linux/timex.h>
+extern int adjtimex (struct timex *);
+#else
#include <sys/timex.h>
+#endif
#ifndef IPTOS_LOWDELAY
# define IPTOS_LOWDELAY 0x10
#endif
@@ -1141,12 +1147,12 @@ select_and_cluster(void)
int size = 3 * G.peer_cnt;
/* for selection algorithm */
point_t point[size];
- unsigned num_points, num_candidates;
+ int num_points, num_candidates;
double low, high;
- unsigned num_falsetickers;
+ int num_falsetickers;
/* for cluster algorithm */
survivor_t survivor[size];
- unsigned num_survivors;
+ int num_survivors;
/* Selection */
@@ -1207,12 +1213,12 @@ select_and_cluster(void)
num_falsetickers = 0;
while (1) {
int c;
- unsigned num_midpoints = 0;
+ int num_midpoints = 0;
low = 1 << 9;
high = - (1 << 9);
c = 0;
- for (i = 0; i < num_points; i++) {
+ for (i = 0; i < (int) num_points; i++) {
/* We want to do:
* if (point[i].type == -1) c++;
* if (point[i].type == 1) c--;
@@ -1297,7 +1303,7 @@ select_and_cluster(void)
* jitter until a termination condition is met.
*/
while (1) {
- unsigned max_idx = max_idx;
+ static int max_idx;
double max_selection_jitter = max_selection_jitter;
double min_jitter = min_jitter;
@@ -2219,7 +2225,7 @@ static NOINLINE void ntp_init(char **argv)
srand(getpid());
if (getuid())
- bb_error_msg_and_die(bb_msg_you_must_be_root);
+ bb_error_msg_and_die("%s", bb_msg_you_must_be_root);
/* Set some globals */
G.discipline_jitter = G_precision_sec;
diff --git a/networking/ping.c b/networking/ping.c
index d0ef7ba..d541b79 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -172,8 +172,8 @@ create_icmp_socket(void)
sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */
if (sock < 0) {
if (errno == EPERM)
- bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
- bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
+ bb_error_msg_and_die("%s", bb_msg_perm_denied_are_you_root);
+ bb_perror_msg_and_die("%s", bb_msg_can_not_create_raw_socket);
}
xmove_fd(sock, pingsock);
diff --git a/networking/route.c b/networking/route.c
index 7dc2b5a..0f90a19 100644
--- a/networking/route.c
+++ b/networking/route.c
@@ -43,12 +43,16 @@
//usage: "\n -e Display other/more information"
//usage: "\n -A inet" IF_FEATURE_IPV6("{6}") " Select address family"
+#include <sys/socket.h>
#include <net/route.h>
#include <net/if.h>
#include "libbb.h"
#include "inet_common.h"
+#if ENABLE_FEATURE_IPV6
+#include <linux/ipv6_route.h>
+#endif
#ifndef RTF_UP
/* Keep this in sync with /usr/src/linux/include/linux/route.h */
@@ -68,6 +72,12 @@
#define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */
#endif
+#ifndef RTF_CACHE
+#define RTF_DEFAULT 0x00010000 /* default - learned via ND */
+#define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */
+#define RTF_CACHE 0x01000000 /* cache entry */
+#endif
+
#if defined(SIOCADDRTOLD) || defined(RTF_IRTT) /* route */
#define HAVE_NEW_ADDRT 1
#endif
diff --git a/networking/traceroute.c b/networking/traceroute.c
index a463b0f..fccfcb3 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -308,8 +308,13 @@
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#if ENABLE_FEATURE_IPV6
-# include <netinet/ip6.h>
-# include <netinet/icmp6.h>
+# ifdef __BIONIC__
+# include "ipv6/ip6.h"
+# include "ipv6/icmp6.h"
+# else
+# include <netinet/ip6.h>
+# include <netinet/icmp6.h>
+# endif
# ifndef SOL_IPV6
# define SOL_IPV6 IPPROTO_IPV6
# endif
@@ -863,7 +868,7 @@ common_traceroute_main(int op, char **argv)
* probe (e.g., on a multi-homed host).
*/
if (getuid() != 0)
- bb_error_msg_and_die(bb_msg_you_must_be_root);
+ bb_error_msg_and_die("%s", bb_msg_you_must_be_root);
}
if (op & OPT_WAITTIME)
waittime = xatou_range(waittime_str, 1, 24 * 60 * 60);
diff --git a/networking/udhcp/arpping.c b/networking/udhcp/arpping.c
index 215d023..778b1d7 100644
--- a/networking/udhcp/arpping.c
+++ b/networking/udhcp/arpping.c
@@ -53,7 +53,7 @@ int FAST_FUNC arpping(uint32_t test_nip,
s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
if (s == -1) {
- bb_perror_msg(bb_msg_can_not_create_raw_socket);
+ bb_perror_msg("%s", bb_msg_can_not_create_raw_socket);
return -1;
}
diff --git a/networking/wget.c b/networking/wget.c
index b082a0f..cf0769e 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -389,7 +389,7 @@ static FILE *open_socket(len_and_sockaddr *lsa)
/* hopefully it understands what ESPIPE means... */
fp = fdopen(fd, "r+");
if (!fp)
- bb_perror_msg_and_die(bb_msg_memory_exhausted);
+ bb_perror_msg_and_die("%s", bb_msg_memory_exhausted);
return fp;
}
@@ -1024,7 +1024,7 @@ static void download_one_url(const char *url)
# endif
sfp = fdopen(fd, "r+");
if (!sfp)
- bb_perror_msg_and_die(bb_msg_memory_exhausted);
+ bb_perror_msg_and_die("%s", bb_msg_memory_exhausted);
goto socket_opened;
}
sfp = open_socket(lsa);
diff --git a/printutils/lpr.c b/printutils/lpr.c
index ed6a84a..29e2fd6 100644
--- a/printutils/lpr.c
+++ b/printutils/lpr.c
@@ -262,7 +262,7 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[])
// send data file, with name "dfaXXX"
if (opts & LPR_V)
bb_error_msg("sending data file");
- fdprintf(fd, "\x3" "%"OFF_FMT"u d%s\n", st.st_size, remote_filename);
+ fdprintf(fd, "\x3" "%"FILESIZE_FMT"u d%s\n", st.st_size, remote_filename);
get_response_or_say_and_die(fd, "sending data file");
if (bb_copyfd_size(dfd, fd, st.st_size) != st.st_size) {
// We're screwed. We sent less bytes than we advertised.
diff --git a/procps/kill.c b/procps/kill.c
index 57a33bc..846e9e2 100644
--- a/procps/kill.c
+++ b/procps/kill.c
@@ -234,7 +234,7 @@ int kill_main(int argc UNUSED_PARAM, char **argv)
ret = 1;
goto resume;
}
- if (p->pid == omit)
+ if ((pid_t) p->pid == (pid_t) omit)
goto dont_kill;
}
kill(p->pid, signo);
diff --git a/procps/lsof.c b/procps/lsof.c
index b0156a5..281a55c 100644
--- a/procps/lsof.c
+++ b/procps/lsof.c
@@ -54,7 +54,7 @@ int lsof_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
char *fdlink;
struct dirent *entry;
- if (getpid() == proc->pid)
+ if ((pid_t) getpid() == (pid_t) proc->pid)
continue;
baseofs = sprintf(name, "/proc/%u/fd/", proc->pid);
diff --git a/procps/mpstat.c b/procps/mpstat.c
index 6028903..d23c9c7 100644
--- a/procps/mpstat.c
+++ b/procps/mpstat.c
@@ -85,7 +85,7 @@ struct stats_irq {
struct globals {
int interval;
int count;
- unsigned cpu_nr; /* Number of CPUs */
+ int cpu_nr; /* Number of CPUs */
unsigned irqcpu_nr; /* Number of interrupts per CPU */
unsigned softirqcpu_nr; /* Number of soft interrupts per CPU */
unsigned options;
@@ -167,7 +167,7 @@ static ALWAYS_INLINE data_t jiffies_diff(data_t old, data_t new)
return (diff == 0) ? 1 : diff;
}
-static int is_cpu_in_bitmap(unsigned cpu)
+static int is_cpu_in_bitmap(int cpu)
{
return G.cpu_bitmap[cpu >> 3] & (1 << (cpu & 7));
}
@@ -462,7 +462,7 @@ static void get_cpu_statistics(struct stats_cpu *cpu, data_t *up, data_t *up0)
while (fgets(buf, sizeof(buf), fp)) {
data_t sum;
- unsigned cpu_number;
+ int cpu_number;
struct stats_cpu *cp;
if (!starts_with_cpu(buf))
@@ -547,8 +547,8 @@ static void get_irqs_from_interrupts(const char *fname,
struct stats_irqcpu *ic;
char *buf;
unsigned buflen;
- unsigned cpu;
- unsigned irq;
+ int cpu;
+ int irq;
int cpu_index[G.cpu_nr];
int iindex;
@@ -603,7 +603,7 @@ static void get_irqs_from_interrupts(const char *fname,
ic = &per_cpu_stats[current][irq];
len = cp - buf;
- if (len >= sizeof(ic->irq_name)) {
+ if (len >= (int) sizeof(ic->irq_name)) {
len = sizeof(ic->irq_name) - 1;
}
safe_strncpy(ic->irq_name, buf, len + 1);
@@ -668,7 +668,7 @@ static void alarm_handler(int sig UNUSED_PARAM)
static void main_loop(void)
{
unsigned current;
- unsigned cpus;
+ int cpus;
/* Read the stats */
if (G.cpu_nr > 1) {
@@ -806,7 +806,7 @@ static int get_irqcpu_nr(const char *f, int max_irqs)
FILE *fp;
char *line;
unsigned linelen;
- unsigned irq;
+ int irq;
fp = fopen_for_read(f);
if (!fp) /* No interrupts file */
@@ -929,7 +929,7 @@ int mpstat_main(int UNUSED_PARAM argc, char **argv)
memset(G.cpu_bitmap, 0xff, G.cpu_bitmap_len);
} else {
/* Get CPU number */
- unsigned n = xatoi_positive(t);
+ int n = xatoi_positive(t);
if (n >= G.cpu_nr)
bb_error_msg_and_die("not that many processors");
n++;
diff --git a/procps/pstree.c b/procps/pstree.c
index c5fb836..000959c 100644
--- a/procps/pstree.c
+++ b/procps/pstree.c
@@ -94,7 +94,7 @@ struct globals {
*/
static void ensure_buffer_capacity(int bufindex)
{
- if (bufindex >= G.capacity) {
+ if ((unsigned)bufindex >= G.capacity) {
G.capacity += 0x100;
G.width = xrealloc(G.width, G.capacity * sizeof(G.width[0]));
G.more = xrealloc(G.more, G.capacity * sizeof(G.more[0]));
diff --git a/procps/smemcap.c b/procps/smemcap.c
index 9d1126a..7dc1601 100644
--- a/procps/smemcap.c
+++ b/procps/smemcap.c
@@ -36,8 +36,16 @@ static void writeheader(const char *path, struct stat *sb, int type)
strcpy(header.name, path);
sprintf(header.mode, "%o", sb->st_mode & 0777);
/* careful to not overflow fields! */
+#ifdef BIONIC_L
+ sprintf(header.uid, "%uo", sb->st_uid & 07777777);
+ sprintf(header.gid, "%uo", sb->st_gid & 07777777);
+#elif defined(__BIONIC__)
+ sprintf(header.uid, "%lo", sb->st_uid & 07777777);
+ sprintf(header.gid, "%lo", sb->st_gid & 07777777);
+#else
sprintf(header.uid, "%o", sb->st_uid & 07777777);
sprintf(header.gid, "%o", sb->st_gid & 07777777);
+#endif
sprintf(header.size, "%o", (unsigned)sb->st_size);
sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL);
header.typeflag = type;
diff --git a/procps/sysctl.c b/procps/sysctl.c
index 93d7c34..16f91dc 100644
--- a/procps/sysctl.c
+++ b/procps/sysctl.c
@@ -103,7 +103,7 @@ static int sysctl_act_on_setting(char *setting)
{
int fd, retval = EXIT_SUCCESS;
char *cptr, *outname;
- char *value = value; /* for compiler */
+ char *value = NULL;
outname = xstrdup(setting);
diff --git a/procps/uptime.c b/procps/uptime.c
index 4361939..88f896a 100644
--- a/procps/uptime.c
+++ b/procps/uptime.c
@@ -44,6 +44,8 @@
#ifdef __linux__
# include <sys/sysinfo.h>
#endif
+# include <utmp.h>
+
#ifndef FSHIFT
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 5eac45f..1bcc1da 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -337,6 +337,9 @@ ifneq ($(cmd_files),)
include $(cmd_files)
endif
+PHONY += show-src
+show-src:
+ @echo $(lib-y:.o=.c)
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable se we can use it in if_changed and friends.
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 8f4ecbd..d215d2d 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -391,19 +391,19 @@ int conf_write(const char *name)
use_timestamp ? ctime(&now) : "");
if (out_h) {
char buf[sizeof("#define AUTOCONF_TIMESTAMP "
- "\"YYYY-MM-DD HH:MM:SS some_timezone\"\n")];
+ "\"YYYY-MM-DD HH:MM some_timezone\"\n")];
buf[0] = '\0';
if (use_timestamp) {
size_t ret = \
strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
- "\"%Y-%m-%d %H:%M:%S %Z\"\n", localtime(&now));
+ "\"%Y-%m-%d %H:%M %z\"\n", localtime(&now));
/* if user has Factory timezone or some other odd install, the
* %Z above will overflow the string leaving us with undefined
* results ... so let's try again without the timezone.
*/
if (ret == 0)
strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
- "\"%Y-%m-%d %H:%M:%S\"\n", localtime(&now));
+ "\"%Y-%m-%d %H:%M\"\n", localtime(&now));
} else { /* bbox */
strcpy(buf, "#define AUTOCONF_TIMESTAMP \"\"\n");
}
diff --git a/scripts/update_config b/scripts/update_config
new file mode 100755
index 0000000..84cac14
--- a/dev/null
+++ b/scripts/update_config
@@ -0,0 +1,15 @@
+#!/bin/bash -ex
+#
+# Update relevant files after config change
+# shade@chemlab.org
+
+for config in full minimal ; do
+ rm -f .config.old
+ cp -f .config-$config .config
+ make clean prepare busybox.links
+ make -s show-sources > busybox-$config.sources
+ mkdir -p include-$config
+ mv -f include/{autoconf,applet_tables,usage_compressed,bbconfigopts}.h include-$config
+ mv -f busybox.links busybox-$config.links
+ rm -f .config
+done
diff --git a/selinux/chcon.c b/selinux/chcon.c
index c743013..c3a1858 100644
--- a/selinux/chcon.c
+++ b/selinux/chcon.c
@@ -58,7 +58,8 @@
//usage: )
#include <selinux/context.h>
-
+#include <selinux/selinux.h>
+#include <selinux/label.h>
#include "libbb.h"
#define OPT_RECURSIVE (1<<0) /* 'R' */
@@ -218,7 +219,7 @@ int chcon_main(int argc UNUSED_PARAM, char **argv)
fname[fname_len] = '\0';
if (recursive_action(fname,
- 1<<option_mask32 & OPT_RECURSIVE,
+ option_mask32 & OPT_RECURSIVE,
change_filedir_context,
change_filedir_context,
NULL, 0) != TRUE)
diff --git a/selinux/matchpathcon.c b/selinux/matchpathcon.c
index a3b2fcb..c5cbac6 100644
--- a/selinux/matchpathcon.c
+++ b/selinux/matchpathcon.c
@@ -75,6 +75,11 @@ int matchpathcon_main(int argc UNUSED_PARAM, char **argv)
bb_perror_msg_and_die("error while processing %s", prefix);
}
+#ifdef ANDROID
+ if (!(opts & (OPT_FCONTEXT | OPT_PREFIX))) {
+ matchpathcon_init(selinux_file_contexts_path());
+ }
+#endif
while ((path = *argv++) != NULL) {
security_context_t con;
int rc;
diff --git a/selinux/setfiles.c b/selinux/setfiles.c
index 9fa5d3f..dce4ef6 100644
--- a/selinux/setfiles.c
+++ b/selinux/setfiles.c
@@ -684,6 +684,16 @@ int setfiles_main(int argc UNUSED_PARAM, char **argv)
argv++;
}
+#ifdef __BIONIC__
+ else {
+ const char *file_contexts = selinux_file_contexts_path();
+ /* Load the default file contexts configuration and check it. */
+ if (matchpathcon_init(file_contexts) < 0) {
+ bb_perror_msg_and_die("%s not found!", file_contexts);
+ }
+ }
+#endif
+
if (input_filename) {
ssize_t len;
FILE *f = stdin;
diff --git a/shell/ash.c b/shell/ash.c
index e6d02f6..02e33e4 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -15,6 +15,66 @@
*
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
+
+/*
+ * The following should be set to reflect the type of system you have:
+ * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
+ * define SYSV if you are running under System V.
+ * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
+ * define DEBUG=2 to compile in and turn on debugging.
+ *
+ * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
+ * debugging info will be written to ./trace and a quit signal
+ * will generate a core dump.
+ */
+#define DEBUG 0
+/* Tweak debug output verbosity here */
+#define DEBUG_TIME 0
+#define DEBUG_PID 1
+#define DEBUG_SIG 1
+
+#define PROFILE 0
+
+#define JOBS ENABLE_ASH_JOB_CONTROL
+
+#include <paths.h>
+#include <setjmp.h>
+#include <fnmatch.h>
+#include <sys/times.h>
+
+#include "busybox.h" /* for applet_names */
+#include "unicode.h"
+
+#include "shell_common.h"
+#if ENABLE_SH_MATH_SUPPORT
+# include "math.h"
+#endif
+#if ENABLE_ASH_RANDOM_SUPPORT
+# include "random.h"
+#else
+# define CLEAR_RANDOM_T(rnd) ((void)0)
+#endif
+
+#include "NUM_APPLETS.h"
+#if NUM_APPLETS == 1
+/* STANDALONE does not make sense, and won't compile */
+# undef CONFIG_FEATURE_SH_STANDALONE
+# undef ENABLE_FEATURE_SH_STANDALONE
+# undef IF_FEATURE_SH_STANDALONE
+# undef IF_NOT_FEATURE_SH_STANDALONE
+# define ENABLE_FEATURE_SH_STANDALONE 0
+# define IF_FEATURE_SH_STANDALONE(...)
+# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
+#endif
+
+#ifndef PIPE_BUF
+# define PIPE_BUF 4096 /* amount of buffering in a pipe */
+#endif
+
+#if !BB_MMU
+# error "Do not even bother, ash will not run on NOMMU machine"
+#endif
+
//config:config ASH
//config: bool "ash"
//config: default y
@@ -26,109 +86,66 @@
//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
//config: (written by Kenneth Almquist) from NetBSD.
//config:
-//config:config ASH_OPTIMIZE_FOR_SIZE
-//config: bool "Optimize for size instead of speed"
-//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
-//config: help
-//config: Compile ash for reduced size at the price of speed.
-//config:
-//config:config ASH_INTERNAL_GLOB
-//config: bool "Use internal glob() implementation"
-//config: default y # Y is bigger, but because of uclibc glob() bug, let Y be default for now
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
-//config: help
-//config: Do not use glob() function from libc, use internal implementation.
-//config: Use this if you are getting "glob.h: No such file or directory"
-//config: or similar build errors.
-//config:
-//config:config ASH_RANDOM_SUPPORT
-//config: bool "Pseudorandom generator and $RANDOM variable"
-//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
-//config: help
-//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
-//config: Each read of "$RANDOM" will generate a new pseudorandom value.
-//config: You can reset the generator by using a specified start value.
-//config: After "unset RANDOM" the generator will switch off and this
-//config: variable will no longer have special treatment.
-//config:
-//config:config ASH_EXPAND_PRMT
-//config: bool "Expand prompt string"
-//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
-//config: help
-//config: "PS#" may contain volatile content, such as backquote commands.
-//config: This option recreates the prompt string from the environment
-//config: variable each time it is displayed.
-//config:
//config:config ASH_BASH_COMPAT
//config: bool "bash-compatible extensions"
//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: depends on ASH
//config: help
//config: Enable bash-compatible extensions.
//config:
//config:config ASH_IDLE_TIMEOUT
//config: bool "Idle timeout variable"
//config: default n
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: depends on ASH
//config: help
//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
//config:
//config:config ASH_JOB_CONTROL
//config: bool "Job control"
//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: depends on ASH
//config: help
//config: Enable job control in the ash shell.
//config:
//config:config ASH_ALIAS
//config: bool "Alias support"
//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: depends on ASH
//config: help
//config: Enable alias support in the ash shell.
//config:
//config:config ASH_GETOPTS
//config: bool "Builtin getopt to parse positional parameters"
//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: depends on ASH
//config: help
//config: Enable support for getopts builtin in ash.
//config:
//config:config ASH_BUILTIN_ECHO
//config: bool "Builtin version of 'echo'"
//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: depends on ASH
//config: help
//config: Enable support for echo builtin in ash.
//config:
//config:config ASH_BUILTIN_PRINTF
//config: bool "Builtin version of 'printf'"
//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: depends on ASH
//config: help
//config: Enable support for printf builtin in ash.
//config:
//config:config ASH_BUILTIN_TEST
//config: bool "Builtin version of 'test'"
//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: depends on ASH
//config: help
//config: Enable support for test builtin in ash.
//config:
-//config:config ASH_HELP
-//config: bool "help builtin"
-//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
-//config: help
-//config: Enable help builtin in ash.
-//config:
//config:config ASH_CMDCMD
//config: bool "'command' command to override shell builtins"
//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: depends on ASH
//config: help
//config: Enable support for the ash 'command' builtin, which allows
//config: you to run the specified command with the specified arguments,
@@ -136,101 +153,46 @@
//config:
//config:config ASH_MAIL
//config: bool "Check for new mail on interactive shells"
-//config: default y
-//config: depends on ASH || SH_IS_ASH || BASH_IS_ASH
+//config: default n
+//config: depends on ASH
//config: help
//config: Enable "check for new mail" function in the ash shell.
+//config:
+//config:config ASH_OPTIMIZE_FOR_SIZE
+//config: bool "Optimize for size instead of speed"
+//config: default y
+//config: depends on ASH
+//config: help
+//config: Compile ash for reduced size at the price of speed.
+//config:
+//config:config ASH_RANDOM_SUPPORT
+//config: bool "Pseudorandom generator and $RANDOM variable"
+//config: default y
+//config: depends on ASH
+//config: help
+//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
+//config: Each read of "$RANDOM" will generate a new pseudorandom value.
+//config: You can reset the generator by using a specified start value.
+//config: After "unset RANDOM" the generator will switch off and this
+//config: variable will no longer have special treatment.
+//config:
+//config:config ASH_EXPAND_PRMT
+//config: bool "Expand prompt string"
+//config: default y
+//config: depends on ASH
+//config: help
+//config: "PS#" may contain volatile content, such as backquote commands.
+//config: This option recreates the prompt string from the environment
+//config: variable each time it is displayed.
+//config:
//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
//applet:IF_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
//applet:IF_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, ash))
//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
-//kbuild:lib-$(CONFIG_SH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
-//kbuild:lib-$(CONFIG_BASH_IS_ASH) += ash.o ash_ptr_hack.o shell_common.o
//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
-/*
- * The following should be set to reflect the type of system you have:
- * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
- * define SYSV if you are running under System V.
- * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
- * define DEBUG=2 to compile in and turn on debugging.
- *
- * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
- * debugging info will be written to ./trace and a quit signal
- * will generate a core dump.
- */
-#define DEBUG 0
-/* Tweak debug output verbosity here */
-#define DEBUG_TIME 0
-#define DEBUG_PID 1
-#define DEBUG_SIG 1
-#define DEBUG_INTONOFF 0
-
-#define PROFILE 0
-
-#define JOBS ENABLE_ASH_JOB_CONTROL
-
-#include <setjmp.h>
-#include <fnmatch.h>
-#include <sys/times.h>
-#include <sys/utsname.h> /* for setting $HOSTNAME */
-
-#include "busybox.h" /* for applet_names */
-
-#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
-/* Bionic at least up to version 24 has no glob() */
-# undef ENABLE_ASH_INTERNAL_GLOB
-# define ENABLE_ASH_INTERNAL_GLOB 1
-#endif
-
-#if !ENABLE_ASH_INTERNAL_GLOB && defined(__UCLIBC__)
-# error uClibc glob() is buggy, use ASH_INTERNAL_GLOB.
-# error The bug is: for "$PWD"/<pattern> ash will escape e.g. dashes in "$PWD"
-# error with backslash, even ones which do not need to be: "/a-b" -> "/a\-b"
-# error glob() should unbackslash them and match. uClibc does not unbackslash,
-# error fails to match dirname, subsequently not expanding <pattern> in it.
-// Testcase:
-// if (glob("/etc/polkit\\-1", 0, NULL, &pglob)) - this returns 0 on uclibc, no bug
-// if (glob("/etc/polkit\\-1/*", 0, NULL, &pglob)) printf("uclibc bug!\n");
-#endif
-
-#if !ENABLE_ASH_INTERNAL_GLOB
-# include <glob.h>
-#endif
-
-#include "unicode.h"
-#include "shell_common.h"
-#if ENABLE_FEATURE_SH_MATH
-# include "math.h"
-#endif
-#if ENABLE_ASH_RANDOM_SUPPORT
-# include "random.h"
-#else
-# define CLEAR_RANDOM_T(rnd) ((void)0)
-#endif
-
-#include "NUM_APPLETS.h"
-#if NUM_APPLETS == 1
-/* STANDALONE does not make sense, and won't compile */
-# undef CONFIG_FEATURE_SH_STANDALONE
-# undef ENABLE_FEATURE_SH_STANDALONE
-# undef IF_FEATURE_SH_STANDALONE
-# undef IF_NOT_FEATURE_SH_STANDALONE
-# define ENABLE_FEATURE_SH_STANDALONE 0
-# define IF_FEATURE_SH_STANDALONE(...)
-# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
-#endif
-
-#ifndef PIPE_BUF
-# define PIPE_BUF 4096 /* amount of buffering in a pipe */
-#endif
-
-#if !BB_MMU
-# error "Do not even bother, ash will not run on NOMMU machine"
-#endif
-
/* ============ Hash table sizes. Configurable. */
@@ -289,10 +251,8 @@ struct jmploc {
};
struct globals_misc {
- uint8_t exitstatus; /* exit status of last command */
- uint8_t back_exitstatus;/* exit status of backquoted command */
- smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
- int rootpid; /* pid of main shell */
+ /* pid of main shell */
+ int rootpid;
/* shell level: 0 for the main shell, 1 for its children, and so on */
int shlvl;
#define rootshell (!shlvl)
@@ -307,13 +267,16 @@ struct globals_misc {
volatile int suppress_int; /* counter */
volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
- volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
- volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
+ /* last pending signal */
+ volatile /*sig_atomic_t*/ smallint pending_sig;
smallint exception_type; /* kind of exception (0..5) */
/* exceptions */
#define EXINT 0 /* SIGINT received */
#define EXERROR 1 /* a generic error */
+#define EXSHELLPROC 2 /* execute a shell procedure */
+#define EXEXEC 3 /* command execution failed */
#define EXEXIT 4 /* exit the shell */
+#define EXSIG 5 /* trapped signal in wait(1) */
smallint isloginsh;
char nullstr[1]; /* zero length string */
@@ -353,7 +316,7 @@ struct globals_misc {
#define S_DFL 1 /* default signal handling (SIG_DFL) */
#define S_CATCH 2 /* signal is caught */
#define S_IGN 3 /* signal is ignored (SIG_IGN) */
-#define S_HARD_IGN 4 /* signal is ignored permanently */
+#define S_HARD_IGN 4 /* signal is ignored permenantly */
/* indicates specified signal received */
uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
@@ -366,12 +329,10 @@ struct globals_misc {
random_t random_gen;
#endif
pid_t backgndpid; /* pid of last background process */
+ smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
};
extern struct globals_misc *const ash_ptr_to_globals_misc;
#define G_misc (*ash_ptr_to_globals_misc)
-#define exitstatus (G_misc.exitstatus )
-#define back_exitstatus (G_misc.back_exitstatus )
-#define job_warning (G_misc.job_warning)
#define rootpid (G_misc.rootpid )
#define shlvl (G_misc.shlvl )
#define minusc (G_misc.minusc )
@@ -382,7 +343,6 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
#define exception_type (G_misc.exception_type )
#define suppress_int (G_misc.suppress_int )
#define pending_int (G_misc.pending_int )
-#define got_sigchld (G_misc.got_sigchld )
#define pending_sig (G_misc.pending_sig )
#define isloginsh (G_misc.isloginsh )
#define nullstr (G_misc.nullstr )
@@ -394,6 +354,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
#define trap_ptr (G_misc.trap_ptr )
#define random_gen (G_misc.random_gen )
#define backgndpid (G_misc.backgndpid )
+#define job_warning (G_misc.job_warning)
#define INIT_G_misc() do { \
(*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
barrier(); \
@@ -422,11 +383,12 @@ static void trace_vprintf(const char *fmt, va_list va);
/* ============ Utility functions */
+#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
+
#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
-static int
-isdigit_str9(const char *str)
+static int isdigit_str9(const char *str)
{
int maxlen = 9 + 1; /* max 9 digits: 999999999 */
while (--maxlen && isdigit(*str))
@@ -434,8 +396,7 @@ isdigit_str9(const char *str)
return (*str == '\0');
}
-static const char *
-var_end(const char *var)
+static const char *var_end(const char *var)
{
while (*var)
if (*var++ == '=')
@@ -454,18 +415,10 @@ static void exitshell(void) NORETURN;
* much more efficient and portable. (But hacking the kernel is so much
* more fun than worrying about efficiency and portability. :-))
*/
-#if DEBUG_INTONOFF
-# define INT_OFF do { \
- TRACE(("%s:%d INT_OFF(%d)\n", __func__, __LINE__, suppress_int)); \
+#define INT_OFF do { \
suppress_int++; \
- barrier(); \
-} while (0)
-#else
-# define INT_OFF do { \
- suppress_int++; \
- barrier(); \
+ xbarrier(); \
} while (0)
-#endif
/*
* Called to raise an exception. Since C doesn't include exceptions, we
@@ -492,7 +445,7 @@ raise_exception(int e)
#endif
/*
- * Called when a SIGINT is received. (If the user specifies
+ * Called from trap.c when a SIGINT is received. (If the user specifies
* that SIGINT is to be trapped or ignored using the trap builtin, then
* this routine is not called.) Suppressint is nonzero when interrupts
* are held using the INT_OFF macro. (The test for iflag is just
@@ -502,20 +455,24 @@ static void raise_interrupt(void) NORETURN;
static void
raise_interrupt(void)
{
+ int ex_type;
+
pending_int = 0;
/* Signal is not automatically unmasked after it is raised,
* do it ourself - unmask all signals */
sigprocmask_allsigs(SIG_UNBLOCK);
/* pending_sig = 0; - now done in signal_handler() */
- if (!(rootshell && iflag)) {
- /* Kill ourself with SIGINT */
- signal(SIGINT, SIG_DFL);
- raise(SIGINT);
+ ex_type = EXSIG;
+ if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
+ if (!(rootshell && iflag)) {
+ /* Kill ourself with SIGINT */
+ signal(SIGINT, SIG_DFL);
+ raise(SIGINT);
+ }
+ ex_type = EXINT;
}
- /* bash: ^C even on empty command line sets $? */
- exitstatus = SIGINT + 128;
- raise_exception(EXINT);
+ raise_exception(ex_type);
/* NOTREACHED */
}
#if DEBUG
@@ -528,23 +485,16 @@ raise_interrupt(void)
static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
int_on(void)
{
- barrier();
+ xbarrier();
if (--suppress_int == 0 && pending_int) {
raise_interrupt();
}
}
-#if DEBUG_INTONOFF
-# define INT_ON do { \
- TRACE(("%s:%d INT_ON(%d)\n", __func__, __LINE__, suppress_int-1)); \
- int_on(); \
-} while (0)
-#else
-# define INT_ON int_on()
-#endif
+#define INT_ON int_on()
static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
force_int_on(void)
{
- barrier();
+ xbarrier();
suppress_int = 0;
if (pending_int)
raise_interrupt();
@@ -554,7 +504,7 @@ force_int_on(void)
#define SAVE_INT(v) ((v) = suppress_int)
#define RESTORE_INT(v) do { \
- barrier(); \
+ xbarrier(); \
suppress_int = (v); \
if (suppress_int == 0 && pending_int) \
raise_interrupt(); \
@@ -579,12 +529,11 @@ flush_stdout_stderr(void)
INT_ON;
}
-/* Was called outcslow(c,FILE*), but c was always '\n' */
static void
-newline_and_flush(FILE *dest)
+outcslow(int c, FILE *dest)
{
INT_OFF;
- putc('\n', dest);
+ putc(c, dest);
fflush(dest);
INT_ON;
}
@@ -641,6 +590,8 @@ out2str(const char *p)
#define CTLVAR ((unsigned char)'\202') /* variable defn */
#define CTLENDVAR ((unsigned char)'\203')
#define CTLBACKQ ((unsigned char)'\204')
+#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
+/* CTLBACKQ | CTLQUOTE == '\205' */
#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
#define CTLENDARI ((unsigned char)'\207')
#define CTLQUOTEMARK ((unsigned char)'\210')
@@ -649,6 +600,7 @@ out2str(const char *p)
/* variable substitution byte (follows CTLVAR) */
#define VSTYPE 0x0f /* type of variable substitution */
#define VSNUL 0x10 /* colon--treat the empty string as unset */
+#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
/* values of VSTYPE field */
#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
@@ -668,9 +620,8 @@ out2str(const char *p)
#endif
static const char dolatstr[] ALIGN1 = {
- CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
+ CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
};
-#define DOLATSTRLEN 6
#define NCMD 0
#define NPIPE 1
@@ -871,8 +822,13 @@ trace_vprintf(const char *fmt, va_list va)
{
if (debug != 1)
return;
+ if (DEBUG_TIME)
+ fprintf(tracefile, "%u ", (int) time(NULL));
+ if (DEBUG_PID)
+ fprintf(tracefile, "[%u] ", (int) getpid());
+ if (DEBUG_SIG)
+ fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
vfprintf(tracefile, fmt, va);
- fprintf(tracefile, "\n");
}
static void
@@ -901,7 +857,9 @@ trace_puts_quoted(char *s)
case '\\': c = '\\'; goto backslash;
case CTLESC: c = 'e'; goto backslash;
case CTLVAR: c = 'v'; goto backslash;
+ case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
case CTLBACKQ: c = 'q'; goto backslash;
+ case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
backslash:
putc('\\', tracefile);
putc(c, tracefile);
@@ -1064,6 +1022,7 @@ sharg(union node *arg, FILE *fp)
putc('}', fp);
break;
case CTLBACKQ:
+ case CTLBACKQ|CTLQUOTE:
putc('$', fp);
putc('(', fp);
shtree(bqlist->n, -1, NULL, fp);
@@ -1205,12 +1164,6 @@ struct strpush {
struct alias *ap; /* if push was associated with an alias */
#endif
char *string; /* remember the string since it may change */
-
- /* Remember last two characters for pungetc. */
- int lastc[2];
-
- /* Number of outstanding calls to pungetc. */
- int unget;
};
struct parsefile {
@@ -1223,12 +1176,6 @@ struct parsefile {
char *buf; /* input buffer */
struct strpush *strpush; /* for pushing strings at this level */
struct strpush basestrpush; /* so pushing one is fast */
-
- /* Remember last two characters for pungetc. */
- int lastc[2];
-
- /* Number of outstanding calls to pungetc. */
- int unget;
};
static struct parsefile basepf; /* top level input file */
@@ -1236,6 +1183,7 @@ static struct parsefile *g_parsefile = &basepf; /* current input file */
static int startlinno; /* line # where last token started */
static char *commandname; /* currently executing command */
static struct strlist *cmdenviron; /* environment for builtin command */
+static uint8_t exitstatus; /* exit status of last command */
/* ============ Message printing */
@@ -1251,7 +1199,7 @@ ash_vmsg(const char *msg, va_list ap)
fprintf(stderr, "line %d: ", startlinno);
}
vfprintf(stderr, msg, ap);
- newline_and_flush(stderr);
+ outcslow('\n', stderr);
}
/*
@@ -1265,10 +1213,11 @@ ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
{
#if DEBUG
if (msg) {
- TRACE(("ash_vmsg_and_raise(%d):", cond));
+ TRACE(("ash_vmsg_and_raise(%d, \"", cond));
TRACEV((msg, ap));
+ TRACE(("\") pid=%d\n", getpid()));
} else
- TRACE(("ash_vmsg_and_raise(%d):NULL\n", cond));
+ TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
if (msg)
#endif
ash_vmsg(msg, ap);
@@ -1284,8 +1233,6 @@ ash_msg_and_raise_error(const char *msg, ...)
{
va_list ap;
- exitstatus = 2;
-
va_start(ap, msg);
ash_vmsg_and_raise(EXERROR, msg, ap);
/* NOTREACHED */
@@ -1353,7 +1300,7 @@ ckrealloc(void * p, size_t nbytes)
{
p = realloc(p, nbytes);
if (!p)
- ash_msg_and_raise_error(bb_msg_memory_exhausted);
+ ash_msg_and_raise_error("%s", bb_msg_memory_exhausted);
return p;
}
@@ -1374,7 +1321,7 @@ ckstrdup(const char *s)
{
char *p = strdup(s);
if (!p)
- ash_msg_and_raise_error(bb_msg_memory_exhausted);
+ ash_msg_and_raise_error("%s", bb_msg_memory_exhausted);
return p;
}
#else
@@ -1408,22 +1355,27 @@ struct stackmark {
struct stack_block *stackp;
char *stacknxt;
size_t stacknleft;
+ struct stackmark *marknext;
};
struct globals_memstack {
struct stack_block *g_stackp; // = &stackbase;
+ struct stackmark *markp;
char *g_stacknxt; // = stackbase.space;
char *sstrend; // = stackbase.space + MINSIZE;
size_t g_stacknleft; // = MINSIZE;
+ int herefd; // = -1;
struct stack_block stackbase;
};
extern struct globals_memstack *const ash_ptr_to_globals_memstack;
#define G_memstack (*ash_ptr_to_globals_memstack)
#define g_stackp (G_memstack.g_stackp )
+#define markp (G_memstack.markp )
#define g_stacknxt (G_memstack.g_stacknxt )
#define sstrend (G_memstack.sstrend )
#define g_stacknleft (G_memstack.g_stacknleft)
+#define herefd (G_memstack.herefd )
#define stackbase (G_memstack.stackbase )
#define INIT_G_memstack() do { \
(*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
@@ -1432,6 +1384,7 @@ extern struct globals_memstack *const ash_ptr_to_globals_memstack;
g_stacknxt = stackbase.space; \
g_stacknleft = MINSIZE; \
sstrend = stackbase.space + MINSIZE; \
+ herefd = -1; \
} while (0)
@@ -1463,7 +1416,7 @@ stalloc(size_t nbytes)
blocksize = MINSIZE;
len = sizeof(struct stack_block) - MINSIZE + blocksize;
if (len < blocksize)
- ash_msg_and_raise_error(bb_msg_memory_exhausted);
+ ash_msg_and_raise_error("%s", bb_msg_memory_exhausted);
INT_OFF;
sp = ckmalloc(len);
sp->prev = g_stackp;
@@ -1502,31 +1455,20 @@ stunalloc(void *p)
* Like strdup but works with the ash stack.
*/
static char *
-sstrdup(const char *p)
+ststrdup(const char *p)
{
size_t len = strlen(p) + 1;
return memcpy(stalloc(len), p, len);
}
-static inline void
-grabstackblock(size_t len)
-{
- stalloc(len);
-}
-
static void
-pushstackmark(struct stackmark *mark, size_t len)
+setstackmark(struct stackmark *mark)
{
mark->stackp = g_stackp;
mark->stacknxt = g_stacknxt;
mark->stacknleft = g_stacknleft;
- grabstackblock(len);
-}
-
-static void
-setstackmark(struct stackmark *mark)
-{
- pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
+ mark->marknext = markp;
+ markp = mark;
}
static void
@@ -1538,6 +1480,7 @@ popstackmark(struct stackmark *mark)
return;
INT_OFF;
+ markp = mark->marknext;
while (g_stackp != mark->stackp) {
sp = g_stackp;
g_stackp = sp->prev;
@@ -1565,16 +1508,19 @@ growstackblock(void)
newlen = g_stacknleft * 2;
if (newlen < g_stacknleft)
- ash_msg_and_raise_error(bb_msg_memory_exhausted);
+ ash_msg_and_raise_error("%s", bb_msg_memory_exhausted);
if (newlen < 128)
newlen += 128;
if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
+ struct stack_block *oldstackp;
+ struct stackmark *xmark;
struct stack_block *sp;
struct stack_block *prevstackp;
size_t grosslen;
INT_OFF;
+ oldstackp = g_stackp;
sp = g_stackp;
prevstackp = sp->prev;
grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
@@ -1584,6 +1530,18 @@ growstackblock(void)
g_stacknxt = sp->space;
g_stacknleft = newlen;
sstrend = sp->space + newlen;
+
+ /*
+ * Stack marks pointing to the start of the old block
+ * must be relocated to point to the new block
+ */
+ xmark = markp;
+ while (xmark != NULL && xmark->stackp == oldstackp) {
+ xmark->stackp = g_stackp;
+ xmark->stacknxt = g_stacknxt;
+ xmark->stacknleft = g_stacknleft;
+ xmark = xmark->marknext;
+ }
INT_ON;
} else {
char *oldspace = g_stacknxt;
@@ -1596,6 +1554,14 @@ growstackblock(void)
}
}
+static void
+grabstackblock(size_t len)
+{
+ len = SHELL_ALIGN(len);
+ g_stacknxt += len;
+ g_stacknleft -= len;
+}
+
/*
* The following routines are somewhat easier to use than the above.
* The user declares a variable of type STACKSTR, which may be declared
@@ -1617,6 +1583,10 @@ static void *
growstackstr(void)
{
size_t len = stackblocksize();
+ if (herefd >= 0 && len >= 1024) {
+ full_write(herefd, stackblock(), len);
+ return stackblock();
+ }
growstackblock();
return (char *)stackblock() + len;
}
@@ -1628,7 +1598,7 @@ static char *
makestrspace(size_t newlen, char *p)
{
size_t len = p - g_stacknxt;
- size_t size;
+ size_t size = stackblocksize();
for (;;) {
size_t nleft;
@@ -1947,7 +1917,7 @@ static const struct {
{ VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
{ VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
#if ENABLE_ASH_GETOPTS
- { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
+ { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
#endif
#if ENABLE_ASH_RANDOM_SUPPORT
{ VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
@@ -1966,6 +1936,7 @@ struct redirtab;
struct globals_var {
struct shparam shellparam; /* $@ current positional parameters */
struct redirtab *redirlist;
+ int g_nullredirs;
int preverrout_fd; /* save fd2 before print debug if xflag is set. */
struct var *vartab[VTABSIZE];
struct var varinit[ARRAY_SIZE(varinit_data)];
@@ -1974,6 +1945,7 @@ extern struct globals_var *const ash_ptr_to_globals_var;
#define G_var (*ash_ptr_to_globals_var)
#define shellparam (G_var.shellparam )
//#define redirlist (G_var.redirlist )
+#define g_nullredirs (G_var.g_nullredirs )
#define preverrout_fd (G_var.preverrout_fd)
#define vartab (G_var.vartab )
#define varinit (G_var.varinit )
@@ -2034,7 +2006,7 @@ extern struct globals_var *const ash_ptr_to_globals_var;
static void FAST_FUNC
getoptsreset(const char *value)
{
- shellparam.optind = number(value) ?: 1;
+ shellparam.optind = number(value);
shellparam.optoff = -1;
}
#endif
@@ -2050,7 +2022,7 @@ varcmp(const char *p, const char *q)
int c, d;
while ((c = *p) == (d = *q)) {
- if (c == '\0' || c == '=')
+ if (!c || c == '=')
goto out;
p++;
q++;
@@ -2148,27 +2120,6 @@ lookupvar(const char *name)
return NULL;
}
-#if ENABLE_UNICODE_SUPPORT
-static void
-reinit_unicode_for_ash(void)
-{
- /* Unicode support should be activated even if LANG is set
- * _during_ shell execution, not only if it was set when
- * shell was started. Therefore, re-check LANG every time:
- */
- if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
- || ENABLE_UNICODE_USING_LOCALE
- ) {
- const char *s = lookupvar("LC_ALL");
- if (!s) s = lookupvar("LC_CTYPE");
- if (!s) s = lookupvar("LANG");
- reinit_unicode(s);
- }
-}
-#else
-# define reinit_unicode_for_ash() ((void)0)
-#endif
-
/*
* Search the environment of a builtin command.
*/
@@ -2206,7 +2157,6 @@ setvareq(char *s, int flags)
if (flags & VNOSAVE)
free(s);
n = vp->var_text;
- exitstatus = 1;
ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
}
@@ -2262,10 +2212,10 @@ setvar(const char *name, const char *val, int flags)
INT_OFF;
nameeq = ckmalloc(namelen + vallen + 2);
- p = memcpy(nameeq, name, namelen) + namelen;
+ p = (char*) ((uintptr_t) memcpy(nameeq, name, namelen) + namelen);
if (val) {
*p++ = '=';
- p = memcpy(p, val, vallen) + vallen;
+ p = (char*) ((uintptr_t) memcpy(p, val, vallen) + vallen);
}
*p = '\0';
setvareq(nameeq, flags | VNOSAVE);
@@ -2273,11 +2223,37 @@ setvar(const char *name, const char *val, int flags)
}
static void FAST_FUNC
-setvar0(const char *name, const char *val)
+setvar2(const char *name, const char *val)
{
setvar(name, val, 0);
}
+#if ENABLE_ASH_GETOPTS
+/*
+ * Safe version of setvar, returns 1 on success 0 on failure.
+ */
+static int
+setvarsafe(const char *name, const char *val, int flags)
+{
+ int err;
+ volatile int saveint;
+ struct jmploc *volatile savehandler = exception_handler;
+ struct jmploc jmploc;
+
+ SAVE_INT(saveint);
+ if (setjmp(jmploc.loc))
+ err = 1;
+ else {
+ exception_handler = &jmploc;
+ setvar(name, val, flags);
+ err = 0;
+ }
+ exception_handler = savehandler;
+ RESTORE_INT(saveint);
+ return err;
+}
+#endif
+
/*
* Unset the specified variable.
*/
@@ -2310,7 +2286,7 @@ unsetvar(const char *s)
free(vp);
INT_ON;
} else {
- setvar0(s, NULL);
+ setvar2(s, 0);
vp->flags &= ~VEXPORT;
}
ok:
@@ -2474,7 +2450,8 @@ setprompt_if(smallint do_set, int whichprompt)
prompt = nullstr;
}
#if ENABLE_ASH_EXPAND_PRMT
- pushstackmark(&smark, stackblocksize());
+ setstackmark(&smark);
+ stalloc(stackblocksize());
#endif
putprompt(expandstr(prompt));
#if ENABLE_ASH_EXPAND_PRMT
@@ -2517,7 +2494,7 @@ updatepwd(const char *dir)
char *cdcomppath;
const char *lim;
- cdcomppath = sstrdup(dir);
+ cdcomppath = ststrdup(dir);
STARTSTACKSTR(new);
if (*dir != '/') {
if (curdir == nullstr)
@@ -2559,7 +2536,7 @@ updatepwd(const char *dir)
new = stack_putstr(p, new);
USTPUTC('/', new);
}
- p = strtok(NULL, "/");
+ p = strtok(0, "/");
}
if (new > lim)
STUNPUTC(new);
@@ -2612,7 +2589,7 @@ setpwd(const char *val, int setold)
static void hashcd(void);
/*
- * Actually do the chdir. We also call hashcd to let other routines
+ * Actually do the chdir. We also call hashcd to let the routines in exec.c
* know that the current directory has changed.
*/
static int
@@ -2660,7 +2637,7 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
if (!dest)
dest = nullstr;
if (*dest == '/')
- goto step6;
+ goto step7;
if (*dest == '.') {
c = dest[1];
dotdot:
@@ -2677,7 +2654,13 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
if (!*dest)
dest = ".";
path = bltinlookup("CDPATH");
- while (path) {
+ if (!path) {
+ step6:
+ step7:
+ p = dest;
+ goto docd;
+ }
+ do {
c = *path;
p = path_advance(&path, dest);
if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
@@ -2686,15 +2669,9 @@ cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
docd:
if (!docd(p, flags))
goto out;
- goto err;
+ break;
}
- }
-
- step6:
- p = dest;
- goto docd;
-
- err:
+ } while (path);
ash_msg_and_raise_error("can't cd to %s", dest);
/* NOTREACHED */
out:
@@ -2749,12 +2726,12 @@ pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
#else
# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
#endif
-static const uint16_t S_I_T[] ALIGN2 = {
+static const uint16_t S_I_T[] = {
#if ENABLE_ASH_ALIAS
SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
#endif
@@ -2812,27 +2789,18 @@ enum {
static int
SIT(int c, int syntax)
{
- /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
- static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
- /*
- * This causes '/' to be prepended with CTLESC in dquoted string,
- * making "./file"* treated incorrectly because we feed
- * ".\/file*" string to glob(), confusing it (see expandmeta func).
- * The "homegrown" glob implementation is okay with that,
- * but glibc one isn't. With '/' always treated as CWORD,
- * both work fine.
- */
+ static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
# if ENABLE_ASH_ALIAS
static const uint8_t syntax_index_table[] ALIGN1 = {
1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
- 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
+ 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
11, 3 /* "}~" */
};
# else
static const uint8_t syntax_index_table[] ALIGN1 = {
0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
- 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
+ 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
10, 2 /* "}~" */
};
@@ -2865,7 +2833,7 @@ SIT(int c, int syntax)
#else /* !USE_SIT_FUNCTION */
-static const uint8_t syntax_index_table[] ALIGN1 = {
+static const uint8_t syntax_index_table[] = {
/* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
/* 0 */ CWORD_CWORD_CWORD_CWORD,
/* 1 */ CWORD_CWORD_CWORD_CWORD,
@@ -2914,8 +2882,7 @@ static const uint8_t syntax_index_table[] ALIGN1 = {
/* 44 "," */ CWORD_CWORD_CWORD_CWORD,
/* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
/* 46 "." */ CWORD_CWORD_CWORD_CWORD,
-/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
- /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
+ /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
/* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
/* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
/* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
@@ -3130,18 +3097,7 @@ static const uint8_t syntax_index_table[] ALIGN1 = {
# endif
};
-#if 1
# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
-#else /* debug version, caught one signed char bug */
-# define SIT(c, syntax) \
- ({ \
- if ((c) < 0 || (c) > (PEOF + ENABLE_ASH_ALIAS)) \
- bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
- if ((syntax) < 0 || (syntax) > (2 + ENABLE_FEATURE_SH_MATH)) \
- bb_error_msg_and_die("line:%d c:%d", __LINE__, (c)); \
- ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf); \
- })
-#endif
#endif /* !USE_SIT_FUNCTION */
@@ -3168,8 +3124,7 @@ static struct alias **atab; // [ATABSIZE];
static struct alias **
-__lookupalias(const char *name)
-{
+__lookupalias(const char *name) {
unsigned int hashval;
struct alias **app;
const char *p;
@@ -3351,6 +3306,8 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
#endif /* ASH_ALIAS */
+/* ============ jobs.c */
+
/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
#define FORK_FG 0
#define FORK_BG 1
@@ -3360,7 +3317,6 @@ unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
-#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
/*
* A job structure contains information about a job. A job is either a
@@ -3428,14 +3384,7 @@ ignoresig(int signo)
static void
signal_handler(int signo)
{
- if (signo == SIGCHLD) {
- got_sigchld = 1;
- if (!trap[SIGCHLD])
- return;
- }
-
gotsig[signo - 1] = 1;
- pending_sig = signo;
if (signo == SIGINT && !trap[SIGINT]) {
if (!suppress_int) {
@@ -3443,6 +3392,8 @@ signal_handler(int signo)
raise_interrupt(); /* does not return */
}
pending_int = 1;
+ } else {
+ pending_sig = signo;
}
}
@@ -3500,9 +3451,6 @@ setsignal(int signo)
//whereas we have to restore it to what shell got on entry
//from the parent. See comment above
- if (signo == SIGCHLD)
- new_act = S_CATCH;
-
t = &sigmode[signo - 1];
cur_act = *t;
if (cur_act == 0) {
@@ -3552,6 +3500,10 @@ setsignal(int signo)
#define CUR_RUNNING 1
#define CUR_STOPPED 0
+/* mode flags for dowait */
+#define DOWAIT_NONBLOCK WNOHANG
+#define DOWAIT_BLOCK 0
+
#if JOBS
/* pgrp of shell on invocation */
static int initialpgrp; //references:2
@@ -3671,7 +3623,7 @@ getjob(const char *name, int getctl)
if (is_number(p)) {
num = atoi(p);
- if (num > 0 && num <= njobs) {
+ if (num < njobs) {
jp = jobtab + num - 1;
if (jp->used)
goto gotit;
@@ -3769,12 +3721,12 @@ setjobctl(int on)
if (--fd < 0)
goto out;
}
- /* fd is a tty at this point */
fd = fcntl(fd, F_DUPFD, 10);
- if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
+ if (ofd >= 0)
close(ofd);
if (fd < 0)
- goto out; /* F_DUPFD failed */
+ goto out;
+ /* fd is a tty at this point */
close_on_exec_on(fd);
while (1) { /* while we are in the background */
pgrp = tcgetpgrp(fd);
@@ -3879,7 +3831,7 @@ showpipe(struct job *jp /*, FILE *out*/)
psend = jp->ps + jp->nprocs;
for (ps = jp->ps + 1; ps < psend; ps++)
printf(" | %s", ps->ps_cmd);
- newline_and_flush(stdout);
+ outcslow('\n', stdout);
flush_stdout_stderr();
}
@@ -3939,129 +3891,74 @@ fg_bgcmd(int argc UNUSED_PARAM, char **argv)
#endif
static int
-sprint_status48(char *s, int status, int sigonly)
+sprint_status(char *s, int status, int sigonly)
{
int col;
int st;
col = 0;
if (!WIFEXITED(status)) {
- if (JOBS && WIFSTOPPED(status))
+#if JOBS
+ if (WIFSTOPPED(status))
st = WSTOPSIG(status);
else
+#endif
st = WTERMSIG(status);
if (sigonly) {
if (st == SIGINT || st == SIGPIPE)
goto out;
- if (JOBS && WIFSTOPPED(status))
+#if JOBS
+ if (WIFSTOPPED(status))
goto out;
+#endif
}
st &= 0x7f;
+ col = fmtstr(s, 32, "%s", strsignal(st));
//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
- col = fmtstr(s, 32, strsignal(st));
if (WCOREDUMP(status)) {
- strcpy(s + col, " (core dumped)");
- col += sizeof(" (core dumped)")-1;
+ col += fmtstr(s + col, 16, " (core dumped)");
}
} else if (!sigonly) {
st = WEXITSTATUS(status);
- col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
+ if (st)
+ col = fmtstr(s, 16, "Done(%d)", st);
+ else
+ col = fmtstr(s, 16, "Done");
}
out:
return col;
}
static int
-wait_block_or_sig(int *status)
-{
- int pid;
-
- do {
- sigset_t mask;
-
- /* Poll all children for changes in their state */
- got_sigchld = 0;
- /* if job control is active, accept stopped processes too */
- pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
- if (pid != 0)
- break; /* Error (e.g. EINTR, ECHILD) or pid */
-
- /* Children exist, but none are ready. Sleep until interesting signal */
-#if 1
- sigfillset(&mask);
- sigprocmask(SIG_SETMASK, &mask, &mask);
- while (!got_sigchld && !pending_sig)
- sigsuspend(&mask);
- sigprocmask(SIG_SETMASK, &mask, NULL);
-#else /* unsafe: a signal can set pending_sig after check, but before pause() */
- while (!got_sigchld && !pending_sig)
- pause();
-#endif
-
- /* If it was SIGCHLD, poll children again */
- } while (got_sigchld);
-
- return pid;
-}
-
-#define DOWAIT_NONBLOCK 0
-#define DOWAIT_BLOCK 1
-#define DOWAIT_BLOCK_OR_SIG 2
-
-static int
-dowait(int block, struct job *job)
+dowait(int wait_flags, struct job *job)
{
int pid;
int status;
struct job *jp;
- struct job *thisjob = NULL;
+ struct job *thisjob;
+ int state;
- TRACE(("dowait(0x%x) called\n", block));
+ TRACE(("dowait(0x%x) called\n", wait_flags));
- /* It's wrong to call waitpid() outside of INT_OFF region:
- * signal can arrive just after syscall return and handler can
- * longjmp away, losing stop/exit notification processing.
- * Thus, for "jobs" builtin, and for waiting for a fg job,
- * we call waitpid() (blocking or non-blocking) inside INT_OFF.
- *
- * However, for "wait" builtin it is wrong to simply call waitpid()
- * in INT_OFF region: "wait" needs to wait for any running job
- * to change state, but should exit on any trap too.
- * In INT_OFF region, a signal just before syscall entry can set
- * pending_sig variables, but we can't check them, and we would
- * either enter a sleeping waitpid() (BUG), or need to busy-loop.
- *
- * Because of this, we run inside INT_OFF, but use a special routine
- * which combines waitpid() and sigsuspend().
- * This is the reason why we need to have a handler for SIGCHLD:
- * SIG_DFL handler does not wake sigsuspend().
- */
- INT_OFF;
- if (block == DOWAIT_BLOCK_OR_SIG) {
- pid = wait_block_or_sig(&status);
- } else {
- int wait_flags = 0;
- if (block == DOWAIT_NONBLOCK)
- wait_flags = WNOHANG;
- /* if job control is active, accept stopped processes too */
- if (doing_jobctl)
- wait_flags |= WUNTRACED;
- /* NB: _not_ safe_waitpid, we need to detect EINTR */
- pid = waitpid(-1, &status, wait_flags);
- }
+ /* Do a wait system call. If job control is compiled in, we accept
+ * stopped processes. wait_flags may have WNOHANG, preventing blocking.
+ * NB: _not_ safe_waitpid, we need to detect EINTR */
+ if (doing_jobctl)
+ wait_flags |= WUNTRACED;
+ pid = waitpid(-1, &status, wait_flags);
TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
pid, status, errno, strerror(errno)));
if (pid <= 0)
- goto out;
+ return pid;
+ INT_OFF;
thisjob = NULL;
for (jp = curjob; jp; jp = jp->prev_job) {
- int jobstate;
struct procstat *ps;
struct procstat *psend;
if (jp->state == JOBDONE)
continue;
- jobstate = JOBDONE;
+ state = JOBDONE;
ps = jp->ps;
psend = ps + jp->nprocs;
do {
@@ -4073,41 +3970,41 @@ dowait(int block, struct job *job)
thisjob = jp;
}
if (ps->ps_status == -1)
- jobstate = JOBRUNNING;
+ state = JOBRUNNING;
#if JOBS
- if (jobstate == JOBRUNNING)
+ if (state == JOBRUNNING)
continue;
if (WIFSTOPPED(ps->ps_status)) {
jp->stopstatus = ps->ps_status;
- jobstate = JOBSTOPPED;
+ state = JOBSTOPPED;
}
#endif
} while (++ps < psend);
- if (!thisjob)
- continue;
-
- /* Found the job where one of its processes changed its state.
- * Is there at least one live and running process in this job? */
- if (jobstate != JOBRUNNING) {
- /* No. All live processes in the job are stopped
- * (JOBSTOPPED) or there are no live processes (JOBDONE)
- */
- thisjob->changed = 1;
- if (thisjob->state != jobstate) {
- TRACE(("Job %d: changing state from %d to %d\n",
- jobno(thisjob), thisjob->state, jobstate));
- thisjob->state = jobstate;
+ if (thisjob)
+ goto gotjob;
+ }
#if JOBS
- if (jobstate == JOBSTOPPED)
- set_curjob(thisjob, CUR_STOPPED);
+ if (!WIFSTOPPED(status))
#endif
+ jobless--;
+ goto out;
+
+ gotjob:
+ if (state != JOBRUNNING) {
+ thisjob->changed = 1;
+
+ if (thisjob->state != state) {
+ TRACE(("Job %d: changing state from %d to %d\n",
+ jobno(thisjob), thisjob->state, state));
+ thisjob->state = state;
+#if JOBS
+ if (state == JOBSTOPPED) {
+ set_curjob(thisjob, CUR_STOPPED);
}
+#endif
}
- goto out;
}
- /* The process wasn't found in job list */
- if (JOBS && !WIFSTOPPED(status))
- jobless--;
+
out:
INT_ON;
@@ -4115,7 +4012,7 @@ dowait(int block, struct job *job)
char s[48 + 1];
int len;
- len = sprint_status48(s, status, 1);
+ len = sprint_status(s, status, 1);
if (len) {
s[len] = '\n';
s[len + 1] = '\0';
@@ -4125,16 +4022,24 @@ dowait(int block, struct job *job)
return pid;
}
+static int
+blocking_wait_with_raise_on_sig(void)
+{
+ pid_t pid = dowait(DOWAIT_BLOCK, NULL);
+ if (pid <= 0 && pending_sig)
+ raise_exception(EXSIG);
+ return pid;
+}
+
#if JOBS
static void
-showjob(struct job *jp, int mode)
+showjob(FILE *out, struct job *jp, int mode)
{
struct procstat *ps;
struct procstat *psend;
int col;
int indent_col;
- char s[16 + 16 + 48];
- FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
+ char s[80];
ps = jp->ps;
@@ -4164,7 +4069,7 @@ showjob(struct job *jp, int mode)
int status = psend[-1].ps_status;
if (jp->state == JOBSTOPPED)
status = jp->stopstatus;
- col += sprint_status48(s + col, status, 0);
+ col += sprint_status(s + col, status, 0);
}
/* By now, "[JOBID]* [maybe PID] STATUS" is printed */
@@ -4191,7 +4096,7 @@ showjob(struct job *jp, int mode)
ps->ps_cmd
);
} while (++ps != psend);
- newline_and_flush(out);
+ outcslow('\n', out);
jp->changed = 0;
@@ -4206,7 +4111,7 @@ showjob(struct job *jp, int mode)
* statuses have changed since the last call to showjobs.
*/
static void
-showjobs(int mode)
+showjobs(FILE *out, int mode)
{
struct job *jp;
@@ -4218,7 +4123,7 @@ showjobs(int mode)
for (jp = curjob; jp; jp = jp->prev_job) {
if (!(mode & SHOW_CHANGED) || jp->changed) {
- showjob(jp, mode);
+ showjob(out, jp, mode);
}
}
}
@@ -4239,10 +4144,10 @@ jobscmd(int argc UNUSED_PARAM, char **argv)
argv = argptr;
if (*argv) {
do
- showjob(getjob(*argv, 0), mode);
+ showjob(stdout, getjob(*argv, 0), mode);
while (*++argv);
} else {
- showjobs(mode);
+ showjobs(stdout, mode);
}
return 0;
@@ -4294,6 +4199,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
int retval;
struct job *jp;
+ if (pending_sig)
+ raise_exception(EXSIG);
+
nextopt(nullstr);
retval = 0;
@@ -4310,20 +4218,21 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
jp->waited = 1;
jp = jp->prev_job;
}
+ blocking_wait_with_raise_on_sig();
/* man bash:
* "When bash is waiting for an asynchronous command via
* the wait builtin, the reception of a signal for which a trap
* has been set will cause the wait builtin to return immediately
* with an exit status greater than 128, immediately after which
* the trap is executed."
- */
- dowait(DOWAIT_BLOCK_OR_SIG, NULL);
- /* if child sends us a signal *and immediately exits*,
- * dowait() returns pid > 0. Check this case,
- * not "if (dowait() < 0)"!
- */
+ *
+ * blocking_wait_with_raise_on_sig raises signal handlers
+ * if it gets no pid (pid < 0). However,
+ * if child sends us a signal *and immediately exits*,
+ * blocking_wait_with_raise_on_sig gets pid > 0
+ * and does not handle pending_sig. Check this case: */
if (pending_sig)
- goto sigout;
+ raise_exception(EXSIG);
}
}
@@ -4343,11 +4252,8 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
job = getjob(*argv, 0);
}
/* loop until process terminated or stopped */
- while (job->state == JOBRUNNING) {
- dowait(DOWAIT_BLOCK_OR_SIG, NULL);
- if (pending_sig)
- goto sigout;
- }
+ while (job->state == JOBRUNNING)
+ blocking_wait_with_raise_on_sig();
job->waited = 1;
retval = getstatus(job);
repeat: ;
@@ -4355,9 +4261,6 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
ret:
return retval;
- sigout:
- retval = 128 + pending_sig;
- return retval;
}
static struct job *
@@ -4486,7 +4389,11 @@ cmdputs(const char *s)
str = "${#";
else
str = "${";
- goto dostr;
+ if (!(subtype & VSQUOTE) == !(quoted & 1))
+ goto dostr;
+ quoted ^= 1;
+ c = '"';
+ break;
case CTLENDVAR:
str = "\"}" + !(quoted & 1);
quoted >>= 1;
@@ -4495,7 +4402,10 @@ cmdputs(const char *s)
case CTLBACKQ:
str = "$(...)";
goto dostr;
-#if ENABLE_FEATURE_SH_MATH
+ case CTLBACKQ+CTLQUOTE:
+ str = "\"$(...)\"";
+ goto dostr;
+#if ENABLE_SH_MATH_SUPPORT
case CTLARI:
str = "$((";
goto dostr;
@@ -4722,7 +4632,8 @@ commandtext(union node *n)
STARTSTACKSTR(cmdnextc);
cmdtxt(n);
name = stackblock();
- TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
+ TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
+ name, cmdnextc, cmdnextc));
return ckstrdup(name);
}
#endif /* JOBS */
@@ -4751,26 +4662,25 @@ clear_traps(void)
{
char **tp;
- INT_OFF;
for (tp = trap; tp < &trap[NSIG]; tp++) {
if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
+ INT_OFF;
if (trap_ptr == trap)
free(*tp);
/* else: it "belongs" to trap_ptr vector, don't free */
*tp = NULL;
if ((tp - trap) != 0)
setsignal(tp - trap);
+ INT_ON;
}
}
may_have_traps = 0;
- INT_ON;
}
/* Lives far away from here, needed for forkchild */
static void closescript(void);
/* Called after fork(), in child */
-/* jp and n are NULL when called by openhere() for heredoc support */
static NOINLINE void
forkchild(struct job *jp, union node *n, int mode)
{
@@ -4829,7 +4739,7 @@ forkchild(struct job *jp, union node *n, int mode)
* Our solution: ONLY bare $(trap) or `trap` is special.
*/
/* Save trap handler strings for trap builtin to print */
- trap_ptr = xmemdup(trap, sizeof(trap));
+ trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
/* Fall through into clearing traps */
}
clear_traps();
@@ -4902,7 +4812,6 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
{
TRACE(("In parent shell: child = %d\n", pid));
if (!jp) {
- /* jp is NULL when called by openhere() for heredoc support */
while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
continue;
jobless++;
@@ -4936,7 +4845,6 @@ forkparent(struct job *jp, union node *n, int mode, pid_t pid)
}
}
-/* jp and n are NULL when called by openhere() for heredoc support */
static int
forkshell(struct job *jp, union node *n, int mode)
{
@@ -5066,7 +4974,8 @@ stoppedjobs(void)
}
-/*
+/* ============ redir.c
+ *
* Code for dealing with input/output redirection.
*/
@@ -5184,26 +5093,8 @@ openredirect(union node *redir)
char *fname;
int f;
- switch (redir->nfile.type) {
-/* Can't happen, our single caller does this itself */
-// case NTOFD:
-// case NFROMFD:
-// return -1;
- case NHERE:
- case NXHERE:
- return openhere(redir);
- }
-
- /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
- * allocated space. Do it only when we know it is safe.
- */
fname = redir->nfile.expfname;
-
switch (redir->nfile.type) {
- default:
-#if DEBUG
- abort();
-#endif
case NFROM:
f = open(fname, O_RDONLY);
if (f < 0)
@@ -5236,6 +5127,20 @@ openredirect(union node *redir)
if (f < 0)
goto ecreate;
break;
+ default:
+#if DEBUG
+ abort();
+#endif
+ /* Fall through to eliminate warning. */
+/* Our single caller does this itself */
+// case NTOFD:
+// case NFROMFD:
+// f = -1;
+// break;
+ case NHERE:
+ case NXHERE:
+ f = openhere(redir);
+ break;
}
return f;
@@ -5246,32 +5151,31 @@ openredirect(union node *redir)
}
/*
- * Copy a file descriptor to be >= 10. Throws exception on error.
+ * Copy a file descriptor to be >= to. Returns -1
+ * if the source file descriptor is closed, EMPTY if there are no unused
+ * file descriptors left.
*/
+/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
+ * old code was doing close(to) prior to copyfd() to achieve the same */
+enum {
+ COPYFD_EXACT = (int)~(INT_MAX),
+ COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
+};
static int
-savefd(int from)
+copyfd(int from, int to)
{
int newfd;
- int err;
- newfd = fcntl(from, F_DUPFD, 10);
- err = newfd < 0 ? errno : 0;
- if (err != EBADF) {
- if (err)
- ash_msg_and_raise_error("%d: %m", from);
- close(from);
- fcntl(newfd, F_SETFD, FD_CLOEXEC);
+ if (to & COPYFD_EXACT) {
+ to &= ~COPYFD_EXACT;
+ /*if (from != to)*/
+ newfd = dup2(from, to);
+ } else {
+ newfd = fcntl(from, F_DUPFD, to);
}
-
- return newfd;
-}
-static int
-dup2_or_raise(int from, int to)
-{
- int newfd;
-
- newfd = (from != to) ? dup2(from, to) : to;
if (newfd < 0) {
+ if (errno == EMFILE)
+ return EMPTY;
/* Happens when source fd is not open: try "echo >&99" */
ash_msg_and_raise_error("%d: %m", from);
}
@@ -5284,16 +5188,13 @@ struct two_fd_t {
};
struct redirtab {
struct redirtab *next;
+ int nullredirs;
int pair_count;
struct two_fd_t two_fd[];
};
#define redirlist (G_var.redirlist)
-enum {
- COPYFD_RESTORE = (int)~(INT_MAX),
-};
-static int
-need_to_remember(struct redirtab *rp, int fd)
+static int need_to_remember(struct redirtab *rp, int fd)
{
int i;
@@ -5310,8 +5211,7 @@ need_to_remember(struct redirtab *rp, int fd)
}
/* "hidden" fd is a fd used to read scripts, or a copy of such */
-static int
-is_hidden_fd(struct redirtab *rp, int fd)
+static int is_hidden_fd(struct redirtab *rp, int fd)
{
int i;
struct parsefile *pf;
@@ -5365,6 +5265,7 @@ redirect(union node *redir, int flags)
int newfd;
int copied_fd2 = -1;
+ g_nullredirs++;
if (!redir) {
return;
}
@@ -5386,6 +5287,8 @@ redirect(union node *redir, int flags)
sv->next = redirlist;
sv->pair_count = sv_pos;
redirlist = sv;
+ sv->nullredirs = g_nullredirs - 1;
+ g_nullredirs = 0;
while (sv_pos > 0) {
sv_pos--;
sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
@@ -5426,11 +5329,11 @@ redirect(union node *redir, int flags)
/* Careful to not accidentally "save"
* to the same fd as right side fd in N>&M */
int minfd = right_fd < 10 ? 10 : right_fd + 1;
-#if defined(F_DUPFD_CLOEXEC)
- i = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
-#else
i = fcntl(fd, F_DUPFD, minfd);
-#endif
+/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
+ * are closed in popredir() in the child, preventing them from leaking
+ * into child. (popredir() also cleans up the mess in case of failures)
+ */
if (i == -1) {
i = errno;
if (i != EBADF) {
@@ -5445,9 +5348,6 @@ redirect(union node *redir, int flags)
remember_to_close:
i = CLOSED;
} else { /* fd is open, save its copy */
-#if !defined(F_DUPFD_CLOEXEC)
- fcntl(i, F_SETFD, FD_CLOEXEC);
-#endif
/* "exec fd>&-" should not close fds
* which point to script file(s).
* Force them to be restored afterwards */
@@ -5467,10 +5367,10 @@ redirect(union node *redir, int flags)
if (fd != -1)
close(fd);
} else {
- dup2_or_raise(redir->ndup.dupfd, fd);
+ copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
}
} else if (fd != newfd) { /* move newfd to fd */
- dup2_or_raise(newfd, fd);
+ copyfd(newfd, fd | COPYFD_EXACT);
#if ENABLE_ASH_BASH_COMPAT
if (!(redir->nfile.type == NTO2 && fd == 2))
#endif
@@ -5500,7 +5400,7 @@ popredir(int drop, int restore)
struct redirtab *rp;
int i;
- if (redirlist == NULL)
+ if (--g_nullredirs >= 0)
return;
INT_OFF;
rp = redirlist;
@@ -5516,12 +5416,13 @@ popredir(int drop, int restore)
if (!drop || (restore && (copy & COPYFD_RESTORE))) {
copy &= ~COPYFD_RESTORE;
/*close(fd);*/
- dup2_or_raise(copy, fd);
+ copyfd(copy, fd | COPYFD_EXACT);
}
close(copy & ~COPYFD_RESTORE);
}
}
redirlist = rp->next;
+ g_nullredirs = rp->nullredirs;
free(rp);
INT_ON;
}
@@ -5530,6 +5431,20 @@ popredir(int drop, int restore)
* Undo all redirections. Called on error or interrupt.
*/
+/*
+ * Discard all saved file descriptors.
+ */
+static void
+clearredir(int drop)
+{
+ for (;;) {
+ g_nullredirs = 0;
+ if (!redirlist)
+ break;
+ popredir(drop, /*restore:*/ 0);
+ }
+}
+
static int
redirectsafe(union node *redir, int flags)
{
@@ -5558,7 +5473,7 @@ redirectsafe(union node *redir, int flags)
* We have to deal with backquotes, shell variables, and file metacharacters.
*/
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
static arith_t
ash_arith(const char *s)
{
@@ -5566,7 +5481,7 @@ ash_arith(const char *s)
arith_t result;
math_state.lookupvar = lookupvar;
- math_state.setvar = setvar0;
+ math_state.setvar = setvar2;
//math_state.endofname = endofname;
INT_OFF;
@@ -5586,35 +5501,19 @@ ash_arith(const char *s)
#define EXP_TILDE 0x2 /* do normal tilde expansion */
#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
-/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
- * POSIX says for this case:
- * Pathname expansion shall not be performed on the word by a
- * non-interactive shell; an interactive shell may perform it, but shall
- * do so only when the expansion would result in one word.
- * Currently, our code complies to the above rule by never globbing
- * redirection filenames.
- * Bash performs globbing, unless it is non-interactive and in POSIX mode.
- * (this means that on a typical Linux distro, bash almost always
- * performs globbing, and thus diverges from what we do).
- */
#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
-#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
+#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
#define EXP_WORD 0x80 /* expand word in parameter expansion */
-#define EXP_QUOTED 0x100 /* expand word in double quotes */
+#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
/*
* rmescape() flags
*/
#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
+#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
-#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
-
-/* Add CTLESC when necessary. */
-#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
-/* Do not skip NUL characters. */
-#define QUOTES_KEEPNUL EXP_TILDE
/*
* Structure specifying which parts of the string should be searched
@@ -5646,7 +5545,7 @@ static struct arglist exparg;
/*
* Our own itoa().
*/
-#if !ENABLE_FEATURE_SH_MATH
+#if !ENABLE_SH_MATH_SUPPORT
/* cvtnum() is used even if math support is off (to prepare $? values and such) */
typedef long arith_t;
# define ARITH_FMT "%ld"
@@ -5656,125 +5555,12 @@ cvtnum(arith_t num)
{
int len;
- expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
- len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
+ expdest = makestrspace(32, expdest);
+ len = fmtstr(expdest, 32, ARITH_FMT, num);
STADJUST(len, expdest);
return len;
}
-/*
- * Break the argument string into pieces based upon IFS and add the
- * strings to the argument list. The regions of the string to be
- * searched for IFS characters have been stored by recordregion.
- */
-static void
-ifsbreakup(char *string, struct arglist *arglist)
-{
- struct ifsregion *ifsp;
- struct strlist *sp;
- char *start;
- char *p;
- char *q;
- const char *ifs, *realifs;
- int ifsspc;
- int nulonly;
-
- start = string;
- if (ifslastp != NULL) {
- ifsspc = 0;
- nulonly = 0;
- realifs = ifsset() ? ifsval() : defifs;
- ifsp = &ifsfirst;
- do {
- p = string + ifsp->begoff;
- nulonly = ifsp->nulonly;
- ifs = nulonly ? nullstr : realifs;
- ifsspc = 0;
- while (p < string + ifsp->endoff) {
- q = p;
- if ((unsigned char)*p == CTLESC)
- p++;
- if (!strchr(ifs, *p)) {
- p++;
- continue;
- }
- if (!nulonly)
- ifsspc = (strchr(defifs, *p) != NULL);
- /* Ignore IFS whitespace at start */
- if (q == start && ifsspc) {
- p++;
- start = p;
- continue;
- }
- *q = '\0';
- sp = stzalloc(sizeof(*sp));
- sp->text = start;
- *arglist->lastp = sp;
- arglist->lastp = &sp->next;
- p++;
- if (!nulonly) {
- for (;;) {
- if (p >= string + ifsp->endoff) {
- break;
- }
- q = p;
- if ((unsigned char)*p == CTLESC)
- p++;
- if (strchr(ifs, *p) == NULL) {
- p = q;
- break;
- }
- if (strchr(defifs, *p) == NULL) {
- if (ifsspc) {
- p++;
- ifsspc = 0;
- } else {
- p = q;
- break;
- }
- } else
- p++;
- }
- }
- start = p;
- } /* while */
- ifsp = ifsp->next;
- } while (ifsp != NULL);
- if (nulonly)
- goto add;
- }
-
- if (!*start)
- return;
-
- add:
- sp = stzalloc(sizeof(*sp));
- sp->text = start;
- *arglist->lastp = sp;
- arglist->lastp = &sp->next;
-}
-
-static void
-ifsfree(void)
-{
- struct ifsregion *p = ifsfirst.next;
-
- if (!p)
- goto out;
-
- INT_OFF;
- do {
- struct ifsregion *ifsp;
- ifsp = p->next;
- free(p);
- p = ifsp;
- } while (p);
- ifsfirst.next = NULL;
- INT_ON;
- out:
- ifslastp = NULL;
-}
-
static size_t
esclen(const char *start, const char *p)
{
@@ -5792,16 +5578,14 @@ esclen(const char *start, const char *p)
static char *
rmescapes(char *str, int flag)
{
- static const char qchars[] ALIGN1 = {
- IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
+ static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
char *p, *q, *r;
unsigned inquotes;
unsigned protect_against_glob;
unsigned globbing;
- IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
- p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
+ p = strpbrk(str, qchars);
if (!p)
return str;
@@ -5828,38 +5612,31 @@ rmescapes(char *str, int flag)
}
}
- inquotes = 0;
+ inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
globbing = flag & RMESCAPE_GLOB;
protect_against_glob = globbing;
while (*p) {
if ((unsigned char)*p == CTLQUOTEMARK) {
+// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
+// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
// Note: both inquotes and protect_against_glob only affect whether
+// CTLESC,<ch> gets converted to <ch> or to \<ch>
inquotes = ~inquotes;
p++;
protect_against_glob = globbing;
continue;
}
- if ((unsigned char)*p == CTLESC) {
- p++;
-#if DEBUG
- if (*p == '\0')
- ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
-#endif
- if (protect_against_glob) {
- *q++ = '\\';
- }
- } else if (*p == '\\' && !inquotes) {
+ if (*p == '\\') {
/* naked back slash */
protect_against_glob = 0;
goto copy;
}
-#if ENABLE_ASH_BASH_COMPAT
- else if (*p == '/' && slash) {
- /* stop handling globbing and mark location of slash */
- globbing = slash = 0;
- *p = CTLESC;
+ if ((unsigned char)*p == CTLESC) {
+ p++;
+ if (protect_against_glob && inquotes && *p != '/') {
+ *q++ = '\\';
+ }
}
-#endif
protect_against_glob = globbing;
copy:
*q++ = *p++;
@@ -5879,9 +5656,13 @@ rmescapes(char *str, int flag)
* Returns an stalloced string.
*/
static char *
-preglob(const char *pattern, int flag)
+preglob(const char *pattern, int quoted, int flag)
{
- return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
+ flag |= RMESCAPE_GLOB;
+ if (quoted) {
+ flag |= RMESCAPE_QUOTED;
+ }
+ return rmescapes((char *)pattern, flag);
}
/*
@@ -5890,40 +5671,29 @@ preglob(const char *pattern, int flag)
static void
memtodest(const char *p, size_t len, int syntax, int quotes)
{
- char *q;
-
- if (!len)
- return;
+ char *q = expdest;
- q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
+ q = makestrspace(quotes ? len * 2 : len, q);
- do {
+ while (len--) {
unsigned char c = *p++;
- if (c) {
- if (quotes & QUOTES_ESC) {
- int n = SIT(c, syntax);
- if (n == CCTL
- || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
- && n == CBACK
- )
- ) {
- USTPUTC(CTLESC, q);
- }
- }
- } else if (!(quotes & QUOTES_KEEPNUL))
+ if (c == '\0')
continue;
+ if (quotes) {
+ int n = SIT(c, syntax);
+ if (n == CCTL || n == CBACK)
+ USTPUTC(CTLESC, q);
+ }
USTPUTC(c, q);
- } while (--len);
+ }
expdest = q;
}
-static size_t
+static void
strtodest(const char *p, int syntax, int quotes)
{
- size_t len = strlen(p);
- memtodest(p, len, syntax, quotes);
- return len;
+ memtodest(p, strlen(p), syntax, quotes);
}
/*
@@ -5996,7 +5766,8 @@ exptilde(char *startp, char *p, int flags)
char *name;
struct passwd *pw;
const char *home;
- int quotes = flags & QUOTES_ESC;
+ int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
+ int startloc;
name = p + 1;
@@ -6028,7 +5799,9 @@ exptilde(char *startp, char *p, int flags)
if (!home || !*home)
goto lose;
*p = c;
+ startloc = expdest - (char *)stackblock();
strtodest(home, SQSYNTAX, quotes);
+ recordregion(startloc, expdest - (char *)stackblock(), 0);
return p;
lose:
*p = c;
@@ -6049,53 +5822,49 @@ struct backcmd { /* result of evalbackcmd */
};
/* These forward decls are needed to use "eval" code for backticks handling: */
+static uint8_t back_exitstatus; /* exit status of backquoted command */
#define EV_EXIT 01 /* exit after evaluating tree */
-static int evaltree(union node *, int);
+static void evaltree(union node *, int);
static void FAST_FUNC
evalbackcmd(union node *n, struct backcmd *result)
{
- int pip[2];
- struct job *jp;
+ int saveherefd;
result->fd = -1;
result->buf = NULL;
result->nleft = 0;
result->jp = NULL;
- if (n == NULL) {
+ if (n == NULL)
goto out;
- }
- if (pipe(pip) < 0)
- ash_msg_and_raise_error("pipe call failed");
- jp = makejob(/*n,*/ 1);
- if (forkshell(jp, n, FORK_NOJOB) == 0) {
- /* child */
- FORCE_INT_ON;
- close(pip[0]);
- if (pip[1] != 1) {
- /*close(1);*/
- dup2_or_raise(pip[1], 1);
- close(pip[1]);
+ saveherefd = herefd;
+ herefd = -1;
+
+ {
+ int pip[2];
+ struct job *jp;
+
+ if (pipe(pip) < 0)
+ ash_msg_and_raise_error("pipe call failed");
+ jp = makejob(/*n,*/ 1);
+ if (forkshell(jp, n, FORK_NOJOB) == 0) {
+ FORCE_INT_ON;
+ close(pip[0]);
+ if (pip[1] != 1) {
+ /*close(1);*/
+ copyfd(pip[1], 1 | COPYFD_EXACT);
+ close(pip[1]);
+ }
+ eflag = 0;
+ evaltree(n, EV_EXIT); /* actually evaltreenr... */
+ /* NOTREACHED */
}
-/* TODO: eflag clearing makes the following not abort:
- * ash -c 'set -e; z=$(false;echo foo); echo $z'
- * which is what bash does (unless it is in POSIX mode).
- * dash deleted "eflag = 0" line in the commit
- * Date: Mon, 28 Jun 2010 17:11:58 +1000
- * [EVAL] Don't clear eflag in evalbackcmd
- * For now, preserve bash-like behavior, it seems to be somewhat more useful:
- */
- eflag = 0;
- ifsfree();
- evaltree(n, EV_EXIT); /* actually evaltreenr... */
- /* NOTREACHED */
+ close(pip[1]);
+ result->fd = pip[0];
+ result->jp = jp;
}
- /* parent */
- close(pip[1]);
- result->fd = pip[0];
- result->jp = jp;
-
+ herefd = saveherefd;
out:
TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
result->fd, result->buf, result->nleft, result->jp));
@@ -6105,7 +5874,7 @@ evalbackcmd(union node *n, struct backcmd *result)
* Expand stuff in backwards quotes.
*/
static void
-expbackq(union node *cmd, int flag)
+expbackq(union node *cmd, int quoted, int quotes)
{
struct backcmd in;
int i;
@@ -6113,12 +5882,14 @@ expbackq(union node *cmd, int flag)
char *p;
char *dest;
int startloc;
- int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
+ int syntax = quoted ? DQSYNTAX : BASESYNTAX;
struct stackmark smark;
INT_OFF;
- startloc = expdest - (char *)stackblock();
- pushstackmark(&smark, startloc);
+ setstackmark(&smark);
+ dest = expdest;
+ startloc = dest - (char *)stackblock();
+ grabstackstr(dest);
evalbackcmd(cmd, &in);
popstackmark(&smark);
@@ -6127,7 +5898,7 @@ expbackq(union node *cmd, int flag)
if (i == 0)
goto read;
for (;;) {
- memtodest(p, i, syntax, flag & QUOTES_ESC);
+ memtodest(p, i, syntax, quotes);
read:
if (in.fd < 0)
break;
@@ -6151,7 +5922,7 @@ expbackq(union node *cmd, int flag)
STUNPUTC(dest);
expdest = dest;
- if (!(flag & EXP_QUOTED))
+ if (quoted == 0)
recordregion(startloc, dest - (char *)stackblock(), 0);
TRACE(("evalbackq: size:%d:'%.*s'\n",
(int)((dest - (char *)stackblock()) - startloc),
@@ -6159,16 +5930,17 @@ expbackq(union node *cmd, int flag)
stackblock() + startloc));
}
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
/*
* Expand arithmetic expression. Backup to start of expression,
* evaluate, place result in (backed up) result, adjust string position.
*/
static void
-expari(int flag)
+expari(int quotes)
{
char *p, *start;
int begoff;
+ int flag;
int len;
/* ifsfree(); */
@@ -6206,14 +5978,16 @@ expari(int flag)
removerecordregions(begoff);
+ flag = p[1];
+
expdest = p;
- if (flag & QUOTES_ESC)
- rmescapes(p + 1, 0);
+ if (quotes)
+ rmescapes(p + 2, 0);
- len = cvtnum(ash_arith(p + 1));
+ len = cvtnum(ash_arith(p + 2));
- if (!(flag & EXP_QUOTED))
+ if (flag != '"')
recordregion(begoff, begoff + len, 0);
}
#endif
@@ -6241,13 +6015,15 @@ argstr(char *p, int flags, struct strlist *var_str_list)
CTLESC,
CTLVAR,
CTLBACKQ,
-#if ENABLE_FEATURE_SH_MATH
+ CTLBACKQ | CTLQUOTE,
+#if ENABLE_SH_MATH_SUPPORT
CTLENDARI,
#endif
'\0'
};
const char *reject = spclchars;
- int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
+ int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
+ int breakall = flags & EXP_WORD;
int inquotes;
size_t length;
int startloc;
@@ -6265,6 +6041,8 @@ argstr(char *p, int flags, struct strlist *var_str_list)
flags &= ~EXP_TILDE;
tilde:
q = p;
+ if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD))
+ q++;
if (*q == '~')
p = exptilde(p, q, flags);
}
@@ -6321,14 +6099,19 @@ argstr(char *p, int flags, struct strlist *var_str_list)
case CTLENDVAR: /* ??? */
goto breakloop;
case CTLQUOTEMARK:
- inquotes ^= EXP_QUOTED;
/* "$@" syntax adherence hack */
- if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
- p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
+ if (!inquotes
+ && memcmp(p, dolatstr, 4) == 0
+ && ( p[4] == (char)CTLQUOTEMARK
+ || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK)
+ )
+ ) {
+ p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
goto start;
}
+ inquotes = !inquotes;
addquote:
- if (flags & QUOTES_ESC) {
+ if (quotes) {
p--;
length++;
startloc++;
@@ -6337,30 +6120,22 @@ argstr(char *p, int flags, struct strlist *var_str_list)
case CTLESC:
startloc++;
length++;
-
- /*
- * Quoted parameter expansion pattern: remove quote
- * unless inside inner quotes or we have a literal
- * backslash.
- */
- if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
- EXP_QPAT && *p != '\\')
- break;
-
goto addquote;
case CTLVAR:
TRACE(("argstr: evalvar('%s')\n", p));
- p = evalvar(p, flags | inquotes, var_str_list);
+ p = evalvar(p, flags, var_str_list);
TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
goto start;
case CTLBACKQ:
- expbackq(argbackq->n, flags | inquotes);
+ c = '\0';
+ case CTLBACKQ|CTLQUOTE:
+ expbackq(argbackq->n, c, quotes);
argbackq = argbackq->next;
goto start;
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
case CTLENDARI:
p--;
- expari(flags | inquotes);
+ expari(quotes);
goto start;
#endif
}
@@ -6490,18 +6265,62 @@ varunset(const char *end, const char *var, const char *umsg, int varflags)
ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
}
+#if ENABLE_ASH_BASH_COMPAT
+static char *
+parse_sub_pattern(char *arg, int varflags)
+{
+ char *idx, *repl = NULL;
+ unsigned char c;
+
+ //char *org_arg = arg;
+ //bb_error_msg("arg:'%s' varflags:%x", arg, varflags);
+ idx = arg;
+ while (1) {
+ c = *arg;
+ if (!c)
+ break;
+ if (c == '/') {
+ /* Only the first '/' seen is our separator */
+ if (!repl) {
+ repl = idx + 1;
+ c = '\0';
+ }
+ }
+ *idx++ = c;
+ arg++;
+ /*
+ * Example: v='ab\c'; echo ${v/\\b/_\\_\z_}
+ * The result is a_\_z_c (not a\_\_z_c)!
+ *
+ * Enable debug prints in this function and you'll see:
+ * ash: arg:'\\b/_\\_z_' varflags:d
+ * ash: pattern:'\\b' repl:'_\_z_'
+ * That is, \\b is interpreted as \\b, but \\_ as \_!
+ * IOW: search pattern and replace string treat backslashes
+ * differently! That is the reason why we check repl below:
+ */
+ if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE))
+ arg++; /* skip both '\', not just first one */
+ }
+ *idx = c; /* NUL */
+ //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
+
+ return repl;
+}
+#endif /* ENABLE_ASH_BASH_COMPAT */
+
static const char *
subevalvar(char *p, char *varname, int strloc, int subtype,
- int startloc, int varflags, int flag, struct strlist *var_str_list)
+ int startloc, int varflags, int quotes, struct strlist *var_str_list)
{
struct nodelist *saveargbackq = argbackq;
- int quotes = flag & QUOTES_ESC;
char *startp;
char *loc;
char *rmesc, *rmescend;
char *str;
- IF_ASH_BASH_COMPAT(char *repl = NULL;)
+ IF_ASH_BASH_COMPAT(const char *repl = NULL;)
IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
+ int saveherefd = herefd;
int amount, resetloc;
IF_ASH_BASH_COMPAT(int workloc;)
int zero;
@@ -6510,16 +6329,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
//bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
// p, varname, strloc, subtype, startloc, varflags, quotes);
- argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
- (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
+ herefd = -1;
+ argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
var_str_list);
STPUTC('\0', expdest);
+ herefd = saveherefd;
argbackq = saveargbackq;
startp = (char *)stackblock() + startloc;
switch (subtype) {
case VSASSIGN:
- setvar0(varname, startp);
+ setvar2(varname, startp);
amount = startp - expdest;
STADJUST(amount, expdest);
return startp;
@@ -6530,9 +6350,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
#if ENABLE_ASH_BASH_COMPAT
case VSSUBSTR:
-//TODO: support more general format ${v:EXPR:EXPR},
-// where EXPR follows $(()) rules
- loc = str = stackblock() + strloc;
+ loc = str = (char*) ((uintptr_t) stackblock() + strloc);
/* Read POS in ${var:POS:LEN} */
pos = atoi(loc); /* number(loc) errors out on "1:4" */
len = str - startp - 1;
@@ -6569,15 +6387,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
len = number(loc);
}
}
- if (pos < 0) {
- /* ${VAR:$((-n)):l} starts n chars from the end */
- pos = orig_len + pos;
- }
- if ((unsigned)pos >= orig_len) {
- /* apart from obvious ${VAR:999999:l},
- * covers ${VAR:$((-9999999)):l} - result is ""
- * (bash-compat)
- */
+ if (pos >= orig_len) {
pos = 0;
len = 0;
}
@@ -6624,17 +6434,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
}
rmescend--;
str = (char *)stackblock() + strloc;
- /*
- * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
- * The result is a_\_z_c (not a\_\_z_c)!
- *
- * The search pattern and replace string treat backslashes differently!
- * RMESCAPE_SLASH causes preglob to work differently on the pattern
- * and string. It's only used on the first call.
- */
- preglob(str, IF_ASH_BASH_COMPAT(
- (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
- RMESCAPE_SLASH :) 0);
+ preglob(str, varflags & VSQUOTE, 0);
#if ENABLE_ASH_BASH_COMPAT
workloc = expdest - (char *)stackblock();
@@ -6642,13 +6442,11 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
char *idx, *end;
if (!repl) {
- repl = strchr(str, CTLESC);
- if (repl)
- *repl++ = '\0';
- else
+ repl = parse_sub_pattern(str, varflags);
+ //bb_error_msg("repl:'%s'", repl);
+ if (!repl)
repl = nullstr;
}
- //bb_error_msg("str:'%s' repl:'%s'", str, repl);
/* If there's no pattern to match, return the expansion unmolested */
if (str[0] == '\0')
@@ -6776,21 +6574,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype,
* ash -c 'echo ${#1#}' name:'1=#'
*/
static NOINLINE ssize_t
-varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
+varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
{
const char *p;
int num;
int i;
+ int sepq = 0;
ssize_t len = 0;
- int sep;
- int quoted = *quotedp;
int subtype = varflags & VSTYPE;
- int discard = subtype == VSPLUS || subtype == VSLENGTH;
- int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
- int syntax;
-
- sep = (flags & EXP_FULL) << CHAR_BIT;
- syntax = quoted ? DQSYNTAX : BASESYNTAX;
+ int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
+ int quoted = varflags & VSQUOTE;
+ int syntax = quoted ? DQSYNTAX : BASESYNTAX;
switch (*name) {
case '$':
@@ -6824,33 +6618,52 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
raise_error_syntax("bad substitution");
#endif
break;
- case '@':
- if (quoted && sep)
- goto param;
- /* fall through */
- case '*': {
+ case '@': {
char **ap;
- char sepc;
+ int sep;
- if (quoted)
- sep = 0;
- sep |= ifsset() ? ifsval()[0] : ' ';
+ if (quoted && (flags & EXP_FULL)) {
+ /* note: this is not meant as PEOF value */
+ sep = 1 << CHAR_BIT;
+ goto param;
+ }
+ /* fall through */
+ case '*':
+ sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
+ i = SIT(sep, syntax);
+ if (quotes && (i == CCTL || i == CBACK))
+ sepq = 1;
param:
- sepc = sep;
- *quotedp = !sepc;
ap = shellparam.p;
if (!ap)
return -1;
while ((p = *ap++) != NULL) {
- len += strtodest(p, syntax, quotes);
+ size_t partlen;
+
+ partlen = strlen(p);
+ len += partlen;
+
+ if (!(subtype == VSPLUS || subtype == VSLENGTH))
+ memtodest(p, partlen, syntax, quotes);
if (*ap && sep) {
+ char *q;
+
len++;
- memtodest(&sepc, 1, syntax, quotes);
+ if (subtype == VSPLUS || subtype == VSLENGTH) {
+ continue;
+ }
+ q = expdest;
+ if (sepq)
+ STPUTC(CTLESC, q);
+ /* note: may put NUL despite sep != 0
+ * (see sep = 1 << CHAR_BIT above) */
+ STPUTC(sep, q);
+ expdest = q;
}
}
- break;
- } /* case '*' */
+ return len;
+ } /* case '@' and '*' */
case '0':
case '1':
case '2':
@@ -6898,21 +6711,13 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
if (!p)
return -1;
- len = strtodest(p, syntax, quotes);
-#if ENABLE_UNICODE_SUPPORT
- if (subtype == VSLENGTH && len > 0) {
- reinit_unicode_for_ash();
- if (unicode_status == UNICODE_ON) {
- STADJUST(-len, expdest);
- discard = 0;
- len = unicode_strlen(p);
- }
- }
-#endif
- break;
+ len = strlen(p);
+ if (!(subtype == VSPLUS || subtype == VSLENGTH))
+ memtodest(p, len, syntax, quotes);
+ return len;
}
- if (discard)
+ if (subtype == VSPLUS || subtype == VSLENGTH)
STADJUST(-len, expdest);
return len;
}
@@ -6922,11 +6727,11 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int
* input string.
*/
static char *
-evalvar(char *p, int flag, struct strlist *var_str_list)
+evalvar(char *p, int flags, struct strlist *var_str_list)
{
char varflags;
char subtype;
- int quoted;
+ char quoted;
char easy;
char *var;
int patloc;
@@ -6935,18 +6740,14 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
varflags = (unsigned char) *p++;
subtype = varflags & VSTYPE;
-
- if (!subtype)
- raise_error_syntax("bad substitution");
-
- quoted = flag & EXP_QUOTED;
+ quoted = varflags & VSQUOTE;
var = p;
easy = (!quoted || (*var == '@' && shellparam.nparam));
startloc = expdest - (char *)stackblock();
p = strchr(p, '=') + 1; //TODO: use var_end(p)?
again:
- varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
+ varlen = varvalue(var, varflags, flags, var_str_list);
if (varflags & VSNUL)
varlen--;
@@ -6960,27 +6761,36 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
if (varlen < 0) {
argstr(
p,
- flag | EXP_TILDE | EXP_WORD,
+ flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD),
var_str_list
);
goto end;
}
- goto record;
+ if (easy)
+ goto record;
+ goto end;
}
if (subtype == VSASSIGN || subtype == VSQUESTION) {
- if (varlen >= 0)
+ if (varlen < 0) {
+ if (subevalvar(p, var, /* strloc: */ 0,
+ subtype, startloc, varflags,
+ /* quotes: */ 0,
+ var_str_list)
+ ) {
+ varflags &= ~VSNUL;
+ /*
+ * Remove any recorded regions beyond
+ * start of variable
+ */
+ removerecordregions(startloc);
+ goto again;
+ }
+ goto end;
+ }
+ if (easy)
goto record;
-
- subevalvar(p, var, 0, subtype, startloc, varflags,
- flag & ~QUOTES_ESC, var_str_list);
- varflags &= ~VSNUL;
- /*
- * Remove any recorded regions beyond
- * start of variable
- */
- removerecordregions(startloc);
- goto again;
+ goto end;
}
if (varlen < 0 && uflag)
@@ -6992,10 +6802,8 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
}
if (subtype == VSNORMAL) {
- record:
- if (!easy)
- goto end;
- recordregion(startloc, expdest - (char *)stackblock(), quoted);
+ if (easy)
+ goto record;
goto end;
}
@@ -7024,7 +6832,10 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
STPUTC('\0', expdest);
patloc = expdest - (char *)stackblock();
if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
- startloc, varflags, flag, var_str_list)) {
+ startloc, varflags,
+ /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR),
+ var_str_list)
+ ) {
int amount = expdest - (
(char *)stackblock() + patloc - 1
);
@@ -7032,7 +6843,8 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
}
/* Remove any recorded regions beyond start of variable */
removerecordregions(startloc);
- goto record;
+ record:
+ recordregion(startloc, expdest - (char *)stackblock(), quoted);
}
end:
@@ -7042,7 +6854,7 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
unsigned char c = *p++;
if (c == CTLESC)
p++;
- else if (c == CTLBACKQ) {
+ else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
if (varlen >= 0)
argbackq = argbackq->next;
} else if (c == CTLVAR) {
@@ -7058,113 +6870,129 @@ evalvar(char *p, int flag, struct strlist *var_str_list)
}
/*
- * Add a file name to the list.
+ * Break the argument string into pieces based upon IFS and add the
+ * strings to the argument list. The regions of the string to be
+ * searched for IFS characters have been stored by recordregion.
*/
static void
-addfname(const char *name)
+ifsbreakup(char *string, struct arglist *arglist)
{
+ struct ifsregion *ifsp;
struct strlist *sp;
+ char *start;
+ char *p;
+ char *q;
+ const char *ifs, *realifs;
+ int ifsspc;
+ int nulonly;
+
+ start = string;
+ if (ifslastp != NULL) {
+ ifsspc = 0;
+ nulonly = 0;
+ realifs = ifsset() ? ifsval() : defifs;
+ ifsp = &ifsfirst;
+ do {
+ p = string + ifsp->begoff;
+ nulonly = ifsp->nulonly;
+ ifs = nulonly ? nullstr : realifs;
+ ifsspc = 0;
+ while (p < string + ifsp->endoff) {
+ q = p;
+ if ((unsigned char)*p == CTLESC)
+ p++;
+ if (!strchr(ifs, *p)) {
+ p++;
+ continue;
+ }
+ if (!nulonly)
+ ifsspc = (strchr(defifs, *p) != NULL);
+ /* Ignore IFS whitespace at start */
+ if (q == start && ifsspc) {
+ p++;
+ start = p;
+ continue;
+ }
+ *q = '\0';
+ sp = stzalloc(sizeof(*sp));
+ sp->text = start;
+ *arglist->lastp = sp;
+ arglist->lastp = &sp->next;
+ p++;
+ if (!nulonly) {
+ for (;;) {
+ if (p >= string + ifsp->endoff) {
+ break;
+ }
+ q = p;
+ if ((unsigned char)*p == CTLESC)
+ p++;
+ if (strchr(ifs, *p) == NULL) {
+ p = q;
+ break;
+ }
+ if (strchr(defifs, *p) == NULL) {
+ if (ifsspc) {
+ p++;
+ ifsspc = 0;
+ } else {
+ p = q;
+ break;
+ }
+ } else
+ p++;
+ }
+ }
+ start = p;
+ } /* while */
+ ifsp = ifsp->next;
+ } while (ifsp != NULL);
+ if (nulonly)
+ goto add;
+ }
+ if (!*start)
+ return;
+
+ add:
sp = stzalloc(sizeof(*sp));
- sp->text = sstrdup(name);
- *exparg.lastp = sp;
- exparg.lastp = &sp->next;
+ sp->text = start;
+ *arglist->lastp = sp;
+ arglist->lastp = &sp->next;
}
-/* If we want to use glob() from libc... */
-#if !ENABLE_ASH_INTERNAL_GLOB
-
-/* Add the result of glob() to the list */
static void
-addglob(const glob_t *pglob)
+ifsfree(void)
{
- char **p = pglob->gl_pathv;
+ struct ifsregion *p;
+ INT_OFF;
+ p = ifsfirst.next;
do {
- addfname(*p);
- } while (*++p);
+ struct ifsregion *ifsp;
+ ifsp = p->next;
+ free(p);
+ p = ifsp;
+ } while (p);
+ ifslastp = NULL;
+ ifsfirst.next = NULL;
+ INT_ON;
}
+
+/*
+ * Add a file name to the list.
+ */
static void
-expandmeta(struct strlist *str /*, int flag*/)
+addfname(const char *name)
{
- /* TODO - EXP_REDIR */
-
- while (str) {
- char *p;
- glob_t pglob;
- int i;
-
- if (fflag)
- goto nometa;
-
- /* Avoid glob() (and thus, stat() et al) for words like "echo" */
- p = str->text;
- while (*p) {
- if (*p == '*')
- goto need_glob;
- if (*p == '?')
- goto need_glob;
- if (*p == '[')
- goto need_glob;
- p++;
- }
- goto nometa;
+ struct strlist *sp;
- need_glob:
- INT_OFF;
- p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
-// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
-// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
-//
-// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
-// if you pass it "file\?", it returns "file\?", not "file?", if no match.
-// Which means you need to unescape the string, right? Not so fast:
-// if there _is_ a file named "file\?" (with backslash), it is returned
-// as "file\?" too (whichever pattern you used to find it, say, "file*").
-// You DONT KNOW by looking at the result whether you need to unescape it.
-//
-// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
-// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
-// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
-// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
-// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
-// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
- i = glob(p, 0, NULL, &pglob);
- //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
- if (p != str->text)
- free(p);
- switch (i) {
- case 0:
-#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
- /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
- if (!(pglob.gl_flags & GLOB_MAGCHAR))
- goto nometa2;
-#endif
- addglob(&pglob);
- globfree(&pglob);
- INT_ON;
- break;
- case GLOB_NOMATCH:
- //nometa2:
- globfree(&pglob);
- INT_ON;
- nometa:
- *exparg.lastp = str;
- rmescapes(str->text, 0);
- exparg.lastp = &str->next;
- break;
- default: /* GLOB_NOSPACE */
- globfree(&pglob);
- INT_ON;
- ash_msg_and_raise_error(bb_msg_memory_exhausted);
- }
- str = str->next;
- }
+ sp = stzalloc(sizeof(*sp));
+ sp->text = ststrdup(name);
+ *exparg.lastp = sp;
+ exparg.lastp = &sp->next;
}
-#else
-/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
-
/*
* Do metacharacter (i.e. *, ?, [...]) expansion.
*/
@@ -7181,11 +7009,10 @@ expmeta(char *expdir, char *enddir, char *name)
struct dirent *dp;
int atend;
int matchdot;
- int esc;
metaflag = 0;
start = name;
- for (p = name; esc = 0, *p; p += esc + 1) {
+ for (p = name; *p; p++) {
if (*p == '*' || *p == '?')
metaflag = 1;
else if (*p == '[') {
@@ -7202,16 +7029,15 @@ expmeta(char *expdir, char *enddir, char *name)
break;
}
}
- } else {
- if (*p == '\\')
- esc++;
- if (p[esc] == '/') {
- if (metaflag)
- break;
- start = p + esc + 1;
- }
+ } else if (*p == '\\')
+ p++;
+ else if (*p == '/') {
+ if (metaflag)
+ goto out;
+ start = p + 1;
}
}
+ out:
if (metaflag == 0) { /* we've reached the end of the file name */
if (enddir != expdir)
metaflag++;
@@ -7251,8 +7077,7 @@ expmeta(char *expdir, char *enddir, char *name)
atend = 1;
} else {
atend = 0;
- *endname = '\0';
- endname += esc + 1;
+ *endname++ = '\0';
}
matchdot = 0;
p = start;
@@ -7277,7 +7102,7 @@ expmeta(char *expdir, char *enddir, char *name)
}
closedir(dirp);
if (!atend)
- endname[-esc - 1] = esc ? '\\' : '/';
+ endname[-1] = '/';
}
static struct strlist *
@@ -7365,11 +7190,10 @@ expandmeta(struct strlist *str /*, int flag*/)
savelastp = exparg.lastp;
INT_OFF;
- p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
+ p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
{
int i = strlen(str->text);
-//BUGGY estimation of how long expanded name can be
- expdir = ckmalloc(i < 2048 ? 2048 : i+1);
+ expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
}
expmeta(expdir, expdir, p);
free(expdir);
@@ -7394,7 +7218,6 @@ expandmeta(struct strlist *str /*, int flag*/)
str = str->next;
}
}
-#endif /* ENABLE_ASH_INTERNAL_GLOB */
/*
* Perform variable substitution and command substitution on an argument,
@@ -7410,14 +7233,15 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
argbackq = arg->narg.backquote;
STARTSTACKSTR(expdest);
+ ifsfirst.next = NULL;
+ ifslastp = NULL;
TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
argstr(arg->narg.text, flag,
/* var_str_list: */ arglist ? arglist->list : NULL);
p = _STPUTC('\0', expdest);
expdest = p - 1;
if (arglist == NULL) {
- /* here document expanded */
- goto out;
+ return; /* here document expanded */
}
p = grabstackstr(p);
TRACE(("expandarg: p:'%s'\n", p));
@@ -7440,14 +7264,13 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
*exparg.lastp = sp;
exparg.lastp = &sp->next;
}
+ if (ifsfirst.next)
+ ifsfree();
*exparg.lastp = NULL;
if (exparg.list) {
*arglist->lastp = exparg.list;
arglist->lastp = exparg.lastp;
}
-
- out:
- ifsfree();
}
/*
@@ -7456,7 +7279,8 @@ expandarg(union node *arg, struct arglist *arglist, int flag)
static void
expandhere(union node *arg, int fd)
{
- expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
+ herefd = fd;
+ expandarg(arg, (struct arglist *)NULL, 0);
full_write(fd, stackblock(), expdest - (char *)stackblock());
}
@@ -7466,7 +7290,7 @@ expandhere(union node *arg, int fd)
static int
patmatch(char *pattern, const char *string)
{
- return pmatch(preglob(pattern, 0), string);
+ return pmatch(preglob(pattern, 0, 0), string);
}
/*
@@ -7481,10 +7305,10 @@ casematch(union node *pattern, char *val)
setstackmark(&smark);
argbackq = pattern->narg.backquote;
STARTSTACKSTR(expdest);
+ ifslastp = NULL;
argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
/* var_str_list: */ NULL);
STACKSTRNUL(expdest);
- ifsfree();
result = patmatch(stackblock(), val);
popstackmark(&smark);
return result;
@@ -7585,7 +7409,13 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **
#else
execve(cmd, argv, envp);
#endif
- if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
+ if (cmd == (char*) bb_busybox_exec_path) {
+ /* We already visited ENOEXEC branch below, don't do it again */
+//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
+ free(argv);
+ return;
+ }
+ if (errno == ENOEXEC) {
/* Run "cmd" as a shell script:
* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
* "If the execve() function fails with ENOEXEC, the shell
@@ -7602,13 +7432,19 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **
* message and exit code 126. For one, this prevents attempts
* to interpret foreign ELF binaries as shell scripts.
*/
- argv[0] = cmd;
+ char **ap;
+ char **new;
+
+ for (ap = argv; *ap; ap++)
+ continue;
+ new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
+ new[0] = (char*) "ash";
+ new[1] = cmd;
+ ap = new + 2;
+ while ((*ap++ = *++argv) != NULL)
+ continue;
cmd = (char*) bb_busybox_exec_path;
- /* NB: this is only possible because all callers of shellexec()
- * ensure that the argv[-1] slot exists!
- */
- argv--;
- argv[0] = (char*) "ash";
+ argv = new;
goto repeat;
}
}
@@ -7616,7 +7452,6 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **
/*
* Exec a program. Never returns. If you change this routine, you may
* have to change the find_command routine as well.
- * argv[-1] must exist and be writable! See tryexec() for why.
*/
static void shellexec(char **, const char *, int) NORETURN;
static void
@@ -7628,6 +7463,7 @@ shellexec(char **argv, const char *path, int idx)
int exerrno;
int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
+ clearredir(/*drop:*/ 1);
envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
if (strchr(argv[0], '/') != NULL
#if ENABLE_FEATURE_SH_STANDALONE
@@ -7671,7 +7507,7 @@ shellexec(char **argv, const char *path, int idx)
exitstatus = exerrno;
TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
argv[0], e, suppress_int));
- ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
+ ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
/* NOTREACHED */
}
@@ -7907,122 +7743,78 @@ changepath(const char *new)
clearcmdentry(firstchange);
builtinloc = idx_bltin;
}
-enum {
- TEOF,
- TNL,
- TREDIR,
- TWORD,
- TSEMI,
- TBACKGND,
- TAND,
- TOR,
- TPIPE,
- TLP,
- TRP,
- TENDCASE,
- TENDBQUOTE,
- TNOT,
- TCASE,
- TDO,
- TDONE,
- TELIF,
- TELSE,
- TESAC,
- TFI,
- TFOR,
-#if ENABLE_ASH_BASH_COMPAT
- TFUNCTION,
-#endif
- TIF,
- TIN,
- TTHEN,
- TUNTIL,
- TWHILE,
- TBEGIN,
- TEND
-};
-typedef smallint token_id_t;
-/* Nth bit indicates if token marks the end of a list */
-enum {
- tokendlist = 0
- /* 0 */ | (1u << TEOF)
- /* 1 */ | (0u << TNL)
- /* 2 */ | (0u << TREDIR)
- /* 3 */ | (0u << TWORD)
- /* 4 */ | (0u << TSEMI)
- /* 5 */ | (0u << TBACKGND)
- /* 6 */ | (0u << TAND)
- /* 7 */ | (0u << TOR)
- /* 8 */ | (0u << TPIPE)
- /* 9 */ | (0u << TLP)
- /* 10 */ | (1u << TRP)
- /* 11 */ | (1u << TENDCASE)
- /* 12 */ | (1u << TENDBQUOTE)
- /* 13 */ | (0u << TNOT)
- /* 14 */ | (0u << TCASE)
- /* 15 */ | (1u << TDO)
- /* 16 */ | (1u << TDONE)
- /* 17 */ | (1u << TELIF)
- /* 18 */ | (1u << TELSE)
- /* 19 */ | (1u << TESAC)
- /* 20 */ | (1u << TFI)
- /* 21 */ | (0u << TFOR)
-#if ENABLE_ASH_BASH_COMPAT
- /* 22 */ | (0u << TFUNCTION)
-#endif
- /* 23 */ | (0u << TIF)
- /* 24 */ | (0u << TIN)
- /* 25 */ | (1u << TTHEN)
- /* 26 */ | (0u << TUNTIL)
- /* 27 */ | (0u << TWHILE)
- /* 28 */ | (0u << TBEGIN)
- /* 29 */ | (1u << TEND)
- , /* thus far 29 bits used */
-};
+#define TEOF 0
+#define TNL 1
+#define TREDIR 2
+#define TWORD 3
+#define TSEMI 4
+#define TBACKGND 5
+#define TAND 6
+#define TOR 7
+#define TPIPE 8
+#define TLP 9
+#define TRP 10
+#define TENDCASE 11
+#define TENDBQUOTE 12
+#define TNOT 13
+#define TCASE 14
+#define TDO 15
+#define TDONE 16
+#define TELIF 17
+#define TELSE 18
+#define TESAC 19
+#define TFI 20
+#define TFOR 21
+#define TIF 22
+#define TIN 23
+#define TTHEN 24
+#define TUNTIL 25
+#define TWHILE 26
+#define TBEGIN 27
+#define TEND 28
+typedef smallint token_id_t;
+/* first char is indicating which tokens mark the end of a list */
static const char *const tokname_array[] = {
- "end of file",
- "newline",
- "redirection",
- "word",
- ";",
- "&",
- "&&",
- "||",
- "|",
- "(",
- ")",
- ";;",
- "`",
+ "\1end of file",
+ "\0newline",
+ "\0redirection",
+ "\0word",
+ "\0;",
+ "\0&",
+ "\0&&",
+ "\0||",
+ "\0|",
+ "\0(",
+ "\1)",
+ "\1;;",
+ "\1`",
#define KWDOFFSET 13
/* the following are keywords */
- "!",
- "case",
- "do",
- "done",
- "elif",
- "else",
- "esac",
- "fi",
- "for",
-#if ENABLE_ASH_BASH_COMPAT
- "function",
-#endif
- "if",
- "in",
- "then",
- "until",
- "while",
- "{",
- "}",
+ "\0!",
+ "\0case",
+ "\1do",
+ "\1done",
+ "\1elif",
+ "\1else",
+ "\1esac",
+ "\1fi",
+ "\0for",
+ "\0if",
+ "\0in",
+ "\1then",
+ "\0until",
+ "\0while",
+ "\0{",
+ "\1}",
};
/* Wrapper around strcmp for qsort/bsearch/... */
static int
pstrcmp(const void *a, const void *b)
{
- return strcmp((char*)a, *(char**)b);
+ return strcmp((char*) a, (*(char**) b) + 1);
}
static const char *const *
@@ -8037,15 +7829,14 @@ findkwd(const char *s)
* Locate and print what a word is...
*/
static int
-describe_command(char *command, const char *path, int describe_command_verbose)
+describe_command(char *command, int describe_command_verbose)
{
struct cmdentry entry;
struct tblentry *cmdp;
#if ENABLE_ASH_ALIAS
const struct alias *ap;
#endif
-
- path = path ? path : pathval();
+ const char *path = pathval();
if (describe_command_verbose) {
out1str(command);
@@ -8145,94 +7936,53 @@ typecmd(int argc UNUSED_PARAM, char **argv)
verbose = 0;
}
while (argv[i]) {
- err |= describe_command(argv[i++], NULL, verbose);
+ err |= describe_command(argv[i++], verbose);
}
return err;
}
#if ENABLE_ASH_CMDCMD
-/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
-static char **
-parse_command_args(char **argv, const char **path)
-{
- char *cp, c;
-
- for (;;) {
- cp = *++argv;
- if (!cp)
- return NULL;
- if (*cp++ != '-')
- break;
- c = *cp++;
- if (!c)
- break;
- if (c == '-' && !*cp) {
- if (!*++argv)
- return NULL;
- break;
- }
- do {
- switch (c) {
- case 'p':
- *path = bb_default_path;
- break;
- default:
- /* run 'typecmd' for other options */
- return NULL;
- }
- c = *cp++;
- } while (c);
- }
- return argv;
-}
-
static int FAST_FUNC
commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
- char *cmd;
int c;
enum {
VERIFY_BRIEF = 1,
VERIFY_VERBOSE = 2,
} verify = 0;
- const char *path = NULL;
-
- /* "command [-p] PROG ARGS" (that is, without -V or -v)
- * never reaches this function.
- */
while ((c = nextopt("pvV")) != '\0')
if (c == 'V')
verify |= VERIFY_VERBOSE;
else if (c == 'v')
- /*verify |= VERIFY_BRIEF*/;
+ verify |= VERIFY_BRIEF;
#if DEBUG
else if (c != 'p')
abort();
#endif
- else
- path = bb_default_path;
-
/* Mimic bash: just "command -v" doesn't complain, it's a nop */
- cmd = *argptr;
- if (/*verify && */ cmd)
- return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
+ if (verify && (*argptr != NULL)) {
+ return describe_command(*argptr, verify - VERIFY_BRIEF);
+ }
return 0;
}
#endif
-/*static int funcblocksize; // size of structures in function */
-/*static int funcstringsize; // size of strings in node */
+/* ============ eval.c */
+
+static int funcblocksize; /* size of structures in function */
+static int funcstringsize; /* size of strings in node */
static void *funcblock; /* block to allocate function from */
-static char *funcstring_end; /* end of block to allocate strings from */
+static char *funcstring; /* block to allocate strings from */
/* flags in argument to evaltree */
#define EV_EXIT 01 /* exit after evaluating tree */
#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
+#define EV_BACKCMD 04 /* command executing within back quotes */
-static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
+static const uint8_t nodesize[N_NUMBER] = {
[NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
[NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
[NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
@@ -8264,72 +8014,71 @@ static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
[NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
};
-static int calcsize(int funcblocksize, union node *n);
+static void calcsize(union node *n);
-static int
-sizenodelist(int funcblocksize, struct nodelist *lp)
+static void
+sizenodelist(struct nodelist *lp)
{
while (lp) {
funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
- funcblocksize = calcsize(funcblocksize, lp->n);
+ calcsize(lp->n);
lp = lp->next;
}
- return funcblocksize;
}
-static int
-calcsize(int funcblocksize, union node *n)
+static void
+calcsize(union node *n)
{
if (n == NULL)
- return funcblocksize;
+ return;
funcblocksize += nodesize[n->type];
switch (n->type) {
case NCMD:
- funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
- funcblocksize = calcsize(funcblocksize, n->ncmd.args);
- funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
+ calcsize(n->ncmd.redirect);
+ calcsize(n->ncmd.args);
+ calcsize(n->ncmd.assign);
break;
case NPIPE:
- funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
+ sizenodelist(n->npipe.cmdlist);
break;
case NREDIR:
case NBACKGND:
case NSUBSHELL:
- funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
- funcblocksize = calcsize(funcblocksize, n->nredir.n);
+ calcsize(n->nredir.redirect);
+ calcsize(n->nredir.n);
break;
case NAND:
case NOR:
case NSEMI:
case NWHILE:
case NUNTIL:
- funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
- funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
+ calcsize(n->nbinary.ch2);
+ calcsize(n->nbinary.ch1);
break;
case NIF:
- funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
- funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
- funcblocksize = calcsize(funcblocksize, n->nif.test);
+ calcsize(n->nif.elsepart);
+ calcsize(n->nif.ifpart);
+ calcsize(n->nif.test);
break;
case NFOR:
- funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
- funcblocksize = calcsize(funcblocksize, n->nfor.body);
- funcblocksize = calcsize(funcblocksize, n->nfor.args);
+ funcstringsize += strlen(n->nfor.var) + 1;
+ calcsize(n->nfor.body);
+ calcsize(n->nfor.args);
break;
case NCASE:
- funcblocksize = calcsize(funcblocksize, n->ncase.cases);
- funcblocksize = calcsize(funcblocksize, n->ncase.expr);
+ calcsize(n->ncase.cases);
+ calcsize(n->ncase.expr);
break;
case NCLIST:
- funcblocksize = calcsize(funcblocksize, n->nclist.body);
- funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
- funcblocksize = calcsize(funcblocksize, n->nclist.next);
+ calcsize(n->nclist.body);
+ calcsize(n->nclist.pattern);
+ calcsize(n->nclist.next);
break;
case NDEFUN:
case NARG:
- funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
- funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
- funcblocksize = calcsize(funcblocksize, n->narg.next);
+ sizenodelist(n->narg.backquote);
+ funcstringsize += strlen(n->narg.text) + 1;
+ calcsize(n->narg.next);
break;
case NTO:
#if ENABLE_ASH_BASH_COMPAT
@@ -8339,31 +8088,33 @@ calcsize(int funcblocksize, union node *n)
case NFROM:
case NFROMTO:
case NAPPEND:
- funcblocksize = calcsize(funcblocksize, n->nfile.fname);
- funcblocksize = calcsize(funcblocksize, n->nfile.next);
+ calcsize(n->nfile.fname);
+ calcsize(n->nfile.next);
break;
case NTOFD:
case NFROMFD:
- funcblocksize = calcsize(funcblocksize, n->ndup.vname);
- funcblocksize = calcsize(funcblocksize, n->ndup.next);
+ calcsize(n->ndup.vname);
+ calcsize(n->ndup.next);
break;
case NHERE:
case NXHERE:
- funcblocksize = calcsize(funcblocksize, n->nhere.doc);
- funcblocksize = calcsize(funcblocksize, n->nhere.next);
+ calcsize(n->nhere.doc);
+ calcsize(n->nhere.next);
break;
case NNOT:
- funcblocksize = calcsize(funcblocksize, n->nnot.com);
+ calcsize(n->nnot.com);
break;
};
- return funcblocksize;
}
static char *
nodeckstrdup(char *s)
{
- funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
- return strcpy(funcstring_end, s);
+ char *rtn = funcstring;
+
+ strcpy(funcstring, s);
+ funcstring += strlen(s) + 1;
+ return rtn;
}
static union node *copynode(union node *);
@@ -8487,13 +8238,15 @@ copyfunc(union node *n)
struct funcnode *f;
size_t blocksize;
- /*funcstringsize = 0;*/
- blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
- f = ckzalloc(blocksize /* + funcstringsize */);
+ funcblocksize = offsetof(struct funcnode, n);
+ funcstringsize = 0;
+ calcsize(n);
+ blocksize = funcblocksize;
+ f = ckmalloc(blocksize + funcstringsize);
funcblock = (char *) f + offsetof(struct funcnode, n);
- funcstring_end = (char *) f + blocksize;
+ funcstring = (char *) f + blocksize;
copynode(n);
- /* f->count = 0; - ckzalloc did it */
+ f->count = 0;
return f;
}
@@ -8501,14 +8254,14 @@ copyfunc(union node *n)
* Define a shell function.
*/
static void
-defun(union node *func)
+defun(char *name, union node *func)
{
struct cmdentry entry;
INT_OFF;
entry.cmdtype = CMDFUNCTION;
entry.u.func = copyfunc(func);
- addcmdentry(func->narg.text, &entry);
+ addcmdentry(name, &entry);
INT_ON;
}
@@ -8516,13 +8269,15 @@ defun(union node *func)
#define SKIPBREAK (1 << 0)
#define SKIPCONT (1 << 1)
#define SKIPFUNC (1 << 2)
+#define SKIPFILE (1 << 3)
+#define SKIPEVAL (1 << 4)
static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
static int skipcount; /* number of levels to skip */
static int funcnest; /* depth of function calls */
static int loopnest; /* current loop nesting level */
/* Forward decl way out to parsing code - dotrap needs it */
-static int evalstring(char *s, int flags);
+static int evalstring(char *s, int mask);
/* Called to execute a trap.
* Single callsite - at the end of evaltree().
@@ -8531,77 +8286,96 @@ static int evalstring(char *s, int flags);
* Perhaps we should avoid entering new trap handlers
* while we are executing a trap handler. [is it a TODO?]
*/
-static void
+static int
dotrap(void)
{
uint8_t *g;
int sig;
- uint8_t last_status;
-
- if (!pending_sig)
- return;
+ uint8_t savestatus;
- last_status = exitstatus;
+ savestatus = exitstatus;
pending_sig = 0;
- barrier();
+ xbarrier();
TRACE(("dotrap entered\n"));
for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
- char *p;
+ int want_exexit;
+ char *t;
- if (!*g)
+ if (*g == 0)
continue;
-
- if (evalskip) {
- pending_sig = sig;
- break;
- }
-
- p = trap[sig];
+ t = trap[sig];
/* non-trapped SIGINT is handled separately by raise_interrupt,
* don't upset it by resetting gotsig[SIGINT-1] */
- if (sig == SIGINT && !p)
+ if (sig == SIGINT && !t)
continue;
- TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
+ TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
*g = 0;
- if (!p)
+ if (!t)
continue;
- evalstring(p, 0);
+ want_exexit = evalstring(t, SKIPEVAL);
+ exitstatus = savestatus;
+ if (want_exexit) {
+ TRACE(("dotrap returns %d\n", want_exexit));
+ return want_exexit;
+ }
}
- exitstatus = last_status;
- TRACE(("dotrap returns\n"));
+
+ TRACE(("dotrap returns 0\n"));
+ return 0;
}
/* forward declarations - evaluation is fairly recursive business... */
-static int evalloop(union node *, int);
-static int evalfor(union node *, int);
-static int evalcase(union node *, int);
-static int evalsubshell(union node *, int);
+static void evalloop(union node *, int);
+static void evalfor(union node *, int);
+static void evalcase(union node *, int);
+static void evalsubshell(union node *, int);
static void expredir(union node *);
-static int evalpipe(union node *, int);
-static int evalcommand(union node *, int);
-static int evalbltin(const struct builtincmd *, int, char **, int);
+static void evalpipe(union node *, int);
+static void evalcommand(union node *, int);
+static int evalbltin(const struct builtincmd *, int, char **);
static void prehash(union node *);
/*
* Evaluate a parse tree. The value is left in the global variable
* exitstatus.
*/
-static int
+static void
evaltree(union node *n, int flags)
{
+ struct jmploc *volatile savehandler = exception_handler;
+ struct jmploc jmploc;
int checkexit = 0;
- int (*evalfn)(union node *, int);
- int status = 0;
+ void (*evalfn)(union node *, int);
+ int status;
+ int int_level;
+
+ SAVE_INT(int_level);
if (n == NULL) {
TRACE(("evaltree(NULL) called\n"));
- goto out;
+ goto out1;
}
TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
- dotrap();
+ exception_handler = &jmploc;
+ {
+ int err = setjmp(jmploc.loc);
+ if (err) {
+ /* if it was a signal, check for trap handlers */
+ if (exception_type == EXSIG) {
+ TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
+ exception_type, err));
+ goto out;
+ }
+ /* continue on the way out */
+ TRACE(("exception %d in evaltree, propagating err=%d\n",
+ exception_type, err));
+ exception_handler = savehandler;
+ longjmp(exception_handler->loc, err);
+ }
+ }
switch (n->type) {
default:
@@ -8611,16 +8385,17 @@ evaltree(union node *n, int flags)
break;
#endif
case NNOT:
- status = !evaltree(n->nnot.com, EV_TESTED);
+ evaltree(n->nnot.com, EV_TESTED);
+ status = !exitstatus;
goto setstatus;
case NREDIR:
expredir(n->nredir.redirect);
status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
if (!status) {
- status = evaltree(n->nredir.n, flags & EV_TESTED);
+ evaltree(n->nredir.n, flags & EV_TESTED);
+ status = exitstatus;
}
- if (n->nredir.redirect)
- popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
+ popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
goto setstatus;
case NCMD:
evalfn = evalcommand;
@@ -8638,7 +8413,7 @@ evaltree(union node *n, int flags)
case NSUBSHELL:
case NBACKGND:
evalfn = evalsubshell;
- goto checkexit;
+ goto calleval;
case NPIPE:
evalfn = evalpipe;
goto checkexit;
@@ -8656,24 +8431,27 @@ evaltree(union node *n, int flags)
#error NOR + 1 != NSEMI
#endif
unsigned is_or = n->type - NAND;
- status = evaltree(
+ evaltree(
n->nbinary.ch1,
(flags | ((is_or >> 1) - 1)) & EV_TESTED
);
- if ((!status) == is_or || evalskip)
+ if (!exitstatus == is_or)
break;
- n = n->nbinary.ch2;
+ if (!evalskip) {
+ n = n->nbinary.ch2;
evaln:
- evalfn = evaltree;
+ evalfn = evaltree;
calleval:
- status = evalfn(n, flags);
- goto setstatus;
+ evalfn(n, flags);
+ break;
+ }
+ break;
}
case NIF:
- status = evaltree(n->nif.test, EV_TESTED);
+ evaltree(n->nif.test, EV_TESTED);
if (evalskip)
break;
- if (!status) {
+ if (exitstatus == 0) {
n = n->nif.ifpart;
goto evaln;
}
@@ -8681,141 +8459,136 @@ evaltree(union node *n, int flags)
n = n->nif.elsepart;
goto evaln;
}
- status = 0;
- goto setstatus;
+ goto success;
case NDEFUN:
- defun(n);
- /* Not necessary. To test it:
- * "false; f() { qwerty; }; echo $?" should print 0.
- */
- /* status = 0; */
+ defun(n->narg.text, n->narg.next);
+ success:
+ status = 0;
setstatus:
exitstatus = status;
break;
}
+
out:
+ exception_handler = savehandler;
+
+ out1:
/* Order of checks below is important:
* signal handlers trigger before exit caused by "set -e".
*/
- dotrap();
+ if (pending_sig && dotrap())
+ goto exexit;
+ if (checkexit & exitstatus)
+ evalskip |= SKIPEVAL;
- if (checkexit & status)
- raise_exception(EXEXIT);
- if (flags & EV_EXIT)
+ if (flags & EV_EXIT) {
+ exexit:
raise_exception(EXEXIT);
+ }
+ RESTORE_INT(int_level);
TRACE(("leaving evaltree (no interrupts)\n"));
- return exitstatus;
}
#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
static
#endif
-int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
-
-static int
-skiploop(void)
-{
- int skip = evalskip;
-
- switch (skip) {
- case 0:
- break;
- case SKIPBREAK:
- case SKIPCONT:
- if (--skipcount <= 0) {
- evalskip = 0;
- break;
- }
- skip = SKIPBREAK;
- break;
- }
- return skip;
-}
+void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
-static int
+static void
evalloop(union node *n, int flags)
{
- int skip;
int status;
loopnest++;
status = 0;
flags &= EV_TESTED;
- do {
+ for (;;) {
int i;
- i = evaltree(n->nbinary.ch1, EV_TESTED);
- skip = skiploop();
- if (skip == SKIPFUNC)
- status = i;
- if (skip)
- continue;
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip) {
+ skipping:
+ if (evalskip == SKIPCONT && --skipcount <= 0) {
+ evalskip = 0;
+ continue;
+ }
+ if (evalskip == SKIPBREAK && --skipcount <= 0)
+ evalskip = 0;
+ break;
+ }
+ i = exitstatus;
if (n->type != NWHILE)
i = !i;
if (i != 0)
break;
- status = evaltree(n->nbinary.ch2, flags);
- skip = skiploop();
- } while (!(skip & ~SKIPCONT));
+ evaltree(n->nbinary.ch2, flags);
+ status = exitstatus;
+ if (evalskip)
+ goto skipping;
+ }
loopnest--;
-
- return status;
+ exitstatus = status;
}
-static int
+static void
evalfor(union node *n, int flags)
{
struct arglist arglist;
union node *argp;
struct strlist *sp;
struct stackmark smark;
- int status = 0;
setstackmark(&smark);
arglist.list = NULL;
arglist.lastp = &arglist.list;
for (argp = n->nfor.args; argp; argp = argp->narg.next) {
- expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
+ /* XXX */
+ if (evalskip)
+ goto out;
}
*arglist.lastp = NULL;
+ exitstatus = 0;
loopnest++;
flags &= EV_TESTED;
for (sp = arglist.list; sp; sp = sp->next) {
- setvar0(n->nfor.var, sp->text);
- status = evaltree(n->nfor.body, flags);
- if (skiploop() & ~SKIPCONT)
+ setvar2(n->nfor.var, sp->text);
+ evaltree(n->nfor.body, flags);
+ if (evalskip) {
+ if (evalskip == SKIPCONT && --skipcount <= 0) {
+ evalskip = 0;
+ continue;
+ }
+ if (evalskip == SKIPBREAK && --skipcount <= 0)
+ evalskip = 0;
break;
+ }
}
loopnest--;
+ out:
popstackmark(&smark);
-
- return status;
}
-static int
+static void
evalcase(union node *n, int flags)
{
union node *cp;
union node *patp;
struct arglist arglist;
struct stackmark smark;
- int status = 0;
setstackmark(&smark);
arglist.list = NULL;
arglist.lastp = &arglist.list;
expandarg(n->ncase.expr, &arglist, EXP_TILDE);
+ exitstatus = 0;
for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
if (casematch(patp, arglist.list->text)) {
- /* Ensure body is non-empty as otherwise
- * EV_EXIT may prevent us from setting the
- * exit status.
- */
- if (evalskip == 0 && cp->nclist.body) {
- status = evaltree(cp->nclist.body, flags);
+ if (evalskip == 0) {
+ evaltree(cp->nclist.body, flags);
}
goto out;
}
@@ -8823,14 +8596,12 @@ evalcase(union node *n, int flags)
}
out:
popstackmark(&smark);
-
- return status;
}
/*
* Kick off a subshell to evaluate a tree.
*/
-static int
+static void
evalsubshell(union node *n, int flags)
{
struct job *jp;
@@ -8853,12 +8624,11 @@ evalsubshell(union node *n, int flags)
evaltreenr(n->nredir.n, flags);
/* never returns */
}
- /* parent */
status = 0;
if (!backgnd)
status = waitforjob(jp);
+ exitstatus = status;
INT_ON;
- return status;
}
/*
@@ -8931,7 +8701,7 @@ expredir(union node *n)
* of the shell, which make the last process in a pipeline the parent
* of all the rest.)
*/
-static int
+static void
evalpipe(union node *n, int flags)
{
struct job *jp;
@@ -8939,7 +8709,6 @@ evalpipe(union node *n, int flags)
int pipelen;
int prevfd;
int pip[2];
- int status = 0;
TRACE(("evalpipe(0x%lx) called\n", (long)n));
pipelen = 0;
@@ -8959,7 +8728,6 @@ evalpipe(union node *n, int flags)
}
}
if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
- /* child */
INT_ON;
if (pip[1] >= 0) {
close(pip[0]);
@@ -8975,7 +8743,6 @@ evalpipe(union node *n, int flags)
evaltreenr(lp->n, flags);
/* never returns */
}
- /* parent */
if (prevfd >= 0)
close(prevfd);
prevfd = pip[0];
@@ -8984,12 +8751,10 @@ evalpipe(union node *n, int flags)
close(pip[1]);
}
if (n->npipe.pipe_backgnd == 0) {
- status = waitforjob(jp);
- TRACE(("evalpipe: job done exit status %d\n", status));
+ exitstatus = waitforjob(jp);
+ TRACE(("evalpipe: job done exit status %d\n", exitstatus));
}
INT_ON;
-
- return status;
}
/*
@@ -9014,8 +8779,8 @@ setinteractive(int on)
if (!did_banner) {
/* note: ash and hush share this string */
out1fmt("\n\n%s %s\n"
- IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
- "\n",
+ "Enter 'help' for a list of built-in commands."
+ "\n\n",
bb_banner,
"built-in shell (ash)"
);
@@ -9088,12 +8853,12 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
saveparam = shellparam;
savelocalvars = localvars;
- savehandler = exception_handler;
e = setjmp(jmploc.loc);
if (e) {
goto funcdone;
}
INT_OFF;
+ savehandler = exception_handler;
exception_handler = &jmploc;
localvars = NULL;
shellparam.malloced = 0;
@@ -9106,7 +8871,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
shellparam.optind = 1;
shellparam.optoff = -1;
#endif
- evaltree(func->n.narg.next, flags & EV_TESTED);
+ evaltree(&func->n, flags & EV_TESTED);
funcdone:
INT_OFF;
funcnest--;
@@ -9121,12 +8886,46 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
return e;
}
+#if ENABLE_ASH_CMDCMD
+static char **
+parse_command_args(char **argv, const char **path)
+{
+ char *cp, c;
+
+ for (;;) {
+ cp = *++argv;
+ if (!cp)
+ return 0;
+ if (*cp++ != '-')
+ break;
+ c = *cp++;
+ if (!c)
+ break;
+ if (c == '-' && !*cp) {
+ argv++;
+ break;
+ }
+ do {
+ switch (c) {
+ case 'p':
+ *path = bb_default_path;
+ break;
+ default:
+ /* run 'typecmd' for other options */
+ return 0;
+ }
+ c = *cp++;
+ } while (c);
+ }
+ return argv;
+}
+#endif
+
/*
* Make a variable a local variable. When a variable is made local, it's
* value and flags are saved in a localvar structure. The saved values
* will be restored when the shell function returns. We handle the name
- * "-" as a special case: it makes changes to "set +-options" local
- * (options will be restored on return from the function).
+ * "-" as a special case.
*/
static void
mklocal(char *name)
@@ -9134,37 +8933,21 @@ mklocal(char *name)
struct localvar *lvp;
struct var **vpp;
struct var *vp;
- char *eq = strchr(name, '=');
INT_OFF;
- /* Cater for duplicate "local". Examples:
- * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
- * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
- */
- lvp = localvars;
- while (lvp) {
- if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
- if (eq)
- setvareq(name, 0);
- /* else:
- * it's a duplicate "local VAR" declaration, do nothing
- */
- goto ret;
- }
- lvp = lvp->next;
- }
-
- lvp = ckzalloc(sizeof(*lvp));
+ lvp = ckzalloc(sizeof(struct localvar));
if (LONE_DASH(name)) {
char *p;
p = ckmalloc(sizeof(optlist));
lvp->text = memcpy(p, optlist, sizeof(optlist));
vp = NULL;
} else {
+ char *eq;
+
vpp = hashvar(name);
vp = *findvar(vpp, name);
+ eq = strchr(name, '=');
if (vp == NULL) {
- /* variable did not exist yet */
if (eq)
setvareq(name, VSTRFIXED);
else
@@ -9174,21 +8957,14 @@ mklocal(char *name)
} else {
lvp->text = vp->var_text;
lvp->flags = vp->flags;
- /* make sure neither "struct var" nor string gets freed
- * during (un)setting:
- */
vp->flags |= VSTRFIXED|VTEXTFIXED;
if (eq)
setvareq(name, 0);
- else
- /* "local VAR" unsets VAR: */
- setvar0(name, NULL);
}
}
lvp->vp = vp;
lvp->next = localvars;
localvars = lvp;
- ret:
INT_ON;
}
@@ -9200,9 +8976,6 @@ localcmd(int argc UNUSED_PARAM, char **argv)
{
char *name;
- if (!funcnest)
- ash_msg_and_raise_error("not in a function");
-
argv = argptr;
while ((name = *argv++) != NULL) {
mklocal(name);
@@ -9229,20 +9002,7 @@ execcmd(int argc UNUSED_PARAM, char **argv)
iflag = 0; /* exit on error */
mflag = 0;
optschanged();
- /* We should set up signals for "exec CMD"
- * the same way as for "CMD" without "exec".
- * But optschanged->setinteractive->setsignal
- * still thought we are a root shell. Therefore, for example,
- * SIGQUIT is still set to IGN. Fix it:
- */
- shlvl++;
- setsignal(SIGQUIT);
- /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
- /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
- /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
-
shellexec(argv + 1, pathval(), 0);
- /* NOTREACHED */
}
return 0;
}
@@ -9257,26 +9017,26 @@ returncmd(int argc UNUSED_PARAM, char **argv)
* If called outside a function, do what ksh does;
* skip the rest of the file.
*/
- evalskip = SKIPFUNC;
+ evalskip = funcnest ? SKIPFUNC : SKIPFILE;
return argv[1] ? number(argv[1]) : exitstatus;
}
/* Forward declarations for builtintab[] */
static int breakcmd(int, char **) FAST_FUNC;
static int dotcmd(int, char **) FAST_FUNC;
-static int evalcmd(int, char **, int) FAST_FUNC;
+static int evalcmd(int, char **) FAST_FUNC;
static int exitcmd(int, char **) FAST_FUNC;
static int exportcmd(int, char **) FAST_FUNC;
#if ENABLE_ASH_GETOPTS
static int getoptscmd(int, char **) FAST_FUNC;
#endif
-#if ENABLE_ASH_HELP
+#if !ENABLE_FEATURE_SH_EXTRA_QUIET
static int helpcmd(int, char **) FAST_FUNC;
#endif
#if MAX_HISTORY
static int historycmd(int, char **) FAST_FUNC;
#endif
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
static int letcmd(int, char **) FAST_FUNC;
#endif
static int readcmd(int, char **) FAST_FUNC;
@@ -9314,9 +9074,9 @@ static const struct builtincmd builtintab[] = {
{ BUILTIN_SPEC_REG ":" , truecmd },
#if ENABLE_ASH_BUILTIN_TEST
{ BUILTIN_REGULAR "[" , testcmd },
-# if ENABLE_ASH_BASH_COMPAT
+#if ENABLE_ASH_BASH_COMPAT
{ BUILTIN_REGULAR "[[" , testcmd },
-# endif
+#endif
#endif
#if ENABLE_ASH_ALIAS
{ BUILTIN_REG_ASSG "alias" , aliascmd },
@@ -9334,7 +9094,7 @@ static const struct builtincmd builtintab[] = {
#if ENABLE_ASH_BUILTIN_ECHO
{ BUILTIN_REGULAR "echo" , echocmd },
#endif
- { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
+ { BUILTIN_SPEC_REG "eval" , evalcmd },
{ BUILTIN_SPEC_REG "exec" , execcmd },
{ BUILTIN_SPEC_REG "exit" , exitcmd },
{ BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
@@ -9346,7 +9106,7 @@ static const struct builtincmd builtintab[] = {
{ BUILTIN_REGULAR "getopts" , getoptscmd },
#endif
{ BUILTIN_NOSPEC "hash" , hashcmd },
-#if ENABLE_ASH_HELP
+#if !ENABLE_FEATURE_SH_EXTRA_QUIET
{ BUILTIN_NOSPEC "help" , helpcmd },
#endif
#if MAX_HISTORY
@@ -9356,7 +9116,7 @@ static const struct builtincmd builtintab[] = {
{ BUILTIN_REGULAR "jobs" , jobscmd },
{ BUILTIN_REGULAR "kill" , killcmd },
#endif
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
{ BUILTIN_NOSPEC "let" , letcmd },
#endif
{ BUILTIN_ASSIGN "local" , localcmd },
@@ -9390,28 +9150,27 @@ static const struct builtincmd builtintab[] = {
/* Should match the above table! */
#define COMMANDCMD (builtintab + \
- /* . : */ 2 + \
- /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
- /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
- /* alias */ 1 * ENABLE_ASH_ALIAS + \
- /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
- /* break cd cddir */ 3)
-#define EVALCMD (COMMANDCMD + \
- /* command */ 1 * ENABLE_ASH_CMDCMD + \
- /* continue */ 1 + \
- /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
- 0)
-#define EXECCMD (EVALCMD + \
- /* eval */ 1)
+ 2 + \
+ 1 * ENABLE_ASH_BUILTIN_TEST + \
+ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
+ 1 * ENABLE_ASH_ALIAS + \
+ 1 * ENABLE_ASH_JOB_CONTROL + \
+ 3)
+#define EXECCMD (builtintab + \
+ 2 + \
+ 1 * ENABLE_ASH_BUILTIN_TEST + \
+ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
+ 1 * ENABLE_ASH_ALIAS + \
+ 1 * ENABLE_ASH_JOB_CONTROL + \
+ 3 + \
+ 1 * ENABLE_ASH_CMDCMD + \
+ 1 + \
+ ENABLE_ASH_BUILTIN_ECHO + \
+ 1)
/*
* Search the table of builtin commands.
*/
-static int
-pstrcmp1(const void *a, const void *b)
-{
- return strcmp((char*)a, *(char**)b + 1);
-}
static struct builtincmd *
find_builtin(const char *name)
{
@@ -9419,7 +9178,7 @@ find_builtin(const char *name)
bp = bsearch(
name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
- pstrcmp1
+ pstrcmp
);
return bp;
}
@@ -9442,7 +9201,7 @@ bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
* as POSIX mandates */
return back_exitstatus;
}
-static int
+static void
evalcommand(union node *cmd, int flags)
{
static const struct builtincmd null_bltin = {
@@ -9497,9 +9256,7 @@ evalcommand(union node *cmd, int flags)
argc++;
}
- /* Reserve one extra spot at the front for shellexec. */
- nargv = stalloc(sizeof(char *) * (argc + 2));
- argv = ++nargv;
+ argv = nargv = stalloc(sizeof(char *) * (argc + 1));
for (sp = arglist.list; sp; sp = sp->next) {
TRACE(("evalcommand arg: %s\n", sp->text));
*nargv++ = sp->text;
@@ -9580,9 +9337,6 @@ evalcommand(union node *cmd, int flags)
nargv = parse_command_args(argv, &path);
if (!nargv)
break;
- /* It's "command [-p] PROG ARGS" (that is, no -Vv).
- * nargv => "PROG". path is updated if -p.
- */
argc -= nargv - argv;
argv = nargv;
cmd_flag |= DO_NOFUNC;
@@ -9593,13 +9347,11 @@ evalcommand(union node *cmd, int flags)
}
if (status) {
- bail:
- exitstatus = status;
-
/* We have a redirection error. */
if (spclbltin > 0)
raise_exception(EXERROR);
-
+ bail:
+ exitstatus = status;
goto out;
}
@@ -9618,7 +9370,7 @@ evalcommand(union node *cmd, int flags)
if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
listsetvar(varlist.list, VEXPORT|VSTACK);
/* run <applet>_main() */
- status = run_nofork_applet(applet_no, argv);
+ exitstatus = run_nofork_applet(applet_no, argv);
break;
}
#endif
@@ -9632,9 +9384,9 @@ evalcommand(union node *cmd, int flags)
jp = makejob(/*cmd,*/ 1);
if (forkshell(jp, cmd, FORK_FG) != 0) {
/* parent */
- status = waitforjob(jp);
+ exitstatus = waitforjob(jp);
INT_ON;
- TRACE(("forked child exited with %d\n", status));
+ TRACE(("forked child exited with %d\n", exitstatus));
break;
}
/* child */
@@ -9663,15 +9415,24 @@ evalcommand(union node *cmd, int flags)
* to reap the zombie and make kill detect that it's gone: */
dowait(DOWAIT_NONBLOCK, NULL);
- if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
- if (exception_type == EXERROR && spclbltin <= 0) {
- FORCE_INT_ON;
- goto readstatus;
- }
+ if (evalbltin(cmdentry.u.cmd, argc, argv)) {
+ int exit_status;
+ int i = exception_type;
+ if (i == EXEXIT)
+ goto raise;
+ exit_status = 2;
+ if (i == EXINT)
+ exit_status = 128 + SIGINT;
+ if (i == EXSIG)
+ exit_status = 128 + pending_sig;
+ exitstatus = exit_status;
+ if (i == EXINT || spclbltin > 0) {
raise:
- longjmp(exception_handler->loc, 1);
+ longjmp(exception_handler->loc, 1);
+ }
+ FORCE_INT_ON;
}
- goto readstatus;
+ break;
case CMDFUNCTION:
listsetvar(varlist.list, 0);
@@ -9679,52 +9440,43 @@ evalcommand(union node *cmd, int flags)
dowait(DOWAIT_NONBLOCK, NULL);
if (evalfun(cmdentry.u.func, argc, argv, flags))
goto raise;
- readstatus:
- status = exitstatus;
break;
+
} /* switch */
out:
- if (cmd->ncmd.redirect)
- popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
+ popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
if (lastarg) {
/* dsl: I think this is intended to be used to support
* '_' in 'vi' command mode during line editing...
* However I implemented that within libedit itself.
*/
- setvar0("_", lastarg);
+ setvar2("_", lastarg);
}
popstackmark(&smark);
-
- return status;
}
static int
-evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
+evalbltin(const struct builtincmd *cmd, int argc, char **argv)
{
char *volatile savecmdname;
struct jmploc *volatile savehandler;
struct jmploc jmploc;
- int status;
int i;
savecmdname = commandname;
- savehandler = exception_handler;
i = setjmp(jmploc.loc);
if (i)
goto cmddone;
+ savehandler = exception_handler;
exception_handler = &jmploc;
commandname = argv[0];
argptr = argv + 1;
optptr = NULL; /* initialize nextopt */
- if (cmd == EVALCMD)
- status = evalcmd(argc, argv, flags);
- else
- status = (*cmd->builtin)(argc, argv);
+ exitstatus = (*cmd->builtin)(argc, argv);
flush_stdout_stderr();
- status |= ferror(stdout);
- exitstatus = status;
cmddone:
+ exitstatus |= ferror(stdout);
clearerr(stdout);
commandname = savecmdname;
exception_handler = savehandler;
@@ -9788,7 +9540,8 @@ breakcmd(int argc UNUSED_PARAM, char **argv)
}
-/*
+/* ============ input.c
+ *
* This implements the input routines used by the parser.
*/
@@ -9827,8 +9580,6 @@ pushstring(char *s, struct alias *ap)
g_parsefile->strpush = sp;
sp->prev_string = g_parsefile->next_to_pgetc;
sp->prev_left_in_line = g_parsefile->left_in_line;
- sp->unget = g_parsefile->unget;
- memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
#if ENABLE_ASH_ALIAS
sp->ap = ap;
if (ap) {
@@ -9838,7 +9589,6 @@ pushstring(char *s, struct alias *ap)
#endif
g_parsefile->next_to_pgetc = s;
g_parsefile->left_in_line = len;
- g_parsefile->unget = 0;
INT_ON;
}
@@ -9866,14 +9616,17 @@ popstring(void)
#endif
g_parsefile->next_to_pgetc = sp->prev_string;
g_parsefile->left_in_line = sp->prev_left_in_line;
- g_parsefile->unget = sp->unget;
- memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
g_parsefile->strpush = sp->prev;
if (sp != &(g_parsefile->basestrpush))
free(sp);
INT_ON;
}
+//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
+//it peeks whether it is &>, and then pushes back both chars.
+//This function needs to save last *next_to_pgetc to buf[0]
+//to make two pungetc() reliable. Currently,
+// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
static int
preadfd(void)
{
@@ -9900,19 +9653,25 @@ preadfd(void)
# if ENABLE_FEATURE_TAB_COMPLETION
line_input_state->path_lookup = pathval();
# endif
- reinit_unicode_for_ash();
+ /* Unicode support should be activated even if LANG is set
+ * _during_ shell execution, not only if it was set when
+ * shell was started. Therefore, re-check LANG every time:
+ */
+ {
+ const char *s = lookupvar("LC_ALL");
+ if (!s) s = lookupvar("LC_CTYPE");
+ if (!s) s = lookupvar("LANG");
+ reinit_unicode(s);
+ }
nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
if (nr == 0) {
- /* ^C pressed, "convert" to SIGINT */
- write(STDOUT_FILENO, "^C", 2);
+ /* Ctrl+C pressed */
if (trap[SIGINT]) {
buf[0] = '\n';
buf[1] = '\0';
raise(SIGINT);
return 1;
}
- exitstatus = 128 + SIGINT;
- bb_putchar('\n');
goto retry;
}
if (nr < 0) {
@@ -9922,14 +9681,14 @@ preadfd(void)
}
# if ENABLE_ASH_IDLE_TIMEOUT
else if (errno == EAGAIN && timeout > 0) {
- puts("\007timed out waiting for input: auto-logout");
+ printf("\007timed out waiting for input: auto-logout\n");
exitshell();
}
# endif
}
}
#else
- nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
+ nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
#endif
#if 0 /* disabled: nonblock_immune_read() handles this problem */
@@ -9961,14 +9720,13 @@ preadfd(void)
*/
//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
#define pgetc_debug(...) ((void)0)
-static int pgetc(void);
static int
preadbuffer(void)
{
char *q;
int more;
- if (g_parsefile->strpush) {
+ while (g_parsefile->strpush) {
#if ENABLE_ASH_ALIAS
if (g_parsefile->left_in_line == -1
&& g_parsefile->strpush->ap
@@ -9980,7 +9738,13 @@ preadbuffer(void)
}
#endif
popstring();
- return pgetc();
+ /* try "pgetc" now: */
+ pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
+ g_parsefile->left_in_line,
+ g_parsefile->next_to_pgetc,
+ g_parsefile->next_to_pgetc);
+ if (--g_parsefile->left_in_line >= 0)
+ return (unsigned char)(*g_parsefile->next_to_pgetc++);
}
/* on both branches above g_parsefile->left_in_line < 0.
* "pgetc" needs refilling.
@@ -10059,53 +9823,39 @@ preadbuffer(void)
return (unsigned char)*g_parsefile->next_to_pgetc++;
}
-static void
-nlprompt(void)
-{
- g_parsefile->linno++;
- setprompt_if(doprompt, 2);
-}
-static void
-nlnoprompt(void)
-{
- g_parsefile->linno++;
- needprompt = doprompt;
-}
+#define pgetc_as_macro() \
+ (--g_parsefile->left_in_line >= 0 \
+ ? (unsigned char)*g_parsefile->next_to_pgetc++ \
+ : preadbuffer() \
+ )
static int
pgetc(void)
{
- int c;
-
- pgetc_debug("pgetc at %d:%p'%s'",
+ pgetc_debug("pgetc_fast at %d:%p'%s'",
g_parsefile->left_in_line,
g_parsefile->next_to_pgetc,
g_parsefile->next_to_pgetc);
- if (g_parsefile->unget)
- return g_parsefile->lastc[--g_parsefile->unget];
-
- if (--g_parsefile->left_in_line >= 0)
- c = (unsigned char)*g_parsefile->next_to_pgetc++;
- else
- c = preadbuffer();
-
- g_parsefile->lastc[1] = g_parsefile->lastc[0];
- g_parsefile->lastc[0] = c;
-
- return c;
+ return pgetc_as_macro();
}
+#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
+# define pgetc_fast() pgetc()
+#else
+# define pgetc_fast() pgetc_as_macro()
+#endif
+
#if ENABLE_ASH_ALIAS
static int
pgetc_without_PEOA(void)
{
int c;
do {
- pgetc_debug("pgetc at %d:%p'%s'",
+ pgetc_debug("pgetc_fast at %d:%p'%s'",
g_parsefile->left_in_line,
g_parsefile->next_to_pgetc,
g_parsefile->next_to_pgetc);
- c = pgetc();
+ c = pgetc_fast();
} while (c == PEOA);
return c;
}
@@ -10139,31 +9889,18 @@ pfgets(char *line, int len)
}
/*
- * Undo a call to pgetc. Only two characters may be pushed back.
+ * Undo the last call to pgetc. Only one character may be pushed back.
* PEOF may be pushed back.
*/
static void
pungetc(void)
{
- g_parsefile->unget++;
-}
-
-/* This one eats backslash+newline */
-static int
-pgetc_eatbnl(void)
-{
- int c;
-
- while ((c = pgetc()) == '\\') {
- if (pgetc() != '\n') {
- pungetc();
- break;
- }
-
- nlprompt();
- }
-
- return c;
+ g_parsefile->left_in_line++;
+ g_parsefile->next_to_pgetc--;
+ pgetc_debug("pushed back to %d:%p'%s'",
+ g_parsefile->left_in_line,
+ g_parsefile->next_to_pgetc,
+ g_parsefile->next_to_pgetc);
}
/*
@@ -10180,7 +9917,6 @@ pushfile(void)
pf->pf_fd = -1;
/*pf->strpush = NULL; - ckzalloc did it */
/*pf->basestrpush.prev = NULL;*/
- /*pf->unget = 0;*/
g_parsefile = pf;
}
@@ -10189,9 +9925,6 @@ popfile(void)
{
struct parsefile *pf = g_parsefile;
- if (pf == &basepf)
- return;
-
INT_OFF;
if (pf->pf_fd >= 0)
close(pf->pf_fd);
@@ -10234,6 +9967,7 @@ closescript(void)
static void
setinputfd(int fd, int push)
{
+ close_on_exec_on(fd);
if (push) {
pushfile();
g_parsefile->buf = NULL;
@@ -10254,19 +9988,22 @@ static int
setinputfile(const char *fname, int flags)
{
int fd;
+ int fd2;
INT_OFF;
fd = open(fname, O_RDONLY);
if (fd < 0) {
if (flags & INPUT_NOFILE_OK)
goto out;
- exitstatus = 127;
ash_msg_and_raise_error("can't open '%s'", fname);
}
- if (fd < 10)
- fd = savefd(fd);
- else
- close_on_exec_on(fd);
+ if (fd < 10) {
+ fd2 = copyfd(fd, 10);
+ close(fd);
+ if (fd2 < 0)
+ ash_msg_and_raise_error("out of file descriptors");
+ fd = fd2;
+ }
setinputfd(fd, flags & INPUT_PUSH_FILE);
out:
INT_ON;
@@ -10289,14 +10026,17 @@ setinputstring(char *string)
}
-/*
+/* ============ mail.c
+ *
* Routines to check for mail.
*/
#if ENABLE_ASH_MAIL
-/* Hash of mtimes of mailboxes */
-static unsigned mailtime_hash;
+#define MAXMBOXES 10
+
+/* times of mailboxes */
+static time_t mailtime[MAXMBOXES];
/* Set if MAIL or MAILPATH is changed. */
static smallint mail_var_path_changed;
@@ -10312,14 +10052,13 @@ chkmail(void)
const char *mpath;
char *p;
char *q;
- unsigned new_hash;
+ time_t *mtp;
struct stackmark smark;
struct stat statb;
setstackmark(&smark);
mpath = mpathset() ? mpathval() : mailval();
- new_hash = 0;
- for (;;) {
+ for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
p = path_advance(&mpath, nullstr);
if (p == NULL)
break;
@@ -10333,15 +10072,16 @@ chkmail(void)
#endif
q[-1] = '\0'; /* delete trailing '/' */
if (stat(p, &statb) < 0) {
+ *mtp = 0;
continue;
}
- /* Very simplistic "hash": just a sum of all mtimes */
- new_hash += (unsigned)statb.st_mtime;
- }
- if (!mail_var_path_changed && mailtime_hash != new_hash) {
- if (mailtime_hash != 0)
- out2str("you have mail\n");
- mailtime_hash = new_hash;
+ if (!mail_var_path_changed && statb.st_mtime != *mtp) {
+ fprintf(
+ stderr, "%s\n",
+ pathopt ? pathopt : "you have mail"
+ );
+ }
+ *mtp = statb.st_mtime;
}
mail_var_path_changed = 0;
popstackmark(&smark);
@@ -10607,25 +10347,23 @@ change_random(const char *value)
#if ENABLE_ASH_GETOPTS
static int
-getopts(char *optstr, char *optvar, char **optfirst)
+getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
{
char *p, *q;
char c = '?';
int done = 0;
- char sbuf[2];
+ int err = 0;
+ char s[12];
char **optnext;
- int ind = shellparam.optind;
- int off = shellparam.optoff;
-
- sbuf[1] = '\0';
- shellparam.optind = -1;
- optnext = optfirst + ind - 1;
+ if (*param_optind < 1)
+ return 1;
+ optnext = optfirst + *param_optind - 1;
- if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
+ if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
p = NULL;
else
- p = optnext[-1] + off;
+ p = optnext[-1] + *optoff;
if (p == NULL || *p == '\0') {
/* Current word is done, advance */
p = *optnext;
@@ -10644,9 +10382,9 @@ getopts(char *optstr, char *optvar, char **optfirst)
for (q = optstr; *q != c;) {
if (*q == '\0') {
if (optstr[0] == ':') {
- sbuf[0] = c;
- /*sbuf[1] = '\0'; - already is */
- setvar0("OPTARG", sbuf);
+ s[0] = c;
+ s[1] = '\0';
+ err |= setvarsafe("OPTARG", s, 0);
} else {
fprintf(stderr, "Illegal option -%c\n", c);
unsetvar("OPTARG");
@@ -10661,9 +10399,9 @@ getopts(char *optstr, char *optvar, char **optfirst)
if (*++q == ':') {
if (*p == '\0' && (p = *optnext) == NULL) {
if (optstr[0] == ':') {
- sbuf[0] = c;
- /*sbuf[1] = '\0'; - already is */
- setvar0("OPTARG", sbuf);
+ s[0] = c;
+ s[1] = '\0';
+ err |= setvarsafe("OPTARG", s, 0);
c = ':';
} else {
fprintf(stderr, "No arg for -%c option\n", c);
@@ -10675,20 +10413,24 @@ getopts(char *optstr, char *optvar, char **optfirst)
if (p == *optnext)
optnext++;
- setvar0("OPTARG", p);
+ err |= setvarsafe("OPTARG", p, 0);
p = NULL;
} else
- setvar0("OPTARG", nullstr);
+ err |= setvarsafe("OPTARG", nullstr, 0);
out:
- ind = optnext - optfirst + 1;
- setvar("OPTIND", itoa(ind), VNOFUNC);
- sbuf[0] = c;
- /*sbuf[1] = '\0'; - already is */
- setvar0(optvar, sbuf);
-
- shellparam.optoff = p ? p - *(optnext - 1) : -1;
- shellparam.optind = ind;
-
+ *optoff = p ? p - *(optnext - 1) : -1;
+ *param_optind = optnext - optfirst + 1;
+ fmtstr(s, sizeof(s), "%d", *param_optind);
+ err |= setvarsafe("OPTIND", s, VNOFUNC);
+ s[0] = c;
+ s[1] = '\0';
+ err |= setvarsafe(optvar, s, 0);
+ if (err) {
+ *param_optind = 1;
+ *optoff = -1;
+ flush_stdout_stderr();
+ raise_exception(EXERROR);
+ }
return done;
}
@@ -10707,19 +10449,20 @@ getoptscmd(int argc, char **argv)
ash_msg_and_raise_error("usage: getopts optstring var [arg]");
if (argc == 3) {
optbase = shellparam.p;
- if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
+ if (shellparam.optind > shellparam.nparam + 1) {
shellparam.optind = 1;
shellparam.optoff = -1;
}
} else {
optbase = &argv[3];
- if ((unsigned)shellparam.optind > argc - 2) {
+ if (shellparam.optind > argc - 2) {
shellparam.optind = 1;
shellparam.optoff = -1;
}
}
- return getopts(argv[1], argv[2], optbase);
+ return getopts(argv[1], argv[2], optbase, &shellparam.optind,
+ &shellparam.optoff);
}
#endif /* ASH_GETOPTS */
@@ -10734,6 +10477,7 @@ struct heredoc {
};
static smallint tokpushback; /* last token pushed back */
+static smallint parsebackquote; /* nonzero if we are inside backquotes */
static smallint quoteflag; /* set if (part of) last token was quoted */
static token_id_t lasttoken; /* last token read (integer id Txxx) */
static struct heredoc *heredoclist; /* list of here documents to read */
@@ -10746,8 +10490,8 @@ static const char *
tokname(char *buf, int tok)
{
if (tok < TSEMI)
- return tokname_array[tok];
- sprintf(buf, "\"%s\"", tokname_array[tok]);
+ return tokname_array[tok] + 1;
+ sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
return buf;
}
@@ -10778,7 +10522,7 @@ static union node *andor(void);
static union node *pipeline(void);
static union node *parse_command(void);
static void parseheredoc(void);
-static int peektoken(void);
+static char peektoken(void);
static int readtoken(void);
static union node *
@@ -10787,27 +10531,11 @@ list(int nlflag)
union node *n1, *n2, *n3;
int tok;
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (nlflag == 2 && peektoken())
+ return NULL;
n1 = NULL;
for (;;) {
- switch (peektoken()) {
- case TNL:
- if (!(nlflag & 1))
- break;
- parseheredoc();
- return n1;
-
- case TEOF:
- if (!n1 && (nlflag & 1))
- n1 = NODE_EOF;
- parseheredoc();
- return n1;
- }
-
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
- return n1;
- nlflag |= 2;
-
n2 = andor();
tok = readtoken();
if (tok == TBACKGND) {
@@ -10833,15 +10561,30 @@ list(int nlflag)
n1 = n3;
}
switch (tok) {
- case TNL:
- case TEOF:
- tokpushback = 1;
- /* fall through */
case TBACKGND:
case TSEMI:
+ tok = readtoken();
+ /* fall through */
+ case TNL:
+ if (tok == TNL) {
+ parseheredoc();
+ if (nlflag == 1)
+ return n1;
+ } else {
+ tokpushback = 1;
+ }
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (peektoken())
+ return n1;
break;
+ case TEOF:
+ if (heredoclist)
+ parseheredoc();
+ else
+ pungetc(); /* push back EOF on input */
+ return n1;
default:
- if ((nlflag & 1))
+ if (nlflag == 1)
raise_error_unexpected_syntax(-1);
tokpushback = 1;
return n1;
@@ -11016,7 +10759,6 @@ simplecmd(void)
int savecheckkwd;
#if ENABLE_ASH_BASH_COMPAT
smallint double_brackets_flag = 0;
- smallint function_flag = 0;
#endif
args = NULL;
@@ -11033,11 +10775,6 @@ simplecmd(void)
t = readtoken();
switch (t) {
#if ENABLE_ASH_BASH_COMPAT
- case TFUNCTION:
- if (peektoken() != TWORD)
- raise_error_unexpected_syntax(TWORD);
- function_flag = 1;
- break;
case TAND: /* "&&" */
case TOR: /* "||" */
if (!double_brackets_flag) {
@@ -11066,29 +10803,6 @@ simplecmd(void)
app = &n->narg.next;
savecheckkwd = 0;
}
-#if ENABLE_ASH_BASH_COMPAT
- if (function_flag) {
- checkkwd = CHKNL | CHKKWD;
- switch (peektoken()) {
- case TBEGIN:
- case TIF:
- case TCASE:
- case TUNTIL:
- case TWHILE:
- case TFOR:
- goto do_func;
- case TLP:
- function_flag = 0;
- break;
- case TWORD:
- if (strcmp("[[", wordtext) == 0)
- goto do_func;
- /* fall through */
- default:
- raise_error_unexpected_syntax(-1);
- }
- }
-#endif
break;
case TREDIR:
*rpp = n = redirnode;
@@ -11096,7 +10810,6 @@ simplecmd(void)
parsefname(); /* read name of redirection file */
break;
case TLP:
- IF_ASH_BASH_COMPAT(do_func:)
if (args && app == &args->narg.next
&& !vars && !redir
) {
@@ -11104,7 +10817,7 @@ simplecmd(void)
const char *name;
/* We have a function */
- if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
+ if (readtoken() != TRP)
raise_error_unexpected_syntax(TRP);
name = n->narg.text;
if (!goodname(name)
@@ -11117,7 +10830,6 @@ simplecmd(void)
n->narg.next = parse_command();
return n;
}
- IF_ASH_BASH_COMPAT(function_flag = 0;)
/* fall through */
default:
tokpushback = 1;
@@ -11186,7 +10898,7 @@ parse_command(void)
n1->nbinary.ch1 = list(0);
got = readtoken();
if (got != TDO) {
- TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
+ TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
got == TWORD ? wordtext : ""));
raise_error_unexpected_syntax(TDO);
}
@@ -11200,7 +10912,7 @@ parse_command(void)
n1 = stzalloc(sizeof(struct nfor));
n1->type = NFOR;
n1->nfor.var = wordtext;
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ checkkwd = CHKKWD | CHKALIAS;
if (readtoken() == TIN) {
app = &ap;
while (readtoken() == TWORD) {
@@ -11227,7 +10939,7 @@ parse_command(void)
* Newline or semicolon here is optional (but note
* that the original Bourne shell only allowed NL).
*/
- if (lasttoken != TSEMI)
+ if (lasttoken != TNL && lasttoken != TSEMI)
tokpushback = 1;
}
checkkwd = CHKNL | CHKKWD | CHKALIAS;
@@ -11246,8 +10958,10 @@ parse_command(void)
/*n2->narg.next = NULL; - stzalloc did it */
n2->narg.text = wordtext;
n2->narg.backquote = backquotelist;
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- if (readtoken() != TIN)
+ do {
+ checkkwd = CHKKWD | CHKALIAS;
+ } while (readtoken() == TNL);
+ if (lasttoken != TIN)
raise_error_unexpected_syntax(TIN);
cpp = &n1->ncase.cases;
next_case:
@@ -11298,7 +11012,6 @@ parse_command(void)
n1 = list(0);
t = TEND;
break;
- IF_ASH_BASH_COMPAT(case TFUNCTION:)
case TWORD:
case TREDIR:
tokpushback = 1;
@@ -11332,8 +11045,7 @@ parse_command(void)
}
#if ENABLE_ASH_BASH_COMPAT
-static int
-decode_dollar_squote(void)
+static int decode_dollar_squote(void)
{
static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
int c, cnt;
@@ -11401,27 +11113,40 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
/* NB: syntax parameter fits into smallint */
/* c parameter is an unsigned char or PEOF or PEOA */
char *out;
- size_t len;
+ int len;
char line[EOFMARKLEN + 1];
struct nodelist *bqlist;
smallint quotef;
smallint dblquote;
smallint oldstyle;
- IF_FEATURE_SH_MATH(smallint prevsyntax;) /* syntax before arithmetic */
+ smallint prevsyntax; /* syntax before arithmetic */
#if ENABLE_ASH_EXPAND_PRMT
smallint pssyntax; /* we are expanding a prompt string */
#endif
int varnest; /* levels of variables expansion */
- IF_FEATURE_SH_MATH(int arinest;) /* levels of arithmetic expansion */
- IF_FEATURE_SH_MATH(int parenlevel;) /* levels of parens in arithmetic */
+ int arinest; /* levels of arithmetic expansion */
+ int parenlevel; /* levels of parens in arithmetic */
int dqvarnest; /* levels of variables expansion within double quotes */
IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
+#if __GNUC__
+ /* Avoid longjmp clobbering */
+ (void) &out;
+ (void) &quotef;
+ (void) &dblquote;
+ (void) &varnest;
+ (void) &arinest;
+ (void) &parenlevel;
+ (void) &dqvarnest;
+ (void) &oldstyle;
+ (void) &prevsyntax;
+ (void) &syntax;
+#endif
startlinno = g_parsefile->linno;
bqlist = NULL;
quotef = 0;
- IF_FEATURE_SH_MATH(prevsyntax = 0;)
+ prevsyntax = 0;
#if ENABLE_ASH_EXPAND_PRMT
pssyntax = (syntax == PSSYNTAX);
if (pssyntax)
@@ -11429,8 +11154,8 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
#endif
dblquote = (syntax == DQSYNTAX);
varnest = 0;
- IF_FEATURE_SH_MATH(arinest = 0;)
- IF_FEATURE_SH_MATH(parenlevel = 0;)
+ arinest = 0;
+ parenlevel = 0;
dqvarnest = 0;
STARTSTACKSTR(out);
@@ -11444,31 +11169,25 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
if (syntax == BASESYNTAX)
goto endword; /* exit outer loop */
USTPUTC(c, out);
- nlprompt();
+ g_parsefile->linno++;
+ setprompt_if(doprompt, 2);
c = pgetc();
goto loop; /* continue outer loop */
case CWORD:
USTPUTC(c, out);
break;
case CCTL:
+ if (eofmark == NULL || dblquote)
+ USTPUTC(CTLESC, out);
#if ENABLE_ASH_BASH_COMPAT
if (c == '\\' && bash_dollar_squote) {
c = decode_dollar_squote();
- if (c == '\0') {
- /* skip $'\000', $'\x00' (like bash) */
- break;
- }
if (c & 0x100) {
- /* Unknown escape. Encode as '\z' */
- c = (unsigned char)c;
- if (eofmark == NULL || dblquote)
- USTPUTC(CTLESC, out);
USTPUTC('\\', out);
+ c = (unsigned char)c;
}
}
#endif
- if (eofmark == NULL || dblquote)
- USTPUTC(CTLESC, out);
USTPUTC(c, out);
break;
case CBACK: /* backslash */
@@ -11478,7 +11197,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
USTPUTC('\\', out);
pungetc();
} else if (c == '\n') {
- nlprompt();
+ setprompt_if(doprompt, 2);
} else {
#if ENABLE_ASH_EXPAND_PRMT
if (c == '$' && pssyntax) {
@@ -11493,9 +11212,11 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
&& c != '$'
&& (c != '"' || eofmark != NULL)
) {
+ USTPUTC(CTLESC, out);
USTPUTC('\\', out);
}
- USTPUTC(CTLESC, out);
+ if (SIT(c, SQSYNTAX) == CCTL)
+ USTPUTC(CTLESC, out);
USTPUTC(c, out);
quotef = 1;
}
@@ -11513,7 +11234,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
goto quotemark;
case CENDQUOTE:
IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
- if (eofmark != NULL && varnest == 0) {
+ if (eofmark != NULL && arinest == 0
+ && varnest == 0
+ ) {
USTPUTC(c, out);
} else {
if (dqvarnest == 0) {
@@ -11537,7 +11260,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
}
USTPUTC(c, out);
break;
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
case CLP: /* '(' in arithmetic */
parenlevel++;
USTPUTC(c, out);
@@ -11546,10 +11269,11 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
if (parenlevel > 0) {
parenlevel--;
} else {
- if (pgetc_eatbnl() == ')') {
- c = CTLENDARI;
+ if (pgetc() == ')') {
if (--arinest == 0) {
syntax = prevsyntax;
+ dblquote = (syntax == DQSYNTAX);
+ c = CTLENDARI;
}
} else {
/*
@@ -11573,7 +11297,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
if (varnest == 0) {
#if ENABLE_ASH_BASH_COMPAT
if (c == '&') {
-//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
if (pgetc() == '>')
c = 0x100 + '>'; /* flag &> */
pungetc();
@@ -11584,15 +11307,15 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
IF_ASH_ALIAS(if (c != PEOA))
USTPUTC(c, out);
}
- c = pgetc();
+ c = pgetc_fast();
} /* for (;;) */
endword:
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
if (syntax == ARISYNTAX)
raise_error_syntax("missing '))'");
#endif
- if (syntax != BASESYNTAX && eofmark == NULL)
+ if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
raise_error_syntax("unterminated quoted string");
if (varnest != 0) {
startlinno = g_parsefile->linno;
@@ -11643,19 +11366,14 @@ checkend: {
if (c == *eofmark) {
if (pfgets(line, sizeof(line)) != NULL) {
char *p, *q;
- int cc;
p = line;
- for (q = eofmark + 1;; p++, q++) {
- cc = *p;
- if (cc == '\n')
- cc = 0;
- if (!*q || cc != *q)
- break;
- }
- if (cc == *q) {
+ for (q = eofmark + 1; *q && *p == *q; p++, q++)
+ continue;
+ if (*p == '\n' && *q == '\0') {
c = PEOF;
- nlnoprompt();
+ g_parsefile->linno++;
+ needprompt = doprompt;
} else {
pushstring(line, NULL);
}
@@ -11752,13 +11470,14 @@ parseredir: {
parsesub: {
unsigned char subtype;
int typeloc;
+ int flags;
- c = pgetc_eatbnl();
+ c = pgetc();
if (c > 255 /* PEOA or PEOF */
|| (c != '(' && c != '{' && !is_name(c) && !is_special(c))
) {
#if ENABLE_ASH_BASH_COMPAT
- if (syntax != DQSYNTAX && c == '\'')
+ if (c == '\'')
bash_dollar_squote = 1;
else
#endif
@@ -11766,8 +11485,8 @@ parsesub: {
pungetc();
} else if (c == '(') {
/* $(command) or $((arith)) */
- if (pgetc_eatbnl() == '(') {
-#if ENABLE_FEATURE_SH_MATH
+ if (pgetc() == '(') {
+#if ENABLE_SH_MATH_SUPPORT
PARSEARITH();
#else
raise_error_syntax("you disabled math support for $((arith)) syntax");
@@ -11780,86 +11499,79 @@ parsesub: {
/* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
USTPUTC(CTLVAR, out);
typeloc = out - (char *)stackblock();
- STADJUST(1, out);
+ USTPUTC(VSNORMAL, out);
subtype = VSNORMAL;
if (c == '{') {
- c = pgetc_eatbnl();
- subtype = 0;
+ c = pgetc();
+ if (c == '#') {
+ c = pgetc();
+ if (c == '}')
+ c = '#'; /* ${#} - same as $# */
+ else
+ subtype = VSLENGTH; /* ${#VAR} */
+ } else {
+ subtype = 0;
+ }
}
- varname:
- if (is_name(c)) {
+ if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
/* $[{[#]]NAME[}] */
do {
STPUTC(c, out);
- c = pgetc_eatbnl();
- } while (is_in_name(c));
+ c = pgetc();
+ } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
} else if (isdigit(c)) {
/* $[{[#]]NUM[}] */
do {
STPUTC(c, out);
- c = pgetc_eatbnl();
+ c = pgetc();
} while (isdigit(c));
} else if (is_special(c)) {
/* $[{[#]]<specialchar>[}] */
- int cc = c;
-
- c = pgetc_eatbnl();
- if (!subtype && cc == '#') {
- subtype = VSLENGTH;
- if (c == '_' || isalnum(c))
- goto varname;
- cc = c;
- c = pgetc_eatbnl();
- if (cc == '}' || c != '}') {
- pungetc();
- subtype = 0;
- c = cc;
- cc = '#';
- }
- }
- USTPUTC(cc, out);
+ USTPUTC(c, out);
+ c = pgetc();
} else {
- goto badsub;
+ badsub:
+ raise_error_syntax("bad substitution");
}
if (c != '}' && subtype == VSLENGTH) {
/* ${#VAR didn't end with } */
goto badsub;
}
+ STPUTC('=', out);
+ flags = 0;
if (subtype == 0) {
- static const char types[] ALIGN1 = "}-+?=";
/* ${VAR...} but not $VAR or ${#VAR} */
/* c == first char after VAR */
switch (c) {
case ':':
- c = pgetc_eatbnl();
+ c = pgetc();
#if ENABLE_ASH_BASH_COMPAT
- /* This check is only needed to not misinterpret
- * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
- * constructs.
- */
- if (!strchr(types, c)) {
+ if (c == ':' || c == '$' || isdigit(c)) {
+//TODO: support more general format ${v:EXPR:EXPR},
+// where EXPR follows $(()) rules
subtype = VSSUBSTR;
pungetc();
- break; /* "goto badsub" is bigger (!) */
+ break; /* "goto do_pungetc" is bigger (!) */
}
#endif
- subtype = VSNUL;
+ flags = VSNUL;
/*FALLTHROUGH*/
default: {
+ static const char types[] ALIGN1 = "}-+?=";
const char *p = strchr(types, c);
if (p == NULL)
- break;
- subtype |= p - types + VSNORMAL;
+ goto badsub;
+ subtype = p - types + VSNORMAL;
break;
}
case '%':
case '#': {
int cc = c;
subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
- c = pgetc_eatbnl();
+ c = pgetc();
if (c != cc)
- goto badsub;
+ goto do_pungetc;
subtype++;
break;
}
@@ -11869,24 +11581,26 @@ parsesub: {
//TODO: encode pattern and repl separately.
// Currently ${v/$var_with_slash/repl} is horribly broken
subtype = VSREPLACE;
- c = pgetc_eatbnl();
+ c = pgetc();
if (c != '/')
- goto badsub;
+ goto do_pungetc;
subtype++; /* VSREPLACEALL */
break;
#endif
}
} else {
- badsub:
+ do_pungetc:
pungetc();
}
- ((unsigned char *)stackblock())[typeloc] = subtype;
+ if (dblquote || arinest)
+ flags |= VSQUOTE;
+ ((unsigned char *)stackblock())[typeloc] = subtype | flags;
if (subtype != VSNORMAL) {
varnest++;
- if (dblquote)
+ if (dblquote || arinest) {
dqvarnest++;
+ }
}
- STPUTC('=', out);
}
goto parsesub_return;
}
@@ -11899,26 +11613,34 @@ parsesub: {
*/
parsebackq: {
struct nodelist **nlpp;
+ smallint savepbq;
union node *n;
- char *str;
+ char *volatile str;
+ struct jmploc jmploc;
+ struct jmploc *volatile savehandler;
size_t savelen;
smallint saveprompt = 0;
+#ifdef __GNUC__
+ (void) &saveprompt;
+#endif
+ savepbq = parsebackquote;
+ if (setjmp(jmploc.loc)) {
+ free(str);
+ parsebackquote = 0;
+ exception_handler = savehandler;
+ longjmp(exception_handler->loc, 1);
+ }
+ INT_OFF;
str = NULL;
savelen = out - (char *)stackblock();
if (savelen > 0) {
- /*
- * FIXME: this can allocate very large block on stack and SEGV.
- * Example:
- * echo "..<100kbytes>..`true` $(true) `true` ..."
- * allocates 100kb for every command subst. With about
- * a hundred command substitutions stack overflows.
- * With larger prepended string, SEGV happens sooner.
- */
- str = alloca(savelen);
+ str = ckmalloc(savelen);
memcpy(str, stackblock(), savelen);
}
-
+ savehandler = exception_handler;
+ exception_handler = &jmploc;
+ INT_ON;
if (oldstyle) {
/* We must read until the closing backquote, giving special
* treatment to some slashes, and then push the string and
@@ -11941,7 +11663,8 @@ parsebackq: {
case '\\':
pc = pgetc();
if (pc == '\n') {
- nlprompt();
+ g_parsefile->linno++;
+ setprompt_if(doprompt, 2);
/*
* If eating a newline, avoid putting
* the newline into the new character
@@ -11966,7 +11689,8 @@ parsebackq: {
raise_error_syntax("EOF in backquote substitution");
case '\n':
- nlnoprompt();
+ g_parsefile->linno++;
+ needprompt = doprompt;
break;
default:
@@ -11987,6 +11711,7 @@ parsebackq: {
nlpp = &(*nlpp)->next;
*nlpp = stzalloc(sizeof(**nlpp));
/* (*nlpp)->next = NULL; - stzalloc did it */
+ parsebackquote = oldstyle;
if (oldstyle) {
saveprompt = doprompt;
@@ -12015,14 +11740,23 @@ parsebackq: {
if (str) {
memcpy(out, str, savelen);
STADJUST(savelen, out);
+ INT_OFF;
+ free(str);
+ str = NULL;
+ INT_ON;
}
- USTPUTC(CTLBACKQ, out);
+ parsebackquote = savepbq;
+ exception_handler = savehandler;
+ if (arinest || dblquote)
+ USTPUTC(CTLBACKQ | CTLQUOTE, out);
+ else
+ USTPUTC(CTLBACKQ, out);
if (oldstyle)
goto parsebackq_oldreturn;
goto parsebackq_newreturn;
}
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
/*
* Parse an arithmetic expansion (indicate start of one and set state)
*/
@@ -12030,11 +11764,22 @@ parsearith: {
if (++arinest == 1) {
prevsyntax = syntax;
syntax = ARISYNTAX;
+ USTPUTC(CTLARI, out);
+ if (dblquote)
+ USTPUTC('"', out);
+ else
+ USTPUTC(' ', out);
+ } else {
+ /*
+ * we collapse embedded arithmetic expansion to
+ * parenthesis, which should be equivalent
+ */
+ USTPUTC('(', out);
}
- USTPUTC(CTLARI, out);
goto parsearith_return;
}
#endif
+
} /* end of readtoken */
/*
@@ -12085,7 +11830,7 @@ xxreadtoken(void)
setprompt_if(needprompt, 2);
startlinno = g_parsefile->linno;
for (;;) { /* until token or start of word found */
- c = pgetc();
+ c = pgetc_fast();
if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
continue;
@@ -12098,14 +11843,16 @@ xxreadtoken(void)
pungetc();
break; /* return readtoken1(...) */
}
- nlprompt();
+ startlinno = ++g_parsefile->linno;
+ setprompt_if(doprompt, 2);
} else {
const char *p;
p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
if (c != PEOF) {
if (c == '\n') {
- nlnoprompt();
+ g_parsefile->linno++;
+ needprompt = doprompt;
}
p = strchr(xxreadtoken_chars, c);
@@ -12146,7 +11893,7 @@ xxreadtoken(void)
setprompt_if(needprompt, 2);
startlinno = g_parsefile->linno;
for (;;) { /* until token or start of word found */
- c = pgetc();
+ c = pgetc_fast();
switch (c) {
case ' ': case '\t':
IF_ASH_ALIAS(case PEOA:)
@@ -12158,13 +11905,15 @@ xxreadtoken(void)
continue;
case '\\':
if (pgetc() == '\n') {
- nlprompt();
+ startlinno = ++g_parsefile->linno;
+ setprompt_if(doprompt, 2);
continue;
}
pungetc();
goto breakloop;
case '\n':
- nlnoprompt();
+ g_parsefile->linno++;
+ needprompt = doprompt;
RETURN(TNL);
case PEOF:
RETURN(TEOF);
@@ -12201,7 +11950,6 @@ static int
readtoken(void)
{
int t;
- int kwd = checkkwd;
#if DEBUG
smallint alreadyseen = tokpushback;
#endif
@@ -12215,7 +11963,7 @@ readtoken(void)
/*
* eat newlines
*/
- if (kwd & CHKNL) {
+ if (checkkwd & CHKNL) {
while (t == TNL) {
parseheredoc();
t = xxreadtoken();
@@ -12229,13 +11977,13 @@ readtoken(void)
/*
* check for keywords
*/
- if (kwd & CHKKWD) {
+ if (checkkwd & CHKKWD) {
const char *const *pp;
pp = findkwd(wordtext);
if (pp) {
lasttoken = t = pp - tokname_array;
- TRACE(("keyword '%s' recognized\n", tokname_array[t]));
+ TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
goto out;
}
}
@@ -12256,21 +12004,21 @@ readtoken(void)
checkkwd = 0;
#if DEBUG
if (!alreadyseen)
- TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
+ TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
else
- TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
+ TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
#endif
return t;
}
-static int
+static char
peektoken(void)
{
int t;
t = readtoken();
tokpushback = 1;
- return t;
+ return tokname_array[t][0];
}
/*
@@ -12280,12 +12028,18 @@ peektoken(void)
static union node *
parsecmd(int interact)
{
+ int t;
+
tokpushback = 0;
- checkkwd = 0;
- heredoclist = 0;
doprompt = interact;
setprompt_if(doprompt, doprompt);
needprompt = 0;
+ t = readtoken();
+ if (t == TEOF)
+ return NODE_EOF;
+ if (t == TNL)
+ return NULL;
+ tokpushback = 1;
return list(1);
}
@@ -12324,17 +12078,11 @@ static const char *
expandstr(const char *ps)
{
union node n;
- int saveprompt;
/* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
* and token processing _can_ alter it (delete NULs etc). */
setinputstring((char *)ps);
-
- saveprompt = doprompt;
- doprompt = 0;
readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
- doprompt = saveprompt;
-
popfile();
n.narg.type = NARG;
@@ -12342,7 +12090,7 @@ expandstr(const char *ps)
n.narg.text = wordtext;
n.narg.backquote = backquotelist;
- expandarg(&n, NULL, EXP_QUOTED);
+ expandarg(&n, NULL, 0);
return stackblock();
}
#endif
@@ -12351,61 +12099,35 @@ expandstr(const char *ps)
* Execute a command or commands contained in a string.
*/
static int
-evalstring(char *s, int flags)
+evalstring(char *s, int mask)
{
- struct jmploc *volatile savehandler;
- struct jmploc jmploc;
- int ex;
-
union node *n;
struct stackmark smark;
- int status;
+ int skip;
- s = sstrdup(s);
setinputstring(s);
setstackmark(&smark);
- status = 0;
- /* On exception inside execution loop, we must popfile().
- * Try interactively:
- * readonly a=a
- * command eval "a=b" # throws "is read only" error
- * "command BLTIN" is not supposed to abort (even in non-interactive use).
- * But if we skip popfile(), we hit EOF in eval's string, and exit.
- */
- savehandler = exception_handler;
- ex = setjmp(jmploc.loc);
- if (ex)
- goto out;
- exception_handler = &jmploc;
-
+ skip = 0;
while ((n = parsecmd(0)) != NODE_EOF) {
- int i;
-
- i = evaltree(n, flags);
- if (n)
- status = i;
+ evaltree(n, 0);
popstackmark(&smark);
- if (evalskip)
+ skip = evalskip;
+ if (skip)
break;
}
- out:
- popstackmark(&smark);
popfile();
- stunalloc(s);
-
- exception_handler = savehandler;
- if (ex)
- longjmp(exception_handler->loc, ex);
- return status;
+ skip &= mask;
+ evalskip = skip;
+ return skip;
}
/*
* The eval command.
*/
static int FAST_FUNC
-evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
+evalcmd(int argc UNUSED_PARAM, char **argv)
{
char *p;
char *concat;
@@ -12425,9 +12147,9 @@ evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
STPUTC('\0', concat);
p = grabstackstr(concat);
}
- return evalstring(p, flags & EV_TESTED);
+ evalstring(p, ~SKIPEVAL);
}
- return 0;
+ return exitstatus;
}
/*
@@ -12441,7 +12163,6 @@ cmdloop(int top)
union node *n;
struct stackmark smark;
int inter;
- int status = 0;
int numeof = 0;
TRACE(("cmdloop(%d) called\n", top));
@@ -12451,7 +12172,7 @@ cmdloop(int top)
setstackmark(&smark);
#if JOBS
if (doing_jobctl)
- showjobs(SHOW_CHANGED|SHOW_STDERR);
+ showjobs(stderr, SHOW_CHANGED);
#endif
inter = 0;
if (iflag && top) {
@@ -12473,24 +12194,20 @@ cmdloop(int top)
}
numeof++;
} else if (nflag == 0) {
- int i;
-
/* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
job_warning >>= 1;
numeof = 0;
- i = evaltree(n, 0);
- if (n)
- status = i;
+ evaltree(n, 0);
}
popstackmark(&smark);
skip = evalskip;
if (skip) {
- evalskip &= ~SKIPFUNC;
- break;
+ evalskip = 0;
+ return skip & SKIPEVAL;
}
}
- return status;
+ return 0;
}
/*
@@ -12535,38 +12252,32 @@ find_dot_file(char *name)
}
static int FAST_FUNC
-dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
+dotcmd(int argc, char **argv)
{
- /* "false; . empty_file; echo $?" should print 0, not 1: */
- int status = 0;
char *fullname;
- char **argv;
struct strlist *sp;
volatile struct shparam saveparam;
for (sp = cmdenviron; sp; sp = sp->next)
setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
- nextopt(nullstr); /* handle possible "--" */
- argv = argptr;
-
- if (!argv[0]) {
+ if (!argv[1]) {
/* bash says: "bash: .: filename argument required" */
return 2; /* bash compat */
}
+ /* "false; . empty_file; echo $?" should print 0, not 1: */
+ exitstatus = 0;
+
/* This aborts if file isn't found, which is POSIXly correct.
* bash returns exitcode 1 instead.
*/
- fullname = find_dot_file(argv[0]);
- argv++;
- if (argv[0]) { /* . FILE ARGS, ARGS exist */
- int argc;
+ fullname = find_dot_file(argv[1]);
+ argv += 2;
+ argc -= 2;
+ if (argc) { /* argc > 0, argv[0] != NULL */
saveparam = shellparam;
shellparam.malloced = 0;
- argc = 1;
- while (argv[argc])
- argc++;
shellparam.nparam = argc;
shellparam.p = argv;
};
@@ -12576,15 +12287,15 @@ dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
*/
setinputfile(fullname, INPUT_PUSH_FILE);
commandname = fullname;
- status = cmdloop(0);
+ cmdloop(0);
popfile();
- if (argv[0]) {
+ if (argc) {
freeparam(&shellparam);
shellparam = saveparam;
};
- return status;
+ return exitstatus;
}
static int FAST_FUNC
@@ -12806,6 +12517,8 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
}
+/* ============ trap.c */
+
/*
* The trap builtin.
*/
@@ -12860,13 +12573,12 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
if (action) {
if (LONE_DASH(action))
action = NULL;
- else {
- if (action[0]) /* not NULL and not "" and not "-" */
- may_have_traps = 1;
+ else
action = ckstrdup(action);
- }
}
free(trap[signo]);
+ if (action)
+ may_have_traps = 1;
trap[signo] = action;
if (signo != 0)
setsignal(signo);
@@ -12880,7 +12592,10 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
/* ============ Builtins */
-#if ENABLE_ASH_HELP
+#if !ENABLE_FEATURE_SH_EXTRA_QUIET
+/*
+ * Lists available builtins
+ */
static int FAST_FUNC
helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
@@ -12898,7 +12613,7 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
col = 0;
}
}
-# if ENABLE_FEATURE_SH_STANDALONE
+#if ENABLE_FEATURE_SH_STANDALONE
{
const char *a = applet_names;
while (*a) {
@@ -12907,15 +12622,14 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
out1fmt("\n");
col = 0;
}
- while (*a++ != '\0')
- continue;
+ a += strlen(a) + 1;
}
}
-# endif
- newline_and_flush(stdout);
+#endif
+ out1fmt("\n\n");
return EXIT_SUCCESS;
}
-#endif
+#endif /* FEATURE_SH_EXTRA_QUIET */
#if MAX_HISTORY
static int FAST_FUNC
@@ -13041,7 +12755,7 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
const unsigned char *p;
struct tms buf;
- clk_tck = bb_clk_tck();
+ clk_tck = sysconf(_SC_CLK_TCK);
times(&buf);
p = timescmd_str;
@@ -13059,7 +12773,7 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
return 0;
}
-#if ENABLE_FEATURE_SH_MATH
+#if ENABLE_SH_MATH_SUPPORT
/*
* The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
* Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
@@ -13136,7 +12850,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
* to jump out of it.
*/
INT_OFF;
- r = shell_builtin_read(setvar0,
+ r = shell_builtin_read(setvar2,
argptr,
bltinlookup("IFS"), /* can be NULL */
read_flags,
@@ -13232,10 +12946,15 @@ exitshell(void)
#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
save_history(line_input_state);
#endif
+
status = exitstatus;
TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
if (setjmp(loc.loc)) {
if (exception_type == EXEXIT)
+/* dash bug: it just does _exit(exitstatus) here
+ * but we have to do setjobctl(0) first!
+ * (bug is still not fixed in dash-0.5.3 - if you run dash
+ * under Midnight Commander, on exit from dash MC is backgrounded) */
status = exitstatus;
goto out;
}
@@ -13243,16 +12962,12 @@ exitshell(void)
p = trap[0];
if (p) {
trap[0] = NULL;
- evalskip = 0;
evalstring(p, 0);
- /*free(p); - we'll exit soon */
+ free(p);
}
+ flush_stdout_stderr();
out:
- /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
- * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
- */
setjobctl(0);
- flush_stdout_stderr();
_exit(status);
/* NOTREACHED */
}
@@ -13260,17 +12975,18 @@ exitshell(void)
static void
init(void)
{
+ /* from input.c: */
/* we will never free this */
basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
- sigmode[SIGCHLD - 1] = S_DFL;
- setsignal(SIGCHLD);
-
+ /* from trap.c: */
+ signal(SIGCHLD, SIG_DFL);
/* bash re-enables SIGHUP which is SIG_IGNed on entry.
* Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
*/
signal(SIGHUP, SIG_DFL);
+ /* from var.c: */
{
char **envp;
const char *p;
@@ -13278,30 +12994,22 @@ init(void)
initvar();
for (envp = environ; envp && *envp; envp++) {
- p = endofname(*envp);
- if (p != *envp && *p == '=') {
+ if (strchr(*envp, '=')) {
setvareq(*envp, VEXPORT|VTEXTFIXED);
}
}
- setvareq((char*)defoptindvar, VTEXTFIXED);
-
- setvar0("PPID", utoa(getppid()));
+ setvar2("PPID", utoa(getppid()));
#if ENABLE_ASH_BASH_COMPAT
p = lookupvar("SHLVL");
setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
- if (!lookupvar("HOSTNAME")) {
- struct utsname uts;
- uname(&uts);
- setvar0("HOSTNAME", uts.nodename);
- }
#endif
p = lookupvar("PWD");
if (p) {
- if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
+ if (*p != '/' || stat(p, &st1) || stat(".", &st2)
|| st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
) {
- p = NULL;
+ p = '\0';
}
}
setpwd(p, 0);
@@ -13314,6 +13022,15 @@ init(void)
//usage:#define ash_full_usage "\n\n"
//usage: "Unix shell interpreter"
+//usage:#if ENABLE_FEATURE_SH_IS_ASH
+//usage:# define sh_trivial_usage ash_trivial_usage
+//usage:# define sh_full_usage ash_full_usage
+//usage:#endif
+//usage:#if ENABLE_FEATURE_BASH_IS_ASH
+//usage:# define bash_trivial_usage ash_trivial_usage
+//usage:# define bash_full_usage ash_full_usage
+//usage:#endif
+
/*
* Process the shell command line arguments.
*/
@@ -13378,22 +13095,24 @@ procargs(char **argv)
}
/*
- * Read /etc/profile, ~/.profile, $ENV.
+ * Read /etc/profile or .profile.
*/
static void
read_profile(const char *name)
{
- name = expandstr(name);
+ int skip;
+
if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
return;
- cmdloop(0);
+ skip = cmdloop(0);
popfile();
+ if (skip)
+ exitshell();
}
/*
* This routine is called when an error or an interrupt occurs in an
* interactive shell and control is returned to the main command loop.
- * (In dash, this function is auto-generated by build machinery).
*/
static void
reset(void)
@@ -13401,18 +13120,15 @@ reset(void)
/* from eval.c: */
evalskip = 0;
loopnest = 0;
-
- /* from expand.c: */
- ifsfree();
-
/* from input.c: */
g_parsefile->left_in_buffer = 0;
g_parsefile->left_in_line = 0; /* clear input buffer */
popallfiles();
-
+ /* from parser.c: */
+ tokpushback = 0;
+ checkkwd = 0;
/* from redir.c: */
- while (redirlist)
- popredir(/*drop:*/ 0, /*restore:*/ 0);
+ clearredir(/*drop:*/ 0);
}
#if PROFILE
@@ -13430,6 +13146,7 @@ extern int etext();
int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int ash_main(int argc UNUSED_PARAM, char **argv)
{
+ const char *shinit;
volatile smallint state;
struct jmploc jmploc;
struct stackmark smark;
@@ -13458,12 +13175,14 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
reset();
e = exception_type;
+ if (e == EXERROR)
+ exitstatus = 2;
s = state;
if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
exitshell();
}
if (e == EXINT) {
- newline_and_flush(stderr);
+ outcslow('\n', stderr);
}
popstackmark(&smark);
@@ -13477,15 +13196,16 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
goto state4;
}
exception_handler = &jmploc;
+#if DEBUG
+ opentrace();
+ TRACE(("Shell args: "));
+ trace_puts_args(argv);
+#endif
rootpid = getpid();
init();
setstackmark(&smark);
procargs(argv);
-#if DEBUG
- TRACE(("Shell args: "));
- trace_puts_args(argv);
-#endif
if (argv[0] && argv[0][0] == '-')
isloginsh = 1;
@@ -13497,8 +13217,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
state1:
state = 2;
hp = lookupvar("HOME");
- if (hp)
- read_profile("$HOME/.profile");
+ if (hp) {
+ hp = concat_path_file(hp, ".profile");
+ read_profile(hp);
+ free((char*)hp);
+ }
}
state2:
state = 3;
@@ -13508,11 +13231,11 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
#endif
iflag
) {
- const char *shinit = lookupvar("ENV");
- if (shinit != NULL && *shinit != '\0')
+ shinit = lookupvar("ENV");
+ if (shinit != NULL && *shinit != '\0') {
read_profile(shinit);
+ }
}
- popstackmark(&smark);
state3:
state = 4;
if (minusc) {
@@ -13534,7 +13257,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
hp = lookupvar("HOME");
if (hp) {
hp = concat_path_file(hp, ".ash_history");
- setvar0("HISTFILE", hp);
+ setvar2("HISTFILE", hp);
free((char*)hp);
hp = lookupvar("HISTFILE");
}
diff --git a/shell/hush.c b/shell/hush.c
index a56d3b2..4ec2d0a 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -2809,7 +2809,7 @@ static int glob_brace(char *pattern, o_string *o, int n)
return o_save_ptr_helper(o, n);
}
if (gr == GLOB_NOSPACE)
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
/* GLOB_ABORTED? Only happens with GLOB_ERR flag,
* but we didn't specify it. Paranoia again. */
bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
@@ -2911,7 +2911,7 @@ static int perform_glob(o_string *o, int n)
goto literal;
}
if (gr == GLOB_NOSPACE)
- bb_error_msg_and_die(bb_msg_memory_exhausted);
+ bb_error_msg_and_die("%s", bb_msg_memory_exhausted);
/* GLOB_ABORTED? Only happens with GLOB_ERR flag,
* but we didn't specify it. Paranoia again. */
bb_error_msg_and_die("glob error %d on '%s'", gr, pattern);
diff --git a/testsuite/date/date-works-1 b/testsuite/date/date-works-1
index 4f53939..6b2421e 100644
--- a/testsuite/date/date-works-1
+++ b/testsuite/date/date-works-1
@@ -9,7 +9,7 @@ test x"$dt" = x"01:02:00"
dt=`busybox date -d 1:2:3 +%T`
test x"$dt" = x"01:02:03"
-host_date=/bin/date
+host_date=/system/bin/date
# date (GNU coreutils) 6.10 reports:
# date: invalid date '1.2-3:4'
diff --git a/testsuite/du/du-s-works b/testsuite/du/du-s-works
index 534432c..adec894 100644
--- a/testsuite/du/du-s-works
+++ b/testsuite/du/du-s-works
@@ -1,6 +1,6 @@
# FEATURE: CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
-d=/bin
+d=/system/bin
du -s "$d" > logfile.gnu
busybox du -s "$d" > logfile.bb
cmp logfile.gnu logfile.bb && exit 0
diff --git a/testsuite/du/du-works b/testsuite/du/du-works
index e320f1d..cac86c1 100644
--- a/testsuite/du/du-works
+++ b/testsuite/du/du-works
@@ -1,6 +1,6 @@
# FEATURE: CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
-d=/bin
+d=/system/bin
du "$d" > logfile.gnu
busybox du "$d" > logfile.bb
cmp logfile.gnu logfile.bb && exit 0
diff --git a/testsuite/testing.sh b/testsuite/testing.sh
index f5b7569..ccfebc8 100644
--- a/testsuite/testing.sh
+++ b/testsuite/testing.sh
@@ -36,6 +36,13 @@
export FAILCOUNT=0
export SKIP=
+# Android Specific
+
+if [ ! -x /bin ]; then
+ mount -o remount,rw /
+ ln -s /system/xbin /bin
+fi
+
# Helper for helpers. Oh my...
test x"$ECHO" != x"" || {
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
index b988e65..6593137 100644
--- a/util-linux/fdisk.c
+++ b/util-linux/fdisk.c
@@ -866,7 +866,7 @@ read_pte(struct pte *pe, sector_t offset)
pe->sectorbuffer = xzalloc(sector_size);
seek_sector(offset);
/* xread would make us abort - bad for fdisk -l */
- if (full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
+ if ((unsigned) full_read(dev_fd, pe->sectorbuffer, sector_size) != sector_size)
fdisk_fatal(unable_to_read);
#if ENABLE_FEATURE_FDISK_WRITABLE
pe->changed = 0;
@@ -2044,7 +2044,7 @@ wrong_p_order(int *prev)
const struct pte *pe;
const struct partition *p;
sector_t last_p_start_pos = 0, p_start_pos;
- unsigned i, last_i = 0;
+ int i, last_i = 0;
for (i = 0; i < g_partitions; i++) {
if (i == 4) {
@@ -2314,7 +2314,7 @@ x_list_table(int extend)
static void
fill_bounds(sector_t *first, sector_t *last)
{
- unsigned i;
+ int i;
const struct pte *pe = &ptes[0];
const struct partition *p;
@@ -2473,7 +2473,7 @@ add_partition(int n, int sys)
do {
temp = start;
for (i = 0; i < g_partitions; i++) {
- int lastplusoff;
+ sector_t lastplusoff;
if (start == ptes[i].offset_from_dev_start)
start += sector_offset;
@@ -2713,7 +2713,8 @@ write_table(void)
static void
print_buffer(char *pbuffer)
{
- int i,l;
+ unsigned i;
+ int l;
for (i = 0, l = 0; i < sector_size; i++, l++) {
if (l == 0)
diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c
index 45d2aa6..8337bfe 100644
--- a/util-linux/fdisk_gpt.c
+++ b/util-linux/fdisk_gpt.c
@@ -46,7 +46,7 @@ static unsigned int n_parts;
static unsigned int part_entry_len;
static inline gpt_partition *
-gpt_part(int i)
+gpt_part(unsigned i)
{
if (i >= n_parts) {
return NULL;
@@ -105,7 +105,7 @@ gpt_print_wide36(uint16_t *s)
static void
gpt_list_table(int xtra UNUSED_PARAM)
{
- int i;
+ unsigned i;
char numstr6[6];
smart_ulltoa5(total_number_of_sectors * sector_size, numstr6, " KMGTPEZY")[0] = '\0';
@@ -201,7 +201,7 @@ check_gpt_label(void)
part_array_len = n_parts * part_entry_len;
part_array = xmalloc(part_array_len);
seek_sector(SWAP_LE64(gpt_hdr->first_part_lba));
- if (full_read(dev_fd, part_array, part_array_len) != part_array_len) {
+ if (full_read(dev_fd, part_array, part_array_len) != (ssize_t) part_array_len) {
fdisk_fatal(unable_to_read);
}
diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c
index 5816a20..68dce5f 100644
--- a/util-linux/mkfs_ext2.c
+++ b/util-linux/mkfs_ext2.c
@@ -78,7 +78,7 @@
#define EXT2_FLAGS_UNSIGNED_HASH 0x0002
// storage helpers
-char BUG_wrong_field_size(void);
+unsigned char BUG_wrong_field_size(void);
#define STORE_LE(field, value) \
do { \
if (sizeof(field) == 4) \
@@ -155,7 +155,7 @@ static uint32_t has_super(uint32_t x)
117649, 177147, 390625, 531441, 823543, 1594323, 1953125,
4782969, 5764801, 9765625, 14348907, 40353607, 43046721,
48828125, 129140163, 244140625, 282475249, 387420489,
- 1162261467, 1220703125, 1977326743, 3486784401/* >2^31 */,
+ 0x4546B3DB, 0x48C27395, 0x75DB9C97, 0xCFD41B91/* >2^31 */,
};
const uint32_t *sp = supers + ARRAY_SIZE(supers);
while (1) {
@@ -331,7 +331,7 @@ int mkfs_ext2_main(int argc UNUSED_PARAM, char **argv)
}
}
- if ((int32_t)bytes_per_inode < blocksize)
+ if ((uint32_t) bytes_per_inode < (uint32_t) blocksize)
bb_error_msg_and_die("-%c is bad", 'i');
// number of bits in one block, i.e. 8*blocksize
#define blocks_per_group (8 * blocksize)
diff --git a/util-linux/more.c b/util-linux/more.c
index 934b30f..31e27ab 100644
--- a/util-linux/more.c
+++ b/util-linux/more.c
@@ -72,15 +72,14 @@ static void gotsig(int sig UNUSED_PARAM)
int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int more_main(int argc UNUSED_PARAM, char **argv)
{
- int c = c; /* for compiler */
- int lines;
+ int c = EOF; /* for compiler */
int input = 0;
int spaces = 0;
int please_display_more_prompt;
struct stat st;
FILE *file;
FILE *cin;
- int len;
+ unsigned len, lines;
unsigned terminal_width;
unsigned terminal_height;
@@ -144,11 +143,8 @@ int more_main(int argc UNUSED_PARAM, char **argv)
if (input != 'r' && please_display_more_prompt) {
len = printf("--More-- ");
if (st.st_size != 0) {
- uoff_t d = (uoff_t)st.st_size / 100;
- if (d == 0)
- d = 1;
- len += printf("(%u%% of %"OFF_FMT"u bytes)",
- (int) ((uoff_t)ftello(file) / d),
+ len += printf("(%u%% of %"FILESIZE_FMT"u bytes)",
+ (int) (ftello(file)*100 / st.st_size),
st.st_size);
}
fflush_all();
diff --git a/util-linux/mount.c b/util-linux/mount.c
index 42962b8..4e4e154 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -188,6 +188,8 @@
#include <mntent.h>
#include <syslog.h>
#include <sys/mount.h>
+#include <android.h>
+
// Grab more as needed from util-linux's mount/mount_constants.h
#ifndef MS_DIRSYNC
# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous
@@ -737,7 +739,7 @@ static int mount_it_now(struct mntent *mp, unsigned long vfsflags, char *filtero
// Abort entirely if permission denied.
if (rc && errno == EPERM)
- bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
+ bb_error_msg_and_die("%s", bb_msg_perm_denied_are_you_root);
// If the mount was successful, and we're maintaining an old-style
// mtab file by hand, add the new entry to it now.
@@ -1033,7 +1035,7 @@ static char *nfs_strerror(int status)
{
int i;
- for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
+ for (i = 0; i < (int) ARRAY_SIZE(nfs_err_stat); i++) {
if (nfs_err_stat[i] == status)
return strerror(nfs_err_errnum[i]);
}
@@ -2028,7 +2030,7 @@ static int singlemount(struct mntent *mp, int ignore_busy)
mp->mnt_fsname = NULL; // will receive malloced loop dev name
if (set_loop(&mp->mnt_fsname, loopFile, 0, /*ro:*/ (vfsflags & MS_RDONLY)) < 0) {
if (errno == EPERM || errno == EACCES)
- bb_error_msg(bb_msg_perm_denied_are_you_root);
+ bb_error_msg("%s", bb_msg_perm_denied_are_you_root);
else
bb_perror_msg("can't setup loop device");
return errno;
@@ -2227,7 +2229,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
// argument when we get it.
if (argv[1]) {
if (nonroot)
- bb_error_msg_and_die(bb_msg_you_must_be_root);
+ bb_error_msg_and_die("%s", bb_msg_you_must_be_root);
mtpair->mnt_fsname = argv[0];
mtpair->mnt_dir = argv[1];
mtpair->mnt_type = fstype;
@@ -2244,7 +2246,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
cmdopt_flags = parse_mount_options(cmdopts, NULL);
if (nonroot && (cmdopt_flags & ~MS_SILENT)) // Non-root users cannot specify flags
- bb_error_msg_and_die(bb_msg_you_must_be_root);
+ bb_error_msg_and_die("%s", bb_msg_you_must_be_root);
// If we have a shared subtree flag, don't worry about fstab or mtab.
if (ENABLE_FEATURE_MOUNT_FLAGS
@@ -2309,7 +2311,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
// No, mount -a won't mount anything,
// even user mounts, for mere humans
if (nonroot)
- bb_error_msg_and_die(bb_msg_you_must_be_root);
+ bb_error_msg_and_die("%s", bb_msg_you_must_be_root);
// Does type match? (NULL matches always)
if (!match_fstype(mtcur, fstype))
@@ -2389,7 +2391,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv)
// fstab must have "users" or "user"
l = parse_mount_options(mtcur->mnt_opts, NULL);
if (!(l & MOUNT_USERS))
- bb_error_msg_and_die(bb_msg_you_must_be_root);
+ bb_error_msg_and_die("%s", bb_msg_you_must_be_root);
}
//util-linux-2.12 does not do this check.
diff --git a/util-linux/nsenter.c b/util-linux/nsenter.c
index 6834292..e4ade5d 100644
--- a/util-linux/nsenter.c
+++ b/util-linux/nsenter.c
@@ -240,12 +240,12 @@ int nsenter_main(int argc UNUSED_PARAM, char **argv)
if (ns_ctx->fd < 0)
continue;
- if (setns(ns_ctx->fd, ns->flag)) {
+ /*if (setns(ns_ctx->fd, ns->flag)) {
bb_perror_msg_and_die(
"setns(): can't reassociate to namespace '%s'",
- ns->ns_nsfile8 + 3 /* skip over "ns/" */
+ ns->ns_nsfile8 + 3
);
- }
+ }*/
close(ns_ctx->fd); /* should close fds, to not confuse exec'ed PROG */
/*ns_ctx->fd = -1;*/
}
diff --git a/util-linux/rdate.c b/util-linux/rdate.c
index 8dd784d..51d5eb6 100644
--- a/util-linux/rdate.c
+++ b/util-linux/rdate.c
@@ -28,6 +28,8 @@
//usage: "\n -p Print time"
#include "libbb.h"
+#include <android.h>
+
enum { RFC_868_BIAS = 2208988800UL };
diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c
index b8f4e94..2a9b74d 100644
--- a/util-linux/swaponoff.c
+++ b/util-linux/swaponoff.c
@@ -70,6 +70,7 @@
#include "libbb.h"
#include "common_bufsiz.h"
#include <mntent.h>
+#include <android.h>
#ifndef __BIONIC__
# include <sys/swap.h>
#endif
diff --git a/util-linux/umount.c b/util-linux/umount.c
index 78eef57..9b8d48e 100644
--- a/util-linux/umount.c
+++ b/util-linux/umount.c
@@ -42,7 +42,7 @@
//usage: "\n -l Lazy umount (detach filesystem)"
//usage: "\n -f Force umount (i.e., unreachable NFS server)"
//usage: IF_FEATURE_MOUNT_LOOP(
-//usage: "\n -D Don't free loop device even if it has been used"
+//usage: "\n -d Free loop device even if it has been used"
//usage: )
//usage:
//usage:#define umount_example_usage
@@ -79,8 +79,8 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
#define OPTION_STRING "fldDnra" "vt:i"
#define OPT_FORCE (1 << 0) // Same as MNT_FORCE
#define OPT_LAZY (1 << 1) // Same as MNT_DETACH
-//#define OPT_FREE_LOOP (1 << 2) // -d is assumed always present
-#define OPT_DONT_FREE_LOOP (1 << 3)
+#define OPT_FREELOOP (1 << 2)
+//#define OPT_DONT_FREE_LOOP (1 << 3) // Default behavior
#define OPT_NO_MTAB (1 << 4)
#define OPT_REMOUNT (1 << 5)
#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? (1 << 6) : 0)
@@ -206,7 +206,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv)
} else {
// De-allocate the loop device. This ioctl should be ignored on
// any non-loop block devices.
- if (ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONT_FREE_LOOP) && m)
+ if (ENABLE_FEATURE_MOUNT_LOOP && (opt & OPT_FREELOOP) && m)
del_loop(m->device);
if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
erase_mtab(m->dir);
diff --git a/util-linux/unshare.c b/util-linux/unshare.c
index bbabeef..bc32803 100644
--- a/util-linux/unshare.c
+++ b/util-linux/unshare.c
@@ -304,8 +304,8 @@ int unshare_main(int argc UNUSED_PARAM, char **argv)
/* Parent continues */
}
- if (unshare(unsflags) != 0)
- bb_perror_msg_and_die("unshare(0x%x)", unsflags);
+ //if (unshare(unsflags) != 0)
+ // bb_perror_msg_and_die("unshare(0x%x)", unsflags);
if (fdp.wr >= 0) {
close(fdp.wr); /* Release child */
diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c
index b64d28c..3789de4 100644
--- a/util-linux/volume_id/get_devname.c
+++ b/util-linux/volume_id/get_devname.c
@@ -250,10 +250,10 @@ void display_uuid_cache(int scan_devices)
int add_to_uuid_cache(const char *device)
{
- char *uuid = uuid; /* for compiler */
- char *label = label;
+ static char *uuid; /* for compiler */
+ static char *label;
#if ENABLE_FEATURE_BLKID_TYPE
- const char *type = type;
+ static const char *type;
#endif
int fd;
diff --git a/util-linux/volume_id/util.c b/util-linux/volume_id/util.c
index 061545f..9da5076 100644
--- a/util-linux/volume_id/util.c
+++ b/util-linux/volume_id/util.c
@@ -228,12 +228,12 @@ void *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
dbg("read seekbuf off:0x%llx len:0x%zx",
(unsigned long long) off, len);
do_read:
- if (lseek(id->fd, off, SEEK_SET) != off) {
+ if (lseek(id->fd, off, SEEK_SET) != (int64_t) off) {
dbg("seek(0x%llx) failed", (unsigned long long) off);
goto err;
}
read_len = full_read(id->fd, dst, len);
- if (read_len != len) {
+ if (read_len != (ssize_t) len) {
dbg("requested 0x%x bytes, got 0x%x bytes",
(unsigned) len, (unsigned) read_len);
err:
diff --git a/util-linux/volume_id/volume_id.c b/util-linux/volume_id/volume_id.c
index 5bb9599..fef7d53 100644
--- a/util-linux/volume_id/volume_id.c
+++ b/util-linux/volume_id/volume_id.c
@@ -175,11 +175,12 @@ static const probe_fptr fs2[] = {
int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64_t size)
{
- unsigned i;
+ unsigned i, arsize;
/* probe for raid first, cause fs probes may be successful on raid members */
if (size) {
- for (i = 0; i < ARRAY_SIZE(raid1); i++) {
+ arsize=ARRAY_SIZE(raid1);
+ for (i = 0; i < arsize; i++) {
if (raid1[i](id, /*off,*/ size) == 0)
goto ret;
if (id->error)
@@ -187,7 +188,8 @@ int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64
}
}
- for (i = 0; i < ARRAY_SIZE(raid2); i++) {
+ arsize=ARRAY_SIZE(raid2);
+ for (i = 0; i < arsize; i++) {
if (raid2[i](id /*,off*/) == 0)
goto ret;
if (id->error)
@@ -195,25 +197,29 @@ int FAST_FUNC volume_id_probe_all(struct volume_id *id, /*uint64_t off,*/ uint64
}
/* signature in the first block, only small buffer needed */
- for (i = 0; i < ARRAY_SIZE(fs1); i++) {
+ arsize=ARRAY_SIZE(fs1);
+ for (i = 0; i < arsize; i++) {
if (fs1[i](id /*,off*/) == 0)
goto ret;
if (id->error)
goto ret;
}
+
/* fill buffer with maximum */
volume_id_get_buffer(id, 0, SB_BUFFER_SIZE);
- for (i = 0; i < ARRAY_SIZE(fs2); i++) {
+ arsize=ARRAY_SIZE(fs2);
+ for (i = 0; i < arsize; i++) {
if (fs2[i](id /*,off*/) == 0)
- goto ret;
+ break;
if (id->error)
- goto ret;
+ break;
}
- ret:
volume_id_free_buffer(id);
+
+ret:
return (- id->error); /* 0 or -1 */
}