[net.sources] remote manual server/client source available - part 2 of 4

broome@ucbvax.ARPA (Jonathan C. Broome) (08/28/85)

[ cat this file onto the end of the previous part ]
{
    struct   stat st;
    long     time;
    FILE     *fp;
    extern   int use_more;
    register int ch, pid;

    if (israw)
        strcpy (cat, man);
    else {
        stat (man, &st);
        time = st.st_mtime;
        if (stat (cat, &st) < 0 || st.st_mtime < time || st.st_size == 0) {
            fprintf (stderr, "Reformatting page. Wait ... ");
            (void) fflush (stderr);
            if (format (man, cat)) {
                fprintf (stderr, "aborted (sorry)\n");
                return (0);
            }
            fprintf (stderr, "done.\n");
        }
    }
    if (!use_more) {
        if ((fp = fopen (cat, "r")) == NULL)
            return (0);
        while ((ch = getc (fp)) != EOF)
            putchar (ch);
        fclose (fp);
    } else {
        if ((pid = fork()) == 0) {
#ifdef SETUID
            setuid (getuid ());
#endif
            execlp (pager, pager, "-s", cat, 0);
            perror (pager);
            _exit (1);
        } else {
            while (wait (0) != pid)
                ;
        }
    }
    return (1);
}


/*
 *  Format the man page, placing the output into `cat'.
 */

format (man, cat)
char *man, *cat;
{
    int   fd, pid;
    union wait status;

    if ((fd = creat (cat, 0644)) < 0)  /* cannot create output file */
        return (1);
    
    if ((pid = fork()) == 0) {    /* child */
        dup2 (fd, 1);
        execl (NROFF, "nroff", "-man", man, 0);
        perror ("exec");
        _exit (1);
    } else if (pid > 0) {
        while (wait (&status) != pid)
            ;
        if (status.w_coredump) {
            (void) unlink ("core");
            return (1);
        }
        if (status.w_status != 0)
            return (1);
        return (0);
    }
    return (1);
}


/*
 *  Get the MANPATH environment variable and turn it 
 *  into a set of strings in an array so we can use it.
 */

getpath (manpath)
char    *manpath[];
{
    char **ap;
    char *getenv();
    char *env;

    if ((env = getenv ("MANPATH")) == (char *) 0) 
#ifdef LOCAL
        env = "/usr/man";     /* give them the default local path */
#else
        return (0);
#endif

    ap = manpath;

    while (*env) {
        *ap = env;
        while (*env) {
            if (*env == ':') {
                *env++ = '\0';
                break;
            }
            env++;
        }
        if (*ap < env)
            ap++;
    }
    *ap = (char *) 0;
    return (ap - manpath);
}
!Funky!Stuff!
if test 6792 -ne "`wc -c < 'dolocal.c'`"
then
	echo shar: error transmitting "'dolocal.c'" '(should have been 6792 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'response.c'" '(886 characters)'
if test -f 'response.c'
then
	echo shar: will not over-write existing file "'response.c'"
else
cat << \!Funky!Stuff! > 'response.c'
#ifndef lint
static char RCSid[] = "$Header: response.c,v 1.2 85/07/06 16:55:32 broome Exp $";
#endif

/*
 * $Log:    response.c,v $
 * Revision 1.2  85/07/06  16:55:32  broome
 * 
 * 
 */

#include <stdio.h>

response ()
{
    extern FILE *sock_rp;
    char   line[128];

    for ( ;; ) {
        fgets (line, 128, sock_rp);

        if (strncmp (line, "141", 3) == 0)  /* don't want to print the \r\n */
            fprintf (stderr, "Reformatting page. Wait ... ");
        else if (line[0] != '2')            /* not a positive response */
            fprintf (stderr, line+4);

        (void) fflush (stderr);    /* we're line buffered, so have to flush */

        if (line[3] == ' ')        /* end of text */
            if (line[0] == '2')    /* good response */
                return (0);
            else                   /* not so good */
                return (1);
    }
}
!Funky!Stuff!
if test 886 -ne "`wc -c < 'response.c'`"
then
	echo shar: error transmitting "'response.c'" '(should have been 886 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'server.c'" '(3018 characters)'
if test -f 'server.c'
then
	echo shar: will not over-write existing file "'server.c'"
