D-Bus 1.6.12

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   /* Don't respect any environment variables if the current process is
00186    * setuid.  This is the equivalent of glibc's __secure_getenv().
00187    */
00188   if (_dbus_check_setuid ())
00189     return NULL;
00190   return getenv (varname);
00191 }
00192 
00198 dbus_bool_t
00199 _dbus_clearenv (void)
00200 {
00201   dbus_bool_t rc = TRUE;
00202 
00203 #ifdef HAVE_CLEARENV
00204   if (clearenv () != 0)
00205      rc = FALSE;
00206 #else
00207 
00208   if (environ != NULL)
00209     environ[0] = NULL;
00210 #endif
00211 
00212   return rc;
00213 }
00214 
00223 dbus_bool_t
00224 _dbus_split_paths_and_append (DBusString *dirs, 
00225                               const char *suffix, 
00226                               DBusList  **dir_list)
00227 {
00228    int start;
00229    int i;
00230    int len;
00231    char *cpath;
00232    DBusString file_suffix;
00233 
00234    start = 0;
00235    i = 0;
00236 
00237    _dbus_string_init_const (&file_suffix, suffix);
00238 
00239    len = _dbus_string_get_length (dirs);
00240 
00241    while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i))
00242      {
00243        DBusString path;
00244 
00245        if (!_dbus_string_init (&path))
00246           goto oom;
00247 
00248        if (!_dbus_string_copy_len (dirs,
00249                                    start,
00250                                    i - start,
00251                                    &path,
00252                                    0))
00253           {
00254             _dbus_string_free (&path);
00255             goto oom;
00256           }
00257 
00258         _dbus_string_chop_white (&path);
00259 
00260         /* check for an empty path */
00261         if (_dbus_string_get_length (&path) == 0)
00262           goto next;
00263 
00264         if (!_dbus_concat_dir_and_file (&path,
00265                                         &file_suffix))
00266           {
00267             _dbus_string_free (&path);
00268             goto oom;
00269           }
00270 
00271         if (!_dbus_string_copy_data(&path, &cpath))
00272           {
00273             _dbus_string_free (&path);
00274             goto oom;
00275           }
00276 
00277         if (!_dbus_list_append (dir_list, cpath))
00278           {
00279             _dbus_string_free (&path);              
00280             dbus_free (cpath);
00281             goto oom;
00282           }
00283 
00284        next:
00285         _dbus_string_free (&path);
00286         start = i + 1;
00287     } 
00288       
00289   if (start != len)
00290     { 
00291       DBusString path;
00292 
00293       if (!_dbus_string_init (&path))
00294         goto oom;
00295 
00296       if (!_dbus_string_copy_len (dirs,
00297                                   start,
00298                                   len - start,
00299                                   &path,
00300                                   0))
00301         {
00302           _dbus_string_free (&path);
00303           goto oom;
00304         }
00305 
00306       if (!_dbus_concat_dir_and_file (&path,
00307                                       &file_suffix))
00308         {
00309           _dbus_string_free (&path);
00310           goto oom;
00311         }
00312 
00313       if (!_dbus_string_copy_data(&path, &cpath))
00314         {
00315           _dbus_string_free (&path);
00316           goto oom;
00317         }
00318 
00319       if (!_dbus_list_append (dir_list, cpath))
00320         {
00321           _dbus_string_free (&path);              
00322           dbus_free (cpath);
00323           goto oom;
00324         }
00325 
00326       _dbus_string_free (&path); 
00327     }
00328 
00329   return TRUE;
00330 
00331  oom:
00332   _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); 
00333   _dbus_list_clear (dir_list);
00334   return FALSE;
00335 }
00336 
00351 dbus_bool_t
00352 _dbus_string_append_int (DBusString *str,
00353                          long        value)
00354 {
00355   /* this calculation is from comp.lang.c faq */
00356 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
00357   int orig_len;
00358   int i;
00359   char *buf;
00360   
00361   orig_len = _dbus_string_get_length (str);
00362 
00363   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
00364     return FALSE;
00365 
00366   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
00367 
00368   snprintf (buf, MAX_LONG_LEN, "%ld", value);
00369 
00370   i = 0;
00371   while (*buf)
00372     {
00373       ++buf;
00374       ++i;
00375     }
00376   
00377   _dbus_string_shorten (str, MAX_LONG_LEN - i);
00378   
00379   return TRUE;
00380 }
00381 
00389 dbus_bool_t
00390 _dbus_string_append_uint (DBusString    *str,
00391                           unsigned long  value)
00392 {
00393   /* this is wrong, but definitely on the high side. */
00394 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
00395   int orig_len;
00396   int i;
00397   char *buf;
00398   
00399   orig_len = _dbus_string_get_length (str);
00400 
00401   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
00402     return FALSE;
00403 
00404   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
00405 
00406   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
00407 
00408   i = 0;
00409   while (*buf)
00410     {
00411       ++buf;
00412       ++i;
00413     }
00414   
00415   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
00416   
00417   return TRUE;
00418 }
00419 
00432 dbus_bool_t
00433 _dbus_string_parse_int (const DBusString *str,
00434                         int               start,
00435                         long             *value_return,
00436                         int              *end_return)
00437 {
00438   long v;
00439   const char *p;
00440   char *end;
00441 
00442   p = _dbus_string_get_const_data_len (str, start,
00443                                        _dbus_string_get_length (str) - start);
00444 
00445   end = NULL;
00446   _dbus_set_errno_to_zero ();
00447   v = strtol (p, &end, 0);
00448   if (end == NULL || end == p || errno != 0)
00449     return FALSE;
00450 
00451   if (value_return)
00452     *value_return = v;
00453   if (end_return)
00454     *end_return = start + (end - p);
00455 
00456   return TRUE;
00457 }
00458 
00471 dbus_bool_t
00472 _dbus_string_parse_uint (const DBusString *str,
00473                          int               start,
00474                          unsigned long    *value_return,
00475                          int              *end_return)
00476 {
00477   unsigned long v;
00478   const char *p;
00479   char *end;
00480 
00481   p = _dbus_string_get_const_data_len (str, start,
00482                                        _dbus_string_get_length (str) - start);
00483 
00484   end = NULL;
00485   _dbus_set_errno_to_zero ();
00486   v = strtoul (p, &end, 0);
00487   if (end == NULL || end == p || errno != 0)
00488     return FALSE;
00489 
00490   if (value_return)
00491     *value_return = v;
00492   if (end_return)
00493     *end_return = start + (end - p);
00494 
00495   return TRUE;
00496 }
00497  /* DBusString group */
00499 
00505 void
00506 _dbus_generate_pseudorandom_bytes_buffer (char *buffer,
00507                                           int   n_bytes)
00508 {
00509   long tv_usec;
00510   int i;
00511   
00512   /* fall back to pseudorandom */
00513   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
00514                  n_bytes);
00515   
00516   _dbus_get_real_time (NULL, &tv_usec);
00517   srand (tv_usec);
00518   
00519   i = 0;
00520   while (i < n_bytes)
00521     {
00522       double r;
00523       unsigned int b;
00524           
00525       r = rand ();
00526       b = (r / (double) RAND_MAX) * 255.0;
00527 
00528       buffer[i] = b;
00529 
00530       ++i;
00531     }
00532 }
00533 
00540 void
00541 _dbus_generate_random_bytes_buffer (char *buffer,
00542                                     int   n_bytes)
00543 {
00544   DBusString str;
00545 
00546   if (!_dbus_string_init (&str))
00547     {
00548       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
00549       return;
00550     }
00551 
00552   if (!_dbus_generate_random_bytes (&str, n_bytes))
00553     {
00554       _dbus_string_free (&str);
00555       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
00556       return;
00557     }
00558 
00559   _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
00560 
00561   _dbus_string_free (&str);
00562 }
00563 
00572 dbus_bool_t
00573 _dbus_generate_random_ascii (DBusString *str,
00574                              int         n_bytes)
00575 {
00576   static const char letters[] =
00577     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
00578   int i;
00579   int len;
00580   
00581   if (!_dbus_generate_random_bytes (str, n_bytes))
00582     return FALSE;
00583   
00584   len = _dbus_string_get_length (str);
00585   i = len - n_bytes;
00586   while (i < len)
00587     {
00588       _dbus_string_set_byte (str, i,
00589                              letters[_dbus_string_get_byte (str, i) %
00590                                      (sizeof (letters) - 1)]);
00591 
00592       ++i;
00593     }
00594 
00595   _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
00596                                              n_bytes));
00597 
00598   return TRUE;
00599 }
00600 
00611 const char*
00612 _dbus_error_from_errno (int error_number)
00613 {
00614   switch (error_number)
00615     {
00616     case 0:
00617       return DBUS_ERROR_FAILED;
00618       
00619 #ifdef EPROTONOSUPPORT
00620     case EPROTONOSUPPORT:
00621       return DBUS_ERROR_NOT_SUPPORTED;
00622 #elif defined(WSAEPROTONOSUPPORT)
00623     case WSAEPROTONOSUPPORT:
00624       return DBUS_ERROR_NOT_SUPPORTED;
00625 #endif
00626 #ifdef EAFNOSUPPORT
00627     case EAFNOSUPPORT:
00628       return DBUS_ERROR_NOT_SUPPORTED;
00629 #elif defined(WSAEAFNOSUPPORT)
00630     case WSAEAFNOSUPPORT:
00631       return DBUS_ERROR_NOT_SUPPORTED;
00632 #endif
00633 #ifdef ENFILE
00634     case ENFILE:
00635       return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
00636 #endif
00637 #ifdef EMFILE
00638     case EMFILE:
00639       return DBUS_ERROR_LIMITS_EXCEEDED;
00640 #endif
00641 #ifdef EACCES
00642     case EACCES:
00643       return DBUS_ERROR_ACCESS_DENIED;
00644 #endif
00645 #ifdef EPERM
00646     case EPERM:
00647       return DBUS_ERROR_ACCESS_DENIED;
00648 #endif
00649 #ifdef ENOBUFS
00650     case ENOBUFS:
00651       return DBUS_ERROR_NO_MEMORY;
00652 #endif
00653 #ifdef ENOMEM
00654     case ENOMEM:
00655       return DBUS_ERROR_NO_MEMORY;
00656 #endif
00657 #ifdef ECONNREFUSED
00658     case ECONNREFUSED:
00659       return DBUS_ERROR_NO_SERVER;
00660 #elif defined(WSAECONNREFUSED)
00661     case WSAECONNREFUSED:
00662       return DBUS_ERROR_NO_SERVER;
00663 #endif
00664 #ifdef ETIMEDOUT
00665     case ETIMEDOUT:
00666       return DBUS_ERROR_TIMEOUT;
00667 #elif defined(WSAETIMEDOUT)
00668     case WSAETIMEDOUT:
00669       return DBUS_ERROR_TIMEOUT;
00670 #endif
00671 #ifdef ENETUNREACH
00672     case ENETUNREACH:
00673       return DBUS_ERROR_NO_NETWORK;
00674 #elif defined(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 #elif defined(WSAEADDRINUSE)
00682     case WSAEADDRINUSE:
00683       return DBUS_ERROR_ADDRESS_IN_USE;
00684 #endif
00685 #ifdef EEXIST
00686     case EEXIST:
00687       return DBUS_ERROR_FILE_EXISTS;
00688 #endif
00689 #ifdef ENOENT
00690     case ENOENT:
00691       return DBUS_ERROR_FILE_NOT_FOUND;
00692 #endif
00693     }
00694 
00695   return DBUS_ERROR_FAILED;
00696 }
00697 
00703 const char*
00704 _dbus_error_from_system_errno (void)
00705 {
00706   return _dbus_error_from_errno (errno);
00707 }
00708 
00712 void
00713 _dbus_set_errno_to_zero (void)
00714 {
00715 #ifdef DBUS_WINCE
00716   SetLastError (0);
00717 #else
00718   errno = 0;
00719 #endif
00720 }
00721 
00726 dbus_bool_t
00727 _dbus_get_is_errno_nonzero (void)
00728 {
00729   return errno != 0;
00730 }
00731 
00736 dbus_bool_t
00737 _dbus_get_is_errno_enomem (void)
00738 {
00739   return errno == ENOMEM;
00740 }
00741 
00746 dbus_bool_t
00747 _dbus_get_is_errno_eintr (void)
00748 {
00749   return errno == EINTR;
00750 }
00751 
00756 dbus_bool_t
00757 _dbus_get_is_errno_epipe (void)
00758 {
00759   return errno == EPIPE;
00760 }
00761 
00766 const char*
00767 _dbus_strerror_from_errno (void)
00768 {
00769   return _dbus_strerror (errno);
00770 }
00771 
00774 /* tests in dbus-sysdeps-util.c */