[net.sources] remote manual server/client source available - here it is!

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

[ how do you spell relief? ]

As you may know, I sent out a message about 2 1/2 weeks ago to
see if anyone was interested in my remote manual code.  Well, the 
response was rather enthusiastic - about 75 replies! - many with
strange return paths, so I'm posting it now.  It comes in four 
pieces, totalling roughly 4600 lines.  Cat the pieces together 
and unshar it; it will create two directories - "client" and "server"
- put them on the right machines and type "make install".

If you install it, I'd like for you send me a note about it so
I know who's got it and is interested in any bug fixes or upgrades.

(And for those of you with ARPA access, the source is also available
in one piece on ucbvax in ~ftp/pub/rman.shar)

===========================================================
Jonathan C. Broome       University of California, Berkeley

          UUCP    ...!ucbvax!broome
          ARPA    broome@ucb-vax.berkeley.edu 
===========================================================

#-----cut here-----cut here-----cut here-----cut here-----
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	READ_ME
#	client (directory)
#	daemon (directory)
# This archive created: Tue Aug 27 19:34:13 1985
export PATH; PATH=/bin:$PATH
echo shar: extracting "'READ_ME'" '(2782 characters)'
if test -f 'READ_ME'
then
	echo shar: will not over-write existing file "'READ_ME'"
else
cat << \!Funky!Stuff! > 'READ_ME'
Notes on installing the remote man system                        21 August 1985
=========================================                        ==============

Compile-time flags
------------------

"mand":
    STRICT         - default whether or not to allow unknown hosts.
    TIMEOUT        - close connection after this many minutes
    SERVICES       - use /etc/services?

"rman":
    LOCAL          - default path to /usr/man for local check if no MANPATH set
    SERVICES       - use /etc/services?
    EXEC_ON_ERROR  - try to exec /usr/ucb/man if remote connection fails


Notes
-----

Client:

  o Edit client/man.hosts to reflect the addresses and names of the hosts
    that each client should try to connect to, then install in 
    LIB/man.hosts on each host.

  o If you want to have rman as a _replacement_ for /usr/ucb/man, make sure
    that you REMOVE the "-DEXEC_ON_ERROR" part from the CFLAGS macro in the
    makefile, as it will just keep invoking ucb/man (itself) on errors!!!!

  o If you want, remove all man pages from your machine (you may want to
    install the local pages on a server), and do a "df" and enjoy ...

  o Install in a suitable location - /usr/ucb/[r]man or /usr/local/[r]man

  o You will probably also want to remember to set up apropos and whatis
    as links to [r]man - it will do the right thing ...

Server:

  o Edit the file "mand.cf" to properly reflect the organization of your
    machine's man pages, adding any extra sections desired, etc, and 
    install in the directory LIB as defined in Makefile (usually /usr/lib)

  o Copy the "mand.hf" help file to the LIB directory

  o Edit the file "mand.hosts" to include the addresses and types of
    any local machines that need special sections (or ALL machines if
    you use the "secure" option.)

  o Copy the binary to somewhere useful, ie. /etc or /usr/lib

  o Edit /etc/rc.local to start up the daemon when the machine reboots.
    (You may want to use some of the flags --- read the man page...:-)

  o Start it initially by hand by typing "mand".


BOTH:

  o Either put an entry for "man" in /etc/services - at Berkeley we use 9535
    because there is no need to use a reserved port. Entry is like this:
        
        man     9535/tcp        # remote manual server
        man     9535/udp        # more of same
    
    (ports MUST be the same for both), or remove the "-DSERVICES" from
    the Makefile.

  o Do a "make -n install" to be sure it wants to put the stuff where
    you want it, then "make install", start the daemon, and you should be set.

  o Install the man pages on a suitable server.

  o Please report any bugs, fixes, or modifications to me at this address:
    
        broome@ucb-vax.berkeley.edu
     or:
        ...!ucbvax!broome


!Funky!Stuff!
if test 2782 -ne "`wc -c < 'READ_ME'`"
then
	echo shar: error transmitting "'READ_ME'" '(should have been 2782 characters)'
fi
fi # end of overwriting check
if test ! -d 'client'
then
	echo shar: creating directory "'client'"
	mkdir 'client'
fi
echo shar: entering directory "'client'"
cd 'client'
echo shar: extracting "'Makefile'" '(2126 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'
#
#  Makefile for remote man client
#
#  21 August 1985