else
cat << \!Funky!Stuff! > 'server.c'
/*
 *  Copyright (c) 1985  Jonathan C. Broome and The Regents of the 
 *  University of California.
 *
 *  This software may be freely redistributed without licensing
 *  provided that this copyright notice remains intact and no profit
 *  is gained through any redistribution.
 *
 *  Please report any bug fixes or modifications to the author at:
 *
 *        broome@ucb-vax.berkeley.edu
 *   or:
 *        ...!ucbvax!broome
 *
 *  The author and the Regents assume no liability for any damages 
 *  or loss of revenue caused directly or indirectly by the use of 
 *  this software.
 */

#ifndef lint
static char *RCSid = "$Header: server.c,v 1.9 85/08/27 15:20:00 broome Exp $";
#endif

/*
 * $Log:    server.c,v $
 * Revision 1.9  85/08/27  15:20:00  broome
 * Added copyright/distribution comment.
 * 
 * Revision 1.8  85/08/27  15:05:04  broome
 * 
 * 
 * Revision 1.7  85/08/09  16:10:37  broome
 * Added #ifdef'ed code to ask for alternate machine type, define TYPE to
 * compile it in, i.e. "-DTYPE=\"sun\"" to cc.
 * 
 * Revision 1.6  85/08/03  02:38:04  broome
 * 
 * Revision 1.5  85/07/31  09:32:43  broome
 * Changed to set errno to EHOSTDOWN when the connection times out, always
 * returns instead of exiting on errors...
 * 
 * Revision 1.4  85/07/16  11:11:29  broome
 * Rewritten to use the routines to ping all possible servers.
 * 
 * Revision 1.3  85/07/04  19:59:09  broome
 * 
 * Revision 1.2  85/07/02  21:05:25  broome
 * 
 * Revision 1.1  85/06/25  11:22:58  broome
 * Initial revision
 */

#include <stdio.h>
#include <netdb.h>

#ifndef PORT
#define PORT 9535
#endif

/*
 *  Open a socket to the specified host.
 */

open_server ()
{
    extern FILE *sock_rp, *sock_wp;
    extern char *type;
#ifdef SERVICES
    struct servent *serv;
#endif
    char   buf[132];
    int    sock, port;

#ifdef SERVICES   /* listed in /etc/services */
    if ((serv = getservbyname ("man", "tcp")) == NULL) {
        fprintf (stderr, "Unknown service: man/tcp\n");
        exit (1);
    }
    port = serv->s_port;
#else SERVICES
    port = htons (PORT);
#endif SERVICES

    if ((sock = get_host (port)) == -1)
        return (-1);

    /*
    **  Create a pair of buffered descriptors to the socket
    **  so that we can use stdio ``fprintf'' and the like.
    */
    sock_wp = fdopen (sock, "w");
    sock_rp = fdopen (sock, "r"); 

    fgets (buf, 128, sock_rp);       /* get the banner line */
    if (strncmp (buf, "210", 3)) {   /* bad response code */
        close (sock);
        fprintf (stderr, "%s", buf+4);
        return (-1);
    }

#ifdef TYPE
    fprintf (sock_wp, "type %s\r\n", TYPE);   /* ask for alternate cpu type */
    fgets (buf, 128, sock_rp);                /* get (and trash) response */
#endif TYPE

    if (type) {   /* they specified a machine type */
        fprintf (sock_wp, "type %s\r\n", type);
        (void) fflush (sock_wp);
        fgets (buf, 128, sock_rp);
        if (strncmp (buf, "223", 3))
            fprintf (stderr, "%s", buf+4);
    }

    return (sock);
}
!Funky!Stuff!
if test 3018 -ne "`wc -c < 'server.c'`"
then
	echo shar: error transmitting "'server.c'" '(should have been 3018 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'man.1'" '(6856 characters)'
if test -f 'man.1'
then
	echo shar: will not over-write existing file "'man.1'"
