D-Bus  1.11.2
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  int 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 
73  int argc;
74  char **argv;
75  char **envp;
76 
77  HANDLE child_handle;
78  DBusSocket socket_to_babysitter; /* Connection to the babysitter thread */
79  DBusSocket socket_to_main;
80 
83  DBusBabysitterFinishedFunc finished_cb;
84  void *finished_data;
85 
86  dbus_bool_t have_spawn_errno;
87  int spawn_errno;
88  dbus_bool_t have_child_status;
89  int child_status;
90  };
91 
92 static DBusBabysitter*
93 _dbus_babysitter_new (void)
94 {
95  DBusBabysitter *sitter;
96 
97  sitter = dbus_new0 (DBusBabysitter, 1);
98  if (sitter == NULL)
99  return NULL;
100 
101  sitter->refcount = 1;
102 
103  sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
104  if (sitter->start_sync_event == NULL)
105  {
106  _dbus_babysitter_unref (sitter);
107  return NULL;
108  }
109 
110 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
111  sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
112  if (sitter->end_sync_event == NULL)
113  {
114  _dbus_babysitter_unref (sitter);
115  return NULL;
116  }
117 #endif
118 
119  sitter->child_handle = NULL;
120 
121  sitter->socket_to_babysitter = sitter->socket_to_main = _dbus_socket_get_invalid ();
122 
123  sitter->argc = 0;
124  sitter->argv = NULL;
125  sitter->envp = NULL;
126 
127  sitter->watches = _dbus_watch_list_new ();
128  if (sitter->watches == NULL)
129  {
130  _dbus_babysitter_unref (sitter);
131  return NULL;
132  }
133 
134  sitter->have_spawn_errno = FALSE;
135  sitter->have_child_status = FALSE;
136 
137  return sitter;
138 }
139 
148 {
149  PING();
150  _dbus_assert (sitter != NULL);
151  _dbus_assert (sitter->refcount > 0);
152 
153  sitter->refcount += 1;
154 
155  return sitter;
156 }
157 
158 static void
159 close_socket_to_babysitter (DBusBabysitter *sitter)
160 {
161  _dbus_verbose ("Closing babysitter\n");
162 
163  if (sitter->sitter_watch != NULL)
164  {
165  _dbus_assert (sitter->watches != NULL);
169  sitter->sitter_watch = NULL;
170  }
171 
172  if (sitter->socket_to_babysitter.sock != INVALID_SOCKET)
173  {
175  sitter->socket_to_babysitter.sock = INVALID_SOCKET;
176  }
177 }
178 
184 void
186 {
187  int i;
188 
189  PING();
190  _dbus_assert (sitter != NULL);
191  _dbus_assert (sitter->refcount > 0);
192 
193  sitter->refcount -= 1;
194 
195  if (sitter->refcount == 0)
196  {
197  close_socket_to_babysitter (sitter);
198 
199  if (sitter->socket_to_main.sock != INVALID_SOCKET)
200  {
201  _dbus_close_socket (sitter->socket_to_main, NULL);
202  sitter->socket_to_main.sock = INVALID_SOCKET;
203  }
204 
205  PING();
206  if (sitter->argv != NULL)
207  {
208  for (i = 0; i < sitter->argc; i++)
209  if (sitter->argv[i] != NULL)
210  {
211  dbus_free (sitter->argv[i]);
212  sitter->argv[i] = NULL;
213  }
214  dbus_free (sitter->argv);
215  sitter->argv = NULL;
216  }
217 
218  if (sitter->envp != NULL)
219  {
220  char **e = sitter->envp;
221 
222  while (*e)
223  dbus_free (*e++);
224  dbus_free (sitter->envp);
225  sitter->envp = NULL;
226  }
227 
228  if (sitter->child_handle != NULL)
229  {
230  CloseHandle (sitter->child_handle);
231  sitter->child_handle = NULL;
232  }
233 
234  if (sitter->sitter_watch)
235  {
238  sitter->sitter_watch = NULL;
239  }
240 
241  if (sitter->watches)
242  _dbus_watch_list_free (sitter->watches);
243 
244  if (sitter->start_sync_event != NULL)
245  {
246  PING();
247  CloseHandle (sitter->start_sync_event);
248  sitter->start_sync_event = NULL;
249  }
250 
251 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
252  if (sitter->end_sync_event != NULL)
253  {
254  CloseHandle (sitter->end_sync_event);
255  sitter->end_sync_event = NULL;
256  }
257 #endif
258 
259  dbus_free (sitter->log_name);
260 
261  dbus_free (sitter);
262  }
263 }
264 
265 void
267 {
268  PING();
269  if (sitter->child_handle == NULL)
270  return; /* child is already dead, or we're so hosed we'll never recover */
271 
272  PING();
273  TerminateProcess (sitter->child_handle, 12345);
274 }
275 
283 {
284  PING();
285  return (sitter->child_handle == NULL);
286 }
287 
302  int *status)
303 {
304  if (!_dbus_babysitter_get_child_exited (sitter))
305  _dbus_assert_not_reached ("Child has not exited");
306 
307  if (!sitter->have_child_status ||
308  sitter->child_status == STILL_ACTIVE)
309  return FALSE;
310 
311  *status = sitter->child_status;
312  return TRUE;
313 }
314 
324 void
326  DBusError *error)
327 {
328  PING();
329  if (!_dbus_babysitter_get_child_exited (sitter))
330  return;
331 
332  PING();
333  if (sitter->have_spawn_errno)
334  {
335  char *emsg = _dbus_win_error_string (sitter->spawn_errno);
337  "Failed to execute program %s: %s",
338  sitter->log_name, emsg);
339  _dbus_win_free_error_string (emsg);
340  }
341  else if (sitter->have_child_status)
342  {
343  PING();
345  "Process %s exited with status %d",
346  sitter->log_name, sitter->child_status);
347  }
348  else
349  {
350  PING();
352  "Process %s exited, status unknown",
353  sitter->log_name);
354  }
355  PING();
356 }
357 
360  DBusAddWatchFunction add_function,
361  DBusRemoveWatchFunction remove_function,
362  DBusWatchToggledFunction toggled_function,
363  void *data,
364  DBusFreeFunction free_data_function)
365 {
366  PING();
367  return _dbus_watch_list_set_functions (sitter->watches,
368  add_function,
369  remove_function,
370  toggled_function,
371  data,
372  free_data_function);
373 }
374 
375 static dbus_bool_t
376 handle_watch (DBusWatch *watch,
377  unsigned int condition,
378  void *data)
379 {
380  DBusBabysitter *sitter = data;
381 
382  /* On Unix dbus-spawn uses a babysitter *process*, thus it has to
383  * actually send the exit statuses, error codes and whatnot through
384  * sockets and/or pipes. On Win32, the babysitter is jus a thread,
385  * so it can set the status fields directly in the babysitter struct
386  * just fine. The socket pipe is used just so we can watch it with
387  * select(), as soon as anything is written to it we know that the
388  * babysitter thread has recorded the status in the babysitter
389  * struct.
390  */
391 
392  PING();
393  close_socket_to_babysitter (sitter);
394  PING();
395 
396  if (_dbus_babysitter_get_child_exited (sitter) &&
397  sitter->finished_cb != NULL)
398  {
399  sitter->finished_cb (sitter, sitter->finished_data);
400  sitter->finished_cb = NULL;
401  }
402 
403  return TRUE;
404 }
405 
406 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */
407 static int
408 protect_argv (char **argv,
409  char ***new_argv)
410 {
411  int i;
412  int argc = 0;
413 
414  while (argv[argc])
415  ++argc;
416  *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
417  if (*new_argv == NULL)
418  return -1;
419 
420  for (i = 0; i < argc; i++)
421  (*new_argv)[i] = NULL;
422 
423  /* Quote each argv element if necessary, so that it will get
424  * reconstructed correctly in the C runtime startup code. Note that
425  * the unquoting algorithm in the C runtime is really weird, and
426  * rather different than what Unix shells do. See stdargv.c in the C
427  * runtime sources (in the Platform SDK, in src/crt).
428  *
429  * Note that an new_argv[0] constructed by this function should
430  * *not* be passed as the filename argument to a spawn* or exec*
431  * family function. That argument should be the real file name
432  * without any quoting.
433  */
434  for (i = 0; i < argc; i++)
435  {
436  char *p = argv[i];
437  char *q;
438  int len = 0;
439  int need_dblquotes = FALSE;
440  while (*p)
441  {
442  if (*p == ' ' || *p == '\t')
443  need_dblquotes = TRUE;
444  else if (*p == '"')
445  len++;
446  else if (*p == '\\')
447  {
448  char *pp = p;
449  while (*pp && *pp == '\\')
450  pp++;
451  if (*pp == '"')
452  len++;
453  }
454  len++;
455  p++;
456  }
457 
458  q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
459 
460  if (q == NULL)
461  return -1;
462 
463 
464  p = argv[i];
465 
466  if (need_dblquotes)
467  *q++ = '"';
468 
469  while (*p)
470  {
471  if (*p == '"')
472  *q++ = '\\';
473  else if (*p == '\\')
474  {
475  char *pp = p;
476  while (*pp && *pp == '\\')
477  pp++;
478  if (*pp == '"')
479  *q++ = '\\';
480  }
481  *q++ = *p;
482  p++;
483  }
484 
485  if (need_dblquotes)
486  *q++ = '"';
487  *q++ = '\0';
488  /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
489  }
490  (*new_argv)[argc] = NULL;
491 
492  return argc;
493 }
494 
495 
496 /* From GPGME, relicensed by g10 Code GmbH. */
497 static char *
498 compose_string (char **strings, char separator)
499 {
500  int i;
501  int n = 0;
502  char *buf;
503  char *p;
504 
505  if (!strings || !strings[0])
506  return 0;
507  for (i = 0; strings[i]; i++)
508  n += strlen (strings[i]) + 1;
509  n++;
510 
511  buf = p = malloc (n);
512  if (!buf)
513  return NULL;
514  for (i = 0; strings[i]; i++)
515  {
516  strcpy (p, strings[i]);
517  p += strlen (strings[i]);
518  *(p++) = separator;
519  }
520  p--;
521  *(p++) = '\0';
522  *p = '\0';
523 
524  return buf;
525 }
526 
527 static char *
528 build_commandline (char **argv)
529 {
530  return compose_string (argv, ' ');
531 }
532 
533 static char *
534 build_env_string (char** envp)
535 {
536  return compose_string (envp, '\0');
537 }
538 
539 static HANDLE
540 spawn_program (char* name, char** argv, char** envp)
541 {
542  PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
543  STARTUPINFOA si;
544  char *arg_string, *env_string;
545  BOOL result;
546 
547 #ifdef DBUS_WINCE
548  if (argv && argv[0])
549  arg_string = build_commandline (argv + 1);
550  else
551  arg_string = NULL;
552 #else
553  arg_string = build_commandline (argv);
554 #endif
555  if (!arg_string)
556  return INVALID_HANDLE_VALUE;
557 
558  env_string = build_env_string(envp);
559 
560  memset (&si, 0, sizeof (si));
561  si.cb = sizeof (si);
562 #ifdef DBUS_WINCE
563  result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0,
564 #else
565  result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0,
566 #endif
567  (LPVOID)env_string, NULL, &si, &pi);
568  free (arg_string);
569  if (env_string)
570  free (env_string);
571 
572  if (!result)
573  return INVALID_HANDLE_VALUE;
574 
575  CloseHandle (pi.hThread);
576  return pi.hProcess;
577 }
578 
579 
580 static DWORD __stdcall
581 babysitter (void *parameter)
582 {
583  int ret = 0;
584  DBusBabysitter *sitter = (DBusBabysitter *) parameter;
585 
586  PING();
587  _dbus_babysitter_ref (sitter);
588 
589  _dbus_verbose ("babysitter: spawning %s\n", sitter->log_name);
590 
591  PING();
592  sitter->child_handle = spawn_program (sitter->log_name,
593  sitter->argv, sitter->envp);
594 
595  PING();
596  if (sitter->child_handle == (HANDLE) -1)
597  {
598  sitter->child_handle = NULL;
599  sitter->have_spawn_errno = TRUE;
600  sitter->spawn_errno = GetLastError();
601  }
602 
603  PING();
604  SetEvent (sitter->start_sync_event);
605 
606  if (sitter->child_handle != NULL)
607  {
608  DWORD status;
609 
610  PING();
611  // wait until process finished
612  WaitForSingleObject (sitter->child_handle, INFINITE);
613 
614  PING();
615  ret = GetExitCodeProcess (sitter->child_handle, &status);
616  if (ret)
617  {
618  sitter->child_status = status;
619  sitter->have_child_status = TRUE;
620  }
621 
622  CloseHandle (sitter->child_handle);
623  sitter->child_handle = NULL;
624  }
625 
626 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
627  SetEvent (sitter->end_sync_event);
628 #endif
629 
630  PING();
631  send (sitter->socket_to_main.sock, " ", 1, 0);
632 
633  _dbus_babysitter_unref (sitter);
634 
635  return ret ? 0 : 1;
636 }
637 
640  const char *log_name,
641  char **argv,
642  char **envp,
643  DBusSpawnChildSetupFunc child_setup _DBUS_GNUC_UNUSED,
644  void *user_data _DBUS_GNUC_UNUSED,
645  DBusError *error)
646 {
647  DBusBabysitter *sitter;
648  HANDLE sitter_thread;
649  DWORD sitter_thread_id;
650 
651  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
652  _dbus_assert (argv[0] != NULL);
653 
654  *sitter_p = NULL;
655 
656  PING();
657  sitter = _dbus_babysitter_new ();
658  if (sitter == NULL)
659  {
660  _DBUS_SET_OOM (error);
661  return FALSE;
662  }
663 
664  sitter->log_name = _dbus_strdup (log_name);
665  if (sitter->log_name == NULL && log_name != NULL)
666  {
667  _DBUS_SET_OOM (error);
668  goto out0;
669  }
670 
671  if (sitter->log_name == NULL)
672  sitter->log_name = _dbus_strdup (argv[0]);
673 
674  if (sitter->log_name == NULL)
675  {
676  _DBUS_SET_OOM (error);
677  goto out0;
678  }
679 
680  PING();
681  if (!_dbus_socketpair (&sitter->socket_to_babysitter,
682  &sitter->socket_to_main,
683  FALSE, error))
684  goto out0;
685 
688  TRUE, handle_watch, sitter, NULL);
689  PING();
690  if (sitter->sitter_watch == NULL)
691  {
692  _DBUS_SET_OOM (error);
693  goto out0;
694  }
695 
696  PING();
697  if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
698  {
699  /* we need to free it early so the destructor won't try to remove it
700  * without it having been added, which DBusLoop doesn't allow */
703  sitter->sitter_watch = NULL;
704 
705  _DBUS_SET_OOM (error);
706  goto out0;
707  }
708 
709  sitter->argc = protect_argv (argv, &sitter->argv);
710  if (sitter->argc == -1)
711  {
712  _DBUS_SET_OOM (error);
713  goto out0;
714  }
715  sitter->envp = envp;
716 
717  PING();
718  sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter,
719  sitter, 0, &sitter_thread_id);
720 
721  if (sitter_thread == 0)
722  {
723  PING();
725  "Failed to create new thread");
726  goto out0;
727  }
728  CloseHandle (sitter_thread);
729 
730  PING();
731  WaitForSingleObject (sitter->start_sync_event, INFINITE);
732 
733  PING();
734  if (sitter_p != NULL)
735  *sitter_p = sitter;
736  else
737  _dbus_babysitter_unref (sitter);
738 
739  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
740 
741  PING();
742  return TRUE;
743 
744 out0:
745  _dbus_babysitter_unref (sitter);
746 
747  return FALSE;
748 }
749 
750 void
751 _dbus_babysitter_set_result_function (DBusBabysitter *sitter,
752  DBusBabysitterFinishedFunc finished,
753  void *user_data)
754 {
755  sitter->finished_cb = finished;
756  sitter->finished_data = user_data;
757 }
758 
759 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
760 
761 static char *
762 get_test_exec (const char *exe,
763  DBusString *scratch_space)
764 {
765  const char *dbus_test_exec;
766 
767  dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC");
768 
769  if (dbus_test_exec == NULL)
770  dbus_test_exec = DBUS_TEST_EXEC;
771 
772  if (!_dbus_string_init (scratch_space))
773  return NULL;
774 
775  if (!_dbus_string_append_printf (scratch_space, "%s/%s%s",
776  dbus_test_exec, exe, DBUS_EXEEXT))
777  {
778  _dbus_string_free (scratch_space);
779  return NULL;
780  }
781 
782  return _dbus_string_get_data (scratch_space);
783 }
784 
785 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
786 
787 static void
788 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
789 {
790  if (sitter->child_handle == NULL)
791  return;
792 
793  WaitForSingleObject (sitter->end_sync_event, INFINITE);
794 }
795 
796 static dbus_bool_t
797 check_spawn_nonexistent (void *data)
798 {
799  char *argv[4] = { NULL, NULL, NULL, NULL };
800  DBusBabysitter *sitter;
801  DBusError error;
802 
803  sitter = NULL;
804 
805  dbus_error_init (&error);
806 
807  /*** Test launching nonexistent binary */
808 
809  argv[0] = "/this/does/not/exist/32542sdgafgafdg";
810  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_nonexistent", argv, NULL,
811  NULL, NULL,
812  &error))
813  {
814  _dbus_babysitter_block_for_child_exit (sitter);
815  _dbus_babysitter_set_child_exit_error (sitter, &error);
816  }
817 
818  if (sitter)
819  _dbus_babysitter_unref (sitter);
820 
821  if (!dbus_error_is_set (&error))
822  {
823  _dbus_warn ("Did not get an error launching nonexistent executable\n");
824  return FALSE;
825  }
826 
827  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
829  {
830  _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
831  error.name, error.message);
832  dbus_error_free (&error);
833  return FALSE;
834  }
835 
836  dbus_error_free (&error);
837 
838  return TRUE;
839 }
840 
841 static dbus_bool_t
842 check_spawn_segfault (void *data)
843 {
844  char *argv[4] = { NULL, NULL, NULL, NULL };
845  DBusBabysitter *sitter;
846  DBusError error;
847  DBusString argv0;
848 
849  sitter = NULL;
850 
851  dbus_error_init (&error);
852 
853  /*** Test launching segfault binary */
854 
855  argv[0] = get_test_exec ("test-segfault", &argv0);
856 
857  if (argv[0] == NULL)
858  {
859  /* OOM was simulated, never mind */
860  return TRUE;
861  }
862 
863  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_segfault", argv, NULL,
864  NULL, NULL,
865  &error))
866  {
867  _dbus_babysitter_block_for_child_exit (sitter);
868  _dbus_babysitter_set_child_exit_error (sitter, &error);
869  }
870 
871  _dbus_string_free (&argv0);
872 
873  if (sitter)
874  _dbus_babysitter_unref (sitter);
875 
876  if (!dbus_error_is_set (&error))
877  {
878  _dbus_warn ("Did not get an error launching segfaulting binary\n");
879  return FALSE;
880  }
881 
882  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
884  {
885  _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
886  error.name, error.message);
887  dbus_error_free (&error);
888  return FALSE;
889  }
890 
891  dbus_error_free (&error);
892 
893  return TRUE;
894 }
895 
896 static dbus_bool_t
897 check_spawn_exit (void *data)
898 {
899  char *argv[4] = { NULL, NULL, NULL, NULL };
900  DBusBabysitter *sitter;
901  DBusError error;
902  DBusString argv0;
903 
904  sitter = NULL;
905 
906  dbus_error_init (&error);
907 
908  /*** Test launching exit failure binary */
909 
910  argv[0] = get_test_exec ("test-exit", &argv0);
911 
912  if (argv[0] == NULL)
913  {
914  /* OOM was simulated, never mind */
915  return TRUE;
916  }
917 
918  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_exit", argv, NULL,
919  NULL, NULL,
920  &error))
921  {
922  _dbus_babysitter_block_for_child_exit (sitter);
923  _dbus_babysitter_set_child_exit_error (sitter, &error);
924  }
925 
926  _dbus_string_free (&argv0);
927 
928  if (sitter)
929  _dbus_babysitter_unref (sitter);
930 
931  if (!dbus_error_is_set (&error))
932  {
933  _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
934  return FALSE;
935  }
936 
937  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
939  {
940  _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
941  error.name, error.message);
942  dbus_error_free (&error);
943  return FALSE;
944  }
945 
946  dbus_error_free (&error);
947 
948  return TRUE;
949 }
950 
951 static dbus_bool_t
952 check_spawn_and_kill (void *data)
953 {
954  char *argv[4] = { NULL, NULL, NULL, NULL };
955  DBusBabysitter *sitter;
956  DBusError error;
957  DBusString argv0;
958 
959  sitter = NULL;
960 
961  dbus_error_init (&error);
962 
963  /*** Test launching sleeping binary then killing it */
964 
965  argv[0] = get_test_exec ("test-sleep-forever", &argv0);
966 
967  if (argv[0] == NULL)
968  {
969  /* OOM was simulated, never mind */
970  return TRUE;
971  }
972 
973  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_and_kill", argv, NULL,
974  NULL, NULL,
975  &error))
976  {
978 
979  _dbus_babysitter_block_for_child_exit (sitter);
980 
981  _dbus_babysitter_set_child_exit_error (sitter, &error);
982  }
983 
984  _dbus_string_free (&argv0);
985 
986  if (sitter)
987  _dbus_babysitter_unref (sitter);
988 
989  if (!dbus_error_is_set (&error))
990  {
991  _dbus_warn ("Did not get an error after killing spawned binary\n");
992  return FALSE;
993  }
994 
995  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
997  {
998  _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
999  error.name, error.message);
1000  dbus_error_free (&error);
1001  return FALSE;
1002  }
1003 
1004  dbus_error_free (&error);
1005 
1006  return TRUE;
1007 }
1008 
1010 _dbus_spawn_test (const char *test_data_dir)
1011 {
1012  if (!_dbus_test_oom_handling ("spawn_nonexistent",
1013  check_spawn_nonexistent,
1014  NULL))
1015  return FALSE;
1016 
1017  /* Don't run the obnoxious segfault test by default,
1018  * it's a pain to have to click all those error boxes.
1019  */
1020  if (getenv ("DO_SEGFAULT_TEST"))
1021  if (!_dbus_test_oom_handling ("spawn_segfault",
1022  check_spawn_segfault,
1023  NULL))
1024  return FALSE;
1025 
1026  if (!_dbus_test_oom_handling ("spawn_exit",
1027  check_spawn_exit,
1028  NULL))
1029  return FALSE;
1030 
1031  if (!_dbus_test_oom_handling ("spawn_and_kill",
1032  check_spawn_and_kill,
1033  NULL))
1034  return FALSE;
1035 
1036  return TRUE;
1037 }
1038 #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
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 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()).
void(* DBusWatchToggledFunction)(DBusWatch *watch, void *data)
Called when dbus_watch_get_enabled() may return a different value than it did before.
#define DBUS_ERROR_SPAWN_CHILD_EXITED
While starting a new process, the child exited with a status code.
int status
Exit status code.
Definition: dbus-spawn.c:261
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:149
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:1215
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
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
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
int refcount
Reference count.
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:259
#define TRUE
Expands to "1".
#define DBUS_ERROR_FAILED
A generic error; "something went wrong" - see the error message for more.
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
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
dbus_bool_t(* DBusAddWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus needs a new watch to be monitored by the main loop.
void(* DBusRemoveWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus no longer needs a watch to be monitored by the main loop.
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
#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 "0".
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
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