]> jfr.im git - irc/atheme/libmowgli-2.git/commitdiff
ext: add proctitle setting functions to set process titles portably
authorElizabeth J. Myers <redacted>
Thu, 5 Apr 2012 02:27:55 +0000 (21:27 -0500)
committerElizabeth J. Myers <redacted>
Thu, 5 Apr 2012 02:27:55 +0000 (21:27 -0500)
configure
configure.ac
src/libmowgli/ext/Makefile
src/libmowgli/ext/proctitle.c [new file with mode: 0644]
src/libmowgli/ext/proctitle.h [new file with mode: 0644]
src/libmowgli/mowgli.h
src/libmowgli/platform/autoconf.h.in

index 47354f7cd8e7f46459a3f259ac50a881c12a3393..645a6faf1865298b2268ef83c0f58a6d6cb78c71 100755 (executable)
--- a/configure
+++ b/configure
@@ -3769,7 +3769,7 @@ fi
 done
 
 
-for ac_header in poll.h winsock2.h sys/epoll.h sys/select.h
+for ac_header in poll.h winsock2.h sys/epoll.h sys/select.h sys/pstat.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -3782,7 +3782,7 @@ fi
 
 done
 
-for ac_func in fcntl kqueue mmap select dispatch_block port_create
+for ac_func in fcntl kqueue mmap select dispatch_block port_create setproctitle pstat
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -3795,6 +3795,41 @@ fi
 done
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PS_STRINGS" >&5
+$as_echo_n "checking for PS_STRINGS... " >&6; }
+if ${pgac_cv_var_PS_STRINGS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <machine/vmparam.h>
+#include <sys/exec.h>
+
+int
+main ()
+{
+PS_STRINGS->ps_nargvstr = 1;
+PS_STRINGS->ps_argvstr = "foo";
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  pgac_cv_var_PS_STRINGS=yes
+else
+  pgac_cv_var_PS_STRINGS=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_var_PS_STRINGS" >&5
+$as_echo "$pgac_cv_var_PS_STRINGS" >&6; }
+if test "$pgac_cv_var_PS_STRINGS" = yes ; then
+
+$as_echo "#define HAVE_PS_STRINGS /**/" >>confdefs.h
+
+fi
+
 # Extract the first word of "ar", so it can be a program name with args.
 set dummy ar; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
index 730a017d903a354ca98967c61c5e6c4a717444ad..93e72e279fe61a2118e71b0cae3f0ebdfcd935e7 100644 (file)
@@ -24,8 +24,21 @@ AS_IF([test "x$GCC" = "xyes"], [
    CFLAGS="$CFLAGS $MORECFLAGS"
 ])
 
-AC_CHECK_HEADERS([poll.h winsock2.h sys/epoll.h sys/select.h])
-AC_CHECK_FUNCS([fcntl kqueue mmap select dispatch_block port_create])
+AC_CHECK_HEADERS([poll.h winsock2.h sys/epoll.h sys/select.h sys/pstat.h])
+AC_CHECK_FUNCS([fcntl kqueue mmap select dispatch_block port_create setproctitle pstat])
+
+AC_CACHE_CHECK([for PS_STRINGS], [pgac_cv_var_PS_STRINGS],
+[AC_TRY_LINK(
+[#include <machine/vmparam.h>
+#include <sys/exec.h>
+],
+[PS_STRINGS->ps_nargvstr = 1;
+PS_STRINGS->ps_argvstr = "foo";],
+[pgac_cv_var_PS_STRINGS=yes],
+[pgac_cv_var_PS_STRINGS=no])])
+if test "$pgac_cv_var_PS_STRINGS" = yes ; then
+  AC_DEFINE([HAVE_PS_STRINGS], [], [Define to 1 if the PS_STRINGS struct exists on your platform (likely no).])
+fi
 
 AC_PATH_PROG(AR, ar)
 AC_PATH_PROG(RANLIB, ranlib)
index a6edb4eb99925f563e0db71790d4fec3aa69c829..d7466b6bf460c5c22023dd79a25c7f644af5dd0d 100644 (file)
@@ -7,13 +7,15 @@ SRCS = confparse.c                    \
        error_backtrace.c               \
        getopt_long.c                   \
        global_storage.c                \
-       program_opts.c
+       program_opts.c                  \
+       proctitle.c
 
 INCLUDES = confparse.h                 \
           error_backtrace.h            \
           getopt_long.h                \
           global_storage.h             \
-          program_opts.h
+          program_opts.h               \
+          proctitle.h
 
 include ../../../buildsys.mk
 
diff --git a/src/libmowgli/ext/proctitle.c b/src/libmowgli/ext/proctitle.c
new file mode 100644 (file)
index 0000000..128416e
--- /dev/null
@@ -0,0 +1,350 @@
+/* 
+ * Code has been calqued from PostgreSQL 9.1 by Elizabeth J. Myers.
+ * Below is their copyright header
+ */
+
+/*--------------------------------------------------------------------
+ * ps_status.c
+ *
+ * Routines to support changing the ps display of PostgreSQL backends
+ * to contain some useful information. Mechanism differs wildly across
+ * platforms.
+ *
+ * src/backend/utils/misc/ps_status.c
+ *
+ * Copyright (c) 2000-2011, PostgreSQL Global Development Group
+ * various details abducted from various places
+ *--------------------------------------------------------------------
+ */
+
+#include "mowgli.h"
+
+#ifdef HAVE_SYS_PSTAT_H
+#include <sys/pstat.h>         /* for HP-UX */
+#endif
+#ifdef HAVE_PS_STRINGS
+#include <machine/vmparam.h>   /* for old BSD */
+#include <sys/exec.h>
+#endif
+#if defined(__darwin__)
+#include <crt_externs.h>
+#endif
+
+extern char **environ;
+bool           mowgli_proctitle_update = true;
+
+
+/*
+ * Alternative ways of updating ps display:
+ *
+ * MOWGLI_SETPROC_USE_SETPROCTITLE
+ *        use the function setproctitle(const char *, ...)
+ *        (newer BSD systems)
+ * MOWGLI_SETPROC_USE_PSTAT
+ *        use the pstat(PSTAT_SETCMD, )
+ *        (HPUX)
+ * MOWGLI_SETPROC_USE_PS_STRINGS
+ *        assign PS_STRINGS->ps_argvstr = "string"
+ *        (some BSD systems)
+ * MOWGLI_SETPROC_USE_CHANGE_ARGV
+ *        assign argv[0] = "string"
+ *        (some other BSD systems)
+ * MOWGLI_SETPROC_USE_CLOBBER_ARGV
+ *        write over the argv and environment area
+ *        (Linux and most SysV-like systems)
+ * MOWGLI_SETPROC_USE_WIN32
+ *        push the string out as the name of a Windows event
+ * MOWGLI_SETPROC_USE_NONE
+ *        don't update ps display
+ *        (This is the default, as it is safest.)
+ */
+#if defined(HAVE_SETPROCTITLE)
+#define MOWGLI_SETPROC_USE_SETPROCTITLE
+#elif defined(HAVE_PSTAT) && defined(PSTAT_SETCMD)
+#define MOWGLI_SETPROC_USE_PSTAT
+#elif defined(HAVE_PS_STRINGS)
+#define MOWGLI_SETPROC_USE_PS_STRINGS
+#elif (defined(BSD) || defined(__bsdi__) || defined(__hurd__)) && !defined(__darwin__)
+#define MOWGLI_SETPROC_USE_CHANGE_ARGV
+#elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__ksr__) || defined(__osf__) || defined(__svr4__) || defined(__svr5__) || defined(__darwin__)
+#define MOWGLI_SETPROC_USE_CLOBBER_ARGV
+#elif defined(WIN32)
+#define MOWGLI_SETPROC_USE_WIN32
+#else
+#define MOWGLI_SETPROC_USE_NONE
+#endif
+
+
+/* Different systems want the buffer padded differently */
+#if defined(_AIX) || defined(__linux__) || defined(__svr4__) || defined(__darwin__)
+#define PS_PADDING '\0'
+#else
+#define PS_PADDING ' '
+#endif
+
+
+#ifndef MOWGLI_SETPROC_USE_CLOBBER_ARGV
+/* all but one option need a buffer to write their ps line in */
+#define PS_BUFFER_SIZE 256
+static char ps_buffer[PS_BUFFER_SIZE];
+static const size_t ps_buffer_size = PS_BUFFER_SIZE;
+#else                                                  /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+static char *ps_buffer;                        /* will point to argv area */
+static size_t ps_buffer_size;  /* space determined at run time */
+static size_t last_status_len; /* use to minimize length of clobber */
+#endif   /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+
+static size_t ps_buffer_cur_len;       /* nominal strlen(ps_buffer) */
+
+static size_t ps_buffer_fixed_size;            /* size of the constant prefix */
+
+/* save the original argv[] location here */
+static int     save_argc;
+static char **save_argv;
+
+
+/*
+ * Call this early in startup to save the original argc/argv values.
+ * If needed, we make a copy of the original argv[] array to preserve it
+ * from being clobbered by subsequent ps_display actions.
+ *
+ * (The original argv[] will not be overwritten by this routine, but may be
+ * overwritten during mowgli_proctitle_init.   Also, the physical location of the
+ * environment strings may be moved, so this should be called before any code
+ * that might try to hang onto a getenv() result.)
+ */
+char     **
+mowgli_proctitle_copy_args(int argc, char **argv)
+{
+       save_argc = argc;
+       save_argv = argv;
+
+#if defined(MOWGLI_SETPROC_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;
+               char      **new_environ;
+               int                     i;
+
+               /*
+                * check for contiguous argv strings
+                */
+               for (i = 0; i < argc; i++)
+               {
+                       if (i == 0 || end_of_area + 1 == argv[i])
+                               end_of_area = argv[i] + strlen(argv[i]);
+               }
+
+               if (end_of_area == NULL)        /* probably can't happen? */
+               {
+                       ps_buffer = NULL;
+                       ps_buffer_size = 0;
+                       return argv;
+               }
+
+               /*
+                * 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];
+               last_status_len = ps_buffer_size = end_of_area - argv[0];
+
+               /*
+                * move the environment out of the way
+                */
+               new_environ = (char **) mowgli_alloc((i + 1) * sizeof(char *));
+               for (i = 0; environ[i] != NULL; i++)
+                       new_environ[i] = mowgli_strdup(environ[i]);
+               new_environ[i] = NULL;
+               environ = new_environ;
+       }
+#endif   /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+
+#if defined(MOWGLI_SETPROC_USE_CHANGE_ARGV) || defined(MOWGLI_SETPROC_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 **) mowgli_alloc((argc + 1) * sizeof(char *));
+               for (i = 0; i < argc; i++)
+                       new_argv[i] = mowgli_strdup(argv[i]);
+               new_argv[argc] = NULL;
+
+#if defined(__darwin__)
+               /*
+                * 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   /* MOWGLI_SETPROC_USE_CHANGE_ARGV or MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+
+       return argv;
+}
+
+/*
+ * Call this once during subprocess startup to set the identification
+ * values.
+ *
+ * At this point, the original argv[] array may be overwritten.
+ */
+void
+mowgli_proctitle_init(const char *initial_str, const char *fmt, ...)
+{
+       va_list va;
+
+#ifndef MOWGLI_SETPROC_USE_NONE
+       /* no ps display if you didn't call mowgli_proctitle_copy_args() */
+       if (!save_argv)
+               return;
+
+#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV
+       /* If ps_buffer is a pointer, it might still be null */
+       if (!ps_buffer)
+               return;
+#endif
+
+       va_start(va, fmt);
+       vsnprintf(ps_buffer, sizeof(ps_buffer), fmt, va);
+       va_end(va);
+
+       /*
+        * Overwrite argv[] to point at appropriate space, if needed
+        */
+
+#ifdef MOWGLI_SETPROC_USE_CHANGE_ARGV
+       save_argv[0] = ps_buffer;
+       save_argv[1] = NULL;
+#endif   /* MOWGLI_SETPROC_USE_CHANGE_ARGV */
+
+#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV
+       /* make extra argv slots point at end_of_area (a NUL) */
+       for (int i = 1; i < save_argc; i++)
+               save_argv[i] = ps_buffer + ps_buffer_size;
+#endif   /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+
+
+       ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer);
+
+       mowgli_proctitle_set(initial_str, true);
+#endif   /* not MOWGLI_SETPROC_USE_NONE */
+}
+
+/*
+ * Call this to update the ps status display to a fixed prefix plus an
+ * indication of what you're currently doing passed in the argument.
+ */
+void
+mowgli_proctitle_set(const char *activity, bool force)
+{
+#ifndef MOWGLI_SETPROC_USE_NONE
+       /* mowgli_proctitle_update=off disables updates, unless force = true */
+       if (!force && !mowgli_proctitle_update)
+               return;
+
+#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV
+       /* If ps_buffer is a pointer, it might still be null */
+       if (!ps_buffer)
+               return;
+#endif
+
+       /* Update ps_buffer to contain both fixed part and activity */
+       mowgli_strlcpy(ps_buffer + ps_buffer_fixed_size, activity,
+                       ps_buffer_size - ps_buffer_fixed_size);
+       ps_buffer_cur_len = strlen(ps_buffer);
+
+       /* Transmit new setting to kernel, if necessary */
+
+#ifdef MOWGLI_SETPROC_USE_SETPROCTITLE
+       setproctitle("%s", ps_buffer);
+#endif
+
+#ifdef MOWGLI_SETPROC_USE_PSTAT
+       {
+               union pstun pst;
+
+               pst.pst_command = ps_buffer;
+               pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0);
+       }
+#endif   /* MOWGLI_SETPROC_USE_PSTAT */
+
+#ifdef MOWGLI_SETPROC_USE_PS_STRINGS
+       PS_STRINGS->ps_nargvstr = 1;
+       PS_STRINGS->ps_argvstr = ps_buffer;
+#endif   /* MOWGLI_SETPROC_USE_PS_STRINGS */
+
+#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV
+       /* pad unused memory; need only clobber remainder of old status string */
+       if (last_status_len > ps_buffer_cur_len)
+               memset(ps_buffer + ps_buffer_cur_len, PS_PADDING,
+                          last_status_len - ps_buffer_cur_len);
+       last_status_len = ps_buffer_cur_len;
+#endif   /* MOWGLI_SETPROC_USE_CLOBBER_ARGV */
+
+#ifdef MOWGLI_SETPROC_USE_WIN32
+       {
+               /*
+                * Win32 does not support showing any changed arguments. To make it at
+                * all possible to track which backend is doing what, we create a
+                * named object that can be viewed with for example Process Explorer.
+                */
+               static HANDLE ident_handle = INVALID_HANDLE_VALUE;
+               char            name[PS_BUFFER_SIZE + 32];
+
+               if (ident_handle != INVALID_HANDLE_VALUE)
+                       CloseHandle(ident_handle);
+
+               sprintf(name, "mowgli_ident(%d): %s", MyProcPid, ps_buffer);
+
+               ident_handle = CreateEvent(NULL, TRUE, FALSE, name);
+       }
+#endif   /* MOWGLI_SETPROC_USE_WIN32 */
+#endif   /* not MOWGLI_SETPROC_USE_NONE */
+}
+
+
+/*
+ * Returns what's currently in the ps display, in case someone needs
+ * it. Note that only the activity part is returned.  On some platforms
+ * the string will not be null-terminated, so return the effective
+ * length into *displen.
+ */
+const char *
+mowgli_proctitle_get(int *displen)
+{
+#ifdef MOWGLI_SETPROC_USE_CLOBBER_ARGV
+       /* If ps_buffer is a pointer, it might still be null */
+       if (!ps_buffer)
+       {
+               *displen = 0;
+               return "";
+       }
+#endif
+
+       *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size);
+
+       return ps_buffer + ps_buffer_fixed_size;
+}
diff --git a/src/libmowgli/ext/proctitle.h b/src/libmowgli/ext/proctitle.h
new file mode 100644 (file)
index 0000000..0c43838
--- /dev/null
@@ -0,0 +1,25 @@
+/*-------------------------------------------------------------------------
+ *
+ * ps_status.h
+ *
+ * Declarations for backend/utils/misc/ps_status.c
+ *
+ * src/include/utils/ps_status.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef __PS_STATUS_H__
+#define __PS_STATUS_H__
+
+extern bool mowgli_proctitle_update;
+
+extern char **mowgli_proctitle_copy_args(int argc, char **argv);
+
+extern void mowgli_proctitle_init(const char *initial_str, const char *fmt, ...);
+
+extern void mowgli_proctitle_set(const char *activity, bool force);
+
+extern const char *mowgli_proctitle_get(int *displen);
+
+#endif   /* __PS_STATUS_H__ */
index a8b86dab1fdad808b4b4a46aa3373e8da36238e4..7c83041e5bb6317bd13b5bb6ba8a7233b975a0bc 100644 (file)
@@ -70,6 +70,7 @@ MOWGLI_DECLS_START
 #include "base/bitvector.h"
 #include "base/hook.h"
 #include "base/mowgli_signal.h"
