diff --git a/patches/openwrt/hack/0001-busybox-Provide-static-busybox-build.patch b/patches/openwrt/hack/0001-busybox-Provide-static-busybox-build.patch index fcdc064f05815b44ec303da8dd16ec16ce4f8630..c23b88d6eb15429ba5971b5a4f89f1a58e29a5e1 100644 --- a/patches/openwrt/hack/0001-busybox-Provide-static-busybox-build.patch +++ b/patches/openwrt/hack/0001-busybox-Provide-static-busybox-build.patch @@ -1,4 +1,4 @@ -From e9f0f3abcd314708048b784c927209987d697e5e Mon Sep 17 00:00:00 2001 +From 841ee10970e1951bb3af23c149edd18cfe0e77c4 Mon Sep 17 00:00:00 2001 From: Michal Hrusecky <Michal@Hrusecky.net> Date: Thu, 22 Feb 2018 14:46:46 +0100 Subject: [PATCH] busybox: Provide static busybox build @@ -7,16 +7,14 @@ Can be handy, but currently it is quite hacky. Signed-off-by: Michal Hrusecky <Michal@Hrusecky.net> --- - package/utils/busybox/Makefile | 38 + - package/utils/busybox/files/busybox-static.config | 1127 +++++++++++++++++++++ - 2 files changed, 1165 insertions(+) - create mode 100644 package/utils/busybox/files/busybox-static.config + package/utils/busybox/Makefile | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) diff --git a/package/utils/busybox/Makefile b/package/utils/busybox/Makefile -index 4f85cc9..fc882d3 100644 +index 315dd42..1965658 100644 --- a/package/utils/busybox/Makefile +++ b/package/utils/busybox/Makefile -@@ -67,6 +67,20 @@ define Package/busybox/description +@@ -66,6 +66,20 @@ define Package/busybox/description It slices, it dices, it makes Julian Fries. endef @@ -37,8 +35,8 @@ index 4f85cc9..fc882d3 100644 define Package/busybox/config source "$(SOURCE)/Config.in" endef -@@ -98,8 +112,21 @@ MAKE_INSTALL_FLAGS += CONFIG_PREFIX="$(PKG_INSTALL_DIR)" - +@@ -101,11 +115,20 @@ ifneq ($(findstring c,$(OPENWRT_VERBOSE)),) + endif define Build/Configure + cp ./files/busybox-static.config $(PKG_BUILD_DIR)/.config @@ -48,18 +46,17 @@ index 4f85cc9..fc882d3 100644 grep 'CONFIG_BUSYBOX_$(BUSYBOX_SYM)' $(TOPDIR)/.config | sed -e "s,\\(# \)\\?CONFIG_BUSYBOX_$(BUSYBOX_SYM)_\\(.*\\),\\1CONFIG_\\2,g" > $(PKG_BUILD_DIR)/.config yes 'n' | $(MAKE) -C $(PKG_BUILD_DIR) $(MAKE_FLAGS) oldconfig + mv $(PKG_BUILD_DIR)/.config $(PKG_BUILD_DIR)/.config-regular -+endef -+ -+define Build/Compile + endef + + define Build/Compile + cp $(PKG_BUILD_DIR)/.config-static $(PKG_BUILD_DIR)/.config + $(call Build/Compile/Default) + cp $(PKG_BUILD_DIR)/busybox $(PKG_BUILD_DIR)/busybox-static + cp $(PKG_BUILD_DIR)/.config-regular $(PKG_BUILD_DIR)/.config -+ $(call Build/Compile/Default) - endef - - define Package/busybox/install -@@ -115,4 +142,15 @@ endif + $(call Build/Compile/Default, \ + CONFIG_PREFIX="$(PKG_INSTALL_DIR)" \ + all install \ +@@ -125,4 +148,15 @@ endif -rm -rf $(1)/lib64 endef @@ -75,1139 +72,6 @@ index 4f85cc9..fc882d3 100644 + $(eval $(call BuildPackage,busybox)) +$(eval $(call BuildPackage,busybox-static)) -diff --git a/package/utils/busybox/files/busybox-static.config b/package/utils/busybox/files/busybox-static.config -new file mode 100644 -index 0000000..c059272 ---- /dev/null -+++ b/package/utils/busybox/files/busybox-static.config -@@ -0,0 +1,1127 @@ -+# -+# Automatically generated make config: don't edit -+# Busybox version: 1.27.2 -+# Fri Feb 23 14:47:40 2018 -+# -+CONFIG_HAVE_DOT_CONFIG=y -+ -+# -+# Busybox Settings -+# -+# CONFIG_DESKTOP is not set -+# CONFIG_EXTRA_COMPAT is not set -+# CONFIG_FEDORA_COMPAT is not set -+CONFIG_INCLUDE_SUSv2=y -+# CONFIG_USE_PORTABLE_CODE is not set -+CONFIG_SHOW_USAGE=y -+CONFIG_FEATURE_VERBOSE_USAGE=y -+CONFIG_FEATURE_COMPRESS_USAGE=y -+CONFIG_BUSYBOX=y -+# CONFIG_FEATURE_INSTALLER is not set -+# CONFIG_INSTALL_NO_USR is not set -+# 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=y -+CONFIG_PID_FILE_PATH="/var/run" -+CONFIG_FEATURE_SUID=y -+# CONFIG_FEATURE_SUID_CONFIG is not set -+# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set -+# CONFIG_SELINUX is not set -+CONFIG_FEATURE_PREFER_APPLETS=y -+CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" -+# CONFIG_FEATURE_SYSLOG is not set -+# CONFIG_FEATURE_HAVE_RPC is not set -+CONFIG_PLATFORM_LINUX=y -+ -+# -+# Build Options -+# -+CONFIG_STATIC=y -+# 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=y -+CONFIG_CROSS_COMPILER_PREFIX="" -+CONFIG_SYSROOT="" -+CONFIG_EXTRA_CFLAGS="" -+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 is not set -+# CONFIG_FEATURE_BUFFERS_USE_MALLOC is not set -+CONFIG_FEATURE_BUFFERS_GO_ON_STACK=y -+# 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=y -+# CONFIG_FEATURE_ETC_NETWORKS is not set -+CONFIG_FEATURE_EDITING=y -+CONFIG_FEATURE_EDITING_MAX_LEN=512 -+# CONFIG_FEATURE_EDITING_VI is not set -+CONFIG_FEATURE_EDITING_HISTORY=256 -+# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set -+# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set -+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_LOCALE_SUPPORT is not set -+# CONFIG_UNICODE_SUPPORT is not set -+# CONFIG_UNICODE_USING_LOCALE is not set -+# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set -+CONFIG_SUBST_WCHAR=0 -+CONFIG_LAST_SUPPORTED_WCHAR=0 -+# 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 is not set -+CONFIG_FEATURE_COPYBUF_KB=4 -+# CONFIG_FEATURE_SKIP_ROOTFS is not set -+# CONFIG_MONOTONIC_SYSCALL is not set -+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_ZCAT=y -+CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y -+CONFIG_BUNZIP2=y -+CONFIG_BZCAT=y -+# CONFIG_UNLZMA is not set -+CONFIG_LZCAT=y -+# CONFIG_LZMA is not set -+# CONFIG_FEATURE_LZMA_FAST is not set -+# CONFIG_UNXZ is not set -+CONFIG_XZCAT=y -+# CONFIG_XZ is not set -+# CONFIG_BZIP2 is not set -+CONFIG_FEATURE_BZIP2_DECOMPRESS=y -+# CONFIG_CPIO is not set -+# CONFIG_FEATURE_CPIO_O is not set -+# CONFIG_FEATURE_CPIO_P is not set -+# CONFIG_DPKG is not set -+# CONFIG_DPKG_DEB is not set -+CONFIG_GZIP=y -+# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set -+CONFIG_GZIP_FAST=0 -+# CONFIG_FEATURE_GZIP_LEVELS is not set -+CONFIG_FEATURE_GZIP_DECOMPRESS=y -+# CONFIG_LZOP is not set -+# CONFIG_UNLZOP is not set -+# CONFIG_LZOPCAT is not set -+# CONFIG_LZOP_COMPR_HIGH is not set -+# CONFIG_RPM2CPIO is not set -+# CONFIG_RPM is not set -+CONFIG_TAR=y -+# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set -+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_TO_COMMAND is not set -+# CONFIG_FEATURE_TAR_UNAME_GNAME is not set -+# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set -+# CONFIG_FEATURE_TAR_SELINUX is not set -+# CONFIG_UNZIP is not set -+# CONFIG_FEATURE_UNZIP_CDF is not set -+# CONFIG_FEATURE_UNZIP_BZIP2 is not set -+# CONFIG_FEATURE_UNZIP_LZMA is not set -+# CONFIG_FEATURE_UNZIP_XZ is not set -+ -+# -+# Coreutils -+# -+CONFIG_BASENAME=y -+CONFIG_CAT=y -+CONFIG_FEATURE_CATV=y -+CONFIG_CHGRP=y -+CONFIG_CHMOD=y -+CONFIG_CHOWN=y -+# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set -+CONFIG_CHROOT=y -+# CONFIG_CKSUM is not set -+# CONFIG_COMM is not set -+CONFIG_CP=y -+# CONFIG_FEATURE_CP_LONG_OPTIONS is not set -+CONFIG_CUT=y -+CONFIG_DATE=y -+CONFIG_FEATURE_DATE_ISOFMT=y -+# CONFIG_FEATURE_DATE_NANO is not set -+# CONFIG_FEATURE_DATE_COMPAT is not set -+CONFIG_DD=y -+CONFIG_FEATURE_DD_SIGNAL_HANDLING=y -+# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set -+CONFIG_FEATURE_DD_IBS_OBS=y -+# CONFIG_FEATURE_DD_STATUS is not set -+CONFIG_DF=y -+# CONFIG_FEATURE_DF_FANCY is not set -+CONFIG_DIRNAME=y -+# CONFIG_DOS2UNIX is not set -+# CONFIG_UNIX2DOS is not set -+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 is not set -+# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set -+# CONFIG_UNEXPAND is not set -+# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set -+CONFIG_EXPR=y -+CONFIG_EXPR_MATH_SUPPORT_64=y -+CONFIG_FACTOR=y -+CONFIG_FALSE=y -+# CONFIG_FOLD is not set -+# CONFIG_FSYNC is not set -+CONFIG_HEAD=y -+CONFIG_FEATURE_FANCY_HEAD=y -+# CONFIG_HOSTID is not set -+CONFIG_ID=y -+# CONFIG_GROUPS is not set -+CONFIG_INSTALL=y -+CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y -+CONFIG_LINK=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_WIDTH=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=y -+CONFIG_MD5SUM=y -+# CONFIG_SHA1SUM is not set -+CONFIG_SHA256SUM=y -+CONFIG_SHA512SUM=y -+# CONFIG_SHA3SUM is not set -+ -+# -+# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum -+# -+CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y -+CONFIG_MKDIR=y -+# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set -+# CONFIG_MKFIFO is not set -+# CONFIG_MKNOD is not set -+# CONFIG_MKTEMP is not set -+CONFIG_MV=y -+# CONFIG_FEATURE_MV_LONG_OPTIONS is not set -+# CONFIG_NICE is not set -+CONFIG_NL=y -+# CONFIG_NOHUP is not set -+CONFIG_NPROC=y -+# CONFIG_OD is not set -+CONFIG_PASTE=y -+# CONFIG_PRINTENV is not set -+CONFIG_PRINTF=y -+CONFIG_PWD=y -+CONFIG_READLINK=y -+CONFIG_FEATURE_READLINK_FOLLOW=y -+# CONFIG_REALPATH is not set -+CONFIG_RM=y -+CONFIG_RMDIR=y -+# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set -+CONFIG_SEQ=y -+CONFIG_SHRED=y -+# CONFIG_SHUF 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 is not set -+# CONFIG_FEATURE_SPLIT_FANCY is not set -+# CONFIG_STAT is not set -+# CONFIG_FEATURE_STAT_FORMAT is not set -+# CONFIG_FEATURE_STAT_FILESYSTEM is not set -+CONFIG_STTY=y -+# CONFIG_SUM is not set -+CONFIG_SYNC=y -+# CONFIG_FEATURE_SYNC_FANCY is not set -+# CONFIG_TAC is not set -+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=y -+# CONFIG_TIMEOUT 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 is not set -+# 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 is not set -+# CONFIG_USLEEP is not set -+# CONFIG_UUDECODE is not set -+# CONFIG_BASE64 is not set -+# CONFIG_UUENCODE is not set -+CONFIG_WC=y -+# CONFIG_FEATURE_WC_LARGE is not set -+# CONFIG_WHOAMI is not set -+# CONFIG_WHO is not set -+# CONFIG_W is not set -+# CONFIG_USERS is not set -+CONFIG_YES=y -+ -+# -+# Common options -+# -+# CONFIG_FEATURE_VERBOSE is not set -+ -+# -+# Common options for cp and mv -+# -+CONFIG_FEATURE_PRESERVE_HARDLINKS=y -+ -+# -+# Common options for df, du, ls -+# -+# CONFIG_FEATURE_HUMAN_READABLE is not set -+ -+# -+# Console Utilities -+# -+# CONFIG_CHVT is not set -+# CONFIG_CLEAR is not set -+# CONFIG_DEALLOCVT is not set -+# CONFIG_DUMPKMAP is not set -+# CONFIG_FGCONSOLE is not set -+# 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 is not set -+# CONFIG_RESET is not set -+# CONFIG_RESIZE is not set -+# CONFIG_FEATURE_RESIZE_PRINT is not set -+# CONFIG_SETCONSOLE is not set -+# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set -+# CONFIG_SETKEYCODES is not set -+# CONFIG_SETLOGCONS is not set -+# CONFIG_SHOWKEY is not set -+ -+# -+# Debian Utilities -+# -+# CONFIG_PIPE_PROGRESS is not set -+# CONFIG_RUN_PARTS is not set -+# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set -+# CONFIG_FEATURE_RUN_PARTS_FANCY is not set -+# CONFIG_START_STOP_DAEMON is not set -+# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set -+# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set -+CONFIG_WHICH=y -+ -+# -+# Editors -+# -+# CONFIG_AWK is not set -+# CONFIG_FEATURE_AWK_LIBM is not set -+# CONFIG_FEATURE_AWK_GNU_EXTENSIONS is not set -+CONFIG_CMP=y -+# CONFIG_DIFF is not set -+# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set -+# CONFIG_FEATURE_DIFF_DIR is not set -+# CONFIG_ED is not set -+# CONFIG_PATCH is not set -+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_VI_UNDO is not set -+# CONFIG_FEATURE_VI_UNDO_QUEUE is not set -+CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=0 -+# CONFIG_FEATURE_ALLOW_EXEC is not set -+ -+# -+# Finding Utilities -+# -+CONFIG_FIND=y -+CONFIG_FEATURE_FIND_PRINT0=y -+CONFIG_FEATURE_FIND_MTIME=y -+# CONFIG_FEATURE_FIND_MMIN is not set -+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_EXEC_PLUS is not set -+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_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 is not set -+ -+# -+# 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_POWEROFF=y -+CONFIG_REBOOT=y -+# CONFIG_FEATURE_CALL_TELINIT is not set -+CONFIG_TELINIT_PATH="" -+# CONFIG_INIT is not set -+# CONFIG_LINUXRC 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_INIT_QUIET is not set -+# CONFIG_FEATURE_INIT_COREDUMPS is not set -+CONFIG_INIT_TERMINAL_TYPE="" -+# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set -+ -+# -+# Login/Password Management Utilities -+# -+CONFIG_FEATURE_SHADOWPASSWDS=y -+# CONFIG_USE_BB_PWD_GRP is not set -+# CONFIG_USE_BB_SHADOW is not set -+# CONFIG_USE_BB_CRYPT is not set -+# CONFIG_USE_BB_CRYPT_SHA 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_ADD_SHELL is not set -+# CONFIG_REMOVE_SHELL is not set -+CONFIG_ADDUSER=y -+CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y -+CONFIG_FEATURE_CHECK_NAMES=y -+CONFIG_LAST_ID=60000 -+CONFIG_FIRST_SYSTEM_ID=100 -+CONFIG_LAST_SYSTEM_ID=999 -+# CONFIG_CHPASSWD is not set -+CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="" -+# CONFIG_CRYPTPW is not set -+# CONFIG_MKPASSWD 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_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_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set -+# CONFIG_SULOGIN is not set -+# CONFIG_VLOCK is not set -+ -+# -+# Linux Ext2 FS Progs -+# -+# CONFIG_CHATTR is not set -+# CONFIG_FSCK is not set -+# CONFIG_LSATTR is not set -+# CONFIG_TUNE2FS is not set -+ -+# -+# Linux Module Utilities -+# -+# CONFIG_MODPROBE_SMALL is not set -+# CONFIG_DEPMOD is not set -+# CONFIG_INSMOD is not set -+# CONFIG_LSMOD is not set -+# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set -+# CONFIG_MODINFO is not set -+# CONFIG_MODPROBE is not set -+# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set -+# CONFIG_RMMOD is not set -+ -+# -+# Options common to multiple modutils -+# -+# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set -+# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set -+# CONFIG_FEATURE_2_4_MODULES is not set -+# 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_INSMOD_TRY_MMAP is not set -+# CONFIG_FEATURE_MODUTILS_ALIAS is not set -+# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set -+CONFIG_DEFAULT_MODULES_DIR="" -+CONFIG_DEFAULT_DEPMOD_FILE="" -+ -+# -+# Linux System Utilities -+# -+# CONFIG_ACPID is not set -+# CONFIG_FEATURE_ACPID_COMPAT is not set -+# CONFIG_BLKDISCARD is not set -+# CONFIG_BLKID is not set -+# CONFIG_FEATURE_BLKID_TYPE is not set -+# CONFIG_BLOCKDEV is not set -+# CONFIG_CAL is not set -+# CONFIG_CHRT is not set -+# CONFIG_DMESG is not set -+# CONFIG_FEATURE_DMESG_PRETTY is not set -+# CONFIG_EJECT is not set -+# CONFIG_FEATURE_EJECT_SCSI is not set -+CONFIG_FALLOCATE=y -+# CONFIG_FATATTR is not set -+# CONFIG_FBSET is not set -+# CONFIG_FEATURE_FBSET_FANCY is not set -+# CONFIG_FEATURE_FBSET_READMODE is not set -+# CONFIG_FDFORMAT is not set -+# CONFIG_FDISK is not set -+# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set -+# CONFIG_FEATURE_FDISK_WRITABLE is not set -+# 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_FDFLUSH is not set -+# CONFIG_FREERAMDISK is not set -+# CONFIG_FSCK_MINIX is not set -+CONFIG_FSFREEZE=y -+# CONFIG_FSTRIM is not set -+# CONFIG_GETOPT is not set -+# CONFIG_FEATURE_GETOPT_LONG is not set -+# CONFIG_HEXDUMP is not set -+# CONFIG_FEATURE_HEXDUMP_REVERSE is not set -+# CONFIG_HD is not set -+CONFIG_XXD=y -+# CONFIG_HWCLOCK is not set -+# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set -+# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set -+# CONFIG_IONICE is not set -+# CONFIG_IPCRM is not set -+# CONFIG_IPCS is not set -+# CONFIG_LAST is not set -+# CONFIG_FEATURE_LAST_FANCY is not set -+# CONFIG_LOSETUP is not set -+# CONFIG_LSPCI is not set -+# CONFIG_LSUSB is not set -+# 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_MESG is not set -+# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set -+CONFIG_MKE2FS=y -+# CONFIG_MKFS_EXT2 is not set -+# CONFIG_MKFS_MINIX is not set -+# CONFIG_FEATURE_MINIX2 is not set -+# CONFIG_MKFS_REISER is not set -+CONFIG_MKDOSFS=y -+# CONFIG_MKFS_VFAT is not set -+# CONFIG_MKSWAP is not set -+# CONFIG_FEATURE_MKSWAP_UUID is not set -+# CONFIG_MORE is not set -+CONFIG_MOUNT=y -+# CONFIG_FEATURE_MOUNT_FAKE is not set -+# CONFIG_FEATURE_MOUNT_VERBOSE is not set -+CONFIG_FEATURE_MOUNT_HELPERS=y -+# CONFIG_FEATURE_MOUNT_LABEL is not set -+# CONFIG_FEATURE_MOUNT_NFS is not set -+# CONFIG_FEATURE_MOUNT_CIFS is not set -+CONFIG_FEATURE_MOUNT_FLAGS=y -+CONFIG_FEATURE_MOUNT_FSTAB=y -+CONFIG_FEATURE_MOUNT_OTHERTAB=y -+# CONFIG_MOUNTPOINT is not set -+# CONFIG_NSENTER is not set -+# CONFIG_FEATURE_NSENTER_LONG_OPTS is not set -+# CONFIG_PIVOT_ROOT is not set -+# CONFIG_RDATE is not set -+# CONFIG_RDEV is not set -+# CONFIG_READPROFILE is not set -+# CONFIG_RENICE is not set -+# CONFIG_REV is not set -+# 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_SETPRIV=y -+# CONFIG_SETSID is not set -+CONFIG_SWAPON=y -+# CONFIG_FEATURE_SWAPON_DISCARD is not set -+# CONFIG_FEATURE_SWAPON_PRI is not set -+CONFIG_SWAPOFF=y -+# CONFIG_SWITCH_ROOT is not set -+# CONFIG_TASKSET is not set -+# CONFIG_FEATURE_TASKSET_FANCY is not set -+# CONFIG_UEVENT is not set -+CONFIG_UMOUNT=y -+CONFIG_FEATURE_UMOUNT_ALL=y -+# CONFIG_UNSHARE is not set -+# CONFIG_WALL 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 is not set -+# CONFIG_FEATURE_VOLUMEID_BCACHE is not set -+# CONFIG_FEATURE_VOLUMEID_BTRFS is not set -+# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set -+# CONFIG_FEATURE_VOLUMEID_EXFAT is not set -+# CONFIG_FEATURE_VOLUMEID_EXT is not set -+# CONFIG_FEATURE_VOLUMEID_F2FS is not set -+# CONFIG_FEATURE_VOLUMEID_FAT is not set -+# CONFIG_FEATURE_VOLUMEID_HFS is not set -+# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set -+# CONFIG_FEATURE_VOLUMEID_JFS is not set -+# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set -+# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set -+# CONFIG_FEATURE_VOLUMEID_LUKS is not set -+# CONFIG_FEATURE_VOLUMEID_NILFS is not set -+# CONFIG_FEATURE_VOLUMEID_NTFS is not set -+# 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 is not set -+# CONFIG_FEATURE_VOLUMEID_SYSV is not set -+# CONFIG_FEATURE_VOLUMEID_UBIFS is not set -+# CONFIG_FEATURE_VOLUMEID_UDF is not set -+# CONFIG_FEATURE_VOLUMEID_XFS is not set -+ -+# -+# Miscellaneous Utilities -+# -+# CONFIG_ADJTIMEX is not set -+# CONFIG_BBCONFIG is not set -+# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set -+# 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_CONSPY 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 is not set -+# 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 is not set -+# CONFIG_FBSPLASH is not set -+# CONFIG_FLASHCP is not set -+# CONFIG_FLASH_ERASEALL is not set -+# CONFIG_FLASH_LOCK is not set -+# CONFIG_FLASH_UNLOCK 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_I2CGET=y -+CONFIG_I2CSET=y -+CONFIG_I2CDUMP=y -+CONFIG_I2CDETECT=y -+# CONFIG_INOTIFYD is not set -+# CONFIG_LESS is not set -+CONFIG_FEATURE_LESS_MAXLINES=0 -+# CONFIG_FEATURE_LESS_BRACKETS is not set -+# CONFIG_FEATURE_LESS_FLAGS is not set -+# CONFIG_FEATURE_LESS_TRUNCATE is not set -+# CONFIG_FEATURE_LESS_MARKS is not set -+# CONFIG_FEATURE_LESS_REGEXP is not set -+# CONFIG_FEATURE_LESS_WINCH is not set -+# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set -+# CONFIG_FEATURE_LESS_DASHCMD is not set -+# CONFIG_FEATURE_LESS_LINENUMS is not set -+# CONFIG_LOCK is not set -+CONFIG_LSSCSI=y -+# CONFIG_MAKEDEVS is not set -+# CONFIG_FEATURE_MAKEDEVS_LEAF is not set -+# CONFIG_FEATURE_MAKEDEVS_TABLE is not set -+# CONFIG_MAN is not set -+# CONFIG_MICROCOM is not set -+# CONFIG_MT is not set -+# CONFIG_NANDWRITE is not set -+# CONFIG_NANDDUMP is not set -+CONFIG_PARTPROBE=y -+# CONFIG_RAIDAUTORUN is not set -+# CONFIG_READAHEAD is not set -+# CONFIG_RFKILL is not set -+# CONFIG_RUNLEVEL is not set -+# CONFIG_RX is not set -+# CONFIG_SETSERIAL is not set -+# CONFIG_STRINGS is not set -+# CONFIG_TIME is not set -+# CONFIG_TTYSIZE is not set -+# CONFIG_UBIRENAME is not set -+# 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_VOLNAME 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 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_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 is not set -+# CONFIG_FTPPUT is not set -+# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set -+# 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 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_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 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=y -+CONFIG_IPADDR=y -+CONFIG_IPLINK=y -+# CONFIG_IPROUTE is not set -+# CONFIG_IPTUNNEL is not set -+# CONFIG_IPRULE is not set -+# CONFIG_IPNEIGH is not set -+CONFIG_FEATURE_IP_ADDRESS=y -+CONFIG_FEATURE_IP_LINK=y -+# CONFIG_FEATURE_IP_ROUTE is not set -+CONFIG_FEATURE_IP_ROUTE_DIR="" -+# CONFIG_FEATURE_IP_TUNNEL is not set -+# CONFIG_FEATURE_IP_RULE is not set -+# CONFIG_FEATURE_IP_NEIGH is not set -+# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set -+# CONFIG_IPCALC is not set -+# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set -+# CONFIG_FEATURE_IPCALC_FANCY is not set -+# CONFIG_FAKEIDENTD is not set -+# 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_NETMSG 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_NSLOOKUP_OPENWRT=y -+CONFIG_FEATURE_NSLOOKUP_OPENWRT_LONG_OPTIONS=y -+# CONFIG_NTPD is not set -+# CONFIG_FEATURE_NTPD_SERVER is not set -+# CONFIG_FEATURE_NTPD_CONF is not set -+CONFIG_PING=y -+CONFIG_PING6=y -+CONFIG_FEATURE_FANCY_PING=y -+# CONFIG_PSCAN is not set -+# CONFIG_ROUTE is not set -+# CONFIG_SLATTACH is not set -+CONFIG_SSL_CLIENT=y -+# CONFIG_TCPSVD is not set -+# CONFIG_UDPSVD is not set -+# CONFIG_TELNET is not set -+# CONFIG_FEATURE_TELNET_TTYPE is not set -+# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set -+# CONFIG_FEATURE_TELNET_WIDTH 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_TLS=y -+# CONFIG_TRACEROUTE is not set -+# CONFIG_TRACEROUTE6 is not set -+# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set -+# 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 is not set -+# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set -+# CONFIG_FEATURE_WGET_STATUSBAR is not set -+# CONFIG_FEATURE_WGET_AUTHENTICATION is not set -+# CONFIG_FEATURE_WGET_TIMEOUT is not set -+# CONFIG_FEATURE_WGET_HTTPS is not set -+# CONFIG_FEATURE_WGET_OPENSSL is not set -+# CONFIG_WHOIS is not set -+# CONFIG_ZCIP is not set -+# CONFIG_UDHCPC6 is not set -+# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set -+# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set -+# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set -+# CONFIG_UDHCPD 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_DUMPLEASES is not set -+# CONFIG_DHCPRELAY is not set -+# CONFIG_UDHCPC is not set -+# CONFIG_FEATURE_UDHCPC_ARPING is not set -+# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set -+CONFIG_UDHCPC_DEFAULT_SCRIPT="" -+# 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_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 is not set -+CONFIG_KILL=y -+CONFIG_KILLALL=y -+# CONFIG_KILLALL5 is not set -+# CONFIG_LSOF is not set -+# CONFIG_MPSTAT is not set -+# CONFIG_NMETER is not set -+CONFIG_PGREP=y -+CONFIG_PKILL=y -+CONFIG_PIDOF=y -+# CONFIG_FEATURE_PIDOF_SINGLE is not set -+# CONFIG_FEATURE_PIDOF_OMIT is not set -+# CONFIG_PMAP is not set -+# CONFIG_POWERTOP is not set -+# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set -+CONFIG_PS=y -+CONFIG_FEATURE_PS_WIDE=y -+# CONFIG_FEATURE_PS_LONG is not set -+# CONFIG_FEATURE_PS_TIME is not set -+# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set -+# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set -+# CONFIG_PSTREE is not set -+# CONFIG_PWDX is not set -+# CONFIG_SMEMCAP is not set -+CONFIG_BB_SYSCTL=y -+# CONFIG_TOP is not set -+# CONFIG_FEATURE_TOP_INTERACTIVE is not set -+# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set -+# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set -+# CONFIG_FEATURE_TOP_SMP_CPU is not set -+# CONFIG_FEATURE_TOP_DECIMALS is not set -+# CONFIG_FEATURE_TOP_SMP_PROCESS is not set -+# CONFIG_FEATURE_TOPMEM is not set -+CONFIG_UPTIME=y -+# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set -+# CONFIG_WATCH is not set -+# CONFIG_FEATURE_SHOW_THREADS is not set -+ -+# -+# 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 -+# CONFIG_CHCON is not set -+# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set -+# CONFIG_GETENFORCE is not set -+# CONFIG_GETSEBOOL is not set -+# CONFIG_LOAD_POLICY is not set -+# CONFIG_MATCHPATHCON is not set -+# CONFIG_RUNCON is not set -+# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set -+# CONFIG_SELINUXENABLED is not set -+# CONFIG_SESTATUS is not set -+# CONFIG_SETENFORCE is not set -+# CONFIG_SETFILES is not set -+# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set -+# CONFIG_RESTORECON is not set -+# CONFIG_SETSEBOOL is not set -+ -+# -+# 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 is not set -+CONFIG_ASH_INTERNAL_GLOB=y -+CONFIG_ASH_BASH_COMPAT=y -+CONFIG_ASH_JOB_CONTROL=y -+CONFIG_ASH_ALIAS=y -+CONFIG_ASH_RANDOM_SUPPORT=y -+CONFIG_ASH_EXPAND_PRMT=y -+# CONFIG_ASH_IDLE_TIMEOUT is not set -+# CONFIG_ASH_MAIL is not set -+CONFIG_ASH_ECHO=y -+CONFIG_ASH_PRINTF=y -+CONFIG_ASH_TEST=y -+# CONFIG_ASH_HELP is not set -+CONFIG_ASH_GETOPTS=y -+CONFIG_ASH_CMDCMD=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_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_MODE_X is not set -+# CONFIG_HUSH_ECHO is not set -+# CONFIG_HUSH_PRINTF is not set -+# CONFIG_HUSH_TEST is not set -+# CONFIG_HUSH_HELP is not set -+# CONFIG_HUSH_EXPORT is not set -+# CONFIG_HUSH_EXPORT_N is not set -+# CONFIG_HUSH_KILL is not set -+# CONFIG_HUSH_WAIT is not set -+# CONFIG_HUSH_TRAP is not set -+# CONFIG_HUSH_TYPE is not set -+# CONFIG_HUSH_READ is not set -+# CONFIG_HUSH_SET is not set -+# CONFIG_HUSH_UNSET is not set -+# CONFIG_HUSH_ULIMIT is not set -+# CONFIG_HUSH_UMASK is not set -+# CONFIG_HUSH_MEMLEAK is not set -+# CONFIG_MSH is not set -+ -+# -+# Options common to all shells -+# -+CONFIG_FEATURE_SH_MATH=y -+CONFIG_FEATURE_SH_MATH_64=y -+# CONFIG_FEATURE_SH_EXTRA_QUIET is not set -+CONFIG_FEATURE_SH_STANDALONE=y -+CONFIG_FEATURE_SH_NOFORK=y -+# 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 -- -2.16.2 +2.18.0 diff --git a/patches/openwrt/hack/0001-ubus-Hackilly-add-Stepans-python-bindings.patch b/patches/openwrt/hack/0001-ubus-Hackilly-add-Stepans-python-bindings.patch index 98110c960afa040ea32502f74c8e4db7791e2649..a23508d2b2f71fe4a975a5d1fd9ce288f62efc49 100644 --- a/patches/openwrt/hack/0001-ubus-Hackilly-add-Stepans-python-bindings.patch +++ b/patches/openwrt/hack/0001-ubus-Hackilly-add-Stepans-python-bindings.patch @@ -1,4 +1,4 @@ -From c6de868c3954517bc169c8ec5cb2a5bc7eaecfea Mon Sep 17 00:00:00 2001 +From 1b918d04f541d201a2fa43d371ecbb1318719d4c Mon Sep 17 00:00:00 2001 From: Michal Hrusecky <Michal@Hrusecky.net> Date: Tue, 23 Jan 2018 23:55:00 +0100 Subject: [PATCH] ubus: Hackilly add Stepans python bindings @@ -14,16 +14,14 @@ There are currently two problems with this solution: Signed-off-by: Michal Hrusecky <Michal@Hrusecky.net> --- - package/system/ubus/Makefile | 31 + - package/system/ubus/patches/001-python.patch | 2443 ++++++++++++++++++++++++++ - 2 files changed, 2474 insertions(+) - create mode 100644 package/system/ubus/patches/001-python.patch + package/system/ubus/Makefile | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) diff --git a/package/system/ubus/Makefile b/package/system/ubus/Makefile -index 7dc3c92..46c608b 100644 +index 523c362..d39b918 100644 --- a/package/system/ubus/Makefile +++ b/package/system/ubus/Makefile -@@ -47,10 +47,35 @@ define Package/libubus-lua +@@ -47,11 +47,34 @@ define Package/libubus-lua TITLE:=Lua binding for the OpenWrt RPC client endef @@ -35,7 +33,8 @@ index 7dc3c92..46c608b 100644 + DEPENDS:=+libubus +libblobmsg-json +python-light +endef + - TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include + TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include -flto + TARGET_LDFLAGS += -flto +define Build/Compile/fake_python_sh + echo -e '#!/bin/sh\nLD_LIBRARY_PATH="$(STAGING_DIR_HOSTPKG)/lib" $(STAGING_DIR_HOSTPKG)/bin/python "$$$$@"' > '$(STAGING_DIR_HOSTPKG)/bin/python.sh' @@ -44,7 +43,6 @@ index 7dc3c92..46c608b 100644 + +Hooks/Configure/Pre += Build/Compile/fake_python_sh + -+ +ifdef CONFIG_PACKAGE_python-ubus +CMAKE_OPTIONS = \ + -DLUAPATH=/usr/lib/lua \ @@ -55,11 +53,10 @@ index 7dc3c92..46c608b 100644 CMAKE_OPTIONS = \ -DLUAPATH=/usr/lib/lua +endif -+ define Package/ubus/install $(INSTALL_DIR) $(1)/bin -@@ -72,7 +97,13 @@ define Package/libubus-lua/install +@@ -73,7 +96,13 @@ define Package/libubus-lua/install $(CP) $(PKG_BUILD_DIR)/lua/ubus.so $(1)/usr/lib/lua/ endef @@ -73,2454 +70,6 @@ index 7dc3c92..46c608b 100644 $(eval $(call BuildPackage,ubus)) $(eval $(call BuildPackage,ubusd)) +$(eval $(call BuildPackage,python-ubus)) -diff --git a/package/system/ubus/patches/001-python.patch b/package/system/ubus/patches/001-python.patch -new file mode 100644 -index 0000000..7338b2f ---- /dev/null -+++ b/package/system/ubus/patches/001-python.patch -@@ -0,0 +1,2442 @@ -+diff --git a/CMakeLists.txt b/CMakeLists.txt -+index 471b38e..cc6376c 100644 -+--- a/CMakeLists.txt -++++ b/CMakeLists.txt -+@@ -4,6 +4,7 @@ PROJECT(ubus C) -+ ADD_DEFINITIONS(-Os -Wall --std=gnu99 -g3 -Wmissing-declarations) -+ -+ OPTION(BUILD_LUA "build Lua plugin" ON) -++OPTION(BUILD_PYTHON "build python plugin" OFF) -+ OPTION(BUILD_EXAMPLES "build examples" ON) -+ -+ SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") -+@@ -37,6 +38,9 @@ SET_TARGET_PROPERTIES(cli PROPERTIES OUTPUT_NAME ubus) -+ TARGET_LINK_LIBRARIES(cli ubus ${ubox_library} ${blob_library} ${json}) -+ -+ ADD_SUBDIRECTORY(lua) -++if (BUILD_PYTHON) -++ ADD_SUBDIRECTORY(python) -++endif () -+ ADD_SUBDIRECTORY(examples) -+ -+ INSTALL(TARGETS ubus cli -+diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt -+new file mode 100644 -+index 0000000..2e66f2a -+--- /dev/null -++++ b/python/CMakeLists.txt -+@@ -0,0 +1,58 @@ -++cmake_minimum_required(VERSION 3.0) -++ -++SET(CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") -++SET(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in") -++SET(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py") -++ -++IF(NOT PYTHON_CFLAGS) -++ FIND_PROGRAM(PKG_CONFIG pkg-config) -++ IF(PKG_CONFIG) -++ EXECUTE_PROCESS( -++ COMMAND pkg-config --silence-errors --cflags python2 -++ OUTPUT_VARIABLE PYTHON_CFLAGS -++ OUTPUT_STRIP_TRAILING_WHITESPACE -++ ) -++ ENDIF() -++ENDIF() -++ -++IF(NOT PYTHON) -++ FIND_PROGRAM(PYTHON python) -++ENDIF() -++ -++SET(PYTHON_CFLAGS "-Os -Wall --std=gnu99 -g3 -I.. ${PYTHON_CFLAGS}") -++INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..) -++LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..) -++ -++IF(APPLE) -++ SET(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -undefined dynamic_lookup") -++ENDIF(APPLE) -++ -++IF(NOT PYTHONPATH) -++ EXECUTE_PROCESS( -++ COMMAND ${PYTHON} -c "import os; print os.path.dirname(os.__file__)" -++ OUTPUT_VARIABLE PYTHONPATH -++ RESULT_VARIABLE PYTHON_CHECK_RES -++ OUTPUT_STRIP_TRAILING_WHITESPACE -++ ) -++ -++ IF(NOT ${PYTHON_CHECK_RES} EQUAL 0 OR "${PYTHONPATH}" EQUAL "") -++ MESSAGE(SEND_ERROR "Python was not found on your system") -++ ENDIF() -++ENDIF() -++ -++CONFIGURE_FILE(${SETUP_PY_IN} ${SETUP_PY}) -++ -++ -++SET(PYTHON_CFLAGS "${PYTHON_CFLAGS} -DUBUS_UNIX_SOCKET=\\\\\\\"${UBUS_UNIX_SOCKET}\\\\\\\"") -++SET_PROPERTY(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "build") -++ -++SET(LDSHARED "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1} -shared") -++ -++ADD_CUSTOM_TARGET(python ALL -++ COMMAND ${CMAKE_COMMAND} -E env "CC=${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" "LDSHARED=${LDSHARED}" "CFLAGS=${PYTHON_CFLAGS}" ${PYTHON} ${SETUP_PY} build -++ DEPENDS ubus "${CURRENT_SOURCE_DIR}/ubus_python.c" -++) -++ -++INSTALL( -++ CODE "execute_process(COMMAND ${CMAKE_COMMAND} -E env \"CC=${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}\" \"LDSHARED=${LDSHARED}\" \"CFLAGS=${PYTHON_CFLAGS}\" ${PYTHON} ${SETUP_PY} install --prefix=${CMAKE_INSTALL_PREFIX})" -++) -+diff --git a/python/README.rst b/python/README.rst -+new file mode 100644 -+index 0000000..8fcd7f4 -+--- /dev/null -++++ b/python/README.rst -+@@ -0,0 +1,97 @@ -++Python bindings for ubus -++======================== -++Code in this directory enables a subset of libubus functions to be used directly from python. -++ -++Examples -++######## -++ -++connect and disconnect -++---------------------- -++To connect you need to:: -++ -++ import ubus -++ ubus.connect("/var/run/ubus.sock") -++ -++To disconnect you can simply:: -++ -++ ubus.disconnect() -++ -++Note that calling connect()/disconnect() on opened/closed connection will throw an exception. -++ -++add -++--- -++To add an object to ubus you can (you need to become root first):: -++ -++ def callback(handler, data): -++ handler.reply(data) # this should return exactly the same data to the caller -++ -++ ubus.add( -++ "my_object", { -++ "my_method": {"method": callback, "signature": { -++ "first": ubus.BLOBMSG_TYPE_STRING, -++ "second": ubus.BLOBMSG_TYPE_BOOL, -++ "third": ubus.BLOBMSG_TYPE_INT32, -++ }}, -++ }, -++ ) -++ -++You need to enter the loop to serve the object methods afterwards:: -++ -++ ubus.loop() -++ -++ -++Note that it might not be a good idea to call the callback function recursively. -++ -++ -++objects -++------- -++To list the objects which are currently connected to ubus you can call:: -++ -++ ubus.objects() -++ -++ -> -++ -++ {u'my_object': {u'my_method': {u'first': 3, u'second': 7, u'third': 5}}} -++ -++ -++ -++call -++---- -++To call an actual method on an object you can use:: -++ -++ ubus.call("my_object", "my_method", {"first": "my_string", "second": True, "third": 42}) -++ -++ -> -++ -++ [{"first": "my_string", "second": True, "third": 42}] -++ -++ -++listen -++------ -++To listen for an event you can:: -++ -++ def callback(event, data): -++ print(event, data) # just print event name and data to stdout -++ -++ ubus.listen(("my_event", callback)) -++ -++And you need to enter the loop to start to listen:: -++ -++ ubus.loop() -++ -++Note that it might not be a good idea to call the callback function recursively. -++ -++send -++---- -++This will send an event to ubus:: -++ -++ ubus.send("my_event", {"some": "data"}) -++ -++ -++Notes -++##### -++ -++There are some tests present ('tests/' directory). So feel free to check it for some more complex examples. -++To run the tests you need to have ubus installed and become root:: -++ -++ sudo python setup.py test -+diff --git a/python/setup.cfg b/python/setup.cfg -+new file mode 100644 -+index 0000000..d1844e1 -+--- /dev/null -++++ b/python/setup.cfg -+@@ -0,0 +1,6 @@ -++[aliases] -++test=pytest -++ -++[tool:pytest] -++addopts = --verbose -s -++python_files = tests/*.py -+diff --git a/python/setup.py.in b/python/setup.py.in -+new file mode 100644 -+index 0000000..b030d87 -+--- /dev/null -++++ b/python/setup.py.in -+@@ -0,0 +1,18 @@ -++from setuptools import setup, Extension -++ -++extension = Extension( -++ 'ubus', -++ ['@CURRENT_SOURCE_DIR@/ubus_python.c'], -++ libraries=['ubus', 'blobmsg_json', 'ubox'], -++ include_dirs=['@PROJECT_SOURCE_DIR@'], -++ library_dirs=['@PROJECT_BINARY_DIR@'], -++) -++ -++setup( -++ name='ubus', -++ version='@PYTHON_PACKAGE_VERSION@', -++ description="Python bindings for libubus", -++ ext_modules=[extension], -++ provides=['ubus'], -++ tests_require=['pytest'], -++) -+diff --git a/python/tests/__init__.py b/python/tests/__init__.py -+new file mode 100644 -+index 0000000..e69de29 -+diff --git a/python/tests/fixtures.py b/python/tests/fixtures.py -+new file mode 100644 -+index 0000000..e9d28b4 -+--- /dev/null -++++ b/python/tests/fixtures.py -+@@ -0,0 +1,226 @@ -++import os -++from multiprocessing import Process, Value -++import pytest -++import subprocess -++import time -++ -++ -++UBUSD_TEST_SOCKET_PATH = "/tmp/ubus-test-socket" -++ -++ -++class Guard(object): -++ -++ def __init__(self): -++ self.counter = Value('i', 0) -++ -++ def __enter__(self): -++ return self -++ -++ def __exit__(self, *args): -++ return True -++ -++ def touch(self): -++ self.counter.value += 1 -++ -++ def wait(self): -++ while not self.counter.value > 0: -++ time.sleep(0.05) -++ -++ -++@pytest.fixture(scope="session") -++def ubusd_test(): -++ ubusd_instance = subprocess.Popen(["ubusd", "-s", UBUSD_TEST_SOCKET_PATH]) -++ while not os.path.exists(UBUSD_TEST_SOCKET_PATH): -++ time.sleep(0.2) -++ yield ubusd_instance -++ ubusd_instance.kill() -++ os.unlink(UBUSD_TEST_SOCKET_PATH) -++ -++ -++@pytest.fixture(scope="function") -++def event_sender(): -++ -++ with Guard() as guard: -++ -++ def process_function(): -++ import ubus -++ ubus.connect(UBUSD_TEST_SOCKET_PATH) -++ while True: -++ ubus.send("event_sender", dict(a="b", c=3, d=False)) -++ guard.touch() -++ time.sleep(0.1) -++ -++ p = Process(target=process_function, name="event_sender") -++ p.start() -++ guard.wait() -++ setattr(p, 'counter', guard.counter) -++ -++ yield p -++ -++ p.terminate() -++ p.join() -++ -++ -++@pytest.fixture(scope="function") -++def registered_objects(): -++ with Guard() as guard: -++ -++ def process_function(): -++ -++ def handler1(*arg): -++ pass -++ -++ import ubus -++ ubus.connect(UBUSD_TEST_SOCKET_PATH) -++ ubus.add( -++ "registered_object1", -++ { -++ "method1": {"method": handler1, "signature": {}}, -++ "method2": {"method": handler1, "signature": { -++ "first": ubus.BLOBMSG_TYPE_STRING, -++ "second": ubus.BLOBMSG_TYPE_BOOL, -++ "third": ubus.BLOBMSG_TYPE_INT32, -++ }}, -++ }, -++ ) -++ ubus.add( -++ "registered_object2", {}, -++ ) -++ ubus.add( -++ "registered_object3", -++ { -++ "method1": {"method": handler1, "signature": {}}, -++ } -++ ) -++ guard.touch() -++ ubus.loop() -++ -++ p = Process(target=process_function) -++ p.start() -++ guard.wait() -++ -++ yield p -++ -++ p.terminate() -++ p.join() -++ -++ -++@pytest.fixture(scope="function") -++def responsive_object(): -++ with Guard() as guard: -++ -++ def process_function(): -++ -++ def handler1(handler, data): -++ data["passed"] = True -++ handler.reply(data) -++ -++ def handler2(handler, data): -++ data["passed1"] = True -++ handler.reply(data) -++ data["passed2"] = True -++ handler.reply(data) -++ data["passed3"] = True -++ handler.reply(data) -++ -++ def handler_fail(handler, data): -++ raise Exception("Handler Fails") -++ -++ import ubus -++ ubus.connect(UBUSD_TEST_SOCKET_PATH) -++ ubus.add( -++ "responsive_object", -++ { -++ "respond": {"method": handler1, "signature": { -++ "first": ubus.BLOBMSG_TYPE_STRING, -++ "second": ubus.BLOBMSG_TYPE_BOOL, -++ "third": ubus.BLOBMSG_TYPE_INT32, -++ }}, -++ "fail": {"method": handler_fail, "signature": {}}, -++ "multi_respond": {"method": handler2, "signature": {}}, -++ "number": {"method": handler1, "signature": { -++ "number": ubus.BLOBMSG_TYPE_INT32, -++ }}, -++ }, -++ ) -++ guard.touch() -++ ubus.loop() -++ -++ p = Process(target=process_function) -++ p.start() -++ guard.wait() -++ -++ yield p -++ -++ p.terminate() -++ p.join() -++ -++ -++@pytest.fixture(scope="function") -++def call_for_object(): -++ with Guard() as guard: -++ -++ def process_function(): -++ -++ import ubus -++ ubus.connect(UBUSD_TEST_SOCKET_PATH) -++ args = [ -++ ('callee_object', 'method1', {'first': 1}), -++ ('callee_object', 'method2', {'second': 2}), -++ ('callee_object', 'method3', {}), -++ ] -++ while True: -++ for arg in args: -++ try: -++ ubus.call(*arg) -++ except RuntimeError as e: -++ pass -++ guard.touch() -++ time.sleep(0.05) -++ -++ p = Process(target=process_function) -++ p.start() -++ guard.wait() -++ -++ yield p -++ -++ p.terminate() -++ p.join() -++ -++ -++@pytest.fixture(scope="function") -++def calls_extensive(): -++ with Guard() as guard: -++ -++ def process_function(): -++ -++ import ubus -++ ubus.connect(UBUSD_TEST_SOCKET_PATH) -++ while True: -++ for i in range(20): -++ try: -++ ubus.call('extensive_object_%d' % i, 'method', {}) -++ time.sleep(0.1) -++ except RuntimeError as e: -++ pass -++ guard.touch() -++ -++ p = Process(target=process_function) -++ p.start() -++ guard.wait() -++ setattr(p, 'counter', guard.counter) -++ -++ yield p -++ -++ p.terminate() -++ p.join() -++ -++ -++@pytest.fixture(scope="function") -++def disconnect_after(): -++ yield None -++ import ubus -++ try: -++ ubus.disconnect() -++ except: -++ pass -+diff --git a/python/tests/test_connection.py b/python/tests/test_connection.py -+new file mode 100644 -+index 0000000..d5ee835 -+--- /dev/null -++++ b/python/tests/test_connection.py -+@@ -0,0 +1,646 @@ -++import time -++import pytest -++import ubus -++import sys -++ -++from fixtures import ( -++ event_sender, -++ call_for_object, -++ calls_extensive, -++ disconnect_after, -++ ubusd_test, -++ registered_objects, -++ responsive_object, -++ UBUSD_TEST_SOCKET_PATH, -++) -++ -++stored_reference_counts = None -++ -++ -++class CheckRefCount(object): -++ -++ def __init__(self, *objects): -++ self.objects = objects -++ -++ def __enter__(self): -++ self.stored_reference_counts = [sys.getrefcount(e) for e in self.objects] -++ -++ def __exit__(self, exc_type, *args): -++ -++ if exc_type: -++ # don't count references when an exception occured -++ return -++ -++ objects = self.objects -++ current = [sys.getrefcount(e) for e in objects] -++ stored = self.stored_reference_counts -++ for (obj, old, new) in zip(objects, stored, current): -++ assert old == new, "Reference count for '%s' mismatch (%d!=%d)" % (obj, old, new) -++ -++ -++def test_socket_missing(ubusd_test): -++ path = "/non/existing/path" -++ -++ with CheckRefCount(path): -++ with pytest.raises(IOError): -++ ubus.connect(socket_path="/non/existing/path") -++ -++ -++def test_connect_and_disconnect(ubusd_test, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ with CheckRefCount(path): -++ -++ assert ubus.get_connected() is False -++ assert ubus.get_socket_path() is None -++ -++ ubus.connect(socket_path=path) -++ assert ubus.get_socket_path() == path -++ assert ubus.get_connected() is True -++ -++ assert ubus.disconnect() is None -++ with pytest.raises(RuntimeError): -++ ubus.disconnect() -++ assert ubus.get_connected() is False -++ assert ubus.get_socket_path() is None -++ -++ ubus.connect(socket_path=path) -++ with pytest.raises(RuntimeError): -++ ubus.connect(socket_path=path) -++ assert ubus.get_socket_path() == path -++ assert ubus.get_connected() is True -++ -++ assert ubus.disconnect() is None -++ -++ assert ubus.get_connected() is False -++ assert ubus.get_socket_path() is None -++ -++ -++def test_send_failed(ubusd_test, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ with CheckRefCount(path): -++ -++ with pytest.raises(RuntimeError): -++ ubus.send("disconnected", {}) -++ -++ ubus.connect(socket_path=path) -++ with pytest.raises(TypeError): -++ ubus.send() -++ -++ with pytest.raises(TypeError): -++ ubus.send({}, {}) -++ -++ with pytest.raises(TypeError): -++ ubus.send("", "") -++ -++ with pytest.raises(TypeError): -++ ubus.send("", {}, {}) -++ -++ class NonSerializable(object): -++ pass -++ -++ with pytest.raises(TypeError): -++ ubus.send("", NonSerializable()) -++ -++ ubus.disconnect() -++ -++ -++def test_send_succeeded(ubusd_test, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ test_dict = dict(a=5, b="True", c=False) -++ -++ with CheckRefCount(path, test_dict): -++ -++ ubus.connect(socket_path=path) -++ -++ assert ubus.send("normal", test_dict) -++ assert ubus.send("*", test_dict) -++ assert ubus.send("", test_dict) -++ -++ ubus.disconnect() -++ -++ -++def test_loop(ubusd_test, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ time1 = 200 -++ time2 = 1 -++ time3 = 50 -++ time4 = 2 ** 65 -++ time5 = None -++ time6 = "5" -++ time7 = 0 -++ -++ with CheckRefCount(path, time1, time2, time3, time4, time6, time7): -++ -++ with pytest.raises(RuntimeError): -++ ubus.loop(time1) -++ -++ ubus.connect(socket_path=path) -++ assert ubus.loop(time1) is None -++ assert ubus.loop(time2) is None -++ assert ubus.loop(time3) is None -++ -++ with pytest.raises(OverflowError): -++ ubus.loop(time4) -++ -++ with pytest.raises(TypeError): -++ ubus.loop(time5) -++ -++ with pytest.raises(TypeError): -++ ubus.loop(time6) -++ -++ assert ubus.loop(time7) is None -++ -++ ubus.disconnect() -++ -++ -++def test_listen_failed(ubusd_test, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ obj1 = {} -++ obj2 = ("a", lambda x, y: (x, y)) -++ obj3 = ("b", None) -++ obj4 = ({}, lambda x, y: (x, y)) -++ obj5 = ("b", lambda x, y: (x, y)) -++ -++ with CheckRefCount(path, obj1, obj2, obj3, obj4, obj5): -++ -++ with pytest.raises(RuntimeError): -++ ubus.listen(obj1, obj1) -++ -++ ubus.connect(socket_path=path) -++ -++ with pytest.raises(TypeError): -++ ubus.listen(obj1, obj1) -++ -++ with pytest.raises(TypeError): -++ ubus.send(obj2, obj3) -++ -++ with pytest.raises(TypeError): -++ ubus.send(obj4, obj5) -++ -++ with pytest.raises(TypeError): -++ ubus.listen() -++ -++ ubus.disconnect() -++ -++ -++def test_listen(ubusd_test, event_sender, disconnect_after): -++ listen_test = {"passed": False, "passed2": False} -++ -++ def set_result(event, data): -++ assert event == "event_sender" -++ assert data == dict(a="b", c=3, d=False) -++ listen_test["passed"] = True -++ -++ def test1(event, data): -++ assert event == "event_sender" -++ assert data == dict(a="b", c=3, d=False) -++ listen_test["passed2"] = True -++ -++ path = UBUSD_TEST_SOCKET_PATH -++ timeout = 300 -++ event_name = "event_sender" -++ -++ with CheckRefCount(path, time, event_name, test1): -++ -++ ubus.connect(socket_path=path) -++ ubus.listen((event_name, test1), (event_name, set_result)) -++ ubus.listen((event_name, test1)) -++ -++ del set_result -++ -++ ubus.loop(timeout) -++ assert listen_test["passed"] -++ assert listen_test["passed2"] -++ -++ listen_test = {"passed": False, "passed2": False} -++ ubus.loop(timeout) -++ assert listen_test["passed"] -++ assert listen_test["passed2"] -++ -++ ubus.disconnect() -++ -++ -++def test_add_object_failed(ubusd_test, registered_objects, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ def fake(*args): -++ pass -++ -++ type_errors = [ -++ [], -++ ("name", ), -++ ("name", {}, False), -++ ("name", {"test": []}), -++ ("name", {"test": 5}), -++ ("name", {"test": {"method": 5, "signature": {}}}), -++ ("name", {"test": {"method": fake}}), -++ ("name", {"test": {"method": fake, "signature": {}, "another": 5}}), -++ ] -++ -++ runtime_errors = [ -++ ("registered_object1", {"test": {"method": fake, "signature": {}}}), -++ ("registered_object2", {}), -++ ] -++ -++ with CheckRefCount(path, fake, *(type_errors + runtime_errors)): -++ -++ with pytest.raises(RuntimeError): -++ ubus.add(*type_errors[0]) -++ -++ ubus.connect(socket_path=path) -++ -++ for wrong_args in type_errors: -++ with pytest.raises(TypeError): -++ ubus.add(*wrong_args) -++ -++ for wrong_args in runtime_errors: -++ with pytest.raises(RuntimeError): -++ ubus.add(*wrong_args) -++ -++ ubus.disconnect() -++ del wrong_args -++ -++ -++def test_add_object(ubusd_test, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ def fake(*args): -++ pass -++ -++ arguments1 = ("new_object1", {}) -++ arguments2 = ("new_object2", {"test": {"method": fake, "signature": {}}}) -++ arguments3 = ("new_object3", { -++ "test1": {"method": fake, "signature": dict(arg1=3)}, -++ "test2": {"method": fake, "signature": dict(arg2=2)}, -++ }) -++ -++ with CheckRefCount(path, fake, *(arguments1 + arguments2 + arguments3)): -++ -++ ubus.connect(socket_path=path) -++ -++ assert ubus.add(*arguments1) is None -++ assert ubus.add(*arguments2) is None -++ assert ubus.add(*arguments3) is None -++ -++ with pytest.raises(RuntimeError): -++ ubus.add(*arguments1) -++ -++ ubus.disconnect() -++ -++ -++def test_list_objects_failed(ubusd_test, registered_objects, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ type_errors = [ -++ ("more", "than", "one"), -++ ({}, ), -++ (True, ), -++ (3, ), -++ (None, ), -++ ] -++ -++ with CheckRefCount(path, *(type_errors)): -++ -++ with pytest.raises(RuntimeError): -++ ubus.objects() -++ -++ ubus.connect(socket_path=path) -++ -++ for wrong_args in type_errors: -++ with pytest.raises(TypeError): -++ ubus.objects(*wrong_args) -++ -++ ubus.disconnect() -++ del wrong_args -++ -++ -++def test_list_objects(ubusd_test, registered_objects, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ def fake(*args): -++ pass -++ -++ new_object = ("new_object", {"new_method": {"method": fake, "signature": {}}}) -++ -++ expected1 = { -++ u"registered_object1": { -++ u"method1": {}, -++ u"method2": { -++ u"first": ubus.BLOBMSG_TYPE_STRING, -++ u"second": ubus.BLOBMSG_TYPE_BOOL, -++ u"third": ubus.BLOBMSG_TYPE_INT32, -++ }, -++ }, -++ u"registered_object2": {}, -++ u"registered_object3": { -++ u"method1": {}, -++ }, -++ } -++ -++ expected2 = { -++ u"registered_object2": {}, -++ } -++ -++ expected3 = { -++ u"registered_object1": { -++ u"method1": {}, -++ u"method2": { -++ u"first": ubus.BLOBMSG_TYPE_STRING, -++ u"second": ubus.BLOBMSG_TYPE_BOOL, -++ u"third": ubus.BLOBMSG_TYPE_INT32, -++ }, -++ }, -++ u"registered_object2": {}, -++ u"registered_object3": { -++ u"method1": {}, -++ }, -++ u"new_object": { -++ u"new_method": {}, -++ }, -++ } -++ -++ expected4 = { -++ u"new_object": {"new_method": {}}, -++ } -++ -++ with CheckRefCount(path, fake, expected1, expected2, expected3, expected4, *new_object): -++ -++ ubus.connect(socket_path=path) -++ -++ # All objects -++ res1 = ubus.objects() -++ assert res1 == expected1 -++ -++ # Filtered objects -++ res2 = ubus.objects("registered_object2") -++ assert res2 == expected2 -++ -++ # Append an object -++ ubus.add(*new_object) -++ -++ # All objects + new -++ res3 = ubus.objects() -++ assert res3 == expected3 -++ -++ # New object -++ res4 = ubus.objects("new_object") -++ assert res4 == expected4 -++ -++ ubus.disconnect() -++ del res1 -++ del res2 -++ del res3 -++ del res4 -++ -++ -++def test_list_objects_empty(ubusd_test, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ with CheckRefCount(path): -++ ubus.connect(path) -++ assert ubus.objects() == {} -++ -++ ubus.disconnect() -++ -++ -++def test_reply_out_of_handler(): -++ data = {"this": "should fail"} -++ -++ with CheckRefCount(data): -++ -++ # should be called only within call -++ handler = ubus.__ResponseHandler() -++ with pytest.raises(RuntimeError): -++ handler.reply(data) -++ -++ del handler -++ -++ -++def test_reply_failed(ubusd_test, call_for_object, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ results = {e: {'data': None, 'exits': False} for e in range(1, 4)} -++ -++ def handler_fail1(handler, data): -++ results[1]['data'] = data -++ handler.reply() -++ results[1]['exits'] = True -++ -++ def handler_fail2(handler, data): -++ results[2]['data'] = data -++ handler.reply(6) -++ results[2]['exits'] = True -++ -++ def handler_fail3(handler, data): -++ results[3]['data'] = data -++ handler.reply({'data': 6}, {'fail': 'here'}) -++ results[3]['exits'] = True -++ -++ with CheckRefCount(path, results, handler_fail1, handler_fail2, handler_fail3): -++ -++ ubus.connect(path) -++ ubus.add( -++ "callee_object", -++ { -++ "method1": {"method": handler_fail1, "signature": { -++ "first": ubus.BLOBMSG_TYPE_INT32, -++ }}, -++ "method2": {"method": handler_fail2, "signature": { -++ "second": ubus.BLOBMSG_TYPE_INT32, -++ }}, -++ "method3": {"method": handler_fail3, "signature": {}}, -++ }, -++ ) -++ ubus.loop(500) -++ -++ assert results == { -++ 1: {'data': {'first': 1}, 'exits': False}, -++ 2: {'data': {'second': 2}, 'exits': False}, -++ 3: {'data': {}, 'exits': False}, -++ } -++ -++ ubus.disconnect() -++ -++ -++def test_reply(ubusd_test, call_for_object, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ results = {e: {'data': None, 'exits': False} for e in range(1, 4)} -++ -++ def handler1(handler, data): -++ results[1]['data'] = data -++ handler.reply(data) -++ results[1]['exits'] = True -++ -++ def handler2(handler, data): -++ results[2]['data'] = data -++ handler.reply(data) -++ results[2]['exits'] = True -++ -++ def handler3(handler, data): -++ results[3]['data'] = data -++ handler.reply(data) -++ results[3]['exits'] = True -++ -++ with CheckRefCount(path, results, handler1, handler2, handler3): -++ -++ ubus.connect(path) -++ ubus.add( -++ "callee_object", -++ { -++ "method1": {"method": handler1, "signature": { -++ "first": ubus.BLOBMSG_TYPE_INT32, -++ }}, -++ "method2": {"method": handler2, "signature": { -++ "second": ubus.BLOBMSG_TYPE_INT32, -++ }}, -++ "method3": {"method": handler3, "signature": {}}, -++ }, -++ ) -++ ubus.loop(500) -++ -++ assert results == { -++ 1: {'data': {'first': 1}, 'exits': True}, -++ 2: {'data': {'second': 2}, 'exits': True}, -++ 3: {'data': {}, 'exits': True}, -++ } -++ -++ ubus.disconnect() -++ -++ -++def test_call_failed(ubusd_test, responsive_object, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ args1 = ( -++ [], -++ ("responsive_object", ), -++ ("responsive_object", "respond", ), -++ ("responsive_object", "respond", 4, ), -++ ("responsive_object", "respond", {"first": "test", "second": True, "third": 56}, "x"), -++ ("responsive_object", "respond", {"first": "test", "second": True, "third": 56}, -1), -++ ) -++ args2 = ( -++ ("responsive_object", "respond", {"first": 6, "second": True, "third": 56}, ), -++ ("responsive_object", "respond", {"first": "test", "third": 56}, ), -++ ("responsive_object", "respond", {"first": "test", "second": True, "third": 56, "x": 1}), -++ ("responsive_object", "fail", {"first": "test", "second": True, "third": 56, "x": 1}), -++ ("responsive_object", "fail", {}), -++ ) -++ args3 = ( -++ ("responsive_object", "respond", {"first": "test", "second": True, "third": 56}, 2 ** 64), -++ ) -++ with CheckRefCount(path, *(args1 + args2 + args3)): -++ -++ with pytest.raises(RuntimeError): -++ ubus.objects(*args1[0]) -++ -++ ubus.connect(path) -++ for arg in args1: -++ with pytest.raises(TypeError): -++ ubus.call(*arg) -++ -++ for arg in args2: -++ with pytest.raises(RuntimeError): -++ ubus.call(*arg) -++ -++ for arg in args3: -++ with pytest.raises(OverflowError): -++ ubus.call(*arg) -++ -++ ubus.disconnect() -++ del arg -++ -++ -++def test_call(ubusd_test, responsive_object, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ ubus_object = "responsive_object" -++ method1 = "respond" -++ method2 = "multi_respond" -++ data = {"first": "1", "second": False, "third": 22} -++ -++ with CheckRefCount(path, ubus_object, method1, method2): -++ -++ ubus.connect(socket_path=path) -++ res = ubus.call(ubus_object, method1, data) -++ assert len(res) == 1 -++ assert res[0] == {"first": "1", "second": False, "third": 22, "passed": True} -++ -++ res = ubus.call(ubus_object, method1, data, timeout=200) -++ assert len(res) == 1 -++ assert res[0] == {"first": "1", "second": False, "third": 22, "passed": True} -++ -++ res = ubus.call(ubus_object, method2, {}) -++ assert len(res) == 3 -++ assert res[0] == {"passed1": True} -++ assert res[1] == {"passed1": True, "passed2": True} -++ assert res[2] == {"passed1": True, "passed2": True, "passed3": True} -++ -++ del res -++ ubus.disconnect() -++ -++ -++def test_call_max_min_number(ubusd_test, responsive_object, disconnect_after): -++ path = UBUSD_TEST_SOCKET_PATH -++ data1 = {"number": 2 ** 32} -++ data2 = {"number": -(2 ** 32)} -++ -++ with CheckRefCount(path, data1, data2): -++ -++ ubus.connect(socket_path=path) -++ res = ubus.call("responsive_object", "number", data1) -++ assert res[0] == {"number": 2 ** 31 - 1, "passed": True} -++ res = ubus.call("responsive_object", "number", data2) -++ assert res[0] == {"number": -(2 ** 31), "passed": True} -++ -++ del res -++ ubus.disconnect() -++ -++ -++def test_multi_objects_listeners(ubusd_test, event_sender, calls_extensive, disconnect_after): -++ counts = 20 -++ listen_test = {"pass%d" % e: False for e in range(counts)} -++ object_test = {"pass%d" % e: False for e in range(counts)} -++ event_name = "event_sender" -++ timeout = 200 -++ -++ path = UBUSD_TEST_SOCKET_PATH -++ -++ def passed_listen_gen(index): -++ def passed(*args): -++ listen_test["pass%d" % index] = True -++ return passed -++ -++ def passed_object_gen(index): -++ def passed(*args): -++ object_test["pass%d" % index] = True -++ return passed -++ -++ with CheckRefCount(path, time): -++ -++ for _ in range(5): -++ ubus.connect(socket_path=path) -++ -++ for i in range(counts): -++ ubus.listen((event_name, passed_listen_gen(i))) -++ ubus.add( -++ "extensive_object_%d" % i, -++ {"method": {"method": passed_object_gen(i), "signature": {}}} -++ ) -++ -++ stored_counter = calls_extensive.counter.value -++ while calls_extensive.counter.value - stored_counter < counts: -++ ubus.loop(timeout) -++ ubus.disconnect() -++ -++ for i in range(counts): -++ current = "pass%d" % i -++ assert listen_test[current] -++ assert object_test[current] -++ -++ listen_test = {"pass%d" % e: False for e in range(counts)} -++ object_test = {"pass%d" % e: False for e in range(counts)} -+diff --git a/python/ubus_python.c b/python/ubus_python.c -+new file mode 100644 -+index 0000000..d51ce43 -+--- /dev/null -++++ b/python/ubus_python.c -+@@ -0,0 +1,1324 @@ -++ -++#include <Python.h> -++#include <dlfcn.h> -++#include <libubox/blobmsg_json.h> -++#include <libubus.h> -++#include <stdio.h> -++ -++#ifndef UBUS_UNIX_SOCKET -++#define UBUS_UNIX_SOCKET "/var/run/ubus.sock" -++#endif -++ -++#define DEFAULT_SOCKET UBUS_UNIX_SOCKET -++#define RESPONSE_HANDLER_OBJECT_NAME "ubus.__ResponseHandler" -++ -++#define MSG_ALLOCATION_FAILS "Failed to allocate memory!" -++#define MSG_LISTEN_TUPLE_EXPECTED "Expected (event, callback) tuple" -++#define MSG_ADD_SIGNATURE_INVALID \ -++"Incorrect method arguments!\n" \ -++"Expected:\n" \ -++" (<obj_name>, { " \ -++ "<method_name>: {'signature': <method_signature>, 'method': <callable>}" \ -++", ...})" -++#define MSG_JSON_TO_UBUS_FAILED "Failed to create json for ubus." -++#define MSG_JSON_FROM_UBUS_FAILED "Failed to create json from ubus." -++#define MSG_NOT_CONNECTED "You are not connected to ubus." -++#define MSG_ALREADY_CONNECTED "You are already connected to ubus." -++ -++typedef struct { -++ struct ubus_object object; -++ PyObject *methods; -++} ubus_Object; -++ -++typedef struct { -++ struct ubus_event_handler handler; -++ PyObject *callback; -++}ubus_Listener ; -++ -++ -++PyObject *prepare_bool(bool yes) -++{ -++ if (yes) { -++ Py_INCREF(Py_True); -++ return Py_True; -++ } else { -++ Py_INCREF(Py_False); -++ return Py_False; -++ } -++} -++ -++/* ubus module objects */ -++static PyMethodDef ubus_methods[]; -++PyObject *python_alloc_list = NULL; -++char *socket_path = NULL; -++ubus_Listener **listeners = NULL; -++size_t listerners_size = 0; -++ubus_Object **objects = NULL; -++size_t objects_size = 0; -++struct blob_buf python_buf; -++struct ubus_context *ctx = NULL; -++ -++#define CONNECTED (ctx != NULL) -++ -++ -++/* json module handlers */ -++PyObject *json_module = NULL; -++ -++enum json_function { -++ LOADS, -++ DUMPS, -++}; -++ -++const char *json_function_names[2] = { -++ [LOADS] = "loads", -++ [DUMPS] = "dumps", -++}; -++ -++ -++PyObject *perform_json_function(enum json_function json_function, PyObject *input) -++{ -++ PyObject *function = PyObject_GetAttrString(json_module, json_function_names[json_function]); -++ if (!function) { -++ return NULL; -++ } -++ PyObject *arglist = Py_BuildValue("(O)", input); -++ if (!arglist) { -++ Py_DECREF(function); -++ return NULL; -++ } -++ PyObject *data_object = PyObject_CallObject(function, arglist); -++ Py_DECREF(function); -++ Py_DECREF(arglist); -++ -++ return data_object; // New reference - should be decreased by the caller -++} -++ -++/* ResponseHandler */ -++ -++typedef struct { -++ PyObject_HEAD -++ struct ubus_context *ctx; -++ struct ubus_request_data *req; -++ struct blob_buf buf; -++} ubus_ResponseHandler; -++ -++static void ubus_ResponseHandler_dealloc(ubus_ResponseHandler* self) -++{ -++ blob_buf_free(&self->buf); -++ Py_TYPE(self)->tp_free((PyObject*)self); -++} -++ -++PyDoc_STRVAR( -++ ResponseHandler_reply_doc, -++ "reply(data)\n" -++ "\n" -++ ":param data: JSON to be send as a response to a ubus call.\n" -++ ":type data: dict\n" -++); -++ -++static PyObject *ubus_ResponseHandler_reply(ubus_ResponseHandler *self, PyObject *args, PyObject *kwargs) -++{ -++ if (!CONNECTED) { -++ PyErr_Format(PyExc_RuntimeError, MSG_NOT_CONNECTED); -++ return NULL; -++ } -++ -++ PyObject *data = NULL; -++ static char *kwlist[] = {"data", NULL}; -++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &data)) { -++ return NULL; -++ } -++ -++ // Call python function json.dumps -++ PyObject *json_str = perform_json_function(DUMPS, data); -++ if (!json_str) { -++ return NULL; -++ } -++ -++ // put json string into buffer -++ blob_buf_init(&self->buf, 0); -++ bool res = blobmsg_add_json_from_string(&self->buf, PyString_AsString(json_str)); -++ Py_DECREF(json_str); -++ if (!res) { -++ PyErr_Format(PyExc_TypeError, MSG_JSON_TO_UBUS_FAILED); -++ return NULL; -++ } -++ -++ // handler is not linked to a call response -++ if (!self->req || !self->ctx) { -++ PyErr_Format(PyExc_RuntimeError, "Handler is not linked to a call response."); -++ return NULL; -++ } -++ -++ int retval = ubus_send_reply(self->ctx, self->req, self->buf.head); -++ return prepare_bool(!retval); -++} -++ -++PyDoc_STRVAR( -++ ResponseHandler_doc, -++ "__ResponseHandler\n" -++ "\n" -++ "Object which is used to handle responses to ubus calls.\n" -++); -++ -++static PyMethodDef ubus_ResponseHandler_methods[] = { -++ {"reply", (PyCFunction)ubus_ResponseHandler_reply, METH_VARARGS|METH_KEYWORDS, ResponseHandler_reply_doc}, -++ {NULL}, -++}; -++ -++static int ubus_ResponseHandler_init(ubus_ResponseHandler *self, PyObject *args, PyObject *kwargs) -++{ -++ static char *kwlist[] = {NULL}; -++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwlist)){ -++ return -1; -++ } -++ memset(&self->buf, 0, sizeof(self->buf)); -++ self->ctx = NULL; -++ self->req = NULL; -++ return 0; -++} -++ -++static PyObject *ubus_ResponseHandler_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) -++{ -++ ubus_ResponseHandler *self = (ubus_ResponseHandler *)type->tp_alloc(type, 0); -++ return (PyObject *)self; -++} -++ -++static PyTypeObject ubus_ResponseHandlerType = { -++ PyVarObject_HEAD_INIT(NULL, 0) -++ RESPONSE_HANDLER_OBJECT_NAME, /* tp_name */ -++ sizeof(ubus_ResponseHandler), /* tp_basicsize */ -++ 0, /* tp_itemsize */ -++ (destructor)ubus_ResponseHandler_dealloc, /* tp_dealloc */ -++ 0, /* tp_print */ -++ 0, /* tp_getattr */ -++ 0, /* tp_setattr */ -++ 0, /* tp_compare */ -++ 0, /* tp_repr */ -++ 0, /* tp_as_number */ -++ 0, /* tp_as_sequence */ -++ 0, /* tp_as_mapping */ -++ 0, /* tp_hash */ -++ 0, /* tp_call */ -++ 0, /* tp_str */ -++ 0, /* tp_getattro */ -++ 0, /* tp_setattro */ -++ 0, /* tp_as_buffer */ -++ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ -++ ResponseHandler_doc, /* tp_doc */ -++ 0, /* tp_traverse */ -++ 0, /* tp_clear */ -++ 0, /* tp_richcompare */ -++ 0, /* tp_weaklistoffset */ -++ 0, /* tp_iter */ -++ 0, /* tp_iternext */ -++ ubus_ResponseHandler_methods, /* tp_methods */ -++ 0, /* tp_members */ -++ 0, /* tp_getset */ -++ 0, /* tp_base */ -++ 0, /* tp_dict */ -++ 0, /* tp_descr_get */ -++ 0, /* tp_descr_set */ -++ 0, /* tp_dictoffset */ -++ (initproc)ubus_ResponseHandler_init, /* tp_init */ -++ 0, /* tp_alloc */ -++ ubus_ResponseHandler_new, /* tp_new */ -++}; -++ -++typedef struct { -++ PyObject_HEAD -++ PyObject *socket_path; -++ ubus_Listener **listeners; -++ size_t listerners_size; -++ ubus_Object **objects; -++ size_t objects_size; -++ PyObject *alloc_list; // Used for easy deallocation -++ struct blob_buf buf; -++ struct ubus_context *ctx; -++} ubus_Connection; -++ -++void free_ubus_object(ubus_Object *obj) -++{ -++ if (obj->object.methods) { -++ for (int i = 0; i < obj->object.n_methods; i++) { -++ if (&obj->object.methods[i] && obj->object.methods[i].policy) { -++ free((struct blobmsg_policy *)obj->object.methods[i].policy); -++ } -++ } -++ free((struct ubus_method *)obj->object.methods); -++ } -++ -++ if (obj->object.type) { -++ free(obj->object.type); -++ } -++ free(obj); -++} -++ -++PyObject *ubus_python_module_init(void) -++{ -++ PyObject *module = Py_InitModule3("ubus", ubus_methods, "Ubus bindings"); -++ return module; -++} -++ -++PyDoc_STRVAR( -++ disconnect_doc, -++ "disconnect(deregister=True)\n" -++ "\n" -++ ":param deregister: Deregisters object and handlers from ubus as well.\n" -++ ":type deregister: bool\n" -++ "Disconnects from ubus and disposes all connection structures.\n" -++); -++ -++void dispose_connection(bool deregister) -++{ -++ if (ctx != NULL) { -++ if (deregister) { -++ // remove objects -++ for (int i = 0; i < objects_size; i++) { -++ ubus_remove_object(ctx, &objects[i]->object); -++ } -++ -++ // remove listeners -++ for (int i = 0; i < listerners_size; i++) { -++ ubus_unregister_event_handler(ctx, &listeners[i]->handler); -++ } -++ } -++ -++ ubus_free(ctx); -++ ctx = NULL; -++ } -++ uloop_done(); -++ blob_buf_free(&python_buf); -++ if (python_alloc_list) { -++ Py_DECREF(python_alloc_list); -++ python_alloc_list = NULL; -++ } -++ // clear event listeners -++ if (listeners) { -++ for (int i = 0; i < listerners_size; i++) { -++ free(listeners[i]); -++ } -++ free(listeners); -++ listerners_size = 0; -++ listeners = NULL; -++ } -++ // clear objects -++ if (objects) { -++ for (int i = 0; i < objects_size; i++) { -++ free_ubus_object(objects[i]); -++ } -++ free(objects); -++ objects_size = 0; -++ objects = NULL; -++ } -++ -++ if (socket_path) { -++ free(socket_path); -++ socket_path = NULL; -++ } -++} -++ -++static PyObject *ubus_python_disconnect(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ if (!CONNECTED) { -++ PyErr_Format(PyExc_RuntimeError, MSG_NOT_CONNECTED); -++ return NULL; -++ } -++ -++ PyObject* deregister = Py_True; -++ static char *kwlist[] = {"deregister", NULL}; -++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O!", kwlist, &PyBool_Type, &deregister)){ -++ return NULL; -++ } -++ -++ dispose_connection(PyObject_IsTrue(deregister)); -++ -++ Py_INCREF(Py_None); -++ return Py_None; -++} -++ -++PyDoc_STRVAR( -++ connect_doc, -++ "connect(socket_path='" DEFAULT_SOCKET "')\n" -++ "\n" -++ "Establishes a connection to ubus.\n" -++); -++ -++static PyObject *ubus_python_connect(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ if (CONNECTED) { -++ PyErr_Format(PyExc_RuntimeError, MSG_ALREADY_CONNECTED); -++ return NULL; -++ } -++ -++ static char *kwlist[] = {"socket_path", NULL}; -++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &socket_path)){ -++ return NULL; -++ } -++ -++ // Init object list -++ python_alloc_list = PyList_New(0); -++ if (!python_alloc_list) { -++ return NULL; -++ } -++ -++ // socket path -++ if (!socket_path) { -++ socket_path = strdup(DEFAULT_SOCKET); -++ if (!socket_path) { -++ PyErr_Format(PyExc_MemoryError, MSG_ALLOCATION_FAILS); -++ return NULL; -++ } -++ } else { -++ char *tmp = strdup(socket_path); -++ if (!tmp) { -++ PyErr_Format(PyExc_MemoryError, MSG_ALLOCATION_FAILS); -++ return NULL; -++ } -++ socket_path = tmp; -++ } -++ -++ // Init event listner array -++ listeners = NULL; -++ listerners_size = 0; -++ -++ // Init objects array -++ objects = NULL; -++ objects_size = 0; -++ -++ // Connect to ubus -++ ctx = ubus_connect(socket_path); -++ if (!ctx) { -++ PyErr_Format( -++ PyExc_IOError, -++ "Failed to connect to the ubus socket '%s'\n", socket_path -++ ); -++ dispose_connection(true); -++ return NULL; -++ } -++ ubus_add_uloop(ctx); -++ memset(&python_buf, 0, sizeof(python_buf)); -++ -++ return prepare_bool(true); -++} -++ -++PyDoc_STRVAR( -++ get_connected_doc, -++ "get_connected()\n" -++ "\n" -++ "Determines whether we are connected to ubus.\n" -++ ":return: True if connected, False otherwise.\n" -++ ":rtype: bool \n" -++); -++ -++static PyObject *ubus_python_get_connected(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ return prepare_bool(CONNECTED); -++} -++ -++PyDoc_STRVAR( -++ get_socket_path_doc, -++ "get_socket_path()\n" -++ "\n" -++ "Gets socket path for the current connection.\n" -++ ":return: path to socket if connected, None otherwise.\n" -++ ":rtype: bool or str \n" -++); -++ -++static PyObject *ubus_python_get_socket_path(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ if (socket_path) { -++ return PyString_FromString(socket_path); -++ } else { -++ Py_INCREF(Py_None); -++ return Py_None; -++ } -++} -++ -++PyDoc_STRVAR( -++ connect_send_doc, -++ "send(event, data)\n" -++ "\n" -++ "Send an event via ubus.\n" -++ "\n" -++ ":param event: ubus event which will be used \n" -++ ":type event: str\n" -++ ":param data: python object which can be serialized to json \n" -++ ":type data: dict or list \n" -++ ":return: True on success, False otherwise \n" -++ ":rtype: bool \n" -++); -++ -++static PyObject *ubus_python_send(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ if (!CONNECTED) { -++ PyErr_Format(PyExc_RuntimeError, MSG_NOT_CONNECTED); -++ return NULL; -++ } -++ -++ char *event = NULL; -++ PyObject *data = NULL; -++ static char *kwlist[] = {"event", "data", NULL}; -++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO", kwlist, &event, &data)){ -++ return NULL; -++ } -++ -++ // Call python function json.dumps -++ PyObject *json_str = perform_json_function(DUMPS, data); -++ if (!json_str) { -++ return NULL; -++ } -++ -++ // put json string into buffer -++ blob_buf_init(&python_buf, 0); -++ bool res = blobmsg_add_json_from_string(&python_buf, PyString_AsString(json_str)); -++ Py_DECREF(json_str); -++ if (!res) { -++ PyErr_Format(PyExc_TypeError, MSG_JSON_TO_UBUS_FAILED); -++ return NULL; -++ } -++ -++ int retval = ubus_send_event(ctx, event, python_buf.head); -++ return prepare_bool(!retval); -++} -++ -++static void ubus_python_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, -++ const char *type, struct blob_attr *msg) -++{ -++ PyGILState_STATE gstate = PyGILState_Ensure(); -++ -++ // Prepare event -++ PyObject *event = PyString_FromString(type); -++ if (!event) { -++ goto event_handler_cleanup0; -++ } -++ -++ // Prepare json data -++ char *str = blobmsg_format_json(msg, true); -++ if (!str) { -++ goto event_handler_cleanup1; -++ } -++ PyObject *data = PyString_FromString(str); -++ free(str); -++ if (!data) { -++ goto event_handler_cleanup1; -++ } -++ -++ // Call python function json.loads -++ PyObject *data_object = perform_json_function(LOADS, data); -++ if (!data_object) { -++ goto event_handler_cleanup2; -++ } -++ -++ // Get PyObject callback -++ ubus_Listener *listener = container_of(ev, ubus_Listener, handler); -++ -++ // Trigger callback -++ PyObject *callback_arglist = Py_BuildValue("(O, O)", event, data_object); -++ if (!callback_arglist) { -++ goto event_handler_cleanup3; -++ } -++ -++ PyObject *result = PyObject_CallObject(listener->callback, callback_arglist); -++ if (result) { -++ Py_DECREF(result); // result of the callback is quite useless -++ } else { -++ PyErr_Print(); -++ } -++ Py_DECREF(callback_arglist); -++ -++event_handler_cleanup3: -++ Py_DECREF(data_object); -++event_handler_cleanup2: -++ Py_DECREF(data); -++event_handler_cleanup1: -++ Py_DECREF(event); -++ -++event_handler_cleanup0: -++ // Clear python exceptions -++ PyErr_Clear(); -++ -++ PyGILState_Release(gstate); -++} -++ -++PyDoc_STRVAR( -++ connect_listen_doc, -++ "listen(event, ...)\n" -++ "\n" -++ "Adds a listener on ubus events.\n" -++ "\n" -++ ":param event: tuple contaning event string and a callback (str, callable) \n" -++ ":type event: tuple\n" -++); -++ -++static PyObject *ubus_python_listen(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ if (!CONNECTED) { -++ PyErr_Format(PyExc_RuntimeError, MSG_NOT_CONNECTED); -++ return NULL; -++ } -++ -++ args = PySequence_Fast(args, "expected a sequence"); -++ int len = PySequence_Size(args); -++ if (!len) { -++ PyErr_Format(PyExc_TypeError, "You need to set at least one event."); -++ goto listen_error1; -++ } -++ -++ if (!PyTuple_Check(args)) { -++ PyErr_Format(PyExc_TypeError, "Tuple of (event, callback) expected."); -++ goto listen_error1; -++ } -++ -++ // Test whether the arguments are valid -++ for (int i = 0; i < len; i++) { -++ PyObject *item = PySequence_Fast_GET_ITEM(args, i); -++ // Test tuple -++ if (!PyTuple_Check(item)) { -++ PyErr_Format(PyExc_TypeError, MSG_LISTEN_TUPLE_EXPECTED); -++ goto listen_error1; -++ } -++ PyObject *item_tuple = PySequence_Fast(item, MSG_LISTEN_TUPLE_EXPECTED); -++ if (!item_tuple) { -++ PyErr_Format(PyExc_MemoryError, "Failed to obtain tuple item"); -++ goto listen_error1; -++ } -++ if (!PyTuple_Check(item_tuple) || PySequence_Size(item_tuple) != 2) { -++ PyErr_Format(PyExc_TypeError, MSG_LISTEN_TUPLE_EXPECTED); -++ Py_DECREF(item_tuple); -++ Py_DECREF(args); -++ goto listen_error1; -++ } -++ -++ // Test types -++ if (!PyString_Check(PyTuple_GET_ITEM(item_tuple, 0)) -++ || !PyCallable_Check(PyTuple_GET_ITEM(item_tuple, 1))) { -++ PyErr_Format(PyExc_TypeError, MSG_LISTEN_TUPLE_EXPECTED); -++ Py_DECREF(item_tuple); -++ goto listen_error1; -++ } -++ Py_DECREF(item_tuple); -++ } -++ -++ // add callbacks -++ for (int i = 0; i < len; i++) { -++ PyObject *item = PySequence_Fast_GET_ITEM(args, i); -++ PyObject *item_tuple = PySequence_Fast(item, MSG_LISTEN_TUPLE_EXPECTED); -++ if (!item_tuple) { -++ PyErr_Format(PyExc_MemoryError, "Failed to obtain tuple item"); -++ goto listen_error1; -++ } -++ PyObject *event = PyTuple_GET_ITEM(item_tuple, 0); -++ PyObject *callback = PyTuple_GET_ITEM(item_tuple, 1); -++ // Keep event and callback references -++ if (PyList_Append(python_alloc_list, event) || PyList_Append(python_alloc_list, callback)) { -++ Py_DECREF(item_tuple); -++ goto listen_error1; -++ } -++ Py_DECREF(item_tuple); -++ -++ // prepare event listener -++ ubus_Listener *listener = calloc(1, sizeof(ubus_Listener)); -++ if (!listener) { -++ PyErr_Format(PyExc_MemoryError, MSG_ALLOCATION_FAILS); -++ Py_DECREF(item_tuple); -++ goto listen_error1; -++ } -++ -++ listener->handler.cb = ubus_python_event_handler; -++ listener->callback = callback; -++ -++ ubus_Listener **new_listeners = realloc(listeners, -++ (listerners_size + 1) * sizeof(*listeners)); -++ if (!new_listeners) { -++ free(listener); -++ goto listen_error1; -++ } -++ listeners = new_listeners; -++ listeners[listerners_size++] = listener; -++ -++ // register event handler -++ int retval = ubus_register_event_handler(ctx, &listener->handler, PyString_AsString(event)); -++ if (retval != UBUS_STATUS_OK) { -++ listerners_size--; -++ free(listener); -++ } -++ } -++ -++ Py_DECREF(args); -++ -++ Py_INCREF(Py_None); -++ return Py_None; -++ -++listen_error1: -++ Py_DECREF(args); -++ return NULL; -++} -++ -++static void ubus_python_timeout_handler(struct uloop_timeout *timeout) { -++ uloop_end(); -++} -++ -++PyDoc_STRVAR( -++ connect_loop_doc, -++ "loop(timeout=-1)\n" -++ "\n" -++ "Enters a loop and processes events.\n" -++ "\n" -++ ":param timeout: loop timeout in ms (if lower than zero then it will run forever) \n" -++ ":type timeout: int\n" -++); -++ -++static PyObject *ubus_python_loop(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ if (!CONNECTED) { -++ PyErr_Format(PyExc_RuntimeError, MSG_NOT_CONNECTED); -++ return NULL; -++ } -++ -++ int timeout = -1; -++ static char *kwlist[] = {"timeout", NULL}; -++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout)){ -++ return NULL; -++ } -++ -++ Py_BEGIN_ALLOW_THREADS -++ if (timeout == 0) { -++ // process events directly without uloop -++ ubus_handle_event(ctx); -++ } else { -++ uloop_init(); -++ struct uloop_timeout u_timeout; -++ if (timeout > 0) { -++ // prepare for timeout -++ memset(&u_timeout, 0, sizeof(u_timeout)); -++ u_timeout.cb = ubus_python_timeout_handler; -++ uloop_timeout_set(&u_timeout, timeout); // Timeout to seconds -++ } -++ uloop_run(); -++ if (timeout > 0) { -++ uloop_timeout_cancel(&u_timeout); -++ } -++ } -++ Py_END_ALLOW_THREADS -++ -++ Py_INCREF(Py_None); -++ return Py_None; -++} -++ -++bool test_policies(const struct blobmsg_policy *policies, int n_policies, struct blob_attr *args) -++{ -++ struct blob_attr *cur; -++ int idx = 0, passed_count = 0; -++ -++ blob_for_each_attr(cur, args, idx) { -++ const char *name = blobmsg_name(cur); -++ int type = blobmsg_type(cur); -++ int pol_idx; -++ -++ // Iterate through policies -++ for (pol_idx = 0; pol_idx < n_policies; pol_idx++) { -++ -++ if (!strcmp(name, policies[pol_idx].name)) { -++ passed_count += 1; -++ int pol_type = policies[pol_idx].type; -++ if (pol_type != BLOBMSG_TYPE_UNSPEC && pol_type != type) { -++ return false; -++ } -++ break; -++ } -++ } -++ -++ // Policy was not found -++ if (pol_idx >= n_policies) { -++ return false; -++ } -++ } -++ -++ // All attributes are present and checked -++ return passed_count == n_policies; -++} -++ -++static int ubus_python_method_handler(struct ubus_context *ctx, struct ubus_object *obj, -++ struct ubus_request_data *req, const char *method, -++ struct blob_attr *msg) -++{ -++ // Check whether method signature matches -++ int method_idx; -++ for (method_idx = 0; method_idx < obj->n_methods; ++method_idx) { -++ if (!strcmp(obj->methods[method_idx].name, method)) { -++ break; -++ } -++ } -++ if (method_idx >= obj->n_methods) { -++ // Can't find method -++ return UBUS_STATUS_UNKNOWN_ERROR; -++ } -++ if (!test_policies(obj->methods[method_idx].policy, obj->methods[method_idx].n_policy, msg)) { -++ return UBUS_STATUS_INVALID_ARGUMENT; -++ } -++ -++ PyGILState_STATE gstate = PyGILState_Ensure(); -++ -++ int retval = UBUS_STATUS_OK; -++ // Get python method -++ PyObject *methods = container_of(obj, ubus_Object, object)->methods; -++ PyObject *python_method = PyDict_GetItemString(methods, method); -++ if (!python_method) { -++ retval = UBUS_STATUS_METHOD_NOT_FOUND; -++ goto method_handler_exit; -++ } -++ -++ // prepare json data -++ char *str = blobmsg_format_json(msg, true); -++ if (!str) { -++ retval = UBUS_STATUS_UNKNOWN_ERROR; -++ goto method_handler_exit; -++ } -++ PyObject *data = PyString_FromString(str); -++ free(str); -++ if (!data) { -++ retval = UBUS_STATUS_UNKNOWN_ERROR; -++ goto method_handler_exit; -++ } -++ -++ // Call python function json.loads -++ PyObject *data_object = perform_json_function(LOADS, data); -++ if (!data_object) { -++ retval = UBUS_STATUS_UNKNOWN_ERROR; -++ goto method_handler_cleanup1; -++ } -++ -++ PyObject *handler = PyObject_CallObject((PyObject *)&ubus_ResponseHandlerType, NULL); -++ if (!handler) { -++ PyErr_Print(); -++ goto method_handler_cleanup2; -++ } -++ ((ubus_ResponseHandler *)handler)->req = req; -++ ((ubus_ResponseHandler *)handler)->ctx = ctx; -++ -++ // Trigger method -++ PyObject *callback_arglist = Py_BuildValue("(O, O)", handler, data_object); -++ if (!callback_arglist) { -++ retval = UBUS_STATUS_UNKNOWN_ERROR; -++ goto method_handler_cleanup3; -++ } -++ PyObject *callable = PyDict_GetItemString(python_method, "method"); -++ PyObject *result = PyObject_CallObject(callable, callback_arglist); -++ Py_DECREF(callback_arglist); -++ if (!result) { -++ PyErr_Print(); -++ retval = UBUS_STATUS_UNKNOWN_ERROR; -++ } else { -++ Py_DECREF(result); // we don't care about the result -++ } -++ -++method_handler_cleanup3: -++ // NULLify the structures so that using this structure will we useless if a reference -++ // is left outside the callback code -++ ((ubus_ResponseHandler *)handler)->req = NULL; -++ ((ubus_ResponseHandler *)handler)->ctx = NULL; -++ Py_DECREF(handler); -++method_handler_cleanup2: -++ Py_DECREF(data_object); -++method_handler_cleanup1: -++ Py_DECREF(data); -++method_handler_exit: -++ -++ // Clear python exceptions -++ PyErr_Clear(); -++ -++ PyGILState_Release(gstate); -++ -++ return retval; -++} -++ -++static bool test_methods_argument(PyObject *methods) -++{ -++ if (!methods) { -++ return false; -++ } -++ -++ PyObject *method_name = NULL, *value = NULL; -++ Py_ssize_t pos = 0; -++ // Iterate through methods -++ while(PyDict_Next(methods, &pos, &method_name, &value)) { -++ // Test name -++ if (!PyString_Check(method_name)) { -++ return false; -++ } -++ if (!PyDict_Check(value)) { -++ return false; -++ } -++ -++ // Dict should contain only two elemnts - 'signature' and 'method' -++ if (PyDict_Size(value) != 2) { -++ return false; -++ } -++ -++ // Test signature -++ PyObject *signature = PyDict_GetItemString(value, "signature"); -++ if (!signature || !PyDict_Check(signature)) { -++ return false; -++ } -++ Py_ssize_t sig_pos = 0; -++ PyObject *signature_name = NULL, *signature_type = NULL; -++ while (PyDict_Next(signature, &sig_pos, &signature_name, &signature_type)) { -++ if (!PyString_Check(signature_name)) { -++ return false; -++ } -++ if (!PyInt_Check(signature_type)) { -++ return false; -++ } -++ int type = PyInt_AsLong(signature_type); -++ if (type < 0 || type > BLOBMSG_TYPE_LAST) { // indexed from 0 -++ return false; -++ } -++ } -++ -++ // Test callable -++ PyObject *method = PyDict_GetItemString(value, "method"); -++ if (!method || !PyCallable_Check(method)) { -++ return false; -++ } -++ } -++ -++ return true; -++} -++ -++PyDoc_STRVAR( -++ connect_add_doc, -++ "add(object_name, methods)\n" -++ "\n" -++ "Adds an object to ubus.\n" -++ "methods should look like this: \n" -++ "{ \n" -++ " <method_name>: {'signature': <method_signature>, 'method': <callable>} \n" -++ "} \n" -++ "\n" -++ "{ \n" -++ " test: {'signature': {'argument1': BLOBMSG_TYPE_STRING}, 'method': my_callback} \n" -++ "} \n" -++ "\n" -++ ":param object_name: the name of the object which will be present on ubus \n" -++ ":type object_name: str\n" -++ ":param methods: {<method_name>: callable} where callable signature is (request, msg) \n" -++ ":type methods: dict\n" -++); -++ -++static PyObject *ubus_python_add(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ if (!CONNECTED) { -++ PyErr_Format(PyExc_RuntimeError, MSG_NOT_CONNECTED); -++ return NULL; -++ } -++ -++ // arguments -++ PyObject *object_name = NULL; -++ PyObject *methods= NULL; -++ static char *kwlist[] = {"object_name", "methods", NULL}; -++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, &object_name, &methods)){ -++ return NULL; -++ } -++ -++ // test arguments -++ if (!PyString_Check(object_name)) { -++ PyErr_Format(PyExc_TypeError, MSG_ADD_SIGNATURE_INVALID); -++ return NULL; -++ } -++ -++ if (!test_methods_argument(methods)) { -++ PyErr_Format(PyExc_TypeError, MSG_ADD_SIGNATURE_INVALID); -++ return NULL; -++ } -++ -++ // allocate the object -++ ubus_Object *object = calloc(1, sizeof(ubus_Object)); -++ if (!object) { -++ PyErr_Format(PyExc_MemoryError, MSG_ALLOCATION_FAILS); -++ return NULL; -++ } -++ object->methods = methods; -++ -++ // set the object -++ object->object.name = PyString_AsString(object_name); -++ object->object.n_methods = PyDict_Size(methods); -++ -++ if (object->object.n_methods > 0) { -++ struct ubus_method *ubus_methods = calloc(object->object.n_methods, sizeof(struct ubus_method)); -++ if (!ubus_methods) { -++ free(object); -++ PyErr_Format(PyExc_MemoryError, MSG_ALLOCATION_FAILS); -++ return NULL; -++ } -++ -++ PyObject *method_name = NULL, *value = NULL; -++ Py_ssize_t pos = 0; -++ // Iterate through methods -++ for (int i = 0; PyDict_Next(methods, &pos, &method_name, &value); i++) { -++ ubus_methods[i].name = PyString_AsString(method_name); -++ ubus_methods[i].handler = ubus_python_method_handler; -++ -++ // alocate and set policy objects -++ PyObject *signature = PyDict_GetItemString(value, "signature"); -++ Py_ssize_t signature_size = PyDict_Size(signature); -++ struct blobmsg_policy *policy = calloc(signature_size, sizeof(struct blobmsg_policy)); -++ if (!policy) { -++ // dealloc allocated data -++ free_ubus_object(object); -++ PyErr_Format(PyExc_MemoryError, MSG_ALLOCATION_FAILS); -++ return NULL; -++ } -++ Py_ssize_t sig_pos = 0; -++ PyObject *signature_name = NULL, *signature_type = NULL; -++ for (int j = 0; PyDict_Next(signature, &sig_pos, &signature_name, &signature_type); j++) { -++ policy[j].name = PyString_AsString(signature_name); -++ policy[j].type = PyInt_AsLong(signature_type); -++ } -++ ubus_methods[i].policy = policy; -++ ubus_methods[i].n_policy = signature_size; -++ } -++ -++ // assign methods -++ object->object.methods = ubus_methods; -++ } -++ -++ object->object.type = calloc(1, sizeof(struct ubus_object_type)); -++ if (!object->object.type) { -++ free_ubus_object(object); -++ PyErr_Format(PyExc_MemoryError, MSG_ALLOCATION_FAILS); -++ return NULL; -++ } -++ object->object.type->name = PyString_AsString(object_name); -++ object->object.type->methods = object->object.methods; -++ object->object.type->n_methods = object->object.n_methods; -++ -++ // add object to object array to be deallocated later -++ ubus_Object **new_objects = realloc(objects, -++ (objects_size + 1) * sizeof(*objects)); -++ if (!new_objects) { -++ // dealloc the object -++ free_ubus_object(object); -++ PyErr_Format(PyExc_MemoryError, MSG_ALLOCATION_FAILS); -++ return NULL; -++ } -++ objects = new_objects; -++ objects[objects_size++] = object; -++ -++ int ret = ubus_add_object(ctx, &object->object); -++ if (ret) { -++ // deallocate object on failure -++ objects_size--; // no need to realloc the whole array -++ free_ubus_object(object); -++ -++ PyErr_Format( -++ PyExc_RuntimeError, -++ "ubus error occured: %s", ubus_strerror(ret) -++ ); -++ return NULL; -++ } -++ -++ // put arguments into alloc list (used for reference counting) -++ if (PyList_Append(python_alloc_list, object_name)) { -++ ubus_remove_object(ctx, &object->object); -++ free_ubus_object(object); -++ return NULL; -++ } -++ -++ if (PyList_Append(python_alloc_list, methods)) { -++ ubus_remove_object(ctx, &object->object); -++ free_ubus_object(object); -++ PyEval_CallMethod(python_alloc_list, "pop", ""); -++ return NULL; -++ } -++ -++ Py_INCREF(Py_None); -++ return Py_None; -++} -++ -++static void ubus_python_objects_handler(struct ubus_context *c, struct ubus_object_data *o, void *p) -++{ -++ // should be a single instance for all the objects -++ PyObject *objects = (PyObject *)p; -++ -++ PyObject *str_signatures = PyString_FromString("{"); -++ if (!str_signatures) { -++ return; -++ } -++ -++ bool first = true; -++ if (o->signature) { -++ struct blob_attr *cur; -++ int rem = 0; -++ blob_for_each_attr(cur, o->signature, rem) { -++ char *s = blobmsg_format_json(cur, false); -++ if (!s) { -++ goto object_handler_cleanup; -++ } -++ PyObject *str_signature = NULL; -++ if (first) { -++ first = false; -++ str_signature = PyString_FromString(s); -++ } else { -++ str_signature = PyString_FromFormat(" ,%s", s); -++ } -++ free(s); -++ if (!str_signature) { -++ goto object_handler_cleanup; -++ } -++ PyString_Concat(&str_signatures, str_signature); -++ Py_DECREF(str_signature); -++ if (!str_signatures) { -++ return; //str_signatures already discarded in PyString_Concat -++ } -++ } -++ } -++ -++ PyObject *closing_bracket = PyString_FromString("}"); -++ PyString_Concat(&str_signatures, closing_bracket); -++ Py_DECREF(closing_bracket); -++ if (!str_signatures) { -++ return; -++ } -++ -++ // convert json string to json -++ PyObject *json_signatures = perform_json_function(LOADS, str_signatures); -++ if (!json_signatures) { -++ goto object_handler_cleanup; -++ } -++ -++ // Add it to dict object -++ PyObject *path = PyUnicode_FromString(o->path); -++ if (!path) { -++ goto object_handler_cleanup; -++ } -++ PyDict_SetItem(objects, path, json_signatures); // we don't care about retval here -++ Py_DECREF(path); -++ -++object_handler_cleanup: -++ Py_DECREF(str_signatures); -++ -++ // Clear python exceptions -++ PyErr_Clear(); -++} -++ -++PyDoc_STRVAR( -++ connect_objects_doc, -++ "objects(path='*')\n" -++ "\n" -++ "Prints all objects present on ubus\n" -++ "\n" -++ ":param path: only object which match the given path \n" -++ ":type path: str\n" -++ ":return: {<object_path>: {{<function_name>: <function_signature>}, ...}, ...} \n" -++ ":rtype: dict\n" -++); -++ -++static PyObject *ubus_python_objects(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ if (!CONNECTED) { -++ PyErr_Format(PyExc_RuntimeError, MSG_NOT_CONNECTED); -++ return NULL; -++ } -++ -++ char *ubus_path = NULL; -++ static char *kwlist[] = {"path", NULL}; -++ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwlist, &ubus_path)){ -++ return NULL; -++ } -++ -++ ubus_path = ubus_path ? ubus_path : "*"; -++ -++ PyObject *res = PyDict_New(); -++ if (!res) { -++ return NULL; -++ } -++ -++ int retval = ubus_lookup(ctx, ubus_path, ubus_python_objects_handler, res); -++ switch (retval) { -++ case UBUS_STATUS_OK: -++ case UBUS_STATUS_NOT_FOUND: -++ break; -++ default: -++ Py_DECREF(res); -++ PyErr_Format( -++ PyExc_RuntimeError, -++ "ubus error occured: %s", ubus_strerror(retval) -++ ); -++ return NULL; -++ } -++ -++ return res; -++} -++ -++static void ubus_python_call_handler(struct ubus_request *req, int type, struct blob_attr *msg) -++{ -++ assert(type == UBUS_MSG_DATA); -++ -++ PyObject **results = (PyObject **)req->priv; -++ if (!*results) { -++ // error has occured in some previous call -> exit -++ return; -++ } -++ -++ if (!msg) { -++ PyErr_Format(PyExc_RuntimeError, "No data in call hander"); -++ goto call_handler_cleanup; -++ } -++ -++ // convert message do python json object -++ char *str = blobmsg_format_json(msg, true); -++ if (!str) { -++ PyErr_Format(PyExc_RuntimeError, MSG_JSON_FROM_UBUS_FAILED); -++ goto call_handler_cleanup; -++ } -++ PyObject *data = PyString_FromString(str); -++ free(str); -++ if (!data) { -++ goto call_handler_cleanup; -++ } -++ PyObject *data_object = perform_json_function(LOADS, data); -++ Py_DECREF(data); -++ if (!data_object) { -++ goto call_handler_cleanup; -++ } -++ -++ // append to results -++ int failed = PyList_Append(*results, data_object); -++ Py_DECREF(data_object); -++ if (failed) { -++ goto call_handler_cleanup; -++ } -++ -++ return; -++ -++ call_handler_cleanup: -++ -++ // clear the result -++ Py_DECREF(*results); -++ results = NULL; -++} -++ -++PyDoc_STRVAR( -++ connect_call_doc, -++ "call(object, method, arguments, timeout=0)\n" -++ "\n" -++ "Calls object's method on ubus.\n" -++ "\n" -++ ":param object: name of the object\n" -++ ":type object: str\n" -++ ":param method: name of the method\n" -++ ":type method: str\n" -++ ":param arguments: arguments of the method (should be JSON serialisable).\n" -++ ":type argument: dict\n" -++ ":param timeout: timeout in ms (0 = wait forever)\n" -++ ":type timeout: int\n" -++); -++ -++static PyObject *ubus_python_call(PyObject *module, PyObject *args, PyObject *kwargs) -++{ -++ if (!CONNECTED) { -++ PyErr_Format(PyExc_RuntimeError, MSG_NOT_CONNECTED); -++ return NULL; -++ } -++ -++ char *object = NULL, *method = NULL; -++ int timeout = 0; -++ PyObject *arguments = NULL; -++ static char *kwlist[] = {"object", "method", "arguments", "timeout", NULL}; -++ if (!PyArg_ParseTupleAndKeywords( -++ args, kwargs, "ssO|i", kwlist, &object, &method, &arguments, &timeout)){ -++ return NULL; -++ } -++ if (timeout < 0) { -++ PyErr_Format(PyExc_TypeError, "timeout can't be lower than 0"); -++ return NULL; -++ } -++ -++ uint32_t id = 0; -++ int retval = ubus_lookup_id(ctx, object, &id); -++ if (retval != UBUS_STATUS_OK) { -++ PyErr_Format(PyExc_RuntimeError, "Object '%s' was not found.", object); -++ return NULL; -++ } -++ -++ // Call python function json.dumps -++ PyObject *json_arguments = perform_json_function(DUMPS, arguments); -++ if (!json_arguments) { -++ return NULL; -++ } -++ -++ // put data into buffer -++ blob_buf_init(&python_buf, 0); -++ bool res = blobmsg_add_json_from_string(&python_buf, PyString_AsString(json_arguments)); -++ Py_DECREF(json_arguments); -++ if (!res) { -++ PyErr_Format(PyExc_TypeError, MSG_JSON_TO_UBUS_FAILED); -++ return NULL; -++ } -++ -++ PyObject *results = PyList_New(0); -++ if (!results) { -++ return NULL; -++ } -++ -++ retval = ubus_invoke( -++ ctx, id, method, python_buf.head, ubus_python_call_handler, &results, timeout); -++ -++ if (retval != UBUS_STATUS_OK) { -++ Py_XDECREF(results); -++ PyErr_Format( -++ PyExc_RuntimeError, -++ "ubus error occured: %s", ubus_strerror(retval) -++ ); -++ return NULL; -++ } -++ -++ // Note that results might be NULL indicating that something went wrong in the handler -++ return results; -++} -++ -++static PyMethodDef ubus_methods[] = { -++ {"disconnect", (PyCFunction)ubus_python_disconnect, METH_VARARGS|METH_KEYWORDS, disconnect_doc}, -++ {"connect", (PyCFunction)ubus_python_connect, METH_VARARGS|METH_KEYWORDS, connect_doc}, -++ {"get_connected", (PyCFunction)ubus_python_get_connected, METH_NOARGS, get_connected_doc}, -++ {"get_socket_path", (PyCFunction)ubus_python_get_socket_path, METH_NOARGS, get_socket_path_doc}, -++ {"send", (PyCFunction)ubus_python_send, METH_VARARGS|METH_KEYWORDS, connect_send_doc}, -++ {"listen", (PyCFunction)ubus_python_listen, METH_VARARGS, connect_listen_doc}, -++ {"loop", (PyCFunction)ubus_python_loop, METH_VARARGS|METH_KEYWORDS, connect_loop_doc}, -++ {"add", (PyCFunction)ubus_python_add, METH_VARARGS|METH_KEYWORDS, connect_add_doc}, -++ {"objects", (PyCFunction)ubus_python_objects, METH_VARARGS|METH_KEYWORDS, connect_objects_doc}, -++ {"call", (PyCFunction)ubus_python_call, METH_VARARGS|METH_KEYWORDS, connect_call_doc}, -++ {NULL} -++}; -++ -++PyMODINIT_FUNC initubus(void) { -++ if (PyType_Ready(&ubus_ResponseHandlerType)) { -++ return; -++ } -++ -++ json_module = PyImport_ImportModule("json"); -++ if (!json_module) { -++ return; -++ } -++ -++ PyObject *module = ubus_python_module_init(); -++ if (!module) { -++ return; -++ } -++ -++ Py_INCREF(&ubus_ResponseHandlerType); -++ PyModule_AddObject(module, "__ResponseHandler", (PyObject *)&ubus_ResponseHandlerType); -++ -++ /* export ubus json types */ -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_UNSPEC); -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_ARRAY); -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_TABLE); -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_STRING); -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_INT64); -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_INT32); -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_INT16); -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_INT8); -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_DOUBLE); -++ PyModule_AddIntMacro(module, BLOBMSG_TYPE_BOOL); -++} -- -2.16.2 +2.18.0