From 09258f1e8b12acc4a2a02b60d942660798038fba Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 25 Oct 2012 16:30:58 +0000 Subject: fdt: Add function to get config int from device tree Add a function to look up a configuration item such as machine id and return its value. Note: The code has been taken as is from the Chromium u-boot development tree and needs Simon Glass' sign-off. Signed-off-by: Abhilash Kesavan Signed-off-by: Simon Glass --- lib/fdtdec.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'lib') diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 4c23f458f0f..1f500224d94 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -512,3 +512,25 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, return NULL; return cell; } + +/** + * Look in the FDT for a config item with the given name and return its value + * as a 32-bit integer. The property must have at least 4 bytes of data. The + * value of the first cell is returned. + * + * @param blob FDT blob to use + * @param prop_name Node property name + * @param default_val default value to return if the property is not found + * @return integer value, if found, or default_val if not + */ +int fdtdec_get_config_int(const void *blob, const char *prop_name, + int default_val) +{ + int config_node; + + debug("%s: %s\n", __func__, prop_name); + config_node = fdt_path_offset(blob, "/config"); + if (config_node < 0) + return default_val; + return fdtdec_get_int(blob, config_node, prop_name, default_val); +} -- cgit v1.3.1 From 332ab0d54aaa5b8b27096996d10c8c6183c6972c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Oct 2012 16:30:59 +0000 Subject: fdt: Add function to get a config string from device tree Add a function to look up a configuration string such as board name and returns its value. We look in the "/config" node for this. Signed-off-by: Simon Glass --- include/fdtdec.h | 10 ++++++++++ lib/fdtdec.c | 28 ++++++++++++++++++---------- 2 files changed, 28 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/include/fdtdec.h b/include/fdtdec.h index d880fe8d9ed..e828662425f 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -367,6 +367,16 @@ int fdtdec_setup_gpio(struct fdt_gpio_state *gpio); int fdtdec_get_config_int(const void *blob, const char *prop_name, int default_val); +/** + * Look in the FDT for a config item with the given name and return its value + * as a string. + * + * @param blob FDT blob + * @param prop_name property name to look up + * @returns property string, NULL on error. + */ +char *fdtdec_get_config_string(const void *blob, const char *prop_name); + /* * Look up a property in a node and return its contents in a byte * array of given length. The property must have at least enough data for diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 1f500224d94..2d60c8aaafe 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -513,16 +513,6 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, return cell; } -/** - * Look in the FDT for a config item with the given name and return its value - * as a 32-bit integer. The property must have at least 4 bytes of data. The - * value of the first cell is returned. - * - * @param blob FDT blob to use - * @param prop_name Node property name - * @param default_val default value to return if the property is not found - * @return integer value, if found, or default_val if not - */ int fdtdec_get_config_int(const void *blob, const char *prop_name, int default_val) { @@ -534,3 +524,21 @@ int fdtdec_get_config_int(const void *blob, const char *prop_name, return default_val; return fdtdec_get_int(blob, config_node, prop_name, default_val); } + +char *fdtdec_get_config_string(const void *blob, const char *prop_name) +{ + const char *nodep; + int nodeoffset; + int len; + + debug("%s: %s\n", __func__, prop_name); + nodeoffset = fdt_path_offset(blob, "/config"); + if (nodeoffset < 0) + return NULL; + + nodep = fdt_getprop(blob, nodeoffset, prop_name, &len); + if (!nodep) + return NULL; + + return (char *)nodep; +} -- cgit v1.3.1 From f20c461984c3d986fde037d4c5bf600aa0497676 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Oct 2012 16:31:00 +0000 Subject: fdt: Add fdtdec_decode_region() to decode memory region A memory region has a start and a size and is often specified in a node by a 'reg' property. Add a function to decode this information from the fdt. Signed-off-by: Simon Glass --- include/fdtdec.h | 19 +++++++++++++++++++ lib/fdtdec.c | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'lib') diff --git a/include/fdtdec.h b/include/fdtdec.h index e828662425f..341e6a18a0a 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -40,10 +40,12 @@ typedef u64 fdt_addr_t; #define FDT_ADDR_T_NONE (-1ULL) #define fdt_addr_to_cpu(reg) be64_to_cpu(reg) +#define fdt_size_to_cpu(reg) be64_to_cpu(reg) #else typedef u32 fdt_addr_t; #define FDT_ADDR_T_NONE (-1U) #define fdt_addr_to_cpu(reg) be32_to_cpu(reg) +#define fdt_size_to_cpu(reg) be32_to_cpu(reg) #endif /* Information obtained about memory from the FDT */ @@ -408,4 +410,21 @@ int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, */ const u8 *fdtdec_locate_byte_array(const void *blob, int node, const char *prop_name, int count); + +/** + * Look up a property in a node which contains a memory region address and + * size. Then return a pointer to this address. + * + * The property must hold one address with a length. This is only tested on + * 32-bit machines. + * + * @param blob FDT blob + * @param node node to examine + * @param prop_name name of property to find + * @param ptrp returns pointer to region, or NULL if no address + * @param size returns size of region + * @return 0 if ok, -1 on error (propery not found) + */ +int fdtdec_decode_region(const void *blob, int node, + const char *prop_name, void **ptrp, size_t *size); #endif diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 2d60c8aaafe..557097217ce 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -542,3 +542,20 @@ char *fdtdec_get_config_string(const void *blob, const char *prop_name) return (char *)nodep; } + +int fdtdec_decode_region(const void *blob, int node, + const char *prop_name, void **ptrp, size_t *size) +{ + const fdt_addr_t *cell; + int len; + + debug("%s: %s\n", __func__, prop_name); + cell = fdt_getprop(blob, node, prop_name, &len); + if (!cell || (len != sizeof(fdt_addr_t) * 2)) + return -1; + + *ptrp = (void *)fdt_addr_to_cpu(*cell); + *size = fdt_size_to_cpu(cell[1]); + debug("%s: size=%zx\n", __func__, *size); + return 0; +} -- cgit v1.3.1 From 5921f6a2924827548caf55b28a6827b9d856e37f Mon Sep 17 00:00:00 2001 From: Abhilash Kesavan Date: Thu, 25 Oct 2012 16:31:01 +0000 Subject: fdt: Add function for decoding multiple gpios globally available Samsung's SDHCI bindings require multiple gpios to be parsed and configured at a time. Export the already available fdtdec_decode_gpios for this purpose. Signed-off-by: Abhilash Kesavan Commit-Ready: Che-Liang Chiou Signed-off-by: Simon Glass --- include/fdtdec.h | 16 ++++++++++++++++ lib/fdtdec.c | 5 ++--- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/include/fdtdec.h b/include/fdtdec.h index 341e6a18a0a..e70714b2f2c 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -344,6 +344,22 @@ int fdtdec_get_bool(const void *blob, int node, const char *prop_name); int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, struct fdt_gpio_state *gpio); +/** + * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no + * terminating item. + * + * @param blob FDT blob to use + * @param node Node to look at + * @param prop_name Node property name + * @param gpio Array of gpio elements to fill from FDT. This will be + * untouched if either 0 or an error is returned + * @param max_count Maximum number of elements allowed + * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would + * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing. + */ +int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name, + struct fdt_gpio_state *gpio, int max_count); + /** * Set up a GPIO pin according to the provided gpio information. At present this * just requests the GPIO. diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 557097217ce..32f03cc82b6 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -426,9 +426,8 @@ int fdtdec_get_bool(const void *blob, int node, const char *prop_name) * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing. */ -static int fdtdec_decode_gpios(const void *blob, int node, - const char *prop_name, struct fdt_gpio_state *gpio, - int max_count) +int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name, + struct fdt_gpio_state *gpio, int max_count) { const struct fdt_property *prop; const u32 *cell; -- cgit v1.3.1 From 7cde397b21a347134a39c40e24355a0e438adae3 Mon Sep 17 00:00:00 2001 From: Gerald Van Baren Date: Mon, 12 Nov 2012 23:13:54 -0500 Subject: fdt: Export fdtdec_lookup() and fix the name The name of this function is not consistent, so fix it, and export the function for external use. Signed-off-by: Simon Glass --- include/fdtdec.h | 13 +++++++++++++ lib/fdtdec.c | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/include/fdtdec.h b/include/fdtdec.h index e70714b2f2c..f8a4e94186d 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -109,6 +109,19 @@ struct fdt_gpio_state { int fdtdec_next_alias(const void *blob, const char *name, enum fdt_compat_id id, int *upto); +/** + * Find the compatible ID for a given node. + * + * Generally each node has at least one compatible string attached to it. + * This function looks through our list of known compatible strings and + * returns the corresponding ID which matches the compatible string. + * + * @param blob FDT blob to use + * @param node Node containing compatible string to find + * @return compatible ID, or COMPAT_UNKNOWN if we cannot find a match + */ +enum fdt_compat_id fdtdec_lookup(const void *blob, int node); + /** * Find the next compatible node for a peripheral. * diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 32f03cc82b6..96f3e7bccf4 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -128,7 +128,7 @@ int fdtdec_get_is_enabled(const void *blob, int node) return 1; } -enum fdt_compat_id fd_dec_lookup(const void *blob, int node) +enum fdt_compat_id fdtdec_lookup(const void *blob, int node) { enum fdt_compat_id id; -- cgit v1.3.1 From 79289c0b5ff4a8c7869d7ca629cddc660dd06095 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 25 Oct 2012 16:31:04 +0000 Subject: fdt: Add function to read boolean property Signed-off-by: Vincent Palatin Commit-Ready: Vincent Palatin Commit-Ready: Gabe Black Signed-off-by: Simon Glass --- include/fdtdec.h | 10 ++++++++++ lib/fdtdec.c | 14 ++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'lib') diff --git a/include/fdtdec.h b/include/fdtdec.h index f8a4e94186d..a37cf54a935 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -398,6 +398,16 @@ int fdtdec_setup_gpio(struct fdt_gpio_state *gpio); int fdtdec_get_config_int(const void *blob, const char *prop_name, int default_val); +/** + * Look in the FDT for a config item with the given name + * and return whether it exists. + * + * @param blob FDT blob + * @param prop_name property name to look up + * @return 1, if it exists, or 0 if not + */ +int fdtdec_get_config_bool(const void *blob, const char *prop_name); + /** * Look in the FDT for a config item with the given name and return its value * as a string. diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 96f3e7bccf4..da12df209c9 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -524,6 +524,20 @@ int fdtdec_get_config_int(const void *blob, const char *prop_name, return fdtdec_get_int(blob, config_node, prop_name, default_val); } +int fdtdec_get_config_bool(const void *blob, const char *prop_name) +{ + int config_node; + const void *prop; + + debug("%s: %s\n", __func__, prop_name); + config_node = fdt_path_offset(blob, "/config"); + if (config_node < 0) + return 0; + prop = fdt_get_property(blob, config_node, prop_name, NULL); + + return prop != NULL; +} + char *fdtdec_get_config_string(const void *blob, const char *prop_name) { const char *nodep; -- cgit v1.3.1 From aadef0a1bc3db81708471c9d18eb6c756659196f Mon Sep 17 00:00:00 2001 From: Che-Liang Chiou Date: Thu, 25 Oct 2012 16:31:05 +0000 Subject: fdt: Add fdtdec_get_uint64 to decode a 64-bit value from a property It decodes a 64-bit value from a property that is at least 8 bytes long. Signed-off-by: Che-Liang Chiou Signed-off-by: Simon Glass --- include/fdtdec.h | 15 +++++++++++++++ lib/fdtdec.c | 13 +++++++++++++ 2 files changed, 28 insertions(+) (limited to 'lib') diff --git a/include/fdtdec.h b/include/fdtdec.h index a37cf54a935..b5d7d2f54a2 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -181,6 +181,21 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node, s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, s32 default_val); +/** + * Look up a 64-bit integer property in a node and return it. The property + * must have at least 8 bytes of data (2 cells). The first two cells are + * concatenated to form a 8 bytes value, where the first cell is top half and + * the second cell is bottom half. + * + * @param blob FDT blob + * @param node node to examine + * @param prop_name name of property to find + * @param default_val default value to return if the property is not found + * @return integer value, if found, or default_val if not + */ +uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, + uint64_t default_val); + /** * Checks whether a node is enabled. * This looks for a 'status' property. If this exists, then returns 1 if diff --git a/lib/fdtdec.c b/lib/fdtdec.c index da12df209c9..150512e5a80 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -111,6 +111,19 @@ s32 fdtdec_get_int(const void *blob, int node, const char *prop_name, return default_val; } +uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, + uint64_t default_val) +{ + const uint64_t *cell64; + int length; + + cell64 = fdt_getprop(blob, node, prop_name, &length); + if (!cell64 || length < sizeof(*cell64)) + return default_val; + + return fdt64_to_cpu(*cell64); +} + int fdtdec_get_is_enabled(const void *blob, int node) { const char *cell; -- cgit v1.3.1 From 202ff7537558edfd759b400cfe9e56c56fc7868c Mon Sep 17 00:00:00 2001 From: Sean Paul Date: Thu, 25 Oct 2012 16:31:06 +0000 Subject: fdt: Add polarity-aware gpio functions to fdtdec Add get and set gpio functions to fdtdec that take into account the polarity field in fdtdec_gpio_state.flags. Signed-off-by: Sean Paul Signed-off-by: Simon Glass --- include/fdtdec.h | 16 ++++++++++++++++ lib/fdtdec.c | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+) (limited to 'lib') diff --git a/include/fdtdec.h b/include/fdtdec.h index b5d7d2f54a2..5164ce24e61 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -89,6 +89,22 @@ struct fdt_gpio_state { /* This tells us whether a fdt_gpio_state record is valid or not */ #define fdt_gpio_isvalid(x) ((x)->gpio != FDT_GPIO_NONE) +/** + * Read the GPIO taking into account the polarity of the pin. + * + * @param gpio pointer to the decoded gpio + * @return value of the gpio if successful, < 0 if unsuccessful + */ +int fdtdec_get_gpio(struct fdt_gpio_state *gpio); + +/** + * Write the GPIO taking into account the polarity of the pin. + * + * @param gpio pointer to the decoded gpio + * @return 0 if successful + */ +int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val); + /** * Find the next numbered alias for a peripheral. This is used to enumerate * all the peripherals of a certain type. diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 150512e5a80..e1b17a5fe58 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -487,6 +487,26 @@ int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name, return err == 1 ? 0 : err; } +int fdtdec_get_gpio(struct fdt_gpio_state *gpio) +{ + int val; + + if (!fdt_gpio_isvalid(gpio)) + return -1; + + val = gpio_get_value(gpio->gpio); + return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; +} + +int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val) +{ + if (!fdt_gpio_isvalid(gpio)) + return -1; + + val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val; + return gpio_set_value(gpio->gpio, val); +} + int fdtdec_setup_gpio(struct fdt_gpio_state *gpio) { /* -- cgit v1.3.1 From 008784765ab7f37fb355d5f7fb180661b94c42ab Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 31 Oct 2012 14:02:42 +0000 Subject: fdt: Remove fdtdec_find_alias_node() function This function is not needed, since fdt_path_offset() performs the same service. Remove it. Signed-off-by: Simon Glass --- lib/fdtdec.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) (limited to 'lib') diff --git a/lib/fdtdec.c b/lib/fdtdec.c index e1b17a5fe58..348144aa705 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -52,28 +52,6 @@ const char *fdtdec_get_compatible(enum fdt_compat_id id) return compat_names[id]; } -/** - * Look in the FDT for an alias with the given name and return its node. - * - * @param blob FDT blob - * @param name alias name to look up - * @return node offset if found, or an error code < 0 otherwise - */ -static int find_alias_node(const void *blob, const char *name) -{ - const char *path; - int alias_node; - - debug("find_alias_node: %s\n", name); - alias_node = fdt_path_offset(blob, "/aliases"); - if (alias_node < 0) - return alias_node; - path = fdt_getprop(blob, alias_node, name, NULL); - if (!path) - return -FDT_ERR_NOTFOUND; - return fdt_path_offset(blob, path); -} - fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name) { @@ -184,7 +162,7 @@ int fdtdec_next_alias(const void *blob, const char *name, /* snprintf() is not available */ assert(strlen(name) < MAX_STR_LEN); sprintf(str, "%.*s%d", MAX_STR_LEN, name, *upto); - node = find_alias_node(blob, str); + node = fdt_path_offset(blob, str); if (node < 0) return node; err = fdt_node_check_compatible(blob, node, compat_names[id]); -- cgit v1.3.1 From 5fe8380db3d5cd9f6c155f800616bdcb6dd34d18 Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Sat, 3 Nov 2012 11:45:19 +0000 Subject: lzma: update to lzma sdk 9.20 Updated code taken from latest lzma sdk release 9.20 at http://downloads.sourceforge.net/sevenzip/lzma920.tar.bz2 This generates quite a lot of checkpatch warnings, but I guess we need to keep the code style as is to avoid a massive job each time we update this. Signed-off-by: Stefan Reinauer Signed-off-by: Simon Glass --- lib/lzma/LzmaDec.c | 14 +++----------- lib/lzma/LzmaDec.h | 6 +++--- lib/lzma/Types.h | 36 +++++++++++++++++++++++++++++++----- lib/lzma/history.txt | 35 +++++++++++++++++++++++++++++++++++ lib/lzma/lzma.txt | 34 +++++++++++++++++++--------------- 5 files changed, 91 insertions(+), 34 deletions(-) (limited to 'lib') diff --git a/lib/lzma/LzmaDec.c b/lib/lzma/LzmaDec.c index f941da27dd0..4f45f80fe26 100644 --- a/lib/lzma/LzmaDec.c +++ b/lib/lzma/LzmaDec.c @@ -1,5 +1,5 @@ /* LzmaDec.c -- LZMA Decoder -2008-11-06 : Igor Pavlov : Public domain */ +2009-09-20 : Igor Pavlov : Public domain */ #include #include @@ -116,12 +116,6 @@ StopCompilingDueBUG #endif -static const Byte kLiteralNextStates[kNumStates * 2] = -{ - 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5, - 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10 -}; - #define LZMA_DIC_MIN (1 << 12) /* First LZMA-symbol is always decoded. @@ -180,6 +174,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte if (state < kNumLitStates) { + state -= (state < 4) ? state : 3; symbol = 1; WATCHDOG_RESET(); @@ -190,6 +185,7 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte { unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; symbol = 1; WATCHDOG_RESET(); @@ -207,9 +203,6 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte } dic[dicPos++] = (Byte)symbol; processedPos++; - - state = kLiteralNextStates[state]; - /* if (state < 4) state = 0; else if (state < 10) state -= 3; else state -= 6; */ continue; } else @@ -395,7 +388,6 @@ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte else if (distance >= checkDicSize) return SZ_ERROR_DATA; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; - /* state = kLiteralNextStates[state]; */ } len += kMatchMinLen; diff --git a/lib/lzma/LzmaDec.h b/lib/lzma/LzmaDec.h index 7fba87f076e..63aa505e8ca 100644 --- a/lib/lzma/LzmaDec.h +++ b/lib/lzma/LzmaDec.h @@ -1,8 +1,8 @@ /* LzmaDec.h -- LZMA Decoder -2008-10-04 : Igor Pavlov : Public domain */ +2009-02-07 : Igor Pavlov : Public domain */ -#ifndef __LZMADEC_H -#define __LZMADEC_H +#ifndef __LZMA_DEC_H +#define __LZMA_DEC_H #include "Types.h" diff --git a/lib/lzma/Types.h b/lib/lzma/Types.h index 1af5cfc4d86..8afcba556eb 100644 --- a/lib/lzma/Types.h +++ b/lib/lzma/Types.h @@ -1,5 +1,5 @@ /* Types.h -- Basic types -2008-11-23 : Igor Pavlov : Public domain */ +2010-10-09 : Igor Pavlov : Public domain */ #ifndef __7Z_TYPES_H #define __7Z_TYPES_H @@ -65,9 +65,11 @@ typedef unsigned long UInt64; #if defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 Int64; typedef unsigned __int64 UInt64; +#define UINT64_CONST(n) n #else typedef long long int Int64; typedef unsigned long long int UInt64; +#define UINT64_CONST(n) n ## ULL #endif #endif @@ -92,13 +94,11 @@ typedef int Bool; #endif #define MY_CDECL __cdecl -#define MY_STD_CALL __stdcall -#define MY_FAST_CALL MY_NO_INLINE __fastcall +#define MY_FAST_CALL __fastcall #else #define MY_CDECL -#define MY_STD_CALL #define MY_FAST_CALL #endif @@ -106,6 +106,16 @@ typedef int Bool; /* The following interfaces use first parameter as pointer to structure */ +typedef struct +{ + Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ +} IByteIn; + +typedef struct +{ + void (*Write)(void *p, Byte b); +} IByteOut; + typedef struct { SRes (*Read)(void *p, void *buf, size_t *size); @@ -140,7 +150,7 @@ typedef struct typedef struct { - SRes (*Look)(void *p, void **buf, size_t *size); + SRes (*Look)(void *p, const void **buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) > input(*size)) is not allowed (output(*size) < input(*size)) is allowed */ @@ -205,4 +215,20 @@ typedef struct #define IAlloc_Alloc(p, size) (p)->Alloc((p), size) #define IAlloc_Free(p, a) (p)->Free((p), a) +#ifdef _WIN32 + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#endif + #endif diff --git a/lib/lzma/history.txt b/lib/lzma/history.txt index aadf8255edb..443511bdd49 100644 --- a/lib/lzma/history.txt +++ b/lib/lzma/history.txt @@ -1,6 +1,41 @@ HISTORY of the LZMA SDK ----------------------- +9.18 beta 2010-11-02 +------------------------- +- New small SFX module for installers (SfxSetup). + + +9.12 beta 2010-03-24 +------------------------- +- The BUG in LZMA SDK 9.* was fixed: LZMA2 codec didn't work, + if more than 10 threads were used (or more than 20 threads in some modes). + + +9.11 beta 2010-03-15 +------------------------- +- PPMd compression method support + + +9.09 2009-12-12 +------------------------- +- The bug was fixed: + Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c + incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8. +- Some bugs were fixed + + +9.06 2009-08-17 +------------------------- +- Some changes in ANSI-C 7z Decoder interfaces. + + +9.04 2009-05-30 +------------------------- +- LZMA2 compression method support +- xz format support + + 4.65 2009-02-03 ------------------------- - Some minor fixes diff --git a/lib/lzma/lzma.txt b/lib/lzma/lzma.txt index aa20f9dc5ce..144cd9aee2e 100644 --- a/lib/lzma/lzma.txt +++ b/lib/lzma/lzma.txt @@ -1,4 +1,4 @@ -LZMA SDK 4.65 +LZMA SDK 9.20 ------------- LZMA SDK provides the documentation, samples, header files, libraries, @@ -20,6 +20,10 @@ LICENSE LZMA SDK is written and placed in the public domain by Igor Pavlov. +Some code in LZMA SDK is based on public domain code from another developers: + 1) PPMd var.H (2001): Dmitry Shkarin + 2) SHA-256: Wei Dai (Crypto++ library) + LZMA SDK Contents ----------------- @@ -33,7 +37,7 @@ LZMA SDK includes: UNIX/Linux version ------------------ To compile C++ version of file->file LZMA encoding, go to directory -C++/7zip/Compress/LZMA_Alone +CPP/7zip/Bundles/LzmaCon and call make to recompile it: make -f makefile.gcc clean all @@ -49,6 +53,7 @@ lzma.txt - LZMA SDK description (this file) 7zC.txt - 7z ANSI-C Decoder description methods.txt - Compression method IDs for .7z lzma.exe - Compiled file->file LZMA encoder/decoder for Windows +7zr.exe - 7-Zip with 7z/lzma/xz support. history.txt - history of the LZMA SDK @@ -66,7 +71,7 @@ C/ - C files LzmaEnc.* - LZMA encoding LzmaLib.* - LZMA Library for DLL calling Types.h - Basic types for another .c files - Threads.* - The code for multithreading. + Threads.* - The code for multithreading. LzmaLib - LZMA Library (.DLL for Windows) @@ -86,12 +91,6 @@ CPP/ -- CPP files Compress - files related to compression/decompression - Copy - Copy coder - RangeCoder - Range Coder (special code of compression/decompression) - LZMA - LZMA compression/decompression on C++ - LZMA_Alone - file->file LZMA compression/decompression - Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code - Archive - files related to archiving Common - common files for archive handling @@ -100,6 +99,7 @@ CPP/ -- CPP files Bundles - Modules that are bundles of other modules Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2 + LzmaCon - lzma.exe: LZMA compression/decompression Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2 Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2. @@ -369,8 +369,8 @@ Interface: propData - LZMA properties (5 bytes) propSize - size of propData buffer (5 bytes) finishMode - It has meaning only if the decoding reaches output limit (*destLen). - LZMA_FINISH_ANY - Decode just destLen bytes. - LZMA_FINISH_END - Stream must be finished after (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). You can use LZMA_FINISH_END, when you know that current output buffer covers last bytes of stream. alloc - Memory allocator. @@ -431,7 +431,7 @@ Memory Requirements: { ... int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, - const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode); + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode); ... } @@ -527,7 +527,8 @@ static ISzAlloc g_Alloc = { SzAlloc, SzFree }; LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc); -If callback function return some error code, LzmaEnc_Encode also returns that code. +If callback function return some error code, LzmaEnc_Encode also returns that code +or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS. Single-call RAM->RAM Compression @@ -549,8 +550,8 @@ Return code: -LZMA Defines ------------- +Defines +------- _LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code. @@ -562,6 +563,9 @@ _LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is _LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type. +_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder. + + C++ LZMA Encoder/Decoder ~~~~~~~~~~~~~~~~~~~~~~~~ C++ LZMA code use COM-like interfaces. So if you want to use it, -- cgit v1.3.1 From 40fef0490610686022f99b8e070df7ac761c11a0 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 2 Dec 2012 04:55:18 +0000 Subject: Introduce arch_phys_memset which works like memset but on physical memory The default implementation of this function is just memset, but other implementations will be needed when physical memory isn't accessible by U-Boot using normal addressing mechanisms. Signed-off-by: Gabe Black Signed-off-by: Che-Liang Chiou Signed-off-by: Simon Glass --- README | 8 ++++++++ include/physmem.h | 21 +++++++++++++++++++++ lib/Makefile | 1 + lib/physmem.c | 24 ++++++++++++++++++++++++ 4 files changed, 54 insertions(+) create mode 100644 include/physmem.h create mode 100644 lib/physmem.c (limited to 'lib') diff --git a/README b/README index ed7d270adb7..c7aab18efad 100644 --- a/README +++ b/README @@ -2200,6 +2200,14 @@ CBFS (Coreboot Filesystem) support HERMES, IP860, RPXlite, LWMON, FLAGADM, TQM8260 +- Access to physical memory region (> 4GB) + Some basic support is provided for operations on memory not + normally accessible to U-Boot - e.g. some architectures + support access to more than 4GB of memory on 32-bit + machines using physical address extension or similar. + Define CONFIG_PHYSMEM to access this basic support, which + currently only supports clearing the memory. + - Error Recovery: CONFIG_PANIC_HANG diff --git a/include/physmem.h b/include/physmem.h new file mode 100644 index 00000000000..03d3a78b741 --- /dev/null +++ b/include/physmem.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +/* + * These functions work like memset but operate on physical memory which may + * not be accessible directly. + * + * @param s The physical address to start setting memory at. + * @param c The character to set each byte of the region to. + * @param n The number of bytes to set. + * + * @return The physical address of the memory which was set. + */ +phys_addr_t arch_phys_memset(phys_addr_t s, int c, phys_size_t n); diff --git a/lib/Makefile b/lib/Makefile index e44e0452331..f83f6e8d8c5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -48,6 +48,7 @@ COBJS-$(CONFIG_LMB) += lmb.o COBJS-y += ldiv.o COBJS-$(CONFIG_MD5) += md5.o COBJS-y += net_utils.o +COBJS-$(CONFIG_PHYSMEM) += physmem.o COBJS-y += qsort.o COBJS-$(CONFIG_SHA1) += sha1.o COBJS-$(CONFIG_SHA256) += sha256.o diff --git a/lib/physmem.c b/lib/physmem.c new file mode 100644 index 00000000000..0f035edcbe5 --- /dev/null +++ b/lib/physmem.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +#include +#include + +static phys_addr_t __arch_phys_memset(phys_addr_t s, int c, phys_size_t n) +{ + void *s_ptr = (void *)(uintptr_t)s; + + assert(((phys_addr_t)(uintptr_t)s) == s); + assert(((phys_addr_t)(uintptr_t)(s + n)) == s + n); + return (phys_addr_t)(uintptr_t)memset(s_ptr, c, n); +} + +phys_addr_t arch_phys_memset(phys_addr_t s, int c, phys_size_t n) + __attribute__((weak, alias("__arch_phys_memset"))); -- cgit v1.3.1 From a7d1d765793a05c0d6f7547122339dbecc94f6c3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Dec 2012 14:46:33 +0000 Subject: sha1: Use const where possible, and unsigned for input len In preparation for making the hash function common, we may as well use const where we can. Also the input length cannot be negative, but may be very large, so use unsigned. Signed-off-by: Simon Glass --- include/sha1.h | 26 +++++++++----------------- lib/sha1.c | 19 +++++++++++-------- 2 files changed, 20 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/include/sha1.h b/include/sha1.h index 734d1fb153d..da09dab9769 100644 --- a/include/sha1.h +++ b/include/sha1.h @@ -59,7 +59,8 @@ void sha1_starts( sha1_context *ctx ); * \param input buffer holding the data * \param ilen length of the input data */ -void sha1_update( sha1_context *ctx, unsigned char *input, int ilen ); +void sha1_update(sha1_context *ctx, const unsigned char *input, + unsigned int ilen); /** * \brief SHA-1 final digest @@ -76,8 +77,8 @@ void sha1_finish( sha1_context *ctx, unsigned char output[20] ); * \param ilen length of the input data * \param output SHA-1 checksum result */ -void sha1_csum( unsigned char *input, int ilen, - unsigned char output[20] ); +void sha1_csum(const unsigned char *input, unsigned int ilen, + unsigned char *output); /** * \brief Output = SHA-1( input buffer ), with watchdog triggering @@ -87,17 +88,8 @@ void sha1_csum( unsigned char *input, int ilen, * \param output SHA-1 checksum result * \param chunk_sz watchdog triggering period (in bytes of input processed) */ -void sha1_csum_wd (unsigned char *input, int ilen, - unsigned char output[20], unsigned int chunk_sz); - -/** - * \brief Output = SHA-1( file contents ) - * - * \param path input file name - * \param output SHA-1 checksum result - * \return 0 if successful, or 1 if fopen failed - */ -int sha1_file( char *path, unsigned char output[20] ); +void sha1_csum_wd(const unsigned char *input, unsigned int ilen, + unsigned char *output, unsigned int chunk_sz); /** * \brief Output = HMAC-SHA-1( input buffer, hmac key ) @@ -108,9 +100,9 @@ int sha1_file( char *path, unsigned char output[20] ); * \param ilen length of the input data * \param output HMAC-SHA-1 result */ -void sha1_hmac( unsigned char *key, int keylen, - unsigned char *input, int ilen, - unsigned char output[20] ); +void sha1_hmac(const unsigned char *key, int keylen, + const unsigned char *input, unsigned int ilen, + unsigned char *output); /** * \brief Checkup routine diff --git a/lib/sha1.c b/lib/sha1.c index da5bc16f3c6..a121224855f 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -73,7 +73,7 @@ void sha1_starts (sha1_context * ctx) ctx->state[4] = 0xC3D2E1F0; } -static void sha1_process (sha1_context * ctx, unsigned char data[64]) +static void sha1_process(sha1_context *ctx, const unsigned char data[64]) { unsigned long temp, W[16], A, B, C, D, E; @@ -230,7 +230,8 @@ static void sha1_process (sha1_context * ctx, unsigned char data[64]) /* * SHA-1 process buffer */ -void sha1_update (sha1_context * ctx, unsigned char *input, int ilen) +void sha1_update(sha1_context *ctx, const unsigned char *input, + unsigned int ilen) { int fill; unsigned long left; @@ -305,7 +306,8 @@ void sha1_finish (sha1_context * ctx, unsigned char output[20]) /* * Output = SHA-1( input buffer ) */ -void sha1_csum (unsigned char *input, int ilen, unsigned char output[20]) +void sha1_csum(const unsigned char *input, unsigned int ilen, + unsigned char *output) { sha1_context ctx; @@ -318,12 +320,12 @@ void sha1_csum (unsigned char *input, int ilen, unsigned char output[20]) * Output = SHA-1( input buffer ). Trigger the watchdog every 'chunk_sz' * bytes of input processed. */ -void sha1_csum_wd (unsigned char *input, int ilen, unsigned char output[20], - unsigned int chunk_sz) +void sha1_csum_wd(const unsigned char *input, unsigned int ilen, + unsigned char *output, unsigned int chunk_sz) { sha1_context ctx; #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) - unsigned char *end, *curr; + const unsigned char *end, *curr; int chunk; #endif @@ -350,8 +352,9 @@ void sha1_csum_wd (unsigned char *input, int ilen, unsigned char output[20], /* * Output = HMAC-SHA-1( input buffer, hmac key ) */ -void sha1_hmac (unsigned char *key, int keylen, - unsigned char *input, int ilen, unsigned char output[20]) +void sha1_hmac(const unsigned char *key, int keylen, + const unsigned char *input, unsigned int ilen, + unsigned char *output) { int i; sha1_context ctx; -- cgit v1.3.1 From ec7381fbf6f77cc465eb06a1ab6f8a99df1e487c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Dec 2012 14:46:34 +0000 Subject: sha256: Use const where possible and add watchdog function In preparation for making the hash function common, we may as well use const where we can. Also add a watchdog version of the hashing function. Signed-off-by: Simon Glass --- include/sha256.h | 8 +++++++- lib/sha256.c | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/include/sha256.h b/include/sha256.h index e38ea898c3e..beadab35ffc 100644 --- a/include/sha256.h +++ b/include/sha256.h @@ -3,6 +3,9 @@ #define SHA256_SUM_LEN 32 +/* Reset watchdog each time we process this many bytes */ +#define CHUNKSZ_SHA256 (64 * 1024) + typedef struct { uint32_t total[2]; uint32_t state[8]; @@ -10,7 +13,10 @@ typedef struct { } sha256_context; void sha256_starts(sha256_context * ctx); -void sha256_update(sha256_context * ctx, uint8_t * input, uint32_t length); +void sha256_update(sha256_context *ctx, const uint8_t *input, uint32_t length); void sha256_finish(sha256_context * ctx, uint8_t digest[SHA256_SUM_LEN]); +void sha256_csum_wd(const unsigned char *input, unsigned int ilen, + unsigned char *output, unsigned int chunk_sz); + #endif /* _SHA256_H */ diff --git a/lib/sha256.c b/lib/sha256.c index deb63a40b6d..ab2db4890ae 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -60,7 +60,7 @@ void sha256_starts(sha256_context * ctx) ctx->state[7] = 0x5BE0CD19; } -void sha256_process(sha256_context * ctx, uint8_t data[64]) +static void sha256_process(sha256_context *ctx, const uint8_t data[64]) { uint32_t temp1, temp2; uint32_t W[64]; @@ -191,7 +191,7 @@ void sha256_process(sha256_context * ctx, uint8_t data[64]) ctx->state[7] += H; } -void sha256_update(sha256_context * ctx, uint8_t * input, uint32_t length) +void sha256_update(sha256_context *ctx, const uint8_t *input, uint32_t length) { uint32_t left, fill; @@ -260,3 +260,36 @@ void sha256_finish(sha256_context * ctx, uint8_t digest[32]) PUT_UINT32_BE(ctx->state[6], digest, 24); PUT_UINT32_BE(ctx->state[7], digest, 28); } + +/* + * Output = SHA-256( input buffer ). Trigger the watchdog every 'chunk_sz' + * bytes of input processed. + */ +void sha256_csum_wd(const unsigned char *input, unsigned int ilen, + unsigned char *output, unsigned int chunk_sz) +{ + sha256_context ctx; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + unsigned char *end, *curr; + int chunk; +#endif + + sha256_starts(&ctx); + +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + curr = input; + end = input + ilen; + while (curr < end) { + chunk = end - curr; + if (chunk > chunk_sz) + chunk = chunk_sz; + sha256_update(&ctx, curr, chunk); + curr += chunk; + WATCHDOG_RESET(); + } +#else + sha256_update(&ctx, input, ilen); +#endif + + sha256_finish(&ctx, output); +} -- cgit v1.3.1 From b1f17bf5ff63a7e22e0299dd576c3b6cd38ae665 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 5 Dec 2012 14:46:35 +0000 Subject: Add strcasecmp() and strncasecmp() strncasecmp() is present as strnicmp() but disabled. Make it available and define strcasecmp() also. There is a only a small performance penalty to having strcasecmp() call strncasecmp(), so do this instead of a standalone function, to save code space. Update the prototype in arch-specific headers as needed to avoid warnings. Signed-off-by: Simon Glass --- arch/m68k/include/asm/string.h | 2 +- arch/powerpc/include/asm/string.h | 2 +- arch/sparc/include/asm/string.h | 2 +- include/linux/string.h | 7 +++++-- lib/string.c | 16 ++++++++++++---- 5 files changed, 20 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/arch/m68k/include/asm/string.h b/arch/m68k/include/asm/string.h index e0773a88285..ecf5e56e107 100644 --- a/arch/m68k/include/asm/string.h +++ b/arch/m68k/include/asm/string.h @@ -16,7 +16,7 @@ #endif extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, int); +extern int strncasecmp(const char *, const char *, __kernel_size_t); extern char * strcpy(char *,const char *); extern char * strncpy(char *,const char *, __kernel_size_t); extern __kernel_size_t strlen(const char *); diff --git a/arch/powerpc/include/asm/string.h b/arch/powerpc/include/asm/string.h index d912a6b5fed..036805ede29 100644 --- a/arch/powerpc/include/asm/string.h +++ b/arch/powerpc/include/asm/string.h @@ -14,7 +14,7 @@ #define __HAVE_ARCH_MEMCHR extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, int); +extern int strncasecmp(const char *, const char *, __kernel_size_t); extern char * strcpy(char *,const char *); extern char * strncpy(char *,const char *, __kernel_size_t); extern __kernel_size_t strlen(const char *); diff --git a/arch/sparc/include/asm/string.h b/arch/sparc/include/asm/string.h index c6bbc203d5d..af6faea234c 100644 --- a/arch/sparc/include/asm/string.h +++ b/arch/sparc/include/asm/string.h @@ -40,7 +40,7 @@ */ extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, int); +extern int strncasecmp(const char *, const char *, __kernel_size_t); extern char *strcpy(char *, const char *); extern char *strncpy(char *, const char *, __kernel_size_t); extern __kernel_size_t strlen(const char *); diff --git a/include/linux/string.h b/include/linux/string.h index 9a8cbc24cdc..de833554a1d 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -38,8 +38,11 @@ extern int strcmp(const char *,const char *); #ifndef __HAVE_ARCH_STRNCMP extern int strncmp(const char *,const char *,__kernel_size_t); #endif -#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ -extern int strnicmp(const char *, const char *, __kernel_size_t); +#ifndef __HAVE_ARCH_STRCASECMP +int strcasecmp(const char *s1, const char *s2); +#endif +#ifndef __HAVE_ARCH_STRNCASECMP +extern int strncasecmp(const char *s1, const char *s2, __kernel_size_t len); #endif #ifndef __HAVE_ARCH_STRCHR extern char * strchr(const char *,int); diff --git a/lib/string.c b/lib/string.c index c3ad055e2ca..68f60bea125 100644 --- a/lib/string.c +++ b/lib/string.c @@ -21,14 +21,13 @@ #include -#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ /** - * strnicmp - Case insensitive, length-limited string comparison + * strncasecmp - Case insensitive, length-limited string comparison * @s1: One string * @s2: The other string * @len: the maximum number of characters to compare */ -int strnicmp(const char *s1, const char *s2, size_t len) +int strncasecmp(const char *s1, const char *s2, size_t len) { /* Yes, Virginia, it had better be unsigned */ unsigned char c1, c2; @@ -52,7 +51,16 @@ int strnicmp(const char *s1, const char *s2, size_t len) } return (int)c1 - (int)c2; } -#endif + +/** + * strcasecmp - Case insensitive string comparison + * @s1: One string + * @s2: The other string + */ +int strcasecmp(const char *s1, const char *s2) +{ + return strncasecmp(s1, s2, -1U); +} char * ___strtok; -- cgit v1.3.1 From 3ec44111aa33f568493f565285a3a519ef38e1dc Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Tue, 11 Dec 2012 11:09:42 +0100 Subject: vsprintf:fix: Change type returned by ustrtoul The ustrtoul shall convert string defined size (e.g. 1GiB) to unsigned long type (as its name implies). Up till now it had returned int, which might cause problems with large numbers (GiB range), when interpreted as U2 signed numbers. Signed-off-by: Lukasz Majewski Signed-off-by: Kyungmin Park --- include/exports.h | 2 +- lib/vsprintf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/include/exports.h b/include/exports.h index 63aa4b264a1..6cf31aa5e79 100644 --- a/include/exports.h +++ b/include/exports.h @@ -23,7 +23,7 @@ char *getenv (const char *name); int setenv (const char *varname, const char *varvalue); long simple_strtol(const char *cp,char **endp,unsigned int base); int strcmp(const char * cs,const char * ct); -int ustrtoul(const char *cp, char **endp, unsigned int base); +unsigned long ustrtoul(const char *cp, char **endp, unsigned int base); #if defined(CONFIG_CMD_I2C) int i2c_write (uchar, uint, int , uchar* , int); int i2c_read (uchar, uint, int , uchar* , int); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index b7a79c0e0c9..3c432f8764f 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -103,7 +103,7 @@ long simple_strtol(const char *cp, char **endp, unsigned int base) return simple_strtoul(cp, endp, base); } -int ustrtoul(const char *cp, char **endp, unsigned int base) +unsigned long ustrtoul(const char *cp, char **endp, unsigned int base) { unsigned long result = simple_strtoul(cp, endp, base); switch (**endp) { -- cgit v1.3.1 From e772cb30f649c1bb8c9cb15e4c05cbf0760f2f61 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:18 -0600 Subject: Make linux kernel string funcs available to tools isspace() and strim() are not in the typical user-mode string.h, so put them in a separate compilation unit so that they can be built into tools that need them independent of the other common string functions. This allows code shared by u-boot and the linux user-mode tools to link. Signed-off-by: Joe Hershberger --- include/linux/linux_string.h | 8 +++++++ include/linux/string.h | 5 +---- lib/Makefile | 1 + lib/linux_string.c | 51 ++++++++++++++++++++++++++++++++++++++++++++ lib/string.c | 39 --------------------------------- 5 files changed, 61 insertions(+), 43 deletions(-) create mode 100644 include/linux/linux_string.h create mode 100644 lib/linux_string.c (limited to 'lib') diff --git a/include/linux/linux_string.h b/include/linux/linux_string.h new file mode 100644 index 00000000000..192b4c9beac --- /dev/null +++ b/include/linux/linux_string.h @@ -0,0 +1,8 @@ +#ifndef _LINUX_LINUX_STRING_H_ +#define _LINUX_LINUX_STRING_H_ + +extern char * skip_spaces(const char *); + +extern char *strim(char *); + +#endif diff --git a/include/linux/string.h b/include/linux/string.h index de833554a1d..e9b134d1428 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -50,10 +50,7 @@ extern char * strchr(const char *,int); #ifndef __HAVE_ARCH_STRRCHR extern char * strrchr(const char *,int); #endif -extern char * skip_spaces(const char *); - -extern char *strim(char *); - +#include #ifndef __HAVE_ARCH_STRSTR extern char * strstr(const char *,const char *); #endif diff --git a/lib/Makefile b/lib/Makefile index f83f6e8d8c5..86ca1a6ec1d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -69,6 +69,7 @@ endif COBJS-y += crc32.o COBJS-y += ctype.o COBJS-y += div64.o +COBJS-y += linux_string.o COBJS-y += string.o COBJS-y += time.o COBJS-$(CONFIG_BOOTP_PXE) += uuid.o diff --git a/lib/linux_string.c b/lib/linux_string.c new file mode 100644 index 00000000000..d5a5e08d98c --- /dev/null +++ b/lib/linux_string.c @@ -0,0 +1,51 @@ +/* + * linux/lib/string.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifdef USE_HOSTCC +#include +#endif + +#include +#include + +/** + * skip_spaces - Removes leading whitespace from @str. + * @str: The string to be stripped. + * + * Returns a pointer to the first non-whitespace character in @str. + */ +char *skip_spaces(const char *str) +{ + while (isspace(*str)) + ++str; + return (char *)str; +} + +/** + * strim - Removes leading and trailing whitespace from @s. + * @s: The string to be stripped. + * + * Note that the first trailing whitespace is replaced with a %NUL-terminator + * in the given string @s. Returns a pointer to the first non-whitespace + * character in @s. + */ +char *strim(char *s) +{ + size_t size; + char *end; + + s = skip_spaces(s); + size = strlen(s); + if (!size) + return s; + + end = s + size - 1; + while (end >= s && isspace(*end)) + end--; + *(end + 1) = '\0'; + + return s; +} diff --git a/lib/string.c b/lib/string.c index 68f60bea125..09dfae03c24 100644 --- a/lib/string.c +++ b/lib/string.c @@ -222,45 +222,6 @@ char * strrchr(const char * s, int c) } #endif - -/** - * skip_spaces - Removes leading whitespace from @str. - * @str: The string to be stripped. - * - * Returns a pointer to the first non-whitespace character in @str. - */ -char *skip_spaces(const char *str) -{ - while (isspace(*str)) - ++str; - return (char *)str; -} - -/** - * strim - Removes leading and trailing whitespace from @s. - * @s: The string to be stripped. - * - * Note that the first trailing whitespace is replaced with a %NUL-terminator - * in the given string @s. Returns a pointer to the first non-whitespace - * character in @s. - */ -char *strim(char *s) -{ - size_t size; - char *end; - - s = skip_spaces(s); - size = strlen(s); - if (!size) - return s; - - end = s + size - 1; - while (end >= s && isspace(*end)) - end--; - *(end + 1) = '\0'; - - return s; -} #ifndef __HAVE_ARCH_STRLEN /** * strlen - Find the length of a string -- cgit v1.3.1 From c4e0057fa78ebb524b9241ad7245fcd1074ba414 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:19 -0600 Subject: env: Refactor do_apply to a flag Use a flag in hsearch_r for insert mode passed from import to allow the behavior be different based on use. Now that "do_check" is called for all imports, ensure console init is complete before updating the console on relocation import Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 19 +++++++++---------- common/console.c | 8 ++++---- common/env_common.c | 26 ++++++++------------------ include/search.h | 15 ++++++++------- lib/hashtable.c | 37 ++++++++++++++++++++----------------- 5 files changed, 49 insertions(+), 56 deletions(-) (limited to 'lib') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 006131f45c1..a8dc9a694d9 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -116,7 +116,7 @@ static int env_print(char *name) e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab); + hsearch_r(e, FIND, &ep, &env_htab, 0); if (ep == NULL) return 0; len = printf("%s=%s\n", ep->key, ep->data); @@ -224,7 +224,7 @@ int env_check_apply(const char *name, const char *oldval, else if (strcmp(name, "stderr") == 0) console = stderr; - if (console != -1) { + if (console != -1 && (gd->flags & GD_FLG_DEVINIT) != 0) { if ((newval == NULL) || (*newval == '\0')) { /* We cannot delete stdin/stdout/stderr */ if ((flag & H_FORCE) == 0) @@ -344,20 +344,19 @@ static int _do_env_set(int flag, int argc, char * const argv[]) */ e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab); + hsearch_r(e, FIND, &ep, &env_htab, 0); /* - * Perform requested checks. Notice how since we are overwriting - * a single variable, we need to set H_NOCLEAR + * Perform requested checks. */ - if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) { + if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) { debug("check function did not approve, refusing\n"); return 1; } /* Delete only ? */ if (argc < 3 || argv[2] == NULL) { - int rc = hdelete_r(name, &env_htab, 0); + int rc = hdelete_r(name, &env_htab, H_INTERACTIVE); return !rc; } @@ -384,7 +383,7 @@ static int _do_env_set(int flag, int argc, char * const argv[]) e.key = name; e.data = value; - hsearch_r(e, ENTER, &ep, &env_htab); + hsearch_r(e, ENTER, &ep, &env_htab, H_INTERACTIVE); free(value); if (!ep) { printf("## Error inserting \"%s\" variable, errno=%d\n", @@ -552,7 +551,7 @@ char *getenv(const char *name) e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab); + hsearch_r(e, FIND, &ep, &env_htab, 0); return ep ? ep->data : NULL; } @@ -951,7 +950,7 @@ static int do_env_import(cmd_tbl_t *cmdtp, int flag, } if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR, - 0, NULL, 0 /* do_apply */) == 0) { + 0, NULL) == 0) { error("Environment import failed: errno = %d\n", errno); return 1; } diff --git a/common/console.c b/common/console.c index 25b141a325a..c21934d1b8a 100644 --- a/common/console.c +++ b/common/console.c @@ -681,8 +681,6 @@ int console_init_r(void) done: #endif - gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ - #ifndef CONFIG_SYS_CONSOLE_INFO_QUIET stdio_print_current_devices(); #endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */ @@ -694,6 +692,8 @@ done: } #endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */ + gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ + #if 0 /* If nothing usable installed, use only the initial console */ if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) @@ -758,8 +758,6 @@ int console_init_r(void) #endif } - gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ - #ifndef CONFIG_SYS_CONSOLE_INFO_QUIET stdio_print_current_devices(); #endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */ @@ -769,6 +767,8 @@ int console_init_r(void) setenv(stdio_names[i], stdio_devices[i]->name); } + gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ + #if 0 /* If nothing usable installed, use only the initial console */ if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) diff --git a/common/env_common.c b/common/env_common.c index 3d3cb70a6d6..f22f5b968ef 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -83,11 +83,8 @@ const uchar *env_get_addr(int index) void set_default_env(const char *s) { - /* - * By default, do not apply changes as they will eventually - * be applied by someone else - */ - int do_apply = 0; + int flags = 0; + if (sizeof(default_environment) > ENV_SIZE) { puts("*** Error - default environment is too large\n\n"); return; @@ -99,14 +96,7 @@ void set_default_env(const char *s) "using default environment\n\n", s + 1); } else { - /* - * This set_to_default was explicitly asked for - * by the user, as opposed to being a recovery - * mechanism. Therefore we check every single - * variable and apply changes to the system - * right away (e.g. baudrate, console). - */ - do_apply = 1; + flags = H_INTERACTIVE; puts(s); } } else { @@ -114,8 +104,8 @@ void set_default_env(const char *s) } if (himport_r(&env_htab, (char *)default_environment, - sizeof(default_environment), '\0', 0, - 0, NULL, do_apply) == 0) + sizeof(default_environment), '\0', flags, + 0, NULL) == 0) error("Environment import failed: errno = %d\n", errno); gd->flags |= GD_FLG_ENV_READY; @@ -130,8 +120,8 @@ int set_default_vars(int nvars, char * const vars[]) * (and use \0 as a separator) */ return himport_r(&env_htab, (const char *)default_environment, - sizeof(default_environment), '\0', H_NOCLEAR, - nvars, vars, 1 /* do_apply */); + sizeof(default_environment), '\0', + H_NOCLEAR | H_INTERACTIVE, nvars, vars); } #ifndef CONFIG_SPL_BUILD @@ -155,7 +145,7 @@ int env_import(const char *buf, int check) } if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, - 0, NULL, 0 /* do_apply */)) { + 0, NULL)) { gd->flags |= GD_FLG_ENV_READY; return 1; } diff --git a/include/search.h b/include/search.h index 93e1cbc6d0b..f5165b0a989 100644 --- a/include/search.h +++ b/include/search.h @@ -73,7 +73,7 @@ struct hsearch_data { extern int hcreate_r(size_t __nel, struct hsearch_data *__htab); /* Destroy current internal hashing table. */ -extern void hdestroy_r(struct hsearch_data *__htab, int do_apply); +extern void hdestroy_r(struct hsearch_data *__htab); /* * Search for entry matching ITEM.key in internal hash table. If @@ -82,7 +82,7 @@ extern void hdestroy_r(struct hsearch_data *__htab, int do_apply); * ITEM.data. * */ extern int hsearch_r(ENTRY __item, ACTION __action, ENTRY ** __retval, - struct hsearch_data *__htab); + struct hsearch_data *__htab, int __flag); /* * Search for an entry matching `MATCH'. Otherwise, Same semantics @@ -99,7 +99,7 @@ extern int hstrstr_r(const char *__match, int __last_idx, ENTRY ** __retval, /* Search and delete entry matching ITEM.key in internal hash table. */ extern int hdelete_r(const char *__key, struct hsearch_data *__htab, - int do_apply); + int __flag); extern ssize_t hexport_r(struct hsearch_data *__htab, const char __sep, char **__resp, size_t __size, @@ -113,10 +113,11 @@ extern ssize_t hexport_r(struct hsearch_data *__htab, */ extern int himport_r(struct hsearch_data *__htab, const char *__env, size_t __size, const char __sep, - int __flag, int nvars, char * const vars[], int do_apply); + int __flag, int nvars, char * const vars[]); -/* Flags for himport_r() */ -#define H_NOCLEAR (1 << 0) /* do not clear hash table before importing */ -#define H_FORCE (1 << 1) /* overwrite read-only/write-once variables */ +/* Flags for himport_r(), hdelete_r(), and hsearch_r() */ +#define H_NOCLEAR (1 << 0) /* do not clear hash table before importing */ +#define H_FORCE (1 << 1) /* overwrite read-only/write-once variables */ +#define H_INTERACTIVE (1 << 2) /* indicate that an import is user directed */ #endif /* search.h */ diff --git a/lib/hashtable.c b/lib/hashtable.c index 94a7b61717a..f0056acf6cd 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -142,7 +142,7 @@ int hcreate_r(size_t nel, struct hsearch_data *htab) * be freed and the local static variable can be marked as not used. */ -void hdestroy_r(struct hsearch_data *htab, int do_apply) +void hdestroy_r(struct hsearch_data *htab) { int i; @@ -156,10 +156,7 @@ void hdestroy_r(struct hsearch_data *htab, int do_apply) for (i = 1; i <= htab->size; ++i) { if (htab->table[i].used > 0) { ENTRY *ep = &htab->table[i].entry; - if (do_apply && htab->apply != NULL) { - /* deletion is always forced */ - htab->apply(ep->key, ep->data, NULL, H_FORCE); - } + free((void *)ep->key); free(ep->data); } @@ -251,7 +248,7 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval, } int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, - struct hsearch_data *htab) + struct hsearch_data *htab, int flag) { unsigned int hval; unsigned int count; @@ -404,7 +401,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, * do that. */ -int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply) +int hdelete_r(const char *key, struct hsearch_data *htab, int flag) { ENTRY e, *ep; int idx; @@ -413,15 +410,21 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply) e.key = (char *)key; - if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) { + idx = hsearch_r(e, FIND, &ep, htab, 0); + if (idx == 0) { __set_errno(ESRCH); return 0; /* not found */ } + /* Check for permission */ + if (htab->apply != NULL && + htab->apply(ep->key, ep->data, NULL, flag)) { + __set_errno(EPERM); + return 0; + } + /* free used ENTRY */ debug("hdelete: DELETING key \"%s\"\n", key); - if (do_apply && htab->apply != NULL) - htab->apply(ep->key, ep->data, NULL, H_FORCE); free((void *)ep->key); free(ep->data); htab->table[idx].used = -1; @@ -674,7 +677,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[]) int himport_r(struct hsearch_data *htab, const char *env, size_t size, const char sep, int flag, - int nvars, char * const vars[], int do_apply) + int nvars, char * const vars[]) { char *data, *sp, *dp, *name, *value; char *localvars[nvars]; @@ -704,7 +707,7 @@ int himport_r(struct hsearch_data *htab, debug("Destroy Hash Table: %p table = %p\n", htab, htab->table); if (htab->table) - hdestroy_r(htab, do_apply); + hdestroy_r(htab); } /* @@ -770,7 +773,7 @@ int himport_r(struct hsearch_data *htab, if (!drop_var_from_set(name, nvars, localvars)) continue; - if (hdelete_r(name, htab, do_apply) == 0) + if (hdelete_r(name, htab, flag) == 0) debug("DELETE ERROR ##############################\n"); continue; @@ -795,14 +798,14 @@ int himport_r(struct hsearch_data *htab, e.data = value; /* if there is an apply function, check what it has to say */ - if (do_apply && htab->apply != NULL) { + if (htab->apply != NULL) { debug("searching before calling cb function" " for %s\n", name); /* * Search for variable in existing env, so to pass * its previous value to the apply callback */ - hsearch_r(e, FIND, &rv, htab); + hsearch_r(e, FIND, &rv, htab, 0); debug("previous value was %s\n", rv ? rv->data : ""); if (htab->apply(name, rv ? rv->data : NULL, value, flag)) { @@ -812,7 +815,7 @@ int himport_r(struct hsearch_data *htab, } } - hsearch_r(e, ENTER, &rv, htab); + hsearch_r(e, ENTER, &rv, htab, flag); if (rv == NULL) { printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value); @@ -839,7 +842,7 @@ int himport_r(struct hsearch_data *htab, * b) if the variable was not present in current env, we notify * it might be a typo */ - if (hdelete_r(localvars[i], htab, do_apply) == 0) + if (hdelete_r(localvars[i], htab, flag) == 0) printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]); else printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]); -- cgit v1.3.1 From 3d3b52f2586a8bf1c53496547062594fd4386454 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:20 -0600 Subject: env: Consolidate common code in hsearch_r() The same chunk of code was replicated in two places and the following changes will make that chunk grow a bit, so combine into a static func. Signed-off-by: Joe Hershberger --- lib/hashtable.c | 71 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 34 deletions(-) (limited to 'lib') diff --git a/lib/hashtable.c b/lib/hashtable.c index f0056acf6cd..f4d57950591 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -247,6 +247,34 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval, return 0; } +/* + * Compare an existing entry with the desired key, and overwrite if the action + * is ENTER. This is simply a helper function for hsearch_r(). + */ +static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, + ENTRY **retval, struct hsearch_data *htab, int flag, + unsigned int hval, unsigned int idx) +{ + if (htab->table[idx].used == hval + && strcmp(item.key, htab->table[idx].entry.key) == 0) { + /* Overwrite existing value? */ + if ((action == ENTER) && (item.data != NULL)) { + free(htab->table[idx].entry.data); + htab->table[idx].entry.data = strdup(item.data); + if (!htab->table[idx].entry.data) { + __set_errno(ENOMEM); + *retval = NULL; + return 0; + } + } + /* return found entry */ + *retval = &htab->table[idx].entry; + return idx; + } + /* keep searching */ + return -1; +} + int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, struct hsearch_data *htab, int flag) { @@ -255,6 +283,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, unsigned int len = strlen(item.key); unsigned int idx; unsigned int first_deleted = 0; + int ret; /* Compute an value for the given string. Perhaps use a better method. */ hval = len; @@ -286,23 +315,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, && !first_deleted) first_deleted = idx; - if (htab->table[idx].used == hval - && strcmp(item.key, htab->table[idx].entry.key) == 0) { - /* Overwrite existing value? */ - if ((action == ENTER) && (item.data != NULL)) { - free(htab->table[idx].entry.data); - htab->table[idx].entry.data = - strdup(item.data); - if (!htab->table[idx].entry.data) { - __set_errno(ENOMEM); - *retval = NULL; - return 0; - } - } - /* return found entry */ - *retval = &htab->table[idx].entry; - return idx; - } + ret = _compare_and_overwrite_entry(item, action, retval, htab, + flag, hval, idx); + if (ret != -1) + return ret; /* * Second hash function: @@ -328,23 +344,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, break; /* If entry is found use it. */ - if ((htab->table[idx].used == hval) - && strcmp(item.key, htab->table[idx].entry.key) == 0) { - /* Overwrite existing value? */ - if ((action == ENTER) && (item.data != NULL)) { - free(htab->table[idx].entry.data); - htab->table[idx].entry.data = - strdup(item.data); - if (!htab->table[idx].entry.data) { - __set_errno(ENOMEM); - *retval = NULL; - return 0; - } - } - /* return found entry */ - *retval = &htab->table[idx].entry; - return idx; - } + ret = _compare_and_overwrite_entry(item, action, retval, + htab, flag, hval, idx); + if (ret != -1) + return ret; } while (htab->table[idx].used); } -- cgit v1.3.1 From 7afcf3a55b5f484b3d3442053fae8186a3fb92d7 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:21 -0600 Subject: env: Refactor apply into change_ok Move the read of the old value to inside the check function. In some cases it can be avoided all together and at the least the code is only called from one place. Also name the function and the callback to more clearly describe what it does. Pass the ENTRY instead of just the name for direct access to the whole data structure. Pass an enum to the callback that specifies the operation being approved. Signed-off-by: Joe Hershberger --- common/cmd_nvedit.c | 34 +++++++++++-------------- common/env_common.c | 3 ++- include/environment.h | 7 +++--- include/search.h | 13 +++++++--- lib/hashtable.c | 70 +++++++++++++++++++++++++++++++-------------------- 5 files changed, 72 insertions(+), 55 deletions(-) (limited to 'lib') diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index a8dc9a694d9..da5689ca67b 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -208,10 +208,20 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag, * overwriting of write-once variables. */ -int env_check_apply(const char *name, const char *oldval, - const char *newval, int flag) +int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, + int flag) { int console = -1; + const char *name; +#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \ +&& defined(CONFIG_ETHADDR) + const char *oldval = NULL; + + if (op != env_op_create) + oldval = item->data; +#endif + + name = item->key; /* Default value for NULL to protect string-manipulating functions */ newval = newval ? : ""; @@ -242,12 +252,12 @@ int env_check_apply(const char *name, const char *oldval, #endif /* CONFIG_CONSOLE_MUX */ } +#ifndef CONFIG_ENV_OVERWRITE /* * Some variables like "ethaddr" and "serial#" can be set only once and * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined. */ -#ifndef CONFIG_ENV_OVERWRITE - if (oldval != NULL && /* variable exists */ + if (op != env_op_create && /* variable exists */ (flag & H_FORCE) == 0) { /* and we are not forced */ if (strcmp(name, "serial#") == 0 || (strcmp(name, "ethaddr") == 0 @@ -265,7 +275,7 @@ int env_check_apply(const char *name, const char *oldval, * (which will erase all variables prior to calling this), * we want the baudrate to actually change - for real. */ - if (oldval != NULL || /* variable exists */ + if (op != env_op_create || /* variable exists */ (flag & H_NOCLEAR) == 0) { /* or env is clear */ /* * Switch to new baudrate if new baudrate is supported @@ -339,20 +349,6 @@ static int _do_env_set(int flag, int argc, char * const argv[]) } env_id++; - /* - * search if variable with this name already exists - */ - e.key = name; - e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab, 0); - - /* - * Perform requested checks. - */ - if (env_check_apply(name, ep ? ep->data : NULL, value, 0)) { - debug("check function did not approve, refusing\n"); - return 1; - } /* Delete only ? */ if (argc < 3 || argv[2] == NULL) { diff --git a/common/env_common.c b/common/env_common.c index f22f5b968ef..a960aa8033c 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR; #include struct hsearch_data env_htab = { - .apply = env_check_apply, + .change_ok = env_change_ok, }; static uchar __env_get_char_spec(int index) @@ -162,6 +162,7 @@ void env_relocate(void) { #if defined(CONFIG_NEEDS_MANUAL_RELOC) env_reloc(); + env_htab.change_ok += gd->reloc_off; #endif if (gd->env_valid == 0) { #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD) diff --git a/include/environment.h b/include/environment.h index e8ab7033bf7..4b19f32be40 100644 --- a/include/environment.h +++ b/include/environment.h @@ -188,13 +188,12 @@ int set_default_vars(int nvars, char * const vars[]); int env_import(const char *buf, int check); /* - * Check if variable "name" can be changed from oldval to newval, - * and if so, apply the changes (e.g. baudrate). + * Check if variable "item" can be changed to newval * When (flag & H_FORCE) is set, it does not print out any error * message and forces overwriting of write-once variables. */ -int env_check_apply(const char *name, const char *oldval, - const char *newval, int flag); +int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, + int flag); #endif /* DO_DEPS_ONLY */ diff --git a/include/search.h b/include/search.h index f5165b0a989..fa00ea1b359 100644 --- a/include/search.h +++ b/include/search.h @@ -32,6 +32,12 @@ #define __set_errno(val) do { errno = val; } while (0) +enum env_op { + env_op_create, + env_op_delete, + env_op_overwrite, +}; + /* Action which shall be performed in the call the hsearch. */ typedef enum { FIND, @@ -59,14 +65,13 @@ struct hsearch_data { unsigned int filled; /* * Callback function which will check whether the given change for variable - * "name" from "oldval" to "newval" may be applied or not, and possibly apply - * such change. + * "item" to "newval" may be applied or not, and possibly apply such change. * When (flag & H_FORCE) is set, it shall not print out any error message and * shall force overwriting of write-once variables. .* Must return 0 for approval, 1 for denial. */ - int (*apply)(const char *name, const char *oldval, - const char *newval, int flag); + int (*change_ok)(const ENTRY *__item, const char *newval, enum env_op, + int flag); }; /* Create a new hashing table which will at most contain NEL elements. */ diff --git a/lib/hashtable.c b/lib/hashtable.c index f4d57950591..6861a42029c 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -66,12 +66,16 @@ * Instead the interface of all functions is extended to take an argument * which describes the current status. */ + typedef struct _ENTRY { int used; ENTRY entry; } _ENTRY; +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, + int idx); + /* * hcreate() */ @@ -259,6 +263,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, && strcmp(item.key, htab->table[idx].entry.key) == 0) { /* Overwrite existing value? */ if ((action == ENTER) && (item.data != NULL)) { + /* check for permission */ + if (htab->change_ok != NULL && htab->change_ok( + &htab->table[idx].entry, item.data, + env_op_overwrite, flag)) { + debug("change_ok() rejected setting variable " + "%s, skipping it!\n", item.key); + __set_errno(EPERM); + *retval = NULL; + return 0; + } + free(htab->table[idx].entry.data); htab->table[idx].entry.data = strdup(item.data); if (!htab->table[idx].entry.data) { @@ -383,6 +398,17 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, ++htab->filled; + /* check for permission */ + if (htab->change_ok != NULL && htab->change_ok( + &htab->table[idx].entry, item.data, env_op_create, flag)) { + debug("change_ok() rejected setting variable " + "%s, skipping it!\n", item.key); + _hdelete(item.key, htab, &htab->table[idx].entry, idx); + __set_errno(EPERM); + *retval = NULL; + return 0; + } + /* return new entry */ *retval = &htab->table[idx].entry; return 1; @@ -404,6 +430,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, * do that. */ +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, + int idx) +{ + /* free used ENTRY */ + debug("hdelete: DELETING key \"%s\"\n", key); + free((void *)ep->key); + free(ep->data); + htab->table[idx].used = -1; + + --htab->filled; +} + int hdelete_r(const char *key, struct hsearch_data *htab, int flag) { ENTRY e, *ep; @@ -420,19 +458,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) } /* Check for permission */ - if (htab->apply != NULL && - htab->apply(ep->key, ep->data, NULL, flag)) { + if (htab->change_ok != NULL && + htab->change_ok(ep, NULL, env_op_delete, flag)) { + debug("change_ok() rejected deleting variable " + "%s, skipping it!\n", key); __set_errno(EPERM); return 0; } - /* free used ENTRY */ - debug("hdelete: DELETING key \"%s\"\n", key); - free((void *)ep->key); - free(ep->data); - htab->table[idx].used = -1; - - --htab->filled; + _hdelete(key, htab, ep, idx); return 1; } @@ -800,24 +834,6 @@ int himport_r(struct hsearch_data *htab, e.key = name; e.data = value; - /* if there is an apply function, check what it has to say */ - if (htab->apply != NULL) { - debug("searching before calling cb function" - " for %s\n", name); - /* - * Search for variable in existing env, so to pass - * its previous value to the apply callback - */ - hsearch_r(e, FIND, &rv, htab, 0); - debug("previous value was %s\n", rv ? rv->data : ""); - if (htab->apply(name, rv ? rv->data : NULL, - value, flag)) { - debug("callback function refused to set" - " variable %s, skipping it!\n", name); - continue; - } - } - hsearch_r(e, ENTER, &rv, htab, flag); if (rv == NULL) { printf("himport_r: can't insert \"%s=%s\" into hash table\n", -- cgit v1.3.1 From be11235ab802844e12d84921a38fd8ae4ddda080 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:23 -0600 Subject: env: Hide '.' variables in env print by default When printing all variables with env print, don't print variables that begin with '.'. If env print is called with a '-a' switch, then include variables that begin with '.' (just like the ls command). Variables printed explicitly will be printed even without the -a. Signed-off-by: Joe Hershberger --- board/esd/pmc440/cmd_pmc440.c | 2 +- common/cmd_nvedit.c | 26 +++++++++++++++++--------- common/env_dataflash.c | 2 +- common/env_eeprom.c | 2 +- common/env_fat.c | 2 +- common/env_flash.c | 4 ++-- common/env_mmc.c | 2 +- common/env_nand.c | 4 ++-- common/env_nvram.c | 2 +- common/env_onenand.c | 2 +- common/env_sf.c | 4 ++-- include/search.h | 5 +++-- lib/hashtable.c | 5 ++++- 13 files changed, 37 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c index f1ffb7b5407..e9a78a303ca 100644 --- a/board/esd/pmc440/cmd_pmc440.c +++ b/board/esd/pmc440/cmd_pmc440.c @@ -391,7 +391,7 @@ int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1)); envp = (env_t *)nextbase; res = (char *)envp->data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index da5689ca67b..022ad394278 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -106,7 +106,7 @@ int get_env_id(void) * * Returns 0 in case of error, or length of printed string */ -static int env_print(char *name) +static int env_print(char *name, int flag) { char *res = NULL; size_t len; @@ -116,7 +116,7 @@ static int env_print(char *name) e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab, 0); + hsearch_r(e, FIND, &ep, &env_htab, flag); if (ep == NULL) return 0; len = printf("%s=%s\n", ep->key, ep->data); @@ -124,7 +124,7 @@ static int env_print(char *name) } /* print whole list */ - len = hexport_r(&env_htab, '\n', &res, 0, 0, NULL); + len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL); if (len > 0) { puts(res); @@ -141,10 +141,17 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, { int i; int rcode = 0; + int env_flag = H_HIDE_DOT; + + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { + argc--; + argv++; + env_flag &= ~H_HIDE_DOT; + } if (argc == 1) { /* print all env vars */ - rcode = env_print(NULL); + rcode = env_print(NULL, env_flag); if (!rcode) return 1; printf("\nEnvironment size: %d/%ld bytes\n", @@ -153,8 +160,9 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, } /* print selected env vars */ + env_flag &= ~H_HIDE_DOT; for (i = 1; i < argc; ++i) { - int rc = env_print(argv[i]); + int rc = env_print(argv[i], env_flag); if (!rc) { printf("## Error: \"%s\" not defined\n", argv[i]); ++rcode; @@ -807,7 +815,7 @@ NXTARG: ; argv++; if (sep) { /* export as text file */ - len = hexport_r(&env_htab, sep, &addr, size, argc, argv); + len = hexport_r(&env_htab, sep, 0, &addr, size, argc, argv); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -825,7 +833,7 @@ NXTARG: ; else /* export as raw binary data */ res = addr; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, argc, argv); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, argc, argv); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -1037,7 +1045,7 @@ static char env_help_text[] = #if defined(CONFIG_CMD_IMPORTENV) "env import [-d] [-t | -b | -c] addr [size] - import environment\n" #endif - "env print [name ...] - print environment\n" + "env print [-a | name ...] - print environment\n" #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif @@ -1069,7 +1077,7 @@ U_BOOT_CMD_COMPLETE( U_BOOT_CMD_COMPLETE( printenv, CONFIG_SYS_MAXARGS, 1, do_env_print, "print environment variables", - "\n - print values of all environment variables\n" + "[-a]\n - print [all] values of all environment variables\n" "printenv name ...\n" " - print value of environment variable 'name'", var_complete diff --git a/common/env_dataflash.c b/common/env_dataflash.c index 3c5af37bf50..38c96157b9f 100644 --- a/common/env_dataflash.c +++ b/common/env_dataflash.c @@ -60,7 +60,7 @@ int saveenv(void) char *res; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_eeprom.c b/common/env_eeprom.c index b66bba29f53..45c935b6df7 100644 --- a/common/env_eeprom.c +++ b/common/env_eeprom.c @@ -139,7 +139,7 @@ int saveenv(void) BUG_ON(env_ptr != NULL); res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_fat.c b/common/env_fat.c index 6ef531821e0..c0f18ab97df 100644 --- a/common/env_fat.c +++ b/common/env_fat.c @@ -61,7 +61,7 @@ int saveenv(void) int err; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_flash.c b/common/env_flash.c index aa970d44007..e07d336a48b 100644 --- a/common/env_flash.c +++ b/common/env_flash.c @@ -142,7 +142,7 @@ int saveenv(void) goto done; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); goto done; @@ -275,7 +275,7 @@ int saveenv(void) goto done; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); goto done; diff --git a/common/env_mmc.c b/common/env_mmc.c index a2ff90bf485..ce216712100 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -130,7 +130,7 @@ int saveenv(void) } res = (char *)&env_new->data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); ret = 1; diff --git a/common/env_nand.c b/common/env_nand.c index 79e80337050..22e72a20b07 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -186,7 +186,7 @@ int saveenv(void) return 1; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -239,7 +239,7 @@ int saveenv(void) return 1; res = (char *)&env_new->data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_nvram.c b/common/env_nvram.c index 6483db39d33..eab0e7be0ec 100644 --- a/common/env_nvram.c +++ b/common/env_nvram.c @@ -90,7 +90,7 @@ int saveenv(void) int rcode = 0; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_onenand.c b/common/env_onenand.c index da35071251f..faa903d2f02 100644 --- a/common/env_onenand.c +++ b/common/env_onenand.c @@ -95,7 +95,7 @@ int saveenv(void) }; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_sf.c b/common/env_sf.c index bbd472fcf28..d9e9085461b 100644 --- a/common/env_sf.c +++ b/common/env_sf.c @@ -79,7 +79,7 @@ int saveenv(void) } res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -277,7 +277,7 @@ int saveenv(void) } res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); goto done; diff --git a/include/search.h b/include/search.h index fa00ea1b359..1e48deb1cf0 100644 --- a/include/search.h +++ b/include/search.h @@ -107,7 +107,7 @@ extern int hdelete_r(const char *__key, struct hsearch_data *__htab, int __flag); extern ssize_t hexport_r(struct hsearch_data *__htab, - const char __sep, char **__resp, size_t __size, + const char __sep, int __flag, char **__resp, size_t __size, int argc, char * const argv[]); /* @@ -120,9 +120,10 @@ extern int himport_r(struct hsearch_data *__htab, const char *__env, size_t __size, const char __sep, int __flag, int nvars, char * const vars[]); -/* Flags for himport_r(), hdelete_r(), and hsearch_r() */ +/* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */ #define H_NOCLEAR (1 << 0) /* do not clear hash table before importing */ #define H_FORCE (1 << 1) /* overwrite read-only/write-once variables */ #define H_INTERACTIVE (1 << 2) /* indicate that an import is user directed */ +#define H_HIDE_DOT (1 << 3) /* don't print env vars that begin with '.' */ #endif /* search.h */ diff --git a/lib/hashtable.c b/lib/hashtable.c index 6861a42029c..7c6b96cac87 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -522,7 +522,7 @@ static int cmpkey(const void *p1, const void *p2) return (strcmp(e1->key, e2->key)); } -ssize_t hexport_r(struct hsearch_data *htab, const char sep, +ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, char **resp, size_t size, int argc, char * const argv[]) { @@ -559,6 +559,9 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, if ((argc > 0) && (found == 0)) continue; + if ((flag & H_HIDE_DOT) && ep->key[0] == '.') + continue; + list[n++] = ep; totlen += strlen(ep->key) + 2; -- cgit v1.3.1 From 170ab11075d3be56e89d6444abf1148329130f4b Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:24 -0600 Subject: env: Add support for callbacks to environment vars Add support for per-variable callbacks to the "hashtable" functions. Signed-off-by: Joe Hershberger !!!fix comment in callback --- README | 30 +++++++ common/Makefile | 4 + common/env_attr.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++++ common/env_callback.c | 144 ++++++++++++++++++++++++++++++++ include/env_attr.h | 55 ++++++++++++ include/env_callback.h | 62 ++++++++++++++ include/env_default.h | 5 ++ include/environment.h | 2 + include/search.h | 5 ++ lib/hashtable.c | 67 ++++++++++++++- 10 files changed, 592 insertions(+), 4 deletions(-) create mode 100644 common/env_attr.c create mode 100644 common/env_callback.c create mode 100644 include/env_attr.h create mode 100644 include/env_callback.h (limited to 'lib') diff --git a/README b/README index a80441c9b57..e00a7c2a8a3 100644 --- a/README +++ b/README @@ -4213,6 +4213,36 @@ Please note that changes to some configuration parameters may take only effect after the next boot (yes, that's just like Windoze :-). +Callback functions for environment variables: +--------------------------------------------- + +For some environment variables, the behavior of u-boot needs to change +when their values are changed. This functionailty allows functions to +be associated with arbitrary variables. On creation, overwrite, or +deletion, the callback will provide the opportunity for some side +effect to happen or for the change to be rejected. + +The callbacks are named and associated with a function using the +U_BOOT_ENV_CALLBACK macro in your board or driver code. + +These callbacks are associated with variables in one of two ways. The +static list can be added to by defining CONFIG_ENV_CALLBACK_LIST_STATIC +in the board configuration to a string that defines a list of +associations. The list must be in the following format: + + entry = variable_name[:callback_name] + list = entry[,list] + +If the callback name is not specified, then the callback is deleted. +Spaces are also allowed anywhere in the list. + +Callbacks can also be associated by defining the ".callbacks" variable +with the same list format above. Any association in ".callbacks" will +override any association in the static list. You can define +CONFIG_ENV_CALLBACK_LIST_DEFAULT to a list (string) to define the +".callbacks" envirnoment variable in the default or embedded environment. + + Command Line Parsing: ===================== diff --git a/common/Makefile b/common/Makefile index ce3035937ea..04812e9b2a7 100644 --- a/common/Makefile +++ b/common/Makefile @@ -44,6 +44,8 @@ COBJS-y += cmd_nvedit.o COBJS-y += cmd_version.o # environment +COBJS-y += env_attr.o +COBJS-y += env_callback.o COBJS-y += env_common.o COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o @@ -207,6 +209,8 @@ COBJS-y += env_common.o COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o diff --git a/common/env_attr.c b/common/env_attr.c new file mode 100644 index 00000000000..7d330a58bba --- /dev/null +++ b/common/env_attr.c @@ -0,0 +1,222 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +/* + * Iterate through the whole list calling the callback for each found element. + * "attr_list" takes the form: + * attributes = [^,:\s]* + * entry = name[:attributes] + * list = entry[,list] + */ +int env_attr_walk(const char *attr_list, + int (*callback)(const char *name, const char *attributes)) +{ + const char *entry, *entry_end; + char *name, *attributes; + + if (!attr_list) + /* list not found */ + return 1; + + entry = attr_list; + do { + char *entry_cpy = NULL; + + entry_end = strchr(entry, ENV_ATTR_LIST_DELIM); + /* check if this is the last entry in the list */ + if (entry_end == NULL) { + int entry_len = strlen(entry); + + if (entry_len) { + /* + * allocate memory to copy the entry into since + * we will need to inject '\0' chars and squash + * white-space before calling the callback + */ + entry_cpy = malloc(entry_len + 1); + if (entry_cpy) + /* copy the rest of the list */ + strcpy(entry_cpy, entry); + else + return -ENOMEM; + } + } else { + int entry_len = entry_end - entry; + + if (entry_len) { + /* + * allocate memory to copy the entry into since + * we will need to inject '\0' chars and squash + * white-space before calling the callback + */ + entry_cpy = malloc(entry_len + 1); + if (entry_cpy) { + /* copy just this entry and null term */ + strncpy(entry_cpy, entry, entry_len); + entry_cpy[entry_len] = '\0'; + } else + return -ENOMEM; + } + } + + /* check if there is anything to process (e.g. not ",,,") */ + if (entry_cpy != NULL) { + attributes = strchr(entry_cpy, ENV_ATTR_SEP); + /* check if there is a ':' */ + if (attributes != NULL) { + /* replace the ':' with '\0' to term name */ + *attributes++ = '\0'; + /* remove white-space from attributes */ + attributes = strim(attributes); + } + /* remove white-space from name */ + name = strim(entry_cpy); + + /* only call the callback if there is a name */ + if (strlen(name) != 0) { + int retval = 0; + + retval = callback(name, attributes); + if (retval) { + free(entry_cpy); + return retval; + } + } + } + + free(entry_cpy); + entry = entry_end + 1; + } while (entry_end != NULL); + + return 0; +} + +/* + * Search for the last matching string in another string with the option to + * start looking at a certain point (i.e. ignore anything beyond that point). + */ +static char *reverse_strstr(const char *searched, const char *search_for, + const char *searched_start) +{ + char *result = NULL; + + if (*search_for == '\0') + return (char *)searched; + + for (;;) { + char *match = strstr(searched, search_for); + + /* + * Stop looking if no new match is found or looking past the + * searched_start pointer + */ + if (match == NULL || (searched_start != NULL && + match + strlen(search_for) > searched_start)) + break; + + result = match; + searched = match + 1; + } + + return result; +} + +/* + * Retrieve the attributes string associated with a single name in the list + * There is no protection on attributes being too small for the value + */ +int env_attr_lookup(const char *attr_list, const char *name, char *attributes) +{ + const char *entry = NULL; + + if (!attributes) + /* bad parameter */ + return -1; + if (!attr_list) + /* list not found */ + return 1; + + entry = reverse_strstr(attr_list, name, NULL); + while (entry != NULL) { + const char *prevch = entry - 1; + const char *nextch = entry + strlen(name); + + /* Skip spaces */ + while (*prevch == ' ') + prevch--; + while (*nextch == ' ') + nextch++; + + /* check for an exact match */ + if ((entry == attr_list || + *prevch == ENV_ATTR_LIST_DELIM) && + (*nextch == ENV_ATTR_SEP || + *nextch == ENV_ATTR_LIST_DELIM || + *nextch == '\0')) + break; + + entry = reverse_strstr(attr_list, name, entry); + } + if (entry != NULL) { + int len; + + /* skip the name */ + entry += strlen(name); + /* skip spaces */ + while (*entry == ' ') + entry++; + if (*entry != ENV_ATTR_SEP) + len = 0; + else { + const char *delim; + static const char delims[] = { + ENV_ATTR_LIST_DELIM, ' ', '\0'}; + + /* skip the attr sep */ + entry += 1; + /* skip spaces */ + while (*entry == ' ') + entry++; + + delim = strpbrk(entry, delims); + if (delim == NULL) + len = strlen(entry); + else + len = delim - entry; + memcpy(attributes, entry, len); + } + attributes[len] = '\0'; + + /* success */ + return 0; + } + + /* not found in list */ + return 2; +} diff --git a/common/env_callback.c b/common/env_callback.c new file mode 100644 index 00000000000..78ca3674f09 --- /dev/null +++ b/common/env_callback.c @@ -0,0 +1,144 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +DECLARE_GLOBAL_DATA_PTR; +#endif + +/* + * Look up a callback function pointer by name + */ +struct env_clbk_tbl *find_env_callback(const char *name) +{ + struct env_clbk_tbl *clbkp; + int i; + int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); + + if (name == NULL) + return NULL; + + /* look up the callback in the linker-list */ + for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); + i < num_callbacks; + i++, clbkp++) { + if (strcmp(name, clbkp->name) == 0) + return clbkp; + } + + return NULL; +} + +/* + * Look for a possible callback for a newly added variable + * This is called specifically when the variable did not exist in the hash + * previously, so the blanket update did not find this variable. + */ +void env_callback_init(ENTRY *var_entry) +{ + const char *var_name = var_entry->key; + const char *callback_list = getenv(ENV_CALLBACK_VAR); + char callback_name[256] = ""; + struct env_clbk_tbl *clbkp; + int ret = 1; + + /* look in the ".callbacks" var for a reference to this variable */ + if (callback_list != NULL) + ret = env_attr_lookup(callback_list, var_name, callback_name); + + /* only if not found there, look in the static list */ + if (ret) + ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name, + callback_name); + + /* if an association was found, set the callback pointer */ + if (!ret && strlen(callback_name)) { + clbkp = find_env_callback(callback_name); + if (clbkp != NULL) +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + var_entry->callback = clbkp->callback + gd->reloc_off; +#else + var_entry->callback = clbkp->callback; +#endif + } +} + +/* + * Called on each existing env var prior to the blanket update since removing + * a callback association should remove its callback. + */ +static int clear_callback(ENTRY *entry) +{ + entry->callback = NULL; + + return 0; +} + +/* + * Call for each element in the list that associates variables to callbacks + */ +static int set_callback(const char *name, const char *value) +{ + ENTRY e, *ep; + struct env_clbk_tbl *clbkp; + + e.key = name; + e.data = NULL; + hsearch_r(e, FIND, &ep, &env_htab, 0); + + /* does the env variable actually exist? */ + if (ep != NULL) { + /* the assocaition delares no callback, so remove the pointer */ + if (value == NULL || strlen(value) == 0) + ep->callback = NULL; + else { + /* assign the requested callback */ + clbkp = find_env_callback(value); + if (clbkp != NULL) +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + ep->callback = clbkp->callback + gd->reloc_off; +#else + ep->callback = clbkp->callback; +#endif + } + } + + return 0; +} + +static int on_callbacks(const char *name, const char *value, enum env_op op, + int flags) +{ + /* remove all callbacks */ + hwalk_r(&env_htab, clear_callback); + + /* configure any static callback bindings */ + env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback); + /* configure any dynamic callback bindings */ + env_attr_walk(value, set_callback); + + return 0; +} +U_BOOT_ENV_CALLBACK(callbacks, on_callbacks); diff --git a/include/env_attr.h b/include/env_attr.h new file mode 100644 index 00000000000..6ef114f5daa --- /dev/null +++ b/include/env_attr.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ENV_ATTR_H__ +#define __ENV_ATTR_H__ + +#define ENV_ATTR_LIST_DELIM ',' +#define ENV_ATTR_SEP ':' + +/* + * env_attr_walk takes as input an "attr_list" that takes the form: + * attributes = [^,:\s]* + * entry = name[:attributes] + * list = entry[,list] + * It will call the "callback" function with the "name" and attribute as "value" + * The callback may return a non-0 to abort the list walk. + * This return value will be passed through to the caller. + * 0 is returned on success. + */ +extern int env_attr_walk(const char *attr_list, + int (*callback)(const char *name, const char *value)); + +/* + * env_attr_lookup takes as input an "attr_list" with the same form as above. + * It also takes as input a "name" to look for. + * If the name is found in the list, it's value is copied into "attributes". + * There is no protection on attributes being too small for the value. + * It returns -1 if attributes is NULL, 1 if "name" is not found, 2 if + * "attr_list" is NULL. + * Returns 0 on success. + */ +extern int env_attr_lookup(const char *attr_list, const char *name, + char *attributes); + +#endif /* __ENV_ATTR_H__ */ diff --git a/include/env_callback.h b/include/env_callback.h new file mode 100644 index 00000000000..5a460f3532e --- /dev/null +++ b/include/env_callback.h @@ -0,0 +1,62 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ENV_CALLBACK_H__ +#define __ENV_CALLBACK_H__ + +#include +#include + +#define ENV_CALLBACK_VAR ".callbacks" + +/* Board configs can define additional static callback bindings */ +#ifndef CONFIG_ENV_CALLBACK_LIST_STATIC +#define CONFIG_ENV_CALLBACK_LIST_STATIC +#endif + +/* + * This list of callback bindings is static, but may be overridden by defining + * a new association in the ".callbacks" environment variable. + */ +#define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \ + CONFIG_ENV_CALLBACK_LIST_STATIC + +struct env_clbk_tbl { + const char *name; /* Callback name */ + int (*callback)(const char *name, const char *value, enum env_op op, + int flags); +}; + +struct env_clbk_tbl *find_env_callback(const char *); +void env_callback_init(ENTRY *var_entry); + +/* + * Define a callback that can be associated with variables. + * when associated through the ".callbacks" environment variable, the callback + * will be executed any time the variable is inserted, overwritten, or deleted. + */ +#define U_BOOT_ENV_CALLBACK(name, callback) \ + ll_entry_declare(struct env_clbk_tbl, name, env_clbk, env_clbk) = \ + {#name, callback} + +#endif /* __ENV_CALLBACK_H__ */ diff --git a/include/env_default.h b/include/env_default.h index a1db73a2c55..d05eba16185 100644 --- a/include/env_default.h +++ b/include/env_default.h @@ -24,6 +24,8 @@ * MA 02111-1307 USA */ +#include + #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED env_t environment __PPCENV__ = { ENV_CRC, /* CRC Sum */ @@ -36,6 +38,9 @@ static char default_environment[] = { #else const uchar default_environment[] = { #endif +#ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT + ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0" +#endif #ifdef CONFIG_BOOTARGS "bootargs=" CONFIG_BOOTARGS "\0" #endif diff --git a/include/environment.h b/include/environment.h index 4b19f32be40..6c302155223 100644 --- a/include/environment.h +++ b/include/environment.h @@ -164,6 +164,8 @@ extern void env_reloc(void); #ifndef DO_DEPS_ONLY +#include +#include #include extern struct hsearch_data env_htab; diff --git a/include/search.h b/include/search.h index 1e48deb1cf0..d68e24a0306 100644 --- a/include/search.h +++ b/include/search.h @@ -47,6 +47,8 @@ typedef enum { typedef struct entry { const char *key; char *data; + int (*callback)(const char *name, const char *value, enum env_op op, + int flags); } ENTRY; /* Opaque type for internal use. */ @@ -120,6 +122,9 @@ extern int himport_r(struct hsearch_data *__htab, const char *__env, size_t __size, const char __sep, int __flag, int nvars, char * const vars[]); +/* Walk the whole table calling the callback on each element */ +extern int hwalk_r(struct hsearch_data *__htab, int (*callback)(ENTRY *)); + /* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */ #define H_NOCLEAR (1 << 0) /* do not clear hash table before importing */ #define H_FORCE (1 << 1) /* overwrite read-only/write-once variables */ diff --git a/lib/hashtable.c b/lib/hashtable.c index 7c6b96cac87..e9226665f34 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -54,7 +54,8 @@ #define CONFIG_ENV_MAX_ENTRIES 512 #endif -#include "search.h" +#include +#include /* * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 @@ -274,6 +275,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, return 0; } + /* If there is a callback, call it */ + if (htab->table[idx].entry.callback && + htab->table[idx].entry.callback(item.key, + item.data, env_op_overwrite, flag)) { + debug("callback() rejected setting variable " + "%s, skipping it!\n", item.key); + __set_errno(EINVAL); + *retval = NULL; + return 0; + } + free(htab->table[idx].entry.data); htab->table[idx].entry.data = strdup(item.data); if (!htab->table[idx].entry.data) { @@ -398,6 +410,9 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, ++htab->filled; + /* This is a new entry, so look up a possible callback */ + env_callback_init(&htab->table[idx].entry); + /* check for permission */ if (htab->change_ok != NULL && htab->change_ok( &htab->table[idx].entry, item.data, env_op_create, flag)) { @@ -409,6 +424,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, return 0; } + /* If there is a callback, call it */ + if (htab->table[idx].entry.callback && + htab->table[idx].entry.callback(item.key, item.data, + env_op_create, flag)) { + debug("callback() rejected setting variable " + "%s, skipping it!\n", item.key); + _hdelete(item.key, htab, &htab->table[idx].entry, idx); + __set_errno(EINVAL); + *retval = NULL; + return 0; + } + /* return new entry */ *retval = &htab->table[idx].entry; return 1; @@ -437,6 +464,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, debug("hdelete: DELETING key \"%s\"\n", key); free((void *)ep->key); free(ep->data); + ep->callback = NULL; htab->table[idx].used = -1; --htab->filled; @@ -466,6 +494,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) return 0; } + /* If there is a callback, call it */ + if (htab->table[idx].entry.callback && + htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) { + debug("callback() rejected deleting variable " + "%s, skipping it!\n", key); + __set_errno(EINVAL); + return 0; + } + _hdelete(key, htab, ep, idx); return 1; @@ -838,11 +875,9 @@ int himport_r(struct hsearch_data *htab, e.data = value; hsearch_r(e, ENTER, &rv, htab, flag); - if (rv == NULL) { + if (rv == NULL) printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value); - return 0; - } debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n", htab, htab->filled, htab->size, @@ -873,3 +908,27 @@ int himport_r(struct hsearch_data *htab, debug("INSERT: done\n"); return 1; /* everything OK */ } + +/* + * hwalk_r() + */ + +/* + * Walk all of the entries in the hash, calling the callback for each one. + * this allows some generic operation to be performed on each element. + */ +int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *)) +{ + int i; + int retval; + + for (i = 1; i <= htab->size; ++i) { + if (htab->table[i].used > 0) { + retval = callback(&htab->table[i].entry); + if (retval) + return retval; + } + } + + return 0; +} -- cgit v1.3.1 From 2598090b7e17f8bdca95b22e7f27217054730e02 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:31 -0600 Subject: env: Add environment variable flags Currently just validates variable types as decimal, hexidecimal, boolean, ip address, and mac address. If the entry is not found in the env ".flags", then look in the static one. This allows the env to override the static definitions, but prevents the need to have every definition in the environment distracting you. Signed-off-by: Joe Hershberger --- README | 37 ++++++ common/Makefile | 2 + common/cmd_nvedit.c | 50 +------- common/env_common.c | 2 +- common/env_flags.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++++ include/env_callback.h | 2 + include/env_default.h | 3 + include/env_flags.h | 76 ++++++++++++ include/environment.h | 9 +- include/search.h | 1 + lib/hashtable.c | 4 + 11 files changed, 447 insertions(+), 58 deletions(-) create mode 100644 common/env_flags.c create mode 100644 include/env_flags.h (limited to 'lib') diff --git a/README b/README index ac61a32adf3..acb711a384c 100644 --- a/README +++ b/README @@ -2188,6 +2188,11 @@ CBFS (Coreboot Filesystem) support serial# is unaffected by this, i. e. it remains read-only.] + The same can be accomplished in a more flexible way + for any variable by configuring the type of access + to allow for those variables in the ".flags" variable + or define CONFIG_ENV_FLAGS_LIST_STATIC. + - Protected RAM: CONFIG_PRAM @@ -3113,6 +3118,38 @@ Configuration Settings: cases. This setting can be used to tune behaviour; see lib/hashtable.c for details. +- CONFIG_ENV_FLAGS_LIST_DEFAULT +- CONFIG_ENV_FLAGS_LIST_STATIC + Enable validation of the values given to enviroment variables when + calling env set. Variables can be restricted to only decimal, + hexadecimal, or boolean. If CONFIG_CMD_NET is also defined, + the variables can also be restricted to IP address or MAC address. + + The format of the list is: + type_attribute = [s|d|x|b|i|m] + attributes = type_attribute + entry = variable_name[:attributes] + list = entry[,list] + + The type attributes are: + s - String (default) + d - Decimal + x - Hexadecimal + b - Boolean ([1yYtT|0nNfF]) + i - IP address + m - MAC address + + - CONFIG_ENV_FLAGS_LIST_DEFAULT + Define this to a list (string) to define the ".flags" + envirnoment variable in the default or embedded environment. + + - CONFIG_ENV_FLAGS_LIST_STATIC + Define this to a list (string) to define validation that + should be done if an entry is not found in the ".flags" + environment variable. To override a setting in the static + list, simply add an entry for the same variable name to the + ".flags" variable. + The following definitions that deal with the placement and management of environment data (variable area); in general, we support the following configurations: diff --git a/common/Makefile b/common/Makefile index 04812e9b2a7..c77439556e2 100644 --- a/common/Makefile +++ b/common/Makefile @@ -47,6 +47,7 @@ COBJS-y += cmd_version.o COBJS-y += env_attr.o COBJS-y += env_callback.o COBJS-y += env_common.o +COBJS-y += env_flags.o COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o @@ -212,6 +213,7 @@ COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o endif diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index cb191cd0637..f645194bf12 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -191,58 +191,10 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag, #endif #endif /* CONFIG_SPL_BUILD */ -/* - * Perform consistency checking before setting, replacing, or deleting an - * environment variable, then (if successful) apply the changes to internals so - * to make them effective. Code for this function was taken out of - * _do_env_set(), which now calls it instead. - * Also called as a callback function by himport_r(). - * Returns 0 in case of success, 1 in case of failure. - * When (flag & H_FORCE) is set, do not print out any error message and force - * overwriting of write-once variables. - */ - -int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, - int flag) -{ -#ifndef CONFIG_ENV_OVERWRITE - const char *name; -#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) - const char *oldval = NULL; - - if (op != env_op_create) - oldval = item->data; -#endif - - name = item->key; -#endif - -#ifndef CONFIG_ENV_OVERWRITE - /* - * Some variables like "ethaddr" and "serial#" can be set only once and - * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined. - */ - if (op != env_op_create && /* variable exists */ - (flag & H_FORCE) == 0) { /* and we are not forced */ - if (strcmp(name, "serial#") == 0 || - (strcmp(name, "ethaddr") == 0 -#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) - && strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0 -#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ - )) { - printf("Can't overwrite \"%s\"\n", name); - return 1; - } - } -#endif - - return 0; -} - /* * Set a new environment variable, * or replace or delete an existing one. -*/ + */ static int _do_env_set(int flag, int argc, char * const argv[]) { int i, len; diff --git a/common/env_common.c b/common/env_common.c index 067fe3f4c1a..bb18070c54a 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR; #include struct hsearch_data env_htab = { - .change_ok = env_change_ok, + .change_ok = env_flags_validate, }; static uchar __env_get_char_spec(int index) diff --git a/common/env_flags.c b/common/env_flags.c new file mode 100644 index 00000000000..a58d614bb3f --- /dev/null +++ b/common/env_flags.c @@ -0,0 +1,319 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#include +#include + +#ifdef CONFIG_CMD_NET +#define ENV_FLAGS_NET_VARTYPE_REPS "im" +#else +#define ENV_FLAGS_NET_VARTYPE_REPS "" +#endif + +static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; + +/* + * Parse the flags string from a .flags attribute list into the vartype enum. + */ +enum env_flags_vartype env_flags_parse_vartype(const char *flags) +{ + char *type; + + if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) + return env_flags_vartype_string; + + type = strchr(env_flags_vartype_rep, + flags[ENV_FLAGS_VARTYPE_LOC]); + + if (type != NULL) + return (enum env_flags_vartype) + (type - &env_flags_vartype_rep[0]); + + printf("## Warning: Unknown environment variable type '%c'\n", + flags[ENV_FLAGS_VARTYPE_LOC]); + return env_flags_vartype_string; +} + +static inline int is_hex_prefix(const char *value) +{ + return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); +} + +static void skip_num(int hex, const char *value, const char **end, + int max_digits) +{ + int i; + + if (hex && is_hex_prefix(value)) + value += 2; + + for (i = max_digits; i != 0; i--) { + if (hex && !isxdigit(*value)) + break; + if (!hex && !isdigit(*value)) + break; + value++; + } + if (end != NULL) + *end = value; +} + +/* + * Based on the declared type enum, validate that the value string complies + * with that format + */ +static int _env_flags_validate_type(const char *value, + enum env_flags_vartype type) +{ + const char *end; +#ifdef CONFIG_CMD_NET + const char *cur; + int i; +#endif + + switch (type) { + case env_flags_vartype_string: + break; + case env_flags_vartype_decimal: + skip_num(0, value, &end, -1); + if (*end != '\0') + return -1; + break; + case env_flags_vartype_hex: + skip_num(1, value, &end, -1); + if (*end != '\0') + return -1; + if (value + 2 == end && is_hex_prefix(value)) + return -1; + break; + case env_flags_vartype_bool: + if (value[0] != '1' && value[0] != 'y' && value[0] != 't' && + value[0] != 'Y' && value[0] != 'T' && + value[0] != '0' && value[0] != 'n' && value[0] != 'f' && + value[0] != 'N' && value[0] != 'F') + return -1; + if (value[1] != '\0') + return -1; + break; +#ifdef CONFIG_CMD_NET + case env_flags_vartype_ipaddr: + cur = value; + for (i = 0; i < 4; i++) { + skip_num(0, cur, &end, 3); + if (cur == end) + return -1; + if (i != 3 && *end != '.') + return -1; + if (i == 3 && *end != '\0') + return -1; + cur = end + 1; + } + break; + case env_flags_vartype_macaddr: + cur = value; + for (i = 0; i < 6; i++) { + skip_num(1, cur, &end, 2); + if (cur == end) + return -1; + if (cur + 2 == end && is_hex_prefix(cur)) + return -1; + if (i != 5 && *end != ':') + return -1; + if (i == 5 && *end != '\0') + return -1; + cur = end + 1; + } + break; +#endif + case env_flags_vartype_end: + return -1; + } + + /* OK */ + return 0; +} + +/* + * Look for flags in a provided list and failing that the static list + */ +static inline int env_flags_lookup(const char *flags_list, const char *name, + char *flags) +{ + int ret = 1; + + if (!flags) + /* bad parameter */ + return -1; + + /* try the env first */ + if (flags_list) + ret = env_attr_lookup(flags_list, name, flags); + + if (ret != 0) + /* if not found in the env, look in the static list */ + ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags); + + return ret; +} + +/* + * Parse the flag charachters from the .flags attribute list into the binary + * form to be stored in the environment entry->flags field. + */ +static int env_parse_flags_to_bin(const char *flags) +{ + return env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK; +} + +/* + * Look for possible flags for a newly added variable + * This is called specifically when the variable did not exist in the hash + * previously, so the blanket update did not find this variable. + */ +void env_flags_init(ENTRY *var_entry) +{ + const char *var_name = var_entry->key; + const char *flags_list = getenv(ENV_FLAGS_VAR); + char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = ""; + int ret = 1; + + /* look in the ".flags" and static for a reference to this variable */ + ret = env_flags_lookup(flags_list, var_name, flags); + + /* if any flags were found, set the binary form to the entry */ + if (!ret && strlen(flags)) + var_entry->flags = env_parse_flags_to_bin(flags); +} + +/* + * Called on each existing env var prior to the blanket update since removing + * a flag in the flag list should remove its flags. + */ +static int clear_flags(ENTRY *entry) +{ + entry->flags = 0; + + return 0; +} + +/* + * Call for each element in the list that defines flags for a variable + */ +static int set_flags(const char *name, const char *value) +{ + ENTRY e, *ep; + + e.key = name; + e.data = NULL; + hsearch_r(e, FIND, &ep, &env_htab, 0); + + /* does the env variable actually exist? */ + if (ep != NULL) { + /* the flag list is empty, so clear the flags */ + if (value == NULL || strlen(value) == 0) + ep->flags = 0; + else + /* assign the requested flags */ + ep->flags = env_parse_flags_to_bin(value); + } + + return 0; +} + +static int on_flags(const char *name, const char *value, enum env_op op, + int flags) +{ + /* remove all flags */ + hwalk_r(&env_htab, clear_flags); + + /* configure any static flags */ + env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags); + /* configure any dynamic flags */ + env_attr_walk(value, set_flags); + + return 0; +} +U_BOOT_ENV_CALLBACK(flags, on_flags); + +/* + * Perform consistency checking before creating, overwriting, or deleting an + * environment variable. Called as a callback function by hsearch_r() and + * hdelete_r(). Returns 0 in case of success, 1 in case of failure. + * When (flag & H_FORCE) is set, do not print out any error message and force + * overwriting of write-once variables. + */ + +int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, + int flag) +{ + const char *name; +#if !defined(CONFIG_ENV_OVERWRITE) && defined(CONFIG_OVERWRITE_ETHADDR_ONCE) \ +&& defined(CONFIG_ETHADDR) + const char *oldval = NULL; + + if (op != env_op_create) + oldval = item->data; +#endif + + name = item->key; + + /* Default value for NULL to protect string-manipulating functions */ + newval = newval ? : ""; + +#ifndef CONFIG_ENV_OVERWRITE + /* + * Some variables like "ethaddr" and "serial#" can be set only once and + * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined. + */ + if (op != env_op_create && /* variable exists */ + (flag & H_FORCE) == 0) { /* and we are not forced */ + if (strcmp(name, "serial#") == 0 || + (strcmp(name, "ethaddr") == 0 +#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) + && strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0 +#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ + )) { + printf("Can't overwrite \"%s\"\n", name); + return 1; + } + } +#endif + + /* validate the value to match the variable type */ + if (op != env_op_delete) { + enum env_flags_vartype type = (enum env_flags_vartype) + (ENV_FLAGS_VARTYPE_BIN_MASK & item->flags); + + if (_env_flags_validate_type(newval, type) < 0) { + printf("## Error: flags type check failure for " + "\"%s\" <= \"%s\" (type: %c)\n", + name, newval, env_flags_vartype_rep[type]); + return -1; + } + } + + return 0; +} diff --git a/include/env_callback.h b/include/env_callback.h index f52e133f1fa..47fdc6fa910 100644 --- a/include/env_callback.h +++ b/include/env_callback.h @@ -24,6 +24,7 @@ #ifndef __ENV_CALLBACK_H__ #define __ENV_CALLBACK_H__ +#include #include #include @@ -45,6 +46,7 @@ * a new association in the ".callbacks" environment variable. */ #define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \ + ENV_FLAGS_VAR ":flags," \ "baudrate:baudrate," \ "bootfile:bootfile," \ "loadaddr:loadaddr," \ diff --git a/include/env_default.h b/include/env_default.h index d05eba16185..39c5b7c6aa3 100644 --- a/include/env_default.h +++ b/include/env_default.h @@ -41,6 +41,9 @@ const uchar default_environment[] = { #ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0" #endif +#ifdef CONFIG_ENV_FLAGS_LIST_DEFAULT + ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0" +#endif #ifdef CONFIG_BOOTARGS "bootargs=" CONFIG_BOOTARGS "\0" #endif diff --git a/include/env_flags.h b/include/env_flags.h new file mode 100644 index 00000000000..bf25f2746bc --- /dev/null +++ b/include/env_flags.h @@ -0,0 +1,76 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ENV_FLAGS_H__ +#define __ENV_FLAGS_H__ + +enum env_flags_vartype { + env_flags_vartype_string, + env_flags_vartype_decimal, + env_flags_vartype_hex, + env_flags_vartype_bool, +#ifdef CONFIG_CMD_NET + env_flags_vartype_ipaddr, + env_flags_vartype_macaddr, +#endif + env_flags_vartype_end +}; + +#define ENV_FLAGS_VAR ".flags" +#define ENV_FLAGS_ATTR_MAX_LEN 2 +#define ENV_FLAGS_VARTYPE_LOC 0 + +#ifndef CONFIG_ENV_FLAGS_LIST_STATIC +#define CONFIG_ENV_FLAGS_LIST_STATIC "" +#endif + +#define ENV_FLAGS_LIST_STATIC \ + CONFIG_ENV_FLAGS_LIST_STATIC + +/* + * Parse the flags string from a .flags attribute list into the vartype enum. + */ +enum env_flags_vartype env_flags_parse_vartype(const char *flags); + +#include + +/* + * When adding a variable to the environment, initialize the flags for that + * variable. + */ +void env_flags_init(ENTRY *var_entry); + +/* + * Validate the newval for to conform with the requirements defined by its flags + */ +int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, + int flag); + +/* + * These are the binary flags used in the environment entry->flags variable to + * decribe properties of veriables in the table + */ +#define ENV_FLAGS_VARTYPE_BIN_MASK 0x00000007 +/* The actual variable type values use the enum value (within the mask) */ + +#endif /* __ENV_FLAGS_H__ */ diff --git a/include/environment.h b/include/environment.h index 6c302155223..00e59ba789c 100644 --- a/include/environment.h +++ b/include/environment.h @@ -166,6 +166,7 @@ extern void env_reloc(void); #include #include +#include #include extern struct hsearch_data env_htab; @@ -189,14 +190,6 @@ int set_default_vars(int nvars, char * const vars[]); /* Import from binary representation into hash table */ int env_import(const char *buf, int check); -/* - * Check if variable "item" can be changed to newval - * When (flag & H_FORCE) is set, it does not print out any error - * message and forces overwriting of write-once variables. - */ -int env_change_ok(const ENTRY *item, const char *newval, enum env_op op, - int flag); - #endif /* DO_DEPS_ONLY */ #endif /* _ENVIRONMENT_H_ */ diff --git a/include/search.h b/include/search.h index d68e24a0306..13d3be62917 100644 --- a/include/search.h +++ b/include/search.h @@ -49,6 +49,7 @@ typedef struct entry { char *data; int (*callback)(const char *name, const char *value, enum env_op op, int flags); + int flags; } ENTRY; /* Opaque type for internal use. */ diff --git a/lib/hashtable.c b/lib/hashtable.c index e9226665f34..07ebfb218f8 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -55,6 +55,7 @@ #endif #include +#include #include /* @@ -412,6 +413,8 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, /* This is a new entry, so look up a possible callback */ env_callback_init(&htab->table[idx].entry); + /* Also look for flags */ + env_flags_init(&htab->table[idx].entry); /* check for permission */ if (htab->change_ok != NULL && htab->change_ok( @@ -465,6 +468,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, free((void *)ep->key); free(ep->data); ep->callback = NULL; + ep->flags = 0; htab->table[idx].used = -1; --htab->filled; -- cgit v1.3.1