+#include "ext/proctitle.h"
 #include "ext/error_backtrace.h"
 #include "base/random.h"
 #include "base/argstack.h"
index 39904bc0571fb1ef3d4ab1e085e05fea3d73877e..9fbdbde33273863062cc8f998696e9c417ad6b2d 100644 (file)
 /* Define to 1 if you have the `port_create' function. */
 #undef HAVE_PORT_CREATE
 
+/* Define to 1 if you have the `pstat' function. */
+#undef HAVE_PSTAT
+
+/* Define to 1 if the PS_STRINGS struct exists on your platform (likely no).
+   */
+#undef HAVE_PS_STRINGS
+
 /* Define if you have POSIX threads libraries and header files. */
 #undef HAVE_PTHREAD
 
 /* Define to 1 if you have the `select' function. */
 #undef HAVE_SELECT
 
+/* Define to 1 if you have the `setproctitle' function. */
+#undef HAVE_SETPROCTITLE
+
 /* Define to 1 if you have the <stdint.h> header file. */
 #undef HAVE_STDINT_H
 
@@ -48,6 +58,9 @@
 /* Define to 1 if you have the <sys/epoll.h> header file. */
 #undef HAVE_SYS_EPOLL_H
 
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+#undef HAVE_SYS_PSTAT_H
+
 /* Define to 1 if you have the <sys/select.h> header file. */
 #undef HAVE_SYS_SELECT_H