Commit 53bf56f8 authored by Fred Drake's avatar Fred Drake

The pcgi/ directory will no longer be distributed with Zope 2.7. The files

it contains have been moved to the Packages/pcgi module in the cvs.zope.org
public CVS repository; it can be distributed as a separate package for those
who need it.
parent 0f6a4160
#!/usr/local/bin/pcgi-wrapper
# example pcgi info file - JeffBauer@bigfoot.com
# substitute 'BogusDirectory' with appropriate path
# and subsitute the correct path to your Python binary
# for PCGI_EXE.
#
# To invoke from browser: http://.../cgi-bin/pcgitest/getTime
PCGI_EXE=/usr/local/bin/python
PCGI_PUBLISHER=/BogusDirectory/pcgi_publisher.py
PCGI_MODULE_PATH=/BogusDirectory/pcgitime.py
PCGI_SOCKET_FILE=/tmp/pcgitest.socket
PCGI_PID_FILE=/tmp/pcgitest.pid
# pcgitime.py - example pcgi script - JeffBauer@bigfoot.com
from time import asctime, localtime, time
beginTime = "<html><pre>time started: %s" % asctime(localtime(time()))
def getTime(arg=None):
"""It's later than you think (don't remove this docstring)"""
return "%s\ncurrent time: %s" % (beginTime, asctime(localtime(time())))
### Makefile.in - Persistent CGI configuration ###
### start of system configuration section ###
prefix= @prefix@
exec_prefix= @exec_prefix@
BINDIR= $(exec_prefix)/bin
srcdir= @srcdir@
VPATH = @srcdir@
VERSION= @VERSION@
MACHDEP= @MACHDEP@
CC = @CC@
CFLAGS= @CFLAGS@
DEFS= @DEFS@ -DUNIX -DOPT_NO_STDERR -DCLOSE_FDS
LIBS= @LIBS@
creosotedir = $(srcdir)/MrCreosote
testdir = $(srcdir)/Test
utildir = $(srcdir)/Util
### end of system configuration section ###
.c.o:
$(CC) -c $(CPPFLAGS) $(DEFS) -I. -I$(srcdir) $(CFLAGS) $<
PROGS = pcgi-wrapper $(creosotedir)/pcgi-creosote $(testdir)/parseinfo
SRCS = pcgi-wrapper.c parseinfo.c $(creosotedir)/creosote.c
OBJS1 = pcgi-wrapper.o parseinfo.o
OBJS2 = $(creosotedir)/pcgi-wrapper.o parseinfo.o $(creosotedir)/creosote.o
OBJS3 = $(srcdir)/pcgi-wrapper.o $(testdir)/parseinfo.o
HDRS = pcgi.h $(creosotedir)/creosote.h
# --with-XXX options for configure
WITH=
MANIFEST=$(srcdir)/manifest
# default path permission settings
DIRMODE= 775
EXEMODE= 755
FILEMODE= 644
# Portable install script (configure doesn't always guess right)
INSTALL= ./install-sh -c
INSTALL_PROGRAM=${INSTALL} -m $(EXEMODE)
INSTALL_DATA= ${INSTALL} -m $(FILEMODE)
##################################################
all: pcgi-wrapper $(testdir)/parseinfo
pcgi-wrapper.o: pcgi-wrapper.c pcgi.h
$(CC) -c -I. -I$(srcdir) $(CFLAGS) -DPCGI_WRAPPER_MAIN -DVERSION=\"$(VERSION)\" $(DEFS) $(srcdir)/pcgi-wrapper.c
parseinfo.o: parseinfo.c pcgi.h
$(CC) -c -I. -I$(srcdir) $(CFLAGS) $(DEFS) $(srcdir)/parseinfo.c
pcgi-wrapper: pcgi-wrapper.o parseinfo.o
$(CC) $(LIBS) $(LDFLAGS) -o pcgi-wrapper $(OBJS1)
### begin CREOSOTE stuff ###
$(creosotedir)/creosote.o: $(creosotedir)/creosote.c $(creosotedir)/creosote.h
$(CC) -c -o $(creosotedir)/creosote.o -I. -I$(srcdir) -I$(creosotedir) $(CFLAGS) -DCREOSOTE $(DEFS) $(creosotedir)/creosote.c
$(creosotedir)/pcgi-wrapper.o: $(srcdir)/pcgi-wrapper.c
$(CC) -c -o $(creosotedir)/pcgi-wrapper.o -I. -I$(srcdir) -I$(creosotedir) $(CFLAGS) -DPCGI_WRAPPER_MAIN -DCREOSOTE $(DEFS) $(srcdir)/pcgi-wrapper.c
creosote: $(creosotedir)/pcgi-creosote
$(creosotedir)/pcgi-creosote: $(creosotedir)/pcgi-wrapper.o parseinfo.o $(creosotedir)/creosote.o
$(CC) $(LIBS) $(LDFLAGS) -o $(creosotedir)/pcgi-creosote $(OBJS2)
### end CREOSOTE stuff ###
### begin TEST stuff ###
$(testdir)/parseinfo.o: $(srcdir)/parseinfo.c
$(CC) -c -o $(testdir)/parseinfo.o -I. -I$(srcdir) -I$(testdir) $(CFLAGS) -DMAIN_PARSEINFO $(DEFS) $(srcdir)/parseinfo.c
$(testdir)/pcgi-wrapper.o: $(srcdir)/pcgi-wrapper.c
$(CC) -c -o $(testdir)/pcgi-wrapper.o -I. -I$(srcdir) -I$(testdir) $(CFLAGS) $(DEFS) $(srcdir)/pcgi-wrapper.c
parseinfo: $(testdir)/parseinfo
$(testdir)/parseinfo: $(testdir)/parseinfo.o $(testdir)/pcgi-wrapper.o
$(CC) $(LIBS) $(LDFLAGS) -o $(testdir)/parseinfo $(testdir)/parseinfo.o $(testdir)/pcgi-wrapper.o
### end TEST stuff ###
install: bininstall
bininstall: altbininstall
cp pcgi-wrapper $(BINDIR)
chmod a+rx $(BINDIR)/pcgi-wrapper
-if test -f $(BINDIR)/pcgi-wrapper; \
then rm -f $(BINDIR)/pcgi-wrapper; \
else true; \
fi
(cd $(BINDIR); ln pcgi-wrapper$(VERSION) pcgi-wrapper)
altbininstall: pcgi-wrapper
@for i in $(BINDIR); \
do \
if test ! -d $$i; then \
echo "Creating directory $$i"; \
mkdir $$i; \
chmod $(DIRMODE) $$i; \
else true; \
fi; \
done
$(INSTALL_PROGRAM) pcgi-wrapper $(BINDIR)/pcgi-wrapper$(VERSION)
clean:
rm -f $(PROGS) *.o *.out core $(creosotedir)/*.o $(testdir)/*.o $(utildir)/*.o Win32/*.obj
distclean: clean
rm -f Makefile autoconf.h config.status config.cache config.log *~
tarball:
cd $(srcdir); mkdir pcgi-$(VERSION)
cpio -pd < $(MANIFEST) pcgi-$(VERSION)
tar -czf $(srcdir)/pcgi-$(VERSION).tgz pcgi-$(VERSION)
rm -rf pcgi-$(VERSION)
# Build the toplevel Makefile
#Makefile: Makefile.in config.status
# CONFIG_FILES=Makefile $(SHELL) config.status
# Run the configure script, calling it with --recheck if config.status exists
#config.status: $(srcdir)/configure
# if test -f config.status; \
# then $(SHELL) config.status --recheck; \
# $(SHELL) config.status; \
# else $(SHELL) $(srcdir)/configure $(WITH); \
# fi
# Rebuild the configure script from configure.in
autoconf:
(cd $(srcdir); autoconf)
(cd $(srcdir); autoheader)
README.MrCreosote - JeffBauer@bigfoot.com - May 21, 1998
MrCreosote is a lightweight message-passing idiom I use
to debug multi-processor/multi-user code sometimes.i
It's basically just a matter of tossing out datagrams
(connectionless sockets). I'll document it later, in
case anyone finds it useful for debugging. For now,
just ignore the contents of this directory.
/* creosote.c */
#include "creosote.h"
struct MrCreosote CreosoteServer;
void closeMrCreosote()
{
struct MrCreosote *c = &CreosoteServer;
if (c->socket)
{
#ifdef UNIX
close(c->socket);
#endif
#ifdef WIN32
closesocket(c->socket);
WSACleanup();
#endif
}
c->socket = 0;
}
#ifdef UNIX
int initializeMrCreosote()
{
struct MrCreosote *c = &CreosoteServer;
SOCKADDR_IN addr, *serv;
creosote_socket *s;
serv = &(c->serv_addr);
s = &(c->socket);
c->port = CREOSOTE_PORT;
strcpy(c->host, CREOSOTE_HOST);
bzero(serv, sizeof(*serv));
serv->sin_family = AF_INET;
serv->sin_addr.s_addr = inet_addr(c->host);
serv->sin_port = htons(c->port);
if ((*s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
return(-1);
}
bzero((char *) &addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(0);
if (bind(*s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
return(-1);
}
return(0);
}
#endif
#ifdef WIN32
int initializeMrCreosote()
{
struct MrCreosote *c = &CreosoteServer;
SOCKADDR_IN *serv;
creosote_socket *s;
WSADATA WsaData;
int enable = 1;
s = &(c->socket);
if (!c->port)
{
c->port = CREOSOTE_PORT;
}
if (!c->host[0])
{
strcpy(c->host, CREOSOTE_HOST);
}
if (0 != WSAStartup(MAKEWORD(2,0), &WsaData))
{
return(-1);
}
/* Set the address */
serv = &(c->serv_addr);
serv->sin_family = AF_INET;
serv->sin_addr.s_addr = inet_addr(c->host);
serv->sin_port = htons((short)c->port);
/* Create socket */
*s = socket(AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET == *s) { return(-1); }
/* Permit the socket to broadcast */
if (SOCKET_ERROR == setsockopt(*s, SOL_SOCKET, SO_BROADCAST, (char *) &enable, sizeof(enable)))
{
return(-1);
}
return(0);
}
#endif
void setMrCreosoteHost(char *host)
{
/*
If not using localhost, setMrCreosoteHost() must be called
before initializeMrCreosote().
*/
strcpy(CreosoteServer.host, host);
}
void setMrCreosotePort(int port)
{
/* must be done before initializeMrCreosote() is called */
CreosoteServer.port = port;
}
void spewMrCreosote(char *msg)
{
struct MrCreosote *c = &CreosoteServer;
sendto(c->socket, msg, strlen(msg), 0, (struct sockaddr *) &(c->serv_addr), sizeof(c->serv_addr));
}
#if 0
int main(int argc, char *argv[])
{
if ( (initializeMrCreosote()) < 0)
{
printf("initializeMrCreosote() failed\n");
exit(1);
}
spew("Hello, world");
closeMrCreosote();
return(0);
}
#endif
/* creosote.h */
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#define CREOSOTE_HOST "127.0.0.1"
#define CREOSOTE_PORT 7739
#define spew(x) spewMrCreosote(x)
#ifdef UNIX
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef int creosote_socket;
typedef struct sockaddr_in SOCKADDR_IN;
#endif
#ifdef WIN32
#include <windows.h>
#include <iostream.h>
#include <winsock.h>
typedef SOCKET creosote_socket;
#endif
struct MrCreosote
{
char host[256];
int port;
creosote_socket socket;
SOCKADDR_IN serv_addr;
};
/* Declarations */
void closeMrCreosote();
int initializeMrCreosote();
void spewMrCreosote(char *msg);
#!/usr/bin/env python
# creosote.py - lightweight message passing with datagrams
# JeffBauer@bigfoot.com
import sys, socket
BUFSIZE = 1024
PORT = 7739
def spew(msg, host='localhost', port=PORT):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', 0))
s.sendto(msg, (host, port))
def bucket(port=PORT, logfile=None):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('', port))
print 'creosote bucket waiting on port: %s' % port
if logfile:
f = open(logfile, 'a+')
while 1:
data, addr = s.recvfrom(BUFSIZE)
print `data`[1:-1]
if logfile:
f.write(`data`[1:-1]+'\n')
f.flush()
class MrCreosote:
"""lightweight message passing with datagrams"""
def __init__(self, host='localhost', port=PORT):
self.host = host
self.port = port
self.client = None
self.disabled = 0
self.redirect_server = None
self.redirect_client = None
def bucket(self, logfile=None):
bucket(self.port, logfile)
def redirector(self, host, port=PORT):
if self.disabled:
return
if self.redirect_server == None:
self.redirect_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.redirect_server.bind(('', self.port))
if self.redirect_client == None:
self.redirect_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.redirect_client.bind(('', 0))
while 1:
data, addr = self.redirect_server.recvfrom(BUFSIZE)
self.redirect_client.sendto(data, (host, port))
def spew(self, msg):
if self.disabled:
return
if self.client == None:
self.client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.client.bind(('', 0))
self.client.sendto(msg, (self.host, self.port))
if __name__ == '__main__':
"""usage: creosote [message]"""
if len(sys.argv) < 2:
bucket()
else:
from string import joinfields
spew(joinfields(sys.argv[1:],' '))
README notes for Persistent CGI - version 2.0 alpha 4
What it is?
Persistent CGI is an architecture designed by Zope Corporation
http://www.zope.com to publish web objects as long-running
processes. The pcgi component is an integral part of ZC's
Zope product, but is also provided to web developers
under open software terms. Please review the copyright appearing
in the source code for full details.
How to build?
Unix:
./configure
make
make install <-- only copies the binary, not the .py modules
Win32:
cd Win32
nmake /f Makefile.nt
A Win32 binary (pcgi-wrapper.exe) is included with the source
distribution.
How to use?
See the HOWTO section in notes I have published:
http://starship.skyport.net/crew/jbauer/persistcgi/
How to get help?
Subscribe to the Zope mailing list: zope@zope.org
Contact me: jeffbauer@bigfoot.com
Have fun.
-Jeff
README.parseinfo - JeffBauer@bigfoot.com - May 21, 1998
parseinfo is an executable to test the parsing the pcgi
info file. Although pcgifile.py can be used to test
how the pcgi-wrapper is expected to react "in vitro"
(i.e. as a CGI process) the parseinfo program actually
runs the info file through the parser code (although
it performs no further environment testing).
usage: parseinfo <pcgi-info-file>
sample output:
r->sw_info /export/home/jbauer/tmp/pcgiinfo
r->sw_name
r->sw_home
r->sw_exe /usr/local/bin/python
r->procpath /export/home/jbauer/var/pcgitime.pid
r->sockpath /export/home/jbauer/var/pcgitime.socket
r->modpath /export/home/jbauer/www/cgi-bin/pcgitime.py
r->pubpath /export/home/jbauer/www/cgi-bin/pcgi_publisher.py
r->procid 0
r->insertPath
r->pythonPath .:/usr/local/lib/python1.5:/var/share/s0/python
CloseFileDescriptors 0
pcgifile.py - JeffBauer@bigfoot.com - May 21, 1998
The pcgifile.py is a sanity tester for pcgi info files and
can be run as a stand-alone program or a CGI script. For
more information, refer to:
http://starship.skyport.net/crew/jbauer/persistcgi/pcgifile/
#!/usr/bin/env python
# killpcgi.py - kill a running pcgi process
# Copyright(c) 1998, Jeff Bauer, All rights reserved.
# killpcgi is a convenience script to kill a running
# pcgi process, provided that it is running on a
# Unix system. You pass it the path of the pcgi info
# file, and killpcgi will kill the running process and
# remove the socket/pid files.
#
# killpcgi has been built at the request of several users,
# but you may want to first examine the script and modify it
# to suit your environment.
#
# Bugs: skimpy error handling
# 0.3a minor win32 exception caught
# 0.2a Added support for NT - 8/8/98
# 0.1a Initial version
__version__ = "0.3a"
def win32_kill(pid):
"""posix-style kill command for the Win32 environment"""
import win32api, pywintypes
try:
handle = win32api.OpenProcess(1, 0, pid)
except pywintypes.error:
return -1
return (0 != win32api.TerminateProcess(handle, 0))
def killpcgi(pcgiInfoFile):
import os, sys, string
delimiter = '='
pidFile = None
socketFile = None
infoFile = open(pcgiInfoFile, 'r')
for i in infoFile.readlines():
if delimiter in i:
n,v = string.split(string.strip(i), delimiter)
if n == 'PCGI_PID_FILE':
pidFile = v
elif n == 'PCGI_SOCKET_FILE':
socketFile = v
infoFile.close()
if pidFile is None:
print "unknown pid file"
else:
f = open(pidFile)
pid = int(f.read())
f.close()
if os.name == 'nt':
if not win32_kill(pid):
print "process %d killed" % pid
elif os.name == 'posix':
if os.kill(pid, 0):
print "process %d doesn't appear to be running" % pid
else:
# safety measure (exclude it if you're fearless)
if os.system('/bin/ps -p %d | grep python > /dev/null' % pid):
print "process %d doesn't appear to be python" % pid
else:
os.kill(pid, 15)
print "process %d killed" % pid
# conservative approach: don't remove pid/socket files
# unless we're reasonably certain we have killed the
# running process
os.unlink(pidFile)
if socketFile is not None:
os.unlink(socketFile)
else:
print "kill not supported for platform:", os.name
if __name__ == '__main__':
import sys
usage = "usage: killpcgi pcgi-info-file"
if len(sys.argv) < 2:
print usage
else:
killpcgi(sys.argv[1])
#!/usr/local/bin/python
# pcgifile.py - pcgi info file sanity testing - jeffbauer@bigfoot.com
# Copyright(c) 1998, Jeff Bauer
# 0.6a August 9, 1998
# - added socket checking
#
# 0.5a August 7, 1998
# - added NT compatibility
# - improved import checking
#
# 0.4a July 27, 1998
# - added checks for executable permissions
# - print versions of relevant modules
__version__ = "0.6a"
Delimiter = '='
# no class-based exceptions due to 1.4 compatbility
PcgiFileException='PcgiFileException'
class PcgiFile:
def __init__(self, pcgifile):
self.pcgifile = pcgifile
self.infodict = {}
self.combined = {}
self.log = []
self.resource = []
self.file_contents = []
self.module_version = []
self.continue_testing = 1
self.pcgi_wrapper = None
try:
self.readInfoFile()
self.checkRequiredKeys()
self.checkPCGIValues()
self.lookupPCGIPublisher()
self.checkWritePermissions()
self.checkImports()
self.checkSockets()
except PcgiFileException:
self.continue_testing = 0
def checkImports(self):
try:
from cgi_module_publisher import publish_module
except ImportError:
self.log.append("error attempting: 'from cgi_module_publisher import publish_module'")
raise PcgiFileException
try:
import cgi_module_publisher, CGIResponse
self.module_version.append("%-20s %-7s %s" % \
('cgi_module_publisher',
cgi_module_publisher.__version__,
cgi_module_publisher.__file__) )
self.module_version.append("%-20s %-7s %s" % \
('CGIResponse',
CGIResponse.__version__,
CGIResponse.__file__) )
self.module_version.append("%-20s %-7s %s" %
('pcgifile',
__version__,
sys.argv[0]) )
self.module_version.append("%-20s %-7s %s" % \
('pcgi-wrapper',
self.getPcgiWrapperVersion(),
self.pcgi_wrapper))
except ImportError:
pass
except NameError:
pass
try:
import pcgi_publisher
except ImportError:
if self.combined.has_key('PCGI_PUBLISHER'):
d, s = os.path.split(self.combined['PCGI_PUBLISHER'])
if not d in sys.path:
sys.path.append(d)
try:
import pcgi_publisher
self.module_version.append("%-20s %-7s %s" % \
('pcgi_publisher',
pcgi_publisher.__version__,
pcgi_publisher.__file__))
except ImportError:
pass
except NameError:
pass
def checkPCGIValues(self):
if self.combined.has_key('PCGI_EXE'):
sw_exe = self.combined['PCGI_EXE']
else:
sw_exe = sys.executable
self.log.append("advisory recommendation: specify PCGI_EXE=%s" % \
sys.executable)
if os.path.isfile(sw_exe):
self.resource.append("Executable:\t%s" % sw_exe)
else:
self.log.append("executable not found: %s" % sw_exe)
raise PcgiFileException
if self.combined.has_key('PCGI_PID_FILE'):
f = self.combined['PCGI_PID_FILE']
d = os.path.split(f)[0]
if os.path.isdir(d):
self.resource.append("PID file:\t%s" % f)
else:
self.log.append("directory not found: %s" % d)
raise PcgiFileException
if self.combined.has_key('PCGI_SOCKET_FILE'):
f = self.combined['PCGI_SOCKET_FILE']
d = os.path.split(f)[0]
if os.path.isdir(d):
self.resource.append("Socket file:\t%s" % f)
else:
self.log.append("directory not found: %s" % d)
raise PcgiFileException
if not self.combined.has_key('PCGI_NAME'):
self.log.append("advisory recommendation: specify PCGI_NAME")
if self.combined.has_key('PCGI_MODULE_PATH'):
p = self.combined['PCGI_MODULE_PATH']
if os.path.isfile(p):
self.resource.append("Module:\t%s" % p)
else:
self.log.append("module not found: %s" % p)
raise PcgiFileException
if self.combined.has_key('PCGI_ERROR_LOG'):
self.resource.append("Error Log:\t%s" % \
self.combined['PCGI_ERROR_LOG'])
if self.combined.has_key('PCGI_WORKING_DIR'): # deprecated
d = self.combined['PCGI_WORKING_DIR']
if os.path.isfile(d):
self.resource.append("Working Directory:\t%s" % d)
else:
self.log.append("working directory not found: %s" % d)
raise PcgiFileException
def checkRequiredKeys(self):
"""
Check for the required PCGI keys.
"""
for (k,v) in os.environ.items():
self.combined[k] = v
for (k,v) in self.infodict.items():
if self.combined.has_key(k):
self.log.append("%s=%s, overwrites: %s" % (k, v, self.combined[k]))
self.combined[k] = v
for k in ['PCGI_PID_FILE','PCGI_SOCKET_FILE','PCGI_MODULE_PATH']:
if not self.combined.has_key(k):
self.log.append("missing parameter: %s" % k)
raise PcgiFileException
# PCGI_INFO_FILE is assigned by the pcgi-wrapper, so that it
# may be known (made available) to pcgi_publisher.
self.combined['PCGI_INFO_FILE'] = self.pcgifile
def checkSockets(self):
"""
Check for possible socket-related error conditions.
"""
try:
import socket
except ImportError:
self.log.append("unable to import socket module")
raise PcgiFileException
port = None
if self.combined.has_key('PCGI_PORT'):
try:
port = string.atoi(self.combined['PCGI_PORT'])
except ValueError:
self.log.append("invalid port '%s', PCGI_PORT must be an integer" % self.combined['PCGI_PORT'])
raise PcgiFileException
if os.name == 'posix':
if port:
self.log.append("cannot specify PCGI_PORT directive on Unix - no support for INET sockets")
raise PcgiFileException
elif not port:
self.log.append("win32 platform must specify missing PCGI_PORT directive (default=7244)");
raise PcgiFileException
if port:
if self.combined.has_key('PCGI_HOST'):
hostname = self.combined['PCGI_HOST']
if hostname != socket.gethostname():
self.log.append("advisory recommendation: PCGI_HOST '%s' doesn't match '%s'" % (hostname, socket.gethostname()))
else:
hostname = socket.gethostname()
if port:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((hostname, port))
except socket.error:
self.log.append("error creating/binding INET socket (%s, %s)" % (hostname, port))
raise PcgiFileException
else:
try:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
except socket.error:
self.log.append("error creating UNIX socket")
raise PcgiFileException
socketFile = self.combined.get('PCGI_SOCKET_FILE')
if os.path.exists(socketFile):
self.log.append("advisory: socket %s in use, bind() not tested" % socketFile)
else:
try:
sock.bind(socketFile)
os.unlink(socketFile)
except socket.error:
self.log.append("error binding UNIX socket (%s)" % socketFile)
raise PcgiFileException
def checkWritePermissions(self):
"""
Check write permissions for PCGI_SOCKET_FILE, PCGI_PID_FILE, and
(if specified) PCGI_ERROR_LOG.
"""
fn = {}
if self.combined.has_key('PCGI_PID_FILE'):
fn['PCGI_PID_FILE'] = self.combined['PCGI_PID_FILE']
if self.combined.has_key('PCGI_SOCKET_FILE'):
fn['PCGI_SOCKET_FILE'] = self.combined['PCGI_SOCKET_FILE']
if self.combined.has_key('PCGI_ERROR_LOG'):
fn['PCGI_ERROR_LOG'] = self.combined['PCGI_ERROR_LOG']
for key, file in fn.items():
if os.path.exists(file):
try:
f = open(file,'a+')
f.close()
except IOError:
self.log.append("%s write permission error: %s" % \
(key, file))
raise PcgiFileException
else:
path = os.path.split(file)[0]
import tempfile
tempfile.tempdir = path
tmpfile = tempfile.mktemp()
try:
f = open(tmpfile,'w+')
f.close()
os.unlink(tmpfile)
except IOError:
self.log.append("%s write permission error: %s" % \
(key, file))
raise PcgiFileException
def environList(self):
"""
return a sorted list of how the environment would likely appear
if run through the pcgi-wrapper.
"""
e = []
keys = self.combined.keys()
keys.sort()
for k in keys:
e.append("%s\t%s" % (k, self.combined[k]))
return e
def getPcgiWrapperVersion(self):
"""
Execute pcgi-wrapper with no arguments and grab the version id.
"""
try:
import tempfile
tmpfile = tempfile.mktemp()
os.system("%s > %s" % (self.pcgi_wrapper, tmpfile))
f = open(tmpfile, 'r')
r = f.readlines()
f.close()
os.unlink(tmpfile)
for l in r:
s = string.strip(l)
if s[:21] == 'pcgi-wrapper-version ':
return string.split(s)[1]
except ImportError:
pass
return None
def isexecutable(self, path, real=None):
if os.name == 'posix':
return self.pathperm(path, real)[2]
else:
return 1
def lookupPCGIPublisher(self):
"""
The most efficient way for pcgi-wrapper to determine which
pcgi_publisher to use is for the pcgi info file to specify
it with the PCGI_PUBLISHER directive. Using the PCGI_PUBLISHER
is arguably the *best* method, as pcgi-wrapper will find it
quicker than otherwise. Still, in the interest of flexibility,
pcgi-wrapper will attempt to locate pcgi_publisher using the
following rules:
1. PCGI_PUBLISHER (*best*)
Rules 2-5, look in the paths below for files named: pcgi_publisher.py,
pcgi_publisher.pyc, pcgi_publisher.pyo, pcgi_publisher.
2. PCGI_INSERT_PATH, if available
3. PYTHONPATH, if available
4. Look in the directory of PCGI_MODULE_PATH
5. Look in the directory of the pcgi info file
"""
if self.combined.has_key('PCGI_PUBLISHER'):
p = self.combined['PCGI_PUBLISHER']
if os.path.isfile(p):
self.resource.append("Publisher:\t%s" % p)
else:
self.log.append("publisher not found: %s" % p)
raise PcgiFileException
return
self.log.append("advisory recommendation: specify PCGI_PUBLISHER")
# search through combined PCGI_INSERT_PATH + PYTHONPATH directories
searchPath = ""
if self.combined.has_key('PCGI_INSERT_PATH'):
searchPath = searchPath + self.combined['PCGI_INSERT_PATH']
if self.combined.has_key('PYTHONPATH'):
searchPath = searchPath + self.combined['PYTHONPATH']
publisherName = ['pcgi_publisher.py','pcgi_publisher.pyc','pcgi_publisher.pyo','pcgi_publisher']
for d in string.split(searchPath, ':'):
for p in publisherName:
pcgiPublisher = "%s%s%s" % (d, os.sep, p)
if os.path.isfile(pcgiPublisher):
self.resource.append("Publisher:\t%s" % pcgiPublisher)
return
# look in module directory
if self.combined.has_key('PCGI_MODULE_PATH'):
(d, x) = os.path.split(self.combined['PCGI_MODULE_PATH'])
for p in publisherName:
pcgiPublisher = "%s%s%s" % (d, os.sep, p)
if os.path.isfile(pcgiPublisher):
self.resource.append("Publisher:\t%s" % pcgiPublisher)
return
# look in pcgi info file directory
(d, x) = os.path.split(self.pcgifile)
for p in publisherName:
pcgiPublisher = "%s%s%s" % (d, os.sep, p)
if os.path.isfile(pcgiPublisher):
self.resource.append("Publisher:\t%s" % pcgiPublisher)
return
self.log.append("Unable to locate the pcgi_publisher")
raise PcgiFileException
def pathperm(self, path, real=None):
"""
Returns a 3-tuple of booleans indicating whether the process has
(read, write, execute) permission. A true value for the 'real'
argument indicates the test should occur for the real id rather
than the effective id.
"""
stat = os.stat(path)
if real is None:
uid = os.geteuid()
gid = os.getegid()
else:
uid = os.getuid()
gid = os.getgid()
if uid == stat[4]:
return (00400 & stat[0], 00200 & stat[0], 00100 & stat[0])
elif gid == stat[5]:
return (00040 & stat[0], 00020 & stat[0], 00010 & stat[0])
else:
return (00004 & stat[0], 00002 & stat[0], 00001 & stat[0])
def readInfoFile(self):
max_directives = 12 # arbitrary number defined in pcgi.h
if not os.path.isfile(self.pcgifile):
self.log.append("unable to locate file: %s" % self.pcgifile)
raise PcgiFileException
elif not self.isexecutable(self.pcgifile):
self.log.append("info file '%s' not executable" % self.pcgifile)
raise PcgiFileException
f = open(self.pcgifile, 'r')
lc = 0
for r in f.readlines():
lc = lc + 1
s = string.strip(r)
self.file_contents.append(s)
if lc == 1:
if s[:2] != '#!':
self.log.append("first line missing header, e.g. #!/usr/local/bin/pcgi-wrapper")
raise PcgiFileException
else:
self.pcgi_wrapper = string.strip(s[2:])
if not os.path.isfile(self.pcgi_wrapper):
self.log.append("unable to find wrapper: %s" % \
self.pcgi_wrapper)
raise PcgiFileException
elif not self.isexecutable(self.pcgi_wrapper):
self.log.append("wrapper '%s' is not executable" % \
self.pcgi_wrapper)
raise PcgiFileException
if len(s) < 1 or s[0] == '#':
continue
pos = string.find(s, Delimiter)
if pos < 0:
self.log.append("missing '%s' delimiter at line %d: %s" % \
(Delimiter, lc, s))
else:
self.infodict[string.strip(s[0:pos])] = string.strip(s[pos+1:])
f.close()
if len(self.infodict.keys()) > max_directives:
self.log.append("info fileexceeds maximum (%d) number of directives" % max_directives)
raise PcgiFileException
class PcgiFileTest:
"""
CGI sanity check of the pcgi info file.
"""
def __init__(self):
fs = cgi.FieldStorage()
infofile = None
if fs.has_key('infofile'):
infofile = fs['infofile'].value
elif fs.has_key('filename'):
infofile = fs['filename'].value
if infofile is None:
print "Please specify the pcgi info file in the following manner:"
print "<pre>"
print " http://.../cgi-bin/pcgifile.py?<STRONG>infofile=</STRONG><I>pcgifile</I>"
print "</pre>"
print "where <I>pcgifile</I> is the absolute path of the pcgi info file."
else:
print "<pre>"
print "<strong>Python %s</strong>" % sys.version
if os.environ.has_key('SERVER_SOFTWARE'):
print "<strong>%s</strong>" % os.environ['SERVER_SOFTWARE']
print
print "PCGI info file:\t%s" % infofile
pcgiFile = PcgiFile(infofile)
print "PCGI wrapper:\t%s" % pcgiFile.pcgi_wrapper
for m in pcgiFile.log:
print m
if not pcgiFile.continue_testing:
print "status: FAILURE"
print
print "<STRONG>%s</STRONG>" % infofile
for r in pcgiFile.file_contents:
print " %s" % r
else:
print "looks OK"
print
print "<STRONG>%s</STRONG>" % infofile
for r in pcgiFile.file_contents:
print " %s" % r
print
print "<STRONG>Likely publisher resource values:</STRONG>"
for r in pcgiFile.resource:
print " %s" % r
print
print "<STRONG>Versions of modules used:</STRONG>"
for r in pcgiFile.module_version:
print " %s" % r
print
print "<STRONG>Resulting environment will probably appear to the publisher as:</STRONG>"
for e in pcgiFile.environList():
print " %s" % e
def test():
usage = 'usage: pcgifile pcgi_info_file'
if len(sys.argv) < 2:
print usage
sys.exit(1)
infoFile = sys.argv[1]
pcgiFile = PcgiFile(infoFile)
for m in pcgiFile.log:
print m
if pcgiFile.continue_testing:
print "%s looks OK" % infoFile
if __name__ == '__main__':
try:
import cgi, os, sys, string, traceback
if os.environ.has_key('SERVER_PROTOCOL'):
print "Content-type: text/html"
print "Expires: Monday, 1-Jan-96 00:00:00 GMT"
print "Pragma: no-cache"
print
sys.stderr = sys.stdout
try:
pcgiFileTest = PcgiFileTest()
except:
print "<pre>"
traceback.print_exc()
else:
test()
except ImportError:
print "Content-type: text/html"
print
print "error during python imports; to fix try adding to pcgifile.py: <br><pre>"
print " sys.path[0:0] = [path1, path2, ...]"
# Makefile.nt
VERSION = 2.0a4
CC = cl
CFLAGS = /W3 /DWIN32 /I..
LIBS = wsock32.lib
SRCDIR= ..
CREOSOTE_DIR = $(SRCDIR)/MrCreosote
CORE = $(SRCDIR)/pcgi.h #parseinfo.c
.c.obj:
$(CC) /c $(CFLAGS) $*.c
all: pcgi-wrapper.exe parseinfo.exe creosote.obj
creosote.obj: $(CREOSOTE_DIR)/creosote.c $(CREOSOTE_DIR)/creosote.h
$(CC) /c $(CFLAGS) /I$(CREOSOTE_DIR) /Focreosote.obj $(CREOSOTE_DIR)/creosote.c
parseinfo1.obj: $(SRCDIR)/parseinfo.c $(CORE)
$(CC) /c $(CFLAGS) /DMAIN_PARSEINFO /Foparseinfo1.obj $(SRCDIR)/parseinfo.c
parseinfo2.obj: $(SRCDIR)/parseinfo.c $(CORE)
$(CC) /c $(CFLAGS) $(SRCDIR)/parseinfo.c /Foparseinfo2.obj
pcgi-wrapper1.obj: $(SRCDIR)/pcgi-wrapper.c $(CORE)
$(CC) /c $(CFLAGS) /I$(CREOSOTE_DIR) /DPCGI_WRAPPER_MAIN /DCREOSOTE /DVERSION=\"$(VERSION)\" /Fopcgi-wrapper1.obj $(SRCDIR)/pcgi-wrapper.c
pcgi-wrapper2.obj: $(SRCDIR)/pcgi-wrapper.c $(CORE)
$(CC) /c $(CFLAGS) /I$(CREOSOTE_DIR) /DCREOSOTE /Fopcgi-wrapper2.obj $(SRCDIR)/pcgi-wrapper.c
parseinfo.exe: parseinfo1.obj pcgi-wrapper2.obj creosote.obj
link /OUT:parseinfo.exe parseinfo1.obj pcgi-wrapper2.obj creosote.obj $(LIBS)
pcgi-wrapper.exe: pcgi-wrapper1.obj parseinfo2.obj creosote.obj
link /OUT:pcgi-wrapper.exe pcgi-wrapper1.obj parseinfo2.obj creosote.obj $(LIBS)
README.NT - one day this will grow up and become a real README file.
PCGI 2.0a4 Win32 binary release (alpha 4) August 10, 1998
contact: jeffbauer@bigfoot.com
What is this?
The collection of files below is the first Win32
release of PCGI, the Persistent CGI wrapper for
Bobo applications. For more information about Bobo,
go to Digital Creations site: http://www.digicool.com
Files (in relative order of importance):
pcgi-wrapper.exe - the main program
pcgi_publisher.py - modified to handle both Unix & Win32
pcgifile.py - indispensible for tracking down problems
pcgitime.py - sample module
pcgitest - sample PCGI info file
killpcgi.py - handy for killing the running process
parseinfo.exe - used only when necessary (to view the pcgi
info file the way pcgi-wrapper sees it)
For information about Persistent CGI, check out:
http://starship.skyport.net/crew/jbauer/persistcgi/
(This information may soon move over to www.digicool.com)
Platforms tested?
Apache/Win32 1.3.1 running on NT 4.0. However, it should
run on any Win32 platform running a server supporting http.
Basic checklist to get the sample application up and running:
0. Install Python, Bobo, and a web server on your machine.
If you haven't got these things already working, please
see my notes on the subject:
http://starship.skyport.net/crew/jbauer/apachenotes/
1. Put pcgi-wrapper.exe where you normally place your
binary executables, or in cgi-bin.
2. Put pcgi_publisher.py in a directory where you normally
put your .py scripts -- cgi-bin is okay, but you will
specify the path in your info file, regardless.
3. Put pcgitest & pcgitime.py in cgi-bin. You will have
to modify the first #! she-bang line in pcgitest to
match the path of where you put pcgi-wrapper.exe. Also,
all directives must match your environment -- the examples
included are for illustration purposes only. Please
read the online (URL above) PCGI documentation for
further information.
4. Run your setup against pcgifile.py, a sanity check
described in:
http://starship.skyport.net/crew/jbauer/persistcgi/pcgifile/
http://starship.skyport.net/crew/jbauer/persistcgi/howto
5. Give me feedback, please: jeffbauer@bigfoot.com
-------------------
Microsoft IIS Notes:
Amos Latteier notes that some web servers, notably Microsoft's IIS,
cannot deal with the first line in a CGI program like Apache:
#!C:\WINNT\system32\pcgi-wrapper.exe
The solution is to use a .pcgi extension for your info file and create
a file association between .pcgi and pcgi-wrapper.exe with an IIS script
map registry entry, e.g.:
.pcgi C:\winnt\system32\pcgi-wrapper.exe %s
Now info files with the .pcgi extension will execute as cgi
programs.
[Amos further notes in a posting to the Bobo list:]
IIS 4 by default sends a custom 404 error message which masks
Bobo's 404 error information. This effectively keeps you from
seeing what Bobo is trying to tell you about why it is not
publishing your object. To get rid of this annoyance go to
the web site properties dialog in the Microsoft Management
Console application. Click on the "Custom Errors" tab. Choose
the 404 error and change it to use "Default" error message.
Voila, you're back in business, and can read Bobo information in
the source of your 404 error messages now.
/* config.h.in. Generated automatically from configure.in by autoheader. */
/* Define to empty if the keyword does not work. */
#undef const
/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
/* Define to `int' if <sys/types.h> doesn't define. */
#undef pid_t
/* Define as the return type of signal handlers (int or void). */
#undef RETSIGTYPE
/* Define if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define if you have the putenv function. */
#undef HAVE_PUTENV
/* Define if you have the socket function. */
#undef HAVE_SOCKET
/* Define if you have the strerror function. */
#undef HAVE_STRERROR
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated automatically using autoconf version 2.12
# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
#
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
# Defaults:
ac_help=
ac_default_prefix=/usr/local
# Any additions from configure.in:
# Initialize some variables set by options.
# The variables have the same names as the options, with
# dashes changed to underlines.
build=NONE
cache_file=./config.cache
exec_prefix=NONE
host=NONE
no_create=
nonopt=NONE
no_recursion=
prefix=NONE
program_prefix=NONE
program_suffix=NONE
program_transform_name=s,x,x,
silent=
site=
srcdir=
target=NONE
verbose=
x_includes=NONE
x_libraries=NONE
bindir='${exec_prefix}/bin'
sbindir='${exec_prefix}/sbin'
libexecdir='${exec_prefix}/libexec'
datadir='${prefix}/share'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
libdir='${exec_prefix}/lib'
includedir='${prefix}/include'
oldincludedir='/usr/include'
infodir='${prefix}/info'
mandir='${prefix}/man'
# Initialize some other variables.
subdirs=
MFLAGS= MAKEFLAGS=
# Maximum number of lines to put in a shell here document.
ac_max_here_lines=12
ac_prev=
for ac_option
do
# If the previous option needs an argument, assign it.
if test -n "$ac_prev"; then
eval "$ac_prev=\$ac_option"
ac_prev=
continue
fi
case "$ac_option" in
-*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) ac_optarg= ;;
esac
# Accept the important Cygnus configure options, so we can diagnose typos.
case "$ac_option" in
-bindir | --bindir | --bindi | --bind | --bin | --bi)
ac_prev=bindir ;;
-bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
bindir="$ac_optarg" ;;
-build | --build | --buil | --bui | --bu)
ac_prev=build ;;
-build=* | --build=* | --buil=* | --bui=* | --bu=*)
build="$ac_optarg" ;;
-cache-file | --cache-file | --cache-fil | --cache-fi \
| --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
ac_prev=cache_file ;;
-cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
| --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
cache_file="$ac_optarg" ;;
-datadir | --datadir | --datadi | --datad | --data | --dat | --da)
ac_prev=datadir ;;
-datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
| --da=*)
datadir="$ac_optarg" ;;
-disable-* | --disable-*)
ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
# Reject names that are not valid shell variable names.
if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
{ echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
fi
ac_feature=`echo $ac_feature| sed 's/-/_/g'`
eval "enable_${ac_feature}=no" ;;
-enable-* | --enable-*)
ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
# Reject names that are not valid shell variable names.
if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
{ echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
fi
ac_feature=`echo $ac_feature| sed 's/-/_/g'`
case "$ac_option" in
*=*) ;;
*) ac_optarg=yes ;;
esac
eval "enable_${ac_feature}='$ac_optarg'" ;;
-exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
| --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
| --exec | --exe | --ex)
ac_prev=exec_prefix ;;
-exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
| --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
| --exec=* | --exe=* | --ex=*)
exec_prefix="$ac_optarg" ;;
-gas | --gas | --ga | --g)
# Obsolete; use --with-gas.
with_gas=yes ;;
-help | --help | --hel | --he)
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat << EOF
Usage: configure [options] [host]
Options: [defaults in brackets after descriptions]
Configuration:
--cache-file=FILE cache test results in FILE
--help print this message
--no-create do not create output files
--quiet, --silent do not print \`checking...' messages
--version print the version of autoconf that created configure
Directory and file names:
--prefix=PREFIX install architecture-independent files in PREFIX
[$ac_default_prefix]
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
[same as prefix]
--bindir=DIR user executables in DIR [EPREFIX/bin]
--sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
--libexecdir=DIR program executables in DIR [EPREFIX/libexec]
--datadir=DIR read-only architecture-independent data in DIR
[PREFIX/share]
--sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data in DIR
[PREFIX/com]
--localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
--libdir=DIR object code libraries in DIR [EPREFIX/lib]
--includedir=DIR C header files in DIR [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
--infodir=DIR info documentation in DIR [PREFIX/info]
--mandir=DIR man documentation in DIR [PREFIX/man]
--srcdir=DIR find the sources in DIR [configure dir or ..]
--program-prefix=PREFIX prepend PREFIX to installed program names
--program-suffix=SUFFIX append SUFFIX to installed program names
--program-transform-name=PROGRAM
run sed PROGRAM on installed program names
EOF
cat << EOF
Host type:
--build=BUILD configure for building on BUILD [BUILD=HOST]
--host=HOST configure for HOST [guessed]
--target=TARGET configure for TARGET [TARGET=HOST]
Features and packages:
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--x-includes=DIR X include files are in DIR
--x-libraries=DIR X library files are in DIR
EOF
if test -n "$ac_help"; then
echo "--enable and --with options recognized:$ac_help"
fi
exit 0 ;;
-host | --host | --hos | --ho)
ac_prev=host ;;
-host=* | --host=* | --hos=* | --ho=*)
host="$ac_optarg" ;;
-includedir | --includedir | --includedi | --included | --include \
| --includ | --inclu | --incl | --inc)
ac_prev=includedir ;;
-includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
| --includ=* | --inclu=* | --incl=* | --inc=*)
includedir="$ac_optarg" ;;
-infodir | --infodir | --infodi | --infod | --info | --inf)
ac_prev=infodir ;;
-infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
infodir="$ac_optarg" ;;
-libdir | --libdir | --libdi | --libd)
ac_prev=libdir ;;
-libdir=* | --libdir=* | --libdi=* | --libd=*)
libdir="$ac_optarg" ;;
-libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
| --libexe | --libex | --libe)
ac_prev=libexecdir ;;
-libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
| --libexe=* | --libex=* | --libe=*)
libexecdir="$ac_optarg" ;;
-localstatedir | --localstatedir | --localstatedi | --localstated \
| --localstate | --localstat | --localsta | --localst \
| --locals | --local | --loca | --loc | --lo)
ac_prev=localstatedir ;;
-localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
| --localstate=* | --localstat=* | --localsta=* | --localst=* \
| --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
localstatedir="$ac_optarg" ;;
-mandir | --mandir | --mandi | --mand | --man | --ma | --m)
ac_prev=mandir ;;
-mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
mandir="$ac_optarg" ;;
-nfp | --nfp | --nf)
# Obsolete; use --without-fp.
with_fp=no ;;
-no-create | --no-create | --no-creat | --no-crea | --no-cre \
| --no-cr | --no-c)
no_create=yes ;;
-no-recursion | --no-recursion | --no-recursio | --no-recursi \
| --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
no_recursion=yes ;;
-oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
| --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
| --oldin | --oldi | --old | --ol | --o)
ac_prev=oldincludedir ;;
-oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
| --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
| --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
oldincludedir="$ac_optarg" ;;
-prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
ac_prev=prefix ;;
-prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
prefix="$ac_optarg" ;;
-program-prefix | --program-prefix | --program-prefi | --program-pref \
| --program-pre | --program-pr | --program-p)
ac_prev=program_prefix ;;
-program-prefix=* | --program-prefix=* | --program-prefi=* \
| --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
program_prefix="$ac_optarg" ;;
-program-suffix | --program-suffix | --program-suffi | --program-suff \
| --program-suf | --program-su | --program-s)
ac_prev=program_suffix ;;
-program-suffix=* | --program-suffix=* | --program-suffi=* \
| --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
program_suffix="$ac_optarg" ;;
-program-transform-name | --program-transform-name \
| --program-transform-nam | --program-transform-na \
| --program-transform-n | --program-transform- \
| --program-transform | --program-transfor \
| --program-transfo | --program-transf \
| --program-trans | --program-tran \
| --progr-tra | --program-tr | --program-t)
ac_prev=program_transform_name ;;
-program-transform-name=* | --program-transform-name=* \
| --program-transform-nam=* | --program-transform-na=* \
| --program-transform-n=* | --program-transform-=* \
| --program-transform=* | --program-transfor=* \
| --program-transfo=* | --program-transf=* \
| --program-trans=* | --program-tran=* \
| --progr-tra=* | --program-tr=* | --program-t=*)
program_transform_name="$ac_optarg" ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
| --sbi=* | --sb=*)
sbindir="$ac_optarg" ;;
-sharedstatedir | --sharedstatedir | --sharedstatedi \
| --sharedstated | --sharedstate | --sharedstat | --sharedsta \
| --sharedst | --shareds | --shared | --share | --shar \
| --sha | --sh)
ac_prev=sharedstatedir ;;
-sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
| --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
| --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
| --sha=* | --sh=*)
sharedstatedir="$ac_optarg" ;;
-site | --site | --sit)
ac_prev=site ;;
-site=* | --site=* | --sit=*)
site="$ac_optarg" ;;
-srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
ac_prev=srcdir ;;
-srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
srcdir="$ac_optarg" ;;
-sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
| --syscon | --sysco | --sysc | --sys | --sy)
ac_prev=sysconfdir ;;
-sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
| --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
sysconfdir="$ac_optarg" ;;
-target | --target | --targe | --targ | --tar | --ta | --t)
ac_prev=target ;;
-target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
target="$ac_optarg" ;;
-v | -verbose | --verbose | --verbos | --verbo | --verb)
verbose=yes ;;
-version | --version | --versio | --versi | --vers)
echo "configure generated by autoconf version 2.12"
exit 0 ;;
-with-* | --with-*)
ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
# Reject names that are not valid shell variable names.
if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
{ echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
fi
ac_package=`echo $ac_package| sed 's/-/_/g'`
case "$ac_option" in
*=*) ;;
*) ac_optarg=yes ;;
esac
eval "with_${ac_package}='$ac_optarg'" ;;
-without-* | --without-*)
ac_package=`echo $ac_option|sed -e 's/-*without-//'`
# Reject names that are not valid shell variable names.
if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
{ echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
fi
ac_package=`echo $ac_package| sed 's/-/_/g'`
eval "with_${ac_package}=no" ;;
--x)
# Obsolete; use --with-x.
with_x=yes ;;
-x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
| --x-incl | --x-inc | --x-in | --x-i)
ac_prev=x_includes ;;
-x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
| --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
x_includes="$ac_optarg" ;;
-x-libraries | --x-libraries | --x-librarie | --x-librari \
| --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
ac_prev=x_libraries ;;
-x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
| --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
x_libraries="$ac_optarg" ;;
-*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
;;
*)
if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
echo "configure: warning: $ac_option: invalid host type" 1>&2
fi
if test "x$nonopt" != xNONE; then
{ echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
fi
nonopt="$ac_option"
;;
esac
done
if test -n "$ac_prev"; then
{ echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
fi
trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
# File descriptor usage:
# 0 standard input
# 1 file creation
# 2 errors and warnings
# 3 some systems may open it to /dev/tty
# 4 used on the Kubota Titan
# 6 checking for... messages and results
# 5 compiler messages saved in config.log
if test "$silent" = yes; then
exec 6>/dev/null
else
exec 6>&1
fi
exec 5>./config.log
echo "\
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
" 1>&5
# Strip out --no-create and --no-recursion so they do not pile up.
# Also quote any args containing shell metacharacters.
ac_configure_args=
for ac_arg
do
case "$ac_arg" in
-no-create | --no-create | --no-creat | --no-crea | --no-cre \
| --no-cr | --no-c) ;;
-no-recursion | --no-recursion | --no-recursio | --no-recursi \
| --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
*" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
ac_configure_args="$ac_configure_args '$ac_arg'" ;;
*) ac_configure_args="$ac_configure_args $ac_arg" ;;
esac
done
# NLS nuisances.
# Only set these to C if already set. These must not be set unconditionally
# because not all systems understand e.g. LANG=C (notably SCO).
# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
# Non-C LC_CTYPE values break the ctype check.
if test "${LANG+set}" = set; then LANG=C; export LANG; fi
if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -rf conftest* confdefs.h
# AIX cpp loses on an empty file, so make sure it contains at least a newline.
echo > confdefs.h
# A filename unique to this package, relative to the directory that
# configure is in, which we can look for to find out if srcdir is correct.
ac_unique_file=pcgi.h
# Find the source files, if location was not specified.
if test -z "$srcdir"; then
ac_srcdir_defaulted=yes
# Try the directory containing this script, then its parent.
ac_prog=$0
ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
srcdir=$ac_confdir
if test ! -r $srcdir/$ac_unique_file; then
srcdir=..
fi
else
ac_srcdir_defaulted=no
fi
if test ! -r $srcdir/$ac_unique_file; then
if test "$ac_srcdir_defaulted" = yes; then
{ echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
else
{ echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
fi
fi
srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
# Prefer explicitly selected file to automatically selected ones.
if test -z "$CONFIG_SITE"; then
if test "x$prefix" != xNONE; then
CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
else
CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
fi
fi
for ac_site_file in $CONFIG_SITE; do
if test -r "$ac_site_file"; then
echo "loading site script $ac_site_file"
. "$ac_site_file"
fi
done
if test -r "$cache_file"; then
echo "loading cache $cache_file"
. $cache_file
else
echo "creating cache $cache_file"
> $cache_file
fi
ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
ac_cpp='$CPP $CPPFLAGS'
ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
cross_compiling=$ac_cv_prog_cc_cross
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
# Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
ac_n= ac_c='
' ac_t=' '
else
ac_n=-n ac_c= ac_t=
fi
else
ac_n= ac_c='\c' ac_t=
fi
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:525: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
for ac_dir in $PATH; do
test -z "$ac_dir" && ac_dir=.
if test -f $ac_dir/$ac_word; then
ac_cv_prog_CC="gcc"
break
fi
done
IFS="$ac_save_ifs"
fi
fi
CC="$ac_cv_prog_CC"
if test -n "$CC"; then
echo "$ac_t""$CC" 1>&6
else
echo "$ac_t""no" 1>&6
fi
if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:554: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
ac_prog_rejected=no
for ac_dir in $PATH; do
test -z "$ac_dir" && ac_dir=.
if test -f $ac_dir/$ac_word; then
if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
ac_prog_rejected=yes
continue
fi
ac_cv_prog_CC="cc"
break
fi
done
IFS="$ac_save_ifs"
if test $ac_prog_rejected = yes; then
# We found a bogon in the path, so make sure we never use it.
set dummy $ac_cv_prog_CC
shift
if test $# -gt 0; then
# We chose a different compiler from the bogus one.
# However, it has the same basename, so the bogon will be chosen
# first if we set CC to just the basename; use the full file name.
shift
set dummy "$ac_dir/$ac_word" "$@"
shift
ac_cv_prog_CC="$@"
fi
fi
fi
fi
CC="$ac_cv_prog_CC"
if test -n "$CC"; then
echo "$ac_t""$CC" 1>&6
else
echo "$ac_t""no" 1>&6
fi
test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
echo "configure:602: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
ac_cpp='$CPP $CPPFLAGS'
ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
cross_compiling=$ac_cv_prog_cc_cross
cat > conftest.$ac_ext <<EOF
#line 612 "configure"
#include "confdefs.h"
main(){return(0);}
EOF
if { (eval echo configure:616: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
ac_cv_prog_cc_works=yes
# If we can't run a trivial program, we are probably using a cross compiler.
if (./conftest; exit) 2>/dev/null; then
ac_cv_prog_cc_cross=no
else
ac_cv_prog_cc_cross=yes
fi
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
ac_cv_prog_cc_works=no
fi
rm -fr conftest*
echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
if test $ac_cv_prog_cc_works = no; then
{ echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
echo "configure:636: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
cross_compiling=$ac_cv_prog_cc_cross
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
echo "configure:641: checking whether we are using GNU C" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.c <<EOF
#ifdef __GNUC__
yes;
#endif
EOF
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:650: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gcc=yes
else
ac_cv_prog_gcc=no
fi
fi
echo "$ac_t""$ac_cv_prog_gcc" 1>&6
if test $ac_cv_prog_gcc = yes; then
GCC=yes
ac_test_CFLAGS="${CFLAGS+set}"
ac_save_CFLAGS="$CFLAGS"
CFLAGS=
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
echo "configure:665: checking whether ${CC-cc} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
echo 'void f(){}' > conftest.c
if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
ac_cv_prog_cc_g=yes
else
ac_cv_prog_cc_g=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
if test "$ac_test_CFLAGS" = set; then
CFLAGS="$ac_save_CFLAGS"
elif test $ac_cv_prog_cc_g = yes; then
CFLAGS="-g -O2"
else
CFLAGS="-O2"
fi
else
GCC=
test "${CFLAGS+set}" = set || CFLAGS="-g"
fi
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
echo "configure:693: checking how to run the C preprocessor" >&5
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
# This must be in double quotes, not single quotes, because CPP may get
# substituted into the Makefile and "${CC-cc}" will confuse make.
CPP="${CC-cc} -E"
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp.
cat > conftest.$ac_ext <<EOF
#line 708 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:714: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
:
else
echo "$ac_err" >&5
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
CPP="${CC-cc} -E -traditional-cpp"
cat > conftest.$ac_ext <<EOF
#line 725 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:731: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
:
else
echo "$ac_err" >&5
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
CPP=/lib/cpp
fi
rm -f conftest*
fi
rm -f conftest*
ac_cv_prog_CPP="$CPP"
fi
CPP="$ac_cv_prog_CPP"
else
ac_cv_prog_CPP="$CPP"
fi
echo "$ac_t""$CPP" 1>&6
# Set VERSION here so we only need to edit it in one place
VERSION=2.0a5
# Set name for machine-dependent library files
echo $ac_n "checking MACHDEP""... $ac_c" 1>&6
echo "configure:761: checking MACHDEP" >&5
if test -z "$MACHDEP"
then
ac_sys_system=`uname -s`
if test "$ac_sys_system" = "AIX" ; then
ac_sys_release=`uname -v`
else
ac_sys_release=`uname -r`
fi
ac_md_system=`echo $ac_sys_system | tr -d '/ ' | tr '[A-Z]' '[a-z]'`
ac_md_release=`echo $ac_sys_release | tr -d '/ ' | sed 's/\..*//'`
MACHDEP="$ac_md_system$ac_md_release"
case $MACHDEP in
'') MACHDEP="unknown";;
esac
fi
echo "$ac_t""$MACHDEP" 1>&6
case $ac_sys_system in
hp*|HP*)
case $CC in
cc|*/cc) CC="$CC -Aa -D_HPUX_SOURCE";;
esac;;
esac
if test "$ac_sys_system" != IRIX
then
echo $ac_n "checking for inet_addr in -lnsl""... $ac_c" 1>&6
echo "configure:792: checking for inet_addr in -lnsl" >&5
ac_lib_var=`echo nsl'_'inet_addr | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_save_LIBS="$LIBS"
LIBS="-lnsl $LIBS"
cat > conftest.$ac_ext <<EOF
#line 800 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char inet_addr();
int main() {
inet_addr()
; return 0; }
EOF
if { (eval echo configure:811: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=no"
fi
rm -f conftest*
LIBS="$ac_save_LIBS"
fi
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
echo "$ac_t""yes" 1>&6
LIBS="-lnsl $LIBS"
else
echo "$ac_t""no" 1>&6
fi
# SVR4
echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
echo "configure:832: checking for socket in -lsocket" >&5
ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
ac_save_LIBS="$LIBS"
LIBS="-lsocket $LIBS $LIBS"
cat > conftest.$ac_ext <<EOF
#line 840 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char socket();
int main() {
socket()
; return 0; }
EOF
if { (eval echo configure:851: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=no"
fi
rm -f conftest*
LIBS="$ac_save_LIBS"
fi
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
echo "$ac_t""yes" 1>&6
LIBS="-lsocket $LIBS"
else
echo "$ac_t""no" 1>&6
fi
# SVR4 sockets
fi
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
echo "configure:874: checking for ANSI C header files" >&5
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 879 "configure"
#include "confdefs.h"
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:887: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
ac_cv_header_stdc=yes
else
echo "$ac_err" >&5
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
#line 904 "configure"
#include "confdefs.h"
#include <string.h>
EOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "memchr" >/dev/null 2>&1; then
:
else
rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
#line 922 "configure"
#include "confdefs.h"
#include <stdlib.h>
EOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "free" >/dev/null 2>&1; then
:
else
rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
fi
if test $ac_cv_header_stdc = yes; then
# /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
if test "$cross_compiling" = yes; then
:
else
cat > conftest.$ac_ext <<EOF
#line 943 "configure"
#include "confdefs.h"
#include <ctype.h>
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
int main () { int i; for (i = 0; i < 256; i++)
if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
exit (0); }
EOF
if { (eval echo configure:954: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
then
:
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -fr conftest*
ac_cv_header_stdc=no
fi
rm -fr conftest*
fi
fi
fi
echo "$ac_t""$ac_cv_header_stdc" 1>&6
if test $ac_cv_header_stdc = yes; then
cat >> confdefs.h <<\EOF
#define STDC_HEADERS 1
EOF
fi
echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
echo "configure:978: checking for sys/wait.h that is POSIX.1 compatible" >&5
if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 983 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/wait.h>
#ifndef WEXITSTATUS
#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
#endif
#ifndef WIFEXITED
#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
#endif
int main() {
int s;
wait (&s);
s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
; return 0; }
EOF
if { (eval echo configure:999: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_header_sys_wait_h=yes
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
ac_cv_header_sys_wait_h=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
if test $ac_cv_header_sys_wait_h = yes; then
cat >> confdefs.h <<\EOF
#define HAVE_SYS_WAIT_H 1
EOF
fi
for ac_hdr in unistd.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:1023: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1028 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1033: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out`
if test -z "$ac_err"; then
rm -rf conftest*
eval "ac_cv_header_$ac_safe=yes"
else
echo "$ac_err" >&5
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
eval "ac_cv_header_$ac_safe=no"
fi
rm -f conftest*
fi
if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
echo "$ac_t""yes" 1>&6
ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
cat >> confdefs.h <<EOF
#define $ac_tr_hdr 1
EOF
else
echo "$ac_t""no" 1>&6
fi
done
echo $ac_n "checking for working const""... $ac_c" 1>&6
echo "configure:1061: checking for working const" >&5
if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1066 "configure"
#include "confdefs.h"
int main() {
/* Ultrix mips cc rejects this. */
typedef int charset[2]; const charset x;
/* SunOS 4.1.1 cc rejects this. */
char const *const *ccp;
char **p;
/* NEC SVR4.0.2 mips cc rejects this. */
struct point {int x, y;};
static struct point const zero = {0,0};
/* AIX XL C 1.02.0.0 rejects this.
It does not let you subtract one const X* pointer from another in an arm
of an if-expression whose if-part is not a constant expression */
const char *g = "string";
ccp = &g + (g ? g-g : 0);
/* HPUX 7.0 cc rejects these. */
++ccp;
p = (char**) ccp;
ccp = (char const *const *) p;
{ /* SCO 3.2v4 cc rejects this. */
char *t;
char const *s = 0 ? (char *) 0 : (char const *) 0;
*t++ = 0;
}
{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
int x[] = {25, 17};
const int *foo = &x[0];
++foo;
}
{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
typedef const int *iptr;
iptr p = 0;
++p;
}
{ /* AIX XL C 1.02.0.0 rejects this saying
"k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
struct s { int j; const int *ap[3]; };
struct s *b; b->j = 5;
}
{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
const int foo = 10;
}
; return 0; }
EOF
if { (eval echo configure:1115: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_c_const=yes
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
ac_cv_c_const=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_c_const" 1>&6
if test $ac_cv_c_const = no; then
cat >> confdefs.h <<\EOF
#define const
EOF
fi
echo $ac_n "checking for pid_t""... $ac_c" 1>&6
echo "configure:1136: checking for pid_t" >&5
if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1141 "configure"
#include "confdefs.h"
#include <sys/types.h>
#if STDC_HEADERS
#include <stdlib.h>
#include <stddef.h>
#endif
EOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
rm -rf conftest*
ac_cv_type_pid_t=yes
else
rm -rf conftest*
ac_cv_type_pid_t=no
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_type_pid_t" 1>&6
if test $ac_cv_type_pid_t = no; then
cat >> confdefs.h <<\EOF
#define pid_t int
EOF
fi
echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
echo "configure:1170: checking return type of signal handlers" >&5
if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1175 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <signal.h>
#ifdef signal
#undef signal
#endif
#ifdef __cplusplus
extern "C" void (*signal (int, void (*)(int)))(int);
#else
void (*signal ()) ();
#endif
int main() {
int i;
; return 0; }
EOF
if { (eval echo configure:1192: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_type_signal=void
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
ac_cv_type_signal=int
fi
rm -f conftest*
fi
echo "$ac_t""$ac_cv_type_signal" 1>&6
cat >> confdefs.h <<EOF
#define RETSIGTYPE $ac_cv_type_signal
EOF
for ac_func in putenv socket strerror
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
echo "configure:1213: checking for $ac_func" >&5
if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1218 "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char $ac_func(); below. */
#include <assert.h>
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
char $ac_func();
int main() {
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
choke me
#else
$ac_func();
#endif
; return 0; }
EOF
if { (eval echo configure:1241: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
eval "ac_cv_func_$ac_func=yes"
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
eval "ac_cv_func_$ac_func=no"
fi
rm -f conftest*
fi
if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
echo "$ac_t""yes" 1>&6
ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
cat >> confdefs.h <<EOF
#define $ac_tr_func 1
EOF
else
echo "$ac_t""no" 1>&6
fi
done
echo $ac_n "checking for union semun""... $ac_c" 1>&6
echo "configure:1267: checking for union semun" >&5
cat > conftest.$ac_ext <<EOF
#line 1269 "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int main() {
union semun semun;
; return 0; }
EOF
if { (eval echo configure:1278: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
rm -rf conftest*
cat >> confdefs.h <<\EOF
#define HAVE_UNION_SEMUN 1
EOF
echo "$ac_t""yes" 1>&6
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
echo "$ac_t""no" 1>&6
fi
rm -f conftest*
trap '' 1 2 15
cat > confcache <<\EOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
# scripts and configure runs. It is not useful on other systems.
# If it contains results you don't want to keep, you may remove or edit it.
#
# By default, configure uses ./config.cache as the cache file,
# creating it if it does not exist already. You can give configure
# the --cache-file=FILE option to use a different cache file; that is
# what configure does when it calls configure scripts in
# subdirectories, so they share the cache.
# Giving --cache-file=/dev/null disables caching, for debugging configure.
# config.status only pays attention to the cache file if you give it the
# --recheck option to rerun configure.
#
EOF
# The following way of writing the cache mishandles newlines in values,
# but we know of no workaround that is simple, portable, and efficient.
# So, don't put newlines in cache variables' values.
# Ultrix sh set writes to stderr and can't be redirected directly,
# and sets the high bit in the cache file unless we assign to the vars.
(set) 2>&1 |
case `(ac_space=' '; set) 2>&1` in
*ac_space=\ *)
# `set' does not quote correctly, so add quotes (double-quote substitution
# turns \\\\ into \\, and sed turns \\ into \).
sed -n \
-e "s/'/'\\\\''/g" \
-e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
;;
*)
# `set' quotes correctly as required by POSIX, so do not add quotes.
sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
;;
esac >> confcache
if cmp -s $cache_file confcache; then
:
else
if test -w $cache_file; then
echo "updating cache $cache_file"
cat confcache > $cache_file
else
echo "not updating unwritable cache $cache_file"
fi
fi
rm -f confcache
trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
# Any assignment to VPATH causes Sun make to only execute
# the first set of double-colon rules, so remove it if not needed.
# If there is a colon in the path, we need to keep it.
if test "x$srcdir" = x.; then
ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
fi
trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
# Transform confdefs.h into DEFS.
# Protect against shell expansion while executing Makefile rules.
# Protect against Makefile macro expansion.
cat > conftest.defs <<\EOF
s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
s%\[%\\&%g
s%\]%\\&%g
s%\$%$$%g
EOF
DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
rm -f conftest.defs
# Without the "./", some shells look in PATH for config.status.
: ${CONFIG_STATUS=./config.status}
echo creating $CONFIG_STATUS
rm -f $CONFIG_STATUS
cat > $CONFIG_STATUS <<EOF
#! /bin/sh
# Generated automatically by configure.
# Run this file to recreate the current configuration.
# This directory was configured as follows,
# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
#
# $0 $ac_configure_args
#
# Compiler output produced by configure, useful for debugging
# configure, is in ./config.log if it exists.
ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
for ac_option
do
case "\$ac_option" in
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
-version | --version | --versio | --versi | --vers | --ver | --ve | --v)
echo "$CONFIG_STATUS generated by autoconf version 2.12"
exit 0 ;;
-help | --help | --hel | --he | --h)
echo "\$ac_cs_usage"; exit 0 ;;
*) echo "\$ac_cs_usage"; exit 1 ;;
esac
done
ac_given_srcdir=$srcdir
trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
EOF
cat >> $CONFIG_STATUS <<EOF
# Protect against being on the right side of a sed subst in config.status.
sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
$ac_vpsub
$extrasub
s%@CFLAGS@%$CFLAGS%g
s%@CPPFLAGS@%$CPPFLAGS%g
s%@CXXFLAGS@%$CXXFLAGS%g
s%@DEFS@%$DEFS%g
s%@LDFLAGS@%$LDFLAGS%g
s%@LIBS@%$LIBS%g
s%@exec_prefix@%$exec_prefix%g
s%@prefix@%$prefix%g
s%@program_transform_name@%$program_transform_name%g
s%@bindir@%$bindir%g
s%@sbindir@%$sbindir%g
s%@libexecdir@%$libexecdir%g
s%@datadir@%$datadir%g
s%@sysconfdir@%$sysconfdir%g
s%@sharedstatedir@%$sharedstatedir%g
s%@localstatedir@%$localstatedir%g
s%@libdir@%$libdir%g
s%@includedir@%$includedir%g
s%@oldincludedir@%$oldincludedir%g
s%@infodir@%$infodir%g
s%@mandir@%$mandir%g
s%@CC@%$CC%g
s%@CPP@%$CPP%g
s%@VERSION@%$VERSION%g
s%@MACHDEP@%$MACHDEP%g
CEOF
EOF
cat >> $CONFIG_STATUS <<\EOF
# Split the substitutions into bite-sized pieces for seds with
# small command number limits, like on Digital OSF/1 and HP-UX.
ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
ac_file=1 # Number of current file.
ac_beg=1 # First line for current file.
ac_end=$ac_max_sed_cmds # Line after last line for current file.
ac_more_lines=:
ac_sed_cmds=""
while $ac_more_lines; do
if test $ac_beg -gt 1; then
sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
else
sed "${ac_end}q" conftest.subs > conftest.s$ac_file
fi
if test ! -s conftest.s$ac_file; then
ac_more_lines=false
rm -f conftest.s$ac_file
else
if test -z "$ac_sed_cmds"; then
ac_sed_cmds="sed -f conftest.s$ac_file"
else
ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
fi
ac_file=`expr $ac_file + 1`
ac_beg=$ac_end
ac_end=`expr $ac_end + $ac_max_sed_cmds`
fi
done
if test -z "$ac_sed_cmds"; then
ac_sed_cmds=cat
fi
EOF
cat >> $CONFIG_STATUS <<EOF
CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
EOF
cat >> $CONFIG_STATUS <<\EOF
for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
# Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
case "$ac_file" in
*:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
*) ac_file_in="${ac_file}.in" ;;
esac
# Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
# Remove last slash and all that follows it. Not all systems have dirname.
ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
# The file is in a subdirectory.
test ! -d "$ac_dir" && mkdir "$ac_dir"
ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
# A "../" for each directory in $ac_dir_suffix.
ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
else
ac_dir_suffix= ac_dots=
fi
case "$ac_given_srcdir" in
.) srcdir=.
if test -z "$ac_dots"; then top_srcdir=.
else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
/*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
*) # Relative path.
srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
top_srcdir="$ac_dots$ac_given_srcdir" ;;
esac
echo creating "$ac_file"
rm -f "$ac_file"
configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
case "$ac_file" in
*Makefile*) ac_comsub="1i\\
# $configure_input" ;;
*) ac_comsub= ;;
esac
ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
sed -e "$ac_comsub
s%@configure_input@%$configure_input%g
s%@srcdir@%$srcdir%g
s%@top_srcdir@%$top_srcdir%g
" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
fi; done
rm -f conftest.s*
EOF
cat >> $CONFIG_STATUS <<EOF
EOF
cat >> $CONFIG_STATUS <<\EOF
exit 0
EOF
chmod +x $CONFIG_STATUS
rm -fr confdefs* $ac_clean_files
test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
dnl Process this file with autoconf to produce a configure script.
AC_INIT(pcgi.h)
AC_PROG_CC
AC_PROG_CPP
# Set VERSION here so we only need to edit it in one place
AC_SUBST(VERSION)
VERSION=2.0a5
# Set name for machine-dependent library files
AC_SUBST(MACHDEP)
AC_MSG_CHECKING(MACHDEP)
if test -z "$MACHDEP"
then
ac_sys_system=`uname -s`
if test "$ac_sys_system" = "AIX" ; then
ac_sys_release=`uname -v`
else
ac_sys_release=`uname -r`
fi
ac_md_system=`echo $ac_sys_system | tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'`
ac_md_release=`echo $ac_sys_release | tr -d '[/ ]' | sed 's/\..*//'`
MACHDEP="$ac_md_system$ac_md_release"
case $MACHDEP in
'') MACHDEP="unknown";;
esac
fi
AC_MSG_RESULT($MACHDEP)
dnl Checks for programs.
dnl Checks for libraries.
case $ac_sys_system in
hp*|HP*)
case $CC in
cc|*/cc) CC="$CC -Aa -D_HPUX_SOURCE";;
esac;;
esac
if test "$ac_sys_system" != IRIX
then
AC_CHECK_LIB(nsl, inet_addr, [LIBS="-lnsl $LIBS"]) # SVR4
AC_CHECK_LIB(socket, socket, [LIBS="-lsocket $LIBS"], [], $LIBS) # SVR4 sockets
fi
dnl Checks for header files.
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(unistd.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_PID_T
dnl Checks for library functions.
AC_TYPE_SIGNAL
AC_CHECK_FUNCS(putenv socket strerror)
AC_MSG_CHECKING(for union semun)
AC_TRY_LINK([#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>],
[union semun semun;],
AC_DEFINE(HAVE_UNION_SEMUN) AC_MSG_RESULT(yes),AC_MSG_RESULT(no))
AC_OUTPUT(Makefile)
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5; it is not part of GNU.
#
# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
instcmd="$mvprog"
chmodcmd=""
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
fi
# Make a temp file name in the proper directory.
dstdir=`dirname $dst`
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp
# and set any options; do chmod last to preserve setuid bits
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
# Now rename the file to the real destination.
$doit $rmcmd $dst
$doit $mvcmd $dsttmp $dst
exit 0
Example/pcgitest
Example/pcgitime.py
Makefile.in
MrCreosote/README.MrCreosote
MrCreosote/creosote.c
MrCreosote/creosote.h
MrCreosote/creosote.py
README
Test/README.parseinfo
Util/README
Util/killpcgi.py
Util/pcgifile.py
Win32/Makefile.nt
Win32/README.NT
Win32/parseinfo.exe
Win32/pcgi-wrapper.exe
config.h.in
configure
configure.in
install-sh
manifest
parseinfo.c
pcgi_publisher.py
pcgi-wrapper.c
pcgi.h
/* parseinfo.c - module to parse the pcgi info file
Copyright (c) 1998, Digital Creations, Fredericksburg, VA, USA. All
rights reserved. This software includes contributions from Jeff Bauer.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o All advertising materials mentioning features or use of this
software must display the following acknowledgement:
This product includes software developed by Digital Creations
and its contributors.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS *AS IS* AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "pcgi.h"
extern char **environ;
extern int CloseFileDescriptors;
int pcgiAssignCloseFileDescriptors(pcgiResource *r, char *val)
{
if ((CloseFileDescriptors = pcgiTruthValue(val[0]) < 0))
{
sprintf(r->errmsg, "unknown value for PCGI_CLOSE_FDS: %s", val);
return(-1);
}
return(0);
}
int pcgiAssignPublisher(pcgiResource *r)
{
/*
// Determine the publisher path based on the current values
// of the pcgiResource structure.
*/
char *p, *pBegin, *pEnd, testdir[MAXSZ];
char combinedPaths[MAXPATH+MAXPATH+2];
if (r->pubpath[0]) /* assignment already made, our work is done :) */
{
return(0);
}
/*
// Look through the PCGI_INSERT_PATH directories for the publisher.
*/
strcat(combinedPaths, r->insertPath);
strcat(combinedPaths, ":");
strcat(combinedPaths, r->pythonPath);
pBegin = combinedPaths;
pEnd = pBegin + strlen(combinedPaths);
while(pBegin < pEnd)
{
p = pBegin;
do {
if (*p == ':' || *p == '\0')
break;
} while(*p++);
strncpy(testdir, pBegin, p-pBegin);
testdir[p-pBegin] = '\0';
if ((pcgiAssignPublisherPath(testdir, r))==0)
{
return(0);
}
if (p == pBegin)
{
pBegin++;
}
else
{
pBegin = p;
}
}
/*
// Run through a gauntlet of misc. attempts to find the publisher.
*/
if (r->modpath[0])
{
if ((pcgiAssignPublisherPath(r->modpath, r)) == 0)
return(0);
}
if (r->sw_info[0])
{
if ((pcgiAssignPublisherPath(r->sw_info, r)) == 0)
return(0);
}
if (r->sw_home[0])
{
if ((pcgiAssignPublisherPath(r->sw_home, r)) == 0)
return(0);
}
if (r->sw_exe[0])
{
if ((pcgiAssignPublisherPath(r->sw_exe, r)) == 0)
return(0);
}
return(-1);
}
#define PubCount 4 /* variations on a publisher name */
int pcgiAssignPublisherPath(char *path, pcgiResource *r)
{
/*
// Attempt to assign the path to the publisher, return 0 for success,
// otherwise -1.
*/
char *p[PubCount];
char testdir[MAXSZ], pubpath[MAXSZ];
int i, len;
struct stat statbuf;
p[0] = PUBLISHER_NAME_1;
p[1] = PUBLISHER_NAME_2;
p[2] = PUBLISHER_NAME_3;
p[3] = PUBLISHER_NAME_4;
strcpy(testdir, path);
len = strlen(testdir);
if (len < 1 || (MAXSZ <= len + strlen(PUBLISHER_NAME_1) + 1))
{
return(-1);
}
if (PATHSEP == testdir[len-1])
{
testdir[len-1] = '\0'; /* truncate trailing slash */
}
if (stat(testdir, &statbuf) == -1)
{
return(-1); /* unable to stat path */
}
if (!(statbuf.st_mode & S_IFDIR))
{
/*
// If the supplied path was not a directory, assume it was
// a file and get the directory portion of it.
*/
while(len > 0)
{
if (PATHSEP == testdir[--len])
{
testdir[len] = '\0';
break;
}
}
if (len < 1) { return(-1); }
}
for (i=0; i < PubCount; i++)
{
sprintf(pubpath, "%s%c%s", testdir, PATHSEP, p[i]);
if (stat(pubpath, &statbuf) != -1)
{
if (statbuf.st_mode & S_IREAD)
{
strcpy(r->pubpath, pubpath);
return(0);
}
}
}
return(-1);
}
int pcgiEnvironmentToResourceAssignment(pcgiResource *r)
{
/*
// Read in the environment and make whatever appropriate assignments
// prior to reading in the pcgi info file. Values from the pcgi info
// override environment settings.
//
// This function is necessary because the user may want to set
// an enviroment variable globally (e.g. PCGI_PUBLISHER from
// a httpd .conf file),
*/
char **env;
char *p = NULL;
char buf[MAXSZ];
char *nam, *val;
for (env=environ; *env != 0; env++)
{
if (strlen(*env) >= MAXSZ)
{
continue;
}
strcpy(buf, *env);
if ((p = strchr(buf,'=')) != NULL)
{
*p++ = '\0';
nam = buf;
val = p;
if((strncmp(nam, "SOFTWARE_", strlen("SOFTWARE_")))==0)
{
if((strcmp(nam,"SOFTWARE_NAME"))==0)
strcpy(r->sw_name, val);
else if((strcmp(nam,"SOFTWARE_HOME"))==0)
strcpy(r->sw_home, val);
else if((strcmp(nam,"SOFTWARE_EXE"))==0)
strcpy(r->sw_exe, val);
}
if((strcmp(nam,"PYTHONPATH"))==0)
{
/* TODO: check strlen against MAXPATH */
strcpy(r->pythonPath, val);
}
else if((strncmp(nam, "PCGI_", strlen("PCGI_")))==0)
{
if ((strcmp(nam,"PCGI_CLOSE_FDS"))==0)
{
if ((pcgiAssignCloseFileDescriptors(r, val)) < 0)
return(-1);
}
else if ((strcmp(nam,"PCGI_DISPLAY_ERRORS"))==0)
r->displayErrors = pcgiTruthValue(val[0]);
else if ((strcmp(nam,"PCGI_ERROR_LOG"))==0)
strcpy(r->errlog, val);
else if ((strcmp(nam,"PCGI_EXE"))==0)
strcpy(r->sw_exe, val);
else if ((strcmp(nam,"PCGI_HOST"))==0)
strcpy(r->sockhost, val);
else if ((strcmp(nam,"PCGI_INSERT_PATH"))==0 ||
(strcmp(nam,"PCGI_WORKING_DIR"))==0)
{
if (strlen(val) >= MAXPATH)
{
strcpy(r->errmsg, "pcgiEnvironmentToResourceAssignment() length exceeds MAXPATH");
return(-1);
}
strcpy(r->insertPath, val);
}
else if ((strcmp(nam,"PCGI_MODULE_PATH"))==0)
strcpy(r->modpath, val);
else if ((strcmp(nam,"PCGI_NAME"))==0)
strcpy(r->sw_name, val);
else if ((strcmp(nam,"PCGI_PID_FILE"))==0)
strcpy(r->procpath, val);
else if ((strcmp(nam,"PCGI_PORT"))==0)
r->sockport = atoi(val);
else if ((strcmp(nam,"PCGI_PUBLISHER"))==0)
strcpy(r->pubpath, val);
else if ((strcmp(nam,"PCGI_SOCKET_FILE"))==0)
strcpy(r->sockpath, val);
}
}
}
return(0);
}
/*
// pcgiParseInfo: Parse info file named in resource->sw_info
*/
int pcgiParseInfo(pcgiResource *r)
{
FILE *f;
char buf[256];
char *v=NULL;
char *p=NULL;
struct stat statbuf;
int _newStyleDirectives = 0;
int _oldStyleLineCount = 0;
enum { oldStyleSocketFile, oldStyleProcessIdFile, oldStyleWorkDir, oldStyleModPath };
if ((pcgiEnvironmentToResourceAssignment(r)) < 0)
{
if (!r->errmsg[0])
strcpy(r->errmsg, "pcgiEnvironmentToResourceAssignment() error");
return(-1);
}
if((f=fopen(r->sw_info, "r")) == NULL)
{
sprintf(r->errmsg, "unable to open info file: %s", r->sw_info);
return(-1);
}
pcgiPutNameValueInEnvironment("PCGI_INFO_FILE", r->sw_info);
while(fgets(buf, 255, f) != NULL)
{
/* XXX - TODO: trim leading, trailing whitespace */
#ifdef WIN32
amendPathSeparators(buf);
#endif
if((buf[0] != '#') && (buf[0] != '\n'))
{
p=(strrchr(buf,'\0')-sizeof(char));
while((p >= buf) && (isspace(*p)))
{
*p=0;
p--;
}
if ((p=strchr(buf,'=')) != NULL)
{
_newStyleDirectives = 1;
if ((pcgiPutEnvironment(buf) < 0))
{
strcpy(r->errmsg, "pcgiPutEnvironment() failed");
fclose(f);
return(-1);
}
*p=0;
p++;
if((strcmp(buf,"SOFTWARE_NAME"))==0)
{
strcpy(r->sw_name, p);
}
else if((strcmp(buf,"SOFTWARE_HOME"))==0)
{
strcpy(r->sw_home, p);
}
else if((strcmp(buf,"SOFTWARE_EXE"))==0)
{
strcpy(r->sw_exe, p);
}
else if((strcmp(buf,"PCGI_CLOSE_FDS"))==0)
{
if ((pcgiAssignCloseFileDescriptors(r, p)) < 0)
return(-1);
}
else if ((strcmp(buf,"PCGI_DISPLAY_ERRORS"))==0)
r->displayErrors = pcgiTruthValue(p[0]);
else if((strcmp(buf,"PCGI_ERROR_LOG"))==0)
{
strcpy(r->errlog, p);
}
else if((strcmp(buf,"PCGI_EXE"))==0)
{
strcpy(r->sw_exe, p);
}
else if((strcmp(buf,"PCGI_HOST"))==0)
{
strcpy(r->sockhost, p);
}
else if((strcmp(buf,"PCGI_INSERT_PATH"))==0)
{
strcpy(r->insertPath, p);
}
else if((strcmp(buf,"PCGI_MODULE_PATH"))==0)
{
strcpy(r->modpath, p);
}
else if((strcmp(buf,"PCGI_NAME"))==0)
{
strcpy(r->sw_name, p);
}
else if((strcmp(buf,"PCGI_PID_FILE"))==0)
{
strcpy(r->procpath, p);
}
else if((strcmp(buf,"PCGI_PORT"))==0)
{
r->sockport = atoi(p);
}
else if((strcmp(buf,"PCGI_PUBLISHER"))==0)
{
strcpy(r->pubpath, p);
}
else if((strcmp(buf,"PCGI_SOCKET_FILE"))==0)
{
strcpy(r->sockpath, p);
}
else if((strcmp(buf,"PCGI_WORKING_DIR"))==0)
{
strcpy(r->insertPath, p);
}
else if((strcmp(buf,"PYTHONPATH"))==0)
{
strcpy(r->pythonPath, p);
}
}
else /* old-style (deprecated) directives */
{
/* assume old style where the first four lines correspond to */
/* 1. path of the socket file */
/* 2. path of the process id file */
/* 3. working directory (to be added to path by publisher) */
/* 4. path of the module to be published */
if (_newStyleDirectives)
{
strcpy(r->errmsg, "pcgi info file mixes old and new style directives (new style uses name=value)");
fclose(f);
return(-1);
}
if (oldStyleSocketFile == _oldStyleLineCount)
{
strcpy(r->sockpath, buf);
pcgiPutNameValueInEnvironment("PCGI_SOCKET_FILE", buf);
}
else if (oldStyleProcessIdFile == _oldStyleLineCount)
{
strcpy(r->procpath, buf);
pcgiPutNameValueInEnvironment("PCGI_PID_FILE", buf);
}
else if (oldStyleWorkDir == _oldStyleLineCount)
{
strcpy(r->insertPath, buf);
if ((pcgiPutNameValueInEnvironment("PCGI_INSERT_PATH", buf)) < 0)
{
strcpy(r->errmsg, "pcgiPutNameValueInEnvironment() error");
fclose(f);
return(-1);
}
}
else if (oldStyleModPath == _oldStyleLineCount)
{
strcpy(r->modpath, buf);
if ((pcgiPutNameValueInEnvironment("PCGI_MODULE_PATH", buf)) < 0)
{
strcpy(r->errmsg, "pcgiPutNameValueInEnvironment() error");
fclose(f);
return(-1);
}
}
else
{
strcpy(r->errmsg, "oldStyleLineCount exceeds maximum");
fclose(f);
return(-1);
}
_oldStyleLineCount++;
}
}
}
fclose(f);
/*
// Post-parsing work: decide if we have enough info to make it work.
*/
/*
// If the location of the publisher was not specified, try to
// locate it.
*/
if (!r->pubpath[0])
{
pcgiAssignPublisher(r);
}
if (!r->pubpath[0])
{
strcpy(r->errmsg, "unable to determine the publisher location");
return(-1);
}
else
{
if (stat(r->pubpath, &statbuf) == -1)
{
sprintf(r->errmsg, "missing publisher: %s", r->pubpath);
return(-1);
}
else
{
if (!(statbuf.st_mode & S_IREAD))
{
sprintf(r->errmsg, "publisher read error: %s", r->pubpath);
return(-1);
}
}
}
/*
// Assign defaults, where necessary, for backward compatibility.
*/
if (r->sw_name[0] && r->sw_home[0])
{
if (!r->sw_exe[0])
{
strcpy(r->sw_exe,"/usr/local/bin/python1.4");
pcgiPutNameValueInEnvironment("SOFTWARE_EXE", r->sw_exe);
}
if (!r->procpath[0])
{
sprintf(r->procpath,"%s/var/%s.pid", r->sw_home,r->sw_name);
pcgiPutNameValueInEnvironment("PCGI_PID_FILE", r->procpath);
}
if (!r->sockpath[0])
{
sprintf(r->sockpath,"%s/var/%s.soc", r->sw_home,r->sw_name);
pcgiPutNameValueInEnvironment("PCGI_SOCKET_FILE", r->sockpath);
}
}
/*
// Other than r->pubpath, the other required attributes to complete
// the process are: r->procpath & r->sockpath.
*/
if (!r->sockpath[0])
{
strcpy(r->errmsg, "missing parameter: PCGI_SOCKET_FILE");
return(-1);
}
if (!r->procpath[0])
{
strcpy(r->errmsg, "missing parameter: PCGI_PID_FILE");
return(-1);
}
/* Add this at a later date: jhb - 8/10/98 */
/*
if (r->sockport && !r->sockhost[0])
{
strcpy(r->errmsg, "unable to determine hostname, recommend specifying: PCGI_HOST");
return(-1);
}
*/
return(0);
}
int pcgiPutEnvironment(char *buf)
{
/*
// Stick a copy of the name=value pair in the
// process environment. Note that this would
// leak and need to be changed for any pcgi
// implementations that work as web server api
// extensions...
*/
char *v = NULL;
if((v=malloc(strlen(buf) + sizeof(char))) == NULL)
{
return(-1);
}
strcpy(v, buf);
if(putenv(v))
{
return(-1);
}
return(0);
}
int pcgiPutNameValueInEnvironment(char *name, char *value)
{
/*
// Slight modification to pcgiPutEnvironment(), convenience function.
*/
char *v = NULL;
if ((v=malloc(strlen(name) + strlen(value) + (2 * sizeof(char)))) == NULL)
return(-1);
sprintf(v, "%s=%s", name, value);
if(putenv(v))
return(-1);
return(0);
}
int pcgiTruthValue(char v)
{
if (v=='1' || v=='t' || v=='T' || v=='y' || v=='Y')
return 1;
else if (v=='0' || v=='f' || v=='F' || v=='n' || v=='N')
return 0;
else
return -1;
}
#ifdef WIN32
/*
This function lets both Unix & Win32 info files
to use the same '/' character as a path separator.
However it does this by assuming that we always
want '\' backslashes as path separators in a
Win32 environment.
*/
void amendPathSeparators(char *src)
{
char ch, *ptr;
ptr = src;
while ((ch = *src++))
{
if (ch == PATHSEP_UNIX) { *ptr = PATHSEP_WIN32; }
*ptr++;
}
}
#endif
#ifdef MAIN_PARSEINFO
int main(int argc, char *argv[])
{
/* char **env; */
pcgiResource resource;
pcgiResource *r = &resource;
if (argc < 2)
{
printf("usage: parseinfo <pcgi-info-file>\n");
return(-1);
}
#ifdef CLOSE_FDS
CloseFileDescriptors = 1;
#endif
/* initialize pcgiResource */
memset(r,0,sizeof(pcgiResource));
r->conn=-1;
strcpy(r->sw_info, argv[1]);
if ((pcgiParseInfo(r)) < 0)
{
printf("error parsing info file: %s\n", r->sw_info);
printf(" %s\n", r->errmsg);
return(-1);
}
printf("pcgi resource attributes:\n");
printf(" %-20s %s\n", "r->sw_info", r->sw_info);
printf(" %-20s %s\n", "r->sw_name", r->sw_name);
printf(" %-20s %s\n", "r->sw_home", r->sw_home);
printf(" %-20s %s\n", "r->sw_exe", r->sw_exe);
printf(" %-20s %s\n", "r->procpath", r->procpath);
printf(" %-20s %s\n", "r->sockpath", r->sockpath);
printf(" %-20s %s\n", "r->modpath", r->modpath);
printf(" %-20s %s\n", "r->pubpath", r->pubpath);
printf(" %-20s %d\n", "r->procid", r->procid);
printf(" %-20s %s\n", "r->insertPath", r->insertPath);
printf(" %-20s %s\n", "r->pythonPath", r->pythonPath);
printf(" %-20s %d\n", "r->sockport", r->sockport);
printf(" %-20s %s\n", "r->sockhost", r->sockhost);
printf(" %-20s %d\n", "r->displayErrors", r->displayErrors);
printf(" %-20s %d\n", "CloseFileDescriptors", CloseFileDescriptors);
/* printf("\nenvironment:\n"); */
/* for (env=environ; *env != 0; env++) */
/* printf(" %s\n", *env); */
}
#endif
/* pcgi-wrapper.c - Persistent CGI wrapper module
Copyright (c) 1998, Digital Creations, Fredericksburg, VA, USA. All
rights reserved. This software includes contributions from Jeff Bauer.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o All advertising materials mentioning features or use of this
software must display the following acknowledgement:
This product includes software developed by Digital Creations
and its contributors.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS *AS IS* AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- 2.0a5 29 October 1998
- (brian) fixed arg type mismatch for semctl
- 2.0a4 10 August 1998
- (jeff) fixed Win32 local socket host address issues
- 2.0a4 8 August 1998
- (jeff) added Win32 support
*/
#include "pcgi.h"
#ifdef CREOSOTE
#include "creosote.h" /* used for debugging */
char spewbuf[1024]; /* yes, it's a global, but only for debugging */
#endif
static char _id_[]="$Id: pcgi-wrapper.c,v 1.9 2000/08/01 15:59:44 brian Exp $";
/* Globals, OR: "I'll know I'll hate myself in the morning" */
extern char **environ;
int CloseFileDescriptors = 0;
#if UNIX
int g_lock = 0;
#endif
#if PCGI_WRAPPER_MAIN
int main(int argc, char *argv[])
{ pcgiResource resource;
pcgiResource *r=&resource;
long l =0;
char t[HDRLEN+1]={0};
char *estatus =NULL;
char *emsg =NULL;
char *p =NULL;
char **env;
#ifdef CREOSOTE
initializeMrCreosote();
/* spew("pcgi-wrapper main()"); */
#endif
#ifdef CLOSE_FDS
CloseFileDescriptors = 1;
#endif
#ifdef WIN32
_setmode(fileno(stdin), O_BINARY);
_setmode(fileno(stdout), O_BINARY);
#endif
/*
// Initialize resource info
*/
memset(r,0,sizeof(pcgiResource));
r->conn=-1;
if (argc < 2)
{
onError(E_500, "No pcgi info file given!", r);
}
strcpy(r->sw_info, argv[1]);
if ((pcgiParseInfo(r)) < 0)
{
onError(E_500, "Error parsing pcgi info file", r);
}
/*
// Copy environment to resource
*/
for(env=environ; *env != 0; env++)
{
r->sz_env+=(strlen(*env)+sizeof(char));
}
if((r->p_env=malloc(((sizeof(char) * r->sz_env)+(sizeof(char)*HDRLEN))))==NULL)
{
onError(E_500, "Error allocating env", r);
}
p=r->p_env;
sprintf(p, HDRFMT, r->sz_env);
if (p[0] != '0')
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR123_BAD_ENV_HEADER);
onError(E_500, "Error allocating env", r);
}
p+=HDRLEN;
for(env=environ; *env != 0; env++)
{ l=strlen(*env);
memcpy(p, *env, l);
p+=l;
*p=0;
p++;
}
/*
// Copy stdin to resource
*/
p=getenv("CONTENT_LENGTH");
if((p != NULL) && ((r->sz_input=atol(p)) > 0))
{
if((r->p_input=malloc(((sizeof(char) * r->sz_input)+
(sizeof(char)*HDRLEN))))==NULL)
{
onError(E_500, "Error allocating stdin", r);
}
p=r->p_input;
sprintf(p, HDRFMT, r->sz_input);
if (p[0] != '0')
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR124_BAD_STDIN_HEADER);
onError(E_500, "Error allocating stdin", r);
}
p+=HDRLEN;
if(pcgiRead(STDIN_FILENO, p, r->sz_input) != r->sz_input)
{
onError(E_500, "Error reading stdin", r);
}
}
else
{
if((r->p_input=malloc(sizeof(char)*HDRLEN))==NULL)
{
onError(E_500, "Error allocating stdin", r);
}
sprintf(r->p_input, HDRFMT, 0);
}
/*
// Attempt to connect
*/
if ((r->conn = pcgiConnect(r)) < 0)
{
if(pcgiVerifyProc(r) < 0)
{
if(pcgiStartProc(r) < 0)
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR101_FAILURE_DURING_START);
onError(E_500, "Failed to start resource", r);
}
if ((r->conn=pcgiConnect(r)) < 0)
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR102_FAILURE_DURING_CONNECT);
onError(E_503, strerror(errno), r);
}
}
else
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR103_UNABLE_VERIFY_RUNNING);
onError(E_503, "pcgiVerifyProc failed", r);
}
}
/*
// Send environment and stdin
*/
#ifdef WIN32
if (pcgiWriteSocket(r->conn,r->p_env,(r->sz_env+HDRLEN)) != (r->sz_env+HDRLEN))
#endif
#ifdef UNIX
if (pcgiWrite(r->conn,r->p_env,(r->sz_env+HDRLEN)) != (r->sz_env+HDRLEN))
#endif
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR104_ENVIRONMENT_SEND);
onError(E_500, "Error sending env", r);
}
#ifdef WIN32
if (pcgiWriteSocket(r->conn,r->p_input,(r->sz_input+HDRLEN)) != (r->sz_input+HDRLEN))
#endif
#ifdef UNIX
if (pcgiWrite(r->conn,r->p_input,(r->sz_input+HDRLEN)) != (r->sz_input+HDRLEN))
#endif
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR105_STDIN_SEND);
onError(E_500, "Error sending stdin", r);
}
#ifdef WIN32
shutdown(r->conn, 1); /* shutdown the socket so we can receive */
#endif
/*
// Receive stdout and stderr
*/
t[0]='\0';
#ifdef WIN32
if (!pcgiReadSocket(r->conn, t, HDRLEN))
#endif
#ifdef UNIX
if (!pcgiRead(r->conn, t, HDRLEN))
#endif
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR106_STDOUT_READ_HEADER);
onError(E_503, strerror(errno), r);
}
if (strlen(t) <= 0)
{
if (!r->errmsg[0])
sprintf(r->errmsg, "%s (%d)", ERR107_BAD_STDOUT_STRLEN, strlen(t));
onError(E_503, strerror(errno), r);
}
if (t[0] != '0')
{
/* XXX - Later: process this as out-of-bound stdin data */
sprintf(r->errmsg, "t[0] = %d", (int) t[0]);
onError(E_500, "unexpected out-of-bound data in stdin", r);
}
else
{
r->sz_output=atol(t);
l=(sizeof(char) * r->sz_output) + sizeof(char);
r->p_output=(char *)malloc(l);
memset(r->p_output,0,l);
#ifdef WIN32
if (pcgiReadSocket(r->conn,r->p_output,r->sz_output) != r->sz_output)
#endif
#ifdef UNIX
if (pcgiRead(r->conn,r->p_output,r->sz_output) != r->sz_output)
#endif
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR108_STDOUT_READ_BODY);
onError(E_500, "Error receiving stdout", r);
}
}
t[0]='\0';
#ifdef WIN32
if (!pcgiReadSocket(r->conn, t, HDRLEN))
#endif
#ifdef UNIX
if (!pcgiRead(r->conn, t, HDRLEN))
#endif
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR109_STDERR_READ_HEADER);
onError(E_500, "Error receiving stderr size", r);
}
if (strlen(t) <= 0)
{
if (!r->errmsg[0])
sprintf(r->errmsg, "%s (%d)", ERR110_BAD_STDERR_STRLEN, strlen(t));
onError(E_500, "Error receiving stderr size", r);
}
if (t[0] != '0')
{
/* XXX - Later: process this as out-of-bound stderr data */
sprintf(r->errmsg, "t[0] = %d", (int) t[0]);
onError(E_500, "unexpected out-of-bound data in stderr", r);
}
else
{
r->sz_error=atol(t);
if (r->sz_error > 0)
{
l=(sizeof(char) * r->sz_error) + sizeof(char);
r->p_error=(char *)malloc(l);
memset(r->p_error,0,l);
#ifdef WIN32
if (pcgiReadSocket(r->conn, r->p_error, r->sz_error) != r->sz_error)
#endif
#ifdef UNIX
if (pcgiRead(r->conn, r->p_error, r->sz_error) != r->sz_error)
#endif
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR111_STDERR_READ_BODY);
onError(E_500, "Error receiving stderr", r);
}
}
}
#ifdef UNIX
close(r->conn);
#endif
#ifdef WIN32
closesocket(r->conn);
#endif
/*
// Return stdout and stderr to server
*/
if (r->sz_output != 0)
{
if (pcgiWrite(STDOUT_FILENO,r->p_output,r->sz_output) != r->sz_output)
{
if (!r->errmsg[0])
strcpy(r->errmsg, "(112) Error returning stdout to server");
onError(E_500, ERR112_STDOUT_TO_SERVER, r);
}
free(r->p_output);
r->p_output=NULL;
}
if (r->sz_error != 0)
{
if (pcgiWrite(STDERR_FILENO,r->p_error,r->sz_error) != r->sz_error)
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR113_STDOUT_TO_SERVER);
onError(E_500, "Error returning stderr", r);
}
free(r->p_error);
r->p_error=NULL;
}
/*
// Free env & input buffers, release lock if needed
*/
free(r->p_env);
r->p_env=NULL;
free(r->p_input);
r->p_input=NULL;
cleanup();
fflush(stdout);
fflush(stderr);
/*exit(0);*/
return 0;
}
#endif /* end of main(): PCGI_WRAPPER_MAIN */
/*
// onError: fatal pcgi error
*/
void onError(char *estatus, char *emsg, pcgiResource *r)
{
FILE *f;
time_t now;
#ifdef VERSION
/* If VERSION isn't defined as a string, everything will blow up here
during compilation. */
char *pcgi_version="pcgi-wrapper-version " VERSION;
#else
char *pcgi_version = "";
#endif
char *displayError = "";
if (r != NULL)
{
#ifdef UNIX
if(r->conn != -1) close(r->conn);
cleanup();
#endif
#ifdef WIN32
if (r->conn)
{
shutdown(r->conn, 1);
closesocket(r->conn);
WSACleanup();
}
#endif
if (r->errlog[0])
{
if((f=fopen(r->errlog, "ab")) != NULL)
{
now = time(NULL);
fprintf(f, "%s pcgi-wrapper: %s %s\n",
ctime(&now), emsg, r->errmsg);
fclose(f);
}
}
if(r->p_env!=NULL) free(r->p_env);
if(r->p_input!=NULL) free(r->p_input);
}
if (r->displayErrors)
displayError = r->errmsg;
printf(errorHtml, estatus, displayError, emsg, pcgi_version);
fflush(stdout);
fflush(stderr);
exit(0);
}
/*
// pcgiWrite: write n bytes to a an fd
*/
long pcgiWrite(pcgi_socket fd, const char *ptr, long nbytes)
{
long done = 0;
long notdone = nbytes;
const char *cptr = (const char *)ptr;
while (notdone > 0)
{
done = write(fd, cptr, notdone);
if (done <= 0)
{
return (done);
}
notdone -= done;
cptr += done;
}
return ((nbytes - notdone));
}
#ifdef WIN32
long pcgiWriteSocket(pcgi_socket fd, const char *ptr, long nbytes)
{
/* The successful completion of a send does not indicate */
/* that the data was successfully delivered. */
int count;
int req;
long bytesSent = 0;
/* begin superKludge(tm) - only for testing, do not leave in place XXX */
/* if (STDOUT_FILENO == (int)fd) */
/* { */
/* printf("%s", ptr); */
/* return 0; */
/* } */
/* end superKludge(tm) - only for testing, do not leave in place XXX */
while ( bytesSent < nbytes )
{
req = nbytes - bytesSent;
count = send(fd, ptr + bytesSent, req, 0);
if (SOCKET_ERROR == count)
{
return(-1);
}
bytesSent += (long) count;
}
return(bytesSent);
}
#endif
/*
// pcgiRead: read n bytes from an fd
*/
long pcgiRead(pcgi_socket fd, char *ptr, long n)
{
long done = 0;
long notdone = n;
char *cptr = ptr;
while (notdone > 0)
{
done = read(fd, cptr, notdone);
if (done < 0)
return (done); /* ERROR */
else if (done == 0)
break; /* EOF */
notdone -= done;
cptr += done;
}
return ((n - notdone));
}
#ifdef WIN32
long pcgiReadSocket(pcgi_socket fd, char *ptr, long nbytes)
{
int count;
int req;
long bytesRecv = 0;
while ( bytesRecv < nbytes )
{
req = nbytes - bytesRecv;
count = recv(fd, ptr + bytesRecv, req, 0);
if (SOCKET_ERROR == count)
{
/* TODO: add error reporting by calling WSAGetLastError */
return(-1);
}
bytesRecv += (long) count;
}
return(bytesRecv);
}
#endif
/*
// pcgiVerifyProc: check to see if a resource is running
*/
int pcgiVerifyProc(pcgiResource *r)
{ FILE *f;
char p[10];
memset(p,0,10);
if (r->procid == 0)
{ if((f=fopen(r->procpath, "r")) == NULL)
return(-1);
if(fgets(p, HDRLEN, f) == NULL)
return(-1);
fclose(f);
if(!(strlen(p) > 0))
return(-1);
r->procid=atoi(p);
}
#ifdef UNIX
return(kill(r->procid, 13));
#endif
#ifdef WIN32
if ((NULL == OpenProcess(PROCESS_VM_READ, FALSE, r->procid)))
{
return(-1);
}
return(0);
#endif
}
/*
// pcgiConnect: return fd of a connected socket
*/
#ifdef UNIX
pcgi_socket pcgiConnect(pcgiResource *r)
{
struct sockaddr_un s;
pcgi_socket fd;
int addrlen=0;
int connected=-1;
int attempted=0;
int retry=10;
int delay=1;
memset((char *) &s, 0, sizeof(s));
s.sun_family=AF_UNIX;
strcpy(s.sun_path, r->sockpath);
addrlen = sizeof(struct sockaddr_un); /* force to use sizeof(s) */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR114_UNABLE_TO_OPEN_SOCKET);
return (-1);
}
while ((connected < 0) && (attempted <= retry))
{
if ((connected=connect(fd, (struct sockaddr *) &s, addrlen)) < 0)
{
if((errno!=ECONNREFUSED) && (errno!=ENOENT))
{
if (!r->errmsg[0])
strcpy(r->errmsg, ERR115_CONNECTION_REFUSED);
return(-1);
}
sleep(delay);
attempted++;
}
}
if (!(connected < 0))
{
if (!r->errmsg[0])
sprintf(r->errmsg, "%s, fd=%d", ERR116_UNABLE_TO_CONNECT, fd);
return (fd);
}
return (connected);
}
#endif /* UNIX pcgiConnect */
#ifdef WIN32
pcgi_socket pcgiConnect(pcgiResource *r)
{
pcgi_socket destSocket;
SOCKADDR_IN destSockAddr;
unsigned long destAddr;
int connected = SOCKET_ERROR;
int attempted = 0;
int status;
WSADATA WsaData;
char hostName[MAXSZ];
LPHOSTENT hostEnt;
SOCKADDR_IN hostAddr;
/* initialize the Windows Socket DLL */
/* TODO: move this startup code outside of pcgiConnect */
if (0 != WSAStartup(MAKEWORD(2, 0), &WsaData))
{
return(-1);
}
/* destAddr = inet_addr("192.168.2.43"); */
hostAddr.sin_addr.s_addr = INADDR_ANY; /* init local address */
/* Bug: assumes r->sockhost is the host name, we should also
check to see if it is the xxx.xxx.xxx.xxx octet string and
act accordingly */
if (r->sockhost[0])
strcpy(hostName, r->sockhost);
else if (SOCKET_ERROR == gethostname(hostName, MAXSZ))
return(-1);
hostEnt = gethostbyname((LPSTR) hostName);
if (hostEnt)
{
/* resolve hostname for local address */
hostAddr.sin_addr.s_addr = *((u_long FAR*) (hostEnt->h_addr));
}
if (INADDR_ANY == hostAddr.sin_addr.s_addr)
{
return(-1);
}
destAddr = hostAddr.sin_addr.s_addr;
memcpy(&destSockAddr.sin_addr, &destAddr, sizeof(destAddr));
destSockAddr.sin_port = htons((short)r->sockport);
destSockAddr.sin_family = AF_INET;
/* create socket */
destSocket = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == destSocket)
{
return(-1);
}
/* Connect */
/* The code below blithely duplicates the Unix version. */
/* TODO: add better recovery/error handling. */
while ((SOCKET_ERROR == connected) && (attempted <= CONNRETRY))
{
connected = connect(destSocket, (LPSOCKADDR) &destSockAddr, sizeof(destSockAddr));
if (SOCKET_ERROR == connected)
{
status = WSAGetLastError();
if ((status != WSAECONNREFUSED) && (status != ENOENT))
{
return(-1);
}
sleep(CONNDELAY);
attempted++;
}
}
if (SOCKET_ERROR == connected)
{
closesocket(destSocket);
WSACleanup();
return(-1);
}
return(destSocket);
}
#endif /* Win32 pcgiConnect */
#ifdef UNIX
static sig_atomic_t sigflag;
static sigset_t nmask, omask, zmask;
#endif
#ifdef UNIX
void pcgiSIG(int s)
{
sigflag=1;
return;
}
#endif
void cleanup()
{
#ifdef UNIX
UNION_SEMUN arg;
arg.val=0;
if (g_lock > 0)
{
semctl(g_lock, 1, IPC_RMID, arg);
}
#endif
}
/*
// pcgiStartProc: manages starting a pcgi resource.
*/
#ifdef UNIX
int pcgiStartProc(pcgiResource *r)
{
pid_t pid;
char *p = NULL;
int i = 0;
UNION_SEMUN arg;
arg.val=0;
if ((p=strrchr(r->sw_exe, PATHSEP))==NULL)
{
p = r->sw_exe;
}
else
{
p++;
}
/* Set up signal handlers to coordinate timing */
signal(SIGUSR1, pcgiSIG);
signal(SIGUSR2, pcgiSIG);
sigemptyset(&zmask);
sigemptyset(&nmask);
sigaddset(&nmask, SIGUSR1);
sigaddset(&nmask, SIGUSR2);
sigprocmask(SIG_BLOCK, &nmask, &omask);
/* Make sure another wrapper isn't already doing a restart */
if ((r->lock=semget(101, 1, 0700 | IPC_CREAT | IPC_EXCL)) == -1)
{
if (errno == EACCES)
strcpy(r->errmsg, ERR117_LOCK_ERROR_EACCES);
else if (errno == EEXIST)
strcpy(r->errmsg, ERR118_LOCK_ERROR_EEXIST);
else if (errno == EINVAL)
strcpy(r->errmsg, ERR119_LOCK_ERROR_EINVAL);
else if (errno == ENOENT)
strcpy(r->errmsg, ERR120_LOCK_ERROR_ENOENT);
else if (errno == ENOSPC)
strcpy(r->errmsg, ERR121_LOCK_ERROR_ENOSPC);
else
sprintf(r->errmsg, "%s, %d", ERR122_LOCK_ERROR_OTHER, errno);
return(-1);
}
/* Keep us from dying without cleaning up our semaphore by
setting signal handlers to ensure that the sem will always
be released. We don't set handlers for SIGUSR1 SIGUSR2 or
SIGCHLD, because we need those to coordinate with the child
process(es) that we fork. */
g_lock = r->lock;
for(i=0; i<32; i++)
{
if ((i!=SIGUSR1) && (i!=SIGUSR2) && (i != SIGCHLD))
{
signal(i, (void *)cleanup);
}
}
/* If the old socket file exists and we have write permission,
attempt to remove it. */
if (r->sockport == 0 && access(r->sockpath, W_OK) == 0)
{
unlink(r->sockpath);
}
/* Fork a child which forks a child -- this is so that
init will inherit the grandchild (so it won't die) */
if ((pid = fork()) < 0)
{
semctl(r->lock, 1, IPC_RMID, arg);
return(-1);
}
else if (pid == 0)
{
if ((pid = fork()) < 0)
{
return(-1);
}
else if (pid > 0)
{ /* Let child know we're going away so it can start */
kill(pid, SIGUSR1);
exit(0);
}
setsid();
chdir("/");
/* Wait for parent to go away */
while(sigflag == 0)
sigsuspend(&zmask);
sigflag = 0;
sigprocmask(SIG_SETMASK, &omask, NULL);
/* Platform oddities... */
if (CloseFileDescriptors)
{
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
}
execl(r->sw_exe,
p,
r->pubpath,
(char *)0);
exit(0);
}
/* Wait for the first child to finish */
if (waitpid(pid, NULL, 0) < 0)
{ semctl(r->lock, 1, IPC_RMID, arg);
return(-1);
}
/*
// Release restart lock!
*/
semctl(r->lock, 1, IPC_RMID, arg);
/*
// Reset signal handlers
*/
for(i=0; i<10; i++)
{
signal(i, SIG_DFL);
}
sleep(2);
return (0);
}
#endif /* UNIX pcgiStartProc */
#ifdef WIN32
int pcgiStartProc(pcgiResource *r)
{
HANDLE mutex = 0;
char pythonExecutable[256];
char command_line[1024];
BOOL createProcessStatus;
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
int waitStatus;
GetStartupInfo(&StartupInfo);
/* Is another wrapper attempting a restart? */
mutex = CreateMutex(NULL, FALSE, MUTEX_NAME);
if (NULL == mutex)
{
//TODO: add error reporting
return(-1);
}
waitStatus = WaitForSingleObject(mutex, (AUTODELAY * 1000));
if (WAIT_TIMEOUT == waitStatus)
{
//TODO: add error reporting
return(-1);
}
else if (WAIT_FAILED == waitStatus)
{
//TODO: add error handling by calling GetLastError()
return(-1);
}
/*
Travel beyond this point requires calling the
ReleaseMutex function. Fortunately, the Win32
mutex is automatically released when a process
terminates, but we could still encounter a
situation where the process is hung or stalled ...
*/
if (r->sw_exe[0])
strcpy(pythonExecutable, r->sw_exe);
else
strcpy(pythonExecutable, "python");
sprintf(command_line, "%s %s", pythonExecutable, r->pubpath);
createProcessStatus = CreateProcess(
NULL,
command_line,
NULL,
NULL,
FALSE,
DETACHED_PROCESS,
NULL,
NULL,
&StartupInfo,
&ProcessInfo);
/* wait a little bit to give the published
application enough time to initialize itself */
//Yech!!!
sleep(AUTODELAY); // <<<-- use a ReadySignal(tm), if available :)
ReleaseMutex(mutex);
CloseHandle(mutex);
if (0 == createProcessStatus)
{
//TODO: report more information about failure
return(-1);
}
else
{
r->procid = ProcessInfo.dwProcessId; /* assign process id */
return(0);
}
}
#endif
/* pcgi.h - Persistent CGI header file for pcgi-wrapper.c, parseinfo.c
Copyright (c) 1998, Digital Creations, Fredericksburg, VA, USA. All
rights reserved. This software includes contributions from Jeff Bauer.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o All advertising materials mentioning features or use of this
software must display the following acknowledgement:
This product includes software developed by Digital Creations
and its contributors.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS *AS IS* AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PCGI_H
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef UNIX
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#ifdef WIN32
#include <windows.h>
#include <io.h>
#include <iostream.h>
#include <winsock.h>
#include <fcntl.h>
#endif
#define MAXLINEBUFFER 12
#define PATHSEP_UNIX '/'
#define PATHSEP_WIN32 '\\'
#define DEFAULT_SOCK_PORT 7244
/*#define DEFAULT_SOCK_HOST "127.0.0.1"*/
#define MAXPATH 1024
#define PUBLISHER_NAME_1 "pcgi_publisher.py"
#define PUBLISHER_NAME_2 "pcgi_publisher.pyc"
#define PUBLISHER_NAME_3 "pcgi_publisher.pyo"
#define PUBLISHER_NAME_4 "pcgi_publisher"
#define HDRLEN 10
#define HDRFMT "%010ld"
#ifdef UNIX
#define PATHSEP PATHSEP_UNIX
typedef int pcgi_socket;
#endif
#ifdef WIN32
#define PATHSEP PATHSEP_WIN32
typedef SOCKET pcgi_socket;
#define sleep(x) Sleep(x * 1000)
#define read(x,y,z) _read(x,y,z)
#define write(x,y,z) _write(x,y,z)
#define MUTEX_NAME "pcgiMutex"
#define AUTODELAY 5
#define CONNRETRY 0
#define CONNDELAY 1
#endif
#ifndef CREOSOTE
/* no-op in case someone forgets to remove a spew() in their debug code */
#define spew(x)
#endif
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
#define STDERR_FILENO 2
#endif
#define MAXSZ 256
#define RKEY 99
#define E_500 "500 Server Error"
#define E_503 "503 Service Unavailable"
#define ERR101_FAILURE_DURING_START "(101) failure during start"
#define ERR102_FAILURE_DURING_CONNECT "(102) failure during connect"
#define ERR103_UNABLE_VERIFY_RUNNING "(103) unable to verify if process is running"
#define ERR104_ENVIRONMENT_SEND "(104) environment send"
#define ERR105_STDIN_SEND "(105) stdin send"
#define ERR106_STDOUT_READ_HEADER "(106) stdout read header"
#define ERR107_BAD_STDOUT_STRLEN "(107) bad stdout strlen"
#define ERR108_STDOUT_READ_BODY "(108) stdout read body"
#define ERR109_STDERR_READ_HEADER "(109 stderr read header"
#define ERR110_BAD_STDERR_STRLEN "(110) bad stderr strlen"
#define ERR111_STDERR_READ_BODY "(111) stderr read body"
#define ERR112_STDOUT_TO_SERVER "(112) error returning stdout to server"
#define ERR113_STDOUT_TO_SERVER "(113) error returning stderr to server"
#define ERR114_UNABLE_TO_OPEN_SOCKET "(114) unable to open socket"
#define ERR115_CONNECTION_REFUSED "(115) connection refused"
#define ERR116_UNABLE_TO_CONNECT "(116) unable to connect"
#define ERR117_LOCK_ERROR_EACCES "(117) lock error: EACCES"
#define ERR118_LOCK_ERROR_EEXIST "(118) lock error: EEXIST"
#define ERR119_LOCK_ERROR_EINVAL "(119) lock error: EINVAL"
#define ERR120_LOCK_ERROR_ENOENT "(120) lock error: ENOENT"
#define ERR121_LOCK_ERROR_ENOSPC "(121) lock error: ENOSPC"
#define ERR122_LOCK_ERROR_OTHER "(122) lock error"
#define ERR123_BAD_ENV_HEADER "(123) bad environment header"
#define ERR124_BAD_STDIN_HEADER "(124) bad stdin header"
/* #define onError(s,x) {estatus=s; emsg=x; goto error;} */
typedef struct resource_tag
{
char sw_info [MAXSZ]; /* path to pcgi info file */
char sw_name [MAXSZ]; /* module name */
char sw_home [MAXSZ]; /* home path */
char sw_exe [MAXSZ]; /* path to executable, e.g. /usr/local/bin/python */
char procpath [MAXSZ]; /* path to file containing pid */
char sockpath [MAXSZ]; /* binding path for UNIX, Win32 named pipes */
char pubpath [MAXSZ]; /* path to pcgi_publisher.py(c) */
int sockport; /* port number, if INET socket */
char sockhost [MAXSZ]; /* hostname, if INET socket */
char modpath [MAXSZ]; /* module path */
char errmsg [MAXSZ]; /* last error, brief message */
char errlog [MAXSZ]; /* fully qualified path to error log file */
char insertPath [MAXPATH]; /* insert path by publisher */
char pythonPath [MAXPATH]; /* PYTHONPATH, if provided */
short displayErrors; /* displayErrors = 0,1 */
long sz_env;
long sz_input;
long sz_output;
long sz_error;
char *p_env;
char *p_input;
char *p_output;
char *p_error;
int procid;
int conn;
int lock;
} pcgiResource;
static char errorHtml[]=
"Status: %s\n"
"Content-Type: text/html\n"
"Pragma: nocache\n"
"Expires: Thu, 01 Dec 1994 16:00:00 GMT\n\n"
"<HTML>\n"
"<HEAD>\n"
"<TITLE>Temporarily Unavailable</TITLE>\n"
"</HEAD>\n"
"<BODY BGCOLOR=\"#FFFFFF\">\n"
"<TABLE BORDER=\"0\" WIDTH=\"100%%\">\n"
"<TR>\n"
" <TD WIDTH=\"10%%\">\n"
" <CENTER>\n"
" <B><FONT SIZE=\"+6\" COLOR=\"#77003B\">!</FONT></B>\n"
" </CENTER>\n"
" </TD>\n"
" <TD WIDTH=\"90%%\"><BR>\n"
" <FONT SIZE=\"+2\">Temporarily Unavailable</FONT>\n"
" <P>\n"
" The resource you requested is temporarily unavailable - "
"please try again later.\n"
" </TD>\n"
"</TR>\n"
"</TABLE>\n"
"%s\n"
"<!--\n%s\n%s\n-->\n"
"</BODY></HTML>";
/* To ensure backward compatibility with pcgi info files, */
/* don't change the order of the first 4 enum elements. */
enum { resource_sockpath=0,
resource_procpath=1,
resource_workdir=2,
resource_modpath=3, /* remaining elements not order dependent */
resource_sockport,
resource_sockhost,
resource_exepath,
resource_exefile,
resource_pubpath,
resource_ENUM };
/* Declarations */
void cleanup(void);
void onError(char *, char *, pcgiResource *);
int pcgiAssignPublisherPath(char *, pcgiResource *);
int pcgiPutEnvironment(char *);
long pcgiRead(pcgi_socket, char *, long);
long pcgiWrite(pcgi_socket, const char *, long);
int pcgiVerifyProc(pcgiResource *);
pcgi_socket pcgiConnect(pcgiResource *);
int pcgiStartProc(pcgiResource *);
int pcgiParseInfo(pcgiResource *);
int pcgiPutNameValueInEnvironment(char *, char *);
void pcgiSIG(int);
void pcgiPrintEnvironment();
void pcgiPrintResourceInfo(pcgiResource *);
int pcgiTruthValue(char);
#ifdef WIN32
void amendPathSeparators(char *);
long pcgiReadSocket(pcgi_socket, char *, long);
long pcgiWriteSocket(pcgi_socket, const char *, long);
#endif
#ifdef HAVE_UNION_SEMUN
#define UNION_SEMUN union semun
#else
#define UNION_SEMUN \
union semun { \
int val; \
struct semid_ds *buf; \
ushort *array; \
} arg;
#endif
#define PCGI_H 1
#endif
# PCGIPublisher.py
# Persistent CGI Publisher - jeffbauer@bigfoot.com
#
# Copyright (c) 1998, Digital Creations, Fredericksburg, VA, USA. All
# rights reserved. This software includes contributions from Jeff Bauer.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# o Redistributions of source code must retain the above copyright
# notice, this list of conditions, and the disclaimer that follows.
#
# o Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# o All advertising materials mentioning features or use of this
# software must display the following acknowledgement:
#
# This product includes software developed by Digital Creations
# and its contributors.
#
# o Neither the name of Digital Creations nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS *AS IS* AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# 2.0 alpha4:
# - adds NT support, using INET sockets
# - added Mike Fletcher's Microsoft IIS hack, suggested by Amos Latteier
#
# 2.0 alpha3:
# - adds error checking
# - expands header to 10 bytes (extra byte defines an out-of-band msg)
#
# 2.0 alpha1:
# - add support for new PCGI_ directives
# - re-write module as a class, rather than a set of functions
__version__ = "2.0a4"
import string, sys, os
class PCGIPublisher:
def __init__(self, resource=None):
### resources passed from the environment, info file or pcgi-wrapper
self.errorLogFile = None
self.hostname = None
self.port = 0
self.insertPath = None
self.moduleName = None
self.modulePath = None
self.socketFile = None
self.pidFile = None
self.swhome = None
self.sock = None
### bound imports ###
self.StringIO = None
self.publish_module = None
### other ###
self.bufsize = 8192
self.error = 0
if resource is None:
self.getResources()
else:
self.resource = resource
self.initPCGI()
def cleanup(self):
if self.socketFile:
import os
if os.path.exists(self.socketFile):
try:
os.unlink(self.socketFile)
except os.error:
pass
def getResources(self):
"""
Obtain the publisher resources from the environment. Done here
in a separate method to make it easy to override, because we may
not always and forever obtain our resources from the environment.
"""
import os
self.resource = os.environ
def fatalError(self, errmsg=''):
if self.errorLogFile:
import sys, traceback, StringIO
try:
from time import asctime, localtime, time
timeStamp = asctime(localtime(time()))
except ImportError:
timeStamp = '???'
try:
f = open(self.errorLogFile, 'a+')
f.write("%s %s\n" % (timeStamp, errmsg))
if sys.exc_type != SystemExit:
trace=StringIO.StringIO()
traceback.print_exception(sys.exc_type,
sys.exc_value,
sys.exc_traceback,
None,
trace)
f.write(" %s\n" % trace.getvalue())
f.close()
except IOError:
pass
self.cleanup()
self.error = 1
def initPCGI(self):
import os
self.initPrincipia()
if self.resource.has_key('PCGI_ERROR_LOG'):
self.errorLogFile = self.resource['PCGI_ERROR_LOG']
if self.resource.has_key('PCGI_HOST'):
self.hostname = self.resource['PCGI_HOST']
if self.resource.has_key('PCGI_INSERT_PATH'):
self.insertPath = self.resource['PCGI_INSERT_PATH']
if self.resource.has_key('PCGI_MODULE_PATH'):
self.modulePath = self.resource['PCGI_MODULE_PATH']
if self.resource.has_key('PCGI_NAME'):
self.moduleName = self.resource['PCGI_NAME']
if self.resource.has_key('PCGI_PID_FILE'):
self.pidFile = self.resource['PCGI_PID_FILE']
if self.resource.has_key('PCGI_PORT'):
import string
try: self.port = string.atoi(self.resource['PCGI_PORT'])
except ValueError: pass
if self.resource.has_key('PCGI_SOCKET_FILE'):
self.socketFile = self.resource['PCGI_SOCKET_FILE']
self.insertSysPath()
if not self.moduleName:
return self.fatalError("missing module name, try specifying PCGI_NAME")
### TODO: probably should make an attempt to import self.moduleName
### to provide the user with earliest possible response.
try:
from cStringIO import StringIO
except:
from StringIO import StringIO
self.StringIO = StringIO
try:
from ZPublisher import publish_module
except ImportError:
try:
from cgi_module_publisher import publish_module
except ImportError:
return self.fatalError(
"unable to import publish_module from ZPublisher")
self.publish_module = publish_module
if not self.pidFile:
return self.fatalError("missing pid file")
### create pid file ###
try:
f = open(self.pidFile, 'wb')
f.write(str(os.getpid()))
f.close()
except IOError:
return self.fatalError("unable to write to pid file: %s" % self.pidFile)
import socket
if not self.socketFile:
return self.fatalError("missing socket file")
if self.port:
if os.sep == '/':
return self.fatalError("INET sockets not yet available on Unix")
if self.hostname is None:
self.hostname = socket.gethostname()
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.bind((self.hostname, self.port))
except socket.error:
return self.fatalError("error binding to socket: %s" % self.socketFile)
try:
sf = open(self.socketFile, 'wb')
sf.write("%s\n%s\n" % (self.hostname, self.port))
sf.close()
except IOError:
return self.fatalError("error attempting to write socket file: %s" % self.socketFile)
else:
try: os.unlink(self.socketFile)
except os.error: pass
try:
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.bind(self.socketFile)
except socket.error:
return self.fatalError("error binding to socket: %s" % self.socketFile)
try: os.chmod(self.socketFile, 0777)
except os.error: pass
def initPrincipia(self):
if self.resource.has_key('SOFTWARE_NAME'):
self.moduleName = self.resource['SOFTWARE_NAME']
def insertSysPath(self, insertPath=None):
import os, sys, string
if insertPath is None:
insertPath = self.insertPath
if insertPath:
sys.path[0:0]=string.split(insertPath,':')
elif self.resource.has_key('PCGI_WORKING_DIR'):
### Note: PCGI_WORKING_DIR is a deprecated pcgi directive ###
workDir = self.resource['PCGI_WORKING_DIR']
while workDir[-1:]=='/' or workDir[-1:]=='\\':
workDir=workDir[:-1]
sys.path[0:0]=[workDir]
else:
pass
# The present assumption is that if the module path isn't in
# sys.path, we want it put there, even if the PCGI_INSERT_PATH
# directive has been specified.
if self.modulePath:
d, s = os.path.split(self.modulePath)
if not d in sys.path:
sys.path[0:0] = [d]
# If the moduleName is not known at this time, we make a
# reasonable guess based on the path. It might behoove the
# user to explicitly specify PCGI_NAME, however.
if not self.moduleName:
import string
self.moduleName = string.splitfields(s,'.')[0]
def handler(self, conn):
from string import split, join, atoi
hdr = conn.recv(10)
size = atoi(hdr)
buff = []
while size > 0:
data = conn.recv(size)
size = size - len(data)
buff.append(data)
### XXX - Later: add out-of-band data handling ###
if (hdr[0] != '0'):
return
env = {}
for i in filter(None, split(join(buff,''),'\000')):
e = split(i,'=')
if len(e) >= 2:
env[e[0]] = join(e[1:],'=')
else:
env[e[0]]=''
size = atoi(conn.recv(10))
if size > 1048576:
### write large upload data to a file ###
from tempfile import TemporaryFile
stdin = TemporaryFile('w+b')
bufsize = self.bufsize
while size > 0:
if size < bufsize:
bufsize=size
data = conn.recv(bufsize)
size = size - len(data)
stdin.write(data)
stdin.seek(0,0)
else:
### use StringIO for smaller data ###
buff = []
while size > 0:
data = conn.recv(size)
size = size-len(data)
buff.append(data)
stdin = self.StringIO(join(buff,''))
stdout = self.StringIO()
stderr = self.StringIO()
### IIS hack to fix broken PATH_INFO
### taken from Mike Fletcher's win_cgi_module_publisher
import string
if env.has_key('SERVER_SOFTWARE') and string.find(env['SERVER_SOFTWARE'],'Microsoft-IIS') != -1:
script = filter(None,string.split(string.strip(env['SCRIPT_NAME']),'/'))
path = filter(None,string.split(string.strip(env['PATH_INFO']),'/'))
env['PATH_INFO'] = string.join(path[len(script):],'/')
try:
self.publish_module(self.moduleName,stdin=stdin,stdout=stdout,stderr=stderr,environ=env)
except:
self.fatalError("unable to publish module")
stdin.close()
stdout=stdout.getvalue()
stderr=stderr.getvalue()
stdout_len=len(stdout)
conn.send('%010d' % len(stdout))
to_send=stdout_len
if to_send > 0:
while 1:
sent = conn.send(stdout)
if sent == to_send:
break
else:
to_send = to_send - sent
stdout = stdout[sent:]
stderr_len=len(stderr)
conn.send('%010d' % stderr_len)
to_send=stderr_len
if to_send > 0:
while 1:
sent = conn.send(stderr)
if sent == to_send:
break
else:
to_send = to_send - sent
stderr = stderr[sent:]
conn.close()
def listen(self):
"""
Note to sub-classes: Aside from the constructor, listen() should
be the only method you *must* invoke.
"""
if self.error:
return self.fatalError("attempt to listen after fatal error")
import os, sys
if not self.sock:
return self.fatalError("no socket available")
self.sock.listen(512)
stdlog('stderr')
stdlog('stdout')
while not self.error:
conn, accept = self.sock.accept()
try:
self.handler(conn)
except socket.error:
pass
def stdlog(name):
NAME=string.upper(name)+'_LOG'
if os.environ.has_key(NAME):
f=os.environ[NAME]
else:
f='/dev/null'
try: f=open(f,'a')
except: f=None
getattr(sys, name).close()
if f is not None: setattr(sys, name, f)
def main():
try:
import os, sys, string, traceback
pcgiPublisher = PCGIPublisher(os.environ)
if not pcgiPublisher.error:
pcgiPublisher.listen()
except ImportError:
print "Content-type: text/html"
print
print "PCGIPublisher catastrophic import error"
if __name__ == '__main__':
try:
main()
finally:
import os
if os.environ.has_key('PCGI_SOCKET_FILE'):
try: os.unlink(os.environ['PCGI_SOCKET_FILE'])
except os.error: pass
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment