From 4d646dac46207a3f6ac6e839820b65c34398fc2c Mon Sep 17 00:00:00 2001 From: Karol Baraniecki Date: Fri, 3 Nov 2017 23:44:43 +0100 Subject: [PATCH] mtr: Fix #305 by implementing hsearch(3) (#1697) This hsearch(3) implementation is (with very minor changes) taken from FreeBSD 11.1. Also fix compilation errors due to calls to index(). This should probably be fixed upstream. --- disabled-packages/mtr/build.sh | 5 +- disabled-packages/mtr/hsearch.patch | 27 ++++ disabled-packages/mtr/hsearch/README.md | 1 + disabled-packages/mtr/hsearch/hcreate.c | 72 ++++++++++ disabled-packages/mtr/hsearch/hcreate_r.c | 63 ++++++++ disabled-packages/mtr/hsearch/hdestroy_r.c | 43 ++++++ disabled-packages/mtr/hsearch/hsearch.h | 40 ++++++ disabled-packages/mtr/hsearch/hsearch_r.c | 150 ++++++++++++++++++++ disabled-packages/mtr/hsearch/search.h | 86 +++++++++++ disabled-packages/mtr/index_to_strchr.patch | 35 +++++ 10 files changed, 519 insertions(+), 3 deletions(-) create mode 100644 disabled-packages/mtr/hsearch.patch create mode 100644 disabled-packages/mtr/hsearch/README.md create mode 100644 disabled-packages/mtr/hsearch/hcreate.c create mode 100644 disabled-packages/mtr/hsearch/hcreate_r.c create mode 100644 disabled-packages/mtr/hsearch/hdestroy_r.c create mode 100644 disabled-packages/mtr/hsearch/hsearch.h create mode 100644 disabled-packages/mtr/hsearch/hsearch_r.c create mode 100644 disabled-packages/mtr/hsearch/search.h create mode 100644 disabled-packages/mtr/index_to_strchr.patch diff --git a/disabled-packages/mtr/build.sh b/disabled-packages/mtr/build.sh index 241a0c013..22e4e5bc5 100644 --- a/disabled-packages/mtr/build.sh +++ b/disabled-packages/mtr/build.sh @@ -1,6 +1,3 @@ -# Status: Needs a working resolv.h. -# Perhaps add libres? -# http://dan.drown.org/android/src/libres/ TERMUX_PKG_HOMEPAGE=https://github.com/traviscross/mtr TERMUX_PKG_DESCRIPTION="Network diagnostic tool" TERMUX_PKG_VERSION=0.92 @@ -10,6 +7,8 @@ TERMUX_PKG_DEPENDS="ncurses" TERMUX_PKG_EXTRA_CONFIGURE_ARGS="--without-gtk --disable-ipv6" termux_step_pre_configure() { + cp $TERMUX_PKG_BUILDER_DIR/hsearch/* $TERMUX_PKG_SRCDIR/portability + cd $TERMUX_PKG_SRCDIR ./bootstrap.sh } diff --git a/disabled-packages/mtr/hsearch.patch b/disabled-packages/mtr/hsearch.patch new file mode 100644 index 000000000..529eb3888 --- /dev/null +++ b/disabled-packages/mtr/hsearch.patch @@ -0,0 +1,27 @@ +--- mtr/ui/asn.c 2017-06-02 08:54:58.000000000 +0000 ++++ ./ui/asn.c 2017-10-21 22:21:43.076825733 +0000 +@@ -41,7 +41,7 @@ + #include + #include + #include +-#include ++#include "portability/search.h" + + #include "mtr.h" + #include "asn.h" +--- mtr/Makefile.am 2017-06-02 08:54:58.000000000 +0000 ++++ ./Makefile.am 2017-10-21 22:39:26.628914946 +0000 +@@ -59,6 +59,12 @@ + img/mtr_icon.xpm \ + ui/mtr-gtk.h + ++mtr_SOURCES += \ ++ portability/hcreate.c \ ++ portability/hcreate_r.c \ ++ portability/hsearch_r.c \ ++ portability/hdestroy_r.c ++ + if WITH_ERROR + mtr_SOURCES += \ + portability/error.h \ + diff --git a/disabled-packages/mtr/hsearch/README.md b/disabled-packages/mtr/hsearch/README.md new file mode 100644 index 000000000..3fe4c2dde --- /dev/null +++ b/disabled-packages/mtr/hsearch/README.md @@ -0,0 +1 @@ +This hsearch(3) implementation is mostly based on the one present in FreeBSD 11.1. diff --git a/disabled-packages/mtr/hsearch/hcreate.c b/disabled-packages/mtr/hsearch/hcreate.c new file mode 100644 index 000000000..2d1d00cd7 --- /dev/null +++ b/disabled-packages/mtr/hsearch/hcreate.c @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include "search.h" +#include +#include + +/* + * Thread unsafe interface: use a single process-wide hash table and + * forward calls to *_r() functions. + */ + +static struct hsearch_data global_hashtable; +static bool global_hashtable_initialized = false; + +int +hcreate(size_t nel) +{ + + return (1); +} + +void +hdestroy(void) +{ + + /* Destroy global hash table if present. */ + if (global_hashtable_initialized) { + hdestroy_r(&global_hashtable); + global_hashtable_initialized = false; + } +} + +ENTRY * +hsearch(ENTRY item, ACTION action) +{ + ENTRY *retval; + + /* Create global hash table if needed. */ + if (!global_hashtable_initialized) { + if (hcreate_r(0, &global_hashtable) == 0) + return (NULL); + global_hashtable_initialized = true; + } + if (hsearch_r(item, action, &retval, &global_hashtable) == 0) + return (NULL); + return (retval); +} diff --git a/disabled-packages/mtr/hsearch/hcreate_r.c b/disabled-packages/mtr/hsearch/hcreate_r.c new file mode 100644 index 000000000..4b77cb1f6 --- /dev/null +++ b/disabled-packages/mtr/hsearch/hcreate_r.c @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD$"); + +#include "search.h" +#include + +#include "hsearch.h" + +int +hcreate_r(size_t nel, struct hsearch_data *htab) +{ + struct __hsearch *hsearch; + + /* + * Allocate a hash table object. Ignore the provided hint and start + * off with a table of sixteen entries. In most cases this hint is + * just a wild guess. Resizing the table dynamically if the use + * increases a threshold does not affect the worst-case running time. + */ + hsearch = malloc(sizeof(*hsearch)); + if (hsearch == NULL) + return 0; + hsearch->entries = calloc(16, sizeof(ENTRY)); + if (hsearch->entries == NULL) { + free(hsearch); + return 0; + } + + /* + * Pick a random initialization for the FNV-1a hashing. This makes it + * hard to come up with a fixed set of keys to force hash collisions. + */ + arc4random_buf(&hsearch->offset_basis, sizeof(hsearch->offset_basis)); + hsearch->index_mask = 0xf; + hsearch->entries_used = 0; + htab->__hsearch = hsearch; + return 1; +} diff --git a/disabled-packages/mtr/hsearch/hdestroy_r.c b/disabled-packages/mtr/hsearch/hdestroy_r.c new file mode 100644 index 000000000..dcb29a527 --- /dev/null +++ b/disabled-packages/mtr/hsearch/hdestroy_r.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD$"); + +#include "search.h" +#include + +#include "hsearch.h" + +void +hdestroy_r(struct hsearch_data *htab) +{ + struct __hsearch *hsearch; + + /* Free hash table object and its entries. */ + hsearch = htab->__hsearch; + free(hsearch->entries); + free(hsearch); +} diff --git a/disabled-packages/mtr/hsearch/hsearch.h b/disabled-packages/mtr/hsearch/hsearch.h new file mode 100644 index 000000000..9fdc2b012 --- /dev/null +++ b/disabled-packages/mtr/hsearch/hsearch.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef HSEARCH_H +#define HSEARCH_H + +#include "search.h" + +struct __hsearch { + size_t offset_basis; /* Initial value for FNV-1a hashing. */ + size_t index_mask; /* Bitmask for indexing the table. */ + size_t entries_used; /* Number of entries currently used. */ + ENTRY *entries; /* Hash table entries. */ +}; + +#endif diff --git a/disabled-packages/mtr/hsearch/hsearch_r.c b/disabled-packages/mtr/hsearch/hsearch_r.c new file mode 100644 index 000000000..7e4aebdfb --- /dev/null +++ b/disabled-packages/mtr/hsearch/hsearch_r.c @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 2015 Nuxi, https://nuxi.nl/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +//__FBSDID("$FreeBSD$"); + +#include +#include +#include "search.h" +#include +#include +#include + +#include "hsearch.h" + +/* + * Look up an unused entry in the hash table for a given hash. For this + * implementation we use quadratic probing. Quadratic probing has the + * advantage of preventing primary clustering. + */ +static ENTRY * +hsearch_lookup_free(struct __hsearch *hsearch, size_t hash) +{ + size_t index, i; + + for (index = hash, i = 0;; index += ++i) { + ENTRY *entry = &hsearch->entries[index & hsearch->index_mask]; + if (entry->key == NULL) + return (entry); + } +} + +/* + * Computes an FNV-1a hash of the key. Depending on the pointer size, this + * either uses the 32- or 64-bit FNV prime. + */ +static size_t +hsearch_hash(size_t offset_basis, const char *str) +{ + size_t hash; + + hash = offset_basis; + while (*str != '\0') { + hash ^= (uint8_t)*str++; + if (sizeof(size_t) * CHAR_BIT <= 32) + hash *= UINT32_C(16777619); + else + hash *= UINT64_C(1099511628211); + } + return (hash); +} + +int +hsearch_r(ENTRY item, ACTION action, ENTRY **retval, struct hsearch_data *htab) +{ + struct __hsearch *hsearch; + ENTRY *entry, *old_entries, *new_entries; + size_t hash, index, i, old_hash, old_count, new_count; + + hsearch = htab->__hsearch; + hash = hsearch_hash(hsearch->offset_basis, item.key); + + /* + * Search the hash table for an existing entry for this key. + * Stop searching if we run into an unused hash table entry. + */ + for (index = hash, i = 0;; index += ++i) { + entry = &hsearch->entries[index & hsearch->index_mask]; + if (entry->key == NULL) + break; + if (strcmp(entry->key, item.key) == 0) { + *retval = entry; + return (1); + } + } + + /* Only perform the insertion if action is set to ENTER. */ + if (action == FIND) { + errno = ESRCH; + return (0); + } + + if (hsearch->entries_used * 2 >= hsearch->index_mask) { + /* Preserve the old hash table entries. */ + old_count = hsearch->index_mask + 1; + old_entries = hsearch->entries; + + /* + * Allocate and install a new table if insertion would + * yield a hash table that is more than 50% used. By + * using 50% as a threshold, a lookup will only take up + * to two steps on average. + */ + new_count = (hsearch->index_mask + 1) * 2; + new_entries = calloc(new_count, sizeof(ENTRY)); + if (new_entries == NULL) + return (0); + hsearch->entries = new_entries; + hsearch->index_mask = new_count - 1; + + /* Copy over the entries from the old table to the new table. */ + for (i = 0; i < old_count; ++i) { + entry = &old_entries[i]; + if (entry->key != NULL) { + old_hash = hsearch_hash(hsearch->offset_basis, + entry->key); + *hsearch_lookup_free(hsearch, old_hash) = + *entry; + } + } + + /* Destroy the old hash table entries. */ + free(old_entries); + + /* + * Perform a new lookup for a free table entry, so that + * we insert the entry into the new hash table. + */ + hsearch = htab->__hsearch; + entry = hsearch_lookup_free(hsearch, hash); + } + + /* Insert the new entry into the hash table. */ + *entry = item; + ++hsearch->entries_used; + *retval = entry; + return (1); +} diff --git a/disabled-packages/mtr/hsearch/search.h b/disabled-packages/mtr/hsearch/search.h new file mode 100644 index 000000000..b1919054f --- /dev/null +++ b/disabled-packages/mtr/hsearch/search.h @@ -0,0 +1,86 @@ +/*- + * Written by J.T. Conklin + * Public domain. + * + * $NetBSD: search.h,v 1.16 2005/02/03 04:39:32 perry Exp $ + * $FreeBSD$ + */ + +#ifndef _SEARCH_H_ +#define _SEARCH_H_ + +#include +//#include +//#include + +#ifndef _SIZE_T_DECLARED +//typedef __size_t size_t; +#define _SIZE_T_DECLARED +#endif + +typedef struct entry { + char *key; + void *data; +} ENTRY; + +typedef enum { + FIND, ENTER +} ACTION; + +typedef enum { + preorder, + postorder, + endorder, + leaf +} VISIT; + +#ifdef _SEARCH_PRIVATE +typedef struct __posix_tnode { + void *key; + struct __posix_tnode *llink, *rlink; + signed char balance; +} posix_tnode; + +struct que_elem { + struct que_elem *next; + struct que_elem *prev; +}; +#else +typedef void posix_tnode; +#endif + +//#if __BSD_VISIBLE +struct hsearch_data { + struct __hsearch *__hsearch; +}; +//#endif + +__BEGIN_DECLS +int hcreate(size_t); +void hdestroy(void); +ENTRY *hsearch(ENTRY, ACTION); +void insque(void *, void *); +void *lfind(const void *, const void *, size_t *, size_t, + int (*)(const void *, const void *)); +void *lsearch(const void *, void *, size_t *, size_t, + int (*)(const void *, const void *)); +void remque(void *); +void *tdelete(const void * __restrict, posix_tnode ** __restrict, + int (*)(const void *, const void *)); +posix_tnode * + tfind(const void *, posix_tnode * const *, + int (*)(const void *, const void *)); +posix_tnode * + tsearch(const void *, posix_tnode **, + int (*)(const void *, const void *)); +void twalk(const posix_tnode *, void (*)(const posix_tnode *, VISIT, int)); + +//#if __BSD_VISIBLE +int hcreate_r(size_t, struct hsearch_data *); +void hdestroy_r(struct hsearch_data *); +int hsearch_r(ENTRY, ACTION, ENTRY **, struct hsearch_data *); +//#endif + +__END_DECLS + +#endif /* !_SEARCH_H_ */ diff --git a/disabled-packages/mtr/index_to_strchr.patch b/disabled-packages/mtr/index_to_strchr.patch new file mode 100644 index 000000000..a9be89aaa --- /dev/null +++ b/disabled-packages/mtr/index_to_strchr.patch @@ -0,0 +1,35 @@ +--- mtr/ui/curses.c 2017-06-02 08:54:58.000000000 +0000 ++++ ./ui/curses.c 2017-10-21 22:47:23.221332133 +0000 +@@ -383,7 +383,7 @@ + const char *format, + int n) + { +- if (index(format, 'N')) { ++ if (strchr(format, 'N')) { + *dst++ = ' '; + format_number(n, 5, dst); + } else if (strchr(format, 'f')) { + +--- mtr/ui/cmdpipe.c 2017-10-21 22:50:49.843505234 +0000 ++++ ./ui/cmdpipe.c 2017-10-21 22:51:08.507344155 +0000 +@@ -736,7 +736,7 @@ + */ + while (true) { + /* If no newline is found, our reply isn't yet complete */ +- end_of_reply = index(reply_start, '\n'); ++ end_of_reply = strchr(reply_start, '\n'); + if (end_of_reply == NULL) { + /* No complete replies remaining */ + break; +--- mtr/packet/command.c 2017-06-02 08:54:58.000000000 +0000 ++++ ./packet/command.c 2017-10-21 22:55:13.321277161 +0000 +@@ -380,7 +380,7 @@ + buffer->incoming_buffer[buffer->incoming_read_position] = 0; + + /* Find the next newline, which terminates command requests */ +- end_of_command = index(buffer->incoming_buffer, '\n'); ++ end_of_command = strchr(buffer->incoming_buffer, '\n'); + if (end_of_command == NULL) { + /* + No newlines found, so any data we've read so far is +