|
|
Log in / Subscribe / Register

+1 on setproctitle

+1 on setproctitle

Posted Oct 7, 2011 16:52 UTC (Fri) by dskoll (subscriber, #1630)
Parent article: A Plumber's Wish List for Linux

I would like to set setproctitle or equivalent. It's very useful if you have a concurrent server that forks and handles requests. If each child sets the process title to reflect what it's doing, ps becomes a pretty effective monitoring and diagnostic tool.


to post comments

+1 on setproctitle

Posted Oct 7, 2011 17:09 UTC (Fri) by ajb (subscriber, #9694) [Link] (7 responses)

What's the difference between that and "prctl(PR_SET_NAME,name,0,0,0);", which we already have?

+1 on setproctitle

Posted Oct 7, 2011 18:08 UTC (Fri) by sionescu (subscriber, #59410) [Link] (6 responses)

An upper limit of more than 16 chars, hopefully

+1 on setproctitle

Posted Oct 7, 2011 20:16 UTC (Fri) by dskoll (subscriber, #1630) [Link] (5 responses)

Yep. 16 characters is too small to be useful. It's nice to get output like this:

postgres 23453 0.2 0.2 1159236 47684 ? Rs 16:05 0:01 postgres: user dbname 127.0.0.1(43135) SELECT

±0 on setproctitle

Posted Oct 7, 2011 23:16 UTC (Fri) by jengelh (subscriber, #33263) [Link] (2 responses)

setproctitle you already have, sort of.
void setproctitle(int argc, char **argv, char *title)
{
    strlcpy(argv[0], title, &argv[argc-1][strlen(argv[argc-1])] - argv[0]);
}
or so is how it is currently done, for the glibc-linux platform.

+1 on setproctitle

Posted Oct 8, 2011 15:31 UTC (Sat) by dskoll (subscriber, #1630) [Link] (1 responses)

It's not that easy. Read the source code to some programs that allow changing of the process title (eg, PostgreSQL, Perl, Sendmail.) They all use horrible hacks to get it to work.

+½ on setproctitle

Posted Oct 8, 2011 15:52 UTC (Sat) by jengelh (subscriber, #33263) [Link]

The pgsql code does the same. Plus a handful of extra checks to ensure linearity etc. of course, because it wants to be multi-platform and safe. Now let's rather think about why glibc still does not have the feature (implementing setproctitle via clobbering of argv).

+1 on setproctitle

Posted Oct 8, 2011 9:27 UTC (Sat) by fdr (guest, #57064) [Link] (1 responses)

Color me confused. I have an Ubuntu 10.04 LTS machine, and I have long proctitles:

postgres: archiver process last was 00000003000004B2000000F5

Along with full on user, database, IP(socket) statement-kind information.

Am I missing something?

+1 on setproctitle

Posted Oct 8, 2011 10:11 UTC (Sat) by neilbrown (subscriber, #359) [Link]

The bit you are missing is "without mucking with environ[]".

When a process is started, the top of memory contains:

all the args, each nul terminated
an extra nul
all the environment, each entry nul terminated
maybe another nul (not sure).

setproctitle copies new text over the args. If the new text is longer than the old text, it copies over the environment as well. This can be a problem if you later want to use the environment.

The kernel remembers where the args and environment start and end:
unsigned long arg_start, arg_end, env_start, env_end;
(mm_types.h)
proc_pid_cmdline (fs/proc/base.c) knows that if the extra nul isn't there at arg_end, it should look for more text in the env_{start,end} range too.

This feature could be implemented by allowing arg_start, arg_end to be set by some user-space system call. So the process would allocate some memory, fill it with the text to appear in /proc/$pid/cmdline, and "give" that memory to the kernel.

It might be easier to just support a 'write' request on /proc/self/cmdline. Then the kernel would need to allocate a page to store the text, but that isn't a big deal...

Re: +1 on setproctitle

Posted Oct 8, 2011 11:49 UTC (Sat) by ldo (guest, #40946) [Link] (3 responses)

Here’s a routine I came up with a while back:
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>

extern char **
    environ;
static char *
    argstart = NULL;
static size_t
    maxarglen; /* maximum available size of argument area */
static bool
    envmoved = false;

void setproctitle
  (
    char ** argv, /* argv as passed to main, so args can be moved if necessary */
    const char * fmt,
    ...
  )
  /* something as close as possible to BSD setproctitle(3), but for Linux.
    Note I need argv as passed to main, in order to be able to poke the process
    arguments area. Also don't call routines like putenv(3) or setenv(3)
    prior to using this routine. */
  {
  /* Theory of operation: the command-line arguments and environment variables
    for a process can be found from fields arg_start, arg_end, env_start and
    env_end of the mm_struct object defined in include/linux/mm_types.h in the
    current kernel sources. These areas are set up in different ways depending
    on the executable format; for ELF, see the routine create_elf_tables in
    fs/binfmt_elf.c. This puts the envp pointer array immediately following
    the null entry at the end of the argv pointer array, both in the userspace
    stack. The actual strings are stored contiguously in the area beginning at
    mm_struct.arg_start for the argument strings, and mm_struct.env_start
    (immediately follows mm_struct.arg_end) for the environment strings.
    The current process command line is made visible (to utilities like ps etc) via
    the proc_pid_cmdline routine in fs/proc/base.c. This routine checks that the
    byte at mm_struct.arg_end is still a null; if not, it assumes the process
    has overwritten its argument and environment area with an extra-long title,
    and appends the extra data beginning at mm_struct.env_start as well.

    Limitations: this routine can only use the available argument and environment
    area. If the command-line arguments and environment are small to begin with, then
    that limits the length of process title that can be set. Also libc library routines
    like putenv(3) do their own relocation of the environ array and strings; if they
    are used before the first call of this routine that needs to overflow into the
    environment area, then I won't be able to find the original location of the latter.
  */
    char title[512]; /* big enough? */
    ssize_t titlelen;
      {
        va_list args;
        va_start(args, fmt);
        titlelen = vsnprintf(title, sizeof title, fmt, args);
        va_end(args);
        if (titlelen < 0)
          {
            titlelen = 0; /* ignore error */
            title[0] = 0;
          } /*if*/
        titlelen += 1; /* including trailing nul */
        if (titlelen > sizeof title)
          {
            title[sizeof title - 1] = '\0'; /* do I need to do this? */
            titlelen = sizeof title;
          } /*if*/
      }
    if (argstart == NULL)
      {
      /* first call, find and initialize argument area */
        char ** thisarg = argv;
        maxarglen = 0;
        argstart = *thisarg;
        while (*thisarg != NULL)
          {
            maxarglen += strlen(*thisarg++) + 1; /* including terminating nul */
          } /*while*/
        memset(argstart, 0, maxarglen); /* clear it all out */
      } /*if*/
    if (titlelen > maxarglen && !envmoved)
      {
      /* relocate the environment strings and use that area for the command line
        as well */
        char ** srcenv;
        char ** dstenv;
        char ** newenv;
        size_t envlen = 0;
        size_t nrenv = 1; /* nr env strings + 1 for terminating NULL pointer */
        if (argstart + maxarglen == environ[0]) /* not already moved by e.g. libc */
          {
            srcenv = environ;
            while (*srcenv != NULL)
              {
                envlen += strlen(*srcenv++) + 1; /* including terminating nul */
                ++nrenv; /* count 'em up */
              } /*while*/
            newenv = (char **)malloc(sizeof(char *) * nrenv); /* new env array, never freed! */
            srcenv = environ;
            dstenv = newenv;
            while (*srcenv != NULL)
              {
              /* copy the environment strings */
                *dstenv++ = strdup(*srcenv++);
              } /*while*/
            *dstenv = NULL; /* mark end of new environment array */
            memset(environ[0], 0, envlen); /* clear old environment area */
            maxarglen += envlen; /* this much extra space now available */
            environ = newenv; /* so libc etc pick up new environment location */
          } /*if*/
        envmoved = true;
      } /*if*/
    if (titlelen > maxarglen)
      {
        titlelen = maxarglen; /* truncate to fit available area */
      } /*if*/
    if (titlelen > 0)
      {
      /* set the new title */
        const size_t oldtitlelen = strlen(argstart) + 1; /* including trailing nul */
        memcpy(argstart, title, titlelen);
        argstart[titlelen - 1] = '\0'; /* if not already done */
        if (oldtitlelen > titlelen)
          {
          /* wipe out remnants of previous title */
            memset(argstart + titlelen, 0, oldtitlelen - titlelen);
          } /*if*/
      } /*if*/
  } /*setproctitle*/

Re: +1 on setproctitle

Posted Oct 9, 2011 3:26 UTC (Sun) by neilbrown (subscriber, #359) [Link]

Neat !!

As long as no-one uses getenv() before-hand and holds on to the string - or uses putenv as you say.

I would probably have a setproctitle_prepare() which is called first-thing in main() and relocates both argv and environ so that the original arg space is not referenced by anything. But that might just be paranoia.

Also - ld-linux.*.so uses environment variables. I wonder if it holds on to any that it looked up before main() was called.. Probably not, that would be asking for trouble.

Re: +1 on setproctitle

Posted Oct 10, 2011 16:57 UTC (Mon) by mezcalero (subscriber, #45103) [Link]

This is more or less what my own Avahi does as well. But it's really broken as it breaks /proc/$PID/environ and suchlike. And it doesn't work at all if the env block passed to you is too small.

It's a hack, nothing more. And what we have been asking for is a nicer solution, that isn't just a hack.

this seems tangential to the desired effect.

Posted Oct 25, 2011 12:59 UTC (Tue) by quanstro (guest, #77996) [Link]

perhaps i'm not following along, but one assumes that changing
argv for internal purposes is already trivial, and requires no
further interface. and i don't see what the process'
view of argv/environment has to do with ps(1)'s view. why not
allow /proc/$pid/args or similar to be writable?

+1 on setproctitle

Posted Oct 26, 2011 19:52 UTC (Wed) by cras (guest, #7000) [Link]

I tried to get setproctitle() added a few years ago, but I got tired after a while and just implemented the ugly environ hack. If someone wants to continue, this is probably the last patch: http://lwn.net/Articles/365733/ Someone didn't like the prctl() way anyway and preferred a separate setproctitle() syscall.


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds