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