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