D-Bus  1.4.10
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 //#define STRICT
46 //#include <windows.h>
47 //#undef STRICT
48 #include <winsock2.h>
49 #undef interface
50 
51 #include <stdlib.h>
52 
53 #ifndef DBUS_WINCE
54 #include <process.h>
55 #endif
56 
61  {
62  int refcount;
63 
64  HANDLE start_sync_event;
65 #ifdef DBUS_BUILD_TESTS
66 
67  HANDLE end_sync_event;
68 #endif
69 
70  char *executable;
71  DBusSpawnChildSetupFunc child_setup;
72  void *user_data;
73 
74  int argc;
75  char **argv;
76  char **envp;
77 
78  HANDLE child_handle;
79  int socket_to_babysitter; /* Connection to the babysitter thread */
80  int socket_to_main;
81 
84 
85  dbus_bool_t have_spawn_errno;
86  int spawn_errno;
87  dbus_bool_t have_child_status;
88  int child_status;
89  };
90 
91 static DBusBabysitter*
92 _dbus_babysitter_new (void)
93 {
94  DBusBabysitter *sitter;
95 
96  sitter = dbus_new0 (DBusBabysitter, 1);
97  if (sitter == NULL)
98  return NULL;
99 
100  sitter->refcount = 1;
101 
102  sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
103  if (sitter->start_sync_event == NULL)
104  {
105  _dbus_babysitter_unref (sitter);
106  return NULL;
107  }
108 
109 #ifdef DBUS_BUILD_TESTS
110  sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
111  if (sitter->end_sync_event == NULL)
112  {
113  _dbus_babysitter_unref (sitter);
114  return NULL;
115  }
116 #endif
117 
118  sitter->child_handle = NULL;
119 
120  sitter->socket_to_babysitter = sitter->socket_to_main = -1;
121 
122  sitter->argc = 0;
123  sitter->argv = NULL;
124  sitter->envp = NULL;
125 
126  sitter->watches = _dbus_watch_list_new ();
127  if (sitter->watches == NULL)
128  {
129  _dbus_babysitter_unref (sitter);
130  return NULL;
131  }
132 
133  sitter->have_spawn_errno = FALSE;
134  sitter->have_child_status = FALSE;
135 
136  return sitter;
137 }
138 
147 {
148  PING();
149  _dbus_assert (sitter != NULL);
150  _dbus_assert (sitter->refcount > 0);
151 
152  sitter->refcount += 1;
153 
154  return sitter;
155 }
156 
162 void
164 {
165  int i;
166 
167  PING();
168  _dbus_assert (sitter != NULL);
169  _dbus_assert (sitter->refcount > 0);
170 
171  sitter->refcount -= 1;
172 
173  if (sitter->refcount == 0)
174  {
175  if (sitter->socket_to_babysitter != -1)
176  {
178  sitter->socket_to_babysitter = -1;
179  }
180 
181  if (sitter->socket_to_main != -1)
182  {
183  _dbus_close_socket (sitter->socket_to_main, NULL);
184  sitter->socket_to_main = -1;
185  }
186 
187  PING();
188  if (sitter->argv != NULL)
189  {
190  for (i = 0; i < sitter->argc; i++)
191  if (sitter->argv[i] != NULL)
192  {
193  dbus_free (sitter->argv[i]);
194  sitter->argv[i] = NULL;
195  }
196  dbus_free (sitter->argv);
197  sitter->argv = NULL;
198  }
199 
200  if (sitter->envp != NULL)
201  {
202  char **e = sitter->envp;
203 
204  while (*e)
205  dbus_free (*e++);
206  dbus_free (sitter->envp);
207  sitter->envp = NULL;
208  }
209 
210  if (sitter->child_handle != NULL)
211  {
212  CloseHandle (sitter->child_handle);
213  sitter->child_handle = NULL;
214  }
215 
216  if (sitter->sitter_watch)
217  {
220  sitter->sitter_watch = NULL;
221  }
222 
223  if (sitter->watches)
224  _dbus_watch_list_free (sitter->watches);
225 
226  if (sitter->start_sync_event != NULL)
227  {
228  PING();
229  CloseHandle (sitter->start_sync_event);
230  sitter->start_sync_event = NULL;
231  }
232 
233 #ifdef DBUS_BUILD_TESTS
234  if (sitter->end_sync_event != NULL)
235  {
236  CloseHandle (sitter->end_sync_event);
237  sitter->end_sync_event = NULL;
238  }
239 #endif
240 
241  dbus_free (sitter->executable);
242 
243  dbus_free (sitter);
244  }
245 }
246 
247 void
249 {
250  PING();
251  if (sitter->child_handle == NULL)
252  return; /* child is already dead, or we're so hosed we'll never recover */
253 
254  PING();
255  TerminateProcess (sitter->child_handle, 12345);
256 }
257 
265 {
266  PING();
267  return (sitter->child_handle == NULL);
268 }
269 
284  int *status)
285 {
286  if (!_dbus_babysitter_get_child_exited (sitter))
287  _dbus_assert_not_reached ("Child has not exited");
288 
289  if (!sitter->have_child_status ||
290  sitter->child_status == STILL_ACTIVE)
291  return FALSE;
292 
293  *status = sitter->child_status;
294  return TRUE;
295 }
296 
306 void
308  DBusError *error)
309 {
310  PING();
311  if (!_dbus_babysitter_get_child_exited (sitter))
312  return;
313 
314  PING();
315  if (sitter->have_spawn_errno)
316  {
317  char *emsg = _dbus_win_error_string (sitter->spawn_errno);
319  "Failed to execute program %s: %s",
320  sitter->executable, emsg);
321  _dbus_win_free_error_string (emsg);
322  }
323  else if (sitter->have_child_status)
324  {
325  PING();
327  "Process %s exited with status %d",
328  sitter->executable, sitter->child_status);
329  }
330  else
331  {
332  PING();
334  "Process %s exited, status unknown",
335  sitter->executable);
336  }
337  PING();
338 }
339 
342  DBusAddWatchFunction add_function,
343  DBusRemoveWatchFunction remove_function,
344  DBusWatchToggledFunction toggled_function,
345  void *data,
346  DBusFreeFunction free_data_function)
347 {
348  PING();
349  return _dbus_watch_list_set_functions (sitter->watches,
350  add_function,
351  remove_function,
352  toggled_function,
353  data,
354  free_data_function);
355 }
356 
357 static dbus_bool_t
358 handle_watch (DBusWatch *watch,
359  unsigned int condition,
360  void *data)
361 {
362  DBusBabysitter *sitter = data;
363 
364  /* On Unix dbus-spawn uses a babysitter *process*, thus it has to
365  * actually send the exit statuses, error codes and whatnot through
366  * sockets and/or pipes. On Win32, the babysitter is jus a thread,
367  * so it can set the status fields directly in the babysitter struct
368  * just fine. The socket pipe is used just so we can watch it with
369  * select(), as soon as anything is written to it we know that the
370  * babysitter thread has recorded the status in the babysitter
371  * struct.
372  */
373 
374  PING();
376  PING();
377  sitter->socket_to_babysitter = -1;
378 
379  return TRUE;
380 }
381 
382 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */
383 static int
384 protect_argv (char **argv,
385  char ***new_argv)
386 {
387  int i;
388  int argc = 0;
389 
390  while (argv[argc])
391  ++argc;
392  *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
393  if (*new_argv == NULL)
394  return -1;
395 
396  for (i = 0; i < argc; i++)
397  (*new_argv)[i] = NULL;
398 
399  /* Quote each argv element if necessary, so that it will get
400  * reconstructed correctly in the C runtime startup code. Note that
401  * the unquoting algorithm in the C runtime is really weird, and
402  * rather different than what Unix shells do. See stdargv.c in the C
403  * runtime sources (in the Platform SDK, in src/crt).
404  *
405  * Note that an new_argv[0] constructed by this function should
406  * *not* be passed as the filename argument to a spawn* or exec*
407  * family function. That argument should be the real file name
408  * without any quoting.
409  */
410  for (i = 0; i < argc; i++)
411  {
412  char *p = argv[i];
413  char *q;
414  int len = 0;
415  int need_dblquotes = FALSE;
416  while (*p)
417  {
418  if (*p == ' ' || *p == '\t')
419  need_dblquotes = TRUE;
420  else if (*p == '"')
421  len++;
422  else if (*p == '\\')
423  {
424  char *pp = p;
425  while (*pp && *pp == '\\')
426  pp++;
427  if (*pp == '"')
428  len++;
429  }
430  len++;
431  p++;
432  }
433 
434  q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
435 
436  if (q == NULL)
437  return -1;
438 
439 
440  p = argv[i];
441 
442  if (need_dblquotes)
443  *q++ = '"';
444 
445  while (*p)
446  {
447  if (*p == '"')
448  *q++ = '\\';
449  else if (*p == '\\')
450  {
451  char *pp = p;
452  while (*pp && *pp == '\\')
453  pp++;
454  if (*pp == '"')
455  *q++ = '\\';
456  }
457  *q++ = *p;
458  p++;
459  }
460 
461  if (need_dblquotes)
462  *q++ = '"';
463  *q++ = '\0';
464  /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
465  }
466  (*new_argv)[argc] = NULL;
467 
468  return argc;
469 }
470 
471 
472 /* From GPGME, relicensed by g10 Code GmbH. */
473 static char *
474 compose_string (char **strings, char separator)
475 {
476  int i;
477  int n = 0;
478  char *buf;
479  char *p;
480  const char *ptr;
481 
482  if (!strings || !strings[0])
483  return 0;
484  for (i = 0; strings[i]; i++)
485  n += strlen (strings[i]) + 1;
486  n++;
487 
488  buf = p = malloc (n);
489  if (!buf)
490  return NULL;
491  for (i = 0; strings[i]; i++)
492  {
493  strcpy (p, strings[i]);
494  p += strlen (strings[i]);
495  *(p++) = separator;
496  }
497  p--;
498  *(p++) = '\0';
499  *p = '\0';
500 
501  return buf;
502 }
503 
504 static char *
505 build_commandline (char **argv)
506 {
507  return compose_string (argv, ' ');
508 }
509 
510 static char *
511 build_env_string (char** envp)
512 {
513  return compose_string (envp, '\0');
514 }
515 
516 static HANDLE
517 spawn_program (char* name, char** argv, char** envp)
518 {
519  PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
520  STARTUPINFOA si;
521  char *arg_string, *env_string;
522  BOOL result;
523 
524 #ifdef DBUS_WINCE
525  if (argv && argv[0])
526  arg_string = build_commandline (argv + 1);
527  else
528  arg_string = NULL;
529 #else
530  arg_string = build_commandline (argv);
531 #endif
532  if (!arg_string)
533  return INVALID_HANDLE_VALUE;
534 
535  env_string = build_env_string(envp);
536 
537  memset (&si, 0, sizeof (si));
538  si.cb = sizeof (si);
539 #ifdef DBUS_WINCE
540  result = CreateProcessA (name, arg_string, NULL, NULL, FALSE, 0,
541 #else
542  result = CreateProcessA (NULL, arg_string, NULL, NULL, FALSE, 0,
543 #endif
544  (LPVOID)env_string, NULL, &si, &pi);
545  free (arg_string);
546  if (env_string)
547  free (env_string);
548 
549  if (!result)
550  return INVALID_HANDLE_VALUE;
551 
552  CloseHandle (pi.hThread);
553  return pi.hProcess;
554 }
555 
556 
557 static DWORD __stdcall
558 babysitter (void *parameter)
559 {
560  DBusBabysitter *sitter = (DBusBabysitter *) parameter;
561  int fd;
562  PING();
563  _dbus_babysitter_ref (sitter);
564 
565  if (sitter->child_setup)
566  {
567  PING();
568  (*sitter->child_setup) (sitter->user_data);
569  }
570 
571  _dbus_verbose ("babysitter: spawning %s\n", sitter->executable);
572 
573  PING();
574  sitter->child_handle = spawn_program (sitter->executable,
575  sitter->argv, sitter->envp);
576 
577  PING();
578  if (sitter->child_handle == (HANDLE) -1)
579  {
580  sitter->child_handle = NULL;
581  sitter->have_spawn_errno = TRUE;
582  sitter->spawn_errno = GetLastError();
583  }
584 
585  PING();
586  SetEvent (sitter->start_sync_event);
587 
588  if (sitter->child_handle != NULL)
589  {
590  int ret;
591  DWORD status;
592 
593  PING();
594  WaitForSingleObject (sitter->child_handle, INFINITE);
595 
596  PING();
597  ret = GetExitCodeProcess (sitter->child_handle, &status);
598 
599  sitter->child_status = status;
600  sitter->have_child_status = TRUE;
601 
602  CloseHandle (sitter->child_handle);
603  sitter->child_handle = NULL;
604  }
605 
606 #ifdef DBUS_BUILD_TESTS
607  SetEvent (sitter->end_sync_event);
608 #endif
609 
610  PING();
611  send (sitter->socket_to_main, " ", 1, 0);
612 
613  _dbus_babysitter_unref (sitter);
614 
615  return 0;
616 }
617 
620  char **argv,
621  char **envp,
622  DBusSpawnChildSetupFunc child_setup,
623  void *user_data,
624  DBusError *error)
625 {
626  DBusBabysitter *sitter;
627  HANDLE sitter_thread;
628  DWORD sitter_thread_id;
629 
630  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
631 
632  *sitter_p = NULL;
633 
634  PING();
635  sitter = _dbus_babysitter_new ();
636  if (sitter == NULL)
637  {
638  _DBUS_SET_OOM (error);
639  return FALSE;
640  }
641 
642  sitter->child_setup = child_setup;
643  sitter->user_data = user_data;
644 
645  sitter->executable = _dbus_strdup (argv[0]);
646  if (sitter->executable == NULL)
647  {
648  _DBUS_SET_OOM (error);
649  goto out0;
650  }
651 
652  PING();
654  &sitter->socket_to_main,
655  FALSE, error))
656  goto out0;
657 
660  TRUE, handle_watch, sitter, NULL);
661  PING();
662  if (sitter->sitter_watch == NULL)
663  {
664  _DBUS_SET_OOM (error);
665  goto out0;
666  }
667 
668  PING();
669  if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
670  {
671  _DBUS_SET_OOM (error);
672  goto out0;
673  }
674 
675  sitter->argc = protect_argv (argv, &sitter->argv);
676  if (sitter->argc == -1)
677  {
678  _DBUS_SET_OOM (error);
679  goto out0;
680  }
681  sitter->envp = envp;
682 
683  PING();
684  sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter,
685  sitter, 0, &sitter_thread_id);
686 
687  if (sitter_thread == 0)
688  {
689  PING();
691  "Failed to create new thread");
692  goto out0;
693  }
694  CloseHandle (sitter_thread);
695 
696  PING();
697  WaitForSingleObject (sitter->start_sync_event, INFINITE);
698 
699  PING();
700  if (sitter_p != NULL)
701  *sitter_p = sitter;
702  else
703  _dbus_babysitter_unref (sitter);
704 
705  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
706 
707  PING();
708  return TRUE;
709 
710 out0:
711  _dbus_babysitter_unref (sitter);
712 
713  return FALSE;
714 }
715 
716 #ifdef DBUS_BUILD_TESTS
717 
718 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
719 
720 static void
721 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
722 {
723  if (sitter->child_handle == NULL)
724  return;
725 
726  WaitForSingleObject (sitter->end_sync_event, INFINITE);
727 }
728 
729 static dbus_bool_t
730 check_spawn_nonexistent (void *data)
731 {
732  char *argv[4] = { NULL, NULL, NULL, NULL };
733  DBusBabysitter *sitter;
734  DBusError error;
735 
736  sitter = NULL;
737 
738  dbus_error_init (&error);
739 
740  /*** Test launching nonexistent binary */
741 
742  argv[0] = "/this/does/not/exist/32542sdgafgafdg";
743  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
744  NULL, NULL,
745  &error))
746  {
747  _dbus_babysitter_block_for_child_exit (sitter);
748  _dbus_babysitter_set_child_exit_error (sitter, &error);
749  }
750 
751  if (sitter)
752  _dbus_babysitter_unref (sitter);
753 
754  if (!dbus_error_is_set (&error))
755  {
756  _dbus_warn ("Did not get an error launching nonexistent executable\n");
757  return FALSE;
758  }
759 
760  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
762  {
763  _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
764  error.name, error.message);
765  dbus_error_free (&error);
766  return FALSE;
767  }
768 
769  dbus_error_free (&error);
770 
771  return TRUE;
772 }
773 
774 static dbus_bool_t
775 check_spawn_segfault (void *data)
776 {
777  char *argv[4] = { NULL, NULL, NULL, NULL };
778  DBusBabysitter *sitter;
779  DBusError error;
780 
781  sitter = NULL;
782 
783  dbus_error_init (&error);
784 
785  /*** Test launching segfault binary */
786 
787  argv[0] = TEST_SEGFAULT_BINARY;
788  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
789  NULL, NULL,
790  &error))
791  {
792  _dbus_babysitter_block_for_child_exit (sitter);
793  _dbus_babysitter_set_child_exit_error (sitter, &error);
794  }
795 
796  if (sitter)
797  _dbus_babysitter_unref (sitter);
798 
799  if (!dbus_error_is_set (&error))
800  {
801  _dbus_warn ("Did not get an error launching segfaulting binary\n");
802  return FALSE;
803  }
804 
805  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
807  {
808  _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
809  error.name, error.message);
810  dbus_error_free (&error);
811  return FALSE;
812  }
813 
814  dbus_error_free (&error);
815 
816  return TRUE;
817 }
818 
819 static dbus_bool_t
820 check_spawn_exit (void *data)
821 {
822  char *argv[4] = { NULL, NULL, NULL, NULL };
823  DBusBabysitter *sitter;
824  DBusError error;
825 
826  sitter = NULL;
827 
828  dbus_error_init (&error);
829 
830  /*** Test launching exit failure binary */
831 
832  argv[0] = TEST_EXIT_BINARY;
833  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
834  NULL, NULL,
835  &error))
836  {
837  _dbus_babysitter_block_for_child_exit (sitter);
838  _dbus_babysitter_set_child_exit_error (sitter, &error);
839  }
840 
841  if (sitter)
842  _dbus_babysitter_unref (sitter);
843 
844  if (!dbus_error_is_set (&error))
845  {
846  _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
847  return FALSE;
848  }
849 
850  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
852  {
853  _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
854  error.name, error.message);
855  dbus_error_free (&error);
856  return FALSE;
857  }
858 
859  dbus_error_free (&error);
860 
861  return TRUE;
862 }
863 
864 static dbus_bool_t
865 check_spawn_and_kill (void *data)
866 {
867  char *argv[4] = { NULL, NULL, NULL, NULL };
868  DBusBabysitter *sitter;
869  DBusError error;
870 
871  sitter = NULL;
872 
873  dbus_error_init (&error);
874 
875  /*** Test launching sleeping binary then killing it */
876 
877  argv[0] = TEST_SLEEP_FOREVER_BINARY;
878  if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
879  NULL, NULL,
880  &error))
881  {
883 
884  _dbus_babysitter_block_for_child_exit (sitter);
885 
886  _dbus_babysitter_set_child_exit_error (sitter, &error);
887  }
888 
889  if (sitter)
890  _dbus_babysitter_unref (sitter);
891 
892  if (!dbus_error_is_set (&error))
893  {
894  _dbus_warn ("Did not get an error after killing spawned binary\n");
895  return FALSE;
896  }
897 
898  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
900  {
901  _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
902  error.name, error.message);
903  dbus_error_free (&error);
904  return FALSE;
905  }
906 
907  dbus_error_free (&error);
908 
909  return TRUE;
910 }
911 
913 _dbus_spawn_test (const char *test_data_dir)
914 {
915  if (!_dbus_test_oom_handling ("spawn_nonexistent",
916  check_spawn_nonexistent,
917  NULL))
918  return FALSE;
919 
920  /* Don't run the obnoxious segfault test by default,
921  * it's a pain to have to click all those error boxes.
922  */
923  if (getenv ("DO_SEGFAULT_TEST"))
924  if (!_dbus_test_oom_handling ("spawn_segfault",
925  check_spawn_segfault,
926  NULL))
927  return FALSE;
928 
929  if (!_dbus_test_oom_handling ("spawn_exit",
930  check_spawn_exit,
931  NULL))
932  return FALSE;
933 
934  if (!_dbus_test_oom_handling ("spawn_and_kill",
935  check_spawn_and_kill,
936  NULL))
937  return FALSE;
938 
939  return TRUE;
940 }
941 #endif