aboutsummaryrefslogtreecommitdiff
path: root/src/sman
diff options
context:
space:
mode:
authordos-reis <gdr@axiomatics.org>2007-08-14 05:14:52 +0000
committerdos-reis <gdr@axiomatics.org>2007-08-14 05:14:52 +0000
commitab8cc85adde879fb963c94d15675783f2cf4b183 (patch)
treec202482327f474583b750b2c45dedfc4e4312b1d /src/sman
downloadopen-axiom-ab8cc85adde879fb963c94d15675783f2cf4b183.tar.gz
Initial population.
Diffstat (limited to 'src/sman')
-rw-r--r--src/sman/ChangeLog83
-rw-r--r--src/sman/Makefile.in91
-rw-r--r--src/sman/Makefile.pamphlet145
-rw-r--r--src/sman/nagman.c.pamphlet636
-rw-r--r--src/sman/session.c.pamphlet601
-rw-r--r--src/sman/sman.c.pamphlet1111
-rw-r--r--src/sman/spadclient.c66
7 files changed, 2733 insertions, 0 deletions
diff --git a/src/sman/ChangeLog b/src/sman/ChangeLog
new file mode 100644
index 00000000..f433a88c
--- /dev/null
+++ b/src/sman/ChangeLog
@@ -0,0 +1,83 @@
+2007-08-10 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * sman.c.pamphlet (HypertexProgram): hypertex is installed in lib/
+ directory.
+
+2007-07-29 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * Makefile.pamphlet: Propagate libtoolization changes.
+ * Makefile.in: Regenerate.
+
+2007-04-09 Bill Page <bill.page1@synthesis.anikast.ca>
+
+ * Makefile.pamphlet (session_LDADD): Add extrac C runtime libraries.
+ (spadclient_LDADD): Likewise.
+ * Makefile.in: Regenerate.
+
+2007-04-08 Gabriel Dos Reis <gdr@cs.tamu.edu>
+ Bill Page <bill.page1@synthesis.anikast.ca>
+
+ * Makefile.pamphlet (sman_LDADD): Add extra runtime libraries.
+
+2006-12-15 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * sman.c.pamphlet: Don't include useproto.h. Avoid including
+ axiom-c-macros.h twice.
+ * session.c.pamphlet: Remove K&R C style function declarations.
+ Don't include useproto.h
+ * spadclient.c.pamphlet: Likewise.
+
+2006-11-29 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * sman.c.pamphlet (should_I_clef): Recover lost return type.
+
+2006-11-26 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * nagman.c.pamphlet: Include axiom-c-macros.h.
+ * session.c.pamphlet: Likewise.
+ * sman.c.pamphlet: Likewise.
+ * spadclient.c.pamphlet: Likewise.
+
+ * Makefile.pamphlet: Add support for OS that require extension for
+ executable binary files.
+ * Makefile.in: Regenerate.
+
+2006-11-23 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * Makefile.pamphlet ($(build_libdir)/libspad.a): Remove.
+ (LDFLAGS): Likewise.
+ (SMANOBJS): Likewise.
+ (LIB): Likewise.
+ (DOC): Likewise.
+
+2006-11-24 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * sman.c.pamphlet: Include "axiom-c-macros.h
+ Remove K&R C style function declarations.
+
+ * Makefile.pamphlet (DOC, CFLAGS, LDFLAGS, SMANOBJS): Remove.
+ (session_DEPENDENCIES): Clear.
+ (spadclient_DEPENDENCIES): Likewise.
+ (sman_DEPENDENCIES): Likewise.
+ * Makefile.in: Regenerate.
+
+2006-11-18 Bill Page <bill.page1@synthesis.anikast.ca>
+
+ * Makefile.pamphlet (LDFLAGS): Add X11 libraries flags.
+ * Makefile.in: Regenerate.
+
+2006-09-26 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * Makefile.pamphlet (all): Create stamp file.
+ * Makefile.in: Regenerate.
+
+2006-09-25 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * Makefile.pamphlet (${OUTLIB}/session, ${OUTLIB}/spadclient,
+ ${OUT}/sman): Fix thinko.
+
+2006-09-18 Gabriel Dos Reis <gdr@cs.tamu.edu>
+
+ * Makefile.pamphlet: Simplify.
+ * Makefile.in: Regenerate.
+
diff --git a/src/sman/Makefile.in b/src/sman/Makefile.in
new file mode 100644
index 00000000..ca0b270f
--- /dev/null
+++ b/src/sman/Makefile.in
@@ -0,0 +1,91 @@
+
+subdir = src/sman/
+
+# this is where to put the various commands
+OUT= $(axiom_target_bindir)
+OUTLIB= $(axiom_target_libdir)
+
+# this is where the include files live
+INC= $(axiom_src_srcdir)/include
+
+build_libdir = $(abs_top_builddir)/src/lib
+
+bin_PROGRAMS = session$(EXEEXT) \
+ spadclient$(EXEEXT) \
+ sman$(EXEEXT)
+
+libspad_la = $(axiom_target_libdir)/libspad.la
+
+session_sources = session.c
+session_SOURCES = $(addsuffix .pamphlet, $(session_sources))
+session_objects = $(session_sources:.c=.lo)
+session_LDADD = $(libspad_la) @axiom_c_runtime_extra@
+session_DEPENDENCIES =
+
+spadclient_sources = spadclient.c
+spadclient_objects = $(spadclient_sources:.c=.lo)
+spadclient_LDADD = $(libspad_la) @axiom_c_runtime_extra@
+spadclient_DEPENDENCIES =
+
+sman_sources = sman.c
+sman_SOURCES = $(addsuffix .pamphlet, $(sman_sources))
+sman_objects = $(sman_sources:.c=.lo)
+sman_LDADD = $(libspad_la) @axiom_c_runtime_extra@
+sman_DEPENDENCIES =
+
+
+pamphlets = $(session_SOURCES) $(sman_SOURCES)
+
+.PHONY: all all-sman
+
+all: all-ax
+
+all-ax all-sman: stamp
+
+stamp: $(OUTLIB)/session$(EXEEXT) \
+ $(OUTLIB)/spadclient$(EXEEXT) \
+ $(OUT)/sman$(EXEEXT)
+ -rm -f stamp
+ $(STAMP) stamp
+
+.SUFFIXES:
+.SUFFIXES: .c .h .lo .$(OBJEXT)
+.PRECIOUS: %.lo %.obj
+.PRECIOUS: %.c
+.PRECIOUS: %.h
+
+%.lo: %.c
+ $(COMPILE) ${CCF} -o $@ $(axiom_includes) -I$(builddir) $<
+
+%.c: $(srcdir)/%.c.pamphlet
+ $(axiom_build_document) --tangle --output=$@ $<
+
+${OUTLIB}/session$(EXEEXT): $(session_objects) $(session_DEPENDENCIES)
+ $(LINK) -o $@ $(session_objects) $(session_LDADD) ${LDF}
+
+${OUTLIB}/spadclient$(EXEEXT): $(spadclient_objects) $(spadclient_DEPENDENCIES)
+ $(LINK) -o $@ $(spadclient_objects) $(spadclient_LDADD) ${LDF}
+
+spadclient.$(OBJEXT): ${INC}/useproto.h ${INC}/spadclient.H1 \
+ $(axiom_configdir)/axiom-c-macros.h
+
+${OUT}/sman$(EXEEXT): $(sman_objects) $(sman_DEPENDENCIES)
+ $(LINK) -o $@ $(sman_objects) $(sman_LDADD) ${LDF}
+
+$(sman_objects): sman.h $(axiom_c_macros_h)
+
+sman.h: $(srcdir)/sman.c.pamphlet
+ $(axiom_build_document) --tangle=$@ --output=$@ $<
+
+mostlyclean-local:
+ @rm -f $(session_sources) $(session_objects) sman.h
+ @rm -f $(spadclient_sources) $(session_objects)
+ @rm -f $(sman_sources) $(sman_objects)
+
+clean-local: mostlyclean-local
+ @rm -f $(OUTLIB)/session$(EXEEXT)
+ @rm -f $(OUTLIB)/spadclient$(EXEEXT)
+ @rm -f $(OUT)/sman$(EXEEXT)
+
+distclean-local: clean-local
+
diff --git a/src/sman/Makefile.pamphlet b/src/sman/Makefile.pamphlet
new file mode 100644
index 00000000..db980d94
--- /dev/null
+++ b/src/sman/Makefile.pamphlet
@@ -0,0 +1,145 @@
+%% Oh Emacs, this is a -*- Makefile -*-, so give me tabs.
+\documentclass{article}
+\usepackage{axiom}
+
+\title{\$SPAD/src/sman Makefile}
+\author{Gabriel Dos~Reis \and Timothy Daly}
+
+\begin{document}
+\maketitle
+
+\begin{abstract}
+\end{abstract}
+\eject
+
+\tableofcontents
+\eject
+
+
+\section{Environment variables}
+
+<<environment>>=
+# this is where to put the various commands
+OUT= $(axiom_target_bindir)
+OUTLIB= $(axiom_target_libdir)
+
+# this is where the include files live
+INC= $(axiom_src_srcdir)/include
+
+build_libdir = $(abs_top_builddir)/src/lib
+
+bin_PROGRAMS = session$(EXEEXT) \
+ spadclient$(EXEEXT) \
+ sman$(EXEEXT)
+
+libspad_la = $(axiom_target_libdir)/libspad.la
+
+session_sources = session.c
+session_SOURCES = $(addsuffix .pamphlet, $(session_sources))
+session_objects = $(session_sources:.c=.lo)
+session_LDADD = $(libspad_la) @axiom_c_runtime_extra@
+session_DEPENDENCIES =
+
+spadclient_sources = spadclient.c
+spadclient_objects = $(spadclient_sources:.c=.lo)
+spadclient_LDADD = $(libspad_la) @axiom_c_runtime_extra@
+spadclient_DEPENDENCIES =
+
+sman_sources = sman.c
+sman_SOURCES = $(addsuffix .pamphlet, $(sman_sources))
+sman_objects = $(sman_sources:.c=.lo)
+sman_LDADD = $(libspad_la) @axiom_c_runtime_extra@
+sman_DEPENDENCIES =
+
+
+pamphlets = $(session_SOURCES) $(sman_SOURCES)
+@
+
+\section{session}
+<<session>>=
+${OUTLIB}/session$(EXEEXT): $(session_objects) $(session_DEPENDENCIES)
+ $(LINK) -o $@ $(session_objects) $(session_LDADD) ${LDF}
+@
+
+\section{nagman}
+Note that we do not build the nagman component as we do not have the
+necessary code (for instance, [[callnag]]).
+<<nagman>>=
+${OUT}/nagman$(EXEEXT): $(nagman_objects) $(nagman_DEPENDENCIES)
+ $(LINK) -o $@ $(nagman_objects) $(nagman_LDADD) ${LDF}
+@
+
+\section{spadclient}
+<<spadclient>>=
+${OUTLIB}/spadclient$(EXEEXT): $(spadclient_objects) $(spadclient_DEPENDENCIES)
+ $(LINK) -o $@ $(spadclient_objects) $(spadclient_LDADD) ${LDF}
+
+spadclient.$(OBJEXT): ${INC}/useproto.h ${INC}/spadclient.H1 \
+ $(axiom_configdir)/axiom-c-macros.h
+@
+
+\section{sman}
+<<sman>>=
+${OUT}/sman$(EXEEXT): $(sman_objects) $(sman_DEPENDENCIES)
+ $(LINK) -o $@ $(sman_objects) $(sman_LDADD) ${LDF}
+
+$(sman_objects): sman.h $(axiom_c_macros_h)
+
+sman.h: $(srcdir)/sman.c.pamphlet
+ $(axiom_build_document) --tangle=$@ --output=$@ $<
+@
+
+<<*>>=
+
+subdir = src/sman/
+
+<<environment>>
+
+.PHONY: all all-sman
+
+all: all-ax
+
+all-ax all-sman: stamp
+
+stamp: $(OUTLIB)/session$(EXEEXT) \
+ $(OUTLIB)/spadclient$(EXEEXT) \
+ $(OUT)/sman$(EXEEXT)
+ -rm -f stamp
+ $(STAMP) stamp
+
+.SUFFIXES:
+.SUFFIXES: .c .h .lo .$(OBJEXT)
+.PRECIOUS: %.lo %.obj
+.PRECIOUS: %.c
+.PRECIOUS: %.h
+
+%.lo: %.c
+ $(COMPILE) ${CCF} -o $@ $(axiom_includes) -I$(builddir) $<
+
+%.c: $(srcdir)/%.c.pamphlet
+ $(axiom_build_document) --tangle --output=$@ $<
+
+<<session>>
+
+<<spadclient>>
+
+<<sman>>
+
+mostlyclean-local:
+ @rm -f $(session_sources) $(session_objects) sman.h
+ @rm -f $(spadclient_sources) $(session_objects)
+ @rm -f $(sman_sources) $(sman_objects)
+
+clean-local: mostlyclean-local
+ @rm -f $(OUTLIB)/session$(EXEEXT)
+ @rm -f $(OUTLIB)/spadclient$(EXEEXT)
+ @rm -f $(OUT)/sman$(EXEEXT)
+
+distclean-local: clean-local
+
+@
+\eject
+\begin{thebibliography}{99}
+\bibitem{1} nothing
+\end{thebibliography}
+\end{document}
diff --git a/src/sman/nagman.c.pamphlet b/src/sman/nagman.c.pamphlet
new file mode 100644
index 00000000..c8db5f61
--- /dev/null
+++ b/src/sman/nagman.c.pamphlet
@@ -0,0 +1,636 @@
+\documentclass{article}
+\usepackage{axiom}
+\begin{document}
+\title{\$SPAD/src/sman nagman.c}
+\author{The Axiom Team}
+\maketitle
+\begin{abstract}
+\end{abstract}
+\eject
+\tableofcontents
+\eject
+\section{nag.x}
+<<nag.x>>=
+
+/*
+ * msg.x: Remote message printing protocol
+ */
+const MAXASP = 10;
+
+/*
+ * the nago structure is essentially a variable length string
+ */
+
+struct nago {
+ opaque z <>;
+ };
+struct nagerr {
+nago p;
+nago q;
+};
+
+struct host{
+nago h <>;
+};
+
+struct nagst {
+
+/* Okay, if you understand this bit you know the essentials of how the link
+ * works. h <> is an array of nago, which is an array of fortran source
+ * code, the length of the array being the no. of asps (0 for most routines).
+ * y is the actual (XDR) input data for the routine. nm is the name of the
+ * routine. id is a tag identifying the host/axiom session. Finally per is a
+ * number telling whether or not to erase old fortran files on the remote
+ * machine (persistence - the number per distinct fortran files will be
+ * stored, any more than this and earlier ones will be deleted.
+ */
+
+ nago h <>;
+ nago y;
+ nago nm;
+ nago id;
+ int per;
+ };
+program NAGPROG {
+ version NAGVERS {
+ nagerr CALLNAG(nagst) = 1;
+ nago NAGMON(int)=2;
+ void AXEND(nago)=3;
+ } = 1;
+/*
+ * the following number is very important. It tells the
+ * portmapper what number to register the nag daemon under.
+ * There are rules about which number to pick - check SUN
+ * technical info for more details
+ */
+} = 100088;
+
+
+@
+\section{nagman}
+\subsection{includes}
+<<includes>>=
+#include "axiom-c-macros.h"
+#include "useproto.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <termios.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <rpc/rpc.h> /* always needed */
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "nag.h" /* generated by rpcgen */
+#include "com.h"
+#include "bsdsignal.h"
+#include "sockio-c.H1"
+#include "bsdsignal.H1"
+#include "nagman.H1"
+
+@
+\subsection{variables}
+<<variables>>=
+#ifdef ALPHAplatform
+extern int getdomainname( char *, int );
+#endif
+#ifdef SUN4OS5platform
+extern int getdomainname( char *, int );
+extern int gethostname( char *, int );
+#endif
+
+#ifdef _NO_PROTO
+nagerr * callnag_1();
+nago * nagmon_1();
+void * axend_1();
+#else
+nagerr * callnag_1(nagst *,CLIENT *);
+nago * nagmon_1(int *,CLIENT *);
+void * axend_1(nago *,CLIENT *);
+#endif
+
+#define DO 1
+#define DONT 0
+
+int hnum, vmax;
+char *datafile, *resultsfile;
+
+struct hostnode {
+ char * name;
+ struct hostnode *next;
+} *hlist=NULL;
+
+nagst nag4;
+Sock *sock1;
+
+@
+\subsection{term}
+this code runs when the user quits axiom. before nagman dies, it does
+an rpc call to nagd to tell it to get rid of files etc. The rpc call in
+question is [[axend_1]]
+we also send a USR1 to sman to beget another nagman
+<<term>>=
+static void
+#ifdef _NO_PROTO
+term(sig)
+ int sig;
+#else
+term(int sig)
+#endif
+{
+ CLIENT *cld;
+ void *res;
+ struct hostnode *pnode;
+
+#ifndef HP9platform /* can't figure out a way to do this on HP/UX 9 */
+ kill(atoi(getenv("SPADNUM")) , SIGUSR1);
+#endif
+
+
+ if(hnum!=0)
+ {
+ unlink(datafile);
+ unlink(resultsfile);
+ }
+
+ for(pnode=hlist;pnode!=NULL;pnode=pnode->next)
+ {
+ cld=clnt_create(pnode->name,NAGPROG, NAGVERS, "tcp");
+ if (cld == NULL)
+ goto NOHOST;
+
+ res=axend_1(&(nag4.id),cld);
+ NOHOST:
+ clnt_destroy(cld);
+ }
+ exit(0);
+}
+
+@
+\subsection{size\_of\_file}
+<<sizeoffile>>=
+static long
+#ifdef _NO_PROTO
+size_of_file(filename)
+ char *filename;
+#else
+size_of_file(char *filename)
+#endif
+{
+ struct stat buf_stat;
+
+ stat(filename,&buf_stat);
+ return (buf_stat.st_size);
+
+}
+
+@
+\subsection{rpcloop}
+<<rpcloop>>=
+static void
+#ifdef _NO_PROTO
+rpcloop()
+#else
+rpcloop(void)
+#endif
+{
+ CLIENT *cl;
+ int res,j,v=0,u,showMessage;
+ long i;
+ register struct hostent *alias1, *alias2;
+ struct in_addr *addrnum;
+ u_long junk;
+ struct timeval tv;
+ nagerr *result;
+ char *Buf , *buf1;
+ char *ffile[MAXASP];
+ char routine[12], naghost[256];
+ FILE *nfp1, *nfp2, *nfp3;
+ struct hostnode *phost;
+ int fd;
+
+ for (;;)
+ {
+
+ if((Buf=get_string(sock1))==NULL) term(1); /* one string carries all */
+
+ if(hnum!=0)
+ {
+ /* call parameters */
+ free(nag4.nm.z.z_val); /* the routine name */
+ free(nag4.y.z.z_val); /* the XDR data */
+ for(i=0;i<v;i++)
+ {
+ unlink(ffile[i]);
+ free(ffile[i]); /* the asp filenames */
+ free(nag4.h.h_val[i].z.z_val); /* the asps themselves*/
+ }
+ free(nag4.h.h_val); /* the asps array */
+ unlink(datafile);
+ unlink(resultsfile);
+ free(resultsfile);
+ free(datafile);
+ vmax= (v>vmax)? v : vmax;
+ }
+
+
+
+
+ buf1=strtok(Buf," ");
+ if (buf1) strcpy(naghost,buf1);
+ else printf("can't parse the naghost\n");
+ /* INFO printf("%s\n",naghost);*/
+
+ buf1=strtok(NULL," ");
+ if (buf1) strcpy(routine,buf1);
+ else printf("can't parse the routine\n");
+ /* INFO printf("%s\n",routine);*/
+
+ /* make copy of filenames because we will reuse Buf before deleting the files*/
+ buf1=strtok(NULL," ");
+ if (buf1) resultsfile=strdup(buf1);
+ else printf("can't parse the resultsfile file\n");
+ /* INFO printf("%s\n",resultsfile);*/
+
+ buf1=strtok(NULL," ");
+ if (buf1) datafile=strdup(buf1);
+ else printf("can't parse the datafile file\n");
+ /* INFO printf("%s\n",datafile);*/
+
+ buf1=strtok(NULL," ");
+ if (buf1) nag4.per=atoi(buf1);
+ else printf("can't parse the persistence\n");
+ /* INFO printf("%d\n",nag4.per);*/
+
+ buf1=strtok(NULL," ");
+ if (buf1) {
+ if (!strcmp(buf1,"on")) showMessage=DO;
+ else showMessage=DONT;
+ }
+ else printf("can't parse the messages flag\n");
+ /* INFO printf("%s\n",buf1);*/
+
+ v=0; /* asp counter */
+ while( (buf1=strtok(NULL," ")) )
+ {
+ ffile[v++]=strdup(buf1);
+ /* INFO printf("%s\n",ffile[v-1]);*/
+ }
+
+ /* INFO printf("number of asps seen %d\n",v);*/
+
+ if(showMessage==DO) printf("nagman:acknowledging request for %s\n",routine);
+
+ res=0; /* prepare result integer to be sent to Lisp */
+
+ if((nfp3=fopen(resultsfile,"w"))==NULL)
+ {
+ printf("can't open output file\n");
+ goto END;
+ }
+
+ /* nag4.h is the XDR array of asp text */
+ nag4.h.h_len=v;
+ nag4.h.h_val=(nago *)malloc((v)*sizeof(nago));
+
+
+ /* get asp text in call argument */
+ for(u=0;u<v;u++)
+ {
+ /* this should be done by mmap */
+ if((nfp1=fopen(ffile[u],"r"))==NULL)
+ {
+ fprintf(stderr,"can't open asp file %s\n",ffile[u]);
+ fclose(nfp1);
+ goto END;
+ }
+ fclose(nfp1);
+ i=size_of_file(ffile[u]);
+
+ /* allocs memory for the file */
+ nag4.h.h_val[u].z.z_val= (char *)malloc((i+1)*sizeof(char));
+
+ fd=open(ffile[u],O_RDONLY);
+ read(fd,nag4.h.h_val[u].z.z_val,i);
+ close(fd);
+ /* make null-term. string */
+ nag4.h.h_val[u].z.z_val[i]='\0';
+ /* set the length */
+ nag4.h.h_val[u].z.z_len=strlen(nag4.h.h_val[u].z.z_val);
+ }
+
+
+ nag4.nm.z.z_val=strdup(routine);
+ nag4.nm.z.z_len=strlen(routine);
+
+ /* get XDR data in call argument */
+ /* should be done by mmap */
+ if((nfp2=fopen(datafile,"r"))==NULL)
+ {
+ fprintf(stderr,"can't open data file\n");
+ fclose(nfp2);
+ goto END;
+ }
+
+ fclose(nfp2);
+ i=size_of_file(datafile);
+ nag4.y.z.z_val=(char *)malloc(i*sizeof(char));
+
+ fd=open(datafile,O_RDONLY);
+ read(fd,nag4.y.z.z_val,i);
+ close(fd);
+ nag4.y.z.z_len=i;
+
+
+ /*
+ * Create client "handle" used for calling MESSAGEPROG on
+ * the server designated on the command line. We tell
+ * the RPC package to use the "tcp" protocol when
+ * contacting the server.
+ */
+
+ /* update naghost by lookup */
+
+ if ((junk = inet_addr(naghost))!=-1)
+ {
+ addrnum=(struct in_addr *)junk;
+ if((alias2=gethostbyaddr((char *)&addrnum,
+ sizeof(addrnum),
+ AF_INET))!=NULL)
+ strcpy(naghost,alias2->h_name);
+ else
+ if((alias1=gethostbyname(naghost))!=NULL)
+ strcpy(naghost,alias1->h_name);
+ }
+ else
+ if((alias1=gethostbyname(naghost))!=NULL)
+ strcpy(naghost,alias1->h_name);
+
+
+
+
+ cl = clnt_create(naghost, NAGPROG, NAGVERS, "tcp");
+ if (cl == NULL)
+ {
+ /*
+ * Couldn't establish connection with server.
+ * Print error message and die.
+ */
+ clnt_pcreateerror(naghost);
+ goto END;
+ }
+ else
+ if (showMessage==DO)
+ printf("nagman:connection successful to %s\n",naghost);
+
+ /*
+ * this number here sets the "timeout" for the rpc call. after this number
+ * of seconds, the call will quit if no response is received
+ *
+ */
+
+ tv.tv_sec=1000000;
+ tv.tv_usec=0;
+ clnt_control(cl,CLSET_TIMEOUT,(char *)&tv);
+
+
+ result = callnag_1(&nag4, cl);
+
+ for(phost=hlist;phost!=NULL;phost=phost->next)
+ {
+ /*
+ * hlist is the "hostlist" of sites that have been contacted by nagman.
+ * here we check if this call is contacting a new site, and if so add it
+ * to the hostlist
+ *
+ */
+
+ if(!strcmp(phost->name,naghost))
+ goto SKIP;
+ }
+
+ if(hnum==0) {
+ hlist=(struct hostnode *)malloc(sizeof(struct hostnode));
+ hlist->name=strdup(naghost);
+ hlist->next=NULL;
+ }
+
+ else {
+ phost=(struct hostnode *)malloc(sizeof(struct hostnode));
+ phost->name=strdup(naghost);
+ phost->next=hlist;
+ hlist=phost;
+ }
+ hnum++;
+
+
+ SKIP:
+ if (result == NULL)
+ {
+ /*
+ * An error occurred while calling the server.
+ * Print error message and die.
+ */
+ if (showMessage==DO)
+ printf("nagman:no results (error) from %s\n",naghost);
+ clnt_perror(cl,naghost);
+ clnt_destroy(cl);
+ goto END;
+ }
+
+ /*
+ * (*result).p is the part of the result with the XDRed results in it
+ * (numbers). (*result).q is the part with (text) error messages that
+ * have come from the NAG library. If there is neither an XDR result,
+ * nor a text error message from the library, then something is wrong
+ * so we just print out the "no result or error returned" message.
+ *
+ */
+
+ else if ((*result).p.z.z_len==0)
+ {
+ if((*result).q.z.z_len==0)
+ {
+ if (showMessage==DO)
+ printf("nagman:empty result (error) from %s\n",naghost);
+ clnt_destroy(cl);
+ goto END;
+ }
+ else
+ {
+ if (showMessage==DO)
+ printf("nagman:receiving results from %s\n\n",naghost);
+ for(j=0;j<(*result).q.z.z_len;j++)
+ printf("%c",(*result).q.z.z_val[j]);
+ clnt_destroy(cl);
+ goto END;
+ }
+ }
+ else
+ if (showMessage==DO)
+ printf("nagman:receiving results from %s\n\n",naghost);
+
+ if (showMessage==DO)
+ fwrite(result->q.z.z_val,sizeof(char),result->q.z.z_len,stdout);
+
+ /*INFO printf("\nRESULTS of length %d\n",(*result).p.z.z_len);*/
+
+ fwrite(result->p.z.z_val,sizeof(char),result->p.z.z_len, nfp3);
+ res=1;
+ clnt_destroy(cl);
+
+ /*
+ * in case of any type of error, a goto END in the above code causes
+ * nagman to skip here and return to AXIOM
+ *
+ */
+
+
+ END:
+ fclose(nfp3);
+ /*
+ * if everything has gone alright, send_int returns the integer res=1. If
+ * not it returns res=0. This is detected by the boot code which acts
+ * accordingly.
+ */
+ send_int(sock1,res);
+ free(Buf);
+ }
+
+
+}
+
+@
+\subsection{catchSignals}
+catchSignals sets up signal handling. If nagman gets a sigterm it does not
+die but goes back to rpcloop
+<<catchSignals>>=
+static void
+#ifdef _NO_PROTO
+catchSignals()
+#else
+catchSignals(void)
+#endif
+{
+ bsdSignal(SIGTERM,term,RestartSystemCalls);
+ bsdSignal(SIGSEGV,term,RestartSystemCalls);
+}
+
+@
+\subsection{main}
+<<main>>=
+void
+#ifdef _NO_PROTO
+main(argc,argv)
+int argc;
+char **argv;
+#else
+main(int argc,char **argv)
+#endif
+{
+ char this[256],*hname,*dname,*spadnum;
+ int stat;
+
+ catchSignals();
+ stat=gethostname(this,256);
+ if (stat!=0) perror("gethostname");
+ hname=strdup(this);
+
+ stat=getdomainname(this,256);
+ if (stat!=0) perror("getdomainname");
+ dname=strdup(this);
+ spadnum=getenv("SPADNUM");
+ if (spadnum==0) {
+ fprintf(stderr,"nagman error: SPADNUM is not in the environment\n");
+ exit(0);
+ }
+
+ /* some machines return a full name from hostname
+ need to check hname has a . in it */
+
+ if (strchr(hname,'.'))
+ /* '.' found */
+ sprintf(this,"%s_%i",hname,atoi(spadnum));
+ else
+ /* substring not found */
+ sprintf(this,"%s.%s_%i",hname,dname,atoi(spadnum));
+
+ /* this must contain the Internet address of the current host */
+ nag4.id.z.z_val=strdup(this);
+ nag4.id.z.z_len=strlen(nag4.id.z.z_val);
+ hnum=0;
+ vmax=0;
+ /*
+ * this line sets up a socket for communication with the lisp
+ */
+
+ sock1 = connect_to_local_server(SpadServer, DebugWindow, 120 /*seconds*/);
+ if (!sock1) exit(0);
+
+ rpcloop();
+}
+
+@
+\subsection{nagman}
+<<nagman>>=
+#define _NAGMAN_C
+<<includes>>
+<<variables>>
+<<term>>
+<<sizeoffile>>
+<<rpcloop>>
+<<catchSignals>>
+<<main>>
+@
+\section{License}
+<<license>>=
+/*
+Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - 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.
+
+ - Neither the name of The Numerical ALgorithms Group Ltd. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER
+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.
+*/
+
+@
+<<*>>=
+<<license>>
+<<nagman>>
+@
+\eject
+\begin{thebibliography}{99}
+\bibitem{1} nothing
+\end{thebibliography}
+\end{document}
diff --git a/src/sman/session.c.pamphlet b/src/sman/session.c.pamphlet
new file mode 100644
index 00000000..8b6f3e92
--- /dev/null
+++ b/src/sman/session.c.pamphlet
@@ -0,0 +1,601 @@
+\documentclass{article}
+\usepackage{axiom}
+\begin{document}
+\title{\$SPAD/src/sman session.c}
+\author{The Axiom Team}
+\maketitle
+\begin{abstract}
+\end{abstract}
+\eject
+\tableofcontents
+\eject
+\section{session}
+\subsection{includes}
+<<includes>>=
+#include "axiom-c-macros.h"
+#include <stdlib.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#ifdef SGIplatform
+#include <bstring.h>
+#endif
+#include "com.h"
+#include "bsdsignal.h"
+#include "sockio-c.H1"
+#include "bsdsignal.H1"
+#include "session.H1"
+
+@
+\subsection{variables}
+<<variables>>=
+#define BufSize 4096 /* size of communication buffer */
+
+typedef struct sock_list { /* linked list of Sock */
+ Sock Socket;
+ struct sock_list *next;
+} Sock_List;
+
+Sock *spad_io = (Sock *) 0; /* to_server socket for SessionIO */
+Sock *spad_server = (Sock *) 0; /* to_server socket for SpadServer */
+Sock *menu_client = (Sock *) 0; /* to_client socket for MenuServerName */
+Sock *active_session = (Sock *) 0; /* pointer to currently active session */
+
+Sock_List *plSock = (Sock_List *) 0;
+
+char big_bad_buf[BufSize]; /* big I/O buffer */
+int num_active_clients = 0; /* number of InterpWindows attached */
+int reading_output = 0;
+fd_set session_socket_mask;
+
+@
+\subsection{usr1\_handler}
+<<usr1handler>>=
+static void
+usr1_handler(int sig)
+{
+ return;
+}
+
+@
+\subsection{usr2\_handler}
+SIGUSR2 is generated by spadclients.
+We interpret it as an interrupt for the Lisp.
+<<usr2handler>>=
+static void
+usr2_handler(int sig)
+{
+ send_signal(spad_server, SIGINT);
+ return;
+}
+
+@
+\subsection{term\_handler}
+<<termhandler>>=
+static void
+term_handler(int sig)
+{
+ exit(1);
+}
+
+@
+\subsection{pr}
+<<pr>>=
+static void
+pr()
+{
+ Sock_List *pSock;
+
+ fprintf(stderr,"The socket list:\n");
+ for(pSock=plSock;pSock!=(Sock_List *)0;pSock=pSock->next){
+ fprintf(stderr,"(%d,%d,%d)\t",pSock->Socket.pid,2<<(pSock->Socket.socket),pSock->Socket.frame);
+ }
+ fprintf(stderr,"\n");
+}
+
+@
+\subsection{close\_client}
+<<closeclient>>=
+static void
+close_client(int frame)
+{
+ Sock_List *pSock,*locSock;
+ int socket_fd;
+
+ /* we will check for frame equality,
+ kill with send_signal,
+ notify HyperTex so that it updates its list (if it's a spadbuf),
+ repair the list,
+ unset the active_session,
+ update num_active_clients
+ */
+
+
+ /* first check head */
+#ifdef DEBUG
+fprintf(stderr,"close_client(%d)\n",frame);
+#endif
+
+ if ( (plSock) && (plSock->Socket.frame == frame) ){
+ socket_fd = plSock->Socket.socket;
+ send_signal((Sock *)plSock, SIGTERM);
+ if ( menu_client != (Sock *) 0){
+ send_int(menu_client,CloseClient);
+ send_int(menu_client,(*plSock).Socket.pid);
+ }
+#ifdef DEBUG
+fprintf(stderr,"trying to clear %u\n",socket_fd);
+#endif
+ FD_CLR(socket_fd,&session_socket_mask);
+ locSock = plSock;
+ if ((*plSock).next == (Sock_List *) 0)
+ {plSock = (Sock_List *) 0;}
+ else
+ {plSock = plSock->next;}
+ active_session = (Sock *) 0;
+ num_active_clients--;
+ free(locSock);
+ }
+
+ /* now check the rest */
+
+ else {
+ for (pSock=plSock; pSock->next != (Sock_List *) 0 ; pSock=pSock->next)
+ if (pSock->next->Socket.frame == frame){
+ socket_fd = pSock->next->Socket.socket;
+ send_signal((Sock *)pSock->next, SIGTERM);
+ if ( menu_client != (Sock *) 0){
+ send_int(menu_client,CloseClient);
+ send_int(menu_client,(*plSock).Socket.pid);
+ }
+#ifdef DEBUG
+fprintf(stderr,"trying to clear %u\n",socket_fd);
+#endif
+ FD_CLR(socket_fd,&session_socket_mask);
+ locSock = pSock->next;
+ if ( pSock->next->next == (Sock_List *) 0 )
+ { pSock->next= (Sock_List *) 0;}
+ else
+ { pSock->next = pSock->next->next;}
+ num_active_clients--;
+ active_session = (Sock *) 0;
+ free(locSock);
+ break;
+ }
+ }
+#ifdef DEBUG
+pr();
+#endif
+}
+
+@
+\subsection{read\_SpadServer\_command}
+<<readSpadServercommand>>=
+static void
+read_SpadServer_command(void)
+{
+ int cmd, frame, num;
+ cmd = get_int(spad_server);
+ switch (cmd) {
+ case EndOfOutput:
+ if (menu_client != (Sock *) 0) send_signal(menu_client, SIGUSR2);
+ if (reading_output != 0) reading_output = 0;
+ break;
+ case QueryClients:
+ /* don't count MenuServer */
+ num = num_active_clients ;
+ send_int(spad_server, num);
+ break;
+ case CloseClient:
+ frame = get_int(spad_server);
+ if (frame != -1) close_client(frame);
+ break;
+ case SendXEventToHyperTeX:
+ break;
+ default:
+ fprintf(stderr, "session : unknown command from SpadServer %d\n", cmd);
+ break;
+ }
+}
+
+@
+\subsection{test\_sock\_for\_process}
+<<testsockforprocess>>=
+static int
+test_sock_for_process(Sock *sock)
+{
+ if (sock == (Sock *)0 ) return -1;
+ return kill(sock->pid, 0);
+}
+
+@
+\subsection{read\_menu\_client\_command}
+<<readmenuclientcommand>>=
+static void
+read_menu_client_command(void)
+{
+ int cmd,frame, i,socket_fd;
+ Sock_List *pSock;
+
+ /* save it for possible clearing */
+ socket_fd = menu_client->socket;
+
+ if (test_sock_for_process(menu_client) == -1) {
+ FD_CLR(socket_fd,&session_socket_mask);
+ menu_client = (Sock *) 0;
+ reading_output = 0;
+ return;
+ }
+ cmd = get_int(menu_client);
+ switch(cmd) {
+ case -1: /* socket closed */
+ FD_CLR(socket_fd,&session_socket_mask);
+ menu_client = (Sock *) 0;
+ reading_output = 0;
+ break;
+ case SwitchFrames:
+#ifdef DEBUG
+fprintf(stderr,"menu:SwitchFrames\n");
+#endif
+ frame = get_int(menu_client);
+ send_int(spad_server, SwitchFrames);
+ send_int(spad_server, frame);
+ for(i=0,pSock=plSock; pSock != (Sock_List *) 0 ; i++,pSock=pSock->next)
+ if ((pSock->Socket.frame == frame)) {
+ active_session = (Sock *)pSock;
+ reading_output = 1;
+ break;
+ }
+ if (i == num_active_clients) {
+ /* fprintf(stderr, "Couldn't find socket for frame %d\n", frame); */
+ }
+ break;
+ case QuerySpad:
+#ifdef DEBUG
+fprintf(stderr,"menu:QuerySpad\n");
+#endif
+ send_int(menu_client, reading_output);
+ break;
+ default:
+ fprintf(stderr, "session : unknown command from MenuServer: %d\n", cmd);
+ menu_client = (Sock *) 0;
+ break;
+ }
+}
+
+@
+\subsection{read\_from\_spad\_io}
+<<readfromspadio>>=
+static void
+read_from_spad_io(void)
+{
+ int ret_code;
+ ret_code = sread(spad_io, big_bad_buf, BufSize, "session: stdout socket");
+ if (ret_code == -1) return;
+ if(active_session != (Sock *) 0) {
+ ret_code = swrite(active_session, big_bad_buf, ret_code,
+ NULL);
+ }
+}
+
+@
+\subsection{kill\_spad}
+<<killspad>>=
+static void
+kill_spad(void)
+{
+ int i;
+ Sock_List *pSock;
+
+ send_signal(spad_server, SIGTERM);
+ for (pSock=plSock,i=0;
+ (i<num_active_clients) && (pSock != (Sock_List *) 0);
+ i++,pSock=pSock->next) {
+ if ((pSock->Socket).socket != 0)
+ send_signal((Sock *)pSock, SIGTERM);
+ }
+ if (menu_client != (Sock *) 0) send_signal(menu_client, SIGTERM);
+ exit(0);
+}
+
+@
+\subsection{accept\_session\_connection}
+<<acceptsessionconnection>>=
+static int
+accept_session_connection(Sock *server_sock)
+{
+ int sock_fd, ret_code;
+ Sock_List *pls;
+
+ /* Could be three things : KillSpad MenuServer InterpWindow */
+
+ pls = (Sock_List *) malloc(sizeof (Sock_List));
+ sock_fd = accept(server_sock->socket, 0, 0);
+ if (sock_fd == -1) {
+ perror("session : accepting connection");
+ return -1;
+ }
+ (pls->Socket).socket = sock_fd;
+ get_socket_type((Sock *)pls);
+
+ switch((pls->Socket).purpose) {
+ case KillSpad:
+ kill_spad();
+ return KillSpad;
+ free(pls);
+ case MenuServer:
+#ifdef DEBUG
+ fprintf(stderr,"session: accepted MenuServer , fd = %d\n",sock_fd);
+#endif
+ menu_client = &(pls->Socket);
+ FD_SET(menu_client->socket, &session_socket_mask);
+ return MenuServer;
+ case InterpWindow:
+#ifdef DEBUG
+ fprintf(stderr,"session: accepted InterpWindow , fd = %d\n",sock_fd);
+#endif
+
+ /* new Sock is put at the head of the list */
+ if (plSock == (Sock_List *)0 ) {
+ plSock = pls;
+ plSock->next = (Sock_List *)0 ;
+ }
+ else{
+ pls->next = plSock;
+ plSock = pls;
+ }
+
+ /* we need to maintain session_socket_mask here since we roll our own accept */
+
+ FD_SET(plSock->Socket.socket, &session_socket_mask);
+ send_int(spad_server, CreateFrame);
+ plSock->Socket.frame = get_int(spad_server);
+ active_session = (Sock *)plSock;
+ get_string_buf(spad_server, big_bad_buf, BufSize);
+ ret_code = swrite((Sock *)plSock, big_bad_buf, strlen(big_bad_buf)+1,
+ "session: writing to InterpWindow");
+ if (ret_code == -1)
+ return -1;
+ num_active_clients++;
+#ifdef DEBUG
+pr();
+#endif
+ return plSock->Socket.purpose;
+ }
+ return (-1);
+}
+
+@
+\subsection{read\_from\_session}
+<<readfromsession>>=
+static void
+read_from_session(Sock *sock)
+{
+ int ret_code;
+ if (sock != active_session) {
+ send_int(spad_server, SwitchFrames);
+ send_int(spad_server, sock->frame);
+ }
+ active_session = sock;
+ ret_code = sread(sock, big_bad_buf, BufSize,
+ "session: reading InterpWindow");
+ if (ret_code == -1) {
+ active_session = (Sock *) 0;
+ reading_output = 0;
+ return;
+ }
+ ret_code = swrite(spad_io, big_bad_buf, ret_code,
+ "session: writing SessionIO");
+ if (ret_code == -1) {
+ active_session = (Sock *)0 ;
+ reading_output = 0;
+ return;
+ }
+ reading_output = 1;
+}
+
+@
+\subsection{manage\_sessions}
+<<managesessions>>=
+static void
+manage_sessions(void)
+{
+ int ret_code;
+ fd_set rd, wr, ex;
+ Sock_List *pSock;
+
+ reading_output = 0;
+ while (1) {
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&ex);
+
+ /* Allow server socket and all connections if not waiting for output
+ socket_mask is maintained by libspad.a */
+#ifdef DEBUG
+fprintf(stderr,"session_socket_mask=%u ",*((long *)session_socket_mask.fds_bits));
+#endif
+ rd = session_socket_mask;
+ if (!reading_output) {
+ rd = session_socket_mask;
+ }
+
+ /* Allow the active_session if set */
+ if (active_session) FD_SET(active_session->socket, &rd);
+#ifdef DEBUG
+fprintf(stderr,"[rd=%u ",*((long *)rd.fds_bits));
+#endif
+
+ ret_code = sselect(FD_SETSIZE, &rd, &wr, &ex, NULL);
+ if (ret_code == -1) {
+ break;
+ }
+#ifdef DEBUG
+fprintf(stderr,"rd=%u]\n",*((long *)rd.fds_bits));
+#endif
+
+ if ((menu_client != (Sock *) 0) && FD_ISSET(menu_client->socket, &rd)) {
+ /* MenuServer wants to talk */
+ read_menu_client_command(); }
+
+
+ if (FD_ISSET(spad_io->socket, &rd)) {
+ /* Lisp has output */
+ read_from_spad_io(); }
+
+
+ if (FD_ISSET(server[1].socket, &rd)) {
+ /* Someone wants to connect to our server socket */
+ accept_session_connection(server+1); }
+
+
+ for(pSock=plSock; pSock != (Sock_List *) 0 ; pSock=pSock->next) {
+ if ((active_session == (Sock *)pSock || !reading_output) &&
+ (pSock->Socket).socket>0 && FD_ISSET(pSock->Socket.socket, &rd)) {
+ /* An InterpWindow */
+ read_from_session((Sock *)pSock); }
+ }
+
+
+ if (FD_ISSET(spad_server->socket, &rd)) {
+ /* The Lisp socket */
+ read_SpadServer_command(); }
+ }
+}
+
+@
+\subsection{main}
+<<main>>=
+int
+main(void)
+{
+
+#ifdef DEBUG2
+ /* delay for attaching with debugger before interesting things happen */
+ sleep(30);
+#endif
+
+ /* spad_server connects to Lisp server socket
+ read_SpadServer_command handles requests */
+ spad_server = connect_to_local_server(SpadServer, SessionManager, Forever);
+ if (spad_server == (Sock *) 0) {
+ fprintf(stderr, "session: Cannot connect to AXIOM server!\n");
+ exit(0);
+ }
+ else {
+#ifdef DEBUG
+ fprintf(stderr, "session: connected SpadServer , fd = %d\n",
+ spad_server->socket);
+#endif
+ FD_SET(spad_server->socket, &session_socket_mask);
+ }
+
+
+ /* spad_io connects to SessionIOName server socket
+ this is Lisp std IO read_from_spad_io handles requests */
+ spad_io = connect_to_local_server(SessionIOName, SessionIO, Forever);
+ if (spad_io == (Sock *) 0) {
+ fprintf(stderr, "session: Cannot connect to AXIOM IO!\n");
+ exit(0);
+ }
+ else {
+#ifdef DEBUG
+ fprintf(stderr,"session: connected SessionIOName , fd = %d\n",
+ spad_io->socket);
+#endif
+ FD_SET(spad_io->socket, &session_socket_mask);
+ }
+ bsdSignal(SIGUSR2, usr2_handler,DontRestartSystemCalls);
+ bsdSignal(SIGUSR1, usr1_handler,RestartSystemCalls);
+ bsdSignal(SIGINT, SIG_IGN,RestartSystemCalls);
+ bsdSignal(SIGTERM, term_handler,RestartSystemCalls);
+
+ /* open_server opens the server socket so that we can accept connections
+ we expect connections from spadbuf/spadclient(purpose:InterpWindow)
+ and hypertex (MenuServer) */
+
+ if (open_server(SessionServer) == -2) {
+ fprintf(stderr, "session: Cannot make server socket!\n");
+ exit(-1);
+ }
+ else {
+#ifdef DEBUG
+ fprintf(stderr, "session: opened SessionServer , fd = %d\n",
+ server[1].socket);
+#endif
+ FD_SET(server[1].socket,&session_socket_mask);
+ }
+ manage_sessions();
+ return(0);
+}
+
+@
+\subsection{session}
+<<session>>=
+/* #define DEBUG */
+#define _SESSION_C
+
+<<includes>>
+<<variables>>
+<<usr1handler>>
+<<usr2handler>>
+<<termhandler>>
+<<pr>>
+<<closeclient>>
+<<readSpadServercommand>>
+<<testsockforprocess>>
+<<readmenuclientcommand>>
+<<readfromspadio>>
+<<killspad>>
+<<acceptsessionconnection>>
+<<readfromsession>>
+<<managesessions>>
+<<main>>
+
+@
+\section{License}
+<<license>>=
+/*
+Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - 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.
+
+ - Neither the name of The Numerical ALgorithms Group Ltd. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER
+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.
+*/
+
+@
+<<*>>=
+<<license>>
+<<session>>
+@
+\eject
+\begin{thebibliography}{99}
+\bibitem{1} nothing
+\end{thebibliography}
+\end{document}
diff --git a/src/sman/sman.c.pamphlet b/src/sman/sman.c.pamphlet
new file mode 100644
index 00000000..d0419627
--- /dev/null
+++ b/src/sman/sman.c.pamphlet
@@ -0,0 +1,1111 @@
+\documentclass{article}
+\usepackage{axiom}
+
+\title{\$SPAD/src/sman sman}
+\author{The Axiom Team}
+
+\begin{document}
+\maketitle
+
+\begin{abstract}
+\end{abstract}
+\eject
+
+\tableofcontents
+\eject
+
+\section{sman.h}
+<<sman.h>>=
+/* Process control definitions. Used by fork_you and spawn_of_hell */
+
+/* When a process dies it kills off everything else */
+#define Die 1
+/* When a process dies, do nothing */
+#define NadaDelShitsky 2
+/* When a process dies start it up again */
+#define DoItAgain 3
+
+typedef struct spad_proc {
+ int proc_id; /* process id of child */
+ int death_action; /* one of the above constants */
+ char *command; /* sh command line to restart the process */
+ struct spad_proc *next;
+} SpadProcess;
+
+@
+\section{sman}
+\subsection{includes}
+<<includes>>=
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#include "axiom-c-macros.h"
+
+#if defined(SUN4OS5platform) || defined(HP10platform)
+#include <sys/stropts.h>
+#endif
+
+#include "com.h"
+#include "bsdsignal.h"
+#include "sman.h"
+
+#include "bsdsignal.H1"
+#include "sockio-c.H1"
+#include "openpty.H1"
+#include "sman.H1"
+
+@
+\subsection{variables}
+We add a debug flag so we can print information about what \Tool{sman}
+is trying to do. This change is pervasive as it touches nearly every
+routine.
+<<debugflag>>=
+int tpd=0; /* to-print-debug information */
+@
+This line is no longer used. We would completely elide it except that
+it would raise spurious issues about deleting credit and/or copyright
+information.
+\begin{verbatim}
+char *start_line =
+"AKCL (Austin Kyoto Common Lisp) Version(1.568) Thu Aug 22 16:49:01 EDT 1991\
+\r\nContains Enhancements by W. Schelter\r\n";
+\end{verbatim}
+We modified the place where the command list lives.
+The command list used to live in
+\begin{verbatim}
+$AXIOM/../../share/algebra/command.list
+\end{verbatim}
+but the open source version of the system no longer has a share
+subdirectory so we move this to the lib subdirectory.
+<<clefprogram>>=
+char *ClefProgram =
+ "$AXIOM/bin/clef -f $AXIOM/lib/command.list -e ";
+@
+and we change the command line arguments
+<<clefprogram1>>=
+ ClefProgram =
+ strcat(ClefCommandLine, " -f $AXIOM/lib/command.list -e ");
+@
+<<variables>>=
+char *ws_path; /* location of the AXIOM executable */
+int start_clef; /* start clef under spad */
+int start_graphics; /* start the viewman */
+int start_nagman; /* start the nagman */
+int start_ht; /* start hypertex */
+int start_spadclient; /* Start the client spad buffer */
+int start_local_spadclient; /* Start the client spad buffer */
+int use_X; /* Use the X windows environment */
+int server_num; /* AXIOM server number */
+<<debugflag>>
+
+/************************************************/
+/* definitions of programs which sman can start */
+/************************************************/
+
+char *GraphicsProgram = "$AXIOM/lib/viewman";
+char *NagManagerProgram = "$AXIOM/lib/nagman";
+char *HypertexProgram = "$AXIOM/lib/hypertex -s";
+<<clefprogram>>
+char *SessionManagerProgram = "$AXIOM/lib/session";
+char *SpadClientProgram = "$AXIOM/lib/spadclient";
+char *PasteFile = NULL;
+char *MakeRecordFile = NULL;
+char *VerifyRecordFile = NULL;
+
+SpadProcess *spad_process_list = NULL;
+/***************************/
+/* sman defaults file name */
+/***************************/
+
+#define SpadDefaultFile "spadprof.input"
+
+char ClefCommandLine[256];
+
+#define BufSize 4096 /* size of communication buffer */
+char big_bad_buf[BufSize]; /* big I/O buffer */
+
+Sock *session_io = NULL; /* socket connecting to session manager */
+
+/***********************************************************/
+/* Some characters used and externally defined in edible.h */
+/***********************************************************/
+
+unsigned char _INTR, _QUIT, _ERASE, _KILL, _EOF, _EOL, _RES1, _RES2;
+
+/*************************************/
+/* Stuff for opening pseudo-terminal */
+/*************************************/
+
+int ptsNum, ptcNum;
+char ptsPath[20], ptcPath[20];
+
+char **new_envp; /* new environment for AXIOM */
+int child_pid; /* child's process id */
+struct termios oldbuf; /* the original settings */
+struct termios childbuf; /* terminal structure for user i/o */
+
+
+int nagman_signal=0;
+int death_signal = 0;
+
+@
+\subsection{process\_arguments}
+<<processarguments>>=
+static void
+process_arguments(int argc,char ** argv)
+{
+ int arg;
+ if (tpd == 1) fprintf(stderr,"sman:process_arguments entered\n");
+ for (arg = 1; arg < argc; arg++) {
+ if (strcmp(argv[arg], "-debug") == 0)
+ tpd = 1;
+ else if (strcmp(argv[arg], "-noclef") == 0)
+ start_clef = 0;
+ else if (strcmp(argv[arg], "-clef") == 0)
+ start_clef = 1;
+ else if (strcmp(argv[arg], "-gr") == 0)
+ start_graphics = 1;
+ else if (strcmp(argv[arg], "-nogr") == 0)
+ start_graphics = 0;
+ else if (strcmp(argv[arg], "-nag") == 0)
+ start_nagman = 1;
+ else if (strcmp(argv[arg], "-nonag") == 0)
+ start_nagman = 0;
+ else if (strcmp(argv[arg], "-ht") == 0)
+ start_ht = 1;
+ else if (strcmp(argv[arg], "-noht") == 0)
+ start_ht = 0;
+ else if (strcmp(argv[arg], "-iw") == 0)
+ start_spadclient = 1;
+ else if (strcmp(argv[arg], "-ihere") == 0)
+ start_local_spadclient = 1;
+ else if (strcmp(argv[arg], "-noihere") == 0)
+ start_local_spadclient = 0;
+ else if (strcmp(argv[arg], "-noiw") == 0)
+ start_spadclient = 0;
+ else if (strcmp(argv[arg], "-ws") == 0)
+ ws_path = argv[++arg];
+ else if (strcmp(argv[arg], "-comp") == 0)
+ ws_path = "$AXIOM/etc/images/comp";
+ else if (strcmp(argv[arg], "-nox") == 0)
+ {
+ use_X = 0;
+ start_local_spadclient = 1;
+ start_spadclient = 0;
+ start_ht = 0;
+ start_graphics = 0;
+ }
+ else if (strcmp(argv[arg], "-grprog") == 0)
+ GraphicsProgram = argv[++arg];
+ else if (strcmp(argv[arg], "-nagprog") == 0)
+ NagManagerProgram = argv[++arg];
+ else if (strcmp(argv[arg], "-htprog") == 0)
+ HypertexProgram = argv[++arg];
+ else if (strcmp(argv[arg], "-clefprog") == 0) {
+ strcpy(ClefCommandLine,argv[++arg]);
+<<clefprogram1>>
+ }
+ else if (strcmp(argv[arg], "-sessionprog") == 0)
+ SessionManagerProgram = argv[++arg];
+ else if (strcmp(argv[arg], "-clientprog") == 0)
+ SpadClientProgram = argv[++arg];
+ else if (strcmp(argv[arg], "-rm") == 0)
+ MakeRecordFile = argv[++arg];
+ else if (strcmp(argv[arg], "-rv") == 0)
+ VerifyRecordFile = argv[++arg];
+ else if (strcmp(argv[arg], "-paste") == 0)
+ PasteFile = argv[++arg];
+ else {
+ fprintf(stderr, "Usage: sman <-clef|-noclef> \
+<-gr|-nogr> <-ht|-noht> <-iw|-noiw> <-nag|-nonag> <-nox> <-comp> <-ws spad_workspace> \
+<-grprog path> <-htprog path> <-clefprog path> <-sessionprog path> <-nagprog path> \
+<-clientprog path>\n");
+ exit(-1);
+ }
+ }
+ if (tpd == 1)
+ { fprintf(stderr," sman ");
+ if (start_clef == 0)
+ fprintf(stderr,"-noclef ");
+ else
+ fprintf(stderr,"-clef ");
+ if (start_graphics == 0)
+ fprintf(stderr,"-nogr ");
+ else
+ fprintf(stderr,"-gr ");
+ if (start_nagman == 0)
+ fprintf(stderr,"-nonag ");
+ else
+ fprintf(stderr,"-nag ");
+ if (start_ht == 0)
+ fprintf(stderr,"-noht ");
+ else
+ fprintf(stderr,"-ht ");
+ if (start_spadclient == 0)
+ fprintf(stderr,"-noiw ");
+ else
+ fprintf(stderr,"-iw ");
+ if (start_local_spadclient == 0)
+ fprintf(stderr,"-noihere ");
+ else
+ fprintf(stderr,"-ihere ");
+ if (start_local_spadclient == 0)
+ fprintf(stderr,"-noihere ");
+ else
+ fprintf(stderr,"-ihere ");
+ if (use_X == 0)
+ fprintf(stderr,"-nox ");
+ fprintf(stderr,"-ws ");
+ fprintf(stderr,"'%s' ",ws_path);
+ fprintf(stderr,"-grprog ");
+ fprintf(stderr,"'%s' ",GraphicsProgram);
+ fprintf(stderr,"-nagprog ");
+ fprintf(stderr,"'%s' ",NagManagerProgram);
+ fprintf(stderr,"-htprog ");
+ fprintf(stderr,"'%s' ",HypertexProgram);
+ fprintf(stderr,"-clefprog ");
+ fprintf(stderr,"'%s' ",ClefCommandLine);
+ fprintf(stderr,"-sessionprog ");
+ fprintf(stderr,"'%s' ",SessionManagerProgram);
+ fprintf(stderr,"-clientprog ");
+ fprintf(stderr,"'%s' ",SpadClientProgram);
+ fprintf(stderr,"-rm ");
+ fprintf(stderr,"'%s' ",MakeRecordFile);
+ fprintf(stderr,"-rv ");
+ fprintf(stderr,"'%s' ",VerifyRecordFile);
+ fprintf(stderr,"-paste ");
+ fprintf(stderr,"'%s' ",PasteFile);
+ fprintf(stderr,"\n");
+ }
+ if (tpd == 1) fprintf(stderr,"sman:process_arguments exit\n");
+}
+
+@
+\subsection{should\_I\_clef}
+<<shouldIclef>>=
+static int
+should_I_clef(void)
+{
+ return(1);
+}
+
+@
+\subsection{in\_X}
+<<inX>>=
+static int
+in_X(void)
+{
+ if (getenv("DISPLAY")) return 1;
+ return 0;
+}
+
+@
+\subsection{set\_up\_defaults}
+These are the default values for sman. A '1' value means that
+sman will try to start the given process, a '0' value means not
+starting the process.
+
+We do not have replacement code for the [[nagman]] process nor
+do we have a copy of the [[nag fortran library]] to test the process.
+Until this changes we set [[start_nagman = 0]] in order to disable
+starting this process by default.
+<<setupdefaults>>=
+static void
+set_up_defaults(void)
+{
+ if (tpd == 1) fprintf(stderr,"sman:set_up_defaults entered\n");
+ start_clef = should_I_clef();
+ start_graphics = 1;
+ start_nagman = 0;
+ start_ht = 1;
+ start_spadclient = 0;
+ start_local_spadclient = 1;
+ use_X = isatty(0) && in_X();
+ ws_path = "$AXIOM/bin/AXIOMsys";
+ if (tpd == 1) fprintf(stderr,"sman:set_up_defaults exit\n");
+}
+
+@
+\subsection{process\_options}
+<<processoptions>>=
+static void
+process_options(int argc, char **argv)
+{
+ if (tpd == 1) fprintf(stderr,"sman:process_options entered\n");
+ set_up_defaults();
+ process_arguments(argc, argv);
+ if (tpd == 1) fprintf(stderr,"sman:process_options exit\n");
+}
+
+@
+\subsection{death\_handler}
+<<deathhandler>>=
+static void
+death_handler(int sig)
+{
+ death_signal = 1;
+}
+
+@
+\subsection{nagman\_handler}
+<<nagmanhandler>>=
+static void
+nagman_handler(int sig)
+{
+ nagman_signal=1;
+}
+
+@
+\subsection{sman\_catch\_signals}
+<<smancatchsignals>>=
+static void
+sman_catch_signals(void)
+{
+
+ /* Set up the signal handlers for sman */
+ bsdSignal(SIGINT, SIG_IGN,RestartSystemCalls);
+ bsdSignal(SIGTERM, death_handler,RestartSystemCalls);
+ bsdSignal(SIGQUIT, death_handler,RestartSystemCalls);
+ bsdSignal(SIGHUP, death_handler,RestartSystemCalls);
+ bsdSignal(SIGILL, death_handler,RestartSystemCalls);
+ bsdSignal(SIGTRAP, death_handler,RestartSystemCalls);
+ bsdSignal(SIGIOT, death_handler,RestartSystemCalls);
+ bsdSignal(SIGBUS, death_handler,RestartSystemCalls);
+ bsdSignal(SIGSEGV, death_handler,RestartSystemCalls);
+ /* don't restart wait call on SIGUSR1 */
+ bsdSignal(SIGUSR1, nagman_handler,DontRestartSystemCalls);
+ /* ONLY nagman should send this.
+ If an error (such as C-c) interrupts a NAGLINK call, nagman
+ gets a signal to clean up. We need to start another nagman
+ almost immediately to process the next NAGLINK request.
+ Since nagman takes a while to clean up, we treat it specially.
+ nagman should send a signal (USR1) to sman.
+ sman should respond by spawning a new nagman.
+
+ so nagman is NOT a DoItAgain but a NadaDelShitsky.
+
+ The USR1 mechanism does not work for HPUX 9 - use DoItAgain
+ */
+
+}
+
+@
+\subsection{fix\_env}
+insert SPADSERVER and SPADNUM variables into the environemnt
+<<fixenv>>=
+static void
+fix_env(char **envp, int spadnum)
+{
+ int len, i;
+ char *sn;
+ for(len = 0; envp[len] != NULL; len++);
+ new_envp = (char **) malloc((len + 3) * sizeof(char *));
+ new_envp[0] = "SPADSERVER=TRUE";
+ sn = (char *) malloc(20 * sizeof(char));
+ sprintf(sn, "SPADNUM=%d", spadnum);
+ new_envp[1] = sn;
+ for(i=0; i<=len; i++)
+ new_envp[i+2] = envp[i];
+}
+
+@
+\subsection{init\_term\_io}
+<<inittermio>>=
+static void
+init_term_io(void)
+{
+ if(!isatty(0)) return;
+ if( tcgetattr(0, &oldbuf) == -1) {
+ perror("getting termios");
+ return ; /* exit(-1); */
+ }
+ if( tcgetattr(0, &childbuf) == -1) {
+ perror("getting termios");
+ return ; /* exit(-1); */
+ }
+ _INTR = oldbuf.c_cc[VINTR];
+ _QUIT = oldbuf.c_cc[VQUIT];
+ _ERASE = oldbuf.c_cc[VERASE];
+ _KILL = oldbuf.c_cc[VKILL];
+ _EOF = oldbuf.c_cc[VEOF];
+ _EOL = oldbuf.c_cc[VEOL];
+}
+
+@
+\subsection{strPrefix}
+<<strPrefix>>=
+static char *
+strPrefix(char *prefix,char * s)
+{
+ while (*prefix != '\0' && *prefix == *s) {
+ prefix++;
+ s++;
+ }
+ if (*prefix == '\0') return s;
+ return NULL;
+}
+
+@
+\subsection{check\_spad\_proc}
+<<checkspadproc>>=
+static void
+check_spad_proc(char *file, char *prefix)
+{
+ char *num;
+ int pid;
+ if ((num = strPrefix(prefix, file))) {
+ pid = atoi(num);
+ if (pid > 2) {
+ kill(pid, 0);
+ if (kill(pid, 0) == -1 && errno == ESRCH) {
+ unlink(file);
+ }
+ }
+ }
+}
+
+@
+\subsection{clean\_up\_old\_sockets}
+<<cleanupoldsockets>>=
+static void
+clean_up_old_sockets(void)
+{
+ char com[512], tmp_file[128];
+ FILE *file;
+ int len;
+ sprintf(tmp_file, "/tmp/socks.%d", server_num);
+ sprintf(com, "ls /tmp/.d* /tmp/.s* /tmp/.i* /tmp/.h* 2> %s > %s",
+ tmp_file, tmp_file);
+ system(com);
+ file = fopen(tmp_file, "r");
+ if (file == NULL) {
+ fprintf(stderr, "Can't open socket listing file\n");
+ return;
+ }
+ while(fgets(com, 512, file) != NULL) {
+ len = strlen(com);
+ if (len) com[len-1] = '\0';
+ else break;
+ check_spad_proc(com, "/tmp/.d");
+ check_spad_proc(com, "/tmp/.s");
+ check_spad_proc(com, "/tmp/.i");
+ check_spad_proc(com, "/tmp/.h");
+ }
+ fclose(file);
+ unlink(tmp_file);
+}
+
+@
+\subsection{fork\_you}
+<<forkyou>>=
+static SpadProcess *
+fork_you(int death_action)
+{
+ /* fork a new process, giving it a default death action */
+ /* return NULL in child, SpadProcess in parent */
+ int child_pid = fork();
+ SpadProcess *proc;
+ if (!child_pid) return NULL;
+ proc = (SpadProcess *) malloc(sizeof(SpadProcess));
+ proc->proc_id = child_pid;
+ proc->death_action = death_action;
+ proc->command = NULL;
+ proc->next = spad_process_list;
+ spad_process_list = proc;
+ return proc;
+}
+
+@
+\subsection{exec\_command\_env}
+<<execcommandenv>>=
+static void
+exec_command_env(char *command,char ** env)
+{
+ char new_command[512];
+ sprintf(new_command, "exec %s", command);
+ execle("/bin/sh","/bin/sh", "-c", new_command, 0, env);
+}
+
+@
+\subsection{spawn\_of\_hell}
+<<spawnofhell>>=
+static SpadProcess *
+spawn_of_hell(char *command, int death_action)
+{
+ SpadProcess *proc = fork_you(death_action);
+ if (proc != NULL) {
+ proc->command = command;
+ return proc;
+ }
+ exec_command_env(command, new_envp);
+ return NULL;
+}
+
+@
+\subsection{start\_the\_spadclient}
+run a AXIOM client in the main process
+<<startthespadclient>>=
+static void
+start_the_spadclient(void)
+{
+ char command[256];
+ if (start_clef)
+#ifdef RIOSplatform
+ sprintf(command,
+ "aixterm -sb -sl 500 -name axiomclient -n AXIOM -T AXIOM -e %s %s",
+ ClefProgram, SpadClientProgram);
+#else
+ sprintf(command,
+ "xterm -sb -sl 500 -name axiomclient -n AXIOM -T AXIOM -e %s %s",
+ ClefProgram, SpadClientProgram);
+#endif
+ else
+#ifdef RIOSplatform
+ sprintf(command,
+ "aixterm -sb -sl 500 -name axiomclient -n AXIOM -T AXIOM -e %s",
+ SpadClientProgram);
+#else
+ sprintf(command,
+ "xterm -sb -sl 500 -name axiomclient -n AXIOM -T AXIOM -e %s",
+ SpadClientProgram);
+#endif
+ if (tpd == 1)
+ fprintf(stderr,"sman:start_the_spadclient: %s\n",command);
+ spawn_of_hell(command, NadaDelShitsky);
+}
+
+@
+\subsection{start\_the\_local\_spadclient}
+<<startthelocalspadclient>>=
+static void
+start_the_local_spadclient(void)
+{
+ char command[256];
+ if (start_clef)
+ sprintf(command, "%s %s", ClefProgram, SpadClientProgram);
+ else
+ sprintf(command, "%s", SpadClientProgram);
+ if (tpd == 1)
+ fprintf(stderr,"sman:start_the_local_spadclient: %s\n",command);
+ spawn_of_hell(command, NadaDelShitsky);
+}
+
+@
+\subsection{start\_the\_nagman}
+<<startthenagman>>=
+static void
+start_the_nagman(void)
+{
+#if defined(HP9platform)
+ spawn_of_hell(NagManagerProgram,DoItAgain);
+#else
+ spawn_of_hell(NagManagerProgram,NadaDelShitsky );
+#endif
+}
+
+@
+\subsection{start\_the\_session\_manager}
+<<startthesessionmanager>>=
+static void
+start_the_session_manager(void)
+{
+ spawn_of_hell(SessionManagerProgram, Die);
+}
+
+@
+\subsection{start\_the\_hypertex}
+<<startthehypertex>>=
+static void
+start_the_hypertex(void)
+{
+ char prog[512];
+
+ if (PasteFile){
+ sprintf(prog, "%s -k -ip %s", HypertexProgram, PasteFile);
+ spawn_of_hell(prog, NadaDelShitsky);
+ }
+ else if (MakeRecordFile){
+ sprintf(prog, "%s -k -rm %s", HypertexProgram,MakeRecordFile );
+ spawn_of_hell(prog, NadaDelShitsky);
+ }
+ else if (VerifyRecordFile){
+ sprintf(prog, "%s -k -rv %s", HypertexProgram, VerifyRecordFile);
+ spawn_of_hell(prog, NadaDelShitsky);
+ }
+ else spawn_of_hell(HypertexProgram, NadaDelShitsky);
+}
+
+@
+\subsection{start\_the\_graphics}
+<<startthegraphics>>=
+static void
+start_the_graphics(void)
+{
+ spawn_of_hell(GraphicsProgram, DoItAgain);
+}
+
+@
+\subsection{fork\_Axiom}
+<<forkAxiom>>=
+/* Start the AXIOM session in a separate process, */
+/* using a pseudo-terminal to catch all input and output */
+static void
+fork_Axiom(void)
+{
+ char augmented_ws_path[256]; /* will append directory path */
+ char *tmp_pointer;
+ SpadProcess *proc;
+
+ proc = fork_you(Die);
+ child_pid = (proc == NULL ? 0 : proc->proc_id);
+ switch(child_pid) {
+ case -1 :
+ fprintf(stderr, "Can't create a new process \n");
+ exit(0);
+ case 0:
+ /* Dissasociate from my parents group so all my child processes */
+ /* look at my terminal as the controlling terminal for the */
+ /* group */
+
+ if(setsid() < 0) {
+ perror("Dissassociating from parents group");
+ exit(-1);
+ }
+
+ close(ptsNum);
+ /* Now reopen the server side, so that pg, su, etc. work properly */
+
+ if ((ptsNum = open(ptsPath, O_RDWR)) < 0 ) {
+ perror("fork_Axiom: Failed to reopen server");
+ exit(-1);
+ }
+#if defined(SUN4OS5platform) || defined(HP10platform)
+ ioctl(ptsNum,I_PUSH,"ptem");
+ ioctl(ptsNum,I_PUSH,"ldterm");
+#endif
+
+ /* since I am the child, I can close ptc, and dup pts for all its */
+ /* standard descriptors */
+
+ if( (dup2(ptsNum, 0) == -1) ||
+ (dup2(ptsNum, 1) == -1) ||
+ (dup2(ptsNum, 2) == -1) ) {
+ perror("trying to dupe the child");
+ exit(-1);
+ }
+ close(ptcNum);
+ close(ptsNum);
+
+
+ /* I also have to turn off echoing, since I am echoing all the */
+ /* input myself */
+
+ childbuf.c_lflag &= ~ECHO;
+ if( tcsetattr(0, TCSAFLUSH, &childbuf) == -1) {
+ perror("setting the term buffer");
+ exit(-1);
+ }
+ strcpy(augmented_ws_path,ws_path); /* write the name */
+ strcat(augmented_ws_path," "); /* space */
+ strcat(augmented_ws_path,ws_path); /* name again */
+ tmp_pointer = (char *)
+ strrchr(augmented_ws_path,'/'); /*pointer to last / */
+ *(++tmp_pointer) = '\0';
+ exec_command_env(augmented_ws_path, new_envp);
+
+ /* fprintf(stderr, "Cannot execute the %s system.\n", ws_path); */
+
+ exit(0);
+ }
+}
+
+@
+\subsection{start\_the\_Axiom}
+<<starttheAxiom>>=
+static void
+start_the_Axiom(char **envp)
+{
+ server_num = make_server_number();
+ clean_up_old_sockets();
+ if (server_num == -1) {
+ fprintf(stderr, "could not get an AXIOM server number\n");
+ exit(-1);
+ }
+ if (ptyopen(&ptcNum, &ptsNum, ptcPath, ptsPath) == -1) {
+ perror("start_the_Axiom: ptyopen failed");
+ exit(-1);
+ }
+ fix_env(envp, server_num);
+ fork_Axiom();
+ close(ptsNum);
+}
+
+@
+\subsection{clean\_up\_sockets}
+<<cleanupsockets>>=
+static void
+clean_up_sockets(void)
+{
+ char name[256];
+ sprintf(name, "%s%d", SpadServer, server_num);
+ unlink(name);
+ sprintf(name, "%s%d", SessionServer, server_num);
+ unlink(name);
+ sprintf(name, "%s%d", SessionIOName, server_num);
+ unlink(name);
+ sprintf(name, "%s%d", MenuServerName, server_num);
+ unlink(name);
+}
+
+@
+\subsection{read\_from\_spad\_io}
+<<readfromspadio>>=
+static void
+read_from_spad_io(int ptcNum)
+{
+ int ret_code = 0, i=0;
+ static int mes_len =0;
+ ret_code = read(ptcNum, big_bad_buf, BufSize);
+ if (ret_code == -1) {
+ clean_up_sockets();
+ exit(-1);
+ }
+ if (session_io == NULL) {
+ if (ret_code < mes_len)
+ mes_len -= ret_code;
+ else {
+ if (mes_len > 0) {
+ i = mes_len;
+ mes_len = 0;
+ }
+ else
+ i = 0;
+ ret_code = write(1, big_bad_buf+i, ret_code-i);
+ }
+ }
+ else
+ ret_code = swrite(session_io, big_bad_buf, ret_code,
+ "writing to session man");
+ if (ret_code == -1) {
+ perror("writing output to session manager");
+ clean_up_sockets();
+ exit(-1);
+ }
+}
+
+@
+\subsection{read\_from\_manager}
+<<readfrommanager>>=
+static void
+read_from_manager(int ptcNum)
+{
+ int ret_code;
+ ret_code = sread(session_io, big_bad_buf, BufSize, "reading session io");
+ if (ret_code == -1) {
+ return;
+ }
+ ret_code = write(ptcNum, big_bad_buf, ret_code);
+ if (ret_code == -1) {
+ return;
+ }
+}
+
+@
+\subsection{manage\_spad\_io}
+<<managespadio>>=
+static void
+manage_spad_io(int ptcNum)
+{
+ int ret_code, i, p;
+ fd_set rd;
+ while (1) {
+ rd = socket_mask;
+ FD_SET(ptcNum, &rd);
+ if (session_io != NULL)
+ FD_SET(session_io->socket, &rd);
+ ret_code = sselect(FD_SETSIZE, &rd, 0, 0, NULL);
+ if (ret_code == -1) {
+ perror("Session manager select");
+ clean_up_sockets();
+ exit(-1);
+ }
+ if (FD_ISSET(ptcNum, &rd)) {
+ read_from_spad_io(ptcNum);
+ }
+ for(i=0; i<2; i++) {
+ if (server[i].socket > 0 && FD_ISSET(server[i].socket, &rd)) {
+ p = accept_connection(server+i);
+ switch(p) {
+ case SessionIO:
+ session_io = purpose_table[SessionIO];
+ /* printf("connected session manager\n\r");*/
+ printf("\n");
+ break;
+ default:
+ printf("sman: Unkown connection request type: %d\n", p);
+ break;
+ }
+ }
+ }
+ if (session_io != NULL && FD_ISSET(session_io->socket, &rd)) {
+ read_from_manager(ptcNum);
+ }
+ }
+}
+
+@
+\subsection{init\_spad\_process\_list}
+<<initspadprocesslist>>=
+static void
+init_spad_process_list(void)
+{
+ spad_process_list = NULL;
+}
+
+@
+\subsection{print\_spad\_process\_list}
+<<printspadprocesslist>>=
+#if 0
+static void
+print_spad_process_list()
+{
+ SpadProcess *proc;
+ for(proc = spad_process_list; proc != NULL; proc = proc->next)
+ fprintf(stderr, "proc_id = %d, death_action = %d\n", proc->proc_id,
+ proc->death_action);
+}
+#endif
+
+@
+\subsection{find\_child}
+<<findchild>>=
+static SpadProcess *
+find_child(int proc_id)
+{
+ SpadProcess *proc;
+ for(proc = spad_process_list; proc != NULL; proc = proc->next)
+ if (proc->proc_id == proc_id) return proc;
+ return NULL;
+}
+
+@
+\subsection{kill\_all\_children}
+<<killallchildren>>=
+static void
+kill_all_children(void)
+{
+ char name[256];
+ SpadProcess *proc;
+
+
+ for(proc = spad_process_list; proc != NULL; proc = proc->next) {
+ kill(proc->proc_id, SIGTERM);
+ }
+ sprintf(name, "/tmp/hyper%d.input",server_num);
+ unlink(name);
+
+}
+
+@
+\subsection{clean\_up\_terminal}
+<<cleanupterminal>>=
+static void
+clean_up_terminal(void)
+{
+ tcsetattr(0, TCSAFLUSH, &oldbuf);
+}
+
+@
+\subsection{monitor\_children}
+<<monitorchildren>>=
+static void
+monitor_children(void)
+{
+ int dead_baby, stat;
+ SpadProcess *proc;
+ while (1) {
+ stat = 0;
+ dead_baby = wait(&stat);
+ /* Check the value of dead_baby, since wait may have returned
+ a pid but subsequently we have received a signal. Yeuch! */
+ if (dead_baby == -1 && death_signal) {
+ kill_all_children();
+ clean_up_sockets();
+ clean_up_terminal();
+ sleep(2);
+ exit(0);
+ }
+ /* Check the value of dead_baby, since wait may have returned
+ a pid but subsequently we have received a signal. Yeuch! */
+ if(dead_baby == -1 && nagman_signal) {
+ nagman_signal=0;
+ spawn_of_hell(NagManagerProgram,NadaDelShitsky);
+ continue;
+ }
+
+ if (dead_baby == -1) {
+ fprintf(stderr, "sman: wait returned -1\n");
+ continue;
+ }
+ proc = find_child(dead_baby);
+ if (proc == NULL) {
+ /* fprintf(stderr, "sman: %d is not known to be a child process\n",
+ dead_baby);
+ */
+ continue;
+ }
+ switch(proc->death_action) {
+ case Die:
+ kill_all_children();
+ clean_up_sockets();
+ clean_up_terminal();
+ sleep(2);
+ exit(0);
+ case NadaDelShitsky:
+ break;
+ case DoItAgain:
+ spawn_of_hell(proc->command, DoItAgain);
+ break;
+ }
+ }
+}
+
+@
+\subsection{main}
+The main procedure should return an [[int]]. We change the return value
+here and in [[src/include/sman.H1]].
+<<result>>=
+ return(0);
+@
+<<main>>=
+int
+main(int argc, char *argv[],char *envp[])
+{
+ if (tpd == 1) fprintf(stderr,"sman:main entered\n");
+ bsdSignal(SIGINT, SIG_IGN,RestartSystemCalls);
+ process_options(argc, argv);
+
+ init_term_io();
+ init_spad_process_list();
+ start_the_Axiom(envp);
+ if (open_server(SessionIOName) == -2) {
+ fprintf(stderr, "Fatal error opening I/O socket\n");
+ clean_up_sockets();
+ exit(-1);
+ }
+ start_the_session_manager();
+ if (start_spadclient) start_the_spadclient();
+ if (start_local_spadclient) start_the_local_spadclient();
+ if (start_nagman) start_the_nagman();
+ if (start_ht) start_the_hypertex();
+ if (start_graphics) start_the_graphics();
+ sleep(1);
+
+ if (fork_you(Die) != NULL) {
+ sman_catch_signals();
+ monitor_children();
+ exit(0);
+ }
+ manage_spad_io(ptcNum);
+ if (tpd == 1) fprintf(stderr,"sman:main exit\n");
+<<result>>
+}
+
+@
+\subsection{sman}
+<<sman>>=
+#define _SMAN_C
+
+<<includes>>
+<<variables>>
+<<processarguments>>
+<<shouldIclef>>
+<<inX>>
+<<setupdefaults>>
+<<processoptions>>
+<<deathhandler>>
+<<nagmanhandler>>
+<<smancatchsignals>>
+<<fixenv>>
+<<inittermio>>
+<<strPrefix>>
+<<checkspadproc>>
+<<cleanupoldsockets>>
+<<forkyou>>
+<<execcommandenv>>
+<<spawnofhell>>
+<<startthespadclient>>
+<<startthelocalspadclient>>
+<<startthenagman>>
+<<startthesessionmanager>>
+<<startthehypertex>>
+<<startthegraphics>>
+<<forkAxiom>>
+<<starttheAxiom>>
+<<cleanupsockets>>
+<<readfromspadio>>
+<<readfrommanager>>
+<<managespadio>>
+<<initspadprocesslist>>
+<<printspadprocesslist>>
+<<findchild>>
+<<killallchildren>>
+<<cleanupterminal>>
+<<monitorchildren>>
+<<main>>
+
+@
+\section{License}
+<<license>>=
+/*
+Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - 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.
+
+ - Neither the name of The Numerical ALgorithms Group Ltd. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER
+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.
+*/
+
+@
+<<*>>=
+<<license>>
+<<sman>>
+@
+\eject
+\begin{thebibliography}{99}
+\bibitem{1} nothing
+\end{thebibliography}
+\end{document}
diff --git a/src/sman/spadclient.c b/src/sman/spadclient.c
new file mode 100644
index 00000000..a41fee2a
--- /dev/null
+++ b/src/sman/spadclient.c
@@ -0,0 +1,66 @@
+/*
+Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - 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.
+
+ - Neither the name of The Numerical ALgorithms Group Ltd. 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER
+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.
+*/
+
+
+#define _SPADCLIENT_C
+
+#include <stdio.h>
+#include <signal.h>
+
+#include "axiom-c-macros.h"
+#include "com.h"
+#include "bsdsignal.h"
+
+#include "bsdsignal.H1"
+#include "sockio-c.H1"
+#include "spadclient.H1"
+
+Sock *sock;
+
+static void
+inter_handler(int sig)
+{
+ send_signal(sock, SIGUSR2);
+ fflush(stderr);
+}
+
+
+int
+main(void)
+{
+ sock = connect_to_local_server(SessionServer, InterpWindow, Forever);
+ bsdSignal(SIGINT, inter_handler,RestartSystemCalls);
+ remote_stdio(sock);
+ return(0);
+}
+