00001 #include "config.h"
00002
00003
00004
00005 #if !defined(SPAWN_DEBUG) || defined(_MSC_VER)
00006 #define PING()
00007 #else
00008 #define PING() fprintf (stderr, "%s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__); fflush (stderr)
00009 #endif
00010
00011 #include <stdio.h>
00012 #ifdef DBUS_WINCE
00013 #include <process.h>
00014 #endif
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "dbus-spawn.h"
00041 #include "dbus-sysdeps.h"
00042 #include "dbus-sysdeps-win.h"
00043 #include "dbus-internals.h"
00044 #include "dbus-test.h"
00045 #include "dbus-protocol.h"
00046
00047 #define WIN32_LEAN_AND_MEAN
00048
00049
00050
00051 #include <winsock2.h>
00052 #undef interface
00053
00054 #include <stdlib.h>
00055
00056 #include <process.h>
00057
00061 struct DBusBabysitter
00062 {
00063 int refcount;
00064
00065 HANDLE start_sync_event;
00066 #ifdef DBUS_BUILD_TESTS
00067
00068 HANDLE end_sync_event;
00069 #endif
00070
00071 char *executable;
00072 DBusSpawnChildSetupFunc child_setup;
00073 void *user_data;
00074
00075 int argc;
00076 char **argv;
00077 char **envp;
00078
00079 HANDLE child_handle;
00080 int socket_to_babysitter;
00081 int socket_to_main;
00082
00083 DBusWatchList *watches;
00084 DBusWatch *sitter_watch;
00085
00086 dbus_bool_t have_spawn_errno;
00087 int spawn_errno;
00088 dbus_bool_t have_child_status;
00089 int child_status;
00090 };
00091
00092 static DBusBabysitter*
00093 _dbus_babysitter_new (void)
00094 {
00095 DBusBabysitter *sitter;
00096
00097 sitter = dbus_new0 (DBusBabysitter, 1);
00098 if (sitter == NULL)
00099 return NULL;
00100
00101 sitter->refcount = 1;
00102
00103 sitter->start_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00104 if (sitter->start_sync_event == NULL)
00105 {
00106 _dbus_babysitter_unref (sitter);
00107 return NULL;
00108 }
00109
00110 #ifdef DBUS_BUILD_TESTS
00111 sitter->end_sync_event = CreateEvent (NULL, FALSE, FALSE, NULL);
00112 if (sitter->end_sync_event == NULL)
00113 {
00114 _dbus_babysitter_unref (sitter);
00115 return NULL;
00116 }
00117 #endif
00118
00119 sitter->child_handle = NULL;
00120
00121 sitter->socket_to_babysitter = sitter->socket_to_main = -1;
00122
00123 sitter->argc = 0;
00124 sitter->argv = NULL;
00125 sitter->envp = NULL;
00126
00127 sitter->watches = _dbus_watch_list_new ();
00128 if (sitter->watches == NULL)
00129 {
00130 _dbus_babysitter_unref (sitter);
00131 return NULL;
00132 }
00133
00134 sitter->have_spawn_errno = FALSE;
00135 sitter->have_child_status = FALSE;
00136
00137 return sitter;
00138 }
00139
00146 DBusBabysitter *
00147 _dbus_babysitter_ref (DBusBabysitter *sitter)
00148 {
00149 PING();
00150 _dbus_assert (sitter != NULL);
00151 _dbus_assert (sitter->refcount > 0);
00152
00153 sitter->refcount += 1;
00154
00155 return sitter;
00156 }
00157
00163 void
00164 _dbus_babysitter_unref (DBusBabysitter *sitter)
00165 {
00166 int i;
00167
00168 PING();
00169 _dbus_assert (sitter != NULL);
00170 _dbus_assert (sitter->refcount > 0);
00171
00172 sitter->refcount -= 1;
00173
00174 if (sitter->refcount == 0)
00175 {
00176 if (sitter->socket_to_babysitter != -1)
00177 {
00178 _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00179 sitter->socket_to_babysitter = -1;
00180 }
00181
00182 if (sitter->socket_to_main != -1)
00183 {
00184 _dbus_close_socket (sitter->socket_to_main, NULL);
00185 sitter->socket_to_main = -1;
00186 }
00187
00188 PING();
00189 if (sitter->argv != NULL)
00190 {
00191 for (i = 0; i < sitter->argc; i++)
00192 if (sitter->argv[i] != NULL)
00193 {
00194 dbus_free (sitter->argv[i]);
00195 sitter->argv[i] = NULL;
00196 }
00197 dbus_free (sitter->argv);
00198 sitter->argv = NULL;
00199 }
00200
00201 if (sitter->envp != NULL)
00202 {
00203 char **e = sitter->envp;
00204
00205 while (*e)
00206 dbus_free (*e++);
00207 dbus_free (sitter->envp);
00208 sitter->envp = NULL;
00209 }
00210
00211 if (sitter->child_handle != NULL)
00212 {
00213 CloseHandle (sitter->child_handle);
00214 sitter->child_handle = NULL;
00215 }
00216
00217 if (sitter->sitter_watch)
00218 {
00219 _dbus_watch_invalidate (sitter->sitter_watch);
00220 _dbus_watch_unref (sitter->sitter_watch);
00221 sitter->sitter_watch = NULL;
00222 }
00223
00224 if (sitter->watches)
00225 _dbus_watch_list_free (sitter->watches);
00226
00227 if (sitter->start_sync_event != NULL)
00228 {
00229 PING();
00230 CloseHandle (sitter->start_sync_event);
00231 sitter->end_sync_event = NULL;
00232 }
00233
00234 #ifdef DBUS_BUILD_TESTS
00235 if (sitter->end_sync_event != NULL)
00236 {
00237 CloseHandle (sitter->end_sync_event);
00238 sitter->end_sync_event = NULL;
00239 }
00240 #endif
00241
00242 dbus_free (sitter->executable);
00243
00244 dbus_free (sitter);
00245 }
00246 }
00247
00248 void
00249 _dbus_babysitter_kill_child (DBusBabysitter *sitter)
00250 {
00251 PING();
00252 if (sitter->child_handle == NULL)
00253 return;
00254
00255 PING();
00256 TerminateProcess (sitter->child_handle, 12345);
00257 }
00258
00264 dbus_bool_t
00265 _dbus_babysitter_get_child_exited (DBusBabysitter *sitter)
00266 {
00267 PING();
00268 return (sitter->child_handle == NULL);
00269 }
00270
00280 void
00281 _dbus_babysitter_set_child_exit_error (DBusBabysitter *sitter,
00282 DBusError *error)
00283 {
00284 PING();
00285 if (!_dbus_babysitter_get_child_exited (sitter))
00286 return;
00287
00288 PING();
00289 if (sitter->have_spawn_errno)
00290 {
00291 dbus_set_error (error, DBUS_ERROR_SPAWN_EXEC_FAILED,
00292 "Failed to execute program %s: %s",
00293 sitter->executable, _dbus_strerror (sitter->spawn_errno));
00294 }
00295 else if (sitter->have_child_status)
00296 {
00297 PING();
00298 dbus_set_error (error, DBUS_ERROR_SPAWN_CHILD_EXITED,
00299 "Process %s exited with status %d",
00300 sitter->executable, sitter->child_status);
00301 }
00302 else
00303 {
00304 PING();
00305 dbus_set_error (error, DBUS_ERROR_FAILED,
00306 "Process %s exited, status unknown",
00307 sitter->executable);
00308 }
00309 PING();
00310 }
00311
00312 dbus_bool_t
00313 _dbus_babysitter_set_watch_functions (DBusBabysitter *sitter,
00314 DBusAddWatchFunction add_function,
00315 DBusRemoveWatchFunction remove_function,
00316 DBusWatchToggledFunction toggled_function,
00317 void *data,
00318 DBusFreeFunction free_data_function)
00319 {
00320 PING();
00321 return _dbus_watch_list_set_functions (sitter->watches,
00322 add_function,
00323 remove_function,
00324 toggled_function,
00325 data,
00326 free_data_function);
00327 }
00328
00329 static dbus_bool_t
00330 handle_watch (DBusWatch *watch,
00331 unsigned int condition,
00332 void *data)
00333 {
00334 DBusBabysitter *sitter = data;
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 PING();
00347 _dbus_close_socket (sitter->socket_to_babysitter, NULL);
00348 PING();
00349 sitter->socket_to_babysitter = -1;
00350
00351 return TRUE;
00352 }
00353
00354
00355 static int
00356 protect_argv (char **argv,
00357 char ***new_argv)
00358 {
00359 int i;
00360 int argc = 0;
00361
00362 while (argv[argc])
00363 ++argc;
00364 *new_argv = dbus_malloc ((argc + 1) * sizeof (char *));
00365 if (*new_argv == NULL)
00366 return -1;
00367
00368 for (i = 0; i < argc; i++)
00369 (*new_argv)[i] = NULL;
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 for (i = 0; i < argc; i++)
00383 {
00384 char *p = argv[i];
00385 char *q;
00386 int len = 0;
00387 int need_dblquotes = FALSE;
00388 while (*p)
00389 {
00390 if (*p == ' ' || *p == '\t')
00391 need_dblquotes = TRUE;
00392 else if (*p == '"')
00393 len++;
00394 else if (*p == '\\')
00395 {
00396 char *pp = p;
00397 while (*pp && *pp == '\\')
00398 pp++;
00399 if (*pp == '"')
00400 len++;
00401 }
00402 len++;
00403 p++;
00404 }
00405
00406 q = (*new_argv)[i] = dbus_malloc (len + need_dblquotes*2 + 1);
00407
00408 if (q == NULL)
00409 return -1;
00410
00411
00412 p = argv[i];
00413
00414 if (need_dblquotes)
00415 *q++ = '"';
00416
00417 while (*p)
00418 {
00419 if (*p == '"')
00420 *q++ = '\\';
00421 else if (*p == '\\')
00422 {
00423 char *pp = p;
00424 while (*pp && *pp == '\\')
00425 pp++;
00426 if (*pp == '"')
00427 *q++ = '\\';
00428 }
00429 *q++ = *p;
00430 p++;
00431 }
00432
00433 if (need_dblquotes)
00434 *q++ = '"';
00435 *q++ = '\0';
00436
00437 }
00438 (*new_argv)[argc] = NULL;
00439
00440 return argc;
00441 }
00442
00443 static unsigned __stdcall
00444 babysitter (void *parameter)
00445 {
00446 DBusBabysitter *sitter = (DBusBabysitter *) parameter;
00447 int fd;
00448 PING();
00449 _dbus_babysitter_ref (sitter);
00450
00451 if (sitter->child_setup)
00452 {
00453 PING();
00454 (*sitter->child_setup) (sitter->user_data);
00455 }
00456
00457 _dbus_verbose ("babysitter: spawning %s\n", sitter->executable);
00458
00459 PING();
00460 if (sitter->envp != NULL)
00461 sitter->child_handle = (HANDLE) spawnve (P_NOWAIT, sitter->executable,
00462 (const char * const *) sitter->argv,
00463 (const char * const *) sitter->envp);
00464 else
00465 sitter->child_handle = (HANDLE) spawnv (P_NOWAIT, sitter->executable,
00466 (const char * const *) sitter->argv);
00467
00468 PING();
00469 if (sitter->child_handle == (HANDLE) -1)
00470 {
00471 sitter->child_handle = NULL;
00472 sitter->have_spawn_errno = TRUE;
00473 sitter->spawn_errno = errno;
00474 }
00475
00476 PING();
00477 SetEvent (sitter->start_sync_event);
00478
00479 if (sitter->child_handle != NULL)
00480 {
00481 int ret;
00482 DWORD status;
00483
00484 PING();
00485 WaitForSingleObject (sitter->child_handle, INFINITE);
00486
00487 PING();
00488 ret = GetExitCodeProcess (sitter->child_handle, &status);
00489
00490 sitter->child_status = status;
00491 sitter->have_child_status = TRUE;
00492
00493 CloseHandle (sitter->child_handle);
00494 sitter->child_handle = NULL;
00495 }
00496
00497 #ifdef DBUS_BUILD_TESTS
00498 SetEvent (sitter->end_sync_event);
00499 #endif
00500
00501 PING();
00502 send (sitter->socket_to_main, " ", 1, 0);
00503
00504 _dbus_babysitter_unref (sitter);
00505
00506 return 0;
00507 }
00508
00509 dbus_bool_t
00510 _dbus_spawn_async_with_babysitter (DBusBabysitter **sitter_p,
00511 char **argv,
00512 char **envp,
00513 DBusSpawnChildSetupFunc child_setup,
00514 void *user_data,
00515 DBusError *error)
00516 {
00517 DBusBabysitter *sitter;
00518 HANDLE sitter_thread;
00519 int sitter_thread_id;
00520
00521 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00522
00523 *sitter_p = NULL;
00524
00525 PING();
00526 sitter = _dbus_babysitter_new ();
00527 if (sitter == NULL)
00528 {
00529 _DBUS_SET_OOM (error);
00530 return FALSE;
00531 }
00532
00533 sitter->child_setup = child_setup;
00534 sitter->user_data = user_data;
00535
00536 sitter->executable = _dbus_strdup (argv[0]);
00537 if (sitter->executable == NULL)
00538 {
00539 _DBUS_SET_OOM (error);
00540 goto out0;
00541 }
00542
00543 PING();
00544 if (!_dbus_full_duplex_pipe (&sitter->socket_to_babysitter,
00545 &sitter->socket_to_main,
00546 FALSE, error))
00547 goto out0;
00548
00549 sitter->sitter_watch = _dbus_watch_new (sitter->socket_to_babysitter,
00550 DBUS_WATCH_READABLE,
00551 TRUE, handle_watch, sitter, NULL);
00552 PING();
00553 if (sitter->sitter_watch == NULL)
00554 {
00555 _DBUS_SET_OOM (error);
00556 goto out0;
00557 }
00558
00559 PING();
00560 if (!_dbus_watch_list_add_watch (sitter->watches, sitter->sitter_watch))
00561 {
00562 _DBUS_SET_OOM (error);
00563 goto out0;
00564 }
00565
00566 sitter->argc = protect_argv (argv, &sitter->argv);
00567 if (sitter->argc == -1)
00568 {
00569 _DBUS_SET_OOM (error);
00570 goto out0;
00571 }
00572 sitter->envp = envp;
00573
00574 PING();
00575 sitter_thread = (HANDLE) _beginthreadex (NULL, 0, babysitter,
00576 sitter, 0, &sitter_thread_id);
00577
00578 if (sitter_thread == 0)
00579 {
00580 PING();
00581 dbus_set_error_const (error, DBUS_ERROR_SPAWN_FORK_FAILED,
00582 "Failed to create new thread");
00583 goto out0;
00584 }
00585 CloseHandle (sitter_thread);
00586
00587 PING();
00588 WaitForSingleObject (sitter->start_sync_event, INFINITE);
00589
00590 PING();
00591 if (sitter_p != NULL)
00592 *sitter_p = sitter;
00593 else
00594 _dbus_babysitter_unref (sitter);
00595
00596 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00597
00598 PING();
00599 return TRUE;
00600
00601 out0:
00602 _dbus_babysitter_unref (sitter);
00603
00604 return FALSE;
00605 }
00606
00607 #ifdef DBUS_BUILD_TESTS
00608
00609 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
00610
00611 static void
00612 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
00613 {
00614 if (sitter->child_handle == NULL)
00615 return;
00616
00617 WaitForSingleObject (sitter->end_sync_event, INFINITE);
00618 }
00619
00620 static dbus_bool_t
00621 check_spawn_nonexistent (void *data)
00622 {
00623 char *argv[4] = { NULL, NULL, NULL, NULL };
00624 DBusBabysitter *sitter = NULL;
00625 DBusError error = DBUS_ERROR_INIT;
00626
00627
00628
00629 argv[0] = "/this/does/not/exist/32542sdgafgafdg";
00630 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00631 NULL, NULL,
00632 &error))
00633 {
00634 _dbus_babysitter_block_for_child_exit (sitter);
00635 _dbus_babysitter_set_child_exit_error (sitter, &error);
00636 }
00637
00638 if (sitter)
00639 _dbus_babysitter_unref (sitter);
00640
00641 if (!dbus_error_is_set (&error))
00642 {
00643 _dbus_warn ("Did not get an error launching nonexistent executable\n");
00644 return FALSE;
00645 }
00646
00647 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00648 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_EXEC_FAILED)))
00649 {
00650 _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s\n",
00651 error.name, error.message);
00652 dbus_error_free (&error);
00653 return FALSE;
00654 }
00655
00656 dbus_error_free (&error);
00657
00658 return TRUE;
00659 }
00660
00661 static dbus_bool_t
00662 check_spawn_segfault (void *data)
00663 {
00664 char *argv[4] = { NULL, NULL, NULL, NULL };
00665 DBusBabysitter *sitter = NULL;
00666 DBusError error = DBUS_ERROR_INIT;
00667
00668
00669
00670 argv[0] = TEST_SEGFAULT_BINARY;
00671 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00672 NULL, NULL,
00673 &error))
00674 {
00675 _dbus_babysitter_block_for_child_exit (sitter);
00676 _dbus_babysitter_set_child_exit_error (sitter, &error);
00677 }
00678
00679 if (sitter)
00680 _dbus_babysitter_unref (sitter);
00681
00682 if (!dbus_error_is_set (&error))
00683 {
00684 _dbus_warn ("Did not get an error launching segfaulting binary\n");
00685 return FALSE;
00686 }
00687
00688 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00689 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00690 {
00691 _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s\n",
00692 error.name, error.message);
00693 dbus_error_free (&error);
00694 return FALSE;
00695 }
00696
00697 dbus_error_free (&error);
00698
00699 return TRUE;
00700 }
00701
00702 static dbus_bool_t
00703 check_spawn_exit (void *data)
00704 {
00705 char *argv[4] = { NULL, NULL, NULL, NULL };
00706 DBusBabysitter *sitter = NULL;
00707 DBusError error = DBUS_ERROR_INIT;
00708
00709
00710
00711 argv[0] = TEST_EXIT_BINARY;
00712 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00713 NULL, NULL,
00714 &error))
00715 {
00716 _dbus_babysitter_block_for_child_exit (sitter);
00717 _dbus_babysitter_set_child_exit_error (sitter, &error);
00718 }
00719
00720 if (sitter)
00721 _dbus_babysitter_unref (sitter);
00722
00723 if (!dbus_error_is_set (&error))
00724 {
00725 _dbus_warn ("Did not get an error launching binary that exited with failure code\n");
00726 return FALSE;
00727 }
00728
00729 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00730 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00731 {
00732 _dbus_warn ("Not expecting error when launching exiting executable: %s: %s\n",
00733 error.name, error.message);
00734 dbus_error_free (&error);
00735 return FALSE;
00736 }
00737
00738 dbus_error_free (&error);
00739
00740 return TRUE;
00741 }
00742
00743 static dbus_bool_t
00744 check_spawn_and_kill (void *data)
00745 {
00746 char *argv[4] = { NULL, NULL, NULL, NULL };
00747 DBusBabysitter *sitter = NULL;
00748 DBusError error = DBUS_ERROR_INIT;
00749
00750
00751
00752 argv[0] = TEST_SLEEP_FOREVER_BINARY;
00753 if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
00754 NULL, NULL,
00755 &error))
00756 {
00757 _dbus_babysitter_kill_child (sitter);
00758
00759 _dbus_babysitter_block_for_child_exit (sitter);
00760
00761 _dbus_babysitter_set_child_exit_error (sitter, &error);
00762 }
00763
00764 if (sitter)
00765 _dbus_babysitter_unref (sitter);
00766
00767 if (!dbus_error_is_set (&error))
00768 {
00769 _dbus_warn ("Did not get an error after killing spawned binary\n");
00770 return FALSE;
00771 }
00772
00773 if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
00774 dbus_error_has_name (&error, DBUS_ERROR_SPAWN_CHILD_EXITED)))
00775 {
00776 _dbus_warn ("Not expecting error when killing executable: %s: %s\n",
00777 error.name, error.message);
00778 dbus_error_free (&error);
00779 return FALSE;
00780 }
00781
00782 dbus_error_free (&error);
00783
00784 return TRUE;
00785 }
00786
00787 dbus_bool_t
00788 _dbus_spawn_test (const char *test_data_dir)
00789 {
00790 if (!_dbus_test_oom_handling ("spawn_nonexistent",
00791 check_spawn_nonexistent,
00792 NULL))
00793 return FALSE;
00794
00795
00796
00797
00798 if (getenv ("DO_SEGFAULT_TEST"))
00799 if (!_dbus_test_oom_handling ("spawn_segfault",
00800 check_spawn_segfault,
00801 NULL))
00802 return FALSE;
00803
00804 if (!_dbus_test_oom_handling ("spawn_exit",
00805 check_spawn_exit,
00806 NULL))
00807 return FALSE;
00808
00809 if (!_dbus_test_oom_handling ("spawn_and_kill",
00810 check_spawn_and_kill,
00811 NULL))
00812 return FALSE;
00813
00814 return TRUE;
00815 }
00816 #endif