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 57/** 58 * Babysitter implementation details 59 */ 60struct DBusBabysitter 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 82 DBusWatchList *watches; 83 DBusWatch *sitter_watch; 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 91static 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 139/** 140 * Increment the reference count on the babysitter object. 141 * 142 * @param sitter the babysitter 143 * @returns the babysitter 144 */ 145DBusBabysitter * 146_dbus_babysitter_ref (DBusBabysitter *sitter) 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 157/** 158 * Decrement the reference count on the babysitter object. 159 * 160 * @param sitter the babysitter 161 */ 162void 163_dbus_babysitter_unref (DBusBabysitter *sitter) 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 { 177 _dbus_close_socket (sitter->socket_to_babysitter, NULL); 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 { 218 _dbus_watch_invalidate (sitter->sitter_watch); 219 _dbus_watch_unref (sitter->sitter_watch); 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 247void 248_dbus_babysitter_kill_child (DBusBabysitter *sitter) 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 258/** 259 * Checks whether the child has exited, without blocking. 260 * 261 * @param sitter the babysitter 262 */ 263dbus_bool_t 264_dbus_babysitter_get_child_exited (DBusBabysitter *sitter) 265{ 266 PING(); 267 return (sitter->child_handle == NULL); 268} 269 270/** 271 * Gets the exit status of the child. We do this so implementation specific 272 * detail is not cluttering up dbus, for example the system launcher code. 273 * This can only be called if the child has exited, i.e. call 274 * _dbus_babysitter_get_child_exited(). It returns FALSE if the child 275 * did not return a status code, e.g. because the child was signaled 276 * or we failed to ever launch the child in the first place. 277 * 278 * @param sitter the babysitter 279 * @param status the returned status code 280 * @returns #FALSE on failure 281 */ 282dbus_bool_t 283_dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter, 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 297/** 298 * Sets the #DBusError with an explanation of why the spawned 299 * child process exited (on a signal, or whatever). If 300 * the child process has not exited, does nothing (error 301 * will remain unset). 302 * 303 * @param sitter the babysitter 304 * @param error an error to fill in 305 */ 306void 307_dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, 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); 318 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, 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(); 326 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, 327 "Process %s exited with status %d", 328 sitter->executable, sitter->child_status); 329 } 330 else 331 { 332 PING(); 333 dbus_set_error (error, DBUS_ERROR_FAILED, 334 "Process %s exited, status unknown", 335 sitter->executable); 336 } 337 PING(); 338} 339 340dbus_bool_t 341_dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, 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 357static dbus_bool_t 358handle_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(); 375 _dbus_close_socket (sitter->socket_to_babysitter, NULL); 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 */ 383static int 384protect_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. */ 473static char * 474compose_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 504static char * 505build_commandline (char **argv) 506{ 507 return compose_string (argv, ' '); 508} 509 510static char * 511build_env_string (char** envp) 512{ 513 return compose_string (envp, '\0'); 514} 515 516static HANDLE 517spawn_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 557static DWORD __stdcall 558babysitter (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 618dbus_bool_t 619_dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p, 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(); 653 if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter, 654 &sitter->socket_to_main, 655 FALSE, error)) 656 goto out0; 657 658 sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter, 659 DBUS_WATCH_READABLE, 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(); 690 dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED, 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 710out0: 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 720static 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 729static dbus_bool_t 730check_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) || 761 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED))) 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 774static dbus_bool_t 775check_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) || 806 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 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 819static dbus_bool_t 820check_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) || 851 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 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 864static dbus_bool_t 865check_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 { 882 _dbus_babysitter_kill_child (sitter); 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) || 899 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED))) 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 912dbus_bool_t 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 942