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