00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "dbus-internals.h"
00024 #include "dbus-protocol.h"
00025 #include "dbus-marshal-basic.h"
00026 #include "dbus-test.h"
00027 #include <stdio.h>
00028 #include <stdarg.h>
00029 #include <string.h>
00030 #include <stdlib.h>
00031
00192 const char _dbus_no_memory_message[] = "Not enough memory";
00193
00194 static dbus_bool_t warn_initted = FALSE;
00195 static dbus_bool_t fatal_warnings = FALSE;
00196 static dbus_bool_t fatal_warnings_on_check_failed = FALSE;
00197
00198 static void
00199 init_warnings(void)
00200 {
00201 if (!warn_initted)
00202 {
00203 const char *s;
00204 s = _dbus_getenv ("DBUS_FATAL_WARNINGS");
00205 if (s && *s)
00206 {
00207 if (*s == '0')
00208 {
00209 fatal_warnings = FALSE;
00210 fatal_warnings_on_check_failed = FALSE;
00211 }
00212 else if (*s == '1')
00213 {
00214 fatal_warnings = TRUE;
00215 fatal_warnings_on_check_failed = TRUE;
00216 }
00217 else
00218 {
00219 fprintf(stderr, "DBUS_FATAL_WARNINGS should be set to 0 or 1 if set, not '%s'",
00220 s);
00221 }
00222 }
00223
00224 warn_initted = TRUE;
00225 }
00226 }
00227
00237 void
00238 _dbus_warn (const char *format,
00239 ...)
00240 {
00241 va_list args;
00242
00243 if (!warn_initted)
00244 init_warnings ();
00245
00246 va_start (args, format);
00247 vfprintf (stderr, format, args);
00248 va_end (args);
00249
00250 if (fatal_warnings)
00251 {
00252 fflush (stderr);
00253 _dbus_abort ();
00254 }
00255 }
00256
00265 void
00266 _dbus_warn_check_failed(const char *format,
00267 ...)
00268 {
00269 va_list args;
00270
00271 if (!warn_initted)
00272 init_warnings ();
00273
00274 fprintf (stderr, "process %lu: ", _dbus_pid_for_log ());
00275
00276 va_start (args, format);
00277 vfprintf (stderr, format, args);
00278 va_end (args);
00279
00280 if (fatal_warnings_on_check_failed)
00281 {
00282 fflush (stderr);
00283 _dbus_abort ();
00284 }
00285 }
00286
00287 #ifdef DBUS_ENABLE_VERBOSE_MODE
00288
00289 static dbus_bool_t verbose_initted = FALSE;
00290 static dbus_bool_t verbose = TRUE;
00291
00293 #define PTHREAD_IN_VERBOSE 0
00294 #if PTHREAD_IN_VERBOSE
00295 #include <pthread.h>
00296 #endif
00297
00298 #ifdef DBUS_WIN
00299 #define inline
00300 #endif
00301
00302 static inline void
00303 _dbus_verbose_init (void)
00304 {
00305 if (!verbose_initted)
00306 {
00307 const char *p = _dbus_getenv ("DBUS_VERBOSE");
00308 verbose = p != NULL && *p == '1';
00309 verbose_initted = TRUE;
00310 }
00311 }
00312
00318 dbus_bool_t
00319 _dbus_is_verbose_real (void)
00320 {
00321 _dbus_verbose_init ();
00322 return verbose;
00323 }
00324
00333 void
00334 _dbus_verbose_real (const char *format,
00335 ...)
00336 {
00337 va_list args;
00338 static dbus_bool_t need_pid = TRUE;
00339 int len;
00340
00341
00342
00343
00344
00345 if (!_dbus_is_verbose_real())
00346 return;
00347
00348
00349 if (need_pid)
00350 {
00351 #if PTHREAD_IN_VERBOSE
00352 fprintf (stderr, "%lu: 0x%lx: ", _dbus_pid_for_log (), pthread_self ());
00353 #else
00354 fprintf (stderr, "%lu: ", _dbus_pid_for_log ());
00355 #endif
00356 }
00357
00358
00359
00360 len = strlen (format);
00361 if (format[len-1] == '\n')
00362 need_pid = TRUE;
00363 else
00364 need_pid = FALSE;
00365
00366 va_start (args, format);
00367 vfprintf (stderr, format, args);
00368 va_end (args);
00369
00370 fflush (stderr);
00371 }
00372
00379 void
00380 _dbus_verbose_reset_real (void)
00381 {
00382 verbose_initted = FALSE;
00383 }
00384
00385 #endif
00386
00395 char*
00396 _dbus_strdup (const char *str)
00397 {
00398 size_t len;
00399 char *copy;
00400
00401 if (str == NULL)
00402 return NULL;
00403
00404 len = strlen (str);
00405
00406 copy = dbus_malloc (len + 1);
00407 if (copy == NULL)
00408 return NULL;
00409
00410 memcpy (copy, str, len + 1);
00411
00412 return copy;
00413 }
00414
00423 void*
00424 _dbus_memdup (const void *mem,
00425 size_t n_bytes)
00426 {
00427 void *copy;
00428
00429 copy = dbus_malloc (n_bytes);
00430 if (copy == NULL)
00431 return NULL;
00432
00433 memcpy (copy, mem, n_bytes);
00434
00435 return copy;
00436 }
00437
00446 char**
00447 _dbus_dup_string_array (const char **array)
00448 {
00449 int len;
00450 int i;
00451 char **copy;
00452
00453 if (array == NULL)
00454 return NULL;
00455
00456 for (len = 0; array[len] != NULL; ++len)
00457 ;
00458
00459 copy = dbus_new0 (char*, len + 1);
00460 if (copy == NULL)
00461 return NULL;
00462
00463 i = 0;
00464 while (i < len)
00465 {
00466 copy[i] = _dbus_strdup (array[i]);
00467 if (copy[i] == NULL)
00468 {
00469 dbus_free_string_array (copy);
00470 return NULL;
00471 }
00472
00473 ++i;
00474 }
00475
00476 return copy;
00477 }
00478
00486 dbus_bool_t
00487 _dbus_string_array_contains (const char **array,
00488 const char *str)
00489 {
00490 int i;
00491
00492 i = 0;
00493 while (array[i] != NULL)
00494 {
00495 if (strcmp (array[i], str) == 0)
00496 return TRUE;
00497 ++i;
00498 }
00499
00500 return FALSE;
00501 }
00502
00509 void
00510 _dbus_generate_uuid (DBusGUID *uuid)
00511 {
00512 long now;
00513
00514 _dbus_get_current_time (&now, NULL);
00515
00516 uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
00517
00518 _dbus_generate_random_bytes_buffer (uuid->as_bytes, DBUS_UUID_LENGTH_BYTES - 4);
00519 }
00520
00528 dbus_bool_t
00529 _dbus_uuid_encode (const DBusGUID *uuid,
00530 DBusString *encoded)
00531 {
00532 DBusString binary;
00533 _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00534 return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
00535 }
00536
00537 static dbus_bool_t
00538 _dbus_read_uuid_file_without_creating (const DBusString *filename,
00539 DBusGUID *uuid,
00540 DBusError *error)
00541 {
00542 DBusString contents;
00543 DBusString decoded;
00544 int end;
00545
00546 _dbus_string_init (&contents);
00547 _dbus_string_init (&decoded);
00548
00549 if (!_dbus_file_get_contents (&contents, filename, error))
00550 goto error;
00551
00552 _dbus_string_chop_white (&contents);
00553
00554 if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
00555 {
00556 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00557 "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
00558 _dbus_string_get_const_data (filename),
00559 DBUS_UUID_LENGTH_HEX,
00560 _dbus_string_get_length (&contents));
00561 goto error;
00562 }
00563
00564 if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
00565 {
00566 _DBUS_SET_OOM (error);
00567 goto error;
00568 }
00569
00570 if (end == 0)
00571 {
00572 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00573 "UUID file '%s' contains invalid hex data",
00574 _dbus_string_get_const_data (filename));
00575 goto error;
00576 }
00577
00578 if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
00579 {
00580 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00581 "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
00582 _dbus_string_get_const_data (filename),
00583 _dbus_string_get_length (&decoded),
00584 DBUS_UUID_LENGTH_BYTES);
00585 goto error;
00586 }
00587
00588 _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00589
00590 _dbus_string_free (&decoded);
00591 _dbus_string_free (&contents);
00592
00593 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00594
00595 return TRUE;
00596
00597 error:
00598 _DBUS_ASSERT_ERROR_IS_SET (error);
00599 _dbus_string_free (&contents);
00600 _dbus_string_free (&decoded);
00601 return FALSE;
00602 }
00603
00604 static dbus_bool_t
00605 _dbus_create_uuid_file_exclusively (const DBusString *filename,
00606 DBusGUID *uuid,
00607 DBusError *error)
00608 {
00609 DBusString encoded;
00610
00611 _dbus_string_init (&encoded);
00612
00613 _dbus_generate_uuid (uuid);
00614
00615 if (!_dbus_uuid_encode (uuid, &encoded))
00616 {
00617 _DBUS_SET_OOM (error);
00618 goto error;
00619 }
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629 if (!_dbus_create_file_exclusively (filename, error))
00630 goto error;
00631
00632 if (!_dbus_string_append_byte (&encoded, '\n'))
00633 {
00634 _DBUS_SET_OOM (error);
00635 goto error;
00636 }
00637
00638 if (!_dbus_string_save_to_file (&encoded, filename, error))
00639 goto error;
00640
00641 if (!_dbus_make_file_world_readable (filename, error))
00642 goto error;
00643
00644 _dbus_string_free (&encoded);
00645
00646 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00647 return TRUE;
00648
00649 error:
00650 _DBUS_ASSERT_ERROR_IS_SET (error);
00651 _dbus_string_free (&encoded);
00652 return FALSE;
00653 }
00654
00665 dbus_bool_t
00666 _dbus_read_uuid_file (const DBusString *filename,
00667 DBusGUID *uuid,
00668 dbus_bool_t create_if_not_found,
00669 DBusError *error)
00670 {
00671 DBusError read_error;
00672
00673 dbus_error_init (&read_error);
00674
00675 if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error))
00676 return TRUE;
00677
00678 if (!create_if_not_found)
00679 {
00680 dbus_move_error (&read_error, error);
00681 return FALSE;
00682 }
00683
00684
00685
00686
00687
00688 if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT))
00689 {
00690 dbus_move_error (&read_error, error);
00691 return FALSE;
00692 }
00693 else
00694 {
00695 dbus_error_free (&read_error);
00696 return _dbus_create_uuid_file_exclusively (filename, uuid, error);
00697 }
00698 }
00699
00700 _DBUS_DEFINE_GLOBAL_LOCK (machine_uuid);
00701 static int machine_uuid_initialized_generation = 0;
00702 static DBusGUID machine_uuid;
00703
00714 dbus_bool_t
00715 _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str)
00716 {
00717 dbus_bool_t ok;
00718
00719 _DBUS_LOCK (machine_uuid);
00720 if (machine_uuid_initialized_generation != _dbus_current_generation)
00721 {
00722 DBusError error;
00723 dbus_error_init (&error);
00724 if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE,
00725 &error))
00726 {
00727 #ifndef DBUS_BUILD_TESTS
00728
00729
00730
00731
00732 _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n"
00733 "See the manual page for dbus-uuidgen to correct this issue.\n",
00734 error.message);
00735 #endif
00736
00737 dbus_error_free (&error);
00738
00739 _dbus_generate_uuid (&machine_uuid);
00740 }
00741 }
00742
00743 ok = _dbus_uuid_encode (&machine_uuid, uuid_str);
00744
00745 _DBUS_UNLOCK (machine_uuid);
00746
00747 return ok;
00748 }
00749
00750 #ifdef DBUS_BUILD_TESTS
00751
00757 const char *
00758 _dbus_header_field_to_string (int header_field)
00759 {
00760 switch (header_field)
00761 {
00762 case DBUS_HEADER_FIELD_INVALID:
00763 return "invalid";
00764 case DBUS_HEADER_FIELD_PATH:
00765 return "path";
00766 case DBUS_HEADER_FIELD_INTERFACE:
00767 return "interface";
00768 case DBUS_HEADER_FIELD_MEMBER:
00769 return "member";
00770 case DBUS_HEADER_FIELD_ERROR_NAME:
00771 return "error-name";
00772 case DBUS_HEADER_FIELD_REPLY_SERIAL:
00773 return "reply-serial";
00774 case DBUS_HEADER_FIELD_DESTINATION:
00775 return "destination";
00776 case DBUS_HEADER_FIELD_SENDER:
00777 return "sender";
00778 case DBUS_HEADER_FIELD_SIGNATURE:
00779 return "signature";
00780 default:
00781 return "unknown";
00782 }
00783 }
00784 #endif
00785
00786 #ifndef DBUS_DISABLE_CHECKS
00787
00788 const char _dbus_return_if_fail_warning_format[] =
00789 "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n"
00790 "This is normally a bug in some application using the D-Bus library.\n";
00791 #endif
00792
00793 #ifndef DBUS_DISABLE_ASSERT
00794
00806 void
00807 _dbus_real_assert (dbus_bool_t condition,
00808 const char *condition_text,
00809 const char *file,
00810 int line,
00811 const char *func)
00812 {
00813 if (_DBUS_UNLIKELY (!condition))
00814 {
00815 _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n",
00816 _dbus_pid_for_log (), condition_text, file, line, func);
00817 _dbus_abort ();
00818 }
00819 }
00820
00831 void
00832 _dbus_real_assert_not_reached (const char *explanation,
00833 const char *file,
00834 int line)
00835 {
00836 _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n",
00837 file, line, _dbus_pid_for_log (), explanation);
00838 _dbus_abort ();
00839 }
00840 #endif
00841
00842 #ifdef DBUS_BUILD_TESTS
00843 static dbus_bool_t
00844 run_failing_each_malloc (int n_mallocs,
00845 const char *description,
00846 DBusTestMemoryFunction func,
00847 void *data)
00848 {
00849 n_mallocs += 10;
00850
00851 while (n_mallocs >= 0)
00852 {
00853 _dbus_set_fail_alloc_counter (n_mallocs);
00854
00855 _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n",
00856 description, n_mallocs,
00857 _dbus_get_fail_alloc_failures ());
00858
00859 if (!(* func) (data))
00860 return FALSE;
00861
00862 n_mallocs -= 1;
00863 }
00864
00865 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
00866
00867 return TRUE;
00868 }
00869
00883 dbus_bool_t
00884 _dbus_test_oom_handling (const char *description,
00885 DBusTestMemoryFunction func,
00886 void *data)
00887 {
00888 int approx_mallocs;
00889 const char *setting;
00890 int max_failures_to_try;
00891 int i;
00892
00893
00894
00895 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
00896
00897 _dbus_verbose ("Running once to count mallocs\n");
00898
00899 if (!(* func) (data))
00900 return FALSE;
00901
00902 approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
00903
00904 _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n",
00905 description, approx_mallocs);
00906
00907 setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES");
00908 if (setting != NULL)
00909 {
00910 DBusString str;
00911 long v;
00912 _dbus_string_init_const (&str, setting);
00913 v = 4;
00914 if (!_dbus_string_parse_int (&str, 0, &v, NULL))
00915 _dbus_warn ("couldn't parse '%s' as integer\n", setting);
00916 max_failures_to_try = v;
00917 }
00918 else
00919 {
00920 max_failures_to_try = 4;
00921 }
00922
00923 i = setting ? max_failures_to_try - 1 : 1;
00924 while (i < max_failures_to_try)
00925 {
00926 _dbus_set_fail_alloc_failures (i);
00927 if (!run_failing_each_malloc (approx_mallocs, description, func, data))
00928 return FALSE;
00929 ++i;
00930 }
00931
00932 _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n",
00933 description);
00934
00935 return TRUE;
00936 }
00937 #endif
00938