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