LCOV - differential code coverage report
Current view: top level - src/backend/utils/misc - ps_status.c (source / functions) Coverage Total Hit UNC LBC UIC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 73.6 % 121 89 16 4 12 5 37 35 12 26 61 1 12
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 8 8 3 5 7 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, PostgreSQL Global Development Group
      11                 :  * various details abducted from various places
      12                 :  *--------------------------------------------------------------------
      13                 :  */
      14                 : 
      15                 : #include "postgres.h"
      16                 : 
      17                 : #include <unistd.h>
      18                 : #if defined(__darwin__)
      19                 : #include <crt_externs.h>
      20                 : #endif
      21                 : 
      22                 : #include "libpq/libpq.h"
      23                 : #include "miscadmin.h"
      24                 : #include "pgstat.h"
      25                 : #include "utils/guc.h"
      26                 : #include "utils/ps_status.h"
      27                 : 
      28                 : extern char **environ;
      29                 : 
      30                 : /* GUC variable */
      31                 : bool        update_process_title = DEFAULT_UPDATE_PROCESS_TITLE;
      32                 : 
      33                 : /*
      34                 :  * Alternative ways of updating ps display:
      35                 :  *
      36                 :  * PS_USE_SETPROCTITLE_FAST
      37                 :  *     use the function setproctitle_fast(const char *, ...)
      38                 :  *     (FreeBSD)
      39                 :  * PS_USE_SETPROCTITLE
      40                 :  *     use the function setproctitle(const char *, ...)
      41                 :  *     (other BSDs)
      42                 :  * PS_USE_CLOBBER_ARGV
      43                 :  *     write over the argv and environment area
      44                 :  *     (Linux and most SysV-like systems)
      45                 :  * PS_USE_WIN32
      46                 :  *     push the string out as the name of a Windows event
      47                 :  * PS_USE_NONE
      48                 :  *     don't update ps display
      49                 :  *     (This is the default, as it is safest.)
      50                 :  */
      51                 : #if defined(HAVE_SETPROCTITLE_FAST)
      52                 : #define PS_USE_SETPROCTITLE_FAST
      53                 : #elif defined(HAVE_SETPROCTITLE)
      54                 : #define PS_USE_SETPROCTITLE
      55                 : #elif defined(__linux__) || defined(_AIX) || defined(__sun) || defined(__darwin__)
      56                 : #define PS_USE_CLOBBER_ARGV
      57                 : #elif defined(WIN32)
      58                 : #define PS_USE_WIN32
      59                 : #else
      60                 : #define PS_USE_NONE
      61                 : #endif
      62                 : 
      63                 : 
      64                 : /* Different systems want the buffer padded differently */
      65                 : #if defined(_AIX) || defined(__linux__) || defined(__darwin__)
      66                 : #define PS_PADDING '\0'
      67                 : #else
      68                 : #define PS_PADDING ' '
      69                 : #endif
      70                 : 
      71                 : 
      72                 : #ifndef PS_USE_NONE
      73                 : 
      74                 : #ifndef PS_USE_CLOBBER_ARGV
      75                 : /* all but one option need a buffer to write their ps line in */
      76                 : #define PS_BUFFER_SIZE 256
      77                 : static char ps_buffer[PS_BUFFER_SIZE];
      78                 : static const size_t ps_buffer_size = PS_BUFFER_SIZE;
      79                 : #else                           /* PS_USE_CLOBBER_ARGV */
      80                 : static char *ps_buffer;         /* will point to argv area */
      81                 : static size_t ps_buffer_size;   /* space determined at run time */
      82                 : static size_t last_status_len;  /* use to minimize length of clobber */
      83                 : #endif                          /* PS_USE_CLOBBER_ARGV */
      84                 : 
      85                 : static size_t ps_buffer_cur_len;    /* nominal strlen(ps_buffer) */
      86                 : 
      87                 : static size_t ps_buffer_fixed_size; /* size of the constant prefix */
      88                 : 
      89                 : /*
      90                 :  * Length of ps_buffer before the suffix was appeneded to the end, or 0 if we
      91                 :  * didn't set a suffix.
      92                 :  */
      93                 : static size_t ps_buffer_nosuffix_len;
      94                 : 
      95                 : static void flush_ps_display(void);
      96                 : 
      97                 : #endif                          /* not PS_USE_NONE */
      98                 : 
      99                 : /* save the original argv[] location here */
     100                 : static int  save_argc;
     101                 : static char **save_argv;
     102                 : 
     103                 : 
     104                 : /*
     105 ECB             :  * Call this early in startup to save the original argc/argv values.
     106                 :  * If needed, we make a copy of the original argv[] array to preserve it
     107                 :  * from being clobbered by subsequent ps_display actions.
     108                 :  *
     109                 :  * (The original argv[] will not be overwritten by this routine, but may be
     110                 :  * overwritten during init_ps_display.  Also, the physical location of the
     111                 :  * environment strings may be moved, so this should be called before any code
     112                 :  * that might try to hang onto a getenv() result.)
     113                 :  *
     114                 :  * Note that in case of failure this cannot call elog() as that is not
     115                 :  * initialized yet.  We rely on write_stderr() instead.
     116                 :  */
     117                 : char      **
     118 GIC        2619 : save_ps_display_args(int argc, char **argv)
     119                 : {
     120            2619 :     save_argc = argc;
     121            2619 :     save_argv = argv;
     122                 : 
     123                 : #if defined(PS_USE_CLOBBER_ARGV)
     124 ECB             : 
     125                 :     /*
     126                 :      * If we're going to overwrite the argv area, count the available space.
     127                 :      * Also move the environment to make additional room.
     128                 :      */
     129                 :     {
     130 CBC        2619 :         char       *end_of_area = NULL;
     131                 :         char      **new_environ;
     132 EUB             :         int         i;
     133                 : 
     134                 :         /*
     135                 :          * check for contiguous argv strings
     136                 :          */
     137 GIC       19862 :         for (i = 0; i < argc; i++)
     138                 :         {
     139           17243 :             if (i == 0 || end_of_area + 1 == argv[i])
     140 CBC       17243 :                 end_of_area = argv[i] + strlen(argv[i]);
     141                 :         }
     142 ECB             : 
     143 CBC        2619 :         if (end_of_area == NULL)    /* probably can't happen? */
     144                 :         {
     145 UIC           0 :             ps_buffer = NULL;
     146 LBC           0 :             ps_buffer_size = 0;
     147               0 :             return argv;
     148                 :         }
     149                 : 
     150                 :         /*
     151                 :          * check for contiguous environ strings following argv
     152 ECB             :          */
     153 CBC      241070 :         for (i = 0; environ[i] != NULL; i++)
     154                 :         {
     155 GBC      238451 :             if (end_of_area + 1 == environ[i])
     156          238451 :                 end_of_area = environ[i] + strlen(environ[i]);
     157                 :         }
     158 ECB             : 
     159 GIC        2619 :         ps_buffer = argv[0];
     160 CBC        2619 :         last_status_len = ps_buffer_size = end_of_area - argv[0];
     161 ECB             : 
     162                 :         /*
     163 EUB             :          * move the environment out of the way
     164                 :          */
     165 GIC        2619 :         new_environ = (char **) malloc((i + 1) * sizeof(char *));
     166            2619 :         if (!new_environ)
     167 ECB             :         {
     168 LBC           0 :             write_stderr("out of memory\n");
     169 UIC           0 :             exit(1);
     170                 :         }
     171 GIC      241070 :         for (i = 0; environ[i] != NULL; i++)
     172                 :         {
     173          238451 :             new_environ[i] = strdup(environ[i]);
     174          238451 :             if (!new_environ[i])
     175                 :             {
     176 UIC           0 :                 write_stderr("out of memory\n");
     177               0 :                 exit(1);
     178                 :             }
     179                 :         }
     180 GIC        2619 :         new_environ[i] = NULL;
     181            2619 :         environ = new_environ;
     182                 :     }
     183                 : 
     184 ECB             :     /*
     185                 :      * If we're going to change the original argv[] then make a copy for
     186                 :      * argument parsing purposes.
     187 EUB             :      *
     188                 :      * (NB: do NOT think to remove the copying of argv[], even though
     189                 :      * postmaster.c finishes looking at argv[] long before we ever consider
     190 ECB             :      * changing the ps display.  On some platforms, getopt() keeps pointers
     191                 :      * into the argv array, and will get horribly confused when it is
     192                 :      * re-called to analyze a subprocess' argument string if the argv storage
     193                 :      * has been clobbered meanwhile.  Other platforms have other dependencies
     194                 :      * on argv[].
     195 EUB             :      */
     196                 :     {
     197                 :         char      **new_argv;
     198                 :         int         i;
     199 ECB             : 
     200 GIC        2619 :         new_argv = (char **) malloc((argc + 1) * sizeof(char *));
     201            2619 :         if (!new_argv)
     202                 :         {
     203 UIC           0 :             write_stderr("out of memory\n");
     204               0 :             exit(1);
     205                 :         }
     206 GIC       19862 :         for (i = 0; i < argc; i++)
     207                 :         {
     208           17243 :             new_argv[i] = strdup(argv[i]);
     209           17243 :             if (!new_argv[i])
     210 ECB             :             {
     211 UIC           0 :                 write_stderr("out of memory\n");
     212               0 :                 exit(1);
     213                 :             }
     214 ECB             :         }
     215 GIC        2619 :         new_argv[argc] = NULL;
     216                 : 
     217                 : #if defined(__darwin__)
     218                 : 
     219                 :         /*
     220                 :          * macOS has a static copy of the argv pointer, which we may fix like
     221                 :          * so:
     222                 :          */
     223                 :         *_NSGetArgv() = new_argv;
     224                 : #endif
     225                 : 
     226 CBC        2619 :         argv = new_argv;
     227                 :     }
     228                 : #endif                          /* PS_USE_CLOBBER_ARGV */
     229                 : 
     230 GIC        2619 :     return argv;
     231                 : }
     232 ECB             : 
     233                 : /*
     234                 :  * Call this once during subprocess startup to set the identification
     235                 :  * values.
     236                 :  *
     237                 :  * If fixed_part is NULL, a default will be obtained from MyBackendType.
     238                 :  *
     239 EUB             :  * At this point, the original argv[] array may be overwritten.
     240                 :  */
     241                 : void
     242 CBC       12761 : init_ps_display(const char *fixed_part)
     243 EUB             : {
     244                 : #ifndef PS_USE_NONE
     245                 :     bool        save_update_process_title;
     246                 : #endif
     247 ECB             : 
     248 GBC       12761 :     Assert(fixed_part || MyBackendType);
     249 GIC       12761 :     if (!fixed_part)
     250            2111 :         fixed_part = GetBackendTypeDesc(MyBackendType);
     251 ECB             : 
     252                 : #ifndef PS_USE_NONE
     253                 :     /* no ps display for stand-alone backend */
     254 GIC       12761 :     if (!IsUnderPostmaster)
     255 UIC           0 :         return;
     256                 : 
     257                 :     /* no ps display if you didn't call save_ps_display_args() */
     258 GIC       12761 :     if (!save_argv)
     259 UIC           0 :         return;
     260                 : 
     261                 : #ifdef PS_USE_CLOBBER_ARGV
     262                 :     /* If ps_buffer is a pointer, it might still be null */
     263 GIC       12761 :     if (!ps_buffer)
     264 UIC           0 :         return;
     265                 : 
     266                 :     /* make extra argv slots point at end_of_area (a NUL) */
     267 GNC       62267 :     for (int i = 1; i < save_argc; i++)
     268           49506 :         save_argv[i] = ps_buffer + ps_buffer_size;
     269                 : #endif                          /* PS_USE_CLOBBER_ARGV */
     270                 : 
     271                 :     /*
     272                 :      * Make fixed prefix of ps display.
     273 ECB             :      */
     274                 : 
     275                 : #if defined(PS_USE_SETPROCTITLE) || defined(PS_USE_SETPROCTITLE_FAST)
     276                 : 
     277                 :     /*
     278                 :      * apparently setproctitle() already adds a `progname:' prefix to the ps
     279                 :      * line
     280                 :      */
     281                 : #define PROGRAM_NAME_PREFIX ""
     282                 : #else
     283                 : #define PROGRAM_NAME_PREFIX "postgres: "
     284                 : #endif
     285                 : 
     286 GIC       12761 :     if (*cluster_name == '\0')
     287 ECB             :     {
     288 GIC        2522 :         snprintf(ps_buffer, ps_buffer_size,
     289                 :                  PROGRAM_NAME_PREFIX "%s ",
     290 ECB             :                  fixed_part);
     291 EUB             :     }
     292                 :     else
     293                 :     {
     294 CBC       10239 :         snprintf(ps_buffer, ps_buffer_size,
     295 ECB             :                  PROGRAM_NAME_PREFIX "%s: %s ",
     296                 :                  cluster_name, fixed_part);
     297                 :     }
     298                 : 
     299 CBC       12761 :     ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer);
     300 EUB             : 
     301                 :     /*
     302                 :      * On the first run, force the update.
     303 ECB             :      */
     304 GIC       12761 :     save_update_process_title = update_process_title;
     305           12761 :     update_process_title = true;
     306           12761 :     set_ps_display("");
     307           12761 :     update_process_title = save_update_process_title;
     308                 : #endif                          /* not PS_USE_NONE */
     309                 : }
     310                 : 
     311 EUB             : #ifndef PS_USE_NONE
     312                 : /*
     313                 :  * update_ps_display_precheck
     314                 :  *      Helper function to determine if updating the process title is
     315                 :  *      something that we need to do.
     316                 :  */
     317                 : static bool
     318 GNC     1066010 : update_ps_display_precheck(void)
     319                 : {
     320                 :     /* update_process_title=off disables updates */
     321 GIC     1066010 :     if (!update_process_title)
     322 UNC           0 :         return false;
     323 EUB             : 
     324                 :     /* no ps display for stand-alone backend */
     325 CBC     1066010 :     if (!IsUnderPostmaster)
     326 GNC      453075 :         return false;
     327 ECB             : 
     328                 : #ifdef PS_USE_CLOBBER_ARGV
     329                 :     /* If ps_buffer is a pointer, it might still be null */
     330 CBC      612935 :     if (!ps_buffer)
     331 UNC           0 :         return false;
     332                 : #endif
     333 EUB             : 
     334 GNC      612935 :     return true;
     335                 : }
     336                 : #endif                          /* not PS_USE_NONE */
     337                 : 
     338                 : /*
     339                 :  * set_ps_display_suffix
     340                 :  *      Adjust the process title to append 'suffix' onto the end with a space
     341                 :  *      between it and the current process title.
     342                 :  */
     343                 : void
     344            1068 : set_ps_display_suffix(const char *suffix)
     345                 : {
     346                 : #ifndef PS_USE_NONE
     347                 :     size_t      len;
     348                 : 
     349                 :     /* first, check if we need to update the process title */
     350            1068 :     if (!update_ps_display_precheck())
     351 UNC           0 :         return;
     352                 : 
     353                 :     /* if there's already a suffix, overwrite it */
     354 GNC        1068 :     if (ps_buffer_nosuffix_len > 0)
     355 UNC           0 :         ps_buffer_cur_len = ps_buffer_nosuffix_len;
     356                 :     else
     357 GNC        1068 :         ps_buffer_nosuffix_len = ps_buffer_cur_len;
     358                 : 
     359            1068 :     len = strlen(suffix);
     360                 : 
     361                 :     /* check if we have enough space to append the suffix */
     362            1068 :     if (ps_buffer_cur_len + len + 1 >= ps_buffer_size)
     363                 :     {
     364                 :         /* not enough space.  Check the buffer isn't full already */
     365 UNC           0 :         if (ps_buffer_cur_len < ps_buffer_size - 1)
     366                 :         {
     367                 :             /* append a space before the suffix */
     368               0 :             ps_buffer[ps_buffer_cur_len++] = ' ';
     369                 : 
     370                 :             /* just add what we can and fill the ps_buffer */
     371               0 :             memcpy(ps_buffer + ps_buffer_cur_len, suffix,
     372               0 :                    ps_buffer_size - ps_buffer_cur_len - 1);
     373               0 :             ps_buffer[ps_buffer_size - 1] = '\0';
     374               0 :             ps_buffer_cur_len = ps_buffer_size - 1;
     375                 :         }
     376                 :     }
     377                 :     else
     378                 :     {
     379 GNC        1068 :         ps_buffer[ps_buffer_cur_len++] = ' ';
     380            1068 :         memcpy(ps_buffer + ps_buffer_cur_len, suffix, len + 1);
     381            1068 :         ps_buffer_cur_len = ps_buffer_cur_len + len;
     382                 :     }
     383                 : 
     384            1068 :     Assert(strlen(ps_buffer) == ps_buffer_cur_len);
     385                 : 
     386                 :     /* and set the new title */
     387            1068 :     flush_ps_display();
     388                 : #endif                          /* not PS_USE_NONE */
     389                 : }
     390                 : 
     391                 : /*
     392                 :  * set_ps_display_remove_suffix
     393                 :  *      Remove the process display suffix added by set_ps_display_suffix
     394                 :  */
     395                 : void
     396            1063 : set_ps_display_remove_suffix(void)
     397                 : {
     398                 : #ifndef PS_USE_NONE
     399                 :     /* first, check if we need to update the process title */
     400            1063 :     if (!update_ps_display_precheck())
     401 UNC           0 :         return;
     402                 : 
     403                 :     /* check we added a suffix */
     404 GNC        1063 :     if (ps_buffer_nosuffix_len == 0)
     405 UNC           0 :         return;                 /* no suffix */
     406                 : 
     407                 :     /* remove the suffix from ps_buffer */
     408 GNC        1063 :     ps_buffer[ps_buffer_nosuffix_len] = '\0';
     409            1063 :     ps_buffer_cur_len = ps_buffer_nosuffix_len;
     410            1063 :     ps_buffer_nosuffix_len = 0;
     411                 : 
     412            1063 :     Assert(ps_buffer_cur_len == strlen(ps_buffer));
     413                 : 
     414                 :     /* and set the new title */
     415            1063 :     flush_ps_display();
     416                 : #endif                          /* not PS_USE_NONE */
     417                 : }
     418                 : 
     419                 : /*
     420                 :  * Call this to update the ps status display to a fixed prefix plus an
     421                 :  * indication of what you're currently doing passed in the argument.
     422                 :  *
     423                 :  * 'len' must be the same as strlen(activity)
     424                 :  */
     425                 : void
     426         1063879 : set_ps_display_with_len(const char *activity, size_t len)
     427                 : {
     428         1063879 :     Assert(strlen(activity) == len);
     429                 : 
     430                 : #ifndef PS_USE_NONE
     431                 :     /* first, check if we need to update the process title */
     432         1063879 :     if (!update_ps_display_precheck())
     433          453075 :         return;
     434                 : 
     435                 :     /* wipe out any suffix when the title is completely changed */
     436          610804 :     ps_buffer_nosuffix_len = 0;
     437                 : 
     438                 :     /* Update ps_buffer to contain both fixed part and activity */
     439          610804 :     if (ps_buffer_fixed_size + len >= ps_buffer_size)
     440                 :     {
     441                 :         /* handle the case where ps_buffer doesn't have enough space */
     442 UNC           0 :         memcpy(ps_buffer + ps_buffer_fixed_size, activity,
     443               0 :                ps_buffer_size - ps_buffer_fixed_size - 1);
     444               0 :         ps_buffer[ps_buffer_size - 1] = '\0';
     445               0 :         ps_buffer_cur_len = ps_buffer_size - 1;
     446                 :     }
     447                 :     else
     448                 :     {
     449 GNC      610804 :         memcpy(ps_buffer + ps_buffer_fixed_size, activity, len + 1);
     450          610804 :         ps_buffer_cur_len = ps_buffer_fixed_size + len;
     451                 :     }
     452          610804 :     Assert(strlen(ps_buffer) == ps_buffer_cur_len);
     453                 : 
     454 EUB             :     /* Transmit new setting to kernel, if necessary */
     455 GNC      610804 :     flush_ps_display();
     456                 : #endif                          /* not PS_USE_NONE */
     457                 : }
     458 EUB             : 
     459                 : #ifndef PS_USE_NONE
     460                 : static void
     461 GNC      612935 : flush_ps_display(void)
     462                 : {
     463 EUB             : #ifdef PS_USE_SETPROCTITLE
     464                 :     setproctitle("%s", ps_buffer);
     465                 : #elif defined(PS_USE_SETPROCTITLE_FAST)
     466                 :     setproctitle_fast("%s", ps_buffer);
     467                 : #endif
     468                 : 
     469                 : #ifdef PS_USE_CLOBBER_ARGV
     470                 :     /* pad unused memory; need only clobber remainder of old status string */
     471 GIC      612935 :     if (last_status_len > ps_buffer_cur_len)
     472 CBC      279726 :         MemSet(ps_buffer + ps_buffer_cur_len, PS_PADDING,
     473                 :                last_status_len - ps_buffer_cur_len);
     474 GIC      612935 :     last_status_len = ps_buffer_cur_len;
     475                 : #endif                          /* PS_USE_CLOBBER_ARGV */
     476 ECB             : 
     477 EUB             : #ifdef PS_USE_WIN32
     478                 :     {
     479                 :         /*
     480 ECB             :          * Win32 does not support showing any changed arguments. To make it at
     481 EUB             :          * all possible to track which backend is doing what, we create a
     482                 :          * named object that can be viewed with for example Process Explorer.
     483                 :          */
     484 ECB             :         static HANDLE ident_handle = INVALID_HANDLE_VALUE;
     485                 :         char        name[PS_BUFFER_SIZE + 32];
     486                 : 
     487                 :         if (ident_handle != INVALID_HANDLE_VALUE)
     488                 :             CloseHandle(ident_handle);
     489                 : 
     490                 :         sprintf(name, "pgident(%d): %s", MyProcPid, ps_buffer);
     491                 : 
     492                 :         ident_handle = CreateEvent(NULL, TRUE, FALSE, name);
     493                 :     }
     494                 : #endif                          /* PS_USE_WIN32 */
     495 GIC      612935 : }
     496                 : #endif                          /* not PS_USE_NONE */
     497                 : 
     498                 : /*
     499                 :  * Returns what's currently in the ps display, in case someone needs
     500                 :  * it.  Note that only the activity part is returned.  On some platforms
     501 ECB             :  * the string will not be null-terminated, so return the effective
     502                 :  * length into *displen.
     503                 :  */
     504                 : const char *
     505 GIC          18 : get_ps_display(int *displen)
     506                 : {
     507 ECB             : #ifdef PS_USE_CLOBBER_ARGV
     508                 :     /* If ps_buffer is a pointer, it might still be null */
     509 GIC          18 :     if (!ps_buffer)
     510                 :     {
     511 LBC           0 :         *displen = 0;
     512 UIC           0 :         return "";
     513                 :     }
     514 ECB             : #endif
     515                 : 
     516                 : #ifndef PS_USE_NONE
     517 GBC          18 :     *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size);
     518 EUB             : 
     519 GBC          18 :     return ps_buffer + ps_buffer_fixed_size;
     520 EUB             : #else
     521                 :     *displen = 0;
     522                 :     return "";
     523                 : #endif
     524 ECB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a