setproctitle-1.1.8/0000775000175000017500000000000012232042534014205 5ustar piropiro00000000000000setproctitle-1.1.8/Makefile0000664000175000017500000000324511714315500015651 0ustar piropiro00000000000000# Oh, makefile, help me with the python3 craze :D # # Copyright (c) 2010-2012 Daniele Varrazzo MKDIR = mkdir -p RM = rm -f # Customize these to select the Python to build/test PYTHON ?= python PYCONFIG ?= python-config PY2TO3 ?= 2to3 # PYVER value is 2 or 3 PYVER := $(shell $(PYTHON) -c "import sys; print(sys.version_info[0])") ROOT_PATH := $(shell pwd) PYINC := $(shell $(PYCONFIG) --includes) PYLIB := $(shell $(PYCONFIG) --ldflags) -L$(shell $(PYCONFIG) --prefix)/lib BUILD_DIR = build/lib.$(PYVER) .PHONY: build check py3 clean ifeq (2,$(PYVER)) build: $(PYTHON) setup.py build --build-lib $(BUILD_DIR) check: build tests/pyrun2 PYTHONPATH=`pwd`/$(BUILD_DIR):$$PYTHONPATH \ ROOT_PATH=$(ROOT_PATH) \ $(PYTHON) `which nosetests` -v -s -w tests tests/pyrun2: tests/pyrun.c $(CC) $(PYINC) -o $@ $< $(PYLIB) else build: py3 $(PYTHON) py3/setup.py build --build-lib $(BUILD_DIR) check: build tests/pyrun3 PYTHONPATH=$(BUILD_DIR):$$PYTHONPATH \ ROOT_PATH=$(ROOT_PATH) \ $(PYTHON) py3/tests/setproctitle_test.py -v py3: MANIFEST $(MKDIR) py3 $(MKDIR) py3/src $(MKDIR) py3/tests for f in `grep -v "#" MANIFEST`; do cp -v $$f py3/$$f; done # setup.py should be executable with python3 as distribute # currenlty doesn't seem to try to convert it $(PY2TO3) -w --no-diffs py3/tests tests/pyrun3: tests/pyrun.c $(CC) $(PYINC) -o $@ $< $(PYLIB) endif sdist: MANIFEST $(PYTHON) setup.py sdist --formats=gztar,zip MANIFEST: # Must run twice because the manifest contains the manifest itself. $(PYTHON) setup.py sdist --manifest-only $(PYTHON) setup.py sdist --manifest-only clean: $(RM) -r MANIFEST py3 build dist tests/pyrun2 tests/pyrun3 setproctitle-1.1.8/HISTORY.rst0000664000175000017500000000410212232040407016072 0ustar piropiro00000000000000Releases history ---------------- Version 1.1.8 ~~~~~~~~~~~~~ - Added support for Python "diehard" 2.4. - Fixed build on Mac OS X 10.9 Maverick (issue #27). Version 1.1.7 ~~~~~~~~~~~~~ - Added PyPy support, courtesy of Ozan Turksever (http://www.logsign.net). Version 1.1.6 ~~~~~~~~~~~~~ - The module can be compiled again on Windows (issue #21). Version 1.1.5 ~~~~~~~~~~~~~ - No module bug, but a packaging issue: files ``README`` and ``HISTORY`` added back into the distribution. Version 1.1.4 ~~~~~~~~~~~~~ - The module works correctly in embedded Python. - ``setproctitle()`` accepts a keyword argument. - Debug output support always compiled in: the variable ``SPT_DEBUG`` can be used to emit debug log. Version 1.1.3 ~~~~~~~~~~~~~ - Don't clobber environ if the variable ``SPT_NOENV`` is set (issue #16). Version 1.1.2 ~~~~~~~~~~~~~ - Find the setproctitle include file on OpenBSD (issue #11). - Skip test with unicode if the file system encoding wouldn't make it pass (issue #13). Version 1.1.1 ~~~~~~~~~~~~~ - Fixed segfault when the module is imported under mod_wsgi (issue #9). Version 1.1 ~~~~~~~~~~~ - The module works correctly with Python 3. Version 1.0.1 ~~~~~~~~~~~~~ - ``setproctitle()`` works even when Python messes up with argv, e.g. when run with the -m option (issue #8). Version 1.0 ~~~~~~~~~~~ No major change since the previous version. The module has been heavily used in production environment without any problem reported, so it's time to declare it stable. Version 0.4 ~~~~~~~~~~~ - Module works on BSD (tested on FreeBSD 7.2). - Module works on Windows. Many thanks to `Develer`_ for providing a neat `GCC package for Windows with Python integration`__ that made the Windows porting painless. .. _Develer: http://www.develer.com/ .. __: http://www.develer.com/oss/GccWinBinaries Version 0.3 ~~~~~~~~~~~ - Module works on Mac OS X 10.2. Reported working on OS X 10.6 too. Version 0.2 ~~~~~~~~~~~ - Added ``prctl()`` call on Linux >= 2.6.9 to update ``/proc/self/status``. Version 0.1 ~~~~~~~~~~~ - Initial public release. setproctitle-1.1.8/README.rst0000664000175000017500000001001511714573644015710 0ustar piropiro00000000000000A ``setproctitle`` implementation for Python ============================================ :author: Daniele Varrazzo The library allows a process to change its title (as displayed by system tools such as ``ps`` and ``top``). Changing the title is mostly useful in multi-process systems, for example when a master process is forked: changing the children's title allows to identify the task each process is busy with. The technique is used by PostgreSQL_ and the `OpenSSH Server`_ for example. The procedure is hardly portable across different systems. PostgreSQL provides a good `multi-platform implementation`__: this module is a Python wrapper around PostgreSQL code. - `Homepage `__ - `Download `__ - `Source repository `__ - `Bug tracker `__ .. _PostgreSQL: http://www.postgresql.org .. _OpenSSH Server: http://www.openssh.com/ .. __: http://doxygen.postgresql.org/ps__status_8c_source.html Installation ------------ You can use ``easy_install`` to install the module: to perform a system-wide installation use:: sudo easy_install setproctitle If you are an unprivileged user or you want to limit installation to a local environment, you can use the command:: easy_install -d /target/path setproctitle Note that ``easy_install`` requires ``/target/path`` to be in your ``PYTHONPATH``. Python 3 support ~~~~~~~~~~~~~~~~ As of version 1.1 the module works with Python 3. In order to install the module, you can use the `distribute`_ replacemente for ``easy_install``. In order to build and test the module under Python 3, the ``Makefile`` contains some helper targets. .. _distribute: http://pypi.python.org/pypi/distribute Usage ----- The ``setproctitle`` module exports the following functions: ``setproctitle(title)`` Set *title* as the title for the current process. ``getproctitle()`` Return the current process title. Environment variables ~~~~~~~~~~~~~~~~~~~~~ A few environment variables can be used to customize the module behavior: ``SPT_NOENV`` Avoid clobbering ``/proc/PID/environ``. On many platforms, setting the process title will clobber the ``environ`` memory area. ``os.environ`` will work as expected from within the Python process, but the content of the file ``/proc/PID/environ`` will be overwritten. If you require this file not to be broken you can set the ``SPT_NOENV`` environment variable to any non-empty value: in this case the maximum length for the title will be limited to the length of the command line. ``SPT_DEBUG`` Print debug information on ``stderr``. If the module doesn't work as expected you can set this variable to a non-empty value to generate information useful for debugging. Note that the most useful information is printed when the module is imported, not when the functions are called. Module status ------------- The module can be currently compiled and effectively used on the following platforms: - GNU/Linux - BSD - MacOS X - Windows Note that on Windows there is no way to change the process string: what the module does is to create a *Named Object* whose value can be read using a tool such as `Process Explorer`_ (contribution of a more useful tool to be used together with ``setproctitle`` would be well accepted). The module can probably work on HP-UX, but I haven't found any to test with. It is unlikely that it can work on Solaris instead. .. _Process Explorer: http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx Other known implementations and discussions ------------------------------------------- - `procname`_: a module exposing the same functionality, but less portable and not well packaged. - `Issue 5672`_: where the introduction of such functionality into the stdlib is being discussed. .. _procname: http://code.google.com/p/procname/ .. _Issue 5672: http://bugs.python.org/issue5672 .. vim: set filetype=rst: setproctitle-1.1.8/src/0000775000175000017500000000000012232042534014774 5ustar piropiro00000000000000setproctitle-1.1.8/src/spt_status.c0000664000175000017500000003101512232040407017346 0ustar piropiro00000000000000/*-------------------------------------------------------------------- * spt_status.c * * Routines to support changing the ps display of a process. * Mechanism differs wildly across platforms. * * Copyright (c) 2000-2009, PostgreSQL Global Development Group * Copyright (C) 2009-2012 Daniele Varrazzo * various details abducted from various places * * This file was taken from PostgreSQL. The PostgreSQL copyright terms follow. *-------------------------------------------------------------------- */ /* * PostgreSQL Database Management System * (formerly known as Postgres, then as Postgres95) * * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * * Portions Copyright (c) 1994, The Regents of the University of California * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without a written agreement * is hereby granted, provided that the above copyright notice and this * paragraph and the following two paragraphs appear in all copies. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ #include "spt_config.h" #include #ifdef HAVE_SYS_PSTAT_H #include /* for HP-UX */ #endif #ifdef HAVE_PS_STRINGS #include /* for old BSD */ #include #endif #ifdef HAVE_SYS_PRCTL_H #include /* for Linux >= 2.6.9 */ #include #endif #if defined(__darwin__) #include #endif #include "spt_status.h" #include #include #include /* Darwin doesn't export environ */ #if defined(__darwin__) #define environ (*_NSGetEnviron()) #else extern char **environ; #endif bool update_process_title = true; /* * Alternative 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_PRCTL * use prctl(PR_SET_NAME, ) * (Linux >= 2.6.9) * PS_USE_CLOBBER_ARGV * write over the argv and environment area * (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_PSTAT) && defined(PSTAT_SETCMD) #define PS_USE_PSTAT #elif defined(HAVE_PS_STRINGS) #define PS_USE_PS_STRINGS #elif (defined(BSD) || defined(__bsdi__) || defined(__hurd__)) && !defined(__darwin__) #define PS_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 PS_USE_CLOBBER_ARGV #elif defined(WIN32) #define PS_USE_WIN32 #else #define PS_USE_NONE #endif /* we use this strategy together with another one (probably PS_USE_CLOBBER_ARGV) */ #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_NAME) && !defined(PS_USE_NONE) #define PS_USE_PRCTL #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 PS_USE_CLOBBER_ARGV /* all but one options 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 /* 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 size_t last_status_len; /* use to minimize length of clobber */ #endif /* PS_USE_CLOBBER_ARGV */ 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 init_ps_display. 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 ** save_ps_display_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; 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; } { /* * Clobbering environ works fine from within the process, but some * external utils use /proc/PID/environ and they would find noting, * or mess, if we clobber it. An user can define SPT_NOENV to limit * clobbering to argv (see ticket #16). */ char *noenv; noenv = getenv("SPT_NOENV"); if (!noenv || !*noenv) { /* * 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]); } /* * move the environment out of the way */ new_environ = (char **) malloc((i + 1) * sizeof(char *)); for (i = 0; environ[i] != NULL; i++) new_environ[i] = strdup(environ[i]); new_environ[i] = NULL; environ = new_environ; } } ps_buffer = argv[0]; last_status_len = ps_buffer_size = end_of_area - argv[0]; } #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[], even though * postmaster.c finishes looking at argv[] long before we ever consider * changing the ps display. 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 *)); for (i = 0; i < argc; i++) new_argv[i] = 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 /* PS_USE_CHANGE_ARGV or PS_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 init_ps_display(const char *initial_str) { #ifndef PS_USE_NONE /* no ps display if you didn't call save_ps_display_args() */ if (!save_argv) return; #ifdef PS_USE_CLOBBER_ARGV /* If ps_buffer is a pointer, it might still be null */ if (!ps_buffer) return; #endif /* * Overwrite argv[] to point at appropriate space, if needed */ #ifdef PS_USE_CHANGE_ARGV save_argv[0] = ps_buffer; save_argv[1] = NULL; #endif /* PS_USE_CHANGE_ARGV */ #ifdef PS_USE_CLOBBER_ARGV { int i; /* make extra argv slots point at end_of_area (a NUL) */ for (i = 1; i < save_argc; i++) save_argv[i] = ps_buffer + ps_buffer_size; } #endif /* PS_USE_CLOBBER_ARGV */ /* * Make fixed prefix of ps display. */ ps_buffer[0] = '\0'; ps_buffer_fixed_size = strlen(ps_buffer); set_ps_display(initial_str, true); #endif /* not PS_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 set_ps_display(const char *activity, bool force) { if (!force && !update_process_title) return; #ifndef PS_USE_NONE #ifdef PS_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 */ spt_strlcpy(ps_buffer + ps_buffer_fixed_size, activity, ps_buffer_size - ps_buffer_fixed_size); /* Transmit new setting to kernel, if necessary */ #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, strlen(ps_buffer), 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 { size_t buflen; /* pad unused memory */ buflen = strlen(ps_buffer); /* clobber remainder of old status string */ if (last_status_len > buflen) memset(ps_buffer + buflen, PS_PADDING, last_status_len - buflen); last_status_len = buflen; } #endif /* PS_USE_CLOBBER_ARGV */ #ifdef PS_USE_PRCTL prctl(PR_SET_NAME, ps_buffer); #endif #ifdef PS_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, "python(%d): %s", _getpid(), ps_buffer); ident_handle = CreateEvent(NULL, TRUE, FALSE, name); } #endif /* PS_USE_WIN32 */ #endif /* not PS_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 * get_ps_display(size_t *displen) { #ifdef PS_USE_CLOBBER_ARGV size_t offset; /* If ps_buffer is a pointer, it might still be null */ if (!ps_buffer) { *displen = 0; return ""; } /* Remove any trailing spaces to offset the effect of PS_PADDING */ offset = ps_buffer_size; while (offset > ps_buffer_fixed_size && ps_buffer[offset - 1] == PS_PADDING) offset--; *displen = offset - ps_buffer_fixed_size; #else *displen = strlen(ps_buffer + ps_buffer_fixed_size); #endif return ps_buffer + ps_buffer_fixed_size; } setproctitle-1.1.8/src/spt.h0000664000175000017500000000075011714315500015755 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * spt.h * Definitions useful throughout all the extension. * * Copyright (c) 2010-2012 Daniele Varrazzo * *------------------------------------------------------------------------- */ #ifndef SPT_H #define SPT_H #include "spt_config.h" #include "spt_python.h" /* expose the debug function to the extension code */ HIDDEN void spt_debug(const char *fmt, ...); #endif setproctitle-1.1.8/src/spt_debug.c0000664000175000017500000000166311727074153017134 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * spt_python.c * A simple function for the module debugging. * * Copyright (c) 2009-2012 Daniele Varrazzo * * Debug logging is enabled if the environment variable SPT_DEBUG is set to a * non-empty value at runtime. * *------------------------------------------------------------------------- */ #include #include #include #include "spt_config.h" HIDDEN void spt_debug(const char *fmt, ...) { static int enabled = -1; va_list ap; /* check if debug is enabled */ if (-1 == enabled) { char *d = getenv("SPT_DEBUG"); enabled = (d && *d) ? 1 : 0; } /* bail out if debug is not enabled */ if (0 == enabled) { return; } fprintf(stderr, "[SPT]: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } setproctitle-1.1.8/src/spt_strlcpy.c0000664000175000017500000000413512232040407017526 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * strlcpy.c * strncpy done right * * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * * * IDENTIFICATION * $PostgreSQL: pgsql/src/port/strlcpy.c,v 1.4 2007/01/05 22:20:03 momjian Exp $ * * This file was taken from OpenBSD and is used on platforms that don't * provide strlcpy(). The OpenBSD copyright terms follow. *------------------------------------------------------------------------- */ /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "c.h" /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. * Function creation history: http://www.gratisoft.us/todd/papers/strlcpy.html */ size_t spt_strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0) { while (--n != 0) { if ((*d++ = *s++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return (s - src - 1); /* count does not include NUL */ } setproctitle-1.1.8/src/spt_status.h0000664000175000017500000000113411714567556017401 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * spt_status.h * * Declarations for spt_status.c * *------------------------------------------------------------------------- */ #ifndef SPT_STATUS_H #define SPT_STATUS_H #include "c.h" HIDDEN extern bool update_process_title; HIDDEN extern char **save_ps_display_args(int argc, char **argv); HIDDEN extern void init_ps_display(const char *initial_str); HIDDEN extern void set_ps_display(const char *activity, bool force); HIDDEN extern const char *get_ps_display(size_t *displen); #endif /* SPT_STATUS_H */ setproctitle-1.1.8/src/spt_python.h0000664000175000017500000000245112124264657017372 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * spt_python.h * Include and customize Python definitions. * * Copyright (c) 2010-2012 Daniele Varrazzo * *------------------------------------------------------------------------- */ #ifndef SPT_PYTHON_H #define SPT_PYTHON_H #include /* Things change a lot here... */ #if PY_MAJOR_VERSION >= 3 #define IS_PY3K #endif /* Detect pypy */ #ifdef PYPY_VERSION #define IS_PYPY #endif /* The type returned by Py_GetArgcArgv */ #ifdef IS_PY3K typedef wchar_t argv_t; #else typedef char argv_t; #endif /* defined in Modules/main.c but not publically declared */ void Py_GetArgcArgv(int *argc, argv_t ***argv); /* Mangle the module name into the name of the module init function */ #ifdef IS_PY3K #define INIT_MODULE(m) PyInit_ ## m #else #define INIT_MODULE(m) init ## m #endif /* Py2/3 compatibility layer */ #ifdef IS_PY3K #define PyInt_AsLong PyLong_AsLong #define Bytes_Size PyBytes_Size #define Bytes_AsString PyBytes_AsString #else /* Python 2 */ #define Bytes_Size PyString_Size #define Bytes_AsString PyString_AsString #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) typedef int Py_ssize_t; #endif #endif /* IS_PY3K > 2 */ #endif /* SPT_PYTHON_H */ setproctitle-1.1.8/src/spt_setup.h0000664000175000017500000000064411726526446017217 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * spt_setup.h * Initalization code for the spt_status.c module functions. * * Copyright (c) 2009-2012 Daniele Varrazzo * *------------------------------------------------------------------------- */ #ifndef SPT_SETUP_H #define SPT_SETUP_H #include "spt_config.h" HIDDEN int spt_setup(void); #endif setproctitle-1.1.8/src/spt_config.h0000664000175000017500000000125212232040407017275 0ustar piropiro00000000000000/* Stub file: should be created in configuration phase */ /* This configuration was taken from an Ubuntu i386 installation. */ /* Define to 1 if you have the `setproctitle' function. */ /* #undef HAVE_SETPROCTITLE */ /* Define to 1 if the PS_STRINGS thing exists. */ /* #undef HAVE_PS_STRINGS */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PSTAT_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_PRCTL_H */ /* GCC 4.0 and later have support for specifying symbol visibility */ #if __GNUC__ >= 4 && !defined(__MINGW32__) # define HIDDEN __attribute__((visibility("hidden"))) #else # define HIDDEN #endif setproctitle-1.1.8/src/c.h0000664000175000017500000000131612232040407015365 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * c.h * A few fundamental C definitions. * * Copyright (c) 2009-2012 Daniele Varrazzo *------------------------------------------------------------------------- */ #ifndef C_H #define C_H #include "spt_config.h" #ifndef __cplusplus #ifndef bool typedef char bool; #endif #ifndef true #define true ((bool) 1) #endif #ifndef false #define false ((bool) 0) #endif #endif /* not C++ */ #include /* Let's use our version of strlcpy to avoid portability problems */ size_t spt_strlcpy(char *dst, const char *src, size_t siz); #ifdef WIN32 #include #endif #endif /* C_H */ setproctitle-1.1.8/src/setproctitle.c0000664000175000017500000000607311726526446017707 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * setproctitle.c * Python extension module to update and read the process title. * * Copyright (c) 2009-2012 Daniele Varrazzo * * The module allows Python code to access the functions get_ps_display() * and set_ps_display(). * *------------------------------------------------------------------------- */ #include "spt.h" #include "spt_setup.h" #include "spt_status.h" #ifndef SPT_VERSION #define SPT_VERSION unknown #endif /* macro trick to stringify a macro expansion */ #define xstr(s) str(s) #define str(s) #s /* ----------------------------------------------------- */ static PyObject *spt_version; static char spt_setproctitle__doc__[] = "setproctitle(title) -- Change the process title." ; static PyObject * spt_setproctitle(PyObject *self, PyObject *args, PyObject *kwargs) { const char *title = NULL; static char *kwlist[] = {"title", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &title)) return NULL; set_ps_display(title, true); Py_INCREF(Py_None); return Py_None; } static char spt_getproctitle__doc__[] = "getproctitle() -- Get the current process title." ; static PyObject * spt_getproctitle(PyObject *self, PyObject *args) { size_t tlen; const char *title; title = get_ps_display(&tlen); return Py_BuildValue("s#", title, (int)tlen); } /* List of methods defined in the module */ static struct PyMethodDef spt_methods[] = { {"setproctitle", (PyCFunction)spt_setproctitle, METH_VARARGS|METH_KEYWORDS, spt_setproctitle__doc__}, {"getproctitle", (PyCFunction)spt_getproctitle, METH_NOARGS, spt_getproctitle__doc__}, {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ }; /* Initialization function for the module (*must* be called initsetproctitle) */ static char setproctitle_module_documentation[] = "Allow customization of the process title." ; #ifdef IS_PY3K static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "setproctitle", setproctitle_module_documentation, -1, spt_methods, NULL, NULL, NULL, NULL }; #endif PyMODINIT_FUNC INIT_MODULE(setproctitle)(void) { PyObject *m, *d; spt_debug("module init"); /* Create the module and add the functions */ #ifdef IS_PY3K m = PyModule_Create(&moduledef); #else m = Py_InitModule3("setproctitle", spt_methods, setproctitle_module_documentation); #endif if (m == NULL) { goto exit; } /* Add version string to the module*/ d = PyModule_GetDict(m); spt_version = Py_BuildValue("s", xstr(SPT_VERSION)); PyDict_SetItemString(d, "__version__", spt_version); /* Initialize the process title */ if (0 > spt_setup()) { spt_debug("failed to initialize module setproctitle"); /* Check for errors */ if (PyErr_Occurred()) { spt_debug("an exception is set: import will fail"); } } exit: #ifdef IS_PY3K return m; #else return; #endif } setproctitle-1.1.8/src/spt_setup.c0000664000175000017500000002754312111005760017175 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * spt_setup.c * Initalization code for the spt_status.c module functions. * * Copyright (c) 2009-2012 Daniele Varrazzo * *------------------------------------------------------------------------- */ #include "spt_setup.h" #include "spt.h" #include "spt_status.h" /* Darwin doesn't export environ */ #if defined(__darwin__) #include #define environ (*_NSGetEnviron()) #else extern char **environ; #endif #ifndef WIN32 /* Return a concatenated version of a strings vector. * * Return newly allocated heap space: clean it up with free(). * * Return NULL and raise an exception on error. */ static char * join_argv(int argc, char **argv) { int i; size_t len = 0; char *buf; char *src; char *dest; /* Calculate the final string length */ for (i = 0; i < argc; i++) { len += strlen(argv[i]) + 1; } if (!(dest = buf = (char *)malloc(len))) { PyErr_NoMemory(); return NULL; } /* Copy the strings in the buffer joining with spaces */ for (i = 0; i < argc; i++) { src = argv[i]; while (*src) { *dest++ = *src++; } *dest++ = ' '; } *--dest = '\x00'; return buf; } #ifdef IS_PY3K /* Return a copy of argv[0] encoded in the default encoding. * * Return a newly allocated buffer to be released with free(). * * Return NULL in case of error. If the error shouldn't be ignored, also set * a Python exception. */ static char * get_encoded_arg0(wchar_t *argv0) { PyObject *ua = NULL, *ba = NULL; char *rv = NULL; if (!(ua = PyUnicode_FromWideChar(argv0, -1))) { spt_debug("failed to convert argv[0] to unicode"); PyErr_Clear(); goto exit; } if (!(ba = PyUnicode_AsEncodedString( ua, PyUnicode_GetDefaultEncoding(), "strict"))) { spt_debug("failed to encode argv[0]"); PyErr_Clear(); goto exit; } if (!(rv = strdup(PyBytes_AsString(ba)))) { PyErr_NoMemory(); } exit: Py_XDECREF(ua); Py_XDECREF(ba); return rv; } #else /* !IS_PY3K */ /* Return a copy of argv referring to the original arg area. * * python -m messes up with arg (issue #8): ensure to have a vector to the * original args or save_ps_display_args() will stop processing too soon. * * Return a buffer allocated with malloc: should be cleaned up with free(). * * Return NULL in case of error. If the error shouldn't be ignored, also set * a Python exception. */ static char ** fix_argv(int argc, char **argv) { char **buf = NULL; int i; char *ptr = argv[0]; if (!(buf = (char **)malloc(argc * sizeof(char *)))) { PyErr_NoMemory(); return NULL; } for (i = 0; i < argc; ++i) { buf[i] = ptr; ptr += strlen(ptr) + 1; } return buf; } #endif /* IS_PY3K */ /* Find the original arg buffer starting from the env position. * * Return a malloc'd argv vector, pointing to the original arguments. * * Return NULL in case of error. If the error shouldn't be ignored, also set * a Python exception. * * Required on Python 3 as Py_GetArgcArgv doesn't return pointers to the * original area. It can be used on Python 2 too in case we can't get argv, * such as in embedded environment. */ static char ** find_argv_from_env(int argc, char *arg0) { int i; char **buf = NULL; char **rv = NULL; char *ptr; char *limit; spt_debug("walking from environ to look for the arguments"); if (!(buf = (char **)malloc((argc + 1) * sizeof(char *)))) { spt_debug("can't malloc %d args!", argc); PyErr_NoMemory(); goto exit; } buf[argc] = NULL; /* Walk back from environ until you find argc-1 null-terminated strings. * Don't look for argv[0] as it's probably not preceded by 0. */ ptr = environ[0]; spt_debug("found environ at %p", ptr); limit = ptr - 8192; /* TODO: empiric limit: should use MAX_ARG */ --ptr; for (i = argc - 1; i >= 1; --i) { if (*ptr) { spt_debug("zero %d not found", i); goto exit; } --ptr; while (*ptr && ptr > limit) { --ptr; } if (ptr <= limit) { spt_debug("failed to found arg %d start", i); goto exit; } buf[i] = (ptr + 1); spt_debug("found argv[%d] at %p: %s", i, buf[i], buf[i]); } /* The first arg has not a zero in front. But what we have is reliable * enough (modulo its encoding). Check if it is exactly what found. * * The check is known to fail on OS X with locale C if there are * non-ascii characters in the executable path. See Python issue #9167 */ ptr -= strlen(arg0); spt_debug("argv[0] should be at %p", ptr); if (ptr <= limit) { spt_debug("failed to found argv[0] start"); goto exit; } if (strcmp(ptr, arg0)) { spt_debug("argv[0] doesn't match '%s'", arg0); goto exit; } /* We have all the pieces of the jigsaw. */ buf[0] = ptr; spt_debug("found argv[0]: %s", buf[0]); rv = buf; buf = NULL; exit: if (buf) { free(buf); } return rv; } #ifdef IS_PY3K /* Come on, why is this missing?! this is just cruel! * I guess you club seal pups for hobby. */ PyObject * PyFile_FromString(const char *filename, const char *mode) { PyObject *io = NULL; PyObject *rv = NULL; if (!(io = PyImport_ImportModule("io"))) { spt_debug("failed to import io"); goto exit; } rv = PyObject_CallMethod(io, "open", "ss", filename, mode); exit: Py_XDECREF(io); return rv; } #endif /* IS_PY3K */ /* Read the number of arguments and the first argument from /proc/pid/cmdline * * Return 0 if found, else -1. Return arg0 in a malloc'd array. * * If the function fails in a way that shouldn't be ignored, also set * a Python exception. */ static int get_args_from_proc(int *argc_o, char **arg0_o) { /* allow /proc/PID/cmdline, with oversize max_pid, and them some. */ #define FNLEN 30 char fn[FNLEN]; PyObject *os = NULL; PyObject *pid_py = NULL; long pid; PyObject *f = NULL; PyObject *cl = NULL; PyObject *tmp = NULL; int rv = -1; spt_debug("looking for args into proc fs"); /* get the pid from os.getpid() */ if (!(os = PyImport_ImportModule("os"))) { spt_debug("failed to import os"); goto exit; } if (!(pid_py = PyObject_CallMethod(os, "getpid", NULL))) { spt_debug("calling os.getpid() failed"); /* os.getpid() may be not available, so ignore this error. */ PyErr_Clear(); goto exit; } if (-1 == (pid = PyInt_AsLong(pid_py))) { spt_debug("os.getpid() returned crap?"); /* Don't bother to check PyErr_Occurred as pid can't just be -1. */ goto exit; } /* get the content of /proc/PID/cmdline */ snprintf(fn, FNLEN, "/proc/%ld/cmdline", pid); if (!(f = PyFile_FromString(fn, "rb"))) { spt_debug("opening '%s' failed", fn); /* That's ok: procfs is easily not available on menomated unices */ PyErr_Clear(); goto exit; } /* the file has been open in binary mode, so we get bytes */ cl = PyObject_CallMethod(f, "read", NULL); if (!(tmp = PyObject_CallMethod(f, "close", NULL))) { spt_debug("closing failed"); } else { Py_DECREF(tmp); } if (!cl) { spt_debug("reading failed"); /* could there be some protected environment where a process cannot * read its own pid? Who knows, better not to risk. */ PyErr_Clear(); goto exit; } /* the cmdline is a buffer of null-terminated strings. We can strdup it to * get a copy of arg0, and count the zeros to get argc */ { char *ccl; Py_ssize_t i; if (!(ccl = Bytes_AsString(cl))) { spt_debug("failed to get cmdline string"); goto exit; } if (!(*arg0_o = strdup(ccl))) { spt_debug("arg0 strdup failed"); PyErr_NoMemory(); goto exit; } spt_debug("got argv[0] = '%s' from /proc", *arg0_o); *argc_o = 0; for (i = Bytes_Size(cl) - 1; i >= 0; --i) { if (ccl[i] == '\0') { (*argc_o)++; } } spt_debug("got argc = %d from /proc", *argc_o); } /* success */ rv = 0; exit: Py_XDECREF(cl); Py_XDECREF(f); Py_XDECREF(pid_py); Py_XDECREF(os); return rv; } /* Find the original arg buffer, return 0 if found, else -1. * * If found, set argc to the number of arguments, argv to an array * of pointers to the single arguments. The array is allocated via malloc. * * If the function fails in a way that shouldn't be ignored, also set * a Python exception. * * The function overcomes three Py_GetArgcArgv shortcomings: * - some python parameters mess up with the original argv, e.g. -m * (see issue #8) * - with Python 3, argv is a decoded copy and doesn't point to * the original area. * - If python is embedded, the function doesn't return anything. */ static int get_argc_argv(int *argc_o, char ***argv_o) { int argc = 0; argv_t **argv_py = NULL; char **argv = NULL; char *arg0 = NULL; int rv = -1; #ifndef IS_PYPY spt_debug("reading argc/argv from Python main"); Py_GetArgcArgv(&argc, &argv_py); #endif if (argc > 0) { spt_debug("found %d arguments", argc); #ifdef IS_PY3K if (!(arg0 = get_encoded_arg0(argv_py[0]))) { spt_debug("couldn't get a copy of argv[0]"); goto exit; } #else if (!(argv = fix_argv(argc, (char **)argv_py))) { spt_debug("failed to fix argv"); goto exit; } #endif /* we got argv: on py2 it points to the right place in memory; on py3 * we only got a copy of argv[0]: we will use it to look from environ */ } else { spt_debug("no good news from Py_GetArgcArgv"); /* get a copy of argv[0] from /proc, so we get back in the same * situation of Py3 */ if (0 > get_args_from_proc(&argc, &arg0)) { spt_debug("failed to get args from proc fs"); goto exit; } } /* If we don't know argv but we know the content of argv[0], we can walk * backwards from environ and see if we get it. */ if (arg0 && !argv) { if (!(argv = find_argv_from_env(argc, arg0))) { spt_debug("couldn't find argv from environ"); goto exit; } } /* success */ *argc_o = argc; *argv_o = argv; argv = NULL; rv = 0; exit: if (arg0) { free(arg0); } if (argv) { free(argv); } return rv; } #endif /* !WIN32 */ /* Initialize the module internal functions. * * The function reproduces the initialization performed by PostgreSQL * to be able to call the functions in pg_status.c * * Return 0 in case of success, else -1. In case of failure with an error that * shouldn't be ignored, also set a Python exception. * * The function should be called only once in the process lifetime. * so is called at module initialization. After the function is called, * set_ps_display() can be used. */ int spt_setup(void) { int rv = -1; #ifndef WIN32 int argc = 0; char **argv = NULL; char *init_title; if (0 > get_argc_argv(&argc, &argv)) { spt_debug("get_argc_argv failed"); goto exit; } save_ps_display_args(argc, argv); /* Set up the first title to fully initialize the code */ if (!(init_title = join_argv(argc, argv))) { goto exit; } init_ps_display(init_title); free(init_title); #else /* On Windows save_ps_display_args is a no-op * This is a good news, because Py_GetArgcArgv seems not usable. */ LPTSTR init_title = GetCommandLine(); init_ps_display(init_title); #endif rv = 0; exit: return rv; } setproctitle-1.1.8/setup.py0000664000175000017500000000572012232041427015723 0ustar piropiro00000000000000#!/usr/bin/env python """ setproctitle setup script. Copyright (c) 2009-2013 Daniele Varrazzo """ VERSION = '1.1.8' import os import re import sys from distutils.core import setup, Extension define_macros={} define_macros['SPT_VERSION'] = VERSION if sys.platform.startswith('linux'): try: linux_version = list(map(int, re.search("[.0-9]+", os.popen("uname -r").read()) .group().split(".")[:3])) except: pass else: if linux_version >= [2, 6, 9]: define_macros['HAVE_SYS_PRCTL_H'] = 1 elif sys.platform == 'darwin': # __darwin__ symbol is not defined; __APPLE__ is instead. define_macros['__darwin__'] = 1 elif 'bsd' in sys.platform: # OMG, how many of them are? # Old BSD versions don't have setproctitle # TODO: not tested on an "old BSD" if 0 == os.spawnlp(os.P_WAIT, 'grep', 'grep', '-q', 'setproctitle', '/usr/include/unistd.h', '/usr/include/stdlib.h'): define_macros['HAVE_SETPROCTITLE'] = 1 else: define_macros['HAVE_PS_STRING'] = 1 # NOTE: the library may work on HP-UX using pstat # thus setting define_macros['HAVE_SYS_PSTAT_H'] # see http://www.noc.utoronto.ca/~mikep/unix/HPTRICKS # But I have none handy to test with. mod_spt = Extension('setproctitle', define_macros=list(define_macros.items()), sources = [ 'src/setproctitle.c', 'src/spt_debug.c', 'src/spt_setup.c', 'src/spt_status.c', 'src/spt_strlcpy.c', ]) # patch distutils if it can't cope with the "classifiers" or # "download_url" keywords if sys.version < '2.2.3': from distutils.dist import DistributionMetadata DistributionMetadata.classifiers = None DistributionMetadata.download_url = None # Try to include the long description in the setup kwargs = {} try: kwargs['long_description'] = ( open('README.rst').read() + '\n' +open('HISTORY.rst').read()) except: pass setup( name = 'setproctitle', description = 'A library to allow customization of the process title.', version = VERSION, author = 'Daniele Varrazzo', author_email = 'daniele.varrazzo@gmail.com', url = 'http://code.google.com/p/py-setproctitle/', download_url = 'http://pypi.python.org/pypi/setproctitle/', license = 'BSD', platforms = ['GNU/Linux', 'BSD', 'MacOS X', 'Windows'], classifiers = [ r for r in map(str.strip, """ Development Status :: 5 - Production/Stable Intended Audience :: Developers License :: OSI Approved :: BSD License Programming Language :: C Programming Language :: Python Programming Language :: Python :: 3 Operating System :: POSIX :: Linux Operating System :: POSIX :: BSD Operating System :: MacOS :: MacOS X Operating System :: Microsoft :: Windows Topic :: Software Development """.splitlines()) if r], ext_modules = [mod_spt], **kwargs) setproctitle-1.1.8/PKG-INFO0000664000175000017500000002153412232042534015307 0ustar piropiro00000000000000Metadata-Version: 1.1 Name: setproctitle Version: 1.1.8 Summary: A library to allow customization of the process title. Home-page: http://code.google.com/p/py-setproctitle/ Author: Daniele Varrazzo Author-email: daniele.varrazzo@gmail.com License: BSD Download-URL: http://pypi.python.org/pypi/setproctitle/ Description: A ``setproctitle`` implementation for Python ============================================ :author: Daniele Varrazzo The library allows a process to change its title (as displayed by system tools such as ``ps`` and ``top``). Changing the title is mostly useful in multi-process systems, for example when a master process is forked: changing the children's title allows to identify the task each process is busy with. The technique is used by PostgreSQL_ and the `OpenSSH Server`_ for example. The procedure is hardly portable across different systems. PostgreSQL provides a good `multi-platform implementation`__: this module is a Python wrapper around PostgreSQL code. - `Homepage `__ - `Download `__ - `Source repository `__ - `Bug tracker `__ .. _PostgreSQL: http://www.postgresql.org .. _OpenSSH Server: http://www.openssh.com/ .. __: http://doxygen.postgresql.org/ps__status_8c_source.html Installation ------------ You can use ``easy_install`` to install the module: to perform a system-wide installation use:: sudo easy_install setproctitle If you are an unprivileged user or you want to limit installation to a local environment, you can use the command:: easy_install -d /target/path setproctitle Note that ``easy_install`` requires ``/target/path`` to be in your ``PYTHONPATH``. Python 3 support ~~~~~~~~~~~~~~~~ As of version 1.1 the module works with Python 3. In order to install the module, you can use the `distribute`_ replacemente for ``easy_install``. In order to build and test the module under Python 3, the ``Makefile`` contains some helper targets. .. _distribute: http://pypi.python.org/pypi/distribute Usage ----- The ``setproctitle`` module exports the following functions: ``setproctitle(title)`` Set *title* as the title for the current process. ``getproctitle()`` Return the current process title. Environment variables ~~~~~~~~~~~~~~~~~~~~~ A few environment variables can be used to customize the module behavior: ``SPT_NOENV`` Avoid clobbering ``/proc/PID/environ``. On many platforms, setting the process title will clobber the ``environ`` memory area. ``os.environ`` will work as expected from within the Python process, but the content of the file ``/proc/PID/environ`` will be overwritten. If you require this file not to be broken you can set the ``SPT_NOENV`` environment variable to any non-empty value: in this case the maximum length for the title will be limited to the length of the command line. ``SPT_DEBUG`` Print debug information on ``stderr``. If the module doesn't work as expected you can set this variable to a non-empty value to generate information useful for debugging. Note that the most useful information is printed when the module is imported, not when the functions are called. Module status ------------- The module can be currently compiled and effectively used on the following platforms: - GNU/Linux - BSD - MacOS X - Windows Note that on Windows there is no way to change the process string: what the module does is to create a *Named Object* whose value can be read using a tool such as `Process Explorer`_ (contribution of a more useful tool to be used together with ``setproctitle`` would be well accepted). The module can probably work on HP-UX, but I haven't found any to test with. It is unlikely that it can work on Solaris instead. .. _Process Explorer: http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx Other known implementations and discussions ------------------------------------------- - `procname`_: a module exposing the same functionality, but less portable and not well packaged. - `Issue 5672`_: where the introduction of such functionality into the stdlib is being discussed. .. _procname: http://code.google.com/p/procname/ .. _Issue 5672: http://bugs.python.org/issue5672 .. vim: set filetype=rst: Releases history ---------------- Version 1.1.8 ~~~~~~~~~~~~~ - Added support for Python "diehard" 2.4. - Fixed build on Mac OS X 10.9 Maverick (issue #27). Version 1.1.7 ~~~~~~~~~~~~~ - Added PyPy support, courtesy of Ozan Turksever (http://www.logsign.net). Version 1.1.6 ~~~~~~~~~~~~~ - The module can be compiled again on Windows (issue #21). Version 1.1.5 ~~~~~~~~~~~~~ - No module bug, but a packaging issue: files ``README`` and ``HISTORY`` added back into the distribution. Version 1.1.4 ~~~~~~~~~~~~~ - The module works correctly in embedded Python. - ``setproctitle()`` accepts a keyword argument. - Debug output support always compiled in: the variable ``SPT_DEBUG`` can be used to emit debug log. Version 1.1.3 ~~~~~~~~~~~~~ - Don't clobber environ if the variable ``SPT_NOENV`` is set (issue #16). Version 1.1.2 ~~~~~~~~~~~~~ - Find the setproctitle include file on OpenBSD (issue #11). - Skip test with unicode if the file system encoding wouldn't make it pass (issue #13). Version 1.1.1 ~~~~~~~~~~~~~ - Fixed segfault when the module is imported under mod_wsgi (issue #9). Version 1.1 ~~~~~~~~~~~ - The module works correctly with Python 3. Version 1.0.1 ~~~~~~~~~~~~~ - ``setproctitle()`` works even when Python messes up with argv, e.g. when run with the -m option (issue #8). Version 1.0 ~~~~~~~~~~~ No major change since the previous version. The module has been heavily used in production environment without any problem reported, so it's time to declare it stable. Version 0.4 ~~~~~~~~~~~ - Module works on BSD (tested on FreeBSD 7.2). - Module works on Windows. Many thanks to `Develer`_ for providing a neat `GCC package for Windows with Python integration`__ that made the Windows porting painless. .. _Develer: http://www.develer.com/ .. __: http://www.develer.com/oss/GccWinBinaries Version 0.3 ~~~~~~~~~~~ - Module works on Mac OS X 10.2. Reported working on OS X 10.6 too. Version 0.2 ~~~~~~~~~~~ - Added ``prctl()`` call on Linux >= 2.6.9 to update ``/proc/self/status``. Version 0.1 ~~~~~~~~~~~ - Initial public release. Platform: GNU/Linux Platform: BSD Platform: MacOS X Platform: Windows Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: C Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Operating System :: POSIX :: Linux Classifier: Operating System :: POSIX :: BSD Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows Classifier: Topic :: Software Development setproctitle-1.1.8/tests/0000775000175000017500000000000012232042534015347 5ustar piropiro00000000000000setproctitle-1.1.8/tests/pyrun.c0000664000175000017500000000111111714315500016662 0ustar piropiro00000000000000/*------------------------------------------------------------------------- * * pyrun.c * Stand-alone program to test with embedded Python. * * Run a Python program read from stdin. In case of error return 1. * * Copyright (c) 2011-2012 Daniele Varrazzo * *------------------------------------------------------------------------- */ #include int main(int argc, char *argv[]) { int rv = 0; Py_Initialize(); if (0 != PyRun_SimpleFile(stdin, "stdin")) { rv = 1; } Py_Finalize(); return rv; } setproctitle-1.1.8/tests/setproctitle_test.py0000664000175000017500000004224612111005760021505 0ustar piropiro00000000000000"""setproctitle module unit test. Use nosetests to run this test suite. Copyright (c) 2009-2012 Daniele Varrazzo """ import os import re import sys import shutil import tempfile import unittest from subprocess import Popen, PIPE IS_PY3K = sys.version_info[0] == 3 IS_PYPY = '__pypy__' in sys.builtin_module_names # SkipTest is available from Python 2.7 and in nose try: from unittest import SkipTest except ImportError: try: from nose.plugins.skip import SkipTest except ImportError: class SkipTest(Exception): pass if unittest.TestCase.assert_ is not unittest.TestCase.assertTrue: # Vaffanculo, Wolf unittest.TestCase.assert_ = unittest.TestCase.assertTrue class SetproctitleTestCase(unittest.TestCase): """Test the module works as expected. The tests are executed in external processes: setproctitle should never be imported directly from here. The tests scrits are written in Python 2 syntax: if the test suite is run with Python 3 they are converted automatically. This test module should be converted though: the Makefile should do that. """ def test_runner(self): """Test the script execution method.""" rv = self.run_script(""" print 10 + 20 """) self.assertEqual(rv, "30\n") def test_init_getproctitle(self): """getproctitle() returns a sensible value at initial call.""" rv = self.run_script(""" import setproctitle print setproctitle.getproctitle() """, args="-u") self.assertEqual(rv, sys.executable + " -u\n") def test_setproctitle(self): """setproctitle() can set the process title, duh.""" rv = self.run_script(r""" import setproctitle setproctitle.setproctitle('Hello, world!') import os print os.getpid() # ps can fail on kfreebsd arch # (http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=460331) print os.popen("ps -x -o pid,command 2> /dev/null").read() """) lines = filter(None, rv.splitlines()) pid = lines.pop(0) pids = dict([r.strip().split(None, 1) for r in lines]) title = self._clean_up_title(pids[pid]) self.assertEqual(title, "Hello, world!") def test_prctl(self): """Check that prctl is called on supported platforms.""" linux_version = [] if sys.platform == 'linux2': try: f = os.popen("uname -r") name = f.read() f.close() except: pass else: linux_version = map(int, re.search("[.0-9]+", name) .group().split(".")[:3]) if linux_version < [2,6,9]: raise SkipTest("syscall not supported") rv = self.run_script(r""" import setproctitle setproctitle.setproctitle('Hello, prctl!') print open('/proc/self/status').read() """) status = dict([r.split(':', 1) for r in rv.splitlines() if ':' in r]) self.assertEqual(status['Name'].strip(), "Hello, prctl!") def test_getproctitle(self): """getproctitle() can read the process title back.""" rv = self.run_script(r""" import setproctitle setproctitle.setproctitle('Hello, world!') print setproctitle.getproctitle() """) self.assertEqual(rv, "Hello, world!\n") def test_kwarg(self): """setproctitle() supports keyword args.""" rv = self.run_script(r""" import setproctitle setproctitle.setproctitle(title='Hello, world!') print setproctitle.getproctitle() """) self.assertEqual(rv, "Hello, world!\n") def test_environ(self): """Check that clobbering environ didn't break env.""" rv = self.run_script(r""" import setproctitle setproctitle.setproctitle('Hello, world! ' + 'X' * 1024) # set a new env variable, update another one import os os.environ['TEST_SETENV'] = "setenv-value" os.environ['PATH'] = os.environ.get('PATH', '') \ + os.pathsep + "fakepath" # read the environment from a spawned process inheriting the # updated env newenv = dict([r.split("=",1) for r in os.popen("env").read().splitlines() if '=' in r]) print setproctitle.getproctitle() print newenv['TEST_SETENV'] print newenv['PATH'] """) title, test, path = rv.splitlines() self.assert_(title.startswith("Hello, world! XXXXX"), title) self.assertEqual(test, 'setenv-value') self.assert_(path.endswith('fakepath'), path) def test_issue_8(self): """Test that the module works with 'python -m'.""" module = 'spt_issue_8' pypath = os.environ.get('PYTHONPATH', None) dir = tempfile.mkdtemp() os.environ['PYTHONPATH'] = dir + os.pathsep + (pypath or '') try: f = open(dir + '/' + module + '.py', 'w') try: f.write( self.to3(self._clean_whitespaces(r""" import setproctitle setproctitle.setproctitle("Hello, module!") import os print os.getpid() print os.popen("ps -x -o pid,command 2> /dev/null").read() """))) finally: f.close() rv = self.run_script(args="-m " + module) lines = filter(None, rv.splitlines()) pid = lines.pop(0) pids = dict([r.strip().split(None, 1) for r in lines]) title = self._clean_up_title(pids[pid]) self.assertEqual(title, "Hello, module!") finally: shutil.rmtree(dir, ignore_errors=True) if pypath is not None: os.environ['PYTHONPATH'] = pypath else: del os.environ['PYTHONPATH'] def test_unicode(self): """Title can contain unicode characters.""" snowman = u'\u2603' try: snowman.encode(sys.getdefaultencoding()) except UnicodeEncodeError: raise SkipTest("default encoding '%s' can't deal with snowmen" % sys.getdefaultencoding()) try: snowman.encode(sys.getfilesystemencoding()) except UnicodeEncodeError: raise SkipTest("file system encoding '%s' can't deal with snowmen" % sys.getfilesystemencoding()) rv = self.run_script(r""" snowman = u'\u2603' import setproctitle setproctitle.setproctitle("Hello, " + snowman + "!") import os import locale from subprocess import Popen, PIPE print os.getpid() proc = Popen("ps -x -o pid,command 2> /dev/null", shell=True, close_fds=True, stdout=PIPE, stderr=PIPE) buf = proc.stdout.read() print buf.decode(locale.getpreferredencoding(), 'replace') """) lines = filter(None, rv.splitlines()) pid = lines.pop(0) pids = dict([r.strip().split(None, 1) for r in lines]) snowmen = [ u'\u2603', # ps supports unicode r'\M-b\M^X\M^C', # ps output on BSD r'M-bM^XM^C', # ps output on some Darwin < 11.2 u'\ufffdM^XM^C', # ps output on Darwin 11.2 ] title = self._clean_up_title(pids[pid]) for snowman in snowmen: if title == "Hello, " + snowman + "!": break else: self.fail("unexpected ps output: %r" % title) def test_weird_args(self): """No problem with encoded arguments.""" euro = u'\u20ac' snowman = u'\u2603' try: rv = self.run_script(r""" import setproctitle setproctitle.setproctitle("Hello, weird args!") import os print os.getpid() print os.popen("ps -x -o pid,command 2> /dev/null").read() """, args=u" ".join(["-", "hello", euro, snowman])) except TypeError: raise SkipTest( "apparently we can't pass unicode args to a program") lines = filter(None, rv.splitlines()) pid = lines.pop(0) pids = dict([r.strip().split(None, 1) for r in lines]) title = self._clean_up_title(pids[pid]) self.assertEqual(title, "Hello, weird args!") def test_weird_path(self): """No problem with encoded argv[0] path.""" self._check_4388() euro = u'\u20ac' snowman = u'\u2603' tdir = tempfile.mkdtemp() dir = tdir + "/" + euro + "/" + snowman try: try: os.makedirs(dir) except UnicodeEncodeError: raise SkipTest("file system doesn't support unicode") exc = dir + "/python" os.symlink(sys.executable, exc) rv = self.run_script(r""" import setproctitle setproctitle.setproctitle("Hello, weird path!") import os print os.getpid() print os.popen("ps -x -o pid,command 2> /dev/null").read() """, args=u" ".join(["-", "foo", "bar", "baz"]), executable=exc) lines = filter(None, rv.splitlines()) pid = lines.pop(0) pids = dict([r.strip().split(None, 1) for r in lines]) title = self._clean_up_title(pids[pid]) self.assertEqual(title, "Hello, weird path!") finally: shutil.rmtree(tdir, ignore_errors=True) def test_embedded(self): """Check the module works with embedded Python. """ if IS_PYPY: raise SkipTest("skip test, pypy") if not os.path.exists('/proc/%s/cmdline' % os.getpid()): raise SkipTest("known failure: '/proc/PID/cmdline' not available") exe = os.environ.get('ROOT_PATH', '.') \ + ('/tests/pyrun%s' % sys.version_info[0]) if not os.path.exists(exe): raise Exception('test program not found: %s' % exe) rv = self.run_script(r""" import setproctitle setproctitle.setproctitle("Hello, embedded!") import os print os.getpid() print os.popen("ps -x -o pid,command 2> /dev/null").read() """, executable=exe) lines = filter(None, rv.splitlines()) pid = lines.pop(0) pids = dict([r.strip().split(None, 1) for r in lines]) title = self._clean_up_title(pids[pid]) self.assertEqual(title, "Hello, embedded!") def test_embedded_many_args(self): """Check more complex cmdlines are handled in embedded env too.""" if IS_PYPY: raise SkipTest("skip test, pypy") if not os.path.exists('/proc/%s/cmdline' % os.getpid()): raise SkipTest("known failure: '/proc/PID/cmdline' not available") exe = os.environ.get('ROOT_PATH', '.') \ + ('/tests/pyrun%s' % sys.version_info[0]) if not os.path.exists(exe): raise Exception('test program not found: %s' % exe) rv = self.run_script(r""" import setproctitle setproctitle.setproctitle("Hello, embedded!") import os print os.getpid() print os.popen("ps -x -o pid,command 2> /dev/null").read() """, executable=exe, args=u" ".join(["foo", "bar", "baz"])) lines = filter(None, rv.splitlines()) pid = lines.pop(0) pids = dict([r.strip().split(None, 1) for r in lines]) title = self._clean_up_title(pids[pid]) self.assertEqual(title, "Hello, embedded!") def test_noenv(self): """Check that SPT_NOENV avoids clobbering environ.""" if not os.path.exists('/proc/self/environ'): raise SkipTest("'/proc/self/environ' not available") env = os.environ.copy() env['SPT_TESTENV'] = 'testenv' rv = self.run_script(""" import os os.environ['SPT_NOENV'] = "1" cmdline_len = len(open('/proc/self/cmdline').read()) print cmdline_len print 'SPT_TESTENV=testenv' in open('/proc/self/environ').read() import setproctitle setproctitle.setproctitle('X' * cmdline_len * 10) title = open('/proc/self/cmdline').read().rstrip() print title print len(title) print 'SPT_TESTENV=testenv' in open('/proc/self/environ').read() """, env=env) lines = rv.splitlines() cmdline_len = int(lines[0]) self.assertEqual(lines[1], 'True', "can't verify testenv") title = lines[2] self.assert_('XXX' in self._clean_up_title(title), "title not set as expected") title_len = int(lines[3]) self.assertEqual(lines[4], 'True', "env has been clobbered") self.assert_(title_len <= cmdline_len, "title (len %s) not limited to argv (len %s)" % (title_len, cmdline_len)) def run_script(self, script=None, args=None, executable=None, env=None): """run a script in a separate process. if the script completes successfully, return its ``stdout``, else fail the test. """ if executable is None: executable = sys.executable cmdline = executable if args: cmdline = cmdline + " " + args proc = Popen(cmdline, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env, shell=True, close_fds=True) if script is not None: script = self._clean_whitespaces(script) script = self.to3(script) if IS_PY3K: script = script.encode() out, err = proc.communicate(script) if 0 != proc.returncode: print out print err self.fail("test script failed") # Py3 subprocess generates bytes strings. if IS_PY3K: out = out.decode() return out def to3(self, script): """Convert a script to Python3 if required.""" if not IS_PY3K: return script script = script.encode() f = tempfile.NamedTemporaryFile(suffix=".py") try: f.write(script) f.flush() # 2to3 is way too chatty import logging logging.basicConfig(filename=os.devnull) from lib2to3.main import main if main("lib2to3.fixes", ['--no-diffs', '-w', '-n', f.name]): raise Exception('py3 conversion failed') ff = open(f.name) try: return ff.read() finally: ff.close() finally: f.close() def _clean_whitespaces(self, script): """clean up a script in a string Remove the amount of whitelines found in the first nonblank line """ script = script.splitlines(True) while script and script[0].isspace(): script.pop(0) if not script: raise ValueError("empty script") line1 = script[0] spaces = script[0][:-len(script[0].lstrip())] assert spaces.isspace() for i, line in enumerate(script): if line.isspace(): continue if line.find(spaces) != 0: raise ValueError("inconsistent spaces at line %d (%s)" % (i + 1, line.strip())) script[i] = line[len(spaces):] # drop final blank lines: they produce import errors while script and script[-1].isspace(): del script[-1] assert not script[0][0].isspace(), script[0] return ''.join(script) def _clean_up_title(self, title): """Clean up a string from the prefix added by the platform. """ # BSD's setproctitle decorates the title with the process name. if 'bsd' in sys.platform: procname = os.path.basename(sys.executable) title = ' '.join([t for t in title.split(' ') if procname not in t]) return title def _check_4388(self): """Check if the system is affected by bug #4388. If positive, unicode chars in the cmdline are not reliable, so bail out. see: http://bugs.python.org/issue4388 """ if not IS_PY3K: return if sys.getfilesystemencoding() == 'ascii': # in this case the char below would get translated in some # inconsistent way. # I'm not getting why the FS encoding is involved in process # spawning, the whole story just seems a gigantic can of worms. return from subprocess import Popen, PIPE p = Popen([sys.executable, '-c', "ord('\xe9')"], stderr=PIPE) p.communicate() if p.returncode: raise SkipTest("bug #4388 detected") if __name__ == '__main__': unittest.main() setproctitle-1.1.8/COPYRIGHT0000664000175000017500000000271411714315500015504 0ustar piropiro00000000000000Copyright (c) 2009-2012, Daniele Varrazzo All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The name of Daniele Varrazzo may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.