dbus-sysdeps.c 17.5 KB
Newer Older
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
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 10 11 12 13 14 15 16 17 18 19 20
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 23 24
 *
 */

25
#include <config.h>
26
#include "dbus-internals.h"
27
#include "dbus-sysdeps.h"
28
#include "dbus-threads.h"
29
#include "dbus-protocol.h"
30
#include "dbus-string.h"
31
#include "dbus-list.h"
32
#include "dbus-misc.h"
33 34 35 36 37 38

/* NOTE: If you include any unix/windows-specific headers here, you are probably doing something
 * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c.
 *
 * These are the standard ANSI C headers...
 */
39
#if HAVE_LOCALE_H
40
#include <locale.h>
41
#endif
42 43 44
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
45

46 47
#ifdef HAVE_ERRNO_H
#include <errno.h>
48 49
#endif

50 51
#ifdef DBUS_WIN
  #include <stdlib.h>
52 53 54
#elif (defined __APPLE__)
# include <crt_externs.h>
# define environ (*_NSGetEnviron())
55
#else
56
extern char **environ;
57
#endif
58

59
/**
60 61 62 63 64 65 66 67 68 69
 * @defgroup DBusSysdeps Internal system-dependent API
 * @ingroup DBusInternals
 * @brief Internal system-dependent API available on UNIX and Windows
 *
 * The system-dependent API has a dual purpose. First, it encapsulates
 * all usage of operating system APIs for ease of auditing and to
 * avoid cluttering the rest of the code with bizarre OS quirks and
 * headers. Second, it abstracts different operating system APIs for
 * portability.
 * 
70 71
 * @{
 */
72

73 74 75 76 77 78
/**
 * Aborts the program with SIGABRT (dumping core).
 */
void
_dbus_abort (void)
{
79
  const char *s;
80 81 82
  
  _dbus_print_backtrace ();
  
83
  s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT");
84
  if (s && *s)
85 86
    {
      /* don't use _dbus_warn here since it can _dbus_abort() */
87
      fprintf (stderr, "  Process %lu sleeping for gdb attach\n", _dbus_pid_for_log ());
88
      _dbus_sleep_milliseconds (1000 * 180);
89 90
    }
  
91
  abort ();
92
  _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */
93 94
}

95
/**
96 97
 * @ingroup DBusMisc
 *
98 99 100
 * Wrapper for setenv(). If the value is #NULL, unsets
 * the environment variable.
 *
101 102 103 104
 * There is an unfixable memleak in that it is unsafe to
 * free memory malloced for use with setenv. This is because
 * we can not rely on internal implementation details of
 * the underlying libc library.
105
 *
106 107 108
 * This function is not thread-safe, because altering the environment
 * in Unix is not thread-safe in general.
 *
109
 * @param varname name of environment variable
110 111
 * @param value value of environment variable, or #NULL to unset
 * @returns #TRUE on success, #FALSE if not enough memory.
112 113
 */
dbus_bool_t
114 115
dbus_setenv (const char *varname,
             const char *value)
116
{
117 118 119 120 121 122 123
  _dbus_assert (varname != NULL);
  
  if (value == NULL)
    {
#ifdef HAVE_UNSETENV
      unsetenv (varname);
      return TRUE;
124
#else
125 126
      char *putenv_value;
      size_t len;
127

128
      len = strlen (varname);
129

130 131 132 133
      /* Use system malloc to avoid memleaks that dbus_malloc
       * will get upset about.
       */
      
134
      putenv_value = malloc (len + 2);
135 136 137 138
      if (putenv_value == NULL)
        return FALSE;

      strcpy (putenv_value, varname);
139 140 141
#if defined(DBUS_WIN)
      strcat (putenv_value, "=");
#endif
142 143 144
      
      return (putenv (putenv_value) == 0);
#endif
145
    }
146 147 148 149 150 151 152 153 154
  else
    {
#ifdef HAVE_SETENV
      return (setenv (varname, value, TRUE) == 0);
#else
      char *putenv_value;
      size_t len;
      size_t varname_len;
      size_t value_len;
155

156 157 158 159
      varname_len = strlen (varname);
      value_len = strlen (value);
      
      len = varname_len + value_len + 1 /* '=' */ ;
160

161 162 163 164 165 166 167 168 169 170 171 172 173
      /* Use system malloc to avoid memleaks that dbus_malloc
       * will get upset about.
       */
      
      putenv_value = malloc (len + 1);
      if (putenv_value == NULL)
        return FALSE;

      strcpy (putenv_value, varname);
      strcpy (putenv_value + varname_len, "=");
      strcpy (putenv_value + varname_len + 1, value);
      
      return (putenv (putenv_value) == 0);
174
#endif
175
    }
176 177
}