# define LOCAL if you still have local man pages in /usr/man
# define SERVICES if you have "man" in /etc/services
# define SETUID if the local man directory is not writable by users,
# and set mode and owner to whoever owns the dirs...
# define EXEC_ON_ERROR if this is _not_ /usr/ucb/man and you want it to
# use ucb/man whenever it can't get a server.
# define PORT={service port}  if you do not have have an /etc/services entry 

CFLAGS = -O -DSERVICES
LFLAGS = -hbxa  
MODE   = 755
OWNER  = root
LIB    = /usr/lib
BIN    = /usr/ucb

SRCS   = dolocal.c getcat.c gethost.c getmore.c response.c rman.c server.c
OBJS   = dolocal.o getcat.o gethost.o getmore.o response.o rman.o server.o
DEST   = rman


.DEFAULT:
	co $<

${DEST}:  ${OBJS}
	cc ${CFLAGS} -o ${DEST} ${OBJS}

gethost.o: gethost.c
	cc ${CFLAGS} -c -DHOSTS=\"${LIB}/man.hosts\" gethost.c

install: ${DEST} man
	install -c -m ${MODE} -o ${OWNER} ${DEST} ${BIN}/${DEST}
	install -c man.hosts ${LIB}/man.hosts

lint: ${SRCS}
	lint ${LFLAGS} ${SRCS} > lint.out

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

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

clean:
	rm -f ${OBJS} 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

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

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

rman.o: /usr/include/sys/file.h

gethost.o: /usr/include/errno.h

gethost.o: /usr/include/netinet/in.h

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

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

gethost.o: /usr/include/sys/socket.h

server.o rman.o response.o getmore.o gethost.o getcat.o dolocal.o: \
/usr/include/stdio.h

dolocal.o: /usr/include/sys/dir.h

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

gethost.o dolocal.o: /usr/include/sys/types.h

dolocal.o: /usr/include/sys/wait.h
 
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see depend: above
!Funky!Stuff!
if test 2126 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 2126 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'rman.c'" '(9533 characters)'
if test -f 'rman.c'
then
	echo shar: will not over-write existing file "'rman.c'"
else
cat << \!Funky!Stuff! > 'rman.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: rman.c,v 1.18 85/08/27 15:19:13 broome Exp $";
#endif

/*
 * $Log:    rman.c,v $
 * Revision 1.18  85/08/27  15:19:13  broome
 * Added copyright/distribution comment.
 * 
 * Revision 1.17  85/08/27  15:04:52  broome
 * 
 * 
 * Revision 1.16  85/08/05  22:14:53  broome
 * Changed method for checking if an arg is a section name --
 * cleaner and more reliable now ...
 * 
 * Also changed local page lookup routine to check for MANPATH 
 * environment variable - list of dirs to search for pages.
 * 
 * Revision 1.15  85/08/04  18:41:20  broome
 * 
 * Revision 1.14  85/08/03  02:36:22  broome
 * Changed to use buffered i/o on temp file, removed error message on 
 * bad options - acts more like the old "man" this way.
 * 
 * Revision 1.13  85/07/31  09:31:28  broome
 * Added "cantconnect" routine so that when EXEC_ON_ERROR is defined, it
 * will fork and execl /usr/ucb/man for each page it needs.  This is
 * obviously only useful for testing purposes!
 * 
 * Revision 1.12  85/07/30  18:51:59  broome
 * Changed to avoid opening host connection until needed.  This way
 * local man pages can be found without needing a remote host.
 * 
 * Revision 1.11  85/07/16  11:10:45  broome
 * Added "-m" option to force use of more, "-" option now disables more,
 * in keeping with the way the old "man" is set up.
 * 
 * Revision 1.10  85/07/13  16:05:57  broome
 * Added fix for setuid version of man.
 * 
 * Revision 1.9  85/07/13  15:57:33  broome
 * Incorporated "pinging" of remote hosts - great speed improvement!
 * 
 * Revision 1.8  85/07/06  16:55:05  broome
 * Ok, *now* it's ready.. Or is it???
 * 
 * Revision 1.7  85/07/04  19:58:21  broome
 * Separated into more logical routines, more error checking,
 * follows the rfc ideas more closely.
 * 
 * Revision 1.6  85/07/03  18:01:55  broome
 * Fixed the '-' option (to force use of "more"), unfortunately breaks
 * being able to specify multiple options in one arg.
 * 
 * Revision 1.5  85/07/03  17:33:30  broome
 * Trying to keep lint happy...
 * 
 * Revision 1.4  85/07/02  21:03:49  broome
 * Getting ready for beta test distribution (Kurt's machines)...
 * Still needs a lot of cleaning in the server, but it works.
 * 
 * Revision 1.3  85/07/02  13:03:28  broome
 * New version, supports the '-k' and '-f' options.
 * 
 * Revision 1.2  85/06/28  12:34:56  broome
 * Added check for output to a tty, cleaned up w.r.t. lint.
 *
 * Revision 1.1  85/06/25  11:22:09  broome
 * Initial revision
 */

