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 = TRUE;
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_getpid ());
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 static inline void
00299 _dbus_verbose_init (void)
00300 {
00301 if (!verbose_initted)
00302 {
00303 const char *p = _dbus_getenv ("DBUS_VERBOSE");
00304 verbose = p != NULL && *p == '1';
00305 verbose_initted = TRUE;
00306 }
00307 }
00308
00314 dbus_bool_t
00315 _dbus_is_verbose_real (void)
00316 {
00317 _dbus_verbose_init ();
00318 return verbose;
00319 }
00320
00329 void
00330 _dbus_verbose_real (const char *format,
00331 ...)
00332 {
00333 va_list args;
00334 static dbus_bool_t need_pid = TRUE;
00335 int len;
00336
00337
00338
00339
00340
00341 if (!_dbus_is_verbose_real())
00342 return;
00343
00344
00345 if (need_pid)
00346 {
00347 #if PTHREAD_IN_VERBOSE
00348 fprintf (stderr, "%lu: 0x%lx: ", _dbus_getpid (), pthread_self ());
00349 #else
00350 fprintf (stderr, "%lu: ", _dbus_getpid ());
00351 #endif
00352 }
00353
00354
00355
00356 len = strlen (format);
00357 if (format[len-1] == '\n')
00358 need_pid = TRUE;
00359 else
00360 need_pid = FALSE;
00361
00362 va_start (args, format);
00363 vfprintf (stderr, format, args);
00364 va_end (args);
00365
00366 fflush (stderr);
00367 }
00368
00375 void
00376 _dbus_verbose_reset_real (void)
00377 {
00378 verbose_initted = FALSE;
00379 }
00380
00381 #endif
00382
00391 char*
00392 _dbus_strdup (const char *str)
00393 {
00394 size_t len;
00395 char *copy;
00396
00397 if (str == NULL)
00398 return NULL;
00399
00400 len = strlen (str);
00401
00402 copy = dbus_malloc (len + 1);
00403 if (copy == NULL)
00404 return NULL;
00405
00406 memcpy (copy, str, len + 1);
00407
00408 return copy;
00409 }
00410
00419 void*
00420 _dbus_memdup (const void *mem,
00421 size_t n_bytes)
00422 {
00423 void *copy;
00424
00425 copy = dbus_malloc (n_bytes);
00426 if (copy == NULL)
00427 return NULL;
00428
00429 memcpy (copy, mem, n_bytes);
00430
00431 return copy;
00432 }
00433
00442 char**
00443 _dbus_dup_string_array (const char **array)
00444 {
00445 int len;
00446 int i;
00447 char **copy;
00448
00449 if (array == NULL)
00450 return NULL;
00451
00452 for (len = 0; array[len] != NULL; ++len)
00453 ;
00454
00455 copy = dbus_new0 (char*, len + 1);
00456 if (copy == NULL)
00457 return NULL;
00458
00459 i = 0;
00460 while (i < len)
00461 {
00462 copy[i] = _dbus_strdup (array[i]);
00463 if (copy[i] == NULL)
00464 {
00465 dbus_free_string_array (copy);
00466 return NULL;
00467 }
00468
00469 ++i;
00470 }
00471
00472 return copy;
00473 }
00474
00482 dbus_bool_t
00483 _dbus_string_array_contains (const char **array,
00484 const char *str)
00485 {
00486 int i;
00487
00488 i = 0;
00489 while (array[i] != NULL)
00490 {
00491 if (strcmp (array[i], str) == 0)
00492 return TRUE;
00493 ++i;
00494 }
00495
00496 return FALSE;
00497 }
00498
00505 void
00506 _dbus_generate_uuid (DBusGUID *uuid)
00507 {
00508 long now;
00509
00510 _dbus_get_current_time (&now, NULL);
00511
00512 uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
00513
00514 _dbus_generate_random_bytes_buffer (uuid->as_bytes, DBUS_UUID_LENGTH_BYTES - 4);
00515 }
00516
00524 dbus_bool_t
00525 _dbus_uuid_encode (const DBusGUID *uuid,
00526 DBusString *encoded)
00527 {
00528 DBusString binary;
00529 _dbus_string_init_const_len (&binary, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00530 return _dbus_string_hex_encode (&binary, 0, encoded, _dbus_string_get_length (encoded));
00531 }
00532
00533 static dbus_bool_t
00534 _dbus_read_uuid_file_without_creating (const DBusString *filename,
00535 DBusGUID *uuid,
00536 DBusError *error)
00537 {
00538 DBusString contents;
00539 DBusString decoded;
00540 int end;
00541
00542 _dbus_string_init (&contents);
00543 _dbus_string_init (&decoded);
00544
00545 if (!_dbus_file_get_contents (&contents, filename, error))
00546 goto error;
00547
00548 _dbus_string_chop_white (&contents);
00549
00550 if (_dbus_string_get_length (&contents) != DBUS_UUID_LENGTH_HEX)
00551 {
00552 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00553 "UUID file '%s' should contain a hex string of length %d, not length %d, with no other text",
00554 _dbus_string_get_const_data (filename),
00555 DBUS_UUID_LENGTH_HEX,
00556 _dbus_string_get_length (&contents));
00557 goto error;
00558 }
00559
00560 if (!_dbus_string_hex_decode (&contents, 0, &end, &decoded, 0))
00561 {
00562 _DBUS_SET_OOM (error);
00563 goto error;
00564 }
00565
00566 if (end == 0)
00567 {
00568 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00569 "UUID file '%s' contains invalid hex data",
00570 _dbus_string_get_const_data (filename));
00571 goto error;
00572 }
00573
00574 if (_dbus_string_get_length (&decoded) != DBUS_UUID_LENGTH_BYTES)
00575 {
00576 dbus_set_error (error, DBUS_ERROR_INVALID_FILE_CONTENT,
00577 "UUID file '%s' contains %d bytes of hex-encoded data instead of %d",
00578 _dbus_string_get_const_data (filename),
00579 _dbus_string_get_length (&decoded),
00580 DBUS_UUID_LENGTH_BYTES);
00581 goto error;
00582 }
00583
00584 _dbus_string_copy_to_buffer (&decoded, uuid->as_bytes, DBUS_UUID_LENGTH_BYTES);
00585
00586 _dbus_string_free (&decoded);
00587 _dbus_string_free (&contents);
00588
00589 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00590
00591 return TRUE;
00592
00593 error:
00594 _DBUS_ASSERT_ERROR_IS_SET (error);
00595 _dbus_string_free (&contents);
00596 _dbus_string_free (&decoded);
00597 return FALSE;
00598 }
00599
00600 static dbus_bool_t
00601 _dbus_create_uuid_file_exclusively (const DBusString *filename,
00602 DBusGUID *uuid,
00603 DBusError *error)
00604 {
00605 DBusString encoded;
00606
00607 _dbus_string_init (&encoded);
00608
00609 _dbus_generate_uuid (uuid);
00610
00611 if (!_dbus_uuid_encode (uuid, &encoded))
00612 {
00613 _DBUS_SET_OOM (error);
00614 goto error;
00615 }
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 if (!_dbus_create_file_exclusively (filename, error))
00626 goto error;
00627
00628 if (!_dbus_string_append_byte (&encoded, '\n'))
00629 {
00630 _DBUS_SET_OOM (error);
00631 goto error;
00632 }
00633
00634 if (!_dbus_string_save_to_file (&encoded, filename, error))
00635 goto error;
00636
00637 if (!_dbus_make_file_world_readable (filename, error))
00638 goto error;
00639
00640 _dbus_string_free (&encoded);
00641
00642 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00643 return TRUE;
00644
00645 error:
00646 _DBUS_ASSERT_ERROR_IS_SET (error);
00647 _dbus_string_free (&encoded);
00648 return FALSE;
00649 }
00650
00661 dbus_bool_t
00662 _dbus_read_uuid_file (const DBusString *filename,
00663 DBusGUID *uuid,
00664 dbus_bool_t create_if_not_found,
00665 DBusError *error)
00666 {
00667 DBusError read_error;
00668
00669 dbus_error_init (&read_error);
00670
00671 if (_dbus_read_uuid_file_without_creating (filename, uuid, &read_error))
00672 return TRUE;
00673
00674 if (!create_if_not_found)
00675 {
00676 dbus_move_error (&read_error, error);
00677 return FALSE;
00678 }
00679
00680
00681
00682
00683
00684 if (dbus_error_has_name (&read_error, DBUS_ERROR_INVALID_FILE_CONTENT))
00685 {
00686 dbus_move_error (&read_error, error);
00687 return FALSE;
00688 }
00689 else
00690 {
00691 dbus_error_free (&read_error);
00692 return _dbus_create_uuid_file_exclusively (filename, uuid, error);
00693 }
00694 }
00695
00696 _DBUS_DEFINE_GLOBAL_LOCK (machine_uuid);
00697 static int machine_uuid_initialized_generation = 0;
00698 static DBusGUID machine_uuid;
00699
00710 dbus_bool_t
00711 _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str)
00712 {
00713 dbus_bool_t ok;
00714
00715 _DBUS_LOCK (machine_uuid);
00716 if (machine_uuid_initialized_generation != _dbus_current_generation)
00717 {
00718 DBusError error;
00719 dbus_error_init (&error);
00720 if (!_dbus_read_local_machine_uuid (&machine_uuid, FALSE,
00721 &error))
00722 {
00723 #ifndef DBUS_BUILD_TESTS
00724
00725
00726
00727
00728 _dbus_warn_check_failed ("D-Bus library appears to be incorrectly set up; failed to read machine uuid: %s\n"
00729 "See the manual page for dbus-uuidgen to correct this issue.\n",
00730 error.message);
00731 #endif
00732
00733 dbus_error_free (&error);
00734
00735 _dbus_generate_uuid (&machine_uuid);
00736 }
00737 }
00738
00739 ok = _dbus_uuid_encode (&machine_uuid, uuid_str);
00740
00741 _DBUS_UNLOCK (machine_uuid);
00742
00743 return ok;
00744 }
00745
00746 #ifdef DBUS_BUILD_TESTS
00747
00753 const char *
00754 _dbus_header_field_to_string (int header_field)
00755 {
00756 switch (header_field)
00757 {
00758 case DBUS_HEADER_FIELD_INVALID:
00759 return "invalid";
00760 case DBUS_HEADER_FIELD_PATH:
00761 return "path";
00762 case DBUS_HEADER_FIELD_INTERFACE:
00763 return "interface";
00764 case DBUS_HEADER_FIELD_MEMBER:
00765 return "member";
00766 case DBUS_HEADER_FIELD_ERROR_NAME:
00767 return "error-name";
00768 case DBUS_HEADER_FIELD_REPLY_SERIAL:
00769 return "reply-serial";
00770 case DBUS_HEADER_FIELD_DESTINATION:
00771 return "destination";
00772 case DBUS_HEADER_FIELD_SENDER:
00773 return "sender";
00774 case DBUS_HEADER_FIELD_SIGNATURE:
00775 return "signature";
00776 default:
00777 return "unknown";
00778 }
00779 }
00780 #endif
00781
00782 #ifndef DBUS_DISABLE_CHECKS
00783
00784 const char _dbus_return_if_fail_warning_format[] =
00785 "arguments to %s() were incorrect, assertion \"%s\" failed in file %s line %d.\n"
00786 "This is normally a bug in some application using the D-Bus library.\n";
00787 #endif
00788
00789 #ifndef DBUS_DISABLE_ASSERT
00790
00802 void
00803 _dbus_real_assert (dbus_bool_t condition,
00804 const char *condition_text,
00805 const char *file,
00806 int line,
00807 const char *func)
00808 {
00809 if (_DBUS_UNLIKELY (!condition))
00810 {
00811 _dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d function %s\n",
00812 _dbus_getpid (), condition_text, file, line, func);
00813 _dbus_abort ();
00814 }
00815 }
00816
00827 void
00828 _dbus_real_assert_not_reached (const char *explanation,
00829 const char *file,
00830 int line)
00831 {
00832 _dbus_warn ("File \"%s\" line %d process %lu should not have been reached: %s\n",
00833 file, line, _dbus_getpid (), explanation);
00834 _dbus_abort ();
00835 }
00836 #endif
00837
00838 #ifdef DBUS_BUILD_TESTS
00839 static dbus_bool_t
00840 run_failing_each_malloc (int n_mallocs,
00841 const char *description,
00842 DBusTestMemoryFunction func,
00843 void *data)
00844 {
00845 n_mallocs += 10;
00846
00847 while (n_mallocs >= 0)
00848 {
00849 _dbus_set_fail_alloc_counter (n_mallocs);
00850
00851 _dbus_verbose ("\n===\n%s: (will fail malloc %d with %d failures)\n===\n",
00852 description, n_mallocs,
00853 _dbus_get_fail_alloc_failures ());
00854
00855 if (!(* func) (data))
00856 return FALSE;
00857
00858 n_mallocs -= 1;
00859 }
00860
00861 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
00862
00863 return TRUE;
00864 }
00865
00879 dbus_bool_t
00880 _dbus_test_oom_handling (const char *description,
00881 DBusTestMemoryFunction func,
00882 void *data)
00883 {
00884 int approx_mallocs;
00885 const char *setting;
00886 int max_failures_to_try;
00887 int i;
00888
00889
00890
00891 _dbus_set_fail_alloc_counter (_DBUS_INT_MAX);
00892
00893 _dbus_verbose ("Running once to count mallocs\n");
00894
00895 if (!(* func) (data))
00896 return FALSE;
00897
00898 approx_mallocs = _DBUS_INT_MAX - _dbus_get_fail_alloc_counter ();
00899
00900 _dbus_verbose ("\n=================\n%s: about %d mallocs total\n=================\n",
00901 description, approx_mallocs);
00902
00903 setting = _dbus_getenv ("DBUS_TEST_MALLOC_FAILURES");
00904 if (setting != NULL)
00905 {
00906 DBusString str;
00907 long v;
00908 _dbus_string_init_const (&str, setting);
00909 v = 4;
00910 if (!_dbus_string_parse_int (&str, 0, &v, NULL))
00911 _dbus_warn ("couldn't parse '%s' as integer\n", setting);
00912 max_failures_to_try = v;
00913 }
00914 else
00915 {
00916 max_failures_to_try = 4;
00917 }
00918
00919 i = setting ? max_failures_to_try - 1 : 1;
00920 while (i < max_failures_to_try)
00921 {
00922 _dbus_set_fail_alloc_failures (i);
00923 if (!run_failing_each_malloc (approx_mallocs, description, func, data))
00924 return FALSE;
00925 ++i;
00926 }
00927
00928 _dbus_verbose ("\n=================\n%s: all iterations passed\n=================\n",
00929 description);
00930
00931 return TRUE;
00932 }
00933 #endif
00934