dbus-sysdeps.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include "dbus-internals.h"
00026 #include "dbus-sysdeps.h"
00027 #include "dbus-threads.h"
00028 #include "dbus-protocol.h"
00029 #include "dbus-string.h"
00030 
00031 /* NOTE: If you include any unix/windows-specific headers here, you are probably doing something
00032  * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c.
00033  *
00034  * These are the standard ANSI C headers...
00035  */
00036 #include <locale.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <stdio.h>
00040 
00041 /* This is UNIX-specific (on windows it's just in stdlib.h I believe)
00042  * but OK since the same stuff does exist on Windows in stdlib.h
00043  * and covered by a configure check.
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 
00069 void
00070 _dbus_abort (void)
00071 {
00072   const char *s;
00073   
00074   _dbus_print_backtrace ();
00075   
00076   s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT");
00077   if (s && *s)
00078     {
00079       /* don't use _dbus_warn here since it can _dbus_abort() */
00080       fprintf (stderr, "  Process %lu sleeping for gdb attach\n", (unsigned long) _dbus_getpid());
00081       _dbus_sleep_milliseconds (1000 * 180);
00082     }
00083   
00084   abort ();
00085   _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */
00086 }
00087 
00101 dbus_bool_t
00102 _dbus_setenv (const char *varname,
00103               const char *value)
00104 {
00105   _dbus_assert (varname != NULL);
00106   
00107   if (value == NULL)
00108     {
00109 #ifdef HAVE_UNSETENV
00110       unsetenv (varname);
00111       return TRUE;
00112 #else
00113       char *putenv_value;
00114       size_t len;
00115 
00116       len = strlen (varname);
00117 
00118       /* Use system malloc to avoid memleaks that dbus_malloc
00119        * will get upset about.
00120        */
00121       
00122       putenv_value = malloc (len + 1);
00123       if (putenv_value == NULL)
00124         return FALSE;
00125 
00126       strcpy (putenv_value, varname);
00127       
00128       return (putenv (putenv_value) == 0);
00129 #endif
00130     }
00131   else
00132     {
00133 #ifdef HAVE_SETENV
00134       return (setenv (varname, value, TRUE) == 0);
00135 #else
00136       char *putenv_value;
00137       size_t len;
00138       size_t varname_len;
00139       size_t value_len;
00140 
00141       varname_len = strlen (varname);
00142       value_len = strlen (value);
00143       
00144       len = varname_len + value_len + 1 /* '=' */ ;
00145 
00146       /* Use system malloc to avoid memleaks that dbus_malloc
00147        * will get upset about.
00148        */
00149       
00150       putenv_value = malloc (len + 1);
00151       if (putenv_value == NULL)
00152         return FALSE;
00153 
00154       strcpy (putenv_value, varname);
00155       strcpy (putenv_value + varname_len, "=");
00156       strcpy (putenv_value + varname_len + 1, value);
00157       
00158       return (putenv (putenv_value) == 0);
00159 #endif
00160     }
00161 }
00162 
00169 const char*
00170 _dbus_getenv (const char *varname)
00171 {  
00172   return getenv (varname);
00173 }
00174 
00189 dbus_bool_t
00190 _dbus_string_append_int (DBusString *str,
00191                          long        value)
00192 {
00193   /* this calculation is from comp.lang.c faq */
00194 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
00195   int orig_len;
00196   int i;
00197   char *buf;
00198   
00199   orig_len = _dbus_string_get_length (str);
00200 
00201   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
00202     return FALSE;
00203 
00204   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
00205 
00206   snprintf (buf, MAX_LONG_LEN, "%ld", value);
00207 
00208   i = 0;
00209   while (*buf)
00210     {
00211       ++buf;
00212       ++i;
00213     }
00214   
00215   _dbus_string_shorten (str, MAX_LONG_LEN - i);
00216   
00217   return TRUE;
00218 }
00219 
00227 dbus_bool_t
00228 _dbus_string_append_uint (DBusString    *str,
00229                           unsigned long  value)
00230 {
00231   /* this is wrong, but definitely on the high side. */
00232 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
00233   int orig_len;
00234   int i;
00235   char *buf;
00236   
00237   orig_len = _dbus_string_get_length (str);
00238 
00239   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
00240     return FALSE;
00241 
00242   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
00243 
00244   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
00245 
00246   i = 0;
00247   while (*buf)
00248     {
00249       ++buf;
00250       ++i;
00251     }
00252   
00253   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
00254   
00255   return TRUE;
00256 }
00257 
00258 #ifdef DBUS_BUILD_TESTS
00259 
00266 dbus_bool_t
00267 _dbus_string_append_double (DBusString *str,
00268                             double      value)
00269 {
00270 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
00271   int orig_len;
00272   char *buf;
00273   int i;
00274   
00275   orig_len = _dbus_string_get_length (str);
00276 
00277   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
00278     return FALSE;
00279 
00280   buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
00281 
00282   snprintf (buf, MAX_LONG_LEN, "%g", value);
00283 
00284   i = 0;
00285   while (*buf)
00286     {
00287       ++buf;
00288       ++i;
00289     }
00290   
00291   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
00292   
00293   return TRUE;
00294 }
00295 #endif /* DBUS_BUILD_TESTS */
00296 
00309 dbus_bool_t
00310 _dbus_string_parse_int (const DBusString *str,
00311                         int               start,
00312                         long             *value_return,
00313                         int              *end_return)
00314 {
00315   long v;
00316   const char *p;
00317   char *end;
00318 
00319   p = _dbus_string_get_const_data_len (str, start,
00320                                        _dbus_string_get_length (str) - start);
00321 
00322   end = NULL;
00323   errno = 0;
00324   v = strtol (p, &end, 0);
00325   if (end == NULL || end == p || errno != 0)
00326     return FALSE;
00327 
00328   if (value_return)
00329     *value_return = v;
00330   if (end_return)
00331     *end_return = start + (end - p);
00332 
00333   return TRUE;
00334 }
00335 
00348 dbus_bool_t
00349 _dbus_string_parse_uint (const DBusString *str,
00350                          int               start,
00351                          unsigned long    *value_return,
00352                          int              *end_return)
00353 {
00354   unsigned long v;
00355   const char *p;
00356   char *end;
00357 
00358   p = _dbus_string_get_const_data_len (str, start,
00359                                        _dbus_string_get_length (str) - start);
00360 
00361   end = NULL;
00362   errno = 0;
00363   v = strtoul (p, &end, 0);
00364   if (end == NULL || end == p || errno != 0)
00365     return FALSE;
00366 
00367   if (value_return)
00368     *value_return = v;
00369   if (end_return)
00370     *end_return = start + (end - p);
00371 
00372   return TRUE;
00373 }
00374 
00375 #ifdef DBUS_BUILD_TESTS
00376 static dbus_bool_t
00377 ascii_isspace (char c)
00378 {
00379   return (c == ' ' ||
00380           c == '\f' ||
00381           c == '\n' ||
00382           c == '\r' ||
00383           c == '\t' ||
00384           c == '\v');
00385 }
00386 #endif /* DBUS_BUILD_TESTS */
00387 
00388 #ifdef DBUS_BUILD_TESTS
00389 static dbus_bool_t
00390 ascii_isdigit (char c)
00391 {
00392   return c >= '0' && c <= '9';
00393 }
00394 #endif /* DBUS_BUILD_TESTS */
00395 
00396 #ifdef DBUS_BUILD_TESTS
00397 static dbus_bool_t
00398 ascii_isxdigit (char c)
00399 {
00400   return (ascii_isdigit (c) ||
00401           (c >= 'a' && c <= 'f') ||
00402           (c >= 'A' && c <= 'F'));
00403 }
00404 #endif /* DBUS_BUILD_TESTS */
00405 
00406 #ifdef DBUS_BUILD_TESTS
00407 /* Calls strtod in a locale-independent fashion, by looking at
00408  * the locale data and patching the decimal comma to a point.
00409  *
00410  * Relicensed from glib.
00411  */
00412 static double
00413 ascii_strtod (const char *nptr,
00414               char      **endptr)
00415 {
00416   char *fail_pos;
00417   double val;
00418   struct lconv *locale_data;
00419   const char *decimal_point;
00420   int decimal_point_len;
00421   const char *p, *decimal_point_pos;
00422   const char *end = NULL; /* Silence gcc */
00423 
00424   fail_pos = NULL;
00425 
00426   locale_data = localeconv ();
00427   decimal_point = locale_data->decimal_point;
00428   decimal_point_len = strlen (decimal_point);
00429 
00430   _dbus_assert (decimal_point_len != 0);
00431   
00432   decimal_point_pos = NULL;
00433   if (decimal_point[0] != '.' ||
00434       decimal_point[1] != 0)
00435     {
00436       p = nptr;
00437       /* Skip leading space */
00438       while (ascii_isspace (*p))
00439         p++;
00440       
00441       /* Skip leading optional sign */
00442       if (*p == '+' || *p == '-')
00443         p++;
00444       
00445       if (p[0] == '0' &&
00446           (p[1] == 'x' || p[1] == 'X'))
00447         {
00448           p += 2;
00449           /* HEX - find the (optional) decimal point */
00450           
00451           while (ascii_isxdigit (*p))
00452             p++;
00453           
00454           if (*p == '.')
00455             {
00456               decimal_point_pos = p++;
00457               
00458               while (ascii_isxdigit (*p))
00459                 p++;
00460               
00461               if (*p == 'p' || *p == 'P')
00462                 p++;
00463               if (*p == '+' || *p == '-')
00464                 p++;
00465               while (ascii_isdigit (*p))
00466                 p++;
00467               end = p;
00468             }
00469         }
00470       else
00471         {
00472           while (ascii_isdigit (*p))
00473             p++;
00474           
00475           if (*p == '.')
00476             {
00477               decimal_point_pos = p++;
00478               
00479               while (ascii_isdigit (*p))
00480                 p++;
00481               
00482               if (*p == 'e' || *p == 'E')
00483                 p++;
00484               if (*p == '+' || *p == '-')
00485                 p++;
00486               while (ascii_isdigit (*p))
00487                 p++;
00488               end = p;
00489             }
00490         }
00491       /* For the other cases, we need not convert the decimal point */
00492     }
00493 
00494   /* Set errno to zero, so that we can distinguish zero results
00495      and underflows */
00496   errno = 0;
00497   
00498   if (decimal_point_pos)
00499     {
00500       char *copy, *c;
00501 
00502       /* We need to convert the '.' to the locale specific decimal point */
00503       copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
00504       
00505       c = copy;
00506       memcpy (c, nptr, decimal_point_pos - nptr);
00507       c += decimal_point_pos - nptr;
00508       memcpy (c, decimal_point, decimal_point_len);
00509       c += decimal_point_len;
00510       memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
00511       c += end - (decimal_point_pos + 1);
00512       *c = 0;
00513 
00514       val = strtod (copy, &fail_pos);
00515 
00516       if (fail_pos)
00517         {
00518           if (fail_pos > decimal_point_pos)
00519             fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
00520           else
00521             fail_pos = (char *)nptr + (fail_pos - copy);
00522         }
00523       
00524       dbus_free (copy);
00525           
00526     }
00527   else
00528     val = strtod (nptr, &fail_pos);
00529 
00530   if (endptr)
00531     *endptr = fail_pos;
00532   
00533   return val;
00534 }
00535 #endif /* DBUS_BUILD_TESTS */
00536 
00537 #ifdef DBUS_BUILD_TESTS
00538 
00550 dbus_bool_t
00551 _dbus_string_parse_double (const DBusString *str,
00552                            int               start,
00553                            double           *value_return,
00554                            int              *end_return)
00555 {
00556   double v;
00557   const char *p;
00558   char *end;
00559 
00560   p = _dbus_string_get_const_data_len (str, start,
00561                                        _dbus_string_get_length (str) - start);
00562 
00563   end = NULL;
00564   errno = 0;
00565   v = ascii_strtod (p, &end);
00566   if (end == NULL || end == p || errno != 0)
00567     return FALSE;
00568 
00569   if (value_return)
00570     *value_return = v;
00571   if (end_return)
00572     *end_return = start + (end - p);
00573 
00574   return TRUE;
00575 }
00576 #endif /* DBUS_BUILD_TESTS */
00577  /* DBusString group */
00579 
00590 void
00591 _dbus_user_info_free (DBusUserInfo *info)
00592 {
00593   dbus_free (info->group_ids);
00594   dbus_free (info->username);
00595   dbus_free (info->homedir);
00596 }
00597 
00603 void
00604 _dbus_group_info_free (DBusGroupInfo    *info)
00605 {
00606   dbus_free (info->groupname);
00607 }
00608 
00615 void
00616 _dbus_credentials_clear (DBusCredentials *credentials)
00617 {
00618   credentials->pid = DBUS_PID_UNSET;
00619   credentials->uid = DBUS_UID_UNSET;
00620   credentials->gid = DBUS_GID_UNSET;
00621 }
00622 
00631 dbus_bool_t
00632 _dbus_credentials_match (const DBusCredentials *expected_credentials,
00633                          const DBusCredentials *provided_credentials)
00634 {
00635   if (provided_credentials->uid == DBUS_UID_UNSET)
00636     return FALSE;
00637   else if (expected_credentials->uid == DBUS_UID_UNSET)
00638     return FALSE;
00639   else if (provided_credentials->uid == 0)
00640     return TRUE;
00641   else if (provided_credentials->uid == expected_credentials->uid)
00642     return TRUE;
00643   else
00644     return FALSE;
00645 }
00646 
00647 _DBUS_DEFINE_GLOBAL_LOCK (atomic);
00648 
00649 #ifdef DBUS_USE_ATOMIC_INT_486
00650 /* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */
00651 /* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */
00652 static inline dbus_int32_t
00653 atomic_exchange_and_add (DBusAtomic            *atomic,
00654                          volatile dbus_int32_t  val)
00655 {
00656   register dbus_int32_t result;
00657 
00658   __asm__ __volatile__ ("lock; xaddl %0,%1"
00659                         : "=r" (result), "=m" (atomic->value)
00660                         : "0" (val), "m" (atomic->value));
00661   return result;
00662 }
00663 #endif
00664 
00673 dbus_int32_t
00674 _dbus_atomic_inc (DBusAtomic *atomic)
00675 {
00676 #ifdef DBUS_USE_ATOMIC_INT_486
00677   return atomic_exchange_and_add (atomic, 1);
00678 #else
00679   dbus_int32_t res;
00680   _DBUS_LOCK (atomic);
00681   res = atomic->value;
00682   atomic->value += 1;
00683   _DBUS_UNLOCK (atomic);
00684   return res;
00685 #endif
00686 }
00687 
00696 dbus_int32_t
00697 _dbus_atomic_dec (DBusAtomic *atomic)
00698 {
00699 #ifdef DBUS_USE_ATOMIC_INT_486
00700   return atomic_exchange_and_add (atomic, -1);
00701 #else
00702   dbus_int32_t res;
00703   
00704   _DBUS_LOCK (atomic);
00705   res = atomic->value;
00706   atomic->value -= 1;
00707   _DBUS_UNLOCK (atomic);
00708   return res;
00709 #endif
00710 }
00711 
00712 void
00713 _dbus_generate_pseudorandom_bytes_buffer (char *buffer,
00714                                           int   n_bytes)
00715 {
00716   long tv_usec;
00717   int i;
00718   
00719   /* fall back to pseudorandom */
00720   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
00721                  n_bytes);
00722   
00723   _dbus_get_current_time (NULL, &tv_usec);
00724   srand (tv_usec);
00725   
00726   i = 0;
00727   while (i < n_bytes)
00728     {
00729       double r;
00730       unsigned int b;
00731           
00732       r = rand ();
00733       b = (r / (double) RAND_MAX) * 255.0;
00734 
00735       buffer[i] = b;
00736 
00737       ++i;
00738     }
00739 }
00740 
00747 void
00748 _dbus_generate_random_bytes_buffer (char *buffer,
00749                                     int   n_bytes)
00750 {
00751   DBusString str;
00752 
00753   if (!_dbus_string_init (&str))
00754     {
00755       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
00756       return;
00757     }
00758 
00759   if (!_dbus_generate_random_bytes (&str, n_bytes))
00760     {
00761       _dbus_string_free (&str);
00762       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
00763       return;
00764     }
00765 
00766   _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
00767 
00768   _dbus_string_free (&str);
00769 }
00770 
00779 dbus_bool_t
00780 _dbus_generate_random_ascii (DBusString *str,
00781                              int         n_bytes)
00782 {
00783   static const char letters[] =
00784     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
00785   int i;
00786   int len;
00787   
00788   if (!_dbus_generate_random_bytes (str, n_bytes))
00789     return FALSE;
00790   
00791   len = _dbus_string_get_length (str);
00792   i = len - n_bytes;
00793   while (i < len)
00794     {
00795       _dbus_string_set_byte (str, i,
00796                              letters[_dbus_string_get_byte (str, i) %
00797                                      (sizeof (letters) - 1)]);
00798 
00799       ++i;
00800     }
00801 
00802   _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
00803                                              n_bytes));
00804 
00805   return TRUE;
00806 }
00807 
00815 dbus_bool_t
00816 _dbus_parse_uid (const DBusString      *uid_str,
00817                  dbus_uid_t            *uid)
00818 {
00819   int end;
00820   long val;
00821   
00822   if (_dbus_string_get_length (uid_str) == 0)
00823     {
00824       _dbus_verbose ("UID string was zero length\n");
00825       return FALSE;
00826     }
00827 
00828   val = -1;
00829   end = 0;
00830   if (!_dbus_string_parse_int (uid_str, 0, &val,
00831                                &end))
00832     {
00833       _dbus_verbose ("could not parse string as a UID\n");
00834       return FALSE;
00835     }
00836   
00837   if (end != _dbus_string_get_length (uid_str))
00838     {
00839       _dbus_verbose ("string contained trailing stuff after UID\n");
00840       return FALSE;
00841     }
00842 
00843   *uid = val;
00844 
00845   return TRUE;
00846 }
00847 
00858 const char*
00859 _dbus_error_from_errno (int error_number)
00860 {
00861   switch (error_number)
00862     {
00863     case 0:
00864       return DBUS_ERROR_FAILED;
00865       
00866 #ifdef EPROTONOSUPPORT
00867     case EPROTONOSUPPORT:
00868       return DBUS_ERROR_NOT_SUPPORTED;
00869 #endif
00870 #ifdef EAFNOSUPPORT
00871     case EAFNOSUPPORT:
00872       return DBUS_ERROR_NOT_SUPPORTED;
00873 #endif
00874 #ifdef ENFILE
00875     case ENFILE:
00876       return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
00877 #endif
00878 #ifdef EMFILE
00879     case EMFILE:
00880       return DBUS_ERROR_LIMITS_EXCEEDED;
00881 #endif
00882 #ifdef EACCES
00883     case EACCES:
00884       return DBUS_ERROR_ACCESS_DENIED;
00885 #endif
00886 #ifdef EPERM
00887     case EPERM:
00888       return DBUS_ERROR_ACCESS_DENIED;
00889 #endif
00890 #ifdef ENOBUFS
00891     case ENOBUFS:
00892       return DBUS_ERROR_NO_MEMORY;
00893 #endif
00894 #ifdef ENOMEM
00895     case ENOMEM:
00896       return DBUS_ERROR_NO_MEMORY;
00897 #endif
00898 #ifdef EINVAL
00899     case EINVAL:
00900       return DBUS_ERROR_FAILED;
00901 #endif
00902 #ifdef EBADF
00903     case EBADF:
00904       return DBUS_ERROR_FAILED;
00905 #endif
00906 #ifdef EFAULT
00907     case EFAULT:
00908       return DBUS_ERROR_FAILED;
00909 #endif
00910 #ifdef ENOTSOCK
00911     case ENOTSOCK:
00912       return DBUS_ERROR_FAILED;
00913 #endif
00914 #ifdef EISCONN
00915     case EISCONN:
00916       return DBUS_ERROR_FAILED;
00917 #endif
00918 #ifdef ECONNREFUSED
00919     case ECONNREFUSED:
00920       return DBUS_ERROR_NO_SERVER;
00921 #endif
00922 #ifdef ETIMEDOUT
00923     case ETIMEDOUT:
00924       return DBUS_ERROR_TIMEOUT;
00925 #endif
00926 #ifdef ENETUNREACH
00927     case ENETUNREACH:
00928       return DBUS_ERROR_NO_NETWORK;
00929 #endif
00930 #ifdef EADDRINUSE
00931     case EADDRINUSE:
00932       return DBUS_ERROR_ADDRESS_IN_USE;
00933 #endif
00934 #ifdef EEXIST
00935     case EEXIST:
00936       return DBUS_ERROR_FILE_EXISTS;
00937 #endif
00938 #ifdef ENOENT
00939     case ENOENT:
00940       return DBUS_ERROR_FILE_NOT_FOUND;
00941 #endif
00942     }
00943 
00944   return DBUS_ERROR_FAILED;
00945 }
00946 
00949 /* tests in dbus-sysdeps-util.c */

Generated on Tue Apr 15 15:54:03 2008 for D-Bus by  doxygen 1.5.1