#include <sys/file.h>
#include <stdio.h>
#include <signal.h>

#define  eq(a,b)    (strcmp (a,b) == 0)

/*
 *  Known sections. This method makes it easier to update...
 */
static char *sections[] = {
    "1",        "2",
    "3",        "4",
    "5",        "6",
    "7",        "8",
    "cad",      "c",
    "local",    "l",
    "new",      "n",
    "old",      "o",
    "public",   "p",
};
#define NUMSEC (sizeof (sections) / sizeof (char *))

#define MAN     1
#define APROPOS 2
#define WHATIS  3
#define RAW     4
#define MORE    "more"    /* use execlp to find it ... */

int     mode = MAN;
int     use_more = 0;
int     verbose = 0; 
int     connected = 0;
int     interrupt();
int     sigpipe();
char    *prog;
char    *pager;
char    fname[256];
char    *type = (char *) 0;
FILE    *sock_rp;
FILE    *sock_wp;
FILE    *tfp;

main (argc, argv)
int   argc;
char *argv[];
{
    char  *section;
    char  *rindex();
    char  *getenv();
    char  *r;

    if (r = rindex (*argv, '/'))   /* what were we invoked as?? */
        prog = ++r;
    else
        prog = *argv;

    /*
     *  Process the command line.
     */

    if (eq (prog, "apropos"))
        mode = APROPOS;
    else if (eq (prog, "whatis"))
        mode = WHATIS;

    while (*++argv && **argv == '-') {
        switch ((*argv)[1]) {
            case 'a':
            case 'f': mode = APROPOS; break;

            case 'w':
            case 'k': mode = WHATIS; break;

            case 'r': mode = RAW;  break;

            case 't': if (argv[1]) 
                            type = *++argv, argc--;
                      else
                            usage ();
                      break;

            case 'v': verbose = 1; break;

            case 'm':  use_more = 1; break;    /* force use of more */
            case '\0': use_more = -1; break;   /* force *not* use of more */
        }
        argc--;
    }

    if (argc <= 1)
        usage ();

    setlinebuf (stderr);
    signal (SIGHUP,  interrupt);
    signal (SIGINT,  interrupt);
    signal (SIGQUIT, interrupt);
    signal (SIGTERM, interrupt);
    signal (SIGPIPE, sigpipe);

    if (mode == MAN && !use_more)    /* if not forced more and using `man' */
        use_more = isatty (1);

    if (use_more == 1) {             /* set up temp file */
        umask (0);                   /* should we do this when setuid? */
        sprintf (fname, "/tmp/rman.%05d", getpid ());
        if ((tfp = fopen (fname, "w")) == NULL) {
            fprintf (stderr, "%s: cannot create temp file: ", prog);
            perror (fname);
            exit (1);
        }
#ifdef SETUID
        if (!geteuid ())             /* running as root */
            (void) chown (fname, getuid (), -1);
#endif
        if ((pager = getenv ("MANPAGER")) == (char *) 0)  /* use ucb/more ?? */
            if ((pager = getenv("PAGER")) == (char *) 0)
                pager = MORE;
    }

    while (*argv) {
        if (is_section (*argv))
            section = *argv++;
        else
            section = (char *) 0;

        if (section && !*argv) {
            fprintf (stderr, "But what do you want from section %s?\n", section);
            break;
        }
        doit (*argv++, section);
    }

    if (use_more)
        unlink (fname);
    if (connected)
        fprintf (sock_wp, "quit\r\n");
    exit (0);
}


