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