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;