PostgreSQL Source Code  git master
ps_status.c
Go to the documentation of this file.
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 */
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 appended 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  * 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 save_ps_display_args(int argc, char **argv)
119 {
120  save_argc = argc;
121  save_argv = argv;
122 
123 #if defined(PS_USE_CLOBBER_ARGV)
124 
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  char *end_of_area = NULL;
131  char **new_environ;
132  int i;
133 
134  /*
135  * check for contiguous argv strings
136  */
137  for (i = 0; i < argc; i++)
138  {
139  if (i == 0 || end_of_area + 1 == argv[i])
140  end_of_area = argv[i] + strlen(argv[i]);
141  }
142 
143  if (end_of_area == NULL) /* probably can't happen? */
144  {
145  ps_buffer = NULL;
146  ps_buffer_size = 0;
147  return argv;
148  }
149 
150  /*
151  * check for contiguous environ strings following argv
152  */
153  for (i = 0; environ[i] != NULL; i++)
154  {
155  if (end_of_area + 1 == environ[i])
156  end_of_area = environ[i] + strlen(environ[i]);
157  }
158 
159  ps_buffer = argv[0];
160  last_status_len = ps_buffer_size = end_of_area - argv[0];
161 
162  /*
163  * move the environment out of the way
164  */
165  new_environ = (char **) malloc((i + 1) * sizeof(char *));
166  if (!new_environ)
167  {
168  write_stderr("out of memory\n");
169  exit(1);
170  }
171  for (i = 0; environ[i] != NULL; i++)
172  {
173  new_environ[i] = strdup(environ[i]);
174  if (!new_environ[i])
175  {
176  write_stderr("out of memory\n");
177  exit(1);
178  }
179  }
180  new_environ[i] = NULL;
181  environ = new_environ;
182  }
183 
184  /*
185  * If we're going to change the original argv[] then make a copy for
186  * argument parsing purposes.
187  *
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  * 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  */
196  {
197  char **new_argv;
198  int i;
199 
200  new_argv = (char **) malloc((argc + 1) * sizeof(char *));
201  if (!new_argv)
202  {
203  write_stderr("out of memory\n");
204  exit(1);
205  }
206  for (i = 0; i < argc; i++)
207  {
208  new_argv[i] = strdup(argv[i]);
209  if (!new_argv[i])
210  {
211  write_stderr("out of memory\n");
212  exit(1);
213  }
214  }
215  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  argv = new_argv;
227  }
228 #endif /* PS_USE_CLOBBER_ARGV */
229 
230  return argv;
231 }
232 
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  * At this point, the original argv[] array may be overwritten.
240  */
241 void
242 init_ps_display(const char *fixed_part)
243 {
244 #ifndef PS_USE_NONE
245  bool save_update_process_title;
246 #endif
247 
248  Assert(fixed_part || MyBackendType);
249  if (!fixed_part)
250  fixed_part = GetBackendTypeDesc(MyBackendType);
251 
252 #ifndef PS_USE_NONE
253  /* no ps display for stand-alone backend */
254  if (!IsUnderPostmaster)
255  return;
256 
257  /* no ps display if you didn't call save_ps_display_args() */
258  if (!save_argv)
259  return;
260 
261 #ifdef PS_USE_CLOBBER_ARGV
262  /* If ps_buffer is a pointer, it might still be null */
263  if (!ps_buffer)
264  return;
265 
266  /* make extra argv slots point at end_of_area (a NUL) */
267  for (int i = 1; i < save_argc; i++)
268  save_argv[i] = ps_buffer + ps_buffer_size;
269 #endif /* PS_USE_CLOBBER_ARGV */
270 
271  /*
272  * Make fixed prefix of ps display.
273  */
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  if (*cluster_name == '\0')
287  {
288  snprintf(ps_buffer, ps_buffer_size,
289  PROGRAM_NAME_PREFIX "%s ",
290  fixed_part);
291  }
292  else
293  {
294  snprintf(ps_buffer, ps_buffer_size,
295  PROGRAM_NAME_PREFIX "%s: %s ",
296  cluster_name, fixed_part);
297  }
298 
299  ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer);
300 
301  /*
302  * On the first run, force the update.
303  */
304  save_update_process_title = update_process_title;
305  update_process_title = true;
306  set_ps_display("");
307  update_process_title = save_update_process_title;
308 #endif /* not PS_USE_NONE */
309 }
310 
311 #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 update_ps_display_precheck(void)
319 {
320  /* update_process_title=off disables updates */
322  return false;
323 
324  /* no ps display for stand-alone backend */
325  if (!IsUnderPostmaster)
326  return false;
327 
328 #ifdef PS_USE_CLOBBER_ARGV
329  /* If ps_buffer is a pointer, it might still be null */
330  if (!ps_buffer)
331  return false;
332 #endif
333 
334  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 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  if (!update_ps_display_precheck())
351  return;
352 
353  /* if there's already a suffix, overwrite it */
354  if (ps_buffer_nosuffix_len > 0)
355  ps_buffer_cur_len = ps_buffer_nosuffix_len;
356  else
357  ps_buffer_nosuffix_len = ps_buffer_cur_len;
358 
359  len = strlen(suffix);
360 
361  /* check if we have enough space to append the suffix */
362  if (ps_buffer_cur_len + len + 1 >= ps_buffer_size)
363  {
364  /* not enough space. Check the buffer isn't full already */
365  if (ps_buffer_cur_len < ps_buffer_size - 1)
366  {
367  /* append a space before the suffix */
368  ps_buffer[ps_buffer_cur_len++] = ' ';
369 
370  /* just add what we can and fill the ps_buffer */
371  memcpy(ps_buffer + ps_buffer_cur_len, suffix,
372  ps_buffer_size - ps_buffer_cur_len - 1);
373  ps_buffer[ps_buffer_size - 1] = '\0';
374  ps_buffer_cur_len = ps_buffer_size - 1;
375  }
376  }
377  else
378  {
379  ps_buffer[ps_buffer_cur_len++] = ' ';
380  memcpy(ps_buffer + ps_buffer_cur_len, suffix, len + 1);
381  ps_buffer_cur_len = ps_buffer_cur_len + len;
382  }
383 
384  Assert(strlen(ps_buffer) == ps_buffer_cur_len);
385 
386  /* and set the new title */
387  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
397 {
398 #ifndef PS_USE_NONE
399  /* first, check if we need to update the process title */
400  if (!update_ps_display_precheck())
401  return;
402 
403  /* check we added a suffix */
404  if (ps_buffer_nosuffix_len == 0)
405  return; /* no suffix */
406 
407  /* remove the suffix from ps_buffer */
408  ps_buffer[ps_buffer_nosuffix_len] = '\0';
409  ps_buffer_cur_len = ps_buffer_nosuffix_len;
410  ps_buffer_nosuffix_len = 0;
411 
412  Assert(ps_buffer_cur_len == strlen(ps_buffer));
413 
414  /* and set the new title */
415  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 set_ps_display_with_len(const char *activity, size_t len)
427 {
428  Assert(strlen(activity) == len);
429 
430 #ifndef PS_USE_NONE
431  /* first, check if we need to update the process title */
432  if (!update_ps_display_precheck())
433  return;
434 
435  /* wipe out any suffix when the title is completely changed */
436  ps_buffer_nosuffix_len = 0;
437 
438  /* Update ps_buffer to contain both fixed part and activity */
439  if (ps_buffer_fixed_size + len >= ps_buffer_size)
440  {
441  /* handle the case where ps_buffer doesn't have enough space */
442  memcpy(ps_buffer + ps_buffer_fixed_size, activity,
443  ps_buffer_size - ps_buffer_fixed_size - 1);
444  ps_buffer[ps_buffer_size - 1] = '\0';
445  ps_buffer_cur_len = ps_buffer_size - 1;
446  }
447  else
448  {
449  memcpy(ps_buffer + ps_buffer_fixed_size, activity, len + 1);
450  ps_buffer_cur_len = ps_buffer_fixed_size + len;
451  }
452  Assert(strlen(ps_buffer) == ps_buffer_cur_len);
453 
454  /* Transmit new setting to kernel, if necessary */
455  flush_ps_display();
456 #endif /* not PS_USE_NONE */
457 }
458 
459 #ifndef PS_USE_NONE
460 static void
461 flush_ps_display(void)
462 {
463 #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  if (last_status_len > ps_buffer_cur_len)
472  MemSet(ps_buffer + ps_buffer_cur_len, PS_PADDING,
473  last_status_len - ps_buffer_cur_len);
474  last_status_len = ps_buffer_cur_len;
475 #endif /* PS_USE_CLOBBER_ARGV */
476 
477 #ifdef PS_USE_WIN32
478  {
479  /*
480  * Win32 does not support showing any changed arguments. To make it at
481  * 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  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 }
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  * the string will not be null-terminated, so return the effective
502  * length into *displen.
503  */
504 const char *
505 get_ps_display(int *displen)
506 {
507 #ifdef PS_USE_CLOBBER_ARGV
508  /* If ps_buffer is a pointer, it might still be null */
509  if (!ps_buffer)
510  {
511  *displen = 0;
512  return "";
513  }
514 #endif
515 
516 #ifndef PS_USE_NONE
517  *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size);
518 
519  return ps_buffer + ps_buffer_fixed_size;
520 #else
521  *displen = 0;
522  return "";
523 #endif
524 }
#define write_stderr(str)
Definition: parallel.c:184
#define MemSet(start, val, len)
Definition: c.h:1009
int MyProcPid
Definition: globals.c:44
bool IsUnderPostmaster
Definition: globals.c:115
char * cluster_name
Definition: guc_tables.c:535
#define malloc(a)
Definition: header.h:50
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
exit(1)
const char * GetBackendTypeDesc(BackendType backendType)
Definition: miscinit.c:263
BackendType MyBackendType
Definition: miscinit.c:63
const void size_t len
#define sprintf
Definition: port.h:240
#define snprintf
Definition: port.h:238
#define PS_PADDING
Definition: ps_status.c:68
const char * get_ps_display(int *displen)
Definition: ps_status.c:505
static int save_argc
Definition: ps_status.c:100
void set_ps_display_remove_suffix(void)
Definition: ps_status.c:396
void set_ps_display_with_len(const char *activity, size_t len)
Definition: ps_status.c:426
void init_ps_display(const char *fixed_part)
Definition: ps_status.c:242
void set_ps_display_suffix(const char *suffix)
Definition: ps_status.c:344
char ** environ
bool update_process_title
Definition: ps_status.c:31
char ** save_ps_display_args(int argc, char **argv)
Definition: ps_status.c:118
static char ** save_argv
Definition: ps_status.c:101
static void set_ps_display(const char *activity)
Definition: ps_status.h:40
#define DEFAULT_UPDATE_PROCESS_TITLE
Definition: ps_status.h:19
const char * name