178 179 180 181 182 183 184 185 186
/**
 * Wrapper for getenv().
 *
 * @param varname name of environment variable
 * @returns value of environment variable or #NULL if unset
 */
const char*
_dbus_getenv (const char *varname)
{  
187 188 189 190 191
  /* Don't respect any environment variables if the current process is
   * setuid.  This is the equivalent of glibc's __secure_getenv().
   */
  if (_dbus_check_setuid ())
    return NULL;
192 193 194
  return getenv (varname);
}

195 196 197 198 199 200 201 202
/**
 * Wrapper for clearenv().
 *
 * @returns #TRUE on success.
 */
dbus_bool_t
_dbus_clearenv (void)
{
203 204 205 206 207 208 209 210 211 212 213 214
  dbus_bool_t rc = TRUE;

#ifdef HAVE_CLEARENV
  if (clearenv () != 0)
     rc = FALSE;
#else

  if (environ != NULL)
    environ[0] = NULL;
#endif

  return rc;
215 216
}

217
/**
218 219
 * Split paths into a list of char strings
 * 
220 221 222 223 224 225 226 227 228 229 230 231 232 233
 * @param dirs string with pathes 
 * @param suffix string concated to each path in dirs
 * @param dir_list contains a list of splitted pathes
 * return #TRUE is pathes could be splittes,#FALSE in oom case 
 */
dbus_bool_t
_dbus_split_paths_and_append (DBusString *dirs, 
                              const char *suffix, 
                              DBusList  **dir_list)
{
   int start;
   int i;
   int len;
   char *cpath;
234
   DBusString file_suffix;
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338

   start = 0;
   i = 0;

   _dbus_string_init_const (&file_suffix, suffix);

   len = _dbus_string_get_length (dirs);

   while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i))
     {
       DBusString path;

       if (!_dbus_string_init (&path))
          goto oom;

       if (!_dbus_string_copy_len (dirs,
                                   start,
                                   i - start,
                                   &path,
                                   0))
          {
            _dbus_string_free (&path);
            goto oom;
          }

        _dbus_string_chop_white (&path);

        /* check for an empty path */
        if (_dbus_string_get_length (&path) == 0)
          goto next;

        if (!_dbus_concat_dir_and_file (&path,
                                        &file_suffix))
          {
            _dbus_string_free (&path);
            goto oom;
          }

        if (!_dbus_string_copy_data(&path, &cpath))
          {
            _dbus_string_free (&path);
            goto oom;
          }

        if (!_dbus_list_append (dir_list, cpath))
          {
            _dbus_string_free (&path);              
            dbus_free (cpath);
            goto oom;
          }

       next:
        _dbus_string_free (&path);
        start = i + 1;
    } 
      
  if (start != len)
    { 
      DBusString path;

      if (!_dbus_string_init (&path))
        goto oom;

      if (!_dbus_string_copy_len (dirs,
                                  start,
                                  len - start,
                                  &path,
                                  0))
        {
          _dbus_string_free (&path);
          goto oom;
        }

      if (!_dbus_concat_dir_and_file (&path,
                                      &file_suffix))
        {
          _dbus_string_free (&path);
          goto oom;
        }

      if (!_dbus_string_copy_data(&path, &cpath))
        {
          _dbus_string_free (&path);
          goto oom;
        }

      if (!_dbus_list_append (dir_list, cpath))
        {
          _dbus_string_free (&path);              
          dbus_free (cpath);
          goto oom;
        }

      _dbus_string_free (&path); 
    }

  return TRUE;

 oom:
  _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); 
  _dbus_list_clear (dir_list);
  return FALSE;
}

339 340
/** @} */

341
/**
342
 * @addtogroup DBusString
343
 *
344
 * @{
345 346
 */
