From 737ecc15d02b4203a3302a715256b700b0a87728 Mon Sep 17 00:00:00 2001 From: NADAL Jean-Baptiste Date: Fri, 26 Feb 2016 23:13:29 +0100 Subject: [PATCH] Merge libubox with the version 2016.02.26 from its git. --- 3P/libubox/.gitignore | 1 + 3P/libubox/CMakeLists.txt | 71 ++ 3P/libubox/base64.c | 327 +++++ 3P/libubox/blobmsg.c | 1 - 3P/libubox/blobmsg_json.c | 14 +- 3P/libubox/blobmsg_json.h | 10 +- 3P/libubox/examples/CMakeLists.txt | 39 +- 3P/libubox/examples/blobmsg-example.c | 1 + 3P/libubox/examples/json_script-example.c | 84 ++ 3P/libubox/examples/json_script-example.json | 38 + 3P/libubox/examples/json_script-tests.sh | 287 +++++ 3P/libubox/examples/runqueue-example.c | 2 +- 3P/libubox/examples/shunit2 | 1067 +++++++++++++++++ 3P/libubox/jshn.c | 37 +- 3P/libubox/json_script.c | 50 +- 3P/libubox/json_script.h | 13 + 3P/libubox/lua/CMakeLists.txt | 10 +- .../uloop.dep | 8 - .../uloop.o | Bin 101140 -> 0 bytes .../uloop.dep | 8 - .../uloop.o | Bin 13392 -> 0 bytes .../uloop.dep | 8 - .../_rt3052d_StriimSOUND-debug-shared/uloop.o | Bin 101588 -> 0 bytes .../uloop.dep | 8 - .../uloop.o | Bin 13468 -> 0 bytes 3P/libubox/lua/uloop.c | 89 +- 3P/libubox/md5.c | 508 ++++---- 3P/libubox/md5.h | 66 +- 3P/libubox/sh/jshn.sh | 57 +- 3P/libubox/ulog.c | 173 +++ 3P/libubox/ulog.h | 42 + 3P/libubox/uloop.c | 82 +- 3P/libubox/usock.c | 200 ++- 3P/libubox/usock.h | 19 + 3P/libubox/ustream-fd.c | 18 +- 3P/libubox/ustream.c | 36 +- 3P/libubox/ustream.h | 5 + 3P/libubox/utils.c | 59 +- 3P/libubox/utils.h | 19 +- 39 files changed, 2971 insertions(+), 486 deletions(-) create mode 100644 3P/libubox/CMakeLists.txt create mode 100644 3P/libubox/base64.c create mode 100644 3P/libubox/examples/json_script-example.c create mode 100644 3P/libubox/examples/json_script-example.json create mode 100644 3P/libubox/examples/json_script-tests.sh create mode 100644 3P/libubox/examples/shunit2 delete mode 100644 3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-debug-shared/uloop.dep delete mode 100644 3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-debug-shared/uloop.o delete mode 100644 3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-release-shared/uloop.dep delete mode 100644 3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-release-shared/uloop.o delete mode 100644 3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-debug-shared/uloop.dep delete mode 100644 3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-debug-shared/uloop.o delete mode 100644 3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-release-shared/uloop.dep delete mode 100644 3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-release-shared/uloop.o create mode 100644 3P/libubox/ulog.c create mode 100644 3P/libubox/ulog.h diff --git a/3P/libubox/.gitignore b/3P/libubox/.gitignore index 0c59f966..5ffd2358 100644 --- a/3P/libubox/.gitignore +++ b/3P/libubox/.gitignore @@ -8,3 +8,4 @@ CMakeFiles install_manifest.txt jshn *-example +tests.* diff --git a/3P/libubox/CMakeLists.txt b/3P/libubox/CMakeLists.txt new file mode 100644 index 00000000..57804cf0 --- /dev/null +++ b/3P/libubox/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 2.6) +INCLUDE(CheckLibraryExists) +INCLUDE(CheckFunctionExists) + +PROJECT(ubox C) +ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -Wmissing-declarations) + +OPTION(BUILD_LUA "build Lua plugin" ON) +OPTION(BUILD_EXAMPLES "build examples" ON) + +INCLUDE(FindPkgConfig) +PKG_SEARCH_MODULE(JSONC json-c) +IF(JSONC_FOUND) + ADD_DEFINITIONS(-DJSONC) + INCLUDE_DIRECTORIES(${JSONC_INCLUDE_DIRS}) +ENDIF() + +SET(SOURCES avl.c avl-cmp.c blob.c blobmsg.c uloop.c usock.c ustream.c ustream-fd.c vlist.c utils.c safe_list.c runqueue.c md5.c kvlist.c ulog.c base64.c) + +ADD_LIBRARY(ubox SHARED ${SOURCES}) +ADD_LIBRARY(ubox-static STATIC ${SOURCES}) +SET_TARGET_PROPERTIES(ubox-static PROPERTIES OUTPUT_NAME ubox) + +SET(LIBS) +CHECK_FUNCTION_EXISTS(clock_gettime HAVE_GETTIME) +IF(NOT HAVE_GETTIME) + CHECK_LIBRARY_EXISTS(rt clock_gettime "" NEED_GETTIME) + IF(NEED_GETTIME) + TARGET_LINK_LIBRARIES(ubox rt) + ENDIF() +ENDIF() + +FILE(GLOB headers *.h) +INSTALL(FILES ${headers} + DESTINATION include/libubox +) +INSTALL(TARGETS ubox ubox-static + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib +) + +ADD_SUBDIRECTORY(lua) +ADD_SUBDIRECTORY(examples) + +find_library(json NAMES json-c) +IF(EXISTS ${json}) + ADD_LIBRARY(blobmsg_json SHARED blobmsg_json.c) + TARGET_LINK_LIBRARIES(blobmsg_json ubox ${json}) + + ADD_LIBRARY(blobmsg_json-static STATIC blobmsg_json.c) + SET_TARGET_PROPERTIES(blobmsg_json-static + PROPERTIES OUTPUT_NAME blobmsg_json) + + ADD_EXECUTABLE(jshn jshn.c) + TARGET_LINK_LIBRARIES(jshn blobmsg_json ${json}) + + ADD_LIBRARY(json_script SHARED json_script.c) + TARGET_LINK_LIBRARIES(json_script ubox) + + INSTALL(TARGETS blobmsg_json blobmsg_json-static jshn json_script + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ) + + FILE(GLOB scripts sh/*.sh) + INSTALL(FILES ${scripts} + DESTINATION share/libubox + ) + +ENDIF() diff --git a/3P/libubox/base64.c b/3P/libubox/base64.c new file mode 100644 index 00000000..4186ce84 --- /dev/null +++ b/3P/libubox/base64.c @@ -0,0 +1,327 @@ +/* + * base64 - libubox base64 functions + * + * Copyright (C) 2015 Felix Fietkau + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* $OpenBSD: base64.c,v 1.7 2013/12/31 02:32:56 tedu Exp $ */ + +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include +#include +#include +#include +#include "utils.h" + +static const char Base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const char Pad64 = '='; + +/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) + The following encoding technique is taken from RFC 1521 by Borenstein + and Freed. It is reproduced here in a slightly edited form for + convenience. + + A 65-character subset of US-ASCII is used, enabling 6 bits to be + represented per printable character. (The extra 65th character, "=", + is used to signify a special processing function.) + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8-bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + + Each 6-bit group is used as an index into an array of 64 printable + characters. The character referenced by the index is placed in the + output string. + + Table 1: The Base64 Alphabet + + Value Encoding Value Encoding Value Encoding Value Encoding + 0 A 17 R 34 i 51 z + 1 B 18 S 35 j 52 0 + 2 C 19 T 36 k 53 1 + 3 D 20 U 37 l 54 2 + 4 E 21 V 38 m 55 3 + 5 F 22 W 39 n 56 4 + 6 G 23 X 40 o 57 5 + 7 H 24 Y 41 p 58 6 + 8 I 25 Z 42 q 59 7 + 9 J 26 a 43 r 60 8 + 10 K 27 b 44 s 61 9 + 11 L 28 c 45 t 62 + + 12 M 29 d 46 u 63 / + 13 N 30 e 47 v + 14 O 31 f 48 w (pad) = + 15 P 32 g 49 x + 16 Q 33 h 50 y + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a quantity. When fewer than 24 input + bits are available in an input group, zero bits are added (on the + right) to form an integral number of 6-bit groups. Padding at the + end of the data is performed using the '=' character. + + Since all base64 input is an integral number of octets, only the + ------------------------------------------------- + following cases can arise: + + (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded + output will be an integral multiple of 4 characters + with no "=" padding, + (2) the final quantum of encoding input is exactly 8 bits; + here, the final unit of encoded output will be two + characters followed by two "=" padding characters, or + (3) the final quantum of encoding input is exactly 16 bits; + here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + +int b64_encode(const void *_src, size_t srclength, + void *dest, size_t targsize) +{ + const unsigned char *src = _src; + char *target = dest; + size_t datalength = 0; + u_char input[3] = {0}; + u_char output[4]; + int i; + + while (2 < srclength) { + input[0] = *src++; + input[1] = *src++; + input[2] = *src++; + srclength -= 3; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + output[3] = input[2] & 0x3f; + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + target[datalength++] = Base64[output[2]]; + target[datalength++] = Base64[output[3]]; + } + + /* Now we worry about padding. */ + if (0 != srclength) { + /* Get what's left. */ + input[0] = input[1] = input[2] = '\0'; + for (i = 0; i < srclength; i++) + input[i] = *src++; + + output[0] = input[0] >> 2; + output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); + output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); + + if (datalength + 4 > targsize) + return (-1); + target[datalength++] = Base64[output[0]]; + target[datalength++] = Base64[output[1]]; + if (srclength == 1) + target[datalength++] = Pad64; + else + target[datalength++] = Base64[output[2]]; + target[datalength++] = Pad64; + } + if (datalength >= targsize) + return (-1); + target[datalength] = '\0'; /* Returned value doesn't count \0. */ + return (datalength); +} + +/* skips all whitespace anywhere. + converts characters, four at a time, starting at (or after) + src from base - 64 numbers into three 8 bit bytes in the target area. + it returns the number of data bytes stored at the target, or -1 on error. + */ + +int b64_decode(const void *_src, void *dest, size_t targsize) +{ + const char *src = _src; + unsigned char *target = dest; + int tarindex, state, ch; + u_char nextbyte; + char *pos; + + state = 0; + tarindex = 0; + + while ((ch = (unsigned char)*src++) != '\0') { + if (isspace(ch)) /* Skip whitespace anywhere. */ + continue; + + if (ch == Pad64) + break; + + pos = strchr(Base64, ch); + if (pos == 0) /* A non-base64 character. */ + return (-1); + + switch (state) { + case 0: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] = (pos - Base64) << 2; + } + state = 1; + break; + case 1: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 4; + nextbyte = ((pos - Base64) & 0x0f) << 4; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 2; + break; + case 2: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64) >> 2; + nextbyte = ((pos - Base64) & 0x03) << 6; + if (tarindex + 1 < targsize) + target[tarindex+1] = nextbyte; + else if (nextbyte) + return (-1); + } + tarindex++; + state = 3; + break; + case 3: + if (target) { + if (tarindex >= targsize) + return (-1); + target[tarindex] |= (pos - Base64); + } + tarindex++; + state = 0; + break; + } + } + + /* + * We are done decoding Base-64 chars. Let's see if we ended + * on a byte boundary, and/or with erroneous trailing characters. + */ + + if (ch == Pad64) { /* We got a pad char. */ + ch = (unsigned char)*src++; /* Skip it, get next. */ + switch (state) { + case 0: /* Invalid = in first position */ + case 1: /* Invalid = in second position */ + return (-1); + + case 2: /* Valid, means one byte of info */ + /* Skip any number of spaces. */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + break; + /* Make sure there is another trailing = sign. */ + if (ch != Pad64) + return (-1); + ch = (unsigned char)*src++; /* Skip the = */ + /* Fall through to "single trailing =" case. */ + /* FALLTHROUGH */ + + case 3: /* Valid, means two bytes of info */ + /* + * We know this char is an =. Is there anything but + * whitespace after it? + */ + for (; ch != '\0'; ch = (unsigned char)*src++) + if (!isspace(ch)) + return (-1); + + /* + * Now make sure for cases 2 and 3 that the "extra" + * bits that slopped past the last full byte were + * zeros. If we don't check them, they become a + * subliminal channel. + */ + if (target && tarindex < targsize && + target[tarindex] != 0) + return (-1); + } + } else { + /* + * We ended by seeing the end of the string. Make sure we + * have no partial bytes lying around. + */ + if (state != 0) + return (-1); + } + + /* Null-terminate if we have room left */ + if (tarindex < targsize) + target[tarindex] = 0; + + return (tarindex); +} diff --git a/3P/libubox/blobmsg.c b/3P/libubox/blobmsg.c index 9fe96e44..80b984a1 100644 --- a/3P/libubox/blobmsg.c +++ b/3P/libubox/blobmsg.c @@ -262,7 +262,6 @@ blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int if (!attr) return NULL; - data_dest = blobmsg_data(attr); blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blob_pad_len(attr)); blob_set_raw_len(attr, blob_raw_len(attr) - maxlen); diff --git a/3P/libubox/blobmsg_json.c b/3P/libubox/blobmsg_json.c index 8f208e0c..2d1d80dd 100644 --- a/3P/libubox/blobmsg_json.c +++ b/3P/libubox/blobmsg_json.c @@ -17,6 +17,12 @@ #include "blobmsg.h" #include "blobmsg_json.h" +#ifdef JSONC + #include +#else + #include +#endif + bool blobmsg_add_object(struct blob_buf *b, json_object *obj) { json_object_object_foreach(obj, key, val) { @@ -43,9 +49,6 @@ bool blobmsg_add_json_element(struct blob_buf *b, const char *name, json_object bool ret = true; void *c; - if (!obj) - return false; - switch (json_object_get_type(obj)) { case json_type_object: c = blobmsg_open_table(b, name); @@ -66,6 +69,9 @@ bool blobmsg_add_json_element(struct blob_buf *b, const char *name, json_object case json_type_int: blobmsg_add_u32(b, name, json_object_get_int(obj)); break; + case json_type_null: + blobmsg_add_field(b, BLOBMSG_TYPE_UNSPEC, name, NULL, 0); + break; default: return false; } @@ -76,7 +82,7 @@ static bool __blobmsg_add_json(struct blob_buf *b, json_object *obj) { bool ret = false; - if (is_error(obj)) + if (!obj) return false; if (json_object_get_type(obj) != json_type_object) diff --git a/3P/libubox/blobmsg_json.h b/3P/libubox/blobmsg_json.h index e8036eb0..cd9ed33e 100644 --- a/3P/libubox/blobmsg_json.h +++ b/3P/libubox/blobmsg_json.h @@ -16,17 +16,13 @@ #ifndef __BLOBMSG_JSON_H #define __BLOBMSG_JSON_H -#ifdef JSONC - #include -#else - #include -#endif +struct json_object; #include #include "blobmsg.h" -bool blobmsg_add_object(struct blob_buf *b, json_object *obj); -bool blobmsg_add_json_element(struct blob_buf *b, const char *name, json_object *obj); +bool blobmsg_add_object(struct blob_buf *b, struct json_object *obj); +bool blobmsg_add_json_element(struct blob_buf *b, const char *name, struct json_object *obj); bool blobmsg_add_json_from_string(struct blob_buf *b, const char *str); bool blobmsg_add_json_from_file(struct blob_buf *b, const char *file); diff --git a/3P/libubox/examples/CMakeLists.txt b/3P/libubox/examples/CMakeLists.txt index 2126d298..a6355356 100644 --- a/3P/libubox/examples/CMakeLists.txt +++ b/3P/libubox/examples/CMakeLists.txt @@ -1,24 +1,23 @@ cmake_minimum_required(VERSION 2.6) -PROJECT(ubox-examples C) -ADD_DEFINITIONS(-O1 -Wall -Werror --std=gnu99 -g3) +IF (BUILD_EXAMPLES) + PROJECT(ubox-examples C) + ADD_DEFINITIONS(-O1 -Wall -Werror --std=gnu99 -g3) -IF(APPLE) - INCLUDE_DIRECTORIES(/opt/local/include) - LINK_DIRECTORIES(/opt/local/lib) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..) + LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..) + + FIND_LIBRARY(json NAMES json-c json) + + ADD_EXECUTABLE(blobmsg-example blobmsg-example.c) + TARGET_LINK_LIBRARIES(blobmsg-example ubox blobmsg_json ${json}) + + ADD_EXECUTABLE(ustream-example ustream-example.c) + TARGET_LINK_LIBRARIES(ustream-example ubox) + + ADD_EXECUTABLE(runqueue-example runqueue-example.c) + TARGET_LINK_LIBRARIES(runqueue-example ubox) + + ADD_EXECUTABLE(json_script-example json_script-example.c) + TARGET_LINK_LIBRARIES(json_script-example ubox blobmsg_json json_script ${json}) ENDIF() - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..) -LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..) - -FIND_LIBRARY(json NAMES json-c json) - -ADD_EXECUTABLE(blobmsg-example blobmsg-example.c) -TARGET_LINK_LIBRARIES(blobmsg-example ubox blobmsg_json ${json}) - -ADD_EXECUTABLE(ustream-example ustream-example.c) -TARGET_LINK_LIBRARIES(ustream-example ubox) - -ADD_EXECUTABLE(runqueue-example runqueue-example.c) -TARGET_LINK_LIBRARIES(runqueue-example ubox) - diff --git a/3P/libubox/examples/blobmsg-example.c b/3P/libubox/examples/blobmsg-example.c index 69ddce89..01b05181 100644 --- a/3P/libubox/examples/blobmsg-example.c +++ b/3P/libubox/examples/blobmsg-example.c @@ -1,4 +1,5 @@ #include +#include #include "blobmsg.h" #include "blobmsg_json.h" diff --git a/3P/libubox/examples/json_script-example.c b/3P/libubox/examples/json_script-example.c new file mode 100644 index 00000000..4d252a9a --- /dev/null +++ b/3P/libubox/examples/json_script-example.c @@ -0,0 +1,84 @@ +#include +#include + +#include +#include "blobmsg.h" +#include "blobmsg_json.h" +#include "json_script.h" + +struct json_script_ctx jctx; +struct blob_buf b_vars; +struct blob_buf b_script; + +static void handle_command(struct json_script_ctx *ctx, const char *name, + struct blob_attr *data, struct blob_attr *vars) +{ + struct blob_attr *cur; + int rem; + + fprintf(stdout, "%s", name); + blobmsg_for_each_attr(cur, data, rem) + fprintf(stdout, " %s", (char *) blobmsg_data(cur)); + fprintf(stdout, "\n"); +} + +static struct json_script_file * +handle_file(struct json_script_ctx *ctx, const char *filename) +{ + json_object *obj; + + obj = json_object_from_file(filename); + if (!obj) { + fprintf(stderr, "load JSON data from %s failed.\n", filename); + return NULL; + } + + blob_buf_init(&b_script, 0); + blobmsg_add_json_element(&b_script, "", obj); + json_object_put(obj); + + return json_script_file_from_blobmsg(filename, + blob_data(b_script.head), blob_len(b_script.head)); +} + +static void usage(const char *prog, int exit_code) +{ + fprintf(stderr, "Usage: %s [VARNAME=value] \n", prog); + exit(exit_code); +} + +int main(int argc, char *argv[]) +{ + int i; + char *file = NULL; + const char *prog = argv[0]; + + blobmsg_buf_init(&b_vars); + blobmsg_buf_init(&b_script); + + json_script_init(&jctx); + jctx.handle_command = handle_command; + jctx.handle_file = handle_file; + + for (i = 1; i < argc; i++) { + char *sep = strchr(argv[i], '='); + if (sep) { + *sep = '\0'; + blobmsg_add_string(&b_vars, argv[i], sep + 1); + } else if (!file) { + file = argv[i]; + } else { + usage(prog, -1); + } + } + if (i < argc || !file) + usage(prog, -2); + + json_script_run(&jctx, file, b_vars.head); + + json_script_free(&jctx); + blob_buf_free(&b_script); + blob_buf_free(&b_vars); + + return 0; +} diff --git a/3P/libubox/examples/json_script-example.json b/3P/libubox/examples/json_script-example.json new file mode 100644 index 00000000..5328e599 --- /dev/null +++ b/3P/libubox/examples/json_script-example.json @@ -0,0 +1,38 @@ +[ + [ "exec", "%EXECVAR%", "/%%/" ], + [ "if", + [ "eq", "EQVAR", "eqval" ], + [ "exec_if", "%VAR%", "%%", "jk" ] + ], + [ "case", "CASEVAR", { + "caseval0": ["cmd_case_0", "cmd_case_arg0", "case_cmd_arg1"], + "caseval1": ["cmd_case_1", "cmd_case_arg0", "case_cmd_arg1"] + } ], + + [ "if", + [ "and", [ "eq", "EQVAR", "eqval" ], + [ "has", "HASVAR" ], + [ "regex", "REGEXVAR0", "regexval" ], + [ "regex", "REGEXVAR1", [ "regexval10", "regexval11" ] ], + [ "not", [ "eq", "NOTEQVAR", "noteqval" ] ] ], + [ "exec_if_and", "%ANDVAR%" ] + ], + + [ "if", + [ "or", [ "eq", "EQVAR", "eqval" ], + [ "has", "HASVAR" ], + [ "regex", "REGEXVAR0", "regexval" ], + [ "regex", "REGEXVAR1", [ "regexval10", "regexval11" ] ], + [ "not", [ "eq", "NOTEQVAR", "noteqval" ] ] ], + [ "exec_if_or", "%ORVAR%" ] + ], + + [ "if", + [ "isdir", "%ISDIRVAR%" ], + [ "exec_isdir", "%ISDIRVAR%" ] + ], + + [ "return", "foobar" ], + + [ "exec_non_reachable", "Arghhh" ] +] diff --git a/3P/libubox/examples/json_script-tests.sh b/3P/libubox/examples/json_script-tests.sh new file mode 100644 index 00000000..7120a7e8 --- /dev/null +++ b/3P/libubox/examples/json_script-tests.sh @@ -0,0 +1,287 @@ +JSON_SCRIPT=tests.json +JSON_SCRIPT_BIN=./json_script-example +FILE_STDOUT=tests.stdout +FILE_STDERR=tests.stderr +FILE_EXPECTED=tests.expected + +call_json_script() { + #export LD_PRELOAD=../libjson_script.so + $JSON_SCRIPT_BIN "$@" "$JSON_SCRIPT" >"$FILE_STDOUT" 2>"$FILE_STDERR" +} + +assertStdioEquals() { + local expected="$1" + local file_stdio="$2" + + echo "$expected" >"$FILE_EXPECTED" + if [ -z "$expected" ]; then + # we are expecting empty output, but we deliberately added a newline + # with echo above, so adding another echo to compensate for that + echo >>"$file_stdio" + fi + diff -up "$FILE_EXPECTED" "$file_stdio" >/dev/null 2>&1 || { + cat >&2 <"$JSON_SCRIPT" <<-EOF + [ + [ ] + [ ] + ] + EOF + call_json_script + assertStderrEquals "load JSON data from $JSON_SCRIPT failed." +} + +test_expr_eq() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "if", + [ "eq", "VAR", "foo" ], + [ "echo", "bar" ], + [ "echo", "baz" ] + ] + ] + EOF + call_json_script "VAR=foo" + assertStdoutEquals "echo bar" + call_json_script "VAR=xxx" + assertStdoutEquals "echo baz" +} + +test_expr_has() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "if", + [ "has", "VAR" ], + [ "echo", "bar" ], + [ "echo", "baz" ] + ] + ] + EOF + call_json_script "VAR=foo" + assertStdoutEquals "echo bar" + call_json_script + assertStdoutEquals "echo baz" +} + +test_expr_regex_single() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "if", + [ "regex", "VAR", ".ell." ], + [ "echo", "bar" ], + [ "echo", "baz" ] + ] + ] + EOF + call_json_script "VAR=hello" + assertStdoutEquals "echo bar" + call_json_script "VAR=.ell." + assertStdoutEquals "echo bar" + call_json_script + assertStdoutEquals "echo baz" + call_json_script "VAR=" + assertStdoutEquals "echo baz" + call_json_script "VAR=hell" + assertStdoutEquals "echo baz" +} + +test_expr_regex_multi() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "if", + [ "regex", "VAR", [ ".ell.", "w.rld" ] ], + [ "echo", "bar" ], + [ "echo", "baz" ] + ] + ] + EOF + call_json_script "VAR=hello" + assertStdoutEquals "echo bar" + call_json_script "VAR=world" + assertStdoutEquals "echo bar" + call_json_script "VAR=.ell." + assertStdoutEquals "echo bar" + call_json_script "VAR=w.rld" + assertStdoutEquals "echo bar" + call_json_script + assertStdoutEquals "echo baz" + call_json_script "VAR=" + assertStdoutEquals "echo baz" + call_json_script "VAR=hell" + assertStdoutEquals "echo baz" +} + +test_expr_not() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "if", + [ "not", [ "has", "VAR" ] ], + [ "echo", "bar" ], + [ "echo", "baz" ] + ] + ] + EOF + call_json_script "VAR=foo" + assertStdoutEquals "echo baz" + call_json_script + assertStdoutEquals "echo bar" +} + +test_expr_and() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "if", + [ "and", [ "eq", "EQVAR", "eqval" ], + [ "regex", "REGEXVAR", "regex..." ] + ], + [ "echo", "bar" ], + [ "echo", "baz" ] + ] + ] + EOF + call_json_script "EQVAR=eqval" "REGEXVAR=regexval" + assertStdoutEquals "echo bar" + call_json_script "EQVAR=foo" + assertStdoutEquals "echo baz" + call_json_script "REGEXVAR=regex***" + assertStdoutEquals "echo baz" + call_json_script + assertStdoutEquals "echo baz" +} + +test_expr_or() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "if", + [ "or", [ "not", [ "eq", "EQVAR", "eqval" ] ], + [ "regex", "REGEXVAR", [ "regexva.[0-9]", "regexva.[a-z]" ] ] + ], + [ "echo", "bar" ], + [ "echo", "baz" ] + ] + ] + EOF + call_json_script "EQVAR=eqval" "REGEXVAR=regexval1" + assertStdoutEquals "echo bar" + call_json_script "EQVAR=neq" "REGEXVAR=sxc" + assertStdoutEquals "echo bar" + call_json_script "REGEXVAR=sxc" + assertStdoutEquals "echo bar" + call_json_script "EQVAR=foo" + assertStdoutEquals "echo bar" + call_json_script + assertStdoutEquals "echo bar" + call_json_script "EQVAR=eqval" "REGEXVAR=regexval" + assertStdoutEquals "echo baz" +} + +test_expr_isdir() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "if", + [ "isdir", "%VAR%" ], + [ "echo", "bar" ], + [ "echo", "baz" ] + ] + ] + EOF + call_json_script "VAR=/" + assertStdoutEquals "echo bar" + call_json_script "VAR=$(mktemp -u)" + assertStdoutEquals "echo baz" + call_json_script + assertStdoutEquals "echo baz" +} + +test_cmd_case() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "case", "CASEVAR", { + "0": [ "echo", "foo" ], + "1": [ + [ "echo", "bar" ], + [ "echo", "baz" ] + ], + "%VAR%": [ "echo", "quz" ] + } ] + ] + EOF + call_json_script "CASEVAR=0" + assertStdoutEquals "echo foo" + call_json_script "CASEVAR=1" + assertStdoutEquals "echo bar +echo baz" + call_json_script "CASEVAR=%VAR%" + assertStdoutEquals "echo quz" + call_json_script "CASEVAR=" + assertStdoutEquals "" + call_json_script + assertStdoutEquals "" + call_json_script "CASEVAR=xxx" "VAR=xxx" + assertStdoutEquals "" +} + +test_cmd_if() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "if", + [ "eq", "VAR", "foo" ], + [ "echo", "bar" ], + [ "echo", "baz" ] + ] + ] + EOF + call_json_script "VAR=foo" + assertStdoutEquals "echo bar" + call_json_script "VAR=xxx" + assertStdoutEquals "echo baz" +} + +test_cmd_cb() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "exec", "%VAR%", "/%VAS%%%/" ] + ] + EOF + call_json_script + assertStdoutEquals "exec /%/" + call_json_script "VAR=" + assertStdoutEquals "exec /%/" + call_json_script "VAR=qux" "VAS=3" + assertStdoutEquals "exec qux /3%/" +} + +test_cmd_return() { + cat >"$JSON_SCRIPT" <<-EOF + [ + [ "heh", "%HEHVAR%" ], + [ "%VAR%", "%VAR%" ], + [ "return" ], + [ "exec_non_reachable", "Arghhh" ] + ] + EOF + call_json_script "HEHVAR=dude" "VAR=ow" + assertStdoutEquals "heh dude +%VAR% ow" +} + +. ./shunit2 diff --git a/3P/libubox/examples/runqueue-example.c b/3P/libubox/examples/runqueue-example.c index 1ae184a9..13ab864e 100644 --- a/3P/libubox/examples/runqueue-example.c +++ b/3P/libubox/examples/runqueue-example.c @@ -16,11 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include +#include "uloop.h" #include "runqueue.h" static struct runqueue q; diff --git a/3P/libubox/examples/shunit2 b/3P/libubox/examples/shunit2 new file mode 100644 index 00000000..d6e75033 --- /dev/null +++ b/3P/libubox/examples/shunit2 @@ -0,0 +1,1067 @@ +#! /bin/sh +# $Id$ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# shUnit2 -- Unit testing framework for Unix shell scripts. +# http://code.google.com/p/shunit2/ +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is +# based on the popular JUnit unit testing framework for Java. + +# return if shunit already loaded +[ -n "${SHUNIT_VERSION:-}" ] && exit 0 +SHUNIT_VERSION='2.1.7pre' + +# return values that scripts can use +SHUNIT_TRUE=0 +SHUNIT_FALSE=1 +SHUNIT_ERROR=2 + +# logging functions +_shunit_warn() { echo "shunit2:WARN $@" >&2; } +_shunit_error() { echo "shunit2:ERROR $@" >&2; } +_shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } + +# determine some reasonable command defaults +__SHUNIT_UNAME_S=`uname -s` +case "${__SHUNIT_UNAME_S}" in + BSD) __SHUNIT_EXPR_CMD='gexpr' ;; + *) __SHUNIT_EXPR_CMD='expr' ;; +esac + +# commands a user can override if needed +SHUNIT_EXPR_CMD=${SHUNIT_EXPR_CMD:-${__SHUNIT_EXPR_CMD}} + +# enable strict mode by default +SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} + +# specific shell checks +if [ -n "${ZSH_VERSION:-}" ]; then + setopt |grep "^shwordsplit$" >/dev/null + if [ $? -ne ${SHUNIT_TRUE} ]; then + _shunit_fatal 'zsh shwordsplit option is required for proper operation' + fi + if [ -z "${SHUNIT_PARENT:-}" ]; then + _shunit_fatal "zsh does not pass \$0 through properly. please declare \ +\"SHUNIT_PARENT=\$0\" before calling shUnit2" + fi +fi + +# +# constants +# + +__SHUNIT_ASSERT_MSG_PREFIX='ASSERT:' +__SHUNIT_MODE_SOURCED='sourced' +__SHUNIT_MODE_STANDALONE='standalone' +__SHUNIT_PARENT=${SHUNIT_PARENT:-$0} + +# set the constants readonly +__shunit_constants=`set |grep '^__SHUNIT_' |cut -d= -f1` +echo "${__shunit_constants}" |grep '^Binary file' >/dev/null && \ + __shunit_constants=`set |grep -a '^__SHUNIT_' |cut -d= -f1` +for __shunit_const in ${__shunit_constants}; do + if [ -z "${ZSH_VERSION:-}" ]; then + readonly ${__shunit_const} + else + case ${ZSH_VERSION} in + [123].*) readonly ${__shunit_const} ;; + *) readonly -g ${__shunit_const} # declare readonly constants globally + esac + fi +done +unset __shunit_const __shunit_constants + +# +# internal variables +# + +# variables +__shunit_lineno='' # line number of executed test +__shunit_mode=${__SHUNIT_MODE_SOURCED} # operating mode +__shunit_reportGenerated=${SHUNIT_FALSE} # is report generated +__shunit_script='' # filename of unittest script (standalone mode) +__shunit_skip=${SHUNIT_FALSE} # is skipping enabled +__shunit_suite='' # suite of tests to execute + +# counts of tests +__shunit_testSuccess=${SHUNIT_TRUE} +__shunit_testsTotal=0 +__shunit_testsPassed=0 +__shunit_testsFailed=0 + +# counts of asserts +__shunit_assertsTotal=0 +__shunit_assertsPassed=0 +__shunit_assertsFailed=0 +__shunit_assertsSkipped=0 + +# macros +_SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' + +#----------------------------------------------------------------------------- +# private functions + +#----------------------------------------------------------------------------- +# assert functions +# + +# Assert that two values are equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertEquals() requires two or three arguments; $# given" + _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + shunit_return=${SHUNIT_TRUE} + if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then + _shunit_assertPass + else + failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" + shunit_return=${SHUNIT_FALSE} + fi + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${shunit_return} +} +_ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' + +# Assert that two values are not equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertNotEquals() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + shunit_return=${SHUNIT_TRUE} + if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then + _shunit_assertPass + else + failSame "${shunit_message_}" "$@" + shunit_return=${SHUNIT_FALSE} + fi + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${shunit_return} +} +_ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' + +# Assert that a value is null (i.e. an empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNull() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertNull() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + assertTrue "${shunit_message_}" "[ -z '$1' ]" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' + +# Assert that a value is not null (i.e. a non-empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotNull() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null + _shunit_error "assertNotNull() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` + test -n "${shunit_actual_}" + assertTrue "${shunit_message_}" $? + shunit_return=$? + + unset shunit_actual_ shunit_message_ + return ${shunit_return} +} +_ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' + +# Assert that two values are the same (i.e. equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + assertEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' + +# Assert that two values are not the same (i.e. not equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertNotSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_:-}$1" + shift + fi + assertNotEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' + +# Assert that a value or shell test condition is true. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertTrue 0 +# assertTrue "[ 34 -gt 23 ]" +# The folloing test will fail with a message: +# assertTrue 123 +# assertTrue "test failed" "[ -r '/non/existant/file' ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertTrue() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertTrue() takes one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_condition_=$1 + + # see if condition is an integer, i.e. a return value + shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + shunit_return=${SHUNIT_TRUE} + if [ -z "${shunit_condition_}" ]; then + # null condition + shunit_return=${SHUNIT_FALSE} + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then + # possible return value. treating 0 as true, and non-zero as false. + [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} + else + # (hopefully) a condition + ( eval ${shunit_condition_} ) >/dev/null 2>&1 + [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} + fi + + # record the test + if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + _shunit_assertPass + else + _shunit_assertFail "${shunit_message_}" + fi + + unset shunit_message_ shunit_condition_ shunit_match_ + return ${shunit_return} +} +_ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' + +# Assert that a value or shell test condition is false. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertFalse 1 +# assertFalse "[ 'apples' = 'oranges' ]" +# The folloing test will fail with a message: +# assertFalse 0 +# assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertFalse() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertFalse() quires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_condition_=$1 + + # see if condition is an integer, i.e. a return value + shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + shunit_return=${SHUNIT_TRUE} + if [ -z "${shunit_condition_}" ]; then + # null condition + shunit_return=${SHUNIT_FALSE} + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then + # possible return value. treating 0 as true, and non-zero as false. + [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE} + else + # (hopefully) a condition + ( eval ${shunit_condition_} ) >/dev/null 2>&1 + [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} + fi + + # record the test + if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + _shunit_assertPass + else + _shunit_assertFail "${shunit_message_}" + fi + + unset shunit_message_ shunit_condition_ shunit_match_ + return ${shunit_return} +} +_ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' + +#----------------------------------------------------------------------------- +# failure functions +# + +# Records a test failure. +# +# Args: +# message: string: failure message [optional] +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +fail() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 1 ]; then + _shunit_error "fail() requires zero or one arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 1 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + + _shunit_assertFail "${shunit_message_}" + + unset shunit_message_ + return ${SHUNIT_FALSE} +} +_FAIL_='eval fail --lineno "${LINENO:-}"' + +# Records a test failure, stating two values were not equal. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failNotEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failNotEquals() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${SHUNIT_FALSE} +} +_FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' + +# Records a test failure, stating two values should have been the same. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + + _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" + + unset shunit_message_ + return ${SHUNIT_FALSE} +} +_FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' + +# Records a test failure, stating two values were not equal. +# +# This is functionally equivalent to calling failNotEquals(). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failNotSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failNotEquals() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + failNotEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' + +#----------------------------------------------------------------------------- +# skipping functions +# + +# Force remaining assert and fail functions to be "skipped". +# +# This function forces the remaining assert and fail functions to be "skipped", +# i.e. they will have no effect. Each function skipped will be recorded so that +# the total of asserts and fails will not be altered. +# +# Args: +# None +startSkipping() +{ + __shunit_skip=${SHUNIT_TRUE} +} + +# Resume the normal recording behavior of assert and fail calls. +# +# Args: +# None +endSkipping() +{ + __shunit_skip=${SHUNIT_FALSE} +} + +# Returns the state of assert and fail call skipping. +# +# Args: +# None +# Returns: +# boolean: (TRUE/FALSE constant) +isSkipping() +{ + return ${__shunit_skip} +} + +#----------------------------------------------------------------------------- +# suite functions +# + +# Stub. This function should contains all unit test calls to be made. +# +# DEPRECATED (as of 2.1.0) +# +# This function can be optionally overridden by the user in their test suite. +# +# If this function exists, it will be called when shunit2 is sourced. If it +# does not exist, shunit2 will search the parent script for all functions +# beginning with the word 'test', and they will be added dynamically to the +# test suite. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Adds a function name to the list of tests schedule for execution. +# +# This function should only be called from within the suite() function. +# +# Args: +# function: string: name of a function to add to current unit test suite +suite_addTest() +{ + shunit_func_=${1:-} + + __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" + __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` + + unset shunit_func_ +} + +# Stub. This function will be called once before any tests are run. +# +# Common one-time environment preparation tasks shared by all tests can be +# defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called once after all tests are finished. +# +# Common one-time environment cleanup tasks shared by all tests can be defined +# here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called before each test is run. +# +# Common environment preparation tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#setUp() { :; } + +# Note: see _shunit_mktempFunc() for actual implementation +# Stub. This function will be called after each test is run. +# +# Common environment cleanup tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +#------------------------------------------------------------------------------ +# internal shUnit2 functions +# + +# Create a temporary directory to store various run-time files in. +# +# This function is a cross-platform temporary directory creation tool. Not all +# OSes have the mktemp function, so one is included here. +# +# Args: +# None +# Outputs: +# string: the temporary directory that was created +_shunit_mktempDir() +{ + # try the standard mktemp function + ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return + + # the standard mktemp didn't work. doing our own. + if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then + _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 "${_shunit_file_}" +#! /bin/sh +exit ${SHUNIT_TRUE} +EOF + chmod +x "${_shunit_file_}" + done + + unset _shunit_file_ +} + +# Final cleanup function to leave things as we found them. +# +# Besides removing the temporary directory, this function is in charge of the +# final exit code of the unit test. The exit code is based on how the script +# was ended (e.g. normal exit, or via Ctrl-C). +# +# Args: +# name: string: name of the trap called (specified when trap defined) +_shunit_cleanup() +{ + _shunit_name_=$1 + + case ${_shunit_name_} in + EXIT) _shunit_signal_=0 ;; + INT) _shunit_signal_=2 ;; + TERM) _shunit_signal_=15 ;; + *) + _shunit_warn "unrecognized trap value (${_shunit_name_})" + _shunit_signal_=0 + ;; + esac + + # do our work + rm -fr "${__shunit_tmpDir}" + + # exit for all non-EXIT signals + if [ ${_shunit_name_} != 'EXIT' ]; then + _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" + # disable EXIT trap + trap 0 + # add 128 to signal and exit + exit `expr ${_shunit_signal_} + 128` + elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then + _shunit_assertFail 'Unknown failure encountered running a test' + _shunit_generateReport + exit ${SHUNIT_ERROR} + fi + + unset _shunit_name_ _shunit_signal_ +} + +# The actual running of the tests happens here. +# +# Args: +# None +_shunit_execSuite() +{ + for _shunit_test_ in ${__shunit_suite}; do + __shunit_testSuccess=${SHUNIT_TRUE} + + # disable skipping + endSkipping + + # execute the per-test setup function + setUp + + # execute the test + echo "${_shunit_test_}" + eval ${_shunit_test_} + + # execute the per-test tear-down function + tearDown + + # update stats + if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then + __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` + else + __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` + fi + done + + unset _shunit_test_ +} + +# Generates the user friendly report with appropriate OK/FAILED message. +# +# Args: +# None +# Output: +# string: the report of successful and failed tests, as well as totals. +_shunit_generateReport() +{ + _shunit_ok_=${SHUNIT_TRUE} + + # if no exit code was provided one, determine an appropriate one + [ ${__shunit_testsFailed} -gt 0 \ + -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ + && _shunit_ok_=${SHUNIT_FALSE} + + echo + if [ ${__shunit_testsTotal} -eq 1 ]; then + echo "Ran ${__shunit_testsTotal} test." + else + echo "Ran ${__shunit_testsTotal} tests." + fi + + _shunit_failures_='' + _shunit_skipped_='' + [ ${__shunit_assertsFailed} -gt 0 ] \ + && _shunit_failures_="failures=${__shunit_assertsFailed}" + [ ${__shunit_assertsSkipped} -gt 0 ] \ + && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" + + if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then + _shunit_msg_='OK' + [ -n "${_shunit_skipped_}" ] \ + && _shunit_msg_="${_shunit_msg_} (${_shunit_skipped_})" + else + _shunit_msg_="FAILED (${_shunit_failures_}" + [ -n "${_shunit_skipped_}" ] \ + && _shunit_msg_="${_shunit_msg_},${_shunit_skipped_}" + _shunit_msg_="${_shunit_msg_})" + fi + + echo + echo ${_shunit_msg_} + __shunit_reportGenerated=${SHUNIT_TRUE} + + unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ +} + +# Test for whether a function should be skipped. +# +# Args: +# None +# Returns: +# boolean: whether the test should be skipped (TRUE/FALSE constant) +_shunit_shouldSkip() +{ + [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} + _shunit_assertSkip +} + +# Records a successful test. +# +# Args: +# None +_shunit_assertPass() +{ + __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` +} + +# Records a test failure. +# +# Args: +# message: string: failure message to provide user +_shunit_assertFail() +{ + _shunit_msg_=$1 + + __shunit_testSuccess=${SHUNIT_FALSE} + __shunit_assertsFailed=`expr ${__shunit_assertsFailed} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` + echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}" + + unset _shunit_msg_ +} + +# Records a skipped test. +# +# Args: +# None +_shunit_assertSkip() +{ + __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` +} + +# Prepare a script filename for sourcing. +# +# Args: +# script: string: path to a script to source +# Returns: +# string: filename prefixed with ./ (if necessary) +_shunit_prepForSourcing() +{ + _shunit_script_=$1 + case "${_shunit_script_}" in + /*|./*) echo "${_shunit_script_}" ;; + *) echo "./${_shunit_script_}" ;; + esac + unset _shunit_script_ +} + +# Escape a character in a string. +# +# Args: +# c: string: unescaped character +# s: string: to escape character in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharInStr() +{ + [ -n "$2" ] || return # no point in doing work on an empty string + + # Note: using shorter variable names to prevent conflicts with + # _shunit_escapeCharactersInString(). + _shunit_c_=$1 + _shunit_s_=$2 + + + # escape the character + echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' + + unset _shunit_c_ _shunit_s_ +} + +# Escape a character in a string. +# +# Args: +# str: string: to escape characters in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharactersInString() +{ + [ -n "$1" ] || return # no point in doing work on an empty string + + _shunit_str_=$1 + + # Note: using longer variable names to prevent conflicts with + # _shunit_escapeCharInStr(). + for _shunit_char_ in '"' '$' "'" '`'; do + _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` + done + + echo "${_shunit_str_}" + unset _shunit_char_ _shunit_str_ +} + +# Extract list of functions to run tests against. +# +# Args: +# script: string: name of script to extract functions from +# Returns: +# string: of function names +_shunit_extractTestFunctions() +{ + _shunit_script_=$1 + + # extract the lines with test function names, strip of anything besides the + # function name, and output everything on a single line. + _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' + egrep "${_shunit_regex_}" "${_shunit_script_}" \ + |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ + |xargs + + unset _shunit_regex_ _shunit_script_ +} + +#------------------------------------------------------------------------------ +# main +# + +# determine the operating mode +if [ $# -eq 0 ]; then + __shunit_script=${__SHUNIT_PARENT} + __shunit_mode=${__SHUNIT_MODE_SOURCED} +else + __shunit_script=$1 + [ -r "${__shunit_script}" ] || \ + _shunit_fatal "unable to read from ${__shunit_script}" + __shunit_mode=${__SHUNIT_MODE_STANDALONE} +fi + +# create a temporary storage location +__shunit_tmpDir=`_shunit_mktempDir` + +# provide a public temporary directory for unit test scripts +# TODO(kward): document this +SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" +mkdir "${SHUNIT_TMPDIR}" + +# setup traps to clean up after ourselves +trap '_shunit_cleanup EXIT' 0 +trap '_shunit_cleanup INT' 2 +trap '_shunit_cleanup TERM' 15 + +# create phantom functions to work around issues with Cygwin +_shunit_mktempFunc +PATH="${__shunit_tmpDir}:${PATH}" + +# make sure phantom functions are executable. this will bite if /tmp (or the +# current $TMPDIR) points to a path on a partition that was mounted with the +# 'noexec' option. the noexec command was created with _shunit_mktempFunc(). +noexec 2>/dev/null || _shunit_fatal \ + 'please declare TMPDIR with path on partition with exec permission' + +# we must manually source the tests in standalone mode +if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then + . "`_shunit_prepForSourcing \"${__shunit_script}\"`" +fi + +# execute the oneTimeSetUp function (if it exists) +oneTimeSetUp + +# execute the suite function defined in the parent test script +# deprecated as of 2.1.0 +suite + +# if no suite function was defined, dynamically build a list of functions +if [ -z "${__shunit_suite}" ]; then + shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` + for shunit_func_ in ${shunit_funcs_}; do + suite_addTest ${shunit_func_} + done +fi +unset shunit_func_ shunit_funcs_ + +# execute the tests +_shunit_execSuite + +# execute the oneTimeTearDown function (if it exists) +oneTimeTearDown + +# generate the report +_shunit_generateReport + +# that's it folks +[ ${__shunit_testsFailed} -eq 0 ] +exit $? diff --git a/3P/libubox/jshn.c b/3P/libubox/jshn.c index cec48a07..69cb06f9 100644 --- a/3P/libubox/jshn.c +++ b/3P/libubox/jshn.c @@ -164,7 +164,7 @@ static int jshn_parse(const char *str) json_object *obj; obj = json_tokener_parse(str); - if (is_error(obj) || json_object_get_type(obj) != json_type_object) { + if (!obj || json_object_get_type(obj) != json_type_object) { fprintf(stderr, "Failed to parse message data\n"); return 1; } @@ -179,8 +179,8 @@ static char *get_keys(const char *prefix) { char *keys; - keys = alloca(var_prefix_len + strlen(prefix) + sizeof("KEYS_") + 1); - sprintf(keys, "%sKEYS_%s", var_prefix, prefix); + keys = alloca(var_prefix_len + strlen(prefix) + sizeof("K_") + 1); + sprintf(keys, "%sK_%s", var_prefix, prefix); return getenv(keys); } @@ -188,15 +188,15 @@ static void get_var(const char *prefix, const char **name, char **var, char **ty { char *tmpname, *varname; - tmpname = alloca(var_prefix_len + strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("TYPE_")); + tmpname = alloca(var_prefix_len + strlen(prefix) + 1 + strlen(*name) + 1 + sizeof("T_")); sprintf(tmpname, "%s%s_%s", var_prefix, prefix, *name); *var = getenv(tmpname); - sprintf(tmpname, "%sTYPE_%s_%s", var_prefix, prefix, *name); + sprintf(tmpname, "%sT_%s_%s", var_prefix, prefix, *name); *type = getenv(tmpname); - sprintf(tmpname, "%sNAME_%s_%s", var_prefix, prefix, *name); + sprintf(tmpname, "%sN_%s_%s", var_prefix, prefix, *name); varname = getenv(tmpname); if (varname) *name = varname; @@ -258,18 +258,31 @@ static int jshn_format(bool no_newline, bool indent) { json_object *obj; const char *output; + char *blobmsg_output = NULL; + int ret = -1; + + if (!(obj = json_object_new_object())) + return -1; + + jshn_add_objects(obj, "J_V", false); + if (!(output = json_object_to_json_string(obj))) + goto out; - obj = json_object_new_object(); - jshn_add_objects(obj, "JSON_VAR", false); - output = json_object_to_json_string(obj); if (indent) { blob_buf_init(&b, 0); - blobmsg_add_json_from_string(&b, output); - output = blobmsg_format_json_indent(b.head, 1, 0); + if (!blobmsg_add_json_from_string(&b, output)) + goto out; + if (!(blobmsg_output = blobmsg_format_json_indent(b.head, 1, 0))) + goto out; + output = blobmsg_output; } fprintf(stdout, "%s%s", output, no_newline ? "" : "\n"); + free(blobmsg_output); + ret = 0; + +out: json_object_put(obj); - return 0; + return ret; } static int usage(const char *progname) diff --git a/3P/libubox/json_script.c b/3P/libubox/json_script.c index 5c35d871..b5d414d7 100644 --- a/3P/libubox/json_script.c +++ b/3P/libubox/json_script.c @@ -32,6 +32,7 @@ struct json_handler { static int json_process_expr(struct json_call *call, struct blob_attr *cur); static int json_process_cmd(struct json_call *call, struct blob_attr *cur); +static int eval_string(struct json_call *call, struct blob_buf *buf, const char *name, const char *pattern); struct json_script_file * json_script_file_from_blobmsg(const char *name, void *data, int len) @@ -333,12 +334,40 @@ static int handle_expr_or(struct json_call *call, struct blob_attr *expr) static int handle_expr_not(struct json_call *call, struct blob_attr *expr) { struct blob_attr *tb[3]; + int ret; json_get_tuple(expr, tb, BLOBMSG_TYPE_ARRAY, 0); if (!tb[1]) return -1; - return json_process_expr(call, tb[1]); + ret = json_process_expr(call, tb[1]); + if (ret < 0) + return ret; + return !ret; +} + +static int handle_expr_isdir(struct json_call *call, struct blob_attr *expr) +{ + static struct blob_buf b; + struct blob_attr *tb[3]; + const char *pattern, *path; + struct stat s; + int ret; + + json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0); + if (!tb[1] || blobmsg_type(tb[1]) != BLOBMSG_TYPE_STRING) + return -1; + pattern = blobmsg_data(tb[1]); + + blob_buf_init(&b, 0); + ret = eval_string(call, &b, NULL, pattern); + if (ret < 0) + return ret; + path = blobmsg_data(blob_data(b.head)); + ret = stat(path, &s); + if (ret < 0) + return 0; + return S_ISDIR(s.st_mode); } static const struct json_handler expr[] = { @@ -348,6 +377,7 @@ static const struct json_handler expr[] = { { "and", handle_expr_and }, { "or", handle_expr_or }, { "not", handle_expr_not }, + { "isdir", handle_expr_isdir }, }; static int @@ -416,7 +446,7 @@ static int eval_string(struct json_call *call, struct blob_buf *buf, const char } if (cur_var) { - if (next > str) { + if (end > str) { cur = msg_find_var(call, str); if (!cur) continue; @@ -434,7 +464,7 @@ static int eval_string(struct json_call *call, struct blob_buf *buf, const char cur_len = end - str; } - dest = blobmsg_realloc_string_buffer(buf, cur_len + 1); + dest = blobmsg_realloc_string_buffer(buf, len + cur_len + 1); memcpy(dest + len, cur, cur_len); len += cur_len; } @@ -480,8 +510,8 @@ static int cmd_process_strings(struct json_call *call, struct blob_attr *attr) continue; if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) { - ctx->handle_error(ctx, "Invalid argument in command", attr); - return -1; + blobmsg_add_blob(&ctx->buf, cur); + continue; } ret = cmd_add_string(call, blobmsg_data(cur)); @@ -537,6 +567,9 @@ static int json_process_cmd(struct json_call *call, struct blob_attr *block) } blobmsg_for_each_attr(cur, block, rem) { + if (ctx->abort) + break; + switch(blobmsg_type(cur)) { case BLOBMSG_TYPE_STRING: if (!i) @@ -556,7 +589,7 @@ static int json_process_cmd(struct json_call *call, struct blob_attr *block) void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file *file, struct blob_attr *vars) { - static __thread unsigned int _seq = 0; + static unsigned int _seq = 0; struct json_call call = { .ctx = ctx, .vars = vars, @@ -567,6 +600,8 @@ void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file * if (!call.seq) call.seq = ++_seq; + ctx->abort = false; + __json_script_run(&call, file, NULL); } @@ -592,8 +627,7 @@ static void __json_script_file_free(struct json_script_file *f) next = f->next; free(f); - if (next) - return __json_script_file_free(next); + __json_script_file_free(next); } void diff --git a/3P/libubox/json_script.h b/3P/libubox/json_script.h index 9475baa5..66563e9d 100644 --- a/3P/libubox/json_script.h +++ b/3P/libubox/json_script.h @@ -28,6 +28,7 @@ struct json_script_ctx { struct blob_buf buf; uint32_t run_seq; + bool abort; /* * handle_command: handle a command that was not recognized by the @@ -99,6 +100,18 @@ void json_script_run(struct json_script_ctx *ctx, const char *filename, void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file *file, struct blob_attr *vars); + +/* + * json_script_abort - abort current json script run + * + * to be called from a script context callback + */ +static inline void +json_script_abort(struct json_script_ctx *ctx) +{ + ctx->abort = true; +} + /* * json_script_eval_string - evaluate a string and store the result * diff --git a/3P/libubox/lua/CMakeLists.txt b/3P/libubox/lua/CMakeLists.txt index 04abe0ca..34c9ab18 100644 --- a/3P/libubox/lua/CMakeLists.txt +++ b/3P/libubox/lua/CMakeLists.txt @@ -5,21 +5,13 @@ PROJECT(uloop C) SET(CMAKE_INSTALL_PREFIX /) IF(NOT LUA_CFLAGS) - FIND_PROGRAM(PKG_CONFIG pkg-config) - IF(PKG_CONFIG) - EXECUTE_PROCESS( - COMMAND pkg-config --silence-errors --cflags lua5.1 - OUTPUT_VARIABLE LUA_CFLAGS - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - ENDIF() + pkg_search_module(LUA lua5.1 lua-5.1) ENDIF() ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3 -I.. ${LUA_CFLAGS}) LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/..) IF(APPLE) - ADD_DEFINITIONS(-I/opt/local/include) SET(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "${CMAKE_SHARED_MODULE_CREATE_C_FLAGS} -undefined dynamic_lookup") ENDIF(APPLE) diff --git a/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-debug-shared/uloop.dep b/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-debug-shared/uloop.dep deleted file mode 100644 index 1809ca2e..00000000 --- a/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-debug-shared/uloop.dep +++ /dev/null @@ -1,8 +0,0 @@ -uloop.o: ../../../uloop.c \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/luaconf.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lnum_config.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lualib.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lauxlib.h \ - ../../../../uloop.h ../../../../list.h ../../../../list.h diff --git a/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-debug-shared/uloop.o b/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-debug-shared/uloop.o deleted file mode 100644 index a5dba2ef91c322b922b6c0879cea4ab7fcf8f542..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101140 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 diff --git a/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-release-shared/uloop.dep b/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-release-shared/uloop.dep deleted file mode 100644 index 1809ca2e..00000000 --- a/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-release-shared/uloop.dep +++ /dev/null @@ -1,8 +0,0 @@ -uloop.o: ../../../uloop.c \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/luaconf.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lnum_config.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lualib.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lauxlib.h \ - ../../../../uloop.h ../../../../list.h ../../../../list.h diff --git a/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-release-shared/uloop.o b/3P/libubox/lua/builders/linux-gcc/_rt3052d_Cabasse_Stream1_64-release-shared/uloop.o deleted file mode 100644 index f79ef714e40f976b632816d708dae4daf6ad5fd2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13392 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 biCu=?M~vf#i25x=>~l;t`qQEIJdytej@t|c diff --git a/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-debug-shared/uloop.dep b/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-debug-shared/uloop.dep deleted file mode 100644 index 1809ca2e..00000000 --- a/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-debug-shared/uloop.dep +++ /dev/null @@ -1,8 +0,0 @@ -uloop.o: ../../../uloop.c \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/luaconf.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lnum_config.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lualib.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lauxlib.h \ - ../../../../uloop.h ../../../../list.h ../../../../list.h diff --git a/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-debug-shared/uloop.o b/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-debug-shared/uloop.o deleted file mode 100644 index ce9d92ec7914ecaef6f418b03d9fc42e77b4d930..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101588 zcmeFa33y~zc_w^sNp8!yF>QAnxA)s}+b-GaZmG1i8oTW-l}b{%OI77sdNGi)S}JuH zR!fQ&cbjDbgkcE~V+fg;B!sL?62LHlkQtUZfozlHPgt^N0+|V9$RvbGNG6jB@x1SM zmV554TXLHr^FPo3{B29R=iAPAzO#L2|Bifd+V_3W{PVp&FARC!_bvP0<-5GKQ6Wfs z`@CBWss4M@y`J|2ckcV*lRdxx%qQ;L@BRE!f%nO$_I>R=J-fV*Kb7`Ajh|n9e6RP5 zPvPhBoAB53Ui-M`O}=GcaLoJa?_aiGg{SfN$;YqwhoFaocX@vd8q($70v_;_{$cN# zXD-{nZ|E2(l4zC8e+JEV_5+c(5mqB8dV*Qa}+|KrgA@wE4eJNvvZiY}fPrtxW{ z@m{2H0%;ueK4{Z<4C%zr8OLZzSZGDtDJ& zK3T4xt$fmUmr}ld73FIb#l-r(2TFEF1BQ zMLg5LCzVJ0gQ6L$8!mr3p=@p!Z&Dcyw>y(z&if%hqt zVV2`F@8h?w1N(O(%=WiWmoc;*(%!Jmh}$6EKA;>wj&h7PBDpQ?);0`!zw|BXGj@Ip z`wUZl?@h>CWh>QB?fMqQIfy)98@Mn1a7S6wdGi+HQ>X(;S&V9-MVlob(Hz=TQOy@kLeKuYLT3m!ID6*7N;ZH)MOk6=*ho8iA-XRn9(zbjolG_rH1<^Z!_f56M1+^^JHRbV)R9cUh0v zCNeJCGqH>yk614;SMxqYf3r@D(SNV^%fLr%$~yk)y(!_{_v)NSTDFr(abPs}fo|!g z9HxPK@|$hRUAxYBUwlUSs*!kh12Df2W>dN*)C&lLB3f}K7Q4tj5X<(CzVB(s|mz`A8F6g-e7$2$;Z*&JYMPILw^zN z(oJZW_B!L60Buq{y?`b9)Qpq9I%Hs6{7Lxl$-esk`|-T?@ef}c^}{Yz_piZ5J7J?f zZ6gnJwzQAuz3xuq*Lj$WW&28*=!4%wn}7%X@F$Un&($X12|Kc_U|+86o>bq7+pg?h zDsPfcNM4q?4@%q2Ip*p8`zFvV#M&oA_j3ttxWRq83ofb6Hax%Dg(qoTN1p9ueZGq< z&I=@^XFFM6>>{i8n~?SOF0%TbgRDy}!`3iS znP;9ca8Ao{bp&$^-k%B3kKm61X7GDbLJ+~b{8K%hcotE^KeVG0@A7}}@=iRbEe(J1 zicY-Czw63Q{4t0B<5zX!UH*S~0rAoFR~-JgiI?O>(jPeZe|Q%B!`Fh?>(2k-1Ux%> zlYZgehX2{{{?-2NSM9#C=c*g8y4t_S-?bx$3_wTfubJdHk zyywcoZjYs(aL?QE0(=m1`5hkr^zHV0uDbF{()kEp@qEiP@jTCa-fjf%-RXH(UhChv zv#^^aJ1-N)=M%#4Rbc5;@sQ;O2O*HbJ9kpU*Bsk%YzN79U1rHrAiH|hM#SJXS0ZKC z_@1}>4#26{o={F)VATwOOSrD|rczYA9I z&*9g*@WX$f->d%ecdGaDbEu*zzwcVmr&5={l7D(H|2qHpI}Ql&veTgK>AkGIvgxJz zE_)DiQhk@-CzO{p5$b&_2rhqn4Zknzy}bANka+p`okOU%#?N>0b4Tx!_zjsq4Za<{ zKY_sIg!H};B-edtmB_x{9SHQ@#9!Ax@MVCm$l}-a$FT(CrFMB&i~@6g@r@Gd^?F}} z;GxWaNAP+4^m~60vJZ`>pwf=sKK#DYr%rqEwUfU9rO-Zd^xb>g3_w@FW%BOb{~kaX zL6M=`|A&MS0SWKD;}!sWzk<(WBW!z8y}i?b^kwkfH+$f%_`YHb(a#>_C#9sJ#_S;# z>P4iB6!1=vAHDP4_}tO^WBC1i|0DRlQ+^Eq2k^%L=sQa2(c5l-jH?#Tct`Jj2LON$*4i*d?Wc8IDL?g_6!kPk`8TCu3);%RndYS7);<3gWw)JI+y)~5 zRu$Ui_5B`X+~oJuephXJ{%uUZX4$WZ_QD>Jv)8|KokVM%pQhrPXh0F|@m}!jkmMf% zrRp@fN2*bAEbd(Pk2|?0rZCmPCc=C4V)W~W$NmA0Q{j}5%3zV!({B}{Z0Jd z&HSKZdltxhkCbV4%mUA1=y(*rEuia=thoe6W!qgL|yglE6 z55FXWD1^Oq5uj7}c}NSIiwG(!L2H-*BkPi|l8qfWtM_-}=R=yc6=6NASkEaP&WXXE zSiE+`InNP5uAYCtaLVokPZJ9=*fU^nX*OU9mI{PKTHQo<a zOs8a5d+{PdO55IR8R?I!z&UTv=OEkvS&>5-bU8i_8NCqyUM=S%T8`59qe@>G^L13= zv%)HD=y87^tSm;?BOO%XGZEI$Db{nM!soRuuVxkZe@EHmVP)ChRk)X2{c_st_f+VV zcikB(d!_Hw@u73`bwu|Pu)hM)?M2~!p43wqdha@m%=1JySo-=SWZdbKj;8)I@P7?I z*Gs|O>AyzcVry2W9ldV=U^ip&oRtm3*} z$F+DPtGj=LFZKP2hi{aUbE8)5CD%NBH8$?-h9+icr8E_$GdBbkKa8JEt@J6Qw0FasY3X^L zMv&6CV}J4m{QRgUe>f!HqV%>RCn;S$cGJ%T{Ii<;oF%{MUPwRM@=3Mxg{UB)90TRe z{!cI^uTpY|xrpxlJ-|K;>Ip;Tdsoj=%y0aNP$5F^^4A!u zj~c2S-t`}$tQG&gLIx@?*w192U@w5(T`j;<-g%TP-~V6m6S3n9%3wf`_VwT)`QJOV zy0&>}VSRODV{>(N`Ox|H+D2>n!2E^PiwBn5D_a*2Y%MIe&nz4oJ~-YTx$)S>`s(WD zp{8Y;f=#3aq!(n%~@7Z*8d1 zR*nU*xv;vj)IJLkO8CNJYl&ENpkPA)-{?9vA6pY9P+VADU)*TFyrt*`fe?9sT-!Xi z-kM)@$XhFm?fDg85xe~c<(bDeTN@YV*A&JHIk*E0tLM+Jk{Q5_vu&*#Bx%h}%7DJG zaBhBG2{WI7YP$1Vo2`pVjMh+5ZY-Q@EvnDW_IV}=vJDXI8W;*%Sbn6rx$uY*wb4F{ z;-i_`XW`jscx&@z=b5mOFN_s1Xg$A9d&97jg64Ajyk^~8Z?6zVJvJASJ?i_ye0y_g zdH$?6GlLtO$VweH_GYfNmRk!{#QkQZk8PZvXKSQT^UKSt3-e0&)=C?3sqeMbjrPSR zS}p{^)mnM9y}r6~zO}NcqheuMnHO6Df3~%0X;F>9geDOmq|$-*dFYC7bR^ILDYZfS zjl@d4!=WLl-LexjY-o3Np2jFdKqln4xVqL_34_ZkTj#@qu9Q^P<@fy7MH^5R=bQ%z zN@u^S3un-XBN;l+R%jq*63W1q$-MU2_R11#8tvUaJHN2mwxzdy7B)dCG-U+kWpmz? zq^%Ig$l7OBHByq6kvsT;KIqsGB}TvpeJtR8J(b>_8rsBix!Yz|5C$5{XW*A;T~FtYG~!IOMRbD-H_J%{#O2e9KYYMw0|Aw089<- z?)&z>uLuDR$?r!&@pqyCBmV#*Vv1;7d>ogg*^j=X$9s?V{LfeQZGz!Ty?)R4rfBTl zjOok#p;g2t_`QX6b^KNW`#x|ywHIzh550|MvsRzVHJiaOnsXhPE!XP#DGQq^HApZj z1QM7ll*(0rMnX^}ThGlF^C$8}z{i!W!bACH{d6S{$kqx=b89i+^a>-Y)T>j4>1l&E z;FG!8Y_$VeDAf(DLlAIt*;59+yt;BWkY7e(qZ>hoq?uEvn%T)h^F+Q{E0jyY@X%03 zB}9~BEHG2%u!7B2>rDk3$s8V6KmHqZ1?JqY6f^zUjGMSN) z!F`)c<{EV* z(q>h{tyzb3jv26J85vTBH3%m9@R7sgM@EK6MkmHIBg11fuuFv)Q34KTGGjxBM<&K5 z@Fz1gJPJcQRH30sIW#&tJ~Vm+91uI)Ixwut3nPsfeDvUv(V_9N@zJq~(c#SK_!y-+ zswWtpG7=4M5S@lEs>IsTtSv9#i0Kt!qU|lpTGBDTj-bQ(7H*lW$@00v94e@eUNmGex&8LbqMEICRgJF%IdaWQ{|fkU5gz#N4r%&g?;}G?H;^hO&kRJGpU0w=Rak z*!zesT}qDFWjKG}$k>#s!6A7wICAia{L3F1k6=S9fisGNRZ#wi4i52OOz!xotG6lT z`5fVn;v*9yx&|whZT?0kRKp4tH4Exv9xd3&)RbxrEJLWfN&$Z7!5*QDq+)n1f{P?W z(xTH7i45(ro1zh`o*dk4@<*H(+VFd+K{iud9i`nfB9UPmjs^2P`4PIP}p;L#a zD+dnGRwY9x;&6yw85-r^(a*Zq-# zMIu)qC;5{4s_x*$hRQ`@+Nr?sm`c53jKyw{jcDwuQfpu&dJPMcu7n$~O}NB7-iTo1 zaT|0o68VVg%QY|(xrRB3FG}i*I{5}~^Bx8e8;lGWl_r`Zrin#2G+vj1k&KiZ1C8in zfT1OH6c*vwLTiy}#AxDrSb}0yk#Xg(7-&Qh19YvT&0_7+#V}$WG0^x((O4+iL?J=L zM5v84t{NN*jwolLj+v|tVp(p@N@a*veL+Yw#fS!`Wr=8@>$s+Lje%A{S%V+S9EK`pk5Dm^ieWTmOfidY z#56MvO_FMcHnfh8!y=qwVpQSZ3jFy-j5e;2B`C%;(yg$D>g+Pc($JW-LUUPr8N%%h zW-O*@;~EYZZ4xv^ymi*#sE%kkbmCJn?KE3_TDG#q8L**dhT=4T3+N31q0)%>)~7%Bgx22e3O ziHX7}LQlKFQSO)3w|*g)`9}Q0{7JD;;#8ul>!orWBGW5*3`**=&2p*8i569$*V+q~ ztx^c*I%je@Oc0#NH*2R$xn{0BSIJiM&1`9^Sv#4nG)K*pD5f#X(}<0;Ybvod1(I32 zB$!6%yjR4v*)nDf&9s@8FkLKXJH$?v8=2`;QsYXWWI{TK?R0FM zyix`|a?B)?YljF(Ch%Ln>_@X%9l?-ETTZ?;u>*HLn<8#$Z9UM1T*8YRYg&Q{HrHE^ zD$rb^Qfp?bxmk>xE47hKH4}pe{bU-+tY@SE34OhRl9L%dp3gbN1P1+?(MMVfs;H4K zqDOmUULuyZLj)CS*+3$0;!A75Vv1?w@`$TRtuPm8DDlEvdkCh~5oiE2H3~sSxPa+O zEng3G8zI)%SY6s|E-kOlZ)zJ+RK6GqXq&qj_Z!u(G}Fk=S9WwbYnA119AN;9>oY<>zNND{F;0A|cnqY-YLvTQL`vnOZEFiay%i=%I0D$7ajMDtklPZz3l zC)o@)Dl=GUz+c#RuKZ9IZKnp=$Q{|1UuU1Noh(cjnzQwK1#P=zndLMVFnr|dCLDx!XO9_@K z(Fw9><%;FpaX0{I3pz@sk*aHMuEQQl1#qr#O1BDgnR>Q1c6eyKISYdmY?B-<8Ah$7 z=14S+@kMKCn3ilYTb|!uOEFcb9p^%BOt>)++Au8lNn;wL zh^l%ih0|6etV^@l)XEJyWOHaO8`WGl4H`&Iyii2rc9YJAAyLtU20lh-lB~;wDH8Fx z4Vg_%OiWa_xLu@VB8K|3tT;;RX9XD1B4XQ4usZRq{orI39S@twNJkoLWiBDc=|VA& zN>tCI@h%>B8UbC>vsJWUHVM(xM^n;CjBmZ0*96CVK zQ93=8(Lyv%?qs9hZWl{9o)MHsOH(Yu4=!-j7Y=JxIyy1}^Jg)sqK#>#P%UO=(4>^m zmM76^scLvgS67CJg_0TC5>zR}WvtcIgjp3eVIb%k5 z3Dar#sg`TUv)U?gY-Lms%|@w^!rpTEU4Xl&9-dx`t85+wh zHfz|%-99gFu_mB#Fkb-wtBFaDS%E%KE0@&d4xJ-Xgk2!!Kta>9E9KwF&7Yd5=cXQi zPjfn-tv66QMNF#M6xKqmoI7&FOFira$Gp_M3W~M7)EOs~@lu#_Wvqf6K5}Ga2>gpt z*x1mxmue~4sd6P>@={Aq$n=_1Uh1p@)9yzmywo{|Ds$XRwIg8=yi5Va?lilXdL#xx z#-x@Nj08H<2tBW$lQqPzP&OKq|+MF4DP)bGl>Ji-GPQ+MNGEw-ggvKU>FD~(&QcR zQcwDr>16KfTHyKbia}76Qs3{ZjJ8BS5CxFt2Ms7^soot21(~6tiJ>D!FZDxyQ;LM8 zeNPk+93C3-Qa>C8h9$=TkuDf&@}oZHJ5i^Yb=XX$sy7cwCV)x*<36*<(*1-RB>ugA zlO@Cw{M$&F6hG-VRY|clKNW+3%Ksp;u#rO}ua_wP1Hvn<)?!niN?^O%KHEGOcs(EU zd;QBS^<4G=$ww@A>?dZUSot1nmw% zYv@)0*<&H?k%@6at_>ka#)a#JA!Hue37YFHEgvzM% z;8ARtCELCbGLPwXFV$}W7hwb?>9!EI*;>Iu1?cu$*upp&{W~o{R!p$6#w7%-cA!l_ zYlNw?a)s_^jUlzFB1=01P1DEAIt7+CWMe#Wsk@@MlEHbYyJHwA%I)+}Y%q%9+6fDV zf1nc%>oS&uotP0yI@Af5EQjH=S0WmRt21OmT*=6)tyy{qzSlZc5ber7D?{W zK=v*cc(1MPq?HxMnlkFqD5e4_o_}8iC~FdCRT6E|{mtf7xykll)>S2MjtT5kt)O9E zDjSh8oiClB%;9OJT@~`LPq{39$ zECr`#9n;c}!U+_fe(_Q$yOPJWBM`-@TAADrXnBT^ZTE3gp#&)2XdP}e{M8w(3Lv|w ziI1}}BBVHl-U4GRwIYn-KBp16Y;G0{Lk5NG3p4_~I+lv3P-0GmXjT+xBq9xgcr&4Z zRK;cuMjv$~zc{4}J5utXX0A3$IKKlsP|2zW*7A~gwPw)_@kopArE+z&8dLlwcCKqi z`phudY^bQ0LQ&IJtj|_a8X&|=p_GVMYCz?pnEhl7T*?FD`KN5Wlw^2HNEDXvMRP3q zYt38=K|K^j6?KNZmME+2Mli)`B`@`DP1K1Z))bgL zc+Wb3)nF|8F%fW~4Xlo7AdHcfJha~$J|hl*>_&h=sl^!^*VJivg~&s!Rh*K;J}3YS zY`w5`0n-{9>iLV7qt>XM7=gz*lg)8M1nAN4X(L5&bJ-jQO;nLSxbi|sFdAV#8{#lt zf|qJ*w(`mqAFW@jH?T+xE6_Q2z_Zz@GP6^B^bn2#H`e>+Fi1X8&dHRBIKb2g9k?T) zVouP&d&elMF^BPf{zS#pFt{vglt4PY3j~RVlj6w0aH;~^DwjUg0fukX3#g->zZRjd z&neH6r^0l>`SvKmLrvCP&ZSF^t;exaD+RTYh+>sM0YG0OM4OhV{*W3}>gv~jsI|Fp zsQwUIyDdvIjS@GR#WGgC+|1We!(qWL&B?~}H0S5JWdxg1#;^IE+T9_?EzFO4{hW{NFDgJeY z@zuUXvN(|doRXr{YofUFWUXApnyT{B3o~5fM&`b@3l*v{+E7F0e`iRB1@TB}e_e=T zMVQK?kwxK@&cXlJA(9Fr2OXQgK8nmvoyeAQ;EPhdAxf3UbPP0SmFH;AvD>L^y{^*k zzbT4Ay+PTs1@F6}*j)8A3OXAfCHBopXo>JGQH+^Hw;c(UdTW#h!@}d3mk{>vj-m<` zm`f0kcOc+6QP|s}h-w8*CYz@xqVQ>KTWku_OT9gcvIA_5_umoX=@20eFbq0oiv6At zXVR1{G_zAvRofe;-Wk%EBFC8!ED=K*O8WOk@w(L|3A!~ru+zCX|tqTP+ z0)uduCMO4W>-1oBQ-`5=Cjsk^J|djL(7cnNQL1I9X*LehJJE1+PgfTc@8rv@O|Js z(n=WP8#)cHVS0R8rad@?W5XGeyl)$lVVnRZ&HJ~Z!7)t?UOfK;+t7>-9Z^*~_0%?0 z6F6H-NzPn{m`JC+fHt&bx**PMtJ?daWQh@KNyNXq1VW}H^)pF?wOQ-}DxWNInJzmi z&bgQRa1tdvh#dNBxJ(rGkt7mqRtZUPb5=q=W*g|St0$Y>L~JR`*iB9)->n%hHAXMiktr&sC5T&;KpJG3FB=5k8ID zo!x&3Ugd8C1Ap4xoZT-ML;?31;N}{rq3DWm9+?hFKdv?b=Civz>#xyvSvq% zsow!g7pcic0Ry~BL3)MX4dHA6&?k+e7GMt@lke-ejdyw1jfea9E#xDrP|#C)+6gJPP4I{|ft;=h1`12ecG802BX+SyLu56k~q zC_%d#>|aKxWXSYgCIMTzvkg=q1rkTkS+Fgx<$FM-2u&k{&QicTjL(t-aPl+Wrby zl_-Y>`SVr4QBYVC8UJ605zIYM8quRZuU8tPr1^7C>MAOGVUD99Jrsgq);KwSu1b)X zLj5s|HfELJZy6i>LA5HvO#GiNWQ>sS#?YTMb{+BUE*Zgq%O+auV=97hqRehI9Pe-??%#$El+K;V6tEKcYbSi>x1s3b;7v9-Y;YrpG%r&d02k(pRCFO4Q~E$W z8W*R)uxDHx5LO)KgU+mOq>*6S`OH>(c@xWkt7l$@+u@qLzb_ze5IDAi(UN{&z&mO% zX#@#F&n{vJ#GDGcFu%UC*jiW?9R|;DoE->o-x=;$R0d~4gEVa)%XyX&^5W(@mKZX! zq;PJCU=}90D-*4J@K;Ww#?FuQti-ehUHb#Z=uJ$Ug;J)c8DxKMDTa&?u| zwe{7_)xr7Y_B@KIBvT;NcLS510n(SP%`snt^lgd^>El4n$dNih&cSa+79x_m=lL9j z>8R2Rs$^L}hI$~g<0tzD14W6ZKIG1%*KoUS`{JOLqUsV#jlc&Klj^3!3XjC`2C-%{ z%_0`dXK4&9MW9HS({y!18RzA0LYU13s+Po{$V6u|WLm?mmWeD1L54q#Fl=p5&4f4< zf(-vT!mzU1UcoV`0>sx7u)vW5B0F7df&GXH&qd1-b1{QPDUZ69okcFYy5 zY~oS`Afb#`qt6Ky&=eb+>r1#z6LRJU&uk+}%Bv+F4CV)eGa~g(kh-$Eva+?joW{!d z{CSjiHy)*rrhsiV4fJ^;q7N%|b8AHmjk`#orkYYc=^eeq0gsLy152act!=~G-ZN%_Qohb;^hHjUZ5sASxeVrP{6>}xBJ)U3R zY%jGJ+PMExdd!a@hDYb62(018$TW>^+H(gUq@m5nqqNQC)=D>e;)I7T6tV$*HhKm& za$(Tx?e!592b~ofU8Lvl(|{7DeX-4@e}~K$C^RzC^EowOkGpz4<^og*C=C2L*PyYp zfMB4H6hZ6;QLcn3IZ7JYaRqJ!k4uOb)psk4C^%(-U&|HO;Hxc^HCsR7{xoB z4lza*mN*9oHP3#W!+7Mi>Mom`+|=V^5YHpYiWp&xKKNZ{j2xF6E2TJWa_r`%zPpD8 z!yWPR7j2>PLI%)#rk;f7Cd5M0+q3_2?0VtmM7c6i`CC0V_4&Io6f0M!7^6PoT6+kG zQE|ijEs@xeEw}FIR3R1(R}pK&;}S=(ac*^eQ{DWCrlw)Q_5wx+e-3QeQ6h(p_?E@2 zf+LJhv{(ai2(qyV4vU1Mq0v8#8vdQ=XE2s8B!Q<_!xog7ZgliQXs8)HHaLienvDi7 z++>3s@cv$0ZtV5E-oGM}^T=qG`^;d>`Jk@o$imd)6$wO$y=@^*tL(Az&Lm^@HL;Fc zc6cIL;rac7XEKsvybZHVWlUX$NE;=F1-u0SE1j0n+TQaqT)=QH#6?So=iecCH`*}! zWv>*^CtAs-7|LcTOkd80sA$ph`~f&yAaEtSCd7`Z$>Q;x9J|*Rj;nUJA#r86+6`iV zNi8lVuE&9p$d%*ja*!k#`9`#f%fWcd5OtG-p_XebQ$_I>0R~JmpB5T2miw6hmx;%& z1S2SNI3`*yVV8&{3S$^WQSZdZEjorW&E>sNLYSc#CD%^Em<}$c<6&-HI_=f)6rp?A`MuXVBh4^$g(4`DuGZ&VAYzaiCxwWtvyn^i}s@kLT%P-En^q$~V zo{tS)wU{WU7Tgap*j<#bOH0nx9ZZFBa@w>HUeABTix=0bK0xn&p-Q?dxb8}91J@hV zWG^`)kL*Xo6}Y_Z50yOJ!WN8sC#MyEeKPJcU% zfB19XeZj;)a7Qq7acOC5Ab2I=09ybiRVL^SLP;eCUT|ELK}BQme6*#CN5`oANz*l? zUlHERZ2Mq|=21F}XErVd*cpCt;GUqp!~vf13~elH0^PvCKyiWGL}+P-#|_avL2G%V z)j=6cPDo8rkD|mg@u>7M8;)cg8!BUQ;%jIKHiSttqft{14J|E&SQy;3GZ93CRjl2C zBw8UM7wVv%C**}v$)KzS1T587@o3Gv=Y^{ANc^`h7jQWVGZ0yIDY@WMlgs2nsUvOU zqg`@=Cgnd2=p;YJaPS~%a+M#7Dx@17iqn~#QMQP;0Dkx1@MoB15+O!G91dbj0g(xEGK^iv_M9a(fgtc6iEZvg; zd4VNt{T_b7Gr-!5uI~Uc{NkaPI#oJSQB@HUt``r#6s5|r3||t@6x2Ra0wZv-!J-Jl^NleS@SC ziM(AQRk{sQ#ewee*tyNsGp%H?S>Tp6PDD+Ta&z?@0>~1hk%}fqN{tiZyhx5VTSlj8 zk*wP)DmineHIj)*HpH{bAxM|Kpse}m` zke-jrl9(=PhX)ZDtCj_rLZQH8AV=pFm#%5|6pNPF|A@P@pch7QG2|RKcL2-l;O|Vv zYJL!)7mTrUpaJet+_r{+Tmmv=hNBw8S5KFUbrleZnfC1}v zav&xdZ*@RB1M|p)4i_*nH3Wl55KgoLV0a^In;7+DPI-~*X&ALw7SBJ1xu*`2$%q&) zHO&D7&W2*B#dD=w1$UnR=9CFSo42Gea#L7@-fBY#aA{ui zA@sQA;vC!CQZj>Q!~%l3WfO8H^st&AgM#!OA&^s#--CE$e$Ob)3BGp%h%JSdn}pa1 zz)8PQr+*U);^Ls1FHB)EpRu5T^WaAQoj;MOZcboB~Qc%W?*BMJ=5g2!$hcBW8 z2V@O!uf=Ci1?dotHlD{`td32m9G{6N0R6!ud;BZx1{7%uVAq}(Tnm*<^C2U&>tD!z z0~=4L)EQ|E%Our&iD_f4wE(7@uS=QIw}3aG@E(_!syk#1Kiq5zu8p}ua1w;cbSnvK zz_Lnfq`KO_+RWP;B(x9q`Zp`3%DiHYHRBc)o-Rz6Ss!jy!D^LF>pm5jK!tjny6l=K=M5Rh%1Hrf=z%dT& zeaaQFzp0Lm9uy(bf?`5ZOy#jZ3&luq5-)H^6b_r}XcUE$n1Q>;l^n*bA_o4b!ei5M zrJ`6>j6h*%po@P~-j0)XFSh7tUZl*0P&xLqu(s92V{uqfFttVw^yF~XFESbD~{{y2kwL4jECfKHmuFD48*-ExNxq$ zj2#Btj_|LP&M+sVA2cecBuWY#3Ceh)=)g;ZS8{#?Aeu_SAdjsAjgTu=pR>R_js{Ad zh(zvgpu_@hndnf`+N`UVcXTKj?1LHDF851uYp$)gSJ&H{kAW}>K<~|nO;NL!qEiFs zPvfG=v_xVN>=@AH!1JdQ&0?+9K|j+a(T+7bcyReky!?b*XekaOXBQDLy4d2j6fyIZs|H{ID=>Sq!G2Y z@lu#ujl_(ye(TM~p+m$E%vDtJyZ?d7W+lg>lWzhD_aBEX;U!Mh(s-2g%+}K2{Nf^( z`>}V!E;OHj}Mhz(WT3Z2EbfF=gd5jBq_vc5D(g zNX))Es4V;jKPKg56?f3d z1S*qdh{3sy(8OR+>du1>4h6>MZOb6DDo&0h<+W`NA~ybXD1(P)i&##K)^r!j4LU|g zobMpHzVFNG7zJ~iO`L&6fZKAqz&-yr<1AS|8GtRxr7~_Bjj_2n?mvv85lz@O9^hWs z&shp=H0Eug1q_fp{|_zLOc7ywCE6q1{RRin4SWN8dlt|Kt!%9|v86fOmxrh1N2I_o!XAX*k{* zsKub6H%&UcaRb!kAvGeSx6U}RmWcIiY};-wwbwT`Ay3b;tBwi%2<)TRzMD-1l{)ih zgS(u_tR7Gf9f(#+Q=|Q4G?69C)YD7w zT*Z!NWScDwGURr0{L+h=5!b21H(%U(dv@L8?=_KXz z%tg+>?TJ#Q=LX_5!JG#V*F+I|Yw5YcLIN>buY%{lFvg&6)KM&)P;D=CMx!_}7ix~k ziDQUkZMf`@dg)!ku_REv>tj6Z7@8-tRdS{I3oUAlZNTgh`pv$_75D+j~zNP6gh z$dPLFm=uUy%IW6R^e)DDrr||jg60fqZm%qDtt{B4HHudqm?e^t6BWS;6Xrop#9MBtk?hIWsRMgjFFsAnrs~cH|_}LFw$^2^QrDKB0W1 z)7hix6L1Lhn4BB!B0LheH3j01;a!=QESmd(twfTJ9zj5cd)&L#S)fwvoBoa;LYNj>dPDlMPSIiOZgHv=wg~rDD{CHGw7V49INtLysTH^Jvz5^}UZ(it zLZp5rbOvrQk@CPZ^&E5A9>bH}^NIQ1K^w0=D(5@MJRjTc;~KhEO_w?}@0L!PJAp`Q z0r%|3RCGyg3EWyr7PmuaxAGY3Y4biT)NpbhGb^`}S!%jfvII?D$g9$53x&7_ zw*SCV$~q39O1FgS{K_s8G0s76*qT4@*v{%?Me{hMCgY+3#d6=6?gHGX&_P8=T^!Wl zoU2-sc2cJ8X!*hvMm5oN(FnHD1@ZB~rjD<8GK<4Op)Er(3GqpZ3MovYA@TLe5-%YQ zUDb!wHzi9=sD|5FDS|(*$RQQ27Bps5&{jrfTlilJ9XO6QoKj14N;(a?k=Emk?dlglnz1bAMDt$-5e)C6c ztcCLQT42s*6|& zYY#jmL<}yE28JgYB~m;yhSLi~V0i@y9$Qp;V#grCSd|C(lLkDE>ltL@)X+t)x&!s| zE(#HWiL3m;JZ&)HJrhG0xyldRFBsf(7JDhCnvly~O=w*tcFW=UzY9v)Uw~Oh^qee} z`KhoV8lOB?HqWnOwq<$#>_)&vUyzGfP`%kST~IvRITGY{6Glw{QqPl4WU6AgEE}Cj}T&alB6(7wz?D{ z`U?`tO!oXlC8CKzSBq9dT2)FP`oN<=F z0ZSxeYoCaKON#z)$wkf%D zB?oT|r>3y_4tMUw*gnY?&-6zU;^o4HGMl^*j1aE|!98#hFhaNl7!473RvKy*#K?wi zd|DO~R%`h@-ZI2{vFLTyB!J~e_BY=y0XB>1X&$XKH_xvvw%2hPH$M8kp6~Pne{Ydc zTIk`Wt{JMu%0&WOIU z!}J}->|y^RhWd*gOW4U~kn9NM8*Mre>`FouJ1LF)suk;K1bIlKksoTMO3YtNL>=U@ zu2*#WnvObwIM&CKytn7-eV71O*P^Js7np68rp9hJf?fj9+l}`9pKUk7eZ1%i7Pr>s z)7-rgJ!yk;f@tn}crjo>;QqVSXPSyh1TK485C76|mRcvZBh-Ec*Wnevm^n1!d$ zlmjl%-kt;dc@#k+=Hg7FhNa~B%`MrGWIyi!4-X3JqqlOh_9WJ0=CIGo5^)h)agzM- z5?VMa$n?2niIK^f3_S6t(r*Q!V0J_!Q_XVl1oRM$i-a*2Fj3xs#3TsWV$5FF1Y6IWKvxNIdfW(vpqJtTHz3Ss-rG|PS?V2Jg1ZDpRSVK zcpmDkh=|Bk&Td>UW*v%GN8vNjZk#V6XRP)qMg{D~_if;_^~+|0a9VITUR*S@yx4x! z*|-X)A9w66cS66@=QX>^w;vuoJUTHlK8k~VZ}gdCc#y78#Pfd~GrUPbYKINjb~d(87pI*#ml5GCp=-poYBa|8aO9g~HtQ8WD(DnnzlXML>23vfd?)O807N+;@FEWp5|O1Z(Hv9WB(5SI(3U!zKAOrmCJMMo!E)bOI75U3Vew! z2UM08c|OHCokH(;yK^auA$lkUFgbhUoJpC+Jvi!|j+}cL=yot=pD2m(e|m9HIq@Oq z2DzrEc#vn&97LI(;#4Za$c294qca58#LC9^6mh|-B zBp1QhvMxm($8sz{ozbIzV?pdEy`F>DrzWF7wh$ORHIRcmjc_8%7jAn~a4SmFQ#7TQ zg6kmW@KW#=lsfVjnkI;DrN^|A&K8&o?U6Ag+!tIpDyN~8T%eB`aYS)W(Xa;kAQZrI z3`%o=1#OqHRvIOUZ2WWJz9rOU9z_DpgU+QsBsXVl(2*LI!_@gNRRrm!#X-oBQ&olu z^Qjm?X(%q91tqgRP6=3yl98%Bj?)S>M*T3TrM^VsSBGj$p@wnb1g z>Ov^8=WlujuyIXZ56h}CKTgO>QMc{$_0Qfsr*2VWX-vDR4|`i`e5_5WO!?EjcI6t= zb@~;tfMfKcbFs+y*g5ZiHqHLapztMQ=j^nZNGjR_5>aP z#LOnIryd^8;IhKBLS&j9m_dWdq21%8rC}Kg5xB4}gpV3{?Idrq3laC}S7c2TV;pEs zY2c|`!^Vv<>Wl$bX5@$WLk1i2V(|~+wwpkdSC=qr- z!_LvdbHxQ8(!MSaC3AO=ycHTjTZoCSz=O|0{#quy+h z5rc&U*2hGqUHxS=FW1x&;43sxb{mlDJ9M1-l~G+w%99VEk~j&)h(YDGKB~#8@vjX` zmpliBohFK0UbU$(B0TG6KzyauoP}atcH()Pp{mX1F&76uY_QO!3@%o=;VOlf(iEyz z!5#N8N$)mDIWg))frr8rmp<^~ps-;=q4YyRc#afTAi8ZE9_Z5ANG-J|SoMJ=TQz>l z(Ai_JaDUir!ESg0OUY12K5H@th%`uewn|apMZZFg%~k;qm4yWpk3}gwUceg)f5Zn)(ucAAX^FO%YSjja_OajfP zEsfmPz^a8yjy0P+#DeF3(AlF^N6aD?w?(>m(B=h$o(|mqzQv;bx&&!G)W+%oXJ^f^DEY5)bJ_6Omr7-eh1$7)+;jSXu0?!E>wTcy9KnWC?h%*f}Vvlh>Xt;=p zaaENHF%I| zUrvf4T^^YhA&dB=8oX`eB~T;wbOHvLg<90P0TejhNdQ|4ugD! zyoQ*nxPOgBIQ-^o;|Qq>a173d*rpMy?v@Zf{mm!Cfho;Y%MD!UW;mTN-^T%kyklt4 zCcrTfaO!?B%Nz#z@Hg=Fhr-$s33~oR#Jhu}SeRRF7=s-zMM8Xg2iOi*G6~4{yFshn zz{nu03!JZagG0MI;U_Qa0X*(7Ccx+khjAL$vlE2HBLd@Ny9Ai$zl=~d$g^KOO#ofmU6`Q}tZZ4o4G7{u#=N_o^ZrA?&W<_ISWmSGn} zg!6zDXhYcLF7hxqQj>uSs{-;Ul~A+JoRDHjLVRQIy5{5iV-D5?u}|G4z+91L7Xk$7 z^{UA9tfCvh26c_Z;E{Va^6pTa5I#=l?%8DMm5fzgvZ3aCzV+mX_w!Of@^#$su5Qb5=7TahM;) zh}u}g0I)&SDk89AoCpBy$Bz(&F_H!6u<;leBEnt^C#5!o4eko9=LUsTeS1D0g(at& zkcdtHb;Zc5uwcW^%$aHvo)ubOYvDLh9uiZ;m6Hj?5um&l3t|k~;i5*WWfbK3Usjr9 z9yvl*cL1J`=VHU;O>uG-3vM_sz?*rpY8Ld_2;@DpPzc`K2wN|0Hv^N`Vnb4y^;AxB z0?_ln>MEy1b%=Jrcz@Gnh|QQf$%tY+|8J7nY@ex95wa2E`CoV0*dNCy?VTtS(DIa9 zm~QFN%`{Dn6K#Xc=z9J?#N*^78Ry)k;%G%hl!kl$KSo*9rEq#mEfSB5;rN@#62x%t zNV&?_i%Y73i~~6^j}zmdk!p-xVgfxM%WIHanMFAfZ$#C38^nGIA;_MHk+=X%kSZcv z8;yMcrf0=XNIK~GZ&1;=ohfG=NsFx(f|R#-jk_djL?ChtF;rDRcd3a9=zz-2#1)MX@pOR5o)t=s;q1skfU?tm9Sye0XZQDWFr!<4Pio21UFpsngFJ(6;cdm zqLpW>RF(V{g^p;|Fd_Idf-V&~>tVQU2%d~V7qLR=;B^rGj3Jn-xp);Pi7Ztt0%0+At0f@iM(|pi-l};4!iamR)o!69IYtUndYY zafTlvqufnQIpc60;arW<4msDJ5@4Q>gK#9pL^3a1b-q3S?*yfLbC)6t^8EiHgcvFn zc8sZOSrXo#84ZwNW|2hGjQDYNNs_yP*W zo6i{&uRuqi-@|WCatn|j=;s9}YZ~;e3X`~3NsRzvF!c5zDQ(MTLnR!;bPYg{9}?+H z7cGqnW70!N;_HSai@|V~Op!K6^=YPKf>lJ%JsBh2zL4~ShPpWcX;}_oI)!^s?s8Tlq!`hCJ>Y^TBG9^bc3hO;8 z4!Lg=F9+7Mtm%>}mHie5?;?p*7xx%3i~D<(N@kHYc$CZG1e6no2ct;pDE4zIU1~W2WBpG! z5y(xt6 zNEpI+I+o_1#S1Ob!FmLOYfpttJ=q{di);V5+B5_=BO3uMO$3Y!O&x~FkW=;&*umy! z95U__2*n}9le+{I5o2+WXh6O2ik1O|-A%Bo9>atIs~Hwi49$FyVfD3?Lu z>Q$F zbuyU9L%j@-!C=NHWE)9T%Y|a@sFOUVmZ8^b{Y58(i9A%x@E8o{j6$~2M73NfW{o<@ zV`>?Ct=88%8BFA%T8779F#RKJvPp>bfFC@f&Tn^%P%I3mOh{roWJnbS!6oY;v@Mde zy+&H3Zy3^ei*(r8x&qfMBnw*~Nh9KR2L)K0>ZMAUE~(}##c-4uhT)S5iL^$#eThyq zIvbM=0zR61 z5IAH?wwn7*+7BsFcSXZJ>n1=?&Z&fV3eae*SoJn@oF%Kz2Id1EmH^S&oGeV$XOTf% zh|1xVE^gUAfxZ$P-H@2MQ4%pPeyS_gvxxX%5iwJ0V0j7aYj))k@y3Dh$y{P{4Qv8S z421tT1E=XJeB_g<)RqqL7 zzJ@{E`D6)-Q)<_kq0nL6?-Y_0=pAYa$Tql9KkFb%^_T=WR06@(PKFHo=AxQd0Pb{h zh+^7+%IfoRm(03@ zHu#HegcvgTLyVZx$uR+U3cpD5sJoS)~Jwx$mw55-s9L zu=e=D?jky@;qprf`Jru?6D<*uVD0e3aWS-0*LEa2Jz(3BAKgYs7i&1tSbO~Vc487N z;>r-4ymwmxU91w3V(ilEf7Tq0#vOaBYrG}$^E(cvuoF=oj8RY=x_Pn>m$P#1iRV$? zg@AnHl*;$xyDotYwv;k}5jx)+{Fy#H1XeK@v|!+l%a`$f%Nn2C!!19!Gaz>T&np7H z`zKd&H2Fx&*7D{(yt%>zc-4=g0JkIR9`o91NO}~9nu>hU5clV;tnxvFJVtp{x#rBs z=4EWXJ=Y%cpSQd<-^6>@Jv(pp`?2wFif0Y@*7a@8Yzcen3nC3mUpE1KZ<%i_uufwJdJ3?M7RGBvJpUE;Zc#pP-rMv19XON& zQ-MS9gEm0v2dya$en@Txm5{uU&SRbR>QrGGWe5zo1_lRmH2`7kuC`$WalF%FNse9B zhPcl7a90f9ACJIz!#2-n;r)^I#kO3agIxE&$Cnq)Eh%!DS76IoF-z&C{?fqI?FL@L zi{_VpR?L5Q4{q?mMHjf_iq{Se;)udzzUr0?gAWuzpebPKT|@pA%eXjaseM+8?Ulp+ z<&uPAVGify@a`tc@|78XhX701seu^>g#qI7;hvX|;Kn1F&oXe{Cgbl5x9afXQyj}J zs{Je28IwMszq6<0?$$RN98Vai%|d3cOS1{@!f#mmART_*6=Z-2c;leg^MpTYo{Sam zY?x}Qn@}Fd%(I2)DgLdvna+9ta9DxC7Q4;*TCr2u2`T zU&;_$naYfT%beZEgt#2^;+=rz;C^%~DsPs>c`H#K>gl6(A_NDfELfeX6RKuij z_!&bT9)A!m%^`g=c^nL5|Cl-R=^SCAjE0sW`%`GF3|jA(Xdw15U{{Y?TT+S{GLLmj zR5j=JU^-azjDectdt<{en>qI$Zm9<~Y}VG)_8^C`K}e$8p`) zx0KoB$jiIf5CD%V4}beN`+&gMSG?|vxSpcEa+;3Ytu>tra<8qcBz!_G<>q}2J_*v zrx?e@<)7E{q(8>npSD(T`+Bp41E##w9d{oakS)S;jie$o84o&Kjig}ayq(u`=eVCj z%`7!eIn9XQYh(`(Wl#clxJ7S#Y-|LnzTC(d9vL1wjH1#P*2N=7V67``#8SSVXLTFS zAkVLi)t{XVI~C{owhBlNUS$ibs{b#rr%Y9N*D2Z49A&y%0d3*YnqQ;9JVhlXM}zl- zWf=`dZ|ZJs122V($s-o`QbQ&&UJ4IYDP#y5Gb#5{xK=Kj3ts9)+Hi8~QzSd&c%~{~ zY9+<&HV^QiGR|b0m4y&2xntTGy_qC=?>lmF+VCe+n6j;+PNd>&?c2Sqf$1Z` z_)dQUHxKbZurgT2vfvh7F<~Zh!iyE=RtI6ub!CP|p`^aGNLcLot$;i@jm-k1F!s!r zJjE_Yt`#zVOp9mH^?f***a0l|mAV_H&ic@mQbYHl8TkA5yp`0>38Mvf(?$v`_n{=6sLW)Bk_*I($EE;+2NK z*Pqn-8L&#Wa}Wy#wR@N0E9#f5P}wmIWsa59%@;g?gL;Fe4>w-o@HTkt_GWGB(2_M^ z_16%c4;@@=9aN#mRsG~;`jEZ z`Z}FzjE}FfT_c7V7(iSto5sQB`PZ0Fq}_ZXfvFpuJ?b~wZ#dd^YkP2jZgT1-3qUt+ zzahOoScrdoPaC?5qdw+OzX|~iXg+phdL9Bs%<`zLi5Qu zPg#WLpSIr^5@}B6N<#)j4N7baTp^j(mqo%x1$UjNQwBg>bnRF#MKm^Of^qV_u{3}o&&Uxu%M=!gLoYVgQT z1M(sRsc5cy3_z56K-i`UlieZx=BppWB!1^YuzUhOOE}-a3WScvBVFA!dwDpZ4z0Cxo+!o(2Ki-hL7qFY3Z_lenzEOtx>{Ra=-e-O;~^ou}B z?(YN~;%i(E8Dof$DS#z|Cg((x&bT&KbyQkLG`zezzlh5f4{oeN#1=&$rdqxND*%9D zzSdtr_W<;I3qsRcJs$Mm58xXFm_L;lOZ4vp2+bo{3pis!q62`ulaPYAHK)JW9aT5(Eb}ta3ol;Be3nfdlfL3HtHY%9-UB zAVUHf3HmXWGm-&doJx=*(0qm^=vNR-M^2IkB$#Buq#`B3qX=Qr4+Z_VFE2sflmnl} zj{pAK4-Su>1>$5A7@V;!WpLFOyv3KQVD^*}oPleB2n`8_z!Zc;A;D;x!5q+WA$mU|1@>>>R497`d>~Qe0At;Uae(=aVf1}g=gd{3kDdw>KY4_n&JoF1A+s@gkX(_dAM{+v_Q= zAonHm3^QdvSWI6W2>S2r4=(bz=l>T4u1U-_Uyq01dF2=8XCA zF-k6s)USyH{23BA*H+hBD-r=7Ue!-<7jY@`(lXux zPxJb;fx$o#EexLL{oJ2be7Ny_qXkCXFN}H{a;Dc5M#1-SxrSU{6CI|CP3u4Wvq~T4 zu&Y^|uF2v36m(CQNeXaD{5l_hXesSN`H=L67>QOSLi5HL&E`40EV~G8i+G&G=n7eH ziqS2tw~(d?$#=y_xW;sz3FktWt{;%}<`~&y?bb3Qj8OIZyO|Sa-)MhvYd#n|IE)5n z58+kZ^2nn;27Yi1m}?ylc5}hl5bE{|3C)!&r>ne^CFsv#Ztqlmckpkr6Qx>nF|0P2sBZwK8 zTZrLNGprKA$K^Ao`w7DNEzH1GPoq)FpCW>DoIu`AB=-Lns^yZ4BjX*!%@oU%xL(!8 zWq`XA#iqHnhFjR7ASOsJrrXG#IKu%zL3}sirwjSw6r0IGiLzSdwJV$&(Lvl^RY%te z2jifIuz7-Oa7YLLcX#I=Wmk3I_j6|^E>sjNwhRIUT+0|n(#&WijikW{q0w^`25GDr zfo$Vk&Et+{U|ybkM+{gd)P+P|Mqb2Gmz8Dg;8?chRE}8=wy~|+aw9ix%5rIgW7@D1 z#br6JOB~wbgf_J9=lk2gea^X8BLQvFKYC&G-M`2F?dRFAv-jD2gRscjfelCd`O4ll zPv0KNIi%FDRpWjmcJ1WKAk8EsQG2$nD|~|47<`AVoBM&b?Xk{?DBKY|g&_?Q*k^QD z-B1kPWi;o)7+?{DcN-Z$=UZfX_C3Z)O|s&8XYgXnds?j@5Y3z`G?CTi7j8(XFM`l~NeyG`kp}iX#nVlS}(uOO5=8pv+9UznodakLp7&-1nCdZUb7xc>G zfQQexhry{SE?`yiFX+i18$5nCrZG0^7xWhvqw)5+7{RH@*nFQiNA)=4{yJSfO6%g|jY0TDH<%cDYul*IzPY zRQR;+xhYs9-n&@&=bJ>?RQ3El^UNlXde5+4)$^Clb9E|>uGiD*R4xTHr7cApALv62 zR*f~1u+;YOiv1qzznh86w_;qvb2oEud`6W~)?zD1RFi9Z1$=%x`aCc+G&ReV#UJhi zL(zvCBaVcIr|b7keaq`}ZlUp9_rSlP2)bjHxS5%y_e1zo7)j@JQ>~RL8o? z8WlKb{CTQj;n!Lb3!N~Ju#l85#abncrIvUuyQy$7MW#!Wv^!?O%BI2_6(1c~=RUoy zbSz8dUQQSOCJAWrcW%}Tw&GIm9OF{Xu}MwXZE&JyBnqwFL9ke!xKuXs8F~0HVRv83 zoYL6AMhNt6DL2$QByW|C+c-3oiY5lCqX=vSu{8^HxI8$kNxUsu`Q$0Yb$Vdv?tue} z=_=LGfeMXVRdYKZxzQ&yHD11f%ov!Ri@Blougg&HDedQ@$ zN758q?#i1kT!nCFNn==StGe|>f>*Rk9b*V(a~P>W@c#-8bvBr;O~sh`tXWMYCfO>K ziw9TSYNCeJX6P=*>&+evC6sw=;gxZXXO_rny_yEz?=tU%73YDv#;Ju>16VEPx$4Zo zM8)D^GeagUh?f-)9SW&KDO_u+PA_<(m0(Ag`?IcdJWE{K!gv$zsmeDqld+j0auYFa znLk^@i0pcQENOTfh3CmESdy+Bt;vzP?6mtf@ii4~yB}XOVZ9_L@FI{OQp+tyc%06H z)9fyWCwK6Ao&et$?M7cA#LQn!(bWW5F|QgTXc;9`Tv#?}aE`TkK8Vm@n264rui+_8 z*zhxw7KPRpommt&6mn^Lhy_O!HKwvBG>q=m1Y>Q^t)(SIr=^ig4|Cjs;gnm1{hI8( z-~93*PB56OAJx=%W;OkXYM>?X17?D3Q|cJ;Y1Io>X{<8IP$2f}QZC-2(ks5BID)GC z{)m>hdP>})roOp(v*zpGdNen0X1YFI+yFx^CfnTVtJy_<)gUIcr^F6PP0Z0jT{UHS zFtB1pyoz=i3joT+-w1)m>y9nZbE2Uo*~rxJfw)T%1Ktvz>>!$_mnOH;@pD$ZOXFSkMLd>g%9BH7mIr6b z#i_vx!@X*GDd|^`-dsRg_4#KOkJ-r(9RK=wB67}+0NE%tlJy1iOP#3oT$&lU2j-Zn ztm*7jJw@6fH+e~oY1=(j{^+fdli#-1G8QJ7wo zwQOzIl3d;! zg_CtsM(;zs(b06;)|ysE!!Z!T%ZHH}wJ@?E6^0AVrefey3v*=_#=uSm!UrO^ak*K} z&D#~Hn9ld}P(-1Vyz_852Zgssq1>vX%FUTEI_xSD;qL2ZgEU8IJTiu2NCo&@@ML## z&+EyuaXRFqr%JQJ6Yh@%xPg|zmMypSD!Ar>G{ZI1Y935UYbT=E?BFF;u*m4Ch#D%A zyn-T2s3$|HG%OZs*t_gE`cb8|OF9ivg_DcUiZn26QBrwrPghhoGSe5yb*n5Sp6hAj z%~qybh@t+iSW%;Ko`70YKU6pVyJwVMq}Z%n{Ypq*Wp?m&r?2&OrZ3aKQ2I8|#E`Jo z*4L6SnonDkvgfEKVGI~=DRAVyf2*dXwjugD&0&kB&HT#}R&{2!tog$ABLm}=vZfMi z*v^ftBuUA*YzHr=_ekhYlEs_smi4V#C)br*jn`c0f|B*@EVJ=l&8-t3XLl$5b)cDk zq&UO{l|_B#i0?tOX`@cS%C0`x47=0c8nMreV*9jMtJXQswp`jW%W?5Jg~Xzfx{-8G zmI*&2A>jsL7KpItVtY5#jvweM-+AfM|cAp!Abav$J+Btlu@35-Ogy0gC%Y<0_frcC5a!mStp` zFf{P9S?_Qvb4Qy;SS zs*TTox6mzwp#Q1~{cuA(vNCUL`*0>cC#jD#=&FOR{@u56Ki9mzf4xTI90MOi?ECHO zGU}5Jccfd&xC}hH`6yl#U@R4Av(l#n=h~v&ss97mU^2G);JH6wgtrbb- z3LTj~P76(4iu9L7Q*~-Py00}TYcnffH#%qL8^%cOsDs?A1sk1&wcA!qwu?>{Mj>Ffv)uuz;(7+0UVym0A9^rIc)kht2ZY z8d%(*Ic0puzKlzFrK!z#T-e*($p}BJ7w0yIm{*%TZnOaInVK1n0nBS?<%JFDt}{in zJTYCpSEF$L7#5#%v=0>|T#?Mh>Nqq~m1Y=Z#>DT^*2}&k%jByy1T)Q6;>qmjJ?-zs z53?0}yX~3f`V70#uhCxR+8-#EHMn}epDN^vTddRummVH$<)UUOFu-L5SYyrvsY%V5 z)N#KPov{O~eGtUobHeX$-^=!j*OB(%;qN;6(Q3?rA>X^cJ<5u0RqE#%Lxr15tY`9#hwv3lYsx9^=|J5Egsq1MI^0=Lw`!Xd3 z;k*iA!vGo~ym_l(_Q)!ntZb~bWI4yub?Rm+}+ zc=AD}&pwS>K3wOY6L#Q}lOIrXW##uEGb<|m)Xe`E<)>%n@3#ETvH1V6{LTsc-11|e zvy~q^2d5^+hVql?2F`u?ostJqG5hB;E=69dCXMgtDqKdd)xFnlu)Q27g9g1ET#S>O zknG6(6=L&Rk#~Vt;$+8@ZH2f>Y_=@317ZozuFdST2rQik*tugHTU6NxaShJxd~%w7 z8`t8zRhHOWB2_LoW}Sj}Ww`sc?YOml~`?OA095pM_t7oHM$GsKo|ZIvPTWg>7pkE6J_dhcMnA@Ny(oAKV3 zZaa+H0=1X@imQoGD{emPy_)#6$%F3wF&4XNK-+S%n)tOt^!N4m+7{eZ5V~ueGo(pj zwIpn+DXu23))=vSZ&7CnJ0NcFw^Zqz+*(LmPFzil)4wW;~kslZIqmk)6FB-Lf0)4>n_D}z3W|Gm&Dz> z$+dIkT8;0vm~a7^K7`Nh**o_1+qj)ZX>4$)G&DQI@_ALw%uID+j5qA~VFQ%ZG>o2C zZD7vSdO4F3?dfdSo=BTV3s+-GK2u!4{PX~;XJN=_*G)c!zf*~rzjQc}BQ za|_>JN}~e@%Ss=kLB^4k&WemTHaRjCm<-}{3lhU|+ly(Z zA~}BvueXZ>&)R~k49@GUOoz!VmhpP0wYY{<@Rf?vG}|%>(zZfW+Ddmb)N2cDwr1m) zonH={7iP${xnZ`FH$nV|M#qO`B?!3*P=>UQeI7lNC53y;%lXwRGQpcQ)W{*$7IP7w zsak-RcS+%1R7mOh6i`(bqrrWGsIu4gRaDX7WHqX+QrGB`+K~ZPs1>?oTs(+tkOwDk z5v}Q|kh2mcg%6-Kaz2$26do#2es&e*E;SL+sUr$d{nqqFhwlEvO%11Qi4L8}#?9N5 z9q$y=9J=Tax4oti(;PaejoShX2HdGnP9U&L{G@FTy_3VOJ$2#<_5Ka#t-AlrA{$)n z4J*(>b0IP(WwsPECllpNuqzXA80b?`(6x0>6yUVg*kG!EPj3|9)LT6n?%i{H3?n%8 z62t|(=Q1A%aN1fbKG-wLB>*M}PIh0LkIh|M`}%J+L2&YEPEHMTAH%NxtvhcoW=<_^ zI<@=u?NNYJYyJ{!?@4_GC!gPpg6IQ*`S^Mi>}7kpd&a37>zvYl<;zvxTE5r&@ zICX2C3;OnMjy`az*;3a?)6uI&KIi6(l!#ZS1#z-)5R4~nUf9BQ6Mia zz^T&+qIA``3xbpDO$zGqOPlv_M7o$c`QTv?z+(He3CyYM(dcG5oy!GgTZ@@f*P)5h zbKrvD)D>tFY~6bsx1O7i;M7J=31mD<+^yZ45~=%*B6n-aOd|Ead>+6prW99u6x4}R zH;Rs2;t^Qf)*W~__)2tOa-cIXaqvaxz*H`oZ_B*@8JHX%4NM%mkjoS_xQdRX;e!p? zAS`qb99M!DyOHui^_SL>d>A(E!#2AZF!T{R3;uA*?&g|`z^9wDy?9{>W<_!Ja%WiA zK?{=lsq1cPthX|R4gsc?mlf-}A?;wKWh@^oO-@zEM(!=eeV%GM#h#sPb6426-j-@; z7h{dr^vH|#Me}=3b#ymWh#dcNBA13tkq?BH-~w%XnKP#r-vSl3Qo64|&=%APOFM0F zh}9s6W?k$<4OTP9`z3z2G^Pdio6ppp|{yQ#2Y^YWZF zlk;OFu`){T=wc+^E{VO?(^%8Ctnb{#1uw>z4+fBH;P3W*(eQPagrCNl+B(2Wp7zJ# z!v#pz28r#GZlCkFhVa+H-?f{AgLE0~a~;7D{CB{oQKi=Jr8#JyOTX~JKvX`od#{-J zO$r+!*pS-S%~Szr8Ve0QNkqRcr!WS-EpCx zpKXKBoXj>DK4Xa9jKO|5gs+K3pgULH$Z7A!ziHTBxQrXB`#7|o3$XBZK6XOCsloE~ zySDebyQ%RLjXT))VV`usl-F&GVpHK71_PySYM->^+g-RupH8q(s_=~w`(jg(9ffaW z_s>YVIy9>7hgfI5raHhb%9#=yfEj1CXjfLtL|Mo4So(RtFX)Ji0=pk@6qhdxTW(u7 zMnzU#S)iTKIuF3&M5@T%JT@%Ji>tI2P$ zVAtnS(K4wR#7W_O=67U_vqI;wkTY)i)4Fkz&4?{^c4ka%eBgDMp)?QHo2iEAOwE+a z1C;Z0i&DR=I5IUu;i!a+4pF$NI9=p$RA7m?xi}pp6vaI?hDw!zkuugMFJ!N!IGLH4 z$M|H80%6=&8-^D^%V>+|eH!bam&@bPkZx+_@@Xc9LI0-W^~B%YAzjoeCCYreahJDc zMNn&lSlvHQta9o9Ka5;R`|F9y`I6(=m@_pwf2y<-G~^7a`X`0?l0^;Tl$%QSJei)W zkpI_tp4HcL^8DB8VkcEas;1_$6-oTGW_j^a=3 z>lkhJi`Q?^Ej9;^1$(F%2n!AEHF@oDP?WK9u-1XR)8%{ia2fHI%`RD|UFTPJH#H^c zkNrI3Q&ZEWp}`~>n`D;G`U9J(?eUS4zHZ2=Ht@iZXcixnp#gSPj!PE&jto~4?T8(g zoIRYpps-G3f?aeRJ1O2^!W(GztD{pW4Rd<0T27LY0rqSS7pqfhsqR+zV^xJQGdr2s zEulv?_WNf2az2OnjtSsDjU16@8jN zR0U6&_(;1@^#D~pGWHXFCx564MooOAS*U7}w<@~GAF6^D{wxpVP&KK^12LZB4`so# z{3#EFsy2DMqA#KVP!%lZ54%sBLsba7Psixm^ZOV~lm#dG!){TiDuvx*)D?XZ)kSuJ zMf^!ss2Y}66+O)#s)9o%K2j8_!sS&(pWzQx!P6!_vQVh{hbr+8KhaD0Lsigh;v+?& zs$<@&=)?S>DmZH5BSqme=FXC}2IJHuem}S8l2}!%995t6C0*zlqzyM3A@jeSz7&x#Ln|2 zd~~FmR7R&}s@i#hjSz%h+}B4jmFZMHy%cNiyfBM>RT_=jq~b}z4GktFf0%A7p&Ojc z!a<;81Hnp+yY|9%VjD?MNgMZT#A!%e>r~uQ>}XrlwyxNEAZI7`Zgh|(^_;9xr}0ci zIJi>!^uBB?6}XUE1lZ;MP_zZKwn?NP2s8o_r4ds<#mIoJxQW||w<+X?0`AUf` zCsqqD`VSW0Hg>ps1sf6>YoD3M6nW|K(>J`5IWRfPmsW8!H70G9dnY*k1oGVtfl zLP)YLm-(NWYU98VIU1}*cAlqWnxzp=5T+)P=0l&J<%yUmTl_I?`U5iqlLy2KB&kl? zhNdPam{TTgWKmnXyjh9u-fO^X(V@dn=xOb@iGR=Ln$FnZUj?6jGyNUEuaF%3he;Cs ztKp?_PTtO+?9s{FuXu$!9HPAy(9+NAMVVBiyB#-in-0A~lE_{zde-2JzL`IT8-JY& zH+sSuJBAx^=hLy_p+fQiJf%Z<5Yw?4ca1$|K<*c1z3{Ffeo@qk-VdS>W^@kL>Amsl z(8oo8QSX;wKNTh#%RV#&4$1-jB%mF=eR#qCFn98hh7$xM2CN^lI!M(|bSe zd^&cwG3Zzwtz_vqf}XfBYkLO@$-+!6Ew|rvy;#2c2Mb9vy!ead@lRpo)7wJ)ROX7` zLjGd>9>=Xx7QKXzwJ9yuCZIw;!JDy@|hQ?+osIdQW5T*<3oJz0>IB?VZA& zA|iW?!BTtw7I)s>vEf4Um6%D$qUp1Bdb1;lgps#*27Ah1r9+QOwAY9S*=vWV-)FG*(U|GbvZudG`9~P_*56%QzESUT z96$T{&!h8-LQ%?-%*Y1(QsncS95+i%wxKTa(l8DZevXd3NO~0D9=5Ruo`PhK(wCd?AK^dWS+j% z>Z~}=^VdN5l#TrqQi1TU10~aZTk=)7@PiG-=K)`9sigo-O(}pyS+H^e3U?Tw3&JCFj8!1x0@W zjB{quPe5y$vd`r}`fDV&zUh?OhC-Tqf!SzJY^qNFGh5018WTNP*{{)_j67Z22{a}e zon*hpgo>E^HKx64U^d!BB~xfju1@|{M%pv*?{c*A^v~+(|6E7^bse3ruzIEzgZpoqd#0nAFHE3T}S_J9sSih`a5;>_v+|Bt)qWh zNB?adeMzoyQT|+AM=!6VSJly7b@Z+}`n`4ZXdOLQM?X|Yf3%MNSRMV_b@b=!=&#n% z->jp5zmEQX9euWrezA`JA9eJ_xi(i%+ZE7pE$dA@p*Q5@%J0?CaXm}&WWG6NnC=V> z`c#}bMc`=eof0HmVSfg%a#Q|PNSl`0jhBAaC@4o&zKE2@LgsTHD2t}DypfF||A1JOrXRov zcKxd|2`_Pd?ZskTo9-;H{L3mamOY+XA@!^R#5!PaA)rMiy_oUz5(1S`fW+lEgI|r7c2{F%F^2}J~$`- zau)MI@gH{nG4Ywuop8R!;L<-OeoGjiDEuFb4=&=dUa&HZSrl#uw8HHazn$=f3}mK- zs}p-Cu%I?f3Mw46tqSLm_@wU<=O1 z^dA+HzQ=`3Ous992lhbOe-V`Zmq5kqB5W&PT0qI$LCHJBC;T4aO}x(%ZXn-;OpG5B zZcLIVUH&vE|IdK(|E%~73||nRG`uK2__Fw$7|$`Rk^Ul3`inv7w+jicTi8WCae5BC z_)_v2d;|EP_?vlu3ac+Y_f?-lVWPmMp7Umc+GYZO$zj*AB8L=%rgqQM71 zD^Kx}9~B=wDL(b}l=DwJ|0(gQug^LEtn*(GjlCB|gD-)y+r-+F>|O-QZV{B-cIS6E zf0Ovw?R9>?^M}RXO1V3K&iRMM=lRh1TIqd4eDJLJ)DKP67i=T{h1B;=!tIQGLB;b< zQ1RR^KJlCrQh$!R{Fuuh6@LfyOGtS=FC^Sogw(&q7lYJ4jq4SUUQqFv6QAeksIZ&- z1QqV%l7ml(zYM$1f6Dn!i%)%hUdVIwije2%5~e%K$AzHsafxW`6h(vAfwI>jKJrfS z!Cvusj`ll$*!k1qliv?G|3T+JA{u)~MT1(WlHC*HWACK+;2H6;`;7CSb^i0>V^{MS z<;NmW`LPvLxeN={E(yuEV?y%%6sT}dg9`VI_~gU0LY~`KB&VKhny31{1hn*vM*lic z@!TM!oce`4$J0W>ISfkwVNm*yh_7@B(LXIj|2ZN0F9~`67yToU=f6dW-d0d{x_+Y2_%Sos6 zdz?QkKIL9@{+#n46n_Qv#`(vbe^UId#LM}oo&U7>EyN2{d|weCY+eYT`q1k*=lGcL zm#_mWKTm^-{~7VysV73}$xFgpNzX3^y&@>R>pEC_6eb@Lh8pe&To2i;1`AP4+(cuzl6P%GpP8U02Pmu;*;NJgp}uVLh9YiLh9S% zMc@|d8L0B@235ZM#D8a)?<>EKiVr>^{vP5j?86Rd`RVc{%=Z`c(=G^+Ydt{nVNm`b z1QpI<(V*4`B!AN7&wvZ|lE2{c+o>;1L?mAb%6~hkdebQy><0C`>=&Q(4vPqL+|gqQR#?Jr8Ha$L{mugFhCZ@_ohmT8ca3Apn z<*&o#oi6VcQcp*P=p6#3_W&q64~mbSM}_D;Aw=)Hp!A*srT4V>=>1rTo)&ndw+NKp zVo-WZ#7D0~h+dCyAN>ZX{5=FJe;)(o@3?621So&{HBeqf$4!p=9UpLf%<;72S;vI& zpZRy(-m5qVF%yE}v#qmBNy7xPNPA{-X_9>2j1c`_ z6Qchm$FB*||L2b17NY+hA^LwJME`GG{krEg^b;B}8ul&z$f|$E8B-U+=hFh`%-={`!RI z54wEB@owiIcKmh6Pq_S3j-L@?@AE?JeM^WvjrSF<#{0sbIbY*_$=~d_)N#Ax9wGX- zJHA_p{a+She^!Y9f9&#y96uyP?}!k+<3jW_{+B(C|AkKq(K{tX?~jD&{Rfx-spAiY z=>15D-U~wXUUvB_j+#eEuStmB5+QocLc(itY!{-}Aw=(1A$oTRsY~NdYo5`-SnQ)t zf70nEo&JuHe(n#QzR&ZQ<|t`+8}SelE@Gpt{e`AmFdDBW2QH|;(B%vhOuycL(dE~< zyxD1Mw+YYukzVr$tuD#Z@A|z?GxRX~<4#+9js9V$A9ne1r%yP2+UYY+Kj-vWr>%V^ z{8yaTx`@JGEX2OnMMP^|M0Bsy{Z5ZNt#uN~4?E4PJ)^Z=BL63xw*C+LjMEfL(m)-F JX!(hq{|%S&^kV=3 diff --git a/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-release-shared/uloop.dep b/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-release-shared/uloop.dep deleted file mode 100644 index 1809ca2e..00000000 --- a/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-release-shared/uloop.dep +++ /dev/null @@ -1,8 +0,0 @@ -uloop.o: ../../../uloop.c \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/luaconf.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lnum_config.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lualib.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lua.h \ - /home/jbnadal/sources/Audio_trunk/AwoxAudio/Libs/External/lua/src/lauxlib.h \ - ../../../../uloop.h ../../../../list.h ../../../../list.h diff --git a/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-release-shared/uloop.o b/3P/libubox/lua/builders/linux-gcc/_rt3052d_StriimSOUND-release-shared/uloop.o deleted file mode 100644 index 5924e5d8f2cfc2d162d198ff312a45a4ccce3d12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13468 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 W4-xXMMC@}+H5%tc6b0>hBL54yt|E{C diff --git a/3P/libubox/lua/uloop.c b/3P/libubox/lua/uloop.c index 2a0a516b..782b5a51 100644 --- a/3P/libubox/lua/uloop.c +++ b/3P/libubox/lua/uloop.c @@ -43,6 +43,26 @@ struct lua_uloop_process { static lua_State *state; +static void * +ul_create_userdata(lua_State *L, size_t size, const luaL_Reg *reg, lua_CFunction gc) +{ + void *ret = lua_newuserdata(L, size); + + memset(ret, 0, size); + lua_createtable(L, 0, 2); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, gc); + lua_setfield(L, -2, "__gc"); + lua_pushvalue(L, -1); + lua_setmetatable(L, -3); + lua_pushvalue(L, -2); + luaI_openlib(L, NULL, reg, 1); + lua_pushvalue(L, -2); + + return ret; +} + static void ul_timer_cb(struct uloop_timeout *t) { struct lua_uloop_timeout *tout = container_of(t, struct lua_uloop_timeout, t); @@ -77,9 +97,9 @@ static int ul_timer_set(lua_State *L) static int ul_timer_free(lua_State *L) { struct lua_uloop_timeout *tout = lua_touserdata(L, 1); - + uloop_timeout_cancel(&tout->t); - + /* obj.__index.__gc = nil , make sure executing only once*/ lua_getfield(L, -1, "__index"); lua_pushstring(L, "__gc"); @@ -120,22 +140,10 @@ static int ul_timer(lua_State *L) lua_pushvalue(L, -2); ref = luaL_ref(L, -2); - tout = lua_newuserdata(L, sizeof(*tout)); - lua_createtable(L, 0, 2); - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, ul_timer_free); - lua_setfield(L, -2, "__gc"); - lua_pushvalue(L, -1); - lua_setmetatable(L, -3); - lua_pushvalue(L, -2); - luaI_openlib(L, NULL, timer_m, 1); - lua_pushvalue(L, -2); - - memset(tout, 0, sizeof(*tout)); - + tout = ul_create_userdata(L, sizeof(*tout), timer_m, ul_timer_free); tout->r = ref; tout->t.cb = ul_timer_cb; + if (set) uloop_timeout_set(&tout->t, set); @@ -181,7 +189,7 @@ static int get_sock_fd(lua_State* L, int idx) { static int ul_ufd_delete(lua_State *L) { struct lua_uloop_fd *ufd = lua_touserdata(L, 1); - + uloop_fd_delete(&ufd->fd); /* obj.__index.__gc = nil , make sure executing only once*/ @@ -238,21 +246,7 @@ static int ul_ufd_add(lua_State *L) fd_ref = luaL_ref(L, -2); lua_pop(L, 1); - ufd = lua_newuserdata(L, sizeof(*ufd)); - - lua_createtable(L, 0, 2); - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, ul_ufd_delete); - lua_setfield(L, -2, "__gc"); - lua_pushvalue(L, -1); - lua_setmetatable(L, -3); - lua_pushvalue(L, -2); - luaI_openlib(L, NULL, ufd_m, 1); - lua_pushvalue(L, -2); - - memset(ufd, 0, sizeof(*ufd)); - + ufd = ul_create_userdata(L, sizeof(*ufd), ufd_m, ul_ufd_delete); ufd->r = ref; ufd->fd.fd = fd; ufd->fd_r = fd_ref; @@ -263,6 +257,32 @@ static int ul_ufd_add(lua_State *L) return 1; } +static int ul_process_free(lua_State *L) +{ + struct lua_uloop_process *proc = lua_touserdata(L, 1); + + /* obj.__index.__gc = nil , make sure executing only once*/ + lua_getfield(L, -1, "__index"); + lua_pushstring(L, "__gc"); + lua_pushnil(L); + lua_settable(L, -3); + + if (proc->r != LUA_NOREF) { + uloop_process_delete(&proc->p); + + lua_getglobal(state, "__uloop_cb"); + luaL_unref(state, -1, proc->r); + lua_remove(state, -1); + } + + return 1; +} + +static const luaL_Reg process_m[] = { + { "delete", ul_process_free }, + { NULL, NULL } +}; + static void ul_process_cb(struct uloop_process *p, int ret) { struct lua_uloop_process *proc = container_of(p, struct lua_uloop_process, p); @@ -271,6 +291,7 @@ static void ul_process_cb(struct uloop_process *p, int ret) lua_rawgeti(state, -1, proc->r); luaL_unref(state, -2, proc->r); + proc->r = LUA_NOREF; lua_remove(state, -2); lua_pushinteger(state, ret >> 8); lua_call(state, 1, 0); @@ -330,9 +351,7 @@ static int ul_process(lua_State *L) lua_pushvalue(L, -2); ref = luaL_ref(L, -2); - proc = lua_newuserdata(L, sizeof(*proc)); - memset(proc, 0, sizeof(*proc)); - + proc = ul_create_userdata(L, sizeof(*proc), process_m, ul_process_free); proc->r = ref; proc->p.pid = pid; proc->p.cb = ul_process_cb; diff --git a/3P/libubox/md5.c b/3P/libubox/md5.c index c9064dce..781dbd16 100644 --- a/3P/libubox/md5.c +++ b/3P/libubox/md5.c @@ -1,284 +1,336 @@ /* - * md5.c - Compute MD5 checksum of strings according to the - * definition of MD5 in RFC 1321 from April 1992. + * Copyright (C) 2014 Felix Fietkau * - * Written by Ulrich Drepper , 1995. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * Copyright (C) 1995-1999 Free Software Foundation, Inc. - * Copyright (C) 2001 Manuel Novoa III - * Copyright (C) 2003 Glenn L. McGrath - * Copyright (C) 2003 Erik Andersen + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. */ -#include "blob.h" /* TODO: better include for bswap_32 compat */ - -#include -#include - -#include -#include +#include +#include +#include "utils.h" #include "md5.h" +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them + * in a properly aligned word in host byte order. + */ #if __BYTE_ORDER == __LITTLE_ENDIAN -#define SWAP_LE32(x) (x) +#define SET(n) \ + (*(uint32_t *)&ptr[(n) * 4]) +#define GET(n) \ + SET(n) #else -#define SWAP_LE32(x) bswap_32(x) +#define SET(n) \ + (block[(n)] = \ + (uint32_t)ptr[(n) * 4] | \ + ((uint32_t)ptr[(n) * 4 + 1] << 8) | \ + ((uint32_t)ptr[(n) * 4 + 2] << 16) | \ + ((uint32_t)ptr[(n) * 4 + 3] << 24)) +#define GET(n) \ + (block[(n)]) #endif -/* Initialize structure containing state of computation. - * (RFC 1321, 3.3: Step 3) +/* + * This processes one or more 64-byte data blocks, but does NOT update + * the bit counters. There are no alignment requirements. */ +static const void *body(md5_ctx_t *ctx, const void *data, unsigned long size) +{ + const unsigned char *ptr; + uint32_t a, b, c, d; + uint32_t saved_a, saved_b, saved_c, saved_d; +#if __BYTE_ORDER != __LITTLE_ENDIAN + uint32_t block[16]; +#endif + + ptr = (const unsigned char *)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + +/* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + +/* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + +/* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + +/* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + void md5_begin(md5_ctx_t *ctx) { - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; - ctx->total = 0; - ctx->buflen = 0; + ctx->lo = 0; + ctx->hi = 0; } -/* These are the four functions used in the four steps of the MD5 algorithm - * and defined in the RFC 1321. The first function is a little bit optimized - * (as found in Colin Plumbs public domain implementation). - * #define FF(b, c, d) ((b & c) | (~b & d)) - */ -# define FF(b, c, d) (d ^ (b & (c ^ d))) -# define FG(b, c, d) FF (d, b, c) -# define FH(b, c, d) (b ^ c ^ d) -# define FI(b, c, d) (c ^ (b | ~d)) - -/* Hash a single block, 64 bytes long and 4-byte aligned. */ -static void md5_hash_block(const void *buffer, md5_ctx_t *ctx) +void md5_hash(const void *data, size_t size, md5_ctx_t *ctx) { - uint32_t correct_words[16]; - const uint32_t *words = buffer; + uint32_t saved_lo; + unsigned long used, available; - static const uint32_t C_array[] = { - /* round 1 */ - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - /* round 2 */ - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - /* round 3 */ - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - /* round 4 */ - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 - }; + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; - static const char P_array[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ - 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ - 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ - 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ - }; + used = saved_lo & 0x3f; - static const char S_array[] = { - 7, 12, 17, 22, - 5, 9, 14, 20, - 4, 11, 16, 23, - 6, 10, 15, 21 - }; + if (used) { + available = 64 - used; - uint32_t A = ctx->A; - uint32_t B = ctx->B; - uint32_t C = ctx->C; - uint32_t D = ctx->D; - - uint32_t *cwp = correct_words; - -# define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) - - const uint32_t *pc; - const char *pp; - const char *ps; - int i; - uint32_t temp; - - for (i = 0; i < 16; i++) { - cwp[i] = SWAP_LE32(words[i]); - } - - pc = C_array; - pp = P_array; - ps = S_array; - - for (i = 0; i < 16; i++) { - temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++; - CYCLIC(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - - ps += 4; - for (i = 0; i < 16; i++) { - temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++; - CYCLIC(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - ps += 4; - for (i = 0; i < 16; i++) { - temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++; - CYCLIC(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - ps += 4; - for (i = 0; i < 16; i++) { - temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++; - CYCLIC(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - - - ctx->A += A; - ctx->B += B; - ctx->C += C; - ctx->D += D; -} - -/* Feed data through a temporary buffer to call md5_hash_aligned_block() - * with chunks of data that are 4-byte aligned and a multiple of 64 bytes. - * This function's internal buffer remembers previous data until it has 64 - * bytes worth to pass on. Call md5_end() to flush this buffer. */ - -void md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx) -{ - char *buf = (char *)buffer; - - /* RFC 1321 specifies the possible length of the file up to 2^64 bits, - * Here we only track the number of bytes. */ - - ctx->total += len; - - // Process all input. - - while (len) { - unsigned i = 64 - ctx->buflen; - - // Copy data into aligned buffer. - - if (i > len) - i = len; - memcpy(ctx->buffer + ctx->buflen, buf, i); - len -= i; - ctx->buflen += i; - buf += i; - - // When buffer fills up, process it. - - if (ctx->buflen == 64) { - md5_hash_block(ctx->buffer, ctx); - ctx->buflen = 0; + if (size < available) { + memcpy(&ctx->buffer[used], data, size); + return; } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char *)data + available; + size -= available; + body(ctx, ctx->buffer, 64); } + + if (size >= 64) { + data = body(ctx, data, size & ~((size_t) 0x3f)); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); } -/* Process the remaining bytes in the buffer and put result from CTX - * in first 16 bytes following RESBUF. The result is always in little - * endian byte order, so that a byte-wise output yields to the wanted - * ASCII representation of the message digest. - * - * IMPORTANT: On some systems it is required that RESBUF is correctly - * aligned for a 32 bits value. - */ void md5_end(void *resbuf, md5_ctx_t *ctx) { - char *buf = ctx->buffer; - int i; + unsigned char *result = resbuf; + unsigned long used, available; - /* Pad data to block size. */ + used = ctx->lo & 0x3f; - buf[ctx->buflen++] = 0x80; - memset(buf + ctx->buflen, 0, 128 - ctx->buflen); + ctx->buffer[used++] = 0x80; - /* Put the 64-bit file length in *bits* at the end of the buffer. */ - ctx->total <<= 3; - if (ctx->buflen > 56) - buf += 64; + available = 64 - used; - for (i = 0; i < 8; i++) - buf[56 + i] = ctx->total >> (i*8); + if (available < 8) { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } - /* Process last bytes. */ - if (buf != ctx->buffer) - md5_hash_block(ctx->buffer, ctx); - md5_hash_block(buf, ctx); + memset(&ctx->buffer[used], 0, available - 8); - /* Put result from CTX in first 16 bytes following RESBUF. The result is - * always in little endian byte order, so that a byte-wise output yields - * to the wanted ASCII representation of the message digest. - * - * IMPORTANT: On some systems it is required that RESBUF is correctly - * aligned for a 32 bits value. - */ - ((uint32_t *) resbuf)[0] = SWAP_LE32(ctx->A); - ((uint32_t *) resbuf)[1] = SWAP_LE32(ctx->B); - ((uint32_t *) resbuf)[2] = SWAP_LE32(ctx->C); - ((uint32_t *) resbuf)[3] = SWAP_LE32(ctx->D); + ctx->lo <<= 3; + ctx->buffer[56] = ctx->lo; + ctx->buffer[57] = ctx->lo >> 8; + ctx->buffer[58] = ctx->lo >> 16; + ctx->buffer[59] = ctx->lo >> 24; + ctx->buffer[60] = ctx->hi; + ctx->buffer[61] = ctx->hi >> 8; + ctx->buffer[62] = ctx->hi >> 16; + ctx->buffer[63] = ctx->hi >> 24; + + body(ctx, ctx->buffer, 64); + + result[0] = ctx->a; + result[1] = ctx->a >> 8; + result[2] = ctx->a >> 16; + result[3] = ctx->a >> 24; + result[4] = ctx->b; + result[5] = ctx->b >> 8; + result[6] = ctx->b >> 16; + result[7] = ctx->b >> 24; + result[8] = ctx->c; + result[9] = ctx->c >> 8; + result[10] = ctx->c >> 16; + result[11] = ctx->c >> 24; + result[12] = ctx->d; + result[13] = ctx->d >> 8; + result[14] = ctx->d >> 16; + result[15] = ctx->d >> 24; + + memset(ctx, 0, sizeof(*ctx)); } -int md5sum(char *file, uint32_t *md5) +int md5sum(char *file, void *md5_buf) { char buf[256]; md5_ctx_t ctx; - int len, fd; int ret = 0; + FILE *f; - memset(md5, 0, sizeof(*md5) * 4); - - fd = open(file, O_RDONLY); - if (fd < 0) + f = fopen(file, "r"); + if (!f) return -1; md5_begin(&ctx); do { - len = read(fd, buf, sizeof(buf)); - if (len < 0) { - if (errno == EINTR) - continue; - - ret = -1; - goto out; - } + int len = fread(buf, 1, sizeof(buf), f); if (!len) break; md5_hash(buf, len, &ctx); + ret += len; } while(1); - md5_end(md5, &ctx); -out: - close(fd); + md5_end(md5_buf, &ctx); + fclose(f); return ret; } diff --git a/3P/libubox/md5.h b/3P/libubox/md5.h index 63059891..b2f1b80c 100644 --- a/3P/libubox/md5.h +++ b/3P/libubox/md5.h @@ -1,36 +1,58 @@ /* - * Copyright (C) 2013 Felix Fietkau - * Copyright (C) 2013 John Crispin + * Copyright (C) 2014 Felix Fietkau * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1 - * as published by the Free Software Foundation + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md5.c for more information. */ -#ifndef __PROCD_MD5_H -#define __PROCD_MD5_H +#ifndef _LIBUBOX_MD5_H +#define _LIBUBOX_MD5_H #include #include typedef struct md5_ctx { - uint32_t A; - uint32_t B; - uint32_t C; - uint32_t D; - uint64_t total; - uint32_t buflen; - char buffer[128]; + uint32_t lo, hi; + uint32_t a, b, c, d; + unsigned char buffer[64]; } md5_ctx_t; -void md5_begin(md5_ctx_t *ctx); -void md5_hash(const void *data, size_t length, md5_ctx_t *ctx); -void md5_end(void *resbuf, md5_ctx_t *ctx); -int md5sum(char *file, uint32_t *md5); +extern void md5_begin(md5_ctx_t *ctx); +extern void md5_hash(const void *data, size_t length, md5_ctx_t *ctx); +extern void md5_end(void *resbuf, md5_ctx_t *ctx); +int md5sum(char *file, void *md5_buf); #endif diff --git a/3P/libubox/sh/jshn.sh b/3P/libubox/sh/jshn.sh index 5db1667d..bf76edbe 100644 --- a/3P/libubox/sh/jshn.sh +++ b/3P/libubox/sh/jshn.sh @@ -42,7 +42,7 @@ _json_inc() { # var=$1 # dest=$2 - eval "${JSON_PREFIX}$1=\$(( \${${JSON_PREFIX}$1:-0} + 1))${2:+; $2=\"\$${JSON_PREFIX}$1\"}" + let "${JSON_PREFIX}$1 += 1" "$2 = ${JSON_PREFIX}$1" } _json_add_generic() { @@ -52,20 +52,18 @@ _json_add_generic() { # cur=$4 local var - if [ "${4%%[0-9]*}" = "JSON_ARRAY" ]; then - _json_inc "SEQ_$4" var + if [ "${4%%[0-9]*}" = "J_A" ]; then + _json_inc "S_$4" var else - local name="${2//[^a-zA-Z0-9_]/_}" - [[ "$name" == "$2" ]] || export -- "${JSON_PREFIX}NAME_${4}_${name}=$2" - var="$name" + var="${2//[^a-zA-Z0-9_]/_}" + [[ "$var" == "$2" ]] || export -- "${JSON_PREFIX}N_${4}_${var}=$2" fi - local cur_var= export -- \ "${JSON_PREFIX}${4}_$var=$3" \ - "${JSON_PREFIX}TYPE_${4}_$var=$1" + "${JSON_PREFIX}T_${4}_$var=$1" _jshn_append "JSON_UNSET" "${4}_$var" - _jshn_append "KEYS_$4" "$var" + _jshn_append "K_$4" "$var" } _json_add_table() { @@ -77,10 +75,10 @@ _json_add_table() { _json_get_var cur JSON_CUR _json_inc JSON_SEQ seq - local table="JSON_$3$seq" - _json_set_var "UP_$table" "$cur" - export -- "${JSON_PREFIX}KEYS_$table=" - unset "${JSON_PREFIX}SEQ_$table" + local table="J_$3$seq" + _json_set_var "U_$table" "$cur" + export -- "${JSON_PREFIX}K_$table=" + unset "${JSON_PREFIX}S_$table" _json_set_var JSON_CUR "$table" _jshn_append "JSON_UNSET" "$table" @@ -91,7 +89,7 @@ _json_close_table() { local _s_cur _json_get_var _s_cur JSON_CUR - _json_get_var "${JSON_PREFIX}JSON_CUR" "UP_$_s_cur" + _json_get_var "${JSON_PREFIX}JSON_CUR" "U_$_s_cur" } json_set_namespace() { @@ -106,13 +104,13 @@ json_cleanup() { local unset tmp _json_get_var unset JSON_UNSET - for tmp in $unset JSON_VAR; do + for tmp in $unset J_V; do unset \ - ${JSON_PREFIX}UP_$tmp \ - ${JSON_PREFIX}KEYS_$tmp \ - ${JSON_PREFIX}SEQ_$tmp \ - ${JSON_PREFIX}TYPE_$tmp \ - ${JSON_PREFIX}NAME_$tmp \ + ${JSON_PREFIX}U_$tmp \ + ${JSON_PREFIX}K_$tmp \ + ${JSON_PREFIX}S_$tmp \ + ${JSON_PREFIX}T_$tmp \ + ${JSON_PREFIX}N_$tmp \ ${JSON_PREFIX}$tmp done @@ -124,15 +122,14 @@ json_cleanup() { json_init() { json_cleanup + export -n ${JSON_PREFIX}JSON_SEQ=0 export -- \ - ${JSON_PREFIX}JSON_SEQ=0 \ - ${JSON_PREFIX}JSON_CUR="JSON_VAR" \ - ${JSON_PREFIX}KEYS_JSON_VAR= \ - ${JSON_PREFIX}TYPE_JSON_VAR= + ${JSON_PREFIX}JSON_CUR="J_V" \ + ${JSON_PREFIX}K_J_V= } json_add_object() { - _json_add_table "$1" object TABLE + _json_add_table "$1" object T } json_close_object() { @@ -140,7 +137,7 @@ json_close_object() { } json_add_array() { - _json_add_table "$1" array ARRAY + _json_add_table "$1" array A } json_close_array() { @@ -186,7 +183,7 @@ json_get_type() { local __cur _json_get_var __cur JSON_CUR - local __var="${JSON_PREFIX}TYPE_${__cur}_${2//[^a-zA-Z0-9_]/_}" + local __var="${JSON_PREFIX}T_${__cur}_${2//[^a-zA-Z0-9_]/_}" eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]" } @@ -199,7 +196,7 @@ json_get_keys() { else _json_get_var _tbl_cur JSON_CUR fi - local __var="${JSON_PREFIX}KEYS_${_tbl_cur}" + local __var="${JSON_PREFIX}K_${_tbl_cur}" eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]" } @@ -252,12 +249,12 @@ json_select() { local cur [ -z "$1" ] && { - _json_set_var JSON_CUR "JSON_VAR" + _json_set_var JSON_CUR "J_V" return 0 } [[ "$1" == ".." ]] && { _json_get_var cur JSON_CUR - _json_get_var cur "UP_$cur" + _json_get_var cur "U_$cur" _json_set_var JSON_CUR "$cur" return 0 } diff --git a/3P/libubox/ulog.c b/3P/libubox/ulog.c new file mode 100644 index 00000000..296605dd --- /dev/null +++ b/3P/libubox/ulog.c @@ -0,0 +1,173 @@ +/* + * ulog - simple logging functions + * + * Copyright (C) 2015 Jo-Philipp Wich + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ulog.h" + +#include +#include +#include +#include +#include + +static int _ulog_channels = -1; +static int _ulog_facility = -1; +static int _ulog_threshold = LOG_DEBUG; +static int _ulog_initialized = 0; +static const char *_ulog_ident = NULL; + +static const char *ulog_default_ident(void) +{ + FILE *self; + static char line[64]; + char *p = NULL; + + if ((self = fopen("/proc/self/status", "r")) != NULL) { + while (fgets(line, sizeof(line), self)) { + if (!strncmp(line, "Name:", 5)) { + strtok(line, "\t\n"); + p = strtok(NULL, "\t\n"); + break; + } + } + fclose(self); + } + + return p; +} + +static void ulog_defaults(void) +{ + char *env; + + if (_ulog_initialized) + return; + + env = getenv("PREINIT"); + + if (_ulog_channels < 0) { + if (env && !strcmp(env, "1")) + _ulog_channels = ULOG_KMSG; + else if (isatty(1)) + _ulog_channels = ULOG_STDIO; + else + _ulog_channels = ULOG_SYSLOG; + } + + if (_ulog_facility < 0) { + if (env && !strcmp(env, "1")) + _ulog_facility = LOG_DAEMON; + else if (isatty(1)) + _ulog_facility = LOG_USER; + else + _ulog_facility = LOG_DAEMON; + } + + if (_ulog_ident == NULL && _ulog_channels != ULOG_STDIO) + _ulog_ident = ulog_default_ident(); + + if (_ulog_channels & ULOG_SYSLOG) + openlog(_ulog_ident, 0, _ulog_facility); + + _ulog_initialized = 1; +} + +static void ulog_kmsg(int priority, const char *fmt, va_list ap) +{ + FILE *kmsg; + + if ((kmsg = fopen("/dev/kmsg", "r+")) != NULL) { + fprintf(kmsg, "<%u>", priority); + + if (_ulog_ident) + fprintf(kmsg, "%s: ", _ulog_ident); + + vfprintf(kmsg, fmt, ap); + fclose(kmsg); + } +} + +static void ulog_stdio(int priority, const char *fmt, va_list ap) +{ + FILE *out = stderr; + + if (_ulog_ident) + fprintf(out, "%s: ", _ulog_ident); + + vfprintf(out, fmt, ap); +} + +static void ulog_syslog(int priority, const char *fmt, va_list ap) +{ + vsyslog(priority, fmt, ap); +} + +void ulog_open(int channels, int facility, const char *ident) +{ + ulog_close(); + + _ulog_channels = channels; + _ulog_facility = facility; + _ulog_ident = ident; +} + +void ulog_close(void) +{ + if (!_ulog_initialized) + return; + + if (_ulog_channels & ULOG_SYSLOG) + closelog(); + + _ulog_initialized = 0; +} + +void ulog_threshold(int threshold) +{ + _ulog_threshold = threshold; +} + +void ulog(int priority, const char *fmt, ...) +{ + va_list ap; + + if (priority > _ulog_threshold) + return; + + ulog_defaults(); + + if (_ulog_channels & ULOG_KMSG) + { + va_start(ap, fmt); + ulog_kmsg(priority, fmt, ap); + va_end(ap); + } + + if (_ulog_channels & ULOG_STDIO) + { + va_start(ap, fmt); + ulog_stdio(priority, fmt, ap); + va_end(ap); + } + + if (_ulog_channels & ULOG_SYSLOG) + { + va_start(ap, fmt); + ulog_syslog(priority, fmt, ap); + va_end(ap); + } +} diff --git a/3P/libubox/ulog.h b/3P/libubox/ulog.h new file mode 100644 index 00000000..4818b1a8 --- /dev/null +++ b/3P/libubox/ulog.h @@ -0,0 +1,42 @@ +/* + * ulog - simple logging functions + * + * Copyright (C) 2015 Jo-Philipp Wich + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __LIBUBOX_ULOG_H +#define __LIBUBOX_ULOG_H + +#include + +enum { + ULOG_KMSG = (1 << 0), + ULOG_SYSLOG = (1 << 1), + ULOG_STDIO = (1 << 2) +}; + +void ulog_open(int channels, int facility, const char *ident); +void ulog_close(void); + +void ulog_threshold(int threshold); + +void ulog(int priority, const char *fmt, ...); + +#define ULOG_INFO(fmt, ...) ulog(LOG_INFO, fmt, ## __VA_ARGS__) +#define ULOG_NOTE(fmt, ...) ulog(LOG_NOTICE, fmt, ## __VA_ARGS__) +#define ULOG_WARN(fmt, ...) ulog(LOG_WARNING, fmt, ## __VA_ARGS__) +#define ULOG_ERR(fmt, ...) ulog(LOG_ERR, fmt, ## __VA_ARGS__) + +#endif diff --git a/3P/libubox/uloop.c b/3P/libubox/uloop.c index 6b484125..4c272ce9 100644 --- a/3P/libubox/uloop.c +++ b/3P/libubox/uloop.c @@ -53,13 +53,12 @@ static __thread struct uloop_fd_stack *fd_stack = NULL; #define ULOOP_MAX_EVENTS 10 -static __thread struct list_head timeouts = {0}; -static __thread struct list_head processes = {0}; +static __thread struct list_head timeouts = LIST_HEAD_INIT(timeouts); +static __thread struct list_head processes = LIST_HEAD_INIT(processes); static __thread int poll_fd = -1; __thread bool uloop_cancelled = false; -__thread bool uloop_handle_sigchld = true; -static __thread bool do_sigchld = false; +__thread static bool do_sigchld = false; static __thread struct uloop_fd_event cur_fds[ULOOP_MAX_EVENTS]; static __thread int cur_fd, cur_nfds; @@ -213,10 +212,7 @@ int uloop_init(void) { if (poll_fd >= 0) return 0; - - if ((timeouts.next == 0) && (timeouts.prev == 0)) INIT_LIST_HEAD (&timeouts); - if ((processes.next == 0) && (processes.prev == 0)) INIT_LIST_HEAD (&processes); - + poll_fd = epoll_create(32); if (poll_fd < 0) return -1; @@ -457,14 +453,14 @@ int uloop_timeout_set(struct uloop_timeout *timeout, int msecs) if (timeout->pending) uloop_timeout_cancel(timeout); - uloop_gettime(&timeout->time); + uloop_gettime(time); time->tv_sec += msecs / 1000; time->tv_usec += (msecs % 1000) * 1000; if (time->tv_usec > 1000000) { time->tv_sec++; - time->tv_usec %= 1000000; + time->tv_usec -= 1000000; } return uloop_timeout_add(timeout); @@ -562,31 +558,61 @@ static void uloop_sigchld(int signo) do_sigchld = true; } -static void uloop_setup_signals(bool add) +static void uloop_install_handler(int signum, void (*handler)(int), struct sigaction* old, bool add) { - static struct sigaction old_sigint, old_sigchld; struct sigaction s; + struct sigaction *act; - memset(&s, 0, sizeof(struct sigaction)); + act = NULL; + sigaction(signum, NULL, &s); if (add) { - s.sa_handler = uloop_handle_sigint; - s.sa_flags = 0; - } else { - s = old_sigint; + if (s.sa_handler == SIG_DFL) { /* Do not override existing custom signal handlers */ + memcpy(old, &s, sizeof(struct sigaction)); + s.sa_handler = handler; + s.sa_flags = 0; + act = &s; + } + } + else if (s.sa_handler == handler) { /* Do not restore if someone modified our handler */ + act = old; } - sigaction(SIGINT, &s, &old_sigint); + if (act != NULL) + sigaction(signum, act, NULL); +} - if (!uloop_handle_sigchld) - return; +static void uloop_ignore_signal(int signum, bool ignore) +{ + struct sigaction s; + void *new_handler = NULL; - if (add) - s.sa_handler = uloop_sigchld; - else - s = old_sigchld; + sigaction(signum, NULL, &s); - sigaction(SIGCHLD, &s, &old_sigchld); + if (ignore) { + if (s.sa_handler == SIG_DFL) /* Ignore only if there isn't any custom handler */ + new_handler = SIG_IGN; + } else { + if (s.sa_handler == SIG_IGN) /* Restore only if noone modified our SIG_IGN */ + new_handler = SIG_DFL; + } + + if (new_handler) { + s.sa_handler = new_handler; + s.sa_flags = 0; + sigaction(signum, &s, NULL); + } +} + +static void uloop_setup_signals(bool add) +{ + static struct sigaction old_sigint, old_sigchld, old_sigterm; + + uloop_install_handler(SIGINT, uloop_handle_sigint, &old_sigint, add); + uloop_install_handler(SIGTERM, uloop_handle_sigint, &old_sigterm, add); + uloop_install_handler(SIGCHLD, uloop_sigchld, &old_sigchld, add); + + uloop_ignore_signal(SIGPIPE, add); } static int uloop_get_next_timeout(struct timeval *tv) @@ -654,11 +680,13 @@ void uloop_run(void) { uloop_gettime(&tv); uloop_process_timeouts(&tv); - if (uloop_cancelled) - break; if (do_sigchld) uloop_handle_processes(); + + if (uloop_cancelled) + break; + uloop_gettime(&tv); uloop_run_events(uloop_get_next_timeout(&tv)); } diff --git a/3P/libubox/usock.c b/3P/libubox/usock.c index 04ed4ee5..0ce53904 100644 --- a/3P/libubox/usock.c +++ b/3P/libubox/usock.c @@ -20,14 +20,18 @@ #include #include #include +#include #include #include #include #include #include #include +#include +#include #include "usock.h" +#include "utils.h" static void usock_set_flags(int sock, unsigned int type) { @@ -38,7 +42,7 @@ static void usock_set_flags(int sock, unsigned int type) fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK); } -static int usock_connect(struct sockaddr *sa, int sa_len, int family, int socktype, bool server) +static int usock_connect(int type, struct sockaddr *sa, int sa_len, int family, int socktype, bool server) { int sock; @@ -46,6 +50,8 @@ static int usock_connect(struct sockaddr *sa, int sa_len, int family, int sockty if (sock < 0) return -1; + usock_set_flags(sock, type); + if (server) { const int one = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); @@ -62,9 +68,11 @@ static int usock_connect(struct sockaddr *sa, int sa_len, int family, int sockty return -1; } -static int usock_unix(const char *host, int socktype, bool server) +static int usock_unix(int type, const char *host) { struct sockaddr_un sun = {.sun_family = AF_UNIX}; + bool server = !!(type & USOCK_SERVER); + int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM; if (strlen(host) >= sizeof(sun.sun_path)) { errno = EINVAL; @@ -72,11 +80,65 @@ static int usock_unix(const char *host, int socktype, bool server) } strcpy(sun.sun_path, host); - return usock_connect((struct sockaddr*)&sun, sizeof(sun), AF_UNIX, socktype, server); + return usock_connect(type, (struct sockaddr*)&sun, sizeof(sun), AF_UNIX, socktype, server); } -static int usock_inet(int type, const char *host, const char *service, int socktype, bool server) +static int +usock_inet_notimeout(int type, struct addrinfo *result, void *addr) { + struct addrinfo *rp; + int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM; + bool server = !!(type & USOCK_SERVER); + int sock; + + for (rp = result; rp != NULL; rp = rp->ai_next) { + sock = usock_connect(type, rp->ai_addr, rp->ai_addrlen, rp->ai_family, socktype, server); + if (sock >= 0) { + if (addr) + memcpy(addr, rp->ai_addr, rp->ai_addrlen); + return sock; + } + } + + return -1; +} + +static int poll_restart(struct pollfd *fds, int nfds, int timeout) +{ + struct timespec ts, cur; + int msec = timeout % 1000; + int ret; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + ts.tv_nsec += msec * 1000000; + if (ts.tv_nsec > 1000000000) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000; + } + ts.tv_sec += timeout / 1000; + + while (1) { + ret = poll(fds, nfds, timeout); + if (ret == EAGAIN) + continue; + + if (ret != EINTR) + return ret; + + clock_gettime(CLOCK_MONOTONIC, &cur); + timeout = (ts.tv_sec - cur.tv_sec) * 1000; + timeout += (ts.tv_nsec - cur.tv_nsec) / 1000000; + if (timeout <= 0) + return 0; + } +} + +int usock_inet_timeout(int type, const char *host, const char *service, + void *addr, int timeout) +{ + int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM; + bool server = !!(type & USOCK_SERVER); struct addrinfo *result, *rp; struct addrinfo hints = { .ai_family = (type & USOCK_IPV6ONLY) ? AF_INET6 : @@ -86,34 +148,146 @@ static int usock_inet(int type, const char *host, const char *service, int sockt | ((type & USOCK_SERVER) ? AI_PASSIVE : 0) | ((type & USOCK_NUMERIC) ? AI_NUMERICHOST : 0), }; + struct addrinfo *rp_v6 = NULL; + struct addrinfo *rp_v4 = NULL; + struct pollfd pfds[2] = { + { .fd = -1, .events = POLLOUT }, + { .fd = -1, .events = POLLOUT }, + }; int sock = -1; + int i; if (getaddrinfo(host, service, &hints, &result)) return -1; - for (rp = result; rp != NULL; rp = rp->ai_next) { - sock = usock_connect(rp->ai_addr, rp->ai_addrlen, rp->ai_family, socktype, server); - if (sock >= 0) - break; + if (timeout <= 0 || server) { + sock = usock_inet_notimeout(type, result, addr); + goto free_addrinfo; } + for (rp = result; rp != NULL; rp = rp->ai_next) { + if (rp->ai_family == AF_INET6 && !rp_v6) + rp_v6 = rp; + if (rp->ai_family == AF_INET && !rp_v4) + rp_v4 = rp; + } + + if (!rp_v6 && !rp_v4) + goto out; + + if (rp_v6) { + rp = rp_v6; + pfds[0].fd = usock_connect(type | USOCK_NONBLOCK, rp->ai_addr, + rp->ai_addrlen, rp->ai_family, + socktype, server); + if (pfds[0].fd < 0) { + rp_v6 = NULL; + goto try_v4; + } + + if (timeout > 300) { + if (poll_restart(pfds, 1, 300) == 1) { + rp = rp_v6; + sock = pfds[0].fd; + goto out; + } + } + timeout -= 300; + } + +try_v4: + if (rp_v4) { + rp = rp_v4; + pfds[1].fd = usock_connect(type | USOCK_NONBLOCK, rp->ai_addr, + rp->ai_addrlen, rp->ai_family, + socktype, server); + if (pfds[1].fd < 0) { + rp_v4 = NULL; + if (!rp_v6) + goto out; + goto wait; + } + } + +wait: + poll_restart(pfds + !rp_v6, !!rp_v6 + !!rp_v4, timeout); + if (pfds[0].revents & POLLOUT) { + rp = rp_v6; + sock = pfds[0].fd; + goto out; + } + + if (pfds[1].revents & POLLOUT) { + rp = rp_v4; + sock = pfds[1].fd; + goto out; + } + +out: + for (i = 0; i < 2; i++) { + int fd = pfds[i].fd; + if (fd >= 0 && fd != sock) + close(fd); + } + + if (!(type & USOCK_NONBLOCK)) + fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) & ~O_NONBLOCK); + + if (addr && sock >= 0) + memcpy(addr, rp->ai_addr, rp->ai_addrlen); +free_addrinfo: freeaddrinfo(result); return sock; } +const char *usock_port(int port) +{ + static char buffer[sizeof("65535\0")]; + + if (port < 0 || port > 65535) + return NULL; + + snprintf(buffer, sizeof(buffer), "%u", port); + + return buffer; +} + int usock(int type, const char *host, const char *service) { - int socktype = ((type & 0xff) == USOCK_TCP) ? SOCK_STREAM : SOCK_DGRAM; - bool server = !!(type & USOCK_SERVER); int sock; if (type & USOCK_UNIX) - sock = usock_unix(host, socktype, server); + sock = usock_unix(type, host); else - sock = usock_inet(type, host, service, socktype, server); + sock = usock_inet(type, host, service, NULL); if (sock < 0) return -1; - usock_set_flags(sock, type); return sock; } + +int usock_wait_ready(int fd, int msecs) { + struct pollfd fds[1]; + int res; + + fds[0].fd = fd; + fds[0].events = POLLOUT; + + res = poll(fds, 1, msecs); + if (res < 0) { + return errno; + } else if (res == 0) { + return -ETIMEDOUT; + } else { + int err = 0; + socklen_t optlen = sizeof(err); + + res = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen); + if (res) + return errno; + if (err) + return err; + } + + return 0; +} diff --git a/3P/libubox/usock.h b/3P/libubox/usock.h index 5df4362c..5f2b84b0 100644 --- a/3P/libubox/usock.h +++ b/3P/libubox/usock.h @@ -30,6 +30,25 @@ #define USOCK_IPV4ONLY 0x4000 #define USOCK_UNIX 0x8000 +const char *usock_port(int port); int usock(int type, const char *host, const char *service); +int usock_inet_timeout(int type, const char *host, const char *service, + void *addr, int timeout); +static inline int +usock_inet(int type, const char *host, const char *service, void *addr) +{ + return usock_inet_timeout(type, host, service, addr, -1); +} + +/** + * Wait for a socket to become ready. + * + * This may be useful for users of USOCK_NONBLOCK to wait (with a timeout) + * for a socket. + * + * @param fd file descriptor of socket + * @param msecs timeout in microseconds + */ +int usock_wait_ready(int fd, int msecs); #endif /* USOCK_H_ */ diff --git a/3P/libubox/ustream-fd.c b/3P/libubox/ustream-fd.c index 4abb5305..b546fa1c 100644 --- a/3P/libubox/ustream-fd.c +++ b/3P/libubox/ustream-fd.c @@ -25,7 +25,7 @@ static void ustream_fd_set_uloop(struct ustream *s, bool write) { struct ustream_fd *sf = container_of(s, struct ustream_fd, stream); struct ustream_buf *buf; - unsigned int flags = ULOOP_EDGE_TRIGGER; + unsigned int flags = ULOOP_EDGE_TRIGGER | ULOOP_ERROR_CB; if (!s->read_blocked && !s->eof) flags |= ULOOP_READ; @@ -50,6 +50,9 @@ static void ustream_fd_read_pending(struct ustream_fd *sf, bool *more) char *buf; do { + if (s->read_blocked) + break; + buf = ustream_reserve(s, 1, &buflen); if (!buf) break; @@ -59,7 +62,7 @@ static void ustream_fd_read_pending(struct ustream_fd *sf, bool *more) if (errno == EINTR) continue; - if (errno == EAGAIN) + if (errno == EAGAIN || errno == ENOTCONN) return; len = 0; @@ -93,7 +96,7 @@ static int ustream_fd_write(struct ustream *s, const char *buf, int buflen, bool if (errno == EINTR) continue; - if (errno == EAGAIN || errno == EWOULDBLOCK) + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN) break; return -1; @@ -119,10 +122,17 @@ static bool __ustream_fd_poll(struct ustream_fd *sf, unsigned int events) ustream_fd_read_pending(sf, &more); if (events & ULOOP_WRITE) { - if (!ustream_write_pending(s)) + bool no_more = ustream_write_pending(s); + if (no_more) ustream_fd_set_uloop(s, false); } + if (sf->fd.error && !s->write_error) { + ustream_state_change(s); + s->write_error = true; + ustream_fd_set_uloop(s, false); + } + return more; } diff --git a/3P/libubox/ustream.c b/3P/libubox/ustream.c index 828a025b..e7ee9f07 100644 --- a/3P/libubox/ustream.c +++ b/3P/libubox/ustream.c @@ -145,21 +145,26 @@ static bool ustream_should_move(struct ustream_buf_list *l, struct ustream_buf * int maxlen; int offset; + /* nothing to squeeze */ if (buf->data == buf->head) return false; maxlen = buf->end - buf->head; offset = buf->data - buf->head; + /* less than half is available */ if (offset > maxlen / 2) return true; + /* less than 32 bytes data but takes more than 1/4 space */ if (buf->tail - buf->data < 32 && offset > maxlen / 4) return true; + /* more buf is already in list or can be allocated */ if (buf != l->tail || ustream_can_alloc(l)) return false; + /* no need to move if len is available at the tail */ return (buf->end - buf->tail < len); } @@ -255,13 +260,14 @@ static bool ustream_prepare_buf(struct ustream *s, struct ustream_buf_list *l, i if (l == &s->r) ustream_fixup_string(s, buf); } + /* some chunks available at the tail */ if (buf->tail != buf->end) return true; - } - - if (buf && buf->next) { - l->data_tail = buf->next; - return true; + /* next buf available */ + if (buf->next) { + l->data_tail = buf->next; + return true; + } } if (!ustream_can_alloc(l)) @@ -333,6 +339,26 @@ char *ustream_get_read_buf(struct ustream *s, int *buflen) return data; } +int ustream_read(struct ustream *s, char *buf, int buflen) +{ + char *chunk; + int chunk_len; + int len = 0; + + do { + chunk = ustream_get_read_buf(s, &chunk_len); + if (!chunk) + break; + if (chunk_len > buflen - len) + chunk_len = buflen - len; + memcpy(buf + len, chunk, chunk_len); + ustream_consume(s, chunk_len); + len += chunk_len; + } while (len < buflen); + + return len; +} + static void ustream_write_error(struct ustream *s) { if (!s->write_error) diff --git a/3P/libubox/ustream.h b/3P/libubox/ustream.h index 64317441..53e08280 100644 --- a/3P/libubox/ustream.h +++ b/3P/libubox/ustream.h @@ -143,6 +143,11 @@ void ustream_free(struct ustream *s); /* ustream_consume: remove data from the head of the read buffer */ void ustream_consume(struct ustream *s, int len); +/* + * ustream_read: read and consume data in read buffer into caller-specified + * area. Return length of data read. + */ +int ustream_read(struct ustream *s, char *buf, int buflen); /* ustream_write: add data to the write buffer */ int ustream_write(struct ustream *s, const char *buf, int len, bool more); int ustream_printf(struct ustream *s, const char *format, ...); diff --git a/3P/libubox/utils.c b/3P/libubox/utils.c index 078a8a19..8fd19f47 100644 --- a/3P/libubox/utils.c +++ b/3P/libubox/utils.c @@ -54,41 +54,50 @@ void *__calloc_a(size_t len, ...) } #ifdef __APPLE__ -#include +#include /* host_get_clock_service() */ +#include /* mach_port_deallocate() */ +#include /* mach_host_self(), mach_task_self() */ +#include /* clock_get_time() */ -static void clock_gettime_realtime(struct timespec *tv) +static clock_serv_t clock_realtime; +static clock_serv_t clock_monotonic; + +static void __constructor clock_name_init(void) { - struct timeval _tv; + mach_port_t host_self = mach_host_self(); - gettimeofday(&_tv, NULL); - tv->tv_sec = _tv.tv_sec; - tv->tv_nsec = _tv.tv_usec * 1000; + host_get_clock_service(host_self, CLOCK_REALTIME, &clock_realtime); + host_get_clock_service(host_self, CLOCK_MONOTONIC, &clock_monotonic); } -static void clock_gettime_monotonic(struct timespec *tv) +static void __destructor clock_name_dealloc(void) { - mach_timebase_info_data_t info; - float sec; - uint64_t val; + mach_port_t self = mach_task_self(); - mach_timebase_info(&info); - - val = mach_absolute_time(); - tv->tv_nsec = (val * info.numer / info.denom) % 1000000000; - - sec = val; - sec *= info.numer; - sec /= info.denom; - sec /= 1000000000; - tv->tv_sec = sec; + mach_port_deallocate(self, clock_realtime); + mach_port_deallocate(self, clock_monotonic); } -void clock_gettime(int type, struct timespec *tv) +int clock_gettime(int type, struct timespec *tv) { - if (type == CLOCK_REALTIME) - return clock_gettime_realtime(tv); - else - return clock_gettime_monotonic(tv); + int retval = -1; + mach_timespec_t mts; + + switch (type) { + case CLOCK_REALTIME: + retval = clock_get_time(clock_realtime, &mts); + break; + case CLOCK_MONOTONIC: + retval = clock_get_time(clock_monotonic, &mts); + break; + default: + goto out; + } + + tv->tv_sec = mts.tv_sec; + tv->tv_nsec = mts.tv_nsec; +out: + return retval; } #endif diff --git a/3P/libubox/utils.h b/3P/libubox/utils.h index 9688a6a4..d00e76b2 100644 --- a/3P/libubox/utils.h +++ b/3P/libubox/utils.h @@ -58,10 +58,11 @@ extern int __BUILD_BUG_ON_CONDITION_FAILED; #ifdef __APPLE__ -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 1 +#include +#define CLOCK_REALTIME CALENDAR_CLOCK +#define CLOCK_MONOTONIC SYSTEM_CLOCK -void clock_gettime(int type, struct timespec *tv); +int clock_gettime(int type, struct timespec *tv); #endif @@ -159,6 +160,10 @@ static inline uint16_t __u_bswap16(uint16_t val) #define __constructor __attribute__((constructor)) #endif +#ifndef __destructor +#define __destructor __attribute__((destructor)) +#endif + #ifndef __hidden #define __hidden __attribute__((visibility("hidden"))) #endif @@ -179,4 +184,12 @@ static inline bool bitfield_test(unsigned long *bits, int bit) return !!(bits[bit / BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))); } +int b64_encode(const void *src, size_t src_len, + void *dest, size_t dest_len); + +int b64_decode(const void *src, void *dest, size_t dest_len); + +#define B64_ENCODE_LEN(_len) ((((_len) + 2) / 3) * 4 + 1) +#define B64_DECODE_LEN(_len) (((_len) / 4) * 3 + 1) + #endif