Age Owner Branch data 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-2026, 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 "miscadmin.h"
23 : : #include "utils/guc.h"
24 : : #include "utils/ps_status.h"
25 : :
26 : : #if !defined(WIN32)
27 : : extern char **environ;
28 : : #endif
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__) || defined(__GNU__)
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__) || defined(__GNU__)
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 : : * Valgrind seems not to consider the global "environ" variable as a valid
105 : : * root pointer; so when we allocate a new environment array, it claims that
106 : : * data is leaked. To fix that, keep our own statically-allocated copy of the
107 : : * pointer. (Oddly, this doesn't seem to be a problem for "argv".)
108 : : */
109 : : #if defined(PS_USE_CLOBBER_ARGV) && defined(USE_VALGRIND)
110 : : extern char **ps_status_new_environ;
111 : : char **ps_status_new_environ;
112 : : #endif
113 : :
114 : :
115 : : /*
116 : : * Call this early in startup to save the original argc/argv values.
117 : : * If needed, we make a copy of the original argv[] array to preserve it
118 : : * from being clobbered by subsequent ps_display actions.
119 : : *
120 : : * (The original argv[] will not be overwritten by this routine, but may be
121 : : * overwritten during init_ps_display. Also, the physical location of the
122 : : * environment strings may be moved, so this should be called before any code
123 : : * that might try to hang onto a getenv() result. But see hack for musl
124 : : * within.)
125 : : *
126 : : * Note that in case of failure this cannot call elog() as that is not
127 : : * initialized yet. We rely on write_stderr() instead.
128 : : */
129 : : char **
8108 tgl@sss.pgh.pa.us 130 :CBC 2164 : save_ps_display_args(int argc, char **argv)
131 : : {
8962 132 : 2164 : save_argc = argc;
133 : 2164 : save_argv = argv;
134 : :
135 : : #if defined(PS_USE_CLOBBER_ARGV)
136 : :
137 : : /*
138 : : * If we're going to overwrite the argv area, count the available space.
139 : : * Also move the environment strings to make additional room.
140 : : */
141 : : {
9175 bruce@momjian.us 142 : 2164 : char *end_of_area = NULL;
143 : : char **new_environ;
144 : : int i;
145 : :
146 : : /*
147 : : * check for contiguous argv strings
148 : : */
8961 tgl@sss.pgh.pa.us 149 [ + + ]: 12343 : for (i = 0; i < argc; i++)
150 : : {
151 [ + + + - ]: 10179 : if (i == 0 || end_of_area + 1 == argv[i])
152 : 10179 : end_of_area = argv[i] + strlen(argv[i]);
153 : : }
154 : :
8955 bruce@momjian.us 155 [ - + ]: 2164 : if (end_of_area == NULL) /* probably can't happen? */
156 : : {
9466 peter_e@gmx.net 157 :UBC 0 : ps_buffer = NULL;
158 : 0 : ps_buffer_size = 0;
8108 tgl@sss.pgh.pa.us 159 : 0 : return argv;
160 : : }
161 : :
162 : : /*
163 : : * check for contiguous environ strings following argv
164 : : */
8961 tgl@sss.pgh.pa.us 165 [ + + ]:CBC 302754 : for (i = 0; environ[i] != NULL; i++)
166 : : {
167 [ + - ]: 300590 : if (end_of_area + 1 == environ[i])
168 : : {
169 : : /*
170 : : * The musl dynamic linker keeps a static pointer to the
171 : : * initial value of LD_LIBRARY_PATH, if that is defined in the
172 : : * process's environment. Therefore, we must not overwrite the
173 : : * value of that setting and thus cannot advance end_of_area
174 : : * beyond it. Musl does not define any identifying compiler
175 : : * symbol, so we have to do this unless we see a symbol
176 : : * identifying a Linux libc we know is safe.
177 : : */
178 : : #if defined(__linux__) && (!defined(__GLIBC__) && !defined(__UCLIBC__))
179 : : if (strncmp(environ[i], "LD_LIBRARY_PATH=", 16) == 0)
180 : : {
181 : : /*
182 : : * We can overwrite the name, but stop at the equals sign.
183 : : * Future loop iterations will not find any more
184 : : * contiguous space, but we don't break early because we
185 : : * need to count the total number of environ[] entries.
186 : : */
187 : : end_of_area = environ[i] + 15;
188 : : }
189 : : else
190 : : #endif
191 : : {
770 192 : 300590 : end_of_area = environ[i] + strlen(environ[i]);
193 : : }
194 : : }
195 : : }
196 : :
8961 197 : 2164 : ps_buffer = argv[0];
7018 bruce@momjian.us 198 : 2164 : last_status_len = ps_buffer_size = end_of_area - argv[0];
199 : :
200 : : /*
201 : : * move the environment out of the way
202 : : */
8108 tgl@sss.pgh.pa.us 203 : 2164 : new_environ = (char **) malloc((i + 1) * sizeof(char *));
3535 204 [ - + ]: 2164 : if (!new_environ)
205 : : {
3535 tgl@sss.pgh.pa.us 206 :UBC 0 : write_stderr("out of memory\n");
207 : 0 : exit(1);
208 : : }
9466 peter_e@gmx.net 209 [ + + ]:CBC 302754 : for (i = 0; environ[i] != NULL; i++)
210 : : {
9175 bruce@momjian.us 211 : 300590 : new_environ[i] = strdup(environ[i]);
3535 tgl@sss.pgh.pa.us 212 [ - + ]: 300590 : if (!new_environ[i])
213 : : {
3535 tgl@sss.pgh.pa.us 214 :UBC 0 : write_stderr("out of memory\n");
215 : 0 : exit(1);
216 : : }
217 : : }
9466 peter_e@gmx.net 218 :CBC 2164 : new_environ[i] = NULL;
219 : 2164 : environ = new_environ;
220 : :
221 : : /* See notes about Valgrind above. */
222 : : #ifdef USE_VALGRIND
223 : : ps_status_new_environ = new_environ;
224 : : #endif
225 : : }
226 : :
227 : : /*
228 : : * If we're going to change the original argv[] then make a copy for
229 : : * argument parsing purposes.
230 : : *
231 : : * NB: do NOT think to remove the copying of argv[], even though
232 : : * postmaster.c finishes looking at argv[] long before we ever consider
233 : : * changing the ps display. On some platforms, getopt() keeps pointers
234 : : * into the argv array, and will get horribly confused when it is
235 : : * re-called to analyze a subprocess' argument string if the argv storage
236 : : * has been clobbered meanwhile. Other platforms have other dependencies
237 : : * on argv[]. (We use custom pg_getopt_start/next() functions nowadays
238 : : * that don't do that, but those other dependencies might still exist.)
239 : : */
240 : : {
241 : : char **new_argv;
242 : : int i;
243 : :
8108 tgl@sss.pgh.pa.us 244 : 2164 : new_argv = (char **) malloc((argc + 1) * sizeof(char *));
3535 245 [ - + ]: 2164 : if (!new_argv)
246 : : {
3535 tgl@sss.pgh.pa.us 247 :UBC 0 : write_stderr("out of memory\n");
248 : 0 : exit(1);
249 : : }
8108 tgl@sss.pgh.pa.us 250 [ + + ]:CBC 12343 : for (i = 0; i < argc; i++)
251 : : {
7919 bruce@momjian.us 252 : 10179 : new_argv[i] = strdup(argv[i]);
3535 tgl@sss.pgh.pa.us 253 [ - + ]: 10179 : if (!new_argv[i])
254 : : {
3535 tgl@sss.pgh.pa.us 255 :UBC 0 : write_stderr("out of memory\n");
256 : 0 : exit(1);
257 : : }
258 : : }
8108 tgl@sss.pgh.pa.us 259 :CBC 2164 : new_argv[argc] = NULL;
260 : :
261 : : #if defined(__darwin__)
262 : :
263 : : /*
264 : : * macOS has a static copy of the argv pointer, which we may fix like
265 : : * so:
266 : : */
267 : : *_NSGetArgv() = new_argv;
268 : : #endif
269 : :
270 : 2164 : argv = new_argv;
271 : : }
272 : : #endif /* PS_USE_CLOBBER_ARGV */
273 : :
274 : 2164 : return argv;
275 : : }
276 : :
277 : : /*
278 : : * Call this once during subprocess startup to set the identification
279 : : * values.
280 : : *
281 : : * If fixed_part is NULL, a default will be obtained from MyBackendType.
282 : : *
283 : : * At this point, the original argv[] array may be overwritten.
284 : : */
285 : : void
2246 peter@eisentraut.org 286 : 22986 : init_ps_display(const char *fixed_part)
287 : : {
288 : : #ifndef PS_USE_NONE
289 : : bool save_update_process_title;
290 : : #endif
291 : :
292 [ + + - + ]: 22986 : Assert(fixed_part || MyBackendType);
293 [ + + ]: 22986 : if (!fixed_part)
294 : 4947 : fixed_part = GetBackendTypeDesc(MyBackendType);
295 : :
296 : : #ifndef PS_USE_NONE
297 : : /* no ps display for stand-alone backend */
8961 tgl@sss.pgh.pa.us 298 [ - + ]: 22986 : if (!IsUnderPostmaster)
8961 tgl@sss.pgh.pa.us 299 :UBC 0 : return;
300 : :
301 : : /* no ps display if you didn't call save_ps_display_args() */
8961 tgl@sss.pgh.pa.us 302 [ - + ]:CBC 22986 : if (!save_argv)
8961 tgl@sss.pgh.pa.us 303 :UBC 0 : return;
304 : :
305 : : #ifdef PS_USE_CLOBBER_ARGV
306 : : /* If ps_buffer is a pointer, it might still be null */
8961 tgl@sss.pgh.pa.us 307 [ - + ]:CBC 22986 : if (!ps_buffer)
8961 tgl@sss.pgh.pa.us 308 :UBC 0 : return;
309 : :
310 : : /* make extra argv slots point at end_of_area (a NUL) */
1173 tmunro@postgresql.or 311 [ + + ]:CBC 118971 : for (int i = 1; i < save_argc; i++)
312 : 95985 : save_argv[i] = ps_buffer + ps_buffer_size;
313 : : #endif /* PS_USE_CLOBBER_ARGV */
314 : :
315 : : /*
316 : : * Make fixed prefix of ps display.
317 : : */
318 : :
319 : : #if defined(PS_USE_SETPROCTITLE) || defined(PS_USE_SETPROCTITLE_FAST)
320 : :
321 : : /*
322 : : * apparently setproctitle() already adds a `progname:' prefix to the ps
323 : : * line
324 : : */
325 : : #define PROGRAM_NAME_PREFIX ""
326 : : #else
327 : : #define PROGRAM_NAME_PREFIX "postgres: "
328 : : #endif
329 : :
4328 andres@anarazel.de 330 [ + + ]: 22986 : if (*cluster_name == '\0')
331 : : {
332 : 4370 : snprintf(ps_buffer, ps_buffer_size,
333 : : PROGRAM_NAME_PREFIX "%s ",
334 : : fixed_part);
335 : : }
336 : : else
337 : : {
338 : 18616 : snprintf(ps_buffer, ps_buffer_size,
339 : : PROGRAM_NAME_PREFIX "%s: %s ",
340 : : cluster_name, fixed_part);
341 : : }
342 : :
5822 tgl@sss.pgh.pa.us 343 : 22986 : ps_buffer_cur_len = ps_buffer_fixed_size = strlen(ps_buffer);
344 : :
345 : : /*
346 : : * On the first run, force the update.
347 : : */
2246 peter@eisentraut.org 348 : 22986 : save_update_process_title = update_process_title;
349 : 22986 : update_process_title = true;
350 : 22986 : set_ps_display("");
351 : 22986 : update_process_title = save_update_process_title;
352 : : #endif /* not PS_USE_NONE */
353 : : }
354 : :
355 : : #ifndef PS_USE_NONE
356 : : /*
357 : : * update_ps_display_precheck
358 : : * Helper function to determine if updating the process title is
359 : : * something that we need to do.
360 : : */
361 : : static bool
1170 drowley@postgresql.o 362 : 1176350 : update_ps_display_precheck(void)
363 : : {
364 : : /* update_process_title=off disables updates */
2246 peter@eisentraut.org 365 [ - + ]: 1176350 : if (!update_process_title)
1170 drowley@postgresql.o 366 :UBC 0 : return false;
367 : :
368 : : /* no ps display for stand-alone backend */
8082 tgl@sss.pgh.pa.us 369 [ + + ]:CBC 1176350 : if (!IsUnderPostmaster)
1170 drowley@postgresql.o 370 : 78043 : return false;
371 : :
372 : : #ifdef PS_USE_CLOBBER_ARGV
373 : : /* If ps_buffer is a pointer, it might still be null */
9466 peter_e@gmx.net 374 [ - + ]: 1098307 : if (!ps_buffer)
1170 drowley@postgresql.o 375 :UBC 0 : return false;
376 : : #endif
377 : :
1170 drowley@postgresql.o 378 :CBC 1098307 : return true;
379 : : }
380 : : #endif /* not PS_USE_NONE */
381 : :
382 : : /*
383 : : * set_ps_display_suffix
384 : : * Adjust the process title to append 'suffix' onto the end with a space
385 : : * between it and the current process title.
386 : : */
387 : : void
388 : 1592 : set_ps_display_suffix(const char *suffix)
389 : : {
390 : : #ifndef PS_USE_NONE
391 : : size_t len;
392 : :
393 : : /* first, check if we need to update the process title */
394 [ - + ]: 1592 : if (!update_ps_display_precheck())
1170 drowley@postgresql.o 395 :UBC 0 : return;
396 : :
397 : : /* if there's already a suffix, overwrite it */
1170 drowley@postgresql.o 398 [ - + ]:CBC 1592 : if (ps_buffer_nosuffix_len > 0)
1170 drowley@postgresql.o 399 :UBC 0 : ps_buffer_cur_len = ps_buffer_nosuffix_len;
400 : : else
1170 drowley@postgresql.o 401 :CBC 1592 : ps_buffer_nosuffix_len = ps_buffer_cur_len;
402 : :
403 : 1592 : len = strlen(suffix);
404 : :
405 : : /* check if we have enough space to append the suffix */
406 [ - + ]: 1592 : if (ps_buffer_cur_len + len + 1 >= ps_buffer_size)
407 : : {
408 : : /* not enough space. Check the buffer isn't full already */
1170 drowley@postgresql.o 409 [ # # ]:UBC 0 : if (ps_buffer_cur_len < ps_buffer_size - 1)
410 : : {
411 : : /* append a space before the suffix */
412 : 0 : ps_buffer[ps_buffer_cur_len++] = ' ';
413 : :
414 : : /* just add what we can and fill the ps_buffer */
415 : 0 : memcpy(ps_buffer + ps_buffer_cur_len, suffix,
416 : 0 : ps_buffer_size - ps_buffer_cur_len - 1);
417 : 0 : ps_buffer[ps_buffer_size - 1] = '\0';
418 : 0 : ps_buffer_cur_len = ps_buffer_size - 1;
419 : : }
420 : : }
421 : : else
422 : : {
1170 drowley@postgresql.o 423 :CBC 1592 : ps_buffer[ps_buffer_cur_len++] = ' ';
424 : 1592 : memcpy(ps_buffer + ps_buffer_cur_len, suffix, len + 1);
425 : 1592 : ps_buffer_cur_len = ps_buffer_cur_len + len;
426 : : }
427 : :
428 [ - + ]: 1592 : Assert(strlen(ps_buffer) == ps_buffer_cur_len);
429 : :
430 : : /* and set the new title */
431 : 1592 : flush_ps_display();
432 : : #endif /* not PS_USE_NONE */
433 : : }
434 : :
435 : : /*
436 : : * set_ps_display_remove_suffix
437 : : * Remove the process display suffix added by set_ps_display_suffix
438 : : */
439 : : void
440 : 1589 : set_ps_display_remove_suffix(void)
441 : : {
442 : : #ifndef PS_USE_NONE
443 : : /* first, check if we need to update the process title */
444 [ - + ]: 1589 : if (!update_ps_display_precheck())
1170 drowley@postgresql.o 445 :UBC 0 : return;
446 : :
447 : : /* check we added a suffix */
1170 drowley@postgresql.o 448 [ - + ]:CBC 1589 : if (ps_buffer_nosuffix_len == 0)
1170 drowley@postgresql.o 449 :UBC 0 : return; /* no suffix */
450 : :
451 : : /* remove the suffix from ps_buffer */
1170 drowley@postgresql.o 452 :CBC 1589 : ps_buffer[ps_buffer_nosuffix_len] = '\0';
453 : 1589 : ps_buffer_cur_len = ps_buffer_nosuffix_len;
454 : 1589 : ps_buffer_nosuffix_len = 0;
455 : :
456 [ - + ]: 1589 : Assert(ps_buffer_cur_len == strlen(ps_buffer));
457 : :
458 : : /* and set the new title */
459 : 1589 : flush_ps_display();
460 : : #endif /* not PS_USE_NONE */
461 : : }
462 : :
463 : : /*
464 : : * Call this to update the ps status display to a fixed prefix plus an
465 : : * indication of what you're currently doing passed in the argument.
466 : : *
467 : : * 'len' must be the same as strlen(activity)
468 : : */
469 : : void
470 : 1173169 : set_ps_display_with_len(const char *activity, size_t len)
471 : : {
472 [ - + ]: 1173169 : Assert(strlen(activity) == len);
473 : :
474 : : #ifndef PS_USE_NONE
475 : : /* first, check if we need to update the process title */
476 [ + + ]: 1173169 : if (!update_ps_display_precheck())
477 : 78043 : return;
478 : :
479 : : /* wipe out any suffix when the title is completely changed */
480 : 1095126 : ps_buffer_nosuffix_len = 0;
481 : :
482 : : /* Update ps_buffer to contain both fixed part and activity */
483 [ - + ]: 1095126 : if (ps_buffer_fixed_size + len >= ps_buffer_size)
484 : : {
485 : : /* handle the case where ps_buffer doesn't have enough space */
1170 drowley@postgresql.o 486 :UBC 0 : memcpy(ps_buffer + ps_buffer_fixed_size, activity,
487 : 0 : ps_buffer_size - ps_buffer_fixed_size - 1);
488 : 0 : ps_buffer[ps_buffer_size - 1] = '\0';
489 : 0 : ps_buffer_cur_len = ps_buffer_size - 1;
490 : : }
491 : : else
492 : : {
1170 drowley@postgresql.o 493 :CBC 1095126 : memcpy(ps_buffer + ps_buffer_fixed_size, activity, len + 1);
494 : 1095126 : ps_buffer_cur_len = ps_buffer_fixed_size + len;
495 : : }
496 [ - + ]: 1095126 : Assert(strlen(ps_buffer) == ps_buffer_cur_len);
497 : :
498 : : /* Transmit new setting to kernel, if necessary */
499 : 1095126 : flush_ps_display();
500 : : #endif /* not PS_USE_NONE */
501 : : }
502 : :
503 : : #ifndef PS_USE_NONE
504 : : static void
505 : 1098307 : flush_ps_display(void)
506 : : {
507 : : #ifdef PS_USE_SETPROCTITLE
508 : : setproctitle("%s", ps_buffer);
509 : : #elif defined(PS_USE_SETPROCTITLE_FAST)
510 : : setproctitle_fast("%s", ps_buffer);
511 : : #endif
512 : :
513 : : #ifdef PS_USE_CLOBBER_ARGV
514 : : /* pad unused memory; need only clobber remainder of old status string */
5822 tgl@sss.pgh.pa.us 515 [ + + ]: 1098307 : if (last_status_len > ps_buffer_cur_len)
516 [ + + + + : 471698 : MemSet(ps_buffer + ps_buffer_cur_len, PS_PADDING,
+ - + - +
+ ]
517 : : last_status_len - ps_buffer_cur_len);
518 : 1098307 : last_status_len = ps_buffer_cur_len;
519 : : #endif /* PS_USE_CLOBBER_ARGV */
520 : :
521 : : #ifdef PS_USE_WIN32
522 : : {
523 : : /*
524 : : * Win32 does not support showing any changed arguments. To make it at
525 : : * all possible to track which backend is doing what, we create a
526 : : * named object that can be viewed with for example Process Explorer.
527 : : */
528 : : static HANDLE ident_handle = INVALID_HANDLE_VALUE;
529 : : char name[PS_BUFFER_SIZE + 32];
530 : :
531 : : if (ident_handle != INVALID_HANDLE_VALUE)
532 : : CloseHandle(ident_handle);
533 : :
534 : : sprintf(name, "pgident(%d): %s", MyProcPid, ps_buffer);
535 : :
536 : : ident_handle = CreateEvent(NULL, TRUE, FALSE, name);
537 : : }
538 : : #endif /* PS_USE_WIN32 */
9466 peter_e@gmx.net 539 : 1098307 : }
540 : : #endif /* not PS_USE_NONE */
541 : :
542 : : /*
543 : : * Returns what's currently in the ps display, in case someone needs
544 : : * it. Note that only the activity part is returned. On some platforms
545 : : * the string will not be null-terminated, so return the effective
546 : : * length into *displen.
547 : : */
548 : : const char *
7486 tgl@sss.pgh.pa.us 549 : 18 : get_ps_display(int *displen)
550 : : {
551 : : #ifdef PS_USE_CLOBBER_ARGV
552 : : /* If ps_buffer is a pointer, it might still be null */
9177 bruce@momjian.us 553 [ - + ]: 18 : if (!ps_buffer)
554 : : {
7486 tgl@sss.pgh.pa.us 555 :UBC 0 : *displen = 0;
9177 bruce@momjian.us 556 : 0 : return "";
557 : : }
558 : : #endif
559 : :
560 : : #ifndef PS_USE_NONE
5822 tgl@sss.pgh.pa.us 561 :CBC 18 : *displen = (int) (ps_buffer_cur_len - ps_buffer_fixed_size);
562 : :
9466 peter_e@gmx.net 563 : 18 : return ps_buffer + ps_buffer_fixed_size;
564 : : #else
565 : : *displen = 0;
566 : : return "";
567 : : #endif
568 : : }
|