else
cat << \!Funky!Stuff! > 'man.1'
.TH MAN 1 "3 August 1985"
.UC 4
.SH NAME
man \- find manual information by keywords; print out the manual
.SH SYNOPSIS
.br
\fBman\fP [ \- ] [ \-r ] [ \-t type ] [ \fBsection\fP ] \fBtitle\fP ...
.br
\fBman\fP \-a | \-f  [ \-m ] \fBfile\fP
.br
\fBman\fP \-k | \-w  [ \-m ] \fBkeyword\fP
.SH DESCRIPTION
\fIMan\fP is a program which uses the local area network and
a remote server process to retrieve information from the 
online programmer's manual.  It can be asked for one line descriptions 
of commands specified by name, or for all commands whose description
contains any of a set of keywords.  It can also provide on-line access 
to the sections of the printed manual.
.SH OPTIONS
When given one of the \fI\-k\fP or \fI\-w\fP options and a set of keywords,
\fIman\fP prints out a one line synopsis of each manual sections whose
listing in the table of contents contains one of those keywords.  This
is identical in operation to the \fIwhatis\fP command.
.PP
When given one of the options \fI\-a\fP or \fI\-f\fP
and a list of file names, \fIman\fR will attempt to locate manual
sections appropriate to those files, printing out the table of contents
lines for those sections. This is similar to the \fIapropos\fP command.
.PP
When none of \fI\-a\fP, \fI\-f\fP, \fI\-k\fP, or \fI\-w\fP
is specified,
\fIman\fP will search for and print the specified set of manual pages,
reformatting pages if they are out of date.
If a section specifier is given then \fIman\fP
will look in the that section of the manual for the named \fItitles\fP.
\fISection\fP may be either an Arabic section number (3 for instance), 
or a name, typically one of the words ``new'', ``local'', ``old'', or
``public''.  The first letter, i.e.  \fIn\fP, \fIl\fP, \fIo\fP, or \fIp\fP, 
respectively, can also be used.
A section \fInumber\fP may followed by
a single letter classifier to restrict the search to a single category
within the section (for instance, 1g, indicating a graphics program 
in section 1).
If \fIsection\fP is omitted, \fIman\fP
searches all sections of the manual, giving preference to commands
over subroutines in system libraries, and printing the first section
it finds, if any.
.PP
The \fI\-t\fP option can be used to specify the machine \fItype\fP 
that should be used when searching for any machine-specific pages,
overriding the actual type of the current host.
.PP
When using \fIman\fP to view the manual pages (the default mode)
with standard output to a terminal, \fIman\fP will use \fImore\fP 
as an output pagination filter, with the \fI\-s\fP option to crush 
out multiple blank lines.  The \fI\-m\fP flag can be used with 
the \fI\-a\fP, \fI\-f\fP, \fI\-k\fP, \fI\-w\fP, and \fI\-r\fP 
options to force the use of \fImore\fP when in one of these modes.
Likewise, the \fI\-\fP option tells \fIman\fP to \fBnot\fP use \fImore\fP.
The environment variables `MANPAGER' and `PAGER' can be used to name the
paginator to use (instead of \fImore\fP).  \fIMan\fP will duplicate the
shell's method of searching for the command, so a full pathname need not
be specified.  Note that the specified paginator should understand
(or at least ignore) the \fI\-s\fP option that is normally passed to
\fImore\fP.
.PP
The \fI\-r\fP flag causes \fIman\fP
to produce the raw (unformatted) set of pages to standard output,
suitable for input to \fItroff\fP with the \fI\-man\fP macros; see
\fItroff\fP (1).
.SH SEARCH STRATEGY
\fIMan\fP first searches the local man directory (typically /usr/man/manl)
for a local version of the requested \fItitle\fP, then 
if the desired page has not been located, \fIman\fP will ask the
remote server for the \fItitle\fP, initiating a network
connection if one has not already been made.
.br
If the shell environment variable \fIMANPATH\fP is set, \fIman\fP
will search each directory listed there (instead of the default) for the 
named \fItitle\fP, reformatting pages if needed. \fIMANPATH\fP 
should be a set of 
colon-separated directory names, like ``/usr/cad/man:~/man'',
each of which is the root of a subtree of ``man?'' and ``cat?'' directories.
Note that this variable completely overrides searching of the 
standard \fI/usr/man\fP directory, so you if you still want /usr/man to be
searched, you must include it in your \fIMANPATH\fP. Remote searching
will still occur if the local search is unsuccessful.