doit (name, sec)
char *name, *sec;
{
    static char *cmd = (char *) 0;

    if (mode == MAN || mode == RAW)            /* check for local pages first */
        if (dolocal (name, sec, mode == RAW))  /* found it locally */
            return;

    /*
     *  Not connected yet, so try to connect to a server.
     */

    if (!connected) {
        if (open_server () == -1) {
            cantconnect (name, sec);
            return;
        } else
            connected = 1;
    }

    if (cmd == (char *) 0)
        switch (mode) {
            case MAN:     cmd = "cat"; break;
            case APROPOS: cmd = "apropos"; break;
            case WHATIS:  cmd = "whatis"; break;
            case RAW:     cmd = "raw"; break;
        }
    fprintf (sock_wp, "%s %s %s\n", cmd, sec, name);  /* ask for a page */
    (void) fflush (sock_wp);

    if (response ())        /* bad response */
        return;

    if (use_more == 1)
        getmore ();
    else
        getcat ();
}


/*
 *  Check to see if `arg' is a valid section name,
 *  return 1 if true, else 0.
 */

is_section (arg)
char *arg;
{
    char *suffixes = "1234567890lnopc";
    char suff;
    int  i, len, arglen;

    arglen = strlen (arg);
    suff = arg[arglen-1];

    /*
     * valid:
     *    exact match - strncmp (a,b,len) == 0  && len == arglen
     *    match for len of a, arglen == len-1, suff in suffixes.
     */

    for (i = 0; i < NUMSEC; i++) {
        len = strlen (sections[i]);
        if (strncmp (arg, sections[i], len))
            continue;
        if (len == arglen)    /* exact match */
            return (1);
        if ((arglen - 1) == len && index (suffixes, suff))    /* subsec */
            return (1);
    }
    return (0);
}


/*
 *  Print a verbose usage message and exit.
 */

usage ()
{
    if (eq (prog, "man") || eq (prog, "rman")) {
        fprintf (stderr, "Usage: man [-r] [-t type] [-v] [ section ] command ...\n");
        fprintf (stderr, "   or: man -k | -w [-m] keyword\n");
        fprintf (stderr, "   or: man -a | -f [-m] file\n");
    } else
        fprintf (stderr, "%s what?\n", prog);
    exit (1);
}


/*
 *  Come here on keyboard interrupt.
 */

interrupt ()
{
    if (use_more)
        (void) unlink (fname);
    exit (1);
}


/*
 *  And come here on sigpipe.
 */

sigpipe ()
{
    fprintf (stderr, "%s: lost connection to remote host.\n", prog);
    if (use_more)
        (void) unlink (fname);
    exit (1);
}


/* 
 *  Try to act intelligently when we can't connect to a server.
 */

/*ARGSUSED*/
cantconnect (name, sec)
char  *name;
char  *sec;
{
#ifdef EXEC_ON_ERROR
    int  pid;

    if (verbose)
        fprintf (stderr, "%s: processing locally.\n", prog);

    if ((pid = fork ()) == -1) {
        perror ("fork");
        return (1);
    } else if (pid == 0) {
        if (sec)
            execl ("/usr/ucb/man", prog, sec, name);
        else
            execl ("/usr/ucb/man", prog, name);
        perror ("execl");
        _exit (1);
    }
    while (wait (0) != pid)
        ;
#else
    fprintf (stderr, "%s: cannot connect to server.\n", prog);
    exit (1);
#endif
}
!Funky!Stuff!
if test 9533 -ne "`wc -c < 'rman.c'`"
then
	echo shar: error transmitting "'rman.c'" '(should have been 9533 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'getcat.c'" '(632 characters)'
if test -f 'getcat.c'
then
	echo shar: will not over-write existing file "'getcat.c'"
else
cat << \!Funky!Stuff! > 'getcat.c'
#ifndef lint
static char RCSid[] = "$Header: getcat.c,v 1.3 85/07/16 11:08:26 broome Exp $";
#endif

/*
 * $Log:    getcat.c,v $
 * Revision 1.3  85/07/16  11:08:26  broome
 * *** empty log message ***
 * 
 * Revision 1.2  85/07/04  20:17:58  broome
 * Just added the RCS keywords ...
 */

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

/*
 *  Read the text from the socket and print directly to stdout.
 */

getcat ()
{
    extern FILE *sock_rp;
    char   line[BUFSIZ];

    while (fgets (line, BUFSIZ, sock_rp)) {
        if (eq (line, ".\r\n"))
            return;
        fputs (line, stdout);
    }
    return;
}
!Funky!Stuff!
if test 632 -ne "`wc -c < 'getcat.c'`"
then
	echo shar: error transmitting "'getcat.c'" '(should have been 632 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'gethost.c'" '(5092 characters)'
