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