dbus-spawn-win.c revision 70bfc74e54ac8a9a93885710cd8350d1a58b3406
1#include "config.h" 2 3#if !defined(DBUS_ENABLE_VERBOSE_MODE) || defined(_MSC_VER) 4#define PING() 5#else 6#define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr) 7#endif 8 9#include <stdio.h> 10#ifdef DBUS_WINCE 11#include <process.h> 12#endif 13 14/* -*- mode: C; c-file-style: "gnu" -*- */ 15/* dbus-spawn-win32.c Wrapper around g_spawn 16 * 17 * Copyright (C) 2002, 2003, 2004 Red Hat, Inc. 18 * Copyright (C) 2003 CodeFactory AB 19 * Copyright (C) 2005 Novell, Inc. 20 * 21 * Licensed under the Academic Free License version 2.1 22 * 23 * This program is free software; you can redistribute it and/or modify 24 * it under the terms of the GNU General Public License as published by 25 * the Free Software Foundation; either version 2 of the License, or 26 * (at your option) any later version. 27 * 28 * This program is distributed in the hope that it will be useful, 29 * but WITHOUT ANY WARRANTY; without even the implied warranty of 30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31 * GNU General Public License for more details. 32 * 33 * You should have received a copy of the GNU General Public License 34 * along with this program; if not, write to the Free Software 35 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 36 * 37 */ 38#include "dbus-spawn.h" 39#include "dbus-sysdeps.h" 40#include "dbus-sysdeps-win.h" 41#include "dbus-internals.h" 42#include "dbus-test.h" 43#include "dbus-protocol.h" 44 45#define WIN32_LEAN_AND_MEAN 46//#define STRICT 47//#include <windows.h> 48//#undef STRICT 49#include <winsock2.h> 50#undef interface 51 52#include <stdlib.h> 53 54#include <process.h> 55 56/** 57 * Babysitter implementation details 58 */ 59struct DBusBabysitter 60 { 61 int refcount; 62 63 HANDLE start_sync_event; 64#ifdef DBUS_BUILD_TESTS 65 66 HANDLE end_sync_event; 67#endif 68 69 char *executable; 70 DBusSpawnChildSetupFunc child_setup; 71 void *user_data; 72 73 int argc; 74 char **argv; 75 char **envp; 76 77 HANDLE child_handle; 78 int socket_to_babysitter; /* Connection to the babysitter thread */ 79 int socket_to_main; 80 81 DBusWatchList *watches; 82 DBusWatch *sitter_watch; 83 84 dbus_bool_t have_spawn_errno; 85 int spawn_errno; 86 dbus_bool_t have_child_status; 87 int child_status; 88 }; 89 90static DBusBabysitter* 91_dbus_babysitter_new (void) 92{ 93 DBusBabysitter *sitter; 94 95 sitter = dbus_new0 (DBusBabysitter, 1); 96 if (sitter == NULL) 97 return NULL; 98 99 sitter->refcount = 1; 100 101 sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); 102 if (sitter->start_sync_event == NULL) 103 { 104 _dbus_babysitter_unref (sitter); 105 return NULL; 106 } 107 108#ifdef DBUS_BUILD_TESTS 109 sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL); 110 if (sitter->end_sync_event == NULL) 111 { 112 _dbus_babysitter_unref (sitter); 113 return NULL; 114 } 115#endif 116 117 sitter->child_handle = NULL; 118 119 sitter->socket_to_babysitter = sitter->socket_to_main = -1; 120 121 sitter->argc = 0; 122 sitter->argv = NULL; 123 sitter->envp = NULL; 124 125 sitter->watches = _dbus_watch_list_new (); 126 if (sitter->watches == NULL) 127 { 128 _dbus_babysitter_unref (sitter); 129 return NULL; 130 } 131 132 sitter->have_spawn_errno = FALSE; 133 sitter->have_child_status = FALSE; 134 135 return sitter; 136} 137 138/** 139 * Increment the reference count on the babysitter object. 140 * 141 * @param sitter the babysitter 142 * @returns the babysitter 143 */ 144DBusBabysitter * 145_dbus_babysitter_ref (DBusBabysitter *sitter) 146{ 147 PING(); 148 _dbus_assert (sitter != NULL); 149 _dbus_assert (sitter->refcount > 0); 150 151 sitter->refcount += 1; 152 153 return sitter; 154} 155 156/** 157 * Decrement the reference count on the babysitter object. 158 * 159 * @param sitter the babysitter 160 */ 161void 162_dbus_babysitter_unref (DBusBabysitter *sitter) 163{ 164 int i; 165 166 PING(); 167 _dbus_assert (sitter != NULL); 168 _dbus_assert (sitter->refcount > 0); 169 170 sitter->refcount -= 1; 171 172 if (sitter->refcount == 0) 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 if (sitter->socket_to_main != -1) 181 { 182 _dbus_close_socket (sitter->socket_to_main, NULL); 183 sitter->socket_to_main = -1; 184 } 185 186 PING(); 187 if (sitter->argv != NULL) 188 { 189 for (i = 0; i < sitter->argc; i++) 190 if (sitter->argv[i] != NULL) 191 { 192 dbus_free (sitter->argv[i]); 193 sitter->argv[i] = NULL; 194 } 195 dbus_free (sitter->argv); 196 sitter->argv = NULL; 197 } 198 199 if (sitter->envp != NULL) 200 { 201 char **e = sitter->envp; 202 203 while (*e) 204 dbus_free (*e++); 205 dbus_free (sitter->envp); 206 sitter->envp = NULL; 207 } 208 209 if (sitter->child_handle != NULL) 210 { 211 CloseHandle (sitter->child_handle); 212 sitter->child_handle = NULL; 213 } 214 215 if (sitter->sitter_watch) 216 { 217 _dbus_watch_invalidate (sitter->sitter_watch); 218 _dbus_watch_unref (sitter->sitter_watch); 219 sitter->sitter_watch = NULL; 220 } 221 222 if (sitter->watches) 223 _dbus_watch_list_free (sitter->watches); 224 225 if (sitter->start_sync_event != NULL) 226 { 227 PING(); 228 CloseHandle (sitter->start_sync_event); 229 sitter->end_sync_event = NULL; 230 } 231 232#ifdef DBUS_BUILD_TESTS 233 if (sitter->end_sync_event != NULL) 234 { 235 CloseHandle (sitter->end_sync_event); 236 sitter->end_sync_event = NULL; 237 } 238#endif 239 240 dbus_free (sitter->executable); 241 242 dbus_free (sitter); 243 } 244} 245 246void 247_dbus_babysitter_kill_child (DBusBabysitter *sitter) 248{ 249 PING(); 250 if (sitter->child_handle == NULL) 251 return; /* child is already dead, or we're so hosed we'll never recover */ 252 253 PING(); 254 TerminateProcess (sitter->child_handle, 12345); 255} 256 257/** 258 * Checks whether the child has exited, without blocking. 259 * 260 * @param sitter the babysitter 261 */ 262dbus_bool_t 263_dbus_babysitter_get_child_exited (DBusBabysitter *sitter) 264{ 265 PING(); 266 return (sitter->child_handle == NULL); 267} 268 269/** 270 * Sets the #DBusError with an explanation of why the spawned 271 * child process exited (on a signal, or whatever). If 272 * the child process has not exited, does nothing (error 273 * will remain unset). 274 * 275 * @param sitter the babysitter 276 * @param error an error to fill in 277 */ 278void 279_dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter, 280 DBusError *error) 281{ 282 PING(); 283 if (!_dbus_babysitter_get_child_exited (sitter)) 284 return; 285 286 PING(); 287 if (sitter->have_spawn_errno) 288 { 289 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED, 290 "Failed to execute program %s: %s", 291 sitter->executable, _dbus_strerror (sitter->spawn_errno)); 292 } 293 else if (sitter->have_child_status) 294 { 295 PING(); 296 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED, 297 "Process %s exited with status %d", 298 sitter->executable, sitter->child_status); 299 } 300 else 301 { 302 PING(); 303 dbus_set_error (error, DBUS_ERROR_FAILED, 304 "Process %s exited, status unknown", 305 sitter->executable); 306 } 307 PING(); 308} 309 310dbus_bool_t 311_dbus_babysitter_set_watch_functions (DBusBabysitter *sitter, 312 DBusAddWatchFunction add_function, 313 DBusRemoveWatchFunction remove_function, 314 DBusWatchToggledFunction toggled_function, 315 void *data, 316 DBusFreeFunction free_data_function) 317{ 318 PING(); 319 return _dbus_watch_list_set_functions (sitter->watches, 320 add_function, 321 remove_function, 322 toggled_function, 323 data, 324 free_data_function); 325} 326 327static dbus_bool_t 328handle_watch (DBusWatch *watch, 329 unsigned int condition, 330 void *data) 331{ 332 DBusBabysitter *sitter = data; 333 334 /* On Unix dbus-spawn uses a babysitter *process*, thus it has to 335 * actually send the exit statuses, error codes and whatnot through 336 * sockets and/or pipes. On Win32, the babysitter is jus a thread, 337 * so it can set the status fields directly in the babysitter struct 338 * just fine. The socket pipe is used just so we can watch it with 339 * select(), as soon as anything is written to it we know that the 340 * babysitter thread has recorded the status in the babysitter 341 * struct. 342 */ 343 344 PING(); 345 _dbus_close_socket (sitter->socket_to_babysitter, NULL); 346 PING(); 347 sitter->socket_to_babysitter = -1; 348 349 return TRUE; 350} 351 352/* protect_argv lifted from GLib, relicensed by author, Tor Lillqvist */ 353static int 354protect_argv (char **argv, 355 char ***new_argv) 356{ 357 int i; 358 int argc = 0; 359 360 while (argv[argc]) 361 ++argc; 362 *new_argv = dbus_malloc ((argc + 1) * sizeof (char *)); 363 if (*new_argv == NULL) 364 return -1; 365 366 for (i = 0; i < argc; i++) 367 (*new_argv)[i] = NULL; 368 369 /* Quote each argv element if necessary, so that it will get 370 * reconstructed correctly in the C runtime startup code. Note that 371 * the unquoting algorithm in the C runtime is really weird, and 372 * rather different than what Unix shells do. See stdargv.c in the C 373 * runtime sources (in the Platform SDK, in src/crt). 374 * 375 * Note that an new_argv[0] constructed by this function should 376 * *not* be passed as the filename argument to a spawn* or exec* 377 * family function. That argument should be the real file name 378 * without any quoting. 379 */ 380 for (i = 0; i < argc; i++) 381 { 382 char *p = argv[i]; 383 char *q; 384 int len = 0; 385 int need_dblquotes = FALSE; 386 while (*p) 387 { 388 if (*p == ' ' || *p == '\t') 389 need_dblquotes = TRUE; 390 else if (*p == '"') 391 len++; 392 else if (*p == '\\') 393 { 394 char *pp = p; 395 while (*pp && *pp == '\\') 396 pp++; 397 if (*pp == '"') 398 len++; 399 } 400 len++; 401 p++; 402 } 403 404 q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1); 405 406 if (q == NULL) 407 return -1; 408 409 410 p = argv[i]; 411 412 if (need_dblquotes) 413 *q++ = '"'; 414 415 while (*p) 416 { 417 if (*p == '"') 418 *q++ = '\\'; 419 else if (*p == '\\') 420 { 421 char *pp = p; 422 while (*pp && *pp == '\\') 423 pp++; 424 if (*pp == '"') 425 *q++ = '\\'; 426 } 427 *q++ = *p; 428 p++; 429 } 430 431 if (need_dblquotes) 432 *q++ = '"'; 433 *q++ = '\0'; 434 /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */ 435 } 436 (*new_argv)[argc] = NULL; 437 438 return argc; 439} 440 441static unsigned __stdcall 442babysitter (void *parameter) 443{ 444 DBusBabysitter *sitter = (DBusBabysitter *) parameter; 445 DBusSocket *sock; 446 PING(); 447 _dbus_babysitter_ref (sitter); 448 449 if (sitter->child_setup) 450 { 451 PING(); 452 (*sitter->child_setup) (sitter->user_data); 453 } 454 455 _dbus_verbose ("babysitter: spawning %s\n", sitter->executable); 456 fprintf (stderr, "babysitter: spawning %s\n", sitter->executable); 457 458 PING(); 459 if (sitter->envp != NULL) 460 sitter->child_handle = (HANDLE) spawnve (P_NOWAIT, sitter->executable, 461 (const char * const *) sitter->argv, 462 (const char * const *) sitter->envp); 463 else 464 sitter->child_handle = (HANDLE) spawnv (P_NOWAIT, sitter->executable, 465 (const char * const *) sitter->argv); 466 467 PING(); 468 if (sitter->child_handle == (HANDLE) -1) 469 { 470 sitter->child_handle = NULL; 471 sitter->have_spawn_errno = TRUE; 472 sitter->spawn_errno = errno; 473 } 474 475 PING(); 476 SetEvent (sitter->start_sync_event); 477 478 if (sitter->child_handle != NULL) 479 { 480 int ret; 481 DWORD status; 482 483 PING(); 484 WaitForSingleObject (sitter->child_handle, INFINITE); 485 486 PING(); 487 ret = GetExitCodeProcess (sitter->child_handle, &status); 488 489 sitter->child_status = status; 490 sitter->have_child_status = TRUE; 491 492 CloseHandle (sitter->child_handle); 493 sitter->child_handle = NULL; 494 } 495 496#ifdef DBUS_BUILD_TESTS 497 SetEvent (sitter->end_sync_event); 498#endif 499 500 PING(); 501 _dbus_handle_to_socket (sitter->socket_to_main, &sock); 502 send (sock->fd, " ", 1, 0); 503 504 _dbus_babysitter_unref (sitter); 505 506 return 0; 507} 508 509dbus_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 601out0: 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 611static 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 620static dbus_bool_t 621check_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 665static dbus_bool_t 666check_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 710static dbus_bool_t 711check_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 755static dbus_bool_t 756check_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 803dbus_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 833