2006-09-30 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / 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  * @addtogroup DBusInternalsUtils
54  * @{
55  */
56 #ifndef DBUS_DISABLE_ASSERT
57 /**
58  * Aborts the program with SIGABRT (dumping core).
59  */
60 void
61 _dbus_abort (void)
62 {
63 #ifdef DBUS_ENABLE_VERBOSE_MODE
64   const char *s;
65   s = _dbus_getenv ("DBUS_PRINT_BACKTRACE");
66   if (s && *s)
67     _dbus_print_backtrace ();
68 #endif
69   abort ();
70   _dbus_exit (1); /* in case someone manages to ignore SIGABRT */
71 }
72 #endif
73
74 /**
75  * Wrapper for setenv(). If the value is #NULL, unsets
76  * the environment variable.
77  *
78  * There is an unfixable memleak in that it is unsafe to
79  * free memory malloced for use with setenv. This is because
80  * we can not rely on internal implementation details of
81  * the underlying libc library.
82  *
83  * @param varname name of environment variable
84  * @param value value of environment variable
85  * @returns #TRUE on success.
86  */
87 dbus_bool_t
88 _dbus_setenv (const char *varname,
89               const char *value)
90 {
91   _dbus_assert (varname != NULL);
92   
93   if (value == NULL)
94     {
95 #ifdef HAVE_UNSETENV
96       unsetenv (varname);
97       return TRUE;
98 #else
99       char *putenv_value;
100       size_t len;
101
102       len = strlen (varname);
103
104       /* Use system malloc to avoid memleaks that dbus_malloc
105        * will get upset about.
106        */
107       
108       putenv_value = malloc (len + 1);
109       if (putenv_value == NULL)
110         return FALSE;
111
112       strcpy (putenv_value, varname);
113       
114       return (putenv (putenv_value) == 0);
115 #endif
116     }
117   else
118     {
119 #ifdef HAVE_SETENV
120       return (setenv (varname, value, TRUE) == 0);
121 #else
122       char *putenv_value;
123       size_t len;
124       size_t varname_len;
125       size_t value_len;
126
127       varname_len = strlen (varname);
128       value_len = strlen (value);
129       
130       len = varname_len + value_len + 1 /* '=' */ ;
131
132       /* Use system malloc to avoid memleaks that dbus_malloc
133        * will get upset about.
134        */
135       
136       putenv_value = malloc (len + 1);
137       if (putenv_value == NULL)
138         return FALSE;
139
140       strcpy (putenv_value, varname);
141       strcpy (putenv_value + varname_len, "=");
142       strcpy (putenv_value + varname_len + 1, value);
143       
144       return (putenv (putenv_value) == 0);
145 #endif
146     }
147 }
148
149 /**
150  * Wrapper for getenv().
151  *
152  * @param varname name of environment variable
153  * @returns value of environment variable or #NULL if unset
154  */
155 const char*
156 _dbus_getenv (const char *varname)
157 {  
158   return getenv (varname);
159 }
160
161 /** @} */
162
163 /**
164  * @addtogroup DBusString
165  *
166  * @{
167  */
168 /**
169  * Appends an integer to a DBusString.
170  * 
171  * @param str the string
172  * @param value the integer value
173  * @returns #FALSE if not enough memory or other failure.
174  */
175 dbus_bool_t
176 _dbus_string_append_int (DBusString *str,
177                          long        value)
178 {
179   /* this calculation is from comp.lang.c faq */
180 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
181   int orig_len;
182   int i;
183   char *buf;
184   
185   orig_len = _dbus_string_get_length (str);
186
187   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
188     return FALSE;
189
190   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
191
192   snprintf (buf, MAX_LONG_LEN, "%ld", value);
193
194   i = 0;
195   while (*buf)
196     {
197       ++buf;
198       ++i;
199     }
200   
201   _dbus_string_shorten (str, MAX_LONG_LEN - i);
202   
203   return TRUE;
204 }
205
206 /**
207  * Appends an unsigned integer to a DBusString.
208  * 
209  * @param str the string
210  * @param value the integer value
211  * @returns #FALSE if not enough memory or other failure.
212  */
213 dbus_bool_t
214 _dbus_string_append_uint (DBusString    *str,
215                           unsigned long  value)
216 {
217   /* this is wrong, but definitely on the high side. */
218 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
219   int orig_len;
220   int i;
221   char *buf;
222   
223   orig_len = _dbus_string_get_length (str);
224
225   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
226     return FALSE;
227
228   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
229
230   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
231
232   i = 0;
233   while (*buf)
234     {
235       ++buf;
236       ++i;
237     }
238   
239   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
240   
241   return TRUE;
242 }
243
244 #ifdef DBUS_BUILD_TESTS
245 /**
246  * Appends a double to a DBusString.
247  * 
248  * @param str the string
249  * @param value the floating point value
250  * @returns #FALSE if not enough memory or other failure.
251  */
252 dbus_bool_t
253 _dbus_string_append_double (DBusString *str,
254                             double      value)
255 {
256 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
257   int orig_len;
258   char *buf;
259   int i;
260   
261   orig_len = _dbus_string_get_length (str);
262
263   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
264     return FALSE;
265
266   buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
267
268   snprintf (buf, MAX_LONG_LEN, "%g", value);
269
270   i = 0;
271   while (*buf)
272     {
273       ++buf;
274       ++i;
275     }
276   
277   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
278   
279   return TRUE;
280 }
281 #endif /* DBUS_BUILD_TESTS */
282
283 /**
284  * Parses an integer contained in a DBusString. Either return parameter
285  * may be #NULL if you aren't interested in it. The integer is parsed
286  * and stored in value_return. Return parameters are not initialized
287  * if the function returns #FALSE.
288  *
289  * @param str the string
290  * @param start the byte index of the start of the integer
291  * @param value_return return location of the integer value or #NULL
292  * @param end_return return location of the end of the integer, or #NULL
293  * @returns #TRUE on success
294  */
295 dbus_bool_t
296 _dbus_string_parse_int (const DBusString *str,
297                         int               start,
298                         long             *value_return,
299                         int              *end_return)
300 {
301   long v;
302   const char *p;
303   char *end;
304
305   p = _dbus_string_get_const_data_len (str, start,
306                                        _dbus_string_get_length (str) - start);
307
308   end = NULL;
309   errno = 0;
310   v = strtol (p, &end, 0);
311   if (end == NULL || end == p || errno != 0)
312     return FALSE;
313
314   if (value_return)
315     *value_return = v;
316   if (end_return)
317     *end_return = start + (end - p);
318
319   return TRUE;
320 }
321
322 /**
323  * Parses an unsigned integer contained in a DBusString. Either return
324  * parameter may be #NULL if you aren't interested in it. The integer
325  * is parsed and stored in value_return. Return parameters are not
326  * initialized if the function returns #FALSE.
327  *
328  * @param str the string
329  * @param start the byte index of the start of the integer
330  * @param value_return return location of the integer value or #NULL
331  * @param end_return return location of the end of the integer, or #NULL
332  * @returns #TRUE on success
333  */
334 dbus_bool_t
335 _dbus_string_parse_uint (const DBusString *str,
336                          int               start,
337                          unsigned long    *value_return,
338                          int              *end_return)
339 {
340   unsigned long v;
341   const char *p;
342   char *end;
343
344   p = _dbus_string_get_const_data_len (str, start,
345                                        _dbus_string_get_length (str) - start);
346
347   end = NULL;
348   errno = 0;
349   v = strtoul (p, &end, 0);
350   if (end == NULL || end == p || errno != 0)
351     return FALSE;
352
353   if (value_return)
354     *value_return = v;
355   if (end_return)
356     *end_return = start + (end - p);
357
358   return TRUE;
359 }
360
361 #ifdef DBUS_BUILD_TESTS
362 static dbus_bool_t
363 ascii_isspace (char c)
364 {
365   return (c == ' ' ||
366           c == '\f' ||
367           c == '\n' ||
368           c == '\r' ||
369           c == '\t' ||
370           c == '\v');
371 }
372 #endif /* DBUS_BUILD_TESTS */
373
374 #ifdef DBUS_BUILD_TESTS
375 static dbus_bool_t
376 ascii_isdigit (char c)
377 {
378   return c >= '0' && c <= '9';
379 }
380 #endif /* DBUS_BUILD_TESTS */
381
382 #ifdef DBUS_BUILD_TESTS
383 static dbus_bool_t
384 ascii_isxdigit (char c)
385 {
386   return (ascii_isdigit (c) ||
387           (c >= 'a' && c <= 'f') ||
388           (c >= 'A' && c <= 'F'));
389 }
390 #endif /* DBUS_BUILD_TESTS */
391
392 #ifdef DBUS_BUILD_TESTS
393 /* Calls strtod in a locale-independent fashion, by looking at
394  * the locale data and patching the decimal comma to a point.
395  *
396  * Relicensed from glib.
397  */
398 static double
399 ascii_strtod (const char *nptr,
400               char      **endptr)
401 {
402   char *fail_pos;
403   double val;
404   struct lconv *locale_data;
405   const char *decimal_point;
406   int decimal_point_len;
407   const char *p, *decimal_point_pos;
408   const char *end = NULL; /* Silence gcc */
409
410   fail_pos = NULL;
411
412   locale_data = localeconv ();
413   decimal_point = locale_data->decimal_point;
414   decimal_point_len = strlen (decimal_point);
415
416   _dbus_assert (decimal_point_len != 0);
417   
418   decimal_point_pos = NULL;
419   if (decimal_point[0] != '.' ||
420       decimal_point[1] != 0)
421     {
422       p = nptr;
423       /* Skip leading space */
424       while (ascii_isspace (*p))
425         p++;
426       
427       /* Skip leading optional sign */
428       if (*p == '+' || *p == '-')
429         p++;
430       
431       if (p[0] == '0' &&
432           (p[1] == 'x' || p[1] == 'X'))
433         {
434           p += 2;
435           /* HEX - find the (optional) decimal point */
436           
437           while (ascii_isxdigit (*p))
438             p++;
439           
440           if (*p == '.')
441             {
442               decimal_point_pos = p++;
443               
444               while (ascii_isxdigit (*p))
445                 p++;
446               
447               if (*p == 'p' || *p == 'P')
448                 p++;
449               if (*p == '+' || *p == '-')
450                 p++;
451               while (ascii_isdigit (*p))
452                 p++;
453               end = p;
454             }
455         }
456       else
457         {
458           while (ascii_isdigit (*p))
459             p++;
460           
461           if (*p == '.')
462             {
463               decimal_point_pos = p++;
464               
465               while (ascii_isdigit (*p))
466                 p++;
467               
468               if (*p == 'e' || *p == 'E')
469                 p++;
470               if (*p == '+' || *p == '-')
471                 p++;
472               while (ascii_isdigit (*p))
473                 p++;
474               end = p;
475             }
476         }
477       /* For the other cases, we need not convert the decimal point */
478     }
479
480   /* Set errno to zero, so that we can distinguish zero results
481      and underflows */
482   errno = 0;
483   
484   if (decimal_point_pos)
485     {
486       char *copy, *c;
487
488       /* We need to convert the '.' to the locale specific decimal point */
489       copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
490       
491       c = copy;
492       memcpy (c, nptr, decimal_point_pos - nptr);
493       c += decimal_point_pos - nptr;
494       memcpy (c, decimal_point, decimal_point_len);
495       c += decimal_point_len;
496       memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
497       c += end - (decimal_point_pos + 1);
498       *c = 0;
499
500       val = strtod (copy, &fail_pos);
501
502       if (fail_pos)
503         {
504           if (fail_pos > decimal_point_pos)
505             fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
506           else
507             fail_pos = (char *)nptr + (fail_pos - copy);
508         }
509       
510       dbus_free (copy);
511           
512     }
513   else
514     val = strtod (nptr, &fail_pos);
515
516   if (endptr)
517     *endptr = fail_pos;
518   
519   return val;
520 }
521 #endif /* DBUS_BUILD_TESTS */
522
523 #ifdef DBUS_BUILD_TESTS
524 /**
525  * Parses a floating point number contained in a DBusString. Either
526  * return parameter may be #NULL if you aren't interested in it. The
527  * integer is parsed and stored in value_return. Return parameters are
528  * not initialized if the function returns #FALSE.
529  *
530  * @param str the string
531  * @param start the byte index of the start of the float
532  * @param value_return return location of the float value or #NULL
533  * @param end_return return location of the end of the float, or #NULL
534  * @returns #TRUE on success
535  */
536 dbus_bool_t
537 _dbus_string_parse_double (const DBusString *str,
538                            int               start,
539                            double           *value_return,
540                            int              *end_return)
541 {
542   double v;
543   const char *p;
544   char *end;
545
546   p = _dbus_string_get_const_data_len (str, start,
547                                        _dbus_string_get_length (str) - start);
548
549   end = NULL;
550   errno = 0;
551   v = ascii_strtod (p, &end);
552   if (end == NULL || end == p || errno != 0)
553     return FALSE;
554
555   if (value_return)
556     *value_return = v;
557   if (end_return)
558     *end_return = start + (end - p);
559
560   return TRUE;
561 }
562 #endif /* DBUS_BUILD_TESTS */
563
564 /** @} */ /* DBusString group */
565
566 /**
567  * @addtogroup DBusInternalsUtils
568  * @{
569  */
570
571 /**
572  * Frees the members of info
573  * (but not info itself)
574  * @param info the user info struct
575  */
576 void
577 _dbus_user_info_free (DBusUserInfo *info)
578 {
579   dbus_free (info->group_ids);
580   dbus_free (info->username);
581   dbus_free (info->homedir);
582 }
583
584 /**
585  * Frees the members of info (but not info itself).
586  *
587  * @param info the group info
588  */
589 void
590 _dbus_group_info_free (DBusGroupInfo    *info)
591 {
592   dbus_free (info->groupname);
593 }
594
595 /**
596  * Sets fields in DBusCredentials to DBUS_PID_UNSET,
597  * DBUS_UID_UNSET, DBUS_GID_UNSET.
598  *
599  * @param credentials the credentials object to fill in
600  */
601 void
602 _dbus_credentials_clear (DBusCredentials *credentials)
603 {
604   credentials->pid = DBUS_PID_UNSET;
605   credentials->uid = DBUS_UID_UNSET;
606   credentials->gid = DBUS_GID_UNSET;
607 }
608
609 /**
610  * Checks whether the provided_credentials are allowed to log in
611  * as the expected_credentials.
612  *
613  * @param expected_credentials credentials we're trying to log in as
614  * @param provided_credentials credentials we have
615  * @returns #TRUE if we can log in
616  */
617 dbus_bool_t
618 _dbus_credentials_match (const DBusCredentials *expected_credentials,
619                          const DBusCredentials *provided_credentials)
620 {
621   if (provided_credentials->uid == DBUS_UID_UNSET)
622     return FALSE;
623   else if (expected_credentials->uid == DBUS_UID_UNSET)
624     return FALSE;
625   else if (provided_credentials->uid == 0)
626     return TRUE;
627   else if (provided_credentials->uid == expected_credentials->uid)
628     return TRUE;
629   else
630     return FALSE;
631 }
632
633 _DBUS_DEFINE_GLOBAL_LOCK (atomic);
634
635 #ifdef DBUS_USE_ATOMIC_INT_486
636 /* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */
637 /* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */
638 static inline dbus_int32_t
639 atomic_exchange_and_add (DBusAtomic            *atomic,
640                          volatile dbus_int32_t  val)
641 {
642   register dbus_int32_t result;
643
644   __asm__ __volatile__ ("lock; xaddl %0,%1"
645                         : "=r" (result), "=m" (atomic->value)
646                         : "0" (val), "m" (atomic->value));
647   return result;
648 }
649 #endif
650
651 /**
652  * Atomically increments an integer
653  *
654  * @param atomic pointer to the integer to increment
655  * @returns the value before incrementing
656  *
657  * @todo implement arch-specific faster atomic ops
658  */
659 dbus_int32_t
660 _dbus_atomic_inc (DBusAtomic *atomic)
661 {
662 #ifdef DBUS_USE_ATOMIC_INT_486
663   return atomic_exchange_and_add (atomic, 1);
664 #else
665   dbus_int32_t res;
666   _DBUS_LOCK (atomic);
667   res = atomic->value;
668   atomic->value += 1;
669   _DBUS_UNLOCK (atomic);
670   return res;
671 #endif
672 }
673
674 /**
675  * Atomically decrement an integer
676  *
677  * @param atomic pointer to the integer to decrement
678  * @returns the value before decrementing
679  *
680  * @todo implement arch-specific faster atomic ops
681  */
682 dbus_int32_t
683 _dbus_atomic_dec (DBusAtomic *atomic)
684 {
685 #ifdef DBUS_USE_ATOMIC_INT_486
686   return atomic_exchange_and_add (atomic, -1);
687 #else
688   dbus_int32_t res;
689   
690   _DBUS_LOCK (atomic);
691   res = atomic->value;
692   atomic->value -= 1;
693   _DBUS_UNLOCK (atomic);
694   return res;
695 #endif
696 }
697
698 void
699 _dbus_generate_pseudorandom_bytes_buffer (char *buffer,
700                                           int   n_bytes)
701 {
702   long tv_usec;
703   int i;
704   
705   /* fall back to pseudorandom */
706   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
707                  n_bytes);
708   
709   _dbus_get_current_time (NULL, &tv_usec);
710   srand (tv_usec);
711   
712   i = 0;
713   while (i < n_bytes)
714     {
715       double r;
716       unsigned int b;
717           
718       r = rand ();
719       b = (r / (double) RAND_MAX) * 255.0;
720
721       buffer[i] = b;
722
723       ++i;
724     }
725 }
726
727 /**
728  * Fills n_bytes of the given buffer with random bytes.
729  *
730  * @param buffer an allocated buffer
731  * @param n_bytes the number of bytes in buffer to write to
732  */
733 void
734 _dbus_generate_random_bytes_buffer (char *buffer,
735                                     int   n_bytes)
736 {
737   DBusString str;
738
739   if (!_dbus_string_init (&str))
740     {
741       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
742       return;
743     }
744
745   if (!_dbus_generate_random_bytes (&str, n_bytes))
746     {
747       _dbus_string_free (&str);
748       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
749       return;
750     }
751
752   _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
753
754   _dbus_string_free (&str);
755 }
756
757 /**
758  * Generates the given number of random bytes, where the bytes are
759  * chosen from the alphanumeric ASCII subset.
760  *
761  * @param str the string
762  * @param n_bytes the number of random ASCII bytes to append to string
763  * @returns #TRUE on success, #FALSE if no memory or other failure
764  */
765 dbus_bool_t
766 _dbus_generate_random_ascii (DBusString *str,
767                              int         n_bytes)
768 {
769   static const char letters[] =
770     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
771   int i;
772   int len;
773   
774   if (!_dbus_generate_random_bytes (str, n_bytes))
775     return FALSE;
776   
777   len = _dbus_string_get_length (str);
778   i = len - n_bytes;
779   while (i < len)
780     {
781       _dbus_string_set_byte (str, i,
782                              letters[_dbus_string_get_byte (str, i) %
783                                      (sizeof (letters) - 1)]);
784
785       ++i;
786     }
787
788   _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
789                                              n_bytes));
790
791   return TRUE;
792 }
793
794 /**
795  * Gets a UID from a UID string.
796  *
797  * @param uid_str the UID in string form
798  * @param uid UID to fill in
799  * @returns #TRUE if successfully filled in UID
800  */
801 dbus_bool_t
802 _dbus_parse_uid (const DBusString      *uid_str,
803                  dbus_uid_t            *uid)
804 {
805   int end;
806   long val;
807   
808   if (_dbus_string_get_length (uid_str) == 0)
809     {
810       _dbus_verbose ("UID string was zero length\n");
811       return FALSE;
812     }
813
814   val = -1;
815   end = 0;
816   if (!_dbus_string_parse_int (uid_str, 0, &val,
817                                &end))
818     {
819       _dbus_verbose ("could not parse string as a UID\n");
820       return FALSE;
821     }
822   
823   if (end != _dbus_string_get_length (uid_str))
824     {
825       _dbus_verbose ("string contained trailing stuff after UID\n");
826       return FALSE;
827     }
828
829   *uid = val;
830
831   return TRUE;
832 }
833
834 /**
835  * Converts a UNIX or Windows errno
836  * into a #DBusError name.
837  *
838  * @todo should cover more errnos, specifically those
839  * from open().
840  * 
841  * @param error_number the errno.
842  * @returns an error name
843  */
844 const char*
845 _dbus_error_from_errno (int error_number)
846 {
847   switch (error_number)
848     {
849     case 0:
850       return DBUS_ERROR_FAILED;
851       
852 #ifdef EPROTONOSUPPORT
853     case EPROTONOSUPPORT:
854       return DBUS_ERROR_NOT_SUPPORTED;
855 #endif
856 #ifdef EAFNOSUPPORT
857     case EAFNOSUPPORT:
858       return DBUS_ERROR_NOT_SUPPORTED;
859 #endif
860 #ifdef ENFILE
861     case ENFILE:
862       return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
863 #endif
864 #ifdef EMFILE
865     case EMFILE:
866       return DBUS_ERROR_LIMITS_EXCEEDED;
867 #endif
868 #ifdef EACCES
869     case EACCES:
870       return DBUS_ERROR_ACCESS_DENIED;
871 #endif
872 #ifdef EPERM
873     case EPERM:
874       return DBUS_ERROR_ACCESS_DENIED;
875 #endif
876 #ifdef ENOBUFS
877     case ENOBUFS:
878       return DBUS_ERROR_NO_MEMORY;
879 #endif
880 #ifdef ENOMEM
881     case ENOMEM:
882       return DBUS_ERROR_NO_MEMORY;
883 #endif
884 #ifdef EINVAL
885     case EINVAL:
886       return DBUS_ERROR_FAILED;
887 #endif
888 #ifdef EBADF
889     case EBADF:
890       return DBUS_ERROR_FAILED;
891 #endif
892 #ifdef EFAULT
893     case EFAULT:
894       return DBUS_ERROR_FAILED;
895 #endif
896 #ifdef ENOTSOCK
897     case ENOTSOCK:
898       return DBUS_ERROR_FAILED;
899 #endif
900 #ifdef EISCONN
901     case EISCONN:
902       return DBUS_ERROR_FAILED;
903 #endif
904 #ifdef ECONNREFUSED
905     case ECONNREFUSED:
906       return DBUS_ERROR_NO_SERVER;
907 #endif
908 #ifdef ETIMEDOUT
909     case ETIMEDOUT:
910       return DBUS_ERROR_TIMEOUT;
911 #endif
912 #ifdef ENETUNREACH
913     case ENETUNREACH:
914       return DBUS_ERROR_NO_NETWORK;
915 #endif
916 #ifdef EADDRINUSE
917     case EADDRINUSE:
918       return DBUS_ERROR_ADDRESS_IN_USE;
919 #endif
920 #ifdef EEXIST
921     case EEXIST:
922       return DBUS_ERROR_FILE_EXISTS;
923 #endif
924 #ifdef ENOENT
925     case ENOENT:
926       return DBUS_ERROR_FILE_NOT_FOUND;
927 #endif
928     }
929
930   return DBUS_ERROR_FAILED;
931 }
932
933 /** @} end of sysdeps */
934
935 /* tests in dbus-sysdeps-util.c */