uboot/env/attr.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2012
   3 * Joe Hershberger, National Instruments, joe.hershberger@ni.com
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
   9#include <stdint.h>
  10#include <stdio.h>
  11#include <linux/linux_string.h>
  12#else
  13#include <common.h>
  14#include <slre.h>
  15#endif
  16
  17#include <env_attr.h>
  18#include <errno.h>
  19#include <linux/string.h>
  20#include <malloc.h>
  21
  22/*
  23 * Iterate through the whole list calling the callback for each found element.
  24 * "attr_list" takes the form:
  25 *      attributes = [^,:\s]*
  26 *      entry = name[:attributes]
  27 *      list = entry[,list]
  28 */
  29int env_attr_walk(const char *attr_list,
  30        int (*callback)(const char *name, const char *attributes, void *priv),
  31        void *priv)
  32{
  33        const char *entry, *entry_end;
  34        char *name, *attributes;
  35
  36        if (!attr_list)
  37                /* list not found */
  38                return 1;
  39
  40        entry = attr_list;
  41        do {
  42                char *entry_cpy = NULL;
  43
  44                entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
  45                /* check if this is the last entry in the list */
  46                if (entry_end == NULL) {
  47                        int entry_len = strlen(entry);
  48
  49                        if (entry_len) {
  50                                /*
  51                                 * allocate memory to copy the entry into since
  52                                 * we will need to inject '\0' chars and squash
  53                                 * white-space before calling the callback
  54                                 */
  55                                entry_cpy = malloc(entry_len + 1);
  56                                if (entry_cpy)
  57                                        /* copy the rest of the list */
  58                                        strcpy(entry_cpy, entry);
  59                                else
  60                                        return -ENOMEM;
  61                        }
  62                } else {
  63                        int entry_len = entry_end - entry;
  64
  65                        if (entry_len) {
  66                                /*
  67                                 * allocate memory to copy the entry into since
  68                                 * we will need to inject '\0' chars and squash
  69                                 * white-space before calling the callback
  70                                 */
  71                                entry_cpy = malloc(entry_len + 1);
  72                                if (entry_cpy) {
  73                                        /* copy just this entry and null term */
  74                                        strncpy(entry_cpy, entry, entry_len);
  75                                        entry_cpy[entry_len] = '\0';
  76                                } else
  77                                        return -ENOMEM;
  78                        }
  79                }
  80
  81                /* check if there is anything to process (e.g. not ",,,") */
  82                if (entry_cpy != NULL) {
  83                        attributes = strchr(entry_cpy, ENV_ATTR_SEP);
  84                        /* check if there is a ':' */
  85                        if (attributes != NULL) {
  86                                /* replace the ':' with '\0' to term name */
  87                                *attributes++ = '\0';
  88                                /* remove white-space from attributes */
  89                                attributes = strim(attributes);
  90                        }
  91                        /* remove white-space from name */
  92                        name = strim(entry_cpy);
  93
  94                        /* only call the callback if there is a name */
  95                        if (strlen(name) != 0) {
  96                                int retval = 0;
  97
  98                                retval = callback(name, attributes, priv);
  99                                if (retval) {
 100                                        free(entry_cpy);
 101                                        return retval;
 102                                }
 103                        }
 104                }
 105
 106                free(entry_cpy);
 107                entry = entry_end + 1;
 108        } while (entry_end != NULL);
 109
 110        return 0;
 111}
 112
 113#if defined(CONFIG_REGEX)
 114struct regex_callback_priv {
 115        const char *searched_for;
 116        char *regex;
 117        char *attributes;
 118};
 119
 120static int regex_callback(const char *name, const char *attributes, void *priv)
 121{
 122        int retval = 0;
 123        struct regex_callback_priv *cbp = (struct regex_callback_priv *)priv;
 124        struct slre slre;
 125        char regex[strlen(name) + 3];
 126
 127        /* Require the whole string to be described by the regex */
 128        sprintf(regex, "^%s$", name);
 129        if (slre_compile(&slre, regex)) {
 130                struct cap caps[slre.num_caps + 2];
 131
 132                if (slre_match(&slre, cbp->searched_for,
 133                               strlen(cbp->searched_for), caps)) {
 134                        free(cbp->regex);
 135                        if (!attributes) {
 136                                retval = -EINVAL;
 137                                goto done;
 138                        }
 139                        cbp->regex = malloc(strlen(regex) + 1);
 140                        if (cbp->regex) {
 141                                strcpy(cbp->regex, regex);
 142                        } else {
 143                                retval = -ENOMEM;
 144                                goto done;
 145                        }
 146
 147                        free(cbp->attributes);
 148                        cbp->attributes = malloc(strlen(attributes) + 1);
 149                        if (cbp->attributes) {
 150                                strcpy(cbp->attributes, attributes);
 151                        } else {
 152                                retval = -ENOMEM;
 153                                free(cbp->regex);
 154                                cbp->regex = NULL;
 155                                goto done;
 156                        }
 157                }
 158        } else {
 159                printf("Error compiling regex: %s\n", slre.err_str);
 160                retval = -EINVAL;
 161        }
 162done:
 163        return retval;
 164}
 165
 166/*
 167 * Retrieve the attributes string associated with a single name in the list
 168 * There is no protection on attributes being too small for the value
 169 */
 170int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
 171{
 172        if (!attributes)
 173                /* bad parameter */
 174                return -EINVAL;
 175        if (!attr_list)
 176                /* list not found */
 177                return -EINVAL;
 178
 179        struct regex_callback_priv priv;
 180        int retval;
 181
 182        priv.searched_for = name;
 183        priv.regex = NULL;
 184        priv.attributes = NULL;
 185        retval = env_attr_walk(attr_list, regex_callback, &priv);
 186        if (retval)
 187                return retval; /* error */
 188
 189        if (priv.regex) {
 190                strcpy(attributes, priv.attributes);
 191                free(priv.attributes);
 192                free(priv.regex);
 193                /* success */
 194                return 0;
 195        }
 196        return -ENOENT; /* not found in list */
 197}
 198#else
 199
 200/*
 201 * Search for the last exactly matching name in an attribute list
 202 */
 203static int reverse_name_search(const char *searched, const char *search_for,
 204        const char **result)
 205{
 206        int result_size = 0;
 207        const char *cur_searched = searched;
 208
 209        if (result)
 210                *result = NULL;
 211
 212        if (*search_for == '\0') {
 213                if (result)
 214                        *result = searched;
 215                return strlen(searched);
 216        }
 217
 218        for (;;) {
 219                const char *match = strstr(cur_searched, search_for);
 220                const char *prevch;
 221                const char *nextch;
 222
 223                /* Stop looking if no new match is found */
 224                if (match == NULL)
 225                        break;
 226
 227                prevch = match - 1;
 228                nextch = match + strlen(search_for);
 229
 230                /* Skip spaces */
 231                while (*prevch == ' ' && prevch >= searched)
 232                        prevch--;
 233                while (*nextch == ' ')
 234                        nextch++;
 235
 236                /* Start looking past the current match so last is found */
 237                cur_searched = match + 1;
 238                /* Check for an exact match */
 239                if (match != searched &&
 240                    *prevch != ENV_ATTR_LIST_DELIM &&
 241                    prevch != searched - 1)
 242                        continue;
 243                if (*nextch != ENV_ATTR_SEP &&
 244                    *nextch != ENV_ATTR_LIST_DELIM &&
 245                    *nextch != '\0')
 246                        continue;
 247
 248                if (result)
 249                        *result = match;
 250                result_size = strlen(search_for);
 251        }
 252
 253        return result_size;
 254}
 255
 256/*
 257 * Retrieve the attributes string associated with a single name in the list
 258 * There is no protection on attributes being too small for the value
 259 */
 260int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
 261{
 262        const char *entry = NULL;
 263        int entry_len;
 264
 265        if (!attributes)
 266                /* bad parameter */
 267                return -EINVAL;
 268        if (!attr_list)
 269                /* list not found */
 270                return -EINVAL;
 271
 272        entry_len = reverse_name_search(attr_list, name, &entry);
 273        if (entry != NULL) {
 274                int len;
 275
 276                /* skip the name */
 277                entry += entry_len;
 278                /* skip spaces */
 279                while (*entry == ' ')
 280                        entry++;
 281                if (*entry != ENV_ATTR_SEP)
 282                        len = 0;
 283                else {
 284                        const char *delim;
 285                        static const char delims[] = {
 286                                ENV_ATTR_LIST_DELIM, ' ', '\0'};
 287
 288                        /* skip the attr sep */
 289                        entry += 1;
 290                        /* skip spaces */
 291                        while (*entry == ' ')
 292                                entry++;
 293
 294                        delim = strpbrk(entry, delims);
 295                        if (delim == NULL)
 296                                len = strlen(entry);
 297                        else
 298                                len = delim - entry;
 299                        memcpy(attributes, entry, len);
 300                }
 301                attributes[len] = '\0';
 302
 303                /* success */
 304                return 0;
 305        }
 306
 307        /* not found in list */
 308        return -ENOENT;
 309}
 310#endif
 311