Age Owner 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 : /*
7840 tgl 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
6986 107 : * from being clobbered by subsequent ps_display actions.
7839 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 : */
6385 bruce 117 : char **
6986 tgl 118 GIC 2619 : save_ps_display_args(int argc, char **argv)
119 : {
7840 120 2619 : save_argc = argc;
121 2619 : save_argv = argv;
122 :
123 : #if defined(PS_USE_CLOBBER_ARGV)
7836 bruce 124 ECB :
125 : /*
6385 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 : {
8053 bruce 130 CBC 2619 : char *end_of_area = NULL;
131 : char **new_environ;
8053 bruce 132 EUB : int i;
8344 peter_e 133 :
134 : /*
135 : * check for contiguous argv strings
136 : */
7839 tgl 137 GIC 19862 : for (i = 0; i < argc; i++)
138 : {
139 17243 : if (i == 0 || end_of_area + 1 == argv[i])
7839 tgl 140 CBC 17243 : end_of_area = argv[i] + strlen(argv[i]);
141 : }
8344 peter_e 142 ECB :
7833 bruce 143 CBC 2619 : if (end_of_area == NULL) /* probably can't happen? */
144 : {
8344 peter_e 145 UIC 0 : ps_buffer = NULL;
8344 peter_e 146 LBC 0 : ps_buffer_size = 0;
6986 tgl 147 0 : return argv;
148 : }
149 :
150 : /*
151 : * check for contiguous environ strings following argv
7839 tgl 152 ECB : */
7839 tgl 153 CBC 241070 : for (i = 0; environ[i] != NULL; i++)
154 : {
7839 tgl 155 GBC 238451 : if (end_of_area + 1 == environ[i])
156 238451 : end_of_area = environ[i] + strlen(environ[i]);
157 : }
7839 tgl 158 ECB :
7839 tgl 159 GIC 2619 : ps_buffer = argv[0];
5896 bruce 160 CBC 2619 : last_status_len = ps_buffer_size = end_of_area - argv[0];
5624 bruce 161 ECB :
162 : /*
8344 peter_e 163 EUB : * move the environment out of the way
164 : */
6986 tgl 165 GIC 2619 : new_environ = (char **) malloc((i + 1) * sizeof(char *));
2413 166 2619 : if (!new_environ)
2413 tgl 167 ECB : {
2413 tgl 168 LBC 0 : write_stderr("out of memory\n");
2413 tgl 169 UIC 0 : exit(1);
170 : }
8344 peter_e 171 GIC 241070 : for (i = 0; environ[i] != NULL; i++)
172 : {
8053 bruce 173 238451 : new_environ[i] = strdup(environ[i]);
2413 tgl 174 238451 : if (!new_environ[i])
175 : {
2413 tgl 176 UIC 0 : write_stderr("out of memory\n");
177 0 : exit(1);
178 : }
179 : }
8344 peter_e 180 GIC 2619 : new_environ[i] = NULL;
181 2619 : environ = new_environ;
182 : }
183 :
6986 tgl 184 ECB : /*
185 : * If we're going to change the original argv[] then make a copy for
186 : * argument parsing purposes.
6986 tgl 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
6385 bruce 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[].
6986 tgl 195 EUB : */
196 : {
197 : char **new_argv;
198 : int i;
6986 tgl 199 ECB :
6986 tgl 200 GIC 2619 : new_argv = (char **) malloc((argc + 1) * sizeof(char *));
2413 201 2619 : if (!new_argv)
202 : {
2413 tgl 203 UIC 0 : write_stderr("out of memory\n");
204 0 : exit(1);
205 : }
6986 tgl 206 GIC 19862 : for (i = 0; i < argc; i++)
207 : {
6797 bruce 208 17243 : new_argv[i] = strdup(argv[i]);
2413 tgl 209 17243 : if (!new_argv[i])
2413 tgl 210 ECB : {
2413 tgl 211 UIC 0 : write_stderr("out of memory\n");
212 0 : exit(1);
213 : }
2413 tgl 214 ECB : }
6986 tgl 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 :
6986 tgl 226 CBC 2619 : argv = new_argv;
227 : }
228 : #endif /* PS_USE_CLOBBER_ARGV */
229 :
6986 tgl 230 GIC 2619 : return argv;
231 : }
7839 tgl 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.
1124 peter 238 : *
1124 peter 239 EUB : * At this point, the original argv[] array may be overwritten.
240 : */
241 : void
1124 peter 242 CBC 12761 : init_ps_display(const char *fixed_part)
7839 tgl 243 EUB : {
244 : #ifndef PS_USE_NONE
245 : bool save_update_process_title;
246 : #endif
1124 peter 247 ECB :
1124 peter 248 GBC 12761 : Assert(fixed_part || MyBackendType);
1124 peter 249 GIC 12761 : if (!fixed_part)
250 2111 : fixed_part = GetBackendTypeDesc(MyBackendType);
7839 tgl 251 ECB :
252 : #ifndef PS_USE_NONE
253 : /* no ps display for stand-alone backend */
7839 tgl 254 GIC 12761 : if (!IsUnderPostmaster)
7839 tgl 255 UIC 0 : return;
256 :
257 : /* no ps display if you didn't call save_ps_display_args() */
7839 tgl 258 GIC 12761 : if (!save_argv)
7839 tgl 259 UIC 0 : return;
260 :
261 : #ifdef PS_USE_CLOBBER_ARGV
262 : /* If ps_buffer is a pointer, it might still be null */
7839 tgl 263 GIC 12761 : if (!ps_buffer)
7839 tgl 264 UIC 0 : return;
265 :
266 : /* make extra argv slots point at end_of_area (a NUL) */
51 tmunro 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.
8344 peter_e 273 ECB : */
8053 bruce 274 :
1720 tmunro 275 : #if defined(PS_USE_SETPROCTITLE) || defined(PS_USE_SETPROCTITLE_FAST)
7836 bruce 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 :
3206 andres 286 GIC 12761 : if (*cluster_name == '\0')
3206 andres 287 ECB : {
3206 andres 288 GIC 2522 : snprintf(ps_buffer, ps_buffer_size,
289 : PROGRAM_NAME_PREFIX "%s ",
1124 peter 290 ECB : fixed_part);
3206 andres 291 EUB : }
292 : else
293 : {
3206 andres 294 CBC 10239 : snprintf(ps_buffer, ps_buffer_size,
1124 peter 295 ECB : PROGRAM_NAME_PREFIX "%s: %s ",
296 : cluster_name, fixed_part);
297 : }
298 :
4700 tgl 299 CBC 12761 : ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer);
6702 bruce 300 EUB :
301 : /*
302 : * On the first run, force the update.
1124 peter 303 ECB : */
1124 peter 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 :
48 drowley 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
48 drowley 318 GNC 1066010 : update_ps_display_precheck(void)
319 : {
320 : /* update_process_title=off disables updates */
1124 peter 321 GIC 1066010 : if (!update_process_title)
48 drowley 322 UNC 0 : return false;
6031 bruce 323 EUB :
324 : /* no ps display for stand-alone backend */
6960 tgl 325 CBC 1066010 : if (!IsUnderPostmaster)
48 drowley 326 GNC 453075 : return false;
6970 bruce 327 ECB :
328 : #ifdef PS_USE_CLOBBER_ARGV
329 : /* If ps_buffer is a pointer, it might still be null */
8344 peter_e 330 CBC 612935 : if (!ps_buffer)
48 drowley 331 UNC 0 : return false;
332 : #endif
8344 peter_e 333 EUB :
48 drowley 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())
48 drowley 351 UNC 0 : return;
352 :
353 : /* if there's already a suffix, overwrite it */
48 drowley 354 GNC 1068 : if (ps_buffer_nosuffix_len > 0)
48 drowley 355 UNC 0 : ps_buffer_cur_len = ps_buffer_nosuffix_len;
356 : else
48 drowley 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 */
48 drowley 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 : {
48 drowley 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())
48 drowley 401 UNC 0 : return;
402 :
403 : /* check we added a suffix */
48 drowley 404 GNC 1063 : if (ps_buffer_nosuffix_len == 0)
48 drowley 405 UNC 0 : return; /* no suffix */
406 :
407 : /* remove the suffix from ps_buffer */
48 drowley 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 */
48 drowley 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 : {
48 drowley 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 :
8055 bruce 454 EUB : /* Transmit new setting to kernel, if necessary */
48 drowley 455 GNC 610804 : flush_ps_display();
456 : #endif /* not PS_USE_NONE */
457 : }
8344 peter_e 458 EUB :
459 : #ifndef PS_USE_NONE
460 : static void
48 drowley 461 GNC 612935 : flush_ps_display(void)
462 : {
8053 bruce 463 EUB : #ifdef PS_USE_SETPROCTITLE
8055 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 */
4700 tgl 471 GIC 612935 : if (last_status_len > ps_buffer_cur_len)
4700 tgl 472 CBC 279726 : MemSet(ps_buffer + ps_buffer_cur_len, PS_PADDING,
473 : last_status_len - ps_buffer_cur_len);
4700 tgl 474 GIC 612935 : last_status_len = ps_buffer_cur_len;
475 : #endif /* PS_USE_CLOBBER_ARGV */
6702 bruce 476 ECB :
6145 tgl 477 EUB : #ifdef PS_USE_WIN32
478 : {
479 : /*
6031 bruce 480 ECB : * Win32 does not support showing any changed arguments. To make it at
6031 bruce 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 : */
6145 tgl 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 */
8344 peter_e 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
6364 tgl 501 ECB : * the string will not be null-terminated, so return the effective
502 : * length into *displen.
8344 peter_e 503 : */
504 : const char *
6364 tgl 505 GIC 18 : get_ps_display(int *displen)
506 : {
8055 bruce 507 ECB : #ifdef PS_USE_CLOBBER_ARGV
508 : /* If ps_buffer is a pointer, it might still be null */
8055 bruce 509 GIC 18 : if (!ps_buffer)
510 : {
6364 tgl 511 LBC 0 : *displen = 0;
8055 bruce 512 UIC 0 : return "";
513 : }
8055 bruce 514 ECB : #endif
515 :
516 : #ifndef PS_USE_NONE
4700 tgl 517 GBC 18 : *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size);
4700 tgl 518 EUB :
8344 peter_e 519 GBC 18 : return ps_buffer + ps_buffer_fixed_size;
1206 peter 520 EUB : #else
521 : *displen = 0;
522 : return "";
523 : #endif
8344 peter_e 524 ECB : }
|