Commit 843451b7 authored by 's avatar

*** empty log message ***

parent 1802f92d
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.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.
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