LCOV - code coverage report
Current view: top level - src/backend/utils/misc - ps_status.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 55 74 74.3 %
Date: 2017-09-29 15:12:54 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*--------------------------------------------------------------------
       2             :  * ps_status.c
       3             :  *
       4             :  * Routines to support changing the ps display of PostgreSQL backends
       5             :  * to contain some useful information. Mechanism differs wildly across
       6             :  * platforms.
       7             :  *
       8             :  * src/backend/utils/misc/ps_status.c
       9             :  *
      10             :  * Copyright (c) 2000-2017, PostgreSQL Global Development Group
      11             :  * various details abducted from various places
      12             :  *--------------------------------------------------------------------
      13             :  */
      14             : 
      15             : #include "postgres.h"
      16             : 
      17             : #include <unistd.h>
      18             : #ifdef HAVE_SYS_PSTAT_H
      19             : #include <sys/pstat.h>            /* for HP-UX */
      20             : #endif
      21             : #ifdef HAVE_PS_STRINGS
      22             : #include <machine/vmparam.h>  /* for old BSD */
      23             : #include <sys/exec.h>
      24             : #endif
      25             : #if defined(__darwin__)
      26             : #include <crt_externs.h>
      27             : #endif
      28             : 
      29             : #include "libpq/libpq.h"
      30             : #include "miscadmin.h"
      31             : #include "utils/ps_status.h"
      32             : #include "utils/guc.h"
      33             : 
      34             : extern char **environ;
      35             : bool        update_process_title = true;
      36             : 
      37             : 
      38             : /*
      39             :  * Alternative ways of updating ps display:
      40             :  *
      41             :  * PS_USE_SETPROCTITLE
      42             :  *     use the function setproctitle(const char *, ...)
      43             :  *     (newer BSD systems)
      44             :  * PS_USE_PSTAT
      45             :  *     use the pstat(PSTAT_SETCMD, )
      46             :  *     (HPUX)
      47             :  * PS_USE_PS_STRINGS
      48             :  *     assign PS_STRINGS->ps_argvstr = "string"
      49             :  *     (some BSD systems)
      50             :  * PS_USE_CHANGE_ARGV
      51             :  *     assign argv[0] = "string"
      52             :  *     (some other BSD systems)
      53             :  * PS_USE_CLOBBER_ARGV
      54             :  *     write over the argv and environment area
      55             :  *     (Linux and most SysV-like systems)
      56             :  * PS_USE_WIN32
      57             :  *     push the string out as the name of a Windows event
      58             :  * PS_USE_NONE
      59             :  *     don't update ps display
      60             :  *     (This is the default, as it is safest.)
      61             :  */
      62             : #if defined(HAVE_SETPROCTITLE)
      63             : #define PS_USE_SETPROCTITLE
      64             : #elif defined(HAVE_PSTAT) && defined(PSTAT_SETCMD)
      65             : #define PS_USE_PSTAT
      66             : #elif defined(HAVE_PS_STRINGS)
      67             : #define PS_USE_PS_STRINGS
      68             : #elif (defined(BSD) || defined(__hurd__)) && !defined(__darwin__)
      69             : #define PS_USE_CHANGE_ARGV
      70             : #elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(__svr5__) || defined(__darwin__)
      71             : #define PS_USE_CLOBBER_ARGV
      72             : #elif defined(WIN32)
      73             : #define PS_USE_WIN32
      74             : #else
      75             : #define PS_USE_NONE
      76             : #endif
      77             : 
      78             : 
      79             : /* Different systems want the buffer padded differently */
      80             : #if defined(_AIX) || defined(__linux__) || defined(__darwin__)
      81             : #define PS_PADDING '\0'
      82             : #else
      83             : #define PS_PADDING ' '
      84             : #endif
      85             : 
      86             : 
      87             : #ifndef PS_USE_CLOBBER_ARGV
      88             : /* all but one option need a buffer to write their ps line in */
      89             : #define PS_BUFFER_SIZE 256
      90             : static char ps_buffer[PS_BUFFER_SIZE];
      91             : static const size_t ps_buffer_size = PS_BUFFER_SIZE;
      92             : #else                           /* PS_USE_CLOBBER_ARGV */
      93             : static char *ps_buffer;         /* will point to argv area */
      94             : static size_t ps_buffer_size;   /* space determined at run time */
      95             : static size_t last_status_len;  /* use to minimize length of clobber */
      96             : #endif                          /* PS_USE_CLOBBER_ARGV */
      97             : 
      98             : static size_t ps_buffer_cur_len;    /* nominal strlen(ps_buffer) */
      99             : 
     100             : static size_t ps_buffer_fixed_size; /* size of the constant prefix */
     101             : 
     102             : /* save the original argv[] location here */
     103             : static int  save_argc;
     104             : static char **save_argv;
     105             : 
     106             : 
     107             : /*
     108             :  * Call this early in startup to save the original argc/argv values.
     109             :  * If needed, we make a copy of the original argv[] array to preserve it
     110             :  * from being clobbered by subsequent ps_display actions.
     111             :  *
     112             :  * (The original argv[] will not be overwritten by this routine, but may be
     113             :  * overwritten during init_ps_display.  Also, the physical location of the
     114             :  * environment strings may be moved, so this should be called before any code
     115             :  * that might try to hang onto a getenv() result.)
     116             :  *
     117             :  * Note that in case of failure this cannot call elog() as that is not
     118             :  * initialized yet.  We rely on write_stderr() instead.
     119             :  */
     120             : char      **
     121           6 : save_ps_display_args(int argc, char **argv)
     122             : {
     123           6 :     save_argc = argc;
     124           6 :     save_argv = argv;
     125             : 
     126             : #if defined(PS_USE_CLOBBER_ARGV)
     127             : 
     128             :     /*
     129             :      * If we're going to overwrite the argv area, count the available space.
     130             :      * Also move the environment to make additional room.
     131             :      */
     132             :     {
     133           6 :         char       *end_of_area = NULL;
     134             :         char      **new_environ;
     135             :         int         i;
     136             : 
     137             :         /*
     138             :          * check for contiguous argv strings
     139             :          */
     140          50 :         for (i = 0; i < argc; i++)
     141             :         {
     142          44 :             if (i == 0 || end_of_area + 1 == argv[i])
     143          44 :                 end_of_area = argv[i] + strlen(argv[i]);
     144             :         }
     145             : 
     146           6 :         if (end_of_area == NULL)    /* probably can't happen? */
     147             :         {
     148           0 :             ps_buffer = NULL;
     149           0 :             ps_buffer_size = 0;
     150           0 :             return argv;
     151             :         }
     152             : 
     153             :         /*
     154             :          * check for contiguous environ strings following argv
     155             :          */
     156         207 :         for (i = 0; environ[i] != NULL; i++)
     157             :         {
     158         201 :             if (end_of_area + 1 == environ[i])
     159         201 :                 end_of_area = environ[i] + strlen(environ[i]);
     160             :         }
     161             : 
     162           6 :         ps_buffer = argv[0];
     163           6 :         last_status_len = ps_buffer_size = end_of_area - argv[0];
     164             : 
     165             :         /*
     166             :          * move the environment out of the way
     167             :          */
     168           6 :         new_environ = (char **) malloc((i + 1) * sizeof(char *));
     169           6 :         if (!new_environ)
     170             :         {
     171           0 :             write_stderr("out of memory\n");
     172           0 :             exit(1);
     173             :         }
     174         207 :         for (i = 0; environ[i] != NULL; i++)
     175             :         {
     176         201 :             new_environ[i] = strdup(environ[i]);
     177         201 :             if (!new_environ[i])
     178             :             {
     179           0 :                 write_stderr("out of memory\n");
     180           0 :                 exit(1);
     181             :             }
     182             :         }
     183           6 :         new_environ[i] = NULL;
     184           6 :         environ = new_environ;
     185             :     }
     186             : #endif                          /* PS_USE_CLOBBER_ARGV */
     187             : 
     188             : #if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV)
     189             : 
     190             :     /*
     191             :      * If we're going to change the original argv[] then make a copy for
     192             :      * argument parsing purposes.
     193             :      *
     194             :      * (NB: do NOT think to remove the copying of argv[], even though
     195             :      * postmaster.c finishes looking at argv[] long before we ever consider
     196             :      * changing the ps display.  On some platforms, getopt() keeps pointers
     197             :      * into the argv array, and will get horribly confused when it is
     198             :      * re-called to analyze a subprocess' argument string if the argv storage
     199             :      * has been clobbered meanwhile.  Other platforms have other dependencies
     200             :      * on argv[].
     201             :      */
     202             :     {
     203             :         char      **new_argv;
     204             :         int         i;
     205             : 
     206           6 :         new_argv = (char **) malloc((argc + 1) * sizeof(char *));
     207           6 :         if (!new_argv)
     208             :         {
     209           0 :             write_stderr("out of memory\n");
     210           0 :             exit(1);
     211             :         }
     212          50 :         for (i = 0; i < argc; i++)
     213             :         {
     214          44 :             new_argv[i] = strdup(argv[i]);
     215          44 :             if (!new_argv[i])
     216             :             {
     217           0 :                 write_stderr("out of memory\n");
     218           0 :                 exit(1);
     219             :             }
     220             :         }
     221           6 :         new_argv[argc] = NULL;
     222             : 
     223             : #if defined(__darwin__)
     224             : 
     225             :         /*
     226             :          * macOS (and perhaps other NeXT-derived platforms?) has a static copy
     227             :          * of the argv pointer, which we may fix like so:
     228             :          */
     229             :         *_NSGetArgv() = new_argv;
     230             : #endif
     231             : 
     232           6 :         argv = new_argv;
     233             :     }
     234             : #endif                          /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */
     235             : 
     236           6 :     return argv;
     237             : }
     238             : 
     239             : /*
     240             :  * Call this once during subprocess startup to set the identification
     241             :  * values.  At this point, the original argv[] array may be overwritten.
     242             :  */
     243             : void
     244         341 : init_ps_display(const char *username, const char *dbname,
     245             :                 const char *host_info, const char *initial_str)
     246             : {
     247         341 :     Assert(username);
     248         341 :     Assert(dbname);
     249         341 :     Assert(host_info);
     250             : 
     251             : #ifndef PS_USE_NONE
     252             :     /* no ps display for stand-alone backend */
     253         341 :     if (!IsUnderPostmaster)
     254           0 :         return;
     255             : 
     256             :     /* no ps display if you didn't call save_ps_display_args() */
     257         341 :     if (!save_argv)
     258           0 :         return;
     259             : 
     260             : #ifdef PS_USE_CLOBBER_ARGV
     261             :     /* If ps_buffer is a pointer, it might still be null */
     262         341 :     if (!ps_buffer)
     263           0 :         return;
     264             : #endif
     265             : 
     266             :     /*
     267             :      * Overwrite argv[] to point at appropriate space, if needed
     268             :      */
     269             : 
     270             : #ifdef PS_USE_CHANGE_ARGV
     271             :     save_argv[0] = ps_buffer;
     272             :     save_argv[1] = NULL;
     273             : #endif                          /* PS_USE_CHANGE_ARGV */
     274             : 
     275             : #ifdef PS_USE_CLOBBER_ARGV
     276             :     {
     277             :         int         i;
     278             : 
     279             :         /* make extra argv slots point at end_of_area (a NUL) */
     280        2728 :         for (i = 1; i < save_argc; i++)
     281        2387 :             save_argv[i] = ps_buffer + ps_buffer_size;
     282             :     }
     283             : #endif                          /* PS_USE_CLOBBER_ARGV */
     284             : 
     285             :     /*
     286             :      * Make fixed prefix of ps display.
     287             :      */
     288             : 
     289             : #ifdef PS_USE_SETPROCTITLE
     290             : 
     291             :     /*
     292             :      * apparently setproctitle() already adds a `progname:' prefix to the ps
     293             :      * line
     294             :      */
     295             : #define PROGRAM_NAME_PREFIX ""
     296             : #else
     297             : #define PROGRAM_NAME_PREFIX "postgres: "
     298             : #endif
     299             : 
     300         341 :     if (*cluster_name == '\0')
     301             :     {
     302         341 :         snprintf(ps_buffer, ps_buffer_size,
     303             :                  PROGRAM_NAME_PREFIX "%s %s %s ",
     304             :                  username, dbname, host_info);
     305             :     }
     306             :     else
     307             :     {
     308           0 :         snprintf(ps_buffer, ps_buffer_size,
     309             :                  PROGRAM_NAME_PREFIX "%s: %s %s %s ",
     310             :                  cluster_name, username, dbname, host_info);
     311             :     }
     312             : 
     313         341 :     ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer);
     314             : 
     315         341 :     set_ps_display(initial_str, true);
     316             : #endif                          /* not PS_USE_NONE */
     317             : }
     318             : 
     319             : 
     320             : 
     321             : /*
     322             :  * Call this to update the ps status display to a fixed prefix plus an
     323             :  * indication of what you're currently doing passed in the argument.
     324             :  */
     325             : void
     326       55839 : set_ps_display(const char *activity, bool force)
     327             : {
     328             : #ifndef PS_USE_NONE
     329             :     /* update_process_title=off disables updates, unless force = true */
     330       55839 :     if (!force && !update_process_title)
     331           0 :         return;
     332             : 
     333             :     /* no ps display for stand-alone backend */
     334       55839 :     if (!IsUnderPostmaster)
     335        1549 :         return;
     336             : 
     337             : #ifdef PS_USE_CLOBBER_ARGV
     338             :     /* If ps_buffer is a pointer, it might still be null */
     339       54290 :     if (!ps_buffer)
     340           0 :         return;
     341             : #endif
     342             : 
     343             :     /* Update ps_buffer to contain both fixed part and activity */
     344       54290 :     strlcpy(ps_buffer + ps_buffer_fixed_size, activity,
     345             :             ps_buffer_size - ps_buffer_fixed_size);
     346       54290 :     ps_buffer_cur_len = strlen(ps_buffer);
     347             : 
     348             :     /* Transmit new setting to kernel, if necessary */
     349             : 
     350             : #ifdef PS_USE_SETPROCTITLE
     351             :     setproctitle("%s", ps_buffer);
     352             : #endif
     353             : 
     354             : #ifdef PS_USE_PSTAT
     355             :     {
     356             :         union pstun pst;
     357             : 
     358             :         pst.pst_command = ps_buffer;
     359             :         pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0);
     360             :     }
     361             : #endif                          /* PS_USE_PSTAT */
     362             : 
     363             : #ifdef PS_USE_PS_STRINGS
     364             :     PS_STRINGS->ps_nargvstr = 1;
     365             :     PS_STRINGS->ps_argvstr = ps_buffer;
     366             : #endif                          /* PS_USE_PS_STRINGS */
     367             : 
     368             : #ifdef PS_USE_CLOBBER_ARGV
     369             :     /* pad unused memory; need only clobber remainder of old status string */
     370       54290 :     if (last_status_len > ps_buffer_cur_len)
     371       27203 :         MemSet(ps_buffer + ps_buffer_cur_len, PS_PADDING,
     372             :                last_status_len - ps_buffer_cur_len);
     373       54290 :     last_status_len = ps_buffer_cur_len;
     374             : #endif                          /* PS_USE_CLOBBER_ARGV */
     375             : 
     376             : #ifdef PS_USE_WIN32
     377             :     {
     378             :         /*
     379             :          * Win32 does not support showing any changed arguments. To make it at
     380             :          * all possible to track which backend is doing what, we create a
     381             :          * named object that can be viewed with for example Process Explorer.
     382             :          */
     383             :         static HANDLE ident_handle = INVALID_HANDLE_VALUE;
     384             :         char        name[PS_BUFFER_SIZE + 32];
     385             : 
     386             :         if (ident_handle != INVALID_HANDLE_VALUE)
     387             :             CloseHandle(ident_handle);
     388             : 
     389             :         sprintf(name, "pgident(%d): %s", MyProcPid, ps_buffer);
     390             : 
     391             :         ident_handle = CreateEvent(NULL, TRUE, FALSE, name);
     392             :     }
     393             : #endif                          /* PS_USE_WIN32 */
     394             : #endif                          /* not PS_USE_NONE */
     395             : }
     396             : 
     397             : 
     398             : /*
     399             :  * Returns what's currently in the ps display, in case someone needs
     400             :  * it.  Note that only the activity part is returned.  On some platforms
     401             :  * the string will not be null-terminated, so return the effective
     402             :  * length into *displen.
     403             :  */
     404             : const char *
     405          14 : get_ps_display(int *displen)
     406             : {
     407             : #ifdef PS_USE_CLOBBER_ARGV
     408             :     /* If ps_buffer is a pointer, it might still be null */
     409          14 :     if (!ps_buffer)
     410             :     {
     411           0 :         *displen = 0;
     412           0 :         return "";
     413             :     }
     414             : #endif
     415             : 
     416          14 :     *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size);
     417             : 
     418          14 :     return ps_buffer + ps_buffer_fixed_size;
     419             : }

Generated by: LCOV version 1.11