From 87306184580c9c49717b00d48a2f9e717f21e0a8 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Sat, 13 Apr 2013 23:42:42 -0400
Subject: [PATCH] pg_ctl: Add idempotent option

This changes the behavior of the start and stop actions to exit
successfully if the server was already started or stopped.

This changes the default behavior of the start action:  Before, if the
server was already running, it would print a message and succeed.  Now,
that situation will result in an error.  When running in idempotent
mode, no message is printed and pg_ctl exits successfully.

It was considered to just make the idempotent behavior the default and
only option, but pg_upgrade needs the old behavior.
---
 contrib/start-scripts/linux      |  6 +++---
 doc/src/sgml/ref/pg_ctl-ref.sgml | 21 +++++++++++++++++++++
 src/bin/pg_ctl/pg_ctl.c          | 29 ++++++++++++++++++++++-------
 3 files changed, 46 insertions(+), 10 deletions(-)

diff --git a/contrib/start-scripts/linux b/contrib/start-scripts/linux
index b950cf512c3..03c6e503bc6 100644
--- a/contrib/start-scripts/linux
+++ b/contrib/start-scripts/linux
@@ -84,17 +84,17 @@ case $1 in
 	echo -n "Starting PostgreSQL: "
 	test x"$OOM_SCORE_ADJ" != x && echo "$OOM_SCORE_ADJ" > /proc/self/oom_score_adj
 	test x"$OOM_ADJ" != x && echo "$OOM_ADJ" > /proc/self/oom_adj
-	su - $PGUSER -c "$DAEMON -D '$PGDATA' &" >>$PGLOG 2>&1
+	su - $PGUSER -c "$DAEMON -I -D '$PGDATA' &" >>$PGLOG 2>&1
 	echo "ok"
 	;;
   stop)
 	echo -n "Stopping PostgreSQL: "
-	su - $PGUSER -c "$PGCTL stop -D '$PGDATA' -s -m fast"
+	su - $PGUSER -c "$PGCTL stop -I -D '$PGDATA' -s -m fast"
 	echo "ok"
 	;;
   restart)
 	echo -n "Restarting PostgreSQL: "
-	su - $PGUSER -c "$PGCTL stop -D '$PGDATA' -s -m fast -w"
+	su - $PGUSER -c "$PGCTL stop -I -D '$PGDATA' -s -m fast -w"
 	test x"$OOM_SCORE_ADJ" != x && echo "$OOM_SCORE_ADJ" > /proc/self/oom_score_adj
 	test x"$OOM_ADJ" != x && echo "$OOM_ADJ" > /proc/self/oom_adj
 	su - $PGUSER -c "$DAEMON -D '$PGDATA' &" >>$PGLOG 2>&1
diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml
index 3107514901c..549730da6f9 100644
--- a/doc/src/sgml/ref/pg_ctl-ref.sgml
+++ b/doc/src/sgml/ref/pg_ctl-ref.sgml
@@ -39,6 +39,7 @@ PostgreSQL documentation
    <arg choice="opt"><option>-o</option> <replaceable>options</replaceable></arg>
    <arg choice="opt"><option>-p</option> <replaceable>path</replaceable></arg>
    <arg choice="opt"><option>-c</option></arg>
+   <arg choice="opt"><option>-I</option></arg>
   </cmdsynopsis>
 
   <cmdsynopsis>
@@ -55,6 +56,7 @@ PostgreSQL documentation
        <arg choice="plain"><option>i[mmediate]</option></arg>
      </group>
    </arg>
+   <arg choice="opt"><option>-I</option></arg>
   </cmdsynopsis>
 
   <cmdsynopsis>
@@ -270,6 +272,25 @@ PostgreSQL documentation
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><option>-I</option></term>
+      <term><option>--idempotent</option></term>
+      <listitem>
+       <para>
+        When used with the <literal>start</literal> or <literal>stop</literal>
+        actions, return exit code 0 if the server is already running or
+        stopped, respectively.  Otherwise, an error is raised and a nonzero
+        exit code is returned in these cases.
+       </para>
+
+       <para>
+        This option is useful for System-V-style init scripts, which require
+        the <literal>start</literal> and <literal>stop</literal> actions to be
+        idempotent.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>-l <replaceable class="parameter">filename</replaceable></option></term>
       <term><option>--log <replaceable class="parameter">filename</replaceable></option></term>
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 537d173e893..a4e7922d687 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -85,6 +85,7 @@ static char *pg_config = NULL;
 static char *pgdata_opt = NULL;
 static char *post_opts = NULL;
 static const char *progname;
