222 files changed, 28253 insertions, 2190 deletions
@@ -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 @@ -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, ®s->pm_prog) && + xdr_u_long (xdrs, ®s->pm_vers) && + xdr_u_long (xdrs, ®s->pm_prot)) + return xdr_u_long (xdrs, ®s->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 (®_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 ? ®s : (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(¤t_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, "ed); + 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 = ≈ 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) "ef; + (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 */ } |