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

Generated by: LCOV version 1.13