(linenum→info "unix/slp.c:2238")

dbus/1.0.2/dbus/dbus-sysdeps.c

    1: /* -*- mode: C; c-file-style: "gnu" -*- */
    2: /* dbus-sysdeps.c Wrappers around system/libc features shared between UNIX and Windows (internal to D-Bus implementation)
    3:  * 
    4:  * Copyright (C) 2002, 2003, 2006  Red Hat, Inc.
    5:  * Copyright (C) 2003 CodeFactory AB
    6:  *
    7:  * Licensed under the Academic Free License version 2.1
    8:  * 
    9:  * This program is free software; you can redistribute it and/or modify
   10:  * it under the terms of the GNU General Public License as published by
   11:  * the Free Software Foundation; either version 2 of the License, or
   12:  * (at your option) any later version.
   13:  *
   14:  * This program is distributed in the hope that it will be useful,
   15:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   16:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17:  * GNU General Public License for more details.
   18:  * 
   19:  * You should have received a copy of the GNU General Public License
   20:  * along with this program; if not, write to the Free Software
   21:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22:  *
   23:  */
   24: 
   25: #include "dbus-internals.h"
   26: #include "dbus-sysdeps.h"
   27: #include "dbus-threads.h"
   28: #include "dbus-protocol.h"
   29: #include "dbus-string.h"
   30: 
   31: /* NOTE: If you include any unix/windows-specific headers here, you are probably doing something
   32:  * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c.
   33:  *
   34:  * These are the standard ANSI C headers...
   35:  */
   36: #include <locale.h>
   37: #include <stdlib.h>
   38: #include <string.h>
   39: #include <stdio.h>
   40: 
   41: /* This is UNIX-specific (on windows it's just in stdlib.h I believe)
   42:  * but OK since the same stuff does exist on Windows in stdlib.h
   43:  * and covered by a configure check.
   44:  */
   45: #ifdef HAVE_ERRNO_H
   46: #include <errno.h>
   47: #endif
   48: 
   49: _DBUS_DEFINE_GLOBAL_LOCK (win_fds);
   50: _DBUS_DEFINE_GLOBAL_LOCK (sid_atom_cache);
   51: 
   52: /**
   53:  * @defgroup DBusSysdeps Internal system-dependent API
   54:  * @ingroup DBusInternals
   55:  * @brief Internal system-dependent API available on UNIX and Windows
   56:  *
   57:  * The system-dependent API has a dual purpose. First, it encapsulates
   58:  * all usage of operating system APIs for ease of auditing and to
   59:  * avoid cluttering the rest of the code with bizarre OS quirks and
   60:  * headers. Second, it abstracts different operating system APIs for
   61:  * portability.
   62:  * 
   63:  * @{
   64:  */
   65: 
   66: /**
   67:  * Aborts the program with SIGABRT (dumping core).
   68:  */
   69: void
   70: _dbus_abort (void)
   71: {
   72:   const char *s;
   73:   
   74:   _dbus_print_backtrace ();
   75:   
   76:   s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT");
   77:   if (s && *s)
   78:     {
   79:       /* don't use _dbus_warn here since it can _dbus_abort() */
   80:       fprintf (stderr, "  Process %lu sleeping for gdb attach\n", (unsigned long) _dbus_getpid());
   81:       _dbus_sleep_milliseconds (1000 * 180);
   82:     }
   83:   
   84:   abort ();
   85:   _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */
   86: }
   87: 
   88: /**
   89:  * Wrapper for setenv(). If the value is #NULL, unsets
   90:  * the environment variable.
   91:  *
   92:  * There is an unfixable memleak in that it is unsafe to
   93:  * free memory malloced for use with setenv. This is because
   94:  * we can not rely on internal implementation details of
   95:  * the underlying libc library.
   96:  *
   97:  * @param varname name of environment variable
   98:  * @param value value of environment variable
   99:  * @returns #TRUE on success.
  100:  */
  101: dbus_bool_t
  102: _dbus_setenv (const char *varname,
  103:               const char *value)
  104: {
  105:   _dbus_assert (varname != NULL);
  106:   
  107:   if (value == NULL)
  108:     {
  109: #ifdef HAVE_UNSETENV
  110:       unsetenv (varname);
  111:       return TRUE;
  112: #else
  113:       char *putenv_value;
  114:       size_t len;
  115: 
  116:       len = strlen (varname);
  117: 
  118:       /* Use system malloc to avoid memleaks that dbus_malloc
  119:        * will get upset about.
  120:        */
  121:       
  122:       putenv_value = malloc (len + 1);
  123:       if (putenv_value == NULL)
  124:         return FALSE;
  125: 
  126:       strcpy (putenv_value, varname);
  127:       
  128:       return (putenv (putenv_value) == 0);
  129: #endif
  130:     }
  131:   else
  132:     {
  133: #ifdef HAVE_SETENV
  134:       return (setenv (varname, value, TRUE) == 0);
  135: #else
  136:       char *putenv_value;
  137:       size_t len;
  138:       size_t varname_len;
  139:       size_t value_len;
  140: 
  141:       varname_len = strlen (varname);
  142:       value_len = strlen (value);
  143:       
  144:       len = varname_len + value_len + 1 /* '=' */ ;
  145: 
  146:       /* Use system malloc to avoid memleaks that dbus_malloc
  147:        * will get upset about.
  148:        */
  149:       
  150:       putenv_value = malloc (len + 1);
  151:       if (putenv_value == NULL)
  152:         return FALSE;
  153: 
  154:       strcpy (putenv_value, varname);
  155:       strcpy (putenv_value + varname_len, "=");
  156:       strcpy (putenv_value + varname_len + 1, value);
  157:       
  158:       return (putenv (putenv_value) == 0);
  159: #endif
  160:     }
  161: }
  162: 
  163: /**
  164:  * Wrapper for getenv().
  165:  *
  166:  * @param varname name of environment variable
  167:  * @returns value of environment variable or #NULL if unset
  168:  */
  169: const char*
  170: _dbus_getenv (const char *varname)
  171: {  
  172:   return getenv (varname);
  173: }
  174: 
  175: /** @} */
  176: 
  177: /**
  178:  * @addtogroup DBusString
  179:  *
  180:  * @{
  181:  */
  182: /**
  183:  * Appends an integer to a DBusString.
  184:  * 
  185:  * @param str the string
  186:  * @param value the integer value
  187:  * @returns #FALSE if not enough memory or other failure.
  188:  */
  189: dbus_bool_t
  190: _dbus_string_append_int (DBusString *str,
  191:                          long        value)
  192: {
  193:   /* this calculation is from comp.lang.c faq */
  194: #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
  195:   int orig_len;
  196:   int i;
  197:   char *buf;
  198:   
  199:   orig_len = _dbus_string_get_length (str);
  200: 
  201:   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
  202:     return FALSE;
  203: 
  204:   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
  205: 
  206:   snprintf (buf, MAX_LONG_LEN, "%ld", value);
  207: 
  208:   i = 0;
  209:   while (*buf)
  210:     {
  211:       ++buf;
  212:       ++i;
  213:     }
  214:   
  215:   _dbus_string_shorten (str, MAX_LONG_LEN - i);
  216:   
  217:   return TRUE;
  218: }
  219: 
  220: /**
  221:  * Appends an unsigned integer to a DBusString.
  222:  * 
  223:  * @param str the string
  224:  * @param value the integer value
  225:  * @returns #FALSE if not enough memory or other failure.
  226:  */
  227: dbus_bool_t
  228: _dbus_string_append_uint (DBusString    *str,
  229:                           unsigned long  value)
  230: {
  231:   /* this is wrong, but definitely on the high side. */
  232: #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
  233:   int orig_len;
  234:   int i;
  235:   char *buf;
  236:   
  237:   orig_len = _dbus_string_get_length (str);
  238: 
  239:   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
  240:     return FALSE;
  241: 
  242:   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
  243: 
  244:   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
  245: 
  246:   i = 0;
  247:   while (*buf)
  248:     {
  249:       ++buf;
  250:       ++i;
  251:     }
  252:   
  253:   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
  254:   
  255:   return TRUE;
  256: }
  257: 
  258: #ifdef DBUS_BUILD_TESTS
  259: /**
  260:  * Appends a double to a DBusString.
  261:  * 
  262:  * @param str the string
  263:  * @param value the floating point value
  264:  * @returns #FALSE if not enough memory or other failure.
  265:  */
  266: dbus_bool_t
  267: _dbus_string_append_double (DBusString *str,
  268:                             double      value)
  269: {
  270: #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
  271:   int orig_len;
  272:   char *buf;
  273:   int i;
  274:   
  275:   orig_len = _dbus_string_get_length (str);
  276: 
  277:   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
  278:     return FALSE;
  279: 
  280:   buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
  281: 
  282:   snprintf (buf, MAX_LONG_LEN, "%g", value);
  283: 
  284:   i = 0;
  285:   while (*buf)
  286:     {
  287:       ++buf;
  288:       ++i;
  289:     }
  290:   
  291:   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
  292:   
  293:   return TRUE;
  294: }
  295: #endif /* DBUS_BUILD_TESTS */
  296: 
  297: /**
  298:  * Parses an integer contained in a DBusString. Either return parameter
  299:  * may be #NULL if you aren't interested in it. The integer is parsed
  300:  * and stored in value_return. Return parameters are not initialized
  301:  * if the function returns #FALSE.
  302:  *
  303:  * @param str the string
  304:  * @param start the byte index of the start of the integer
  305:  * @param value_return return location of the integer value or #NULL
  306:  * @param end_return return location of the end of the integer, or #NULL
  307:  * @returns #TRUE on success
  308:  */
  309: dbus_bool_t
  310: _dbus_string_parse_int (const DBusString *str,
  311:                         int               start,
  312:                         long             *value_return,
  313:                         int              *end_return)
  314: {
  315:   long v;
  316:   const char *p;
  317:   char *end;
  318: 
  319:   p = _dbus_string_get_const_data_len (str, start,
  320:                                        _dbus_string_get_length (str) - start);
  321: 
  322:   end = NULL;
  323:   errno = 0;
  324:   v = strtol (p, &end, 0);
  325:   if (end == NULL || end == p || errno != 0)
  326:     return FALSE;
  327: 
  328:   if (value_return)
  329:     *value_return = v;
  330:   if (end_return)
  331:     *end_return = start + (end - p);
  332: 
  333:   return TRUE;
  334: }
  335: 
  336: /**
  337:  * Parses an unsigned integer contained in a DBusString. Either return
  338:  * parameter may be #NULL if you aren't interested in it. The integer
  339:  * is parsed and stored in value_return. Return parameters are not
  340:  * initialized if the function returns #FALSE.
  341:  *
  342:  * @param str the string
  343:  * @param start the byte index of the start of the integer
  344:  * @param value_return return location of the integer value or #NULL
  345:  * @param end_return return location of the end of the integer, or #NULL
  346:  * @returns #TRUE on success
  347:  */
  348: dbus_bool_t
  349: _dbus_string_parse_uint (const DBusString *str,
  350:                          int               start,
  351:                          unsigned long    *value_return,
  352:                          int              *end_return)
  353: {
  354:   unsigned long v;
  355:   const char *p;
  356:   char *end;
  357: 
  358:   p = _dbus_string_get_const_data_len (str, start,
  359:                                        _dbus_string_get_length (str) - start);
  360: 
  361:   end = NULL;
  362:   errno = 0;
  363:   v = strtoul (p, &end, 0);
  364:   if (end == NULL || end == p || errno != 0)
  365:     return FALSE;
  366: 
  367:   if (value_return)
  368:     *value_return = v;
  369:   if (end_return)
  370:     *end_return = start + (end - p);
  371: 
  372:   return TRUE;
  373: }
  374: 
  375: #ifdef DBUS_BUILD_TESTS
  376: static dbus_bool_t
  377: ascii_isspace (char c)
  378: {
  379:   return (c == ' ' ||
  380:           c == '\f' ||
  381:           c == '\n' ||
  382:           c == '\r' ||
  383:           c == '\t' ||
  384:           c == '\v');
  385: }
  386: #endif /* DBUS_BUILD_TESTS */
  387: 
  388: #ifdef DBUS_BUILD_TESTS
  389: static dbus_bool_t
  390: ascii_isdigit (char c)
  391: {
  392:   return c >= '0' && c <= '9';
  393: }
  394: #endif /* DBUS_BUILD_TESTS */
  395: 
  396: #ifdef DBUS_BUILD_TESTS
  397: static dbus_bool_t
  398: ascii_isxdigit (char c)
  399: {
  400:   return (ascii_isdigit (c) ||
  401:           (c >= 'a' && c <= 'f') ||
  402:           (c >= 'A' && c <= 'F'));
  403: }
  404: #endif /* DBUS_BUILD_TESTS */
  405: 
  406: #ifdef DBUS_BUILD_TESTS
  407: /* Calls strtod in a locale-independent fashion, by looking at
  408:  * the locale data and patching the decimal comma to a point.
  409:  *
  410:  * Relicensed from glib.
  411:  */
  412: static double
  413: ascii_strtod (const char *nptr,
  414:               char      **endptr)
  415: {
  416:   char *fail_pos;
  417:   double val;
  418:   struct lconv *locale_data;
  419:   const char *decimal_point;
  420:   int decimal_point_len;
  421:   const char *p, *decimal_point_pos;
  422:   const char *end = NULL; /* Silence gcc */
  423: 
  424:   fail_pos = NULL;
  425: 
  426:   locale_data = localeconv ();
  427:   decimal_point = locale_data->decimal_point;
  428:   decimal_point_len = strlen (decimal_point);
  429: 
  430:   _dbus_assert (decimal_point_len != 0);
  431:   
  432:   decimal_point_pos = NULL;
  433:   if (decimal_point[0] != '.' ||
  434:       decimal_point[1] != 0)
  435:     {
  436:       p = nptr;
  437:       /* Skip leading space */
  438:       while (ascii_isspace (*p))
  439:         p++;
  440:       
  441:       /* Skip leading optional sign */
  442:       if (*p == '+' || *p == '-')
  443:         p++;
  444:       
  445:       if (p[0] == '0' &&
  446:           (p[1] == 'x' || p[1] == 'X'))
  447:         {
  448:           p += 2;
  449:           /* HEX - find the (optional) decimal point */
  450:           
  451:           while (ascii_isxdigit (*p))
  452:             p++;
  453:           
  454:           if (*p == '.')
  455:             {
  456:               decimal_point_pos = p++;
  457:               
  458:               while (ascii_isxdigit (*p))
  459:                 p++;
  460:               
  461:               if (*p == 'p' || *p == 'P')
  462:                 p++;
  463:               if (*p == '+' || *p == '-')
  464:                 p++;
  465:               while (ascii_isdigit (*p))
  466:                 p++;
  467:               end = p;
  468:             }
  469:         }
  470:       else
  471:         {
  472:           while (ascii_isdigit (*p))
  473:             p++;
  474:           
  475:           if (*p == '.')
  476:             {
  477:               decimal_point_pos = p++;
  478:               
  479:               while (ascii_isdigit (*p))
  480:                 p++;
  481:               
  482:               if (*p == 'e' || *p == 'E')
  483:                 p++;
  484:               if (*p == '+' || *p == '-')
  485:                 p++;
  486:               while (ascii_isdigit (*p))
  487:                 p++;
  488:               end = p;
  489:             }
  490:         }
  491:       /* For the other cases, we need not convert the decimal point */
  492:     }
  493: 
  494:   /* Set errno to zero, so that we can distinguish zero results
  495:      and underflows */
  496:   errno = 0;
  497:   
  498:   if (decimal_point_pos)
  499:     {
  500:       char *copy, *c;
  501: 
  502:       /* We need to convert the '.' to the locale specific decimal point */
  503:       copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
  504:       
  505:       c = copy;
  506:       memcpy (c, nptr, decimal_point_pos - nptr);
  507:       c += decimal_point_pos - nptr;
  508:       memcpy (c, decimal_point, decimal_point_len);
  509:       c += decimal_point_len;
  510:       memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
  511:       c += end - (decimal_point_pos + 1);
  512:       *c = 0;
  513: 
  514:       val = strtod (copy, &fail_pos);
  515: 
  516:       if (fail_pos)
  517:         {
  518:           if (fail_pos > decimal_point_pos)
  519:             fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
  520:           else
  521:             fail_pos = (char *)nptr + (fail_pos - copy);
  522:         }
  523:       
  524:       dbus_free (copy);
  525:           
  526:     }
  527:   else
  528:     val = strtod (nptr, &fail_pos);
  529: 
  530:   if (endptr)
  531:     *endptr = fail_pos;
  532:   
  533:   return val;
  534: }
  535: #endif /* DBUS_BUILD_TESTS */
  536: 
  537: #ifdef DBUS_BUILD_TESTS
  538: /**
  539:  * Parses a floating point number contained in a DBusString. Either
  540:  * return parameter may be #NULL if you aren't interested in it. The
  541:  * integer is parsed and stored in value_return. Return parameters are
  542:  * not initialized if the function returns #FALSE.
  543:  *
  544:  * @param str the string
  545:  * @param start the byte index of the start of the float
  546:  * @param value_return return location of the float value or #NULL
  547:  * @param end_return return location of the end of the float, or #NULL
  548:  * @returns #TRUE on success
  549:  */
  550: dbus_bool_t
  551: _dbus_string_parse_double (const DBusString *str,
  552:                            int               start,
  553:                            double           *value_return,
  554:                            int              *end_return)
  555: {
  556:   double v;
  557:   const char *p;
  558:   char *end;
  559: 
  560:   p = _dbus_string_get_const_data_len (str, start,
  561:                                        _dbus_string_get_length (str) - start);
  562: 
  563:   end = NULL;
  564:   errno = 0;
  565:   v = ascii_strtod (p, &end);
  566:   if (end == NULL || end == p || errno != 0)
  567:     return FALSE;
  568: 
  569:   if (value_return)
  570:     *value_return = v;
  571:   if (end_return)
  572:     *end_return = start + (end - p);
  573: 
  574:   return TRUE;
  575: }
  576: #endif /* DBUS_BUILD_TESTS */
  577: 
  578: /** @} */ /* DBusString group */
  579: 
  580: /**
  581:  * @addtogroup DBusInternalsUtils
  582:  * @{
  583:  */
  584: 
  585: /**
  586:  * Frees the members of info
  587:  * (but not info itself)
  588:  * @param info the user info struct
  589:  */
  590: void
  591: _dbus_user_info_free (DBusUserInfo *info)
  592: {
  593:   dbus_free (info->group_ids);
  594:   dbus_free (info->username);
  595:   dbus_free (info->homedir);
  596: }
  597: 
  598: /**
  599:  * Frees the members of info (but not info itself).
  600:  *
  601:  * @param info the group info
  602:  */
  603: void
  604: _dbus_group_info_free (DBusGroupInfo    *info)
  605: {
  606:   dbus_free (info->groupname);
  607: }
  608: 
  609: /**
  610:  * Sets fields in DBusCredentials to DBUS_PID_UNSET,
  611:  * DBUS_UID_UNSET, DBUS_GID_UNSET.
  612:  *
  613:  * @param credentials the credentials object to fill in
  614:  */
  615: void
  616: _dbus_credentials_clear (DBusCredentials *credentials)
  617: {
  618:   credentials->pid = DBUS_PID_UNSET;
  619:   credentials->uid = DBUS_UID_UNSET;
  620:   credentials->gid = DBUS_GID_UNSET;
  621: }
  622: 
  623: /**
  624:  * Checks whether the provided_credentials are allowed to log in
  625:  * as the expected_credentials.
  626:  *
  627: