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 strlcpy(dirnamebuf, conf_file, sizeof(dirnamebuf));
341 dirp = dirname(dirnamebuf);
342 snprintf(pool_passwd, sizeof(pool_passwd), "%s/%s",
343 dirp, pool_config->pool_passwd);
344 pool_init_pool_passwd(pool_passwd, POOL_PASSWD_R);
345 }
346
347 pool_semaphore_create(MAX_NUM_SEMAPHORES);
348
349 PgpoolMain(discard_status, clear_memcache_oidmaps); /* this is an infinate
350 * loop */
351
352 exit(0);
353
354 }
355
356 static void
show_version(void)357 show_version(void)
358 {
359 fprintf(stderr, "%s version %s (%s)\n", PACKAGE, VERSION, PGPOOLVERSION);
360 }
361
362 static void
usage(void)363 usage(void)
364 {
365 char homedir[POOLMAXPATHLEN];
366
367 if (!get_home_directory(homedir, sizeof(homedir)))
368 strncpy(homedir, "USER-HOME-DIR", POOLMAXPATHLEN);
369
370 fprintf(stderr, "%s version %s (%s),\n", PACKAGE, VERSION, PGPOOLVERSION);
371 fprintf(stderr, " A generic connection pool/replication/load balance server for PostgreSQL\n\n");
372 fprintf(stderr, "Usage:\n");
373 fprintf(stderr, " pgpool [ -c] [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ]\n");
374 fprintf(stderr, " [ -n ] [ -D ] [ -d ]\n");
375 fprintf(stderr, " pgpool [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ]\n");
376 fprintf(stderr, " [ -m SHUTDOWN-MODE ] stop\n");
377 fprintf(stderr, " pgpool [ -f CONFIG_FILE ] [ -F PCP_CONFIG_FILE ] [ -a HBA_CONFIG_FILE ] reload\n\n");
378 fprintf(stderr, "Common options:\n");
379 fprintf(stderr, " -a, --hba-file=HBA_CONFIG_FILE\n");
380 fprintf(stderr, " Set the path to the pool_hba.conf configuration file\n");
381 fprintf(stderr, " (default: %s/%s)\n", DEFAULT_CONFIGDIR, HBA_CONF_FILE_NAME);
382 fprintf(stderr, " -f, --config-file=CONFIG_FILE\n");
383 fprintf(stderr, " Set the path to the pgpool.conf configuration file\n");
384 fprintf(stderr, " (default: %s/%s)\n", DEFAULT_CONFIGDIR, POOL_CONF_FILE_NAME);
385 fprintf(stderr, " -k, --key-file=KEY_FILE\n");
386 fprintf(stderr, " Set the path to the pgpool key file\n");
387 fprintf(stderr, " (default: %s/%s)\n", homedir, POOLKEYFILE);
388 fprintf(stderr, " can be over ridden by %s environment variable\n", POOLKEYFILEENV);
389 fprintf(stderr, " -F, --pcp-file=PCP_CONFIG_FILE\n");
390 fprintf(stderr, " Set the path to the pcp.conf configuration file\n");
391 fprintf(stderr, " (default: %s/%s)\n", DEFAULT_CONFIGDIR, PCP_PASSWD_FILE_NAME);
392 fprintf(stderr, " -h, --help Print this help\n\n");
393 fprintf(stderr, "Start options:\n");
394 fprintf(stderr, " -C, --clear-oidmaps Clear query cache oidmaps when memqcache_method is memcached\n");
395 fprintf(stderr, " (If shmem, discards whenever pgpool starts.)\n");
396 fprintf(stderr, " -n, --dont-detach Don't run in daemon mode, does not detach control tty\n");
397 fprintf(stderr, " -x, --debug-assertions Turns on various assertion checks, This is a debugging aid\n");
398 fprintf(stderr, " -D, --discard-status Discard pgpool_status file and do not restore previous status\n");
399 fprintf(stderr, " -d, --debug Debug mode\n\n");
400 fprintf(stderr, "Stop options:\n");
401 fprintf(stderr, " -m, --mode=SHUTDOWN-MODE\n");
402 fprintf(stderr, " Can be \"smart\", \"fast\", or \"immediate\"\n\n");
403 fprintf(stderr, "Shutdown modes are:\n");
404 fprintf(stderr, " smart quit after all clients have disconnected\n");
405 fprintf(stderr, " fast quit directly, with proper shutdown\n");
406 fprintf(stderr, " immediate the same mode as fast\n");
407 }
408
409 static bool
get_pool_key_filename(char * poolKeyFile)410 get_pool_key_filename(char *poolKeyFile)
411 {
412 char *passfile_env;
413
414 if ((passfile_env = getenv(POOLKEYFILEENV)) != NULL)
415 {
416 /* use the literal path from the environment, if set */
417 strlcpy(poolKeyFile, passfile_env, POOLMAXPATHLEN);
418 }
419 else
420 {
421 char homedir[POOLMAXPATHLEN];
422
423 if (!get_home_directory(homedir, sizeof(homedir)))
424 return false;
425 snprintf(poolKeyFile, POOLMAXPATHLEN + sizeof(POOLKEYFILE) + 1, "%s/%s", homedir, POOLKEYFILE);
426 }
427 return true;
428 }
429
430
431 char *
get_pool_key(void)432 get_pool_key(void)
433 {
434 return pool_key;
435 }
436
437 /*
438 * detach control ttys
439 */
440 static void
daemonize(void)441 daemonize(void)
442 {
443 int i;
444 pid_t pid;
445 int fdlimit;
446
447 pid = fork();
448 if (pid == (pid_t) -1)
449 {
450 ereport(FATAL,
451 (errmsg("could not daemonize the pgpool-II"),
452 errdetail("fork() system call failed with reason: \"%m\"")));
453 }
454 else if (pid > 0)
455 { /* parent */
456 exit(0);
457 }
458
459 #ifdef HAVE_SETSID
460 if (setsid() < 0)
461 {
462 ereport(FATAL,
463 (errmsg("could not daemonize the pgpool-II"),
464 errdetail("setsid() system call failed with reason: \"%m\"")));
465 }
466 #endif
467
468 mypid = getpid();
469 write_pid_file();
470 if (chdir("/"))
471 ereport(WARNING,
472 (errmsg("change directory failed"),
473 errdetail("chdir() system call failed with reason: \"%m\"")));
474
475 /* redirect stdin, stdout and stderr to /dev/null */
476 i = open("/dev/null", O_RDWR);
477 if (i < 0)
478 {
479 ereport(WARNING,
480 (errmsg("failed to open \"/dev/null\""),
481 errdetail("%m")));
482 }
483 else
484 {
485 dup2(i, 0);
486 dup2(i, 1);
487 dup2(i, 2);
488 close(i);
489 }
490 /* close syslog connection for daemonizing */
491 if (pool_config->log_destination & LOG_DESTINATION_SYSLOG)
492 {
493 closelog();
494 }
495
496 /* close other file descriptors */
497 fdlimit = sysconf(_SC_OPEN_MAX);
498 for (i = 3; i < fdlimit; i++)
499 close(i);
500 }
501
502 /*
503 * stop myself
504 */
505 static void
stop_me(void)506 stop_me(void)
507 {
508 pid_t pid;
509 char *pid_file;
510
511 pid = read_pid_file();
512 if (pid < 0)
513 {
514 ereport(FATAL,
515 (errmsg("could not read pid file")));
516 }
517
518 if (kill(pid, stop_sig) == -1)
519 {
520 ereport(FATAL,
521 (errmsg("could not stop process with pid: %d", pid),
522 errdetail("%m")));
523 }
524 ereport(LOG,
525 (errmsg("stop request sent to pgpool. waiting for termination...")));
526
527 while (kill(pid, 0) == 0)
528 {
529 fprintf(stderr, ".");
530 sleep(1);
531 }
532 fprintf(stderr, "done.\n");
533 pid_file = get_pid_file_path();
534 unlink(pid_file);
535 pfree(pid_file);
536 }
537
538 /*
539 * The function returns the palloc'd copy of pid_file_path,
540 * caller must free it after use
541 */
542 static char *
get_pid_file_path(void)543 get_pid_file_path(void)
544 {
545 char *new = NULL;
546
547 if (!is_absolute_path(pool_config->pid_file_name))
548 {
549 /*
550 * some implementations of dirname() may modify the string argument
551 * passed to it, so do not use the original conf_file as an argument
552 */
553 char *conf_file_copy = pstrdup(conf_file);
554 char *conf_dir = dirname(conf_file_copy);
555 size_t path_size;
556
557 if (conf_dir == NULL)
558 {
559 ereport(LOG,
560 (errmsg("failed to get the dirname of pid file:\"%s\"",
561 pool_config->pid_file_name),
562 errdetail("%m")));
563 return NULL;
564 }
565 path_size = strlen(conf_dir) + strlen(pool_config->pid_file_name) + 1 + 1;
566 new = palloc(path_size);
567 snprintf(new, path_size, "%s/%s", conf_dir, pool_config->pid_file_name);
568
569 ereport(DEBUG1,
570 (errmsg("pid file location is \"%s\"",
571 new)));
572
573 pfree(conf_file_copy);
574 }
575 else
576 {
577 new = pstrdup(pool_config->pid_file_name);
578 }
579
580 return new;
581 }
582
583 /*
584 * read the pid file
585 */
586 static int
read_pid_file(void)587 read_pid_file(void)
588 {
589 int fd;
590 int readlen;
591 char pidbuf[128];
592 char *pid_file = get_pid_file_path();
593
594 if (pid_file == NULL)
595 {
596 ereport(FATAL,
597 (errmsg("failed to read pid file"),
598 errdetail("failed to get pid file path from \"%s\"",
599 pool_config->pid_file_name)));
600 }
601 fd = open(pid_file, O_RDONLY);
602 if (fd == -1)
603 {
604 pfree(pid_file);
605 return -1;
606 }
607 if ((readlen = read(fd, pidbuf, sizeof(pidbuf))) == -1)
608 {
609 close(fd);
610 pfree(pid_file);
611 ereport(FATAL,
612 (errmsg("could not read pid file \"%s\"",
613 pool_config->pid_file_name),
614 errdetail("%m")));
615 }
616 else if (readlen == 0)
617 {
618 close(fd);
619 pfree(pid_file);
620 ereport(FATAL,
621 (errmsg("EOF detected while reading pid file \"%s\"",
622 pool_config->pid_file_name),
623 errdetail("%m")));
624 }
625 pfree(pid_file);
626 close(fd);
627 return (atoi(pidbuf));
628 }
629
630 /*
631 * write the pid file
632 */
633 static void
write_pid_file(void)634 write_pid_file(void)
635 {
636 int fd;
637 char pidbuf[128];
638 char *pid_file = get_pid_file_path();
639
640 if (pid_file == NULL)
641 {
642 ereport(FATAL,
643 (errmsg("failed to write pid file"),
644 errdetail("failed to get pid file path from \"%s\"",
645 pool_config->pid_file_name)));
646 }
647
648 fd = open(pid_file, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
649 if (fd == -1)
650 {
651 ereport(FATAL,
652 (errmsg("could not open pid file \"%s\"",
653 pool_config->pid_file_name),
654 errdetail("%m")));
655 }
656 snprintf(pidbuf, sizeof(pidbuf), "%d", (int) getpid());
657 if (write(fd, pidbuf, strlen(pidbuf) + 1) == -1)
658 {
659 close(fd);
660 pfree(pid_file);
661 ereport(FATAL,
662 (errmsg("could not write pid file \"%s\"",
663 pool_config->pid_file_name),
664 errdetail("%m")));
665 }
666 if (fsync(fd) == -1)
667 {
668 close(fd);
669 pfree(pid_file);
670 ereport(FATAL,
671 (errmsg("could not fsync pid file \"%s\"",
672 pool_config->pid_file_name),
673 errdetail("%m")));
674 }
675 if (close(fd) == -1)
676 {
677 pfree(pid_file);
678 ereport(FATAL,
679 (errmsg("could not close pid file \"%s\"",
680 pool_config->pid_file_name),
681 errdetail("%m")));
682 }
683 /* register the call back to delete the pid file at system exit */
684 on_proc_exit(FileUnlink, (Datum) pid_file);
685 }
686
687 /*
688 * get_config_file_name: return full path of pgpool.conf.
689 */
690 char *
get_config_file_name(void)691 get_config_file_name(void)
692 {
693 return conf_file;
694 }
695
696 /*
697 * get_hba_file_name: return full path of pool_hba.conf.
698 */
699 char *
get_hba_file_name(void)700 get_hba_file_name(void)
701 {
702 return hba_file;
703 }
704
705 /*
706 * Call back function to unlink the file
707 */
708 static void
FileUnlink(int code,Datum path)709 FileUnlink(int code, Datum path)
710 {
711 char *filePath = (char *) path;
712
713 if (unlink(filePath) == 0)
714 return;
715
716 /*
717 * We are already exiting the system just produce a log entry to report an
718 * error
719 */
720 ereport(LOG,
721 (errmsg("unlink failed for file at path \"%s\"", filePath),
722 errdetail("%m")));
723 }
724