D-Bus 1.4.1
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-internals.c random utility stuff (internal to D-Bus implementation) 00003 * 00004 * Copyright (C) 2002, 2003 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 _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 /* things are written a bit oddly here so that 00411 * in the non-verbose case we just have the one 00412 * conditional and return immediately. 00413 */ 00414 if (!_dbus_is_verbose_real()) 00415 return; 00416 00417 #ifndef DBUS_USE_OUTPUT_DEBUG_STRING 00418 /* Print out pid before the line */ 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 /* Only print pid again if the next line is a new line */ 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 /* DBUS_ENABLE_VERBOSE_MODE */ 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 /* If the file exists and contains junk, we want to keep that error 00770 * message instead of overwriting it with a "file exists" error 00771 * message when we try to write 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 /* For the test suite, we may not be installed so just continue silently 00814 * here. But in a production build, we want to be nice and loud about 00815 * this. 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 /* DBUS_BUILD_TESTS */ 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 /* DBUS_DISABLE_ASSERT */ 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; /* fudge factor to ensure reallocs etc. are covered */ 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 /* Run once to see about how many mallocs are involved */ 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 /* DBUS_BUILD_TESTS */ 01023