.SH REMOTE OPERATION
\fIMan\fP uses a remote manual page daemon (\fImand\fP) running 
on a strategically-placed server host, allowing an entire local 
network to share one copy of the manual pages.  This is beneficial 
in several areas, primarily in the savings in disk space (up to 20
megabytes per host!), and the ease of updating pages without needing 
to distribute to numerous hosts.
.PP
The decision as to which server to connect to (assuming that several 
are available) is made by first `pinging' each known server host on
a relatively inexpensive datagram socket, then waiting
for responses indicating a host's load average and willingness 
to be a server.  A stream socket connection is then made to 
the one with the lowest load.  This simple protocol may need 
to be augmented in the future as the number of clients increases 
with the profusion of workstations, due to the possibility of one
host being bombarded with many requests at the same time. Currently,
the only protection that a host has against this is a load cutoff that
may be set. Another possible addition is to send the name
of the page desired when `pinging', so that a server may indicate whether
it has the page in formatted form when responding. Unfortunately, no
suitable method for doing this has been established without entailing
considerable overhead.
.PP
The protocol used by the \fImand\fP is similar to that used by the smtp
server (\fIsendmail\fP), using a set of requests and three-digit response
codes.  For further information, consult the manual entry for \fImand\fP(8).
.SH FILES
.nf
.ta \w'/usr/man/man?/*   'u
/usr/man	standard manual area  (on remote host)
/usr/man/man?/*	directories containing source for manuals
/usr/man/cat?/*	directories containing preformatted pages
/usr/man/whatis	keyword database
/tmp/man.$$	temporary man file
.fi
.SH DIAGNOSTICS
"cannot connect to server" - the network is down, the selected host went down,
or the host is not running a server process.
.br
"lost connection to remote host" - the server died, or the host went down.
.SH BUGS
The manual is supposed to be reproducible either on the phototypesetter
or on a typewriter.
However, on a typewriter some information is necessarily lost.
.br
When using \fImore\fP, the percentage values at the bottom of the screen 
are usually off due to \fImore\fP being invoked while the file is still 
being transferred.
.SH AUTHOR
Jonathan C. Broome (broome@ucb-vax.berkeley.edu)
.SH SEE\ ALSO
apropos(1), more(1), whereis(1), catman(8), mand(8)
!Funky!Stuff!
if test 6856 -ne "`wc -c < 'man.1'`"
then
	echo shar: error transmitting "'man.1'" '(should have been 6856 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'getmore.c'" '(2628 characters)'
if test -f 'getmore.c'
then
	echo shar: will not over-write existing file "'getmore.c'"
else
cat << \!Funky!Stuff! > 'getmore.c'
#ifndef lint
static char RCSid[] = "$Header: getmore.c,v 1.5 85/08/27 15:04:44 broome Exp $";
#endif

/*
 * $Log:    getmore.c,v $
 * Revision 1.5  85/08/27  15:04:44  broome
 * Final cleanup before sending out.
 * 
 * Revision 1.4  85/08/03  02:35:50  broome
 * Changed to use buffered i/o on the temp file - fewer system calls that way.
 * 
 * Revision 1.3  85/07/13  16:07:14  broome
 * Fixed for installations where man is setuid to root.
 * 
 * Revision 1.2  85/07/04  20:18:13  broome
 */

#include <stdio.h>
#define  eq(a,b)   (strcmp (a, b) == 0)

/*
 *  Get the text from the socket into the temp file
 *  and invoke ``more''.
 */

getmore ()
{
    extern char fname[];             /* name of temp file        */
    extern FILE *tfp;                /* temp file pointer        */
    extern FILE *sock_rp;            /* socket read pointer      */
    extern char *pager;              /* name of output paginator */
    char   line[BUFSIZ];             /* input buffer             */
    int    pid;                      /* pid of `more' subprocess */
    int    lines;                    /* number of lines fetched  */
    int    more = 1;                 /* more lines left to fetch */

    fseek (tfp, 0L, 0);              /* rewind the temp file */
    ftruncate (fileno (tfp), 0L);    /* and zap the contents */

    /*
     *  We get the first 66 lines (one page) into the temp 
     *  file before forking and invoking more on the temp file.
     */

    for (lines = 0; lines < 66; lines++) {  /* get the first page or so */
        fgets (line, BUFSIZ, sock_rp);
        if (eq (line, ".\r\n")) {           /* end of the file */
            more = 0;
            break;
        }
        (void) fputs (line, tfp);
    }

    (void) fflush (tfp);

    /*
     *  We now have the first screenful, so start up more..
     */

    switch (pid = fork ()) {
        case -1: perror ("cannot fork"); return;

        case 0:  
#ifdef SETUID
                 setuid (getuid ());    /* running as root? */
#endif
                 execlp (pager, pager, "-s", fname, 0);
                 perror (pager);
                 return;
        
        default: if (more)      /* still have more lines to fetch */
                    while (fgets (line, BUFSIZ, sock_rp)) {
                        if (eq (line, ".\r\n"))
                            break;
                        (void) fputs (line, tfp);
                        if (++lines % 5 == 0)   /* flush every 5 lines */
                            (void) fflush (tfp);
                    }
                 while (wait (0) != pid)
                        ;
    }
}
!Funky!Stuff!
if test 2628 -ne "`wc -c < 'getmore.c'`"
then
	echo shar: error transmitting "'getmore.c'" '(should have been 2628 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'rman.1'" '(6880 characters)'
