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 * 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., 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
33/* NOTE: If you include any unix/windows-specific headers here, you are probably doing something
34 * wrong and should be putting some code in dbus-sysdeps-unix.c or dbus-sysdeps-win.c.
35 *
36 * These are the standard ANSI C headers...
37 */
38#if HAVE_LOCALE_H
39#include <locale.h>
40#endif
41#include <stdlib.h>
42#include <string.h>
43#include <stdio.h>
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_DBUS_DEFINE_GLOBAL_LOCK (system_users);
52
53#ifdef DBUS_WIN
54  #include <stdlib.h>
55#elif (defined __APPLE__)
56# include <crt_externs.h>
57# define environ (*_NSGetEnviron())
58#else
59extern char **environ;
60#endif
61
62/**
63 * @defgroup DBusSysdeps Internal system-dependent API
64 * @ingroup DBusInternals
65 * @brief Internal system-dependent API available on UNIX and Windows
66 *
67 * The system-dependent API has a dual purpose. First, it encapsulates
68 * all usage of operating system APIs for ease of auditing and to
69 * avoid cluttering the rest of the code with bizarre OS quirks and
70 * headers. Second, it abstracts different operating system APIs for
71 * portability.
72 *
73 * @{
74 */
75
76/**
77 * Aborts the program with SIGABRT (dumping core).
78 */
79void
80_dbus_abort (void)
81{
82  const char *s;
83
84  _dbus_print_backtrace ();
85
86  s = _dbus_getenv ("DBUS_BLOCK_ON_ABORT");
87  if (s && *s)
88    {
89      /* don't use _dbus_warn here since it can _dbus_abort() */
90      fprintf (stderr, "  Process %lu sleeping for gdb attach\n", _dbus_pid_for_log ());
91      _dbus_sleep_milliseconds (1000 * 180);
92    }
93
94  abort ();
95  _dbus_exit (1); /* in case someone manages to ignore SIGABRT ? */
96}
97
98/**
99 * Wrapper for setenv(). If the value is #NULL, unsets
100 * the environment variable.
101 *
102 * There is an unfixable memleak in that it is unsafe to
103 * free memory malloced for use with setenv. This is because
104 * we can not rely on internal implementation details of
105 * the underlying libc library.
106 *
107 * @param varname name of environment variable
108 * @param value value of environment variable
109 * @returns #TRUE on success.
110 */
111dbus_bool_t
112_dbus_setenv (const char *varname,
113              const char *value)
114{
115  _dbus_assert (varname != NULL);
116
117  if (value == NULL)
118    {
119#ifdef HAVE_UNSETENV
120      unsetenv (varname);
121      return TRUE;
122#else
123      char *putenv_value;
124      size_t len;
125
126      len = strlen (varname);
127
128      /* Use system malloc to avoid memleaks that dbus_malloc
129       * will get upset about.
130       */
131
132      putenv_value = malloc (len + 2);
133      if (putenv_value == NULL)
134        return FALSE;
135
136      strcpy (putenv_value, varname);
137#if defined(DBUS_WIN)
138      strcat (putenv_value, "=");
139#endif
140
141      return (putenv (putenv_value) == 0);
142#endif
143    }
144  else
145    {
146#ifdef HAVE_SETENV
147      return (setenv (varname, value, TRUE) == 0);
148#else
149      char *putenv_value;
150      size_t len;
151      size_t varname_len;
152      size_t value_len;
153
154      varname_len = strlen (varname);
155      value_len = strlen (value);
156
157      len = varname_len + value_len + 1 /* '=' */ ;
158
159      /* Use system malloc to avoid memleaks that dbus_malloc
160       * will get upset about.
161       */
162
163      putenv_value = malloc (len + 1);
164      if (putenv_value == NULL)
165        return FALSE;
166
167      strcpy (putenv_value, varname);
168      strcpy (putenv_value + varname_len, "=");
169      strcpy (putenv_value + varname_len + 1, value);
170
171      return (putenv (putenv_value) == 0);
172#endif
173    }
174}
175
176/**
177 * Wrapper for getenv().
178 *
179 * @param varname name of environment variable
180 * @returns value of environment variable or #NULL if unset
181 */
182const char*
183_dbus_getenv (const char *varname)
184{
185  return getenv (varname);
186}
187
188/**
189 * Wrapper for clearenv().
190 *
191 * @returns #TRUE on success.
192 */
193dbus_bool_t
194_dbus_clearenv (void)
195{
196  dbus_bool_t rc = TRUE;
197
198#ifdef HAVE_CLEARENV
199  if (clearenv () != 0)
200     rc = FALSE;
201#else
202
203  if (environ != NULL)
204    environ[0] = NULL;
205#endif
206
207  return rc;
208}
209
210/**
211 * Gets a #NULL-terminated list of key=value pairs from the
212 * environment. Use dbus_free_string_array to free it.
213 *
214 * @returns the environment or #NULL on OOM
215 */
216char **
217_dbus_get_environment (void)
218{
219  int i, length;
220  char **environment;
221
222  _dbus_assert (environ != NULL);
223
224  for (length = 0; environ[length] != NULL; length++);
225
226  /* Add one for NULL */
227  length++;
228
229  environment = dbus_new0 (char *, length);
230
231  if (environment == NULL)
232    return NULL;
233
234  for (i = 0; environ[i] != NULL; i++)
235    {
236      environment[i] = _dbus_strdup (environ[i]);
237
238      if (environment[i] == NULL)
239        break;
240    }
241
242  if (environ[i] != NULL)
243    {
244      dbus_free_string_array (environment);
245      environment = NULL;
246    }
247
248  return environment;
249}
250
251/**
252 * Split paths into a list of char strings
253 *
254 * @param dirs string with pathes
255 * @param suffix string concated to each path in dirs
256 * @param dir_list contains a list of splitted pathes
257 * return #TRUE is pathes could be splittes,#FALSE in oom case
258 */
259dbus_bool_t
260_dbus_split_paths_and_append (DBusString *dirs,
261                              const char *suffix,
262                              DBusList  **dir_list)
263{
264   int start;
265   int i;
266   int len;
267   char *cpath;
268   DBusString file_suffix;
269
270   start = 0;
271   i = 0;
272
273   _dbus_string_init_const (&file_suffix, suffix);
274
275   len = _dbus_string_get_length (dirs);
276
277   while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i))
278     {
279       DBusString path;
280
281       if (!_dbus_string_init (&path))
282          goto oom;
283
284       if (!_dbus_string_copy_len (dirs,
285                                   start,
286                                   i - start,
287                                   &path,
288                                   0))
289          {
290            _dbus_string_free (&path);
291            goto oom;
292          }
293
294        _dbus_string_chop_white (&path);
295
296        /* check for an empty path */
297        if (_dbus_string_get_length (&path) == 0)
298          goto next;
299
300        if (!_dbus_concat_dir_and_file (&path,
301                                        &file_suffix))
302          {
303            _dbus_string_free (&path);
304            goto oom;
305          }
306
307        if (!_dbus_string_copy_data(&path, &cpath))
308          {
309            _dbus_string_free (&path);
310            goto oom;
311          }
312
313        if (!_dbus_list_append (dir_list, cpath))
314          {
315            _dbus_string_free (&path);
316            dbus_free (cpath);
317            goto oom;
318          }
319
320       next:
321        _dbus_string_free (&path);
322        start = i + 1;
323    }
324
325  if (start != len)
326    {
327      DBusString path;
328
329      if (!_dbus_string_init (&path))
330        goto oom;
331
332      if (!_dbus_string_copy_len (dirs,
333                                  start,
334                                  len - start,
335                                  &path,
336                                  0))
337        {
338          _dbus_string_free (&path);
339          goto oom;
340        }
341
342      if (!_dbus_concat_dir_and_file (&path,
343                                      &file_suffix))
344        {
345          _dbus_string_free (&path);
346          goto oom;
347        }
348
349      if (!_dbus_string_copy_data(&path, &cpath))
350        {
351          _dbus_string_free (&path);
352          goto oom;
353        }
354
355      if (!_dbus_list_append (dir_list, cpath))
356        {
357          _dbus_string_free (&path);
358          dbus_free (cpath);
359          goto oom;
360        }
361
362      _dbus_string_free (&path);
363    }
364
365  return TRUE;
366
367 oom:
368  _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL);
369  _dbus_list_clear (dir_list);
370  return FALSE;
371}
372
373/** @} */
374
375/**
376 * @addtogroup DBusString
377 *
378 * @{
379 */
380/**
381 * Appends an integer to a DBusString.
382 *
383 * @param str the string
384 * @param value the integer value
385 * @returns #FALSE if not enough memory or other failure.
386 */
387dbus_bool_t
388_dbus_string_append_int (DBusString *str,
389                         long        value)
390{
391  /* this calculation is from comp.lang.c faq */
392#define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
393  int orig_len;
394  int i;
395  char *buf;
396
397  orig_len = _dbus_string_get_length (str);
398
399  if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
400    return FALSE;
401
402  buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
403
404  snprintf (buf, MAX_LONG_LEN, "%ld", value);
405
406  i = 0;
407  while (*buf)
408    {
409      ++buf;
410      ++i;
411    }
412
413  _dbus_string_shorten (str, MAX_LONG_LEN - i);
414
415  return TRUE;
416}
417
418/**
419 * Appends an unsigned integer to a DBusString.
420 *
421 * @param str the string
422 * @param value the integer value
423 * @returns #FALSE if not enough memory or other failure.
424 */
425dbus_bool_t
426_dbus_string_append_uint (DBusString    *str,
427                          unsigned long  value)
428{
429  /* this is wrong, but definitely on the high side. */
430#define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
431  int orig_len;
432  int i;
433  char *buf;
434
435  orig_len = _dbus_string_get_length (str);
436
437  if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
438    return FALSE;
439
440  buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
441
442  snprintf (buf, MAX_ULONG_LEN, "%lu", value);
443
444  i = 0;
445  while (*buf)
446    {
447      ++buf;
448      ++i;
449    }
450
451  _dbus_string_shorten (str, MAX_ULONG_LEN - i);
452
453  return TRUE;
454}
455
456#ifdef DBUS_BUILD_TESTS
457/**
458 * Appends a double to a DBusString.
459 *
460 * @param str the string
461 * @param value the floating point value
462 * @returns #FALSE if not enough memory or other failure.
463 */
464dbus_bool_t
465_dbus_string_append_double (DBusString *str,
466                            double      value)
467{
468#define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
469  int orig_len;
470  char *buf;
471  int i;
472
473  orig_len = _dbus_string_get_length (str);
474
475  if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
476    return FALSE;
477
478  buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
479
480  snprintf (buf, MAX_LONG_LEN, "%g", value);
481
482  i = 0;
483  while (*buf)
484    {
485      ++buf;
486      ++i;
487    }
488
489  _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
490
491  return TRUE;
492}
493#endif /* DBUS_BUILD_TESTS */
494
495/**
496 * Parses an integer contained in a DBusString. Either return parameter
497 * may be #NULL if you aren't interested in it. The integer is parsed
498 * and stored in value_return. Return parameters are not initialized
499 * if the function returns #FALSE.
500 *
501 * @param str the string
502 * @param start the byte index of the start of the integer
503 * @param value_return return location of the integer value or #NULL
504 * @param end_return return location of the end of the integer, or #NULL
505 * @returns #TRUE on success
506 */
507dbus_bool_t
508_dbus_string_parse_int (const DBusString *str,
509                        int               start,
510                        long             *value_return,
511                        int              *end_return)
512{
513  long v;
514  const char *p;
515  char *end;
516
517  p = _dbus_string_get_const_data_len (str, start,
518                                       _dbus_string_get_length (str) - start);
519
520  end = NULL;
521  _dbus_set_errno_to_zero ();
522  v = strtol (p, &end, 0);
523  if (end == NULL || end == p || errno != 0)
524    return FALSE;
525
526  if (value_return)
527    *value_return = v;
528  if (end_return)
529    *end_return = start + (end - p);
530
531  return TRUE;
532}
533
534/**
535 * Parses an unsigned integer contained in a DBusString. Either return
536 * parameter may be #NULL if you aren't interested in it. The integer
537 * is parsed and stored in value_return. Return parameters are not
538 * initialized if the function returns #FALSE.
539 *
540 * @param str the string
541 * @param start the byte index of the start of the integer
542 * @param value_return return location of the integer value or #NULL
543 * @param end_return return location of the end of the integer, or #NULL
544 * @returns #TRUE on success
545 */
546dbus_bool_t
547_dbus_string_parse_uint (const DBusString *str,
548                         int               start,
549                         unsigned long    *value_return,
550                         int              *end_return)
551{
552  unsigned long v;
553  const char *p;
554  char *end;
555
556  p = _dbus_string_get_const_data_len (str, start,
557                                       _dbus_string_get_length (str) - start);
558
559  end = NULL;
560  _dbus_set_errno_to_zero ();
561  v = strtoul (p, &end, 0);
562  if (end == NULL || end == p || errno != 0)
563    return FALSE;
564
565  if (value_return)
566    *value_return = v;
567  if (end_return)
568    *end_return = start + (end - p);
569
570  return TRUE;
571}
572
573#ifdef DBUS_BUILD_TESTS
574static dbus_bool_t
575ascii_isspace (char c)
576{
577  return (c == ' ' ||
578	  c == '\f' ||
579	  c == '\n' ||
580	  c == '\r' ||
581	  c == '\t' ||
582	  c == '\v');
583}
584#endif /* DBUS_BUILD_TESTS */
585
586#ifdef DBUS_BUILD_TESTS
587static dbus_bool_t
588ascii_isdigit (char c)
589{
590  return c >= '0' && c <= '9';
591}
592#endif /* DBUS_BUILD_TESTS */
593
594#ifdef DBUS_BUILD_TESTS
595static dbus_bool_t
596ascii_isxdigit (char c)
597{
598  return (ascii_isdigit (c) ||
599	  (c >= 'a' && c <= 'f') ||
600	  (c >= 'A' && c <= 'F'));
601}
602#endif /* DBUS_BUILD_TESTS */
603
604#ifdef DBUS_BUILD_TESTS
605/* Calls strtod in a locale-independent fashion, by looking at
606 * the locale data and patching the decimal comma to a point.
607 *
608 * Relicensed from glib.
609 */
610static double
611ascii_strtod (const char *nptr,
612	      char      **endptr)
613{
614  /* FIXME: The Win32 C library's strtod() doesn't handle hex.
615   * Presumably many Unixes don't either.
616   */
617
618  char *fail_pos;
619  double val;
620  struct lconv *locale_data;
621  const char *decimal_point;
622  int decimal_point_len;
623  const char *p, *decimal_point_pos;
624  const char *end = NULL; /* Silence gcc */
625
626  fail_pos = NULL;
627
628#if HAVE_LOCALECONV
629  locale_data = localeconv ();
630  decimal_point = locale_data->decimal_point;
631#else
632  decimal_point = ".";
633#endif
634
635  decimal_point_len = strlen (decimal_point);
636  _dbus_assert (decimal_point_len != 0);
637
638  decimal_point_pos = NULL;
639  if (decimal_point[0] != '.' ||
640      decimal_point[1] != 0)
641    {
642      p = nptr;
643      /* Skip leading space */
644      while (ascii_isspace (*p))
645	p++;
646
647      /* Skip leading optional sign */
648      if (*p == '+' || *p == '-')
649	p++;
650
651      if (p[0] == '0' &&
652	  (p[1] == 'x' || p[1] == 'X'))
653	{
654	  p += 2;
655	  /* HEX - find the (optional) decimal point */
656
657	  while (ascii_isxdigit (*p))
658	    p++;
659
660	  if (*p == '.')
661	    {
662	      decimal_point_pos = p++;
663
664	      while (ascii_isxdigit (*p))
665		p++;
666
667	      if (*p == 'p' || *p == 'P')
668		p++;
669	      if (*p == '+' || *p == '-')
670		p++;
671	      while (ascii_isdigit (*p))
672		p++;
673	      end = p;
674	    }
675	}
676      else
677	{
678	  while (ascii_isdigit (*p))
679	    p++;
680
681	  if (*p == '.')
682	    {
683	      decimal_point_pos = p++;
684
685	      while (ascii_isdigit (*p))
686		p++;
687
688	      if (*p == 'e' || *p == 'E')
689		p++;
690	      if (*p == '+' || *p == '-')
691		p++;
692	      while (ascii_isdigit (*p))
693		p++;
694	      end = p;
695	    }
696	}
697      /* For the other cases, we need not convert the decimal point */
698    }
699
700  /* Set errno to zero, so that we can distinguish zero results
701     and underflows */
702  _dbus_set_errno_to_zero ();
703
704  if (decimal_point_pos)
705    {
706      char *copy, *c;
707
708      /* We need to convert the '.' to the locale specific decimal point */
709      copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
710
711      c = copy;
712      memcpy (c, nptr, decimal_point_pos - nptr);
713      c += decimal_point_pos - nptr;
714      memcpy (c, decimal_point, decimal_point_len);
715      c += decimal_point_len;
716      memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
717      c += end - (decimal_point_pos + 1);
718      *c = 0;
719
720      val = strtod (copy, &fail_pos);
721
722      if (fail_pos)
723	{
724	  if (fail_pos > decimal_point_pos)
725	    fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
726	  else
727	    fail_pos = (char *)nptr + (fail_pos - copy);
728	}
729
730      dbus_free (copy);
731
732    }
733  else
734    val = strtod (nptr, &fail_pos);
735
736  if (endptr)
737    *endptr = fail_pos;
738
739  return val;
740}
741#endif /* DBUS_BUILD_TESTS */
742
743#ifdef DBUS_BUILD_TESTS
744/**
745 * Parses a floating point number contained in a DBusString. Either
746 * return parameter may be #NULL if you aren't interested in it. The
747 * integer is parsed and stored in value_return. Return parameters are
748 * not initialized if the function returns #FALSE.
749 *
750 * @param str the string
751 * @param start the byte index of the start of the float
752 * @param value_return return location of the float value or #NULL
753 * @param end_return return location of the end of the float, or #NULL
754 * @returns #TRUE on success
755 */
756dbus_bool_t
757_dbus_string_parse_double (const DBusString *str,
758                           int               start,
759                           double           *value_return,
760                           int              *end_return)
761{
762  double v;
763  const char *p;
764  char *end;
765
766  p = _dbus_string_get_const_data_len (str, start,
767                                       _dbus_string_get_length (str) - start);
768
769  /* parsing hex works on linux but isn't portable, so intercept it
770   * here to get uniform behavior.
771   */
772  if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
773    return FALSE;
774
775  end = NULL;
776  _dbus_set_errno_to_zero ();
777  v = ascii_strtod (p, &end);
778  if (end == NULL || end == p || errno != 0)
779    return FALSE;
780
781  if (value_return)
782    *value_return = v;
783  if (end_return)
784    *end_return = start + (end - p);
785
786  return TRUE;
787}
788#endif /* DBUS_BUILD_TESTS */
789
790/** @} */ /* DBusString group */
791
792/**
793 * @addtogroup DBusInternalsUtils
794 * @{
795 */
796
797void
798_dbus_generate_pseudorandom_bytes_buffer (char *buffer,
799                                          int   n_bytes)
800{
801  long tv_usec;
802  int i;
803
804  /* fall back to pseudorandom */
805  _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
806                 n_bytes);
807
808  _dbus_get_current_time (NULL, &tv_usec);
809  srand (tv_usec);
810
811  i = 0;
812  while (i < n_bytes)
813    {
814      double r;
815      unsigned int b;
816
817      r = rand ();
818      b = (r / (double) RAND_MAX) * 255.0;
819
820      buffer[i] = b;
821
822      ++i;
823    }
824}
825
826/**
827 * Fills n_bytes of the given buffer with random bytes.
828 *
829 * @param buffer an allocated buffer
830 * @param n_bytes the number of bytes in buffer to write to
831 */
832void
833_dbus_generate_random_bytes_buffer (char *buffer,
834                                    int   n_bytes)
835{
836  DBusString str;
837
838  if (!_dbus_string_init (&str))
839    {
840      _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
841      return;
842    }
843
844  if (!_dbus_generate_random_bytes (&str, n_bytes))
845    {
846      _dbus_string_free (&str);
847      _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
848      return;
849    }
850
851  _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
852
853  _dbus_string_free (&str);
854}
855
856/**
857 * Generates the given number of random bytes, where the bytes are
858 * chosen from the alphanumeric ASCII subset.
859 *
860 * @param str the string
861 * @param n_bytes the number of random ASCII bytes to append to string
862 * @returns #TRUE on success, #FALSE if no memory or other failure
863 */
864dbus_bool_t
865_dbus_generate_random_ascii (DBusString *str,
866                             int         n_bytes)
867{
868  static const char letters[] =
869    "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
870  int i;
871  int len;
872
873  if (!_dbus_generate_random_bytes (str, n_bytes))
874    return FALSE;
875
876  len = _dbus_string_get_length (str);
877  i = len - n_bytes;
878  while (i < len)
879    {
880      _dbus_string_set_byte (str, i,
881                             letters[_dbus_string_get_byte (str, i) %
882                                     (sizeof (letters) - 1)]);
883
884      ++i;
885    }
886
887  _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
888                                             n_bytes));
889
890  return TRUE;
891}
892
893/**
894 * Converts a UNIX errno, or Windows errno or WinSock error value into
895 * a #DBusError name.
896 *
897 * @todo should cover more errnos, specifically those
898 * from open().
899 *
900 * @param error_number the errno.
901 * @returns an error name
902 */
903const char*
904_dbus_error_from_errno (int error_number)
905{
906  switch (error_number)
907    {
908    case 0:
909      return DBUS_ERROR_FAILED;
910
911#ifdef EPROTONOSUPPORT
912    case EPROTONOSUPPORT:
913      return DBUS_ERROR_NOT_SUPPORTED;
914#endif
915#ifdef WSAEPROTONOSUPPORT
916    case WSAEPROTONOSUPPORT:
917      return DBUS_ERROR_NOT_SUPPORTED;
918#endif
919#ifdef EAFNOSUPPORT
920    case EAFNOSUPPORT:
921      return DBUS_ERROR_NOT_SUPPORTED;
922#endif
923#ifdef WSAEAFNOSUPPORT
924    case WSAEAFNOSUPPORT:
925      return DBUS_ERROR_NOT_SUPPORTED;
926#endif
927#ifdef ENFILE
928    case ENFILE:
929      return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
930#endif
931#ifdef EMFILE
932    case EMFILE:
933      return DBUS_ERROR_LIMITS_EXCEEDED;
934#endif
935#ifdef EACCES
936    case EACCES:
937      return DBUS_ERROR_ACCESS_DENIED;
938#endif
939#ifdef EPERM
940    case EPERM:
941      return DBUS_ERROR_ACCESS_DENIED;
942#endif
943#ifdef ENOBUFS
944    case ENOBUFS:
945      return DBUS_ERROR_NO_MEMORY;
946#endif
947#ifdef ENOMEM
948    case ENOMEM:
949      return DBUS_ERROR_NO_MEMORY;
950#endif
951#ifdef ECONNREFUSED
952    case ECONNREFUSED:
953      return DBUS_ERROR_NO_SERVER;
954#endif
955#ifdef WSAECONNREFUSED
956    case WSAECONNREFUSED:
957      return DBUS_ERROR_NO_SERVER;
958#endif
959#ifdef ETIMEDOUT
960    case ETIMEDOUT:
961      return DBUS_ERROR_TIMEOUT;
962#endif
963#ifdef WSAETIMEDOUT
964    case WSAETIMEDOUT:
965      return DBUS_ERROR_TIMEOUT;
966#endif
967#ifdef ENETUNREACH
968    case ENETUNREACH:
969      return DBUS_ERROR_NO_NETWORK;
970#endif
971#ifdef WSAENETUNREACH
972    case WSAENETUNREACH:
973      return DBUS_ERROR_NO_NETWORK;
974#endif
975#ifdef EADDRINUSE
976    case EADDRINUSE:
977      return DBUS_ERROR_ADDRESS_IN_USE;
978#endif
979#ifdef WSAEADDRINUSE
980    case WSAEADDRINUSE:
981      return DBUS_ERROR_ADDRESS_IN_USE;
982#endif
983#ifdef EEXIST
984    case EEXIST:
985      return DBUS_ERROR_FILE_EXISTS;
986#endif
987#ifdef ENOENT
988    case ENOENT:
989      return DBUS_ERROR_FILE_NOT_FOUND;
990#endif
991    }
992
993  return DBUS_ERROR_FAILED;
994}
995
996/**
997 * Converts the current system errno value into a #DBusError name.
998 *
999 * @returns an error name
1000 */
1001const char*
1002_dbus_error_from_system_errno (void)
1003{
1004  return _dbus_error_from_errno (errno);
1005}
1006
1007/**
1008 * Assign 0 to the global errno variable
1009 */
1010void
1011_dbus_set_errno_to_zero (void)
1012{
1013#ifdef DBUS_WINCE
1014  SetLastError (0);
1015#else
1016  errno = 0;
1017#endif
1018}
1019
1020/**
1021 * See if errno is set
1022 * @returns #TRUE if errno is not 0
1023 */
1024dbus_bool_t
1025_dbus_get_is_errno_nonzero (void)
1026{
1027  return errno != 0;
1028}
1029
1030/**
1031 * See if errno is ENOMEM
1032 * @returns #TRUE if errno == ENOMEM
1033 */
1034dbus_bool_t
1035_dbus_get_is_errno_enomem (void)
1036{
1037  return errno == ENOMEM;
1038}
1039
1040/**
1041 * See if errno is EINTR
1042 * @returns #TRUE if errno == EINTR
1043 */
1044dbus_bool_t
1045_dbus_get_is_errno_eintr (void)
1046{
1047  return errno == EINTR;
1048}
1049
1050/**
1051 * See if errno is EPIPE
1052 * @returns #TRUE if errno == EPIPE
1053 */
1054dbus_bool_t
1055_dbus_get_is_errno_epipe (void)
1056{
1057  return errno == EPIPE;
1058}
1059
1060/**
1061 * Get error message from errno
1062 * @returns _dbus_strerror(errno)
1063 */
1064const char*
1065_dbus_strerror_from_errno (void)
1066{
1067  return _dbus_strerror (errno);
1068}
1069
1070/** @} end of sysdeps */
1071
1072/* tests in dbus-sysdeps-util.c */
1073