]> granicus.if.org Git - postgresql/blob - src/backend/utils/misc/ps_status.c
Fix comment to agree with presentation.
[postgresql] / src / backend / utils / misc / ps_status.c
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  * $PostgreSQL: pgsql/src/backend/utils/misc/ps_status.c,v 1.33 2006/10/04 00:30:04 momjian Exp $
9  *
10  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
11  * various details abducted from various places
12  *--------------------------------------------------------------------
13  */
14
15 #include "postgres.h"
16
17 #include <unistd.h>
18 #ifdef HAVE_SYS_PSTAT_H
19 #include <sys/pstat.h>                  /* for HP-UX */
20 #endif
21 #ifdef HAVE_PS_STRINGS
22 #include <machine/vmparam.h>    /* for old BSD */
23 #include <sys/exec.h>
24 #endif
25 #if defined(__darwin__)
26 #include <crt_externs.h>
27 #endif
28
29 #include "libpq/libpq.h"
30 #include "miscadmin.h"
31 #include "utils/ps_status.h"
32
33 extern char **environ;
34 bool            update_process_title = true;
35
36
37 /*
38  * Alternative ways of updating ps display:
39  *
40  * PS_USE_SETPROCTITLE
41  *         use the function setproctitle(const char *, ...)
42  *         (newer BSD systems)
43  * PS_USE_PSTAT
44  *         use the pstat(PSTAT_SETCMD, )
45  *         (HPUX)
46  * PS_USE_PS_STRINGS
47  *         assign PS_STRINGS->ps_argvstr = "string"
48  *         (some BSD systems)
49  * PS_USE_CHANGE_ARGV
50  *         assign argv[0] = "string"
51  *         (some other BSD systems)
52  * PS_USE_CLOBBER_ARGV
53  *         write over the argv and environment area
54  *         (most SysV-like systems)
55  * PS_USE_WIN32
56  *         push the string out as the name of a Windows event
57  * PS_USE_NONE
58  *         don't update ps display
59  *         (This is the default, as it is safest.)
60  */
61 #if defined(HAVE_SETPROCTITLE)
62 #define PS_USE_SETPROCTITLE
63 #elif defined(HAVE_PSTAT) && defined(PSTAT_SETCMD)
64 #define PS_USE_PSTAT
65 #elif defined(HAVE_PS_STRINGS)
66 #define PS_USE_PS_STRINGS
67 #elif (defined(BSD) || defined(__bsdi__) || defined(__hurd__)) && !defined(__darwin__)
68 #define PS_USE_CHANGE_ARGV
69 #elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__ksr__) || defined(__osf__) || defined(__svr4__) || defined(__svr5__) || defined(__darwin__)
70 #define PS_USE_CLOBBER_ARGV
71 #elif defined(WIN32)
72 #define PS_USE_WIN32
73 #else
74 #define PS_USE_NONE
75 #endif
76
77
78 /* Different systems want the buffer padded differently */
79 #if defined(_AIX) || defined(__linux__) || defined(__svr4__)
80 #define PS_PADDING '\0'
81 #else
82 #define PS_PADDING ' '
83 #endif
84
85
86 #ifndef PS_USE_CLOBBER_ARGV
87 /* all but one options need a buffer to write their ps line in */
88 #define PS_BUFFER_SIZE 256
89 static char ps_buffer[PS_BUFFER_SIZE];
90 static const size_t ps_buffer_size = PS_BUFFER_SIZE;
91 #else                                                   /* PS_USE_CLOBBER_ARGV */
92 static char *ps_buffer;                 /* will point to argv area */
93 static size_t ps_buffer_size;   /* space determined at run time */
94 #endif   /* PS_USE_CLOBBER_ARGV */
95
96 static size_t ps_buffer_fixed_size;             /* size of the constant prefix */
97
98 /* save the original argv[] location here */
99 static int      save_argc;
100 static char **save_argv;
101
102
103 /*
104  * Call this early in startup to save the original argc/argv values.
105  * If needed, we make a copy of the original argv[] array to preserve it
106  * from being clobbered by subsequent ps_display actions.
107  *
108  * (The original argv[] will not be overwritten by this routine, but may be
109  * overwritten during init_ps_display.  Also, the physical location of the
110  * environment strings may be moved, so this should be called before any code
111  * that might try to hang onto a getenv() result.)
112  */
113 char      **
114 save_ps_display_args(int argc, char **argv)
115 {
116         save_argc = argc;
117         save_argv = argv;
118
119 #if defined(PS_USE_CLOBBER_ARGV)
120
121         /*
122          * If we're going to overwrite the argv area, count the available space.
123          * Also move the environment to make additional room.
124          */
125         {
126                 char       *end_of_area = NULL;
127                 char      **new_environ;
128                 int                     i;
129
130                 /*
131                  * check for contiguous argv strings
132                  */
133                 for (i = 0; i < argc; i++)
134                 {
135                         if (i == 0 || end_of_area + 1 == argv[i])
136                                 end_of_area = argv[i] + strlen(argv[i]);
137                 }
138
139                 if (end_of_area == NULL)        /* probably can't happen? */
140                 {
141                         ps_buffer = NULL;
142                         ps_buffer_size = 0;
143                         return argv;
144                 }
145
146                 /*
147                  * check for contiguous environ strings following argv
148                  */
149                 for (i = 0; environ[i] != NULL; i++)
150                 {
151                         if (end_of_area + 1 == environ[i])
152                                 end_of_area = environ[i] + strlen(environ[i]);
153                 }
154
155                 ps_buffer = argv[0];
156                 ps_buffer_size = end_of_area - argv[0];
157
158                 /*
159                  * move the environment out of the way
160                  */
161                 new_environ = (char **) malloc((i + 1) * sizeof(char *));
162                 for (i = 0; environ[i] != NULL; i++)
163                         new_environ[i] = strdup(environ[i]);
164                 new_environ[i] = NULL;
165                 environ = new_environ;
166         }
167 #endif   /* PS_USE_CLOBBER_ARGV */
168
169 #if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV)
170
171         /*
172          * If we're going to change the original argv[] then make a copy for
173          * argument parsing purposes.
174          *
175          * (NB: do NOT think to remove the copying of argv[], even though
176          * postmaster.c finishes looking at argv[] long before we ever consider
177          * changing the ps display.  On some platforms, getopt() keeps pointers
178          * into the argv array, and will get horribly confused when it is
179          * re-called to analyze a subprocess' argument string if the argv storage
180          * has been clobbered meanwhile.  Other platforms have other dependencies
181          * on argv[].
182          */
183         {
184                 char      **new_argv;
185                 int                     i;
186
187                 new_argv = (char **) malloc((argc + 1) * sizeof(char *));
188                 for (i = 0; i < argc; i++)
189                         new_argv[i] = strdup(argv[i]);
190                 new_argv[argc] = NULL;
191
192 #if defined(__darwin__)
193
194                 /*
195                  * Darwin (and perhaps other NeXT-derived platforms?) has a static
196                  * copy of the argv pointer, which we may fix like so:
197                  */
198                 *_NSGetArgv() = new_argv;
199 #endif
200
201                 argv = new_argv;
202         }
203 #endif   /* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */
204
205         return argv;
206 }
207
208 /*
209  * Call this once during subprocess startup to set the identification
210  * values.      At this point, the original argv[] array may be overwritten.
211  */
212 void
213 init_ps_display(const char *username, const char *dbname,
214                                 const char *host_info, const char *initial_str)
215 {
216         Assert(username);
217         Assert(dbname);
218         Assert(host_info);
219
220 #ifndef PS_USE_NONE
221         /* no ps display for stand-alone backend */
222         if (!IsUnderPostmaster)
223                 return;
224
225         /* no ps display if you didn't call save_ps_display_args() */
226         if (!save_argv)
227                 return;
228 #ifdef PS_USE_CLOBBER_ARGV
229         /* If ps_buffer is a pointer, it might still be null */
230         if (!ps_buffer)
231                 return;
232 #endif
233
234         /*
235          * Overwrite argv[] to point at appropriate space, if needed
236          */
237
238 #ifdef PS_USE_CHANGE_ARGV
239         save_argv[0] = ps_buffer;
240         save_argv[1] = NULL;
241 #endif   /* PS_USE_CHANGE_ARGV */
242
243 #ifdef PS_USE_CLOBBER_ARGV
244         {
245                 int                     i;
246
247                 /* make extra argv slots point at end_of_area (a NUL) */
248                 for (i = 1; i < save_argc; i++)
249                         save_argv[i] = ps_buffer + ps_buffer_size;
250         }
251 #endif   /* PS_USE_CLOBBER_ARGV */
252
253         /*
254          * Make fixed prefix of ps display.
255          */
256
257 #ifdef PS_USE_SETPROCTITLE
258
259         /*
260          * apparently setproctitle() already adds a `progname:' prefix to the ps
261          * line
262          */
263         snprintf(ps_buffer, ps_buffer_size,
264                          "%s %s %s ",
265                          username, dbname, host_info);
266 #else
267         snprintf(ps_buffer, ps_buffer_size,
268                          "postgres: %s %s %s ",
269                          username, dbname, host_info);
270 #endif
271
272         ps_buffer_fixed_size = strlen(ps_buffer);
273
274         set_ps_display(initial_str, true);
275 #endif   /* not PS_USE_NONE */
276 }
277
278
279
280 /*
281  * Call this to update the ps status display to a fixed prefix plus an
282  * indication of what you're currently doing passed in the argument.
283  */
284 void
285 set_ps_display(const char *activity, bool force)
286 {
287
288         if (!force && !update_process_title)
289                 return;
290
291 #ifndef PS_USE_NONE
292         /* no ps display for stand-alone backend */
293         if (!IsUnderPostmaster)
294                 return;
295
296 #ifdef PS_USE_CLOBBER_ARGV
297         /* If ps_buffer is a pointer, it might still be null */
298         if (!ps_buffer)
299                 return;
300 #endif
301
302         /* Update ps_buffer to contain both fixed part and activity */
303         strlcpy(ps_buffer + ps_buffer_fixed_size, activity,
304                         ps_buffer_size - ps_buffer_fixed_size);
305
306         /* Transmit new setting to kernel, if necessary */
307
308 #ifdef PS_USE_SETPROCTITLE
309         setproctitle("%s", ps_buffer);
310 #endif
311
312 #ifdef PS_USE_PSTAT
313         {
314                 union pstun pst;
315
316                 pst.pst_command = ps_buffer;
317                 pstat(PSTAT_SETCMD, pst, strlen(ps_buffer), 0, 0);
318         }
319 #endif   /* PS_USE_PSTAT */
320
321 #ifdef PS_USE_PS_STRINGS
322         PS_STRINGS->ps_nargvstr = 1;
323         PS_STRINGS->ps_argvstr = ps_buffer;
324 #endif   /* PS_USE_PS_STRINGS */
325
326 #ifdef PS_USE_CLOBBER_ARGV
327         {
328                 int                     buflen;
329
330                 /* pad unused memory */
331                 buflen = strlen(ps_buffer);
332                 MemSet(ps_buffer + buflen, PS_PADDING, ps_buffer_size - buflen);
333         }
334 #endif   /* PS_USE_CLOBBER_ARGV */
335
336 #ifdef PS_USE_WIN32
337         {
338                 /*
339                  * Win32 does not support showing any changed arguments. To make it at
340                  * all possible to track which backend is doing what, we create a
341                  * named object that can be viewed with for example Process Explorer.
342                  */
343                 static HANDLE ident_handle = INVALID_HANDLE_VALUE;
344                 char            name[PS_BUFFER_SIZE + 32];
345
346                 if (ident_handle != INVALID_HANDLE_VALUE)
347                         CloseHandle(ident_handle);
348
349                 sprintf(name, "pgident: %s", ps_buffer);
350
351                 ident_handle = CreateEvent(NULL, TRUE, FALSE, name);
352         }
353 #endif   /* PS_USE_WIN32 */
354 #endif   /* not PS_USE_NONE */
355 }
356
357
358 /*
359  * Returns what's currently in the ps display, in case someone needs
360  * it.  Note that only the activity part is returned.  On some platforms
361  * the string will not be null-terminated, so return the effective
362  * length into *displen.
363  */
364 const char *
365 get_ps_display(int *displen)
366 {
367 #ifdef PS_USE_CLOBBER_ARGV
368         size_t          offset;
369
370         /* If ps_buffer is a pointer, it might still be null */
371         if (!ps_buffer)
372         {
373                 *displen = 0;
374                 return "";
375         }
376
377         /* Remove any trailing spaces to offset the effect of PS_PADDING */
378         offset = ps_buffer_size;
379         while (offset > ps_buffer_fixed_size && ps_buffer[offset - 1] == PS_PADDING)
380                 offset--;
381
382         *displen = offset - ps_buffer_fixed_size;
383 #else
384         *displen = strlen(ps_buffer + ps_buffer_fixed_size);
385 #endif
386
387         return ps_buffer + ps_buffer_fixed_size;
388 }