head	1.82;
access;
symbols
	release_4_2:1.79
	marc_alpha:1.72
	aix_ok:1.74
	Version_2_1:1.40
	old_buffer_manager:1.22
	Version_2:1.16
	C_Demo_1:1.9;
locks; strict;
comment	@ * @;


1.82
date	94.09.30.16.17.16;	author postgres;	state Exp;
branches;
next	1.81;

1.81
date	94.09.28.18.03.39;	author postdev;	state Exp;
branches;
next	1.80;

1.80
date	94.09.28.18.01.47;	author postdev;	state Exp;
branches;
next	1.79;

1.79
date	94.06.16.03.23.06;	author aoki;	state Exp;
branches;
next	1.78;

1.78
date	94.05.07.00.09.19;	author aoki;	state Exp;
branches;
next	1.77;

1.77
date	94.02.09.00.12.24;	author aoki;	state Exp;
branches;
next	1.76;

1.76
date	94.02.07.13.16.20;	author aoki;	state Exp;
branches;
next	1.75;

1.75
date	94.02.07.11.57.34;	author aoki;	state Exp;
branches;
next	1.74;

1.74
date	93.09.22.01.25.51;	author aoki;	state Exp;
branches;
next	1.73;

1.73
date	93.08.10.20.31.38;	author aoki;	state Exp;
branches;
next	1.72;

1.72
date	93.08.10.01.46.51;	author marc;	state Exp;
branches;
next	1.71;

1.71
date	93.07.29.18.38.47;	author mao;	state Exp;
branches;
next	1.70;

1.70
date	93.06.24.04.07.14;	author aoki;	state Exp;
branches;
next	1.69;

1.69
date	93.06.16.04.29.18;	author aoki;	state Exp;
branches;
next	1.68;

1.68
date	93.06.09.19.04.52;	author mao;	state Exp;
branches;
next	1.67;

1.67
date	93.04.07.18.33.38;	author mao;	state Exp;
branches;
next	1.66;

1.66
date	93.03.23.02.16.54;	author aoki;	state Exp;
branches;
next	1.65;

1.65
date	93.03.17.20.31.06;	author aoki;	state Exp;
branches;
next	1.64;

1.64
date	93.02.23.23.47.13;	author aoki;	state Exp;
branches;
next	1.63;

1.63
date	93.02.02.22.45.08;	author marc;	state Exp;
branches;
next	1.62;

1.62
date	93.01.29.05.08.05;	author aoki;	state Exp;
branches;
next	1.61;

1.61
date	93.01.05.02.31.00;	author aoki;	state Exp;
branches;
next	1.60;

1.60
date	92.12.29.01.38.03;	author aoki;	state Exp;
branches;
next	1.59;

1.59
date	92.11.11.05.00.21;	author marc;	state Exp;
branches;
next	1.58;

1.58
date	92.09.05.23.43.25;	author mao;	state Exp;
branches;
next	1.57;

1.57
date	92.08.12.02.47.20;	author mao;	state Exp;
branches;
next	1.56;

1.56
date	92.06.10.05.18.42;	author mer;	state Exp;
branches;
next	1.55;

1.55
date	92.05.21.18.06.05;	author mer;	state Exp;
branches;
next	1.54;

1.54
date	92.04.28.00.25.49;	author mer;	state Exp;
branches;
next	1.53;

1.53
date	92.04.27.22.35.18;	author mer;	state Exp;
branches;
next	1.52;

1.52
date	91.12.16.20.43.25;	author mer;	state Exp;
branches;
next	1.51;

1.51
date	91.11.18.20.17.57;	author clarsen;	state Exp;
branches;
next	1.50;

1.50
date	91.11.07.22.13.55;	author mer;	state Exp;
branches;
next	1.49;

1.49
date	91.09.09.23.58.33;	author mao;	state Exp;
branches;
next	1.48;

1.48
date	91.08.15.15.00.49;	author mer;	state Exp;
branches;
next	1.47;

1.47
date	91.08.14.12.36.50;	author mer;	state Exp;
branches;
next	1.46;

1.46
date	91.08.12.15.25.00;	author mer;	state Exp;
branches;
next	1.45;

1.45
date	91.07.22.22.20.07;	author mao;	state Exp;
branches;
next	1.44;

1.44
date	91.07.22.14.52.31;	author mer;	state Exp;
branches;
next	1.43;

1.43
date	91.05.08.15.19.33;	author choi;	state Exp;
branches;
next	1.42;

1.42
date	91.03.20.19.17.11;	author cimarron;	state Exp;
branches;
next	1.41;

1.41
date	91.03.10.21.10.52;	author kemnitz;	state Exp;
branches;
next	1.40;

1.40
date	91.03.09.06.58.57;	author kemnitz;	state Exp;
branches;
next	1.39;

1.39
date	91.03.09.04.10.16;	author kemnitz;	state Exp;
branches;
next	1.38;

1.38
date	91.03.07.23.18.35;	author kemnitz;	state Exp;
branches;
next	1.37;

1.37
date	91.03.05.12.57.04;	author mao;	state Exp;
branches;
next	1.36;

1.36
date	91.03.05.10.27.27;	author mer;	state Exp;
branches;
next	1.35;

1.35
date	91.03.01.17.49.12;	author mer;	state Exp;
branches;
next	1.34;

1.34
date	91.03.01.17.44.08;	author mer;	state Exp;
branches;
next	1.33;

1.33
date	91.02.28.13.46.51;	author mer;	state Exp;
branches;
next	1.32;

1.32
date	91.02.28.10.38.30;	author mer;	state Exp;
branches;
next	1.31;

1.31
date	91.02.27.00.15.18;	author hong;	state Exp;
branches;
next	1.30;

1.30
date	91.02.26.22.50.42;	author mer;	state Exp;
branches;
next	1.29;

1.29
date	91.02.25.13.36.26;	author sp;	state Exp;
branches;
next	1.28;

1.28
date	91.02.22.17.12.43;	author mer;	state Exp;
branches;
next	1.27;

1.27
date	91.02.06.13.32.21;	author kemnitz;	state Exp;
branches;
next	1.26;

1.26
date	91.02.06.13.17.19;	author kemnitz;	state Exp;
branches;
next	1.25;

1.25
date	91.02.04.17.28.24;	author kemnitz;	state Exp;
branches;
next	1.24;

1.24
date	91.02.02.18.34.10;	author mao;	state Exp;
branches;
next	1.23;

1.23
date	91.01.18.22.22.04;	author hong;	state Exp;
branches;
next	1.22;

1.22
date	90.10.16.00.29.30;	author kemnitz;	state Exp;
branches;
next	1.21;

1.21
date	90.09.25.17.23.59;	author kemnitz;	state Exp;
branches;
next	1.20;

1.20
date	90.09.25.15.52.02;	author kemnitz;	state Exp;
branches;
next	1.19;

1.19
date	90.09.18.21.57.26;	author hong;	state Exp;
branches;
next	1.18;

1.18
date	90.08.24.14.40.14;	author choi;	state Exp;
branches;
next	1.17;

1.17
date	90.08.23.16.02.59;	author hong;	state Exp;
branches;
next	1.16;

1.16
date	90.05.25.12.16.44;	author kemnitz;	state Version_2;
branches;
next	1.15;

1.15
date	90.04.19.17.49.45;	author kemnitz;	state Exp;
branches;
next	1.14;

1.14
date	90.04.11.21.42.26;	author kemnitz;	state Exp;
branches;
next	1.13;

1.13
date	90.03.31.19.06.04;	author cimarron;	state Exp;
branches;
next	1.12;

1.12
date	90.02.12.19.51.24;	author cimarron;	state Exp;
branches;
next	1.11;

1.11
date	89.11.24.15.55.35;	author hirohama;	state Exp;
branches;
next	1.10;

1.10
date	89.09.21.18.58.34;	author hirohama;	state Exp;
branches;
next	1.9;

1.9
date	89.09.05.16.53.19;	author mao;	state C_Demo_1;
branches;
next	1.8;

1.8
date	89.08.31.17.52.38;	author mao;	state Exp;
branches;
next	1.7;

1.7
date	89.08.31.10.21.08;	author goh;	state Exp;
branches;
next	1.6;

1.6
date	89.08.30.18.52.04;	author goh;	state Exp;
branches;
next	1.5;

1.5
date	89.08.02.23.56.46;	author dillon;	state Exp;
branches;
next	1.4;

1.4
date	89.07.17.14.40.16;	author dillon;	state Exp;
branches;
next	1.3;

1.3
date	89.04.14.18.33.41;	author dillon;	state Exp;
branches;
next	1.2;

1.2
date	89.02.02.15.58.13;	author dillon;	state Stab;
branches;
next	1.1;

1.1
date	89.01.17.05.57.58;	author cimarron;	state Exp;
branches;
next	;


desc
@@


1.82
log
@changed #define FORK() vfork()
to      #define FORK() fork()
since 'fork' and not 'vfork' is what is used in rest of routine
@
text
@/*
 * $Header: /usr/local/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.81 1994/09/28 18:03:39 postdev Exp postgres $
 *
 *	POSTMASTER
 *
 *	This program acts as a clearing house for requests to the
 *	POSTGRES system.  Frontend programs send a startup message
 *	to the Postmaster and the postmaster uses the info in the
 *	message to setup a backend process.
 *
 * Initialization:
 *	The Postmaster sets up a few shared memory data structures 
 * 	for the backends.  It should at the very least initialize the
 *	lock manager.
 *
 * Synchronization:
 *	The Postmaster shares memory with the backends and will have to lock
 *	the shared memory it accesses.  The Postmaster should never block
 *	on messages from clients.
 *	
 * Garbage Collection:
 *	The Postmaster cleans up after backends if they have an emergency
 *	exit and/or core dump.
 *
 * Communication:
 *
 * NOTES:
 *
 */

#include "libpq/pqsignal.h"	/* substitute for <signal.h> */
#include <strings.h>
#include <sys/types.h>		/* for fd_set stuff */
#include <sys/stat.h>		/* for umask */
#include <sys/time.h>
#include <sys/param.h>		/* for MAXHOSTNAMELEN on most */
#include <netdb.h>		/* for MAXHOSTNAMELEN on some */
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <values.h>		/* for MAXINT */
#include <sys/wait.h>

#if defined(PORTNAME_aix)
#include <sys/select.h>
#endif /* PORTNAME_aix */

#include "storage/ipci.h"
#include "tmp/pqcomm.h"
#include "tmp/miscadmin.h"
#include "catalog/pg_user.h"	/* for USER_NAMESIZE */
#include "tmp/simplelists.h"

#ifdef DBX_VERSION
#define FORK() (0)
#else
#define FORK() fork()
#endif

/*
 * Info for garbage collection.  Whenever a process dies, the Postmaster
 * cleans up after it.  Currently, NO information is required for cleanup,
 * but I left this structure around in case that changed.
 */
typedef struct bkend {
    int	pid;		/* process id of backend */
} Backend;

typedef struct bnode {
    SLNode	bn_node;
    Backend	bn_backend;
} BackendNode;

/* list of active backends.  For garbage collection only now. */
static SLList	BackendList;

typedef struct pnode {
    SLNode	pn_node;
    Port	pn_port;
} PortNode;

/* list of ports associated with still open, but incomplete connections */
static SLList	PortList;

static short	PostPortName = -1;
static short	ActiveBackends = FALSE;
static int	NextBackendId = MAXINT;		/* XXX why? */
static char	*progname = (char *) NULL;

char		*DataDir = (char *) NULL;
    
/*
 * Default Values
 */
static char	Execfile[MAXPATHLEN] = "";
static char	Username[USER_NAMESIZE] = "NOT_PROVIDED";

static int	ServerSock = INVALID_SOCK;	/* stream socket server */

/* 
 * Defined in utils/init/globals.c, set by the -d option and passed on
 * to child processes
 */
extern short	DebugLvl;

/*
 * Set by the -o option
 */
static char	ExtraOptions[ARGV_SIZE] = "";

/*
 * These globals control the behavior of the postmaster in case some
 * backend dumps core.  Normally, it kills all peers of the dead backend
 * and reinitializes shared memory.  By specifying -s or -n, we can have
 * the postmaster stop (rather than kill) peers and not reinitialize
 * shared data structures.
 */
static int	Reinit = 1;
static int	SendStop = 0;

/* 
 * postmaster.c - function prototypes (none of the funcs are public use)
 */
void	pmdaemonize ARGS((void));
int	ServerLoop ARGS((int serverFd));
int     ConnStartup ARGS((Port * port));
int     ConnCreate ARGS((int serverFd, int *newFdP));
void	reset_shared ARGS((short port));
int     pmdie ARGS((void));
int     reaper ARGS((void));
int	dumpstatus ARGS((void));
void	CleanupProc ARGS((int pid, int exitstatus));
int     BackendStartup ARGS((StartupPacket * packet, Port * port));
int     DoExec ARGS((StartupPacket * packet, int portFd));
int     ExitPostmaster ARGS((int status));

/* from utils/init/miscinit.c */
extern	ValidateBackend ARGS((char *path));
extern	FindBackend ARGS((char *backend, char *argv0));

extern	Quiet;

main(argc, argv)
    int		argc;
    char	*argv[];
{
    extern char	*getenv(), *optarg;
    extern int	getopt(), opterr, optind;
    extern int	NBuffers;	/* from buffer/bufmgr.c */
    extern bool	IsPostmaster;	/* from smgr/mm.c */
    char	opt;
    char	*hostName;
    int		status;
    int		silentflag = 0;
    char	hostbuf[MAXHOSTNAMELEN];

#if defined(NOFIXADE) || defined(NOPRINTADE)
    /*
     * Must be first so that the bootstrap code calls it, too.
     * (Only needed on some RISC architectures.)
     */
    init_address_fixup();    /* must be first */
#endif /* NOFIXADE || NOPRINTADE */

    progname = argv[0];

    /* for security, no dir or file created can be group or other accessible */
    (void) umask((mode_t) 0077);

    if (!(hostName = getenv("PGHOST"))) {
	if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
	    (void) strcpy(hostbuf, "localhost");
	hostName = hostbuf;
    }

    opterr = 0;
    while ((opt = getopt(argc, argv, "a:B:b:D:dno:p:Ss")) != EOF) {
	switch (opt) {
	case 'a': 
	    /* Set the authentication system. */
	    be_setauthsvc(optarg);
	    break;
	case 'B': 
	    /*
	     * The number of buffers to create.  Setting this
	     * option means we have to start each backend with
	     * a -B # to make sure they know how many buffers
	     * were allocated. 
	     */
	    NBuffers = atol(optarg);
	    (void) strcat(ExtraOptions, " -B ");
	    (void) strcat(ExtraOptions, optarg);
	    break;
	case 'b': 
	    /* Set the backend executable file to use. */
	    if (!ValidateBackend(optarg))
		strcpy(Execfile, optarg);
	    else {
		fprintf(stderr, "%s: invalid backend \"%s\"\n",
			progname, optarg);
		exit(2);
	    }
	    break;
	case 'D': 
	    /* Set PGDATA from the command line. */
	    DataDir = optarg;
	    break;
	case 'd': 
	    /*
	     * Turn on debugging for the postmaster and the backend
	     * servers descended from it.
	     */
	    if ((optind < argc) && *argv[optind] != '-') {
		DebugLvl = atoi(argv[optind]);
		optind++;
	    }
	    else
		DebugLvl = 1;
	    break;
	case 'n': 
	    /* Don't reinit shared mem after abnormal exit */
	    Reinit = 0;
	    break;
	case 'o': 
	    /*
	     * Other options to pass to the backend on the
	     * command line -- useful only for debugging.
	     */
	    (void) strcat(ExtraOptions, " ");
	    (void) strcat(ExtraOptions, optarg);
	    break;
	case 'p': 
	    /* Set PGPORT by hand. */
	    PostPortName = (short) atoi(optarg);
	    break;
	case 'S':
	    /*
	     * Start in 'S'ilent mode (disassociate from controlling tty).
	     * You may also think of this as 'S'ysV mode since it's most
	     * badly needed on SysV-derived systems like SVR4 and HP-UX.
	     */
	    silentflag = 1;
	    break;
	case 's':
	    /*
	     * In the event that some backend dumps core,
	     * send SIGSTOP, rather than SIGUSR1, to all
	     * its peers.  This lets the wily post_hacker
	     * collect core dumps from everyone.
	     */
	    SendStop = 1;
	    break;
	default: 
	    /* usage() never returns */
	    usage(progname);
	    break;
	}
    }
    if (PostPortName == -1)
	PostPortName = pq_getport();

    IsPostmaster = true;

    if (!DataDir)
	DataDir = GetPGData();

    if (!Execfile[0] && FindBackend(Execfile, argv[0]) < 0) {
	fprintf(stderr, "%s: could not find backend to execute...\n",
		argv[0]);
	exit(1);
    }

    status = StreamServerPort(hostName, PostPortName, &ServerSock);
    if (status != STATUS_OK) {
	fprintf(stderr, "%s: cannot create stream port\n",
		progname);
	exit(1);
    }

    /* set up shared memory and semaphores */
    EnableMemoryContext(TRUE);
    reset_shared(PostPortName);

    /* 
     * Initialize the list of active backends.  This list is only
     * used for garbage collecting the backend processes.
     */
    SLNewList(&BackendList, 0);
    SLNewList(&PortList, 0);

    if (silentflag)
	pmdaemonize();

    signal(SIGCHLD, reaper);
    signal(SIGTTIN, SIG_IGN);
    signal(SIGTTOU, SIG_IGN);
    signal(SIGHUP, pmdie);
    signal(SIGINT, pmdie);
    signal(SIGTERM, pmdie);
    signal(SIGCONT, dumpstatus);

    status = ServerLoop(ServerSock);

    ExitPostmaster(status != STATUS_OK);
}

