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