if test -f 'rman.1'
then
	echo shar: will not over-write existing file "'rman.1'"
else
cat << \!Funky!Stuff! > 'rman.1'
.TH RMAN 1 "3 August 1985"
.UC 4
.SH NAME
rman \- find manual information by keywords; print out the manual
.SH SYNOPSIS
.br
\fBrman\fP [ \- ] [ \-r ] [ \-t type ] [ \fBsection\fP ] \fBtitle\fP ...
.br
\fBrman\fP \-a | \-f  [ \-m ] \fBfile\fP
.br
\fBrman\fP \-k | \-w  [ \-m ] \fBkeyword\fP
.SH DESCRIPTION
\fIRman\fP is a program which uses the local area network and
a remote server process to retrieve information from the 
online programmer's manual.  It can be asked for one line descriptions 
of commands specified by name, or for all commands whose description
contains any of a set of keywords.  It can also provide on-line access 
to the sections of the printed manual.
.SH OPTIONS
When given one of the \fI\-k\fP or \fI\-w\fP options and a set of keywords,
\fIrman\fP prints out a one line synopsis of each manual sections whose
listing in the table of contents contains one of those keywords.  This
is identical in operation to the \fIwhatis\fP command.
.PP
When given one of the options \fI\-a\fP or \fI\-f\fP
and a list of file names, \fIrman\fR will attempt to locate manual
sections appropriate to those files, printing out the table of contents
lines for those sections. This is similar to the \fIapropos\fP command.
.PP
When none of \fI\-a\fP, \fI\-f\fP, \fI\-k\fP, or \fI\-w\fP
is specified,
\fIrman\fP will search for and print the specified set of manual pages,
reformatting pages if they are out of date.
If a section specifier is given then \fIrman\fP
will look in the that section of the manual for the named \fItitles\fP.
\fISection\fP may be either an Arabic section number (3 for instance), 
or a name, typically one of the words ``new'', ``local'', ``old'', or
``public''.  The first letter, i.e.  \fIn\fP, \fIl\fP, \fIo\fP, or \fIp\fP, 
respectively, can also be used.
A section \fInumber\fP may be followed by
a single letter classifier to restrict the search to a single category
within the section (for instance, 1g, indicating a graphics program 
in section 1).
If \fIsection\fP is omitted, \fIrman\fP
searches all sections of the manual, giving preference to commands
over subroutines in system libraries, and printing the first section
it finds, if any.
.PP
The \fI\-t\fP option can be used to specify the machine \fItype\fP 
that should be used when searching for any machine-specific pages,
overriding the actual type of the current host.
.PP
When using \fIrman\fP to view the manual pages (the default mode)
with standard output to a terminal, \fIrman\fP will use \fImore\fP 
as an output pagination filter, with the \fI\-s\fP option to crush 
out multiple blank lines.  The \fI\-m\fP flag can be used with 
the \fI\-a\fP, \fI\-f\fP, \fI\-k\fP, \fI\-w\fP, and \fI\-r\fP 
options to force the use of \fImore\fP when in one of these modes.
Likewise, the \fI\-\fP option tells \fIrman\fP to \fBnot\fP use \fImore\fP.
The environment variables `MANPAGER' and `PAGER' can be used to name the
paginator to use (instead of \fImore\fP).  \fIRman\fP will duplicate the
shell's method of searching for the command, so a full pathname need not
be specified.  Note that the specified paginator should understand
(or at least ignore) the \fI\-s\fP option that is normally passed to
\fImore\fP.
.PP
The \fI\-r\fP flag causes \fIrman\fP
to produce the raw (unformatted) set of pages to standard output,
suitable for input to \fItroff\fP with the \fI\-man\fP macros; see
\fItroff\fP (1).
.SH SEARCH STRATEGY
\fIRman\fP first searches the local man directory (typically /usr/man/manl)
for a local version of the requested \fItitle\fP, then 
if the desired page has not been located, \fIrman\fP will ask the
remote server for the \fItitle\fP, initiating a network
connection if one has not already been made.
.br
If the shell environment variable \fIMANPATH\fP is set, \fIrman\fP
will search each directory listed there (instead of the default) for the 
named \fItitle\fP, reformatting pages if needed. \fIMANPATH\fP 
should be a set of 
colon-separated directory names, like ``/usr/cad/man:~/man'',
each of which is the root of a subtree of ``man?'' and ``cat?'' directories.
Note that this variable completely overrides searching of the 
standard \fI/usr/man\fP directory, so you if you still want /usr/man to be
searched, you must include it in your \fIMANPATH\fP. Remote searching
will still occur if the local search is unsuccessful.