void
pmdaemonize()
{
    int i;
    
    if (fork())
	exit(0);

    if (setsid() < 0) {
	fprintf(stderr, "%s: ", progname);
	perror("cannot disassociate from controlling TTY");
	exit(1);
    }
    i = open("/dev/null", O_RDWR);
    (void) dup2(i, 0);
    (void) dup2(i, 1);
    (void) dup2(i, 2);
    (void) close(i);
}

usage(progname)
    char   *progname;
{
    fprintf(stderr, "usage: %s [options..]\n", progname);
    fprintf(stderr, "\t-B nbufs\tset number of shared buffers\n");
    fprintf(stderr, "\t-D datadir\tset data directory\n");
    fprintf(stderr, "\t-S\t\tsilent mode (disassociate from tty)\n");
    fprintf(stderr, "\t-a authsys\tdo/do not permit use of an authentication system\n");
    fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
    fprintf(stderr, "\t-d [debuglvl]\tset debugging level\n");
    fprintf(stderr, "\t-n\t\tdon't reinitialize shared memory after abnormal exit\n");
    fprintf(stderr, "\t-o option\tpass 'option' to each backend servers\n");
    fprintf(stderr, "\t-p port\t\tspecify port for postmaster to listen on\n");
    fprintf(stderr, "\t-s\t\tsend SIGSTOP to all backend servers if one dies\n");
    exit(1);
}

ServerLoop(serverFd)
    int     serverFd;
{
    fd_set	rmask, basemask;
    int		nSockets, nSelected, status, newFd;
    PortNode	*prev, *curr;

    nSockets = ServerSock + 1;
    FD_ZERO(&basemask);
    FD_SET(ServerSock, &basemask);

    for (;;) {
	newFd = -1;
	bcopy((char *) &basemask, (char *) &rmask, sizeof(fd_set));
	if ((nSelected = select(nSockets, &rmask,
				(fd_set *) NULL,
				(fd_set *) NULL,
				(struct timeval *) NULL)) < 0) {
	    if (errno == EINTR)
		continue;
	    fprintf(stderr, "%s: ServerLoop: select failed\n",
		    progname);
	    return(STATUS_ERROR);
	}
	if (DebugLvl > 1) {
	    fprintf(stderr, "%s: ServerLoop: %d sockets pending\n",
		    progname, nSelected);
	}

	/* new connection pending on our well-known port's socket */
	if (FD_ISSET(ServerSock, &rmask)) {
	    /*
	     * connect and make an addition to PortList.  If
	     * the connection dies and we notice it, just forget
	     * about the whole thing.
	     */
	    if (ConnCreate(serverFd, &newFd) == STATUS_OK) {
		if (newFd >= nSockets)
		    nSockets = newFd + 1;
		FD_SET(newFd, &rmask);
		FD_SET(newFd, &basemask);
		if (DebugLvl)
		    fprintf(stderr, "%s: ServerLoop: connect on %d\n",
			    progname, newFd);
	    }
	    --nSelected;
	    FD_CLR(ServerSock, &rmask);
	}

	if (DebugLvl > 1) {
	    fprintf(stderr, "%s: ServerLoop:\tnSelected=%d\n",
		    progname, nSelected);
	    curr = (PortNode *) SLGetHead(&PortList);
	    while (curr) {
		Port *port = &curr->pn_port;

		fprintf(stderr, "%s: ServerLoop:\t\tport %d%s pending\n",
			progname, port->sock,
			FD_ISSET(port->sock, &rmask)
			? "" :
			" not");
		curr = (PortNode *) SLGetSucc(&curr->pn_node);
	    }
	}

	curr = (PortNode *) SLGetHead(&PortList);
	while (curr) {
	    ConnId connId;	/* dummy argument */
	    Port *port = &curr->pn_port;
	    int lastbytes = port->nBytes;

	    if (FD_ISSET(port->sock, &rmask) && port->sock != newFd) {
		if (DebugLvl > 1)
		    fprintf(stderr, "%s: ServerLoop:\t\thandling %d\n",
			    progname, port->sock);
		--nSelected;

		/*
		 * Read the incoming packet into its packet buffer.
		 * Read the connection id out of the packet so we
		 * know who the packet is from.
		 */
		status = PacketReceive(port, (Addr) &port->buf,
				       NON_BLOCKING, &connId);
		switch (status) {
		case STATUS_OK: 
		    ConnStartup(port);
		    ActiveBackends = TRUE;
		    /*FALLTHROUGH*/
		case STATUS_INVALID: 
		    if (DebugLvl)
			fprintf(stderr, "%s: ServerLoop:\t\tdone with %d\n",
				progname, port->sock);
		    break;
		case STATUS_NOT_DONE:
		    if (DebugLvl)
			fprintf(stderr, "%s: ServerLoop:\t\tpartial packet (%d bytes actually read) on %d\n",
				progname, port->nBytes, port->sock);
		    /*
		     * If we've received at least a PacketHdr's worth of data
		     * and we're still receiving data each time we read, we're
		     * ok.  If the client gives us less than a PacketHdr at
		     * the beginning, just kill the connection and forget
		     * about the whole thing.
		     */
		    if (lastbytes < port->nBytes) {
			if (DebugLvl)
			    fprintf(stderr, "%s: ServerLoop:\t\tpartial packet on %d ok\n",
				    progname, port->sock);
			curr = (PortNode *) SLGetSucc(&curr->pn_node);
			continue;
		    }
		    break;
		case STATUS_ERROR:	/* system call error - die */
		    fprintf(stderr, "%s: ServerLoop:\t\terror receiving packet\n",
			    progname);
		    return(STATUS_ERROR);
		}
		FD_CLR(port->sock, &basemask);
		StreamClose(port->sock);
		prev = (PortNode *) SLGetPred(&curr->pn_node);
		SLRemove(&curr->pn_node);
		free((char *) curr);
		if (!prev) {	/* removed head */
		    curr = (PortNode *) SLGetHead(&PortList);
		    continue;
		}
	    }
	    curr = (PortNode *) SLGetSucc(&curr->pn_node);
	}
	Assert(nSelected == 0);
    }
    /*NOTREACHED*/
}

ConnStartup(port)
    Port	*port;			/* receiving port */
{
    int		status;
    MsgType		msgType;
    SeqNo		seqno = INITIAL_SEQNO;
    PacketLen	bufSize;
    Addr		buf;
    char		namebuf[USER_NAMESIZE + 1];
    StartupPacket	*sp;
    
    /* 
     * Get the packet header information.
     *  XXX This is the only use of PacketData() in the entire system,
     *	yet we're feeding it arguments (buf, bufSize, seqno) that
     *	we never use.  WTF??
     */
    sp = (StartupPacket *) &port->buf;
    PacketData((Addr) sp, &buf, &bufSize, &msgType, &seqno);
    
    (void) strncpy(namebuf, sp->user, USER_NAMESIZE);
    namebuf[USER_NAMESIZE] = '\0';
    if (!namebuf[0]) {
	fprintf(stderr, "%s: ConnStartup: no user name specified\n",
		progname);
	return(STATUS_ERROR);
    }
    
    if (be_recvauth(msgType, port, namebuf) != STATUS_OK) {
	fprintf(stderr, "%s: ConnStartup: authentication failed\n",
		progname);
	return(STATUS_ERROR);
    }
    
    if (BackendStartup(sp, port) != STATUS_OK) {
	fprintf(stderr, "%s: ConnStartup: couldn't start backend\n",
		progname);
	return(STATUS_ERROR);
    }
    
    return(STATUS_OK);
}


/*
 * ConnCreate -- create a local connection data structure
 */
ConnCreate(serverFd, newFdP)
    int	serverFd;
    int	*newFdP;
{
#if 0
    /* dead code having to do with the pseudo-Packet stuff */
    Connection	*conn;
    int		connId;
    long		currTime;
#endif
    int		status;
    Port		*port;
    PortNode	*pn;
    
    if (!(pn = (PortNode *) calloc(1, sizeof(PortNode)))) {
	fprintf(stderr, "%s: ConnCreate: malloc failed\n",
		progname);
	ExitPostmaster(1);
    }
    SLNewNode(&pn->pn_node);
    port = &pn->pn_port;
    
    if ((status = StreamConnection(serverFd, port)) != STATUS_OK) {
	StreamClose(port->sock);
	free((char *) pn);
    }
    else {
	SLAddHead(&PortList, &pn->pn_node);
	*newFdP = port->sock;
    }
    
    return (status);
}

/*
 * reset_shared -- reset shared memory and semaphores
 */
void
reset_shared(port)
    short	port;
{
    IPCKey	key;
    
    key = SystemPortAddressCreateIPCKey((SystemPortAddress) port);
    CreateSharedMemoryAndSemaphores(key);
    ActiveBackends = FALSE;
}

/*
 * pmdie -- signal handler for cleaning up after a kill signal.
 */
pmdie()
{
    exitpg(0);
}

/*
 * Reaper -- signal handler to cleanup after a backend (child) dies.
 */
reaper()
{
    int	status;		/* backend exit status */
    int	pid;		/* process id of dead backend */
    
    if (DebugLvl)
	fprintf(stderr, "%s: reaping dead processes...\n",
		progname);
    while((pid = waitpid(-1, &status, WNOHANG)) > 0)
	CleanupProc(pid, status);
}

/*
 * CleanupProc -- cleanup after terminated backend.
 *
 * Remove all local state associated with backend.
 *
 * Dillon's note: should log child's exit status in the system log.
 */
void
CleanupProc(pid, exitstatus)
    int	pid;
    int	exitstatus;		/* child's exit status. */
{
    BackendNode	*prev, *curr;
    Backend		*bp;
    int		sig;
    
    if (DebugLvl) {
	fprintf(stderr, "%s: CleanupProc: pid %d exited with status %d\n",
		progname, pid, exitstatus);
    }
    /*
     * -------------------------
     * If a backend dies in an ugly way (i.e. exit status not 0) then
     * we must signal all other backends to quickdie.  If exit status
     * is zero we assume everything is hunky dory and simply remove the
     * backend from the active backend list.
     * -------------------------
     */
    if (!exitstatus) {
	curr = (BackendNode *) SLGetHead(&BackendList);
	while (curr) {
	    bp = &curr->bn_backend;
	    if (bp->pid == pid) {
		SLRemove(&curr->bn_node);
		free((char *) curr);
		break;
	    }
	    curr = (BackendNode *) SLGetSucc(&curr->bn_node);
	}
	return;
    }
    
    curr = (BackendNode *) SLGetHead(&BackendList);
    while (curr) {
	bp = &curr->bn_backend;
	
	/*
	 * -----------------
	 * SIGUSR1 is the special signal that sez exit without exitpg
	 * and let the user know what's going on. ProcSemaphoreKill()
	 * cleans up the backends semaphore.  If SendStop is set (-s on
	 * the command line), then we send a SIGSTOP so that we can
	 * collect core dumps from all backends by hand.
	 * -----------------
	 */
	sig = (SendStop) ? SIGSTOP : SIGUSR1;
	if (bp->pid != pid) {
	    if (DebugLvl)
		fprintf(stderr, "%s: CleanupProc: sending %s to process %d\n",
			progname,
			(sig == SIGUSR1)
			? "SIGUSR1" : "SIGSTOP",
			bp->pid);
	    (void) kill(bp->pid, sig);
	}
	ProcSemaphoreKill(bp->pid);
	
	prev = (BackendNode *) SLGetPred(&curr->bn_node);
	SLRemove(&curr->bn_node);
	free((char *) curr);
	if (!prev) {		/* removed head */
	    curr = (BackendNode *) SLGetHead(&BackendList);
	    continue;
	}
	curr = (BackendNode *) SLGetSucc(&curr->bn_node);
    }
    /*
     * -------------
     * Quasi_exit means run all of the on_exitpg routines but don't
     * acutally call exit().  The on_exit list of routines to do is
     * also truncated.
     *
     * Nothing up my sleeve here, ActiveBackends means that since the
     * last time we recreated shared memory and sems another frontend
     * has requested and received a connection and I have forked off
     * another backend.  This prevents me from reinitializing shared
     * stuff more than once for the set of backends that caused the
     * failure and were killed off.
     * ----------------
     */
    if (ActiveBackends == TRUE && Reinit) {
	IPCKey	key;
	
	if (DebugLvl)
	    fprintf(stderr, "%s: CleanupProc: reinitializing shared memory and semaphores\n",
		    progname);
	quasi_exitpg();
	reset_shared(PostPortName);
    }
}

/*
 * BackendStartup -- start backend process
 *
 * returns: STATUS_ERROR if the fork/exec failed, STATUS_OK
 *	otherwise.
 *
 */
BackendStartup(packet, port)
    StartupPacket	*packet;	/* client's startup packet */
    Port		*port;
{
    int		status = 0;	/* return status */
    BackendNode	*bn;		/* for backend cleanup */
    int		i,pid;
    char	*envEntry[4];
    
    /*
     * Set up the necessary environment variables for the backend
     * This should really be some sort of message....
     */
     for (i = 0; i < 4; ++i) {
       envEntry[i] = calloc(2 * ARGV_SIZE, 1);
     }
    sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
    putenv(envEntry[0]);
    sprintf(envEntry[1], "POSTID=%d", NextBackendId);
    putenv(envEntry[1]);
    sprintf(envEntry[2], "PG_USER=%s", packet->user);
    putenv(envEntry[2]);
    if (!getenv("PGDATA")) {
	sprintf(envEntry[3], "PGDATA=%s", DataDir);
	putenv(envEntry[3]);
    }
    if (DebugLvl > 2) {
	char		**p;
	extern char	**environ;
	
	fprintf(stderr, "%s: BackendStartup: environ dump:\n",
		progname);
	fprintf(stderr, "-----------------------------------------\n");
	for (p = environ; *p; ++p)
	    fprintf(stderr, "\t%s\n", *p);
	fprintf(stderr, "-----------------------------------------\n");
    }
    
    if ((pid = FORK()) == 0) {	/* child */
	if (DoExec(packet, port->sock))
	    fprintf(stderr, "%s child[%d]: BackendStartup: execv failed\n",
		    progname, pid);
	/* use _exit to keep from double-flushing stdio */
	_exit(1);
    }
    
    if (pid < 0) {
	fprintf(stderr, "%s: BackendStartup: fork failed\n",
		progname);
	return(STATUS_ERROR);
    }
    
    if (DebugLvl)
	fprintf(stderr, "%s: BackendStartup: pid %d user %s db %s socket %d\n",
		progname, pid, packet->user,
		(packet->database[0] == '\0' ? packet->user : packet->database),
		port->sock);
    
    /* adjust backend counter */
    /* XXX Don't know why this is done, but for now backend needs it */
    NextBackendId -= 1;
    
    /*
     * Everything's been successful, it's safe to add this backend to our
     * list of backends.
     */
    if (!(bn = (BackendNode *) calloc(1, sizeof (BackendNode)))) {
	fprintf(stderr, "%s: BackendStartup: malloc failed\n",
		progname);
	ExitPostmaster(1);
    }
    SLNewNode(&bn->bn_node);
    bn->bn_backend.pid = pid;
    SLAddHead(&BackendList, &bn->bn_node);
    
    return(STATUS_OK);
}

/*
 * split_opts -- destructively load a string into an argv array
 *
 * Since no current POSTGRES arguments require any quoting characters,
 * we can use the simple-minded tactic of assuming each set of space-
 * delimited characters is a separate argv element.
 *
 * If you don't like that, well, we *used* to pass the whole option string
 * as ONE argument to execl(), which was even less intelligent...
 */
void
split_opts(argv, argcp, s)
    char	**argv;
    int	*argcp;
    char	*s;
{
    int	i = *argcp;
    
    while (s && *s) {
	while (isspace(*s))
	    ++s;
	if (*s)
	    argv[i++] = s;
	while (*s && !isspace(*s))
	    ++s;
	if (isspace(*s))
	    *s++ = '\0';
    }
    *argcp = i;
}

/*
 * DoExec -- set up the argument list and perform an execv system call
 *
 * Tries fairly hard not to dork with anything that isn't automatically
 * allocated so we don't do anything weird to the postmaster when it gets
 * its thread back.  (This is vfork() we're talking about.  If we're using
 * fork() because we don't have vfork(), then we don't really care.)
 *
 * returns: 
 *	Shouldn't return at all.
 *	If execv() fails, return status.
 */
