Header And Logo

PostgreSQL
| The world's most advanced open source database.

ps_status.c

Go to the documentation of this file.
00001 /*--------------------------------------------------------------------
00002  * ps_status.c
00003  *
00004  * Routines to support changing the ps display of PostgreSQL backends
00005  * to contain some useful information. Mechanism differs wildly across
00006  * platforms.
00007  *
00008  * src/backend/utils/misc/ps_status.c
00009  *
00010  * Copyright (c) 2000-2013, PostgreSQL Global Development Group
00011  * various details abducted from various places
00012  *--------------------------------------------------------------------
00013  */
00014 
00015 #include "postgres.h"
00016 
00017 #include <unistd.h>
00018 #ifdef HAVE_SYS_PSTAT_H
00019 #include <sys/pstat.h>          /* for HP-UX */
00020 #endif
00021 #ifdef HAVE_PS_STRINGS
00022 #include <machine/vmparam.h>    /* for old BSD */
00023 #include <sys/exec.h>
00024 #endif
00025 #if defined(__darwin__)
00026 #include <crt_externs.h>
00027 #endif
00028 
00029 #include "libpq/libpq.h"
00030 #include "miscadmin.h"
00031 #include "utils/ps_status.h"
00032 
00033 extern char **environ;
00034 bool        update_process_title = true;
00035 
00036 
00037 /*
00038  * Alternative ways of updating ps display:
00039  *
00040  * PS_USE_SETPROCTITLE
00041  *     use the function setproctitle(const char *, ...)
00042  *     (newer BSD systems)
00043  * PS_USE_PSTAT
00044  *     use the pstat(PSTAT_SETCMD, )
00045  *     (HPUX)
00046  * PS_USE_PS_STRINGS
00047  *     assign PS_STRINGS->ps_argvstr = "string"
00048  *     (some BSD systems)
00049  * PS_USE_CHANGE_ARGV
00050  *     assign argv[0] = "string"
00051  *     (some other BSD systems)
00052  * PS_USE_CLOBBER_ARGV
00053  *     write over the argv and environment area
00054  *     (Linux and most SysV-like systems)
00055  * PS_USE_WIN32
00056  *     push the string out as the name of a Windows event
00057  * PS_USE_NONE
00058  *     don't update ps display
00059  *     (This is the default, as it is safest.)
00060  */
00061 #if defined(HAVE_SETPROCTITLE)
00062 #define PS_USE_SETPROCTITLE
00063 #elif defined(HAVE_PSTAT) && defined(PSTAT_SETCMD)
00064 #define PS_USE_PSTAT
00065 #elif defined(HAVE_PS_STRINGS)
00066 #define PS_USE_PS_STRINGS
00067 #elif (defined(BSD) || defined(__hurd__)) && !defined(__darwin__)
00068 #define PS_USE_CHANGE_ARGV
00069 #elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__ksr__) || defined(__osf__) || defined(__svr5__) || defined(__darwin__)
00070 #define PS_USE_CLOBBER_ARGV
00071 #elif defined(WIN32)
00072 #define PS_USE_WIN32
00073 #else
00074 #define PS_USE_NONE
00075 #endif
00076 
00077 
00078 /* Different systems want the buffer padded differently */
00079 #if defined(_AIX) || defined(__linux__) || defined(__darwin__)
00080 #define PS_PADDING '\0'
00081 #else
00082 #define PS_PADDING ' '
00083 #endif
00084 
00085 
00086 #ifndef PS_USE_CLOBBER_ARGV
00087 /* all but one option need a buffer to write their ps line in */
00088 #define PS_BUFFER_SIZE 256
00089 static char ps_buffer[PS_BUFFER_SIZE];
00090 static const size_t ps_buffer_size = PS_BUFFER_SIZE;
00091 #else                           /* PS_USE_CLOBBER_ARGV */
00092 static char *ps_buffer;         /* will point to argv area */
00093 static size_t ps_buffer_size;   /* space determined at run time */
00094 static size_t last_status_len;  /* use to minimize length of clobber */
00095 #endif   /* PS_USE_CLOBBER_ARGV */
00096 
00097 static size_t ps_buffer_cur_len;    /* nominal strlen(ps_buffer) */
00098 
00099 static size_t ps_buffer_fixed_size;     /* size of the constant prefix */
00100 
00101 /* save the original argv[] location here */
00102 static int  save_argc;
00103 static char **save_argv;
00104 
00105 
00106 /*
00107  * Call this early in startup to save the original argc/argv values.
00108  * If needed, we make a copy of the original argv[] array to preserve it
00109  * from being clobbered by subsequent ps_display actions.
00110  *
00111  * (The original argv[] will not be overwritten by this routine, but may be
00112  * overwritten during init_ps_display.  Also, the physical location of the
00113  * environment strings may be moved, so this should be called before any code
00114  * that might try to hang onto a getenv() result.)
00115  */
00116 char      **
00117 save_ps_display_args(int argc, char **argv)
00118 {
00119     save_argc = argc;
00120     save_argv = argv;
00121 
00122 #if defined(PS_USE_CLOBBER_ARGV)
00123 
00124     /*
00125      * If we're going to overwrite the argv area, count the available space.
00126      * Also move the environment to make additional room.
00127      */
00128     {
00129         char       *end_of_area = NULL;
00130         char      **new_environ;
00131         int         i;
00132 
00133         /*
00134          * check for contiguous argv strings
00135          */
00136         for (i = 0; i < argc; i++)
00137         {
00138             if (i == 0 || end_of_area + 1 == argv[i])
00139                 end_of_area = argv[i] + strlen(argv[i]);
00140         }
00141 
00142         if (end_of_area == NULL)    /* probably can't happen? */
00143         {
00144             ps_buffer = NULL;
00145             ps_buffer_size = 0;
00146             return argv;
00147         }
00148 
00149         /*
00150          * check for contiguous environ strings following argv
00151          */
00152         for (i = 0; environ[i] != NULL; i++)
00153         {
00154             if (end_of_area + 1 == environ[i])
00155                 end_of_area = environ[i] + strlen(environ[i]);
00156         }
00157 
00158         ps_buffer = argv[0];
00159         last_status_len = ps_buffer_size = end_of_area - argv[0];
00160 
00161         /*
00162          * move the environment out of the way
00163          */
00164         new_environ = (char **) malloc((i + 1) * sizeof(char *));
00165         for (i = 0; environ[i] != NULL; i++)
00166             new_environ[i] = strdup(environ[i]);
00167         new_environ[i] = NULL;
00168         environ = new_environ;
00169     }
00170 #endif   /* PS_USE_CLOBBER_ARGV */
00171 
00172 #if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV)
00173 
00174     /*
00175      * If we're going to change the original argv[] then make a copy for
00176      * argument parsing purposes.
00177      *
00178      * (NB: do NOT think to remove the copying of argv[], even though
00179      * postmaster.c finishes looking at argv[] long before we ever consider
00180      * changing the ps display.  On some platforms, getopt() keeps pointers
00181      * into the argv array, and will get horribly confused when it is
00182      * re-called to analyze a subprocess' argument string if the argv storage
00183      * has been clobbered meanwhile.  Other platforms have other dependencies
00184      * on argv[].
00185      */
00186     {
00187         char      **new_argv;
00188         int         i;
00189 
00190         new_argv = (char **) malloc((argc + 1) * sizeof(char *));
00191         for (i = 0; i < argc; i++)
00192             new_argv[i] = strdup(argv[i]);
00193         new_argv[argc] = NULL;
00194 
00195 #if defined(__darwin__)
00196 
00197         /*
00198          * Darwin (and perhaps other NeXT-derived platforms?) has a static
00199          * copy of the argv pointer, which we may fix like so:
00200          */
00201         *_NSGetArgv() = new_argv;
00202 #endif
00203 
00204         argv = new_argv;
00205     }
00206 #endif   /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */
00207 
00208     return argv;
00209 }
00210 
00211 /*
00212  * Call this once during subprocess startup to set the identification
00213  * values.  At this point, the original argv[] array may be overwritten.
00214  */
00215 void
00216 init_ps_display(const char *username, const char *dbname,
00217                 const char *host_info, const char *initial_str)
00218 {
00219     Assert(username);
00220     Assert(dbname);
00221     Assert(host_info);
00222 
00223 #ifndef PS_USE_NONE
00224     /* no ps display for stand-alone backend */
00225     if (!IsUnderPostmaster)
00226         return;
00227 
00228     /* no ps display if you didn't call save_ps_display_args() */
00229     if (!save_argv)
00230         return;
00231 
00232 #ifdef PS_USE_CLOBBER_ARGV
00233     /* If ps_buffer is a pointer, it might still be null */
00234     if (!ps_buffer)
00235         return;
00236 #endif
00237 
00238     /*
00239      * Overwrite argv[] to point at appropriate space, if needed
00240      */
00241 
00242 #ifdef PS_USE_CHANGE_ARGV
00243     save_argv[0] = ps_buffer;
00244     save_argv[1] = NULL;
00245 #endif   /* PS_USE_CHANGE_ARGV */
00246 
00247 #ifdef PS_USE_CLOBBER_ARGV
00248     {
00249         int         i;
00250 
00251         /* make extra argv slots point at end_of_area (a NUL) */
00252         for (i = 1; i < save_argc; i++)
00253             save_argv[i] = ps_buffer + ps_buffer_size;
00254     }
00255 #endif   /* PS_USE_CLOBBER_ARGV */
00256 
00257     /*
00258      * Make fixed prefix of ps display.
00259      */
00260 
00261 #ifdef PS_USE_SETPROCTITLE
00262 
00263     /*
00264      * apparently setproctitle() already adds a `progname:' prefix to the ps
00265      * line
00266      */
00267     snprintf(ps_buffer, ps_buffer_size,
00268              "%s %s %s ",
00269              username, dbname, host_info);
00270 #else
00271     snprintf(ps_buffer, ps_buffer_size,
00272              "postgres: %s %s %s ",
00273              username, dbname, host_info);
00274 #endif
00275 
00276     ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer);
00277 
00278     set_ps_display(initial_str, true);
00279 #endif   /* not PS_USE_NONE */
00280 }
00281 
00282 
00283 
00284 /*
00285  * Call this to update the ps status display to a fixed prefix plus an
00286  * indication of what you're currently doing passed in the argument.
00287  */
00288 void
00289 set_ps_display(const char *activity, bool force)
00290 {
00291 #ifndef PS_USE_NONE
00292     /* update_process_title=off disables updates, unless force = true */
00293     if (!force && !update_process_title)
00294         return;
00295 
00296     /* no ps display for stand-alone backend */
00297     if (!IsUnderPostmaster)
00298         return;
00299 
00300 #ifdef PS_USE_CLOBBER_ARGV
00301     /* If ps_buffer is a pointer, it might still be null */
00302     if (!ps_buffer)
00303         return;
00304 #endif
00305 
00306     /* Update ps_buffer to contain both fixed part and activity */
00307     strlcpy(ps_buffer + ps_buffer_fixed_size, activity,
00308             ps_buffer_size - ps_buffer_fixed_size);
00309     ps_buffer_cur_len = strlen(ps_buffer);
00310 
00311     /* Transmit new setting to kernel, if necessary */
00312 
00313 #ifdef PS_USE_SETPROCTITLE
00314     setproctitle("%s", ps_buffer);
00315 #endif
00316 
00317 #ifdef PS_USE_PSTAT
00318     {
00319         union pstun pst;
00320 
00321         pst.pst_command = ps_buffer;
00322         pstat(PSTAT_SETCMD, pst, ps_buffer_cur_len, 0, 0);
00323     }
00324 #endif   /* PS_USE_PSTAT */
00325 
00326 #ifdef PS_USE_PS_STRINGS
00327     PS_STRINGS->ps_nargvstr = 1;
00328     PS_STRINGS->ps_argvstr = ps_buffer;
00329 #endif   /* PS_USE_PS_STRINGS */
00330 
00331 #ifdef PS_USE_CLOBBER_ARGV
00332     /* pad unused memory; need only clobber remainder of old status string */
00333     if (last_status_len > ps_buffer_cur_len)
00334         MemSet(ps_buffer + ps_buffer_cur_len, PS_PADDING,
00335                last_status_len - ps_buffer_cur_len);
00336     last_status_len = ps_buffer_cur_len;
00337 #endif   /* PS_USE_CLOBBER_ARGV */
00338 
00339 #ifdef PS_USE_WIN32
00340     {
00341         /*
00342          * Win32 does not support showing any changed arguments. To make it at
00343          * all possible to track which backend is doing what, we create a
00344          * named object that can be viewed with for example Process Explorer.
00345          */
00346         static HANDLE ident_handle = INVALID_HANDLE_VALUE;
00347         char        name[PS_BUFFER_SIZE + 32];
00348 
00349         if (ident_handle != INVALID_HANDLE_VALUE)
00350             CloseHandle(ident_handle);
00351 
00352         sprintf(name, "pgident(%d): %s", MyProcPid, ps_buffer);
00353 
00354         ident_handle = CreateEvent(NULL, TRUE, FALSE, name);
00355     }
00356 #endif   /* PS_USE_WIN32 */
00357 #endif   /* not PS_USE_NONE */
00358 }
00359 
00360 
00361 /*
00362  * Returns what's currently in the ps display, in case someone needs
00363  * it.  Note that only the activity part is returned.  On some platforms
00364  * the string will not be null-terminated, so return the effective
00365  * length into *displen.
00366  */
00367 const char *
00368 get_ps_display(int *displen)
00369 {
00370 #ifdef PS_USE_CLOBBER_ARGV
00371     /* If ps_buffer is a pointer, it might still be null */
00372     if (!ps_buffer)
00373     {
00374         *displen = 0;
00375         return "";
00376     }
00377 #endif
00378 
00379     *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size);
00380 
00381     return ps_buffer + ps_buffer_fixed_size;
00382 }