Merge branch 'master' of ssh://git.freedesktop.org/git/dbus/dbus
[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   dbus_bool_t rc = TRUE;
189
190 #ifdef HAVE_CLEARENV
191   if (clearenv () != 0)
192      rc = FALSE;
193 #else
194   extern char **environ;
195
196   if (environ != NULL)
197     environ[0] = NULL;
198 #endif
199
200   return rc;
201 }
202
203 /*
204  * init a pipe instance.
205  *
206  * @param pipe the pipe
207  * @param fd the file descriptor to init from 
208  */
209 void
210 _dbus_pipe_init (DBusPipe *pipe,
211                  int       fd)
212 {
213   pipe->fd_or_handle = fd;
214 }
215
216 /**
217  * init a pipe with stdout
218  *
219  * @param pipe the pipe
220  */
221 void
222 _dbus_pipe_init_stdout (DBusPipe *pipe)
223 {
224   _dbus_pipe_init (pipe, 1);
225 }
226
227 /**
228  * check if a pipe is valid; pipes can be set invalid, similar to
229  * a -1 file descriptor.
230  *
231  * @param pipe the pipe instance
232  * @returns #FALSE if pipe is not valid
233  */
234 dbus_bool_t
235 _dbus_pipe_is_valid(DBusPipe *pipe)
236 {
237   return pipe->fd_or_handle >= 0;
238 }
239
240 /**
241  * Check if a pipe is stdout or stderr.
242  *
243  * @param pipe the pipe instance
244  * @returns #TRUE if pipe is one of the standard out/err channels
245  */
246 dbus_bool_t
247 _dbus_pipe_is_stdout_or_stderr (DBusPipe *pipe)
248 {
249   return pipe->fd_or_handle == 1 || pipe->fd_or_handle == 2;
250 }
251
252 /**
253  * Initializes a pipe to an invalid value.
254  * @param pipe the pipe
255  */
256 void
257 _dbus_pipe_invalidate (DBusPipe *pipe)
258 {
259   pipe->fd_or_handle = -1;
260 }
261
262 /**
263  * Split paths into a list of char strings
264  * 
265  * @param dirs string with pathes 
266  * @param suffix string concated to each path in dirs
267  * @param dir_list contains a list of splitted pathes
268  * return #TRUE is pathes could be splittes,#FALSE in oom case 
269  */
270 dbus_bool_t
271 _dbus_split_paths_and_append (DBusString *dirs, 
272                               const char *suffix, 
273                               DBusList  **dir_list)
274 {
275    int start;
276    int i;
277    int len;
278    char *cpath;
279    DBusString file_suffix;
280
281    start = 0;
282    i = 0;
283
284    _dbus_string_init_const (&file_suffix, suffix);
285
286    len = _dbus_string_get_length (dirs);
287
288    while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i))
289      {
290        DBusString path;
291
292        if (!_dbus_string_init (&path))
293           goto oom;
294
295        if (!_dbus_string_copy_len (dirs,
296                                    start,
297                                    i - start,
298                                    &path,
299                                    0))
300           {
301             _dbus_string_free (&path);
302             goto oom;
303           }
304
305         _dbus_string_chop_white (&path);
306
307         /* check for an empty path */
308         if (_dbus_string_get_length (&path) == 0)
309           goto next;
310
311         if (!_dbus_concat_dir_and_file (&path,
312                                         &file_suffix))
313           {
314             _dbus_string_free (&path);
315             goto oom;
316           }
317
318         if (!_dbus_string_copy_data(&path, &cpath))
319           {
320             _dbus_string_free (&path);
321             goto oom;
322           }
323
324         if (!_dbus_list_append (dir_list, cpath))
325           {
326             _dbus_string_free (&path);              
327             dbus_free (cpath);
328             goto oom;
329           }
330
331        next:
332         _dbus_string_free (&path);
333         start = i + 1;
334     } 
335       
336   if (start != len)
337     { 
338       DBusString path;
339
340       if (!_dbus_string_init (&path))
341         goto oom;
342
343       if (!_dbus_string_copy_len (dirs,
344                                   start,
345                                   len - start,
346                                   &path,
347                                   0))
348         {
349           _dbus_string_free (&path);
350           goto oom;
351         }
352
353       if (!_dbus_concat_dir_and_file (&path,
354                                       &file_suffix))
355         {
356           _dbus_string_free (&path);
357           goto oom;
358         }
359
360       if (!_dbus_string_copy_data(&path, &cpath))
361         {
362           _dbus_string_free (&path);
363           goto oom;
364         }
365
366       if (!_dbus_list_append (dir_list, cpath))
367         {
368           _dbus_string_free (&path);              
369           dbus_free (cpath);
370           goto oom;
371         }
372
373       _dbus_string_free (&path); 
374     }
375
376   return TRUE;
377
378  oom:
379   _dbus_list_foreach (dir_list, (DBusForeachFunction)dbus_free, NULL); 
380   _dbus_list_clear (dir_list);
381   return FALSE;
382 }
383
384 /** @} */
385
386 /**
387  * @addtogroup DBusString
388  *
389  * @{
390  */
391 /**
392  * Appends an integer to a DBusString.
393  * 
394  * @param str the string
395  * @param value the integer value
396  * @returns #FALSE if not enough memory or other failure.
397  */
398 dbus_bool_t
399 _dbus_string_append_int (DBusString *str,
400                          long        value)
401 {
402   /* this calculation is from comp.lang.c faq */
403 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
404   int orig_len;
405   int i;
406   char *buf;
407   
408   orig_len = _dbus_string_get_length (str);
409
410   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
411     return FALSE;
412
413   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
414
415   snprintf (buf, MAX_LONG_LEN, "%ld", value);
416
417   i = 0;
418   while (*buf)
419     {
420       ++buf;
421       ++i;
422     }
423   
424   _dbus_string_shorten (str, MAX_LONG_LEN - i);
425   
426   return TRUE;
427 }
428
429 /**
430  * Appends an unsigned integer to a DBusString.
431  * 
432  * @param str the string
433  * @param value the integer value
434  * @returns #FALSE if not enough memory or other failure.
435  */
436 dbus_bool_t
437 _dbus_string_append_uint (DBusString    *str,
438                           unsigned long  value)
439 {
440   /* this is wrong, but definitely on the high side. */
441 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
442   int orig_len;
443   int i;
444   char *buf;
445   
446   orig_len = _dbus_string_get_length (str);
447
448   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
449     return FALSE;
450
451   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
452
453   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
454
455   i = 0;
456   while (*buf)
457     {
458       ++buf;
459       ++i;
460     }
461   
462   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
463   
464   return TRUE;
465 }
466
467 #ifdef DBUS_BUILD_TESTS
468 /**
469  * Appends a double to a DBusString.
470  * 
471  * @param str the string
472  * @param value the floating point value
473  * @returns #FALSE if not enough memory or other failure.
474  */
475 dbus_bool_t
476 _dbus_string_append_double (DBusString *str,
477                             double      value)
478 {
479 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
480   int orig_len;
481   char *buf;
482   int i;
483   
484   orig_len = _dbus_string_get_length (str);
485
486   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
487     return FALSE;
488
489   buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
490
491   snprintf (buf, MAX_LONG_LEN, "%g", value);
492
493   i = 0;
494   while (*buf)
495     {
496       ++buf;
497       ++i;
498     }
499   
500   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
501   
502   return TRUE;
503 }
504 #endif /* DBUS_BUILD_TESTS */
505
506 /**
507  * Parses an integer contained in a DBusString. Either return parameter
508  * may be #NULL if you aren't interested in it. The integer is parsed
509  * and stored in value_return. Return parameters are not initialized
510  * if the function returns #FALSE.
511  *
512  * @param str the string
513  * @param start the byte index of the start of the integer
514  * @param value_return return location of the integer value or #NULL
515  * @param end_return return location of the end of the integer, or #NULL
516  * @returns #TRUE on success
517  */
518 dbus_bool_t
519 _dbus_string_parse_int (const DBusString *str,
520                         int               start,
521                         long             *value_return,
522                         int              *end_return)
523 {
524   long v;
525   const char *p;
526   char *end;
527
528   p = _dbus_string_get_const_data_len (str, start,
529                                        _dbus_string_get_length (str) - start);
530
531   end = NULL;
532   errno = 0;
533   v = strtol (p, &end, 0);
534   if (end == NULL || end == p || errno != 0)
535     return FALSE;
536
537   if (value_return)
538     *value_return = v;
539   if (end_return)
540     *end_return = start + (end - p);
541
542   return TRUE;
543 }
544
545 /**
546  * Parses an unsigned integer contained in a DBusString. Either return
547  * parameter may be #NULL if you aren't interested in it. The integer
548  * is parsed and stored in value_return. Return parameters are not
549  * initialized if the function returns #FALSE.
550  *
551  * @param str the string
552  * @param start the byte index of the start of the integer
553  * @param value_return return location of the integer value or #NULL
554  * @param end_return return location of the end of the integer, or #NULL
555  * @returns #TRUE on success
556  */
557 dbus_bool_t
558 _dbus_string_parse_uint (const DBusString *str,
559                          int               start,
560                          unsigned long    *value_return,
561                          int              *end_return)
562 {
563   unsigned long v;
564   const char *p;
565   char *end;
566
567   p = _dbus_string_get_const_data_len (str, start,
568                                        _dbus_string_get_length (str) - start);
569
570   end = NULL;
571   errno = 0;
572   v = strtoul (p, &end, 0);
573   if (end == NULL || end == p || errno != 0)
574     return FALSE;
575
576   if (value_return)
577     *value_return = v;
578   if (end_return)
579     *end_return = start + (end - p);
580
581   return TRUE;
582 }
583
584 #ifdef DBUS_BUILD_TESTS
585 static dbus_bool_t
586 ascii_isspace (char c)
587 {
588   return (c == ' ' ||
589           c == '\f' ||
590           c == '\n' ||
591           c == '\r' ||
592           c == '\t' ||
593           c == '\v');
594 }
595 #endif /* DBUS_BUILD_TESTS */
596
597 #ifdef DBUS_BUILD_TESTS
598 static dbus_bool_t
599 ascii_isdigit (char c)
600 {
601   return c >= '0' && c <= '9';
602 }
603 #endif /* DBUS_BUILD_TESTS */
604
605 #ifdef DBUS_BUILD_TESTS
606 static dbus_bool_t
607 ascii_isxdigit (char c)
608 {
609   return (ascii_isdigit (c) ||
610           (c >= 'a' && c <= 'f') ||
611           (c >= 'A' && c <= 'F'));
612 }
613 #endif /* DBUS_BUILD_TESTS */
614
615 #ifdef DBUS_BUILD_TESTS
616 /* Calls strtod in a locale-independent fashion, by looking at
617  * the locale data and patching the decimal comma to a point.
618  *
619  * Relicensed from glib.
620  */
621 static double
622 ascii_strtod (const char *nptr,
623               char      **endptr)
624 {
625   /* FIXME: The Win32 C library's strtod() doesn't handle hex.
626    * Presumably many Unixes don't either.
627    */
628
629   char *fail_pos;
630   double val;
631   struct lconv *locale_data;
632   const char *decimal_point;
633   int decimal_point_len;
634   const char *p, *decimal_point_pos;
635   const char *end = NULL; /* Silence gcc */
636
637   fail_pos = NULL;
638
639   locale_data = localeconv ();
640   decimal_point = locale_data->decimal_point;
641   decimal_point_len = strlen (decimal_point);
642
643   _dbus_assert (decimal_point_len != 0);
644   
645   decimal_point_pos = NULL;
646   if (decimal_point[0] != '.' ||
647       decimal_point[1] != 0)
648     {
649       p = nptr;
650       /* Skip leading space */
651       while (ascii_isspace (*p))
652         p++;
653       
654       /* Skip leading optional sign */
655       if (*p == '+' || *p == '-')
656         p++;
657       
658       if (p[0] == '0' &&
659           (p[1] == 'x' || p[1] == 'X'))
660         {
661           p += 2;
662           /* HEX - find the (optional) decimal point */
663           
664           while (ascii_isxdigit (*p))
665             p++;
666           
667           if (*p == '.')
668             {
669               decimal_point_pos = p++;
670               
671               while (ascii_isxdigit (*p))
672                 p++;
673               
674               if (*p == 'p' || *p == 'P')
675                 p++;
676               if (*p == '+' || *p == '-')
677                 p++;
678               while (ascii_isdigit (*p))
679                 p++;
680               end = p;
681             }
682         }
683       else
684         {
685           while (ascii_isdigit (*p))
686             p++;
687           
688           if (*p == '.')
689             {
690               decimal_point_pos = p++;
691               
692               while (ascii_isdigit (*p))
693                 p++;
694               
695               if (*p == 'e' || *p == 'E')
696                 p++;
697               if (*p == '+' || *p == '-')
698                 p++;
699               while (ascii_isdigit (*p))
700                 p++;
701               end = p;
702             }
703         }
704       /* For the other cases, we need not convert the decimal point */
705     }
706
707   /* Set errno to zero, so that we can distinguish zero results
708      and underflows */
709   errno = 0;
710   
711   if (decimal_point_pos)
712     {
713       char *copy, *c;
714
715       /* We need to convert the '.' to the locale specific decimal point */
716       copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
717       
718       c = copy;
719       memcpy (c, nptr, decimal_point_pos - nptr);
720       c += decimal_point_pos - nptr;
721       memcpy (c, decimal_point, decimal_point_len);
722       c += decimal_point_len;
723       memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
724       c += end - (decimal_point_pos + 1);
725       *c = 0;
726
727       val = strtod (copy, &fail_pos);
728
729       if (fail_pos)
730         {
731           if (fail_pos > decimal_point_pos)
732             fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
733           else
734             fail_pos = (char *)nptr + (fail_pos - copy);
735         }
736       
737       dbus_free (copy);
738           
739     }
740   else
741     val = strtod (nptr, &fail_pos);
742
743   if (endptr)
744     *endptr = fail_pos;
745   
746   return val;
747 }
748 #endif /* DBUS_BUILD_TESTS */
749
750 #ifdef DBUS_BUILD_TESTS
751 /**
752  * Parses a floating point number contained in a DBusString. Either
753  * return parameter may be #NULL if you aren't interested in it. The
754  * integer is parsed and stored in value_return. Return parameters are
755  * not initialized if the function returns #FALSE.
756  *
757  * @param str the string
758  * @param start the byte index of the start of the float
759  * @param value_return return location of the float value or #NULL
760  * @param end_return return location of the end of the float, or #NULL
761  * @returns #TRUE on success
762  */
763 dbus_bool_t
764 _dbus_string_parse_double (const DBusString *str,
765                            int               start,
766                            double           *value_return,
767                            int              *end_return)
768 {
769   double v;
770   const char *p;
771   char *end;
772
773   p = _dbus_string_get_const_data_len (str, start,
774                                        _dbus_string_get_length (str) - start);
775
776   /* parsing hex works on linux but isn't portable, so intercept it
777    * here to get uniform behavior.
778    */
779   if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
780     return FALSE;
781   
782   end = NULL;
783   errno = 0;
784   v = ascii_strtod (p, &end);
785   if (end == NULL || end == p || errno != 0)
786     return FALSE;
787
788   if (value_return)
789     *value_return = v;
790   if (end_return)
791     *end_return = start + (end - p);
792
793   return TRUE;
794 }
795 #endif /* DBUS_BUILD_TESTS */
796
797 /** @} */ /* DBusString group */
798
799 /**
800  * @addtogroup DBusInternalsUtils
801  * @{
802  */
803
804 void
805 _dbus_generate_pseudorandom_bytes_buffer (char *buffer,
806                                           int   n_bytes)
807 {
808   long tv_usec;
809   int i;
810   
811   /* fall back to pseudorandom */
812   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
813                  n_bytes);
814   
815   _dbus_get_current_time (NULL, &tv_usec);
816   srand (tv_usec);
817   
818   i = 0;
819   while (i < n_bytes)
820     {
821       double r;
822       unsigned int b;
823           
824       r = rand ();
825       b = (r / (double) RAND_MAX) * 255.0;
826
827       buffer[i] = b;
828
829       ++i;
830     }
831 }
832
833 /**
834  * Fills n_bytes of the given buffer with random bytes.
835  *
836  * @param buffer an allocated buffer
837  * @param n_bytes the number of bytes in buffer to write to
838  */
839 void
840 _dbus_generate_random_bytes_buffer (char *buffer,
841                                     int   n_bytes)
842 {
843   DBusString str;
844
845   if (!_dbus_string_init (&str))
846     {
847       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
848       return;
849     }
850
851   if (!_dbus_generate_random_bytes (&str, n_bytes))
852     {
853       _dbus_string_free (&str);
854       _dbus_generate_pseudorandom_bytes_buffer (buffer, n_bytes);
855       return;
856     }
857
858   _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
859
860   _dbus_string_free (&str);
861 }
862
863 /**
864  * Generates the given number of random bytes, where the bytes are
865  * chosen from the alphanumeric ASCII subset.
866  *
867  * @param str the string
868  * @param n_bytes the number of random ASCII bytes to append to string
869  * @returns #TRUE on success, #FALSE if no memory or other failure
870  */
871 dbus_bool_t
872 _dbus_generate_random_ascii (DBusString *str,
873                              int         n_bytes)
874 {
875   static const char letters[] =
876     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
877   int i;
878   int len;
879   
880   if (!_dbus_generate_random_bytes (str, n_bytes))
881     return FALSE;
882   
883   len = _dbus_string_get_length (str);
884   i = len - n_bytes;
885   while (i < len)
886     {
887       _dbus_string_set_byte (str, i,
888                              letters[_dbus_string_get_byte (str, i) %
889                                      (sizeof (letters) - 1)]);
890
891       ++i;
892     }
893
894   _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
895                                              n_bytes));
896
897   return TRUE;
898 }
899
900 /**
901  * Converts a UNIX or Windows errno
902  * into a #DBusError name.
903  *
904  * @todo should cover more errnos, specifically those
905  * from open().
906  * 
907  * @param error_number the errno.
908  * @returns an error name
909  */
910 const char*
911 _dbus_error_from_errno (int error_number)
912 {
913   switch (error_number)
914     {
915     case 0:
916       return DBUS_ERROR_FAILED;
917       
918 #ifdef EPROTONOSUPPORT
919     case EPROTONOSUPPORT:
920       return DBUS_ERROR_NOT_SUPPORTED;
921 #endif
922 #ifdef EAFNOSUPPORT
923     case EAFNOSUPPORT:
924       return DBUS_ERROR_NOT_SUPPORTED;
925 #endif
926 #ifdef ENFILE
927     case ENFILE:
928       return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
929 #endif
930 #ifdef EMFILE
931     case EMFILE:
932       return DBUS_ERROR_LIMITS_EXCEEDED;
933 #endif
934 #ifdef EACCES
935     case EACCES:
936       return DBUS_ERROR_ACCESS_DENIED;
937 #endif
938 #ifdef EPERM
939     case EPERM:
940       return DBUS_ERROR_ACCESS_DENIED;
941 #endif
942 #ifdef ENOBUFS
943     case ENOBUFS:
944       return DBUS_ERROR_NO_MEMORY;
945 #endif
946 #ifdef ENOMEM
947     case ENOMEM:
948       return DBUS_ERROR_NO_MEMORY;
949 #endif
950 #ifdef EINVAL
951     case EINVAL:
952       return DBUS_ERROR_FAILED;
953 #endif
954 #ifdef EBADF
955     case EBADF:
956       return DBUS_ERROR_FAILED;
957 #endif
958 #ifdef EFAULT
959     case EFAULT:
960       return DBUS_ERROR_FAILED;
961 #endif
962 #ifdef ENOTSOCK
963     case ENOTSOCK:
964       return DBUS_ERROR_FAILED;
965 #endif
966 #ifdef EISCONN
967     case EISCONN:
968       return DBUS_ERROR_FAILED;
969 #endif
970 #ifdef ECONNREFUSED
971     case ECONNREFUSED:
972       return DBUS_ERROR_NO_SERVER;
973 #endif
974 #ifdef ETIMEDOUT
975     case ETIMEDOUT:
976       return DBUS_ERROR_TIMEOUT;
977 #endif
978 #ifdef ENETUNREACH
979     case ENETUNREACH:
980       return DBUS_ERROR_NO_NETWORK;
981 #endif
982 #ifdef EADDRINUSE
983     case EADDRINUSE:
984       return DBUS_ERROR_ADDRESS_IN_USE;
985 #endif
986 #ifdef EEXIST
987     case EEXIST:
988       return DBUS_ERROR_FILE_EXISTS;
989 #endif
990 #ifdef ENOENT
991     case ENOENT:
992       return DBUS_ERROR_FILE_NOT_FOUND;
993 #endif
994     }
995
996   return DBUS_ERROR_FAILED;
997 }
998
999 /**
1000  * Assign 0 to the global errno variable
1001  */
1002 void
1003 _dbus_set_errno_to_zero (void)
1004 {
1005   errno = 0;
1006 }
1007
1008 /**
1009  * See if errno is set
1010  * @returns #TRUE if errno is not 0
1011  */
1012 dbus_bool_t
1013 _dbus_get_is_errno_nonzero (void)
1014 {
1015   return errno != 0;
1016 }
1017
1018 /**
1019  * See if errno is ENOMEM
1020  * @returns #TRUE if errno == ENOMEM
1021  */
1022 dbus_bool_t
1023 _dbus_get_is_errno_enomem (void)
1024 {
1025   return errno == ENOMEM;
1026 }
1027
1028 /**
1029  * See if errno is EINTR
1030  * @returns #TRUE if errno == EINTR
1031  */
1032 dbus_bool_t
1033 _dbus_get_is_errno_eintr (void)
1034 {
1035   return errno == EINTR;
1036 }
1037
1038 /**
1039  * Get error message from errno
1040  * @returns _dbus_strerror(errno)
1041  */
1042 const char*
1043 _dbus_strerror_from_errno (void)
1044 {
1045   return _dbus_strerror (errno);
1046 }
1047
1048 /** @} end of sysdeps */
1049
1050 /* tests in dbus-sysdeps-util.c */