1 /*--------------------------------------------------------------------
4 * Routines to support changing the ps display of PostgreSQL backends
5 * to contain some useful information. Mechanism differs wildly across
8 * src/backend/utils/misc/ps_status.c
10 * Copyright (c) 2000-2024, PostgreSQL Global Development Group
11 * various details abducted from various places
12 *--------------------------------------------------------------------
18 #if defined(__darwin__)
19 #include <crt_externs.h>
22 #include "miscadmin.h"
23 #include "utils/guc.h"
24 #include "utils/ps_status.h"
26 extern char **environ
;
29 bool update_process_title
= DEFAULT_UPDATE_PROCESS_TITLE
;
32 * Alternative ways of updating ps display:
34 * PS_USE_SETPROCTITLE_FAST
35 * use the function setproctitle_fast(const char *, ...)
38 * use the function setproctitle(const char *, ...)
41 * write over the argv and environment area
42 * (Linux and most SysV-like systems)
44 * push the string out as the name of a Windows event
46 * don't update ps display
47 * (This is the default, as it is safest.)
49 #if defined(HAVE_SETPROCTITLE_FAST)
50 #define PS_USE_SETPROCTITLE_FAST
51 #elif defined(HAVE_SETPROCTITLE)
52 #define PS_USE_SETPROCTITLE
53 #elif defined(__linux__) || defined(__sun) || defined(__darwin__)
54 #define PS_USE_CLOBBER_ARGV
62 /* Different systems want the buffer padded differently */
63 #if defined(__linux__) || defined(__darwin__)
64 #define PS_PADDING '\0'
66 #define PS_PADDING ' '
72 #ifndef PS_USE_CLOBBER_ARGV
73 /* all but one option need a buffer to write their ps line in */
74 #define PS_BUFFER_SIZE 256
75 static char ps_buffer
[PS_BUFFER_SIZE
];
76 static const size_t ps_buffer_size
= PS_BUFFER_SIZE
;
77 #else /* PS_USE_CLOBBER_ARGV */
78 static char *ps_buffer
; /* will point to argv area */
79 static size_t ps_buffer_size
; /* space determined at run time */
80 static size_t last_status_len
; /* use to minimize length of clobber */
81 #endif /* PS_USE_CLOBBER_ARGV */
83 static size_t ps_buffer_cur_len
; /* nominal strlen(ps_buffer) */
85 static size_t ps_buffer_fixed_size
; /* size of the constant prefix */
88 * Length of ps_buffer before the suffix was appended to the end, or 0 if we
89 * didn't set a suffix.
91 static size_t ps_buffer_nosuffix_len
;
93 static void flush_ps_display(void);
95 #endif /* not PS_USE_NONE */
97 /* save the original argv[] location here */
99 static char **save_argv
;
103 * Call this early in startup to save the original argc/argv values.
104 * If needed, we make a copy of the original argv[] array to preserve it
105 * from being clobbered by subsequent ps_display actions.
107 * (The original argv[] will not be overwritten by this routine, but may be
108 * overwritten during init_ps_display. Also, the physical location of the
109 * environment strings may be moved, so this should be called before any code
110 * that might try to hang onto a getenv() result. But see hack for musl
113 * Note that in case of failure this cannot call elog() as that is not
114 * initialized yet. We rely on write_stderr() instead.
117 save_ps_display_args(int argc
, char **argv
)
122 #if defined(PS_USE_CLOBBER_ARGV)
125 * If we're going to overwrite the argv area, count the available space.
126 * Also move the environment strings to make additional room.
129 char *end_of_area
= NULL
;
134 * check for contiguous argv strings
136 for (i
= 0; i
< argc
; i
++)
138 if (i
== 0 || end_of_area
+ 1 == argv
[i
])
139 end_of_area
= argv
[i
] + strlen(argv
[i
]);
142 if (end_of_area
== NULL
) /* probably can't happen? */
150 * check for contiguous environ strings following argv
152 for (i
= 0; environ
[i
] != NULL
; i
++)
154 if (end_of_area
+ 1 == environ
[i
])
157 * The musl dynamic linker keeps a static pointer to the
158 * initial value of LD_LIBRARY_PATH, if that is defined in the
159 * process's environment. Therefore, we must not overwrite the
160 * value of that setting and thus cannot advance end_of_area
161 * beyond it. Musl does not define any identifying compiler
162 * symbol, so we have to do this unless we see a symbol
163 * identifying a Linux libc we know is safe.
165 #if defined(__linux__) && (!defined(__GLIBC__) && !defined(__UCLIBC__))
166 if (strncmp(environ
[i
], "LD_LIBRARY_PATH=", 16) == 0)
169 * We can overwrite the name, but stop at the equals sign.
170 * Future loop iterations will not find any more
171 * contiguous space, but we don't break early because we
172 * need to count the total number of environ[] entries.
174 end_of_area
= environ
[i
] + 15;
179 end_of_area
= environ
[i
] + strlen(environ
[i
]);
185 last_status_len
= ps_buffer_size
= end_of_area
- argv
[0];
188 * move the environment out of the way
190 new_environ
= (char **) malloc((i
+ 1) * sizeof(char *));
193 write_stderr("out of memory\n");
196 for (i
= 0; environ
[i
] != NULL
; i
++)
198 new_environ
[i
] = strdup(environ
[i
]);
201 write_stderr("out of memory\n");
205 new_environ
[i
] = NULL
;
206 environ
= new_environ
;
210 * If we're going to change the original argv[] then make a copy for
211 * argument parsing purposes.
213 * NB: do NOT think to remove the copying of argv[], even though
214 * postmaster.c finishes looking at argv[] long before we ever consider
215 * changing the ps display. On some platforms, getopt() keeps pointers
216 * into the argv array, and will get horribly confused when it is
217 * re-called to analyze a subprocess' argument string if the argv storage
218 * has been clobbered meanwhile. Other platforms have other dependencies
225 new_argv
= (char **) malloc((argc
+ 1) * sizeof(char *));
228 write_stderr("out of memory\n");
231 for (i
= 0; i
< argc
; i
++)
233 new_argv
[i
] = strdup(argv
[i
]);
236 write_stderr("out of memory\n");
240 new_argv
[argc
] = NULL
;
242 #if defined(__darwin__)
245 * macOS has a static copy of the argv pointer, which we may fix like
248 *_NSGetArgv() = new_argv
;
253 #endif /* PS_USE_CLOBBER_ARGV */
259 * Call this once during subprocess startup to set the identification
262 * If fixed_part is NULL, a default will be obtained from MyBackendType.
264 * At this point, the original argv[] array may be overwritten.
267 init_ps_display(const char *fixed_part
)
270 bool save_update_process_title
;
273 Assert(fixed_part
|| MyBackendType
);
275 fixed_part
= GetBackendTypeDesc(MyBackendType
);
278 /* no ps display for stand-alone backend */
279 if (!IsUnderPostmaster
)
282 /* no ps display if you didn't call save_ps_display_args() */
286 #ifdef PS_USE_CLOBBER_ARGV
287 /* If ps_buffer is a pointer, it might still be null */
291 /* make extra argv slots point at end_of_area (a NUL) */
292 for (int i
= 1; i
< save_argc
; i
++)
293 save_argv
[i
] = ps_buffer
+ ps_buffer_size
;
294 #endif /* PS_USE_CLOBBER_ARGV */
297 * Make fixed prefix of ps display.
300 #if defined(PS_USE_SETPROCTITLE) || defined(PS_USE_SETPROCTITLE_FAST)
303 * apparently setproctitle() already adds a `progname:' prefix to the ps
306 #define PROGRAM_NAME_PREFIX ""
308 #define PROGRAM_NAME_PREFIX "postgres: "
311 if (*cluster_name
== '\0')
313 snprintf(ps_buffer
, ps_buffer_size
,
314 PROGRAM_NAME_PREFIX
"%s ",
319 snprintf(ps_buffer
, ps_buffer_size
,
320 PROGRAM_NAME_PREFIX
"%s: %s ",
321 cluster_name
, fixed_part
);
324 ps_buffer_cur_len
= ps_buffer_fixed_size
= strlen(ps_buffer
);
327 * On the first run, force the update.
329 save_update_process_title
= update_process_title
;
330 update_process_title
= true;
332 update_process_title
= save_update_process_title
;
333 #endif /* not PS_USE_NONE */
338 * update_ps_display_precheck
339 * Helper function to determine if updating the process title is
340 * something that we need to do.
343 update_ps_display_precheck(void)
345 /* update_process_title=off disables updates */
346 if (!update_process_title
)
349 /* no ps display for stand-alone backend */
350 if (!IsUnderPostmaster
)
353 #ifdef PS_USE_CLOBBER_ARGV
354 /* If ps_buffer is a pointer, it might still be null */
361 #endif /* not PS_USE_NONE */
364 * set_ps_display_suffix
365 * Adjust the process title to append 'suffix' onto the end with a space
366 * between it and the current process title.
369 set_ps_display_suffix(const char *suffix
)
374 /* first, check if we need to update the process title */
375 if (!update_ps_display_precheck())
378 /* if there's already a suffix, overwrite it */
379 if (ps_buffer_nosuffix_len
> 0)
380 ps_buffer_cur_len
= ps_buffer_nosuffix_len
;
382 ps_buffer_nosuffix_len
= ps_buffer_cur_len
;
384 len
= strlen(suffix
);
386 /* check if we have enough space to append the suffix */
387 if (ps_buffer_cur_len
+ len
+ 1 >= ps_buffer_size
)
389 /* not enough space. Check the buffer isn't full already */
390 if (ps_buffer_cur_len
< ps_buffer_size
- 1)
392 /* append a space before the suffix */
393 ps_buffer
[ps_buffer_cur_len
++] = ' ';
395 /* just add what we can and fill the ps_buffer */
396 memcpy(ps_buffer
+ ps_buffer_cur_len
, suffix
,
397 ps_buffer_size
- ps_buffer_cur_len
- 1);
398 ps_buffer
[ps_buffer_size
- 1] = '\0';
399 ps_buffer_cur_len
= ps_buffer_size
- 1;
404 ps_buffer
[ps_buffer_cur_len
++] = ' ';
405 memcpy(ps_buffer
+ ps_buffer_cur_len
, suffix
, len
+ 1);
406 ps_buffer_cur_len
= ps_buffer_cur_len
+ len
;
409 Assert(strlen(ps_buffer
) == ps_buffer_cur_len
);
411 /* and set the new title */
413 #endif /* not PS_USE_NONE */
417 * set_ps_display_remove_suffix
418 * Remove the process display suffix added by set_ps_display_suffix
421 set_ps_display_remove_suffix(void)
424 /* first, check if we need to update the process title */
425 if (!update_ps_display_precheck())
428 /* check we added a suffix */
429 if (ps_buffer_nosuffix_len
== 0)
430 return; /* no suffix */
432 /* remove the suffix from ps_buffer */
433 ps_buffer
[ps_buffer_nosuffix_len
] = '\0';
434 ps_buffer_cur_len
= ps_buffer_nosuffix_len
;
435 ps_buffer_nosuffix_len
= 0;
437 Assert(ps_buffer_cur_len
== strlen(ps_buffer
));
439 /* and set the new title */
441 #endif /* not PS_USE_NONE */
445 * Call this to update the ps status display to a fixed prefix plus an
446 * indication of what you're currently doing passed in the argument.
448 * 'len' must be the same as strlen(activity)
451 set_ps_display_with_len(const char *activity
, size_t len
)
453 Assert(strlen(activity
) == len
);
456 /* first, check if we need to update the process title */
457 if (!update_ps_display_precheck())
460 /* wipe out any suffix when the title is completely changed */
461 ps_buffer_nosuffix_len
= 0;
463 /* Update ps_buffer to contain both fixed part and activity */
464 if (ps_buffer_fixed_size
+ len
>= ps_buffer_size
)
466 /* handle the case where ps_buffer doesn't have enough space */
467 memcpy(ps_buffer
+ ps_buffer_fixed_size
, activity
,
468 ps_buffer_size
- ps_buffer_fixed_size
- 1);
469 ps_buffer
[ps_buffer_size
- 1] = '\0';
470 ps_buffer_cur_len
= ps_buffer_size
- 1;
474 memcpy(ps_buffer
+ ps_buffer_fixed_size
, activity
, len
+ 1);
475 ps_buffer_cur_len
= ps_buffer_fixed_size
+ len
;
477 Assert(strlen(ps_buffer
) == ps_buffer_cur_len
);
479 /* Transmit new setting to kernel, if necessary */
481 #endif /* not PS_USE_NONE */
486 flush_ps_display(void)
488 #ifdef PS_USE_SETPROCTITLE
489 setproctitle("%s", ps_buffer
);
490 #elif defined(PS_USE_SETPROCTITLE_FAST)
491 setproctitle_fast("%s", ps_buffer
);
494 #ifdef PS_USE_CLOBBER_ARGV
495 /* pad unused memory; need only clobber remainder of old status string */
496 if (last_status_len
> ps_buffer_cur_len
)
497 MemSet(ps_buffer
+ ps_buffer_cur_len
, PS_PADDING
,
498 last_status_len
- ps_buffer_cur_len
);
499 last_status_len
= ps_buffer_cur_len
;
500 #endif /* PS_USE_CLOBBER_ARGV */
505 * Win32 does not support showing any changed arguments. To make it at
506 * all possible to track which backend is doing what, we create a
507 * named object that can be viewed with for example Process Explorer.
509 static HANDLE ident_handle
= INVALID_HANDLE_VALUE
;
510 char name
[PS_BUFFER_SIZE
+ 32];
512 if (ident_handle
!= INVALID_HANDLE_VALUE
)
513 CloseHandle(ident_handle
);
515 sprintf(name
, "pgident(%d): %s", MyProcPid
, ps_buffer
);
517 ident_handle
= CreateEvent(NULL
, TRUE
, FALSE
, name
);
519 #endif /* PS_USE_WIN32 */
521 #endif /* not PS_USE_NONE */
524 * Returns what's currently in the ps display, in case someone needs
525 * it. Note that only the activity part is returned. On some platforms
526 * the string will not be null-terminated, so return the effective
527 * length into *displen.
530 get_ps_display(int *displen
)
532 #ifdef PS_USE_CLOBBER_ARGV
533 /* If ps_buffer is a pointer, it might still be null */
542 *displen
= (int) (ps_buffer_cur_len
- ps_buffer_fixed_size
);
544 return ps_buffer
+ ps_buffer_fixed_size
;