/**
347
 * Appends an integer to a DBusString.
348
 * 
349 350 351
 * @param str the string
 * @param value the integer value
 * @returns #FALSE if not enough memory or other failure.
352
 */
353 354 355
dbus_bool_t
_dbus_string_append_int (DBusString *str,
                         long        value)
356
{
357 358 359 360 361
  /* this calculation is from comp.lang.c faq */
#define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
  int orig_len;
  int i;
  char *buf;
362
  
363
  orig_len = _dbus_string_get_length (str);
364

365 366
  if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
    return FALSE;
367

368
  buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
369

370
  snprintf (buf, MAX_LONG_LEN, "%ld", value);
371

372 373 374 375 376 377 378 379
  i = 0;
  while (*buf)
    {
      ++buf;
      ++i;
    }
  
  _dbus_string_shorten (str, MAX_LONG_LEN - i);
380
  
381
  return TRUE;
382 383 384
}

/**
385
 * Appends an unsigned integer to a DBusString.
386
 * 
387 388 389
 * @param str the string
 * @param value the integer value
 * @returns #FALSE if not enough memory or other failure.
390
 */
391 392 393
dbus_bool_t
_dbus_string_append_uint (DBusString    *str,
                          unsigned long  value)
394
{
395 396 397 398 399
  /* this is wrong, but definitely on the high side. */
#define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
  int orig_len;
  int i;
  char *buf;
400
  
401
  orig_len = _dbus_string_get_length (str);
402

403 404
  if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
    return FALSE;
405

406
  buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
407

408
  snprintf (buf, MAX_ULONG_LEN, "%lu", value);
409

410 411
  i = 0;
  while (*buf)
412
    {
413 414
      ++buf;
      ++i;
415
    }
416 417 418 419
  
  _dbus_string_shorten (str, MAX_ULONG_LEN - i);
  
  return TRUE;
420 421
}

422
/**
423 424 425 426
 * Parses an integer contained in a DBusString. Either return parameter
 * may be #NULL if you aren't interested in it. The integer is parsed
 * and stored in value_return. Return parameters are not initialized
 * if the function returns #FALSE.
427
 *
428 429 430 431 432
 * @param str the string
 * @param start the byte index of the start of the integer
 * @param value_return return location of the integer value or #NULL
 * @param end_return return location of the end of the integer, or #NULL
 * @returns #TRUE on success
433
 */
434 435 436 437 438
dbus_bool_t
_dbus_string_parse_int (const DBusString *str,
                        int               start,
                        long             *value_return,
                        int              *end_return)
439
{
440 441 442
  long v;
  const char *p;
  char *end;
443

444 445
  p = _dbus_string_get_const_data_len (str, start,
                                       _dbus_string_get_length (str) - start);
446

447
  end = NULL;
448
  _dbus_set_errno_to_zero ();
449 450 451
  v = strtol (p, &end, 0);
  if (end == NULL || end == p || errno != 0)
    return FALSE;
452

453 454 455 456
  if (value_return)
    *value_return = v;
  if (end_return)
    *end_return = start + (end - p);
457

458
  return TRUE;
459 460 461
}

/**
462 463 464 465
 * Parses an unsigned integer contained in a DBusString. Either return
 * parameter may be #NULL if you aren't interested in it. The integer
 * is parsed and stored in value_return. Return parameters are not
 * initialized if the function returns #FALSE.
466
 *
467 468 469 470 471
 * @param str the string
 * @param start the byte index of the start of the integer
 * @param value_return return location of the integer value or #NULL
 * @param end_return return location of the end of the integer, or #NULL
 * @returns #TRUE on success
472
 */
473 474 475 476 477
dbus_bool_t
_dbus_string_parse_uint (const DBusString *str,
                         int               start,
                         unsigned long    *value_return,
                         int              *end_return)
478
{
479 480 481
  unsigned long v;
  const char *p;
  char *end;
482

483 484
  p = _dbus_string_get_const_data_len (str, start,
                                       _dbus_string_get_length (str) - start);
485

486
  end = NULL;
487
  _dbus_set_errno_to_zero ();
488 489 490
  v = strtoul (p, &end, 0);
  if (end == NULL || end == p || errno != 0)
    return FALSE;
491

492 493 494 495
  if (value_return)
    *value_return = v;
  if (end_return)
    *end_return = start + (end - p);
496 497 498 499

  return TRUE;
}