DoExec(packet, portFd)
    StartupPacket	*packet;
    int		portFd;
{
    char	execbuf[MAXPATHLEN];
    char	portbuf[ARGV_SIZE];
    char	debugbuf[ARGV_SIZE];
    char	ttybuf[ARGV_SIZE + 1];
    char	argbuf[(2 * ARGV_SIZE) + 1];
    /*
     * each argument takes at least three chars, so we can't
     * have more than ARGV_SIZE arguments in (2 * ARGV_SIZE)
     * chars (i.e., packet->options plus ExtraOptions)...
     */
    char	*av[ARGV_SIZE];
    char	dbbuf[ARGV_SIZE + 1];
    int	ac = 0;
    
#ifdef ANY_BACKEND
    if (packet->execFile[0])
	(void) strncpy(execbuf, packet->execFile, ARGV_SIZE);
    else
#endif
	(void) strncpy(execbuf, Execfile, MAXPATHLEN);
    execbuf[MAXPATHLEN - 1] = '\0';
    av[ac++] = execbuf;
    
    /* Tell the backend it is being called from the postmaster */
    av[ac++] = "-p";
    
    /*
     *  Pass the requested debugging level along to the backend.  We
     *  decrement by one; level one debugging in the postmaster traces
     *  postmaster connection activity, and levels two and higher
     *  are passed along to the backend.  This allows us to watch only
     *  the postmaster or the postmaster and the backend.
     */

    if (DebugLvl > 1) {
	(void) sprintf(debugbuf, "-d%d", DebugLvl - 1);
	av[ac++] = debugbuf;
    }
    else
	av[ac++] = "-Q";
    
    /* Pass the requested debugging output file */
    if (packet->tty[0]) {
	(void) strncpy(ttybuf, packet->tty, ARGV_SIZE);
	av[ac++] = "-o";
	av[ac++] = ttybuf;
    }
    
    /* Tell the backend the descriptor of the fe/be socket */
    (void) sprintf(portbuf, "-P%d", portFd);
    av[ac++] = portbuf;
    
    (void) strncpy(argbuf, packet->options, ARGV_SIZE);
    argbuf[ARGV_SIZE] = '\0';
    (void) strncat(argbuf, ExtraOptions, ARGV_SIZE);
    argbuf[(2 * ARGV_SIZE) + 1] = '\0';
    split_opts(av, &ac, argbuf);
    
    if (packet->database[0])
	(void) strncpy(dbbuf, packet->database, ARGV_SIZE);
    else
	(void) strncpy(dbbuf, packet->user, USER_NAMESIZE);
    dbbuf[ARGV_SIZE] = '\0';
    av[ac++] = dbbuf;
    
    av[ac] = (char *) NULL;
    
    if (DebugLvl > 1) {
	int	i;
	
	fprintf(stderr, "%s child[%d]: execv(",
		progname, getpid());
	for (i = 0; i < ac; ++i)
	    fprintf(stderr, "%s, ", av[i]);
	fprintf(stderr, ")\n");
    }
    
    return(execv(av[0], av));
}

/*
 * ExitPostmaster -- cleanup
 */
ExitPostmaster(status)
    int	status;
{
    /* should cleanup shared memory and kill all backends */
    
    /* 
     * Not sure of the semantics here.  When the Postmaster dies,
     * should the backends all be killed? probably not.
     */
    if (ServerSock != INVALID_SOCK)
	close(ServerSock);
    exitpg(status);
}

dumpstatus()
{
    PortNode	*curr = (PortNode *) SLGetHead(&PortList);

    while (curr) {
	Port *port = &curr->pn_port;
	
	fprintf(stderr, "%s: dumpstatus:\n", progname);
	fprintf(stderr, "\tsock %d: nBytes=%d, laddr=0x%x, raddr=0x%x\n",
		port->sock, port->nBytes, port->laddr, port->raddr);
	curr = (PortNode *) SLGetSucc(&curr->pn_node);
    }
}
@


1.81
log
@stupid mistake corrected
@
text
@d2 1
a2 1
 * $Header: /usr/people/postdev/src/backend/postmaster/RCS/postmaster.c,v 1.80 1994/09/28 18:01:47 postdev Exp postdev $
d57 1
a57 1
#define FORK() vfork()
@


1.80
log
@added patch to BackendStartup
@
text
@d2 1
a2 1
 * $Header: /usr/people/postdev/src/backend/postmaster/RCS/postmaster.c,v 1.79 1994/06/16 03:23:06 aoki Exp postdev $
d718 3
a720 3
+     for (i = 0; i < 4; ++i) {
+       envEntry[i] = calloc(2 * ARGV_SIZE, 1);
+     }
@


1.79
log
@clean out union wait
@
text
@d2 1
a2 1
 * $Header: /import/faerie/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.78 1994/05/07 00:09:19 aoki Exp aoki $
d711 2
a712 2
    int		pid;
    char		envEntry[4][2 * ARGV_SIZE];
d718 3
@


1.78
log
@move the signal handlers to just before ServerLoop so that
the @@#$%! sunos library (which implemented getcwd using popen)
doesn't get mucked up
@
text
@d2 1
a2 1
 * $Header: /usr/local/devel/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.77 1994/02/09 00:12:24 aoki Exp aoki $
d36 2
a37 1
#include <sys/param.h>		/* for MAXHOSTNAMELEN */
d42 1
a43 6
#if defined(PORTNAME_alpha) || defined(PORTNAME_aix)
#if !defined(_BSD)
#define _BSD			/* so that union wait gets defined */
#endif /* !_BSD */
#endif /* PORTNAME_alpha || PORTNAME_aix */
#include <sys/wait.h>
d587 2
a588 2
    union wait	status;		/* backend exit status */
    int		pid;		/* process id of dead backend */
d593 2
a594 2
    while((pid = wait3(&status, WNOHANG, (struct rusage  *) NULL)) > 0)
	CleanupProc(pid, status.w_status);
@


1.77
log
@POSIX signal fixup.  actually use sigaction instead of trying
to do old SVID1-style signal handler reinstall (i keep missing
one signal or another..)
@
text
@d2 1
a2 1
 * $Header: /faerie/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.76 1994/02/07 13:16:20 aoki Exp aoki $
a170 8
    signal(SIGCHLD, reaper);
    signal(SIGTTIN, SIG_IGN);
    signal(SIGTTOU, SIG_IGN);
    signal(SIGHUP, pmdie);
    signal(SIGINT, pmdie);
    signal(SIGTERM, pmdie);
    signal(SIGCONT, dumpstatus);

d298 8
@


1.76
log
@what the heck?  the version i checked in got mangled.  did
the disk take a hit?
@
text
@d2 1
a2 1
 * $Header: /usr/local/devel/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.75 1994/02/07 11:57:34 aoki Exp aoki $
d31 1
a31 1
#include <signal.h>
a598 3
#ifdef SYSV_SIGNAL
    signal(SIGCHLD, reaper);	/* XXX is there a race here? */
#endif /* SYSV_SIGNAL */
a939 3
#ifdef SYSV_SIGNAL
    signal(SIGCONT, dumpstatus);	/* XXX is there a race here? */
#endif /* SYSV_SIGNAL */
@


1.75
log
@added -S flag to daemonize (disassociate from controlling tty)
@
text
@d2 1
a2 1
 * $Header: /faerie/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.74 1993/09/22 01:25:51 aoki Exp aoki $
a51 4
#if defined(PORTNAME_hpux)
#include <unistd.h>		/* for _SC_OPEN_MAX */
#endif /* PORTNAME_hpux */

d304 9
a312 1
	pmdaemoaemonize()
@


1.74
log
@added a poorly-conditionalized #include of <sys/select>
@
text
@d2 1
a2 1
 * $Header: /home2/aoki/master/src/backend/postmaster/RCS/postmaster.c,v 1.73 1993/08/10 20:31:38 aoki Exp $
