diff options
Diffstat (limited to 'src/backend/utils/init/miscinit.c')
-rw-r--r-- | src/backend/utils/init/miscinit.c | 72 |
1 files changed, 48 insertions, 24 deletions
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 0b004d7e5f0..85f1507ba36 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)) |