Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_isready --- checks the status of the PostgreSQL server
4 : *
5 : * Copyright (c) 2013-2024, 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
23 10 : main(int argc, char **argv)
24 : {
25 : int c;
26 :
27 : const char *progname;
28 :
29 10 : const char *pghost = NULL;
30 10 : const char *pgport = NULL;
31 10 : const char *pguser = NULL;
32 10 : const char *pgdbname = NULL;
33 10 : const char *connect_timeout = DEFAULT_CONNECT_TIMEOUT;
34 :
35 10 : const char *pghost_str = NULL;
36 10 : const char *pghostaddr_str = NULL;
37 10 : 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 :
44 10 : bool quiet = false;
45 :
46 : PGPing rv;
47 10 : PQconninfoOption *opts = NULL;
48 10 : PQconninfoOption *defs = NULL;
49 : PQconninfoOption *opt;
50 : PQconninfoOption *def;
51 10 : 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 :
68 10 : pg_logging_init(argv[0]);
69 10 : progname = get_progname(argv[0]);
70 10 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
71 10 : handle_help_version_opts(argc, argv, progname, help);
72 :
73 8 : while ((c = getopt_long(argc, argv, "d:h:p:qt:U:", long_options, NULL)) != -1)
74 : {
75 4 : switch (c)
76 : {
77 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;
89 2 : case 't':
90 2 : connect_timeout = pg_strdup(optarg);
91 2 : break;
92 0 : case 'U':
93 0 : pguser = pg_strdup(optarg);
94 0 : break;
95 2 : default:
96 : /* getopt_long already emitted a complaint */
97 2 : 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 : */
103 2 : exit(PQPING_NO_ATTEMPT);
104 : }
105 : }
106 :
107 4 : if (optind < argc)
108 : {
109 0 : pg_log_error("too many command-line arguments (first is \"%s\")",
110 : argv[optind]);
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 : */
117 0 : exit(PQPING_NO_ATTEMPT);
118 : }
119 :
120 4 : keywords[0] = "host";
121 4 : values[0] = pghost;
122 4 : keywords[1] = "port";
123 4 : values[1] = pgport;
124 4 : keywords[2] = "user";
125 4 : values[2] = pguser;
126 4 : keywords[3] = "dbname";
127 4 : values[3] = pgdbname;
128 4 : keywords[4] = "connect_timeout";
129 4 : values[4] = connect_timeout;
130 4 : keywords[5] = "fallback_application_name";
131 4 : values[5] = progname;
132 4 : keywords[6] = NULL;
133 4 : values[6] = NULL;
134 :
135 : /*
136 : * Get the host and port so we can display them in our output
137 : */
138 4 : if (pgdbname &&
139 0 : (strncmp(pgdbname, "postgresql://", 13) == 0 ||
140 0 : strncmp(pgdbname, "postgres://", 11) == 0 ||
141 0 : strchr(pgdbname, '=') != NULL))
142 : {
143 0 : opts = PQconninfoParse(pgdbname, &errmsg);
144 0 : if (opts == NULL)
145 : {
146 0 : pg_log_error("%s", errmsg);
147 0 : exit(PQPING_NO_ATTEMPT);
148 : }
149 : }
150 :
151 4 : defs = PQconndefaults();
152 4 : if (defs == NULL)
153 : {
154 0 : pg_log_error("could not fetch default options");
155 0 : exit(PQPING_NO_ATTEMPT);
156 : }
157 :
158 168 : for (opt = opts, def = defs; def->keyword; def++)
159 : {
160 164 : if (strcmp(def->keyword, "host") == 0)
161 : {
162 4 : if (opt && opt->val)
163 0 : pghost_str = opt->val;
164 4 : else if (pghost)
165 0 : pghost_str = pghost;
166 4 : else if (def->val)
167 4 : pghost_str = def->val;
168 : else
169 0 : pghost_str = DEFAULT_PGSOCKET_DIR;
170 : }
171 160 : else if (strcmp(def->keyword, "hostaddr") == 0)
172 : {
173 4 : if (opt && opt->val)
174 0 : pghostaddr_str = opt->val;
175 4 : else if (def->val)
176 0 : pghostaddr_str = def->val;
177 : }
178 156 : else if (strcmp(def->keyword, "port") == 0)
179 : {
180 4 : if (opt && opt->val)
181 0 : pgport_str = opt->val;
182 4 : else if (pgport)
183 0 : pgport_str = pgport;
184 4 : else if (def->val)
185 4 : pgport_str = def->val;
186 : }
187 :
188 164 : if (opt)
189 0 : opt++;
190 : }
191 :
192 4 : rv = PQpingParams(keywords, values, 1);
193 :
194 4 : if (!quiet)
195 : {
196 4 : printf("%s:%s - ",
197 : pghostaddr_str != NULL ? pghostaddr_str : pghost_str,
198 : pgport_str);
199 :
200 4 : switch (rv)
201 : {
202 2 : case PQPING_OK:
203 2 : printf(_("accepting connections\n"));
204 2 : break;
205 0 : case PQPING_REJECT:
206 0 : printf(_("rejecting connections\n"));
207 0 : break;
208 2 : case PQPING_NO_RESPONSE:
209 2 : printf(_("no response\n"));
210 2 : break;
211 0 : case PQPING_NO_ATTEMPT:
212 0 : printf(_("no attempt\n"));
213 0 : break;
214 0 : default:
215 0 : printf(_("unknown\n"));
216 : }
217 0 : }
218 :
219 4 : exit(rv);
220 : }
221 :
222 : static void
223 2 : help(const char *progname)
224 : {
225 2 : printf(_("%s issues a connection check to a PostgreSQL database.\n\n"), progname);
226 2 : printf(_("Usage:\n"));
227 2 : printf(_(" %s [OPTION]...\n"), progname);
228 :
229 2 : printf(_("\nOptions:\n"));
230 2 : printf(_(" -d, --dbname=DBNAME database name\n"));
231 2 : printf(_(" -q, --quiet run quietly\n"));
232 2 : printf(_(" -V, --version output version information, then exit\n"));
233 2 : printf(_(" -?, --help show this help, then exit\n"));
234 :
235 2 : printf(_("\nConnection options:\n"));
236 2 : printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
237 2 : printf(_(" -p, --port=PORT database server port\n"));
238 2 : printf(_(" -t, --timeout=SECS seconds to wait when attempting connection, 0 disables (default: %s)\n"), DEFAULT_CONNECT_TIMEOUT);
239 2 : printf(_(" -U, --username=USERNAME user name to connect as\n"));
240 2 : printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
241 2 : printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
242 2 : }
|