diff options
Diffstat (limited to 'missing/setproctitle.c')
| -rw-r--r-- | missing/setproctitle.c | 92 |
1 files changed, 82 insertions, 10 deletions
diff --git a/missing/setproctitle.c b/missing/setproctitle.c index f4078bd993..5b2dfa65ce 100644 --- a/missing/setproctitle.c +++ b/missing/setproctitle.c @@ -34,6 +34,8 @@ #include "ruby.h" #include "ruby/util.h" +#define compat_init_setproctitle ruby_init_setproctitle +RUBY_FUNC_EXPORTED void ruby_init_setproctitle(int argc, char *argv[]); #ifndef HAVE_SETPROCTITLE @@ -47,6 +49,16 @@ #endif #include <string.h> +#if defined(__APPLE__) +# ifdef HAVE_CRT_EXTERNS_H +# include <crt_externs.h> +# undef environ +# define environ (*_NSGetEnviron()) +# else +# include "crt_externs.h" +# endif +#endif + #define SPT_NONE 0 /* don't use it at all */ #define SPT_PSTAT 1 /* use pstat(PSTAT_SETCMD, ...) */ #define SPT_REUSEARGV 2 /* cover argv with title information */ @@ -63,14 +75,48 @@ static char *argv_start = NULL; static size_t argv_env_len = 0; static size_t argv_len = 0; +static char **argv1_addr = NULL; #endif #endif /* HAVE_SETPROCTITLE */ +#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV +# define ALLOCATE_ENVIRON 1 +#else +# define ALLOCATE_ENVIRON 0 +#endif + +#if ALLOCATE_ENVIRON +/* system_environ is the value of environ before we allocate a custom buffer. + * + * We use this to restore environ in ruby_free_proctitle. + */ +static char **system_environ = NULL; +/* orig_environ is the buffer we allocate for environ. + * + * We use this to free this buffer in ruby_free_proctitle. When we add new + * environment variables using setenv, the system may change environ to a + * different buffer and will not free the original buffer, so we need to hold + * onto this so we can free it in ruby_free_proctitle. + * + * We must not free any of the contents because it may change if the system + * updates existing environment variables. + */ +static char **orig_environ = NULL; +/* alloc_environ is a copy of orig_environ. + * + * We use this to free all the original string copies that were in orig_environ. + * Since environ could be changed to point to strings allocated by the system + * if environment variables are updated, so we need this to point to the + * original strings. + */ +static char **alloc_environ = NULL; +#endif + void compat_init_setproctitle(int argc, char *argv[]) { -#if defined(SPT_TYPE) && SPT_TYPE == SPT_REUSEARGV +#if ALLOCATE_ENVIRON extern char **environ; char *lastargv = NULL; char *lastenvp = NULL; @@ -87,9 +133,13 @@ compat_init_setproctitle(int argc, char *argv[]) return; /* Fail if we can't allocate room for the new environment */ - for (i = 0; envp[i] != NULL; i++) - ; - if ((environ = calloc(i + 1, sizeof(*environ))) == NULL) { + for (i = 0; envp[i] != NULL; i++); + + system_environ = environ; + + alloc_environ = xcalloc(i + 1, sizeof(*environ)); + orig_environ = environ = xcalloc(i + 1, sizeof(*environ)); + if (environ == NULL) { environ = envp; /* put it back */ return; } @@ -108,18 +158,39 @@ compat_init_setproctitle(int argc, char *argv[]) lastenvp = envp[i] + strlen(envp[i]); } - argv[1] = NULL; + /* We keep argv[1], argv[2], etc. at this moment, + because the ps command of AIX refers to them. */ + argv1_addr = &argv[1]; argv_start = argv[0]; argv_len = lastargv - argv[0]; argv_env_len = lastenvp - argv[0]; for (i = 0; envp[i] != NULL; i++) - environ[i] = ruby_strdup(envp[i]); - environ[i] = NULL; + alloc_environ[i] = environ[i] = ruby_strdup(envp[i]); + alloc_environ[i] = environ[i] = NULL; #endif /* SPT_REUSEARGV */ } +void +ruby_free_proctitle(void) +{ +#if ALLOCATE_ENVIRON + extern char **environ; + + if (!orig_environ) return; /* environ is allocated by OS */ + + for (int i = 0; alloc_environ[i] != NULL; i++) { + xfree(alloc_environ[i]); + } + xfree(alloc_environ); + xfree(orig_environ); + + environ = system_environ; +#endif +} + #ifndef HAVE_SETPROCTITLE + void setproctitle(const char *fmt, ...) { @@ -137,10 +208,9 @@ setproctitle(const char *fmt, ...) return; #endif + /* fmt must be non-NULL */ va_start(ap, fmt); - if (fmt != NULL) { - vsnprintf(ptitle, sizeof(ptitle) , fmt, ap); - } + vsnprintf(ptitle, sizeof(ptitle), fmt, ap); va_end(ap); #if SPT_TYPE == SPT_PSTAT @@ -151,6 +221,8 @@ setproctitle(const char *fmt, ...) argvlen = len > argv_len ? argv_env_len : argv_len; for(; len < argvlen; len++) argv_start[len] = SPT_PADCHAR; + /* argv[1], argv[2], etc. are no longer valid. */ + *argv1_addr = NULL; #endif #endif /* SPT_NONE */ |