500
/** @} */ /* DBusString group */
501 502

/**
503 504
 * @addtogroup DBusInternalsUtils
 * @{
505 506
 */

507 508 509 510 511
/**
 * Fills n_bytes of the given buffer with random bytes.
 *
 * @param buffer an allocated buffer
 * @param n_bytes the number of bytes in buffer to write to
512 513
 * @param error location to store reason for failure
 * @returns #TRUE on success
514
 */
515 516 517 518
dbus_bool_t
_dbus_generate_random_bytes_buffer (char      *buffer,
                                    int        n_bytes,
                                    DBusError *error)
519 520 521 522
{
  DBusString str;

  if (!_dbus_string_init (&str))
523
    {
524 525
      _DBUS_SET_OOM (error);
      return FALSE;
526
    }
527

528
  if (!_dbus_generate_random_bytes (&str, n_bytes, error))
529 530
    {
      _dbus_string_free (&str);
531
      return FALSE;
532 533 534 535 536
    }

  _dbus_string_copy_to_buffer (&str, buffer, n_bytes);

  _dbus_string_free (&str);
537
  return TRUE;
538 539 540 541 542 543 544 545
}

/**
 * Generates the given number of random bytes, where the bytes are
 * chosen from the alphanumeric ASCII subset.
 *
 * @param str the string
 * @param n_bytes the number of random ASCII bytes to append to string
546
 * @param error location to store reason for failure
547 548 549 550
 * @returns #TRUE on success, #FALSE if no memory or other failure
 */
dbus_bool_t
_dbus_generate_random_ascii (DBusString *str,
551 552
                             int         n_bytes,
                             DBusError  *error)
553 554 555 556 557 558
{
  static const char letters[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
  int i;
  int len;
  
559
  if (!_dbus_generate_random_bytes (str, n_bytes, error))
560 561 562 563 564
    return FALSE;
  
  len = _dbus_string_get_length (str);
  i = len - n_bytes;
  while (i < len)
565
    {
566 567 568
      _dbus_string_set_byte (str, i,
                             letters[_dbus_string_get_byte (str, i) %
                                     (sizeof (letters) - 1)]);
569

570
      ++i;
571 572
    }

573 574 575 576
  _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
                                             n_bytes));

  return TRUE;
577
}
578

579
/**
580 581
 * Converts a UNIX errno, or Windows errno or WinSock error value into
 * a #DBusError name.
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
 *
 * @todo should cover more errnos, specifically those
 * from open().
 * 
 * @param error_number the errno.
 * @returns an error name
 */
