D-Bus  1.5.10
dbus-sysdeps.c
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-sysdeps.c Wrappers around system/libc features shared between UNIX and Windows (internal to D-Bus implementation)
00003  * 
00004  * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
00005  * Copyright (C) 2003 CodeFactory AB
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 #include "dbus-internals.h"
00027 #include "dbus-sysdeps.h"
00028 #include "dbus-threads.h"
00029 #include "dbus-protocol.h"
00030 #include "dbus-string.h"
00031 #include "dbus-list.h"
00032 
00033 /* NOTE: If you include any unix/windows-specific headers here, you are probably doing something
00034  * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c.
00035  *
00036  * These are the standard ANSI C headers...
00037  */
00038 #if HAVE_LOCALE_H
00039 #include <locale.h>
00040 #endif
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <stdio.h>
00044 
00045 #ifdef HAVE_ERRNO_H
00046 #include <errno.h>
00047 #endif
00048 
00049 _DBUS_DEFINE_GLOBAL_LOCK (win_fds);
00050 _DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache);
00051 _DBUS_DEFINE_GLOBAL_LOCK (system_users);
00052 
00053 #ifdef DBUS_WIN
00054   #include <stdlib.h>
00055 #elif (defined __APPLE__)
00056 # include <crt_externs.h>
00057 # define environ (*_NSGetEnviron())
00058 #else
00059 extern char **environ;
00060 #endif
00061 
00079 void
00080 _dbus_abort (void)
00081 {
00082   const char *s;
00083   
00084   _dbus_print_backtrace ();
00085   
00086   s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT");
00087   if (s && *s)
00088     {
00089       /* don't use _dbus_warn here since it can _dbus_abort() */
00090       fprintf (stderr, "  Process %lu sleeping for gdb attach\n", _dbus_pid_for_log ());
00091       _dbus_sleep_milliseconds (1000 * 180);
00092     }
00093   
00094   abort ();
00095   _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */
00096 }
00097 
00111 dbus_bool_t
00112 _dbus_setenv (const char *varname,
00113               const char *value)
00114 {
00115   _dbus_assert (varname != NULL);
00116   
00117   if (value == NULL)
00118     {
00119 #ifdef HAVE_UNSETENV
00120       unsetenv (varname);
00121       return TRUE;
00122 #else
00123       char *putenv_value;
00124       size_t len;
00125 
00126       len = strlen (varname);
00127 
00128       /* Use system malloc to avoid memleaks that dbus_malloc
00129        * will get upset about.
00130        */
00131       
00132       putenv_value = malloc (len + 2);
00133       if (putenv_value == NULL)
00134         return FALSE;
00135 
00136       strcpy (putenv_value, varname);
00137 #if defined(DBUS_WIN)
00138       strcat (putenv_value, "=");
00139 #endif
00140       
00141       return (putenv (putenv_value) == 0);
00142 #endif
00143     }
00144   else
00145     {
00146 #ifdef HAVE_SETENV
00147       return (setenv (varname, value, TRUE) == 0);
00148 #else
00149       char *putenv_value;
00150       size_t len;
00151       size_t varname_len;
00152       size_t value_len;
00153 
00154       varname_len = strlen (varname);
00155       value_len = strlen (value);
00156       
00157       len = varname_len + value_len + 1 /* '=' */ ;
00158 
00159       /* Use system malloc to avoid memleaks that dbus_malloc
00160        * will get upset about.
00161        */
00162       
00163       putenv_value = malloc (len + 1);
00164       if (putenv_value == NULL)
00165         return FALSE;
00166 
00167       strcpy (putenv_value, varname);
00168       strcpy (putenv_value + varname_len, "=");
00169       strcpy (putenv_value + varname_len + 1, value);
00170       
00171       return (putenv (putenv_value) == 0);
00172 #endif
00173     }
00174 }
00175 
00182 const char*
00183 _dbus_getenv (const char *varname)
00184 {  
00185   return getenv (varname);
00186 }
00187 
00193 dbus_bool_t
00194 _dbus_clearenv (void)
00195 {
00196   dbus_bool_t rc = TRUE;
00197 
00198 #ifdef HAVE_CLEARENV
00199   if (clearenv () != 0)
00200      rc = FALSE;
00201 #else
00202 
00203   if (environ != NULL)
00204     environ[0] = NULL;
00205 #endif
00206 
00207   return rc;
00208 }
00209 
00218 dbus_bool_t
00219 _dbus_split_paths_and_append (DBusString *dirs, 
00220                               const char *suffix, 
00221                               DBusList  **dir_list)
00222 {
00223    int start;
00224    int i;
00225    int len;
00226    char *cpath;
00227    DBusString file_suffix;
00228 
00229    start = 0;
00230    i = 0;
00231 
00232    _dbus_string_init_const (&file_suffix, suffix);
00233 
00234    len = _dbus_string_get_length (dirs);
00235 
00236    while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i))
00237      {
00238        DBusString path;
00239 
00240        if (!_dbus_string_init (&path))
00241           goto oom;
00242 
00243        if (!_dbus_string_copy_len (dirs,
00244                                    start,
00245                                    i - start,
00246                                    &path,
00247                                    0))
00248           {
00249             _dbus_string_free (&path);
00250             goto oom;
00251           }
00252 
00253         _dbus_string_chop_white (&path);
00254 
00255         /* check for an empty path */
00256         if (_dbus_string_get_length (&path) == 0)
00257           goto next;
00258 
00259         if (!_dbus_concat_dir_and_file (&path,
00260                                         &file_suffix))
00261           {
00262             _dbus_string_free (&path);
00263             goto oom;
00264           }
00265 
00266         if (!_dbus_string_copy_data(&path, &cpath))
00267           {
00268             _dbus_string_free (&path);
00269             goto oom;
00270           }
00271 
00272         if (!_dbus_list_append (dir_list, cpath))
00273           {
00274             _dbus_string_free (&path);              
00275             dbus_free (cpath);
00276             goto oom;
00277           }
00278 
00279        next:
00280         _dbus_string_free (&path);
00281         start = i + 1;
00282     } 
00283       
00284   if (start != len)
00285     { 
00286       DBusString path;
00287 
00288       if (!_dbus_string_init (&path))
00289         goto oom;
00290 
00291       if (!_dbus_string_copy_len (dirs,
00292                                   start,
00293                                   len - start,
00294                                   &path,
00295                                   0))
00296         {
00297           _dbus_string_free (&path);
00298           goto oom;
00299         }
00300 
00301       if (!_dbus_concat_dir_and_file (&path,
00302                                       &file_suffix))
00303         {
00304           _dbus_string_free (&path);
00305           goto oom;
00306         }
00307 
00308       if (!_dbus_string_copy_data(&path, &cpath))
00309         {
00310           _dbus_string_free (&path);
00311           goto oom;
00312         }
00313 
00314       if (!_dbus_list_append (dir_list, cpath))
00315         {
00316           _dbus_string_free (&path);              
00317           dbus_free (cpath);
00318           goto oom;
00319         }
00320 
00321       _dbus_string_free (&path); 
00322     }
00323 
00324   return TRUE;
00325 
00326  oom:
00327   _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); 
00328   _dbus_list_clear (dir_list);
00329   return FALSE;
00330 }
00331 
00346 dbus_bool_t
00347 _dbus_string_append_int (DBusString *str,
00348                          long        value)
00349 {
00350   /* this calculation is from comp.lang.c faq */
00351 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
00352   int orig_len;
00353   int i;
00354   char *buf;
00355   
00356   orig_len = _dbus_string_get_length (str);
00357 
00358   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
00359     return FALSE;
00360 
00361   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
00362 
00363   snprintf (buf, MAX_LONG_LEN, "%ld", value);
00364 
00365   i = 0;
00366   while (*buf)
00367     {
00368       ++buf;
00369       ++i;
00370     }
00371   
00372   _dbus_string_shorten (str, MAX_LONG_LEN - i);
00373   
00374   return TRUE;
00375 }
00376 
00384 dbus_bool_t
00385 _dbus_string_append_uint (DBusString    *str,
00386                           unsigned long  value)
00387 {
00388   /* this is wrong, but definitely on the high side. */
00389 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
00390   int orig_len;
00391   int i;
00392   char *buf;
00393   
00394   orig_len = _dbus_string_get_length (str);
00395 
00396   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
00397     return FALSE;
00398 
00399   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
00400 
00401   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
00402 
00403   i = 0;
00404   while (*buf)
00405     {
00406       ++buf;
00407       ++i;
00408     }
00409   
00410   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
00411   
00412   return TRUE;
00413 }
00414 
00427 dbus_bool_t
00428 _dbus_string_parse_int (const DBusString *str,
00429                         int               start,
00430                         long             *value_return,
00431                         int              *end_return)
00432 {
00433   long v;
00434   const char *p;
00435   char *end;
00436 
00437   p = _dbus_string_get_const_data_len (str, start,
00438                                        _dbus_string_get_length (str) - start);
00439 
00440   end = NULL;
00441   _dbus_set_errno_to_zero ();
00442   v = strtol (p, &end, 0);
00443   if (end == NULL || end == p || errno != 0)
00444     return FALSE;
00445 
00446   if (value_return)
00447     *value_return = v;
00448   if (end_return)
00449     *end_return = start + (end - p);
00450 
00451   return TRUE;
00452 }
00453 
00466 dbus_bool_t
00467 _dbus_string_parse_uint (const DBusString *str,
00468                          int               start,
00469                          unsigned long    *value_return,
00470                          int              *end_return)
00471 {
00472   unsigned long v;
00473   const char *p;
00474   char *end;
00475 
00476   p = _dbus_string_get_const_data_len (str, start,
00477                                        _dbus_string_get_length (str) - start);
00478 
00479   end = NULL;
00480   _dbus_set_errno_to_zero ();
00481   v = strtoul (p, &end, 0);
00482   if (end == NULL || end == p || errno != 0)
00483     return FALSE;
00484 
00485   if (value_return)
00486     *value_return = v;
00487   if (end_return)
00488     *end_return = start + (end - p);
00489 
00490   return TRUE;
00491 }
00492  /* DBusString group */
00494 
00500 void
00501 _dbus_generate_pseudorandom_bytes_buffer (char *buffer,
00502                                           int   n_bytes)
00503 {
00504   long tv_usec;
00505   int i;
00506   
00507   /* fall back to pseudorandom */
00508   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
00509                  n_bytes);
00510   
00511   _dbus_get_current_time (NULL, &tv_usec);
00512   srand (tv_usec);
00513   
00514   i = 0;
00515   while (i < n_bytes)
00516     {
00517       double r;
00518       unsigned int b;
00519           
00520       r = rand ();
00521       b = (r / (double) RAND_MAX) * 255.0;
00522 
00523       buffer[i] = b;
00524 
00525       ++i;
00526     }
00527 }
00528 
00535 void
00536 _dbus_generate_random_bytes_buffer (char *buffer,
00537                                     int   n_bytes)
00538 {
00539   DBusString str;
00540 
00541   if (!_dbus_string_init (&str))
00542     {
00543       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
00544       return;
00545     }
00546 
00547   if (!_dbus_generate_random_bytes (&str, n_bytes))
00548     {
00549       _dbus_string_free (&str);
00550       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
00551       return;
00552     }
00553 
00554   _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
00555 
00556   _dbus_string_free (&str);
00557 }
00558 
00567 dbus_bool_t
00568 _dbus_generate_random_ascii (DBusString *str,
00569                              int         n_bytes)
00570 {
00571   static const char letters[] =
00572     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
00573   int i;
00574   int len;
00575   
00576   if (!_dbus_generate_random_bytes (str, n_bytes))
00577     return FALSE;
00578   
00579   len = _dbus_string_get_length (str);
00580   i = len - n_bytes;
00581   while (i < len)
00582     {
00583       _dbus_string_set_byte (str, i,
00584                              letters[_dbus_string_get_byte (str, i) %
00585                                      (sizeof (letters) - 1)]);
00586 
00587       ++i;
00588     }
00589 
00590   _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
00591                                              n_bytes));
00592 
00593   return TRUE;
00594 }
00595 
00606 const char*
00607 _dbus_error_from_errno (int error_number)
00608 {
00609   switch (error_number)
00610     {
00611     case 0:
00612       return DBUS_ERROR_FAILED;
00613       
00614 #ifdef EPROTONOSUPPORT
00615     case EPROTONOSUPPORT:
00616       return DBUS_ERROR_NOT_SUPPORTED;
00617 #endif
00618 #ifdef WSAEPROTONOSUPPORT
00619     case WSAEPROTONOSUPPORT:
00620       return DBUS_ERROR_NOT_SUPPORTED;
00621 #endif
00622 #ifdef EAFNOSUPPORT
00623     case EAFNOSUPPORT:
00624       return DBUS_ERROR_NOT_SUPPORTED;
00625 #endif
00626 #ifdef WSAEAFNOSUPPORT
00627     case WSAEAFNOSUPPORT:
00628       return DBUS_ERROR_NOT_SUPPORTED;
00629 #endif
00630 #ifdef ENFILE
00631     case ENFILE:
00632       return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
00633 #endif
00634 #ifdef EMFILE
00635     case EMFILE:
00636       return DBUS_ERROR_LIMITS_EXCEEDED;
00637 #endif
00638 #ifdef EACCES
00639     case EACCES:
00640       return DBUS_ERROR_ACCESS_DENIED;
00641 #endif
00642 #ifdef EPERM
00643     case EPERM:
00644       return DBUS_ERROR_ACCESS_DENIED;
00645 #endif
00646 #ifdef ENOBUFS
00647     case ENOBUFS:
00648       return DBUS_ERROR_NO_MEMORY;
00649 #endif
00650 #ifdef ENOMEM
00651     case ENOMEM:
00652       return DBUS_ERROR_NO_MEMORY;
00653 #endif
00654 #ifdef ECONNREFUSED
00655     case ECONNREFUSED:
00656       return DBUS_ERROR_NO_SERVER;
00657 #endif
00658 #ifdef WSAECONNREFUSED
00659     case WSAECONNREFUSED:
00660       return DBUS_ERROR_NO_SERVER;
00661 #endif
00662 #ifdef ETIMEDOUT
00663     case ETIMEDOUT:
00664       return DBUS_ERROR_TIMEOUT;
00665 #endif
00666 #ifdef WSAETIMEDOUT
00667     case WSAETIMEDOUT:
00668       return DBUS_ERROR_TIMEOUT;
00669 #endif
00670 #ifdef ENETUNREACH
00671     case ENETUNREACH:
00672       return DBUS_ERROR_NO_NETWORK;
00673 #endif
00674 #ifdef WSAENETUNREACH
00675     case WSAENETUNREACH:
00676       return DBUS_ERROR_NO_NETWORK;
00677 #endif
00678 #ifdef EADDRINUSE
00679     case EADDRINUSE:
00680       return DBUS_ERROR_ADDRESS_IN_USE;
00681 #endif
00682 #ifdef WSAEADDRINUSE
00683     case WSAEADDRINUSE:
00684       return DBUS_ERROR_ADDRESS_IN_USE;
00685 #endif
00686 #ifdef EEXIST
00687     case EEXIST:
00688       return DBUS_ERROR_FILE_EXISTS;
00689 #endif
00690 #ifdef ENOENT
00691     case ENOENT:
00692       return DBUS_ERROR_FILE_NOT_FOUND;
00693 #endif
00694     }
00695 
00696   return DBUS_ERROR_FAILED;
00697 }
00698 
00704 const char*
00705 _dbus_error_from_system_errno (void)
00706 {
00707   return _dbus_error_from_errno (errno);
00708 }
00709 
00713 void
00714 _dbus_set_errno_to_zero (void)
00715 {
00716 #ifdef DBUS_WINCE
00717   SetLastError (0);
00718 #else
00719   errno = 0;
00720 #endif
00721 }
00722 
00727 dbus_bool_t
00728 _dbus_get_is_errno_nonzero (void)
00729 {
00730   return errno != 0;
00731 }
00732 
00737 dbus_bool_t
00738 _dbus_get_is_errno_enomem (void)
00739 {
00740   return errno == ENOMEM;
00741 }
00742 
00747 dbus_bool_t
00748 _dbus_get_is_errno_eintr (void)
00749 {
00750   return errno == EINTR;
00751 }
00752 
00757 dbus_bool_t
00758 _dbus_get_is_errno_epipe (void)
00759 {
00760   return errno == EPIPE;
00761 }
00762 
00767 const char*
00768 _dbus_strerror_from_errno (void)
00769 {
00770   return _dbus_strerror (errno);
00771 }
00772 
00775 /* tests in dbus-sysdeps-util.c */