diff --git a/contrib/start-scripts/freebsd b/contrib/start-scripts/freebsd index 528fc776c7..10ea482498 100644 --- a/contrib/start-scripts/freebsd +++ b/contrib/start-scripts/freebsd @@ -6,7 +6,7 @@ # Created through merger of the Linux start script by Ryan Kirkpatrick # and the script in the FreeBSD ports collection. -# $PostgreSQL: pgsql/contrib/start-scripts/freebsd,v 1.4 2004/10/01 18:30:21 tgl Exp $ +# $PostgreSQL: pgsql/contrib/start-scripts/freebsd,v 1.5 2009/08/27 16:59:38 tgl Exp $ ## EDIT FROM HERE @@ -27,9 +27,9 @@ PGLOG="$PGDATA/serverlog" # The path that is to be used for the script PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -# What to use to start up the postmaster (we do NOT use pg_ctl for this, -# as it adds no value and can cause the postmaster to misrecognize a stale -# lock file) +# What to use to start up the postmaster. (If you want the script to wait +# until the server has started, you could use "pg_ctl start -w" here. +# But without -w, pg_ctl adds no value.) DAEMON="$prefix/bin/postmaster" # What to use to shut down the postmaster diff --git a/contrib/start-scripts/linux b/contrib/start-scripts/linux index f1feb34f94..6d6ff2aed9 100644 --- a/contrib/start-scripts/linux +++ b/contrib/start-scripts/linux @@ -24,7 +24,7 @@ # Original author: Ryan Kirkpatrick -# $PostgreSQL: pgsql/contrib/start-scripts/linux,v 1.8 2006/07/13 14:44:33 petere Exp $ +# $PostgreSQL: pgsql/contrib/start-scripts/linux,v 1.9 2009/08/27 16:59:38 tgl Exp $ ## EDIT FROM HERE @@ -45,9 +45,9 @@ PGLOG="$PGDATA/serverlog" # The path that is to be used for the script PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -# What to use to start up the postmaster (we do NOT use pg_ctl for this, -# as it adds no value and can cause the postmaster to misrecognize a stale -# lock file) +# What to use to start up the postmaster. (If you want the script to wait +# until the server has started, you could use "pg_ctl start -w" here. +# But without -w, pg_ctl adds no value.) DAEMON="$prefix/bin/postmaster" # What to use to shut down the postmaster diff --git a/contrib/start-scripts/osx/PostgreSQL b/contrib/start-scripts/osx/PostgreSQL index dc826837a3..65150d0fd5 100755 --- a/contrib/start-scripts/osx/PostgreSQL +++ b/contrib/start-scripts/osx/PostgreSQL @@ -68,9 +68,9 @@ ROTATESEC="604800" # The path that is to be used for the script PATH="$prefix/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" -# What to use to start up the postmaster (we do NOT use pg_ctl for this, -# as it adds no value and can cause the postmaster to misrecognize a stale -# lock file) +# What to use to start up the postmaster. (If you want the script to wait +# until the server has started, you could use "pg_ctl start -w" here. +# But without -w, pg_ctl adds no value.) DAEMON="$prefix/bin/postmaster" # What to use to shut down the postmaster @@ -85,7 +85,7 @@ StartService () { if [ "${POSTGRESQL:=-NO-}" = "-YES-" ]; then ConsoleMessage "Starting PostgreSQL database server" if [ "${ROTATELOGS}" = "1" ]; then - sudo -u $PGUSER sh -c "${DAEMON} -D '${PGDATA}' 2>&1 | ${LOGUTIL} '${PGLOG}' ${ROTATESEC} &" + sudo -u $PGUSER sh -c "${DAEMON} -D '${PGDATA}' &" 2>&1 | ${LOGUTIL} '${PGLOG}' ${ROTATESEC} & else sudo -u $PGUSER sh -c "${DAEMON} -D '${PGDATA}' &" >>$PGLOG 2>&1 fi @@ -104,7 +104,7 @@ RestartService () { sudo -u $PGUSER $PGCTL stop -D "$PGDATA" -s -m fast # should match StartService: if [ "${ROTATELOGS}" = "1" ]; then - sudo -u $PGUSER sh -c "${DAEMON} -D '${PGDATA}' 2>&1 | ${LOGUTIL} '${PGLOG}' ${ROTATESEC} &" + sudo -u $PGUSER sh -c "${DAEMON} -D '${PGDATA}' &" 2>&1 | ${LOGUTIL} '${PGLOG}' ${ROTATESEC} & else sudo -u $PGUSER sh -c "${DAEMON} -D '${PGDATA}' &" >>$PGLOG 2>&1 fi diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 0b004d7e5f..85f1507ba3 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.176 2009/08/12 20:53:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.177 2009/08/27 16:59:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -683,7 +683,46 @@ CreateLockFile(const char *filename, bool amPostmaster, int len; int encoded_pid; pid_t other_pid; - pid_t my_pid = getpid(); + pid_t my_pid, + my_p_pid, + my_gp_pid; + const char *envvar; + + /* + * If the PID in the lockfile is our own PID or our parent's or + * grandparent's PID, then the file must be stale (probably left over from + * a previous system boot cycle). We need to check this because of the + * likelihood that a reboot will assign exactly the same PID as we had in + * the previous reboot, or one that's only one or two counts larger and + * hence the lockfile's PID now refers to an ancestor shell process. We + * allow pg_ctl to pass down its parent shell PID (our grandparent PID) + * via the environment variable PG_GRANDPARENT_PID; this is so that + * launching the postmaster via pg_ctl can be just as reliable as + * launching it directly. There is no provision for detecting + * further-removed ancestor processes, but if the init script is written + * carefully then all but the immediate parent shell will be root-owned + * processes and so the kill test will fail with EPERM. Note that we + * cannot get a false negative this way, because an existing postmaster + * would surely never launch a competing postmaster or pg_ctl process + * directly. + */ + my_pid = getpid(); + +#ifndef WIN32 + my_p_pid = getppid(); +#else + /* + * Windows hasn't got getppid(), but doesn't need it since it's not + * using real kill() either... + */ + my_p_pid = 0; +#endif + + envvar = getenv("PG_GRANDPARENT_PID"); + if (envvar) + my_gp_pid = atoi(envvar); + else + my_gp_pid = 0; /* * We need a loop here because of race conditions. But don't loop forever @@ -745,17 +784,11 @@ CreateLockFile(const char *filename, bool amPostmaster, /* * Check to see if the other process still exists * - * If the PID in the lockfile is our own PID or our parent's PID, then - * the file must be stale (probably left over from a previous system - * boot cycle). We need this test because of the likelihood that a - * reboot will assign exactly the same PID as we had in the previous - * reboot. Also, if there is just one more process launch in this - * reboot than in the previous one, the lockfile might mention our - * parent's PID. We can reject that since we'd never be launched - * directly by a competing postmaster. We can't detect grandparent - * processes unfortunately, but if the init script is written - * carefully then all but the immediate parent shell will be - * root-owned processes and so the kill test will fail with EPERM. + * Per discussion above, my_pid, my_p_pid, and my_gp_pid can be + * ignored as false matches. + * + * Normally kill() will fail with ESRCH if the given PID doesn't + * exist. * * We can treat the EPERM-error case as okay because that error * implies that the existing process has a different userid than we @@ -772,18 +805,9 @@ CreateLockFile(const char *filename, bool amPostmaster, * Unix socket file belonging to an instance of Postgres being run by * someone else, at least on machines where /tmp hasn't got a * stickybit.) - * - * Windows hasn't got getppid(), but doesn't need it since it's not - * using real kill() either... - * - * Normally kill() will fail with ESRCH if the given PID doesn't - * exist. */ - if (other_pid != my_pid -#ifndef WIN32 - && other_pid != getppid() -#endif - ) + if (other_pid != my_pid && other_pid != my_p_pid && + other_pid != my_gp_pid) { if (kill(other_pid, 0) == 0 || (errno != ESRCH && errno != EPERM)) diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index 40ede2c1a8..ff8f4a2552 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -4,7 +4,7 @@ * * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.111 2009/06/11 14:49:07 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.112 2009/08/27 16:59:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -672,6 +672,21 @@ do_start(void) unlimit_core_size(); #endif + /* + * If possible, tell the postmaster our parent shell's PID (see the + * comments in CreateLockFile() for motivation). Windows hasn't got + * getppid() unfortunately. + */ +#ifndef WIN32 + { + static char env_var[32]; + + snprintf(env_var, sizeof(env_var), "PG_GRANDPARENT_PID=%d", + (int) getppid()); + putenv(env_var); + } +#endif + exitcode = start_postmaster(); if (exitcode != 0) {