1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include <errno.h>
17#include <malloc.h>
18
19#ifdef USE_HOSTCC
20# include <string.h>
21# include <assert.h>
22# include <ctype.h>
23
24# ifndef debug
25# ifdef DEBUG
26# define debug(fmt,args...) printf(fmt ,##args)
27# else
28# define debug(fmt,args...)
29# endif
30# endif
31#else
32# include <common.h>
33# include <linux/string.h>
34# include <linux/ctype.h>
35#endif
36
37#ifndef CONFIG_ENV_MIN_ENTRIES
38#define CONFIG_ENV_MIN_ENTRIES 64
39#endif
40#ifndef CONFIG_ENV_MAX_ENTRIES
41#define CONFIG_ENV_MAX_ENTRIES 512
42#endif
43
44#include <env_callback.h>
45#include <env_flags.h>
46#include <search.h>
47#include <slre.h>
48
49
50
51
52
53
54
55
56
57
58
59
60typedef struct _ENTRY {
61 int used;
62 ENTRY entry;
63} _ENTRY;
64
65
66static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
67 int idx);
68
69
70
71
72
73
74
75
76
77
78
79
80static int isprime(unsigned int number)
81{
82
83 unsigned int div = 3;
84
85 while (div * div < number && number % div != 0)
86 div += 2;
87
88 return number % div != 0;
89}
90
91
92
93
94
95
96
97
98
99
100int hcreate_r(size_t nel, struct hsearch_data *htab)
101{
102
103 if (htab == NULL) {
104 __set_errno(EINVAL);
105 return 0;
106 }
107
108
109 if (htab->table != NULL)
110 return 0;
111
112
113 nel |= 1;
114 while (!isprime(nel))
115 nel += 2;
116
117 htab->size = nel;
118 htab->filled = 0;
119
120
121 htab->table = (_ENTRY *) calloc(htab->size + 1, sizeof(_ENTRY));
122 if (htab->table == NULL)
123 return 0;
124
125
126 return 1;
127}
128
129
130
131
132
133
134
135
136
137
138
139void hdestroy_r(struct hsearch_data *htab)
140{
141 int i;
142
143
144 if (htab == NULL) {
145 __set_errno(EINVAL);
146 return;
147 }
148
149
150 for (i = 1; i <= htab->size; ++i) {
151 if (htab->table[i].used > 0) {
152 ENTRY *ep = &htab->table[i].entry;
153
154 free((void *)ep->key);
155 free(ep->data);
156 }
157 }
158 free(htab->table);
159
160
161 htab->table = NULL;
162}
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201int hmatch_r(const char *match, int last_idx, ENTRY ** retval,
202 struct hsearch_data *htab)
203{
204 unsigned int idx;
205 size_t key_len = strlen(match);
206
207 for (idx = last_idx + 1; idx < htab->size; ++idx) {
208 if (htab->table[idx].used <= 0)
209 continue;
210 if (!strncmp(match, htab->table[idx].entry.key, key_len)) {
211 *retval = &htab->table[idx].entry;
212 return idx;
213 }
214 }
215
216 __set_errno(ESRCH);
217 *retval = NULL;
218 return 0;
219}
220
221
222
223
224
225static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
226 ENTRY **retval, struct hsearch_data *htab, int flag,
227 unsigned int hval, unsigned int idx)
228{
229 if (htab->table[idx].used == hval
230 && strcmp(item.key, htab->table[idx].entry.key) == 0) {
231
232 if ((action == ENTER) && (item.data != NULL)) {
233
234 if (htab->change_ok != NULL && htab->change_ok(
235 &htab->table[idx].entry, item.data,
236 env_op_overwrite, flag)) {
237 debug("change_ok() rejected setting variable "
238 "%s, skipping it!\n", item.key);
239 __set_errno(EPERM);
240 *retval = NULL;
241 return 0;
242 }
243
244
245 if (htab->table[idx].entry.callback &&
246 htab->table[idx].entry.callback(item.key,
247 item.data, env_op_overwrite, flag)) {
248 debug("callback() rejected setting variable "
249 "%s, skipping it!\n", item.key);
250 __set_errno(EINVAL);
251 *retval = NULL;
252 return 0;
253 }
254
255 free(htab->table[idx].entry.data);
256 htab->table[idx].entry.data = strdup(item.data);
257 if (!htab->table[idx].entry.data) {
258 __set_errno(ENOMEM);
259 *retval = NULL;
260 return 0;
261 }
262 }
263
264 *retval = &htab->table[idx].entry;
265 return idx;
266 }
267
268 return -1;
269}
270
271int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
272 struct hsearch_data *htab, int flag)
273{
274 unsigned int hval;
275 unsigned int count;
276 unsigned int len = strlen(item.key);
277 unsigned int idx;
278 unsigned int first_deleted = 0;
279 int ret;
280
281
282 hval = len;
283 count = len;
284 while (count-- > 0) {
285 hval <<= 4;
286 hval += item.key[count];
287 }
288
289
290
291
292
293 hval %= htab->size;
294 if (hval == 0)
295 ++hval;
296
297
298 idx = hval;
299
300 if (htab->table[idx].used) {
301
302
303
304
305 unsigned hval2;
306
307 if (htab->table[idx].used == -1
308 && !first_deleted)
309 first_deleted = idx;
310
311 ret = _compare_and_overwrite_entry(item, action, retval, htab,
312 flag, hval, idx);
313 if (ret != -1)
314 return ret;
315
316
317
318
319
320 hval2 = 1 + hval % (htab->size - 2);
321
322 do {
323
324
325
326
327 if (idx <= hval2)
328 idx = htab->size + idx - hval2;
329 else
330 idx -= hval2;
331
332
333
334
335
336 if (idx == hval)
337 break;
338
339
340 ret = _compare_and_overwrite_entry(item, action, retval,
341 htab, flag, hval, idx);
342 if (ret != -1)
343 return ret;
344 }
345 while (htab->table[idx].used);
346 }
347
348
349 if (action == ENTER) {
350
351
352
353
354 if (htab->filled == htab->size) {
355 __set_errno(ENOMEM);
356 *retval = NULL;
357 return 0;
358 }
359
360
361
362
363
364 if (first_deleted)
365 idx = first_deleted;
366
367 htab->table[idx].used = hval;
368 htab->table[idx].entry.key = strdup(item.key);
369 htab->table[idx].entry.data = strdup(item.data);
370 if (!htab->table[idx].entry.key ||
371 !htab->table[idx].entry.data) {
372 __set_errno(ENOMEM);
373 *retval = NULL;
374 return 0;
375 }
376
377 ++htab->filled;
378
379
380 env_callback_init(&htab->table[idx].entry);
381
382 env_flags_init(&htab->table[idx].entry);
383
384
385 if (htab->change_ok != NULL && htab->change_ok(
386 &htab->table[idx].entry, item.data, env_op_create, flag)) {
387 debug("change_ok() rejected setting variable "
388 "%s, skipping it!\n", item.key);
389 _hdelete(item.key, htab, &htab->table[idx].entry, idx);
390 __set_errno(EPERM);
391 *retval = NULL;
392 return 0;
393 }
394
395
396 if (htab->table[idx].entry.callback &&
397 htab->table[idx].entry.callback(item.key, item.data,
398 env_op_create, flag)) {
399 debug("callback() rejected setting variable "
400 "%s, skipping it!\n", item.key);
401 _hdelete(item.key, htab, &htab->table[idx].entry, idx);
402 __set_errno(EINVAL);
403 *retval = NULL;
404 return 0;
405 }
406
407
408 *retval = &htab->table[idx].entry;
409 return 1;
410 }
411
412 __set_errno(ESRCH);
413 *retval = NULL;
414 return 0;
415}
416
417
418
419
420
421
422
423
424
425
426
427
428static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
429 int idx)
430{
431
432 debug("hdelete: DELETING key \"%s\"\n", key);
433 free((void *)ep->key);
434 free(ep->data);
435 ep->callback = NULL;
436 ep->flags = 0;
437 htab->table[idx].used = -1;
438
439 --htab->filled;
440}
441
442int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
443{
444 ENTRY e, *ep;
445 int idx;
446
447 debug("hdelete: DELETE key \"%s\"\n", key);
448
449 e.key = (char *)key;
450
451 idx = hsearch_r(e, FIND, &ep, htab, 0);
452 if (idx == 0) {
453 __set_errno(ESRCH);
454 return 0;
455 }
456
457
458 if (htab->change_ok != NULL &&
459 htab->change_ok(ep, NULL, env_op_delete, flag)) {
460 debug("change_ok() rejected deleting variable "
461 "%s, skipping it!\n", key);
462 __set_errno(EPERM);
463 return 0;
464 }
465
466
467 if (htab->table[idx].entry.callback &&
468 htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) {
469 debug("callback() rejected deleting variable "
470 "%s, skipping it!\n", key);
471 __set_errno(EINVAL);
472 return 0;
473 }
474
475 _hdelete(key, htab, ep, idx);
476
477 return 1;
478}
479
480
481
482
483
484#ifndef CONFIG_SPL_BUILD
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523static int cmpkey(const void *p1, const void *p2)
524{
525 ENTRY *e1 = *(ENTRY **) p1;
526 ENTRY *e2 = *(ENTRY **) p2;
527
528 return (strcmp(e1->key, e2->key));
529}
530
531static int match_string(int flag, const char *str, const char *pat, void *priv)
532{
533 switch (flag & H_MATCH_METHOD) {
534 case H_MATCH_IDENT:
535 if (strcmp(str, pat) == 0)
536 return 1;
537 break;
538 case H_MATCH_SUBSTR:
539 if (strstr(str, pat))
540 return 1;
541 break;
542#ifdef CONFIG_REGEX
543 case H_MATCH_REGEX:
544 {
545 struct slre *slrep = (struct slre *)priv;
546 struct cap caps[slrep->num_caps + 2];
547
548 if (slre_match(slrep, str, strlen(str), caps))
549 return 1;
550 }
551 break;
552#endif
553 default:
554 printf("## ERROR: unsupported match method: 0x%02x\n",
555 flag & H_MATCH_METHOD);
556 break;
557 }
558 return 0;
559}
560
561static int match_entry(ENTRY *ep, int flag,
562 int argc, char * const argv[])
563{
564 int arg;
565 void *priv = NULL;
566
567 for (arg = 0; arg < argc; ++arg) {
568#ifdef CONFIG_REGEX
569 struct slre slre;
570
571 if (slre_compile(&slre, argv[arg]) == 0) {
572 printf("Error compiling regex: %s\n", slre.err_str);
573 return 0;
574 }
575
576 priv = (void *)&slre;
577#endif
578 if (flag & H_MATCH_KEY) {
579 if (match_string(flag, ep->key, argv[arg], priv))
580 return 1;
581 }
582 if (flag & H_MATCH_DATA) {
583 if (match_string(flag, ep->data, argv[arg], priv))
584 return 1;
585 }
586 }
587 return 0;
588}
589
590ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
591 char **resp, size_t size,
592 int argc, char * const argv[])
593{
594 ENTRY *list[htab->size];
595 char *res, *p;
596 size_t totlen;
597 int i, n;
598
599
600 if ((resp == NULL) || (htab == NULL)) {
601 __set_errno(EINVAL);
602 return (-1);
603 }
604
605 debug("EXPORT table = %p, htab.size = %d, htab.filled = %d, "
606 "size = %zu\n", htab, htab->size, htab->filled, size);
607
608
609
610
611
612 for (i = 1, n = 0, totlen = 0; i <= htab->size; ++i) {
613
614 if (htab->table[i].used > 0) {
615 ENTRY *ep = &htab->table[i].entry;
616 int found = match_entry(ep, flag, argc, argv);
617
618 if ((argc > 0) && (found == 0))
619 continue;
620
621 if ((flag & H_HIDE_DOT) && ep->key[0] == '.')
622 continue;
623
624 list[n++] = ep;
625
626 totlen += strlen(ep->key) + 2;
627
628 if (sep == '\0') {
629 totlen += strlen(ep->data);
630 } else {
631 char *s = ep->data;
632
633 while (*s) {
634 ++totlen;
635
636 if ((*s == sep) || (*s == '\\'))
637 ++totlen;
638 ++s;
639 }
640 }
641 totlen += 2;
642 }
643 }
644
645#ifdef DEBUG
646
647 printf("Unsorted: n=%d\n", n);
648 for (i = 0; i < n; ++i) {
649 printf("\t%3d: %p ==> %-10s => %s\n",
650 i, list[i], list[i]->key, list[i]->data);
651 }
652#endif
653
654
655 qsort(list, n, sizeof(ENTRY *), cmpkey);
656
657
658 if (size) {
659 if (size < totlen + 1) {
660 printf("Env export buffer too small: %zu, "
661 "but need %zu\n", size, totlen + 1);
662 __set_errno(ENOMEM);
663 return (-1);
664 }
665 } else {
666 size = totlen + 1;
667 }
668
669
670 if (*resp) {
671
672 res = *resp;
673 memset(res, '\0', size);
674 } else {
675
676 *resp = res = calloc(1, size);
677 if (res == NULL) {
678 __set_errno(ENOMEM);
679 return (-1);
680 }
681 }
682
683
684
685
686 for (i = 0, p = res; i < n; ++i) {
687 const char *s;
688
689 s = list[i]->key;
690 while (*s)
691 *p++ = *s++;
692 *p++ = '=';
693
694 s = list[i]->data;
695
696 while (*s) {
697 if ((*s == sep) || (*s == '\\'))
698 *p++ = '\\';
699 *p++ = *s++;
700 }
701 *p++ = sep;
702 }
703 *p = '\0';
704
705 return size;
706}
707#endif
708
709
710
711
712
713
714
715
716
717
718static int drop_var_from_set(const char *name, int nvars, char * vars[])
719{
720 int i = 0;
721 int res = 0;
722
723
724 if (nvars == 0)
725 return 1;
726
727 for (i = 0; i < nvars; i++) {
728 if (vars[i] == NULL)
729 continue;
730
731 if (!strcmp(name, vars[i])) {
732 vars[i] = NULL;
733 res = 1;
734 }
735 }
736 if (!res)
737 debug("Skipping non-listed variable %s\n", name);
738
739 return res;
740}
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777int himport_r(struct hsearch_data *htab,
778 const char *env, size_t size, const char sep, int flag,
779 int crlf_is_lf, int nvars, char * const vars[])
780{
781 char *data, *sp, *dp, *name, *value;
782 char *localvars[nvars];
783 int i;
784
785
786 if (htab == NULL) {
787 __set_errno(EINVAL);
788 return 0;
789 }
790
791
792 if ((data = malloc(size + 1)) == NULL) {
793 debug("himport_r: can't malloc %zu bytes\n", size + 1);
794 __set_errno(ENOMEM);
795 return 0;
796 }
797 memcpy(data, env, size);
798 data[size] = '\0';
799 dp = data;
800
801
802 if (nvars)
803 memcpy(localvars, vars, sizeof(vars[0]) * nvars);
804
805 if ((flag & H_NOCLEAR) == 0) {
806
807 debug("Destroy Hash Table: %p table = %p\n", htab,
808 htab->table);
809 if (htab->table)
810 hdestroy_r(htab);
811 }
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831 if (!htab->table) {
832 int nent = CONFIG_ENV_MIN_ENTRIES + size / 8;
833
834 if (nent > CONFIG_ENV_MAX_ENTRIES)
835 nent = CONFIG_ENV_MAX_ENTRIES;
836
837 debug("Create Hash Table: N=%d\n", nent);
838
839 if (hcreate_r(nent, htab) == 0) {
840 free(data);
841 return 0;
842 }
843 }
844
845 if (!size) {
846 free(data);
847 return 1;
848 }
849 if(crlf_is_lf) {
850
851 unsigned ignored_crs = 0;
852 for(;dp < data + size && *dp; ++dp) {
853 if(*dp == '\r' &&
854 dp < data + size - 1 && *(dp+1) == '\n')
855 ++ignored_crs;
856 else
857 *(dp-ignored_crs) = *dp;
858 }
859 size -= ignored_crs;
860 dp = data;
861 }
862
863 do {
864 ENTRY e, *rv;
865
866
867 while (isblank(*dp))
868 ++dp;
869
870
871 if (*dp == '#') {
872 while (*dp && (*dp != sep))
873 ++dp;
874 ++dp;
875 continue;
876 }
877
878
879 for (name = dp; *dp != '=' && *dp && *dp != sep; ++dp)
880 ;
881
882
883 if (*dp == '\0' || *(dp + 1) == '\0' ||
884 *dp == sep || *(dp + 1) == sep) {
885 if (*dp == '=')
886 *dp++ = '\0';
887 *dp++ = '\0';
888
889 debug("DELETE CANDIDATE: \"%s\"\n", name);
890 if (!drop_var_from_set(name, nvars, localvars))
891 continue;
892
893 if (hdelete_r(name, htab, flag) == 0)
894 debug("DELETE ERROR ##############################\n");
895
896 continue;
897 }
898 *dp++ = '\0';
899
900
901 for (value = sp = dp; *dp && (*dp != sep); ++dp) {
902 if ((*dp == '\\') && *(dp + 1))
903 ++dp;
904 *sp++ = *dp;
905 }
906 *sp++ = '\0';
907 ++dp;
908
909 if (*name == 0) {
910 debug("INSERT: unable to use an empty key\n");
911 __set_errno(EINVAL);
912 free(data);
913 return 0;
914 }
915
916
917 if (!drop_var_from_set(name, nvars, localvars))
918 continue;
919
920
921 e.key = name;
922 e.data = value;
923
924 hsearch_r(e, ENTER, &rv, htab, flag);
925 if (rv == NULL)
926 printf("himport_r: can't insert \"%s=%s\" into hash table\n",
927 name, value);
928
929 debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",
930 htab, htab->filled, htab->size,
931 rv, name, value);
932 } while ((dp < data + size) && *dp);
933
934 debug("INSERT: free(data = %p)\n", data);
935 free(data);
936
937
938 for (i = 0; i < nvars; i++) {
939 if (localvars[i] == NULL)
940 continue;
941
942
943
944
945
946
947
948
949 if (hdelete_r(localvars[i], htab, flag) == 0)
950 printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]);
951 else
952 printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]);
953 }
954
955 debug("INSERT: done\n");
956 return 1;
957}
958
959
960
961
962
963
964
965
966
967int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *))
968{
969 int i;
970 int retval;
971
972 for (i = 1; i <= htab->size; ++i) {
973 if (htab->table[i].used > 0) {
974 retval = callback(&htab->table[i].entry);
975 if (retval)
976 return retval;
977 }
978 }
979
980 return 0;
981}
982