00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025 #include "dbus-internals.h"
00026 #include "dbus-protocol.h"
00027 #include "dbus-marshal-basic.h"
00028 #include "dbus-test.h"
00029 #include <stdio.h>
00030 #include <stdarg.h>
00031 #include <string.h>
00032 #include <stdlib.h>
00033 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00034 #include <windows.h>
00035 #include <mbstring.h>
00036 #endif
00037
00198 const char *_dbus_no_memory_message = "Not enough memory";
00199
00200 static dbus_bool_t warn_initted = FALSE;
00201 static dbus_bool_t fatal_warnings = FALSE;
00202 static dbus_bool_t fatal_warnings_on_check_failed = FALSE;
00203
00204 static void
00205 init_warnings(void)
00206 {
00207 if (!warn_initted)
00208 {
00209 const char *s;
00210 s = _dbus_getenv ("DBUS_FATAL_WARNINGS");
00211 if (s && *s)
00212 {
00213 if (*s == '0')
00214 {
00215 fatal_warnings = FALSE;
00216 fatal_warnings_on_check_failed = FALSE;
00217 }
00218 else if (*s == '1')
00219 {
00220 fatal_warnings = TRUE;
00221 fatal_warnings_on_check_failed = TRUE;
00222 }
00223 else
00224 {
00225 fprintf(stderr, "DBUS_FATAL_WARNINGS should be set to 0 or 1 if set, not '%s'",
00226 s);
00227 }
00228 }
00229
00230 warn_initted = TRUE;
00231 }
00232 }
00233
00243 void
00244 _dbus_warn (const char *format,
00245 ...)
00246 {
00247 va_list args;
00248
00249 if (!warn_initted)
00250 init_warnings ();
00251
00252 va_start (args, format);
00253 vfprintf (stderr, format, args);
00254 va_end (args);
00255
00256 if (fatal_warnings)
00257 {
00258 fflush (stderr);
00259 _dbus_abort ();
00260 }
00261 }
00262
00271 void
00272 _dbus_warn_check_failed(const char *format,
00273 ...)
00274 {
00275 va_list args;
00276
00277 if (!warn_initted)
00278 init_warnings ();
00279
00280 fprintf (stderr, "process %lu: ", _dbus_pid_for_log ());
00281
00282 va_start (args, format);
00283 vfprintf (stderr, format, args);
00284 va_end (args);
00285
00286 if (fatal_warnings_on_check_failed)
00287 {
00288 fflush (stderr);
00289 _dbus_abort ();
00290 }
00291 }
00292
00293 #ifdef DBUS_ENABLE_VERBOSE_MODE
00294
00295 static dbus_bool_t verbose_initted = FALSE;
00296 static dbus_bool_t verbose = TRUE;
00297
00299 #define PTHREAD_IN_VERBOSE 0
00300 #if PTHREAD_IN_VERBOSE
00301 #include <pthread.h>
00302 #endif
00303
00304 #ifdef _MSC_VER
00305 #define inline
00306 #endif
00307 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00308 static char module_name[1024];
00309 #endif
00310
00311 static inline void
00312 _dbus_verbose_init (void)
00313 {
00314 if (!verbose_initted)
00315 {
00316 const char *p = _dbus_getenv ("DBUS_VERBOSE");
00317 verbose = p != NULL && *p == '1';
00318 verbose_initted = TRUE;
00319 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00320 {
00321 char *last_period, *last_slash;
00322 GetModuleFileName(0,module_name,sizeof(module_name)-1);
00323 last_period = _mbsrchr(module_name,'.');
00324 if (last_period)
00325 *last_period ='\0';
00326 last_slash = _mbsrchr(module_name,'\\');
00327 if (last_slash)
00328 strcpy(module_name,last_slash+1);
00329 strcat(module_name,": ");
00330 }
00331 #endif
00332 }
00333 }
00334
00340 #ifdef DBUS_WIN
00341 #define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/')
00342 #else
00343 #define DBUS_IS_DIR_SEPARATOR(c) (c == '/')
00344 #endif
00345
00350 static char *_dbus_file_path_extract_elements_from_tail(const char *file,int level)
00351 {
00352 static int prefix = -1;
00353 char *p;
00354
00355 if (prefix == -1)
00356 {
00357 char *p = (char *)file + strlen(file);
00358 int i = 0;
00359 prefix = 0;
00360 for (;p >= file;p--)
00361 {
00362 if (DBUS_IS_DIR_SEPARATOR(*p))
00363 {
00364 if (++i >= level)
00365 {
00366 prefix = p-file+1;
00367 break;
00368 }
00369 }
00370 }
00371 }
00372 return (char *)file+prefix;
00373 }
00374
00380 dbus_bool_t
00381 _dbus_is_verbose_real (void)
00382 {
00383 _dbus_verbose_init ();
00384 return verbose;
00385 }
00386
00395 void
00396 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00397 _dbus_verbose_real (const char *file,
00398 const int line,
00399 const char *function,
00400 const char *format,
00401 #else
00402 _dbus_verbose_real (const char *format,
00403 #endif
00404 ...)
00405 {
00406 va_list args;
00407 static dbus_bool_t need_pid = TRUE;
00408 int len;
00409
00410
00411
00412
00413
00414 if (!_dbus_is_verbose_real())
00415 return;
00416
00417 #ifndef DBUS_USE_OUTPUT_DEBUG_STRING
00418
00419 if (need_pid)
00420 {
00421 #if PTHREAD_IN_VERBOSE
00422 fprintf (stderr, "%lu: 0x%lx: ", _dbus_pid_for_log (), pthread_self ());
00423 #else
00424 fprintf (stderr, "%lu: ", _dbus_pid_for_log ());
00425 #endif
00426 }
00427 #endif
00428
00429
00430 len = strlen (format);
00431 if (format[len-1] == '\n')
00432 need_pid = TRUE;
00433 else
00434 need_pid = FALSE;
00435
00436 va_start (args, format);
00437 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00438 {
00439 char buf[1024];
00440 strcpy(buf,module_name);
00441 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00442 sprintf (buf+strlen(buf), "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00443 #endif
00444 vsprintf (buf+strlen(buf),format, args);
00445 va_end (args);
00446 OutputDebugStringA(buf);
00447 }
00448 #else
00449 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00450 fprintf (stderr, "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00451 #endif
00452
00453 vfprintf (stderr, format, args);
00454 va_end (args);
00455
00456 fflush (stderr);
00457 #endif
00458 }
00459
00466 void
00467 _dbus_verbose_reset_real (void)
00468 {
00469 verbose_initted = FALSE;
00470 }
00471
00472 #endif
00473
00482 char*
00483 _dbus_strdup (const char *str)
00484 {
00485 size_t len;
00486 char *copy;
00487
00488 if (str == NULL)
00489 return NULL;
00490
00491 len = strlen (str);
00492
00493 copy = dbus_malloc (len + 1);
00494 if (copy == NULL)
00495 return NULL;
00496
00497 memcpy (copy, str, len + 1);
00498
00499 return copy;
00500 }
00501
00510 void*
00511 _dbus_memdup (const void *mem,
00512 size_t n_bytes)
00513 {
00514 void *copy;
00515
00516 copy = dbus_malloc (n_bytes);
00517 if (copy == NULL)
00518 return NULL;
00519
00520 memcpy (copy, mem, n_bytes);
00521
00522 return copy;
00523 }
00524
00533 char**
00534 _dbus_dup_string_array (const char **array)
00535 {
00536 int len;
00537 int i;
00538 char **copy;
00539
00540 if (array == NULL)
00541 return NULL;
00542
00543 for (len = 0; array[len] != NULL; ++len)
00544 ;
00545
00546 copy = dbus_new0 (char*, len + 1);
00547 if (copy == NULL)
00548 return NULL;
00549
00550 i = 0;
00551 while (i < len)
00552 {
00553 copy[i] = _dbus_strdup (array[i]);
00554 if (copy[i] == NULL)
00555 {
00556 dbus_free_string_array (copy);
00557 return NULL;
00558 }
00559
00560 ++i;
00561 }
00562
00563 return copy;
00564 }
00565
00573 dbus_bool_t
00574 _dbus_string_array_contains (const char **array,
00575 const char *str)
00576 {
00577 int i;
00578
00579 i = 0;
00580 while (array[i] != NULL)
00581 {
00582 if (strcmp (array[i], str) == 0)
00583 return TRUE;
00584 ++i;
00585 }
00586
00587 return FALSE;
00588 }
00589
00596 void
00597 _dbus_generate_uuid (DBusGUID *uuid)
00598 {
00599 long now;
00600
00601 _dbus_get_current_time (&now, NULL);
00602
00603 uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
00604
00605 _dbus_generate_random_bytes_buffer (uuid->as_bytes, DBUS_UUID_LENGTH_BYTES - 4);
00606 }
00607
00615 dbus_bool_t
00616 _dbus_uuid_encode (const DBusGUID *uuid,
00617 DBusString *encoded)
00618 {
00619 DBusString binary;
00620 _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00621 return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
00622 }
00623
00624 static dbus_bool_t
00625 _dbus_read_uuid_file_without_creating (const DBusString *filename,
00626 DBusGUID *uuid,
00627 DBusError *error)
00628 {
00629 DBusString contents;
00630 DBusString decoded;
00631 int end;
00632
00633 if (!_dbus_string_init (&contents))
00634 {
00635 _DBUS_SET_OOM (error);
00636 return FALSE;
00637 }
00638
00639 if (!_dbus_string_init (&decoded))
00640 {
00641 _dbus_string_free (&contents);
00642 _DBUS_SET_OOM (error);
00643 return FALSE;
00644 }
00645
00646 if (!_dbus_file_get_contents (&contents, filename, error))
00647 goto error;
00648
00649 _dbus_string_chop_white (&contents);
00650
00651 if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
00652 {
00653 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00654 "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
00655 _dbus_string_get_const_data (filename),
00656 DBUS_UUID_LENGTH_HEX,
00657 _dbus_string_get_length (&contents));
00658 goto error;
00659 }
00660
00661 if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
00662 {
00663 _DBUS_SET_OOM (error);
00664 goto error;
00665 }
00666
00667 if (end == 0)
00668 {
00669 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00670 "UUID file '%s' contains invalid hex data",
00671 _dbus_string_get_const_data (filename));
00672 goto error;
00673 }
00674
00675 if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
00676 {
00677 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00678 "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
00679 _dbus_string_get_const_data (filename),
00680 _dbus_string_get_length (&decoded),
00681 DBUS_UUID_LENGTH_BYTES);
00682 goto error;
00683 }
00684
00685 _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00686
00687 _dbus_string_free (&decoded);
00688 _dbus_string_free (&contents);
00689
00690 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00691
00692 return TRUE;
00693
00694 error:
00695 _DBUS_ASSERT_ERROR_IS_SET (error);
00696 _dbus_string_free (&contents);
00697 _dbus_string_free (&decoded);
00698 return FALSE;
00699 }
00700
00701 static dbus_bool_t
00702 _dbus_create_uuid_file_exclusively (const DBusString *filename,
00703 DBusGUID *uuid,
00704 DBusError *error)
00705 {
00706 DBusString encoded;
00707
00708 if (!_dbus_string_init (&encoded))
00709 {
00710 _DBUS_SET_OOM (error);
00711 return FALSE;
00712 }
00713
00714 _dbus_generate_uuid (uuid);
00715
00716 if (!_dbus_uuid_encode (uuid, &encoded))
00717 {
00718 _DBUS_SET_OOM (error);
00719 goto error;
00720 }
00721
00722 if (!_dbus_string_append_byte (&encoded, '\n'))
00723 {
00724 _DBUS_SET_OOM (error);
00725 goto error;
00726 }
00727
00728 if (!_dbus_string_save_to_file (&encoded, filename, TRUE, error))
00729 goto error;
00730
00731 _dbus_string_free (&encoded);
00732
00733 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00734 return TRUE;
00735
00736 error:
00737 _DBUS_ASSERT_ERROR_IS_SET (error);
00738 _dbus_string_free (&encoded);
00739 return FALSE;
00740 }
00741
00752 dbus_bool_t
00753 _dbus_read_uuid_file (const DBusString *filename,
00754 DBusGUID *uuid,
00755 dbus_bool_t create_if_not_found,
00756 DBusError *error)
00757 {
00758 DBusError read_error = DBUS_ERROR_INIT;
00759
00760 if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error))
00761 return TRUE;
00762
00763 if (!create_if_not_found)
00764 {
00765 dbus_move_error (&read_error, error);
00766 return FALSE;
00767 }
00768
00769
00770
00771
00772
00773 if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT))
00774 {
00775 dbus_move_error (&read_error, error);
00776 return FALSE;
00777 }
00778 else
00779 {
00780 dbus_error_free (&read_error);
00781 return _dbus_create_uuid_file_exclusively (filename, uuid, error);
00782 }
00783 }
00784
00785 _DBUS_DEFINE_GLOBAL_LOCK (machine_uuid);
00786 static int machine_uuid_initialized_generation = 0;
00787 static DBusGUID machine_uuid;
00788
00799 dbus_bool_t
00800 _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str)
00801 {
00802 dbus_bool_t ok;
00803
00804 _DBUS_LOCK (machine_uuid);
00805 if (machine_uuid_initialized_generation != _dbus_current_generation)
00806 {
00807 DBusError error = DBUS_ERROR_INIT;
00808
00809 if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE,
00810 &error))
00811 {
00812 #ifndef DBUS_BUILD_TESTS
00813
00814
00815
00816
00817 _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n"
00818 "See the manual page for dbus-uuidgen to correct this issue.\n",
00819 error.message);
00820 #endif
00821
00822 dbus_error_free (&error);
00823
00824 _dbus_generate_uuid (&machine_uuid);
00825 }
00826 }
00827
00828 ok = _dbus_uuid_encode (&machine_uuid, uuid_str);
00829
00830 _DBUS_UNLOCK (machine_uuid);
00831
00832 return ok;
00833 }
00834
00835 #ifdef DBUS_BUILD_TESTS
00836
00842 const char *
00843 _dbus_header_field_to_string (int header_field)
00844 {
00845 switch (header_field)
00846 {
00847 case DBUS_HEADER_FIELD_INVALID:
00848 return "invalid";
00849 case DBUS_HEADER_FIELD_PATH:
00850 return "path";
00851 case DBUS_HEADER_FIELD_INTERFACE:
00852 return "interface";
00853 case DBUS_HEADER_FIELD_MEMBER:
00854 return "member";
00855 case DBUS_HEADER_FIELD_ERROR_NAME:
00856 return "error-name";
00857 case DBUS_HEADER_FIELD_REPLY_SERIAL:
00858 return "reply-serial";
00859 case DBUS_HEADER_FIELD_DESTINATION:
00860 return "destination";
00861 case DBUS_HEADER_FIELD_SENDER:
00862 return "sender";
00863 case DBUS_HEADER_FIELD_SIGNATURE:
00864 return "signature";
00865 default:
00866 return "unknown";
00867 }
00868 }
00869 #endif
00870
00871 #ifndef DBUS_DISABLE_CHECKS
00872
00873 const char *_dbus_return_if_fail_warning_format =
00874 "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n"
00875 "This is normally a bug in some application using the D-Bus library.\n";
00876 #endif
00877
00878 #ifndef DBUS_DISABLE_ASSERT
00879
00891 void
00892 _dbus_real_assert (dbus_bool_t condition,
00893 const char *condition_text,
00894 const char *file,
00895 int line,
00896 const char *func)
00897 {
00898 if (_DBUS_UNLIKELY (!condition))
00899 {
00900 _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n",
00901 _dbus_pid_for_log (), condition_text, file, line, func);
00902 _dbus_abort ();
00903 }
00904 }
00905
00916 void
00917 _dbus_real_assert_not_reached (const char *explanation,
00918 const char *file,
00919 int line)
00920 {
00921 _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n",
00922 file, line, _dbus_pid_for_log (), explanation);
00923 _dbus_abort ();
00924 }
00925 #endif
00926
00927 #ifdef DBUS_BUILD_TESTS
00928 static dbus_bool_t
00929 run_failing_each_malloc (int n_mallocs,
00930 const char *description,
00931 DBusTestMemoryFunction func,
00932 void *data)
00933 {
00934 n_mallocs += 10;
00935
00936 while (n_mallocs >= 0)
00937 {
00938 _dbus_set_fail_alloc_counter (n_mallocs);
00939
00940 _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n",
00941 description, n_mallocs,
00942 _dbus_get_fail_alloc_failures ());
00943
00944 if (!(* func) (data))
00945 return FALSE;
00946
00947 n_mallocs -= 1;
00948 }
00949
00950 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
00951
00952 return TRUE;
00953 }
00954
00968 dbus_bool_t
00969 _dbus_test_oom_handling (const char *description,
00970 DBusTestMemoryFunction func,
00971 void *data)
00972 {
00973 int approx_mallocs;
00974 const char *setting;
00975 int max_failures_to_try;
00976 int i;
00977
00978
00979
00980 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
00981
00982 _dbus_verbose ("Running once to count mallocs\n");
00983
00984 if (!(* func) (data))
00985 return FALSE;
00986
00987 approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
00988
00989 _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n",
00990 description, approx_mallocs);
00991
00992 setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES");
00993 if (setting != NULL)
00994 {
00995 DBusString str;
00996 long v;
00997 _dbus_string_init_const (&str, setting);
00998 v = 4;
00999 if (!_dbus_string_parse_int (&str, 0, &v, NULL))
01000 _dbus_warn ("couldn't parse '%s' as integer\n", setting);
01001 max_failures_to_try = v;
01002 }
01003 else
01004 {
01005 max_failures_to_try = 4;
01006 }
01007
01008 i = setting ? max_failures_to_try - 1 : 1;
01009 while (i < max_failures_to_try)
01010 {
01011 _dbus_set_fail_alloc_failures (i);
01012 if (!run_failing_each_malloc (approx_mallocs, description, func, data))
01013 return FALSE;
01014 ++i;
01015 }
01016
01017 _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n",
01018 description);
01019
01020 return TRUE;
01021 }
01022 #endif
01023