]> git.proxmox.com Git - mirror_ovs.git/blame - lib/smap.c
lldp: fix a buffer overflow when handling management address TLV
[mirror_ovs.git] / lib / smap.c
CommitLineData
f99f67bd 1/* Copyright (c) 2012, 2014, 2015, 2016 Nicira, Inc.
79f1cbe9
EJ
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License. */
14
15#include <config.h>
16#include "smap.h"
17
edefaa2e
YT
18#include <strings.h>
19
79f1cbe9 20#include "hash.h"
ee89ea7b 21#include "openvswitch/json.h"
719a3d25 22#include "packets.h"
01393f00 23#include "util.h"
d65467f1 24#include "uuid.h"
79f1cbe9
EJ
25
26static struct smap_node *smap_add__(struct smap *, char *, void *,
27 size_t hash);
28static struct smap_node *smap_find__(const struct smap *, const char *key,
29 size_t key_len, size_t hash);
30static int compare_nodes_by_key(const void *, const void *);
31\f
32/* Public Functions. */
33
34void
35smap_init(struct smap *smap)
36{
37 hmap_init(&smap->map);
38}
39
40void
41smap_destroy(struct smap *smap)
42{
43 if (smap) {
44 smap_clear(smap);
45 hmap_destroy(&smap->map);
46 }
47}
48
49/* Adds 'key' paired with 'value' to 'smap'. It is the caller's responsibility
50 * to avoid duplicate keys if desirable. */
51struct smap_node *
52smap_add(struct smap *smap, const char *key, const char *value)
53{
54 size_t key_len = strlen(key);
55 return smap_add__(smap, xmemdup0(key, key_len), xstrdup(value),
56 hash_bytes(key, key_len, 0));
57}
58
ff929935
BP
59/* Adds 'key' paired with 'value' to 'smap'. Takes ownership of 'key' and
60 * 'value' (which will eventually be freed with free()). It is the caller's
61 * responsibility to avoid duplicate keys if desirable. */
62struct smap_node *
63smap_add_nocopy(struct smap *smap, char *key, char *value)
64{
65 return smap_add__(smap, key, value, hash_bytes(key, strlen(key), 0));
66}
67
79f1cbe9
EJ
68/* Attempts to add 'key' to 'smap' associated with 'value'. If 'key' already
69 * exists in 'smap', does nothing and returns false. Otherwise, performs the
70 * addition and returns true. */
71bool
72smap_add_once(struct smap *smap, const char *key, const char *value)
73{
74 if (!smap_get(smap, key)) {
75 smap_add(smap, key, value);
76 return true;
77 } else {
78 return false;
79 }
80}
81
82/* Adds 'key' paired with a value derived from 'format' (similar to printf).
83 * It is the caller's responsibility to avoid duplicate keys if desirable. */
84void
85smap_add_format(struct smap *smap, const char *key, const char *format, ...)
86{
87 size_t key_len;
88 va_list args;
89 char *value;
90
91 va_start(args, format);
92 value = xvasprintf(format, args);
93 va_end(args);
94
95 key_len = strlen(key);
96 smap_add__(smap, xmemdup0(key, key_len), value,
97 hash_bytes(key, key_len, 0));
98}
99
9835576b
JB
100/* Adds 'key' paired with a string representation of 'addr'. It is the
101 * caller's responsibility to avoid duplicate keys if desirable. */
102void
103smap_add_ipv6(struct smap *smap, const char *key, struct in6_addr *addr)
104{
105 char buf[INET6_ADDRSTRLEN];
719a3d25 106 ipv6_string_mapped(buf, addr);
9835576b
JB
107 smap_add(smap, key, buf);
108}
109
79f1cbe9 110/* Searches for 'key' in 'smap'. If it does not already exists, adds it.
1b1d2e6d
BP
111 * Otherwise, changes its value to 'value'. The caller retains ownership of
112 * 'value'. */
79f1cbe9
EJ
113void
114smap_replace(struct smap *smap, const char *key, const char *value)
1b1d2e6d
BP
115{
116 smap_replace_nocopy(smap, key, xstrdup(value));
117}
118
119/* Searches for 'key' in 'smap'. If it does not already exists, adds it.
120 * Otherwise, changes its value to 'value'. Takes ownership of 'value'. */
121void
122smap_replace_nocopy(struct smap *smap, const char *key, char *value)
79f1cbe9
EJ
123{
124 size_t key_len = strlen(key);
125 size_t hash = hash_bytes(key, key_len, 0);
126
127 struct smap_node *node;
128
129 node = smap_find__(smap, key, key_len, hash);
130 if (node) {
131 free(node->value);
1b1d2e6d 132 node->value = value;
79f1cbe9 133 } else {
1b1d2e6d 134 smap_add__(smap, xmemdup0(key, key_len), value, hash);
79f1cbe9
EJ
135 }
136}
137
138/* If 'key' is in 'smap', removes it. Otherwise does nothing. */
139void
140smap_remove(struct smap *smap, const char *key)
141{
142 struct smap_node *node = smap_get_node(smap, key);
143
144 if (node) {
145 smap_remove_node(smap, node);
146 }
147}
148
149/* Removes 'node' from 'smap'. */
150void
151smap_remove_node(struct smap *smap, struct smap_node *node)
152{
153 hmap_remove(&smap->map, &node->node);
154 free(node->key);
155 free(node->value);
156 free(node);
157}
158
57c8677b
BP
159/* Deletes 'node' from 'smap'.
160 *
161 * If 'keyp' is nonnull, stores the node's key in '*keyp' and transfers
162 * ownership to the caller. Otherwise, frees the node's key. Similarly for
163 * 'valuep' and the node's value. */
164void
165smap_steal(struct smap *smap, struct smap_node *node,
166 char **keyp, char **valuep)
51c82a49 167{
57c8677b
BP
168 if (keyp) {
169 *keyp = node->key;
170 } else {
171 free(node->key);
172 }
173
174 if (valuep) {
175 *valuep = node->value;
176 } else {
177 free(node->value);
178 }
51c82a49
BP
179
180 hmap_remove(&smap->map, &node->node);
181 free(node);
51c82a49
BP
182}
183
79f1cbe9
EJ
184/* Removes all key-value pairs from 'smap'. */
185void
186smap_clear(struct smap *smap)
187{
188 struct smap_node *node, *next;
189
190 SMAP_FOR_EACH_SAFE (node, next, smap) {
191 smap_remove_node(smap, node);
192 }
193}
194
f99f67bd
BP
195/* Returns the value associated with 'key' in 'smap'.
196 * If 'smap' does not contain 'key', returns NULL. */
79f1cbe9
EJ
197const char *
198smap_get(const struct smap *smap, const char *key)
f99f67bd
BP
199{
200 return smap_get_def(smap, key, NULL);
201}
202
203/* Returns the value associated with 'key' in 'smap'.
204 * If 'smap' does not contain 'key', returns 'def'. */
205const char *
206smap_get_def(const struct smap *smap, const char *key, const char *def)
79f1cbe9
EJ
207{
208 struct smap_node *node = smap_get_node(smap, key);
f99f67bd 209 return node ? node->value : def;
79f1cbe9
EJ
210}
211
212/* Returns the node associated with 'key' in 'smap', or NULL. */
213struct smap_node *
214smap_get_node(const struct smap *smap, const char *key)
215{
216 size_t key_len = strlen(key);
217 return smap_find__(smap, key, key_len, hash_bytes(key, key_len, 0));
218}
219
220/* Gets the value associated with 'key' in 'smap' and converts it to a boolean.
221 * If 'key' is not in 'smap', or its value is neither "true" nor "false",
222 * returns 'def'. */
223bool
224smap_get_bool(const struct smap *smap, const char *key, bool def)
225{
f99f67bd 226 const char *value = smap_get_def(smap, key, "");
79f1cbe9
EJ
227 if (def) {
228 return strcasecmp("false", value) != 0;
229 } else {
230 return !strcasecmp("true", value);
231 }
232}
233
01393f00
IM
234/* Gets the value associated with 'key' in 'smap' and converts it to an int.
235 * If 'key' is not in 'smap' or a valid integer can't be parsed from it's
236 * value, returns 'def'. */
79f1cbe9
EJ
237int
238smap_get_int(const struct smap *smap, const char *key, int def)
239{
240 const char *value = smap_get(smap, key);
01393f00 241 int i_value;
79f1cbe9 242
01393f00
IM
243 if (!value || !str_to_int(value, 10, &i_value)) {
244 return def;
245 }
246
247 return i_value;
79f1cbe9
EJ
248}
249
7b2e999f
NS
250/* Gets the value associated with 'key' in 'smap' and converts it to an
251 * unsigned int. If 'key' is not in 'smap' or a valid unsigned integer
252 * can't be parsed from it's value, returns 'def'. */
253unsigned int
254smap_get_uint(const struct smap *smap, const char *key, unsigned int def)
255{
256 const char *value = smap_get(smap, key);
257 unsigned int u_value;
258
259 if (!value || !str_to_uint(value, 10, &u_value)) {
260 return def;
261 }
262
263 return u_value;
264}
265
01393f00
IM
266/* Gets the value associated with 'key' in 'smap' and converts it to an
267 * unsigned long long. If 'key' is not in 'smap' or a valid number can't be
268 * parsed from it's value, returns 'def'. */
13c1637f
BP
269unsigned long long int
270smap_get_ullong(const struct smap *smap, const char *key,
271 unsigned long long def)
272{
273 const char *value = smap_get(smap, key);
01393f00
IM
274 unsigned long long ull_value;
275
276 if (!value || !str_to_ullong(value, 10, &ull_value)) {
277 return def;
278 }
13c1637f 279
01393f00 280 return ull_value;
13c1637f
BP
281}
282
d65467f1
BP
283/* Gets the value associated with 'key' in 'smap' and converts it to a UUID
284 * using uuid_from_string(). Returns true if successful, false if 'key' is not
285 * in 'smap' or if 'key' does not have the correct syntax for a UUID. */
286bool
287smap_get_uuid(const struct smap *smap, const char *key, struct uuid *uuid)
288{
f99f67bd 289 return uuid_from_string(uuid, smap_get_def(smap, key, ""));
d65467f1
BP
290}
291
79f1cbe9
EJ
292/* Returns true of there are no elements in 'smap'. */
293bool
294smap_is_empty(const struct smap *smap)
295{
296 return hmap_is_empty(&smap->map);
297}
298
299/* Returns the number of elements in 'smap'. */
300size_t
301smap_count(const struct smap *smap)
302{
303 return hmap_count(&smap->map);
304}
305
306/* Initializes 'dst' as a clone of 'src. */
307void
4512aaa7 308smap_clone(struct smap *dst, const struct smap *src)
79f1cbe9 309{
4512aaa7 310 const struct smap_node *node;
79f1cbe9
EJ
311
312 smap_init(dst);
313 SMAP_FOR_EACH (node, src) {
314 smap_add__(dst, xstrdup(node->key), xstrdup(node->value),
315 node->node.hash);
316 }
317}
318
319/* Returns an array of nodes sorted on key or NULL if 'smap' is empty. The
320 * caller is responsible for freeing this array. */
321const struct smap_node **
322smap_sort(const struct smap *smap)
323{
324 if (smap_is_empty(smap)) {
325 return NULL;
326 } else {
327 const struct smap_node **nodes;
328 struct smap_node *node;
329 size_t i, n;
330
331 n = smap_count(smap);
332 nodes = xmalloc(n * sizeof *nodes);
333 i = 0;
334 SMAP_FOR_EACH (node, smap) {
335 nodes[i++] = node;
336 }
cb22974d 337 ovs_assert(i == n);
79f1cbe9
EJ
338
339 qsort(nodes, n, sizeof *nodes, compare_nodes_by_key);
340
341 return nodes;
342 }
343}
cccc1356
BP
344
345/* Adds each of the key-value pairs from 'json' (which must be a JSON object
346 * whose values are strings) to 'smap'.
347 *
348 * The caller must have initialized 'smap'.
349 *
350 * The caller retains ownership of 'json' and everything in it. */
351void
352smap_from_json(struct smap *smap, const struct json *json)
353{
354 const struct shash_node *node;
355
356 SHASH_FOR_EACH (node, json_object(json)) {
357 const struct json *value = node->data;
358 smap_add(smap, node->name, json_string(value));
359 }
360}
361
362/* Returns a JSON object that maps from the keys in 'smap' to their values.
363 *
364 * The caller owns the returned value and must eventually json_destroy() it.
365 *
366 * The caller retains ownership of 'smap' and everything in it. */
367struct json *
368smap_to_json(const struct smap *smap)
369{
370 const struct smap_node *node;
371 struct json *json;
372
373 json = json_object_create();
374 SMAP_FOR_EACH (node, smap) {
375 json_object_put_string(json, node->key, node->value);
376 }
377 return json;
378}
7962b7f0
RB
379
380/* Returns true if the two maps are equal, meaning that they have the same set
381 * of key-value pairs.
382 */
383bool
384smap_equal(const struct smap *smap1, const struct smap *smap2)
385{
386 if (smap_count(smap1) != smap_count(smap2)) {
387 return false;
388 }
389
390 const struct smap_node *node;
391 SMAP_FOR_EACH (node, smap1) {
392 const char *value2 = smap_get(smap2, node->key);
393 if (!value2 || strcmp(node->value, value2)) {
394 return false;
395 }
396 }
397 return true;
398}
79f1cbe9
EJ
399\f
400/* Private Helpers. */
401
402static struct smap_node *
403smap_add__(struct smap *smap, char *key, void *value, size_t hash)
404{
405 struct smap_node *node = xmalloc(sizeof *node);
406 node->key = key;
407 node->value = value;
408 hmap_insert(&smap->map, &node->node, hash);
409 return node;
410}
411
412static struct smap_node *
413smap_find__(const struct smap *smap, const char *key, size_t key_len,
414 size_t hash)
415{
416 struct smap_node *node;
417
418 HMAP_FOR_EACH_WITH_HASH (node, node, hash, &smap->map) {
419 if (!strncmp(node->key, key, key_len) && !node->key[key_len]) {
420 return node;
421 }
422 }
423
424 return NULL;
425}
426
427static int
428compare_nodes_by_key(const void *a_, const void *b_)
429{
430 const struct smap_node *const *a = a_;
431 const struct smap_node *const *b = b_;
432 return strcmp((*a)->key, (*b)->key);
433}