Index: src/backend/postmaster/postmaster.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/postmaster.c,v retrieving revision 1.476 diff -u -r1.476 postmaster.c --- src/backend/postmaster/postmaster.c 22 Nov 2005 18:17:18 -0000 1.476 +++ src/backend/postmaster/postmaster.c 10 Dec 2005 18:28:04 -0000 @@ -254,6 +254,7 @@ static void ConnFree(Port *port); static void reset_shared(int port); static void SIGHUP_handler(SIGNAL_ARGS); +static void RunAtexitScriptFile(const char *); static void pmdie(SIGNAL_ARGS); static void reaper(SIGNAL_ARGS); static void sigusr1_handler(SIGNAL_ARGS); @@ -1856,6 +1858,21 @@ errno = save_errno; } +/* + * RunAtexitScriptFile -- run configured atexit script. + */ +static void +RunAtexitScriptFile(const char *shuttype) +{ + if (enable_atexit_script_file && atexit_script_file) + { + int l = strlen(atexit_script_file) + strlen(shuttype) + 2; + char buf[l]; + + sprintf(buf, "%s %s", atexit_script_file, shuttype); + system(buf); + } +} /* * pmdie -- signal handler for processing various postmaster signals. @@ -1885,6 +1902,7 @@ Shutdown = SmartShutdown; ereport(LOG, (errmsg("received smart shutdown request"))); + RunAtexitScriptFile("smart"); /* * We won't wait out an autovacuum iteration ... @@ -1931,6 +1949,7 @@ Shutdown = FastShutdown; ereport(LOG, (errmsg("received fast shutdown request"))); + RunAtexitScriptFile("fast"); if (DLGetHead(BackendList) || AutoVacPID != 0) { @@ -1978,6 +1997,8 @@ */ ereport(LOG, (errmsg("received immediate shutdown request"))); + RunAtexitScriptFile("immediate"); + if (StartupPID != 0) kill(StartupPID, SIGQUIT); if (BgWriterPID != 0) Index: src/backend/utils/misc/guc.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/guc.c,v retrieving revision 1.301 diff -u -r1.301 guc.c --- src/backend/utils/misc/guc.c 22 Nov 2005 18:17:26 -0000 1.301 +++ src/backend/utils/misc/guc.c 10 Dec 2005 18:28:24 -0000 @@ -145,6 +145,7 @@ /* * GUC option variables that are exported from this module */ +bool enable_atexit_script_file = false; #ifdef USE_ASSERT_CHECKING bool assert_enabled = true; #endif @@ -181,6 +182,7 @@ char *HbaFileName; char *IdentFileName; char *external_pid_file; +char *atexit_script_file; int tcp_keepalives_idle; int tcp_keepalives_interval; @@ -391,6 +393,14 @@ static struct config_bool ConfigureNamesBool[] = { { + {"enable_atexit_script_file", PGC_POSTMASTER, FILE_LOCATIONS, + gettext_noop("Enables usage of atexit script file on postmaster shutdown."), + NULL + }, + &enable_atexit_script_file, + false, NULL, NULL + }, + { {"enable_seqscan", PGC_USERSET, QUERY_TUNING_METHOD, gettext_noop("Enables the planner's use of sequential-scan plans."), NULL @@ -2119,6 +2129,16 @@ NULL, assign_canonical_path, NULL }, + { + {"atexit_script_file", PGC_POSTMASTER, FILE_LOCATIONS, + gettext_noop("Executes specified atexit script file on database shutdown."), + NULL, + GUC_SUPERUSER_ONLY + }, + &atexit_script_file, + NULL, assign_canonical_path, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL @@ -2856,6 +2876,47 @@ free(configdir); + /* + * Access permission check for atexit_script_file. + */ + if (enable_atexit_script_file) + { + int xmask; + + if (!atexit_script_file) + { + write_stderr("You must specify an atexit script file when you " + "enabled its usage.\n"); + return false; + } + else if (stat(atexit_script_file, &stat_buf) != 0) + { + write_stderr("%s cannot access atexit script file to run on server " + "shutdown.\n\"%s\": %s\n", + progname, atexit_script_file, strerror(errno)); + return false; + } + + /* + * FIXME: Below execution masks require editing + * (like S_IXROOT) for some platforms (like Netware). + */ + if (stat_buf.st_uid == getuid()) + xmask = S_IXUSR; + else if (stat_buf.st_uid == getgid()) + xmask = S_IXGRP; + else + xmask = S_IXOTH; + + if ((stat_buf.st_mode&xmask) == 0 || S_ISDIR(stat_buf.st_mode)) + { + write_stderr("%s doesn't have execution permissions on script " + "file to run on server shutdown.\n\"%s\": %s\n", + progname, atexit_script_file, strerror(errno)); + return false; + } + } + return true; } Index: src/backend/utils/misc/postgresql.conf.sample =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/postgresql.conf.sample,v retrieving revision 1.171 diff -u -r1.171 postgresql.conf.sample --- src/backend/utils/misc/postgresql.conf.sample 17 Nov 2005 22:14:54 -0000 1.171 +++ src/backend/utils/misc/postgresql.conf.sample 10 Dec 2005 18:28:25 -0000 @@ -39,6 +39,9 @@ # If external_pid_file is not explicitly set, no extra pid file is written. #external_pid_file = '(none)' # write an extra pid file +# atexit script file to run on database shutdown. +#enable_atexit_script_file = off +#atexit_script_file = '(none)' #--------------------------------------------------------------------------- # CONNECTIONS AND AUTHENTICATION Index: src/include/utils/guc.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/utils/guc.h,v retrieving revision 1.63 diff -u -r1.63 guc.h --- src/include/utils/guc.h 15 Oct 2005 02:49:46 -0000 1.63 +++ src/include/utils/guc.h 10 Dec 2005 19:14:00 -0000 @@ -103,6 +103,7 @@ #define GUC_QUALIFIER_SEPARATOR '.' /* GUC vars that are actually declared in guc.c, rather than elsewhere */ +extern bool enable_atexit_script_file; extern bool log_duration; extern bool Debug_print_plan; extern bool Debug_print_parse; @@ -133,6 +134,7 @@ extern char *HbaFileName; extern char *IdentFileName; extern char *external_pid_file; +extern char *atexit_script_file; extern int tcp_keepalives_idle; extern int tcp_keepalives_interval;