#include "ps_title.h"
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <stdlib.h>
#ifdef PHP_WIN32
#include "config.w32.h"
#include <windows.h>
#include <process.h>
#else
#include "php_config.h"
extern char** environ;
#endif
#ifdef HAVE_SYS_PSTAT_H
#include <sys/pstat.h>
#endif
#ifdef HAVE_PS_STRINGS
#include <machine/vmparam.h>
#include <sys/exec.h>
#endif
#if defined(DARWIN)
#include <crt_externs.h>
#endif
#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(DARWIN)
#define PS_USE_CHANGE_ARGV
#elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__osf__) || defined(DARWIN)
#define PS_USE_CLOBBER_ARGV
#elif defined(PHP_WIN32)
#define PS_USE_WIN32
#else
#define PS_USE_NONE
#endif
#if defined(_AIX) || defined(__linux__) || defined(DARWIN)
#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;
static size_t ps_buffer_size;
static char *empty_environ[] = {0};
#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;
static int save_argc;
static char** save_argv;
static char** frozen_environ, **new_environ;
char** save_ps_args(int argc, char** argv)
{
save_argc = argc;
save_argv = argv;
#if defined(PS_USE_CLOBBER_ARGV)
{
char* end_of_area = NULL;
int non_contiguous_area = 0;
int i;
for (i = 0; (non_contiguous_area == 0) && (i < argc); i++)
{
if (i != 0 && end_of_area + 1 != argv[i])
non_contiguous_area = 1;
end_of_area = argv[i] + strlen(argv[i]);
}
for (i = 0; (non_contiguous_area == 0) && (environ[i] != NULL); i++)
{
if (end_of_area + 1 != environ[i])
non_contiguous_area = 1;
end_of_area = environ[i] + strlen(environ[i]);
}
if (non_contiguous_area != 0)
goto clobber_error;
ps_buffer = argv[0];
ps_buffer_size = end_of_area - argv[0];
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
#if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_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])
goto clobber_error;
}
new_argv[argc] = NULL;
#if defined(DARWIN)
*_NSGetArgv() = new_argv;
#endif
argv = new_argv;
}
#endif
#if defined(PS_USE_CLOBBER_ARGV)
{
int i;
for (i = 1; i < save_argc; i++)
save_argv[i] = ps_buffer + ps_buffer_size;
}
#endif
#ifdef PS_USE_CHANGE_ARGV
save_argv[0] = ps_buffer;
save_argv[1] = NULL;
#endif
return argv;
#if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV)
clobber_error:
save_argv = NULL;
save_argc = 0;
ps_buffer = NULL;
ps_buffer_size = 0;
return argv;
#endif
}
int is_ps_title_available()
{
#ifdef PS_USE_NONE
return PS_TITLE_NOT_AVAILABLE;
#endif
if (!save_argv)
return PS_TITLE_NOT_INITIALIZED;
#ifdef PS_USE_CLOBBER_ARGV
if (!ps_buffer)
return PS_TITLE_BUFFER_NOT_AVAILABLE;
#endif
return PS_TITLE_SUCCESS;
}
const char* ps_title_errno(int 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";
#ifdef PS_USE_WIN32
case PS_TITLE_WINDOWS_ERROR:
sprintf(windows_error_details, "Windows error code: %d", GetLastError());
return windows_error_details;
#endif
}
return "Unknown error code";
}
int set_ps_title(const char* title)
{
int rc = is_ps_title_available();
if (rc != PS_TITLE_SUCCESS)
return rc;
strncpy(ps_buffer, title, ps_buffer_size);
ps_buffer[ps_buffer_size - 1] = '\0';
ps_buffer_cur_len = strlen(ps_buffer);
#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
#ifdef PS_USE_PS_STRINGS
PS_STRINGS->ps_nargvstr = 1;
PS_STRINGS->ps_argvstr = ps_buffer;
#endif
#ifdef PS_USE_CLOBBER_ARGV
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
#ifdef PS_USE_WIN32
{
if (!SetConsoleTitle(ps_buffer))
return PS_TITLE_WINDOWS_ERROR;
}
#endif
return PS_TITLE_SUCCESS;
}
int get_ps_title(int *displen, const char** string)
{
int rc = is_ps_title_available();
if (rc != PS_TITLE_SUCCESS)
return rc;
#ifdef PS_USE_WIN32
if (!(ps_buffer_cur_len = GetConsoleTitle(ps_buffer, ps_buffer_size)))
return PS_TITLE_WINDOWS_ERROR;
#endif
*displen = (int)ps_buffer_cur_len;
*string = ps_buffer;
return PS_TITLE_SUCCESS;
}
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);
environ = empty_environ;
}
#endif
#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
}
#endif
return;
}