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