diff --git a/src/cpp/main.cc b/src/cpp/main.cc deleted file mode 100644 index d60600fd..00000000 --- a/src/cpp/main.cc +++ /dev/null @@ -1,151 +0,0 @@ -#if PPROF_ON -#include -#endif - -#include -#include -#include "sapi/embed/php_embed.h" -#include "ps_title.h" - -extern zend_module_entry *php_embed_get_module(); - -void module_init(zend_module_entry *module) { - if (zend_register_module_ex(module, MODULE_PERSISTENT) == NULL) { - zend_error(E_ERROR, "Failed to register module [%s]", module->name); - exit(255); - } - if (zend_startup_module_ex(module) == FAILURE) { - zend_error(E_ERROR, "Failed to startup module [%s]", module->name); - exit(255); - } -} - -const char *php_get_called_class(php::Object &this_) { - auto ce = php_get_called_ce(this_); - if (ce) { - return ce->name->val; - } else { - return ""; - } -} - -zend_class_entry *php_get_called_ce(php::Object &this_) { - if (this_.isObject()) { - return this_.ce(); - } else { - return (zend_class_entry *) Z_PTR_P(this_.ptr()); - } -} - -static zend_execute_data *get_frame() { - zend_execute_data *frame = EG(current_execute_data); - while (frame && (!frame->func || !ZEND_USER_CODE(frame->func->type))) { - frame = frame->prev_execute_data; - } - return frame; -} - -php::Scope php_switch_scope(php::Object &this_) { - php::Scope scope; - scope.frame = get_frame(); - scope.ce = scope.frame->func->common.scope; - scope.frame->func->common.scope = php_get_called_ce(this_); - return scope; -} - -void php_restore_scope(php::Scope &ori_scope) { - ori_scope.frame->func->common.scope = ori_scope.ce; -} - -static php_stream *s_in_process = NULL; -static void cli_register_file_handles(void) { - php_stream *s_in, *s_out, *s_err; - php_stream_context *sc_in = NULL, *sc_out = NULL, *sc_err = NULL; - zend_constant ic, oc, ec; - - s_in = php_stream_open_wrapper_ex("php://stdin", "rb", 0, NULL, sc_in); - s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out); - s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err); - - /* Release stream resources, but don't free the underlying handles. Otherwise, - * extensions which write to stderr or company during mshutdown/gshutdown - * won't have the expected functionality. - */ - if (s_in) s_in->flags |= PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE; - if (s_out) s_out->flags |= PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE; - if (s_err) s_err->flags |= PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE; - - if (s_in == NULL || s_out == NULL || s_err == NULL) { - if (s_in) php_stream_close(s_in); - if (s_out) php_stream_close(s_out); - if (s_err) php_stream_close(s_err); - return; - } - - s_in_process = s_in; - - php_stream_to_zval(s_in, &ic.value); - php_stream_to_zval(s_out, &oc.value); - php_stream_to_zval(s_err, &ec.value); - - Z_CONSTANT_FLAGS(ic.value) = 0; - ic.name = zend_string_init_interned("STDIN", sizeof("STDIN") - 1, 0); - zend_register_constant(&ic); - - Z_CONSTANT_FLAGS(oc.value) = 0; - oc.name = zend_string_init_interned("STDOUT", sizeof("STDOUT") - 1, 0); - zend_register_constant(&oc); - - Z_CONSTANT_FLAGS(ec.value) = 0; - ec.name = zend_string_init_interned("STDERR", sizeof("STDERR") - 1, 0); - zend_register_constant(&ec); -} - -void module_shutdown(zend_module_entry *module) { - /** - * There is a bug in PHP's handling of internal strings. All interned strings are released in the request shutdown - * function, but then released again in the php_embed_shutdown function, resulting in a use-after-free issue. These - * must be manually removed from the module table to prevent double release. - */ - auto name_len = strlen(module->name); - auto lcname = zend_string_alloc(name_len, module->type == MODULE_PERSISTENT); - zend_str_tolower_copy(ZSTR_VAL(lcname), module->name, name_len); - zend_hash_del(&module_registry, lcname); -} - -int main(int cpp_argc, char **cpp_argv) { - php_embed_init(cpp_argc, cpp_argv); - php::throw_impl = [](zend_object *ex) { throw ex; }; - - zend_module_entry *module = php_embed_get_module(); - module_init(module); - - save_ps_args(cpp_argc, cpp_argv); - - int rc = 0; -#if PPROF_ON - ProfilerStart("profile.out"); -#endif - zend_first_try { - try { - char path_translated[] = "embed"; - cli_register_file_handles(); - SG(request_info).path_translated = path_translated; - module->request_startup_func(module->type, module->module_number); - } catch (zend_object *e) { - rc = EG(exit_status); - CG(unclean_shutdown) = 1; - zend_exception_error(e, E_ERROR); - } - } - zend_end_try(); -#if PPROF_ON - ProfilerStop(); -#endif - - module->request_shutdown_func(module->type, module->module_number); - module_shutdown(module); - php_embed_shutdown(); - - return rc; -} diff --git a/src/cpp/php_aot_helper.h b/src/cpp/php_aot_helper.h deleted file mode 100644 index 933b68e0..00000000 --- a/src/cpp/php_aot_helper.h +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include - -#include - -extern zend_class_entry *php_get_class(int class_id, const php::Str &class_name); -extern zend_function *php_get_func(int func_id, const php::Str &func_name); -extern zend_function *php_get_method(int func_id, - const php::Str &method_name, - int class_id, - const php::Str &class_name); -extern uint32_t php_get_prop(int prop_id, const php::Str &prop_name, int class_id, const php::Str &class_name); - -namespace php { -struct Scope { - zend_class_entry *ce; - zend_execute_data *frame; -}; -}; // namespace php - -extern const char *php_get_called_class(php::Object &this_); -extern zend_class_entry *php_get_called_ce(php::Object &this_); -extern php::Scope php_switch_scope(php::Object &this_); -extern void php_restore_scope(php::Scope &ori_scope); - -static inline auto php_std_create_object(zend_class_entry *ce) { - auto obj = zend_objects_new(ce); - object_properties_init(obj, ce); - return obj; -} - -static inline auto php_get_create_object_fn(zend_class_entry *ce) { - return ce->create_object ? ce->create_object : php_std_create_object; -} diff --git a/src/cpp/php_cli_process_title.c b/src/cpp/php_cli_process_title.c deleted file mode 100644 index a786de2b..00000000 --- a/src/cpp/php_cli_process_title.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Keyur Govande (kgovande@gmail.com) | - +----------------------------------------------------------------------+ -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "php.h" -#include "php_cli_process_title.h" -#include "ps_title.h" - -/* {{{ Return a boolean to confirm if the process title was successfully changed or not */ -PHP_FUNCTION(cli_set_process_title) -{ - char *title = NULL; - size_t title_len; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &title, &title_len) == FAILURE) { - RETURN_THROWS(); - } - - ps_title_status rc = set_ps_title(title, title_len); - if (rc == PS_TITLE_SUCCESS) { - RETURN_TRUE; - } - - php_error_docref(NULL, E_WARNING, "cli_set_process_title had an error: %s", ps_title_errno(rc)); - RETURN_FALSE; -} -/* }}} */ - -/* {{{ Return a string with the current process title. NULL if error. */ -PHP_FUNCTION(cli_get_process_title) -{ - size_t length = 0; - const char* title = NULL; - - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } - - ps_title_status rc = get_ps_title(&length, &title); - if (rc != PS_TITLE_SUCCESS) { - php_error_docref(NULL, E_WARNING, "cli_get_process_title had an error: %s", ps_title_errno(rc)); - RETURN_NULL(); - } - - RETURN_STRINGL(title, length); -} -/* }}} */ diff --git a/src/cpp/php_cli_process_title.h b/src/cpp/php_cli_process_title.h deleted file mode 100644 index 9527b4b4..00000000 --- a/src/cpp/php_cli_process_title.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Keyur Govande (kgovande@gmail.com) | - +----------------------------------------------------------------------+ -*/ - -#ifndef PHP_PS_TITLE_HEADER -#define PHP_PS_TITLE_HEADER - -PHP_FUNCTION(cli_set_process_title); -PHP_FUNCTION(cli_get_process_title); - -#endif diff --git a/src/cpp/php_cli_process_title.stub.php b/src/cpp/php_cli_process_title.stub.php deleted file mode 100644 index 97dc8b27..00000000 --- a/src/cpp/php_cli_process_title.stub.php +++ /dev/null @@ -1,5 +0,0 @@ - -#ifdef PHP_WIN32 -#include "config.w32.h" -#include -#include -#include "win32/codepage.h" -#else -#include -extern char** environ; -#endif - -#include "ps_title.h" -#include - -#ifdef HAVE_UNISTD_H -#include -#include -#endif - -#include -#include -#include - -#ifdef HAVE_SYS_PSTAT_H -#include /* for HP-UX */ -#endif -#ifdef HAVE_PS_STRINGS -#include /* for old BSD */ -#include -#endif -#if defined(__APPLE__) -#include -#endif - -/* - * Ways of updating ps display: - * - * PS_USE_SETPROCTITLE - * use the function setproctitle(const char *, ...) - * (newer BSD systems) - * PS_USE_PSTAT - * use the pstat(PSTAT_SETCMD, ) - * (HPUX) - * PS_USE_PS_STRINGS - * assign PS_STRINGS->ps_argvstr = "string" - * (some BSD systems) - * PS_USE_CHANGE_ARGV - * assign argv[0] = "string" - * (some other BSD systems) - * PS_USE_CLOBBER_ARGV - * write over the argv and environment area - * (Linux and most SysV-like systems) - * PS_USE_WIN32 - * push the string out as the name of a Windows event - * PS_USE_NONE - * don't update ps display - * (This is the default, as it is safest.) - */ -#if defined(HAVE_SETPROCTITLE) -#define PS_USE_SETPROCTITLE -#elif defined(HAVE_SYS_PSTAT_H) && defined(PSTAT_SETCMD) -#define PS_USE_PSTAT -#elif defined(HAVE_PS_STRINGS) -#define PS_USE_PS_STRINGS -#elif defined(BSD) && !defined(__APPLE__) -#define PS_USE_CHANGE_ARGV -#elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__osf__) || defined(__APPLE__) -#define PS_USE_CLOBBER_ARGV -#elif defined(PHP_WIN32) -#define PS_USE_WIN32 -#else -#define PS_USE_NONE -#endif - -/* Different systems want the buffer padded differently */ -#if defined(_AIX) || defined(__linux__) || defined(__APPLE__) -#define PS_PADDING '\0' -#else -#define PS_PADDING ' ' -#endif - -#ifdef PS_USE_WIN32 -static char windows_error_details[64]; -static char ps_buffer[MAX_PATH]; -static const size_t ps_buffer_size = MAX_PATH; -#elif defined(PS_USE_CLOBBER_ARGV) -static char *ps_buffer; /* will point to argv area */ -static size_t ps_buffer_size; /* space determined at run time */ -static char *empty_environ[] = {0}; /* empty environment */ -#else -#define PS_BUFFER_SIZE 256 -static char ps_buffer[PS_BUFFER_SIZE]; -static const size_t ps_buffer_size = PS_BUFFER_SIZE; -#endif - -static size_t ps_buffer_cur_len; /* actual string length in ps_buffer */ - -/* save the original argv[] location here */ -static int save_argc; -static char** save_argv; - -/* - * This holds the 'locally' allocated environ from the save_ps_args method. - * This is subsequently free'd at exit. - */ -#if defined(PS_USE_CLOBBER_ARGV) -static char** frozen_environ, **new_environ; -#endif - -/* - * Call this method early, before any code has used the original argv passed in - * from main(). - * If needed, this code will make deep copies of argv and environ and return - * these to the caller for further use. The original argv is then 'clobbered' - * to store the process title. - */ -char** save_ps_args(int argc, char** argv) -{ - save_argc = argc; - save_argv = argv; - -#if defined(PS_USE_CLOBBER_ARGV) - /* - * If we're going to overwrite the argv area, count the available space. - * Also move the environment to make additional room. - */ - { - char* end_of_area = NULL; - bool is_contiguous_area = true; - int i; - - /* - * check for contiguous argv strings - */ - for (i = 0; is_contiguous_area && (i < argc); i++) - { - if (i != 0 && end_of_area + 1 != argv[i]) { - is_contiguous_area = false; - } - end_of_area = argv[i] + strlen(argv[i]); - } - - if (!is_contiguous_area) { - goto clobber_error; - } - - /* - * check for contiguous environ strings following argv - */ - for (i = 0; environ[i] != NULL; i++) - { - if (end_of_area + 1 == environ[i]) { - end_of_area = environ[i] + strlen(environ[i]); - } - } - - ps_buffer = argv[0]; - ps_buffer_size = end_of_area - argv[0]; - - /* - * move the environment out of the way - */ - new_environ = (char **) malloc((i + 1) * sizeof(char *)); - frozen_environ = (char **) malloc((i + 1) * sizeof(char *)); - if (!new_environ || !frozen_environ) { - goto clobber_error; - } - for (i = 0; environ[i] != NULL; i++) - { - new_environ[i] = strdup(environ[i]); - if (!new_environ[i]) - goto clobber_error; - } - new_environ[i] = NULL; - environ = new_environ; - memcpy((char *)frozen_environ, (char *)new_environ, sizeof(char *) * (i + 1)); - - } -#endif /* PS_USE_CLOBBER_ARGV */ - -#if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV) - /* - * If we're going to change the original argv[] then make a copy for - * argument parsing purposes. - * - * (NB: do NOT think to remove the copying of argv[]! - * On some platforms, getopt() keeps pointers into the argv array, and - * will get horribly confused when it is re-called to analyze a subprocess' - * argument string if the argv storage has been clobbered meanwhile. - * Other platforms have other dependencies on argv[].) - */ - { - char** new_argv; - int i; - - new_argv = (char **) malloc((argc + 1) * sizeof(char *)); - if (!new_argv) - goto clobber_error; - for (i = 0; i < argc; i++) - { - new_argv[i] = strdup(argv[i]); - if (!new_argv[i]) { - free(new_argv); - goto clobber_error; - } - } - new_argv[argc] = NULL; - -#if defined(__APPLE__) - /* - * Darwin (and perhaps other NeXT-derived platforms?) has a static - * copy of the argv pointer, which we may fix like so: - */ - *_NSGetArgv() = new_argv; -#endif - - argv = new_argv; - - } -#endif /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */ - -#if defined(PS_USE_CLOBBER_ARGV) - { - /* make extra argv slots point at end_of_area (a NUL) */ - int i; - for (i = 1; i < save_argc; i++) - save_argv[i] = ps_buffer + ps_buffer_size; - } -#endif /* PS_USE_CLOBBER_ARGV */ - -#ifdef PS_USE_CHANGE_ARGV - save_argv[0] = ps_buffer; /* ps_buffer here is a static const array of size PS_BUFFER_SIZE */ - save_argv[1] = NULL; -#endif /* PS_USE_CHANGE_ARGV */ - - return argv; - -#if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV) -clobber_error: - /* probably can't happen?! - * if we ever get here, argv still points to originally passed - * in argument - */ - save_argv = NULL; - save_argc = 0; - ps_buffer = NULL; - ps_buffer_size = 0; - return argv; -#endif /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */ -} - -/* - * Returns PS_TITLE_SUCCESS if the OS supports this functionality - * and the init function was called. - * Otherwise returns NOT_AVAILABLE or NOT_INITIALIZED - */ -ps_title_status is_ps_title_available(void) -{ -#ifdef PS_USE_NONE - return PS_TITLE_NOT_AVAILABLE; /* disabled functionality */ -#endif - - if (!save_argv) - return PS_TITLE_NOT_INITIALIZED; - -#ifdef PS_USE_CLOBBER_ARGV - if (!ps_buffer) - return PS_TITLE_BUFFER_NOT_AVAILABLE; -#endif /* PS_USE_CLOBBER_ARGV */ - - return PS_TITLE_SUCCESS; -} - -/* - * Convert error codes into error strings - */ -const char* ps_title_errno(ps_title_status rc) -{ - switch(rc) - { - case PS_TITLE_SUCCESS: - return "Success"; - - case PS_TITLE_NOT_AVAILABLE: - return "Not available on this OS"; - - case PS_TITLE_NOT_INITIALIZED: - return "Not initialized correctly"; - - case PS_TITLE_BUFFER_NOT_AVAILABLE: - return "Buffer not contiguous"; - - case PS_TITLE_TOO_LONG: - // TODO Indicate max length? - return "Too long"; - - case PS_TITLE_WINDOWS_ERROR: -#ifdef PS_USE_WIN32 - snprintf(windows_error_details, sizeof(windows_error_details), "Windows error code: %lu", GetLastError()); - return windows_error_details; -#endif - return "Windows error"; - } - - return "Unknown error code"; -} - -/* - * Set a new process title. - * Returns the appropriate error code if if there's an error - * (like the functionality is compile time disabled, or the - * save_ps_args() was not called. - * Else returns 0 on success. - */ -ps_title_status set_ps_title(const char *title, size_t title_len) -{ - if (title_len >= ps_buffer_size) { - return PS_TITLE_TOO_LONG; - } - - ps_title_status rc = is_ps_title_available(); - if (rc != PS_TITLE_SUCCESS) - return rc; - - /* Include final null byte */ - memcpy(ps_buffer, title, title_len+1); - ps_buffer_cur_len = title_len; - -#ifdef PS_USE_SETPROCTITLE - setproctitle("%s", ps_buffer); -#endif - -#ifdef PS_USE_PSTAT - { - union pstun pst; - - pst.pst_command = ps_buffer; - pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0); - } -#endif /* PS_USE_PSTAT */ - -#ifdef PS_USE_PS_STRINGS - PS_STRINGS->ps_nargvstr = 1; - PS_STRINGS->ps_argvstr = ps_buffer; -#endif /* PS_USE_PS_STRINGS */ - -#ifdef PS_USE_CLOBBER_ARGV - /* pad unused memory */ - if (ps_buffer_cur_len < ps_buffer_size) - { - memset(ps_buffer + ps_buffer_cur_len, PS_PADDING, - ps_buffer_size - ps_buffer_cur_len); - } -#endif /* PS_USE_CLOBBER_ARGV */ - -#ifdef PS_USE_WIN32 - { - wchar_t *ps_buffer_w = php_win32_cp_any_to_w(ps_buffer); - - if (!ps_buffer_w || !SetConsoleTitleW(ps_buffer_w)) { - return PS_TITLE_WINDOWS_ERROR; - } - - free(ps_buffer_w); - } -#endif /* PS_USE_WIN32 */ - - return PS_TITLE_SUCCESS; -} - -/* - * Returns the current ps_buffer value into string. On some platforms - * the string will not be null-terminated, so return the effective - * length into *displen. - * The return code indicates the error. - */ -ps_title_status get_ps_title(size_t *displen, const char** string) -{ - ps_title_status rc = is_ps_title_available(); - if (rc != PS_TITLE_SUCCESS) - return rc; - -#ifdef PS_USE_WIN32 - { - wchar_t ps_buffer_w[MAX_PATH]; - char *tmp; - - if (!(ps_buffer_cur_len = GetConsoleTitleW(ps_buffer_w, (DWORD)sizeof(ps_buffer_w)))) { - return PS_TITLE_WINDOWS_ERROR; - } - - tmp = php_win32_cp_conv_w_to_any(ps_buffer_w, PHP_WIN32_CP_IGNORE_LEN, &ps_buffer_cur_len); - if (!tmp) { - return PS_TITLE_WINDOWS_ERROR; - } - - ps_buffer_cur_len = ps_buffer_cur_len > sizeof(ps_buffer)-1 ? sizeof(ps_buffer)-1 : ps_buffer_cur_len; - - memmove(ps_buffer, tmp, ps_buffer_cur_len); - free(tmp); - } -#endif - *displen = ps_buffer_cur_len; - *string = ps_buffer; - return PS_TITLE_SUCCESS; -} - -/* - * Clean up the allocated argv and environ if applicable. Only call - * this right before exiting. - * This isn't needed per-se because the OS will clean-up anyway, but - * having and calling this will ensure Valgrind doesn't output 'false - * positives'. - */ -void cleanup_ps_args(char **argv) -{ -#ifndef PS_USE_NONE - if (save_argv) - { - save_argv = NULL; - save_argc = 0; - -#ifdef PS_USE_CLOBBER_ARGV - { - int i; - for (i = 0; frozen_environ[i] != NULL; i++) - free(frozen_environ[i]); - free(frozen_environ); - free(new_environ); - /* leave a sane environment behind since some atexit() handlers - call getenv(). */ - environ = empty_environ; - } -#endif /* PS_USE_CLOBBER_ARGV */ - -#if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV) - { - int i; - for (i=0; argv[i] != NULL; i++) - free(argv[i]); - free(argv); - } -#endif /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */ - } -#endif /* PS_USE_NONE */ - - return; -} diff --git a/src/cpp/ps_title.h b/src/cpp/ps_title.h deleted file mode 100644 index 7436c2b2..00000000 --- a/src/cpp/ps_title.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Keyur Govande | - +----------------------------------------------------------------------+ - */ - -#ifndef PS_TITLE_HEADER -#define PS_TITLE_HEADER - -typedef enum { - PS_TITLE_SUCCESS = 0, - PS_TITLE_NOT_AVAILABLE = 1, - PS_TITLE_NOT_INITIALIZED = 2, - PS_TITLE_BUFFER_NOT_AVAILABLE = 3, - PS_TITLE_WINDOWS_ERROR = 4, - PS_TITLE_TOO_LONG = 5, -} ps_title_status; - -extern char** save_ps_args(int argc, char** argv); - -extern ps_title_status set_ps_title(const char *title, size_t title_len); - -extern ps_title_status get_ps_title(size_t* displen, const char** string); - -extern const char* ps_title_errno(ps_title_status rc); - -extern ps_title_status is_ps_title_available(void); - -extern void cleanup_ps_args(char **argv); - -#endif // PS_TITLE_HEADER