D-Bus  1.13.7
dbus-spawn-test.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-spawn-test.c
3  *
4  * Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
5  * Copyright (C) 2003 CodeFactory AB
6  * Copyright (C) 2005 Novell, Inc.
7  *
8  * Licensed under the Academic Free License version 2.1
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  */
25 #include <config.h>
26 
27 
28 #include "dbus-spawn.h"
29 #include "dbus-sysdeps.h"
30 #include "dbus-test.h"
31 
32 static char *
33 get_test_exec (const char *exe,
34  DBusString *scratch_space)
35 {
36  const char *dbus_test_exec;
37 
38  dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC");
39 
40  if (dbus_test_exec == NULL)
41  return NULL;
42 
43  if (!_dbus_string_init (scratch_space))
44  return NULL;
45 
46  if (!_dbus_string_append_printf (scratch_space, "%s/%s%s",
47  dbus_test_exec, exe, DBUS_EXEEXT))
48  {
49  _dbus_string_free (scratch_space);
50  return NULL;
51  }
52 
53  return _dbus_string_get_data (scratch_space);
54 }
55 
56 static dbus_bool_t
57 check_spawn_nonexistent (void *data,
58  dbus_bool_t have_memory)
59 {
60  static const char arg_does_not_exist[] = "/this/does/not/exist/32542sdgafgafdg";
61 
62  const char *argv[4] = { NULL, NULL, NULL, NULL };
63  DBusBabysitter *sitter = NULL;
64  DBusError error = DBUS_ERROR_INIT;
65 
66  /*** Test launching nonexistent binary */
67 
68  argv[0] = arg_does_not_exist;
69  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_nonexistent",
70  (char * const *) argv,
71  NULL, DBUS_SPAWN_NONE, NULL, NULL,
72  &error))
73  {
74  _dbus_babysitter_block_for_child_exit (sitter);
76  }
77 
78  if (sitter)
79  _dbus_babysitter_unref (sitter);
80 
81  if (!dbus_error_is_set (&error))
82  {
83  _dbus_warn ("Did not get an error launching nonexistent executable");
84  return FALSE;
85  }
86 
87  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
89  {
90  _dbus_warn ("Not expecting error when launching nonexistent executable: %s: %s",
91  error.name, error.message);
92  dbus_error_free (&error);
93  return FALSE;
94  }
95 
96  dbus_error_free (&error);
97 
98  return TRUE;
99 }
100 
101 static dbus_bool_t
102 check_spawn_segfault (void *data,
103  dbus_bool_t have_memory)
104 {
105  char *argv[4] = { NULL, NULL, NULL, NULL };
106  DBusBabysitter *sitter = NULL;
107  DBusError error = DBUS_ERROR_INIT;
108  DBusString argv0;
109 
110  /*** Test launching segfault binary */
111 
112  argv[0] = get_test_exec ("test-segfault", &argv0);
113 
114  if (argv[0] == NULL)
115  {
116  /* OOM was simulated or DBUS_TEST_EXEC was unset; either is OK */
117  return TRUE;
118  }
119 
120  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_segfault", argv,
121  NULL, DBUS_SPAWN_NONE, NULL, NULL,
122  &error))
123  {
124  _dbus_babysitter_block_for_child_exit (sitter);
125  _dbus_babysitter_set_child_exit_error (sitter, &error);
126  }
127 
128  _dbus_string_free (&argv0);
129 
130  if (sitter)
131  _dbus_babysitter_unref (sitter);
132 
133  if (!dbus_error_is_set (&error))
134  {
135  _dbus_warn ("Did not get an error launching segfaulting binary");
136  return FALSE;
137  }
138 
139  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
140 #ifdef DBUS_WIN
142 #else
144 #endif
145  {
146  _dbus_warn ("Not expecting error when launching segfaulting executable: %s: %s",
147  error.name, error.message);
148  dbus_error_free (&error);
149  return FALSE;
150  }
151 
152  dbus_error_free (&error);
153 
154  return TRUE;
155 }
156 
157 static dbus_bool_t
158 check_spawn_exit (void *data,
159  dbus_bool_t have_memory)
160 {
161  char *argv[4] = { NULL, NULL, NULL, NULL };
162  DBusBabysitter *sitter = NULL;
163  DBusError error = DBUS_ERROR_INIT;
164  DBusString argv0;
165 
166  /*** Test launching exit failure binary */
167 
168  argv[0] = get_test_exec ("test-exit", &argv0);
169 
170  if (argv[0] == NULL)
171  {
172  /* OOM was simulated or DBUS_TEST_EXEC was unset; either is OK */
173  return TRUE;
174  }
175 
176  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_exit", argv,
177  NULL, DBUS_SPAWN_NONE, NULL, NULL,
178  &error))
179  {
180  _dbus_babysitter_block_for_child_exit (sitter);
181  _dbus_babysitter_set_child_exit_error (sitter, &error);
182  }
183 
184  _dbus_string_free (&argv0);
185 
186  if (sitter)
187  _dbus_babysitter_unref (sitter);
188 
189  if (!dbus_error_is_set (&error))
190  {
191  _dbus_warn ("Did not get an error launching binary that exited with failure code");
192  return FALSE;
193  }
194 
195  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
197  {
198  _dbus_warn ("Not expecting error when launching exiting executable: %s: %s",
199  error.name, error.message);
200  dbus_error_free (&error);
201  return FALSE;
202  }
203 
204  dbus_error_free (&error);
205 
206  return TRUE;
207 }
208 
209 static dbus_bool_t
210 check_spawn_and_kill (void *data,
211  dbus_bool_t have_memory)
212 {
213  char *argv[4] = { NULL, NULL, NULL, NULL };
214  DBusBabysitter *sitter = NULL;
215  DBusError error = DBUS_ERROR_INIT;
216  DBusString argv0;
217 
218  /*** Test launching sleeping binary then killing it */
219 
220  argv[0] = get_test_exec ("test-sleep-forever", &argv0);
221 
222  if (argv[0] == NULL)
223  {
224  /* OOM was simulated or DBUS_TEST_EXEC was unset; either is OK */
225  return TRUE;
226  }
227 
228  if (_dbus_spawn_async_with_babysitter (&sitter, "spawn_and_kill", argv,
229  NULL, DBUS_SPAWN_NONE, NULL, NULL,
230  &error))
231  {
233 
234  _dbus_babysitter_block_for_child_exit (sitter);
235 
236  _dbus_babysitter_set_child_exit_error (sitter, &error);
237  }
238 
239  _dbus_string_free (&argv0);
240 
241  if (sitter)
242  _dbus_babysitter_unref (sitter);
243 
244  if (!dbus_error_is_set (&error))
245  {
246  _dbus_warn ("Did not get an error after killing spawned binary");
247  return FALSE;
248  }
249 
250  if (!(dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY) ||
251 #ifdef DBUS_WIN
253 #else
255 #endif
256  {
257  _dbus_warn ("Not expecting error when killing executable: %s: %s",
258  error.name, error.message);
259  dbus_error_free (&error);
260  return FALSE;
261  }
262 
263  dbus_error_free (&error);
264 
265  return TRUE;
266 }
267 
269 _dbus_spawn_test (const char *test_data_dir)
270 {
271  if (!_dbus_test_oom_handling ("spawn_nonexistent",
272  check_spawn_nonexistent,
273  NULL))
274  return FALSE;
275 
276  if (!_dbus_test_oom_handling ("spawn_segfault",
277  check_spawn_segfault,
278  NULL))
279  return FALSE;
280 
281  if (!_dbus_test_oom_handling ("spawn_exit",
282  check_spawn_exit,
283  NULL))
284  return FALSE;
285 
286  if (!_dbus_test_oom_handling ("spawn_and_kill",
287  check_spawn_and_kill,
288  NULL))
289  return FALSE;
290 
291  return TRUE;
292 }
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
const char * message
public error message field
Definition: dbus-errors.h:51
#define NULL
A null pointer, defined appropriately for C or C++.
#define DBUS_ERROR_SPAWN_EXEC_FAILED
While starting a new process, the exec() call failed.
#define DBUS_ERROR_SPAWN_CHILD_EXITED
While starting a new process, the child exited with a status code.
#define DBUS_ERROR_INIT
Expands to a suitable initializer for a DBusError on the stack.
Definition: dbus-errors.h:62
void dbus_error_free(DBusError *error)
Frees an error that&#39;s been set (or just initialized), then reinitializes the error as in dbus_error_i...
Definition: dbus-errors.c:211
dbus_bool_t _dbus_string_init(DBusString *str)
Initializes a string.
Definition: dbus-string.c:175
#define DBUS_ERROR_SPAWN_CHILD_SIGNALED
While starting a new process, the child exited on a signal.
dbus_uint32_t dbus_bool_t
A boolean, valid values are TRUE and FALSE.
Definition: dbus-types.h:35
void _dbus_babysitter_kill_child(DBusBabysitter *sitter)
Blocks until the babysitter process gives us the PID of the spawned grandchild, then kills the spawne...
Babysitter implementation details.
void _dbus_warn(const char *format,...)
Prints a warning message to stderr.
dbus_bool_t _dbus_spawn_async_with_babysitter(DBusBabysitter **sitter_p, const char *log_name, char *const *argv, char **env, DBusSpawnFlags flags, DBusSpawnChildSetupFunc child_setup, void *user_data, DBusError *error)
Spawns a new process.
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:1131
Object representing an exception.
Definition: dbus-errors.h:48
void _dbus_string_free(DBusString *str)
Frees a string created by _dbus_string_init(), and fills it with the same contents as #_DBUS_STRING_I...
Definition: dbus-string.c:264
#define TRUE
Expands to "1".
const char * name
public error name field
Definition: dbus-errors.h:50
void _dbus_babysitter_unref(DBusBabysitter *sitter)
Decrement the reference count on the babysitter object.
#define DBUS_ERROR_NO_MEMORY
There was not enough memory to complete an operation.
#define FALSE
Expands to "0".
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...
const char * _dbus_getenv(const char *varname)
Wrapper for getenv().
Definition: dbus-sysdeps.c:195
dbus_bool_t dbus_error_is_set(const DBusError *error)
Checks whether an error occurred (the error is set).
Definition: dbus-errors.c:329