.SH REMOTE OPERATION
\fIRman\fP uses a remote manual page daemon (\fImand\fP) running 
on a strategically-placed server host, allowing an entire local 
network to share one copy of the manual pages.  This is beneficial 
in several areas, primarily in the savings in disk space (up to 20
megabytes per host!), and the ease of updating pages without needing 
to distribute to numerous hosts.
.PP
The decision as to which server to connect to (assuming that several 
are available) is made by first `pinging' each known server host on
a relatively inexpensive datagram socket, then waiting
for responses indicating a host's load average and willingness 
to be a server.  A stream socket connection is then made to 
the one with the lowest load.  This simple protocol may need 
to be augmented in the future as the number of clients increases 
with the profusion of workstations, due to the possibility of one
host being bombarded with many requests at the same time. Currently,
the only protection that a host has against this is a load cutoff that
may be set. Another possible addition is to send the name
of the page desired when `pinging', so that a server may indicate whether
it has the page in formatted form when responding. Unfortunately, no
suitable method for doing this has been established without entailing
considerable overhead.
.PP
The protocol used by the \fImand\fP is similar to that used by the smtp
server (\fIsendmail\fP), using a set of requests and three-digit response
codes.  For further information, consult the manual entry for \fImand\fP(8).
.SH FILES
.nf
.ta \w'/usr/man/man?/*   'u
/usr/man	standard manual area  (on remote host)
/usr/man/man?/*	directories containing source for manuals
/usr/man/cat?/*	directories containing preformatted pages
/usr/man/whatis	keyword database
/tmp/rman.$$	temporary man file
.fi
.SH DIAGNOSTICS
"cannot connect to server" - the network is down, the selected host went down,
or the host is not running a server process.
.br
"lost connection to remote host" - the server died, or the host went down.
.SH BUGS
The manual is supposed to be reproducible either on the phototypesetter
or on a typewriter.
However, on a typewriter some information is necessarily lost.
.br
When using \fImore\fP, the percentage values at the bottom of the screen 
are usually off due to \fImore\fP being invoked while the file is still 
being transferred.
.SH AUTHOR
Jonathan C. Broome (broome@ucb-vax.berkeley.edu)
.SH SEE\ ALSO
apropos(1), more(1), whereis(1), catman(8), mand(8)
!Funky!Stuff!
if test 6880 -ne "`wc -c < 'rman.1'`"
then
	echo shar: error transmitting "'rman.1'" '(should have been 6880 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'man.hosts'" '(500 characters)'
if test -f 'man.hosts'
then
	echo shar: will not over-write existing file "'man.hosts'"
else
cat << \!Funky!Stuff! > 'man.hosts'
#  Hosts that should be running servers.
#  Group them in the order to call,
#  we always grab the first one with 
#  the lowest load average anyway.
#  Groups are separated by a blank line.

# The primary servers
128.32.149.3	ucbseymour seymour
128.32.149.5	ucbbuddy buddy

# Secondary servers
128.32.149.2	ucbzooey zooey
128.32.149.6	ucbfranny franny

# And so on ....
128.32.5	ucbcad cad
128.32.132.1	ucbic ic
128.32.132.4	ucbsim sim

128.32.137.1	ucbcory cory
128.32.137.2	ucbholden-il holden-il
!Funky!Stuff!
if test 500 -ne "`wc -c < 'man.hosts'`"
then
	echo shar: error transmitting "'man.hosts'" '(should have been 500 characters)'
fi
fi # end of overwriting check
echo shar: done with directory "'client'"
cd ..
if test ! -d 'daemon'
then
	echo shar: creating directory "'daemon'"
	mkdir 'daemon'
fi
echo shar: entering directory "'daemon'"
cd 'daemon'
echo shar: extracting "'Makefile'" '(3821 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'
#
#  Makefile for manual server daemon  21 August 1985
#

# Server (daemon) sources.

HDRS   = cmd.h defs.h response.h 

SRCS   = apropos.c cat.c cmd.c config.c find.c format.c getline.c help.c \
	        identify.c main.c misc.c parse.c ping.c raw.c sections.c \
	        show.c showpath.c so.c stat.c type.c ver.c whatis.c 

OBJS   = apropos.o cat.o cmd.o config.c find.o format.o getline.o help.o \
	        identify.o main.o misc.o parse.o ping.o raw.o sections.o \
	        show.o showpath.o so.o stat.o type.o version.o whatis.o 

DEST   = mand
MAN    = mand.8
LPR    = lpr

# a few notes:
# define SERVICES if you have "man" in /etc/services
# use MODE = 2711 if the man directories are unwritable, else use MODE = 755
# set OWNER to the user who owns the man pages, usually root, sometimes "man"
# KMEM needs to be the name of the group which can read /dev/kmem (for load avg)

CFLAGS = -DSERVICES -O
LFLAGS = -hbxa
MODE   = 711
OWNER  = root
KMEM   = kmem

# The help files should be in this directory.

LIB      = /usr/lib
HELPFILE = ${LIB}/${DEST}.hf
HOSTFILE = ${LIB}/${DEST}.hosts
CONFIG   = ${LIB}/${DEST}.cf


.DEFAULT:
	co $<

${DEST}: ${OBJS}
	/bin/rm -f ${DEST}
	cc ${CFLAGS} -o ${DEST} ${OBJS}

install: ${DEST} man
	install -c -m ${MODE} -o ${OWNER} -g ${KMEM} mand /etc/mand
	install -c -m 644  -o ${OWNER} mand.cf ${CONFIG}
	install -c -m 644  -o ${OWNER} mand.hf ${HELPFILE}
	install -c -m 644  mand.8 /usr/man/man8
	@echo Don't forget to put "man" in /etc/services

new: paths ${DEST}      # need to recompile the ones with paths in them ...

paths:
	-rm -f main.o help.o identify.o

main.o: main.c
	cc ${CFLAGS} -c -DCONFIG=\"${CONFIG}\" main.c

help.o: help.c
	cc ${CFLAGS} -c -DHELPFILE=\"${HELPFILE}\" help.c

identify.o: identify.c
	cc ${CFLAGS} -c -DHOSTFILE=\"${HOSTFILE}\" identify.c

# Updates whenever any sources change
version.o: $(SRCS)
	@csh -f newver.csh
	cc ${CFLAGS} -c version.c

lint: ${DSRCS}
	lint ${LFLAGS} -DCONFIG=\"${CONFIG}\" -DHELPFILE=\"${HELPFILE}\"  \
	    -DHOSTFILE=\"${HOSTFILE}\" ${SRCS}  | egrep -v "pointer alignment" \
	    > lint.out
	
shar: ${HDRS} ${SRCS}
	shar -v Makefile ${HDRS} ${SRCS} mand.cf mand.hf ${MAN} > mand.shar

print:
	pr -f ${HDRS} ${SRCS} ${CONFIG} ${HELPFILE} | ${LPR}

tags: ${SRCS} ${DSRCS}
	ctags -w ${SRCS} ${DSRCS}

clean:
	rm -f *.o core

depend: ${SRCS} 
	mv Makefile makefile.old
	sed '/^# Dependencies follow/,$$d' makefile.old > Makefile
	@echo '# Dependencies follow' >> Makefile
	includes -so ${SRCS} >> Makefile
	@echo ' ' >> Makefile
	@echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
	@echo '# see depend: above' >> Makefile

# DO NOT DELETE THE FOLLOWING LINE
# Dependencies follow

ping.o: /usr/include/nlist.h

ping.o: /usr/include/syslog.h

main.o: /usr/include/signal.h

main.o: /usr/include/sys/ttydev.h

main.o: /usr/include/sys/ttychars.h

main.o: /usr/include/sys/ioctl.h

main.o: /usr/include/time.h

main.o: /usr/include/sys/time.h

identify.o: /usr/include/netdb.h

ping.o main.o identify.o: /usr/include/netinet/in.h

ping.o main.o identify.o: /usr/include/sys/socket.h

main.o format.o: /usr/include/sys/wait.h

show.o format.o find.o: /usr/include/sys/file.h

cmd.o: ./cmd.h

main.o cat.o: /usr/include/errno.h

stat.o cat.o: /usr/include/sys/stat.h

stat.o ping.o main.o identify.o cat.o: /usr/include/sys/types.h

type.o stat.o showpath.o show.o sections.o raw.o misc.o identify.o find.o \
config.o cat.o: ./defs.h

whatis.o ver.o type.o stat.o stat.o so.o showpath.o show.o sections.o raw.o \
raw.o misc.o misc.o main.o identify.o identify.o help.o getline.o format.o \
find.o config.o cmd.o cat.o cat.o apropos.o: /usr/include/stdio.h

whatis.o type.o stat.o raw.o misc.o main.o help.o format.o cmd.o cat.o \
apropos.o: ./response.h
 
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see depend: above
!Funky!Stuff!
if test 3821 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 3821 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'config.c'" '(3908 characters)'
if test -f 'config.c'
then
	echo shar: will not over-write existing file "'config.c'"
else
cat << \!Funky!Stuff! > 'config.c'
/*
 *  Copyright (c) 1985  Jonathan C. Broome and The Regents of the 
 *  University of California.
 *
 *  This software may be freely redistributed without licensing
 *  provided that this copyright notice remains intact and no profit
 *  is gained through any redistribution.
 *
 *  Please report any bug fixes or modifications to the author at:
 *
 *        broome@ucb-vax.berkeley.edu
 *   or:
 *        ...!ucbvax!broome
 *
 *  The author and the Regents assume no liability for any damages 
 *  or loss of revenue caused directly or indirectly by the use of 
 *  this software.
 */

