1 /* -*-pgsql-c-*- */
2 /*
3  *
4  * $Header$
5  *
6  * This file was imported from PostgreSQL source code.
7  * See below for the copyright and description.
8  *
9  * pgpool: a language independent connection pool server for PostgreSQL
10  * written by Tatsuo Ishii
11  *
12  * Portions Copyright (c) 2003-2020	PgPool Global Development Group
13  *
14  */
15 /*--------------------------------------------------------------------
16  * ps_status.c
17  *
18  * Routines to support changing the ps display of PostgreSQL backends
19  * to contain some useful information. Mechanism differs wildly across
20  * platforms.
21  *
22  * $PostgreSQL: pgsql/src/backend/utils/misc/ps_status.c,v 1.33 2006/10/04 00:30:04 momjian Exp $
23  *
24  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
25  * various details abducted from various places
26  *--------------------------------------------------------------------
27  */
28 
29 #include <unistd.h>
30 #ifdef HAVE_SYS_PSTAT_H
31 #include <sys/pstat.h>			/* for HP-UX */
32 #endif
33 #ifdef HAVE_PS_STRINGS
34 #include <machine/vmparam.h>	/* for old BSD */
35 #include <sys/exec.h>
36 #endif
37 #if defined(__darwin__)
38 #include <crt_externs.h>
39 #endif
40 
41 #include "utils/ps_status.h"
42 #include "pool_type.h"
43 #include <stdlib.h>
44 #include <string.h>
45 
46 extern char **environ;
47 bool		update_process_title = true;
48 char		remote_ps_data[NI_MAXHOST + NI_MAXSERV + 2]; /* used for set_ps_display */
49 
50 
51 /*
52  * Alternative ways of updating ps display:
53  *
54  * PS_USE_SETPROCTITLE
55  *	   use the function setproctitle(const char *, ...)
56  *	   (newer BSD systems)
57  * PS_USE_PSTAT
58  *	   use the pstat(PSTAT_SETCMD, )
59  *	   (HPUX)
60  * PS_USE_PS_STRINGS
61  *	   assign PS_STRINGS->ps_argvstr = "string"
62  *	   (some BSD systems)
63  * PS_USE_CHANGE_ARGV
64  *	   assign argv[0] = "string"
65  *	   (some other BSD systems)
66  * PS_USE_CLOBBER_ARGV
67  *	   write over the argv and environment area
68  *	   (most SysV-like systems)
69  * PS_USE_WIN32
70  *	   push the string out as the name of a Windows event
71  * PS_USE_NONE
72  *	   don't update ps display
73  *	   (This is the default, as it is safest.)
74  */
75 #if defined(HAVE_SETPROCTITLE)
76 #define PS_USE_SETPROCTITLE
77 #elif defined(HAVE_PSTAT) && defined(PSTAT_SETCMD)
78 #define PS_USE_PSTAT
79 #elif defined(HAVE_PS_STRINGS)
80 #define PS_USE_PS_STRINGS
81 #elif (defined(BSD) || defined(__bsdi__) || defined(__hurd__)) && !defined(__darwin__)
82 #define PS_USE_CHANGE_ARGV
83 #elif defined(__linux__) || defined(_AIX) || defined(__sgi) || (defined(sun) && !defined(BSD)) || defined(ultrix) || defined(__ksr__) || defined(__osf__) || defined(__svr4__) || defined(__svr5__) || defined(__darwin__)
84 #define PS_USE_CLOBBER_ARGV
85 #elif defined(WIN32)
86 #define PS_USE_WIN32
87 #else
88 #define PS_USE_NONE
89 #endif
90 
91 
92 /* Different systems want the buffer padded differently */
93 #if defined(_AIX) || defined(__linux__) || defined(__svr4__)
94 #define PS_PADDING '\0'
95 #else
96 #define PS_PADDING ' '
97 #endif
98 
99 
100 #ifndef PS_USE_CLOBBER_ARGV
101 /* all but one options need a buffer to write their ps line in */
102 #define PS_BUFFER_SIZE 256
103 static char ps_buffer[PS_BUFFER_SIZE];
104 static const size_t ps_buffer_size = PS_BUFFER_SIZE;
105 #else							/* PS_USE_CLOBBER_ARGV */
106 static char *ps_buffer;			/* will point to argv area */
107 static size_t ps_buffer_size;	/* space determined at run time */
108 #endif							/* PS_USE_CLOBBER_ARGV */
109 
110 static size_t ps_buffer_fixed_size; /* size of the constant prefix */
111 
112 /* save the original argv[] location here */
113 static int	save_argc;
114 static char **save_argv;
115 
116 
117 /*
118  * Call this early in startup to save the original argc/argv values.
119  * If needed, we make a copy of the original argv[] array to preserve it
120  * from being clobbered by subsequent ps_display actions.
121  *
122  * (The original argv[] will not be overwritten by this routine, but may be
123  * overwritten during init_ps_display.	Also, the physical location of the
124  * environment strings may be moved, so this should be called before any code
125  * that might try to hang onto a getenv() result.)
126  */
127 char	  **
save_ps_display_args(int argc,char ** argv)128 save_ps_display_args(int argc, char **argv)
129 {
130 	save_argc = argc;
131 	save_argv = argv;
132 
133 #if defined(PS_USE_CLOBBER_ARGV)
134 
135 	/*
136 	 * If we're going to overwrite the argv area, count the available space.
137 	 * Also move the environment to make additional room.
138 	 */
139 	{
140 		char	   *end_of_area = NULL;
141 		char	  **new_environ;
142 		int			i;
143 
144 		/*
145 		 * check for contiguous argv strings
146 		 */
147 		for (i = 0; i < argc; i++)
148 		{
149 			if (i == 0 || end_of_area + 1 == argv[i])
150 				end_of_area = argv[i] + strlen(argv[i]);
151 		}
152 
153 		if (end_of_area == NULL)	/* probably can't happen? */
154 		{
155 			ps_buffer = NULL;
156 			ps_buffer_size = 0;
157 			return argv;
158 		}
159 
160 		/*
161 		 * check for contiguous environ strings following argv
162 		 */
163 		for (i = 0; environ[i] != NULL; i++)
164 		{
165 			if (end_of_area + 1 == environ[i])
166 				end_of_area = environ[i] + strlen(environ[i]);
167 		}
168 
169 		ps_buffer = argv[0];
170 		ps_buffer_size = end_of_area - argv[0];
171 
172 		/*
173 		 * move the environment out of the way
174 		 */
175 		new_environ = (char **) malloc((i + 1) * sizeof(char *));
176 		for (i = 0; environ[i] != NULL; i++)
177 			new_environ[i] = strdup(environ[i]);
178 		new_environ[i] = NULL;
179 		environ = new_environ;
180 	}
181 #endif							/* PS_USE_CLOBBER_ARGV */
182 
183 #if defined(PS_USE_CHANGE_ARGV) || defined(PS_USE_CLOBBER_ARGV)
184 
185 	/*
186 	 * If we're going to change the original argv[] then make a copy for
187 	 * argument parsing purposes.
188 	 *
189 	 * (NB: do NOT think to remove the copying of argv[], even though
190 	 * postmaster.c finishes looking at argv[] long before we ever consider
191 	 * changing the ps display.  On some platforms, getopt() keeps pointers
192 	 * into the argv array, and will get horribly confused when it is
193 	 * re-called to analyze a subprocess' argument string if the argv storage
194 	 * has been clobbered meanwhile.  Other platforms have other dependencies
195 	 * on argv[].
196 	 */
197 	{
198 		char	  **new_argv;
199 		int			i;
200 
201 		new_argv = (char **) malloc((argc + 1) * sizeof(char *));
202 		for (i = 0; i < argc; i++)
203 			new_argv[i] = strdup(argv[i]);
204 		new_argv[argc] = NULL;
205 
206 #if defined(__darwin__)
207 
208 		/*
209 		 * Darwin (and perhaps other NeXT-derived platforms?) has a static
210 		 * copy of the argv pointer, which we may fix like so:
211 		 */
212 		*_NSGetArgv() = new_argv;
213 #endif
214 
215 		argv = new_argv;
216 	}
217 #endif							/* PS_USE_CHANGE_ARGV or PS_USE_CLOBBER_ARGV */
218 
219 	return argv;
220 }
221 
222 /*
223  * Call this once during subprocess startup to set the identification
224  * values.	At this point, the original argv[] array may be overwritten.
225  */
226 void
init_ps_display(const char * username,const char * dbname,const char * host_info,const char * initial_str)227 init_ps_display(const char *username, const char *dbname,
228 				const char *host_info, const char *initial_str)
229 {
230 #ifndef PS_USE_NONE
231 	/* no ps display if you didn't call save_ps_display_args() */
232 	if (!save_argv)
233 		return;
234 #ifdef PS_USE_CLOBBER_ARGV
235 	/* If ps_buffer is a pointer, it might still be null */
236 	if (!ps_buffer)
237 		return;
238 #endif
239 
240 	/*
241 	 * Overwrite argv[] to point at appropriate space, if needed
242 	 */
243 
244 #ifdef PS_USE_CHANGE_ARGV
245 	save_argv[0] = ps_buffer;
246 	save_argv[1] = NULL;
247 #endif							/* PS_USE_CHANGE_ARGV */
248 
249 #ifdef PS_USE_CLOBBER_ARGV
250 	{
251 		int			i;
252 
253 		/* make extra argv slots point at end_of_area (a NUL) */
254 		for (i = 1; i < save_argc; i++)
255 			save_argv[i] = ps_buffer + ps_buffer_size;
256 	}
257 #endif							/* PS_USE_CLOBBER_ARGV */
258 
259 	/*
260 	 * Make fixed prefix of ps display.
261 	 */
262 
263 #ifdef PS_USE_SETPROCTITLE
264 
265 	/*
266 	 * apparently setproctitle() already adds a `progname: ' prefix to the ps
267 	 * line
268 	 */
269 	snprintf(ps_buffer, ps_buffer_size, "");
270 #else
271 	snprintf(ps_buffer, ps_buffer_size,
272 			 "pgpool: ");
273 #endif
274 
275 	ps_buffer_fixed_size = strlen(ps_buffer);
276 
277 	set_ps_display(initial_str, true);
278 #endif							/* not PS_USE_NONE */
279 }
280 
281 
282 
283 /*
284  * Call this to update the ps status display to a fixed prefix plus an
285  * indication of what you're currently doing passed in the argument.
286  */
287 void
set_ps_display(const char * activity,bool force)288 set_ps_display(const char *activity, bool force)
289 {
290 
291 	if (!force && !update_process_title)
292 		return;
293 
294 #ifndef PS_USE_NONE
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 
355 #endif							/* not PS_USE_NONE */
356 }
357 
358 
359 /*
360  * Returns what's currently in the ps display, in case someone needs
361  * it.	Note that only the activity part is returned.  On some platforms
362  * the string will not be null-terminated, so return the effective
363  * length into *displen.
364  */
365 const char *
get_ps_display(int * displen)366 get_ps_display(int *displen)
367 {
368 #ifdef PS_USE_CLOBBER_ARGV
369 	size_t		offset;
370 
371 	/* If ps_buffer is a pointer, it might still be null */
372 	if (!ps_buffer)
373 	{
374 		*displen = 0;
375 		return "";
376 	}
377 
378 	/* Remove any trailing spaces to offset the effect of PS_PADDING */
379 	offset = ps_buffer_size;
380 	while (offset > ps_buffer_fixed_size && ps_buffer[offset - 1] == PS_PADDING)
381 		offset--;
382 
383 	*displen = offset - ps_buffer_fixed_size;
384 #else
385 	*displen = strlen(ps_buffer + ps_buffer_fixed_size);
386 #endif
387 
388 	return ps_buffer + ps_buffer_fixed_size;
389 }
390 
391 /*
392  * Show ps idle status
393  */
394 void
pool_ps_idle_display(POOL_CONNECTION_POOL * backend)395 pool_ps_idle_display(POOL_CONNECTION_POOL * backend)
396 {
397 	StartupPacket *sp;
398 	char		psbuf[1024];
399 
400 	sp = MAIN_CONNECTION(backend)->sp;
401 	if (MAIN(backend)->tstate == 'T')
402 		snprintf(psbuf, sizeof(psbuf), "%s %s %s idle in transaction",
403 				 sp->user, sp->database, remote_ps_data);
404 	else
405 		snprintf(psbuf, sizeof(psbuf), "%s %s %s idle",
406 				 sp->user, sp->database, remote_ps_data);
407 	set_ps_display(psbuf, false);
408 }
409