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