D-Bus: dbus-spawn-win.c Source File

D-Bus 1.8.16

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List

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
61 struct DBusBabysitter
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 int socket_to_babysitter; /* Connection to the babysitter thread */
81 int socket_to_main;
82
83 DBusWatchList *watches;
84 DBusWatch *sitter_watch;
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 = -1;
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
148 DBusBabysitter *
149 _dbus_babysitter_ref (DBusBabysitter *sitter)
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);
168 _dbus_watch_list_remove_watch (sitter->watches, sitter->sitter_watch);
169 _dbus_watch_invalidate (sitter->sitter_watch);
170 _dbus_watch_unref (sitter->sitter_watch);
171 sitter->sitter_watch = NULL;
172 }
173
174 if (sitter->socket_to_babysitter != -1)
175 {
176 _dbus_close_socket (sitter->socket_to_babysitter, NULL);
177 sitter->socket_to_babysitter = -1;
178 }
179 }
180
186 void
187 _dbus_babysitter_unref (DBusBabysitter *sitter)
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 != -1)
202 {
203 _dbus_close_socket (sitter->socket_to_main, NULL);
204 sitter->socket_to_main = -1;
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 {
238 _dbus_watch_invalidate (sitter->sitter_watch);
239 _dbus_watch_unref (sitter->sitter_watch);
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
268 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
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
283 dbus_bool_t
284 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
285 {
286 PING();
287 return (sitter->child_handle == NULL);
288 }
289
302 dbus_bool_t
303 _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter,
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
327 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
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);
338 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
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();
346 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
347 "Process %s exited with status %d",
348 sitter->log_name, sitter->child_status);
349 }
350 else
351 {
352 PING();
353 dbus_set_error (error, DBUS_ERROR_FAILED,
354 "Process %s exited, status unknown",
355 sitter->log_name);
356 }
357 PING();
358 }
359
360 dbus_bool_t
361 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
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 DBusBabysitter *sitter = (DBusBabysitter *) parameter;
586
587 PING();
588 _dbus_babysitter_ref (sitter);
589
590 if (sitter->child_setup)
591 {
592 PING();
593 (*sitter->child_setup) (sitter->user_data);
594 }
595
596 _dbus_verbose ("babysitter: spawning %s\n", sitter->log_name);
597
598 PING();
599 sitter->child_handle = spawn_program (sitter->log_name,
600 sitter->argv, sitter->envp);
601
602 PING();
603 if (sitter->child_handle == (HANDLE) -1)
604 {
605 sitter->child_handle = NULL;
606 sitter->have_spawn_errno = TRUE;
607 sitter->spawn_errno = GetLastError();
608 }
609
610 PING();
611 SetEvent (sitter->start_sync_event);
612
613 if (sitter->child_handle != NULL)
614 {
615 int ret;
616 DWORD status;
617
618 PING();
619 WaitForSingleObject (sitter->child_handle, INFINITE);
620
621 PING();
622 ret = GetExitCodeProcess (sitter->child_handle, &status);
623
624 sitter->child_status = status;
625 sitter->have_child_status = TRUE;
626
627 CloseHandle (sitter->child_handle);
628 sitter->child_handle = NULL;
629 }
630
631 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
632 SetEvent (sitter->end_sync_event);
633 #endif
634
635 PING();
636 send (sitter->socket_to_main, " ", 1, 0);
637
638 _dbus_babysitter_unref (sitter);
639
640 return 0;
641 }
642
643 dbus_bool_t
644 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
645 const char *log_name,
646 char **argv,
647 char **envp,
648 DBusSpawnChildSetupFunc child_setup,
649 void *user_data,
650 DBusError *error)
651 {
652 DBusBabysitter *sitter;
653 HANDLE sitter_thread;
654 DWORD sitter_thread_id;
655
656 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
657 _dbus_assert (argv[0] != NULL);
658
659 *sitter_p = NULL;
660
661 PING();
662 sitter = _dbus_babysitter_new ();
663 if (sitter == NULL)
664 {
665 _DBUS_SET_OOM (error);
666 return FALSE;
667 }
668
669 sitter->child_setup = child_setup;
670 sitter->user_data = user_data;
671
672 sitter->log_name = _dbus_strdup (log_name);
673 if (sitter->log_name == NULL && log_name != NULL)
674 {
675 _DBUS_SET_OOM (error);
676 goto out0;
677 }
678
679 if (sitter->log_name == NULL)
680 sitter->log_name = _dbus_strdup (argv[0]);
681
682 if (sitter->log_name == NULL)
683 {
684 _DBUS_SET_OOM (error);
685 goto out0;
686 }
687
688 PING();
689 if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
690 &sitter->socket_to_main,
691 FALSE, error))
692 goto out0;
693
694 sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
695 DBUS_WATCH_READABLE,
696 TRUE, handle_watch, sitter, NULL);
697 PING();
698 if (sitter->sitter_watch == NULL)
699 {
700 _DBUS_SET_OOM (error);
701 goto out0;
702 }
703
704 PING();
705 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
706 {
707 /* we need to free it early so the destructor won't try to remove it
708 * without it having been added, which DBusLoop doesn't allow */
709 _dbus_watch_invalidate (sitter->sitter_watch);
710 _dbus_watch_unref (sitter->sitter_watch);
711 sitter->sitter_watch = NULL;
712
713 _DBUS_SET_OOM (error);
714 goto out0;
715 }
716
717 sitter->argc = protect_argv (argv, &sitter->argv);
718 if (sitter->argc == -1)
719 {
720 _DBUS_SET_OOM (error);
721 goto out0;
722 }
723 sitter->envp = envp;
724
725 PING();
726 sitter_thread = (HANDLE) CreateThread (NULL, 0, babysitter,
727 sitter, 0, &sitter_thread_id);
728
729 if (sitter_thread == 0)
730 {
731 PING();
732 dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
733 "Failed to create new thread");
734 goto out0;
735 }
736 CloseHandle (sitter_thread);
737
738 PING();
739 WaitForSingleObject (sitter->start_sync_event, INFINITE);
740
741 PING();
742 if (sitter_p != NULL)
743 *sitter_p = sitter;
744 else
745 _dbus_babysitter_unref (sitter);
746
747 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
748
749 PING();
750 return TRUE;
751
752 out0:
753 _dbus_babysitter_unref (sitter);
754
755 return FALSE;
756 }
757
758 void
759 _dbus_babysitter_set_result_function (DBusBabysitter *sitter,
760 DBusBabysitterFinishedFunc finished,
761 void *user_data)
762 {
763 sitter->finished_cb = finished;
764 sitter->finished_data = user_data;
765 }
766
767 #ifdef DBUS_ENABLE_EMBEDDED_TESTS
768
769 static char *
770 get_test_exec (const char *exe,
771 DBusString *scratch_space)
772 {
773 const char *dbus_test_exec;
774
775 dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC");
776
777 if (dbus_test_exec == NULL)
778 dbus_test_exec = DBUS_TEST_EXEC;
779
780 if (!_dbus_string_init (scratch_space))
781 return NULL;
782
783 if (!_dbus_string_append_printf (scratch_space, "%s/%s%s",
784 dbus_test_exec, exe, DBUS_EXEEXT))
785 {
786 _dbus_string_free (scratch_space);
787 return NULL;
788 }
789
790 return _dbus_string_get_data (scratch_space);
791 }
792
793 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
794
795 static void
796 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
797 {
798 if (sitter->child_handle == NULL)
799 return;
800
801 WaitForSingleObject (sitter->end_sync_event, INFINITE);
802 }
803
804 static dbus_bool_t
805 check_spawn_nonexistent (void *data)
806 {
807 char *argv[4] = { NULL, NULL, NULL, NULL };
808 DBusBabysitter *sitter;
809 DBusError error;
810
811 sitter = NULL;
812
813 dbus_error_init (&error);
814
815 /*** Test launching nonexistent binary */
816
817 argv[0] = "/this/does/not/exist/32542sdgafgafdg";
818 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_nonexistent", argv, NULL,
819 NULL, NULL,
820 &error))
821 {
822 _dbus_babysitter_block_for_child_exit (sitter);
823 _dbus_babysitter_set_child_exit_error (sitter, &error);
824 }
825
826 if (sitter)
827 _dbus_babysitter_unref (sitter);
828
829 if (!dbus_error_is_set (&error))
830 {
831 _dbus_warn ("Did not get an error launching nonexistent executable\n");
832 return FALSE;
833 }
834
835 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
836 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
837 {
838 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
839 error.name, error.message);
840 dbus_error_free (&error);
841 return FALSE;
842 }
843
844 dbus_error_free (&error);
845
846 return TRUE;
847 }
848
849 static dbus_bool_t
850 check_spawn_segfault (void *data)
851 {
852 char *argv[4] = { NULL, NULL, NULL, NULL };
853 DBusBabysitter *sitter;
854 DBusError error;
855 DBusString argv0;
856
857 sitter = NULL;
858
859 dbus_error_init (&error);
860
861 /*** Test launching segfault binary */
862
863 argv[0] = get_test_exec ("test-segfault", &argv0);
864
865 if (argv[0] == NULL)
866 {
867 /* OOM was simulated, never mind */
868 return TRUE;
869 }
870
871 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_segfault", argv, NULL,
872 NULL, NULL,
873 &error))
874 {
875 _dbus_babysitter_block_for_child_exit (sitter);
876 _dbus_babysitter_set_child_exit_error (sitter, &error);
877 }
878
879 _dbus_string_free (&argv0);
880
881 if (sitter)
882 _dbus_babysitter_unref (sitter);
883
884 if (!dbus_error_is_set (&error))
885 {
886 _dbus_warn ("Did not get an error launching segfaulting binary\n");
887 return FALSE;
888 }
889
890 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
891 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
892 {
893 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
894 error.name, error.message);
895 dbus_error_free (&error);
896 return FALSE;
897 }
898
899 dbus_error_free (&error);
900
901 return TRUE;
902 }
903
904 static dbus_bool_t
905 check_spawn_exit (void *data)
906 {
907 char *argv[4] = { NULL, NULL, NULL, NULL };
908 DBusBabysitter *sitter;
909 DBusError error;
910 DBusString argv0;
911
912 sitter = NULL;
913
914 dbus_error_init (&error);
915
916 /*** Test launching exit failure binary */
917
918 argv[0] = get_test_exec ("test-exit", &argv0);
919
920 if (argv[0] == NULL)
921 {
922 /* OOM was simulated, never mind */
923 return TRUE;
924 }
925
926 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_exit", argv, NULL,
927 NULL, NULL,
928 &error))
929 {
930 _dbus_babysitter_block_for_child_exit (sitter);
931 _dbus_babysitter_set_child_exit_error (sitter, &error);
932 }
933
934 _dbus_string_free (&argv0);
935
936 if (sitter)
937 _dbus_babysitter_unref (sitter);
938
939 if (!dbus_error_is_set (&error))
940 {
941 _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
942 return FALSE;
943 }
944
945 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
946 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
947 {
948 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
949 error.name, error.message);
950 dbus_error_free (&error);
951 return FALSE;
952 }
953
954 dbus_error_free (&error);
955
956 return TRUE;
957 }
958
959 static dbus_bool_t
960 check_spawn_and_kill (void *data)
961 {
962 char *argv[4] = { NULL, NULL, NULL, NULL };
963 DBusBabysitter *sitter;
964 DBusError error;
965 DBusString argv0;
966
967 sitter = NULL;
968
969 dbus_error_init (&error);
970
971 /*** Test launching sleeping binary then killing it */
972
973 argv[0] = get_test_exec ("test-sleep-forever", &argv0);
974
975 if (argv[0] == NULL)
976 {
977 /* OOM was simulated, never mind */
978 return TRUE;
979 }
980
981 if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_and_kill", argv, NULL,
982 NULL, NULL,
983 &error))
984 {
985 _dbus_babysitter_kill_child (sitter);
986
987 _dbus_babysitter_block_for_child_exit (sitter);
988
989 _dbus_babysitter_set_child_exit_error (sitter, &error);
990 }
991
992 _dbus_string_free (&argv0);
993
994 if (sitter)
995 _dbus_babysitter_unref (sitter);
996
997 if (!dbus_error_is_set (&error))
998 {
999 _dbus_warn ("Did not get an error after killing spawned binary\n");
1000 return FALSE;
1001 }
1002
1003 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
1004 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
1005 {
1006 _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
1007 error.name, error.message);
1008 dbus_error_free (&error);
1009 return FALSE;
1010 }
1011
1012 dbus_error_free (&error);
1013
1014 return TRUE;
1015 }
1016
1017 dbus_bool_t
1018 _dbus_spawn_test (const char *test_data_dir)
1019 {
1020 if (!_dbus_test_oom_handling ("spawn_nonexistent",
1021 check_spawn_nonexistent,
1022 NULL))
1023 return FALSE;
1024
1025 /* Don't run the obnoxious segfault test by default,
1026 * it's a pain to have to click all those error boxes.
1027 */
1028 if (getenv ("DO_SEGFAULT_TEST"))
1029 if (!_dbus_test_oom_handling ("spawn_segfault",
1030 check_spawn_segfault,
1031 NULL))
1032 return FALSE;
1033
1034 if (!_dbus_test_oom_handling ("spawn_exit",
1035 check_spawn_exit,
1036 NULL))
1037 return FALSE;
1038
1039 if (!_dbus_test_oom_handling ("spawn_and_kill",
1040 check_spawn_and_kill,
1041 NULL))
1042 return FALSE;
1043
1044 return TRUE;
1045 }
1046 #endif
dbus_error_has_name
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
DBusError::message
const char * message
public error message field
Definition: dbus-errors.h:51
DBusWatch
Implementation of DBusWatch.
Definition: dbus-watch.c:40
NULL
#define NULL
A null pointer, defined appropriately for C or C++.
DBUS_ERROR_SPAWN_EXEC_FAILED
#define DBUS_ERROR_SPAWN_EXEC_FAILED
While starting a new process, the exec() call failed.
Definition: dbus-protocol.h:411
DBusFreeFunction
void(* DBusFreeFunction)(void *memory)
The type of a function which frees a block of memory.
Definition: dbus-memory.h:64
dbus_free
void dbus_free(void *memory)
Frees a block of memory previously allocated by dbus_malloc() or dbus_malloc0().
Definition: dbus-memory.c:701
_dbus_watch_list_new
DBusWatchList * _dbus_watch_list_new(void)
Creates a new watch list.
Definition: dbus-watch.c:232
_dbus_watch_invalidate
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
DBusWatchToggledFunction
void(* DBusWatchToggledFunction)(DBusWatch *watch, void *data)
Called when dbus_watch_get_enabled() may return a different value than it did before.
Definition: dbus-connection.h:97
DBUS_ERROR_SPAWN_CHILD_EXITED
#define DBUS_ERROR_SPAWN_CHILD_EXITED
While starting a new process, the child exited with a status code.
Definition: dbus-protocol.h:415
_dbus_assert
#define _dbus_assert(condition)
Aborts with an error message if the condition is false.
Definition: dbus-internals.h:135
DBusBabysitter::socket_to_babysitter
int socket_to_babysitter
Connection to the babysitter process.
Definition: dbus-spawn-win.c:80
_dbus_full_duplex_pipe
dbus_bool_t _dbus_full_duplex_pipe(int *fd1, int *fd2, dbus_bool_t blocking, DBusError *error)
Creates a full-duplex pipe (as in socketpair()).
Definition: dbus-sysdeps-unix.c:3108
_dbus_watch_list_add_watch
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:376
dbus_error_free
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
_dbus_string_init
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
_dbus_babysitter_get_child_exited
dbus_bool_t _dbus_babysitter_get_child_exited(DBusBabysitter *sitter)
Checks whether the child has exited, without blocking.
Definition: dbus-spawn.c:690
_dbus_getenv
const char * _dbus_getenv(const char *varname)
Wrapper for getenv().
Definition: dbus-sysdeps.c:185
DBusBabysitter::watches
DBusWatchList * watches
Watches.
Definition: dbus-spawn-win.c:83
dbus_malloc
void * dbus_malloc(size_t bytes)
Allocates the given number of bytes, as with standard malloc().
Definition: dbus-memory.c:461
dbus_new0
#define dbus_new0(type, count)
Safe macro for using dbus_malloc0().
Definition: dbus-memory.h:59
DBusString
Definition: dbus-string.h:42
dbus_bool_t
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
DBusBabysitter::sitter_watch
DBusWatch * sitter_watch
Sitter pipe watch.
Definition: dbus-spawn-win.c:84
_dbus_babysitter_get_child_exit_status
dbus_bool_t _dbus_babysitter_get_child_exit_status(DBusBabysitter *sitter, int *status)
Gets the exit status of the child.
Definition: dbus-spawn.c:715
_dbus_babysitter_kill_child
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:668
DBusBabysitter
Babysitter implementation details.
Definition: dbus-spawn-win.c:61
_dbus_spawn_async_with_babysitter
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:1194
_dbus_warn
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
Definition: dbus-internals.c:230
_dbus_string_append_printf
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:1096
_dbus_babysitter_set_watch_functions
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:797
DBusError
Object representing an exception.
Definition: dbus-errors.h:48
dbus_set_error
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
DBusBabysitter::refcount
int refcount
Reference count.
Definition: dbus-spawn-win.c:63
_dbus_string_free
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init().
Definition: dbus-string.c:242
TRUE
#define TRUE
Expands to "1".
_dbus_assert_not_reached
#define _dbus_assert_not_reached(explanation)
Aborts with an error message if called.
Definition: dbus-internals.h:145
DBUS_ERROR_FAILED
#define DBUS_ERROR_FAILED
A generic error; "something went wrong" - see the error message for more.
Definition: dbus-protocol.h:350
DBusError::name
const char * name
public error name field
Definition: dbus-errors.h:50
DBusAddWatchFunction
dbus_bool_t(* DBusAddWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus needs a new watch to be monitored by the main loop.
Definition: dbus-connection.h:91
DBusRemoveWatchFunction
void(* DBusRemoveWatchFunction)(DBusWatch *watch, void *data)
Called when libdbus no longer needs a watch to be monitored by the main loop.
Definition: dbus-connection.h:103
DBusWatchList
DBusWatchList implementation details.
Definition: dbus-watch.c:214
_dbus_babysitter_unref
void _dbus_babysitter_unref(DBusBabysitter *sitter)
Decrement the reference count on the babysitter object.
Definition: dbus-spawn.c:324
dbus_error_init
void dbus_error_init(DBusError *error)
Initializes a DBusError structure.
Definition: dbus-errors.c:188
_dbus_watch_list_set_functions
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
DBUS_ERROR_SPAWN_FORK_FAILED
#define DBUS_ERROR_SPAWN_FORK_FAILED
While starting a new process, the fork() call failed.
Definition: dbus-protocol.h:413
_dbus_watch_new
DBusWatch * _dbus_watch_new(int 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
DBusBabysitter::log_name
char * log_name
the name under which to log messages about this process being spawned
Definition: dbus-spawn-win.c:71
DBUS_ERROR_NO_MEMORY
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
Definition: dbus-protocol.h:352
FALSE
#define FALSE
Expands to "0".
dbus_set_error_const
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
_dbus_watch_unref
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
DBUS_WATCH_READABLE
As in POLLIN.
Definition: dbus-connection.h:60
_dbus_watch_list_free
void _dbus_watch_list_free(DBusWatchList *watch_list)
Frees a DBusWatchList.
Definition: dbus-watch.c:249
_dbus_strdup
char * _dbus_strdup(const char *str)
Duplicates a string.
Definition: dbus-internals.c:527
_dbus_close_socket
dbus_bool_t _dbus_close_socket(int fd, DBusError *error)
Closes a socket.
Definition: dbus-sysdeps-unix.c:201
_dbus_babysitter_set_child_exit_error
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:739
dbus_error_is_set
dbus_bool_t dbus_error_is_set(const DBusError *error)
Checks whether an error occurred (the error is set).
Definition: dbus-errors.c:329
_dbus_watch_list_remove_watch
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:409
_dbus_babysitter_ref
DBusBabysitter * _dbus_babysitter_ref(DBusBabysitter *sitter)
Increment the reference count on the babysitter object.
Definition: dbus-spawn.c:302