diff --git a/changelog b/changelog index 282bd89..180fc5c 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,4 @@ +20070821 tpd src/sman/bookvol6 document the axiom shell script 20070821 tpd src/sman/bookvol6 add axiom command 20070821 tpd src/sman/Makefile add axiom command 20070821 tpd src/etc/axiom remove axiom command diff --git a/src/sman/bookvol6.pamphlet b/src/sman/bookvol6.pamphlet index ade0c54..d80388b 100644 --- a/src/sman/bookvol6.pamphlet +++ b/src/sman/bookvol6.pamphlet @@ -25,47 +25,50 @@ $$ \center{\large{VOLUME 6: AXIOM COMMAND}} \end{titlepage} \pagenumbering{roman} -\begin{verbatim} + Portions Copyright (c) 2005 Timothy Daly The Blue Bayou image Copyright (c) 2004 Jocelyn Guidry Portions Copyright (c) 2004 Martin Dunstan -Portions Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. -All rights reserved. +Portions Copyright (c) 1991-2002, The Numerical ALgorithms Group +Ltd. All rights reserved. This book and the Axiom software is licensed as follows: -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. - -\end{verbatim} +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: +\begin{itemize} +\item Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + +\item 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. + +\item 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. +\end{itemize} + +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. Inclusion of names in the list of credits is based on historical information and is as accurate as possible. Inclusion of names @@ -194,86 +197,408 @@ November 10, 2003 ((iHy)) \pagenumbering{arabic} \setcounter{chapter}{0} % Chapter 1 \chapter{Overview} -The superman process, called sman, is normally invoked from the -axiom shell script in order to start a tree of subprocesses. +The axiom system consists of a set of processes managed by the +superman process. The superman process, called sman, is normally +invoked from the axiom shell script in order to start a tree of +subprocesses. + +The {\tt axiom} command is a shell script that collects the +command line options for the {\tt sman} process, sets some shell +variables, and then invokes {\tt sman}. + +The {\tt sman} process starts the following tree of processes: +\begin{verbatim} + --xterm---bash---sman-|-AXIOMsys + |-clef---spadclient + |-hypertex + |-session + |-sman + |-viewman +\end{verbatim} \chapter{The axiom Command} +The {\tt axiom} command starts everything for Axiom. The options +for the {\tt axiom} command are: +\begin{verbatim} +axiom + [-ht |-noht] whether to use HyperDoc + [-gr |-nogr] whether to use Graphics + [-clef |-noclef] whether to use Clef + [-nonag |-nag] whether to use NAG + [-noiw |-iw] start in interpreter in a separate window + [-ihere |-noihere] start an interpreter in this window + [-nox] don't use X Windows + [-go |-nogo] whether to start system + [-ws wsname] use named workspace + [-list] list workspaces only + [-grprog fname] use named program for Graphics + [-nagprog fname] use named program for Nag + [-htprog fname] use named program for HyperDoc + [-clefprog fname] use named program for Clef + [-sessionprog fname] use named program for session + [-clientprog fname] use named program for spadclient + [-h] show usage +\end{verbatim} + +In detail, the command options are: +\subsection{[-ht $\vert$ -noht]} +\begin{verbatim} + [-ht |-noht] whether to use HyperDoc +\end{verbatim} +{\tt Hyperdoc}\cite{7} is the documentation tool for Axiom. The +{\tt -ht} option, enabled by default, will start this tool. +See Jenks\cite{1} Chapter 3 for further information on the +{\tt hyperdoc} subsystem. + +\subsection{[-gr $\vert$ -nogr]} +\begin{verbatim} + [-gr |-nogr] whether to use Graphics +\end{verbatim} +The {\tt graphics}\cite{8} subsystem is enabled using the +{\tt -gr} option, enabled by default. Graphics will appear as a +result of a draw command, such as +\begin{verbatim} + draw(sin(x),x=0..1) +\end{verbatim} +Note that attempting to use draw commands when the graphics is +disabled will simply hang the interpreter waiting for a response. +See Jenks\cite{1} Chapter 7 for further information on the +{\tt graphics} subsystem. + +\subsection{[-clef $\vert$ -noclef]} +\begin{verbatim} + [-clef |-noclef] whether to use Clef +\end{verbatim} +The {\tt clef} (Command Line Edit Facility) allows for command completion. +The list of command completion strings is in the last chapter of this +document. If {\tt clef}, enabled by default, is running then you can type: +\begin{verbatim} + x:Dena +\end{verbatim} +and this will automatically be expanded to: +\begin{verbatim} + x:DenavitHartenbergMatrix +\end{verbatim} + +The {\tt clef} program also allows command line editing. The commands are +special keyboard keys. +\begin{itemize} +\item HOME move to beginning of the line +\item END move to the end of the line +\item CTRL-END delete to end of the line +\item TAB command completion (multiple tabs give new choices) +\item UPARROW move back thru commands +\item DOWNARROW move forward thru commands +\item LEFTARROW move left on the line +\item RIGHTARROW move right on the line +\item INSERT toggle insert/overstrike +\end{itemize} +See Jenks\cite{1} page 21 for further information on the {\tt clef} command. + +\subsection{[-nonag $\vert$ -nag]} +\begin{verbatim} + [-nonag |-nag] whether to use NAG +\end{verbatim} +The {\tt nag} option, disabled by default, will attempt to start +the {\tt nagman} program in the \$AXIOM/lib subdirectory. Since +the open source version does not include the NAG numeric libraries +this option does not work. + +\subsection{[-noiw $\vert$ -iw]} +\begin{verbatim} + [-noiw |-iw] start in interpreter in a separate window +\end{verbatim} +The {\tt iw} option, disabled by default, will start a second +interpreter in its own window with its own frame. The fact that +the second interpreter is in its own frame can be seen using the +{\tt )frame} command. For instance, if you type +\begin{verbatim} + axiom -iw +\end{verbatim} +there will be two interpreter windows available, one in the current +window and one in a new window. In the current window if you type: +\begin{verbatim} + )frame names +\end{verbatim} +you will see: +\begin{verbatim} + The names of the existing frames are: + frame0 + frame1 + initial + The current frame is the first one listed. +\end{verbatim} + +In the second window, if you type +\begin{verbatim} + )frame names +\end{verbatim} +you will see: +\begin{verbatim} + The names of the existing frames are: + frame1 + frame0 + initial + The current frame is the first one listed. +\end{verbatim} +Setting +\begin{verbatim} + x:=3 +\end{verbatim} +in the second window will set the variable $x$ in the frame {\tt frame1}. +Switching to the first window and typing: +\begin{verbatim} + x +\end{verbatim} +gives: +\begin{verbatim} + + (1) x + Type: Variable x +\end{verbatim} +since the first window is in {\tt frame0} and the variable $x$ is +defined in {\tt frame1}. +But we can switch frames in the first window using +\begin{verbatim} + )frame next +\end{verbatim} +and then +\begin{verbatim} + x +\end{verbatim} +gives: +\begin{verbatim} + + (2) 3 + Type: PositiveInteger +\end{verbatim} +and now the two windows share the same frame space. +See Jenks\cite{1} page 579 for further information on the {\tt frame} command. + +\subsection{[-ihere $\vert$ -noihere]} +\begin{verbatim} + [-ihere |-noihere] start an interpreter in this window +\end{verbatim} +This option determines whether Axiom will start in the current window. +Using this option alone is not particularly useful and it is generally +used in combination with the {\tt -iw} option: +\begin{verbatim} + axiom -noihere -iw & +\end{verbatim} + +However, used alone, as in: +\begin{verbatim} + axiom -noihere & +\end{verbatim} +it will start Axiom and show the Hyperdoc window. Graphics will also +work from the Hyperdoc pages. + +\subsection{[-nox]} +\begin{verbatim} + [-nox] don't use X Windows +\end{verbatim} +allows Axiom to start the interpreter without Hyperdoc or the graphics +subsystem. This is useful for starting Axiom in an emacs buffer. + +\subsection{[-go $\vert$ -nogo]} +\begin{verbatim} + [-go |-nogo] whether to start system +\end{verbatim} +uses the {\tt -go} option, enabled by default, controls whether +the system starts from the command line. If the {\tt -nogo} +option is chosen the system prints the command line that would +have been issued. This is useful for finding out what the command +line options to {\tt sman} will be. For instance: +\begin{verbatim} + axiom -nogo -iw +\end{verbatim} +does not start Axiom but types out: +\begin{verbatim} +Would now start the processes. +exec ~/mnt/linux/bin/sman -iw -ws ~/mnt/linux/bin/AXIOMsys +\end{verbatim} + +\subsection{[-ws wsname]} +\begin{verbatim} + [-ws wsname] use named workspace +\end{verbatim} +In the {\tt -nogo} command above you can see that the default +workspace name is +\begin{verbatim} +-ws ~/mnt/linux/bin/AXIOMsys +\end{verbatim} +This option allows you to change that. This is useful for +debugging new system builds. During build a debugging version +of Axiom is created in the {\tt obj/linux/bin} directory. The +{\tt debugsys} image uses interpreted lisp code rather than +compiled code. This makes it possible to do deep debugging. To +use this workspace you would incant: +\begin{verbatim} + cd youraxiombuild + export AXIOM=`pwd`/mnt/linux + export PATH=$AXIOM/bin:$PATH + axiom -ws obj/linux/bin/debugsys +\end{verbatim} + + +\subsection{[-list]} +\begin{verbatim} + [-list] list workspaces only +\end{verbatim} +shows you the executable workspaces. Generally in a built system +there is only one, called\\ +{\tt \$AXIOM/bin/AXIOMsys}. + +\subsection{[-grprog fname]} +\begin{verbatim} + [-grprog fname] use named program for Graphics +\end{verbatim} +allows you to specify which program to use for the graphics. +By default this is\\ +{\tt \$AXIOM/lib/viewman}. + +\subsection{[-nagprog fname]} +\begin{verbatim} + [-nagprog fname] use named program for Nag +\end{verbatim} +allows you to specify which program to use for the NAG library +connection. By default this is\\ +{\tt \$AXIOM/lib/nagman} but it is disabled by default. + +\subsection{[-htprog fname]} +\begin{verbatim} + [-htprog fname] use named program for Hyperdoc +\end{verbatim} +allows you tp specify which program to use for Hyperdoc. By +default it is\\ +{\tt \$AXIOM/bin/hypertex -s}. + +\subsection{[-clefprog fname]} +\begin{verbatim} + [-clefprog fname] use named program for Clef +\end{verbatim} +allows you to specify which program to use for clef. By default +it is\\ +{\tt \$AXIOM/bin/clef -f \$AXIOM/lib/command.list -e}. + +\subsection{[-sessionprog fname]} +\begin{verbatim} + [-sessionprog fname] use named program for session +\end{verbatim} +allows you to specify the session manager program. By default it is\\ +{\tt \$AXIOM/lib/session}. + +\subsection{[-clientprog fname]} +\begin{verbatim} + [-clientprog fname] use named program for spadclient +\end{verbatim} +allows you to specify the spadclient program. By default it is\\ +{\tt \$AXIOM/lib/spadclient}. + +\subsection{[-h]} +\begin{verbatim} + [-h] show usage +\end{verbatim} + <>= #!/bin/sh -# Start everything for Axiom. -# -# axiom -# [-ht |-noht] whether to use HyperDoc -# [-gr |-nogr] whether to use Graphics -# [-clef |-noclef] whether to use Clef -# [-nag |-nonag] whether to use NAG -# [-iw |-noiw] start in interpreter window -# [-ihere|-noihere] start an interpreter buffer in the original window -# [-nox] don't use X Windows -# [-go |-nogo] whether to start system -# [-ws wsname] use named workspace -# [-list] list workspaces only -# [-grprog fname] use named program for Graphics -# [-nagprog fname] use named program for Nag -# [-htprog fname] use named program for HyperDoc -# [-clefprog fname] use named program for Clef -# [-sessionprog fname] use named program for session -# [-clientprog fname] use named program for spadclient -# [-h] show usage -# -# +@ +The {\tt MALLOCTYPE} shell variable is an {\tt IBM} {\tt AIX} +shell variable that controls buckets based extensions in the default +memory allocator which may enhance performance. AIX uses a new +memory management routine that does not zero {\tt malloc} memory +and does not round up to the nearest power of 2, unlike most non-AIX +systems. This can cause failures so we protect against that here. +See the AIX Performance Tuning Guide\cite{9} for details. +<>= MALLOCTYPE=3.1 export MALLOCTYPE -# NAGMAN needs to know the hostname +@ +The {\tt nagman} process needs to know the hostname +<>= HOST=`hostname` export HOST -# 0. Basic utilities - +@ +There are 4 basic utilities used by this script. +The {\tt ciao} script for immediate exit: +<>= ciao() { echo "Goodbye." exit 1 } +@ +The {\tt needsubopt} script which is used to issue an error message +when one of the command line options requires an option: +<>= needsubopt () { echo "The $1 option requires an argument." ciao } - - +@ +The {\tt showuse} script which gives basic command line help: +<>= showuse() { echo "axiom" -echo " [-ht |-noht] whether to use HyperDoc" -echo " [-gr |-nogr] whether to use Graphics" -echo " [-clef |-noclef] whether to use Clef" -echo " [-nag |-nonag] whether to use NAG" -echo " [-iw |-noiw] start in interpreter window" -echo " [-ihere|-noihere] start an interpreter buffer in the original window." -echo " [-nox] don't use X Windows" -echo " [-go |-nogo] whether to start system" -echo " [-ws wsname] use named workspace" -echo " [-list] list workspaces only" -#echo " [-grprog fname] use named program for Graphics" -#echo " [-nagprog fname] use named program for Nag" -#echo " [-htprog fname] use named program for HyperDoc" -#echo " [-clefprog fname] use named program for Clef" -#echo " [-sessionprog fname] use named program for session" -#echo " [-clientprog fname] use named program for spadclient" -echo " [-h] show usage" +echo " [-ht |-noht] whether to use HyperDoc" +echo " [-gr |-nogr] whether to use Graphics" +echo " [-clef |-noclef] whether to use Clef" +echo " [-nonag |-nag] whether to use NAG" +echo " [-noiw |-iw] start in interpreter in a separate window" +echo " [-ihere |-noihere] start an interpreter in this window" +echo " [-nox] don't use X Windows" +echo " [-go |-nogo] whether to start system" +echo " [-ws wsname] use named workspace" +echo " [-list] list workspaces only" +echo " [-grprog fname] use named program for Graphics" +echo " [-nagprog fname] use named program for Nag" +echo " [-htprog fname] use named program for HyperDoc" +echo " [-clefprog fname] use named program for Clef" +echo " [-sessionprog fname] use named program for session" +echo " [-clientprog fname] use named program for spadclient" +echo " [-h] show usage" } -# 1. Ensure the environment is set. +@ +List the various workspaces if asked. +<>= +listwspaces() +{ + echo "$1" + ls -l $2 | grep "sys$" + echo "" +} -# Just process '-h' +@ +Step 1. Ensure the environment is set. + +Just process ``-h''. If it exists in the command line then we +print out the simple command line help menu. +<>= if [ "$*" = "-h" ] ; then showuse fi -SPADDEFAULT=/axiom/mnt/linux +@ +We assume that Axiom is installed in the standard place on +a linux system. We will modify this assumption as we process +the environment and command line. The term {\tt spad} is an +historical shortened version of the name {\tt scratchpad}, +the original name of the {\tt Axiom} system. +<>= +SPADDEFAULT=/usr/local/axiom/mnt/linux + +@ +If the {\tt \$AXIOM} shell variable is set then we use it.\\ +If not, then if the {\tt \$SPAD} shell variable is set then we use it.\\ +If not, then we try to use the default value above.\\ +If not, we simply fail. +<>= if [ "$SPAD" = "" ] ; then if [ "$AXIOM" = "" ] ; then SPAD=$SPADDEFAULT @@ -300,6 +625,25 @@ else fi fi +@ +If we get here then all attempts to find axiom have failed +so we complain and exit. +<>= +if [ ! -d "$SPAD" ] ; then + echo "The directory for Axiom, $SPAD, does not exist." + ciao +fi + +@ +If we get here we now +know where axiom lives. We need to see if we can find the +Aldor compiler. Aldor is optional and is not part of the open source +version of Axiom due to license issues. However you can install it +under the location specified by the {\tt \$AXIOMXLROOT} shell variable. +If the compiler is found we add it to the {\tt PATH}. +This shell variable defaults to the location:\\ +{\tt \$AXIOM/compiler} +<>= if [ "$AXIOMXLROOT" = "" ] ; then AXIOMXLROOT=${AXIOM}/compiler fi @@ -307,97 +651,1182 @@ export AXIOMXLROOT PATH=$AXIOM/bin:$AXIOMXLROOT/bin:${PATH} export PATH - - -if [ ! -d "$SPAD" ] ; then - echo "The directory for Axiom, $SPAD, does not exist." - ciao -fi - -# Name the workspace directories. +@ +Name the workspace directories. +<>= rootwsdir=$SPAD/bin -# 2. Process command line arguments. +@ +Step 2. Process command line arguments. -# Defaults for command-line arguments. +First we set up the defaults for command-line arguments. +We don't want just a list by default +<>= list=no + +@ +We default to actually executing the workspace. +<>= go=yes + +@ +We default to the {\tt AXIOMsys} workspace. +<>= wsname=AXIOMsys +@ +And all other options are unset. +<>= otheropts="" +@ +For each option on the command line do +<>= while [ "$*" != "" ] ; do +@ +<>= case $1 in +@ +If the user specified list anywhere then we give the workspace list +and exit. +<>= + -list) list=yes go=no;; +@ +If the user specified {\tt go} or {\tt nogo} we handle that case +<>= -go) go=yes ;; -nogo) go=no ;; +@ +The workspace option requires an argument which follows immediately. +If the argument is missing we complain and exit. +<>= -ws) if [ "$2" = "" ] ; then needsubopt "$1" ; fi shift wsname="$1" ;; - -nagprog|-grprog|-htprog|-clefprog|-sessionprog|-clientprog|-paste|-rm|-rv) +@ +We can specify the various subprograms to use. +<>= + -nagprog|-grprog|-htprog|-clefprog|-sessionprog|-clientprog) if [ "$2" = "" ] ; then needsubopt "$1" ; fi otheropts="$otheropts $1 $2" shift ;; - -clef|-noclef|-gr|-nogr|-ht|-noht|-iw|-noiw|-ihere|-noihere|-nox|-nag|-nonag) +@ +These options were not explained earlier and are only for developer use. +<>= + -paste|-rm|-rv) + if [ "$2" = "" ] ; then needsubopt "$1" ; fi + otheropts="$otheropts $1 $2" + shift + ;; +@ +We handle the various [{\tt -option} $\vert$ {\tt -nooption}] cases +<>= + -clef|-noclef|-gr|-nogr|-ht|-noht|-iw|-noiw) + otheropts="$otheropts $1" + ;; + -ihere|-noihere|-nox|-nag|-nonag) otheropts="$otheropts $1" ;; - +@ +The user wanted help so we will not execute. +<>= -h) go=no ;; - - +@ +The user is confused. Complain and exit. +<>= *) echo "Unknown option: $1" echo "To use a specific workspace use, e.g.: spad -ws $1" ciao ;; esac +@ +Move to the next option and loop. +<>= shift done -# 3. List the available workspaces, if asked - -listwspaces() -{ - echo "$1" - ls -l $2 | grep "sys$" - echo "" -} +@ +Step 3. Handle options that require special case handling. +The user just wanted to know what workspaces are available. +<>= if [ $list = yes ] ; then - listwspaces "AXIOM workspaces in \$AXIOM/bin = $rootwsdir: " $rootwsdir + listwspaces "AXIOM workspaces in \$AXIOM/bin = $rootwsdir: " $rootwsdir fi -# 5. Try to ensure a suitable workspace on this host. - +@ +Try to ensure a suitable workspace on this host. +<>= if [ `expr $wsname : '.*/.*'` = 0 ] ; then serverws=$rootwsdir/$wsname else serverws=$wsname fi +@ +If we can't find the executable then we complain and exit. +<>= -if [ ! -f $serverws ] ; then +if [ ! -x $serverws ] ; then + echo "Cannot find the executable $serverws" showuse ciao fi - -# 6. Start processes - +@ +The user just wanted to see what would happen so we output the +command line and exit. +<>= if [ $go = no ] ; then echo "Would now start the processes." echo exec $SPAD/bin/sman $otheropts -ws $serverws exit 0 fi - +@ +All of the options have been processed so we start {\tt sman} +<>= exec $SPAD/bin/sman $otheropts -ws $serverws + +@ +\chapter{The {\tt sman} program} +\section{sman.h} +The spad\_proc structure holds information about the process id +of a child process, what to do when it dies, and the shell command +line necessary to restart the process. There is a linked list of +these structures which maintains the process list for axiom. +<>= +/* 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} +<>= +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(SUN4OS5platform) || defined(HP10platform) +#include +#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} +<>= +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 */ +@ +We add a debug flag so we can print information about what [[sman]] +is trying to do. This change is pervasive as it touches nearly every +routine. +<>= +int tpd=0; /* to-print-debug information */ + +/************************************************/ +/* definitions of programs which sman can start */ +/************************************************/ + +<> +<> +<> +<> +<> +<> +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} +<>= +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]); + ClefProgram = + strcat(ClefCommandLine, " -f $AXIOM/lib/command.list -e "); + } + 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>"); + fprintf(stderr, " <-iw|-noiw> <-nag|-nonag> <-nox> <-comp>"); + fprintf(stderr, " <-ws spad_workspace> <-grprog path> <-htprog path>"); + fprintf(stderr, " <-clefprog path> <-sessionprog path> <-nagprog path>"); + fprintf(stderr, " <-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} +<>= +static int +should_I_clef(void) +{ + return(1); +} + +@ +\subsection{in\_X} +<>= +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. +<>= +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} +<>= +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} +<>= +static void +death_handler(int sig) +{ + death_signal = 1; +} + +@ +\subsection{nagman\_handler} +<>= +static void +nagman_handler(int sig) +{ + nagman_signal=1; +} + +@ +\subsection{sman\_catch\_signals} +<>= +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 +<>= +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} +<>= +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} +<>= +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} +<>= +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} +<>= +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} +<>= +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} +Note that the next-to-last argument of {\tt execle} must be an +explicit NULL pointer. The previous naked 0 value was not correct. +<>= +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, (char *)0, env); +} + +@ +\subsection{spawn\_of\_hell} +<>= +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 +<>= +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} +<>= +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} +<>= +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} +<>= +static void +start_the_session_manager(void) +{ + spawn_of_hell(SessionManagerProgram, Die); +} + +@ +\subsection{start\_the\_hypertex} +<>= +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} +<>= +static void +start_the_graphics(void) +{ + spawn_of_hell(GraphicsProgram, DoItAgain); +} + +@ +\subsection{fork\_Axiom} +<>= +/* 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} +<>= +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} +<>= +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} +<>= +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} +<>= +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} +<>= +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} +<>= +static void +init_spad_process_list(void) +{ + spad_process_list = NULL; +} + +@ +\subsection{print\_spad\_process\_list} +<>= +#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} +<>= +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} +<>= +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} +<>= +static void +clean_up_terminal(void) +{ + tcsetattr(0, TCSAFLUSH, &oldbuf); +} + +@ +\subsection{monitor\_children} +<>= +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 sman} +The main procedure should return an [[int]]. We change the return value +here and in [[src/include/sman.h1]]. +<>= + return(0); +@ +<>= +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"); +<> +} + +@ +\subsection{sman} +<>= +#define _SMAN_C + +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> +<> + @ \chapter{Support Routines} \section{Command Completion} @@ -1565,1037 +2994,6 @@ main(void) } @ -\chapter{The {\tt sman} program} -\section{sman.h} -The spad\_proc structure holds information about the process id -of a child process, what to do when it dies, and the shell command -line necessary to restart the process. There is a linked list of -these structures which maintains the process list for axiom. -<>= -/* 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} -<>= -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(SUN4OS5platform) || defined(HP10platform) -#include -#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} -<>= -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 */ -@ -We add a debug flag so we can print information about what [[sman]] -is trying to do. This change is pervasive as it touches nearly every -routine. -<>= -int tpd=0; /* to-print-debug information */ - -/************************************************/ -/* definitions of programs which sman can start */ -/************************************************/ - -<> -<> -<> -<> -<> -<> -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} -<>= -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]); - ClefProgram = - strcat(ClefCommandLine, " -f $AXIOM/lib/command.list -e "); - } - 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>"); - fprintf(stderr, " <-iw|-noiw> <-nag|-nonag> <-nox> <-comp>"); - fprintf(stderr, " <-ws spad_workspace> <-grprog path> <-htprog path>"); - fprintf(stderr, " <-clefprog path> <-sessionprog path> <-nagprog path>"); - fprintf(stderr, " <-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} -<>= -static int -should_I_clef(void) -{ - return(1); -} - -@ -\subsection{in\_X} -<>= -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. -<>= -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} -<>= -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} -<>= -static void -death_handler(int sig) -{ - death_signal = 1; -} - -@ -\subsection{nagman\_handler} -<>= -static void -nagman_handler(int sig) -{ - nagman_signal=1; -} - -@ -\subsection{sman\_catch\_signals} -<>= -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 -<>= -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} -<>= -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} -<>= -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} -<>= -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} -<>= -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} -<>= -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} -Note that the next-to-last argument of {\tt execle} must be an -explicit NULL pointer. The previous naked 0 value was not correct. -<>= -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, (char *)0, env); -} - -@ -\subsection{spawn\_of\_hell} -<>= -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 -<>= -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} -<>= -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} -<>= -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} -<>= -static void -start_the_session_manager(void) -{ - spawn_of_hell(SessionManagerProgram, Die); -} - -@ -\subsection{start\_the\_hypertex} -<>= -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} -<>= -static void -start_the_graphics(void) -{ - spawn_of_hell(GraphicsProgram, DoItAgain); -} - -@ -\subsection{fork\_Axiom} -<>= -/* 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} -<>= -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} -<>= -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} -<>= -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} -<>= -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} -<>= -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} -<>= -static void -init_spad_process_list(void) -{ - spad_process_list = NULL; -} - -@ -\subsection{print\_spad\_process\_list} -<>= -#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} -<>= -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} -<>= -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} -<>= -static void -clean_up_terminal(void) -{ - tcsetattr(0, TCSAFLUSH, &oldbuf); -} - -@ -\subsection{monitor\_children} -<>= -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 sman} -The main procedure should return an [[int]]. We change the return value -here and in [[src/include/sman.h1]]. -<>= - return(0); -@ -<>= -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"); -<> -} - -@ -\subsection{sman} -<>= -#define _SMAN_C - -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> -<> - -@ \chapter{The Command Completion List} <>= - @@ -6723,11 +7121,11 @@ XExponentialPackage ZeroDimensionalSolvePackage @ \begin{thebibliography}{99} -\bibitem{1} Jenks, R.J. and Sutor, R.S. -``Axiom -- The Scientific Computation System'' +\bibitem{1} Jenks, R.J. and Sutor, R.S. \\ +``Axiom -- The Scientific Computation System''\\ Springer-Verlag New York (1992) ISBN 0-387-97855-0 -\bibitem{2} Knuth, Donald E., ``Literate Programming'' +\bibitem{2} Knuth, Donald E., ``Literate Programming''\\ Center for the Study of Language and Information ISBN 0-937073-81-4 Stanford CA (1992) @@ -6735,11 +7133,20 @@ Stanford CA (1992) {\bf http://wiki.axiom-developer.org} \bibitem{4} Watt, Stephen, ``Aldor'',\\ {\bf http://www.aldor.org} -\bibitem{5} Lamport, Leslie, ``Latex -- A Document Preparation System'', +\bibitem{5} Lamport, Leslie,\\ +``Latex -- A Document Preparation System'', Addison-Wesley, New York ISBN 0-201-52983-1 -\bibitem{6} Ramsey, Norman ``Noweb -- A Simple, Extensible Tool for -Literate Programming''\\ +\bibitem{6} Ramsey, Norman\\ +``Noweb -- A Simple, Extensible Tool for Literate Programming''\\ {\bf http://www.eecs.harvard.edu/ $\tilde{}$nr/noweb} +\bibitem{7} Axiom Book Volume 7 -- Hyperdoc\\ +{\bf file://usr/local/axiom/src/hyper/bookvol7.pamphlet} +\bibitem{8} Axiom Book Volume 8 -- Graphics\\ +{\bf file://usr/local/axiom/src/graph/bookvol8.pamphlet} +\bibitem{9} AIX Version 3.2 and 4 Performance Tuning Guide\\ +{\bf +http://www.rs6000.ibm.com/doc\_link/en\_US/\\ +{\hbox {\hskip 1.0cm}}a\_doc\_lib/aixbman/prftungd/toc.htm} \end{thebibliography} \printindex \end{document}