#ifndef lint
static char RCSid[] = "$Header: config.c,v 1.4 85/08/27 18:46:06 broome Exp $";
#endif

/*
 * $Log:    config.c,v $
 * Revision 1.4  85/08/27  15:16:26  broome
 * Last cleanup before release.
 * 
 * Revision 1.3  85/08/04  16:31:12  broome
 * Rewrote most of the code to make it much less obscure, also faster.
 * 
 * Revision 1.2  85/07/06  16:56:24  broome
 * 
 * Revision 1.1  85/07/05  18:19:16  broome
 * Initial revision
 */

#include "defs.h"

/*
 *  Read in the configuration file, parse into sections and suffixes.
 */

config (file)
char   *file;
{
    FILE *fp;
    char line[512];
    char **argv = (char **) 0;
    int  d = 0;
    int  s;
    int  iscont;
    int  suffs;                      /* number of suffixes given */
    SEC  *sec = (SEC *) 0;
    SEC  *seclast = (SEC *) 0;
    DIR  *dir, *dirlast = (DIR *) 0;
    DIR  *dup, *isdup();

    if ((fp = fopen (file, "r")) == (FILE *) 0) {
        fprintf (stderr, "cannot open config file ");
        perror (file);
        exit (1);
    }

    while (getline (line, 512, fp)) {
        iscont = (*line == ' ');    /* continuation line begins with a space */
        if ((suffs = parse (line, &argv)) == 0)
            continue;
        
        if (streql (argv[0], "type") == 0) {   /* beginning of new cpu type */
            addtype (argv[1]);                 /* save the pointers         */
            continue;
        }

        if (!iscont) {     /* not a continuation line - need new section */ 
            if (sec)
                sec->dirs[d] = (DIR *) 0;  /* null-term last list of dirs */
            d = 0;
            sec = (SEC *) malloc (sizeof (SEC));   /* malloc section */
            if (sections == (SEC *) 0)             /* and add to list */
                sections = sec;                    /* first one? */
            else
                seclast->next = sec;
            sec->next = (SEC *) 0;          /* nothing after it */
            seclast = sec;                  /* keep track of last one in list */
            sec->name = strsave (*argv++);  /* save this section name */
            suffs--;
        }

        if (dup = isdup (*argv)) {     /* this element already exists */
            sec->dirs[d++] = dup;      /* point section to existing dir */
            continue;
        }

        dir = (DIR *) malloc (sizeof (DIR));
        dir->man = strsave (*argv++);
        dir->cat = strsave (*argv++);