if test -f 'gethost.c'
then
	echo shar: will not over-write existing file "'gethost.c'"
else
cat << \!Funky!Stuff! > 'gethost.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: gethost.c,v 1.7 85/08/27 15:19:41 broome Exp $";
#endif

/*
 * $Log:    gethost.c,v $
 * Revision 1.7  85/08/27  15:19:41  broome
 * Added copyright/distribution comment.
 * 
 * Revision 1.6  85/08/27  15:04:37  broome
 * Final cleanup before sending out.
 * 
 * Revision 1.5  85/08/04  18:41:06  broome
 * 
 * Revision 1.4  85/07/31  22:18:22  broome
 * Changed all tracing routines ("verbose") to print to stderr, not stdout....
 * 
 * Revision 1.3  85/07/24  10:38:49  broome
 * 
 * Revision 1.2  85/07/13  15:29:06  broome
 * Changed to ignore errors on sendto - don't want users to see "sendto: 
 * network is unreachable" all over the place...
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdio.h>

/*  Return the ascii form of this address  */
#define asc(sin)  inet_ntoa(sin.sin_addr.s_addr)
#define vprintf   if (verbose) fprintf

#ifndef HOSTS
#define HOSTS "/c/support/broome/mandy/client/man.hosts"
#endif

/*
 *  Try to find an available server host, 
 *  Returns a stream socket descriptor.
 */

get_host (port)
int port;        /* in network order */
{
    struct sockaddr_in sin, low;
    static struct timeval timeout = { 0, 100 };   /* 1/10th sec timeout */
    float  curr_low = 200.0;           /* higher than your system goes! */
    float  la;
    int    got_one = 0;
    int    sock;
    int    hosts;
    int    eof = 0;
    extern int errno;
    extern int verbose;
    char   buf[20];
    char   line[128];
    char   *inet_ntoa();
    char   *index();
    char   *i;
    FILE   *fp;

    if ((fp = fopen (HOSTS, "r")) == NULL)
        return (-1);

    bzero ((char *)&sin, sizeof (sin));
    sin.sin_family = AF_INET;
    sin.sin_port   = port;
    if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror ("get_host: datagram socket");
        return (1);
    }

    while (!got_one && !eof) {
        /*  Read one set of hosts, ping each one  */
        hosts = 0;
        for ( ;; ) {
            if (!fgets (line, 128, fp)) {   /* end of file - drop out */
                eof = 1;
                break;
            }
            i = line;
            /* blank line - end of host group */
            if (*i == '\n' || *i == ' ' || *i == '\t')   
                break;
            if (*i == '#')  /* comment */
                continue;

            if (i = index (line, ' '))     /* grab the first word */
                *i = '\0';
            if (i = index (line, '\t'))
                *i = '\0';

            /* ping each host */
            sin.sin_addr.s_addr = inet_addr (line);
            vprintf (stderr, "Pinging address %s (%s)\n", asc (sin), i+1);
            (void) sendto (sock, "man", 4, 0, &sin, sizeof (sin));
            hosts++;                      /* increment ping count */
        }

        if (!hosts)    /* didn't ping any hosts */
            continue;

        for ( ; hosts; hosts--) {    /* now listen for responses */
            int x, mask = 1 << sock;
            if ((x = select (20, &mask, 0, 0, &timeout)) <= 0) { /* timed out */
                vprintf (stderr, "Select returns %d.\n", x);
                if (got_one)             /* do we already have a viable host? */
                    break;
                continue;
            }
            if ((x = recvfrom (sock, buf, 20, 0, &sin, sizeof (sin))) <= 0)
                continue;
            buf[x] = '\0';
            (void) sscanf (buf, "%f", &la);
            vprintf (stderr, "Recv: address is %s, la is %.2f\n", asc(sin), la);
            if (la < curr_low) {     /* this load lower than previous */
                curr_low = la;       /* save this load */
                bcopy ((char *)&sin, (char *)&low, sizeof (sin));  /*save addr*/
            }
            got_one++;
        }
    }
    (void) fclose (fp);
    (void) close (sock);     /* shutdown datagram socket */
    if (!got_one)            /* timed out after pinging all hosts */
        return (-1);

    vprintf (stderr, "Selected host: address is %s, load is %.2f\n", 
                asc (low), curr_low);

    /* open a stream socket to the selected host */

    if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) { 
        perror ("get_host: socket");
        return (-1);
    }

    if (connect (sock, &low, sizeof (low)) < 0) {
        if (errno != ECONNREFUSED)
            perror ("get_host: connect");
        return (-1);
    }
    return (sock);
}
!Funky!Stuff!
if test 5092 -ne "`wc -c < 'gethost.c'`"
then
	echo shar: error transmitting "'gethost.c'" '(should have been 5092 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'dolocal.c'" '(6792 characters)'
