D-Bus  1.10.24
dbus-spawn-win.c
1 #include <config.h>
2 
3 //#define SPAWN_DEBUG
4 
5 #if !defined(SPAWN_DEBUG) || defined(_MSC_VER)
6 #define PING()
7 #else
8 #define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr)
9 #endif
10 
11 #include <stdio.h>
12 
13 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
14 /* dbus-spawn-win32.c Wrapper around g_spawn
15  *
16  * Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
17  * Copyright (C) 2003 CodeFactory AB
18  * Copyright (C) 2005 Novell, Inc.
19  *
20  * Licensed under the Academic Free License version 2.1
21  *
22  * This program is free software; you can redistribute it and/or modify
23  * it under the terms of the GNU General Public License as published by
24  * the Free Software Foundation; either version 2 of the License, or
25  * (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program; if not, write to the Free Software
34  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
35  *
36  */
37 #include "dbus-spawn.h"
38 #include "dbus-sysdeps.h"
39 #include "dbus-sysdeps-win.h"
40 #include "dbus-internals.h"
41 #include "dbus-test.h"
42 #include "dbus-protocol.h"
43 
44 #define WIN32_LEAN_AND_MEAN
45 #include <windows.h>
46 //#define STRICT
47 //#include <windows.h>
48 //#undef STRICT
49 #include <winsock2.h>
50 #undef interface
51 
52 #include <stdlib.h>
53 
54 #ifndef DBUS_WINCE
55 #include <process.h>
56 #endif
57 
62  {
63  DBusAtomic refcount;
64 
65  HANDLE start_sync_event;
66 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
67 
68  HANDLE end_sync_event;
69 #endif
70 
71  char *log_name;
72  DBusSpawnChildSetupFunc child_setup;
73  void *user_data;
74 
75  int argc;
76  char **argv;
77  char **envp;
78 
79  HANDLE child_handle;
80  DBusSocket socket_to_babysitter; /* Connection to the babysitter thread */
81  DBusSocket socket_to_main;
82 
85  DBusBabysitterFinishedFunc finished_cb;
86  void *finished_data;
87 
88  dbus_bool_t have_spawn_errno;
89  int spawn_errno;
90  dbus_bool_t have_child_status;
91  int child_status;
92  };
93 
94 static void
95 _dbus_babysitter_trace_ref (DBusBabysitter *sitter,
96  int old_refcount,
97  int new_refcount,
98  const char *why)
99 {
100 #ifdef DBUS_ENABLE_VERBOSE_MODE
101  static int enabled = -1;
102 
103  _dbus_trace_ref ("DBusBabysitter", sitter, old_refcount, new_refcount, why,
104  "DBUS_BABYSITTER_TRACE", &enabled);
105 #endif
106 }
107 
108 static DBusBabysitter*
109 _dbus_babysitter_new (void)
110 {
111  DBusBabysitter *sitter;
112  dbus_int32_t old_refcount;
113 
114  sitter = dbus_new0 (DBusBabysitter, 1);
115  if (sitter == NULL)
116  return NULL;
117 
118  old_refcount = _dbus_atomic_inc (&sitter->refcount);
119 
120  _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, __FUNCTION__);
121 
122  sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
123  if (sitter->start_sync_event == NULL)
124  {
125  _dbus_babysitter_unref (sitter);
126  return NULL;
127  }
128 
129 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
130  sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
131  if (sitter->end_sync_event == NULL)
132  {
133  _dbus_babysitter_unref (sitter);
134  return NULL;
135  }
136 #endif
137 
138  sitter->child_handle = NULL;
139 
140  sitter->socket_to_babysitter = sitter->socket_to_main = _dbus_socket_get_invalid ();
141 
142  sitter->argc = 0;
143  sitter->argv = NULL;
144  sitter->envp = NULL;
145 
146  sitter->watches = _dbus_watch_list_new ();
147  if (sitter->watches == NULL)
148  {
149  _dbus_babysitter_unref (sitter);
150  return NULL;
151  }
152 
153  sitter->have_spawn_errno = FALSE;
154  sitter->have_child_status = FALSE;
155 
156  return sitter;
157 }
158 
167 {
168  dbus_int32_t old_refcount;
169  PING();
170  _dbus_assert (sitter != NULL);
171 
172  old_refcount = _dbus_atomic_inc (&sitter->refcount);
173  _dbus_assert (old_refcount > 0);
174  _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount+1, __FUNCTION__);
175 
176  return sitter;
177 }
178 
179 static void
180 close_socket_to_babysitter (DBusBabysitter *sitter)
181 {
182  _dbus_verbose ("Closing babysitter\n");
183 
184  if (sitter->sitter_watch != NULL)
185  {
186  _dbus_assert (sitter->watches != NULL);
190  sitter->sitter_watch = NULL;
191  }
192 
193  if (sitter->socket_to_babysitter.sock != INVALID_SOCKET)
194  {
196  sitter->socket_to_babysitter.sock = INVALID_SOCKET;
197  }
198 }
199 
205 void
207 {
208  int i;
209  dbus_int32_t old_refcount;
210 
211  PING();
212  _dbus_assert (sitter != NULL);
213 
214  old_refcount = _dbus_atomic_dec (&sitter->refcount);
215  _dbus_assert (old_refcount > 0);
216  _dbus_babysitter_trace_ref (sitter, old_refcount, old_refcount-1, __FUNCTION__);
217 
218  if (old_refcount == 1)
219  {
220  close_socket_to_babysitter (sitter);
221 
222  if (sitter->socket_to_main.sock != INVALID_SOCKET)
223  {
224  _dbus_close_socket (sitter->socket_to_main, NULL);
225  sitter->socket_to_main.sock = INVALID_SOCKET;
226  }
227 
228  PING();
229  if (sitter->argv != NULL)
230  {
231  for (i = 0; i < sitter->argc; i++)
232  if (sitter->argv[i] != NULL)
233  {
234  dbus_free (sitter->argv[i]);
235  sitter->argv[i] = NULL;
236  }
237  dbus_free (sitter->argv);
238  sitter->argv = NULL;
239  }
240 
241  if (sitter->envp != NULL)
242  {
243  char **e = sitter->envp;
244 
245  while (*e)
246  dbus_free (*e++);
247  dbus_free (sitter->envp);
248  sitter->envp = NULL;
249  }
250 
251  if (sitter->child_handle != NULL)
252  {
253  CloseHandle (sitter->child_handle);
254  sitter->child_handle = NULL;
255  }
256 
257  if (sitter->sitter_watch)
258  {
261  sitter->sitter_watch = NULL;
262  }
263 
264  if (sitter->watches)
265  _dbus_watch_list_free (sitter->watches);
266 
267  if (sitter->start_sync_event != NULL)
268  {
269  PING();
270  CloseHandle (sitter->start_sync_event);
271  sitter->start_sync_event = NULL;
272  }
273 
274 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
275  if (sitter->end_sync_event != NULL)
276  {
277  CloseHandle (sitter->end_sync_event);
278  sitter->end_sync_event = NULL;
279  }
280 #endif
281 
282  dbus_free (sitter->log_name);
283 
284  dbus_free (sitter);
285  }
286 }
287 
288 void
290 {
291  PING();
292  if (sitter->child_handle == NULL)
293  return; /* child is already dead, or we're so hosed we'll never recover */
294 
295  PING();
296  TerminateProcess (sitter->child_handle, 12345);
297 }
298 
306 {
307  PING();
308  return (sitter->child_handle == NULL);
309 }
310 
325  int *status)
326 {
327  if (!_dbus_babysitter_get_child_exited (sitter))
328  _dbus_assert_not_reached ("Child has not exited");
329 
330  if (!sitter->have_child_status ||
331  sitter->child_status == STILL_ACTIVE)
332  return FALSE;
333 
334  *status = sitter->child_status;
335  return TRUE;
336 }
337 
347 void
349  DBusError *error)
350 {
351  PING();
352  if (!_dbus_babysitter_get_child_exited (sitter))
353  return;
354 
355  PING();
356  if (sitter->have_spawn_errno)
357  {
358  char *emsg = _dbus_win_error_string (sitter->spawn_errno);
360  "Failed to execute program %s: %s",
361  sitter->log_name, emsg);
362  _dbus_win_free_error_string (emsg);
363  }
364  else if (sitter->have_child_status)
365  {
366  PING();
368  "Process %s exited with status %d",
369  sitter->log_name, sitter->child_status);
370  }
371  else
372  {
373  PING();
375  "Process %s exited, status unknown",
376  sitter->log_name);
377  }
378  PING();
379 }
380 
383  DBusAddWatchFunction add_function,
384  DBusRemoveWatchFunction remove_function,
385  DBusWatchToggledFunction toggled_function,
386  void *data,
387  DBusFreeFunction free_data_function)
388 {
389  PING();
390  return _dbus_watch_list_set_functions (sitter->watches,
391  add_function,
392  remove_function,
393  toggled_function,
394  data,
395  free_data_function);
396 }
397 
398 static dbus_bool_t
399 handle_watch (DBusWatch *watch,
400  unsigned int condition,
401  void *data)
402 {
403  DBusBabysitter *sitter = data;
404 
405  /* On Unix dbus-spawn uses a babysitter *process*, thus it has to
406  * actually send the exit statuses, error codes and whatnot through
407  * sockets and/or pipes. On Win32, the babysitter is jus a thread,
408  * so it can set the status fields directly in the babysitter struct
409  * just fine. The socket pipe is used just so we can watch it with
410  * select(), as soon as anything is written to it we know that the
411  * babysitter thread has recorded the status in the babysitter
412  * struct.
413  */
414 
415  PING();
416  close_socket_to_babysitter (sitter);
417  PING();
418 
419  if (_dbus_babysitter_get_child_exited (sitter) &&
420  sitter->finished_cb != NULL)
421  {
422  sitter->finished_cb (sitter, sitter->finished_data);
423  sitter->finished_cb = NULL;
424  }
425 
426  return TRUE;
427 }
428 
429 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */
430 static int
431 protect_argv (char **argv,
432  char ***new_argv)
433 {
434  int i;
435  int argc = 0;
436 
437  while (argv[argc])
438  ++argc;
439  *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
440  if (*new_argv == NULL)
441  return -1;
442 
443  for (i = 0; i < argc; i++)
444  (*new_argv)[i] = NULL;
445 
446  /* Quote each argv element if necessary, so that it will get
447  * reconstructed correctly in the C runtime startup code. Note that
448  * the unquoting algorithm in the C runtime is really weird, and
449  * rather different than what Unix shells do. See stdargv.c in the C
450  * runtime sources (in the Platform SDK, in src/crt).
451  *
452  * Note that an new_argv[0] constructed by this function should
453  * *not* be passed as the filename argument to a spawn* or exec*
454  * family function. That argument should be the real file name
455  * without any quoting.
456  */
457  for (i = 0; i < argc; i++)
458  {
459  char *p = argv[i];
460  char *q;
461  int len = 0;
462  int need_dblquotes = FALSE;
463  while (*p)
464  {
465  if (*p == ' ' || *p == '\t')
466  need_dblquotes = TRUE;
467  else if (*p == '"')
468  len++;
469  else if (*p == '\\')
470  {
471  char *pp = p;
472  while (*pp && *pp == '\\')
473  pp++;
474  if (*pp == '"')
475  len++;
476  }
477  len++;
478  p++;
479  }
480 
481  q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
482 
483  if (q == NULL)
484  return -1;
485 
486 
487  p = argv[i];
488 
489  if (need_dblquotes)
490  *q++ = '"';
491 
492  while (*p)
493  {
494  if (*p == '"')
495  *q++ = '\\';
496  else if (*p == '\\')
497  {
498  char *pp = p;
499  while (*pp && *pp == '\\')
500  pp++;
501  if (*pp == '"')
502  *q++ = '\\';
503  }
504  *q++ = *p;
505  p++;
506  }
507 
508  if (need_dblquotes)
509  *q++ = '"';
510  *q++ = '\0';
511  /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
512  }
513  (*new_argv)[argc] = NULL;
514 
515  return argc;
516 }
517 
518 
519 /* From GPGME, relicensed by g10 Code GmbH. */
520 static char *
521 compose_string (char **strings, char separator)
522 {
523  int i;
524  int n = 0;
525  char *buf;
526  char *p;
527 
528  if (!strings || !strings[0])
529  return 0;
530  for (i = 0; strings[i]; i++)
531  n += strlen (strings[i]) + 1;
532  n++;
533 
534  buf = p = malloc (n);
535  if (!buf)
536  return NULL;
537  for (i = 0; strings[i]; i++)
538  {
539  strcpy (p, strings[i]);
540  p += strlen (strings[i]);
541  *(p++) = separator;
542  }
543  p--;
544  *(p++) = '\0';
545  *p = '\0';
546 
547  return buf;
548 }
549 
550 static char *
551 build_commandline (char **argv)
552 {
553  return compose_string (argv, ' ');
554 }
555 
556 static char *
557 build_env_string (char** envp)
558 {
559  return compose_string (envp, '\0');
560 }
561 
562 static HANDLE
563 spawn_program (char* name, char** argv, char** envp)
564 {
565  PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
566  STARTUPINFOA si;
567  char *arg_string, *env_string;
568  BOOL result;
569 
570 #ifdef DBUS_WINCE
571  if (argv && argv[0])
572  arg_string = build_commandline (argv + 1);
573  else
574  arg_string = NULL;
575 #else
576  arg_string = build_commandline (argv);
577 #endif
578  if (!arg_string)
579  return INVALID_HANDLE_VALUE;
580 
581  env_string = build_env_string(envp);
582 
583  memset (&si, 0, sizeof (si));
584  si.cb = sizeof (si);
585 #ifdef DBUS_WINCE
586  result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0,
587 #else
588  result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0,
589 #endif
590  (LPVOID)env_string, NULL, &si, &pi);
591  free (arg_string);
592  if (env_string)
593  free (env_string);
594 
595  if (!result)
596  return INVALID_HANDLE_VALUE;
597 
598  CloseHandle (pi.hThread);
599  return pi.hProcess;
600 }
601 
602 
603 static DWORD __stdcall
604 babysitter (void *parameter)
605 {
606  int ret = 0;
607  DBusBabysitter *sitter = (DBusBabysitter *) parameter;
608  HANDLE handle;
609 
610  PING();
611  if (sitter->child_setup)
612  {
613  PING();
614  (*sitter->child_setup) (sitter->user_data);
615  }
616 
617  _dbus_verbose ("babysitter: spawning %s\n", sitter->log_name);
618 
619  PING();
620  handle = spawn_program (sitter->log_name, sitter->argv, sitter->envp);
621 
622  PING();
623  if (handle != INVALID_HANDLE_VALUE)
624  {
625  sitter->child_handle = handle;
626  }
627  else
628  {
629  sitter->child_handle = NULL;
630  sitter->have_spawn_errno = TRUE;
631  sitter->spawn_errno = GetLastError();
632  }
633 
634  PING();
635  SetEvent (sitter->start_sync_event);
636 
637  if (sitter->child_handle != NULL)
638  {
639  DWORD status;
640 
641  PING();
642  // wait until process finished
643  WaitForSingleObject (sitter->child_handle, INFINITE);
644 
645  PING();
646  ret = GetExitCodeProcess (sitter->child_handle, &status);
647  if (ret)
648  {
649  sitter->child_status = status;
650  sitter->have_child_status = TRUE;
651  }
652 
653  CloseHandle (sitter->child_handle);
654  sitter->child_handle = NULL;
655  }
656 
657 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
658  SetEvent (sitter->end_sync_event);
659 #endif
660 
661  PING();
662  send (sitter->socket_to_main.sock, " ", 1, 0);
663 
664  _dbus_babysitter_unref (sitter);
665 
666  return ret ? 0 : 1;
667 }
668 
671  const char *log_name,
672  char **argv,
673  char **envp,
674  DBusSpawnChildSetupFunc child_setup,
675  void *user_data,
676  DBusError *error)
677 {
678  DBusBabysitter *sitter;
679  HANDLE sitter_thread;
680  DWORD sitter_thread_id;
681 
682  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
683  _dbus_assert (argv[0] != NULL);
684 
685  if (sitter_p != NULL)
686  *sitter_p = NULL;
687 
688  PING();
689  sitter = _dbus_babysitter_new ();
690  if (sitter == NULL)
691  {
692  _DBUS_SET_OOM (error);
693  return FALSE;
694  }
695 
696  sitter->child_setup = child_setup;
697  sitter->user_data = user_data;
698 
699  sitter->log_name = _dbus_strdup (log_name);
700  if (sitter->log_name == NULL && log_name != NULL)
701  {
702  _DBUS_SET_OOM (error);
703  goto out0;
704  }
705 
706  if (sitter->log_name == NULL)
707  sitter->log_name = _dbus_strdup (argv[0]);
708 
709  if (sitter->log_name == NULL)
710  {
711  _DBUS_SET_OOM (error);
712  goto out0;
713  }
714 
715  PING();
716  if (!_dbus_socketpair (&sitter->socket_to_babysitter,
717  &sitter->socket_to_main,
718  FALSE, error))
719  goto out0;
720 
723  TRUE, handle_watch, sitter, NULL);
724  PING();
725  if (sitter->sitter_watch == NULL)
726  {
727  _DBUS_SET_OOM (error);
728  goto out0;
729  }
730 
731  PING();
732  if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
733  {
734  /* we need to free it early so the destructor won't try to remove it
735  * without it having been added, which DBusLoop doesn't allow */
738  sitter->sitter_watch = NULL;
739 
740  _DBUS_SET_OOM (error);
741  goto out0;
742  }
743 
744  sitter->argc = protect_argv (argv, &sitter->argv);
745  if (sitter->argc == -1)
746  {
747  _DBUS_SET_OOM (error);
748  goto out0;
749  }
750  sitter->envp = envp;
751 
752  PING();
753  sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter,
754  _dbus_babysitter_ref (sitter), 0, &sitter_thread_id);
755 
756  if (sitter_thread == 0)
757  {
758  PING();
760  "Failed to create new thread");
761  goto out0;
762  }
763  CloseHandle (sitter_thread);
764 
765  PING();
766  WaitForSingleObject (sitter->start_sync_event, INFINITE);
767 
768  PING();
769  if (sitter_p != NULL)
770  *sitter_p = sitter;
771  else
772  _dbus_babysitter_unref (sitter);
773 
774  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
775 
776  PING();
777  return TRUE;
778 
779 out0:
780  _dbus_babysitter_unref (sitter);
781 
782  return FALSE;
783 }
784 
785 void
786 _dbus_babysitter_set_result_function (DBusBabysitter *sitter,
787  DBusBabysitterFinishedFunc finished,
788  void *user_data)
789 {
790  sitter->finished_cb = finished;
791  sitter->finished_data = user_data;
792 }
793 
794 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
795 
796 static char *
797 get_test_exec (const char *exe,
798  DBusString *scratch_space)
799 {
800  const char *dbus_test_exec;
801 
802  dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC");
803 
804  if (dbus_test_exec == NULL)
805  dbus_test_exec = DBUS_TEST_EXEC;
806 
807  if (!_dbus_string_init (scratch_space))
808  return NULL;
809 
810  if (!_dbus_string_append_printf (scratch_space, "%s/%s%s",
811  dbus_test_exec, exe, DBUS_EXEEXT))
812  {
813  _dbus_string_free (scratch_space);
814  return NULL;
815  }
816 
817  return _dbus_string_get_data (scratch_space);
818 }
819 
820 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
821 
822 static void
823 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
824 {
825  if (sitter->child_handle == NULL)
826  return;
827 
828  WaitForSingleObject (sitter->end_sync_event, INFINITE);
829 }
830 
831 static dbus_bool_t
832 check_spawn_nonexistent (void *data)
833 {
834  char *argv[4] = { NULL, NULL, NULL, NULL };
835  DBusBabysitter *sitter;
836  DBusError error;
837 
838  sitter = NULL;
839 
840  dbus_error_init (&error);
841 
842  /*** Test launching nonexistent binary */
843 
844  argv[0] = "/this/does/not/exist/32542sdgafgafdg";
845  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_nonexistent", argv, NULL,
846  NULL, NULL,
847  &error))
848  {
849  _dbus_babysitter_block_for_child_exit (sitter);
850  _dbus_babysitter_set_child_exit_error (sitter, &error);
851  }
852 
853  if (sitter)
854  _dbus_babysitter_unref (sitter);
855 
856  if (!dbus_error_is_set (&error))
857  {
858  _dbus_warn ("Did not get an error launching nonexistent executable\n");
859  return FALSE;
860  }
861 
862  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
864  {
865  _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
866  error.name, error.message);
867  dbus_error_free (&error);
868  return FALSE;
869  }
870 
871  dbus_error_free (&error);
872 
873  return TRUE;
874 }
875 
876 static dbus_bool_t
877 check_spawn_segfault (void *data)
878 {
879  char *argv[4] = { NULL, NULL, NULL, NULL };
880  DBusBabysitter *sitter;
881  DBusError error;
882  DBusString argv0;
883 
884  sitter = NULL;
885 
886  dbus_error_init (&error);
887 
888  /*** Test launching segfault binary */
889 
890  argv[0] = get_test_exec ("test-segfault", &argv0);
891 
892  if (argv[0] == NULL)
893  {
894  /* OOM was simulated, never mind */
895  return TRUE;
896  }
897 
898  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_segfault", argv, NULL,
899  NULL, NULL,
900  &error))
901  {
902  _dbus_babysitter_block_for_child_exit (sitter);
903  _dbus_babysitter_set_child_exit_error (sitter, &error);
904  }
905 
906  _dbus_string_free (&argv0);
907 
908  if (sitter)
909  _dbus_babysitter_unref (sitter);
910 
911  if (!dbus_error_is_set (&error))
912  {
913  _dbus_warn ("Did not get an error launching segfaulting binary\n");
914  return FALSE;
915  }
916 
917  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
919  {
920  _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
921  error.name, error.message);
922  dbus_error_free (&error);
923  return FALSE;
924  }
925 
926  dbus_error_free (&error);
927 
928  return TRUE;
929 }
930 
931 static dbus_bool_t
932 check_spawn_exit (void *data)
933 {
934  char *argv[4] = { NULL, NULL, NULL, NULL };
935  DBusBabysitter *sitter;
936  DBusError error;
937  DBusString argv0;
938 
939  sitter = NULL;
940 
941  dbus_error_init (&error);
942 
943  /*** Test launching exit failure binary */
944 
945  argv[0] = get_test_exec ("test-exit", &argv0);
946 
947  if (argv[0] == NULL)
948  {
949  /* OOM was simulated, never mind */
950  return TRUE;
951  }
952 
953  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_exit", argv, NULL,
954  NULL, NULL,
955  &error))
956  {
957  _dbus_babysitter_block_for_child_exit (sitter);
958  _dbus_babysitter_set_child_exit_error (sitter, &error);
959  }
960 
961  _dbus_string_free (&argv0);
962 
963  if (sitter)
964  _dbus_babysitter_unref (sitter);
965 
966  if (!dbus_error_is_set (&error))
967  {
968  _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
969  return FALSE;
970  }
971 
972  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
974  {
975  _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
976  error.name, error.message);
977  dbus_error_free (&error);
978  return FALSE;
979  }
980 
981  dbus_error_free (&error);
982 
983  return TRUE;
984 }
985 
986 static dbus_bool_t
987 check_spawn_and_kill (void *data)
988 {
989  char *argv[4] = { NULL, NULL, NULL, NULL };
990  DBusBabysitter *sitter;
991  DBusError error;
992  DBusString argv0;
993 
994  sitter = NULL;
995 
996  dbus_error_init (&error);
997 
998  /*** Test launching sleeping binary then killing it */
999 
1000  argv[0] = get_test_exec ("test-sleep-forever", &argv0);
1001 
1002  if (argv[0] == NULL)
1003  {
1004  /* OOM was simulated, never mind */
1005  return TRUE;
1006  }
1007 
1008  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_and_kill", argv, NULL,
1009  NULL, NULL,
1010  &error))
1011  {
1012  _dbus_babysitter_kill_child (sitter);
1013 
1014  _dbus_babysitter_block_for_child_exit (sitter);
1015 
1016  _dbus_babysitter_set_child_exit_error (sitter, &error);
1017  }
1018 
1019  _dbus_string_free (&argv0);
1020 
1021  if (sitter)
1022  _dbus_babysitter_unref (sitter);
1023 
1024  if (!dbus_error_is_set (&error))
1025  {
1026  _dbus_warn ("Did not get an error after killing spawned binary\n");
1027  return FALSE;
1028  }
1029 
1030  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
1032  {
1033  _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
1034  error.name, error.message);
1035  dbus_error_free (&error);
1036  return FALSE;
1037  }
1038 
1039  dbus_error_free (&error);
1040 
1041  return TRUE;
1042 }
1043 
1045 _dbus_spawn_test (const char *test_data_dir)
1046 {
1047  if (!_dbus_test_oom_handling ("spawn_nonexistent",
1048  check_spawn_nonexistent,
1049  NULL))
1050  return FALSE;
1051 
1052  /* Don't run the obnoxious segfault test by default,
1053  * it's a pain to have to click all those error boxes.
1054  */
1055  if (getenv ("DO_SEGFAULT_TEST"))
1056  if (!_dbus_test_oom_handling ("spawn_segfault",
1057  check_spawn_segfault,
1058  NULL))
1059  return FALSE;
1060 
1061  if (!_dbus_test_oom_handling ("spawn_exit",
1062  check_spawn_exit,
1063  NULL))
1064  return FALSE;
1065 
1066  if (!_dbus_test_oom_handling ("spawn_and_kill",
1067  check_spawn_and_kill,
1068  NULL))
1069  return FALSE;
1070 
1071  return TRUE;
1072 }
1073 #endif
dbus_bool_t dbus_error_has_name(const DBusError *error, const char *name)
Checks whether the error is set and has the given name.
Definition: dbus-errors.c:302
An atomic integer safe to increment or decrement from multiple threads.
Definition: dbus-sysdeps.h:279
const char * message
public error message field
Definition: dbus-errors.h:51
DBusWatch * _dbus_watch_new(DBusPollable fd, unsigned int flags, dbus_bool_t enabled, DBusWatchHandler handler, void *data, DBusFreeFunction free_data_function)
Creates a new DBusWatch.
Definition: dbus-watch.c:88
Implementation of DBusWatch.
Definition: dbus-watch.c:40
#define NULL
A null pointer, defined appropriately for C or C++.
#define DBUS_ERROR_SPAWN_EXEC_FAILED
While starting a new process, the exec() call failed.
void(* DBusFreeFunction)(void *memory)
The type of a function which frees a block of memory.
Definition: dbus-memory.h:64
void(* DBusRemoveWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus no longer needs a watch to be monitored by the main loop.
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:701
dbus_bool_t _dbus_socketpair(DBusSocket *fd1, DBusSocket *fd2, dbus_bool_t blocking, DBusError *error)
Creates pair of connect sockets (as in socketpair()).
#define DBUS_ERROR_SPAWN_CHILD_EXITED
While starting a new process, the child exited with a status code.
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
void dbus_error_free(DBusError *error)
Frees an error that&#39;s been set (or just initialized), then reinitializes the error as in dbus_error_i...
Definition: dbus-errors.c:211
void _dbus_watch_list_free(DBusWatchList *watch_list)
Frees a DBusWatchList.
Definition: dbus-watch.c:249
DBusWatchList * _dbus_watch_list_new(void)
Creates a new watch list.
Definition: dbus-watch.c:232
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
dbus_bool_t _dbus_close_socket(DBusSocket fd, DBusError *error)
Closes a socket.
dbus_bool_t _dbus_babysitter_get_child_exited(DBusBabysitter *sitter)
Checks whether the child has exited, without blocking.
Definition: dbus-spawn.c:706
dbus_bool_t _dbus_watch_list_set_functions(DBusWatchList *watch_list, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function)
Sets the watch functions.
Definition: dbus-watch.c:296
Socket interface.
Definition: dbus-sysdeps.h:148
dbus_bool_t(* DBusAddWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus needs a new watch to be monitored by the main loop.
DBusWatchList * watches
Watches.
void * dbus_malloc(size_t bytes)
Allocates the given number of bytes, as with standard malloc().
Definition: dbus-memory.c:461
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition: dbus-memory.h:59
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
DBusWatch * sitter_watch
Sitter pipe watch.
dbus_bool_t _dbus_babysitter_get_child_exit_status(DBusBabysitter *sitter, int *status)
Gets the exit status of the child.
Definition: dbus-spawn.c:731
void _dbus_babysitter_kill_child(DBusBabysitter *sitter)
Blocks until the babysitter process gives us the PID of the spawned grandchild, then kills the spawne...
Definition: dbus-spawn.c:684
Babysitter implementation details.
dbus_bool_t _dbus_spawn_async_with_babysitter(DBusBabysitter **sitter_p, const char *log_name, char **argv, char **env, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error)
Spawns a new process.
Definition: dbus-spawn.c:1210
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
dbus_int32_t _dbus_atomic_inc(DBusAtomic *atomic)
Atomically increments an integer.
dbus_bool_t _dbus_string_append_printf(DBusString *str, const char *format,...)
Appends a printf-style formatted string to the DBusString.
Definition: dbus-string.c:1114
void _dbus_watch_invalidate(DBusWatch *watch)
Clears the file descriptor from a now-invalid watch object so that no one tries to use it...
Definition: dbus-watch.c:169
dbus_bool_t _dbus_babysitter_set_watch_functions(DBusBabysitter *sitter, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, DBusWatchToggledFunction toggled_function, void *data, DBusFreeFunction free_data_function)
Sets watch functions to notify us when the babysitter object needs to read/write file descriptors...
Definition: dbus-spawn.c:813
Object representing an exception.
Definition: dbus-errors.h:48
void dbus_set_error(DBusError *error, const char *name, const char *format,...)
Assigns an error name and message to a DBusError.
Definition: dbus-errors.c:354
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:259
#define TRUE
Expands to &quot;1&quot;.
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
#define DBUS_ERROR_FAILED
A generic error; &quot;something went wrong&quot; - see the error message for more.
dbus_bool_t _dbus_watch_list_add_watch(DBusWatchList *watch_list, DBusWatch *watch)
Adds a new watch to the watch list, invoking the application DBusAddWatchFunction if appropriate...
Definition: dbus-watch.c:382
const char * name
public error name field
Definition: dbus-errors.h:50
DBusWatchList implementation details.
Definition: dbus-watch.c:214
void _dbus_watch_list_remove_watch(DBusWatchList *watch_list, DBusWatch *watch)
Removes a watch from the watch list, invoking the application&#39;s DBusRemoveWatchFunction if appropriat...
Definition: dbus-watch.c:415
void _dbus_babysitter_unref(DBusBabysitter *sitter)
Decrement the reference count on the babysitter object.
Definition: dbus-spawn.c:324
void dbus_error_init(DBusError *error)
Initializes a DBusError structure.
Definition: dbus-errors.c:188
dbus_int32_t _dbus_atomic_dec(DBusAtomic *atomic)
Atomically decrement an integer.
#define DBUS_ERROR_SPAWN_FORK_FAILED
While starting a new process, the fork() call failed.
char * log_name
the name under which to log messages about this process being spawned
void _dbus_watch_unref(DBusWatch *watch)
Decrements the reference count of a DBusWatch object and finalizes the object if the count reaches ze...
Definition: dbus-watch.c:138
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
#define FALSE
Expands to &quot;0&quot;.
void dbus_set_error_const(DBusError *error, const char *name, const char *message)
Assigns an error name and message to a DBusError.
Definition: dbus-errors.c:243
void(* DBusWatchToggledFunction)(DBusWatch *watch, void *data)
Called when dbus_watch_get_enabled() may return a different value than it did before.
As in POLLIN.
DBusSocket socket_to_babysitter
Connection to the babysitter process.
char * _dbus_strdup(const char *str)
Duplicates a string.
void _dbus_babysitter_set_child_exit_error(DBusBabysitter *sitter, DBusError *error)
Sets the DBusError with an explanation of why the spawned child process exited (on a signal...
Definition: dbus-spawn.c:755
const char * _dbus_getenv(const char *varname)
Wrapper for getenv().
Definition: dbus-sysdeps.c:185
dbus_bool_t dbus_error_is_set(const DBusError *error)
Checks whether an error occurred (the error is set).
Definition: dbus-errors.c:329
DBusBabysitter * _dbus_babysitter_ref(DBusBabysitter *sitter)
Increment the reference count on the babysitter object.
Definition: dbus-spawn.c:302