const char*
_dbus_error_from_errno (int error_number)
{
  switch (error_number)
    {
    case 0:
      return DBUS_ERROR_FAILED;
      
#ifdef EPROTONOSUPPORT
    case EPROTONOSUPPORT:
      return DBUS_ERROR_NOT_SUPPORTED;
600
#elif defined(WSAEPROTONOSUPPORT)
601 602 603
    case WSAEPROTONOSUPPORT:
      return DBUS_ERROR_NOT_SUPPORTED;
#endif
604 605 606
#ifdef EAFNOSUPPORT
    case EAFNOSUPPORT:
      return DBUS_ERROR_NOT_SUPPORTED;
607
#elif defined(WSAEAFNOSUPPORT)
608 609 610
    case WSAEAFNOSUPPORT:
      return DBUS_ERROR_NOT_SUPPORTED;
#endif
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637
#ifdef ENFILE
    case ENFILE:
      return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
#endif
#ifdef EMFILE
    case EMFILE:
      return DBUS_ERROR_LIMITS_EXCEEDED;
#endif
#ifdef EACCES
    case EACCES:
      return DBUS_ERROR_ACCESS_DENIED;
#endif
#ifdef EPERM
    case EPERM:
      return DBUS_ERROR_ACCESS_DENIED;
#endif
#ifdef ENOBUFS
    case ENOBUFS:
      return DBUS_ERROR_NO_MEMORY;
#endif
#ifdef ENOMEM
    case ENOMEM:
      return DBUS_ERROR_NO_MEMORY;
#endif
#ifdef ECONNREFUSED
    case ECONNREFUSED:
      return DBUS_ERROR_NO_SERVER;
638
#elif defined(WSAECONNREFUSED)
639 640 641
    case WSAECONNREFUSED:
      return DBUS_ERROR_NO_SERVER;
#endif
642 643 644
#ifdef ETIMEDOUT
    case ETIMEDOUT:
      return DBUS_ERROR_TIMEOUT;
645
#elif defined(WSAETIMEDOUT)
646 647 648
    case WSAETIMEDOUT:
      return DBUS_ERROR_TIMEOUT;
#endif
649 650 651
#ifdef ENETUNREACH
    case ENETUNREACH:
      return DBUS_ERROR_NO_NETWORK;
652
#elif defined(WSAENETUNREACH)
653 654 655
    case WSAENETUNREACH:
      return DBUS_ERROR_NO_NETWORK;
#endif
656 657 658
#ifdef EADDRINUSE
    case EADDRINUSE:
      return DBUS_ERROR_ADDRESS_IN_USE;
659
#elif defined(WSAEADDRINUSE)
660 661 662
    case WSAEADDRINUSE:
      return DBUS_ERROR_ADDRESS_IN_USE;
#endif
663 664
#ifdef EEXIST
    case EEXIST:
665
      return DBUS_ERROR_FILE_EXISTS;
666 667 668 669 670 671 672 673 674 675
#endif
#ifdef ENOENT
    case ENOENT:
      return DBUS_ERROR_FILE_NOT_FOUND;
#endif
    }

  return DBUS_ERROR_FAILED;
}

676 677 678 679 680 681 682 683 684 685 686
/**
 * Converts the current system errno value into a #DBusError name.
 *
 * @returns an error name
 */
const char*
_dbus_error_from_system_errno (void)
{
  return _dbus_error_from_errno (errno);
}

687 688 689 690 691 692
/**
 * Assign 0 to the global errno variable
 */
void
_dbus_set_errno_to_zero (void)
{
693 694 695
#ifdef DBUS_WINCE
  SetLastError (0);
#else
696
  errno = 0;
697
#endif
698 699 700 701
}

/**
 * See if errno is ENOMEM
702
 * @returns #TRUE if e == ENOMEM
703 704
 */
dbus_bool_t
705
_dbus_get_is_errno_enomem (int e)
706
{
707
  return e == ENOMEM;
708 709 710 711
}

/**
 * See if errno is EINTR
712
 * @returns #TRUE if e == EINTR
713 714
 */
dbus_bool_t
715
_dbus_get_is_errno_eintr (int e)
716
{
717
  return e == EINTR;
718 719
}

720 721 722 723 724
/**
 * See if errno is EPIPE
 * @returns #TRUE if errno == EPIPE
 */
dbus_bool_t
725
_dbus_get_is_errno_epipe (int e)
726
{
727
  return e == EPIPE;
728 729
}

730 731 732 733 734
/**
 * See if errno is ETOOMANYREFS
 * @returns #TRUE if errno == ETOOMANYREFS
 */
dbus_bool_t
735
_dbus_get_is_errno_etoomanyrefs (int e)
736 737
{
#ifdef ETOOMANYREFS
738
  return e == ETOOMANYREFS;
739 740 741 742 743
#else
  return FALSE;
#endif
}

744 745 746 747 748 749 750 751 752 753
/**
 * Get error message from errno
 * @returns _dbus_strerror(errno)
 */
const char*
_dbus_strerror_from_errno (void)
{
  return _dbus_strerror (errno);
}

754
/**
755
 * Log a message to the system log file (e.g. syslog on Unix) and/or stderr.
756 757 758 759 760
 *
 * @param severity a severity value
 * @param msg a printf-style format string
 */
void
761 762 763
_dbus_log (DBusSystemLogSeverity  severity,
           const char            *msg,
           ...)
764 765 766 767 768
{
  va_list args;

  va_start (args, msg);

769
  _dbus_logv (severity, msg, args);
770 771 772 773

  va_end (args);
}

774
/** @} end of sysdeps */
775 776

/* tests in dbus-sysdeps-util.c */