static dbus_bool_t print_install_root() { DBusString runtime_prefix; if (!_dbus_string_init (&runtime_prefix)) { _dbus_assert_not_reached ("out of memory"); return FALSE; } if (!_dbus_get_install_root (&runtime_prefix)) { _dbus_assert_not_reached ("out of memory"); _dbus_string_free (&runtime_prefix); return FALSE; } if (_dbus_string_get_length (&runtime_prefix) == 0) { fprintf (stderr, "_dbus_get_install_root() failed\n"); _dbus_string_free (&runtime_prefix); return FALSE; } fprintf (stdout, "_dbus_get_install_root() returned '%s'\n", _dbus_string_get_const_data (&runtime_prefix)); _dbus_string_free (&runtime_prefix); return TRUE; }
static void check_dirname (const char *filename, const char *dirname) { DBusString f, d; _dbus_string_init_const (&f, filename); if (!_dbus_string_init (&d)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_get_dirname (&f, &d)) _dbus_assert_not_reached ("no memory"); if (!_dbus_string_equal_c_str (&d, dirname)) { _dbus_warn ("For filename \"%s\" got dirname \"%s\" and expected \"%s\"\n", filename, _dbus_string_get_const_data (&d), dirname); exit (1); } _dbus_string_free (&d); }
/** * @ingroup DBusMemoryInternals * Unit test for DBusMemory * @returns #TRUE on success. */ dbus_bool_t _dbus_memory_test (void) { dbus_bool_t old_guards; void *p; size_t size; old_guards = guards; guards = TRUE; p = dbus_malloc (4); if (p == NULL) _dbus_assert_not_reached ("no memory"); for (size = 4; size < 256; size += 4) { p = dbus_realloc (p, size); if (p == NULL) _dbus_assert_not_reached ("no memory"); } for (size = 256; size != 0; size -= 4) { p = dbus_realloc (p, size); if (p == NULL) _dbus_assert_not_reached ("no memory"); } dbus_free (p); guards = old_guards; return TRUE; }
/** * Unit test for dbus-userdb.c. * * @returns #TRUE on success. */ dbus_bool_t _dbus_userdb_test (const char *test_data_dir) { const DBusString *username; const DBusString *homedir; dbus_uid_t uid; unsigned long *group_ids; int n_group_ids, i; if (!_dbus_username_from_current_process (&username)) _dbus_assert_not_reached ("didn't get username"); if (!_dbus_homedir_from_current_process (&homedir)) _dbus_assert_not_reached ("didn't get homedir"); if (!_dbus_get_user_id (username, &uid)) _dbus_assert_not_reached ("didn't get uid"); if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids)) _dbus_assert_not_reached ("didn't get groups"); printf (" Current user: %s homedir: %s gids:", _dbus_string_get_const_data (username), _dbus_string_get_const_data (homedir)); for (i=0; i<n_group_ids; i++) printf(" %ld", group_ids[i]); printf ("\n"); dbus_free (group_ids); return TRUE; }
static void set_reply_serial (DBusMessage *message) { if (message == NULL) _dbus_assert_not_reached ("oom"); if (!dbus_message_set_reply_serial (message, 100)) _dbus_assert_not_reached ("oom"); }
static dbus_bool_t generate_many_bodies_inner (DBusMessageDataIter *iter, DBusMessage **message_p) { DBusMessage *message; DBusString signature; DBusString body; char byte_order; /* Keeping this small makes things go faster */ message = dbus_message_new_method_call ("o.z.F", "/", "o.z.B", "Nah"); if (message == NULL) _dbus_assert_not_reached ("oom"); byte_order = _dbus_header_get_byte_order (&message->header); set_reply_serial (message); if (!_dbus_string_init (&signature) || !_dbus_string_init (&body)) _dbus_assert_not_reached ("oom"); if (dbus_internal_do_not_use_generate_bodies (iter_get_sequence (iter), byte_order, &signature, &body)) { const char *v_SIGNATURE; v_SIGNATURE = _dbus_string_get_const_data (&signature); if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_SIGNATURE)) _dbus_assert_not_reached ("oom"); if (!_dbus_string_move (&body, 0, &message->body, 0)) _dbus_assert_not_reached ("oom"); _dbus_marshal_set_uint32 (&message->header.data, BODY_LENGTH_OFFSET, _dbus_string_get_length (&message->body), byte_order); *message_p = message; } else { dbus_message_unref (message); *message_p = NULL; } _dbus_string_free (&signature); _dbus_string_free (&body); return *message_p != NULL; }
static dbus_bool_t generate_trivial_inner (DBusMessageDataIter *iter, DBusMessage **message_p) { DBusMessage *message; switch (iter_get_sequence (iter)) { case 0: message = dbus_message_new_method_call ("org.freedesktop.TextEditor", "/foo/bar", "org.freedesktop.DocumentFactory", "Create"); break; case 1: message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN); set_reply_serial (message); break; case 2: message = dbus_message_new_signal ("/foo/bar", "org.freedesktop.DocumentFactory", "Created"); break; case 3: message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); if (!dbus_message_set_error_name (message, "org.freedesktop.TestErrorName")) _dbus_assert_not_reached ("oom"); { DBusMessageIter iter; const char *v_STRING = "This is an error"; dbus_message_iter_init_append (message, &iter); if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING)) _dbus_assert_not_reached ("oom"); } set_reply_serial (message); break; default: return FALSE; } if (message == NULL) _dbus_assert_not_reached ("oom"); *message_p = message; return TRUE; }
dbus_bool_t _dbus_server_test (void) { const char *valid_addresses[] = { "tcp:port=1234", "tcp:host=localhost,port=1234", "tcp:host=localhost,port=1234;tcp:port=5678", #ifdef DBUS_UNIX "unix:path=./boogie", "tcp:port=1234;unix:path=./boogie", #endif }; DBusServer *server; int i; for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++) { DBusError error = DBUS_ERROR_INIT; char *address; char *id; server = dbus_server_listen (valid_addresses[i], &error); if (server == NULL) { _dbus_warn ("server listen error: %s: %s\n", error.name, error.message); dbus_error_free (&error); _dbus_assert_not_reached ("Failed to listen for valid address."); } id = dbus_server_get_id (server); _dbus_assert (id != NULL); address = dbus_server_get_address (server); _dbus_assert (address != NULL); if (strstr (address, id) == NULL) { _dbus_warn ("server id '%s' is not in the server address '%s'\n", id, address); _dbus_assert_not_reached ("bad server id or address"); } dbus_free (id); dbus_free (address); dbus_server_disconnect (server); dbus_server_unref (server); } return TRUE; }
static DBusMessage* simple_error (void) { DBusMessage *message; message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); if (message == NULL) _dbus_assert_not_reached ("oom"); if (!dbus_message_set_error_name (message, "foo.bar")) _dbus_assert_not_reached ("oom"); set_reply_serial (message); return message; }
static void run_validity_tests (const ValidityTest *tests, int n_tests, DBusValidity (* func) (const DBusString*,int,int)) { int i; for (i = 0; i < n_tests; i++) { DBusString str; DBusValidity v; _dbus_string_init_const (&str, tests[i].data); v = (*func) (&str, 0, _dbus_string_get_length (&str)); if (v != tests[i].expected) { _dbus_warn ("Improper validation result %d for '%s'\n", v, tests[i].data); _dbus_assert_not_reached ("test failed"); } ++i; } }
/** * Sets a struct of { byte, variant } with the given basic type. * * @param reader the reader (should be iterating over the array pointing at the field to set) * @param type the type of the value * @param value the value as for _dbus_marshal_set_basic() * @param realign_root where to realign from * @returns #FALSE if no memory */ static dbus_bool_t set_basic_field (DBusTypeReader *reader, int field, int type, const void *value, const DBusTypeReader *realign_root) { DBusTypeReader sub; DBusTypeReader variant; _dbus_type_reader_recurse (reader, &sub); _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE); #ifndef DBUS_DISABLE_ASSERT { unsigned char v_BYTE; _dbus_type_reader_read_basic (&sub, &v_BYTE); _dbus_assert (((int) v_BYTE) == field); } #endif if (!_dbus_type_reader_next (&sub)) _dbus_assert_not_reached ("no variant field?"); _dbus_type_reader_recurse (&sub, &variant); _dbus_assert (_dbus_type_reader_get_current_type (&variant) == type); if (!_dbus_type_reader_set_basic (&variant, value, realign_root)) return FALSE; return TRUE; }
static void randomly_set_extreme_ints (const DBusString *orig_data, DBusString *mutated) { int i; int byte_order; const char *d; dbus_uint32_t orig; static int which = 0; unsigned int extreme_ints[] = { _DBUS_INT_MAX, _DBUS_UINT_MAX, _DBUS_INT_MAX - 1, _DBUS_UINT_MAX - 1, _DBUS_INT_MAX - 2, _DBUS_UINT_MAX - 2, _DBUS_INT_MAX - 17, _DBUS_UINT_MAX - 17, _DBUS_INT_MAX / 2, _DBUS_INT_MAX / 3, _DBUS_UINT_MAX / 2, _DBUS_UINT_MAX / 3, 0, 1, 2, 3, (unsigned int) -1, (unsigned int) -2, (unsigned int) -3 }; if (orig_data != mutated) { _dbus_string_set_length (mutated, 0); if (!_dbus_string_copy (orig_data, 0, mutated, 0)) _dbus_assert_not_reached ("out of mem"); } if (_dbus_string_get_length (mutated) < 12) return; d = _dbus_string_get_const_data (mutated); if (!(*d == DBUS_LITTLE_ENDIAN || *d == DBUS_BIG_ENDIAN)) return; byte_order = *d; i = random_int_in_range (4, _dbus_string_get_length (mutated) - 8); i = _DBUS_ALIGN_VALUE (i, 4); orig = _dbus_demarshal_uint32 (mutated, byte_order, i, NULL); which = random_int_in_range (0, _DBUS_N_ELEMENTS (extreme_ints)); _dbus_assert (which >= 0); _dbus_assert (which < _DBUS_N_ELEMENTS (extreme_ints)); _dbus_marshal_set_uint32 (mutated, byte_order, i, extreme_ints[which]); }
/** * Tries loading the message in the given message file * and verifies that DBusMessageLoader can handle it. * * @param filename filename to load * @param expected_validity what the message has to be like to return #TRUE * @returns #TRUE if the message has the expected validity */ dbus_bool_t dbus_internal_do_not_use_try_message_file (const DBusString *filename, DBusValidity expected_validity) { DBusString data; dbus_bool_t retval; retval = FALSE; if (!_dbus_string_init (&data)) _dbus_assert_not_reached ("could not allocate string\n"); if (!dbus_internal_do_not_use_load_message_file (filename, &data)) goto failed; retval = dbus_internal_do_not_use_try_message_data (&data, expected_validity); failed: if (!retval) { if (_dbus_string_get_length (&data) > 0) _dbus_verbose_bytes_of_string (&data, 0, _dbus_string_get_length (&data)); _dbus_warn ("Failed message loader test on %s\n", _dbus_string_get_const_data (filename)); } _dbus_string_free (&data); return retval; }
static dbus_bool_t check_loader_results (DBusMessageLoader *loader, DBusValidity expected_validity) { if (!_dbus_message_loader_queue_messages (loader)) _dbus_assert_not_reached ("no memory to queue messages"); if (expected_validity == DBUS_VALID) return check_have_valid_message (loader); else if (expected_validity == DBUS_VALID_BUT_INCOMPLETE) return check_incomplete_message (loader); else if (expected_validity == DBUS_VALIDITY_UNKNOWN) { /* here we just know we didn't segfault and that was the * only test. Also, we record that we got coverage * for the validity reason. */ if (_dbus_message_loader_get_is_corrupted (loader)) record_validity_seen (loader->corruption_reason); return TRUE; } else return check_invalid_message (loader, expected_validity); }
static dbus_bool_t create_unique_client_name (BusRegistry *registry, DBusString *str) { /* We never want to use the same unique client name twice, because * we want to guarantee that if you send a message to a given unique * name, you always get the same application. So we use two numbers * for INT_MAX * INT_MAX combinations, should be pretty safe against * wraparound. */ /* FIXME these should be in BusRegistry rather than static vars */ static int next_major_number = 0; static int next_minor_number = 0; int len; len = _dbus_string_get_length (str); while (TRUE) { /* start out with 1-0, go to 1-1, 1-2, 1-3, * up to 1-MAXINT, then 2-0, 2-1, etc. */ if (next_minor_number <= 0) { next_major_number += 1; next_minor_number = 0; if (next_major_number <= 0) _dbus_assert_not_reached ("INT_MAX * INT_MAX clients were added"); } _dbus_assert (next_major_number > 0); _dbus_assert (next_minor_number >= 0); /* appname:MAJOR-MINOR */ if (!_dbus_string_append (str, ":")) return FALSE; if (!_dbus_string_append_int (str, next_major_number)) return FALSE; if (!_dbus_string_append (str, ".")) return FALSE; if (!_dbus_string_append_int (str, next_minor_number)) return FALSE; next_minor_number += 1; /* Check if a client with the name exists */ if (bus_registry_lookup (registry, str) == NULL) break; /* drop the number again, try the next one. */ _dbus_string_set_length (str, len); } return TRUE; }
/** * Unit test for dbus-userdb.c. * * @returns #TRUE on success. */ dbus_bool_t _dbus_userdb_test (const char *test_data_dir) { const DBusString *username; const DBusString *homedir; dbus_uid_t uid; unsigned long *group_ids; int n_group_ids, i; DBusError error; if (!_dbus_username_from_current_process (&username)) _dbus_assert_not_reached ("didn't get username"); if (!_dbus_homedir_from_current_process (&homedir)) _dbus_assert_not_reached ("didn't get homedir"); if (!_dbus_get_user_id (username, &uid)) _dbus_assert_not_reached ("didn't get uid"); if (!_dbus_groups_from_uid (uid, &group_ids, &n_group_ids)) _dbus_assert_not_reached ("didn't get groups"); printf (" Current user: %s homedir: %s gids:", _dbus_string_get_const_data (username), _dbus_string_get_const_data (homedir)); for (i=0; i<n_group_ids; i++) printf(" %ld", group_ids[i]); printf ("\n"); dbus_error_init (&error); printf ("Is Console user: %i\n", _dbus_is_console_user (uid, &error)); printf ("Invocation was OK: %s\n", error.message ? error.message : "yes"); dbus_error_free (&error); printf ("Is Console user 4711: %i\n", _dbus_is_console_user (4711, &error)); printf ("Invocation was OK: %s\n", error.message ? error.message : "yes"); dbus_error_free (&error); dbus_free (group_ids); return TRUE; }
void test_server_shutdown (DBusLoop *loop, DBusServer *server) { dbus_server_disconnect (server); if (!dbus_server_set_watch_functions (server, NULL, NULL, NULL, NULL, NULL)) _dbus_assert_not_reached ("setting watch functions to NULL failed"); if (!dbus_server_set_timeout_functions (server, NULL, NULL, NULL, NULL, NULL)) _dbus_assert_not_reached ("setting timeout functions to NULL failed"); }
const char* bus_config_parser_element_type_to_name (ElementType type) { switch (type) { case ELEMENT_NONE: return NULL; case ELEMENT_BUSCONFIG: return "busconfig"; case ELEMENT_INCLUDE: return "include"; case ELEMENT_USER: return "user"; case ELEMENT_LISTEN: return "listen"; case ELEMENT_AUTH: return "auth"; case ELEMENT_POLICY: return "policy"; case ELEMENT_LIMIT: return "limit"; case ELEMENT_ALLOW: return "allow"; case ELEMENT_DENY: return "deny"; case ELEMENT_FORK: return "fork"; case ELEMENT_PIDFILE: return "pidfile"; case ELEMENT_STANDARD_SESSION_SERVICEDIRS: return "standard_session_servicedirs"; case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS: return "standard_system_servicedirs"; case ELEMENT_SERVICEDIR: return "servicedir"; case ELEMENT_SERVICEHELPER: return "servicehelper"; case ELEMENT_INCLUDEDIR: return "includedir"; case ELEMENT_CONFIGTYPE: return "type"; case ELEMENT_SELINUX: return "selinux"; case ELEMENT_ASSOCIATE: return "associate"; case ELEMENT_SYSLOG: return "syslog"; case ELEMENT_KEEP_UMASK: return "keep_umask"; case ELEMENT_ALLOW_ANONYMOUS: return "allow_anonymous"; } _dbus_assert_not_reached ("bad element type"); return NULL; }
static void check_guards (void *free_block, dbus_bool_t overwrite) { if (free_block != NULL) { unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET; size_t requested_bytes = *(dbus_uint32_t*)block; BlockSource source = *(dbus_uint32_t*)(block + 4); unsigned int i; dbus_bool_t failed; failed = FALSE; #if 0 _dbus_verbose ("Checking %d bytes request from source %s\n", requested_bytes, source_string (source)); #endif i = GUARD_INFO_SIZE; while (i < GUARD_START_OFFSET) { dbus_uint32_t value = *(dbus_uint32_t*) &block[i]; if (value != GUARD_VALUE) { _dbus_warn ("Block of %lu bytes from %s had start guard value 0x%ux at %d expected 0x%x\n", (long) requested_bytes, source_string (source), value, i, GUARD_VALUE); failed = TRUE; } i += 4; } i = GUARD_START_OFFSET + requested_bytes; while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD)) { dbus_uint32_t value = *(dbus_uint32_t*) &block[i]; if (value != GUARD_VALUE) { _dbus_warn ("Block of %lu bytes from %s had end guard value 0x%ux at %d expected 0x%x\n", (long) requested_bytes, source_string (source), value, i, GUARD_VALUE); failed = TRUE; } i += 4; } /* set memory to anything but nul bytes */ if (overwrite) memset (free_block, 'g', requested_bytes); if (failed) _dbus_assert_not_reached ("guard value corruption"); } }
/** * Deallocates an object previously created with * _dbus_mem_pool_alloc(). The previous object * must have come from this same pool. * @param pool the memory pool * @param element the element earlier allocated. * @returns #TRUE if there are no remaining allocated elements */ dbus_bool_t _dbus_mem_pool_dealloc (DBusMemPool *pool, void *element) { #ifdef DBUS_BUILD_TESTS if (_dbus_disable_mem_pools ()) { DBusMemBlock *block; DBusMemBlock *prev; /* mmm, fast. ;-) debug-only code, so doesn't matter. */ prev = NULL; block = pool->blocks; while (block != NULL) { if (block->elements == (unsigned char*) element) { if (prev) prev->next = block->next; else pool->blocks = block->next; dbus_free (block); _dbus_assert (pool->allocated_elements > 0); pool->allocated_elements -= 1; if (pool->allocated_elements == 0) _dbus_assert (pool->blocks == NULL); return pool->blocks == NULL; } prev = block; block = block->next; } _dbus_assert_not_reached ("freed nonexistent block"); return FALSE; } else #endif { DBusFreedElement *freed; freed = element; freed->next = pool->free_elements; pool->free_elements = freed; _dbus_assert (pool->allocated_elements > 0); pool->allocated_elements -= 1; return pool->allocated_elements == 0; } }
static void test_max_len (DBusString *str, int max_len) { if (max_len > 0) { if (!_dbus_string_set_length (str, max_len - 1)) _dbus_assert_not_reached ("setting len to one less than max should have worked"); } if (!_dbus_string_set_length (str, max_len)) _dbus_assert_not_reached ("setting len to max len should have worked"); if (_dbus_string_set_length (str, max_len + 1)) _dbus_assert_not_reached ("setting len to one more than max len should not have worked"); if (!_dbus_string_set_length (str, 0)) _dbus_assert_not_reached ("setting len to zero should have worked"); }
static void generate_from_message (DBusString *data, DBusValidity *expected_validity, DBusMessage *message) { dbus_message_set_serial (message, 1); dbus_message_lock (message); *expected_validity = DBUS_VALID; /* move for efficiency, since we'll nuke the message anyway */ if (!_dbus_string_move (&message->header.data, 0, data, 0)) _dbus_assert_not_reached ("oom"); if (!_dbus_string_copy (&message->body, 0, data, _dbus_string_get_length (data))) _dbus_assert_not_reached ("oom"); }
void test_connection_shutdown (DBusLoop *loop, DBusConnection *connection) { if (!dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, NULL, NULL)) _dbus_assert_not_reached ("setting watch functions to NULL failed"); if (!dbus_connection_set_timeout_functions (connection, NULL, NULL, NULL, NULL, NULL)) _dbus_assert_not_reached ("setting timeout functions to NULL failed"); dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); }
static DBusMessage* simple_signal (void) { DBusMessage *message; message = dbus_message_new_signal ("/f/b", "o.b.Z", "Fro"); if (message == NULL) _dbus_assert_not_reached ("oom"); return message; }
static DBusMessage* simple_method_return (void) { DBusMessage *message; message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN); if (message == NULL) _dbus_assert_not_reached ("oom"); set_reply_serial (message); return message; }
static void check_memleaks (void) { dbus_shutdown (); if (_dbus_get_malloc_blocks_outstanding () != 0) { _dbus_warn ("%d dbus_malloc blocks were not freed in %s\n", _dbus_get_malloc_blocks_outstanding (), __FILE__); _dbus_assert_not_reached ("memleaks"); } }
/** * Removes a timeout from the timeout list, invoking the * application's DBusRemoveTimeoutFunction if appropriate. * * @param timeout_list the timeout list. * @param timeout the timeout to remove. */ void _dbus_timeout_list_remove_timeout (DBusTimeoutList *timeout_list, DBusTimeout *timeout) { if (!_dbus_list_remove (&timeout_list->timeouts, timeout)) _dbus_assert_not_reached ("Nonexistent timeout was removed"); if (timeout_list->remove_timeout_function != NULL) (* timeout_list->remove_timeout_function) (timeout, timeout_list->timeout_data); _dbus_timeout_unref (timeout); }
static DBusMessage* simple_method_call (void) { DBusMessage *message; /* Keeping this small makes stuff go faster */ message = dbus_message_new_method_call ("o.b.Q", "/f/b", "o.b.Z", "Fro"); if (message == NULL) _dbus_assert_not_reached ("oom"); return message; }
static void randomly_shorten_or_lengthen (const DBusString *orig_data, DBusString *mutated) { int delta; if (orig_data != mutated) { _dbus_string_set_length (mutated, 0); if (!_dbus_string_copy (orig_data, 0, mutated, 0)) _dbus_assert_not_reached ("out of mem"); } if (_dbus_string_get_length (mutated) == 0) delta = random_int_in_range (0, 10); else delta = random_int_in_range (- _dbus_string_get_length (mutated), _dbus_string_get_length (mutated) * 3); if (delta < 0) _dbus_string_shorten (mutated, - delta); else if (delta > 0) { int i = 0; i = _dbus_string_get_length (mutated); if (!_dbus_string_lengthen (mutated, delta)) _dbus_assert_not_reached ("couldn't lengthen string"); while (i < _dbus_string_get_length (mutated)) { _dbus_string_set_byte (mutated, i, random_int_in_range (0, 256)); ++i; } } }
/** * Gets the exit status of the child. We do this so implementation specific * detail is not cluttering up dbus, for example the system launcher code. * This can only be called if the child has exited, i.e. call * _dbus_babysitter_get_child_exited(). It returns FALSE if the child * did not return a status code, e.g. because the child was signaled * or we failed to ever launch the child in the first place. * * @param sitter the babysitter * @param status the returned status code * @returns #FALSE on failure */ dbus_bool_t _dbus_babysitter_get_child_exit_status (DBusBabysitter *sitter, int *status) { if (!_dbus_babysitter_get_child_exited (sitter)) _dbus_assert_not_reached ("Child has not exited"); if (!sitter->have_child_status || !(WIFEXITED (sitter->status))) return FALSE; *status = WEXITSTATUS (sitter->status); return TRUE; }