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 = TRUE;
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 DBUS_USE_OUTPUT_DEBUG_STRING
00305 static char module_name[1024];
00306 #endif
00307
00308 static inline void
00309 _dbus_verbose_init (void)
00310 {
00311 if (!verbose_initted)
00312 {
00313 const char *p = _dbus_getenv ("DBUS_VERBOSE");
00314 verbose = p != NULL && *p == '1';
00315 verbose_initted = TRUE;
00316 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00317 {
00318 char *last_period, *last_slash;
00319 GetModuleFileName(0,module_name,sizeof(module_name)-1);
00320 last_period = _mbsrchr(module_name,'.');
00321 if (last_period)
00322 *last_period ='\0';
00323 last_slash = _mbsrchr(module_name,'\\');
00324 if (last_slash)
00325 strcpy(module_name,last_slash+1);
00326 strcat(module_name,": ");
00327 }
00328 #endif
00329 }
00330 }
00331
00337 #ifdef DBUS_WIN
00338 #define DBUS_IS_DIR_SEPARATOR(c) (c == '\\' || c == '/')
00339 #else
00340 #define DBUS_IS_DIR_SEPARATOR(c) (c == '/')
00341 #endif
00342
00347 static char *_dbus_file_path_extract_elements_from_tail(const char *file,int level)
00348 {
00349 static int prefix = -1;
00350 char *p;
00351
00352 if (prefix == -1)
00353 {
00354 char *p = (char *)file + strlen(file);
00355 int i = 0;
00356 prefix = 0;
00357 for (;p >= file;p--)
00358 {
00359 if (DBUS_IS_DIR_SEPARATOR(*p))
00360 {
00361 if (++i >= level)
00362 {
00363 prefix = p-file+1;
00364 break;
00365 }
00366 }
00367 }
00368 }
00369 return (char *)file+prefix;
00370 }
00371
00377 dbus_bool_t
00378 _dbus_is_verbose_real (void)
00379 {
00380 _dbus_verbose_init ();
00381 return verbose;
00382 }
00383
00392 void
00393 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00394 _dbus_verbose_real (const char *file,
00395 const int line,
00396 const char *function,
00397 const char *format,
00398 #else
00399 _dbus_verbose_real (const char *format,
00400 #endif
00401 ...)
00402 {
00403 va_list args;
00404 static dbus_bool_t need_pid = TRUE;
00405 int len;
00406
00407
00408
00409
00410
00411 if (!_dbus_is_verbose_real())
00412 return;
00413
00414 #ifndef DBUS_USE_OUTPUT_DEBUG_STRING
00415
00416 if (need_pid)
00417 {
00418 #if PTHREAD_IN_VERBOSE
00419 fprintf (stderr, "%lu: 0x%lx: ", _dbus_pid_for_log (), pthread_self ());
00420 #else
00421 fprintf (stderr, "%lu: ", _dbus_pid_for_log ());
00422 #endif
00423 }
00424 #endif
00425
00426
00427 len = strlen (format);
00428 if (format[len-1] == '\n')
00429 need_pid = TRUE;
00430 else
00431 need_pid = FALSE;
00432
00433 va_start (args, format);
00434 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
00435 {
00436 char buf[1024];
00437 strcpy(buf,module_name);
00438 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00439 sprintf (buf+strlen(buf), "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00440 #endif
00441 vsprintf (buf+strlen(buf),format, args);
00442 va_end (args);
00443 OutputDebugStringA(buf);
00444 }
00445 #else
00446 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
00447 fprintf (stderr, "[%s(%d):%s] ",_dbus_file_path_extract_elements_from_tail(file,2),line,function);
00448 #endif
00449
00450 vfprintf (stderr, format, args);
00451 va_end (args);
00452
00453 fflush (stderr);
00454 #endif
00455 }
00456
00463 void
00464 _dbus_verbose_reset_real (void)
00465 {
00466 verbose_initted = FALSE;
00467 }
00468
00469 #endif
00470
00479 char*
00480 _dbus_strdup (const char *str)
00481 {
00482 size_t len;
00483 char *copy;
00484
00485 if (str == NULL)
00486 return NULL;
00487
00488 len = strlen (str);
00489
00490 copy = dbus_malloc (len + 1);
00491 if (copy == NULL)
00492 return NULL;
00493
00494 memcpy (copy, str, len + 1);
00495
00496 return copy;
00497 }
00498
00507 void*
00508 _dbus_memdup (const void *mem,
00509 size_t n_bytes)
00510 {
00511 void *copy;
00512
00513 copy = dbus_malloc (n_bytes);
00514 if (copy == NULL)
00515 return NULL;
00516
00517 memcpy (copy, mem, n_bytes);
00518
00519 return copy;
00520 }
00521
00530 char**
00531 _dbus_dup_string_array (const char **array)
00532 {
00533 int len;
00534 int i;
00535 char **copy;
00536
00537 if (array == NULL)
00538 return NULL;
00539
00540 for (len = 0; array[len] != NULL; ++len)
00541 ;
00542
00543 copy = dbus_new0 (char*, len + 1);
00544 if (copy == NULL)
00545 return NULL;
00546
00547 i = 0;
00548 while (i < len)
00549 {
00550 copy[i] = _dbus_strdup (array[i]);
00551 if (copy[i] == NULL)
00552 {
00553 dbus_free_string_array (copy);
00554 return NULL;
00555 }
00556
00557 ++i;
00558 }
00559
00560 return copy;
00561 }
00562
00570 dbus_bool_t
00571 _dbus_string_array_contains (const char **array,
00572 const char *str)
00573 {
00574 int i;
00575
00576 i = 0;
00577 while (array[i] != NULL)
00578 {
00579 if (strcmp (array[i], str) == 0)
00580 return TRUE;
00581 ++i;
00582 }
00583
00584 return FALSE;
00585 }
00586
00593 void
00594 _dbus_generate_uuid (DBusGUID *uuid)
00595 {
00596 long now;
00597
00598 _dbus_get_current_time (&now, NULL);
00599
00600 uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
00601
00602 _dbus_generate_random_bytes_buffer (uuid->as_bytes, DBUS_UUID_LENGTH_BYTES - 4);
00603 }
00604
00612 dbus_bool_t
00613 _dbus_uuid_encode (const DBusGUID *uuid,
00614 DBusString *encoded)
00615 {
00616 DBusString binary;
00617 _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00618 return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
00619 }
00620
00621 static dbus_bool_t
00622 _dbus_read_uuid_file_without_creating (const DBusString *filename,
00623 DBusGUID *uuid,
00624 DBusError *error)
00625 {
00626 DBusString contents;
00627 DBusString decoded;
00628 int end;
00629
00630 if (!_dbus_string_init (&contents))
00631 {
00632 _DBUS_SET_OOM (error);
00633 return FALSE;
00634 }
00635
00636 if (!_dbus_string_init (&decoded))
00637 {
00638 _dbus_string_free (&contents);
00639 _DBUS_SET_OOM (error);
00640 return FALSE;
00641 }
00642
00643 if (!_dbus_file_get_contents (&contents, filename, error))
00644 goto error;
00645
00646 _dbus_string_chop_white (&contents);
00647
00648 if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
00649 {
00650 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00651 "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
00652 _dbus_string_get_const_data (filename),
00653 DBUS_UUID_LENGTH_HEX,
00654 _dbus_string_get_length (&contents));
00655 goto error;
00656 }
00657
00658 if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
00659 {
00660 _DBUS_SET_OOM (error);
00661 goto error;
00662 }
00663
00664 if (end == 0)
00665 {
00666 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00667 "UUID file '%s' contains invalid hex data",
00668 _dbus_string_get_const_data (filename));
00669 goto error;
00670 }
00671
00672 if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
00673 {
00674 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00675 "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
00676 _dbus_string_get_const_data (filename),
00677 _dbus_string_get_length (&decoded),
00678 DBUS_UUID_LENGTH_BYTES);
00679 goto error;
00680 }
00681
00682 _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00683
00684 _dbus_string_free (&decoded);
00685 _dbus_string_free (&contents);
00686
00687 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00688
00689 return TRUE;
00690
00691 error:
00692 _DBUS_ASSERT_ERROR_IS_SET (error);
00693 _dbus_string_free (&contents);
00694 _dbus_string_free (&decoded);
00695 return FALSE;
00696 }
00697
00698 static dbus_bool_t
00699 _dbus_create_uuid_file_exclusively (const DBusString *filename,
00700 DBusGUID *uuid,
00701 DBusError *error)
00702 {
00703 DBusString encoded;
00704
00705 if (!_dbus_string_init (&encoded))
00706 {
00707 _DBUS_SET_OOM (error);
00708 return FALSE;
00709 }
00710
00711 _dbus_generate_uuid (uuid);
00712
00713 if (!_dbus_uuid_encode (uuid, &encoded))
00714 {
00715 _DBUS_SET_OOM (error);
00716 goto error;
00717 }
00718
00719 if (!_dbus_string_append_byte (&encoded, '\n'))
00720 {
00721 _DBUS_SET_OOM (error);
00722 goto error;
00723 }
00724
00725 if (!_dbus_string_save_to_file (&encoded, filename, TRUE, error))
00726 goto error;
00727
00728 _dbus_string_free (&encoded);
00729
00730 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00731 return TRUE;
00732
00733 error:
00734 _DBUS_ASSERT_ERROR_IS_SET (error);
00735 _dbus_string_free (&encoded);
00736 return FALSE;
00737 }
00738
00749 dbus_bool_t
00750 _dbus_read_uuid_file (const DBusString *filename,
00751 DBusGUID *uuid,
00752 dbus_bool_t create_if_not_found,
00753 DBusError *error)
00754 {
00755 DBusError read_error = DBUS_ERROR_INIT;
00756
00757 if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error))
00758 return TRUE;
00759
00760 if (!create_if_not_found)
00761 {
00762 dbus_move_error (&read_error, error);
00763 return FALSE;
00764 }
00765
00766
00767
00768
00769
00770 if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT))
00771 {
00772 dbus_move_error (&read_error, error);
00773 return FALSE;
00774 }
00775 else
00776 {
00777 dbus_error_free (&read_error);
00778 return _dbus_create_uuid_file_exclusively (filename, uuid, error);
00779 }
00780 }
00781
00782 _DBUS_DEFINE_GLOBAL_LOCK (machine_uuid);
00783 static int machine_uuid_initialized_generation = 0;
00784 static DBusGUID machine_uuid;
00785
00796 dbus_bool_t
00797 _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str)
00798 {
00799 dbus_bool_t ok;
00800
00801 _DBUS_LOCK (machine_uuid);
00802 if (machine_uuid_initialized_generation != _dbus_current_generation)
00803 {
00804 DBusError error = DBUS_ERROR_INIT;
00805
00806 if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE,
00807 &error))
00808 {
00809 #ifndef DBUS_BUILD_TESTS
00810
00811
00812
00813
00814 _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n"
00815 "See the manual page for dbus-uuidgen to correct this issue.\n",
00816 error.message);
00817 #endif
00818
00819 dbus_error_free (&error);
00820
00821 _dbus_generate_uuid (&machine_uuid);
00822 }
00823 }
00824
00825 ok = _dbus_uuid_encode (&machine_uuid, uuid_str);
00826
00827 _DBUS_UNLOCK (machine_uuid);
00828
00829 return ok;
00830 }
00831
00832 #ifdef DBUS_BUILD_TESTS
00833
00839 const char *
00840 _dbus_header_field_to_string (int header_field)
00841 {
00842 switch (header_field)
00843 {
00844 case DBUS_HEADER_FIELD_INVALID:
00845 return "invalid";
00846 case DBUS_HEADER_FIELD_PATH:
00847 return "path";
00848 case DBUS_HEADER_FIELD_INTERFACE:
00849 return "interface";
00850 case DBUS_HEADER_FIELD_MEMBER:
00851 return "member";
00852 case DBUS_HEADER_FIELD_ERROR_NAME:
00853 return "error-name";
00854 case DBUS_HEADER_FIELD_REPLY_SERIAL:
00855 return "reply-serial";
00856 case DBUS_HEADER_FIELD_DESTINATION:
00857 return "destination";
00858 case DBUS_HEADER_FIELD_SENDER:
00859 return "sender";
00860 case DBUS_HEADER_FIELD_SIGNATURE:
00861 return "signature";
00862 default:
00863 return "unknown";
00864 }
00865 }
00866 #endif
00867
00868 #ifndef DBUS_DISABLE_CHECKS
00869
00870 const char *_dbus_return_if_fail_warning_format =
00871 "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n"
00872 "This is normally a bug in some application using the D-Bus library.\n";
00873 #endif
00874
00875 #ifndef DBUS_DISABLE_ASSERT
00876
00888 void
00889 _dbus_real_assert (dbus_bool_t condition,
00890 const char *condition_text,
00891 const char *file,
00892 int line,
00893 const char *func)
00894 {
00895 if (_DBUS_UNLIKELY (!condition))
00896 {
00897 _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n",
00898 _dbus_pid_for_log (), condition_text, file, line, func);
00899 _dbus_abort ();
00900 }
00901 }
00902
00913 void
00914 _dbus_real_assert_not_reached (const char *explanation,
00915 const char *file,
00916 int line)
00917 {
00918 _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n",
00919 file, line, _dbus_pid_for_log (), explanation);
00920 _dbus_abort ();
00921 }
00922 #endif
00923
00924 #ifdef DBUS_BUILD_TESTS
00925 static dbus_bool_t
00926 run_failing_each_malloc (int n_mallocs,
00927 const char *description,
00928 DBusTestMemoryFunction func,
00929 void *data)
00930 {
00931 n_mallocs += 10;
00932
00933 while (n_mallocs >= 0)
00934 {
00935 _dbus_set_fail_alloc_counter (n_mallocs);
00936
00937 _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n",
00938 description, n_mallocs,
00939 _dbus_get_fail_alloc_failures ());
00940
00941 if (!(* func) (data))
00942 return FALSE;
00943
00944 n_mallocs -= 1;
00945 }
00946
00947 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
00948
00949 return TRUE;
00950 }
00951
00965 dbus_bool_t
00966 _dbus_test_oom_handling (const char *description,
00967 DBusTestMemoryFunction func,
00968 void *data)
00969 {
00970 int approx_mallocs;
00971 const char *setting;
00972 int max_failures_to_try;
00973 int i;
00974
00975
00976
00977 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
00978
00979 _dbus_verbose ("Running once to count mallocs\n");
00980
00981 if (!(* func) (data))
00982 return FALSE;
00983
00984 approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
00985
00986 _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n",
00987 description, approx_mallocs);
00988
00989 setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES");
00990 if (setting != NULL)
00991 {
00992 DBusString str;
00993 long v;
00994 _dbus_string_init_const (&str, setting);
00995 v = 4;
00996 if (!_dbus_string_parse_int (&str, 0, &v, NULL))
00997 _dbus_warn ("couldn't parse '%s' as integer\n", setting);
00998 max_failures_to_try = v;
00999 }
01000 else
01001 {
01002 max_failures_to_try = 4;
01003 }
01004
01005 i = setting ? max_failures_to_try - 1 : 1;
01006 while (i < max_failures_to_try)
01007 {
01008 _dbus_set_fail_alloc_failures (i);
01009 if (!run_failing_each_malloc (approx_mallocs, description, func, data))
01010 return FALSE;
01011 ++i;
01012 }
01013
01014 _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n",
01015 description);
01016
01017 return TRUE;
01018 }
01019 #endif
01020