Merge branch 'fd-passing'
[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"; indent-tabs-mode: nil; -*- */
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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 = NULL;
625   DBusError error = DBUS_ERROR_INIT;
626
627   /*** Test launching nonexistent binary */
628
629   argv[0] = "/this/does/not/exist/32542sdgafgafdg";
630   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
631                                          NULL, NULL,
632                                          &error))
633     {
634       _dbus_babysitter_block_for_child_exit (sitter);
635       _dbus_babysitter_set_child_exit_error (sitter, &error);
636     }
637
638   if (sitter)
639     _dbus_babysitter_unref (sitter);
640
641   if (!dbus_error_is_set (&error))
642     {
643       _dbus_warn ("Did not get an error launching nonexistent executable\n");
644       return FALSE;
645     }
646
647   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
648         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
649     {
650       _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
651                   error.name, error.message);
652       dbus_error_free (&error);
653       return FALSE;
654     }
655
656   dbus_error_free (&error);
657
658   return TRUE;
659 }
660
661 static dbus_bool_t
662 check_spawn_segfault (void *data)
663 {
664   char *argv[4] = { NULL, NULL, NULL, NULL };
665   DBusBabysitter *sitter = NULL;
666   DBusError error = DBUS_ERROR_INIT;
667
668   /*** Test launching segfault binary */
669
670   argv[0] = TEST_SEGFAULT_BINARY;
671   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
672                                          NULL, NULL,
673                                          &error))
674     {
675       _dbus_babysitter_block_for_child_exit (sitter);
676       _dbus_babysitter_set_child_exit_error (sitter, &error);
677     }
678
679   if (sitter)
680     _dbus_babysitter_unref (sitter);
681
682   if (!dbus_error_is_set (&error))
683     {
684       _dbus_warn ("Did not get an error launching segfaulting binary\n");
685       return FALSE;
686     }
687
688   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
689         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
690     {
691       _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
692                   error.name, error.message);
693       dbus_error_free (&error);
694       return FALSE;
695     }
696
697   dbus_error_free (&error);
698
699   return TRUE;
700 }
701
702 static dbus_bool_t
703 check_spawn_exit (void *data)
704 {
705   char *argv[4] = { NULL, NULL, NULL, NULL };
706   DBusBabysitter *sitter = NULL;
707   DBusError error = DBUS_ERROR_INIT;
708
709   /*** Test launching exit failure binary */
710
711   argv[0] = TEST_EXIT_BINARY;
712   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
713                                          NULL, NULL,
714                                          &error))
715     {
716       _dbus_babysitter_block_for_child_exit (sitter);
717       _dbus_babysitter_set_child_exit_error (sitter, &error);
718     }
719
720   if (sitter)
721     _dbus_babysitter_unref (sitter);
722
723   if (!dbus_error_is_set (&error))
724     {
725       _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
726       return FALSE;
727     }
728
729   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
730         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
731     {
732       _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
733                   error.name, error.message);
734       dbus_error_free (&error);
735       return FALSE;
736     }
737
738   dbus_error_free (&error);
739
740   return TRUE;
741 }
742
743 static dbus_bool_t
744 check_spawn_and_kill (void *data)
745 {
746   char *argv[4] = { NULL, NULL, NULL, NULL };
747   DBusBabysitter *sitter = NULL;
748   DBusError error = DBUS_ERROR_INIT;
749
750   /*** Test launching sleeping binary then killing it */
751
752   argv[0] = TEST_SLEEP_FOREVER_BINARY;
753   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
754                                          NULL, NULL,
755                                          &error))
756     {
757       _dbus_babysitter_kill_child (sitter);
758
759       _dbus_babysitter_block_for_child_exit (sitter);
760
761       _dbus_babysitter_set_child_exit_error (sitter, &error);
762     }
763
764   if (sitter)
765     _dbus_babysitter_unref (sitter);
766
767   if (!dbus_error_is_set (&error))
768     {
769       _dbus_warn ("Did not get an error after killing spawned binary\n");
770       return FALSE;
771     }
772
773   if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
774         dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
775     {
776       _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
777                   error.name, error.message);
778       dbus_error_free (&error);
779       return FALSE;
780     }
781
782   dbus_error_free (&error);
783
784   return TRUE;
785 }
786
787 dbus_bool_t
788 _dbus_spawn_test (const char *test_data_dir)
789 {
790   if (!_dbus_test_oom_handling ("spawn_nonexistent",
791                                 check_spawn_nonexistent,
792                                 NULL))
793     return FALSE;
794
795   /* Don't run the obnoxious segfault test by default,
796    * it's a pain to have to click all those error boxes.
797    */
798   if (getenv ("DO_SEGFAULT_TEST"))
799     if (!_dbus_test_oom_handling ("spawn_segfault",
800                                   check_spawn_segfault,
801                                   NULL))
802       return FALSE;
803
804   if (!_dbus_test_oom_handling ("spawn_exit",
805                                 check_spawn_exit,
806                                 NULL))
807     return FALSE;
808
809   if (!_dbus_test_oom_handling ("spawn_and_kill",
810                                 check_spawn_and_kill,
811                                 NULL))
812     return FALSE;
813
814   return TRUE;
815 }
816 #endif