pg_ctl.c
Here is the C version of pg_ctl.c written by Andrew Dunstan and updated
by me.
You can use it by creating a src/bin/pg_ctl_test directory and putting
the C and Makefile into that directory. You can then do a make install
and use it for testing.
Unless someone finds a problem, I will apply the change soon. This
removes our last shell script!
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Bruce Momjian wrote:
Here is the C version of pg_ctl.c written by Andrew Dunstan and updated
by me.You can use it by creating a src/bin/pg_ctl_test directory and putting
the C and Makefile into that directory. You can then do a make install
and use it for testing.Unless someone finds a problem, I will apply the change soon. This
removes our last shell script!
It desn't compile on my platform:
$ gcc -I /usr/include/pgsql/server pg_ctl.c
pg_ctl.c: In function `start_postmaster':
pg_ctl.c:219: error: `DEVNULL' undeclared (first use in this function)
pg_ctl.c:219: error: (Each undeclared identifier is reported only once
pg_ctl.c:219: error: for each function it appears in.)
however below the result of my quich review:
1) exit(1) => exit(EXIT_FAILURE)
2) xstrdup protected by duplicate NULL string
I seen also that you don't use always the _ macro for error display.
Regards
Gaetano Mendola
*** pg_ctl.c 2004-05-26 02:48:38.000000000 +0200
--- pg_ctl.c.orig 2004-05-26 02:43:32.000000000 +0200
***************
*** 26,33 ****
/* postmaster version ident string */
#define PM_VERSIONSTR "postmaster (PostgreSQL) " PG_VERSION "\n"
- #define EXIT_FAILURE 1
-
typedef enum
{
--- 26,31 ----
***************
*** 100,106 ****
if (!result)
{
fprintf(stderr, _("%s: out of memory\n"), progname);
! exit(EXIT_FAILURE);
}
return result;
}
--- 98,104 ----
if (!result)
{
fprintf(stderr, _("%s: out of memory\n"), progname);
! exit(1);
}
return result;
}
***************
*** 112,130 ****
{
char *result;
-
- if (!s)
- {
- fprintf(stderr, "%s: can not duplicate null pointer", progname);
- exit(EXIT_FAILURE);
- }
-
-
result = strdup(s);
if (!result)
{
fprintf(stderr, _("%s: out of memory\n"), progname);
! exit(EXIT_FAILURE);
}
return result;
}
--- 110,120 ----
{
char *result;
result = strdup(s);
if (!result)
{
fprintf(stderr, _("%s: out of memory\n"), progname);
! exit(1);
}
return result;
}
***************
*** 146,152 ****
else
{
perror("openning pid file");
! exit(EXIT_FAILURE);
}
}
fscanf(pidf, "%ld", &pid);
--- 136,142 ----
else
{
perror("openning pid file");
! exit(1);
}
}
fscanf(pidf, "%ld", &pid);
***************
*** 353,359 ****
else
{
fprintf(stderr, "%s: cannot read %s\n", progname, postopts_file);
! exit(EXIT_FAILURE);
}
}
else if (optlines[0] == NULL || optlines[1] != NULL)
--- 343,349 ----
else
{
fprintf(stderr, "%s: cannot read %s\n", progname, postopts_file);
! exit(1);
}
}
else if (optlines[0] == NULL || optlines[1] != NULL)
***************
*** 361,367 ****
fprintf(stderr, "%s: option file %s must have exactly 1 line\n",
progname, ctl_command == RESTART_COMMAND ?
postopts_file : def_postopts_file);
! exit(EXIT_FAILURE);
}
else
{
--- 351,357 ----
fprintf(stderr, "%s: option file %s must have exactly 1 line\n",
progname, ctl_command == RESTART_COMMAND ?
postopts_file : def_postopts_file);
! exit(1);
}
else
{
***************
*** 411,417 ****
"but was not the same version as \"%s\".\n"
"Check your installation.\n"),
progname, progname);
! exit(EXIT_FAILURE);
}
postgres_path = postmaster_path;
}
--- 401,407 ----
"but was not the same version as \"%s\".\n"
"Check your installation.\n"),
progname, progname);
! exit(1);
}
postgres_path = postmaster_path;
}
***************
*** 428,434 ****
"%s: cannot start postmaster\n"
"Examine the log output\n",
progname);
! exit(EXIT_FAILURE);
}
}
--- 418,424 ----
"%s: cannot start postmaster\n"
"Examine the log output\n",
progname);
! exit(1);
}
}
***************
*** 463,469 ****
{
fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
fprintf(stderr, "Is postmaster running?\n");
! exit(EXIT_FAILURE);
}
else if (pid < 0) /* standalone backend, not postmaster */
{
--- 453,459 ----
{
fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
fprintf(stderr, "Is postmaster running?\n");
! exit(1);
}
else if (pid < 0) /* standalone backend, not postmaster */
{
***************
*** 472,478 ****
"%s: cannot stop postmaster; "
"postgres is running (PID: %ld)\n",
progname, pid);
! exit(EXIT_FAILURE);
}
if (kill((pid_t) pid, sig) != 0)
--- 462,468 ----
"%s: cannot stop postmaster; "
"postgres is running (PID: %ld)\n",
progname, pid);
! exit(1);
}
if (kill((pid_t) pid, sig) != 0)
***************
*** 513,519 ****
printf(" failed\n");
fprintf(stderr, "%s: postmaster does not shut down\n", progname);
! exit(EXIT_FAILURE);
}
}
}
--- 503,509 ----
printf(" failed\n");
fprintf(stderr, "%s: postmaster does not shut down\n", progname);
! exit(1);
}
}
}
***************
*** 546,552 ****
"postgres is running (PID: %ld)\n",
progname, pid);
fprintf(stderr, "Please terminate postgres and try again.\n");
! exit(EXIT_FAILURE);
}
if (kill((pid_t) pid, sig) != 0)
--- 536,542 ----
"postgres is running (PID: %ld)\n",
progname, pid);
fprintf(stderr, "Please terminate postgres and try again.\n");
! exit(1);
}
if (kill((pid_t) pid, sig) != 0)
***************
*** 581,587 ****
printf(" failed\n");
fprintf(stderr, "%s: postmaster does not shut down\n", progname);
! exit(EXIT_FAILURE);
}
do_start();
--- 571,577 ----
printf(" failed\n");
fprintf(stderr, "%s: postmaster does not shut down\n", progname);
! exit(1);
}
do_start();
***************
*** 599,605 ****
{
fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
fprintf(stderr, "Is postmaster running?\n");
! exit(EXIT_FAILURE);
}
else if (pid < 0) /* standalone backend, not postmaster */
{
--- 589,595 ----
{
fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
fprintf(stderr, "Is postmaster running?\n");
! exit(1);
}
else if (pid < 0) /* standalone backend, not postmaster */
{
***************
*** 609,615 ****
"postgres is running (PID: %ld)\n",
progname, pid);
fprintf(stderr, "Please terminate postgres and try again.\n");
! exit(EXIT_FAILURE);
}
if (kill((pid_t) pid, sig) != 0)
--- 599,605 ----
"postgres is running (PID: %ld)\n",
progname, pid);
fprintf(stderr, "Please terminate postgres and try again.\n");
! exit(1);
}
if (kill((pid_t) pid, sig) != 0)
***************
*** 632,638 ****
if (pid == 0) /* no pid file */
{
fprintf(stderr, "%s: postmaster or postgres not running", progname);
! exit(EXIT_FAILURE);
}
else if (pid < 0) /* standalone backend */
{
--- 622,628 ----
if (pid == 0) /* no pid file */
{
fprintf(stderr, "%s: postmaster or postgres not running", progname);
! exit(1);
}
else if (pid < 0) /* standalone backend */
{
***************
*** 745,751 ****
{
fprintf(stderr, "%s: invalid shutdown mode %s\n", progname, modeopt);
do_advice();
! exit(EXIT_FAILURE);
}
}
--- 735,741 ----
{
fprintf(stderr, "%s: invalid shutdown mode %s\n", progname, modeopt);
do_advice();
! exit(1);
}
}
***************
*** 778,784 ****
{
fprintf(stderr, "%s: invalid signal \"%s\"\n", progname, signame);
do_advice();
! exit(EXIT_FAILURE);
}
}
--- 768,774 ----
{
fprintf(stderr, "%s: invalid signal \"%s\"\n", progname, signame);
do_advice();
! exit(1);
}
}
***************
*** 878,884 ****
{
fprintf(stderr, "%s: invalid option %s\n", progname, arg);
do_advice();
! exit(EXIT_FAILURE);
}
else if (strcmp(arg, "start") == 0 && ctl_command == NO_COMMAND)
ctl_command = START_COMMAND;
--- 868,874 ----
{
fprintf(stderr, "%s: invalid option %s\n", progname, arg);
do_advice();
! exit(1);
}
else if (strcmp(arg, "start") == 0 && ctl_command == NO_COMMAND)
ctl_command = START_COMMAND;
***************
*** 902,908 ****
{
fprintf(stderr, "%s: invalid operation mode %s\n", progname, arg);
do_advice();
! exit(EXIT_FAILURE);
}
}
--- 892,898 ----
{
fprintf(stderr, "%s: invalid operation mode %s\n", progname, arg);
do_advice();
! exit(1);
}
}
***************
*** 910,916 ****
{
fprintf(stderr, "%s: no operation specified\n", progname);
do_advice();
! exit(EXIT_FAILURE);
}
pg_data = getenv("PGDATA");
--- 900,906 ----
{
fprintf(stderr, "%s: no operation specified\n", progname);
do_advice();
! exit(1);
}
pg_data = getenv("PGDATA");
***************
*** 923,929 ****
"and environment variable PGDATA unset\n",
progname);
do_advice();
! exit(EXIT_FAILURE);
}
if (!wait_set)
--- 913,919 ----
"and environment variable PGDATA unset\n",
progname);
do_advice();
! exit(1);
}
if (!wait_set)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Bruce Momjian wrote:
| Gaetano Mendola wrote:
|
|>Bruce Momjian wrote:
|>
|>
|>>Here is the C version of pg_ctl.c written by Andrew Dunstan and updated
|>>by me.
|>>
|>>You can use it by creating a src/bin/pg_ctl_test directory and putting
|>>the C and Makefile into that directory. You can then do a make install
|>>and use it for testing.
|>>
|>>Unless someone finds a problem, I will apply the change soon. This
|>>removes our last shell script!
|>
|>It desn't compile on my platform:
|>
|>$ gcc -I /usr/include/pgsql/server pg_ctl.c
|>pg_ctl.c: In function `start_postmaster':
|>pg_ctl.c:219: error: `DEVNULL' undeclared (first use in this function)
|>pg_ctl.c:219: error: (Each undeclared identifier is reported only once
|>pg_ctl.c:219: error: for each function it appears in.)
|
|
| DEVNULL is in CVS port.h. Are you running against CVS?
No. Against 7.4.1
|>2) xstrdup protected by duplicate NULL string
|
|
| You mean that you can't pass NULL to xstrdup? Yea, but if we do, it
| will crash and we will hear about it right away.
Yea u'r right, it will crash without know why, for the same reason you can
avoid to use the xstrdup then.
Regards
Gaetano Mendola
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org
iD8DBQFAtE3h7UpzwH2SGd4RAjDhAKDV8lRn7XEAGqHLBJzQTvrBlyJsXgCgrw5c
CljcRIysGU3+IGoVbHU9vYg=
=9jrs
-----END PGP SIGNATURE-----
Import Notes
Reply to msg id not found: 200405260114.i4Q1EA220169@candle.pha.pa.usReference msg id not found: 200405260114.i4Q1EA220169@candle.pha.pa.us | Resolved by subject fallback
Gaetano Mendola wrote:
Bruce Momjian wrote:
Here is the C version of pg_ctl.c written by Andrew Dunstan and updated
by me.You can use it by creating a src/bin/pg_ctl_test directory and putting
the C and Makefile into that directory. You can then do a make install
and use it for testing.Unless someone finds a problem, I will apply the change soon. This
removes our last shell script!It desn't compile on my platform:
$ gcc -I /usr/include/pgsql/server pg_ctl.c
pg_ctl.c: In function `start_postmaster':
pg_ctl.c:219: error: `DEVNULL' undeclared (first use in this function)
pg_ctl.c:219: error: (Each undeclared identifier is reported only once
pg_ctl.c:219: error: for each function it appears in.)
It does not appear that you have followed Bruce's instructions above for
testing this. It works just fine for me:
[andrew@marmaduke pg_ctl_x]$ make
make -C ../../../src/interfaces/libpq all
make[1]: Entering directory `/home/andrew/pgwnew/pgsql/src/interfaces/libpq'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/andrew/pgwnew/pgsql/src/interfaces/libpq'
make -C ../../../src/port all
make[1]: Entering directory `/home/andrew/pgwnew/pgsql/src/port'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/andrew/pgwnew/pgsql/src/port'
gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes
-Wmissing-declarations -DFRONTEND -DDEF_PGPORT=5432
-I../../../src/interfaces/libpq -I../../../src/include -D_GNU_SOURCE
-c -o pg_ctl.o pg_ctl.c
rm -f exec.c && ln -s ../../../src/port/exec.c .
gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes
-Wmissing-declarations -DFRONTEND -DDEF_PGPORT=5432
-I../../../src/interfaces/libpq -I../../../src/include -D_GNU_SOURCE
-c -o exec.o exec.c
gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes
-Wmissing-declarations pg_ctl.o exec.o -L../../../src/interfaces/libpq
-lpq -L../../../src/port -Wl,-rpath,/usr/local/pgsql/lib -lz -lreadline
-ltermcap -lcrypt -lresolv -lnsl -ldl -lm -lbsd -lpgport -o pg_ctl
[andrew@marmaduke pg_ctl_x]$
What version of the pg include files is in /usr/include/pgsql/server ?
If <= 7.4 then of course DEVNULL will not be defined.
however below the result of my quich review:
1) exit(1) => exit(EXIT_FAILURE)
If we used a number of different error codes I might agree. But it seems
pointless here, and the style is widely used in our code base (I just
counted 201 other occurrrences, not including cases of exit(0) ).
2) xstrdup protected by duplicate NULL string
I don't object, but it is redundant - in every case where it is called
the argument is demonstrably not NULL.
I seen also that you don't use always the _ macro for error display.
True - that's part of the polish needed.
BTW, please don't send reverse diffs, they are a pain to read, IMNSHO
(i.e. you should do diff -c file.c.orig file.c instead of having the
files the other way around).
There is one small thing that is wrong with it - an incorrect format
argument. see patch below.
cheers
andrew
*** pg_ctl.c.orig 2004-05-26 10:27:20.000000000 -0400
--- pg_ctl.c 2004-05-26 10:28:34.000000000 -0400
***************
*** 237,243 ****
*portstr = '\0';
if (getenv("PGPORT") != NULL) /* environment */
! snprintf(portstr, sizeof(portstr), "%d", getenv("PGPORT"));
else /* post_opts */
{
char *p;
--- 237,243 ----
*portstr = '\0';
if (getenv("PGPORT") != NULL) /* environment */
! snprintf(portstr, sizeof(portstr), "%s", getenv("PGPORT"));
else /* post_opts */
{
char *p;
OK, here is a new version with lots of fixes.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073
Andrew Dunstan wrote:
Gaetano Mendola wrote:
Bruce Momjian wrote:
however below the result of my quich review:
1) exit(1) => exit(EXIT_FAILURE)
If we used a number of different error codes I might agree. But it seems
pointless here, and the style is widely used in our code base (I just
counted 201 other occurrrences, not including cases of exit(0) ).
This doesn't mean that we don't have to.
2) xstrdup protected by duplicate NULL string
I don't object, but it is redundant - in every case where it is called
the argument is demonstrably not NULL.
Now it's true, and in the future ? Bruce was arguing about that check
that if the string is null the program simply will exit crashing!
I really appreciate the quality software of Postgres but some time
I don't understand why test "NULL" pointer is an overkill for you.
I mean xstrdup is supposed to be the strdup safe version, and without
that control is not safe, why don't use directly the strdup then ?
If there is no memory available before postgresql start go figure after!
Regards
Gaetano Mendola
Gaetano Mendola wrote:
Andrew Dunstan wrote:
Gaetano Mendola wrote:
Bruce Momjian wrote:
however below the result of my quich review:
1) exit(1) => exit(EXIT_FAILURE)
If we used a number of different error codes I might agree. But it
seems pointless here, and the style is widely used in our code base
(I just counted 201 other occurrrences, not including cases of
exit(0) ).This doesn't mean that we don't have to.
We should be consistent. If you want to prepare a global patch that
replaces every instance of exit(n) with exit(SOME_CONSTANT) then be my
guest.
2) xstrdup protected by duplicate NULL string
I don't object, but it is redundant - in every case where it is
called the argument is demonstrably not NULL.Now it's true, and in the future ? Bruce was arguing about that check
that if the string is null the program simply will exit crashing!
I really appreciate the quality software of Postgres but some time
I don't understand why test "NULL" pointer is an overkill for you.
I mean xstrdup is supposed to be the strdup safe version, and without
that control is not safe, why don't use directly the strdup then ?
If there is no memory available before postgresql start go figure after!
I am not arguing that we should crash. I am arguing that we will not
crash in this case, and the test is therefore redundant.
I already said I don't object to the change, if that's the consensus,
just that it is unnecessary. BTW, this code was lifted directly from
initdb.c.
I'd far rather you found real bugs than the ghosts of imaginary bugs,
though.
cheers
andrew
Andrew Dunstan wrote:
Gaetano Mendola wrote:
Andrew Dunstan wrote:
Gaetano Mendola wrote:
Bruce Momjian wrote:
however below the result of my quich review:
1) exit(1) => exit(EXIT_FAILURE)
If we used a number of different error codes I might agree. But it
seems pointless here, and the style is widely used in our code base
(I just counted 201 other occurrrences, not including cases of
exit(0) ).This doesn't mean that we don't have to.
We should be consistent. If you want to prepare a global patch that
replaces every instance of exit(n) with exit(SOME_CONSTANT) then be my
guest.
I'd like to do it, partecipate more on postgres coding but in this
period I really don't have time, this doesn't mean that we have to
wrote exit(1) instead of exit(EXIT_FAILURE) and change these
exit in the future. BTW the next patch will write again: exit(1).
2) xstrdup protected by duplicate NULL string
I don't object, but it is redundant - in every case where it is
called the argument is demonstrably not NULL.Now it's true, and in the future ? Bruce was arguing about that check
that if the string is null the program simply will exit crashing!
I really appreciate the quality software of Postgres but some time
I don't understand why test "NULL" pointer is an overkill for you.
I mean xstrdup is supposed to be the strdup safe version, and without
that control is not safe, why don't use directly the strdup then ?
If there is no memory available before postgresql start go figure after!I am not arguing that we should crash. I am arguing that we will not
crash in this case, and the test is therefore redundant.I already said I don't object to the change, if that's the consensus,
just that it is unnecessary. BTW, this code was lifted directly from
initdb.c.I'd far rather you found real bugs than the ghosts of imaginary bugs,
though.
I was not looking for bugs or ghost, I repeat the test may be redundant
now with the current version of pg_ctl.c, do you write free function
trusting in the caller ( as Bruce do ) or watching were and how it's called?
I write free function without trust the caller and without see where and
how is called, different point of view.
Regards
Gaetano Mendola
Neither the version in CVS head nor the version you attached here links on
win32 (msys/mingw). I get the following:
gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes -Wmissing-declaratio
ns pg_ctl.o
ec.o -L../../../src/interfaces/libpq -lpq -L../../../src/port -lz -lreadli
ne -lwsock32 -lm -lpgport -lws2_32 -o pg_ctl.exe
pg_ctl.o(.text+0xa3c):pg_ctl.c: undefined reference to `kill'
pg_ctl.o(.text+0xc4c):pg_ctl.c: undefined reference to `kill'
pg_ctl.o(.text+0xe5a):pg_ctl.c: undefined reference to `kill'
pg_ctl.o(.text+0x1058):pg_ctl.c: undefined reference to `kill'
Regards,
Thomas Hallgren
"Bruce Momjian" <pgman@candle.pha.pa.us> wrote in message
news:200405261459.i4QExWT28671@candle.pha.pa.us...
OK, here is a new version with lots of fixes.
-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania
19073
----------------------------------------------------------------------------
----
/*-------------------------------------------------------------------------
*
* pg_ctl --- start/stops/restarts the PostgreSQL server
*
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql-server/src/bin/initdb/initdb.c,v 1.32 2004/05/18
03:36:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include "libpq-fe.h"#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>#include "libpq/pqsignal.h"
#include "getopt_long.h"#ifndef HAVE_OPTRESET
int optreset;
#endif#define _(x) gettext((x))
#define WHITESPACE "\f\n\r\t\v" /* as defined by isspace() */
/* postmaster version ident string */
#define PM_VERSIONSTR "postmaster (PostgreSQL) " PG_VERSION "\n"typedef enum
{
SMART_MODE,
FAST_MODE,
IMMEDIATE_MODE
} ShutdownMode;typedef enum
{
NO_COMMAND = 0,
START_COMMAND,
STOP_COMMAND,
RESTART_COMMAND,
RELOAD_COMMAND,
STATUS_COMMAND,
KILL_COMMAND
} CtlCommand;static bool do_wait = false;
static bool wait_set = false;
static int wait_seconds = 60;
static bool silence_echo = false;
static ShutdownMode shutdown_mode = SMART_MODE;
static int sig = SIGTERM; /* default */
static int killproc;
static CtlCommand ctl_command = NO_COMMAND;
static char *pg_data_opts = NULL;
static char *pg_data = NULL;
static char *post_opts = NULL;
static const char *progname;
static char *log_file = NULL;
static char *postgres_path = NULL;
static char *argv0 = NULL;static void *xmalloc(size_t size);
static char *xstrdup(const char *s);
static void do_advice(void);
static void do_help(void);
static void set_mode(char *modeopt);
static void set_sig(char *signame);
static void do_start();
static void do_stop(void);
static void do_restart(void);
static void do_reload(void);
static void do_status(void);
static void do_kill(void);
static long get_pgpid(void);
static char **readfile(char *path);
static int start_postmaster(void);
static bool test_postmaster_connection(void);static char def_postopts_file[MAXPGPATH];
static char postopts_file[MAXPGPATH];
static char pid_file[MAXPGPATH];
static char conf_file[MAXPGPATH];/*
* routines to check memory allocations and fail noisily.
*/static void *
xmalloc(size_t size)
{
void *result;result = malloc(size);
if (!result)
{
fprintf(stderr, _("%s: out of memory\n"), progname);
exit(1);
}
return result;
}static char *
xstrdup(const char *s)
{
char *result;result = strdup(s);
if (!result)
{
fprintf(stderr, _("%s: out of memory\n"), progname);
exit(1);
}
return result;
}static long
get_pgpid(void)
{
FILE *pidf;
long pid;pidf = fopen(pid_file, "r");
if (pidf == NULL)
{
/* No pid file, not an error on startup */
if (errno == ENOENT)
return 0;
else
{
perror("openning pid file");
exit(1);
}
}
fscanf(pidf, "%ld", &pid);
fclose(pidf);
return pid;
}/*
* get the lines from a text file - return NULL if file can't be opened
*/
static char **
readfile(char *path)
{
FILE *infile;
int maxlength = 0,
linelen = 0;
int nlines = 0;
char **result;
char *buffer;
int c;if ((infile = fopen(path, "r")) == NULL)
return NULL;/* pass over the file twice - the first time to size the result */
while ((c = fgetc(infile)) != EOF)
{
linelen++;
if (c == '\n')
{
nlines++;
if (linelen > maxlength)
maxlength = linelen;
linelen = 0;
}
}/* handle last line without a terminating newline (yuck) */
if (linelen)
nlines++;
if (linelen > maxlength)
maxlength = linelen;/* set up the result and the line buffer */
result = (char **) xmalloc((nlines + 1) * sizeof(char *));
buffer = (char *) xmalloc(maxlength + 1);/* now reprocess the file and store the lines */
rewind(infile);
nlines = 0;
while (fgets(buffer, maxlength + 1, infile) != NULL)
result[nlines++] = xstrdup(buffer);fclose(infile);
result[nlines] = NULL;return result;
}/*
* start/test/stop routines
*/static int
start_postmaster(void)
{
/*
* Since there might be quotes to handle here, it is easier simply
* to pass everything to a shell to process them.
*/
char cmd[MAXPGPATH];/* Does '&' work on Win32? */
if (log_file != NULL)
snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s >>\"%s\" 2>&1 &",
postgres_path, post_opts, DEVNULL, log_file);
else
snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s 2>&1 &",
postgres_path, post_opts, DEVNULL);
return system(cmd);
}/* Find the pgport and try a connection */
static bool
test_postmaster_connection(void)
{
PGconn *conn;
bool success = false;
int i;
char portstr[32];
char *p;*portstr = '\0';
/* post_opts */
for (p = post_opts; *p;)
{
/* advance past whitespace/quoting */
while (isspace(*p) || *p == '\'' || *p == '"')
p++;if (strncmp(p, "-p", strlen("-p")) == 0)
{
p += strlen("-p");
/* advance past whitespace/quoting */
while (isspace(*p) || *p == '\'' || *p == '"')
p++;
StrNCpy(portstr, p, Min(strcspn(p, "\"'"WHITESPACE) + 1,
sizeof(portstr)));
/* keep looking, maybe there is another -p */
}
/* Advance to next whitespace */
while (!isspace(*p))
p++;
}/* config file */
if (!*portstr)
{
char **optlines;optlines = readfile(conf_file);
if (optlines != NULL)
{
for (;*optlines != NULL; optlines++)
{
p = *optlines;while (isspace(*p))
p++;
if (strncmp(p, "port", strlen("port")) != 0)
continue;
p += strlen("port");
while (isspace(*p))
p++;
if (*p != '=')
continue;
p++;
while (isspace(*p))
p++;
StrNCpy(portstr, p, Min(strcspn(p, "#"WHITESPACE) + 1,
sizeof(portstr)));
/* keep looking, maybe there is another */
}
}
}/* environment */
if (!*portstr && getenv("PGPORT") != NULL)
StrNCpy(portstr, getenv("PGPORT"), sizeof(portstr));/* default */
if (!*portstr)
snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);for (i = 0; i < wait_seconds; i++)
{
if ((conn = PQsetdbLogin(NULL, portstr, NULL, NULL, "template1", NULL,
NULL)) != NULL)
{
PQfinish(conn);
success = true;
break;
}
}return success;
}static void
do_start(void)
{
long pid;
long old_pid = 0;
char *optline = NULL;if (ctl_command != RESTART_COMMAND)
{
old_pid = get_pgpid();
if (old_pid != 0)
fprintf(stderr,
_("%s: Another postmaster may be running. "
"Trying to start postmaster anyway.\n"),
progname);
}if (post_opts == NULL)
{
char **optlines;
int len;optlines = readfile(ctl_command == RESTART_COMMAND ?
postopts_file : def_postopts_file);
if (optlines == NULL)
{
if (ctl_command == START_COMMAND)
post_opts = "";
else
{
fprintf(stderr, _("%s: cannot read %s\n"), progname, postopts_file);
exit(1);
}
}
else if (optlines[0] == NULL || optlines[1] != NULL)
{
fprintf(stderr, _("%s: option file %s must have exactly 1 line\n"),
progname, ctl_command == RESTART_COMMAND ?
postopts_file : def_postopts_file);
exit(1);
}
else
{
optline = optlines[0];
len = strcspn(optline, "\r\n");
optline[len] = '\0';if (ctl_command == RESTART_COMMAND)
{
char *arg1;arg1 = strchr(optline, '\'');
if (arg1 == NULL || arg1 == optline)
post_opts = "";
else
{
*(arg1 - 1) = '\0'; /* this should be a space */
post_opts = arg1;
}
if (postgres_path != NULL)
postgres_path = optline;
}
else
post_opts = optline;
}
}if (postgres_path == NULL)
{
char *postmaster_path;
int ret;postmaster_path = xmalloc(MAXPGPATH);
if ((ret = find_other_exec(argv0, "postmaster", PM_VERSIONSTR,
postmaster_path)) < 0)
{
if (ret == -1)
fprintf(stderr,
_("The program \"postmaster\" is needed by %s "
"but was not found in the same directory as \"%s\".\n"
"Check your installation.\n"),
progname, progname);
else
fprintf(stderr,
_("The program \"postmaster\" was found by %s "
"but was not the same version as \"%s\".\n"
"Check your installation.\n"),
progname, progname);
exit(1);
}
postgres_path = postmaster_path;
}if (start_postmaster() != 0)
{
fprintf(stderr, _("Unable to run the postmaster binary\n"));
exit(1);
}if (old_pid != 0)
{
pg_usleep(1000000);
pid = get_pgpid();
if (pid == old_pid)
{
fprintf(stderr,
_("%s: cannot start postmaster\n"
"Examine the log output\n"),
progname);
exit(1);
}
}if (do_wait)
{
if (!silence_echo)
{
printf(_("waiting for postmaster to start..."));
fflush(stdout);
}if (test_postmaster_connection() == false)
printf(_("could not start postmaster\n"));
else if (!silence_echo)
printf(_("done\npostmaster started\n"));
}
else if (!silence_echo)
printf(_("postmaster starting\n"));
}static void
do_stop(void)
{
int cnt;
long pid;pid = get_pgpid();
if (pid == 0) /* no pid file */
{
fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
fprintf(stderr, _("Is postmaster running?\n"));
exit(1);
}
else if (pid < 0) /* standalone backend, not postmaster */
{
pid = -pid;
fprintf(stderr,
_("%s: cannot stop postmaster; "
"postgres is running (PID: %ld)\n"),
progname, pid);
exit(1);
}if (kill((pid_t) pid, sig) != 0)
{
fprintf(stderr, _("stop signal failed\n"));
exit(1);
}if (!do_wait)
{
if (!silence_echo)
printf(_("postmaster shutting down\n"));
return;
}
else
{
if (!silence_echo)
{
printf(_("waiting for postmaster to shut down..."));
fflush(stdout);
}for (cnt = 0; cnt < wait_seconds; cnt++)
{
if ((pid = get_pgpid()) != 0)
{
if (!silence_echo)
{
printf(".");
fflush(stdout);
}
pg_usleep(1000000); /* 1 sec */
}
else
break;
}if (pid != 0) /* pid file still exists */
{
if (!silence_echo)
printf(_(" failed\n"));fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
exit(1);
}
printf(_("done\npostmaster stopped\n"));
}
}/*
* restart/reload routines
*/static void
do_restart(void)
{
int cnt;
long pid;pid = get_pgpid();
if (pid == 0) /* no pid file */
{
fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
fprintf(stderr, _("Is postmaster running?\nstarting postmaster
anyway\n"));
do_start();
return;
}
else if (pid < 0) /* standalone backend, not postmaster */
{
pid = -pid;
fprintf(stderr,
_("%s: cannot restart postmaster; "
"postgres is running (PID: %ld)\n"),
progname, pid);
fprintf(stderr, _("Please terminate postgres and try again.\n"));
exit(1);
}if (kill((pid_t) pid, sig) != 0)
{
fprintf(stderr, _("stop signal failed\n"));
exit(1);
}if (!silence_echo)
{
printf(_("waiting for postmaster to shut down..."));
fflush(stdout);
}/* always wait for restart */
for (cnt = 0; cnt < wait_seconds; cnt++)
{
if ((pid = get_pgpid()) != 0)
{
if (!silence_echo)
{
printf(".");
fflush(stdout);
}
pg_usleep(1000000); /* 1 sec */
}
else
break;
}if (pid != 0) /* pid file still exists */
{
if (!silence_echo)
printf(_(" failed\n"));fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
exit(1);
}printf(_("done\npostmaster stopped\n"));
do_start();
}static void
do_reload(void)
{
long pid;pid = get_pgpid();
if (pid == 0) /* no pid file */
{
fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
fprintf(stderr, _("Is postmaster running?\n"));
exit(1);
}
else if (pid < 0) /* standalone backend, not postmaster */
{
pid = -pid;
fprintf(stderr,
_("%s: cannot reload postmaster; "
"postgres is running (PID: %ld)\n"),
progname, pid);
fprintf(stderr, _("Please terminate postgres and try again.\n"));
exit(1);
}if (kill((pid_t) pid, sig) != 0)
{
fprintf(stderr, _("reload signal failed\n"));
exit(1);
}if (!silence_echo)
fprintf(stdout, _("postmaster signaled\n"));
}/*
* utility routines
*/static void
do_status(void)
{
long pid;pid = get_pgpid();
if (pid == 0) /* no pid file */
{
fprintf(stderr, _("%s: postmaster or postgres not running\n"), progname);
exit(1);
}
else if (pid < 0) /* standalone backend */
{
pid = -pid;
fprintf(stdout, _("%s: a standalone backend \"postgres\" is running (PID:
%ld)\n"), progname, pid);
}
else /* postmaster */
{
char **optlines;fprintf(stdout, _("%s: postmaster is running (PID: %ld)\n"), progname,
pid);
optlines = readfile(postopts_file);
if (optlines != NULL)
for (; *optlines != NULL; optlines++)
fputs(*optlines, stdout);
}
}static void
do_kill(void)
{
if (kill(killproc, sig) != 0)
{
fprintf(stderr, _("signal %d failed\n"), sig);
exit(1);
}
}static void
do_advice(void)
{
fprintf(stderr, _("\nTry \"%s --help\" for more information.\n"),
progname);
}
static void
do_help(void)
{
printf(_("%s is a utility to start, stop, restart, reload configuration
files,\n"), progname);
printf(_("report the status of a PostgreSQL server, or kill a PostgreSQL
process\n\n"));
printf(_("Usage:\n"));
printf(_(" %s start [-w] [-D DATADIR] [-s] [-l FILENAME] [-o
\"OPTIONS\"]\n"), progname);
printf(_(" %s stop [-W] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"),
progname);
printf(_(" %s restart [-w] [-D DATADIR] [-s] [-m SHUTDOWN-MODE] [-o
\"OPTIONS\"]\n"), progname);
printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
printf(_(" %s status [-D DATADIR]\n"), progname);
printf(_(" %s kill SIGNALNAME PROCESSID\n"), progname);
printf(_("Common options:\n"));
printf(_(" -D, --pgdata DATADIR location of the database storage
area\n"));
printf(_(" -s, --silent only print errors, no informational
messages\n"));
printf(_(" -w wait until operation completes\n"));
printf(_(" -W do not wait until operation completes\n"));
printf(_(" --help show this help, then exit\n"));
printf(_(" --version output version information, then exit\n"));
printf(_("(The default is to wait for shutdown, but not for start or
restart.)\n\n"));
printf(_("If the -D option is omitted, the environment variable PGDATA is
used.\n\n"));
printf(_("Options for start or restart:\n"));
printf(_(" -l, --log FILENAME write (or append) server log to
FILENAME. The\n"));
printf(_(" use of this option is highly
recommended.\n"));
printf(_(" -o OPTIONS command line options to pass to the
postmaster\n"));
printf(_(" (PostgreSQL server executable)\n"));
printf(_(" -p PATH-TO-POSTMASTER normally not necessary\n\n"));
printf(_("Options for stop or restart:\n"));
printf(_(" -m SHUTDOWN-MODE may be 'smart', 'fast', or
'immediate'\n\n"));
printf(_("Allowed signal names for kill:\n"));
printf(_(" -HUP -INT -QUIT -ABRT -TERM -USR1 -USR2\n\n"));
printf(_("Shutdown modes are:\n"));
printf(_(" smart quit after all clients have disconnected\n"));
printf(_(" fast quit directly, with proper shutdown\n"));
printf(_(" immediate quit without complete shutdown; will lead to
recovery on restart\n\n"));
printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
}static void
set_mode(char *modeopt)
{
if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
{
shutdown_mode = SMART_MODE;
sig = SIGTERM;
}
else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
{
shutdown_mode = FAST_MODE;
sig = SIGINT;
}
else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)
{
shutdown_mode = IMMEDIATE_MODE;
sig = SIGQUIT;
}
else
{
fprintf(stderr, _("%s: invalid shutdown mode %s\n"), progname, modeopt);
do_advice();
exit(1);
}
}static void
set_sig(char *signame)
{
if (!strcmp(signame, "-HUP"))
sig = SIGHUP;
else if (!strcmp(signame, "-INT"))
sig = SIGINT;
else if (!strcmp(signame, "-QUIT"))
sig = SIGQUIT;
else if (!strcmp(signame, "-ABRT"))
sig = SIGABRT;/*
* probably should NOT provide SIGKILL
*
* else if (!strcmp(signame,"-KILL")) sig = SIGKILL;
*/
else if (!strcmp(signame, "-TERM"))
sig = SIGTERM;
else if (!strcmp(signame, "-USR1"))
sig = SIGUSR1;
else if (!strcmp(signame, "-USR2"))
sig = SIGUSR2;
else
{
fprintf(stderr, _("%s: invalid signal \"%s\"\n"), progname, signame);
do_advice();
exit(1);
}}
int
main(int argc, char **argv)
{
static struct option long_options[] = {
{"help", no_argument, NULL, '?'},
{"version", no_argument, NULL, 'V'},
{"log", required_argument, NULL, 'l'},
{"mode", required_argument, NULL, 'm'},
{"pgdata", required_argument, NULL, 'D'},
{"silent", no_argument, NULL, 's'},
{0, 0, 0, 0}
};int option_index;
int c;#ifdef WIN32
setvbuf(stderr, NULL, _IONBF, 0);
#endifprogname = get_progname(argv[0]);
/*
* save argv[0] so do_start() can look for the postmaster if
* necessary. we don't look for postmaster here because in many cases
* we won't need it.
*/
argv0 = argv[0];umask(077);
if (argc > 1)
{
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 ||
strcmp(argv[1], "-?") == 0)
{
do_help();
exit(0);
}
else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0)
{
printf("%s (PostgreSQL) %s\n", progname, PG_VERSION);
exit(0);
}
}/* process command-line options */
while ((c = getopt_long(argc, argv, "D:l:m:o:p:swW", long_options,
&option_index)) != -1)
{
switch (c)
{
case 'D':
{
int len = strlen(optarg) + 4;
char *env_var;pg_data_opts = xmalloc(len);
snprintf(pg_data_opts, len, "-D %s", optarg);
env_var = xmalloc(len + sizeof("PGDATA="));
snprintf(env_var, len + sizeof("PGDATA="), "PGDATA=%s", optarg);
putenv(env_var);
break;
}
case 'l':
log_file = xstrdup(optarg);
break;
case 'm':
set_mode(optarg);
break;
case 'o':
post_opts = xstrdup(optarg);
break;
case 'p':
postgres_path = xstrdup(optarg);
break;
case 's':
silence_echo = true;
break;
case 'w':
do_wait = true;
wait_set = true;
break;
case 'W':
do_wait = false;
wait_set = true;
break;
default:
fprintf(stderr, _("%s: invalid option %s\n"), progname, optarg);
do_advice();
exit(1);
}
}for (; optind < argc; optind++)
{
if (ctl_command != NO_COMMAND)
{
fprintf(stderr, _("%s: extra operation mode %s\n"), progname,
argv[optind]);
do_advice();
exit(1);
}if (strcmp(argv[optind], "start") == 0)
ctl_command = START_COMMAND;
else if (strcmp(argv[optind], "stop") == 0)
ctl_command = STOP_COMMAND;
else if (strcmp(argv[optind], "restart") == 0)
ctl_command = RESTART_COMMAND;
else if (strcmp(argv[optind], "reload") == 0)
ctl_command = RELOAD_COMMAND;
else if (strcmp(argv[optind], "status") == 0)
ctl_command = STATUS_COMMAND;
else if (strcmp(argv[optind], "kill") == 0)
{
if (argc - optind < 3)
{
fprintf(stderr, _("%s: invalid kill syntax\n"), progname);
do_advice();
exit(1);
}
ctl_command = KILL_COMMAND;
set_sig(argv[optind + 1]);
killproc = atol(argv[optind + 2]);
}
else
{
fprintf(stderr, _("%s: invalid operation mode %s\n"), progname,
argv[optind]);
do_advice();
exit(1);
}
}if (ctl_command == NO_COMMAND)
{
fprintf(stderr, _("%s: no operation specified\n"), progname);
do_advice();
exit(1);
}pg_data = getenv("PGDATA");
canonicalize_path(pg_data);if (pg_data == NULL && ctl_command != KILL_COMMAND)
{
fprintf(stderr,
_("%s: no database directory specified "
"and environment variable PGDATA unset\n"),
progname);
do_advice();
exit(1);
}if (!wait_set)
{
switch (ctl_command)
{
case RESTART_COMMAND:
case START_COMMAND:
do_wait = false;
break;
case STOP_COMMAND:
do_wait = true;
break;
default:
break;
}
}if (ctl_command == RELOAD_COMMAND)
{
sig = SIGHUP;
do_wait = false;
}snprintf(def_postopts_file, MAXPGPATH, "%s/postmaster.opts.default",
pg_data);
snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
snprintf(conf_file, MAXPGPATH, "%s/postgresql.conf", pg_data);switch (ctl_command)
{
case STATUS_COMMAND:
do_status();
break;
case START_COMMAND:
do_start();
break;
case STOP_COMMAND:
do_stop();
break;
case RESTART_COMMAND:
do_restart();
break;
case RELOAD_COMMAND:
do_reload();
break;
case KILL_COMMAND:
do_kill();
break;
default:
break;
}exit(0);
}
----------------------------------------------------------------------------
----
#-------------------------------------------------------------------------
#
# Makefile for src/bin/pg_ctl
#
# Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $PostgreSQL: pgsql-server/src/bin/pg_ctl/Makefile,v 1.41 2004/05/24
01:01:37 momjian Exp $
#
#-------------------------------------------------------------------------subdir = src/bin/pg_ctl
top_builddir = ../../..
include $(top_builddir)/src/Makefile.globaloverride CPPFLAGS
:= -DFRONTEND -DDEF_PGPORT=$(DEF_PGPORT) -I$(libpq_srcdir) $(CPPFLAGS)
OBJS= pg_ctl.o exec.o
all: submake-libpq submake-libpgport pg_ctl
pg_ctl: $(OBJS) $(libpq_builddir)/libpq.a
$(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)exec.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .install: all installdirs
$(INSTALL_PROGRAM) pg_ctl$(X) $(DESTDIR)$(bindir)/pg_ctl$(X)installdirs:
$(mkinstalldirs) $(DESTDIR)$(bindir)uninstall:
rm -f $(DESTDIR)$(bindir)/pg_ctl$(X)clean distclean maintainer-clean:
rm -f pg_ctl$(X) $(OBJS) exec.c# ensure that changes in DEF_PGPORT propagate into object file
pg_ctl.o: pg_ctl.c $(top_builddir)/src/Makefile.global
----------------------------------------------------------------------------
----
Show quoted text
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
Seems it needs an implementation of the "pgwin32 special kill". Try
stealing the one from backend/port/win32/signal.c (look for pqkill).
Perhaps this function (not the rest of signal.c!) should be moved into
port/, instead of backend/port. IIRC it depends on no other backend
code.
//Magnus
Show quoted text
-----Original Message-----
From: Thomas Hallgren [mailto:thhal@mailblocks.com]
Sent: Thursday, May 27, 2004 10:53 AM
To: pgsql-patches@postgresql.org
Subject: Re: [PATCHES] pg_ctl.cNeither the version in CVS head nor the version you attached
here links on
win32 (msys/mingw). I get the following:gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes
-Wmissing-declaratio ns pg_ctl.o
ec.o -L../../../src/interfaces/libpq -lpq -L../../../src/port
-lz -lreadli
ne -lwsock32 -lm -lpgport -lws2_32 -o pg_ctl.exe
pg_ctl.o(.text+0xa3c):pg_ctl.c: undefined reference to `kill'
pg_ctl.o(.text+0xc4c):pg_ctl.c: undefined reference to `kill'
pg_ctl.o(.text+0xe5a):pg_ctl.c: undefined reference to `kill'
pg_ctl.o(.text+0x1058):pg_ctl.c: undefined reference to `kill'Regards,
Thomas Hallgren
"Bruce Momjian" <pgman@candle.pha.pa.us> wrote in message
news:200405261459.i4QExWT28671@candle.pha.pa.us...OK, here is a new version with lots of fixes.
-- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square,Pennsylvania
19073--------------------------------------------------------------
--------------
----/*------------------------------------------------------------
-------------*
* pg_ctl --- start/stops/restarts the PostgreSQL server
*
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development
Group
*
* $PostgreSQL: pgsql-server/src/bin/initdb/initdb.c,v 1.322004/05/18
03:36:36 momjian Exp $*
*-------------------------------------------------------------
------------*/
#include "postgres_fe.h"
#include "libpq-fe.h"#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>#include "libpq/pqsignal.h"
#include "getopt_long.h"#ifndef HAVE_OPTRESET
int optreset;
#endif#define _(x) gettext((x))
#define WHITESPACE "\f\n\r\t\v" /* as defined by isspace() */
/* postmaster version ident string */
#define PM_VERSIONSTR "postmaster (PostgreSQL) " PG_VERSION "\n"typedef enum
{
SMART_MODE,
FAST_MODE,
IMMEDIATE_MODE
} ShutdownMode;typedef enum
{
NO_COMMAND = 0,
START_COMMAND,
STOP_COMMAND,
RESTART_COMMAND,
RELOAD_COMMAND,
STATUS_COMMAND,
KILL_COMMAND
} CtlCommand;static bool do_wait = false;
static bool wait_set = false;
static int wait_seconds = 60;
static bool silence_echo = false;
static ShutdownMode shutdown_mode = SMART_MODE; static int sig =
SIGTERM; /* default */ static int killproc; static CtlCommand
ctl_command = NO_COMMAND; static char *pg_data_opts = NULL; static
char *pg_data = NULL; static char *post_opts = NULL; staticconst char
*progname; static char *log_file = NULL; static char
*postgres_path =
NULL; static char *argv0 = NULL;
static void *xmalloc(size_t size);
static char *xstrdup(const char *s);
static void do_advice(void);
static void do_help(void);
static void set_mode(char *modeopt);
static void set_sig(char *signame);
static void do_start();
static void do_stop(void);
static void do_restart(void);
static void do_reload(void);
static void do_status(void);
static void do_kill(void);
static long get_pgpid(void);
static char **readfile(char *path);
static int start_postmaster(void);
static bool test_postmaster_connection(void);static char def_postopts_file[MAXPGPATH]; static char
postopts_file[MAXPGPATH]; static char pid_file[MAXPGPATH];static char
conf_file[MAXPGPATH];
/*
* routines to check memory allocations and fail noisily.
*/static void *
xmalloc(size_t size)
{
void *result;result = malloc(size);
if (!result)
{
fprintf(stderr, _("%s: out of memory\n"), progname);exit(1); } return
result; }
static char *
xstrdup(const char *s)
{
char *result;result = strdup(s);
if (!result)
{
fprintf(stderr, _("%s: out of memory\n"), progname);exit(1); } return
result; }
static long
get_pgpid(void)
{
FILE *pidf;
long pid;pidf = fopen(pid_file, "r");
if (pidf == NULL)
{
/* No pid file, not an error on startup */ if (errno ==ENOENT) return
0; else { perror("openning pid file"); exit(1); } } fscanf(pidf,
"%ld", &pid); fclose(pidf); return pid; }/*
* get the lines from a text file - return NULL if file can't be
opened */ static char ** readfile(char *path) {
FILE *infile;
int maxlength = 0,
linelen = 0;
int nlines = 0;
char **result;
char *buffer;
int c;if ((infile = fopen(path, "r")) == NULL) return NULL;
/* pass over the file twice - the first time to size the result */
while ((c = fgetc(infile)) != EOF)
{
linelen++;
if (c == '\n')
{
nlines++;
if (linelen > maxlength)
maxlength = linelen;
linelen = 0;
}
}/* handle last line without a terminating newline (yuck) */ if
(linelen)
nlines++;
if (linelen > maxlength)
maxlength = linelen;/* set up the result and the line buffer */
result = (char **) xmalloc((nlines + 1) * sizeof(char *)); buffer =
(char *) xmalloc(maxlength + 1);/* now reprocess the file and store the lines */ rewind(infile);
nlines = 0; while (fgets(buffer, maxlength + 1, infile) != NULL)
result[nlines++] = xstrdup(buffer);fclose(infile);
result[nlines] = NULL;return result;
}/*
* start/test/stop routines
*/static int
start_postmaster(void)
{
/*
* Since there might be quotes to handle here, it is easier simply
* to pass everything to a shell to process them.
*/
char cmd[MAXPGPATH];/* Does '&' work on Win32? */
if (log_file != NULL)
snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s >>\"%s\" 2>&1 &",
postgres_path, post_opts, DEVNULL, log_file); else snprintf(cmd,
MAXPGPATH, "\"%s\" %s < %s 2>&1 &", postgres_path, post_opts,
DEVNULL); return system(cmd); }/* Find the pgport and try a connection */ static bool
test_postmaster_connection(void)
{
PGconn *conn;
bool success = false;
int i;
char portstr[32];
char *p;*portstr = '\0';
/* post_opts */
for (p = post_opts; *p;)
{
/* advance past whitespace/quoting */
while (isspace(*p) || *p == '\'' || *p == '"')
p++;if (strncmp(p, "-p", strlen("-p")) == 0)
{
p += strlen("-p");
/* advance past whitespace/quoting */
while (isspace(*p) || *p == '\'' || *p == '"')
p++;
StrNCpy(portstr, p, Min(strcspn(p, "\"'"WHITESPACE) + 1,
sizeof(portstr)));
/* keep looking, maybe there is another -p */
}
/* Advance to next whitespace */
while (!isspace(*p))
p++;
}/* config file */
if (!*portstr)
{
char **optlines;optlines = readfile(conf_file);
if (optlines != NULL)
{
for (;*optlines != NULL; optlines++)
{
p = *optlines;while (isspace(*p))
p++;
if (strncmp(p, "port", strlen("port")) != 0)
continue;
p += strlen("port");
while (isspace(*p))
p++;
if (*p != '=')
continue;
p++;
while (isspace(*p))
p++;
StrNCpy(portstr, p, Min(strcspn(p, "#"WHITESPACE) + 1,
sizeof(portstr)));
/* keep looking, maybe there is another */
}
}
}/* environment */
if (!*portstr && getenv("PGPORT") != NULL)
StrNCpy(portstr, getenv("PGPORT"), sizeof(portstr));/* default */
if (!*portstr)
snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);for (i = 0; i < wait_seconds; i++)
{
if ((conn = PQsetdbLogin(NULL, portstr, NULL, NULL,"template1", NULL,
NULL)) != NULL){
PQfinish(conn);
success = true;
break;
}
}return success;
}static void
do_start(void)
{
long pid;
long old_pid = 0;
char *optline = NULL;if (ctl_command != RESTART_COMMAND)
{
old_pid = get_pgpid();
if (old_pid != 0)
fprintf(stderr,
_("%s: Another postmaster may be running. "
"Trying to start postmaster anyway.\n"),
progname);
}if (post_opts == NULL)
{
char **optlines;
int len;optlines = readfile(ctl_command == RESTART_COMMAND ?
postopts_file : def_postopts_file);
if (optlines == NULL)
{
if (ctl_command == START_COMMAND)
post_opts = "";
else
{
fprintf(stderr, _("%s: cannot read %s\n"), progname, postopts_file);
exit(1);
}
}
else if (optlines[0] == NULL || optlines[1] != NULL)
{
fprintf(stderr, _("%s: option file %s must have exactly 1 line\n"),
progname, ctl_command == RESTART_COMMAND ?
postopts_file : def_postopts_file);
exit(1);
}
else
{
optline = optlines[0];
len = strcspn(optline, "\r\n");
optline[len] = '\0';if (ctl_command == RESTART_COMMAND)
{
char *arg1;arg1 = strchr(optline, '\'');
if (arg1 == NULL || arg1 == optline)
post_opts = "";
else
{
*(arg1 - 1) = '\0'; /* this should be a space */
post_opts = arg1;
}
if (postgres_path != NULL)
postgres_path = optline;
}
else
post_opts = optline;
}
}if (postgres_path == NULL)
{
char *postmaster_path;
int ret;postmaster_path = xmalloc(MAXPGPATH);
if ((ret = find_other_exec(argv0, "postmaster", PM_VERSIONSTR,
postmaster_path)) < 0)
{
if (ret == -1)
fprintf(stderr,
_("The program \"postmaster\" is needed by %s "
"but was not found in the same directory as \"%s\".\n"
"Check your installation.\n"),
progname, progname);
else
fprintf(stderr,
_("The program \"postmaster\" was found by %s "
"but was not the same version as \"%s\".\n"
"Check your installation.\n"),
progname, progname);
exit(1);
}
postgres_path = postmaster_path;
}if (start_postmaster() != 0)
{
fprintf(stderr, _("Unable to run the postmaster binary\n"));
exit(1);
}if (old_pid != 0)
{
pg_usleep(1000000);
pid = get_pgpid();
if (pid == old_pid)
{
fprintf(stderr,
_("%s: cannot start postmaster\n"
"Examine the log output\n"),
progname);
exit(1);
}
}if (do_wait)
{
if (!silence_echo)
{
printf(_("waiting for postmaster to start..."));
fflush(stdout);
}if (test_postmaster_connection() == false)
printf(_("could not start postmaster\n"));
else if (!silence_echo)
printf(_("done\npostmaster started\n"));
}
else if (!silence_echo)
printf(_("postmaster starting\n"));
}static void
do_stop(void)
{
int cnt;
long pid;pid = get_pgpid();
if (pid == 0) /* no pid file */
{
fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
fprintf(stderr, _("Is postmaster running?\n"));
exit(1);
}
else if (pid < 0) /* standalone backend, not postmaster */
{
pid = -pid;
fprintf(stderr,
_("%s: cannot stop postmaster; "
"postgres is running (PID: %ld)\n"),
progname, pid);
exit(1);
}if (kill((pid_t) pid, sig) != 0)
{
fprintf(stderr, _("stop signal failed\n"));
exit(1);
}if (!do_wait)
{
if (!silence_echo)
printf(_("postmaster shutting down\n"));
return;
}
else
{
if (!silence_echo)
{
printf(_("waiting for postmaster to shut down..."));
fflush(stdout);
}for (cnt = 0; cnt < wait_seconds; cnt++)
{
if ((pid = get_pgpid()) != 0)
{
if (!silence_echo)
{
printf(".");
fflush(stdout);
}
pg_usleep(1000000); /* 1 sec */
}
else
break;
}if (pid != 0) /* pid file still exists */
{
if (!silence_echo)
printf(_(" failed\n"));fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
exit(1);
}
printf(_("done\npostmaster stopped\n"));
}
}/*
* restart/reload routines
*/static void
do_restart(void)
{
int cnt;
long pid;pid = get_pgpid();
if (pid == 0) /* no pid file */
{
fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
fprintf(stderr, _("Is postmaster running?\nstarting postmasteranyway\n"));
do_start();
return;
}
else if (pid < 0) /* standalone backend, not postmaster */
{
pid = -pid;
fprintf(stderr,
_("%s: cannot restart postmaster; "
"postgres is running (PID: %ld)\n"),
progname, pid);
fprintf(stderr, _("Please terminate postgres and try again.\n"));
exit(1);
}if (kill((pid_t) pid, sig) != 0)
{
fprintf(stderr, _("stop signal failed\n"));
exit(1);
}if (!silence_echo)
{
printf(_("waiting for postmaster to shut down..."));
fflush(stdout);
}/* always wait for restart */
for (cnt = 0; cnt < wait_seconds; cnt++)
{
if ((pid = get_pgpid()) != 0)
{
if (!silence_echo)
{
printf(".");
fflush(stdout);
}
pg_usleep(1000000); /* 1 sec */
}
else
break;
}if (pid != 0) /* pid file still exists */
{
if (!silence_echo)
printf(_(" failed\n"));fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
exit(1);
}printf(_("done\npostmaster stopped\n"));
do_start();
}static void
do_reload(void)
{
long pid;pid = get_pgpid();
if (pid == 0) /* no pid file */
{
fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
fprintf(stderr, _("Is postmaster running?\n"));
exit(1);
}
else if (pid < 0) /* standalone backend, not postmaster */
{
pid = -pid;
fprintf(stderr,
_("%s: cannot reload postmaster; "
"postgres is running (PID: %ld)\n"),
progname, pid);
fprintf(stderr, _("Please terminate postgres and try again.\n"));
exit(1);
}if (kill((pid_t) pid, sig) != 0)
{
fprintf(stderr, _("reload signal failed\n"));
exit(1);
}if (!silence_echo)
fprintf(stdout, _("postmaster signaled\n"));
}/*
* utility routines
*/static void
do_status(void)
{
long pid;pid = get_pgpid();
if (pid == 0) /* no pid file */
{
fprintf(stderr, _("%s: postmaster or postgres notrunning\n"), progname);
exit(1);
}
else if (pid < 0) /* standalone backend */
{
pid = -pid;
fprintf(stdout, _("%s: a standalone backend \"postgres\" isrunning (PID:
%ld)\n"), progname, pid);}
else /* postmaster */
{
char **optlines;fprintf(stdout, _("%s: postmaster is running (PID:
%ld)\n"), progname,
pid);optlines = readfile(postopts_file);
if (optlines != NULL)
for (; *optlines != NULL; optlines++)
fputs(*optlines, stdout);
}
}static void
do_kill(void)
{
if (kill(killproc, sig) != 0)
{
fprintf(stderr, _("signal %d failed\n"), sig);
exit(1);
}
}static void
do_advice(void)
{
fprintf(stderr, _("\nTry \"%s --help\" for more information.\n"),progname);
}
static void
do_help(void)
{
printf(_("%s is a utility to start, stop, restart, reloadconfiguration
files,\n"), progname);printf(_("report the status of a PostgreSQL server, or kill
a PostgreSQL
process\n\n"));printf(_("Usage:\n"));
printf(_(" %s start [-w] [-D DATADIR] [-s] [-l FILENAME] [-o\"OPTIONS\"]\n"), progname);
printf(_(" %s stop [-W] [-D DATADIR] [-s] [-m
SHUTDOWN-MODE]\n"),
progname);printf(_(" %s restart [-w] [-D DATADIR] [-s] [-m SHUTDOWN-MODE] [-o
\"OPTIONS\"]\n"), progname);
printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
printf(_(" %s status [-D DATADIR]\n"), progname);
printf(_(" %s kill SIGNALNAME PROCESSID\n"), progname);
printf(_("Common options:\n"));
printf(_(" -D, --pgdata DATADIR location of the database storagearea\n"));
printf(_(" -s, --silent only print errors, no informational
messages\n"));
printf(_(" -w wait until operation completes\n"));
printf(_(" -W do not wait until operation completes\n"));
printf(_(" --help show this help, then exit\n"));
printf(_(" --version output version information, then exit\n"));
printf(_("(The default is to wait for shutdown, but not for start orrestart.)\n\n"));
printf(_("If the -D option is omitted, the environment
variable PGDATA is
used.\n\n"));printf(_("Options for start or restart:\n"));
printf(_(" -l, --log FILENAME write (or append) server log toFILENAME. The\n"));
printf(_(" use of this option is highly
recommended.\n"));
printf(_(" -o OPTIONS command line options to
pass to the
postmaster\n"));printf(_(" (PostgreSQL server
executable)\n"));
printf(_(" -p PATH-TO-POSTMASTER normally not necessary\n\n"));
printf(_("Options for stop or restart:\n"));
printf(_(" -m SHUTDOWN-MODE may be 'smart', 'fast', or'immediate'\n\n"));
printf(_("Allowed signal names for kill:\n"));
printf(_(" -HUP -INT -QUIT -ABRT -TERM -USR1 -USR2\n\n"));
printf(_("Shutdown modes are:\n"));
printf(_(" smart quit after all clients havedisconnected\n"));
printf(_(" fast quit directly, with proper shutdown\n"));
printf(_(" immediate quit without complete shutdown; will lead torecovery on restart\n\n"));
printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
}static void
set_mode(char *modeopt)
{
if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
{
shutdown_mode = SMART_MODE;
sig = SIGTERM;
}
else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
{
shutdown_mode = FAST_MODE;
sig = SIGINT;
}
else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt,"immediate") == 0)
{
shutdown_mode = IMMEDIATE_MODE;
sig = SIGQUIT;
}
else
{
fprintf(stderr, _("%s: invalid shutdown mode %s\n"),progname, modeopt);
do_advice();
exit(1);
}
}static void
set_sig(char *signame)
{
if (!strcmp(signame, "-HUP"))
sig = SIGHUP;
else if (!strcmp(signame, "-INT"))
sig = SIGINT;
else if (!strcmp(signame, "-QUIT"))
sig = SIGQUIT;
else if (!strcmp(signame, "-ABRT"))
sig = SIGABRT;/*
* probably should NOT provide SIGKILL
*
* else if (!strcmp(signame,"-KILL")) sig = SIGKILL;
*/
else if (!strcmp(signame, "-TERM"))
sig = SIGTERM;
else if (!strcmp(signame, "-USR1"))
sig = SIGUSR1;
else if (!strcmp(signame, "-USR2"))
sig = SIGUSR2;
else
{
fprintf(stderr, _("%s: invalid signal \"%s\"\n"), progname,signame);
do_advice();
exit(1);
}}
int
main(int argc, char **argv)
{
static struct option long_options[] = {
{"help", no_argument, NULL, '?'},
{"version", no_argument, NULL, 'V'},
{"log", required_argument, NULL, 'l'},
{"mode", required_argument, NULL, 'm'},
{"pgdata", required_argument, NULL, 'D'},
{"silent", no_argument, NULL, 's'},
{0, 0, 0, 0}
};int option_index;
int c;#ifdef WIN32
setvbuf(stderr, NULL, _IONBF, 0);
#endifprogname = get_progname(argv[0]);
/*
* save argv[0] so do_start() can look for the postmaster if
* necessary. we don't look for postmaster here because in many cases
* we won't need it.
*/
argv0 = argv[0];umask(077);
if (argc > 1)
{
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 ||
strcmp(argv[1], "-?") == 0)
{
do_help();
exit(0);
}
else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1],"--version") == 0)
{
printf("%s (PostgreSQL) %s\n", progname, PG_VERSION);
exit(0);
}
}/* process command-line options */
while ((c = getopt_long(argc, argv, "D:l:m:o:p:swW", long_options,
&option_index)) != -1)
{
switch (c)
{
case 'D':
{
int len = strlen(optarg) + 4;
char *env_var;pg_data_opts = xmalloc(len);
snprintf(pg_data_opts, len, "-D %s", optarg);
env_var = xmalloc(len + sizeof("PGDATA="));
snprintf(env_var, len + sizeof("PGDATA="), "PGDATA=%s", optarg);
putenv(env_var);
break;
}
case 'l':
log_file = xstrdup(optarg);
break;
case 'm':
set_mode(optarg);
break;
case 'o':
post_opts = xstrdup(optarg);
break;
case 'p':
postgres_path = xstrdup(optarg);
break;
case 's':
silence_echo = true;
break;
case 'w':
do_wait = true;
wait_set = true;
break;
case 'W':
do_wait = false;
wait_set = true;
break;
default:
fprintf(stderr, _("%s: invalid option %s\n"), progname, optarg);
do_advice();
exit(1);
}
}for (; optind < argc; optind++)
{
if (ctl_command != NO_COMMAND)
{
fprintf(stderr, _("%s: extra operation mode %s\n"), progname,argv[optind]);
do_advice();
exit(1);
}if (strcmp(argv[optind], "start") == 0)
ctl_command = START_COMMAND;
else if (strcmp(argv[optind], "stop") == 0)
ctl_command = STOP_COMMAND;
else if (strcmp(argv[optind], "restart") == 0)
ctl_command = RESTART_COMMAND;
else if (strcmp(argv[optind], "reload") == 0)
ctl_command = RELOAD_COMMAND;
else if (strcmp(argv[optind], "status") == 0)
ctl_command = STATUS_COMMAND;
else if (strcmp(argv[optind], "kill") == 0)
{
if (argc - optind < 3)
{
fprintf(stderr, _("%s: invalid kill syntax\n"), progname);
do_advice();
exit(1);
}
ctl_command = KILL_COMMAND;
set_sig(argv[optind + 1]);
killproc = atol(argv[optind + 2]);
}
else
{
fprintf(stderr, _("%s: invalid operation mode %s\n"), progname,argv[optind]);
do_advice();
exit(1);
}
}if (ctl_command == NO_COMMAND)
{
fprintf(stderr, _("%s: no operation specified\n"), progname);
do_advice();
exit(1);
}pg_data = getenv("PGDATA");
canonicalize_path(pg_data);if (pg_data == NULL && ctl_command != KILL_COMMAND)
{
fprintf(stderr,
_("%s: no database directory specified "
"and environment variable PGDATA unset\n"),
progname);
do_advice();
exit(1);
}if (!wait_set)
{
switch (ctl_command)
{
case RESTART_COMMAND:
case START_COMMAND:
do_wait = false;
break;
case STOP_COMMAND:
do_wait = true;
break;
default:
break;
}
}if (ctl_command == RELOAD_COMMAND)
{
sig = SIGHUP;
do_wait = false;
}snprintf(def_postopts_file, MAXPGPATH, "%s/postmaster.opts.default",
pg_data);
snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
snprintf(conf_file, MAXPGPATH, "%s/postgresql.conf", pg_data);switch (ctl_command)
{
case STATUS_COMMAND:
do_status();
break;
case START_COMMAND:
do_start();
break;
case STOP_COMMAND:
do_stop();
break;
case RESTART_COMMAND:
do_restart();
break;
case RELOAD_COMMAND:
do_reload();
break;
case KILL_COMMAND:
do_kill();
break;
default:
break;
}exit(0);
}--------------------------------------------------------------
--------------
----#-------------------------------------------------------------
------------#
# Makefile for src/bin/pg_ctl
#
# Portions Copyright (c) 1996-2003, PostgreSQL GlobalDevelopment Group
# Portions Copyright (c) 1994, Regents of the University of
California
#
# $PostgreSQL: pgsql-server/src/bin/pg_ctl/Makefile,v 1.412004/05/24
01:01:37 momjian Exp $#
#-------------------------------------------------------------
------------subdir = src/bin/pg_ctl
top_builddir = ../../..
include $(top_builddir)/src/Makefile.globaloverride CPPFLAGS
:= -DFRONTEND -DDEF_PGPORT=$(DEF_PGPORT) -I$(libpq_srcdir) $(CPPFLAGS)
OBJS= pg_ctl.o exec.o
all: submake-libpq submake-libpgport pg_ctl
pg_ctl: $(OBJS) $(libpq_builddir)/libpq.a
$(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)exec.c: % : $(top_srcdir)/src/port/%
rm -f $@ && $(LN_S) $< .install: all installdirs
$(INSTALL_PROGRAM) pg_ctl$(X) $(DESTDIR)$(bindir)/pg_ctl$(X)installdirs:
$(mkinstalldirs) $(DESTDIR)$(bindir)uninstall:
rm -f $(DESTDIR)$(bindir)/pg_ctl$(X)clean distclean maintainer-clean:
rm -f pg_ctl$(X) $(OBJS) exec.c# ensure that changes in DEF_PGPORT propagate into object file
pg_ctl.o: pg_ctl.c $(top_builddir)/src/Makefile.global--------------------------------------------------------------
--------------
-------------------------------(end of
broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to
majordomo@postgresql.org
---------------------------(end of
broadcast)---------------------------
TIP 8: explain analyze is your friend
Import Notes
Resolved by subject fallback
Magnus Hagander wrote:
Seems it needs an implementation of the "pgwin32 special kill". Try
stealing the one from backend/port/win32/signal.c (look for pqkill).Perhaps this function (not the rest of signal.c!) should be moved into
port/, instead of backend/port. IIRC it depends on no other backend
code.
OK, patch attached and applied, and new kill.c file that goes into
/port.
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 359-1001
+ If your life is a hard drive, | 13 Roberts Road
+ Christ can be your backup. | Newtown Square, Pennsylvania 19073