1 // SPDX-License-Identifier: LGPL-2.1+ 2 /* 3 * This implementation is based on code from uClibc-0.9.30.3 but was 4 * modified and extended for use within U-Boot. 5 * 6 * Copyright (C) 2010-2013 Wolfgang Denk <wd@denx.de> 7 * 8 * Original license header: 9 * 10 * Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc. 11 * This file is part of the GNU C Library. 12 * Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1993. 13 */ 14 15 #include <errno.h> 16 #include <malloc.h> 17 18 #ifdef USE_HOSTCC /* HOST build */ 19 # include <string.h> 20 # include <assert.h> 21 # include <ctype.h> 22 23 # ifndef debug 24 # ifdef DEBUG 25 # define debug(fmt,args...) printf(fmt ,##args) 26 # else 27 # define debug(fmt,args...) 28 # endif 29 # endif 30 #else /* U-Boot build */ 31 # include <common.h> 32 # include <linux/string.h> 33 # include <linux/ctype.h> 34 #endif 35 36 #ifndef CONFIG_ENV_MIN_ENTRIES /* minimum number of entries */ 37 #define CONFIG_ENV_MIN_ENTRIES 64 38 #endif 39 #ifndef CONFIG_ENV_MAX_ENTRIES /* maximum number of entries */ 40 #define CONFIG_ENV_MAX_ENTRIES 512 41 #endif 42 43 #define USED_FREE 0 44 #define USED_DELETED -1 45 46 #include <env_callback.h> 47 #include <env_flags.h> 48 #include <search.h> 49 #include <slre.h> 50 51 /* 52 * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 53 * [Knuth] The Art of Computer Programming, part 3 (6.4) 54 */ 55 56 /* 57 * The reentrant version has no static variables to maintain the state. 58 * Instead the interface of all functions is extended to take an argument 59 * which describes the current status. 60 */ 61 62 typedef struct _ENTRY { 63 int used; 64 ENTRY entry; 65 } _ENTRY; 66 67 68 static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, 69 int idx); 70 71 /* 72 * hcreate() 73 */ 74 75 /* 76 * For the used double hash method the table size has to be a prime. To 77 * correct the user given table size we need a prime test. This trivial 78 * algorithm is adequate because 79 * a) the code is (most probably) called a few times per program run and 80 * b) the number is small because the table must fit in the core 81 * */ 82 static int isprime(unsigned int number) 83 { 84 /* no even number will be passed */ 85 unsigned int div = 3; 86 87 while (div * div < number && number % div != 0) 88 div += 2; 89 90 return number % div != 0; 91 } 92 93 /* 94 * Before using the hash table we must allocate memory for it. 95 * Test for an existing table are done. We allocate one element 96 * more as the found prime number says. This is done for more effective 97 * indexing as explained in the comment for the hsearch function. 98 * The contents of the table is zeroed, especially the field used 99 * becomes zero. 100 */ 101 102 int hcreate_r(size_t nel, struct hsearch_data *htab) 103 { 104 /* Test for correct arguments. */ 105 if (htab == NULL) { 106 __set_errno(EINVAL); 107 return 0; 108 } 109 110 /* There is still another table active. Return with error. */ 111 if (htab->table != NULL) 112 return 0; 113 114 /* Change nel to the first prime number not smaller as nel. */ 115 nel |= 1; /* make odd */ 116 while (!isprime(nel)) 117 nel += 2; 118 119 htab->size = nel; 120 htab->filled = 0; 121 122 /* allocate memory and zero out */ 123 htab->table = (_ENTRY *) calloc(htab->size + 1, sizeof(_ENTRY)); 124 if (htab->table == NULL) 125 return 0; 126 127 /* everything went alright */ 128 return 1; 129 } 130 131 132 /* 133 * hdestroy() 134 */ 135 136 /* 137 * After using the hash table it has to be destroyed. The used memory can 138 * be freed and the local static variable can be marked as not used. 139 */ 140 141 void hdestroy_r(struct hsearch_data *htab) 142 { 143 int i; 144 145 /* Test for correct arguments. */ 146 if (htab == NULL) { 147 __set_errno(EINVAL); 148 return; 149 } 150 151 /* free used memory */ 152 for (i = 1; i <= htab->size; ++i) { 153 if (htab->table[i].used > 0) { 154 ENTRY *ep = &htab->table[i].entry; 155 156 free((void *)ep->key); 157 free(ep->data); 158 } 159 } 160 free(htab->table); 161 162 /* the sign for an existing table is an value != NULL in htable */ 163 htab->table = NULL; 164 } 165 166 /* 167 * hsearch() 168 */ 169 170 /* 171 * This is the search function. It uses double hashing with open addressing. 172 * The argument item.key has to be a pointer to an zero terminated, most 173 * probably strings of chars. The function for generating a number of the 174 * strings is simple but fast. It can be replaced by a more complex function 175 * like ajw (see [Aho,Sethi,Ullman]) if the needs are shown. 176 * 177 * We use an trick to speed up the lookup. The table is created by hcreate 178 * with one more element available. This enables us to use the index zero 179 * special. This index will never be used because we store the first hash 180 * index in the field used where zero means not used. Every other value 181 * means used. The used field can be used as a first fast comparison for 182 * equality of the stored and the parameter value. This helps to prevent 183 * unnecessary expensive calls of strcmp. 184 * 185 * This implementation differs from the standard library version of 186 * this function in a number of ways: 187 * 188 * - While the standard version does not make any assumptions about 189 * the type of the stored data objects at all, this implementation 190 * works with NUL terminated strings only. 191 * - Instead of storing just pointers to the original objects, we 192 * create local copies so the caller does not need to care about the 193 * data any more. 194 * - The standard implementation does not provide a way to update an 195 * existing entry. This version will create a new entry or update an 196 * existing one when both "action == ENTER" and "item.data != NULL". 197 * - Instead of returning 1 on success, we return the index into the 198 * internal hash table, which is also guaranteed to be positive. 199 * This allows us direct access to the found hash table slot for 200 * example for functions like hdelete(). 201 */ 202 203 int hmatch_r(const char *match, int last_idx, ENTRY ** retval, 204 struct hsearch_data *htab) 205 { 206 unsigned int idx; 207 size_t key_len = strlen(match); 208 209 for (idx = last_idx + 1; idx < htab->size; ++idx) { 210 if (htab->table[idx].used <= 0) 211 continue; 212 if (!strncmp(match, htab->table[idx].entry.key, key_len)) { 213 *retval = &htab->table[idx].entry; 214 return idx; 215 } 216 } 217 218 __set_errno(ESRCH); 219 *retval = NULL; 220 return 0; 221 } 222 223 /* 224 * Compare an existing entry with the desired key, and overwrite if the action 225 * is ENTER. This is simply a helper function for hsearch_r(). 226 */ 227 static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, 228 ENTRY **retval, struct hsearch_data *htab, int flag, 229 unsigned int hval, unsigned int idx) 230 { 231 if (htab->table[idx].used == hval 232 && strcmp(item.key, htab->table[idx].entry.key) == 0) { 233 /* Overwrite existing value? */ 234 if ((action == ENTER) && (item.data != NULL)) { 235 /* check for permission */ 236 if (htab->change_ok != NULL && htab->change_ok( 237 &htab->table[idx].entry, item.data, 238 env_op_overwrite, flag)) { 239 debug("change_ok() rejected setting variable " 240 "%s, skipping it!\n", item.key); 241 __set_errno(EPERM); 242 *retval = NULL; 243 return 0; 244 } 245 246 /* If there is a callback, call it */ 247 if (htab->table[idx].entry.callback && 248 htab->table[idx].entry.callback(item.key, 249 item.data, env_op_overwrite, flag)) { 250 debug("callback() rejected setting variable " 251 "%s, skipping it!\n", item.key); 252 __set_errno(EINVAL); 253 *retval = NULL; 254 return 0; 255 } 256 257 free(htab->table[idx].entry.data); 258 htab->table[idx].entry.data = strdup(item.data); 259 if (!htab->table[idx].entry.data) { 260 __set_errno(ENOMEM); 261 *retval = NULL; 262 return 0; 263 } 264 } 265 /* return found entry */ 266 *retval = &htab->table[idx].entry; 267 return idx; 268 } 269 /* keep searching */ 270 return -1; 271 } 272 273 int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, 274 struct hsearch_data *htab, int flag) 275 { 276 unsigned int hval; 277 unsigned int count; 278 unsigned int len = strlen(item.key); 279 unsigned int idx; 280 unsigned int first_deleted = 0; 281 int ret; 282 283 /* Compute an value for the given string. Perhaps use a better method. */ 284 hval = len; 285 count = len; 286 while (count-- > 0) { 287 hval <<= 4; 288 hval += item.key[count]; 289 } 290 291 /* 292 * First hash function: 293 * simply take the modul but prevent zero. 294 */ 295 hval %= htab->size; 296 if (hval == 0) 297 ++hval; 298 299 /* The first index tried. */ 300 idx = hval; 301 302 if (htab->table[idx].used) { 303 /* 304 * Further action might be required according to the 305 * action value. 306 */ 307 unsigned hval2; 308 309 if (htab->table[idx].used == USED_DELETED 310 && !first_deleted) 311 first_deleted = idx; 312 313 ret = _compare_and_overwrite_entry(item, action, retval, htab, 314 flag, hval, idx); 315 if (ret != -1) 316 return ret; 317 318 /* 319 * Second hash function: 320 * as suggested in [Knuth] 321 */ 322 hval2 = 1 + hval % (htab->size - 2); 323 324 do { 325 /* 326 * Because SIZE is prime this guarantees to 327 * step through all available indices. 328 */ 329 if (idx <= hval2) 330 idx = htab->size + idx - hval2; 331 else 332 idx -= hval2; 333 334 /* 335 * If we visited all entries leave the loop 336 * unsuccessfully. 337 */ 338 if (idx == hval) 339 break; 340 341 if (htab->table[idx].used == USED_DELETED 342 && !first_deleted) 343 first_deleted = idx; 344 345 /* If entry is found use it. */ 346 ret = _compare_and_overwrite_entry(item, action, retval, 347 htab, flag, hval, idx); 348 if (ret != -1) 349 return ret; 350 } 351 while (htab->table[idx].used != USED_FREE); 352 } 353 354 /* An empty bucket has been found. */ 355 if (action == ENTER) { 356 /* 357 * If table is full and another entry should be 358 * entered return with error. 359 */ 360 if (htab->filled == htab->size) { 361 __set_errno(ENOMEM); 362 *retval = NULL; 363 return 0; 364 } 365 366 /* 367 * Create new entry; 368 * create copies of item.key and item.data 369 */ 370 if (first_deleted) 371 idx = first_deleted; 372 373 htab->table[idx].used = hval; 374 htab->table[idx].entry.key = strdup(item.key); 375 htab->table[idx].entry.data = strdup(item.data); 376 if (!htab->table[idx].entry.key || 377 !htab->table[idx].entry.data) { 378 __set_errno(ENOMEM); 379 *retval = NULL; 380 return 0; 381 } 382 383 ++htab->filled; 384 385 /* This is a new entry, so look up a possible callback */ 386 env_callback_init(&htab->table[idx].entry); 387 /* Also look for flags */ 388 env_flags_init(&htab->table[idx].entry); 389 390 /* check for permission */ 391 if (htab->change_ok != NULL && htab->change_ok( 392 &htab->table[idx].entry, item.data, env_op_create, flag)) { 393 debug("change_ok() rejected setting variable " 394 "%s, skipping it!\n", item.key); 395 _hdelete(item.key, htab, &htab->table[idx].entry, idx); 396 __set_errno(EPERM); 397 *retval = NULL; 398 return 0; 399 } 400 401 /* If there is a callback, call it */ 402 if (htab->table[idx].entry.callback && 403 htab->table[idx].entry.callback(item.key, item.data, 404 env_op_create, flag)) { 405 debug("callback() rejected setting variable " 406 "%s, skipping it!\n", item.key); 407 _hdelete(item.key, htab, &htab->table[idx].entry, idx); 408 __set_errno(EINVAL); 409 *retval = NULL; 410 return 0; 411 } 412 413 /* return new entry */ 414 *retval = &htab->table[idx].entry; 415 return 1; 416 } 417 418 __set_errno(ESRCH); 419 *retval = NULL; 420 return 0; 421 } 422 423 424 /* 425 * hdelete() 426 */ 427 428 /* 429 * The standard implementation of hsearch(3) does not provide any way 430 * to delete any entries from the hash table. We extend the code to 431 * do that. 432 */ 433 434 static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, 435 int idx) 436 { 437 /* free used ENTRY */ 438 debug("hdelete: DELETING key \"%s\"\n", key); 439 free((void *)ep->key); 440 free(ep->data); 441 ep->callback = NULL; 442 ep->flags = 0; 443 htab->table[idx].used = USED_DELETED; 444 445 --htab->filled; 446 } 447 448 int hdelete_r(const char *key, struct hsearch_data *htab, int flag) 449 { 450 ENTRY e, *ep; 451 int idx; 452 453 debug("hdelete: DELETE key \"%s\"\n", key); 454 455 e.key = (char *)key; 456 457 idx = hsearch_r(e, FIND, &ep, htab, 0); 458 if (idx == 0) { 459 __set_errno(ESRCH); 460 return 0; /* not found */ 461 } 462 463 /* Check for permission */ 464 if (htab->change_ok != NULL && 465 htab->change_ok(ep, NULL, env_op_delete, flag)) { 466 debug("change_ok() rejected deleting variable " 467 "%s, skipping it!\n", key); 468 __set_errno(EPERM); 469 return 0; 470 } 471 472 /* If there is a callback, call it */ 473 if (htab->table[idx].entry.callback && 474 htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) { 475 debug("callback() rejected deleting variable " 476 "%s, skipping it!\n", key); 477 __set_errno(EINVAL); 478 return 0; 479 } 480 481 _hdelete(key, htab, ep, idx); 482 483 return 1; 484 } 485 486 #if !(defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_SAVEENV)) 487 /* 488 * hexport() 489 */ 490 491 /* 492 * Export the data stored in the hash table in linearized form. 493 * 494 * Entries are exported as "name=value" strings, separated by an 495 * arbitrary (non-NUL, of course) separator character. This allows to 496 * use this function both when formatting the U-Boot environment for 497 * external storage (using '\0' as separator), but also when using it 498 * for the "printenv" command to print all variables, simply by using 499 * as '\n" as separator. This can also be used for new features like 500 * exporting the environment data as text file, including the option 501 * for later re-import. 502 * 503 * The entries in the result list will be sorted by ascending key 504 * values. 505 * 506 * If the separator character is different from NUL, then any 507 * separator characters and backslash characters in the values will 508 * be escaped by a preceding backslash in output. This is needed for 509 * example to enable multi-line values, especially when the output 510 * shall later be parsed (for example, for re-import). 511 * 512 * There are several options how the result buffer is handled: 513 * 514 * *resp size 515 * ----------- 516 * NULL 0 A string of sufficient length will be allocated. 517 * NULL >0 A string of the size given will be 518 * allocated. An error will be returned if the size is 519 * not sufficient. Any unused bytes in the string will 520 * be '\0'-padded. 521 * !NULL 0 The user-supplied buffer will be used. No length 522 * checking will be performed, i. e. it is assumed that 523 * the buffer size will always be big enough. DANGEROUS. 524 * !NULL >0 The user-supplied buffer will be used. An error will 525 * be returned if the size is not sufficient. Any unused 526 * bytes in the string will be '\0'-padded. 527 */ 528 529 static int cmpkey(const void *p1, const void *p2) 530 { 531 ENTRY *e1 = *(ENTRY **) p1; 532 ENTRY *e2 = *(ENTRY **) p2; 533 534 return (strcmp(e1->key, e2->key)); 535 } 536 537 static int match_string(int flag, const char *str, const char *pat, void *priv) 538 { 539 switch (flag & H_MATCH_METHOD) { 540 case H_MATCH_IDENT: 541 if (strcmp(str, pat) == 0) 542 return 1; 543 break; 544 case H_MATCH_SUBSTR: 545 if (strstr(str, pat)) 546 return 1; 547 break; 548 #ifdef CONFIG_REGEX 549 case H_MATCH_REGEX: 550 { 551 struct slre *slrep = (struct slre *)priv; 552 553 if (slre_match(slrep, str, strlen(str), NULL)) 554 return 1; 555 } 556 break; 557 #endif 558 default: 559 printf("## ERROR: unsupported match method: 0x%02x\n", 560 flag & H_MATCH_METHOD); 561 break; 562 } 563 return 0; 564 } 565 566 static int match_entry(ENTRY *ep, int flag, 567 int argc, char * const argv[]) 568 { 569 int arg; 570 void *priv = NULL; 571 572 for (arg = 0; arg < argc; ++arg) { 573 #ifdef CONFIG_REGEX 574 struct slre slre; 575 576 if (slre_compile(&slre, argv[arg]) == 0) { 577 printf("Error compiling regex: %s\n", slre.err_str); 578 return 0; 579 } 580 581 priv = (void *)&slre; 582 #endif 583 if (flag & H_MATCH_KEY) { 584 if (match_string(flag, ep->key, argv[arg], priv)) 585 return 1; 586 } 587 if (flag & H_MATCH_DATA) { 588 if (match_string(flag, ep->data, argv[arg], priv)) 589 return 1; 590 } 591 } 592 return 0; 593 } 594 595 ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, 596 char **resp, size_t size, 597 int argc, char * const argv[]) 598 { 599 ENTRY *list[htab->size]; 600 char *res, *p; 601 size_t totlen; 602 int i, n; 603 604 /* Test for correct arguments. */ 605 if ((resp == NULL) || (htab == NULL)) { 606 __set_errno(EINVAL); 607 return (-1); 608 } 609 610 debug("EXPORT table = %p, htab.size = %d, htab.filled = %d, size = %lu\n", 611 htab, htab->size, htab->filled, (ulong)size); 612 /* 613 * Pass 1: 614 * search used entries, 615 * save addresses and compute total length 616 */ 617 for (i = 1, n = 0, totlen = 0; i <= htab->size; ++i) { 618 619 if (htab->table[i].used > 0) { 620 ENTRY *ep = &htab->table[i].entry; 621 int found = match_entry(ep, flag, argc, argv); 622 623 if ((argc > 0) && (found == 0)) 624 continue; 625 626 if ((flag & H_HIDE_DOT) && ep->key[0] == '.') 627 continue; 628 629 list[n++] = ep; 630 631 totlen += strlen(ep->key); 632 633 if (sep == '\0') { 634 totlen += strlen(ep->data); 635 } else { /* check if escapes are needed */ 636 char *s = ep->data; 637 638 while (*s) { 639 ++totlen; 640 /* add room for needed escape chars */ 641 if ((*s == sep) || (*s == '\\')) 642 ++totlen; 643 ++s; 644 } 645 } 646 totlen += 2; /* for '=' and 'sep' char */ 647 } 648 } 649 650 #ifdef DEBUG 651 /* Pass 1a: print unsorted list */ 652 printf("Unsorted: n=%d\n", n); 653 for (i = 0; i < n; ++i) { 654 printf("\t%3d: %p ==> %-10s => %s\n", 655 i, list[i], list[i]->key, list[i]->data); 656 } 657 #endif 658 659 /* Sort list by keys */ 660 qsort(list, n, sizeof(ENTRY *), cmpkey); 661 662 /* Check if the user supplied buffer size is sufficient */ 663 if (size) { 664 if (size < totlen + 1) { /* provided buffer too small */ 665 printf("Env export buffer too small: %lu, but need %lu\n", 666 (ulong)size, (ulong)totlen + 1); 667 __set_errno(ENOMEM); 668 return (-1); 669 } 670 } else { 671 size = totlen + 1; 672 } 673 674 /* Check if the user provided a buffer */ 675 if (*resp) { 676 /* yes; clear it */ 677 res = *resp; 678 memset(res, '\0', size); 679 } else { 680 /* no, allocate and clear one */ 681 *resp = res = calloc(1, size); 682 if (res == NULL) { 683 __set_errno(ENOMEM); 684 return (-1); 685 } 686 } 687 /* 688 * Pass 2: 689 * export sorted list of result data 690 */ 691 for (i = 0, p = res; i < n; ++i) { 692 const char *s; 693 694 s = list[i]->key; 695 while (*s) 696 *p++ = *s++; 697 *p++ = '='; 698 699 s = list[i]->data; 700 701 while (*s) { 702 if ((*s == sep) || (*s == '\\')) 703 *p++ = '\\'; /* escape */ 704 *p++ = *s++; 705 } 706 *p++ = sep; 707 } 708 *p = '\0'; /* terminate result */ 709 710 return size; 711 } 712 #endif 713 714 715 /* 716 * himport() 717 */ 718 719 /* 720 * Check whether variable 'name' is amongst vars[], 721 * and remove all instances by setting the pointer to NULL 722 */ 723 static int drop_var_from_set(const char *name, int nvars, char * vars[]) 724 { 725 int i = 0; 726 int res = 0; 727 728 /* No variables specified means process all of them */ 729 if (nvars == 0) 730 return 1; 731 732 for (i = 0; i < nvars; i++) { 733 if (vars[i] == NULL) 734 continue; 735 /* If we found it, delete all of them */ 736 if (!strcmp(name, vars[i])) { 737 vars[i] = NULL; 738 res = 1; 739 } 740 } 741 if (!res) 742 debug("Skipping non-listed variable %s\n", name); 743 744 return res; 745 } 746 747 /* 748 * Import linearized data into hash table. 749 * 750 * This is the inverse function to hexport(): it takes a linear list 751 * of "name=value" pairs and creates hash table entries from it. 752 * 753 * Entries without "value", i. e. consisting of only "name" or 754 * "name=", will cause this entry to be deleted from the hash table. 755 * 756 * The "flag" argument can be used to control the behaviour: when the 757 * H_NOCLEAR bit is set, then an existing hash table will kept, i. e. 758 * new data will be added to an existing hash table; otherwise, if no 759 * vars are passed, old data will be discarded and a new hash table 760 * will be created. If vars are passed, passed vars that are not in 761 * the linear list of "name=value" pairs will be removed from the 762 * current hash table. 763 * 764 * The separator character for the "name=value" pairs can be selected, 765 * so we both support importing from externally stored environment 766 * data (separated by NUL characters) and from plain text files 767 * (entries separated by newline characters). 768 * 769 * To allow for nicely formatted text input, leading white space 770 * (sequences of SPACE and TAB chars) is ignored, and entries starting 771 * (after removal of any leading white space) with a '#' character are 772 * considered comments and ignored. 773 * 774 * [NOTE: this means that a variable name cannot start with a '#' 775 * character.] 776 * 777 * When using a non-NUL separator character, backslash is used as 778 * escape character in the value part, allowing for example for 779 * multi-line values. 780 * 781 * In theory, arbitrary separator characters can be used, but only 782 * '\0' and '\n' have really been tested. 783 */ 784 785 int himport_r(struct hsearch_data *htab, 786 const char *env, size_t size, const char sep, int flag, 787 int crlf_is_lf, int nvars, char * const vars[]) 788 { 789 char *data, *sp, *dp, *name, *value; 790 char *localvars[nvars]; 791 int i; 792 793 /* Test for correct arguments. */ 794 if (htab == NULL) { 795 __set_errno(EINVAL); 796 return 0; 797 } 798 799 /* we allocate new space to make sure we can write to the array */ 800 if ((data = malloc(size + 1)) == NULL) { 801 debug("himport_r: can't malloc %lu bytes\n", (ulong)size + 1); 802 __set_errno(ENOMEM); 803 return 0; 804 } 805 memcpy(data, env, size); 806 data[size] = '\0'; 807 dp = data; 808 809 /* make a local copy of the list of variables */ 810 if (nvars) 811 memcpy(localvars, vars, sizeof(vars[0]) * nvars); 812 813 if ((flag & H_NOCLEAR) == 0 && !nvars) { 814 /* Destroy old hash table if one exists */ 815 debug("Destroy Hash Table: %p table = %p\n", htab, 816 htab->table); 817 if (htab->table) 818 hdestroy_r(htab); 819 } 820 821 /* 822 * Create new hash table (if needed). The computation of the hash 823 * table size is based on heuristics: in a sample of some 70+ 824 * existing systems we found an average size of 39+ bytes per entry 825 * in the environment (for the whole key=value pair). Assuming a 826 * size of 8 per entry (= safety factor of ~5) should provide enough 827 * safety margin for any existing environment definitions and still 828 * allow for more than enough dynamic additions. Note that the 829 * "size" argument is supposed to give the maximum environment size 830 * (CONFIG_ENV_SIZE). This heuristics will result in 831 * unreasonably large numbers (and thus memory footprint) for 832 * big flash environments (>8,000 entries for 64 KB 833 * environment size), so we clip it to a reasonable value. 834 * On the other hand we need to add some more entries for free 835 * space when importing very small buffers. Both boundaries can 836 * be overwritten in the board config file if needed. 837 */ 838 839 if (!htab->table) { 840 int nent = CONFIG_ENV_MIN_ENTRIES + size / 8; 841 842 if (nent > CONFIG_ENV_MAX_ENTRIES) 843 nent = CONFIG_ENV_MAX_ENTRIES; 844 845 debug("Create Hash Table: N=%d\n", nent); 846 847 if (hcreate_r(nent, htab) == 0) { 848 free(data); 849 return 0; 850 } 851 } 852 853 if (!size) { 854 free(data); 855 return 1; /* everything OK */ 856 } 857 if(crlf_is_lf) { 858 /* Remove Carriage Returns in front of Line Feeds */ 859 unsigned ignored_crs = 0; 860 for(;dp < data + size && *dp; ++dp) { 861 if(*dp == '\r' && 862 dp < data + size - 1 && *(dp+1) == '\n') 863 ++ignored_crs; 864 else 865 *(dp-ignored_crs) = *dp; 866 } 867 size -= ignored_crs; 868 dp = data; 869 } 870 /* Parse environment; allow for '\0' and 'sep' as separators */ 871 do { 872 ENTRY e, *rv; 873 874 /* skip leading white space */ 875 while (isblank(*dp)) 876 ++dp; 877 878 /* skip comment lines */ 879 if (*dp == '#') { 880 while (*dp && (*dp != sep)) 881 ++dp; 882 ++dp; 883 continue; 884 } 885 886 /* parse name */ 887 for (name = dp; *dp != '=' && *dp && *dp != sep; ++dp) 888 ; 889 890 /* deal with "name" and "name=" entries (delete var) */ 891 if (*dp == '\0' || *(dp + 1) == '\0' || 892 *dp == sep || *(dp + 1) == sep) { 893 if (*dp == '=') 894 *dp++ = '\0'; 895 *dp++ = '\0'; /* terminate name */ 896 897 debug("DELETE CANDIDATE: \"%s\"\n", name); 898 if (!drop_var_from_set(name, nvars, localvars)) 899 continue; 900 901 if (hdelete_r(name, htab, flag) == 0) 902 debug("DELETE ERROR ##############################\n"); 903 904 continue; 905 } 906 *dp++ = '\0'; /* terminate name */ 907 908 /* parse value; deal with escapes */ 909 for (value = sp = dp; *dp && (*dp != sep); ++dp) { 910 if ((*dp == '\\') && *(dp + 1)) 911 ++dp; 912 *sp++ = *dp; 913 } 914 *sp++ = '\0'; /* terminate value */ 915 ++dp; 916 917 if (*name == 0) { 918 debug("INSERT: unable to use an empty key\n"); 919 __set_errno(EINVAL); 920 free(data); 921 return 0; 922 } 923 924 /* Skip variables which are not supposed to be processed */ 925 if (!drop_var_from_set(name, nvars, localvars)) 926 continue; 927 928 /* enter into hash table */ 929 e.key = name; 930 e.data = value; 931 932 hsearch_r(e, ENTER, &rv, htab, flag); 933 if (rv == NULL) 934 printf("himport_r: can't insert \"%s=%s\" into hash table\n", 935 name, value); 936 937 debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n", 938 htab, htab->filled, htab->size, 939 rv, name, value); 940 } while ((dp < data + size) && *dp); /* size check needed for text */ 941 /* without '\0' termination */ 942 debug("INSERT: free(data = %p)\n", data); 943 free(data); 944 945 if (flag & H_NOCLEAR) 946 goto end; 947 948 /* process variables which were not considered */ 949 for (i = 0; i < nvars; i++) { 950 if (localvars[i] == NULL) 951 continue; 952 /* 953 * All variables which were not deleted from the variable list 954 * were not present in the imported env 955 * This could mean two things: 956 * a) if the variable was present in current env, we delete it 957 * b) if the variable was not present in current env, we notify 958 * it might be a typo 959 */ 960 if (hdelete_r(localvars[i], htab, flag) == 0) 961 printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]); 962 else 963 printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]); 964 } 965 966 end: 967 debug("INSERT: done\n"); 968 return 1; /* everything OK */ 969 } 970 971 /* 972 * hwalk_r() 973 */ 974 975 /* 976 * Walk all of the entries in the hash, calling the callback for each one. 977 * this allows some generic operation to be performed on each element. 978 */ 979 int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *)) 980 { 981 int i; 982 int retval; 983 984 for (i = 1; i <= htab->size; ++i) { 985 if (htab->table[i].used > 0) { 986 retval = callback(&htab->table[i].entry); 987 if (retval) 988 return retval; 989 } 990 } 991 992 return 0; 993 } 994