Remote troff package
Steve D. Miller
steve at tove.UUCP
Fri Mar 29 13:26:45 AEST 1985
I've gotten quite a bit of mail about my remote troff stuff;
while I've replied to most of it already, the level of interest
indicates that the world might actually be interested in such a
beast. Anyway, here it is (it's pretty short, so I'm posting
this both here and in net.sources...). For those of you who don't
want to read the code (and those of you who don't want to
read someone's first C program...), here's what I'm including,
how it works, and (roughly) how to install it.
This set of programs includes:
1) A set of manual entries for rtroff (remote troff),
load (a program written by Fred Blonder here
at UMCP to return load status to the shell
in various interesting forms), and ltroff (a
shell script that uses load, rtroff, and rcatdvi
to wrap all this stuff into a form that the average
user can use to get stuff to our imagen without
having to know what all this stuff does).
2) The source for ltroff (shell script), load, rtroff,
and rcatdvi (remote Imagen catdvi/dviimp).
3) A makefile to make, install, and set the permissions
stuff for everything.
Rtroff operates via the rcmd() call in 4.2 BSD; it takes normal
troff arguments, figures out what refers to files and what doesn't
do so, then adds the "-t" and "-" options to the command line,
snips out all the filenames, and starts a troff up on a remote
machine. Rtroff then sends all the files down the socket, doing
junk like ".so" elimination on the fly, and reads the socket (stdout/
stderr for the troff). The results go to rtroff's stdout. Rtroff
also looks at its invocation, and is perfectly capable of acting
as rnroff if a link is made between the two.
Rcatdvi is like rtroff, but it doesn't need to do macro manipulation
or argument parsing, so it's a *lot* simpler.
Ltroff is a csh script (yes, I've seen the recent postings about
csh scripts, but I didn't write it to start; I think Pete Cottrell
did most of it, with my mods for load-sharing and my documentation;
I avoid shell scripts whenever I can and I doubt that I could have
written it from scratch) that acts like troff, but handles load checking,
offloading (calling rtroff vs troff and rcatdvi vs catdvi), and
queueing (we use MDQS here; the script shouldn't be hard to change for
something else) for a user community that doesn't want to think about
such things. The load level cutoff is specified in the "load"
variable in the shell script, and there is also extra stuff
in there that checks to see if the user is authorized to use our
Imagen.
Load is a program that opens kmem and looks at the load average,
and returns status to the shell depending on what it finds there;
check the man entry for details.
Rtroff handles going from host to host by reading a list of
hosts in a file (/etc/rtrhosts); it connects to the first in
the list, and if that times out, tries the next, until it hits
the end of the list and gives up. Rcatdvi operates in the
same way. This scheme means that the least loaded of your
machines should be at the top of the list, followed by your
other machines in a sensible order. The remote execution runs
under the "rtroff" account, which can have an asterisk for
a password field entry (as long as /etc/hosts.equiv is set
up properly; I suppose that one could do this using ~rtroff/
.rhosts and listing names, but that's ugly...).
To do the things it has to, rtroff, rcatdvi, and load all need
to be setuid root; the makefile will set permissions if you
are running as root. To make, do "make all", then "make install".
If you have problems or questions, please let me know. And without
further ado...
Spoken: Steve Miller ARPA: steve at maryland Phone: +1-301-454-4251
CSNet: steve at umcp-cs UUCP: {seismo,allegra}!umcp-cs!steve
USPS: Computer Science Dept., University of Maryland, College Park, MD 20742
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting Makefile'
sed 's/^X//' <<'//go.sysin dd *' >Makefile
# Makefile for the remote troff stuff
# Steven D. Miller (steve at maryland.ARPA)
CC = cc -s -O
#
# RTRBIN is the place you want all this stuff to live (usually
# /usr/local/bin).
#
RTRBIN = /usr/local/bin
RTRSRC = load.c rtroff.c rcatdvi.c
# MAN is where you want the manual entries; should be /usr/man/man1
MAN = /usr/man/man1
all: man load rtroff rcatdvi
load: load.o
$(CC) -o load load.o
rtroff: rtroff.o
$(CC) -o rtroff rtroff.o
rcatdvi: rcatdvi.o
$(CC) -o rcatdvi rcatdvi.o
man: rtroff.1l load.1l ltroff.1
cp rtroff.1l $(MAN)/rtroff.1l
cp ltroff.1 $(MAN)/ltroff.1
cp load.1l $(MAN)/load.1l
install: $(RTRBIN)/ltroff $(RTRBIN)/rtroff $(RTRBIN)/rnroff \
$(RTRBIN)/load $(RTRBIN)/rcatdvi
$(RTRBIN)/ltroff: ltroff
cp ltroff $(RTRBIN)/ltroff
$(RTRBIN)/rtroff: rtroff
echo I hope you're running as root...
cp rtroff $(RTRBIN)/rtroff
chmod 4555 $(RTRBIN)/rtroff
$(RTRBIN)/rnroff : rtroff
ln -s $(RTRBIN)/rnroff $(RTRBIN)/rtroff
$(RTRBIN)/load : load
echo Need to be root for this, too...
cp load $(RTRBIN)/load
chmod 4555 $(RTRBIN)/load
$(RTRBIN)/rcatdvi : rcatdvi
echo Need to be root to install rcatdvi
cp rcatdvi $(RTRBIN)/rcatdvi
chmod 4555 $(RTRBIN)/rcatdvi
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 Makefile
/bin/echo -n ' '; /bin/ls -ld Makefile
fi
/bin/echo 'Extracting load.1l'
sed 's/^X//' <<'//go.sysin dd *' >load.1l
X.TH LOAD 1L 4-Oct-1984
X.SH NAME
load \- determines if system load is greater than input value,
or prints current system load
X.SH SYNOPSIS
X.B load
[\-sv]
X.B [ maxload ]
X.SH DESCRIPTION
X.I Load
returns true if the system load is greater
than or equal to the value given by
X.I
maxload.
By default, the program returns yes if the system
load is too high and no if it is not.
If the -v option is specified, a more detailed message
is displayed.
The -s option will display no message.
X.sp
If
X.I load
is invoked with no argument, it prints the current 15-minute load average.
X.SH FILES
X.SH "SEE ALSO"
uptime(1), w(1), vmpic(1l)
X.SH DIAGNOSTICS
X.SH AUTHOR
Fred Blonder
X.SH BUGS
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 load.1l
/bin/echo -n ' '; /bin/ls -ld load.1l
fi
/bin/echo 'Extracting load.c'
sed 's/^X//' <<'//go.sysin dd *' >load.c
#ifndef lint
static char *scssid = "@(#)load.c (University of Maryland) Oct 7, 1981";
static char RCSid[] = "@(#)$Header: /usr/fred/src/progs/RCS/load.c,v 1.2 84/10/04 21:54:14 fred Exp $";
#endif lint
X/*
* load.c - returns true if the system load is >= value given by argv[1]
*
* Cannibalized from rogue (main.c) by Fred Blonder, Oct 7, 1981
*
* $Log: load.c,v $
* Revision 1.2 84/10/04 21:54:14 fred
* RCSified everything. Uses sysexits.h. Default action is to print
* current load. 4-Oct-84 FLB.
*
* To compile:
% cc -s -O load.c -o load
*/
#include <sysexits.h>
#include <nlist.h>
main(argc, argv)
int argc;
char *argv[];
{
double maxload = 0.0, avec[3], atof();
char *yes_msg = "Yes\n", *no_msg = "No\n";
while (argc > 2 && argv[1][0] == '-') {
switch (argv[1][1]) {
case 's':
yes_msg = no_msg = "";
break;
case 'v':
yes_msg = "System load too high\n";
no_msg = "System load not too high\n";
break;
default:
printf("Load: option ``%s'' not recognized, ignored.\n", argv[1]);
}
argc--;
argv++;
}
loadav(avec);
if (argc < 2) {
printf("%5.2f\n", avec[2]);
exit(EX_OK);
}
if ((maxload = atof(argv[1])) <= 0.0) {
printf("Load: absurd load value: %f\n", maxload);
exit(EX_DATAERR);
}
if (avec[2] >= maxload) {
printf(yes_msg);
exit(EX_OK);
}
else {
printf(no_msg);
exit(1);
}
}
struct nlist avenrun =
{
"_avenrun"
};
loadav(avg)
register double *avg;
{
register int kmem;
if ((kmem = open("/dev/kmem", 0)) < 0) {
perror("Can't open /dev/kmem");
exit(EX_OSFILE);
}
nlist("/vmunix", &avenrun);
if (avenrun.n_type == 0) {
avg[0] = avg[1] = avg[2] = 0.0;
return;
}
lseek(kmem, (long) avenrun.n_value, 0);
read(kmem, avg, 3 * sizeof (double));
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 load.c
/bin/echo -n ' '; /bin/ls -ld load.c
fi
/bin/echo 'Extracting ltroff'
sed 's/^X//' <<'//go.sysin dd *' >ltroff
#! /bin/csh -f
# troff to the IMAGEN imPrint printer
# /etc/renice 4 $$ >& /dev/null
set flags=(-rv1) noglob fonts=() cflags=() host=() rshhost=()
set macp=(/usr/lib/tmac/tmac.vcat)
set facp=(-F/usr/lib/imagen/font/ftXX )
set PATH=(. /usr/local/bin /usr/bin /usr/ucb )
set path=($PATH)
set local load=(2)
unset t w dv i doremote
top:
if ($#argv > 0) then
switch ($argv[1])
case -sd:
set dv
shift argv
goto top
case -si:
set i
shift argv
goto top
case -sc:
case -t:
set t
shift argv
goto top
case -w:
set w
shift argv
goto top
case -x:
set macp=()
shift argv
goto top
case -F:
shift argv
if ($#argv > 0) then
set flags = ($flags -F$argv[1]/ftXX)
set cflags = ($cflags -C$argv[1]/catab)
set facp = ()
set w
shift argv
endif
goto top
case -c*:
set cflags = ($cflags $argv[1])
shift argv
goto top
case -h:
set host = ($argv[1])
set doremote
shift argv
set host= ($host $argv[1])
set rshhost= ($argv[1])
shift argv
goto top
case -l:
unset local
shift argv
goto top
case -r:
shift argv
set load=($argv[1])
shift argv
goto top
case -*:
set flags = ($flags $argv[1])
shift argv
goto top
endsw
endif
if ($#argv == 0) then
set argv=(-)
set banner=stdin
else
set banner="$argv"
endif
X/usr/local/bin/load -s $load
if ($status == 0 && $?local) then
set troffcmd=(rtroff)
set catcmd=(/usr/local/bin/rcatdvi $host )
else
set troffcmd=(troff)
set catcmd=(/usr/local/bin/catdvi)
set host=()
endif
if ($?doremote) then
set troffcmd=(rtroff)
set catcmd=(/usr/local/bin/rcatdvi $host )
endif
if ($?t) then
/usr/bin/troff -x -t $flags $facp $macp $*
else
/usr/bin/fgrep -s ,`/usr/ucb/whoami`, /etc/restrict/mdqs/ltroff_users
if ($status) then
echo Sorry, you\'re not authorized to send directly to the Imagen.
else if ($?dv) then
$troffcmd $host -x -t $flags $facp $macp $* | $catcmd -b "$banner" $cflags
else if ($?i) then
$troffcmd $host -x -t $flags $facp $macp $* | $catcmd -a -b "$banner" $cflags
else if ($?w) then
$troffcmd $host -x -t $flags $facp $macp $* | $catcmd -b "$banner" $cflags
else
$troffcmd $host -x -t $flags $facp $macp $* | $catcmd -a -b "$banner" $cflags | /usr/bin/qpr -q imagen-imp
#######else
####### /usr/bin/troff -x -t $flags $facp $macp $* | /usr/ucb/lpr -Pimagen -t
endif
endif
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 ltroff
/bin/echo -n ' '; /bin/ls -ld ltroff
fi
/bin/echo 'Extracting ltroff.1'
sed 's/^X//' <<'//go.sysin dd *' >ltroff.1
X.TH LTROFF 1 "4 October 1984"
X.SH NAME
ltroff \- text formatting on Imagen printer
X.SH SYNOPSIS
X.B ltroff
[ macro option ] ...
[ option ] ...
[ file ] ...
X.SH DESCRIPTION
X.I Ltroff
formats text in the named
X.I files
for printing on an Imprint-10 laser printer. If the local load is above
seven, then the processing needed is done remotely; otherwise, the
processing is done locally.
X.I Ltroff
accepts files that would be used as input for
X.I troff
transparently, as far as the user is concerned. In addition to
standard
X.I troff
options, the options that are specific to
X.I ltroff
are:
X.TP
X.BR \-sd " or " \-w
Leave output on standard output in DVI form.
X.TP
X.BI \-si
Leave output on standard output in imPress form.
This output may be printed with "qpr -q imagen-imp".
X.TP
X.BR \-sc " or " \-t
Leave output on standard output in C/A/T form.
X.TP
X.B \-x
Turn off the use of the standard macro package /usr/lib/tmac/tmac.vcat.
X.TP
X.B \-h [hostname]
If the load is above the cutoff, do the processing on machine
X.I hostname.
X.TP
X.B \-l
Force processing to be done on local machine, regardless of load.
X.TP
X.B \-Ffontdir
Use the files in this directory as the font width tables for
X.I troff.
The default font spacing files are in /usr/lib/imagen/font/ftXX.
X.TP
X.BR \-c " arg"
Pass arg to
X.I catdvi.
X.SH BUGS
X.PP
The options to leave files in DVI form are not currently implemented
due to modifications made in catdvi and dviimp. The output
produced is in imPress form.
X.PP
Remote processing may only be done on hosts running the rtroff daemon.
The default host is gymble.
X.SH FILES
X.ta \w'/usr/lib/tmac/tmac.vcat 'u
X.br
X/usr/lib/tmac/tmac.vcat C/A/T macro file
X.SH "SEE ALSO"
X.br
troff(1), rtroff(1), catdvi(1), dviimp(1), qpr(1), istat(1)
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 ltroff.1
/bin/echo -n ' '; /bin/ls -ld ltroff.1
fi
/bin/echo 'Extracting rcatdvi.c'
sed 's/^X//' <<'//go.sysin dd *' >rcatdvi.c
X/*
*
* rcatdvi -- send stdin to catdvi on remote
* machine, get stdout and stderr back. Invoked as
* "rcatdvi [-h host] [catdvioptions], runs setuid to make
* connection, then does a setuid(getuid) to go back.
*
*/
#include <stdio.h>
#include <netdb.h>
#include <pwd.h>
#include <time.h>
#define LINESIZ 133
main(argc,argv)
int argc;
char *argv[];
{
char cmdline[LINESIZ];
char *host;
struct servent *serv;
struct passwd *rtroff;
struct hostent *rhost;
int i;
int firstarg;
int errfd, iofd;
int uid;
int readfds, writefds, readyrd, readywt;
if((serv=getservbyname("shell","tcp"))==NULL) {
perror("rcatdvi:getservbyname");
exit(-1);
}
if (strcmp("-h",argv[1])==0) {
host=argv[2];
firstarg=3;
}
else
firstarg=1;
strcat(cmdline,"/usr/local/bin/catdvi");
if (argc>(firstarg-1)) {
for (i=firstarg;i<=argc;i++) {
strcat(cmdline," ");
strcat(cmdline,argv[i]);
}
}
if ((rhost=gethostbyname(host))==NULL) {
/*
* since we can't find the requested host, if any,
* let's check the config file and connect around
* in there.
*/
FILE *rtrhosts;
char *pos;
char thishost[LINESIZ];
char *index();
if ((rtrhosts=fopen("/etc/rtrhosts","r"))==NULL) {
perror("rcatdvi:can't open /etc/rtrhosts");
exit(1);
}
while ((host=fgets(thishost,LINESIZ,rtrhosts))!=NULL) {
if ((pos=index(thishost,'\n'))!=0)
*pos='\0';
if((iofd=rcmd(&host,serv->s_port,"rtroff",
"rtroff",cmdline,&errfd))<0) {
perror("rcatdvi:rcmd:");
continue;
} else break;
}
if(iofd<0) {
perror("rcatdvi:can't get a host");
exit(1);
}
} else if((iofd=rcmd(&host,serv->s_port,"rtroff",
"rtroff",cmdline,&errfd))<0) {
perror("rcatdvi:rcmd");
exit(-1);
}
setuid(getuid());
setgid(getgid());
readfds=(1<<iofd | 1<<errfd);
writefds=(1<< iofd);
while (readfds || writefds) {
readyrd=readfds;
readywt=writefds;
if (select(16,&readyrd,&readywt,0,0)<0) {
perror("rcatdvi:select");
exit(1);
}
if (readyrd & (1<<iofd)) {
char buf[LINESIZ];
int nread;
if ((nread=read(iofd,buf,sizeof(buf)))<=0)
readfds &= ~(1<<iofd);
else
write(1,buf,nread);
}
if (readyrd & (1<<errfd)) {
char buf[LINESIZ];
int nread;
if ((nread=read(errfd,buf,sizeof(buf)))<=0)
readfds &=~ (1<<errfd);
else
write(2,buf,nread);
}
if (readywt & (1<<iofd)) {
char buf[LINESIZ];
int nread;
if ((nread=read(0,buf,sizeof(buf)))<=0) {
shutdown(iofd,1);
writefds &= ~(1<<iofd);
}
else
write(iofd,buf,nread);
}
}
shutdown(errfd,1);
fflush(stdout);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 rcatdvi.c
/bin/echo -n ' '; /bin/ls -ld rcatdvi.c
fi
/bin/echo 'Extracting rtroff.1l'
sed 's/^X//' <<'//go.sysin dd *' >rtroff.1l
X.TH RTROFF 1 "16 September 1984"
X.SH NAME
rtroff, rnroff \- remote text formatting and typesetting
X.SH SYNOPSIS
X.B rtroff
[ \-h hostname ]
[ option ] ...
[ file ] ...
X.PP
X.B rnroff
[ \-h hostname ]
[ option ] ...
[ file ] ...
X.SH DESCRIPTION
X.I Rtroff
formats text in the named
X.I files
for printing on a Graphic Systems C/A/T phototypesetter;
X.I rnroff
is used for typewriter-like devices.
Both of these commands act like
X.I troff(1)
and
X.I nroff(1)
,except that the text processing is done on a remote machine.
The \-h option may be used to specify the remote host for processing;
if no host is specified, the file /etc/rtrhosts is searched and a
connection is attempted to the machines listed in that file in the order
in which they appear. If a connection cannot be established to one machine,
the next in order is consulted.
All options and
files are specified as in
X.I
troff(1).
X.SH SEE ALSO
troff(1)
X.SH BUGS
The troff directives '.so', '.nx', and '.rd' will not be handled
correctly if part of a macro definition or conditional statement,
but will be handled correctly if used as a deferred (i.e. "'so")
directive.
X.PP
Use of the '.pi' directive may produce unpredictable results.
X.PP
Files that use the '\-man' macros may have unusual page titles; i.e.
files sent from a Vax to a Pyramid 90X will not say "Unix Programmers'
Manual" but will say "Pyramid OSX Users' Manual."
X.PP
If rtroff has to try more than one machine in /etc/rtrhosts,
extraneous scary error messages ("Connection
timed out") will be printed. If there are more machines in the list
left to be tried, these errors can be ignored.
X.SH AUTHOR
Steven D. Miller
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 rtroff.1l
/bin/echo -n ' '; /bin/ls -ld rtroff.1l
fi
/bin/echo 'Extracting rtroff.c'
sed 's/^X//' <<'//go.sysin dd *' >rtroff.c
#define BUFSIZE 1024
#define LINESIZ 133
#define ATPORT 562
#define MAXARGS 256
#define FALSE 0
#define TRUE 1
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/wait.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
int skt,errskt;
int errno;
char *hostname;
main(argc,argv)
int argc;
char *argv[];
{
struct sockaddr_in addr;
int needstdin=FALSE;
char tcmd[BUFSIZE];
char *fargv[MAXARGS];
struct passwd *pwd;
int geterrs();
struct servent *serv;
signal(SIGPIPE,geterrs); /* if t/nroff dies before all files are
sent, then read error msgs */
needstdin=parseargs(argc,argv,fargv,tcmd);
if ((serv=getservbyname("shell","tcp"))==NULL) {
perror("rtroff:getservbyname");
exit(1);
}
if ((pwd=getpwuid(getuid()))==NULL) {
perror("rtroff:getpwuid");
exit(1);
}
if (hostname!=NULL) {
if ((skt=rcmd(&hostname,serv->s_port,"rtroff",
"rtroff",tcmd,&errskt))<0) {
perror("rtroff:rcmd");
exit(1);
}
}
else {
/*
* If the user has not specified a host name, then
* we search the hosts in /etc/rtrhosts in the
* order specified in the file for a place to get
* a connection to.
*/
FILE *rtrhosts;
char *pos;
char thishost[LINESIZ];
char *index();
if ((rtrhosts=fopen("/etc/rtrhosts","r"))==NULL) {
perror("rtroff:can't open /etc/rtrhosts");
exit(1);
}
while ((hostname=fgets(thishost,LINESIZ,rtrhosts))!=NULL) {
if ((pos=index(thishost,'\n'))!=0)
*pos='\0';
if((skt=rcmd(&hostname,serv->s_port,"rtroff",
"rtroff",tcmd,&errskt))<0) {
perror("rtroff:rcmd:");
continue;
} else break;
}
if (skt<0) {
perror("rtroff:can't get a host");
exit(1);
}
}
setuid(getuid());
setgid(getgid());
sendfiles(fargv,skt);
if(needstdin)
sendonefile(0,skt);
getmsgs(skt,errskt);
close(skt);
exit(0);
}
char *
sindex(s1,s2)
char *s1,
*s2;
{
char *ch;
char *ch2=s2;
char *index();
if ((ch=index(s1,*s2))==NULL)
return(NULL);
while(*ch2!=0) {
if (*ch++!=*ch2++)
return(NULL);
}
return(index(s1,*s2));
}
int
parseargs(argc,argv,fargv,tcmd)
int argc;
char *argv[];
char *fargv[];
char *tcmd;
{
int cnt=1;
int tostdout=FALSE;
int needstdin=FALSE;
int fcnt=0;
int tcnt=1;
char *index();
if (sindex(argv[0],"troff")!=NULL)
strcpy(tcmd,"/usr/bin/troff ");
else
strcpy(tcmd,"/usr/bin/nroff ");
hostname=NULL;
cnt=1;
while (cnt<argc) {
char *arg;
if(*argv[cnt]=='-') {
arg=argv[cnt];
arg++;
switch(*arg) {
case '\0':
needstdin=TRUE;
break; /* don't copy this arg, since troff
doesn't handle options after '-'
properly. It will be put on the
end of the argument list later. */
case 's':
case 'i':
needstdin=TRUE;
strcat(tcmd,argv[cnt]);
strcat(tcmd," ");
break;
case 't':
case 'a':
tostdout=TRUE;
strcat(tcmd,argv[cnt]);
strcat(tcmd," ");
break;
case 'h':
hostname=argv[cnt+1];
cnt++;
break;
default:
strcat(tcmd,argv[cnt]);
strcat(tcmd," ");
}
cnt++;
}
else { /* must be a file name */
fargv[fcnt++]=argv[cnt];
cnt++;
}
}
if ((tostdout==FALSE) && (sindex(tcmd,"nroff")==0)) { /* not nroff */
strcat(tcmd,"-t"); /* force to stdout if not going there */
strcat(tcmd," ");
}
strcat(tcmd,"-"); /* must act as if reading only from stdin */
fargv[fcnt]=0; /* terminate lists */
return(needstdin);
}
sendfiles(fargv,skt)
char *fargv[];
int skt;
{
char *sendbuf[BUFSIZE];
int cnt=0;
int nread;
if (fargv[0]==0) {
sendonefile(0,skt); /* send stdin */
return;
}
while (fargv[cnt]!=0) {
int ftosend;
if ((ftosend=open(fargv[cnt],0))==-1) {
fprintf(stderr,"rtroff: could not open file %s\n",
fargv[cnt]);
exit(-1);
}
else {
sendonefile(ftosend,skt);
cnt++;
}
}
return;
}
sendonefile(fd,sktout)
int fd; /* open descriptor for file to be sent */
int sktout; /* descriptor to which it is to go */
{
char *buf[LINESIZ];
int nread;
int readfds, writefds, readyrd, readywt;
struct timeval timeout;
readfds=(1<<skt) | (1<<errskt);
writefds=(1<<sktout);
do {
readyrd=readfds;
readywt=writefds;
if (select(16,&readyrd,&readywt,0,0)<0)
break;
if(readyrd & (1<<skt)) {
nread=read(skt,buf,sizeof(buf));
if (nread >0)
write(1,buf,nread);
}
if (readyrd & (1<<errskt)) {
nread=read(errskt,buf,sizeof(buf));
if (nread >0)
write(2,buf,nread);
}
if (readywt & (1<<sktout)) {
nread=getline(buf,fd);
if (nread<=0) {
close(fd);
return;
}
if ((strncmp(buf,".so",3)==0) || (strncmp(buf,"'so",3)==0)) /* include .so file in stream */
getso(buf,sktout);
else if ((strncmp(buf,".nx",3)==0) || (strncmp(buf,"'nx",3)==0)) /* send .nx file */
getnx(buf,sktout,fd);
else if((strncmp(buf,".rd",3)==0) || (strncmp(buf,"'rd",3)==0)) /* handle .rd instruction */
getrd(buf,sktout);
else if (write(sktout,buf,strlen(buf))<=0) {
perror("sendfiles:write");
exit(-1);
}
}
} while (readfds);
}
getline(buf,fd)
char *buf;
int fd;
{
int nread=0;
char chr=0;
while(read(fd,&chr,1)!=0) {
*buf++=chr;
nread++;
if (chr=='\n')
break;
}
*buf++='\0';
if(chr='\n')
return(nread);
else
return(0);
}
getfname(chrptr,buf) /* copies from chrptr to white space into buf */
char *chrptr;
char *buf;
{
int index=0;
while((*chrptr!=' ') && (*chrptr!='\t') && (*chrptr!='\n')) {
*buf++ = *chrptr;
chrptr++;
}
*buf='\0';
}
getso(buf,skt)
char *buf;
int skt;
{
char *sobuf[LINESIZ];
char *sofname;
int sofd;
if ((sofname=index(buf,' '))==0) {
if ((sofname=index(buf,'\t'))==0)
return;
}
sofname++;
getfname(sofname,sobuf);
if((sofd=open(sobuf,0))<0) {
fprintf(stderr,"rtroff: could not open file %s\n",sobuf);
exit(-1);
}
sendonefile(sofd,skt);
}
getnx(buf,skt,fd)
char *buf;
int skt;
int fd;
{
char *nxbuf[LINESIZ];
char *nxfname;
int nxfd;
if ((nxfname=index(buf,' '))==0) {
if ((nxfname=index(buf,'\t'))==0)
return;
}
nxfname++;
getfname(nxfname,nxbuf);
close(fd);
if((nxfd=open(nxbuf,0))<0) {
fprintf(stderr,"rtroff: could not open file %s\n",nxbuf);
exit(-1);
}
sendonefile(nxfd,skt);
}
getrd(buf,skt)
char *buf;
int skt;
{
char *prompt[LINESIZ];
char chr;
char *prstart;
int newlines=0;
int nread;
if ((prstart=index(buf,' '))==0)
if ((prstart=index(buf,'\t'))==0)
strcpy(prompt,"\7");
else {
prstart++;
getfname(prstart,prompt);
}
fprintf(stderr,"%s",prompt);
chr=getchar();
while(chr !=EOF) {
if (chr=='\n') {
fprintf(stderr,"%s",prompt);
chr=getchar();
if (chr=='\n')
chr=EOF;
else
write(skt,"\n",1);
}
write(skt,&chr,1);
fprintf(stderr,"%s",prompt);
chr=getchar();
}
/* should really pass the end of the line on here */
}
getmsgs(sfd,errsfd)
int sfd;
int errsfd;
{
char *buf[BUFSIZE];
char *retstat[BUFSIZE];
char *pos;
int nread;
int selectfds,readyfds;
struct timeval timeout;
shutdown(sfd,1);
shutdown(errsfd,1);
selectfds=(1<<sfd) | (1<<errsfd);
do {
readyfds=selectfds;
if(select(16,&readyfds,0,0,0)<0)
break;
if (readyfds & (1<<sfd)) {
nread=read(sfd,buf,sizeof(buf));
if (nread <=0) {
shutdown(sfd,2);
selectfds &= ~(1<<sfd);
}
else
write(1,buf,nread);
}
if (readyfds & (1<<errsfd)) {
nread=read(errsfd,buf,sizeof(buf));
if (nread<=0) {
shutdown(errsfd,2);
selectfds &= ~(1<<errsfd);
}
else
write(2,buf,nread);
}
} while (selectfds);
close(sfd);
close(errsfd);
exit(0);
}
geterrs()
{
char *buf[BUFSIZE];
int nread;
fcntl(1,F_SETFL,FNDELAY);
if (write(1,"\0",1)<0) {
if (errno==EPIPE) {
fprintf(stderr,"Broken pipe\n");
exit (-1);
}
}
while((nread=read(errskt,buf,sizeof(buf)))!=0)
write(2,buf,nread);
exit(0);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 rtroff.c
/bin/echo -n ' '; /bin/ls -ld rtroff.c
fi
More information about the Comp.unix.wizards
mailing list