if test -f 'dolocal.c'
then
	echo shar: will not over-write existing file "'dolocal.c'"
else
cat << \!Funky!Stuff! > 'dolocal.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: dolocal.c,v 1.9 85/08/27 15:20:14 broome Exp $";
#endif

/*
 * $Log:    dolocal.c,v $
 * Revision 1.9  85/08/27  15:20:14  broome
 * Added copyright/distribution comment.
 * 
 * Revision 1.8  85/08/27  15:04:13  broome
 * Final cleanup before sending out.
 * 
 * Revision 1.7  85/08/05  22:14:03  broome
 * All new stuff... Uses $MANPATH for searching on local machine, 
 * allows each user to have his own set of man pages.
 * 
 * Revision 1.6  85/08/04  18:40:45  broome
 * Fixed to do raw mode files properly.
 * 
 * Revision 1.5  85/07/24  10:38:45  broome
 * 
 * Revision 1.4  85/07/16  11:07:52  broome
 * Added new option "-m" to force use of more, "-" option now disables more.
 * 
 * Revision 1.3  85/07/13  16:05:37  broome
 * Added fix for setuid version of man.
 * 
 * Revision 1.2  85/07/13  15:56:45  broome
 * Changed to do local reformatting if needed.
 * (Still need to deal with man running setuid)
 */

#define  NROFF "/usr/bin/nroff"
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <stdio.h>

static char *manpath[30];
static char *sections;
char   *getenv();
char   *sec;
extern char *pager;

/*
 *  Handle lookup of local man pages, dealing with $MANPATH, etc ...
 *  Returns 1 if found page here, else 0.
 */

dolocal (page, sec, israw)
char  *page;
char  *sec;
int   israw;
{
    static int paths = -1;

    if (paths == -1) {
        if ((sections = getenv ("MANSEC")) == (char *) 0)  /* undocumented */
            sections = "1lnpo6823457";     /* allows change of search order */
        paths = getpath (manpath);
    }

    if (paths == 0)      /* no MANPATH set */
        return (0);

    return (find (page, sec, manpath, israw));
}


/*
 *  See if the page we're looking for is somewhere in $MANPATH,
 *  show it if it found.
 */

find (page, section, dirs, mode)
char *page;
char *section;
char *dirs[];
int  mode;
{
    DIR    *dirp;              /* pointer to directory to search */
    struct direct *dp;         /* one directory entry */
    char   cat[512];           /* name of catable page */
    char   man[512];           /* name of source page */
    char   mandir[512];        /* full pathname of this (sub)directory */
    char   base[512];          /* basename of file to find */
    int    len;                /* length of file basename */
    int    s;                  /* index into section list */
    int    suff = section[0];  /* base suffix for this directory */

    for ( ; *dirs; ++dirs) {       /* for each root directory in $MANPATH */
        if (chdir (*dirs))         /* chdir to handle .so directives properly */
            continue;              /* if cd fails, then we can't search dir */
        for (s = 0; sections[s]; s++) {      /* for each subdirectory ... */
            if (section && sections[s] != suff)           /* wrong section */
                continue;
            sprintf (mandir, "%s/man%c", *dirs, sections[s]);
            if ((dirp = opendir (mandir)) == (DIR *) 0)   /* bad directory */
                continue;
            sprintf (base, "%s.%c", page, sections[s]);
            len = strlen (base);
            while (dp = readdir (dirp)) {
                if (strncmp (base, dp->d_name, len) == 0) {
                    sprintf (man, "%s/%s", mandir, dp->d_name);
                    sprintf (cat, "%s/cat%c/%s", *dirs, sections[s],dp->d_name);
                    if (showpage (man, cat, mode))
                        return (1);
                }
            }
            closedir (dirp);
        }
    }
    return (0);
}


/*
 *  Do the right thing to show this page. Returns 1 if successful, 0 on error.
 */

showpage (man, cat, israw)
char *man;
char *cat;
int  israw;