d34f729f159d75f8b42593a702a262bf4150a8b6
[platform/upstream/dbus.git] / dbus / 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 #ifdef DBUS_WINCE
13 #include <process.h>
14 #endif
15
16 /* -*- mode: C; c-file-style: "gnu" -*- */
17 /* dbus-spawn-win32.c Wrapper around g_spawn
18  * 
19  * Copyright (C) 2002, 2003, 2004  Red Hat, Inc.
20  * Copyright (C) 2003 CodeFactory AB
21  * Copyright (C) 2005 Novell, Inc.
22  *
23  * Licensed under the Academic Free License version 2.1
24  * 
25  * This program is free software; you can redistribute it and/or modify
26  * it under the terms of the GNU General Public License as published by
27  * the Free Software Foundation; either version 2 of the License, or
28  * (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33  * GNU General Public License for more details.
34  * 
35  * You should have received a copy of the GNU General Public License
36  * along with this program; if not, write to the Free Software
37  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
38  *
39  */
40 #include "dbus-spawn.h"
41 #include "dbus-sysdeps.h"
42 #include "dbus-sysdeps-win.h"
43 #include "dbus-internals.h"
44 #include "dbus-test.h"
45 #include "dbus-protocol.h"
46
47 #define WIN32_LEAN_AND_MEAN
48 //#define STRICT
49 //#include <windows.h>
50 //#undef STRICT
51 #include <winsock2.h>
52 #undef interface
53
54 #include <stdlib.h>
55
56 #include <process.h>
57
58 /**
59  * Babysitter implementation details
60  */
61 struct DBusBabysitter
62   {
63     int refcount;
64
65     HANDLE start_sync_event;
66 #ifdef DBUS_BUILD_TESTS
67
68     HANDLE end_sync_event;
69 #endif
70
71     char *executable;
72     DBusSpawnChildSetupFunc child_setup;
73     void *user_data;
74
75     int argc;
76     char **argv;
77     char **envp;
78
79     HANDLE child_handle;
80     int socket_to_babysitter;   /* Connection to the babysitter thread */
81     int socket_to_main;
82
83     DBusWatchList *watches;
84     DBusWatch *sitter_watch;
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_BUILD_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 = -1;
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
140 /**
141  * Increment the reference count on the babysitter object.
142  *
143  * @param sitter the babysitter
144  * @returns the babysitter
145  */
146 DBusBabysitter *
147 _dbus_babysitter_ref (DBusBabysitter *sitter)
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 /**
159  * Decrement the reference count on the babysitter object.
160  *
161  * @param sitter the babysitter
162  */
163 void
164 _dbus_babysitter_unref (DBusBabysitter *sitter)
165 {
166   int i;
167
168   PING();
169   _dbus_assert (sitter != NULL);
170   _dbus_assert (sitter->refcount > 0);
171
172   sitter->refcount -= 1;
173
174   if (sitter->refcount == 0)
175     {
176       if (sitter->socket_to_babysitter != -1)
177         {
178           _dbus_close_socket (sitter->socket_to_babysitter, NULL);
179           sitter->socket_to_babysitter = -1;
180         }
181
182       if (sitter->socket_to_main != -1)
183         {
184           _dbus_close_socket (sitter->socket_to_main, NULL);
185           sitter->socket_to_main = -1;
186         }
187
188       PING();
189       if (sitter->argv != NULL)
190         {
191           for (i = 0; i < sitter->argc; i++)
192             if (sitter->argv[i] != NULL)
193               {
194                 dbus_free (sitter->argv[i]);
195                 sitter->argv[i] = NULL;
196               }
197           dbus_free (sitter->argv);
198           sitter->argv = NULL;
199         }
200
201       if (sitter->envp != NULL)
202         {
203           char **e = sitter->envp;
204
205           while (*e)
206             dbus_free (*e++);
207           dbus_free (sitter->envp);
208           sitter->envp = NULL;
209         }
210
211       if (sitter->child_handle != NULL)
212         {
213           CloseHandle (sitter->child_handle);
214           sitter->child_handle = NULL;
215         }
216
217       if (sitter->sitter_watch)
218         {
219           _dbus_watch_invalidate (sitter->sitter_watch);
220           _dbus_watch_unref (sitter->sitter_watch);
221           sitter->sitter_watch = NULL;
222         }
223
224       if (sitter->watches)
225         _dbus_watch_list_free (sitter->watches);
226
227       if (sitter->start_sync_event != NULL)
228         {
229           PING();
230           CloseHandle (sitter->start_sync_event);
231           sitter->end_sync_event = NULL;
232         }
233
234 #ifdef DBUS_BUILD_TESTS
235       if (sitter->end_sync_event != NULL)
236         {
237           CloseHandle (sitter->end_sync_event);
238           sitter->end_sync_event = NULL;
239         }
240 #endif
241
242       dbus_free (sitter->executable);
243
244       dbus_free (sitter);
245     }
246 }
247
248 void
249 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
250 {
251   PING();
252   if (sitter->child_handle == NULL)
253     return; /* child is already dead, or we're so hosed we'll never recover */
254
255   PING();
256   TerminateProcess (sitter->child_handle, 12345);
257 }
258
259 /**
260  * Checks whether the child has exited, without blocking.
261  *
262  * @param sitter the babysitter
263  */
264 dbus_bool_t
265 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
266 {
267   PING();
268   return (sitter->child_handle == NULL);
269 }
270
271 /**
272  * Sets the #DBusError with an explanation of why the spawned
273  * child process exited (on a signal, or whatever). If
274  * the child process has not exited, does nothing (error
275  * will remain unset).
276  *
277  * @param sitter the babysitter
278  * @param error an error to fill in
279  */
280 void
281 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
282                                        DBusError      *error)
283 {
284   PING();
285   if (!_dbus_babysitter_get_child_exited (sitter))
286     return;
287
288   PING();
289   if (sitter->have_spawn_errno)
290     {
291       dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
292                       "Failed to execute program %s: %s",
293                       sitter->executable, _dbus_strerror (sitter->spawn_errno));
294     }
295   else if (sitter->have_child_status)
296     {
297       PING();
298       dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
299                       "Process %s exited with status %d",
300                       sitter->executable, sitter->child_status);
301     }
302   else
303     {
304       PING();
305       dbus_set_error (error, DBUS_ERROR_FAILED,
306                       "Process %s exited, status unknown",
307                       sitter->executable);
308     }
309   PING();
310 }
311
312 dbus_bool_t
313 _dbus_babysitter_set_watch_functions (DBusBabysitter            *sitter,
314                                       DBusAddWatchFunction       add_function,
315                                       DBusRemoveWatchFunction    remove_function,
316                                       DBusWatchToggledFunction   toggled_function,
317                                       void                      *data,
318                                       DBusFreeFunction           free_data_function)
319 {
320   PING();
321   return _dbus_watch_list_set_functions (sitter->watches,
322                                          add_function,
323                                          remove_function,
324                                          toggled_function,
325                                          data,
326                                          free_data_function);
327 }
328
329 static dbus_bool_t
330 handle_watch (DBusWatch       *watch,
331               unsigned int     condition,
332               void            *data)
333 {
334   DBusBabysitter *sitter = data;
335
336   /* On Unix dbus-spawn uses a babysitter *process*, thus it has to
337    * actually send the exit statuses, error codes and whatnot through
338    * sockets and/or pipes. On Win32, the babysitter is jus a thread,
339    * so it can set the status fields directly in the babysitter struct
340    * just fine. The socket pipe is used just so we can watch it with
341    * select(), as soon as anything is written to it we know that the
342    * babysitter thread has recorded the status in the babysitter
343    * struct.
344    */
345
346   PING();
347   _dbus_close_socket (sitter->socket_to_babysitter, NULL);
348   PING();
349   sitter->socket_to_babysitter = -1;
350
351   return TRUE;
352 }
353
354 /* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */
355 static int
356 protect_argv (char  **argv,
357               char ***new_argv)
358 {
359   int i;
360   int argc = 0;
361
362   while (argv[argc])
363     ++argc;
364   *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
365   if (*new_argv == NULL)
366     return -1;
367
368   for (i = 0; i < argc; i++)
369     (*new_argv)[i] = NULL;
370
371   /* Quote each argv element if necessary, so that it will get
372    * reconstructed correctly in the C runtime startup code.  Note that
373    * the unquoting algorithm in the C runtime is really weird, and
374    * rather different than what Unix shells do. See stdargv.c in the C
375    * runtime sources (in the Platform SDK, in src/crt).
376    *
377    * Note that an new_argv[0] constructed by this function should
378    * *not* be passed as the filename argument to a spawn* or exec*
379    * family function. That argument should be the real file name
380    * without any quoting.
381    */
382   for (i = 0; i < argc; i++)
383     {
384       char *p = argv[i];
385       char *q;
386       int len = 0;
387       int need_dblquotes = FALSE;
388       while (*p)
389         {
390           if (*p == ' ' || *p == '\t')
391             need_dblquotes = TRUE;
392           else if (*p == '"')
393             len++;
394           else if (*p == '\\')
395             {
396               char *pp = p;
397               while (*pp && *pp == '\\')
398                 pp++;
399               if (*pp == '"')
400                 len++;
401             }
402           len++;
403           p++;
404         }
405
406       q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
407
408       if (q == NULL)
409         return -1;
410
411
412       p = argv[i];
413
414       if (need_dblquotes)
415         *q++ = '"';
416
417       while (*p)
418         {
419           if (*p == '"')
420             *q++ = '\\';
421           else if (*p == '\\')
422             {
423               char *pp = p;
424               while (*pp && *pp == '\\')
425                 pp++;
426               if (*pp == '"')
427                 *q++ = '\\';
428             }
429           *q++ = *p;
430           p++;
431         }
432
433       if (need_dblquotes)
434         *q++ = '"';
435       *q++ = '\0';
436       /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
437     }
438   (*new_argv)[argc] = NULL;
439
440   return argc;
441 }
442
443 static unsigned __stdcall
444 babysitter (void *parameter)
445 {
446   DBusBabysitter *sitter = (DBusBabysitter *) parameter;
447   int fd;
448   PING();
449   _dbus_babysitter_ref (sitter);
450
451   if (sitter->child_setup)
452     {
453       PING();
454       (*sitter->child_setup) (sitter->user_data);
455     }
456
457   _dbus_verbose ("babysitter: spawning %s\n", sitter->executable);
458
459   PING();
460   if (sitter->envp != NULL)
461     sitter->child_handle = (HANDLE) spawnve (P_NOWAIT, sitter->executable,
462                            (const char * const *) sitter->argv,
463                            (const char * const *) sitter->envp);
464   else
465     sitter->child_handle = (HANDLE) spawnv (P_NOWAIT, sitter->executable,
466                                             (const char * const *) sitter->argv);
467
468   PING();
469   if (sitter->child_handle == (HANDLE) -1)
470     {
471       sitter->child_handle = NULL;
472       sitter->have_spawn_errno = TRUE;
473       sitter->spawn_errno = errno;
474     }
475
476   PING();
477   SetEvent (sitter->start_sync_event);
478
479   if (sitter->child_handle != NULL)
480     {
481       int ret;
482       DWORD status;
483
484       PING();
485       WaitForSingleObject (sitter->child_handle, INFINITE);
486
487       PING();
488       ret = GetExitCodeProcess (sitter->child_handle, &status);
489
490       sitter->child_status = status;
491       sitter->have_child_status = TRUE;
492
493       CloseHandle (sitter->child_handle);
494       sitter->child_handle = NULL;
495     }
496
497 #ifdef DBUS_BUILD_TESTS
498   SetEvent (sitter->end_sync_event);
499 #endif
500
501   PING();
502   send (sitter->socket_to_main, " ", 1, 0);
503
504   _dbus_babysitter_unref (sitter);
505
506   return 0;
507 }
508
509 dbus_bool_t
510 _dbus_spawn_async_with_babysitter (DBusBabysitter           **sitter_p,
511                                    char                     **argv,
512                                    char                     **envp,
513                                    DBusSpawnChildSetupFunc    child_setup,
514                                    void                      *user_data,
515                                    DBusError                 *error)
516 {
517   DBusBabysitter *sitter;
518   HANDLE sitter_thread;
519   int sitter_thread_id;
520
521   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
522
523   *sitter_p = NULL;
524
525   PING();
526   sitter = _dbus_babysitter_new ();
527   if (sitter == NULL)
528     {
529       _DBUS_SET_OOM (error);
530       return FALSE;
531     }
532
533   sitter->child_setup = child_setup;
534   sitter->user_data = user_data;
535
536   sitter->executable = _dbus_strdup (argv[0]);
537   if (sitter->executable == NULL)
538     {
539       _DBUS_SET_OOM (error);
540       goto out0;
541     }
542
543   PING();
544   if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
545                                &sitter->socket_to_main,
546                                FALSE, error))
547     goto out0;
548
549   sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
550                                           DBUS_WATCH_READABLE,
551                                           TRUE, handle_watch, sitter, NULL);
552   PING();
553   if (sitter->sitter_watch == NULL)
554     {
555       _DBUS_SET_OOM (error);
556       goto out0;
557     }
558
559   PING();
560   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
561     {
562       _DBUS_SET_OOM (error);
563       goto out0;
564     }
565
566   sitter->argc = protect_argv (argv, &sitter->argv);
567   if (sitter->argc == -1)
568     {
569       _DBUS_SET_OOM (error);
570       goto out0;
571     }
572   sitter->envp = envp;
573
574   PING();
575   sitter_thread = (HANDLE) _beginthreadex (NULL, 0, babysitter,
576                   sitter, 0, &sitter_thread_id);
577
578   if (sitter_thread == 0)
579     {
580       PING();
581       dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
582                             "Failed to create new thread");
583       goto out0;
584     }
585   CloseHandle (sitter_thread);
586
587   PING();
588   WaitForSingleObject (sitter->start_sync_event, INFINITE);
589
590   PING();
591   if (sitter_p != NULL)
592     *sitter_p = sitter;
593   else
594     _dbus_babysitter_unref (sitter);
595
596   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
597
598   PING();
599   return TRUE;
600
601 out0:
602   _dbus_babysitter_unref (sitter);
603
604   return FALSE;
605 }
606
607 #ifdef DBUS_BUILD_TESTS
608
609 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
610
611 static void
612 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
613 {
614   if (sitter->child_handle == NULL)
615     return;
616
617   WaitForSingleObject (sitter->end_sync_event, INFINITE);
618 }
619
620 static dbus_bool_t
621 check_spawn_nonexistent (void *data)
622 {
623   char *argv[4] = { NULL, NULL, NULL, NULL };
624   DBusBabysitter *sitter;
625   DBusError error;
626
627   sitter = NULL;
628
629   dbus_error_init (&error);
630
631   /*** Test launching nonexistent binary */
632
633   argv[0] = "/this/does/not/exist/32542sdgafgafdg";
634   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
635                                          NULL, NULL,
636                                          &error))
637     {
638       _dbus_babysitter_block_for_child_exit (sitter);
639       _dbus_babysitter_set_child_exit_error (sitter, &error);
640     }
641
642   if (sitter)
643     _dbus_babysitter_unref (sitter);
644
645   if (!dbus_error_is_set (&error))
646     {
647       _dbus_warn ("Did not get an error launching nonexistent executable\n");
648       return FALSE;
649     }
650
651   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
652         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
653     {
654       _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
655                   error.name, error.message);
656       dbus_error_free (&error);
657       return FALSE;
658     }
659
660   dbus_error_free (&error);
661
662   return TRUE;
663 }
664
665 static dbus_bool_t
666 check_spawn_segfault (void *data)
667 {
668   char *argv[4] = { NULL, NULL, NULL, NULL };
669   DBusBabysitter *sitter;
670   DBusError error;
671
672   sitter = NULL;
673
674   dbus_error_init (&error);
675
676   /*** Test launching segfault binary */
677
678   argv[0] = TEST_SEGFAULT_BINARY;
679   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
680                                          NULL, NULL,
681                                          &error))
682     {
683       _dbus_babysitter_block_for_child_exit (sitter);
684       _dbus_babysitter_set_child_exit_error (sitter, &error);
685     }
686
687   if (sitter)
688     _dbus_babysitter_unref (sitter);
689
690   if (!dbus_error_is_set (&error))
691     {
692       _dbus_warn ("Did not get an error launching segfaulting binary\n");
693       return FALSE;
694     }
695
696   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
697         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
698     {
699       _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
700                   error.name, error.message);
701       dbus_error_free (&error);
702       return FALSE;
703     }
704
705   dbus_error_free (&error);
706
707   return TRUE;
708 }
709
710 static dbus_bool_t
711 check_spawn_exit (void *data)
712 {
713   char *argv[4] = { NULL, NULL, NULL, NULL };
714   DBusBabysitter *sitter;
715   DBusError error;
716
717   sitter = NULL;
718
719   dbus_error_init (&error);
720
721   /*** Test launching exit failure binary */
722
723   argv[0] = TEST_EXIT_BINARY;
724   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
725                                          NULL, NULL,
726                                          &error))
727     {
728       _dbus_babysitter_block_for_child_exit (sitter);
729       _dbus_babysitter_set_child_exit_error (sitter, &error);
730     }
731
732   if (sitter)
733     _dbus_babysitter_unref (sitter);
734
735   if (!dbus_error_is_set (&error))
736     {
737       _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
738       return FALSE;
739     }
740
741   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
742         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
743     {
744       _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
745                   error.name, error.message);
746       dbus_error_free (&error);
747       return FALSE;
748     }
749
750   dbus_error_free (&error);
751
752   return TRUE;
753 }
754
755 static dbus_bool_t
756 check_spawn_and_kill (void *data)
757 {
758   char *argv[4] = { NULL, NULL, NULL, NULL };
759   DBusBabysitter *sitter;
760   DBusError error;
761
762   sitter = NULL;
763
764   dbus_error_init (&error);
765
766   /*** Test launching sleeping binary then killing it */
767
768   argv[0] = TEST_SLEEP_FOREVER_BINARY;
769   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
770                                          NULL, NULL,
771                                          &error))
772     {
773       _dbus_babysitter_kill_child (sitter);
774
775       _dbus_babysitter_block_for_child_exit (sitter);
776
777       _dbus_babysitter_set_child_exit_error (sitter, &error);
778     }
779
780   if (sitter)
781     _dbus_babysitter_unref (sitter);
782
783   if (!dbus_error_is_set (&error))
784     {
785       _dbus_warn ("Did not get an error after killing spawned binary\n");
786       return FALSE;
787     }
788
789   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
790         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
791     {
792       _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
793                   error.name, error.message);
794       dbus_error_free (&error);
795       return FALSE;
796     }
797
798   dbus_error_free (&error);
799
800   return TRUE;
801 }
802
803 dbus_bool_t
804 _dbus_spawn_test (const char *test_data_dir)
805 {
806   if (!_dbus_test_oom_handling ("spawn_nonexistent",
807                                 check_spawn_nonexistent,
808                                 NULL))
809     return FALSE;
810
811   /* Don't run the obnoxious segfault test by default,
812    * it's a pain to have to click all those error boxes.
813    */
814   if (getenv ("DO_SEGFAULT_TEST"))
815     if (!_dbus_test_oom_handling ("spawn_segfault",
816                                   check_spawn_segfault,
817                                   NULL))
818       return FALSE;
819
820   if (!_dbus_test_oom_handling ("spawn_exit",
821                                 check_spawn_exit,
822                                 NULL))
823     return FALSE;
824
825   if (!_dbus_test_oom_handling ("spawn_and_kill",
826                                 check_spawn_and_kill,
827                                 NULL))
828     return FALSE;
829
830   return TRUE;
831 }
832 #endif