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