1 /* -*-pgsql-c-*- */
2 /*
3  * $Header$
4  *
5  * pgpool: a language independent connection pool server for PostgreSQL
6  * written by Tatsuo Ishii
7  *
8  * Copyright (c) 2003-2018	PgPool Global Development Group
9  *
10  * Permission to use, copy, modify, and distribute this software and
11  * its documentation for any purpose and without fee is hereby
12  * granted, provided that the above copyright notice appear in all
13  * copies and that both that copyright notice and this permission
14  * notice appear in supporting documentation, and that the name of the
15  * author not be used in advertising or publicity pertaining to
16  * distribution of the software without specific, written prior
17  * permission. The author makes no representations about the
18  * suitability of this software for any purpose.  It is provided "as
19  * is" without express or implied warranty.
20  */
21 #include "pool.h"
22 #include "pool_config.h"
23 #include <fcntl.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 
28 
29 #ifdef HAVE_GETOPT_H
30 #include <getopt.h>
31 #else
32 #include "utils/getopt_long.h"
33 #endif
34 
35 #include <errno.h>
36 #include <string.h>
37 #include <libgen.h>
38 #include "utils/elog.h"
39 #include "utils/palloc.h"
40 #include "utils/memutils.h"
41 #include "utils/pool_path.h"
42 
43 #include "version.h"
44 #include "auth/pool_passwd.h"
45 #include "auth/pool_hba.h"
46 #include "query_cache/pool_memqcache.h"
47 #include "watchdog/wd_utils.h"
48 #include "pool_config_variables.h"
49 
50 static void daemonize(void);
51 static char	*get_pid_file_path(void);
52 static int read_pid_file(void);
53 static void write_pid_file(void);
54 static void usage(void);
55 static void show_version(void);
56 static void stop_me(void);
57 static void FileUnlink(int code, Datum path);
58 
59 char *pcp_conf_file = NULL; /* absolute path of the pcp.conf */
60 char *conf_file = NULL;		/* absolute path of the pgpool.conf */
61 char *hba_file = NULL;		/* absolute path of the hba.conf */
62 char *base_dir = NULL;		/* The working dir from where pgpool was invoked from */
63 
64 static int not_detach = 0;		/* non 0 if non detach option (-n) is given */
65 int stop_sig = SIGTERM;		/* stopping signal default value */
66 int myargc;
67 char **myargv;
68 int assert_enabled = 0;
69 
main(int argc,char ** argv)70 int main(int argc, char **argv)
71 {
72 	int opt;
73 	int debug_level = 0;
74 	int	optindex;
75 	bool discard_status = false;
76 	bool clear_memcache_oidmaps = false;
77 
78 	char pcp_conf_file_path[POOLMAXPATHLEN+1];
79 	char conf_file_path[POOLMAXPATHLEN+1];
80 	char hba_file_path[POOLMAXPATHLEN+1];
81 
82 	static struct option long_options[] = {
83 		{"hba-file", required_argument, NULL, 'a'},
84 		{"debug", no_argument, NULL, 'd'},
85 		{"config-file", required_argument, NULL, 'f'},
86 		{"pcp-file", required_argument, NULL, 'F'},
87 		{"help", no_argument, NULL, 'h'},
88 		{"mode", required_argument, NULL, 'm'},
89 		{"dont-detach", no_argument, NULL, 'n'},
90 		{"discard-status", no_argument, NULL, 'D'},
91 		{"clear-oidmaps", no_argument, NULL, 'C'},
92 		{"debug-assertions", no_argument, NULL, 'x'},
93 		{"version", no_argument, NULL, 'v'},
94 		{NULL, 0, NULL, 0}
95 	};
96 
97 	myargc = argc;
98 	myargv = argv;
99 
100 	snprintf(conf_file_path, sizeof(conf_file_path), "%s/%s", DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
101 	snprintf(pcp_conf_file_path, sizeof(pcp_conf_file_path), "%s/%s", DEFAULT_CONFIGDIR, PCP_PASSWD_FILE_NAME);
102 	snprintf(hba_file_path, sizeof(hba_file_path), "%s/%s", DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
103     while ((opt = getopt_long(argc, argv, "a:df:F:hm:nDCxv", long_options, &optindex)) != -1)
104 	{
105 		switch (opt)
106 		{
107 			case 'a':    /* specify hba configuration file */
108 				if (!optarg)
109 				{
110 					usage();
111 					exit(1);
112 				}
113 				strlcpy(hba_file_path, optarg, sizeof(hba_file_path));
114 				break;
115 
116 			case 'x':	/* enable cassert */
117 				assert_enabled = 1;
118 				break;
119 
120 			case 'd':	/* debug option */
121 				debug_level = 1;
122 				break;
123 
124 			case 'f':	/* specify configuration file */
125 				if (!optarg)
126 				{
127 					usage();
128 					exit(1);
129 				}
130 				strlcpy(conf_file_path, optarg, sizeof(conf_file_path));
131 				break;
132 
133 			case 'F':   /* specify PCP password file */
134 				if (!optarg)
135 				{
136 					usage();
137 					exit(1);
138 				}
139 				strlcpy(pcp_conf_file_path, optarg, sizeof(pcp_conf_file_path));
140 				break;
141 
142 			case 'h':
143 				usage();
144 				exit(0);
145 				break;
146 
147 			case 'm':	/* stop mode */
148 				if (!optarg)
149 				{
150 					usage();
151 					exit(1);
152 				}
153 				if (*optarg == 's' || !strcmp("smart", optarg))
154 					stop_sig = SIGTERM;		/* smart shutdown */
155 				else if (*optarg == 'f' || !strcmp("fast", optarg))
156 					stop_sig = SIGINT;		/* fast shutdown */
157 				else if (*optarg == 'i' || !strcmp("immediate", optarg))
158 					stop_sig = SIGQUIT;		/* immediate shutdown */
159 				else
160 				{
161 					usage();
162 					exit(1);
163 				}
164 				break;
165 
166 			case 'n':	/* no detaching control ttys */
167 				not_detach = 1;
168 				break;
169 
170 			case 'D':	/* discard pgpool_status */
171 				discard_status = true;
172 				break;
173 
174 			case 'C': /* discard caches in memcached */
175 				clear_memcache_oidmaps = true;
176 				break;
177 
178 			case 'v':
179 				show_version();
180 				exit(0);
181 
182 			default:
183 				usage();
184 				exit(1);
185 		}
186 	}
187 #ifdef USE_SSL
188 	/* global ssl init */
189 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined (LIBRESSL_VERSION_NUMBER))
190 	OPENSSL_init_ssl(0, NULL);
191 #else
192 	SSL_library_init();
193 #endif
194 	SSL_load_error_strings();
195 #endif /* USE_SSL */
196 
197 	myargv = save_ps_display_args(myargc, myargv);
198 	/* create MemoryContexts */
199 	MemoryContextInit();
200 
201 	/* load the CWD before it is changed */
202 	base_dir = get_current_working_dir();
203 	/* convert all the paths to absolute paths*/
204 	conf_file = make_absolute_path(conf_file_path, base_dir);
205 	pcp_conf_file = make_absolute_path(pcp_conf_file_path, base_dir);
206 	hba_file = make_absolute_path(hba_file_path, base_dir);
207 
208 	mypid = getpid();
209 
210 	pool_init_config();
211 
212 	pool_get_config(conf_file, CFGCXT_INIT);
213 
214 	/*
215 	 * Override debug level
216 	 * if command line -d arg is given adjust the log_min_message config variable
217 	 */
218 	if(debug_level > 0 && pool_config->log_min_messages > DEBUG1)
219 		set_one_config_option("log_min_messages", "DEBUG1",CFGCXT_INIT, PGC_S_ARGV, INFO);
220 
221 	/*
222 	 * If a non-switch argument remains, then it should be either "reload" or "stop".
223 	 */
224 	if (optind == (argc - 1))
225 	{
226 		if (!strcmp(argv[optind], "reload"))
227 		{
228 				pid_t pid;
229 
230 				pid = read_pid_file();
231 				if (pid < 0)
232 				{
233 					ereport(FATAL,
234 						(return_code(1),
235                              errmsg("could not read pid file")));
236 				}
237 
238 				if (kill(pid, SIGHUP) == -1)
239 				{
240 					ereport(FATAL,
241 						(return_code(1),
242 						 errmsg("could not reload configuration file pid: %d. reason: %s", pid, strerror(errno))));
243 				}
244 				exit(0);
245 		}
246 		if (!strcmp(argv[optind], "stop"))
247 		{
248 			stop_me();
249 			exit(0);
250 		}
251 		else
252 		{
253 			usage();
254 			exit(1);
255 		}
256 	}
257 	/*
258 	 * else if no non-switch argument remains, then it should be a start request
259 	 */
260 	else if (optind == argc)
261 	{
262 		int pid = read_pid_file();
263 		if (pid > 0)
264 		{
265 			if (kill(pid, 0) == 0)
266 			{
267 				fprintf(stderr, "ERROR: pid file found. is another pgpool(%d) is running?\n", pid);
268 				exit(EXIT_FAILURE);
269 			}
270 			else
271 				fprintf(stderr, "NOTICE: pid file found but it seems bogus. Trying to start pgpool anyway...\n");
272 		}
273 	}
274 	/*
275 	 * otherwise an error...
276 	 */
277 	else
278 	{
279 		usage();
280 		exit(1);
281 	}
282 
283 	if (pool_config->enable_pool_hba)
284 		load_hba(hba_file);
285 
286 	/* check effective user id for watchdog */
287 	/* watchdog must be started under the privileged user */
288 	wd_check_network_command_configurations();
289 
290 	/* set signal masks */
291 	poolinitmask();
292 
293 	if (not_detach)
294 		write_pid_file();
295 	else
296 		daemonize();
297 	/*
298 	 * Locate pool_passwd
299 	 * The default file name "pool_passwd" can be changed by setting
300 	 * pgpool.conf's "pool_passwd" directive.
301 	 */
302 	if (strcmp("", pool_config->pool_passwd))
303 	{
304 		char pool_passwd[POOLMAXPATHLEN+1];
305 		char dirnamebuf[POOLMAXPATHLEN+1];
306 		char *dirp;
307 
308 		strlcpy(dirnamebuf, conf_file, sizeof(dirnamebuf));
309 		dirp = dirname(dirnamebuf);
310 		snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s",
311 				 dirp, pool_config->pool_passwd);
312 		pool_init_pool_passwd(pool_passwd, POOL_PASSWD_R);
313 	}
314 
315 	pool_semaphore_create(MAX_NUM_SEMAPHORES);
316 
317 	PgpoolMain(discard_status, clear_memcache_oidmaps); /* this is an infinate loop */
318 
319 	exit(0);
320 
321 }
322 
show_version(void)323 static void show_version(void)
324 {
325 	fprintf(stderr, "%s version %s (%s)\n",	PACKAGE, VERSION, PGPOOLVERSION);
326 }
327 
usage(void)328 static void usage(void)
329 {
330 	fprintf(stderr, "%s version %s (%s),\n",	PACKAGE, VERSION, PGPOOLVERSION);
331 	fprintf(stderr, "  A generic connection pool/replication/load balance server for PostgreSQL\n\n");
332 	fprintf(stderr, "Usage:\n");
333 	fprintf(stderr, "  pgpool [ -c] [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ]\n");
334 	fprintf(stderr, "         [ -n ] [ -D ] [ -d ]\n");
335 	fprintf(stderr, "  pgpool [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ]\n");
336 	fprintf(stderr, "         [ -m SHUTDOWN-MODE ] stop\n");
337 	fprintf(stderr, "  pgpool [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ] reload\n\n");
338 	fprintf(stderr, "Common options:\n");
339 	fprintf(stderr, "  -a, --hba-file=HBA_CONFIG_FILE\n");
340 	fprintf(stderr, "                      Set the path to the pool_hba.conf configuration file\n");
341 	fprintf(stderr, "                      (default: %s/%s)\n",DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
342 	fprintf(stderr, "  -f, --config-file=CONFIG_FILE\n");
343 	fprintf(stderr, "                      Set the path to the pgpool.conf configuration file\n");
344 	fprintf(stderr, "                      (default: %s/%s)\n",DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
345 	fprintf(stderr, "  -F, --pcp-file=PCP_CONFIG_FILE\n");
346 	fprintf(stderr, "                      Set the path to the pcp.conf configuration file\n");
347 	fprintf(stderr, "                      (default: %s/%s)\n",DEFAULT_CONFIGDIR, PCP_PASSWD_FILE_NAME);
348 	fprintf(stderr, "  -h, --help          Print this help\n\n");
349 	fprintf(stderr, "Start options:\n");
350 	fprintf(stderr, "  -C, --clear-oidmaps Clear query cache oidmaps when memqcache_method is memcached\n");
351 	fprintf(stderr, "                      (If shmem, discards whenever pgpool starts.)\n");
352 	fprintf(stderr, "  -n, --dont-detach   Don't run in daemon mode, does not detach control tty\n");
353 	fprintf(stderr, "  -x, --debug-assertions   Turns on various assertion checks, This is a debugging aid\n");
354 	fprintf(stderr, "  -D, --discard-status Discard pgpool_status file and do not restore previous status\n");
355 	fprintf(stderr, "  -d, --debug         Debug mode\n\n");
356 	fprintf(stderr, "Stop options:\n");
357 	fprintf(stderr, "  -m, --mode=SHUTDOWN-MODE\n");
358 	fprintf(stderr, "                      Can be \"smart\", \"fast\", or \"immediate\"\n\n");
359 	fprintf(stderr, "Shutdown modes are:\n");
360 	fprintf(stderr, "  smart       quit after all clients have disconnected\n");
361 	fprintf(stderr, "  fast        quit directly, with proper shutdown\n");
362 	fprintf(stderr, "  immediate   the same mode as fast\n");
363 }
364 
365 /*
366 * detach control ttys
367 */
daemonize(void)368 static void daemonize(void)
369 {
370 	int			i;
371 	pid_t		pid;
372 	int			fdlimit;
373 
374 	pid = fork();
375 	if (pid == (pid_t) -1)
376 	{
377 		ereport(FATAL,
378 			(errmsg("could not daemonize the pgpool-II"),
379 				errdetail("fork() system call failed with reason: \"%s\"", strerror(errno) )));
380 	}
381 	else if (pid > 0)
382 	{			/* parent */
383 		exit(0);
384 	}
385 
386 #ifdef HAVE_SETSID
387 	if (setsid() < 0)
388 	{
389 		ereport(FATAL,
390 			(errmsg("could not daemonize the pgpool-II"),
391 				errdetail("setsid() system call failed with reason: \"%s\"", strerror(errno) )));
392 	}
393 #endif
394 
395 	mypid = getpid();
396 	write_pid_file();
397 	if(chdir("/"))
398 		ereport(WARNING,
399 			(errmsg("change directory failed"),
400                  errdetail("chdir() system call failed with reason: \"%s\"", strerror(errno) )));
401 
402 	/* redirect stdin, stdout and stderr to /dev/null */
403 	i = open("/dev/null", O_RDWR);
404 	if(i < 0)
405 	{
406 		ereport(WARNING,
407 			(errmsg("failed to open \"/dev/null\", open() failed with error \"%s\"", strerror(errno))));
408 	}
409 	else
410 	{
411 		dup2(i, 0);
412 		dup2(i, 1);
413 		dup2(i, 2);
414 		close(i);
415 	}
416 	/* close syslog connection for daemonizing */
417 	if (pool_config->log_destination & LOG_DESTINATION_SYSLOG)
418 	{
419 		closelog();
420 	}
421 
422 	/* close other file descriptors */
423     fdlimit = sysconf(_SC_OPEN_MAX);
424     for (i = 3; i < fdlimit; i++)
425 		close(i);
426 }
427 
428 /*
429 * stop myself
430 */
stop_me(void)431 static void stop_me(void)
432 {
433 	pid_t pid;
434 	char *pid_file;
435 
436 	pid = read_pid_file();
437 	if (pid < 0)
438 	{
439 		ereport(FATAL,
440 			(errmsg("could not read pid file")));
441 	}
442 
443 	if (kill(pid, stop_sig) == -1)
444 	{
445 		ereport(FATAL,
446 			(errmsg("could not stop process with pid: %d", pid),
447 				errdetail("\"%s\"", strerror(errno))));
448 	}
449 	ereport(LOG,
450 		(errmsg ("stop request sent to pgpool. waiting for termination...")));
451 
452 	while (kill(pid, 0) == 0)
453 	{
454 		fprintf(stderr, ".");
455 		sleep(1);
456 	}
457 	fprintf(stderr, "done.\n");
458 	pid_file = get_pid_file_path();
459 	unlink(pid_file);
460 	pfree(pid_file);
461 }
462 
463 /*
464  * The function returns the palloc'd copy of pid_file_path,
465  * caller must free it after use
466  */
get_pid_file_path(void)467 static char *get_pid_file_path(void)
468 {
469 	char *new = NULL;
470 	if (!is_absolute_path(pool_config->pid_file_name))
471 	{
472 		/*
473 		 * some implementations of dirname() may modify the
474 		 * string argument passed to it, so do not use the original
475 		 * conf_file as an argument
476 		 */
477 		char *conf_file_copy = pstrdup(conf_file);
478 		char *conf_dir = dirname(conf_file_copy);
479 		size_t  path_size;
480 		if (conf_dir == NULL)
481 		{
482 			ereport(LOG,
483 					(errmsg("failed to get the dirname of pid file:\"%s\". reason: %s",
484 				   pool_config->pid_file_name, strerror(errno))));
485 			return NULL;
486 		}
487 		path_size = strlen(conf_dir) + strlen(pool_config->pid_file_name) + 1 + 1;
488 		new = palloc(path_size);
489 		snprintf(new, path_size, "%s/%s",conf_dir, pool_config->pid_file_name);
490 
491 		ereport(DEBUG1,
492 				(errmsg("pid file location is \"%s\"",
493 						new)));
494 
495 		pfree(conf_file_copy);
496 	}
497 	else
498 	{
499 		new = pstrdup(pool_config->pid_file_name);
500 	}
501 
502 	return new;
503 }
504 
505 /*
506 * read the pid file
507 */
read_pid_file(void)508 static int read_pid_file(void)
509 {
510 	int fd;
511 	int readlen;
512 	char pidbuf[128];
513 	char *pid_file = get_pid_file_path();
514 
515 	if (pid_file == NULL)
516 	{
517 		ereport(FATAL,
518 				(errmsg("failed to read pid file"),
519 				 errdetail("failed to get pid file path from \"%s\"",
520 						   pool_config->pid_file_name)));
521 	}
522 	fd = open(pid_file, O_RDONLY);
523 	if (fd == -1)
524 	{
525 		pfree(pid_file);
526 		return -1;
527 	}
528 	if ((readlen = read(fd, pidbuf, sizeof(pidbuf))) == -1)
529 	{
530 		close(fd);
531 		pfree(pid_file);
532 		ereport(FATAL,
533 			(errmsg("could not read pid file as \"%s\". reason: %s",
534 				   pool_config->pid_file_name, strerror(errno))));
535 	}
536 	else if (readlen == 0)
537 	{
538 		close(fd);
539 		pfree(pid_file);
540 		ereport(FATAL,
541 			(errmsg("EOF detected while reading pid file \"%s\". reason: %s",
542 				   pool_config->pid_file_name, strerror(errno))));
543 	}
544 	pfree(pid_file);
545 	close(fd);
546 	return(atoi(pidbuf));
547 }
548 
549 /*
550 * write the pid file
551 */
write_pid_file(void)552 static void write_pid_file(void)
553 {
554 	int fd;
555 	char pidbuf[128];
556 	char *pid_file = get_pid_file_path();
557 
558 	if (pid_file == NULL)
559 	{
560 		ereport(FATAL,
561 				(errmsg("failed to write pid file"),
562 				 errdetail("failed to get pid file path from \"%s\"",
563 						pool_config->pid_file_name)));
564 	}
565 
566 	fd = open(pid_file, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
567 	if (fd == -1)
568 	{
569 		ereport(FATAL,
570 			(errmsg("could not open pid file as %s. reason: %s",
571 				   pool_config->pid_file_name, strerror(errno))));
572 	}
573 	snprintf(pidbuf, sizeof(pidbuf), "%d", (int)getpid());
574 	if (write(fd, pidbuf, strlen(pidbuf)+1) == -1)
575 	{
576 		close(fd);
577 		pfree(pid_file);
578 		ereport(FATAL,
579 			(errmsg("could not write pid file as %s. reason: %s",
580 				   pool_config->pid_file_name, strerror(errno))));
581 	}
582 	if (fsync(fd) == -1)
583 	{
584 		close(fd);
585 		pfree(pid_file);
586 		ereport(FATAL,
587 			(errmsg("could not fsync pid file as %s. reason: %s",
588 				   pool_config->pid_file_name, strerror(errno))));
589 	}
590 	if (close(fd) == -1)
591 	{
592 		pfree(pid_file);
593 		ereport(FATAL,
594 			(errmsg("could not close pid file as %s. reason: %s",
595 				   pool_config->pid_file_name, strerror(errno))));
596 	}
597 	/* register the call back to delete the pid file at system exit */
598 	on_proc_exit(FileUnlink, (Datum) pid_file);
599 }
600 
601 /*
602  * get_config_file_name: return full path of pgpool.conf.
603  */
get_config_file_name(void)604 char *get_config_file_name(void)
605 {
606 	return conf_file;
607 }
608 
609 /*
610  * get_hba_file_name: return full path of pool_hba.conf.
611  */
get_hba_file_name(void)612 char *get_hba_file_name(void)
613 {
614 	return hba_file;
615 }
616 /*
617  * Call back function to unlink the file
618  */
FileUnlink(int code,Datum path)619 static void FileUnlink(int code, Datum path)
620 {
621 	char* filePath = (char*)path;
622 	if (unlink(filePath) == 0) return;
623 	/*
624 	 * We are already exiting the system just produce a log entry to report an error
625 	 */
626 	ereport(LOG,
627 		(errmsg("unlink failed for file at path \"%s\"", filePath),
628 			errdetail("\"%s\"", strerror(errno))));
629 }
630