d128 1
d158 1
d189 1
a189 1
    while ((opt = getopt(argc, argv, "a:B:b:D:dno:p:s")) != EOF) {
d248 1
a248 1
	case 's': 
d250 8
d303 3
d311 20
d337 1
d343 1
a343 1
    fprintf(stderr, "\t-p port\tspecify port for postmaster to listen on\n");
@


1.73
log
@made init_address_fixup conditional
@
text
@d2 1
a2 1
 * $Header: /home2/aoki/master/src/backend/postmaster/RCS/postmaster.c,v 1.72 1993/08/10 01:46:51 marc Exp aoki $
d42 2
a43 1
#if defined(PORTNAME_alpha) && !defined(_BSD)
d45 2
a46 1
#endif /* PORTNAME_alpha && !_BSD */
d48 3
@


1.72
log
@alpha port
@
text
@d2 1
a2 1
 * $Header: /usr/local/devel/postgres.alpha.merge/src/backend/postmaster/RCS/postmaster.c,v 1.71 1993/07/29 18:38:47 mao Exp marc $
d154 7
a160 1
    init_address_fixups();    /* must be first */
@


1.71
log
@fix up umask to turn off group, other access to files and directories
created by postgres
@
text
@d2 1
a2 1
 * $Header: /private/src/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.70 1993/06/24 04:07:14 aoki Exp mao $
d154 2
@


1.70
log
@changed PORTNAME_svr4 conditionals around signal-handler-reinstalls
to use SYSV_SIGNAL
@
text
@d2 1
a2 1
 * $Header: /home2/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.69 1993/06/16 04:29:18 aoki Exp $
d34 1
d164 3
@


1.69
log
@there was only one thing in "tmp/master.h"
that was still being used.  moved that into postmaster.c
(will nuke the old header later)
@
text
@d2 1
a2 1
 * $Header: /home2/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.68 1993/06/09 19:04:52 mao Exp aoki $
d41 1
a41 1
#if defined(PORTNAME_alpha) && ! defined(_BSD)
d126 3
a128 3
int     pmdie ARGS(());
int     reaper ARGS(());
int	dumpstatus ARGS(());
d548 1
a548 1
#ifdef PORTNAME_svr4
d550 1
a550 1
#endif /* PORTNAME_svr4 */
d892 1
a892 1
#ifdef PORTNAME_svr4
d894 1
a894 1
#endif /* PORTNAME_svr4 */
@


1.68
log
@add user name, db name to debugging output on backend startup (i have
a bunch of s2k analysis scripts that need this)
@
text
@d2 1
a2 1
 * $Header: /usr/local/devel/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.67 1993/04/07 18:33:38 mao Exp $
d41 5
a45 1
#include "tmp/master.h"		/* for DEF_PORT */
@


1.67
log
@new behavior of -d flag:  if debug level is one, then trace connection
traffic, but nothing else.  if debug level is two, trace connections
and turn on debugging in the backend.  if debug level is three, do
all that plus show the env passed to new backends when they're started.
@
text
@d2 1
a2 1
 * $Header: /private/src/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.66 1993/03/23 02:16:54 aoki Exp mao $
d707 4
a710 2
	fprintf(stderr, "%s: BackendStartup: forked pid[%d] on socket %d\n",
		progname, pid, port->sock);
@


1.66
log
@fixes to work with <stdlib.h>
@
text
@d2 1
a2 1
 * $Header: /home2/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.65 1993/03/17 20:31:06 aoki Exp aoki $
d317 1
a317 1
	if (DebugLvl) {
d342 1
a342 1
	if (DebugLvl) {
d365 1
a365 1
		if (DebugLvl)
d680 1
a680 1
    if (DebugLvl) {
d803 10
a812 3
    /* Pass the requested debugging level along to the backend */
    if (DebugLvl) {
	(void) sprintf(debugbuf, "-d%d", DebugLvl);
d844 1
a844 1
    if (DebugLvl) {
@


1.65
log
@ruggedized the case of partial startup packets a bit.
(this never happens if you use libpq...)
@
text
@d2 1
a2 1
 * $Header: /home2/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.64 1993/02/23 23:47:13 aoki Exp aoki $
d140 2
a141 2
    extern char	*getenv(), getopt(), *optarg;
    extern int	opterr, optind;
a487 1
    extern char	*calloc ();
a664 1
    extern char	*calloc();
@


1.64
log
@disable the remotely-set backend "feature"
(e.g. using Packet->execFile)
@
text
@d2 1
a2 1
 * $Header: /home2/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.63 1993/02/02 22:45:08 marc Exp aoki $
d39 1
d60 1
a60 1
	int	pid;		/* process id of backend */
d64 2
a65 2
	SLNode	bn_node;
	Backend	bn_backend;
d72 2
a73 2
	SLNode	pn_node;
	Port	pn_port;
d81 1
a81 1
static int	NextBackendId = 0x7fffffff;	/* XXX should use MAXINT */
d85 1
a85 1

d124 1
d135 1
a135 1
	
d137 2
a138 2
	int	argc;
	char	*argv[];
d140 135
a274 140
	extern char	*getenv(), getopt(), *optarg;
	extern int	opterr, optind;
	extern int	NBuffers;	/* from buffer/bufmgr.c */
	extern bool	IsPostmaster;	/* from smgr/mm.c */
	char		opt;
	char		*hostName;
	int		status;
	char		hostbuf[MAXHOSTNAMELEN];

	progname = argv[0];

	/* 
	 * Initialize signal handlers.  I took this from Dillon's code.
	 * Not sure who made the decision about what signals to handle.
	 */
	signal(SIGCHLD, reaper);
	signal(SIGTTIN, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);
	
	signal(SIGHUP, pmdie);
	signal(SIGINT, pmdie);
	signal(SIGTERM, pmdie);
	
	
	if (!(hostName = getenv("PGHOST"))) {
		if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
			(void) strcpy(hostbuf, "localhost");
		hostName = hostbuf;
	}
	
	opterr = 0;
	while ((opt = getopt(argc, argv, "a:B:b:D:dno:p:s")) != EOF) {
		switch (opt) {
		case 'a': 
			/* Set the authentication system. */
			be_setauthsvc(optarg);
			break;
		case 'B': 
			/*
			 * The number of buffers to create.  Setting this
			 * option means we have to start each backend with
			 * a -B # to make sure they know how many buffers
			 * were allocated. 
			 */
			NBuffers = atol(optarg);
			(void) strcat(ExtraOptions, " -B ");
			(void) strcat(ExtraOptions, optarg);
			break;
		case 'b': 
			/* Set the backend executable file to use. */
			if (!ValidateBackend(optarg))
				strcpy(Execfile, optarg);
			else {
				fprintf(stderr, "%s: invalid backend \"%s\"\n",
					progname, optarg);
				exit(2);
			}
			break;
		case 'D': 
			/* Set PGDATA from the command line. */
			DataDir = optarg;
			break;
		case 'd': 
			/*
			 * Turn on debugging for the postmaster and the backend
			 * servers descended from it.
			 */
			if ((optind < argc) && *argv[optind] != '-') {
				DebugLvl = atoi(argv[optind]);
				optind++;
			}
			else
				DebugLvl = 1;
			break;
		case 'n': 
			/* Don't reinit shared mem after abnormal exit */
			Reinit = 0;
			break;
		case 'o': 
			/*
			 * Other options to pass to the backend on the
			 * command line -- useful only for debugging.
			 */
			(void) strcat(ExtraOptions, " ");
			(void) strcat(ExtraOptions, optarg);
			break;
		case 'p': 
			/* Set PGPORT by hand. */
			PostPortName = (short) atoi(optarg);
			break;
		case 's': 
			/*
			 * In the event that some backend dumps core,
			 * send SIGSTOP, rather than SIGUSR1, to all
			 * its peers.  This lets the wily post_hacker
			 * collect core dumps from everyone.
			 */
			SendStop = 1;
			break;
		default: 
			/* usage() never returns */
			usage(progname);
			break;
		}
	}
	if (PostPortName == -1)
		PostPortName = pq_getport();
	
	IsPostmaster = true;
	
	if (!DataDir)
		DataDir = GetPGData();
	
	if (!Execfile[0] && FindBackend(Execfile, argv[0]) < 0) {
		fprintf(stderr, "%s: could not find backend to execute...\n",
			argv[0]);
		exit(1);
	}
	
	status = StreamServerPort(hostName, PostPortName, &ServerSock);
	if (status != STATUS_OK) {
		fprintf(stderr, "%s: cannot create stream port\n",
			progname);
		exit(1);
	}
	
	/* set up shared memory and semaphores */
	EnableMemoryContext(TRUE);
	reset_shared(PostPortName);
	
	/* 
	 * Initialize the list of active backends.  This list is only
	 * used for garbage collecting the backend processes.
	 */
	SLNewList(&BackendList, 0);
	SLNewList(&PortList, 0);
	
	status = ServerLoop(ServerSock);
	
	ExitPostmaster(status != STATUS_OK);
d278 1
a278 1
	char   *progname;
d280 11
a290 11
	fprintf(stderr, "usage: %s [options..]\n", progname);
	fprintf(stderr, "\t-B nbufs\tset number of shared buffers\n");
	fprintf(stderr, "\t-D datadir\tset data directory\n");
	fprintf(stderr, "\t-a authsys\tdo/do not permit use of an authentication system\n");
	fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
	fprintf(stderr, "\t-d [debuglvl]\tset debugging level\n");
	fprintf(stderr, "\t-n\t\tdon't reinitialize shared memory after abnormal exit\n");
	fprintf(stderr, "\t-o option\tpass 'option' to each backend servers\n");
	fprintf(stderr, "\t-p port\tspecify port for postmaster to listen on\n");
	fprintf(stderr, "\t-s\t\tsend SIGSTOP to all backend servers if one dies\n");
	exit(1);
d294 1
a294 1
	int     serverFd;
d296 69
a364 19
	fd_set		mask, basemask, dummy;
	int		nSockets, nSelected, status;
	PortNode	*prev, *curr;
	
	nSockets = ServerSock + 1;
	FD_ZERO(&basemask);
	FD_SET(ServerSock, &basemask);
	
	for (;;) {
		bcopy((char *) & basemask, (char *) & mask, sizeof(fd_set));
		FD_ZERO(&dummy);
		if ((nSelected = select(nSockets, &mask, &dummy, &dummy,
					(struct timeval *) NULL)) < 0) {
			if (errno == EINTR)
				continue;
			fprintf(stderr, "%s: ServerLoop: select failed\n",
				progname);
			return(STATUS_ERROR);
		}
d366 33
a398 45
			fprintf(stderr, "%s: ServerLoop: %d sockets pending\n",
				progname, nSelected);
		
		/* new connection pending on our well-known port's socket */
		if (FD_ISSET(ServerSock, &mask)) {
			int     newFd;
			
			/*
			 * connect and make an addition to PortList.  If
			 * the connection dies and we notice it, just forget
			 * about the whole thing.
			 */
			if (ConnCreate(serverFd, &newFd) == STATUS_OK) {
				if (newFd >= nSockets)
					nSockets = newFd + 1;
				FD_SET(newFd, &mask);
				FD_SET(newFd, &basemask);
				if (DebugLvl)
					fprintf(stderr, "%s: ServerLoop: connect on %d\n",
						progname, newFd);
			} else {
				/* already read the new connection */
				--nSelected;
			}
			FD_CLR(ServerSock, &mask);
		}
		
		if (DebugLvl) {
			curr = (PortNode *) SLGetHead(&PortList);
			while (curr) {
				Port *port = &curr->pn_port;
				
				fprintf(stderr, "%s: ServerLoop: port %d%s pending\n",
					progname, port->sock,
					FD_ISSET(port->sock, &mask)
					? "" : " not");
				curr = (PortNode *) SLGetSucc(&curr->pn_node);
			}
		}
		
		curr = (PortNode *) SLGetHead(&PortList);
		while (curr) {
			ConnId connId;	/* dummy argument */
			Port *port = &curr->pn_port;
			
d400 2
a401 44
				fprintf(stderr, "%s: ServerLoop: processing %d\n",
					progname, port->sock);
			if (!(FD_ISSET(port->sock, &mask)))
				continue;
			
			--nSelected;
			
			/*
			 * Read the incoming packet into its packet buffer.
			 * Read the connection id out of the packet so we
			 * know who the packet is from.
			 */
			status = PacketReceive(port, (Addr) & port->buf,
					       NON_BLOCKING, &connId);
			switch (status) {
			case STATUS_OK: 
				ConnStartup(port);
				ActiveBackends = TRUE;
				/* FALLTHROUGH */
			case STATUS_INVALID: 
				if (DebugLvl)
					fprintf(stderr, "%s: ServerLoop: done with %d\n",
						progname, port->sock);
				FD_CLR(port->sock, &basemask);
				StreamClose(port->sock);
				prev = (PortNode *) SLGetPred(&curr->pn_node);
				SLRemove(&curr->pn_node);
				free((char *) curr);
				if (!prev) {	/* removed head */
					curr = (PortNode *)
						SLGetHead(&PortList);
					continue;
				}
				break;
				
			case STATUS_NOT_DONE: 
				fprintf(stderr, "%s: ServerLoop: partial packet (%d bytes) on %d\n",
					progname, port->nBytes, port->sock);
				break;
			case STATUS_ERROR:	/* system call error - die */
				fprintf(stderr, "%s: ServerLoop: error receiving packet\n",
					progname);
				return(STATUS_ERROR);
			}
d403 16
d420 2
a421 1
		Assert(nSelected == 0);
d423 3
a425 1
	/* shouldn't ever get here */
d429 1
a429 1
	Port	*port;			/* receiving port */
d431 38
a468 40
	int		status;
	MsgType		msgType;
	SeqNo		seqno = INITIAL_SEQNO;
	PacketLen	bufSize;
	Addr		buf;
	char		namebuf[USER_NAMESIZE + 1];
	StartupPacket	*sp;
	
	/* 
	 * Get the packet header information.
	 *  XXX This is the only use of PacketData() in the entire system,
	 *	yet we're feeding it arguments (buf, bufSize, seqno) that
	 *	we never use.  WTF??  The ONLY reason we call this is
	 *	because the stupid Packet module does host/network
	 *	byte-ordering WRONG and we need to get the MsgType field...
	 */
	sp = (StartupPacket *) &port->buf;
	PacketData((Addr) sp, &buf, &bufSize, &msgType, &seqno);
	
	(void) strncpy(namebuf, sp->user, USER_NAMESIZE);
	namebuf[USER_NAMESIZE] = '\0';
	if (!namebuf[0]) {
		fprintf(stderr, "%s: ConnStartup: no user name specified\n",
			progname);
		return(STATUS_ERROR);
	}
	
	if (be_recvauth(msgType, port, namebuf) != STATUS_OK) {
		fprintf(stderr, "%s: ConnStartup: authentication failed\n",
			progname);
		return(STATUS_ERROR);
	}
	
	if (BackendStartup(sp, port) != STATUS_OK) {
		fprintf(stderr, "%s: ConnStartup: couldn't start backend\n",
			progname);
		return(STATUS_ERROR);
	}
	
	return(STATUS_OK);
d476 2
a477 2
	int	serverFd;
	int	*newFdP;
d480 4
a483 4
	/* dead code having to do with the pseudo-Packet shit */
	Connection	*conn;
	int		connId;
	long		currTime;
d485 23
a507 23
	int		status;
	Port		*port;
	PortNode	*pn;
	extern char	*calloc ();
	
	if (!(pn = (PortNode *) calloc(1, sizeof(PortNode)))) {
		fprintf(stderr, "%s: ConnCreate: malloc failed\n",
			progname);
		ExitPostmaster(1);
	}
	SLNewNode(&pn->pn_node);
	port = &pn->pn_port;
	
	if ((status = StreamConnection(serverFd, port)) != STATUS_OK) {
		StreamClose(port->sock);
		free((char *) pn);
	}
	else {
		SLAddHead(&PortList, &pn->pn_node);
		*newFdP = port->sock;
	}
	
	return (status);
d515 1
a515 1
	short	port;
d517 5
a521 5
	IPCKey	key;
	
	key = SystemPortAddressCreateIPCKey((SystemPortAddress) port);
	CreateSharedMemoryAndSemaphores(key);
	ActiveBackends = FALSE;
d529 1
a529 1
	exitpg (0);
d537 11
a547 8
	union wait	status;		/* backend exit status */
	int		pid;		/* process id of dead backend */
	
	if (DebugLvl)
		fprintf(stderr, "%s: reaping dead processes...\n",
			progname);
	while((pid = wait3(&status, WNOHANG, (struct rusage  *) NULL)) > 0)
		CleanupProc(pid, status.w_status);
d559 2
a560 2
	int	pid;
	int	exitstatus;		/* child's exit status. */
d562 17
a578 30
	BackendNode	*prev, *curr;
	Backend		*bp;
	int		sig;
	
	if (DebugLvl) {
		fprintf(stderr, "%s: CleanupProc: pid %d exited with status %d\n",
			progname, pid, exitstatus);
	}
	/*
	 * -------------------------
	 * If a backend dies in an ugly way (i.e. exit status not 0) then
	 * we must signal all other backends to quickdie.  If exit status
	 * is zero we assume everything is hunky dory and simply remove the
	 * backend from the active backend list.
	 * -------------------------
	 */
	if (!exitstatus) {
		curr = (BackendNode *) SLGetHead(&BackendList);
		while (curr) {
			bp = &curr->bn_backend;
			if (bp->pid == pid) {
				SLRemove(&curr->bn_node);
				free((char *) curr);
				break;
			}
			curr = (BackendNode *) SLGetSucc(&curr->bn_node);
		}
		return;
	}
	
d581 2
a582 24
		bp = &curr->bn_backend;
		
		/*
		 * -----------------
		 * SIGUSR1 is the special signal that sez exit without exitpg
		 * and let the user know what's going on. ProcSemaphoreKill()
		 * cleans up the backends semaphore.  If SendStop is set (-s on
		 * the command line), then we send a SIGSTOP so that we can
		 * collect core dumps from all backends by hand.
		 * -----------------
		 */
		sig = (SendStop) ? SIGSTOP : SIGUSR1;
		if (bp->pid != pid) {
			if (DebugLvl)
				fprintf(stderr, "%s: CleanupProc: sending %s to process %d\n",
					progname,
					(sig == SIGUSR1)
					? "SIGUSR1" : "SIGSTOP",
					bp->pid);
			(void) kill(bp->pid, sig);
		}
		ProcSemaphoreKill(bp->pid);
		
		prev = (BackendNode *) SLGetPred(&curr->bn_node);
d585 11
a595 6
		if (!prev) {		/* removed head */
			curr = (BackendNode *) SLGetHead(&BackendList);
			continue;
		}
		curr = (BackendNode *) SLGetSucc(&curr->bn_node);
	}
d597 7
a603 12
	 * -------------
	 * Quasi_exit means run all of the on_exitpg routines but don't
	 * acutally call exit().  The on_exit list of routines to do is
	 * also truncated.
	 *
	 * Nothing up my sleeve here, ActiveBackends means that since the
	 * last time we recreated shared memory and sems another frontend
	 * has requested and received a connection and I have forked off
	 * another backend.  This prevents me from reinitializing shared
	 * stuff more than once for the set of backends that caused the
	 * failure and were killed off.
	 * ----------------
d605 44
a648 9
	if (ActiveBackends == TRUE && Reinit) {
		IPCKey	key;
		
		if (DebugLvl)
			fprintf(stderr, "%s: CleanupProc: reinitializing shared memory and semaphores\n",
				progname);
		quasi_exitpg();
		reset_shared(PostPortName);
	}
d659 2
a660 2
	StartupPacket	*packet;	/* client's startup packet */
	Port		*port;
d662 68
a729 79
	int		status = 0;	/* return status */
	BackendNode	*bn;		/* for backend cleanup */
	int		pid;
	char		envEntry[4][2 * ARGV_SIZE];
	extern char	*calloc();
	
	/*
	 * Set up the necessary environment variables for the backend
	 * This should really be some sort of message....
	 */
#ifdef sprite
	sprintf(envEntry[0], "%d", PostPortName);
	setenv("POSTPORT", envEntry[0]);
	sprintf(envEntry[1], "%d", NextBackendId);
	setenv("POSTID", envEntry[1]);
	sprintf(envEntry[2], "%s", packet->user);
	setenv("PG_USER", envEntry[2]);
	sprintf(envEntry[3], "%s", DataDir);
	setenv("PGDATA", envEntry[3]);
#else
	sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
	putenv(envEntry[0]);
	sprintf(envEntry[1], "POSTID=%d", NextBackendId);
	putenv(envEntry[1]);
	sprintf(envEntry[2], "PG_USER=%s", packet->user);
	putenv(envEntry[2]);
	if (!getenv("PGDATA")) {
		sprintf(envEntry[3], "PGDATA=%s", DataDir);
		putenv(envEntry[3]);
	}
	if (DebugLvl) {
		char		**p;
		extern char	**environ;
		
		fprintf(stderr, "%s: BackendStartup: environ dump:\n",
			progname);
		fprintf(stderr, "-----------------------------------------\n");
		for (p = environ; *p; ++p)
			fprintf(stderr, "\t%s\n", *p);
		fprintf(stderr, "-----------------------------------------\n");
	}
#endif /* sprite */
	
	if ((pid = FORK()) == 0) {	/* child */
		if (DoExec(packet, port->sock))
			fprintf(stderr, "%s child[%d]: BackendStartup: execv failed\n",
				progname, pid);
		/* use _exit to keep from double-flushing stdio */
		_exit(1);
	}
	
	if (pid < 0) {
		fprintf(stderr, "%s: BackendStartup: fork failed\n",
			progname);
		return(STATUS_ERROR);
	}
	
	if (DebugLvl)
		fprintf(stderr, "%s: BackendStartup: forked pid[%d] on socket %d\n",
			progname, pid, port->sock);
	
	/* adjust backend counter */
	/* XXX Don't know why this is done, but for now backend needs it */
	NextBackendId -= 1;
	
	/*
	 * Everything's been successful, it's safe to add this backend to our
	 * list of backends.
	 */
	if (!(bn = (BackendNode *) calloc(1, sizeof (BackendNode)))) {
		fprintf(stderr, "%s: BackendStartup: malloc failed\n",
			progname);
		ExitPostmaster(1);
	}
	SLNewNode(&bn->bn_node);
	bn->bn_backend.pid = pid;
	SLAddHead(&BackendList, &bn->bn_node);
	
	return(STATUS_OK);
d744 17
a760 17
	char	**argv;
	int	*argcp;
	char	*s;
{
	int	i = *argcp;
	
	while (s && *s) {
		while (isspace(*s))
			++s;
		if (*s)
			argv[i++] = s;
		while (*s && !isspace(*s))
			++s;
		if (isspace(*s))
			*s++ = '\0';
	}
	*argcp = i;
d776 2
a777 2
	StartupPacket	*packet;
	int		portFd;
d779 14
a792 14
	char	execbuf[MAXPATHLEN];
	char	portbuf[ARGV_SIZE];
	char	debugbuf[ARGV_SIZE];
	char	ttybuf[ARGV_SIZE + 1];
	char	argbuf[(2 * ARGV_SIZE) + 1];
	/*
	 * each argument takes at least three chars, so we can't
	 * have more than ARGV_SIZE arguments in (2 * ARGV_SIZE)
	 * chars (i.e., packet->options plus ExtraOptions)...
	 */
	char	*av[ARGV_SIZE];
	char	dbbuf[ARGV_SIZE + 1];
	int	ac = 0;
	
d794 3
a796 3
	if (packet->execFile[0])
		(void) strncpy(execbuf, packet->execFile, ARGV_SIZE);
	else
d798 52
a849 52
		(void) strncpy(execbuf, Execfile, MAXPATHLEN);
	execbuf[MAXPATHLEN - 1] = '\0';
	av[ac++] = execbuf;
	
	/* Tell the backend it is being called from the postmaster */
	av[ac++] = "-p";
	
	/* Pass the requested debugging level along to the backend */
	if (DebugLvl) {
		(void) sprintf(debugbuf, "-d%d", DebugLvl);
		av[ac++] = debugbuf;
	}
	else
		av[ac++] = "-Q";
	
	/* Pass the requested debugging output file */
	if (packet->tty[0]) {
		(void) strncpy(ttybuf, packet->tty, ARGV_SIZE);
		av[ac++] = "-o";
		av[ac++] = ttybuf;
	}
	
	/* Tell the backend the descriptor of the fe/be socket */
	(void) sprintf(portbuf, "-P%d", portFd);
	av[ac++] = portbuf;
	
	(void) strncpy(argbuf, packet->options, ARGV_SIZE);
	argbuf[ARGV_SIZE] = '\0';
	(void) strncat(argbuf, ExtraOptions, ARGV_SIZE);
	argbuf[(2 * ARGV_SIZE) + 1] = '\0';
	split_opts(av, &ac, argbuf);
	
	if (packet->database[0])
		(void) strncpy(dbbuf, packet->database, ARGV_SIZE);
	else
		(void) strncpy(dbbuf, packet->user, USER_NAMESIZE);
	dbbuf[ARGV_SIZE] = '\0';
	av[ac++] = dbbuf;
	
	av[ac] = (char *) NULL;
	
	if (DebugLvl) {
		int	i;
		
		fprintf(stderr, "%s child[%d]: execv(",
			progname, getpid());
		for (i = 0; i < ac; ++i)
			fprintf(stderr, "%s, ", av[i]);
		fprintf(stderr, ")\n");
	}
	
	return(execv(av[0], av));
d856 1
a856 1
	int	status;
d858 26
a883 9
	/* should cleanup shared memory and kill all backends */
	
	/* 
	 * Not sure of the semantics here.  When the Postmaster dies,
	 * should the backends all be killed? probably not.
	 */
	if (ServerSock != INVALID_SOCK)
		close(ServerSock);
	exitpg(status);
@


1.63
log
@obey PGPORT
@
text
@d2 1
a2 1
 * $Header: /usr/local/devel/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.62 1993/01/29 05:08:05 aoki Exp marc $
d791 1
d795 1
@


1.62
log
@changed backend validation routine interface in miscinit.c, so ..
@
text
@d2 1
a2 1
 * $Header: /home2/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.61 1993/01/05 02:31:00 aoki Exp aoki $
d78 1
a78 1
static short	PostPortName = DEF_PORT;
d243 2
@


1.61
log
@modified for slightly-changed auth.c API
@
text
@d2 1
a2 1
 * $Header: /home2/aoki/postgres/src/backend/postmaster/RCS/postmaster.c,v 1.60 1992/12/29 01:38:03 aoki Exp aoki $
d129 1
a129 1
extern	ValidBackend ARGS((char *path));
d188 1
a188 1
			if (ValidBackend(optarg))
@


1.60
log
@added kerberos authentication, rewrote backend-search code, changed
to use simplelist instead of list.h cruft, minor bug fixes,
reindented..
@
text
@d2 1
a2 1
 * $Header: /usr/local/dev/postgres/mastertree/newconf/RCS/postmaster.c,v 1.58 1992/09/05 23:43:25 mao Exp $
d444 1
a444 1
	if (pg_recvauth(msgType, port, namebuf) != STATUS_OK) {
@


1.59
log
@headers moved
@
text
@d2 1
a2 1
 * $Header: /usr/local/dev/postgres/newtree/src/backend/postmaster/RCS/postmaster.c,v 1.58 1992/09/05 23:43:25 mao Exp marc $
a26 3
 * Security:  
 *	There is none. Not a little bit.
 *
d32 2
a33 3
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
d35 1
a38 4
#include <netdb.h>
#if !sprite
#include <sys/un.h>
#endif /* !sprite */
d40 1
a40 2
#include "tmp/master.h"
#include "utils/log.h"
d44 2
a45 12
#include "catalog/pg_user.h"
#include "list.h"

/* default permissions for opening files. */
#define OPEN_PERMISSIONS	(0666)

List *ListGarbage;	/* holds used list nodes for future use */
short CommPort;
char ShmIdStr[10];
char ShmSizeStr[10];
extern char *GetPGHome();

d50 1
a50 1
#define FORK() fork()
d58 2
a59 2
typedef struct	bkend	{
  int			pid;	/* process id of backend */
d62 5
d68 1
a68 1
List	*BackendList;
d70 4
d76 1
a76 4
List	*PortList;

/* for elog() messages.  Port to send the message to. */
Port	*SendPort;
d78 4
a81 4
/*
 * Default startup message parameters.  
 */
StartupPacket DefaultStartup;
d83 1
a83 37
/*
 * IOList is used to setup file descriptors of backend processes.
 *	Specify here how the descriptor set of the child (backend)
 *	is different from the parent (Postmaster).  I'm not sure
 *	this stuff works all that well.  I don't use any of the 
 * 	sys logs.
 *
 * See descriptor reset for some notes.
 */
typedef struct IOList {
  int	fd;
  char  *name;
  int	mode;
} IOList;

#define DEFAULT	""

IOList IO_List[] = {
  { 0, DEFAULT, (O_RDONLY) },
  { 1, DEFAULT, (O_WRONLY | O_APPEND | O_CREAT) },
  { 2, DEFAULT, (O_WRONLY | O_APPEND| O_CREAT) },
  { 0, NULL, 0 },
};

extern int NBuffers;

extern char *optarg;
extern int opterr;
extern int optind;
extern int errno;

extern bool	IsPostmaster;

short	PostPortName =	DEF_PORT;
short	ActiveBackends = FALSE;
char	*DataDir = (char *) NULL;
int	NextBackendId = 0x7fffffff;	/* XXX not sure what this does */
a84 1
char *Usage = "postmaster [ -p port ] [ -b backend_pathname ] [ -d [level] ]\n";
d88 2
a89 7
char Username[USER_NAMESIZE];
char Dbname[64];

/* 
 * This is set by getpghome().
 */
char *Home = "";
d91 1
a91 1
int	ServerSock = INVALID_SOCK;  /* stream socket server */
d94 2
a95 1
 * Set by the -d option
d97 1
a97 1
int	Debug = 0;
d102 1
a102 1
char ExtraOptions[ARGV_SIZE] = {0};
d111 2
a112 2
int	Reinit = 1;
int	SendStop = 0;
d117 14
a130 19
int ServerLoop ARGS((int serverFd ));
int ConnStartup ARGS((Port *port ));
int ConnCreate ARGS((int serverFd , int *newFdP ));
int PortDestroy ARGS((Port *port ));
int pmdie ARGS((void ));
int reaper ARGS((void ));
int CleanupProc ARGS((int pid , int exitstatus ));
int BackendStartup ARGS((Port *port , StartupPacket *packet , IOList *ioList ));
int fixlead ARGS((char *str , char **dstP , int *sizeP ));
int DoExec ARGS((char *execFile , char *database , int portFd , StartupPacket *pack ));
int DescriptorReset ARGS((IOList *ioList ));
int ExitPostmaster ARGS((int status ));
int FindBackend ARGS((char *backend ));
int ValidBackend ARGS((char *path ));
int ReadObjDir ARGS((char *dir ));
char *zalloc ARGS((unsigned long size ));
#if 0
int *CacheAlloc ARGS((unsigned int size ));
#endif
d132 2
d135 2
a136 2
int	argc;
char	*argv[];
d138 38
a175 34
  char  	*getenv();
  char		getopt();
  char		opt;
  int		serverMask;
  char		*hostName;
  int		status;
  int		size;
  char 		sysLogPath[PATH_SIZE];
  char		*sysLogPtr = sysLogPath;
  char 		dblogPath[PATH_SIZE];
  char		*dblogPtr = dblogPath;

  /*
   * Initialize signal handlers.  I took this from Dillon's code.
   * Not sure who made the decision about what signals to handle.
   */
  signal(SIGCHLD, reaper);
  signal(SIGTTIN, SIG_IGN);
  signal(SIGTTOU, SIG_IGN);
  
  signal(SIGHUP, pmdie);
  signal(SIGINT, pmdie);
  signal(SIGTERM, pmdie);

  ListHead(&ListGarbage);	/* initialize ListGarbage */

  if (!(hostName = getenv("PGHOST"))) {
    hostName = "localhost";
  }

  opterr = 0;
  while ((opt = getopt(argc, argv, "B:b:D:dno:p:s")) != EOF) {
	switch (opt) {
		case 'B':
d180 1
a180 1
			 * were allocated.
d183 2
a184 2
			strcat(ExtraOptions, "-B ");
			strcat(ExtraOptions, optarg);
d186 2
a187 1
		case 'b':
d189 6
a194 5
  				strcpy(DefaultStartup.execFile, optarg);
			else
				fprintf(stderr, "%s %s",
			  		"Couldn't find the requested backend",
			  		"-- Using a default search path...\n");
d196 2
a197 1
		case 'D':
d200 5
a204 1
		case 'd':
d206 1
a206 1
				Debug = atoi(argv[optind]);
d210 1
a210 1
				Debug = 1;
d212 2
a213 2
		case 'n':
			/* don't reinit shared mem after abnormal exit */
d216 1
a216 1
		case 'o':
d219 1
a219 1
			 * command line -- Useful only for debugging.
d221 2
a222 1
			strcat(ExtraOptions, optarg);
d224 3
a226 2
		case 'p':
			PostPortName = (short)atoi(optarg);
d228 1
a228 1
		case 's':
d230 4
a233 4
			 *  In the event that some backend dumps core,
			 *  send SIGSTOP, rather than SIGUSR1, to all
			 *  its peers.  This lets the wily post_hacker
			 *  collect core dumps from everyone.
d237 1
a237 1
		default:
d239 1
a239 1
			usage(argv[0]);
d241 19
d261 15
a275 54
  }

  IsPostmaster = true;

  Home = GetPGHome();
  if (DataDir == (char *) NULL) {
      DataDir = GetPGData();
  } else {
      char *e;
      /*
       *  The data directory was supplied on the command line.  We need
       *  to put it in the environment so it's found by children of this
       *  process.
       */
      if ((e = (char *) malloc(strlen(DataDir) + 8)) == (char *) NULL) {
	  fprintf(stderr, "%s: cannot alloc space for new env var\n", argv[0]);
	  fflush(stderr);
	  exit (1);
      }
      sprintf(e, "PGDATA=%s", DataDir);
      putenv(e);

      /* don't free e -- it's now in the environment */
  }

  /* default startup values */
  if (! DefaultStartup.execFile[0])
  	FindBackend(DefaultStartup.execFile);

  strncpy(Username, getenv("USER"), USER_NAMESIZE);
  strcpy(DefaultStartup.user, Username);
  strcpy(DefaultStartup.database,Username);
  strcpy(Dbname, Username);

  status = StreamServerPort(hostName,PostPortName, &ServerSock);
  if (status != STATUS_OK)  {
    elog(WARN,"%s: cannot create stream port", argv[0]) ;
    exit(1);
  }

  /* set up shared memory and semaphores */
  EnableMemoryContext(TRUE);
  CreateSharedMemoryAndSemaphores(
	SystemPortAddressCreateIPCKey((SystemPortAddress)PostPortName));

  /*
   * Initialize the list of active backends.  This list is only
   * used for garbage collecting the backend processes.
   */
  ListHead(&BackendList);
  ListHead(&PortList);

  status = ServerLoop(ServerSock);
  ExitPostmaster(status != STATUS_OK);
d278 2
a279 2
usage(p)
  char *p;
d281 11
a291 4
  fprintf(stderr, "usage: %s [-B nbufs] [-b backend] [-D datadir ] [-d [debuglvl]]\n", p);
  fprintf(stderr, "\t[-n] [-o pass_opts] [-p portno] [-s]\n");
  fflush(stderr);
  exit (1);
d295 1
a295 1
int	serverFd;
d297 7
a303 47
  int		mask;
  int		baseMask;
  int		serverMask;
  int		nSockets;
  int		nSelected;
  int		status;
  int		dummy;
  List		*curr;

  nSockets  = ServerSock+1;
  baseMask = 1 << ServerSock;
  serverMask = baseMask;

  for (;;) {
    dummy = 0;
    mask = baseMask;
    if ((nSelected = select(nSockets, &mask, &dummy, &dummy, NULL)) < 0) {
      if (errno == EINTR)
	continue;
      elog(WARN,"Postmaster: select failed");
      return(STATUS_ERROR);
    }

    if (serverMask & mask) {
      int	newFd;
      int	newMask;

      status = ConnCreate(serverFd, &newFd);

      if (newFd >= nSockets)
	nSockets = newFd+1;

      /* read the new connection on the first pass */
      newMask = 1 << newFd;
      nSelected--;
      /* add the new connection to the baseMask */
      baseMask |= newMask;
    }

    ListForEach( curr, PortList, PortList) {
      ConnId		connId;	/* dummy argument */
      Port		*port;	/* port for I/O */

      port = (Port *) ListElem(curr);

      if (port->mask & mask) {
	nSelected--;
d305 107
a411 34
	/*
	 * read the incoming packet into its packet buffer.  Read the
	 * connection id out of the packet so we know who the packet
	 * is from. 
	 */
	status = PacketReceive(port, (Addr) &port->buf,
			       NON_BLOCKING, &connId);
	switch (status) {
	case STATUS_OK:
	  ConnStartup (port);
	  ActiveBackends = TRUE;
	  baseMask &= ~ port->mask;
	  PortDestroy (port) ;
	  ListDelete (curr) ;
	  break;

	case STATUS_INVALID:
	  baseMask &= ~ port->mask;
	  PortDestroy (port) ;
	  ListDelete (curr) ;
	  break;

	case STATUS_NOT_DONE:
	  break;

	case STATUS_ERROR:
	  elog(WARN,"Postmaster: error receiving packet\n");
	  return(STATUS_ERROR);
	}
      }
    }
    Assert (! nSelected);
  }
  /* shouldn't ever get here */
d415 1
a415 1
Port	*port;		/* receiving port */	
d417 40
a456 20
    int 	status;		/* procedure return code */
    MsgType	msgType;	/* type of message recieved */
    SeqNo	seqno= INITIAL_SEQNO;/* dummy argument expected by packetData*/
    PacketLen	bufSize;	/* dummy argument */
    Addr	buf;		/* dummy argument */

    /*
     * Get the packet header information.
     */
    PacketData((Addr) &port->buf, &buf, &bufSize, &msgType,  &seqno);
    if (msgType != STARTUP_MSG) {
      elog(WARN,"Postmaster: unrecognized message type\n");
      return(STATUS_ERROR);
    }
    if (BackendStartup(port, (StartupPacket *)&port->buf, IO_List) != STATUS_OK)
    {
      elog(WARN,"Postmaster: couldn't startup backend for client\n");
      return(STATUS_ERROR);
    }
    return(STATUS_OK);
d464 2
a465 2
int		serverFd;
int		*newFdP;
d467 29
a495 28
  Connection	*conn;
  int		connId;
  int		status;
  long		currTime;
  int		newFd;
  Port		*port = (Port *) zalloc(sizeof(Port));


  status = StreamConnection(serverFd,&newFd,&port->addr);

  port->sock = newFd;
  port->mask = 1 << newFd;

  ListPush(PortList, port);
  *newFdP = newFd;

  /* in case of error message */
  SendPort = port;

  /* 
   * If there was an error in the port creation, the connection
   * struct should be freed again.
   */
  if (status != STATUS_OK) {
    PortDestroy ( port ) ;
  }

  return(status);
d498 6
a503 2
PortDestroy(port)
Port	*port;
d505 5
a509 2
  StreamClose( port->sock );
  free ((char *)port);
d517 1
a517 1
  exitpg(0);
a521 1
 *
d525 8
a532 9
  union	wait	status;		/* backend exit status */
  struct	rusage	ruse;	/* resource usage structure */
  int		pid;		/* process id of dead backend */

  if (Debug)
    fprintf(stderr, "In reaper\n");
  while ((pid = wait3(&status, WNOHANG, &ruse)) > 0) {
    (void) CleanupProc(pid,status.w_status);
  }
d542 92
a633 91
CleanupProc(pid,exitstatus)
int	pid;
int	exitstatus;		/* child's exit status. */
{
  List	*curr;
  int sig;

  if (Debug)
  {
    fprintf(stderr, "In CleanUpProc - ");
    fprintf(stderr, "Backend with pid %d exited with status %d\n", pid, exitstatus);
    fflush(stderr);
  }
  /* -------------------------
   * If a backend dies in an ugly way (i.e. status not 0) then
   * we must signal all other backends to quickdie.  If exit status
   * is zero we assume everything is hunky dory and simply remove the
   * backend from the active backend list.
   * -------------------------
   */
  if (!exitstatus)
  {
      ListForEach( curr, BackendList, BackendList)
      {
        Backend *bp = (Backend *) ListElem(curr);

	if (bp->pid == pid)
	{
	  (void) free ((char *)bp);
	  ListDelete(curr);
	  break;
	}
      }
      return(STATUS_OK);
  }
  ListForEach( curr, BackendList, BackendList)
  {
    Backend *bp = (Backend *) ListElem(curr);
      
    /* -----------------
     * SIGUSR1 is the special signal that sez exit without exitpg
     * and let the user know what's going on.  ProcSemaphoreKill() 
     * cleans up the backends semaphore.  If SendStop is set (-s on
     * the command line), then we send a SIGSTOP so that we can collect
     * core dumps from all backends by hand.
     * -----------------
     */
    if (SendStop)
	sig = SIGSTOP;
    else
	sig = SIGUSR1;
    if (bp->pid != pid)
    {
	if (Debug)
	  fprintf(stderr, "Sending %s to process %d\n",
		  (sig == SIGUSR1 ? "SIGUSR1" : "SIGSTOP"), bp->pid);
	kill(bp->pid, sig);
	ProcSemaphoreKill(bp->pid);
    }
    else
	ProcSemaphoreKill(bp->pid);

    (void) free ((char *)bp);
    ListDelete(curr);
  }
  /* -------------
   * Quasi_exit means run all of the on_exitpg routines but don't
   * acutally call exit().  The on_exit list of routines to do is
   * also truncated.
   *
   * Nothing up my sleeve here, ActiveBackends means that since the last time
   * we recreated shared memory and sems another frontend has requested and
   * received a connection and I have forked off another backend.  This
   * prevents me from reinitializing shared stuff more than once for the
   * set of backends that caused the failure and were killed off.
   * ----------------
   */
  if (ActiveBackends == TRUE && Reinit)
  {
    if (Debug)
      fprintf(stderr, "Reinitializing shared memory and semaphores\n");
    quasi_exitpg();
    /* --------------
     * Recreate shared memory and semaphores.
     * --------------
     */
    CreateSharedMemoryAndSemaphores(
	  SystemPortAddressCreateIPCKey((SystemPortAddress)PostPortName));
    ActiveBackends = FALSE;
  }
    return(STATUS_OK);
d637 1
a637 1
 * BackendStartup -- startup backend process
d643 13
a655 63
BackendStartup(port, packet, ioList)
Port		*port;
StartupPacket	*packet;   /* client's startup packet */
IOList		*ioList;   /* io devices to setup */
{
  int		status;	   /* return status */
  Backend 	*bp;	   /* info to be used for backend cleanup */
  char		dbData[PATH_SIZE];
  char		efData[ARGV_SIZE];
  char		*execFile;
  char		*database;  /* database after fixlead */
  int		size;	   /* of fixlead string */
  int		pid;

  database = dbData;
  execFile = efData;

  bp = (Backend *) zalloc(sizeof(Backend));
  if (! bp) {
    elog(FATAL,"Postmaster: cannot zalloc backend structure\n");
    ExitPostmaster(1);
  }
  ListPush(BackendList,bp);

  /*
   * If any of the arguments is missing, use the defaults.
   */

  /* Set up the backend as specified by the startup packet */

  if (* (packet->tty)) {	/* Stdout/Stderr will become the tty file */
    ioList[1].name = packet->tty;
    ioList[2].name = packet->tty;
  }

  if (! * (packet->user)) 
    strcpy(packet->user,DefaultStartup.user);

  size = PATH_SIZE;
  if (! * (packet->database)) 
    strcpy(database,DefaultStartup.database);
  else 
    (void) fixlead(packet->database,&database,&size);

  database = dbData;
    
  size = ARGV_SIZE;
  if (! * (packet->execFile))
    strcpy(execFile, DefaultStartup.execFile);
  else
    (void) fixlead(packet->execFile, &execFile, &size);

  execFile = efData;

  /*
   * Security: check the arguments.  There should be an authorized
   *	list of execFiles at the very least.
   */

  if ((pid = FORK()) == 0) {
    /* child: 
     * 	use the ioList structure to setup your file descriptors and
     * 	then exec the file requested.
a656 18
	/*
	 * These have to be made big enough!
     */
    char	envEntry1[64];
    char	envEntry2[64];
    char	envEntry3[64];

    /* This goes to backend as command line arg!!!
     * dup2(port->sock,BACKEND_SOCK); 
     */
    status = DescriptorReset(ioList);
    if (status) {
      _exit(1);
    }

    /* Set up the necessary environment variables for the backend
     * This should really be some sort of message....
     */
d658 8
a665 9
    { 
      char c[50];
      sprintf(c, "%d", PostPortName);
      setenv("POSTPORT", c);
      sprintf(c, "%d", NextBackendId);
      setenv("POSTID", c);
      sprintf(c, "%s", packet->user);
      setenv("PG_USER", c);
    }
d667 21
a687 11

    sprintf(envEntry1, "POSTPORT=%d", PostPortName);
    putenv(envEntry1);
    sprintf(envEntry2, "POSTID=%d", NextBackendId);
    putenv(envEntry2);
    sprintf(envEntry3, "PG_USER=%s", packet->user);
    putenv(envEntry3);
    if (Debug) {
	printf("ENVIRONMENT: %s, %s, %s\n", envEntry1,envEntry2,envEntry3);
    }

d689 37
a725 27

    if (! DoExec(execFile, database, port->sock,packet)) {
      return;
    }

    /* error -- exec has failed if we get here. */
    elog(FATAL,"Postmaster: DoExec failed for '%s'\n",DefaultStartup.execFile);
    _exit(1);
  }

  if (Debug)
	fprintf(stderr,
		"started '%s' for '%s' on '%s' (%d) pid (%d)\n",
	 	execFile,packet->user, database,port->sock, pid);

  if (pid < 0) {
    fprintf(stderr, "PostMaster: fork failed");
    return(STATUS_ERROR);
  } 
  else
    bp->pid = pid;

  /* adjust backend counter */
  /* XXX Don't know why this is done, but for now backend needs it */
  NextBackendId -= 1;

  return(STATUS_OK);
d728 6
a733 5
/* 
 * fixlead -- Expand special characters from path names. 
 * 
 * returns: TRUE if expansion occurred FALSE otherwise.
 * SIDE EFFECTS: copies str into dst
d735 2
a736 2
 * NOTES: this does not use the sizeP parameter.  It should
 *	check for string overflow.
d738 5
a742 3
fixlead(str, dstP, sizeP)
char	**dstP, *str;
int	*sizeP;
d744 13
a756 38
  char *dst = *dstP;
  int	size = *sizeP;
  int	status = TRUE;

  switch (*str) {
    /* carriage return == NULL */
  case '\n':
    return(FALSE);

  case '~':
    /* home directory of postgres installation */
    strcpy(dst, Home);
    break;

  case '&':
    /* directory of database */
    strcpy(dst, DataDir);
    strcat(dst, "/base/");
    strcat(dst, Dbname);
    break;

  case '%':
    /* data directory (where shared relations live) */
    strcpy(dst, DataDir);
    break;

  default:
    *dst = '\0';
    status = FALSE;
  }
  if (status)
    str++;

  strncat(dst,str,size);
  size = strlen(dst);
  *dstP += size;
  *sizeP -= size;
  return(status);
a758 1

d760 1
a760 1
 * DoExec -- setup the arguments and make an execv system call.
d762 5
d768 2
a769 3
 *	if not debugging, we shouldn't return at all (exec()).
 *	if debugging, return 0.
 *	if exec fails, return 1.
d771 73
a843 85
DoExec(execFile,database, portFd, pack)
char	*execFile,*database;
StartupPacket	*pack;
int 	portFd;
{
  int	status;
  char portBuf[32];
  char debugBuf[32];
  char startDir[PATH_SIZE];
  char args[2*ARGV_SIZE];
  
  /*
   * Call backend with any/all desired options.  These extra options
   * can either come from the front-end via the packet or from the
   * command line of the postmaster -o option.
   */
  args[0] = '\0';
  if (pack->options[0])
  	strcpy(args, pack->options);
  if (ExtraOptions[0])
	strcat(args, ExtraOptions);

  status = 1;

  strcpy(startDir, DataDir);
  strcat(startDir, "/base/");
  strcat(startDir, pack->database);
  if (chdir(startDir))
	perror(startDir);
  /* If debugging requested pass the request along to the backend */
  if (Debug)
	sprintf(debugBuf, "-d %d", Debug);	
  else
	sprintf(debugBuf, "-Q");

  sprintf(portBuf, "-P%d", portFd);
  if (Debug) {
	printf("The port file descriptor is %d\n", portFd);
	printf("execl: %s -p %s %s %s %s\n", 
		execFile, debugBuf, portBuf, database, args);
  }
  if (!(*args)) {
  status =
    execl(execFile, execFile, "-p", debugBuf, portBuf, database, NULL);
  }
  else {
    status =
      execl(execFile, execFile, "-p", debugBuf, portBuf, args, database, NULL);
  }
  return(status);
}


/*
 * DescriptorReset -- reset the servers file descriptors to
 *	match the configuration the new backend expects.
 *
 * This routine closes, stdin etc.  It'll set up a log file.
 */
DescriptorReset(ioList)
IOList	*ioList;
{
  /*
   * For each element of the io list: 
   *   If the name is NONE, close the corresponding file descriptor.
   *   If the name is DEFAULT, let the child inherit the parent's descriptors.
   *   Otherwise, open the named descriptor.
   */
  for (;ioList->name;ioList++) {
    if (! strcmp(ioList->name, "NONE")) {
      close(ioList->fd);
    } else if (strcmp(ioList->name,DEFAULT)) {
      int tmpfd;

      if (! (tmpfd = open(ioList->name, ioList->mode, OPEN_PERMISSIONS))) {
	perror(ioList->name);
	fprintf(stderr,"PostMaster: child cannot open tty '%s'\n",ioList->name);
	return(STATUS_ERROR);
      }
      close(ioList->fd);
      dup2(tmpfd,ioList->fd);
      close(tmpfd);
    }
  }
  return(STATUS_OK);
d850 1
d852 9
a860 169
  /* should cleanup shared memory and kill all backends */

  /*
   * Not sure of the semantics here.  When the Postmaster dies,
   * should the backends all be killed? probably not.
   */
  if (ServerSock != INVALID_SOCK)
    close(ServerSock);
  exitpg(status);
}

/* Delete this once the simple list implementation is ready */

#define MAX_SIZE 450000
#define MALLOC_MAGICNO		'M'
#define PRINT_ALLOC(STR, STR1, NUM)
#define DO_ALLOC(size)
#define TOP_ADDR(str)
int TotalCacheAlloc;

int *
CacheAlloc(size)
unsigned int size;
{
  char *tmp;

  Assert(size);
  Assert(size < MAX_SIZE);
  /* have to add four bytes because zalloc is going to align the space */
  tmp = (char *)zalloc(size+4);
  Assert(tmp);
  TOP_ADDR(tmp);
  PRINT_ALLOC("CacheAlloc",tmp,size);
  DO_ALLOC(TotalCacheAlloc += size);

  *(tmp+3) = MALLOC_MAGICNO;
  tmp += 4;

  return((int *)tmp);
}

FindBackend(backend)
char *backend;
{
	char path[PATH_SIZE];
	char objDir[PATH_SIZE];
	char *envVar;
	struct stat buf;

	/* check $POSTGRESHOME/bin/postgres */

	envVar = getenv("POSTGRESHOME");
	if (envVar) {
		strncpy(path, envVar, PATH_SIZE-21);
		strcat(path, "/bin/postgres");
		if (ValidBackend(path)) {
			strcpy(backend, path);
			return;
		}
	}

	/* check $POSTTREE/bin/postgres */

	envVar = getenv("POSTTREE");
	if (envVar) {
		strncpy(path, envVar, PATH_SIZE-21);
		strcat(path, "/bin/postgres");
		if (ValidBackend(path)) {
			strcpy(backend, path);
			return;
		}
	}

	/* check $POSTTREE/<obj.dir>/support/postgres */

	ReadObjDir(objDir);

	if (objDir[0]) {
		strncpy(path, objDir, PATH_SIZE-21);
		strcat(path, "/support/postgres");
		if (ValidBackend(path)) {
			strcpy(backend, path);
			return;
		}
	}

	/* check /usr/postgres/bin/postgres */

	strncpy(path, "/usr/postgres/bin/postgres", PATH_SIZE);
	if (ValidBackend(path)) {
		strcpy(backend, path);
		return;
	}
	fprintf(stderr,"Could not find a backend to execute -- giving up...\n");
	fprintf(stderr,"Have you set POSTGRESHOME in your environment?\n");
	fprintf(stderr,"Have you installed everything successfully?\n");
	exit(1);
}

ValidBackend(path)
char *path;
{
	struct stat buf;

	if ( stat(path, &buf) < 0 )
		return (FALSE);
	else if ( ! (buf.st_mode & S_IEXEC) )
		return (FALSE);
	else
		return (TRUE);
}

ReadObjDir(dir)
char *dir;
{
	FILE *fp;
	char buf[256];
	char tmpFile[32];
	char *bufptr;
	char *envPtr;

	/* Look for $POSTTREE/newconf/config.mk */

	if ((envPtr = getenv("POSTTREE")) == NULL)
	{
		*dir = '\0';
		return;
	}

	/* make a temporary file */
	sprintf(tmpFile, "/tmp/pm.%d", getpid());

	sprintf(buf, 
		"fgrep OD= %s/newconf/config.mk | sed -e \'s/OD=\t//\' > %s",
		envPtr,
		tmpFile);

	system( buf );

	if ((fp = fopen(tmpFile, "r")) == NULL) {
		*dir = '\0';
		return;
	}

	fgets(buf, 255, fp);

	/* kill the annoying \n fgets always puts at the end of the line */

	bufptr = (char *)index(buf, '\n');
	if (bufptr)
		*bufptr = (char)NULL;
	strncpy(dir, buf, PATH_SIZE);

	fclose(fp);
	unlink(tmpFile);
	return;
}

char *
zalloc(size)

unsigned long size;

{
	char *t;

	t = (char *) malloc(size);
	bzero(t, size);
	return(t);
@


1.58
log
@allow location of data/ to be supplied in environment or on command line
@
text
@d2 1
a2 1
 * $Header: /private/mao/postgres/src/support/RCS/postmaster.c,v 1.57 1992/08/12 02:47:20 mao Exp mao $
d47 1
a47 1
#include "support/master.h"
d53 1
a53 1
#include "support/list.h"
@


1.57
log
@two new flags:  -n keeps the postmaster from reinitializing shared memory
after a backend dumps core, and -s tells it to send SIGSTOP, rather than
SIGUSR1, to peers of the dead backend.
@
text
@d2 1
a2 1
 * $Header: /private/mao/postgres/src/support/RCS/postmaster.c,v 1.56 1992/06/10 05:18:42 mer Exp $
d51 1
d130 1
d225 1
a225 1
  while ((opt = getopt(argc, argv, "B:b:dno:p:s")) != EOF) {
d246 3
d281 2
a282 3
			perror("argument list");
			fprintf(stderr, "Usage: %s", Usage);
			exit(errno);
d290 19
d321 1
a321 1
    elog(WARN,"PostMaster:cannot create stream port") ;
d341 9
a795 1

d801 3
a803 2
    strcpy(dst, Home);
    strcat(dst, "/data/base/");
a806 1
    /* directory of database */
d808 2
a809 2
    strcpy(dst, Home);
    strcat(dst, "/data");
d811 1
a811 1
    /* directory of global data (should be '&/..') */
d859 2
a860 2
  strcpy(startDir, Home);
  strcat(startDir, "/data/base/");
@


1.56
log
@get rid of Dblog and SysLog bogosity, fixes the evil postmaster EOF bug.
@
text
@d2 1
a2 1
 * $Header: /usr/local/dev/postgres/mastertree/newconf/RCS/postmaster.c,v 1.55 1992/05/21 18:06:05 mer Exp $
d155 10
d223 1
a223 1
  while ((opt = getopt(argc, argv, "dp:b:o:B:")) != EOF) {
d225 10
a234 2
		case 'p':
			PostPortName = (short)atoi(optarg);
d252 4
d263 4
a266 1
		case 'B':
d268 4
a271 4
			 * The number of buffers to create.  Setting this
			 * option means we have to start each backend with
			 * a -B # to make sure they know how many buffers
			 * were allocated.
d273 1
a273 3
			NBuffers = atol(optarg);
			strcat(ExtraOptions, "-B ");
			strcat(ExtraOptions, optarg);
d512 1
d546 12
a559 6
	/* -----------------
	 * SIGUSR1 is the special signal that sez exit without exitpg
	 * and let the user know what's going on.  ProcSemaphoreKill() 
	 * cleans up the backends semaphore.
	 * -----------------
	 */
d561 3
a563 2
	  fprintf(stderr, "Sending SIGUSR1 to process %d\n", bp->pid);
	kill(bp->pid, SIGUSR1);
d584 1
a584 1
  if (ActiveBackends == TRUE)
@


1.55
log
@add some options (-o and -B)
@
text
@d2 1
a2 1
 * $Header: /users/mer/pg/src/support/RCS/postmaster.c,v 1.54 1992/04/28 00:25:49 mer Exp mer $
a114 2
  { SYSLOG_FD, NULL, (O_WRONLY|O_APPEND|O_CREAT) },
  { DBLOG_FD, NULL, (O_WRONLY|O_APPEND|O_CREAT) },
a136 2
char *Dblog = DEF_DBLOG;
char *SysLogName = DEF_SLOG;
a272 12
/* The corresponding files are opened just before we exec the backend */

  size = PATH_SIZE;
  fixlead(SysLogName, &sysLogPtr, &size);
  IO_List[3].name = sysLogPath;
  Assert(IO_List[3].fd == SYSLOG_FD);

  size = PATH_SIZE;
  fixlead(Dblog, &dblogPtr, &size);
  IO_List[4].name = dblogPath;
  Assert(IO_List[4].fd == DBLOG_FD);

d692 2
a693 1
	fprintf(stderr, "starting '%s' for '%s' on '%s' (%d) pid (%d)\n",
d697 1
a697 1
    elog(WARN, "PostMaster: fork failed");
d849 1
a849 1
	elog(WARN,"PostMaster: child cannot open tty '%s'",ioList->name);
@


1.54
log
@check if env var is null before using.
@
text
@d2 1
a2 1
 * $Header: /users/mer/pg/src/support/RCS/postmaster.c,v 1.53 1992/04/27 22:35:18 mer Exp mer $
d120 1
d154 5
d217 1
a217 1
  while ((opt = getopt(argc, argv, "dp:b:")) != EOF) {
d238 18
d797 12
a808 1
  char *args = pack->options;
@


1.53
log
@get rid of bogus dlog() call.  We don't really use this anymore
@
text
@d2 1
a2 1
 * $Header: /u/mer/pg/src/support/RCS/postmaster.c,v 1.52 1991/12/16 20:43:25 mer Exp mer $
d939 2
d964 1
d968 6
d979 1
a979 1
		getenv("POSTTREE"),
@


1.52
log
@bug fix.  using a struct after it has been freed.
@
text
@d2 1
a2 1
 * $Header: /users/mer/postgres/src/support/RCS/postmaster.c,v 1.51 1991/11/18 20:17:57 clarsen Exp mer $
a625 10

#ifdef	POSTMASTERLOG
  /*
   *  this is dillon's: the old data structures are gone so I'm not sure
   *  what the log message should contain.
   */
  dlog(2, form("key %d\naddr %lx\nport %d", bp->startTime,
	       bp->addr.sin_addr.s_addr, ntohs(bp->addr.sin_port)));
#endif	/* POSTMASTERLOG */

@


1.51
log
@prototypes
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.50 91/11/07 22:13:55 mer Exp Locker: clarsen $
d349 1
a350 1
	  baseMask &= ~ port->mask;
d355 1
a356 1
	  baseMask &= ~ port->mask;
@


1.50
log
@prototyping changes
@
text
@d2 1
a2 1
 * $Header: /users/mer/postgres/src/support/RCS/postmaster.c,v 1.49 1991/09/09 23:58:33 mao Exp mer $
d172 1
d174 1
@


1.49
log
@use GetPGHome() instead of using getenv directly
@
text
@d2 1
a2 1
 * $Header: /local/mao/postgres/src/support/RCS/postmaster.c,v 1.48 1991/08/15 15:00:49 mer Exp mao $
a60 1
char *zalloc();
d153 21
a177 2
  int		reaper();
  int		pmdie();
d389 2
a390 1
    if (BackendStartup(port, &port->buf, IO_List) != STATUS_OK) {
d439 1
a439 1
  free (port);
d501 1
a501 1
	  (void) free (bp);
d528 1
a528 1
    (void) free (bp);
@


1.48
log
@machine depency fix with passing a structure as a parameter
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.47 91/08/14 12:36:50 mer Exp Locker: mer $
d62 1
d143 1
a143 1
 * This is set by getenv("POSTGRESHOME");
d222 1
a222 2
  if (!(Home = getenv("POSTGRESHOME")) && !(Home = getenv("HOME")))
	Home = "/usr/postgres";
a224 1

@


1.47
log
@add recovery functionality, now when backend exit with status > 0 
shared stuff is completely re-initialized and all backends are torched
@
text
@d2 1
a2 1
 * $Header: /users/mer/postgres/src/support/RCS/postmaster.c,v 1.46 91/08/12 15:25:00 mer Exp Locker: mer $
d445 1
a445 1
    (void) CleanupProc(pid,status);
d456 1
a456 1
CleanupProc(pid,status)
d458 1
a458 1
int	status;		/* child's exit status. */
a460 1
  union wait dummy;
d465 1
a465 1
    fprintf(stderr, "Backend with pid %d exited with status %d\n", pid, status);
d475 1
a475 1
  if (!status)
@


1.46
log
@more debug output and clean-up proc bug fix
@
text
@d2 1
a2 1
 * $Header: /users/mer/postgres/src/support/RCS/postmaster.c,v 1.45 91/07/22 22:20:07 mao Exp Locker: mer $
d129 1
d329 1
a434 3
 * Eventually, this should do more complete error handling.  Right now,
 * all it does is is call CleanupProc to cleanup local data associated
 * with the backend.
d461 1
d464 29
a492 2
    fprintf(stderr, "In CleanUpProc pid %d\n", pid);
  ListForEach( curr, BackendList, BackendList) {
d495 8
a502 15
    if (bp->pid == pid) {
      /*
       * cleanup all shared mem state associated with the 
       * POSTGRES backend.  ProcKill() is my cleanup routine.
       * if the status is zero, assume that the backend exited
       * cleanly and took care of its own cleanup.
       */
      if (Debug)
	fprintf(stderr, 
	  "Backend with pid (%d) exitted with status %d\n",
	  pid,
	  status);

      if (status)
      {
d504 3
a506 6
	  fprintf(stderr, "Backend exit status non-zero calling ProcKill()\n");
	(void) ProcKill(pid);
      }
      ListDelete(curr);
      (void) free (bp);
      return(STATUS_OK);
d508 5
d514 26
a539 1
  return(STATUS_NOT_FOUND);
a602 4
  if (Debug)
	printf("starting '%s' for '%s' on '%s' (%d)\n",
	 	execFile,packet->user, database,port->sock);

d673 4
@


1.45
log
@jukebox storage manager installation
@
text
@d2 1
a2 1
 * $Header: /users/mao/postgres/src/support/RCS/postmaster.c,v 1.44 1991/07/22 14:52:31 mer Exp mao $
d443 2
d463 2
d475 6
d482 3
d486 1
d635 2
@


1.44
log
@incremental checkin for new lock manager
@
text
@d2 1
a2 1
 * $Header: support/RCS/postmaster.c,v 1.43 91/05/08 15:19:33 choi Exp Locker: mer $
d126 2
d217 2
@


1.43
log
@sprite doesn't have <sys/un.h>
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.42 91/03/20 19:17:11 cimarron Exp Locker: choi $
a69 3
#define GARBAGE /* Turn on garbage collection, at least for now */

#ifdef GARBAGE
a81 1
#endif GARBAGE
a255 1
#ifdef GARBAGE
a256 1
#endif
a438 1
#ifdef GARBAGE
a441 1
#endif
a443 1
#ifdef GARBAGE
a466 1
#ifdef NOTDEF
a468 1
#endif
a476 2
#endif GARBAGE

a489 1
#ifdef GARBAGE
a490 1
#endif
a500 1
#ifdef GARBAGE
a506 1
#endif
a551 1
#ifdef GARBAGE
a553 1
#endif
@


1.42
log
@fixed a macro wierdness problem
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.41 91/03/10 21:10:52 kemnitz Exp $
d43 1
d45 1
@


1.41
log
@Fixes the Kansas City bug.
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.40 91/03/09 06:58:57 kemnitz Exp Locker: kemnitz $
d464 1
a464 1
  ListForEach ( curr, BackendList, BackendList) {
@


1.40
log
@fixed compile error.
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.39 91/03/09 04:10:16 kemnitz Exp Locker: kemnitz $
d578 3
d582 3
a584 3
    char	envEntry1[20];
    char	envEntry2[18];
    char	envEntry3[USER_NAMESIZE];
@


1.39
log
@"Fixed" zombie processes problem - sadly ProcKill is nowhere to be
found.  Ifdef'ed out for now.
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.38 91/03/07 23:18:35 kemnitz Exp Locker: kemnitz $
d76 1
a76 1
typedef struct	backend	{
@


1.38
log
@Fixed problem with uninitialized vars.
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.37 91/03/05 12:57:04 mao Exp Locker: kemnitz $
d68 2
d474 1
d477 1
@


1.37
log
@brain-damaged "fixlead" procedure
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.36 91/03/05 10:27:27 mer Exp Locker: mao $
d59 1
d388 1
a388 1
  Port		*port = (Port *) malloc(sizeof(Port));
d511 1
a511 1
  bp = (Backend *) malloc(sizeof(Backend));
d513 1
a513 1
    elog(FATAL,"Postmaster: cannot malloc backend structure\n");
d807 2
a808 2
  /* have to add four bytes because malloc is going to align the space */
  tmp = (char *)malloc(size+4);
d926 13
@


1.36
log
@added vacuum cleaner ability
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.35 91/03/01 17:49:12 mer Exp Locker: mer $
d545 2
@


1.35
log
@fixed usage statement
@
text
@d2 1
a2 1
 * $Header: support/RCS/postmaster.c,v 1.34 91/03/01 17:44:08 mer Exp Locker: mer $
d501 1
d507 1
a520 1
  size = ARGV_SIZE;
d540 6
d548 1
a548 2
	 	DefaultStartup.execFile,packet->user,
	 	database,port->sock);
d611 1
a611 2
    if (! DoExec(DefaultStartup.execFile, 
		database, port->sock,packet)) {
@


1.34
log
@fixed command line args and added default list of search dirs for a backend
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.33 91/02/28 13:46:51 mer Exp Locker: mer $
d128 1
a128 1
char *Usage = "postmaster [ -p port ] [ -b backend_pathname ] [ -d level ]\n";
@


1.33
log
@run down default list of backends to exec (if not given on command line)
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.32 91/02/28 10:38:30 mer Exp Locker: mer $
d121 3
d128 1
a128 1
char *Usage = "postmaster -p port -b backend_pathname [ -d ]";
d185 2
a186 1
  while ((opt = getopt(argc, argv, "d:p:b:")) != EOF) {
d192 6
a197 1
  			strcpy(DefaultStartup.execFile, optarg);
d200 6
a205 1
			Debug = atoi(optarg);
d210 1
d712 1
a712 1
	sprintf(debugBuf, "-Q -n");
d816 1
d845 6
a850 5
	
	if (envVar) {
		strncpy(path, envVar, PATH_SIZE-21);
	/* /bin/postgres for now.... */
		strcat(path, "/bin/postgres");
d864 2
d879 39
@


1.32
log
@added functionality to support debug output redirection
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.31 91/02/27 00:15:18 hong Exp Locker: mer $
d37 1
a203 2
  if (!DefaultStartup.execFile[0])
  	strcpy(DefaultStartup.execFile,"/usr/postgres");
d205 3
d795 65
@


1.31
log
@fixed a compilation error
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.30 91/02/26 22:50:42 mer Exp Locker: hong $
d504 7
d657 1
a657 1
  strcpy(dst,str,size);
d682 1
a682 1
  char *args = pack->options;	/* last parameter to execl */
d695 1
a695 1
	sprintf(debugBuf, "-n");
d703 1
a703 3
  if (!(*args))
	args = (char *)NULL;

d705 6
a710 1
    execl( execFile, execFile, "-p", debugBuf, portBuf, database, args, NULL);
@


1.30
log
@quiet down messages unless requested
@
text
@d2 1
a2 1
 * $Header: RCS/postmaster.c,v 1.29 91/02/25 13:36:26 sp Exp Locker: mer $
a41 1
#include <netinet/in.h>
@


1.29
log
@Added a 'Header' line to keep rcs happy...
,.
@
text
@d2 1
a2 1
 * $Header: $
d692 1
a692 1
  if (Debug) 
d696 1
@


1.28
log
@All new postmaster, fixes bug where applications hang on there first try.
@
text
@d2 2
@


1.27
log
@Added a check for null user options.
@
text
@a0 2
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.26 91/02/06 13:17:19 kemnitz Exp $";

d5 3
a7 4
 *	POSTGRES system.  Frontend programs connect here and this
 *	program decides what to do with the request.  Also, this program
 *	keeps track of system errors and communication between backend
 *	processes.
d9 4
a12 1
 *	A lock manager uses a shared memory segment started by this program.
d14 8
a21 8
 *	Backend processes are started with the following file descriptors:
 *	0, 1, 2:	Read write terminal, for emergency use.
 *	3:		System log file append write only
 *	4:		Data stream to front end
 *	5:		Packet socket
 *	6:		Database log file append write only
 *	7:		Write end of pipe to postmaster
 *	8 to NOFILE:	free
d23 7
a29 2
 *	Backend processes are started with -postmaster indicating that they
 *	are non-interactive.
d35 1
a35 2
#include <sys/stat.h>
#include <sys/param.h>
d40 2
a41 3
#include <arpa/inet.h>
#include <strings.h>
/* #include "postgres.h" */
a42 2
#include "tmp/c.h"

d46 3
a48 3
/* OPT #include "sinval.h" */
#include "storage/sinvaladt.h"
#include "tmp/xid.h"	/* XXX only to define local GetNewTransactionId */
d50 2
a51 2
extern char *calloc();
#define ALLOC(t, c)	(t *)calloc((unsigned)(c), sizeof(t))
d53 4
a56 10
short   DebugOveride = 0;	/* overide frontend's terminal spec 	*/
short	Port = DEF_PORT;
short	Pack = DEF_PACK;
char	*Slog = DEF_SLOG;
short	Loglvl = DEF_LOGLVL;
char	*Back = DEF_BIN;
char	*Dblog = DEF_DBLOG;
char	*Dbname = "dbdb";	/* place holder */
char	*Home;
char	pg_pathname[256];
a57 2
int	Slogfd, Portfd, Packfd, Pipefds[2];
int	Ttyfile, Debugfile;
d59 5
a63 2
BackendId	MyBackendId = -1;	/* XXX ipc/sinvaladt.c requires -1 */
BackendTag	MyBackendTag = -1;
d65 9
a73 2
struct	backend	Master;
struct	bcommon	Ident;
d75 2
a76 1
int	NextBackendId = 0x7fffffff;	/* XXX */
d78 1
d80 64
d148 25
a172 11
	struct	sockaddr_in	sin;
	long			selmask;
	int			reaper(), i;
	int			die();
	long			len;
	struct	stat		sbuf;
	char			comm[512];
	extern	int		errno;
	char			tslog[64];
	extern char		*getenv();
	char			*p;
d174 1
a174 33
	/* should eventually look up the HOME of postgres */
	if (!(Home = getenv("POSTGRESHOME")) && !(Home = getenv("HOME")))
		Home = "/usr/postgres";
	/* Handle arguments */
	p = index(Home, ':');
	if (p != NULL)
	   *p = '\0';
	switch (argc) {
	  default:
		fprintf(stderr, "Postmaster: warning, too many arguments!\n");
	  case 8:
		DebugOveride = 1;
		fprintf(stderr, "Warning, DebugOveride activated\n");
	  case 7:
		Dblog = argv[6];
	  case 6:
		Slog = argv[5];
	  case 5:
		Back = argv[4];
	  case 4:
		Loglvl = atoi(argv[3]);
	  case 3:
		Pack = atoi(argv[2]);
	  case 2:
		Port = atoi(argv[1]);
	  case 1:
		/* do nothing */
		;
	}
	if (!Port) {
		fputs("Usage: postmaster port packet loglevel backend syslogfile dblogfile\n", stderr);
		exitpg(1);
	}
d176 3
a178 2
	fixpath(tslog, Slog, 64);
	Slog = tslog;
d180 15
a194 4
	/* initial setup of file descriptors */
	if ((Slogfd = open(Slog, O_WRONLY|O_APPEND|O_CREAT, 0666)) < 0) {
		perror(Slog);
		exitpg(2);
d196 1
a196 41
	if (Slogfd == 0) {	/* not on a terminal */
		dup(0);
		dup(0);
		Slogfd = dup(0);
	}
	Ttyfile = 1;
	Debugfile = Slogfd;
	if ((Portfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket port");
		exitpg(3);
	}
	if ((Packfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("socket pack");
		exitpg(4);
	}
	if (pipe(Pipefds) < 0) {
		perror("pipe");
		exitpg(7);
	}
	if (Pipefds[1] != 7) {	/* Hmmm.  Something wrong here. */
		perror("file descriptors scrambled");
		exitpg(8);
	}
	bzero((char *)&sin, sizeof sin);
	sin.sin_family = AF_INET;
	sin.sin_port = htons(Port);
	if (bind(Portfd, (char *)&sin, sizeof sin) < 0) {
		perror("bind port");
		exitpg(5);
	}
	sin.sin_port = htons(Pack);
	if (bind(Packfd, (char *)&sin, sizeof sin) < 0) {
		perror("bind pack");
		exitpg(6);
	}
	listen(Portfd, SOMAXCONN);
	fcntl(Portfd, F_SETFD, 1);
	fcntl(Packfd, F_SETFD, 1);
	fcntl(Pipefds[0], F_SETFD, 1);
	fcntl(Portfd, F_SETFL, FNDELAY);
	fcntl(Pipefds[0], F_SETFL, FNDELAY);
d198 2
a199 3
	signal(SIGCHLD, reaper);
	signal(SIGTTIN, SIG_IGN);
	signal(SIGTTOU, SIG_IGN);
d201 3
a203 3
	signal(SIGHUP, die);
	signal(SIGINT, die);
	signal(SIGTERM, die);
d205 4
a208 1
	Ident = Master.bcomm;
d210 1
a210 7
	EnableMemoryContext(true);  /* initializes the "top context" */
#ifndef	PRODUCTION
	CreateSharedMemoryAndSemaphores(
		SystemPortAddressCreateIPCKey((SystemPortAddress)Port));
#else	/* defined(PRODUCTION) */
	CreateSharedMemoryAndSemaphores(DefaultMemoryKey);
#endif	/* defined(PRODUCTION) */
d212 112
a323 44
	/* main processing loop */
	while (1) {
		selmask = (1 << Portfd) | (1 << Packfd) | (1 << Pipefds[0]);
		if (select(32, &selmask, NULL, NULL, NULL) < 0) {
			if (errno == EINTR)
				continue;
			perror("select");
			exitpg(8);
		}
		/* incomming packet */
		if (selmask & (1 << Packfd)) {
			i = sizeof sin;
			if ((len = recvfrom(Packfd, comm, sizeof comm, 0,
				(struct sockaddr *)&sin, &i)) < 0) {
					perror("recvfrom");
					exitpg(9);
			}
			/* do packet */
			packet(comm, len, &sin);
		}
		/* incomming packet from a local backend */
		if (selmask & (1 << Pipefds[0])) {
			if (recv(Pipefds[0], (char *)&len, sizeof len,
				 MSG_PEEK) != sizeof len) {
				fputs("read pipe len error\n", stderr);
				exitpg(10);
			}
			if (len != (i = read(Pipefds[0], comm, len))) {
				fprintf(stderr, "read pipe len wrong %d %d\n",
					i, len);
				exitpg(11);
			}
			/* do packet */
			packet(comm, len, NULL);
		}
		/* incomming connection */
		if (selmask & (1 << Portfd)) {
			len = sizeof sin;
			if ((i = accept(Portfd, (char *)&sin, &len)) < 0) {
				perror("accept");
				exitpg(12);
			}
			startup(i, sin);
		}
d325 5
d332 2
a333 2
/* reap dead backends */
reaper()
d335 5
a339 2
	union	wait	status;
	struct	rusage	ruse;
d341 13
a353 4
	/* will eventually keep track of backends in operation and */
	/* log abnormal terminations */
	while (wait3(&status, WNOHANG, &ruse) > 0)
		continue;
d356 7
a362 2
/* exit gracefully */
die()
d364 28
a391 1
	exitpg(0);
d394 2
a395 5
/* packet handler */
packet(comm, len, sin)
char	*comm;
int	len;
struct	sockaddr_in	*sin;
d397 2
a398 2
	/* will eventually do lots of fun stuff */
	dlog(SLOG|PTIME, comm);
d401 4
a404 4
/* new connection handler */
startup(fd, sin)
int	fd;
struct	sockaddr_in	*sin;
d406 2
a407 7
	char	line[512], *cp, *index(), lognum[8], *mvitem();
	char	portFdBuf[32];	/* -Pn where n is the comm socket fd */
	char	debugModeBuf[32];	/* -debug if DebugOveride set */
	int	i, dportfd;
	FILE	*fp;
	struct	backend	*bp;
	struct	hostent	*hp;
d409 12
a420 19
	/* should not leave the possibility of blocking on this routine */
	fcntl(fd, F_SETFL, 0);	/* reset to block on read */
	fp = fdopen(fd, "r");
	fgets(line, 512, fp);
	fputs(line, stdout);
	fflush(stdout);
	bp = ALLOC(struct backend, 1);
	cp = mvitem(line, bp->bcomm.user, 16, "nobody");
	cp = mvitem(cp, bp->database, 64, "dbdb");
	Dbname = bp->database;
	cp = mvitem(cp, bp->tty, 16, "null");
	cp = mvitem(cp, bp->options, 16, "");
	cp = mvitem(cp, lognum, 8, "");
	if (*lognum)
		bp->bcomm.debuglvl = atoi(lognum);
	else
		bp->bcomm.debuglvl = DEF_LOGLVL;
	cp = mvitem(cp, bp->back, 64, Back);
	cp = mvitem(cp, bp->dblog, 64, DEF_DBLOG);
d422 6
a427 4
#ifdef	POSTMASTERLOG
	dlog(1, form("user %.16s db %.64s backend %.64s",
		     bp->bcomm.user, bp->database, bp->back));
#endif	/* POSTMASTERLOG */
d429 1
d431 5
a435 2
 * Set PG_USER so that Postgres can know who the user is.  I can't think of
 * any better way than to do it in the environment.
d437 5
d443 19
a461 2
	{
		char env[50];
d463 1
a463 1
#ifdef sprite
d465 21
a485 1
		setenv("PG_USER", bp->bcomm.user);
d487 1
a487 1
#else
d489 7
a495 2
		sprintf(env, "PG_USER=%s", bp->bcomm.user);
		putenv(env);
a496 1
	}
d498 4
a501 28
	bp->last = &Master;
	bp->next = Master.next;
	Master.next = bp;
	/* build a datagram port for backend */
	if ((dportfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("socket dport");
		fclose(fp);
		return;
	}
	bzero((char *)&bp->sin, sizeof (bp->sin));
	bp->sin.sin_family = AF_INET;
	bp->sin.sin_addr.s_addr = INADDR_ANY;
	if (bind(dportfd, &bp->sin, sizeof(bp->sin)) < 0) {
		perror("bind dport");
		fclose(fp);
	}
	i = sizeof(bp->sin);	
	if (getsockname(dportfd, &bp->sin, &i)) {
		perror("getsockname");
		fclose(fp);
		return;
	}
	if ((hp = gethostbyname("localhost")) && hp->h_addrtype == AF_INET)
	  bcopy(hp->h_addr, (char *)&bp->sin.sin_addr, hp->h_length);
	else
	  bp->sin.sin_addr.s_addr = inet_addr("127.0.0.1");
	/* choose a key for backend */
	bp->bcomm.key = time(0);
d503 21
d525 8
a532 2
	dlog(2, form("key %d\naddr %lx\nport %d", bp->bcomm.key,
	       bp->sin.sin_addr.s_addr, ntohs(bp->sin.sin_port)));
a534 3
	/* fork */
	if ((bp->bcomm.pid = fork()) == 0) {
	/* child: move file descriptors and open files */
d536 20
a555 8
		/*
		 * XXX Should someday write a message instead of modifying
		 * XXX the environment here.  Done this way now to aid
		 * XXX debugging.
		 */
		{
			char	environmentEntry1[20];
			char	environmentEntry2[18];
d557 9
a565 6
                        { char c[50];
                        sprintf(c, "%d", Port);
                        setenv("POSTPORT", c);
                        sprintf(c, "%d", NextBackendId);
                        setenv("POSTID", c);
                        }
a566 2
			sprintf(environmentEntry1, "POSTPORT=%d", Port);
			putenv(environmentEntry1);
d568 10
a577 3
			sprintf(environmentEntry2, "POSTID=%d",
				NextBackendId);
			putenv(environmentEntry2);
a578 1
		}
d580 38
a617 35
		if (strcmp(bp->dblog, "def")) {
			close(6);
			open(bp->dblog, O_WRONLY|O_APPEND|O_CREAT, 0644);
		}
		dup2(fd, Portfd);
#ifdef sprite
                /*
                 * Patch bug in dup2() on Sprite that doesn't clear
                 * close-on-exec flag.
                 */
                (void) fcntl(Portfd, F_SETFD, 0);
#endif
		dup2(dportfd, Packfd);
		if (strcmp(bp->tty, "def")) {
		    if (DebugOveride == 0) {
			close(0);
			close(1);
			close(2);
			open(bp->tty, O_WRONLY);
			dup(0);
			dup(0);
		    }
		}
		if (DebugOveride)
		    strcpy(debugModeBuf, "-d");
		else
		    strcpy(debugModeBuf, "-n");	/* nop */
		sprintf(portFdBuf, "-P%d", Portfd);
		for (i = 8; i < NOFILE; i++)
			close(i);
		strcpy(line, Home);
		strcat(line, "/data/base/");
		strcat(line, bp->database);
		if (chdir(line))
		  perror(line);
d619 4
a622 32
#ifdef POSTMASTERLOG
strcpy(debugModeBuf, "-d");
write(Ttyfile,bp->back,strlen(bp->back));
write(Ttyfile," ",1);
write(Ttyfile,debugModeBuf,strlen(debugModeBuf));
write(Ttyfile," ",1);
write(Ttyfile,portFdBuf,strlen(portFdBuf));
write(Ttyfile," ",1);
write(Ttyfile,bp->database,strlen(bp->database));
write(Ttyfile," ",1);
#endif	     
		if (bp->options[0] != '\0')
		{
		    execl( bp->back, bp->back, debugModeBuf, portFdBuf,
		           bp->options, "-p", bp->database, (char *)0);
		}
		else
		{
		    execl( bp->back, bp->back, debugModeBuf, portFdBuf,
		           "-p", bp->database, (char *)0);
		}
		perror(bp->back);
		fflush(stderr);
		exitpg(1);
	}
	/* parent: pid is set and close files */
	close(dportfd);
	fclose(fp);
	if (bp->bcomm.pid < 0)
	  dlog(SLOG, "fork failed");
	else
	  sendpg(bp, 'I', (char *)&bp->bcomm, sizeof(bp->bcomm));
d624 30
a653 2
	/* adjust backend counter */
	NextBackendId -= 1;
d656 13
a668 4
char *
mvitem(src, dst, len, def)
char	*src, *dst, *def;
int	len;
d670 5
a674 1
	int	i;
d676 24
a699 22
	if (src && *src != '\n') {
		if (*src == ',') {
			fixpath(dst, def, len);
			return(src+1);
		}
		i = fixlead(dst, *src);
		dst += i;
		len -= i;
		src++;
		while (len-- && *src != '\n' && *src != ',')
			*dst++ = *src++;
		if (len == -1)
			while (*src != '\n' && *src != ',')
				src++;
		else
			*dst = '\0';
		if (*src != '\n')
			return(src+1);
		return(NULL);
	}
	fixpath(dst, def, len);
	return(NULL);
d702 9
a710 2
fixlead(dst, c)
char	*dst, c;
d712 23
a734 23
	int	i;
	
	switch (c) {
	  case '~':
		/* home directory of postgres installation */
		strcpy(dst, Home);
		break;
	  case '&':
		strcpy(dst, Home);
		strcat(dst, "/data/base/");
		strcat(dst, Dbname);
		break;
		/* directory of database */
	  case '%':
		strcpy(dst, Home);
		strcat(dst, "/data");
		break;
		/* directory of global data (should be '&/..') */
	  default:
		*dst = c;
		return(1);
	}
	return(strlen(dst));
d737 4
a740 3
fixpath(dst, src, len)
char	*dst, *src;
int	len;
d742 1
a742 1
	int	i;
d744 7
a750 5
	i = fixlead(dst, *src);
	dst += i;
	len -= i;
	src++;
	strncpy(dst, src, len);
d753 12
a764 5
sendpg(bp, type, data, len)
struct	backend	*bp;
short		type;
char		*data;
short		len;
d766 1
a766 1
	static	struct	dpacket	pack;
d768 13
a780 8
	pack.key = bp->bcomm.key;
	pack.pid = bp->bcomm.pid;
	pack.type = type;
	bcopy(data, pack.data, len);
	pack.len = len + 12;
	if (sendto(Packfd, &pack, len+8, 0, &bp->sin,
		   sizeof(bp->sin)) < 0)
	  perror("sendto");
a781 1

@


1.26
log
@Fixed problem with stupid "bp" structure.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.25 91/02/04 17:28:24 kemnitz Exp Locker: kemnitz $";
d435 10
a444 10
		execl(
		    bp->back, 
		    bp->back, 
		    debugModeBuf,
		    portFdBuf,
		    bp->options,
		    "-p", 
		    bp->database,
		    (char *)0
		);
@


1.25
log
@Added an environment variable for user name.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.24 91/02/02 18:34:10 mao Exp Locker: kemnitz $";
d320 1
a320 1
		sprintf(env, "PG_USER=%s", bcomm.user);
@


1.24
log
@pass user-specified options to backend.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.23 91/01/18 22:22:04 hong Exp Locker: kemnitz $";
d305 19
@


1.23
log
@change for the new buffer manager
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.22 90/10/16 00:29:30 kemnitz Exp Locker: hong $";
d292 1
d421 1
@


1.22
log
@Added pg_pathname so linking is happy.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.21 90/09/25 17:23:59 kemnitz Exp Locker: kemnitz $";
d185 1
@


1.21
log
@Fixed stuff.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.19 90/09/18 21:57:26 hong Exp $";
d61 1
@


1.20
log
@Updating from revision 1.$t2 to revision 1.$t
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.18 90/08/24 14:40:14 choi Exp Locker: hong $";
d37 1
d88 1
d94 3
@


1.19
log
@to support file striping
@
text
@a36 1
#include <strings.h>
a86 1
	char			*p;
a91 3
	p = index(Home, ':');
	if (p != NULL)
	   *p = '\0';
@


1.18
log
@lines added for Sprite OS port.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.17 90/08/23 16:02:59 hong Exp Locker: choi $";
d37 1
d88 1
d94 3
@


1.17
log
@fixed #include's with path name.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.16 90/05/25 12:16:44 kemnitz Version_2 Locker: hong $";
d344 8
a351 1

d358 1
d366 7
@


1.16
log
@Got rid of POSTHOME variable.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.15 90/04/19 17:49:45 kemnitz Exp Locker: kemnitz $";
d39 1
a39 1
#include "c.h"
d41 3
a43 3
#include "master.h"
#include "log.h"
#include "ipci.h"
d45 2
a46 2
#include "sinvaladt.h"
#include "xid.h"	/* XXX only to define local GetNewTransactionId */
@


1.15
log
@Got rid of old sequent hacks - no longer needed.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.14 90/04/11 21:42:26 kemnitz Exp Locker: kemnitz $";
d89 1
a89 1
	if (!(Home = getenv("POSTHOME")) && !(Home = getenv("HOME")))
@


1.14
log
@Changed "debugging mode" from -debug to -d and set up to send -n
for nodebug node.
(so that tcop/postgres.c is happy with its arguments).
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.13 90/03/31 19:06:04 cimarron Exp Locker: kemnitz $";
a71 5
/*
 * TEMPORARY SEQUENT HACKS
 *
 * on_exit()
 */
a72 15
#ifdef sequent

int Pipefd;	/* due to inclusion of pcomm.o and disclusion of cinit.o */

void
on_exit()
{
    fprintf(stderr, "on_exit() called! not implemented on sequent yet\n");
}

#endif




a507 5
sendannounce(mess)
char	*mess;
{
	dlog(SLOG, mess);
}
@


1.13
log
@removed redundant GetNewTransctionId().
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.12 90/02/12 19:51:24 cimarron Exp $";
d390 1
a390 1
		    strcpy(debugModeBuf, "-debug");
d392 1
a392 1
		    strcpy(debugModeBuf, "-");	/* nop */
@


1.12
log
@added buffer manager statistics and exitpg() stuff -cim
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.11 89/11/24 15:55:35 hirohama Exp $";
a531 14
}

TransactionId
GetNewTransactionId()
{
	TransactionIdData	transactionIdData;

	transactionIdData.data[0] = AsUint8(0xff);
	transactionIdData.data[1] = AsUint8(0xff);
	transactionIdData.data[2] = AsUint8(0xff);
	transactionIdData.data[3] = AsUint8(0xff);
	transactionIdData.data[4] = AsUint8(0xff);

	return(&transactionIdData);	/* XXX */
@


1.11
log
@readded argc==1 case (why was it removed?!?)
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.10 89/09/21 18:58:34 hirohama Exp Locker: hirohama $";
d136 1
a136 1
		exit(1);
d145 1
a145 1
		exit(2);
d156 1
a156 1
		exit(3);
d160 1
a160 1
		exit(4);
d164 1
a164 1
		exit(7);
d168 1
a168 1
		exit(8);
d175 1
a175 1
		exit(5);
d180 1
a180 1
		exit(6);
d213 1
a213 1
			exit(8);
d221 1
a221 1
					exit(9);
d231 1
a231 1
				exit(10);
d236 1
a236 1
				exit(11);
d246 1
a246 1
				exit(12);
d268 1
a268 1
	exit(0);
d424 1
a424 1
		_exit(1);
@


1.10
log
@removed "postgres.h" dependency
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.9 89/09/05 16:53:19 mao C_Demo_1 Locker: hirohama $";
d130 3
@


1.9
log
@Working version of C-only demo
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.8 89/08/31 17:52:38 mao Exp $";
d37 1
a37 1
#include "postgres.h"
d47 3
@


1.8
log
@close stdin, stdout, stderr.
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.7 89/08/31 10:21:08 goh Exp $";
@


1.7
log
@removed the transaction override flag.  someday should add
it back as an option
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.6 89/08/30 18:52:04 goh Exp Locker: goh $";
a374 1
/*
a377 1
*/
@


1.6
log
@now works with postgres.c (backend) for be/fe communications
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: RCS/postmaster.c,v 1.5 89/08/02 23:56:46 dillon Exp $";
a414 1
		    "-O",
@


1.5
log
@major changes, works with new backend now
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: postmaster.c,v 1.4 89/07/17 14:40:16 dillon Exp $";
d375 1
d379 1
d397 12
a411 2
		    bp->database, 
		    "-postmaster", 
d414 3
a416 1
		    debugModeBuf,
@


1.4
log
@now passes -postmaster flag to backend on startup
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: postmaster.c,v 1.3 89/04/14 18:33:41 dillon Locked $";
d48 1
d110 5
d281 2
d374 1
d381 1
d383 5
d400 3
@


1.3
log
@added hacks so we don't have to include cinit.c
cinit.o..
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: /usr6/postgres/dillon/ptree/src/support/RCS/postmaster.c,v 1.2 89/02/02 15:58:13 dillon Stab $";
d22 3
d380 7
a386 1
		execl(bp->back, bp->back, bp->database, (char *)0);
@


1.2
log
@Txfer from old tree
@
text
@d1 1
a1 1
static	char	*postmaster_c = "$Header: postmaster.c,v 2.7 88/09/12 22:18:10 dillon Locked $";
d64 21
@


1.1
log
@Initial revision
@
text
@d1 1
a1 28

/*
 * 
 * POSTGRES Data Base Management System
 * 
 * Copyright (c) 1988 Regents of the University of California
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for educational, research, and non-profit purposes and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of the University of California not be used in advertising
 * or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Permission to incorporate this
 * software into commercial products can be obtained from the Campus
 * Software Office, 295 Evans Hall, University of California, Berkeley,
 * Ca., 94720 provided only that the the requestor give the University
 * of California a free licence to any derived software for educational
 * and research purposes.  The University of California makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 * 
 */



static	char	*postmaster_c = "$Header: postmaster.c,v 1.1 88/11/11 16:40:22 postgres Exp $";
@
