D-Bus 1.12.20
dbus-address.c
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2/* dbus-address.c Server address parser.
3 *
4 * Copyright (C) 2003 CodeFactory AB
5 * Copyright (C) 2004,2005 Red Hat, Inc.
6 *
7 * Licensed under the Academic Free License version 2.1
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25#include <config.h>
26#include "dbus-address.h"
27#include "dbus-internals.h"
28#include "dbus-list.h"
29#include "dbus-string.h"
30#include "dbus-protocol.h"
31
44{
49};
50
51
64void
66 const char *address_problem_type,
67 const char *address_problem_field,
68 const char *address_problem_other)
69{
70 if (address_problem_type != NULL)
72 "Server address of type %s was missing argument %s",
73 address_problem_type, address_problem_field);
74 else
76 "Could not parse server address: %s",
77 address_problem_other);
78}
79
84#define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b) \
85 (((b) >= 'a' && (b) <= 'z') || \
86 ((b) >= 'A' && (b) <= 'Z') || \
87 ((b) >= '0' && (b) <= '9') || \
88 (b) == '-' || \
89 (b) == '_' || \
90 (b) == '/' || \
91 (b) == '\\' || \
92 (b) == '*' || \
93 (b) == '.')
94
105 const DBusString *unescaped)
106{
107 const unsigned char *p;
108 const unsigned char *end;
109 dbus_bool_t ret;
110 int orig_len;
111
112 ret = FALSE;
113
114 orig_len = _dbus_string_get_length (escaped);
115 p = _dbus_string_get_const_udata (unescaped);
116 end = p + _dbus_string_get_length (unescaped);
117 while (p != end)
118 {
120 {
121 if (!_dbus_string_append_byte (escaped, *p))
122 goto out;
123 }
124 else
125 {
126 if (!_dbus_string_append_byte (escaped, '%'))
127 goto out;
128 if (!_dbus_string_append_byte_as_hex (escaped, *p))
129 goto out;
130 }
131
132 ++p;
133 }
134
135 ret = TRUE;
136
137 out:
138 if (!ret)
139 _dbus_string_set_length (escaped, orig_len);
140 return ret;
141}
142 /* End of internals */
144
145static void
146dbus_address_entry_free (DBusAddressEntry *entry)
147{
148 DBusList *link;
149
150 _dbus_string_free (&entry->method);
151
152 link = _dbus_list_get_first_link (&entry->keys);
153 while (link != NULL)
154 {
155 _dbus_string_free (link->data);
156 dbus_free (link->data);
157
158 link = _dbus_list_get_next_link (&entry->keys, link);
159 }
160 _dbus_list_clear (&entry->keys);
161
162 link = _dbus_list_get_first_link (&entry->values);
163 while (link != NULL)
164 {
165 _dbus_string_free (link->data);
166 dbus_free (link->data);
167
168 link = _dbus_list_get_next_link (&entry->values, link);
169 }
170 _dbus_list_clear (&entry->values);
171
172 dbus_free (entry);
173}
174
188void
190{
191 int i;
192
193 for (i = 0; entries[i] != NULL; i++)
194 dbus_address_entry_free (entries[i]);
195 dbus_free (entries);
196}
197
198static DBusAddressEntry *
199create_entry (void)
200{
201 DBusAddressEntry *entry;
202
203 entry = dbus_new0 (DBusAddressEntry, 1);
204
205 if (entry == NULL)
206 return NULL;
207
208 if (!_dbus_string_init (&entry->method))
209 {
210 dbus_free (entry);
211 return NULL;
212 }
213
214 return entry;
215}
216
226const char *
228{
229 return _dbus_string_get_const_data (&entry->method);
230}
231
243const char *
245 const char *key)
246{
247 DBusList *values, *keys;
248
249 keys = _dbus_list_get_first_link (&entry->keys);
250 values = _dbus_list_get_first_link (&entry->values);
251
252 while (keys != NULL)
253 {
254 _dbus_assert (values != NULL);
255
256 if (_dbus_string_equal_c_str (keys->data, key))
257 return _dbus_string_get_const_data (values->data);
258
259 keys = _dbus_list_get_next_link (&entry->keys, keys);
260 values = _dbus_list_get_next_link (&entry->values, values);
261 }
262
263 return NULL;
264}
265
266static dbus_bool_t
267append_unescaped_value (DBusString *unescaped,
268 const DBusString *escaped,
269 int escaped_start,
270 int escaped_len,
271 DBusError *error)
272{
273 const char *p;
274 const char *end;
275 dbus_bool_t ret;
276
277 ret = FALSE;
278
279 p = _dbus_string_get_const_data (escaped) + escaped_start;
280 end = p + escaped_len;
281 while (p != end)
282 {
284 {
285 if (!_dbus_string_append_byte (unescaped, *p))
286 goto out;
287 }
288 else if (*p == '%')
289 {
290 /* Efficiency is king */
291 char buf[3];
292 DBusString hex;
293 int hex_end;
294
295 ++p;
296
297 if ((p + 2) > end)
298 {
300 "In D-Bus address, percent character was not followed by two hex digits");
301 goto out;
302 }
303
304 buf[0] = *p;
305 ++p;
306 buf[1] = *p;
307 buf[2] = '\0';
308
309 _dbus_string_init_const (&hex, buf);
310
311 if (!_dbus_string_hex_decode (&hex, 0, &hex_end,
312 unescaped,
313 _dbus_string_get_length (unescaped)))
314 goto out;
315
316 if (hex_end != 2)
317 {
319 "In D-Bus address, percent character was followed by characters other than hex digits");
320 goto out;
321 }
322 }
323 else
324 {
325 /* Error, should have been escaped */
327 "In D-Bus address, character '%c' should have been escaped\n",
328 *p);
329 goto out;
330 }
331
332 ++p;
333 }
334
335 ret = TRUE;
336
337 out:
338 if (!ret && error && !dbus_error_is_set (error))
339 _DBUS_SET_OOM (error);
340
341 _dbus_assert (ret || error == NULL || dbus_error_is_set (error));
342
343 return ret;
344}
345
363dbus_parse_address (const char *address,
364 DBusAddressEntry ***entry_result,
365 int *array_len,
366 DBusError *error)
367{
368 DBusString str;
369 int pos, end_pos, len, i;
370 DBusList *entries, *link;
371 DBusAddressEntry **entry_array;
372
373 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
374
375 _dbus_string_init_const (&str, address);
376
377 entries = NULL;
378 pos = 0;
379 len = _dbus_string_get_length (&str);
380
381 if (len == 0)
382 {
384 "Empty address '%s'", address);
385 goto error;
386 }
387
388 while (pos < len)
389 {
390 DBusAddressEntry *entry;
391
392 int found_pos;
393
394 entry = create_entry ();
395 if (!entry)
396 {
398
399 goto error;
400 }
401
402 /* Append the entry */
403 if (!_dbus_list_append (&entries, entry))
404 {
406 dbus_address_entry_free (entry);
407 goto error;
408 }
409
410 /* Look for a semi-colon */
411 if (!_dbus_string_find (&str, pos, ";", &end_pos))
412 end_pos = len;
413
414 /* Look for the colon : */
415 if (!_dbus_string_find_to (&str, pos, end_pos, ":", &found_pos))
416 {
417 dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, "Address does not contain a colon");
418 goto error;
419 }
420
421 if (!_dbus_string_copy_len (&str, pos, found_pos - pos, &entry->method, 0))
422 {
424 goto error;
425 }
426
427 pos = found_pos + 1;
428
429 while (pos < end_pos)
430 {
431 int comma_pos, equals_pos;
432
433 if (!_dbus_string_find_to (&str, pos, end_pos, ",", &comma_pos))
434 comma_pos = end_pos;
435
436 if (!_dbus_string_find_to (&str, pos, comma_pos, "=", &equals_pos) ||
437 equals_pos == pos || equals_pos + 1 == comma_pos)
438 {
440 "'=' character not found or has no value following it");
441 goto error;
442 }
443 else
444 {
445 DBusString *key;
446 DBusString *value;
447
448 key = dbus_new0 (DBusString, 1);
449
450 if (!key)
451 {
453 goto error;
454 }
455
456 value = dbus_new0 (DBusString, 1);
457 if (!value)
458 {
460 dbus_free (key);
461 goto error;
462 }
463
464 if (!_dbus_string_init (key))
465 {
467 dbus_free (key);
468 dbus_free (value);
469
470 goto error;
471 }
472
473 if (!_dbus_string_init (value))
474 {
476 _dbus_string_free (key);
477
478 dbus_free (key);
479 dbus_free (value);
480 goto error;
481 }
482
483 if (!_dbus_string_copy_len (&str, pos, equals_pos - pos, key, 0))
484 {
486 _dbus_string_free (key);
487 _dbus_string_free (value);
488
489 dbus_free (key);
490 dbus_free (value);
491 goto error;
492 }
493
494 if (!append_unescaped_value (value, &str, equals_pos + 1,
495 comma_pos - equals_pos - 1, error))
496 {
497 _dbus_assert (error == NULL || dbus_error_is_set (error));
498 _dbus_string_free (key);
499 _dbus_string_free (value);
500
501 dbus_free (key);
502 dbus_free (value);
503 goto error;
504 }
505
506 if (!_dbus_list_append (&entry->keys, key))
507 {
509 _dbus_string_free (key);
510 _dbus_string_free (value);
511
512 dbus_free (key);
513 dbus_free (value);
514 goto error;
515 }
516
517 if (!_dbus_list_append (&entry->values, value))
518 {
520 _dbus_string_free (value);
521
522 dbus_free (value);
523 goto error;
524 }
525 }
526
527 pos = comma_pos + 1;
528 }
529
530 pos = end_pos + 1;
531 }
532
533 *array_len = _dbus_list_get_length (&entries);
534
535 entry_array = dbus_new (DBusAddressEntry *, *array_len + 1);
536
537 if (!entry_array)
538 {
540
541 goto error;
542 }
543
544 entry_array [*array_len] = NULL;
545
546 link = _dbus_list_get_first_link (&entries);
547 i = 0;
548 while (link != NULL)
549 {
550 entry_array[i] = link->data;
551 i++;
552 link = _dbus_list_get_next_link (&entries, link);
553 }
554
555 _dbus_list_clear (&entries);
556 *entry_result = entry_array;
557
558 return TRUE;
559
560 error:
561
562 link = _dbus_list_get_first_link (&entries);
563 while (link != NULL)
564 {
565 dbus_address_entry_free (link->data);
566 link = _dbus_list_get_next_link (&entries, link);
567 }
568
569 _dbus_list_clear (&entries);
570
571 return FALSE;
572
573}
574
582char*
583dbus_address_escape_value (const char *value)
584{
585 DBusString escaped;
586 DBusString unescaped;
587 char *ret;
588
589 ret = NULL;
590
591 _dbus_string_init_const (&unescaped, value);
592
593 if (!_dbus_string_init (&escaped))
594 return NULL;
595
596 if (!_dbus_address_append_escaped (&escaped, &unescaped))
597 goto out;
598
599 if (!_dbus_string_steal_data (&escaped, &ret))
600 goto out;
601
602 out:
603 _dbus_string_free (&escaped);
604 return ret;
605}
606
616char*
618 DBusError *error)
619{
620 DBusString unescaped;
621 DBusString escaped;
622 char *ret;
623
624 ret = NULL;
625
626 _dbus_string_init_const (&escaped, value);
627
628 if (!_dbus_string_init (&unescaped))
629 return NULL;
630
631 if (!append_unescaped_value (&unescaped, &escaped,
632 0, _dbus_string_get_length (&escaped),
633 error))
634 goto out;
635
636 if (!_dbus_string_steal_data (&unescaped, &ret))
637 goto out;
638
639 out:
640 if (ret == NULL && error && !dbus_error_is_set (error))
641 _DBUS_SET_OOM (error);
642
643 _dbus_assert (ret != NULL || error == NULL || dbus_error_is_set (error));
644
645 _dbus_string_free (&unescaped);
646 return ret;
647}
648 /* End of public API */
650
651#ifdef DBUS_ENABLE_EMBEDDED_TESTS
652
653#ifndef DOXYGEN_SHOULD_SKIP_THIS
654
655#include "dbus-test.h"
656#include <stdlib.h>
657
658typedef struct
659{
660 const char *escaped;
661 const char *unescaped;
662} EscapeTest;
663
664static const EscapeTest escape_tests[] = {
665 { "abcde", "abcde" },
666 { "", "" },
667 { "%20%20", " " },
668 { "%24", "$" },
669 { "%25", "%" },
670 { "abc%24", "abc$" },
671 { "%24abc", "$abc" },
672 { "abc%24abc", "abc$abc" },
673 { "/", "/" },
674 { "-", "-" },
675 { "_", "_" },
676 { "A", "A" },
677 { "I", "I" },
678 { "Z", "Z" },
679 { "a", "a" },
680 { "i", "i" },
681 { "z", "z" },
682 /* Bug: https://bugs.freedesktop.org/show_bug.cgi?id=53499 */
683 { "%c3%b6", "\xc3\xb6" }
684};
685
686static const char* invalid_escaped_values[] = {
687 "%a",
688 "%q",
689 "%az",
690 "%%",
691 "%$$",
692 "abc%a",
693 "%axyz",
694 "%",
695 "$",
696 " ",
697};
698
700_dbus_address_test (void)
701{
702 DBusAddressEntry **entries;
703 int len;
705 int i;
706
707 i = 0;
708 while (i < _DBUS_N_ELEMENTS (escape_tests))
709 {
710 const EscapeTest *test = &escape_tests[i];
711 char *escaped;
712 char *unescaped;
713
714 escaped = dbus_address_escape_value (test->unescaped);
715 if (escaped == NULL)
717
718 if (strcmp (escaped, test->escaped) != 0)
719 {
720 _dbus_warn ("Escaped '%s' as '%s' should have been '%s'",
721 test->unescaped, escaped, test->escaped);
722 exit (1);
723 }
724 dbus_free (escaped);
725
726 unescaped = dbus_address_unescape_value (test->escaped, &error);
727 if (unescaped == NULL)
728 {
729 _dbus_warn ("Failed to unescape '%s': %s",
730 test->escaped, error.message);
731 dbus_error_free (&error);
732 exit (1);
733 }
734
735 if (strcmp (unescaped, test->unescaped) != 0)
736 {
737 _dbus_warn ("Unescaped '%s' as '%s' should have been '%s'",
738 test->escaped, unescaped, test->unescaped);
739 exit (1);
740 }
741 dbus_free (unescaped);
742
743 ++i;
744 }
745
746 i = 0;
747 while (i < _DBUS_N_ELEMENTS (invalid_escaped_values))
748 {
749 char *unescaped;
750
751 unescaped = dbus_address_unescape_value (invalid_escaped_values[i],
752 &error);
753 if (unescaped != NULL)
754 {
755 _dbus_warn ("Should not have successfully unescaped '%s' to '%s'",
756 invalid_escaped_values[i], unescaped);
757 dbus_free (unescaped);
758 exit (1);
759 }
760
762 dbus_error_free (&error);
763
764 ++i;
765 }
766
767 if (!dbus_parse_address ("unix:path=/tmp/foo;debug:name=test,sliff=sloff;",
768 &entries, &len, &error))
769 _dbus_assert_not_reached ("could not parse address");
770 _dbus_assert (len == 2);
771 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[0], "path"), "/tmp/foo") == 0);
772 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "name"), "test") == 0);
773 _dbus_assert (strcmp (dbus_address_entry_get_value (entries[1], "sliff"), "sloff") == 0);
774
776
777 /* Different possible errors */
778 if (dbus_parse_address ("", &entries, &len, &error))
779 _dbus_assert_not_reached ("Parsed incorrect address.");
780 else
781 dbus_error_free (&error);
782
783 if (dbus_parse_address ("foo", &entries, &len, &error))
784 _dbus_assert_not_reached ("Parsed incorrect address.");
785 else
786 dbus_error_free (&error);
787
788 if (dbus_parse_address ("foo:bar", &entries, &len, &error))
789 _dbus_assert_not_reached ("Parsed incorrect address.");
790 else
791 dbus_error_free (&error);
792
793 if (dbus_parse_address ("foo:bar,baz", &entries, &len, &error))
794 _dbus_assert_not_reached ("Parsed incorrect address.");
795 else
796 dbus_error_free (&error);
797
798 if (dbus_parse_address ("foo:bar=foo,baz", &entries, &len, &error))
799 _dbus_assert_not_reached ("Parsed incorrect address.");
800 else
801 dbus_error_free (&error);
802
803 if (dbus_parse_address ("foo:bar=foo;baz", &entries, &len, &error))
804 _dbus_assert_not_reached ("Parsed incorrect address.");
805 else
806 dbus_error_free (&error);
807
808 if (dbus_parse_address ("foo:=foo", &entries, &len, &error))
809 _dbus_assert_not_reached ("Parsed incorrect address.");
810 else
811 dbus_error_free (&error);
812
813 if (dbus_parse_address ("foo:foo=", &entries, &len, &error))
814 _dbus_assert_not_reached ("Parsed incorrect address.");
815 else
816 dbus_error_free (&error);
817
818 if (dbus_parse_address ("foo:foo,bar=baz", &entries, &len, &error))
819 _dbus_assert_not_reached ("Parsed incorrect address.");
820 else
821 dbus_error_free (&error);
822
823 return TRUE;
824}
825
826#endif /* !DOXYGEN_SHOULD_SKIP_THIS */
827
828#endif
#define _DBUS_ADDRESS_OPTIONALLY_ESCAPED_BYTE(b)
TRUE if the byte need not be escaped when found in a dbus address.
Definition: dbus-address.c:84
dbus_bool_t _dbus_address_append_escaped(DBusString *escaped, const DBusString *unescaped)
Appends an escaped version of one string to another string, using the D-Bus address escaping mechanis...
Definition: dbus-address.c:104
void _dbus_set_bad_address(DBusError *error, const char *address_problem_type, const char *address_problem_field, const char *address_problem_other)
Sets DBUS_ERROR_BAD_ADDRESS.
Definition: dbus-address.c:65
void dbus_address_entries_free(DBusAddressEntry **entries)
Frees a NULL-terminated array of address entries.
Definition: dbus-address.c:189
dbus_bool_t dbus_parse_address(const char *address, DBusAddressEntry ***entry_result, int *array_len, DBusError *error)
Parses an address string of the form:
Definition: dbus-address.c:363
const char * dbus_address_entry_get_method(DBusAddressEntry *entry)
Returns the method string of an address entry.
Definition: dbus-address.c:227
char * dbus_address_unescape_value(const char *value, DBusError *error)
Unescapes the given string as a value in a key=value pair for a D-Bus address.
Definition: dbus-address.c:617
char * dbus_address_escape_value(const char *value)
Escapes the given string as a value in a key=value pair for a D-Bus address.
Definition: dbus-address.c:583
const char * dbus_address_entry_get_value(DBusAddressEntry *entry, const char *key)
Returns a value from a key of an entry.
Definition: dbus-address.c:244
#define DBUS_ERROR_INIT
Expands to a suitable initializer for a DBusError on the stack.
Definition: dbus-errors.h:62
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
Definition: dbus-errors.c:354
void dbus_error_free(DBusError *error)
Frees an error that's been set (or just initialized), then reinitializes the error as in dbus_error_i...
Definition: dbus-errors.c:211
dbus_bool_t dbus_error_is_set(const DBusError *error)
Checks whether an error occurred (the error is set).
Definition: dbus-errors.c:329
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
#define _DBUS_N_ELEMENTS(array)
Computes the number of elements in a fixed-size array using sizeof().
DBusList * _dbus_list_get_first_link(DBusList **list)
Gets the first link in the list.
Definition: dbus-list.c:567
int _dbus_list_get_length(DBusList **list)
Gets the length of a list.
Definition: dbus-list.c:730
void _dbus_list_clear(DBusList **list)
Frees all links in the list and sets the list head to NULL.
Definition: dbus-list.c:542
dbus_bool_t _dbus_list_append(DBusList **list, void *data)
Appends a value to the list.
Definition: dbus-list.c:270
#define _dbus_list_get_next_link(list, link)
Gets the next link in the list, or NULL if there are no more links.
Definition: dbus-list.h:116
#define NULL
A null pointer, defined appropriately for C or C++.
#define TRUE
Expands to "1".
#define FALSE
Expands to "0".
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:702
#define dbus_new(type, count)
Safe macro for using dbus_malloc().
Definition: dbus-memory.h:57
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition: dbus-memory.h:58
#define DBUS_ERROR_BAD_ADDRESS
A D-Bus bus address was malformed.
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
dbus_bool_t _dbus_string_set_length(DBusString *str, int length)
Sets the length of a string.
Definition: dbus-string.c:802
dbus_bool_t _dbus_string_hex_decode(const DBusString *source, int start, int *end_return, DBusString *dest, int insert_at)
Decodes a string from hex encoding.
Definition: dbus-string.c:2309
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
void _dbus_string_init_const(DBusString *str, const char *value)
Initializes a constant string.
Definition: dbus-string.c:190
dbus_bool_t _dbus_string_steal_data(DBusString *str, char **data_return)
Like _dbus_string_get_data(), but removes the gotten data from the original string.
Definition: dbus-string.c:641
dbus_bool_t _dbus_string_find(const DBusString *str, int start, const char *substr, int *found)
Finds the given substring in the string, returning TRUE and filling in the byte index where the subst...
Definition: dbus-string.c:1604
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:259
dbus_bool_t _dbus_string_equal_c_str(const DBusString *a, const char *c_str)
Checks whether a string is equal to a C string.
Definition: dbus-string.c:2152
dbus_bool_t _dbus_string_append_byte(DBusString *str, unsigned char byte)
Appends a single byte to the string, returning FALSE if not enough memory.
Definition: dbus-string.c:1157
dbus_bool_t _dbus_string_append_byte_as_hex(DBusString *str, unsigned char byte)
Appends a two-character hex digit to a string, where the hex digit has the value of the given byte.
Definition: dbus-string.c:2225
dbus_bool_t _dbus_string_find_to(const DBusString *str, int start, int end, const char *substr, int *found)
Finds the given substring in the string, up to a certain position, returning TRUE and filling in the ...
Definition: dbus-string.c:1697
dbus_bool_t _dbus_string_copy_len(const DBusString *source, int start, int len, DBusString *dest, int insert_at)
Like _dbus_string_copy(), but can copy a segment from the middle of the source string.
Definition: dbus-string.c:1375
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
Internals of DBusAddressEntry.
Definition: dbus-address.c:44
DBusString method
The address type (unix, tcp, etc.)
Definition: dbus-address.c:45
DBusList * values
List of values.
Definition: dbus-address.c:48
DBusList * keys
List of keys.
Definition: dbus-address.c:47
Object representing an exception.
Definition: dbus-errors.h:49
const char * message
public error message field
Definition: dbus-errors.h:51
A node in a linked list.
Definition: dbus-list.h:35
void * data
Data stored at this element.
Definition: dbus-list.h:38