P8000/WEGA/contrib/ingres/dbs/src/support/proc_tab.c

1299 lines
28 KiB
C

# include <stdio.h>
# include "gen.h"
# include "../h/dbs.h"
# include "../h/aux.h"
# include "../h/access.h"
# include "../h/pipes.h"
# include "../h/lock.h"
# include "../h/bs.h"
# ifdef P8000
ret_buf AAjmp_buf;
# else
jmp_buf AAjmp_buf;
# endif
/*
** DBS -- DBS startup
**
** This program starts up the entire system.
**
** Parameters:
** 1 -- database name
** 2 -- optional process table name
** x -- flags of the form +x or -x may be freely inter-
** sperced in the argument list.
**
** Return:
** none if successful
** 1 -- user error (no database, etc)
** -1 -- system error
**
** Flags:
** -&xxxx -- EQL flag: xxxx are file descriptors for the
** status return pipe, the command write pipe, the
** data return pipe, and the data transfer pipe
** respectively.
** -@xxxx -- xxxx is same as EQL flag, but no flags
** are set.
** -*?? -- Masterid flag. Gives the siteid of the master
** site in a distributed DBS. (Used in dist.
** DBS' initproc() function.)
** -|xxxx -- Network flag. This flag is just passed to
** the other processes, to be processed by the
** DBU's.
** -uusername -- set effective user to be username. You
** must be DBS or the DBA for the database to
** use this option.
** -cN -- set minimum character field output width to be
** N, default 6. This is the fewest number of
** characters which may be output in any "c" type
** field.
** -inN -- integer output width. this is the width of
** an integer field. The small "n" is the size
** of the internal field ("1", "2", or "4") and
** N is the width of the field for that flag.
** The defaults are -i16, -i26, and -i413.
** -fnxN.M -- floating point output width and precision.
** Small "n" is the internal width in bytes ("4"
** or "8"), x is the format (f, F, g, G, e, E,
** n, or N), N is the field width, and M is the
** precision (number of digits after the decimal
** point). The formats are:
** "f" or "F": FORTRAN-style F format: digits,
** decimal point, digits, no exponent.
** "e" or "E": FORTRAN-style E format: digits,
** decimal point, digits, letter "e" (or
** "E", depending on "x" in the param-
** eter), and an exponent. The scaling
** factor is always one, that is, there
** is always one digit before the decimal
** point.
** "g" or "G": F format if it will fit in the
** field, otherwise E format. Space is
** always left at the right of the field
** for the exponent, so that decimal
** points will align.
** "n" or "N": like G, except that space is not
** left for the decimal point in F style
** format (useful if you expect everything
** to fit, but you're not sure).
** The default is -fn10.3.
** -lx -- set horizontal seperator for print operations
** -vx -- set vertical seperator for print operations
** and retrieves to the terminal to be "x". The
** default is vertical bar ("|").
** +w -- database wait state. If set ("+w"), you will
** wait until the database is not busy. If clear,
** you will be informed if the database is busy.
** If not specified, the same operations take
** place depending on whether or not you are
** running in background (determined by whether
** or not your input is a teletype). If in fore-
** ground, you are informed; if in background,
** you wait.
** -M -- monitor trace flag
** -P -- parser trace flag
** -O -- ovqp trace flag
** -Q -- qrymod trace flag
** -D -- decomp trace flag
** -Z -- dbu trace flag. These flags require the 020 bit
** in the status field of the AA_USERS to be
** set. The syntax is loose and is described
** elsewhere. Briefly, "-Z" sets all flags except
** the last 20, "-Z4" sets flag 4, and "-Z5/7"
** sets all flags from 5 through 7.
** +L -- enable/disable upper to lower case mapping in the
** parser. Used for debugging.
** -rmode -- retrieve into mode
** -nmode -- index mode. These flags give the default
** modify mode for retrieve into and index. They
** default to cheapsort and isam. "Mode" can be
** any mode to modify except "truncated".
** +a -- enable/disable autoclear function in monitor.
** Default on.
** +b -- enable/disable batch update. Default on.
** The 02 bit is needed to clear this flag.
** +d -- enable/disable printing of the dayfile. Default
** on.
** +s -- enable/disable printing of almost everything from
** the monitor.
** +U -- enable/disable direct update of system catalogs.
** Default off. The 04 bit is needed to set this
** option.
**
** Files:
** USE_PROC -- to print a "usage: ..." message.
** .../data/base/<database>/admin -- to determine
** existance and some info about <database>.
** .../sys/etc/dayfile<VERSION> -- dayfile (printed by
** monitor).
** AA_USERS -- file with BS uid -> DBS code
** mapping, plus a pile of other information about
** the user.
** .../sys/etc/proctab<VERSION> -- default process table
*/
# define PTSIZE 2048 /* maximum size of the process table */
# define PTPARAM '$' /* parameter expansion indicator */
# define PTDELIM "$" /* separator string in proctab */
# define MAXPARAMS 10 /* max number of params in proctab */
# define MAXOPTNS 10 /* maximum number of options you can specify */
# define MAXPROCS 10 /* maximum number of processes in the system */
# define PVECTSIZE 6 /* number of pipes to each process */
# define EQLFLAG '&'
# define NETFLAG '|' /* network slave flag */
# define CLOSED 077
char Fileset[10];
char *AAdatabase;
extern char *AAdbpath; /* defined in initucode */
struct admin AAdmin; /* set in initucode */
char Fdesc[] = "??????????";
struct lockreq AALOCKREQ;
char Ptbuf[PTSIZE + 1];
char *Ptptr = Ptbuf; /* ptr to freespace in Ptbuf */
char *Opt[MAXOPTNS + 1];
int Nopts;
int No_exec; /* if set, don't execute */
char *User_ovrd; /* override usercode from -u flag */
int R_up; /* pipe descriptor: read from above */
int W_up; /* pipe descriptor: write to above */
int R_down; /* pipe descriptor: read from below */
int W_down; /* pipe descriptor: write to below */
char USE_PROC[] = "/sys/etc/";
/* system error messages, etc. */
extern int sys_nerr;
extern char *sys_errlist[];
extern int errno;
main(argc, argv)
int argc;
char **argv;
{
register int i;
register int j;
register char *p;
register int fd;
register char *proctab;
register char *ptr;
char *uservect[4];
extern int AAdbstat;
extern char *AAproc_name;
extern char *Flagvect[]; /* defined in initucode.c */
extern char *Parmvect[]; /* ditto */
extern char AAversion[]; /* version number */
extern char *AAztack();
AAproc_name = argv[0];
# ifdef xSTR1
AAtTrace(&argc, argv, 'X');
# endif
AA_itoa(getpid(), Fileset);
proctab = (char *) 0;
AAdatabase = (char *) 0;
/*
** Initialize everything, like Flagvect, Parmvect, AAusercode,
** etc.
*/
switch (i = initucode(argc, argv, TRUE, uservect, -1))
{
case 0:
case 5:
break;
case 1:
case 6:
AAsyserr(0, "Die Datenbank '%s' existiert nicht", Parmvect[0]);
case 2:
AAsyserr(0, "Sie duerfen auf die Datenbank '%s' nicht zugreifen", AAdatabase);
case 3:
AAsyserr(0, "Sie sind kein eingetragener DBS-Nutzer");
case 4:
printf("Sie haben keinen Datenbanknamen angegeben\n");
goto usage;
default:
AAsyserr(22200, AAproc_name, i);
}
/*
** Extract database name and process table name from
** parameter vector.
*/
proctab = Parmvect[1];
if (checkdbname(AAdatabase = Parmvect[0]))
{
printf("Unerlauber Datenbankname '%s'\n", AAdatabase);
goto usage;
}
/* scan flags in AA_USERS */
for (p = uservect[0]; *p; p++)
{
/* skip initial blanks and tabs */
if (*p == ' ' || *p == '\t')
continue;
ptr = p;
/* find end of flag and null-terminate it */
while (*p && *p != ' ' && *p != '\t')
p++;
i = *p;
*p = '\0';
/* process the flag */
doflag(ptr, 1);
if (!i)
break;
}
/* scan flags on command line */
for (i = 0; p = Flagvect[i]; i++)
doflag(p, 0);
/* check for query modification specified for this database */
if (!(AAdmin.adhdr.adflags & A_QRYMOD))
doflag("-q", -1);
/* do the -u flag processing */
if (User_ovrd)
AAbmove(User_ovrd, AAusercode, 2);
/* close any extraneous files, being careful not to close anything we need */
for (i = 'C'; i < 0100 + MAXFILES; i++)
{
for (j = 0; j < (sizeof Fdesc / sizeof *Fdesc); j++)
{
if (Fdesc[j] == i)
break;
}
if (j >= (sizeof Fdesc / sizeof *Fdesc))
close(i & 077);
}
/* determine process table */
if (!proctab)
{
/* use default proctab */
proctab = uservect[1];
if (!*proctab)
{
/* no proctab in AA_USERS */
AAconcat(AAztack(AAztack("=", argv[0]), "_tab"), AAversion, Ptbuf);
/* strip off the mod number */
for (p = Ptbuf; *p; p++)
if (*p == '/')
break;
*p = 0;
proctab = Ptbuf;
}
}
else
{
/* proctab specified; check permissions */
if (!(AAdbstat & ((*proctab == '=')? U_EPROCTAB: U_APROCTAB)))
{
printf("Sie duerfen die Prozesstabelle '%s' nicht angeben\n", proctab);
goto usage;
}
}
/* expand process table name */
if (*proctab == '=')
{
AAsmove(AAztack(AAztack(AApath, "/sys/etc/"), &proctab[1]), Ptbuf);
proctab = Ptbuf;
}
/* open and read the process table */
if ((fd = open(proctab, 0)) < 0)
{
printf("Prozesstabelle %s: %s\n", proctab, sys_errlist[errno]);
goto usage;
}
if ((i = read(fd, Ptbuf, PTSIZE + 1)) < 0)
AAsyserr(21058, proctab);
if (i > PTSIZE)
AAsyserr(21059, proctab, PTSIZE);
close(fd);
Ptbuf[i] = 0;
/* build internal form of the process table */
buildint();
/* don't bother executing if we have found errors */
if (No_exec)
{
usage: /* cat USE_PROC */
AAcat(AAztack(AAztack(AAztack(AApath, USE_PROC), argv[0]), "_use"));
fflush(stdout);
exit(1);
}
/* A lock is set on the database */
db_lock(flagval('E') > 0? M_EXCL: M_SHARE);
/* satisfy process table (never returns) */
satisfypt();
}
/*
** Process rubouts (just exit)
*/
rubproc()
{
AAunlall();
fflush(stdout);
exit(1);
}
/*
** DOFLAG -- process flag
**
** Parameters:
** flag -- the flag (as a string)
** where -- where it is called from
** -1 -- internally inserted
** 0 -- on user command line
** 1 -- from AA_USERS
**
** Side effects:
** All flags are inserted on the end of the
** "Flaglist" vector for passing to the processes.
** The "No_exec" flag is set if the flag is bad or you
** are not authorized to use it.
*/
struct flag
{
char flagname; /* name of the flag */
char flagstat; /* status of flag (see below) */
int flagsyntx; /* syntax code for this flag */
int flagperm; /* status bits needed to use this flag */
};
/* status bits for flag */
# define F_PLOK 01 /* allow +x form */
# define F_PLD 02 /* defaults to +x */
# define F_DBA 04 /* must be the DBA to use */
# define F_DROP 010 /* don't save in Flaglist */
/* syntax codes */
# define F_ACCPT 1 /* always accept */
# define F_C_SPEC 3 /* -cN spec */
# define F_I_SPEC 4 /* -inN spec */
# define F_F_SPEC 5 /* -fnxN.M spec */
# define F_CHAR 6 /* single character */
# define F_MODE 7 /* a modify mode */
# define F_INTERNAL 8 /* internal flag, e.g., -q */
# define F_EQL 9 /* EQL flag */
# define F_STRING 10 /* text */
struct flag Flagok[] =
{
'a', F_PLD|F_PLOK, F_ACCPT, 0,
'b', F_PLD|F_PLOK, F_ACCPT, U_DRCTUPDT,
'c', 0, F_C_SPEC, 0,
'd', F_PLD|F_PLOK, F_ACCPT, 0,
'f', 0, F_F_SPEC, 0,
'i', 0, F_I_SPEC, 0,
'l', 0, F_CHAR, 0,
'n', 0, F_MODE, 0,
'q', F_PLD|F_PLOK, F_INTERNAL, 0,
'r', 0, F_MODE, 0,
's', F_PLD|F_PLOK, F_ACCPT, 0,
'v', 0, F_CHAR, 0,
'w', F_PLOK|F_DROP, F_ACCPT, 0,
'D', 0, F_ACCPT, U_TRACE,
'E', F_PLOK|F_DBA, F_ACCPT, 0,
'I', 0, F_STRING, 0,
'L', F_PLOK, F_ACCPT, 0,
'M', 0, F_ACCPT, U_TRACE,
'O', 0, F_ACCPT, U_TRACE,
'P', 0, F_ACCPT, U_TRACE,
'Q', 0, F_ACCPT, U_TRACE,
'U', F_PLOK, F_ACCPT, U_UPSYSCAT,
'Z', 0, F_ACCPT, U_TRACE,
EQLFLAG, 0, F_EQL, 0,
NETFLAG, 0, F_EQL, 0,
'@', 0, F_EQL, 0,
'*', 0, F_ACCPT, 0,
0, 0, 0, 0
};
/* list of valid retrieve into or index modes */
char *Relmode[] =
{
"isam",
"cisam",
"hash",
"chash",
"heap",
"cheap",
"heapsort",
"cheapsort",
(char *) 0
};
doflag(p, where)
register char *p;
int where;
{
register struct flag *f;
register char *ptr;
register int i;
short intxx;
extern int AAdbstat;
/* check for valid flag format (begin with + or -) */
if (*p != '+' && *p != '-')
goto badflag;
/* check for flag in table */
for (f = Flagok; f->flagname != p[1]; f++)
if (!f->flagname)
goto badflag;
/* check for +x form allowed */
if (*p == '+' && !(f->flagstat & F_PLOK))
goto badflag;
/* check for permission to use the flag */
if ((f->flagperm && !(AAdbstat & f->flagperm) &&
(!(f->flagstat & F_PLD)? (*p == '+'): (*p == '-'))) ||
((f->flagstat & F_DBA) && !(AAdbstat & U_SUPER) &&
!AAbequal(AAusercode, AAdmin.adhdr.adowner, 2)))
{
printf("Sie duerfen das %s Flag nicht verwenden\n", p);
No_exec++;
}
/* check syntax */
switch (f->flagsyntx)
{
case F_ACCPT:
break;
case F_C_SPEC:
if (AA_atoi(&p[2], &intxx) || intxx > MAXFIELD)
goto badflag;
break;
case F_I_SPEC:
i = p[2] - '0';
if (i != sizeof (char) && i != sizeof (short) && i != sizeof (long))
goto badflag;
if (AA_atoi(&p[3], &intxx) || intxx > MAXFIELD)
goto badflag;
break;
case F_F_SPEC:
i = p[2] - '0';
if
(
# ifndef NO_F4
i != sizeof (float) &&
# endif
i != sizeof (double)
)
goto badflag;
switch (p[3])
{
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
case 'n':
case 'N':
break;
default:
goto badflag;
}
ptr = &p[4];
while (*ptr != '.')
if (!*ptr)
goto badflag;
else
ptr++;
*ptr = 0;
if (AA_atoi(&p[4], &intxx) || intxx > MAXFIELD)
goto badflag;
*ptr++ = '.';
if (AA_atoi(ptr, &intxx) || intxx > MAXFIELD)
goto badflag;
break;
case F_CHAR:
if (!p[2] || p[3])
goto badflag;
break;
case F_STRING:
if (!p[2])
goto badflag;
break;
case F_MODE:
for (i = 0; ptr = Relmode[i]; i++)
{
if (AAsequal(&p[2], ptr))
break;
}
if (!ptr)
goto badflag;
break;
case F_INTERNAL:
if (where >= 0)
goto badflag;
break;
case F_EQL:
ptr = &p[2];
for (i = 0; i < (sizeof Fdesc / sizeof *Fdesc); i++, ptr++)
{
if (*ptr == CLOSED)
continue;
if (!*ptr || *ptr < 0100 || *ptr >= 0100 + MAXFILES)
break;
Fdesc[i] = (*ptr & 077) | 0100;
}
break;
default:
AAsyserr(21060, f->flagsyntx);
}
/* save flag */
if (Nopts >= MAXOPTNS)
AAsyserr(0, "Zu viele Argumente");
if (!(f->flagstat & F_DROP))
Opt[Nopts++] = p;
return;
badflag:
printf("Unbekanntes Flag '%s'\n", p);
No_exec++;
return;
}
/*
** BUILDINT -- build internal form of process table
**
** The text of the process table is scanned and converted to
** internal form. Non-applicable entries are deleted in this
** pass, and the EQL pipes are turned into real file descrip-
** tors.
*/
struct proc
{
char *prpath;
char *prcond;
int prstat;
char *prstdout; /* file for stdout this proc */
char prpipes[PVECTSIZE + 2];
char *prparam;
};
/* bits for prstat */
# define PR_REALUID 01 /* run the process as the real user */
# define PR_NOCHDIR 02 /* run in the user's directory */
# define PR_CLSSIN 04 /* close standard input */
# define PR_CLSDOUT 010 /* close diagnostic output */
struct proc Proctab[MAXPROCS];
struct param
{
char *pname;
char *pvalue;
};
struct param Params[MAXPARAMS];
buildint()
{
register struct proc *pr;
register char *p;
register char *pipes;
register struct param *pp;
register int i;
register int j;
char *ptp;
extern char *getptline();
/* scan the template */
pr = Proctab;
while (ptp = getptline())
{
/* check for overflow of internal Proctab */
if (pr >= &Proctab[MAXPROCS])
AAsyserr(21061);
/* collect a line into the fixed-format proctab */
pr->prpath = ptp;
scanpt(&ptp, ':');
pr->prcond = ptp;
scanpt(&ptp, ':');
pipes = ptp;
scanpt(&ptp, ':');
pr->prstat = AA_oatoi(pipes);
pr->prstdout = ptp;
scanpt(&ptp, ':');
pipes = ptp;
scanpt(&ptp, ':');
if (AAlength(pipes) != PVECTSIZE)
AAsyserr(21062, pr->prpath, pipes);
AAsmove(pipes, pr->prpipes);
for (p = pr->prpipes; p < &pr->prpipes[PVECTSIZE]; p++)
if (!*p)
*p = CLOSED;
pr->prparam = ptp;
/* check to see if this entry is applicable */
for (p = pr->prcond; *p; )
{
/* determine type of flag */
switch (*p++)
{
case '=': /* flag must not be set */
j = 1;
break;
case '+': /* flag must be set on */
case '>':
j = 2;
if (*p == '=')
{
j++;
p++;
}
break;
case '-': /* flag must be set off */
case '<':
j = 4;
if (*p == '=')
{
j++;
p++;
}
break;
default:
/* skip any initial garbage */
continue;
}
/* get value of this flag */
i = flagval(*p++);
/* check to see if we should keep looking */
switch (j)
{
case 1:
if (!i)
continue;
break;
case 2:
if (i > 0)
continue;
break;
case 3:
if (i >= 0)
continue;
break;
case 4:
if (i < 0)
continue;
break;
case 5:
if (i <= 0)
continue;
break;
}
/* mark this entry as a loser and quit */
p = (char *) 0;
break;
}
if (!p) /* this entry does not apply; throw it out */
continue;
/* replace EQL codes with actual file descriptors */
for (p = pr->prpipes; *p; p++)
{
if (*p < '0' || *p > '9')
continue;
*p = Fdesc[*p - '0'];
}
/* this entry is valid, move up to next entry */
pr++;
}
pr->prpath = 0;
/* scan for parameters */
pp = Params;
pp->pname = "pathname";
pp++->pvalue = AApath;
while (p = getptline())
{
/* check for parameter list overflow */
if (pp >= &Params[MAXPARAMS])
AAsyserr(21063);
pp->pname = p;
/* get value for parameter */
if (!(pp->pvalue = p = getptline())) /* if no lines, make it null string */
pp->pvalue = "";
else /* get 2nd thru nth and concatenate them */
do
{
ptp = &p[AAlength(p)];
p = getptline();
*ptp = '\n';
} while (p);
/* bump to next entry */
pp++;
}
/* adjust free space pointer for eventual call to expand() */
Ptptr++;
}
/*
** FLAGVAL -- return value of flag
**
** Parameter:
** flag -- the name of the flag
**
** Return:
** -1 -- flag is de-asserted (-x)
** 0 -- flag is not specified
** 1 -- flag is asserted (+x)
*/
flagval(f)
register int f;
{
register char **p;
register char *o;
/* start scanning option list */
for (p = Opt; o = *p; p++)
if (o[1] == f)
return ((*o == '+')? 1: -1);
return (0);
}
/*
** SCANPT -- scan through process table for a set of delimiters
**
** Parameters:
** pp -- a pointer to a pointer to the process table
** delim -- a primary delimiter.
**
** Returns:
** The actual delimiter found
**
** Side effects:
** Updates pp to point the the delimiter. The delimiter
** is replaced with null.
*/
scanpt(pp, d)
register char **pp;
register int d;
{
register char *p;
register int c;
for (p = *pp; ; p++)
{
/* check to see if it is a delimiter */
if ((c = *p) == d)
{
/* we have a delim match */
*p++ = 0;
*pp = p;
return (c);
}
if (!c)
AAsyserr("SCANPT: d=%c, *pp=%s", d, *pp);
}
}
/*
** GETPTLINE -- get line from process table
**
** Return:
** zero -- end of process table or section
** else -- pointer to a line, which is a null-terminated
** string (without the newline).
**
** Side effects:
** sticks a null byte into Ptbuf at the end of the line.
**
** Note:
** sequential lines returned will be sequential in core,
** that is, they can be AAconcatenated by just
** changing the null-terminator back to a newline.
*/
char *getptline()
{
register int c;
register char *line;
/* mark the beginning of the line */
line = Ptptr;
/* scan for a newline or a null */
while ((c = *Ptptr++) != '\n')
{
if (!c)
{
/* arrange to return zero next time too */
Ptptr--;
return ((char *) 0);
}
}
/* replace the newline with null */
Ptptr[-1] = 0;
/* see if it is an "end-of-section" mark */
if (AAsequal(line, PTDELIM))
{
line[0] = 0;
return ((char *) 0);
}
return (line);
}
/*
** EXPAND -- macro expand a string
**
** A string is expanded: $name constructs are looked up and
** expanded if found. If not, the old construct is passed
** thru. The return is the address of a new string that will
** do what you want. Calls may be recursive. The string is
** not copied unless necessary.
**
** Parameters:
** s1 -- the string to expand
** intflag -- a flag set if recursing
**
** Return:
** the address of the expanded string, not copied unless
** necessary.
**
** Side effects:
** Ptbuf is allocated (from Ptptr) for copy space. There
** must be enough space to copy, even if the copy
** is not saved.
** Ptptr is updated to point to the new free space.
*/
char *expand(s1, intflag)
char *s1;
int intflag;
{
register char *s;
register struct param *pp;
register int c;
register int flag;
register int count;
register char *mark;
register char *xmark;
s = s1;
xmark = Ptptr;
flag = 0; /* set if made a macro expansion */
count = 0; /* set if any characters copied directly */
/* scan input string to end */
while (c = *s++)
{
/* check for possible parameter expansion */
if (c != PTPARAM)
{
/* nope, copy through if space */
if (Ptptr >= &Ptbuf[PTSIZE])
goto ptsizeerr;
*Ptptr++ = c;
count++;
continue;
}
/* possible expansion; mark this point */
mark = Ptptr;
/* collect the name of the parameter */
do
{
if (Ptptr >= &Ptbuf[PTSIZE])
{
ptsizeerr:
AAsyserr(21065);
}
*Ptptr++ = c;
c = *s++;
} while ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
s--;
/* look up in parameter table */
*Ptptr = 0;
for (pp = Params; pp->pname; pp++)
if (AAsequal(pp->pname, mark + 1))
break;
if (!pp->pname)
{
/* search failed, take string as is */
count++;
continue;
}
/* reprocess name delimiter unless a newline */
if (c == '\n')
s++;
/* found entry, copy it in instead */
/* back up over name */
Ptptr = mark;
/* check to see if we can return expansion as value */
if (!count && !*s)
{
/* then nothing before or after this call */
if (!intflag)
Ptptr = xmark;
return (pp->pvalue = expand(pp->pvalue, 1));
}
/* expand to new buffer */
pp->pvalue = expand(pp->pvalue, 1);
/* we are appending */
Ptptr--;
flag++;
}
/* null terminate the new entry (which must be copied) */
*Ptptr++ = 0;
/* see if we expanded anything */
if (flag) /* yes, return the new stuff in buffer */
return (xmark);
/* no, then we can return the original and reclaim space */
if (!intflag)
Ptptr = xmark;
return (s1);
}
/*
** SATISFYPT -- satisfy the process table
**
** Well folks, now that you've read this far, this is it!!! I
** mean, this one really does it!!! It takes the internal form
** built by buildint() and creates pipes as necessary, forks, and
** execs the DBS processes. Isn't that neat?
**
** * * * * * W A R N I N G * * * * *
**
** In some versions, the pipe() system call support function
** in libc.a clobbers r2. In versions 6 and 7 PDP-11 C compilers,
** this is the third register variable declared (in this case,
** "i"). This isn't a problem here, but take care if you change
** this routine.
**
** Returns:
** never
*/
satisfypt()
{
register struct proc *pr;
register char *p;
register int i;
struct pipfrmt pbuf;
int pipex[2];
/* scan the process table */
for (pr = Proctab; pr->prpath; pr++)
{
/* scan pipe vector, creating new pipes as needed */
for (p = pr->prpipes; *p; p++)
{
if ((*p >= 0100 && *p < 0100 + MAXFILES) || *p == CLOSED)
continue; /* then already open or never open */
/* not yet open: create a pipe */
if (pipe(pipex))
AAsyserr(21066, *p);
/* propagate pipe through rest of proctab */
fillpipe(*p, pr, pipex);
}
/* fork if necessary */
fflush(stdout);
if (!pr[1].prpath || !(i = fork()))
proc_exec(pr); /* child!! */
/* parent */
if (i < 0)
AAsyserr(21067);
/* resync to child */
rdpipe(P_PRIME, &pbuf);
rdpipe(P_INT, &pbuf, pr[1].prpipes[2] & 077);
/* scan pipes. close all not used in the future */
for (p = pr->prpipes; *p; p++)
{
if (*p == CLOSED)
continue;
if (checkpipes(&pr[1], *p))
if (close(*p & 077))
AAsyserr(21068, pr->prpath, *p & 077);
}
}
AAsyserr(21069);
}
/*
** FILLPIPE -- extend pipe through rest of process table
**
** The only tricky thing in here is that "rw" alternates between
** zero and one as a pipe vector is scanned, so that it will know
** whether to get the read or the write end of a pipe.
**
** Parameters:
** name -- external name of the pipe
** proc -- the point in the process table to scan from
** pipex -- the pipe
*/
fillpipe(name, pr, pipex)
int name;
register struct proc *pr;
int pipex[2];
{
register char *p;
register int rw;
/* scan rest of processes */
for ( ; pr->prpath; pr++)
{
/* scan the pipe vector */
rw = 1;
for (p = pr->prpipes; *p; p++)
{
rw = 1 - rw;
if (*p == name)
*p = pipex[rw] | 0100;
}
}
}
/*
** CHECKPIPES -- check for pipe referenced in the future
**
** Parameters:
** proc -- point in the process table to start looking
** from.
** fd -- the file descriptor to look for.
**
** Return:
** zero -- it will be referenced in the future.
** one -- it is never again referenced.
*/
checkpipes(pr, fd)
register struct proc *pr;
int fd;
{
register char *p;
register int fdx;
fdx = fd | 0100;
for ( ; pr->prpath; pr++)
{
for (p = pr->prpipes; *p; p++)
if (*p == fdx)
return (0);
}
return (1);
}
/*
** TABEXEC -- execute DBS process
**
** This routine handles all the setup of the argument vector
** and then executes a process.
**
** Parameters:
** process -- a pointer to the process table entry which
** describes this process.
**
** Returns:
** never
**
** Side Effects:
** never returns, but starts up a new overlay. Notice
** that it does NOT fork.
*/
proc_exec(pr)
register struct proc *pr;
{
register char *p;
register char **v;
register char **opt;
register int i;
register int outfd;
char *vect[30];
extern char *AAproc_name;
v = vect;
*v++ = expand(pr->prpath);
for (p = pr->prpipes; *p; p++)
continue;
*p++ = (AAlockdes < 0)? CLOSED: AAlockdes | 0100;
*p = 0;
*v++ = pr->prpipes;
*v++ = Fileset;
*v++ = AAusercode;
*v++ = AAdatabase;
*v++ = AApath;
/* expand variable number of parameters */
for (p = pr->prparam; *p; )
{
for (*v = p; *p; p++)
if (*p == ':')
{
*p++ = 0;
break;
}
/* expand macros in parameters */
*v = expand(*v);
v++;
}
/* insert flag parameters */
for (opt = Opt; *opt; opt++)
*v++ = *opt;
*v = 0;
/* close extra pipes (those not in pipe vector) */
for (i = 0100; i < 0100 + MAXFILES; i++)
{
for (p = pr->prpipes; *p; p++)
if (i == *p)
break;
if (!*p && i != 0101 &&
(i != 0100 || (pr->prstat & PR_CLSSIN)) &&
(i != 0102 || (pr->prstat & PR_CLSDOUT)))
close(i & 077);
}
/* change to the correct directory */
if (!(pr->prstat & PR_NOCHDIR) && chdir(AAdbpath))
AAsyserr(22201, AAproc_name, AAdbpath);
/* change to normal userid/groupid if a non-dangerous process */
if (pr->prstat & PR_REALUID)
{
setuid(getuid());
setgid(getgid());
}
/* change standard output if specified in proctab */
p = pr->prstdout;
if (*p)
{
/* chew up fd 0 (just in case) */
outfd = dup(1);
close(1);
if (creat(p, 0666) != 1)
{
/* restore standard output and print error */
close(1);
dup(outfd); /* better go into slot 1 */
AAsyserr(21071, p);
}
close(outfd);
}
/* give it the old college (or in this case, University) try */
fflush(stdout);
execv(vect[0], vect);
AAsyserr("PROC_EXEC: \"%s\" not executable", vect[0]);
}
/*
** CHECKDBNAME -- check for valid database name
**
** Parameter:
** name -- the database name
**
** Return:
** zero -- ok
** else -- bad database name
*/
checkdbname(name)
register char *name;
{
register int c;
if (AAlength(name) > MAXNAME)
return (1);
while (c = *name++)
if (c == '/')
return (1);
return (0);
}
AApageflush()
{
}