Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_isready --- checks the status of the PostgreSQL server
4 : *
5 : * Copyright (c) 2013-2023, PostgreSQL Global Development Group
6 : *
7 : * src/bin/scripts/pg_isready.c
8 : *
9 : *-------------------------------------------------------------------------
10 : */
11 :
12 : #include "postgres_fe.h"
13 : #include "common.h"
14 : #include "common/logging.h"
15 : #include "fe_utils/option_utils.h"
16 :
17 : #define DEFAULT_CONNECT_TIMEOUT "3"
18 :
19 : static void
20 : help(const char *progname);
21 :
22 : int
3728 rhaas 23 CBC 5 : main(int argc, char **argv)
24 : {
25 : int c;
26 :
27 : const char *progname;
28 :
29 5 : const char *pghost = NULL;
30 5 : const char *pgport = NULL;
31 5 : const char *pguser = NULL;
32 5 : const char *pgdbname = NULL;
3726 33 5 : const char *connect_timeout = DEFAULT_CONNECT_TIMEOUT;
34 :
3589 fujii 35 5 : const char *pghost_str = NULL;
3426 36 5 : const char *pghostaddr_str = NULL;
3589 37 5 : const char *pgport_str = NULL;
38 :
39 : #define PARAMS_ARRAY_SIZE 7
40 :
41 : const char *keywords[PARAMS_ARRAY_SIZE];
42 : const char *values[PARAMS_ARRAY_SIZE];
43 :
3602 bruce 44 5 : bool quiet = false;
45 :
46 : PGPing rv;
3589 fujii 47 5 : PQconninfoOption *opts = NULL;
48 5 : PQconninfoOption *defs = NULL;
49 : PQconninfoOption *opt;
50 : PQconninfoOption *def;
51 5 : char *errmsg = NULL;
52 :
53 : /*
54 : * We accept user and database as options to avoid useless errors from
55 : * connecting with invalid params
56 : */
57 :
58 : static struct option long_options[] = {
59 : {"dbname", required_argument, NULL, 'd'},
60 : {"host", required_argument, NULL, 'h'},
61 : {"port", required_argument, NULL, 'p'},
62 : {"quiet", no_argument, NULL, 'q'},
63 : {"timeout", required_argument, NULL, 't'},
64 : {"username", required_argument, NULL, 'U'},
65 : {NULL, 0, NULL, 0}
66 : };
67 :
1469 peter 68 5 : pg_logging_init(argv[0]);
3728 rhaas 69 5 : progname = get_progname(argv[0]);
3726 70 5 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
3728 71 5 : handle_help_version_opts(argc, argv, progname, help);
72 :
3589 fujii 73 4 : while ((c = getopt_long(argc, argv, "d:h:p:qt:U:", long_options, NULL)) != -1)
74 : {
3728 rhaas 75 2 : switch (c)
76 : {
3728 rhaas 77 UBC 0 : case 'd':
78 0 : pgdbname = pg_strdup(optarg);
79 0 : break;
80 0 : case 'h':
81 0 : pghost = pg_strdup(optarg);
82 0 : break;
83 0 : case 'p':
84 0 : pgport = pg_strdup(optarg);
85 0 : break;
86 0 : case 'q':
87 0 : quiet = true;
88 0 : break;
3726 rhaas 89 CBC 1 : case 't':
90 1 : connect_timeout = pg_strdup(optarg);
91 1 : break;
3728 rhaas 92 UBC 0 : case 'U':
93 0 : pguser = pg_strdup(optarg);
94 0 : break;
3728 rhaas 95 CBC 1 : default:
96 : /* getopt_long already emitted a complaint */
366 tgl 97 1 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
98 :
99 : /*
100 : * We need to make sure we don't return 1 here because someone
101 : * checking the return code might infer unintended meaning
102 : */
3728 rhaas 103 1 : exit(PQPING_NO_ATTEMPT);
104 : }
105 : }
106 :
107 2 : if (optind < argc)
108 : {
1469 peter 109 UBC 0 : pg_log_error("too many command-line arguments (first is \"%s\")",
110 : argv[optind]);
366 tgl 111 0 : pg_log_error_hint("Try \"%s --help\" for more information.", progname);
112 :
113 : /*
114 : * We need to make sure we don't return 1 here because someone
115 : * checking the return code might infer unintended meaning
116 : */
3728 rhaas 117 0 : exit(PQPING_NO_ATTEMPT);
118 : }
119 :
3589 fujii 120 CBC 2 : keywords[0] = "host";
121 2 : values[0] = pghost;
122 2 : keywords[1] = "port";
123 2 : values[1] = pgport;
124 2 : keywords[2] = "user";
125 2 : values[2] = pguser;
126 2 : keywords[3] = "dbname";
127 2 : values[3] = pgdbname;
128 2 : keywords[4] = "connect_timeout";
129 2 : values[4] = connect_timeout;
130 2 : keywords[5] = "fallback_application_name";
131 2 : values[5] = progname;
132 2 : keywords[6] = NULL;
133 2 : values[6] = NULL;
134 :
135 : /*
136 : * Get the host and port so we can display them in our output
137 : */
3426 138 2 : if (pgdbname &&
3426 fujii 139 UBC 0 : (strncmp(pgdbname, "postgresql://", 13) == 0 ||
140 0 : strncmp(pgdbname, "postgres://", 11) == 0 ||
141 0 : strchr(pgdbname, '=') != NULL))
142 : {
3589 143 0 : opts = PQconninfoParse(pgdbname, &errmsg);
144 0 : if (opts == NULL)
145 : {
1469 peter 146 0 : pg_log_error("%s", errmsg);
3589 fujii 147 0 : exit(PQPING_NO_ATTEMPT);
148 : }
149 : }
150 :
3589 fujii 151 CBC 2 : defs = PQconndefaults();
152 2 : if (defs == NULL)
153 : {
1469 peter 154 UBC 0 : pg_log_error("could not fetch default options");
3589 fujii 155 0 : exit(PQPING_NO_ATTEMPT);
156 : }
157 :
3589 fujii 158 CBC 80 : for (opt = opts, def = defs; def->keyword; def++)
159 : {
3426 160 78 : if (strcmp(def->keyword, "host") == 0)
161 : {
3589 162 2 : if (opt && opt->val)
3589 fujii 163 UBC 0 : pghost_str = opt->val;
3589 fujii 164 CBC 2 : else if (pghost)
3589 fujii 165 UBC 0 : pghost_str = pghost;
3589 fujii 166 CBC 2 : else if (def->val)
167 2 : pghost_str = def->val;
168 : else
3589 fujii 169 UBC 0 : pghost_str = DEFAULT_PGSOCKET_DIR;
170 : }
3426 fujii 171 CBC 76 : else if (strcmp(def->keyword, "hostaddr") == 0)
172 : {
173 2 : if (opt && opt->val)
3426 fujii 174 UBC 0 : pghostaddr_str = opt->val;
3426 fujii 175 CBC 2 : else if (def->val)
3426 fujii 176 UBC 0 : pghostaddr_str = def->val;
177 : }
3589 fujii 178 CBC 74 : else if (strcmp(def->keyword, "port") == 0)
179 : {
180 2 : if (opt && opt->val)
3589 fujii 181 UBC 0 : pgport_str = opt->val;
3589 fujii 182 CBC 2 : else if (pgport)
3589 fujii 183 UBC 0 : pgport_str = pgport;
3589 fujii 184 CBC 2 : else if (def->val)
185 2 : pgport_str = def->val;
186 : }
187 :
188 78 : if (opt)
3589 fujii 189 UBC 0 : opt++;
190 : }
191 :
3728 rhaas 192 CBC 2 : rv = PQpingParams(keywords, values, 1);
193 :
194 2 : if (!quiet)
195 : {
3426 fujii 196 2 : printf("%s:%s - ",
197 : pghostaddr_str != NULL ? pghostaddr_str : pghost_str,
198 : pgport_str);
199 :
3728 rhaas 200 2 : switch (rv)
201 : {
202 1 : case PQPING_OK:
3054 fujii 203 1 : printf(_("accepting connections\n"));
3728 rhaas 204 1 : break;
3728 rhaas 205 UBC 0 : case PQPING_REJECT:
3054 fujii 206 0 : printf(_("rejecting connections\n"));
3728 rhaas 207 0 : break;
3728 rhaas 208 CBC 1 : case PQPING_NO_RESPONSE:
3054 fujii 209 1 : printf(_("no response\n"));
3728 rhaas 210 1 : break;
3728 rhaas 211 UBC 0 : case PQPING_NO_ATTEMPT:
3054 fujii 212 0 : printf(_("no attempt\n"));
3728 rhaas 213 0 : break;
214 0 : default:
3054 fujii 215 0 : printf(_("unknown\n"));
216 : }
217 : }
218 :
3728 rhaas 219 CBC 2 : exit(rv);
220 : }
221 :
222 : static void
223 1 : help(const char *progname)
224 : {
225 1 : printf(_("%s issues a connection check to a PostgreSQL database.\n\n"), progname);
226 1 : printf(_("Usage:\n"));
227 1 : printf(_(" %s [OPTION]...\n"), progname);
228 :
229 1 : printf(_("\nOptions:\n"));
230 1 : printf(_(" -d, --dbname=DBNAME database name\n"));
231 1 : printf(_(" -q, --quiet run quietly\n"));
232 1 : printf(_(" -V, --version output version information, then exit\n"));
233 1 : printf(_(" -?, --help show this help, then exit\n"));
234 :
235 1 : printf(_("\nConnection options:\n"));
236 1 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
237 1 : printf(_(" -p, --port=PORT database server port\n"));
3726 238 1 : printf(_(" -t, --timeout=SECS seconds to wait when attempting connection, 0 disables (default: %s)\n"), DEFAULT_CONNECT_TIMEOUT);
3563 peter_e 239 1 : printf(_(" -U, --username=USERNAME user name to connect as\n"));
1136 peter 240 1 : printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
241 1 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
3728 rhaas 242 1 : }
|