+static bool idempotent = false;
 static char *log_file = NULL;
 static char *exec_path = NULL;
 static char *register_servicename = "PostgreSQL";		/* FIXME: + version ID? */
@@ -773,9 +774,15 @@ do_start(void)
 	{
 		old_pid = get_pgpid();
 		if (old_pid != 0)
-			write_stderr(_("%s: another server might be running; "
-						   "trying to start server anyway\n"),
-						 progname);
+		{
+			if (idempotent)
+				exit(0);
+			else
+			{
+				write_stderr(_("%s: another server might be running\n"), progname);
+				exit(1);
+			}
+		}
 	}
 
 	read_post_opts();
@@ -859,6 +866,8 @@ do_stop(void)
 
 	if (pid == 0)				/* no pid file */
 	{
+		if (idempotent)
+			exit(0);
 		write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
 		write_stderr(_("Is server running?\n"));
 		exit(1);
@@ -1763,9 +1772,9 @@ do_help(void)
 	printf(_("%s is a utility to initialize, start, stop, or control a PostgreSQL server.\n\n"), progname);
 	printf(_("Usage:\n"));
 	printf(_("  %s init[db]               [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
-	printf(_("  %s start   [-w] [-t SECS] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);
-	printf(_("  %s stop    [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
-	printf(_("  %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
+	printf(_("  %s start   [-w] [-t SECS] [-D DATADIR] [-s] [-I] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);
+	printf(_("  %s stop    [-W] [-t SECS] [-D DATADIR] [-s] [-I] [-m SHUTDOWN-MODE]\n"), progname);
+	printf(_("  %s restart [-w] [-t SECS] [-D DATADIR] [-s]      [-m SHUTDOWN-MODE]\n"
 			 "                 [-o \"OPTIONS\"]\n"), progname);
 	printf(_("  %s reload  [-D DATADIR] [-s]\n"), progname);
 	printf(_("  %s status  [-D DATADIR]\n"), progname);
@@ -1798,6 +1807,8 @@ do_help(void)
 	printf(_("  -o OPTIONS             command line options to pass to postgres\n"
 	 "                         (PostgreSQL server executable) or initdb\n"));
 	printf(_("  -p PATH-TO-POSTGRES    normally not necessary\n"));
+	printf(_("\nOptions for start or stop:\n"));
+	printf(_("  -I, --idempotent       don't error if server already running or stopped\n"));
 	printf(_("\nOptions for stop, restart, or promote:\n"));
 	printf(_("  -m, --mode=MODE        MODE can be \"smart\", \"fast\", or \"immediate\"\n"));
 
@@ -1980,6 +1991,7 @@ main(int argc, char **argv)
 		{"silent", no_argument, NULL, 's'},
 		{"timeout", required_argument, NULL, 't'},
 		{"core-files", no_argument, NULL, 'c'},
+		{"idempotent", no_argument, NULL, 'I'},
 		{NULL, 0, NULL, 0}
 	};
 
@@ -2045,7 +2057,7 @@ main(int argc, char **argv)
 	/* process command-line options */
 	while (optind < argc)
 	{
-		while ((c = getopt_long(argc, argv, "cD:l:m:N:o:p:P:sS:t:U:wW", long_options, &option_index)) != -1)
+		while ((c = getopt_long(argc, argv, "cD:Il:m:N:o:p:P:sS:t:U:wW", long_options, &option_index)) != -1)
 		{
 			switch (c)
 			{
@@ -2071,6 +2083,9 @@ main(int argc, char **argv)
 								 pgdata_D);
 						break;
 					}
+				case 'I':
+					idempotent = true;
+					break;
 				case 'l':
 					log_file = pg_strdup(optarg);
 					break;
-- 
GitLab