D-Bus  1.4.10
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., 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 
79 void
81 {
82  const char *s;
83 
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 
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 
182 const char*
183 _dbus_getenv (const char *varname)
184 {
185  /* Don't respect any environment variables if the current process is
186  * setuid. This is the equivalent of glibc's __secure_getenv().
187  */
188  if (_dbus_check_setuid ())
189  return NULL;
190  return getenv (varname);
191 }
192 
200 {
201  dbus_bool_t rc = TRUE;
202 
203 #ifdef HAVE_CLEARENV
204  if (clearenv () != 0)
205  rc = FALSE;
206 #else
207 
208  if (environ != NULL)
209  environ[0] = NULL;
210 #endif
211 
212  return rc;
213 }
214 
221 char **
223 {
224  int i, length;
225  char **environment;
226 
227  _dbus_assert (environ != NULL);
228 
229  for (length = 0; environ[length] != NULL; length++);
230 
231  /* Add one for NULL */
232  length++;
233 
234  environment = dbus_new0 (char *, length);
235 
236  if (environment == NULL)
237  return NULL;
238 
239  for (i = 0; environ[i] != NULL; i++)
240  {
241  environment[i] = _dbus_strdup (environ[i]);
242 
243  if (environment[i] == NULL)
244  break;
245  }
246 
247  if (environ[i] != NULL)
248  {
249  dbus_free_string_array (environment);
250  environment = NULL;
251  }
252 
253  return environment;
254 }
255 
266  const char *suffix,
267  DBusList **dir_list)
268 {
269  int start;
270  int i;
271  int len;
272  char *cpath;
273  DBusString file_suffix;
274 
275  start = 0;
276  i = 0;
277 
278  _dbus_string_init_const (&file_suffix, suffix);
279 
280  len = _dbus_string_get_length (dirs);
281 
282  while (_dbus_string_find (dirs, start, _DBUS_PATH_SEPARATOR, &i))
283  {
284  DBusString path;
285 
286  if (!_dbus_string_init (&path))
287  goto oom;
288 
289  if (!_dbus_string_copy_len (dirs,
290  start,
291  i - start,
292  &path,
293  0))
294  {
295  _dbus_string_free (&path);
296  goto oom;
297  }
298 
299  _dbus_string_chop_white (&path);
300 
301  /* check for an empty path */
302  if (_dbus_string_get_length (&path) == 0)
303  goto next;
304 
305  if (!_dbus_concat_dir_and_file (&path,
306  &file_suffix))
307  {
308  _dbus_string_free (&path);
309  goto oom;
310  }
311 
312  if (!_dbus_string_copy_data(&path, &cpath))
313  {
314  _dbus_string_free (&path);
315  goto oom;
316  }
317 
318  if (!_dbus_list_append (dir_list, cpath))
319  {
320  _dbus_string_free (&path);
321  dbus_free (cpath);
322  goto oom;
323  }
324 
325  next:
326  _dbus_string_free (&path);
327  start = i + 1;
328  }
329 
330  if (start != len)
331  {
332  DBusString path;
333 
334  if (!_dbus_string_init (&path))
335  goto oom;
336 
337  if (!_dbus_string_copy_len (dirs,
338  start,
339  len - start,
340  &path,
341  0))
342  {
343  _dbus_string_free (&path);
344  goto oom;
345  }
346 
347  if (!_dbus_concat_dir_and_file (&path,
348  &file_suffix))
349  {
350  _dbus_string_free (&path);
351  goto oom;
352  }
353 
354  if (!_dbus_string_copy_data(&path, &cpath))
355  {
356  _dbus_string_free (&path);
357  goto oom;
358  }
359 
360  if (!_dbus_list_append (dir_list, cpath))
361  {
362  _dbus_string_free (&path);
363  dbus_free (cpath);
364  goto oom;
365  }
366 
367  _dbus_string_free (&path);
368  }
369 
370  return TRUE;
371 
372  oom:
374  _dbus_list_clear (dir_list);
375  return FALSE;
376 }
377 
394  long value)
395 {
396  /* this calculation is from comp.lang.c faq */
397 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1) /* +1 for '-' */
398  int orig_len;
399  int i;
400  char *buf;
401 
402  orig_len = _dbus_string_get_length (str);
403 
404  if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
405  return FALSE;
406 
407  buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
408 
409  snprintf (buf, MAX_LONG_LEN, "%ld", value);
410 
411  i = 0;
412  while (*buf)
413  {
414  ++buf;
415  ++i;
416  }
417 
418  _dbus_string_shorten (str, MAX_LONG_LEN - i);
419 
420  return TRUE;
421 }
422 
432  unsigned long value)
433 {
434  /* this is wrong, but definitely on the high side. */
435 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
436  int orig_len;
437  int i;
438  char *buf;
439 
440  orig_len = _dbus_string_get_length (str);
441 
442  if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
443  return FALSE;
444 
445  buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
446 
447  snprintf (buf, MAX_ULONG_LEN, "%lu", value);
448 
449  i = 0;
450  while (*buf)
451  {
452  ++buf;
453  ++i;
454  }
455 
456  _dbus_string_shorten (str, MAX_ULONG_LEN - i);
457 
458  return TRUE;
459 }
460 
461 #ifdef DBUS_BUILD_TESTS
462 
470 _dbus_string_append_double (DBusString *str,
471  double value)
472 {
473 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
474  int orig_len;
475  char *buf;
476  int i;
477 
478  orig_len = _dbus_string_get_length (str);
479 
480  if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
481  return FALSE;
482 
483  buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
484 
485  snprintf (buf, MAX_LONG_LEN, "%g", value);
486 
487  i = 0;
488  while (*buf)
489  {
490  ++buf;
491  ++i;
492  }
493 
494  _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
495 
496  return TRUE;
497 }
498 #endif /* DBUS_BUILD_TESTS */
499 
514  int start,
515  long *value_return,
516  int *end_return)
517 {
518  long v;
519  const char *p;
520  char *end;
521 
522  p = _dbus_string_get_const_data_len (str, start,
523  _dbus_string_get_length (str) - start);
524 
525  end = NULL;
527  v = strtol (p, &end, 0);
528  if (end == NULL || end == p || errno != 0)
529  return FALSE;
530 
531  if (value_return)
532  *value_return = v;
533  if (end_return)
534  *end_return = start + (end - p);
535 
536  return TRUE;
537 }
538 
553  int start,
554  unsigned long *value_return,
555  int *end_return)
556 {
557  unsigned long v;
558  const char *p;
559  char *end;
560 
561  p = _dbus_string_get_const_data_len (str, start,
562  _dbus_string_get_length (str) - start);
563 
564  end = NULL;
566  v = strtoul (p, &end, 0);
567  if (end == NULL || end == p || errno != 0)
568  return FALSE;
569 
570  if (value_return)
571  *value_return = v;
572  if (end_return)
573  *end_return = start + (end - p);
574 
575  return TRUE;
576 }
577 
578 #ifdef DBUS_BUILD_TESTS
579 static dbus_bool_t
580 ascii_isspace (char c)
581 {
582  return (c == ' ' ||
583  c == '\f' ||
584  c == '\n' ||
585  c == '\r' ||
586  c == '\t' ||
587  c == '\v');
588 }
589 #endif /* DBUS_BUILD_TESTS */
590 
591 #ifdef DBUS_BUILD_TESTS
592 static dbus_bool_t
593 ascii_isdigit (char c)
594 {
595  return c >= '0' && c <= '9';
596 }
597 #endif /* DBUS_BUILD_TESTS */
598 
599 #ifdef DBUS_BUILD_TESTS
600 static dbus_bool_t
601 ascii_isxdigit (char c)
602 {
603  return (ascii_isdigit (c) ||
604  (c >= 'a' && c <= 'f') ||
605  (c >= 'A' && c <= 'F'));
606 }
607 #endif /* DBUS_BUILD_TESTS */
608 
609 #ifdef DBUS_BUILD_TESTS
610 /* Calls strtod in a locale-independent fashion, by looking at
611  * the locale data and patching the decimal comma to a point.
612  *
613  * Relicensed from glib.
614  */
615 static double
616 ascii_strtod (const char *nptr,
617  char **endptr)
618 {
619  /* FIXME: The Win32 C library's strtod() doesn't handle hex.
620  * Presumably many Unixes don't either.
621  */
622 
623  char *fail_pos;
624  double val;
625  struct lconv *locale_data;
626  const char *decimal_point;
627  int decimal_point_len;
628  const char *p, *decimal_point_pos;
629  const char *end = NULL; /* Silence gcc */
630 
631  fail_pos = NULL;
632 
633 #if HAVE_LOCALECONV
634  locale_data = localeconv ();
635  decimal_point = locale_data->decimal_point;
636 #else
637  decimal_point = ".";
638 #endif
639 
640  decimal_point_len = strlen (decimal_point);
641  _dbus_assert (decimal_point_len != 0);
642 
643  decimal_point_pos = NULL;
644  if (decimal_point[0] != '.' ||
645  decimal_point[1] != 0)
646  {
647  p = nptr;
648  /* Skip leading space */
649  while (ascii_isspace (*p))
650  p++;
651 
652  /* Skip leading optional sign */
653  if (*p == '+' || *p == '-')
654  p++;
655 
656  if (p[0] == '0' &&
657  (p[1] == 'x' || p[1] == 'X'))
658  {
659  p += 2;
660  /* HEX - find the (optional) decimal point */
661 
662  while (ascii_isxdigit (*p))
663  p++;
664 
665  if (*p == '.')
666  {
667  decimal_point_pos = p++;
668 
669  while (ascii_isxdigit (*p))
670  p++;
671 
672  if (*p == 'p' || *p == 'P')
673  p++;
674  if (*p == '+' || *p == '-')
675  p++;
676  while (ascii_isdigit (*p))
677  p++;
678  end = p;
679  }
680  }
681  else
682  {
683  while (ascii_isdigit (*p))
684  p++;
685 
686  if (*p == '.')
687  {
688  decimal_point_pos = p++;
689 
690  while (ascii_isdigit (*p))
691  p++;
692 
693  if (*p == 'e' || *p == 'E')
694  p++;
695  if (*p == '+' || *p == '-')
696  p++;
697  while (ascii_isdigit (*p))
698  p++;
699  end = p;
700  }
701  }
702  /* For the other cases, we need not convert the decimal point */
703  }
704 
705  /* Set errno to zero, so that we can distinguish zero results
706  and underflows */
708 
709  if (decimal_point_pos)
710  {
711  char *copy, *c;
712 
713  /* We need to convert the '.' to the locale specific decimal point */
714  copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
715 
716  c = copy;
717  memcpy (c, nptr, decimal_point_pos - nptr);
718  c += decimal_point_pos - nptr;
719  memcpy (c, decimal_point, decimal_point_len);
720  c += decimal_point_len;
721  memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
722  c += end - (decimal_point_pos + 1);
723  *c = 0;
724 
725  val = strtod (copy, &fail_pos);
726 
727  if (fail_pos)
728  {
729  if (fail_pos > decimal_point_pos)
730  fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
731  else
732  fail_pos = (char *)nptr + (fail_pos - copy);
733  }
734 
735  dbus_free (copy);
736 
737  }
738  else
739  val = strtod (nptr, &fail_pos);
740 
741  if (endptr)
742  *endptr = fail_pos;
743 
744  return val;
745 }
746 #endif /* DBUS_BUILD_TESTS */
747 
748 #ifdef DBUS_BUILD_TESTS
749 
762 _dbus_string_parse_double (const DBusString *str,
763  int start,
764  double *value_return,
765  int *end_return)
766 {
767  double v;
768  const char *p;
769  char *end;
770 
771  p = _dbus_string_get_const_data_len (str, start,
772  _dbus_string_get_length (str) - start);
773 
774  /* parsing hex works on linux but isn't portable, so intercept it
775  * here to get uniform behavior.
776  */
777  if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
778  return FALSE;
779 
780  end = NULL;
782  v = ascii_strtod (p, &end);
783  if (end == NULL || end == p || errno != 0)
784  return FALSE;
785 
786  if (value_return)
787  *value_return = v;
788  if (end_return)
789  *end_return = start + (end - p);
790 
791  return TRUE;
792 }
793 #endif /* DBUS_BUILD_TESTS */
794  /* DBusString group */
796 
802 void
804  int n_bytes)
805 {
806  long tv_usec;
807  int i;
808 
809  /* fall back to pseudorandom */
810  _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
811  n_bytes);
812 
813  _dbus_get_current_time (NULL, &tv_usec);
814  srand (tv_usec);
815 
816  i = 0;
817  while (i < n_bytes)
818  {
819  double r;
820  unsigned int b;
821 
822  r = rand ();
823  b = (r / (double) RAND_MAX) * 255.0;
824 
825  buffer[i] = b;
826 
827  ++i;
828  }
829 }
830 
837 void
839  int n_bytes)
840 {
841  DBusString str;
842 
843  if (!_dbus_string_init (&str))
844  {
846  return;
847  }
848 
849  if (!_dbus_generate_random_bytes (&str, n_bytes))
850  {
851  _dbus_string_free (&str);
853  return;
854  }
855 
856  _dbus_string_copy_to_buffer (&str, buffer, n_bytes);
857 
858  _dbus_string_free (&str);
859 }
860 
871  int n_bytes)
872 {
873  static const char letters[] =
874  "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
875  int i;
876  int len;
877 
878  if (!_dbus_generate_random_bytes (str, n_bytes))
879  return FALSE;
880 
881  len = _dbus_string_get_length (str);
882  i = len - n_bytes;
883  while (i < len)
884  {
885  _dbus_string_set_byte (str, i,
886  letters[_dbus_string_get_byte (str, i) %
887  (sizeof (letters) - 1)]);
888 
889  ++i;
890  }
891 
892  _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
893  n_bytes));
894 
895  return TRUE;
896 }
897 
908 const char*
909 _dbus_error_from_errno (int error_number)
910 {
911  switch (error_number)
912  {
913  case 0:
914  return DBUS_ERROR_FAILED;
915 
916 #ifdef EPROTONOSUPPORT
917  case EPROTONOSUPPORT:
919 #endif
920 #ifdef WSAEPROTONOSUPPORT
921  case WSAEPROTONOSUPPORT:
923 #endif
924 #ifdef EAFNOSUPPORT
925  case EAFNOSUPPORT:
927 #endif
928 #ifdef WSAEAFNOSUPPORT
929  case WSAEAFNOSUPPORT:
931 #endif
932 #ifdef ENFILE
933  case ENFILE:
934  return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
935 #endif
936 #ifdef EMFILE
937  case EMFILE:
939 #endif
940 #ifdef EACCES
941  case EACCES:
943 #endif
944 #ifdef EPERM
945  case EPERM:
947 #endif
948 #ifdef ENOBUFS
949  case ENOBUFS:
950  return DBUS_ERROR_NO_MEMORY;
951 #endif
952 #ifdef ENOMEM
953  case ENOMEM:
954  return DBUS_ERROR_NO_MEMORY;
955 #endif
956 #ifdef ECONNREFUSED
957  case ECONNREFUSED:
958  return DBUS_ERROR_NO_SERVER;
959 #endif
960 #ifdef WSAECONNREFUSED
961  case WSAECONNREFUSED:
962  return DBUS_ERROR_NO_SERVER;
963 #endif
964 #ifdef ETIMEDOUT
965  case ETIMEDOUT:
966  return DBUS_ERROR_TIMEOUT;
967 #endif
968 #ifdef WSAETIMEDOUT
969  case WSAETIMEDOUT:
970  return DBUS_ERROR_TIMEOUT;
971 #endif
972 #ifdef ENETUNREACH
973  case ENETUNREACH:
974  return DBUS_ERROR_NO_NETWORK;
975 #endif
976 #ifdef WSAENETUNREACH
977  case WSAENETUNREACH:
978  return DBUS_ERROR_NO_NETWORK;
979 #endif
980 #ifdef EADDRINUSE
981  case EADDRINUSE:
983 #endif
984 #ifdef WSAEADDRINUSE
985  case WSAEADDRINUSE:
987 #endif
988 #ifdef EEXIST
989  case EEXIST:
990  return DBUS_ERROR_FILE_EXISTS;
991 #endif
992 #ifdef ENOENT
993  case ENOENT:
995 #endif
996  }
997 
998  return DBUS_ERROR_FAILED;
999 }
1000 
1006 const char*
1008 {
1009  return _dbus_error_from_errno (errno);
1010 }
1011 
1015 void
1017 {
1018 #ifdef DBUS_WINCE
1019  SetLastError (0);
1020 #else
1021  errno = 0;
1022 #endif
1023 }
1024 
1031 {
1032  return errno != 0;
1033 }
1034 
1041 {
1042  return errno == ENOMEM;
1043 }
1044 
1051 {
1052  return errno == EINTR;
1053 }
1054 
1061 {
1062  return errno == EPIPE;
1063 }
1064 
1069 const char*
1071 {
1072  return _dbus_strerror (errno);
1073 }
1074 
1077 /* tests in dbus-sysdeps-util.c */