Initial commit at 0.16 of geomyidae. - geomyidae - A small C-based gopherd.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 97230aa165bee0bffae624707ff98d6098da1823
 (HTM) Author: Christoph Lohmann <20h@r-36.net>
       Date:   Fri, 19 Nov 2010 09:20:38 +0100
       
       Initial commit at 0.16 of geomyidae.
       
       Diffstat:
         LICENSE                             |      24 ++++++++++++++++++++++++
         Makefile                            |      56 +++++++++++++++++++++++++++++++
         README                              |      43 ++++++++++++++++++++++++++++++
         arg.h                               |      19 +++++++++++++++++++
         geomyidae.8                         |     407 +++++++++++++++++++++++++++++++
         handlr.c                            |     196 +++++++++++++++++++++++++++++++
         handlr.h                            |      20 ++++++++++++++++++++
         ind.c                               |     287 +++++++++++++++++++++++++++++++
         ind.h                               |      48 +++++++++++++++++++++++++++++++
         index.gph                           |       6 ++++++
         main.c                              |     385 +++++++++++++++++++++++++++++++
         rc.d/Archlinux.conf.d               |       4 ++++
         rc.d/Archlinux.rc.d                 |      38 +++++++++++++++++++++++++++++++
         rc.d/Gentoo.conf.d                  |       5 +++++
         rc.d/Gentoo.init.d                  |      17 +++++++++++++++++
         rc.d/NetBSD.rc.d                    |      55 +++++++++++++++++++++++++++++++
         rc.d/README                         |       5 +++++
       
       17 files changed, 1615 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/LICENSE b/LICENSE
       @@ -0,0 +1,24 @@
       +MIT/X Consortium License
       +
       +© 2006-2010 Christoph Lohmann <20h@r-36.net>
       +© 2007 Jeff Woodall <jgw@freeshell.org> 
       +© 2008 J. A. Neitzel <jan@v6shell.org> 
       +© 2010 James Penketh <tamber@furryhelix.co.uk> 
       +
       +Permission is hereby granted, free of charge, to any person obtaining a
       +copy of this software and associated documentation files (the "Software"),
       +tto deal in the Software without restriction, including without limitation
       +tthe rights to use, copy, modify, merge, publish, distribute, sublicense,
       +and/or sell copies of the Software, and to permit persons to whom the
       +Software is furnished to do so, subject to the following conditions:
       +
       +The above copyright notice and this permission notice shall be included in
       +all copies or substantial portions of the Software.
       +
       +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
       +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
       +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
       +DEALINGS IN THE SOFTWARE.
 (DIR) diff --git a/Makefile b/Makefile
       @@ -0,0 +1,56 @@
       +PROGRAM = geomyidae
       +VERSION = 0.16
       +
       +PREFIX ?= /usr
       +BINDIR ?= $(PREFIX)/bin
       +MANDIR ?= $(PREFIX)/man/man8
       +
       +#CPPFLAGS += -D_BSD_SOURCE
       +CFLAGS += -O2 -Wall -I. -I/usr/include 
       +LDFLAGS += -L/usr/lib -L. -lc
       +
       +CFILES = main.c ind.c handlr.c 
       +
       +OBJECTS = ${CFILES:.c=.o}
       +
       +all: $(PROGRAM)
       +
       +${PROGRAM}: ${OBJECTS}
       +        ${CC} ${LDFLAGS} -o ${PROGRAM} ${OBJECTS}
       +
       +.SUFFIXES : .c .h
       +
       +.c.o :
       +        ${CC} ${CFLAGS} ${CPPFLAGS} -c $<
       +.c :
       +        ${CC} ${CFLAGS} ${CPPFLAGS} -c $<
       +
       +clean :
       +        @rm -f *.o ${PROGRAM} core *~
       +
       +install: $(PROGRAM)
       +        @mkdir -p ${DESTDIR}${BINDIR}
       +        @cp -f ${PROGRAM} ${DESTDIR}${BINDIR}
       +        @strip ${DESTDIR}${BINDIR}/${PROGRAM}
       +        @chmod 755 ${DESTDIR}${BINDIR}/${PROGRAM}
       +        @mkdir -p ${DESTDIR}${MANDIR}
       +        @cp -f geomyidae.8 ${DESTDIR}${MANDIR}
       +        @chmod 644 ${DESTDIR}${MANDIR}/${PROGRAM}.8
       +
       +uninstall:
       +        @rm -f ${DESTDIR}${BINDIR}/${PROGRAM}
       +        @rm -f ${DESTDIR}${MANDIR}/${PROGRAM}.8
       +
       +dist: clean
       +        @mkdir -p "${PROGRAM}-${VERSION}"
       +        @cp -r rc.d README LICENSE index.gph Makefile geomyidae.8 \
       +                       *.c *.h "${PROGRAM}-${VERSION}"
       +        @chmod 755 "${PROGRAM}-${VERSION}"
       +        @chmod 744 "${PROGRAM}-${VERSION}"/*
       +        @tar -cf "${PROGRAM}-${VERSION}.tar" "${PROGRAM}-${VERSION}"
       +        @gzip "${PROGRAM}-${VERSION}.tar"
       +        @mv "${PROGRAM}-${VERSION}.tar.gz" "${PROGRAM}-${VERSION}.tgz"
       +        @rm -rf "${PROGRAM}-${VERSION}"
       +
       +.PHONY: all clean dist install uninstall
       +
 (DIR) diff --git a/README b/README
       @@ -0,0 +1,43 @@
       +A gopherd for Linux/BSD.
       +
       +Features:
       +        * gopher menus (see index.gph for an example)
       +        * dir listings (if no index.gph was found)
       +        * cgi support (.cgi files are executed)
       +        * search support in CGI files
       +        * logging (-l option) and loglevels (-v option)
       +
       +Usage:
       +
       +        geomyidae [-d] [-l logfile] [-v loglvl] [-b htdocs] [-p port] [-o sport]
       +                  [-u user] [-g group] [-h host] [-i IP]
       +                -d                don't fork into background
       +                -l logfile        setting this will turn on logging into logfile
       +                -v loglevel        see below (default 7) 
       +                -b htdocs        the htdocs root for serving files (default
       +                                /var/gopher)
       +                -p port                set the port where geomyidae should listen on
       +                                (default 70)
       +                -o sport        set the port that should be shown in the dir
       +                                listings
       +                -u user                which user rights the serving children should get
       +                -g group        which group rights the serving children should get
       +                -i IP                IP which geomyidae should bind to
       +                -h host                host that should be used in the dir listings
       +
       +Loglevels:
       +
       +        0 - no logging
       +        1 - served plain files
       +        2 - dir listings
       +        4 - HTTP redirects
       +        8 - not found queries
       +
       +        1 + 2 + 4 = 7 (files + dir listings + HTTP)
       +
       +Init scripts:
       +        The rc.d directory includes startup scripts for various distributions.
       +
       +
       +Have fun!
       +
 (DIR) diff --git a/arg.h b/arg.h
       @@ -0,0 +1,19 @@
       +#ifndef ARG_H
       +#define ARG_H
       +
       +#define USED(x) ((void)(x))        
       +
       +extern char *argv0;
       +
       +#define        ARGBEGIN        for(argv0 = *argv, argv++, argc--;\
       +                            argv[0] && argv[0][0]=='-' && argv[0][1];\
       +                            argc--, argv++) {\
       +                                char _argc;\
       +                                _argc = argv[0][1];\
       +                                switch(_argc)
       +#define        ARGEND                USED(_argc);} USED(argv);USED(argc);
       +#define        EARGF(x)        ((argv[1] == nil)? ((x), abort(), (char *)0) :\
       +                        (argc--, argv++, argv[0]))
       +
       +#endif
       +
 (DIR) diff --git a/geomyidae.8 b/geomyidae.8
       @@ -0,0 +1,407 @@
       +.\" geomyidae.8 handcrafted in GNU groff -mdoc using nvi
       +.\"
       +.Dd March 9, 2008
       +.Dt GEOMYIDAE 8
       +.Os
       +.
       +.Sh NAME
       +.Nm geomyidae
       +.Nd a gopher daemon for Linux/BSD
       +.
       +.Sh SYNOPSIS
       +.Nm
       +.Bk -words
       +.Op Fl d
       +.Op Fl l Ar logfile
       +.Op Fl v Ar loglevel
       +.Op Fl b Ar base 
       +.Op Fl p Ar port
       +.Op Fl o Ar sport
       +.Op Fl u Ar user
       +.Op Fl g Ar group
       +.Op Fl h Ar host
       +.Op Fl i Ar IP
       +.Ek
       +.
       +.Sh DESCRIPTION
       +.Nm
       +is a daemon for serving the protocol specified in
       +.Em RFC 1436
       +(Gopher). Under 1000 lines of C by design, it is lightweight yet supports
       +dynamic content, automatic file/directory indexing, logging and privilege
       +separation.
       +. 
       +.Sh IMPLEMENTATION
       +Installation is straightforward: grab the zipped tar file, expand it in
       +an appropriate temp directory, change to the
       +.Qq "../geomyidae-x.xx"
       +directory, tweak the Makefile if desired (installs in
       +.Qq "/usr/bin"
       +by default), then run the 
       +.Sq "make ; make install"
       +commands.  The resulting executable should be run by root.
       +.
       +.Ss Installation example:
       +.Pp
       +.Bd -literal
       +     % wget http://www.r-36.net/src/geomyidae/geomyidae-current.tgz;
       +     % tar -xzvf geomyidae-*.tgz;
       +     % cd geomyidae-*;
       +     % make; sudo make install;
       +     % sudo mkdir -p /var/gopher;
       +     % sudo cp index.gph /var/gopher;
       +     % sudo eomyidae -l /var/log/geomyidae.log -b /var/gopher -p 70;
       +     % tail -f /var/log/geomyidae.log;
       +     #
       +     # Use whatever gopher client you like to gopher to
       +     # gopher://localhost
       +     #
       +     # Have fun!
       +.Ed
       +.
       +.Ss Running
       +Geomyidae should normally be started by root.  Though, it can be started
       +by a regular user provided that the base directory and its contents are owned
       +by the same user.  Geomyidae will only serve content within the base directory
       +ttree and will drop privileges to the
       +.Fl u Ar user
       +and
       +.Fl g Ar group
       +values if set.  See
       +.Ic OPTIONS
       +below for specifics.
       +.
       +.Sh OPTIONS
       +geomyidae options and default settings:
       +.Pp
       +.Bl -tag -width ".Fl test Ao Ar string Ac"
       +.
       +.It Fl d
       +Don't fork into background.
       +.
       +.It Fl l Ar logfile
       +Specify the file where the log output will be written (default: no default).
       +.
       +.It Fl v Ar loglevel
       +Set the logging level (default: 15).
       +.
       +.Bd -literal
       +Loglevels:
       +        0 - no logging
       +        1 - served plain files
       +        2 - directory listings
       +        4 - HTTP redirects
       +        8 - errors (e.g., not found)
       +  e.g.:
       +        1 + 2 + 4 + 8 = 15
       +        (files + directories + HTTP + errors)
       +.Ed
       +.
       +.It Fl b Ar base 
       +Root directory to serve (default: /var/gopher)
       +.
       +.It Fl p Ar port
       +Port geomyidae should listen on (default: 70)
       +.
       +.It Fl o Ar sport
       +Port geomyidae displays within base directory (default: 70).
       +.
       +Use in conjunction with
       +.Ic -p
       +for obfuscating actual port neomyidae is running on.
       +.
       +.It Fl u Ar user
       +Sets the user to which privileges drop when geomyidae is ready
       +tto accept network connections (default: user geomyidae runs as).
       +Helps improve security by reducing privileges during request
       +processing.
       +.
       +.It Fl g Ar group
       +Sets the group to which privileges drop when geomyidae is ready
       +tto accept network connections (default: group geomyidae runs as).
       +Helps improve security by reducing privileges during request
       +processing.
       +.
       +.It Fl h Ar host
       +Host to use in directory listings (default: localhost)
       +.
       +.It Fl i Ar IP
       +IP to which geomyidae binds to (default: 127.0.0.1)
       +.El
       +.
       +.Sh FORMATTING
       +Structured Gopher space(s) can be created with geomyidae through the
       +use of special indexing files of the form
       +.Ic <name>.gph
       +which, if present, geomyidae uses to format and/or filter the contents of
       +tthe base directory (/var/gopher by default) and create gopher menus.
       +However, index files are
       +.Em not
       +required: if no .gph files are found geomyidae simply lists the directory
       +contents in alphanumeric order.  In addition, a directory can utilize
       +multiple index files to create a layered gopher environment without the
       +use of sub-directories: ie. pictures.gph, music.gph, documents.gph could
       +be "directories" within main.gph, yet all reside in /var/gopher along with
       +ttheir respective files (*.jpg, *.mp3, *.pdf for example).
       +.
       +.Ss Anatomy of an index.gph file
       +In general, each line of an index.gph file has the following structure:
       +.Pp
       +.Bl -inset -offset indent
       +.It Ic [<type>|<desc>|<path>|<port>]
       +.El
       +.Pp
       +where,
       +.Bl -inset -offset indent
       +.It Ic <type>
       += A valid gopher Item Type.
       +.Pp
       +Some common Gopher Types as defined in
       +.Em RFC 1436
       +:
       +.
       +.Bd -literal
       + 0   Item is a file
       + 1   Gopher directory
       + 3   Error
       + 7   Item is an Index-Search server.
       + 8   Item points to a text-based telnet session.
       + 9   Binary file. Client reads until TCP connection closes!
       + g   GIF format graphics file.
       + I   Indeterminate image file. Client decides how to display.
       +.Ed
       +.Pp
       +In addition, geomyidae provides these:
       +.Bd -literal
       + h   Item is a hypertext (HTTP) link
       + i   Informational Item (used for descriptive purposes)
       +.Ed
       +.
       +.Pp
       +Note: geomyidae doesn't require "informational" text to be formally
       +Typed as "[i|...]"; any line
       +.Em not
       +beginning with "[" is treated as informational, greatly simplifying the
       +formatting of index.gph files.
       +If a line begins with "t", this "t" is left out. This measurement is
       +tthere to allow lines "informational" text beginning with "[".
       +.
       +.It Ic <desc>
       += description of gopher item. Most printable characters should work.
       +.
       +.It Ic <path>
       += full path to gopher item (base value is / ).  Use the "Err" path for
       +items not intended to be served.
       +.
       +.It Ic <host>
       += hostname or IP hosting the gopher item. Must be resolvable for the
       +intended clients.
       +.
       +.It Ic <port>
       += TCP port number ( usually 70)
       +.
       +May be omitted if defaults are used.
       +.El
       +.
       +.Ss index.gph Example
       +A root.gph file for a server running on host=frog.bog, port=70.  Note use
       +of optional [i]nformational Item (line 2) for vertical space insertion:
       +.Pp
       +.Bd -literal -offset indent
       +Welcome to Frog.bog
       +t[i||||]
       +t[0|About this server|about.txt|frog.bog|70]
       +t[0|Daily Log|/dtail.cgi|frog.bog|70]
       +t[1|Phlog: like a blog, but not|/PHLOG|frog.bog|70]
       +t[9|Some binary file|widget.exe|frog.bog|70]
       +t[I|Snowflake picture|snowflake.jpg|frog.bog|70]
       +
       +Links and Searches
       +t[1|Go to R-36.net|/|gopher.r-36.net|70]
       +t[h|Go to NetBSD.org|URL:http://netbsd.org|frog.bog|70]
       +t[7|Query US Weather by Zipcode|/weather.cgi?|frog.bog|70]
       +t[7|Search Veronica II|/v2/vs|gopher.floodgap.com|70]
       +t[8|Telnet to SDF Public Access Unix System||freeshell.org|23]
       +.Ed
       +.
       +.Pp
       +The above looks something like this in a text-based gopher client:
       +.Pp
       +.Bl -tag -width ".It Ic WIDTHS" -compact -offset indent
       +.D1 Welcome to Frog.bog
       +.Pp
       +.It Ic (FILE)
       +About this server
       +.It Ic (FILE)
       +Daily Log
       +.It Ic (DIR)
       +Phlog: like a blog, but not
       +.It Ic (BIN)
       +Some binary file
       +.It Ic (IMG)
       +Snowflake picture
       +.El
       +.Pp
       +.Bl -tag -width ".It Ic WIDTHS" -compact -offset indent
       +.D1 Links and Searches
       +.It Ic (DIR)
       +Go to R-36.net
       +.It Ic (HTML)
       +Go to NetBSD.org
       +.It Ic (?)
       +Query US Weather by Zipcode
       +.It Ic (?)
       +Search Veronica II
       +.It Ic (TEL)
       +Telnet to SDF Public Access Unix System
       +.El
       +.Pp
       +.Sh USING DYNAMIC CONTENT 
       +Dynamic content can be generated under geomyidae by simply creating a file
       +in for form of
       +.Ic <name>.cgi
       +in a directory that is being served. Such files are run as a shell script.
       +(See below for description.)
       +.Pp
       +ex. dtail.cgi - prints daily log entries
       +.
       +.Bd -literal -offset indent
       +#!/bin/sh -e
       +echo "Logged activity for `date '+%A, %B %d, %Y'` :"
       +echo "==============================================="
       +LOG="/var/log/gopherd.log"
       +DATE=`date "+%a %b %d"`
       +/usr/bin/grep "$DATE" $LOG
       +exit 0
       +.Ed
       +.
       +.Pp
       +Geomyidae supports two variable queries.  The basic form is
       +.Pp
       +.D1 executable.cgi{argv[1]}?{argv[2]}
       +.Pp
       +where
       +.Pp
       +.D1 argv[1] = strings (everything before the '?' in the query)
       +.D1 argv[2] = arguments (everything behind the '?' in the query)
       +.Pp
       +A search query request must have an item Type of "7" to be called
       +from an index.gph file.  It may also need a "?" suffix in the <path>
       +field.
       +.
       +.Pp
       +ex. hello.cgi - say hello to user
       +.
       +.Bd -literal -offset indent
       +#!/bin/sh
       +NAME=$1
       +echo ""
       +echo Hello $NAME - welcome to Frog.bog
       +exit 0
       +.Ed
       +.
       +.Pp
       +Call the above with the following index.gph entry:
       +.Pp
       +.D1 [7|Hello You - Please enter your name|/hello.cgi?|frog.bog|70]
       +.
       +.Pp
       +And do a simple
       +.Xr snarf 1
       +query:
       +.Pp
       +.D1 % snarf Qo gopher://frog.bog/7/hello.cgi?Christoph Qc -
       +.D1 Hello Christoph - welcome to Frog.bog
       +.Dl %
       +.
       +.Sh LOG FILES
       +.Pp
       +The log file (/var/log/gopherd.log is default) has the following structure:
       +.
       +.Pp
       +.Ic [<date>|<IP:port>] <item path> <query> (<status>)
       +.
       +.Pp
       +where,
       +.
       +.Bl -inset
       +.It Ic <date>
       += access date and time (std 'date' format)
       +.Bl -inset -offset indent
       +ex.
       +.Qq "Sun Feb 17 06:11:10 PST 2008"
       +.El
       +.It Ic <IP:port>
       += client IP address and port served
       +.Bl -inset -offset indent
       +ex.
       +.Qq "24.208.18.127:16857"
       +.El
       +.Pp
       +.It Ic <item path>
       += full path to item served
       +.Bl -inset -offset indent
       +ex.
       +.D1 Qo "/PICS/simple2.jpg" Qc for an image file
       +.D1 Qo "/PICS" Qc for a directory access
       +.El
       +.It Ic <query>
       += query term submitted (Type 7 requests only)
       +.Bl -inset -offset indent
       +ex.
       +.Dl % snarf Qq "gopher://frog.bog/7/hello.cgi?Christoph"
       +.Dl would log Qo "Christoph" Qc as the query term.
       +.El
       +.It Ic (<status>)
       += status of client request
       +.Bl -inset -offset indent
       +ex. - some common status entries:
       +.El
       +.Pp
       +.Bl -hang -width XXXXXXXXXXXXXXXX -compact -offset XXXXXXXXXXXX
       +.It Qo (serving) Qc
       +=> a successful request
       +.It Qo (not found) Qc
       +=> an unsuccessful request
       +.It Qo (HTTP redirect) Qc
       +=> web link redirect (Type h)
       +.It Qo (dir listing) Qc
       +=> unindexed directory listing
       +.El
       +.El
       +.
       +.Sh FILES
       +README, LICENSE, index.gph
       +.
       +.Sh "SEE ALSO"
       +Links for further information on gopher:
       +.Pp
       +.D1 Pa gopher://gopher.gopherproject.org
       +.D1 Pa http://www.gopherproject.org
       +.Pp
       +.Sh STANDARDS
       +.Em Internet RFC 1436
       +.
       +.Sh HISTORY
       +Geomyidae started as a Linux/BSD port of the Plan 9 gopherd_P9 server.
       +Originally called gopherd_BSD, the name was later changed to Geomyidae
       +(latin), the taxonomic family of burrowing rodents known as "pocket
       +gophers" which are in fact the true gophers. Because of inconsitencies
       +and the UNIX culture, the name was changed to lowercase in 2010.
       +.
       +.Sh AUTHORS
       +See LICENSE file for authors in the distribution.
       +.
       +.Sh LICENSE
       +Geomyidae is released under the MIT/X Consortium License.
       +.
       +.Sh BUGS
       +Geomyidae occasionally aborts silently if too many simultaneous
       +requests are made.  Limiting gopher traffic via firewall rules
       +may help.
       +.Pp
       +Dynamic content functionality may vary across gopher clients.
       +.
       +.Ss "Reporting Bugs"
       +Report bugs to: 
       +.An "Christoph Lohmann" Aq 20h@R-36.net
 (DIR) diff --git a/handlr.c b/handlr.c
       @@ -0,0 +1,196 @@
       +/*
       + * Copy me if you can. 
       + * by 20h
       + */
       +
       +#include <unistd.h>
       +#include <memory.h>
       +#include <netdb.h>
       +#include <netinet/in.h>
       +#include <fcntl.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <sys/socket.h>
       +#include <sys/types.h>
       +#include <sys/stat.h>
       +#include <dirent.h>
       +#include "ind.h"
       +#include "arg.h"
       +
       +void
       +handledir(int sock, char *path, char *port, char *base, char *args,
       +                char *sear)
       +{
       +        char *pa, *file, *e, *addr, *par, *b;
       +        struct dirent **dirent;
       +        int ndir, i;
       +        struct stat st;
       +        filetype *type;
       +
       +        USED(sear);
       +        addr = nil;
       +
       +        pa = gstrdup(path);
       +        e = strrchr(pa, '/');
       +        if(e != nil) {
       +                *e = '\0';
       +
       +                if(args == nil) {
       +                        addr = gmallocz(512, 2);
       +                        if(gethostname(addr, 512) == -1) {
       +                                perror("gethostname");
       +                                close(sock);
       +                                free(addr);
       +                                free(pa);
       +                                return;
       +                        }
       +                } else
       +                        addr = gstrdup(args);
       +
       +                par = gstrdup(pa);
       +                b = strrchr(par + strlen(base), '/');
       +                if(b != nil) {
       +                        *b = '\0';
       +                        tprintf(sock, "1..\t%s\t%s\t%s\r\n", 
       +                                par + strlen(base), addr, port);
       +                }
       +                free(par);
       +
       +                ndir = scandir(pa, &dirent, 0, alphasort);        
       +                if(ndir < 0) {
       +                        perror("scandir");
       +                        close(sock);
       +                        free(addr);
       +                        free(pa);
       +                        return;
       +                } else {
       +                        for(i = 0; i < ndir; i++) {
       +                                if(dirent[i]->d_name[0] == '.') {
       +                                        free(dirent[i]);
       +                                        continue;
       +                                }
       +
       +                                type = gettype(dirent[i]->d_name);
       +                                file = smprintf("%s/%s", pa,
       +                                                dirent[i]->d_name);
       +                                if(stat(file, &st) >= 0 && S_ISDIR(st.st_mode))
       +                                        type = gettype("index.gph");
       +                                e = file + strlen(base);
       +                                tprintf(sock, "%c%s\t%s\t%s\t%s\r\n", *type->type,
       +                                        dirent[i]->d_name, e, addr, port);
       +                                free(file);
       +                                free(dirent[i]);
       +                        }
       +                        free(dirent);
       +                }
       +                tprintf(sock, "\r\n");
       +        }
       +
       +        if(addr != nil)
       +                free(addr);
       +        free(pa);
       +        close(sock);
       +        return;
       +} 
       +
       +void
       +handlegph(int sock, char *file, char *port, char *base, char *args,
       +                char *sear)
       +{
       +        Indexs *act;
       +        int i;
       +        char addr[512];
       +
       +        USED(base);
       +        USED(args);
       +        USED(sear);
       +
       +        act = scanfile(file);
       +        if(act != nil) {
       +                if(args == nil) {
       +                        if(gethostname(addr, sizeof(addr)) == -1) {
       +                                perror("gethostname");
       +                                close(sock);
       +                                return;
       +                        }
       +                } else
       +                        snprintf(addr, sizeof(addr), "%s", args);
       +
       +
       +                for(i = 0; i < act->num; i++) { 
       +                        if(!strncmp(act->n[i]->e[3], "server", 6)) {
       +                                free(act->n[i]->e[3]);
       +                                act->n[i]->e[3] = gstrdup(addr);
       +                        }
       +                        if(!strncmp(act->n[i]->e[4], "port", 4)) {
       +                                free(act->n[i]->e[4]);
       +                                act->n[i]->e[4] = gstrdup(port);
       +                        }
       +                        tprintf(sock, "%.1s%s\t%s\t%s\t%s\r\n",
       +                                act->n[i]->e[0], act->n[i]->e[1],
       +                                act->n[i]->e[2], act->n[i]->e[3],
       +                                act->n[i]->e[4]);
       +
       +                        freeelem(act->n[i]);
       +                        act->n[i] = nil;
       +                }
       +                tprintf(sock, "\r\n.\r\n\r\n");
       +
       +                freeindex(act);
       +        }
       +
       +        close(sock);
       +        return;
       +}
       +
       +void
       +handlebin(int sock, char *file, char *port, char *base, char *args,
       +                char *sear)
       +{
       +        char sendb[1024];
       +        int len, fd;
       +
       +        len = -1;
       +        USED(port);
       +        USED(base);
       +        USED(args);
       +        USED(sear);
       +
       +        fd = open(file, O_RDONLY);
       +        if(fd >= 0) {
       +                while((len = read(fd, sendb, sizeof(sendb))) > 0)
       +                        send(sock, sendb, len, 0);
       +                close(fd);
       +        }
       +
       +        close(sock);
       +        return;
       +}
       +
       +void
       +handlecgi(int sock, char *file, char *port, char *base, char *args,
       +                char *sear)
       +{
       +        char *p;
       +
       +        USED(port);
       +        USED(base);
       +
       +        p = strrchr(file, '/');
       +        if(p == nil)
       +                p = file;
       +
       +        dup2(sock, 1);
       +        dup2(sock, 0);
       +        dup2(sock, 2);
       +
       +        if(sear == nil)
       +                sear = "";
       +
       +        execl(file, p, sear, args, nil); 
       +
       +        close(sock);
       +        return;
       +}
       +
 (DIR) diff --git a/handlr.h b/handlr.h
       @@ -0,0 +1,20 @@
       +/*
       + * Copy me if you can. 
       + * by 20h
       + */
       +
       +#ifndef HANDLR_H
       +#define HANDLR_H
       +
       +#define nil NULL
       +
       +void handledir(int sock, char *path, char *port, char *base, char *args,
       +                        char *sear);
       +void handlegph(int sock, char *file, char *port, char *base, char *args,
       +                        char *sear);
       +void handlebin(int sock, char *file, char *port, char *base, char *args,
       +                        char *sear);
       +void handlecgi(int sock, char *file, char *port, char *base, char *args,
       +                        char *sear);
       +
       +#endif
 (DIR) diff --git a/ind.c b/ind.c
       @@ -0,0 +1,287 @@
       +/*
       + * Copy me if you can. 
       + * by 20h
       + */
       +
       +#include <unistd.h>
       +#include <stdarg.h>
       +#include <string.h>
       +#include <memory.h>
       +#include <fcntl.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include "ind.h"
       +#include "handlr.h"
       +
       +filetype type[] = {
       +        {"default", "0", handlebin},
       +        {"gph", "1", handlegph},
       +        {"cgi", "0", handlecgi},
       +        {"bin", "9", handlebin},
       +        {"tgz", "9", handlebin},
       +        {"gz", "9", handlebin},
       +        {"jpg", "I", handlebin},
       +        {"gif", "g", handlebin},
       +        {"png", "I", handlebin},
       +        {"bmp", "I", handlebin},
       +        {"txt", "0", handlebin},
       +        {"html", "0", handlebin},
       +        {"htm", "0", handlebin},
       +        {"xhtml", "0", handlebin},
       +        {"css", "0", handlebin},
       +        {nil, nil, nil},
       +};
       +
       +filetype *
       +gettype(char *filename)
       +{
       +        char *end;
       +        int i;
       +
       +        end = strrchr(filename, '.');
       +        if(end == nil) 
       +                return &type[0]; 
       +        end++;
       +
       +        for(i = 0; type[i].end != nil; i++)
       +                if(!strncasecmp(end, type[i].end, strlen(type[i].end)))
       +                        return &type[i];
       +
       +        return &type[0];
       +}
       +
       +void *
       +gmallocz(int l, int d)
       +{
       +        char *ret;
       +
       +        ret = malloc(l);
       +        if(ret == nil) {
       +                perror("malloc");
       +                exit(1);
       +        }
       +
       +        if(d)
       +                memset(ret, 0, l);
       +
       +        return (void *)ret;
       +}
       +
       +char *
       +gstrdup(char *str)
       +{
       +        char *ret;
       +
       +        ret = strdup(str);
       +        if(ret == nil) {
       +                perror("strdup");
       +                exit(1);
       +        }
       +
       +        return ret;
       +}
       +
       +char *
       +readln(int fd)
       +{
       +        char *ret;
       +        int len;
       +
       +        len = 1;
       +
       +        ret = malloc(2);
       +        while(read(fd, &ret[len - 1], 1) > 0 && ret[len - 1] != '\n')
       +                ret = realloc(ret, ++len + 1);
       +        if(ret[len - 1] != '\n') {
       +                free(ret);
       +                return nil;
       +        }
       +        ret[len - 1] = '\0';
       +
       +        return ret;
       +}
       +
       +void
       +freeelem(Elems *e)
       +{
       +
       +        if(e != nil) {
       +                if(e->e != nil) {
       +                        for(;e->num > 0; e->num--)
       +                                if(e->e[e->num - 1] != nil)
       +                                        free(e->e[e->num - 1]);
       +                        free(e->e);
       +                }
       +                free(e);
       +        }
       +        return;
       +}
       +
       +void
       +freeindex(Indexs *i)
       +{
       +
       +        if(i != nil) {
       +                if(i->n != nil) {
       +                        for(;i->num > 0; i->num--)
       +                                if(i->n[i->num - 1] != nil)
       +                                        freeelem(i->n[i->num - 1]);
       +                        free(i->n);
       +                }
       +                free(i);
       +        }
       +
       +        return;
       +}
       +
       +void
       +addelem(Elems *e, char *s)
       +{
       +
       +        e->num++;
       +        e->e = realloc(e->e, sizeof(char *) * e->num);
       +        e->e[e->num - 1] = gmallocz(strlen(s) + 1, 0);
       +        strcpy(e->e[e->num - 1], s);
       +
       +        return;
       +}
       +
       +Elems *
       +getadv(char *str)
       +{
       +        char *b, *e;
       +        Elems *ret;
       +
       +        ret = gmallocz(sizeof(Elems), 2);
       +        if(*str != '[') {
       +                b = str;
       +                if(*str == 't')
       +                        b++;
       +                addelem(ret, "i");
       +                addelem(ret, b);
       +                addelem(ret, "Err");
       +                addelem(ret, "server");
       +                addelem(ret, "port");
       +                
       +                return ret;
       +        }
       +                
       +        b = str + 1;
       +        while((e = strchr(b, '|')) != nil) {
       +                *e = '\0';
       +                e++;
       +                addelem(ret, b);
       +                b = e;
       +        }
       +
       +        e = strchr(b, ']');
       +        if(e != nil) {
       +                *e = '\0';
       +                addelem(ret, b);
       +        }
       +        if(ret->e == nil) {
       +                free(ret);
       +                return nil;
       +        }
       +
       +        return ret;
       +}
       +
       +Indexs *
       +scanfile(char *fname)
       +{
       +        char *ln;
       +        int fd;
       +        Indexs *ret;
       +        Elems *el;
       +
       +        fd = open(fname, O_RDONLY);
       +        if(fd < 0)
       +                return nil;
       +
       +        ret = gmallocz(sizeof(Indexs), 2);
       +
       +        while((ln = readln(fd)) != nil) {
       +                el = getadv(ln);
       +                free(ln);
       +                if(el == nil)
       +                        continue;
       +
       +                ret->num++;
       +                ret->n = realloc(ret->n, sizeof(Elems) * ret->num);
       +                ret->n[ret->num - 1] = el;
       +                el = nil;
       +        }
       +        close(fd);
       +
       +        if(ret->n == nil) {
       +                free(ret);
       +                return nil;
       +        }
       +
       +        return ret;
       +}
       +
       +void
       +ttprintf(int fd, char *fmt, ...)
       +{
       +        va_list fmtargs;
       +        int fd2;
       +        FILE *fp;
       +
       +        fd2 = dup(fd);
       +        fp = fdopen(fd2, "w");
       +        if(fp == nil) {
       +                perror("fdopen");
       +                return;
       +        }
       +
       +        va_start(fmtargs, fmt);
       +        vfprintf(fp, fmt, fmtargs);
       +        va_end(fmtargs);
       +
       +        fclose(fp);
       +
       +        return;
       +}
       +
       +int
       +initlogging(char *logf)
       +{
       +        int fd;
       +
       +        fd = open(logf, O_APPEND | O_WRONLY | O_CREAT, 0644);
       +
       +        return fd;
       +}
       +
       +void
       +stoplogging(int fd)
       +{
       +
       +        close(fd);
       +
       +        return;
       +}
       +
       +char *
       +smprintf(char *fmt, ...)
       +{
       +        va_list fmtargs;
       +        char *ret;
       +        int size;
       +
       +        ret = "";
       +
       +        va_start(fmtargs, fmt);
       +        size = vsnprintf(ret, 0, fmt, fmtargs);
       +        va_end(fmtargs);
       +
       +        ret = gmallocz(++size, 2);
       +        va_start(fmtargs, fmt);
       +        vsnprintf(ret, size, fmt, fmtargs);
       +        va_end(fmtargs);
       +
       +        return ret;
       +}
       +
 (DIR) diff --git a/ind.h b/ind.h
       @@ -0,0 +1,48 @@
       +/*
       + * Copy me if you can. 
       + * by 20h
       + */
       +
       +#ifndef IND_H
       +#define IND_H
       +
       +#include <stdio.h>
       +#define nil NULL
       +
       +extern int glfd;
       +
       +ttypedef struct Elems Elems;
       +struct Elems {
       +        char **e;
       +        int num;
       +};
       +
       +ttypedef struct Indexs Indexs;
       +struct Indexs {
       +        Elems **n;
       +        int num;
       +};
       +
       +ttypedef struct filetype filetype;
       +struct filetype {
       +        char *end;
       +        char *type;
       +        void (* f)(int, char *, char *, char *, char *, char *);
       +};
       +
       +filetype *gettype(char *filename);
       +void *gmallocz(int l, int d);
       +char *gstrdup(char *str);
       +Indexs *scanfile(char *fname);
       +Elems *getadv(char *str);
       +void addelem(Elems *e, char *s);
       +void freeindex(Indexs *i);
       +void freeelem(Elems *e);
       +char *readln(int fd);
       +void tprintf(int fd, char *fmt, ...);
       +int initlogging(char *logf);
       +void stoplogging(int fd);
       +char *smprintf(char *fmt, ...);
       +
       +#endif
       +
 (DIR) diff --git a/index.gph b/index.gph
       @@ -0,0 +1,6 @@
       +comment
       +ttcomment
       +t[1|R-36|/|server|port]
       +t[0|file - comment|/file.dat|server|port]
       +t[h|http://www.heise.de|URL:http://www.heise.de|server|port]
       +
 (DIR) diff --git a/main.c b/main.c
       @@ -0,0 +1,385 @@
       +/*
       + * Copy me if you can. 
       + * by 20h
       + */
       +
       +#include <unistd.h>
       +#include <dirent.h>
       +#include <memory.h>
       +#include <netdb.h>
       +#include <netinet/in.h>
       +#include <fcntl.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <sys/socket.h>
       +#include <sys/stat.h>
       +#include <sys/wait.h>
       +#include <sys/types.h>
       +#include <signal.h>
       +#include <time.h>
       +#include <pwd.h>
       +#include <grp.h>
       +#include "ind.h"
       +#include "handlr.h"
       +#include "arg.h"
       +
       +enum {
       +        NOLOG         = 0,
       +        FILES         = 1,
       +        DIRS         = 2,        
       +        HTTP        = 4,
       +        ERRORS        = 8,
       +}; 
       +
       +int glfd = -1;
       +int loglvl = 15;
       +
       +char *argv0;
       +char *stdbase = "/var/gopher";
       +char *stdport = "70";
       +char *indexf = "/index.gph";
       +char *err = "0Sorry, but the requested token could not be found\tErr"
       +            "\tlocalhost\t70\r\n.\r\n\r\n";
       +char *htredir = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
       +                "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
       +                "        \"DTD/xhtml-transitional.dtd\">\n"
       +                "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\">\n"
       +                "  <head>\n"
       +                "    <title>gopher redirect</title>\n"
       +                "\n"
       +                "    <meta http-equiv=\"Refresh\" content=\"1;url=%s\" />\n"
       +                "  </head>\n"
       +                "  <body>\n"
       +                "    This page is for redirecting you to: <a href=\"%s\">%s</a>.\n"
       +                "  </body>\n"
       +                "</html>\n";
       +
       +int
       +dropprivileges(struct group *gr, struct passwd *pw)
       +{
       +
       +        if(gr != nil)
       +                if(setgroups(1, &gr->gr_gid) != 0 || setgid(gr->gr_gid) != 0)
       +                        return -1;
       +        if(pw != nil) {
       +                if(gr == nil) {
       +                        if(setgroups(1, &pw->pw_gid) != 0 ||
       +                            setgid(pw->pw_gid) != 0)
       +                                return -1;
       +                }
       +                if(setuid(pw->pw_uid) != 0)
       +                        return -1;
       +        }
       +
       +        return 0;
       +}
       +
       +char *
       +securepath(char *p, int len)
       +{
       +        int i;
       +
       +        if(len < 2)
       +                return p;
       +
       +        for(i = 1; i < strlen(p); i++) {
       +                if(p[i - 1] == '.' && p[i] == '.') {
       +                        if(p[i - 2] == '/')
       +                                p[i] = '/';
       +                        if(p[i + 1] == '/')
       +                                p[i] = '/';
       +                        if(len == 2)
       +                                p[i] = '/';
       +                }
       +        }
       +
       +        return p;
       +}
       +
       +void
       +logentry(char *host, char *port, char *qry, char *status) 
       +{
       +        time_t tim;
       +        struct tm *ptr;
       +        char timstr[128]; 
       +
       +        if(glfd >= 0) {
       +                tim = time(0);
       +                ptr = localtime(&tim);
       +
       +                strftime(timstr, sizeof(timstr), "%a %b %d %H:%M:%S %Z %Y",
       +                                        ptr);
       +
       +                tprintf(glfd, "[%s|%s:%s] %s (%s)\n",
       +                        timstr, host, port, qry, status);
       +        }
       +
       +        return;
       +}
       +
       +void
       +handlerequest(int sock, char *base, char *ohost, char *port, char *clienth,
       +                        char *clientp)
       +{
       +        struct stat dir;
       +        char recvc[1024], recvb[1024], path[1024], *args, *sear, *c;
       +        int len, fd;
       +        filetype *type;
       +
       +        memset(&dir, 0, sizeof(dir));
       +        memset(recvb, 0, sizeof(recvb));
       +        memset(recvc, 0, sizeof(recvc));
       +
       +        len = recv(sock, recvb, sizeof(recvb), 0);
       +        if(len > 1) {
       +                if(recvb[len - 2] == '\r')
       +                        recvb[len - 2] = '\0';
       +                if(recvb[len - 1] == '\n')
       +                        recvb[len - 1] = '\0';
       +        }
       +        strcpy(recvc, recvb);
       +
       +        if(!strncmp(recvb, "URL:", 4)) {
       +                len = snprintf(path, sizeof(path), htredir,
       +                                recvb + 4, recvb + 4, recvb + 4);
       +                if(len > sizeof(path))
       +                        len = sizeof(path);
       +                send(sock, path, len, 0); 
       +                if(loglvl & HTTP) 
       +                        logentry(clienth, clientp, recvc, "HTTP redirect");  
       +                return;
       +        }
       +
       +        sear = strchr(recvb, '\t');
       +        if(sear != nil)
       +                *sear++ = '\0';
       +        args = strchr(recvb, '?');
       +        if(args != nil)
       +                *args++ = '\0';
       +        else
       +                args = ohost;
       +
       +        securepath(recvb, len - 2);
       +        snprintf(path, sizeof(path), "%s%s", base, recvb);
       +        if(stat(path, &dir) != -1 && S_ISDIR(dir.st_mode))
       +                strncat(path, indexf, sizeof(path) - strlen(path));
       +
       +        fd = open(path, O_RDONLY);
       +        if(fd >= 0) {
       +                close(fd);
       +                if(loglvl & FILES)
       +                        logentry(clienth, clientp, recvc, "serving");
       +
       +                c = strrchr(path, '/');
       +                if(c == nil)
       +                        c = path;
       +                type = gettype(c);
       +                type->f(sock, path, port, base, args, sear);
       +        } else {
       +                if(S_ISDIR(dir.st_mode)) {
       +                        handledir(sock, path, port, base, args, sear);
       +                        if(loglvl & DIRS)
       +                                logentry(clienth, clientp, recvc,
       +                                                        "dir listing");
       +                        return;
       +                }
       +                        
       +                send(sock, err, strlen(err), 0);
       +                if(loglvl & ERRORS) 
       +                        logentry(clienth, clientp, recvc, "not found"); 
       +                close(sock);
       +        }
       +
       +        return;
       +}
       +
       +void
       +hndlsigchld(int signo)
       +{
       +        int status;
       +
       +        while(waitpid(-1, &status, WNOHANG) > 0);
       +
       +        return;
       +}
       +
       +void
       +usage(void)
       +{
       +
       +        tprintf(2, "usage: %s [-d] [-l logfile] [-v loglvl] [-b base]"
       +                   " [-p port] [-o sport] [-u user] [-g group] [-h host]"
       +                   " [-i IP]\n",
       +                   argv0);
       +
       +        exit(1);
       +}
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        struct addrinfo hints, *ai;
       +        struct sockaddr_storage clt;
       +        socklen_t cltlen;
       +        int sock, list, opt, dofork;
       +        char *port, *base, *logfile, clienth[NI_MAXHOST], clientp[NI_MAXSERV];
       +        char *user, *group, *bindip, *ohost, *sport;
       +        struct passwd *us;
       +        struct group *gr;
       +
       +        base = stdbase;
       +        port = stdport;
       +        dofork = 1;
       +        logfile = nil;
       +        user = nil;
       +        group = nil;
       +        us = nil;
       +        gr = nil;
       +        bindip = nil;
       +        ohost = nil;
       +        sport = port;
       +
       +        ARGBEGIN {
       +        case 'b':
       +                base = EARGF(usage());
       +                break;
       +        case 'p':
       +                port = EARGF(usage());
       +                break;
       +        case 'l':
       +                logfile = EARGF(usage());
       +                break;
       +        case 'd':
       +                dofork = 0;
       +                break; 
       +        case 'v':
       +                loglvl = atoi(EARGF(usage()));
       +                break;
       +        case 'u':
       +                user = EARGF(usage());
       +                break;
       +        case 'g':
       +                group = EARGF(usage());
       +                break;        
       +        case 'i':
       +                bindip = EARGF(usage());
       +                break;
       +        case 'h':
       +                ohost = EARGF(usage());
       +                break;
       +        case 'o':
       +                sport = EARGF(usage());
       +                break;
       +        default:
       +                usage();
       +        } ARGEND;
       +
       +        if(group != nil) {
       +                if((gr = getgrnam(group)) == nil) {
       +                        perror("no such group");
       +                        return 1;
       +                }
       +        }
       +
       +        if(user != nil) {
       +                if((us = getpwnam(user)) == nil) {
       +                        perror("no such user");
       +                        return 1;
       +                }
       +        }
       +
       +        if(dofork && fork() != 0)
       +                return 0;
       +
       +        if(logfile != nil) {
       +                glfd = initlogging(logfile);
       +                if(glfd < 0) {
       +                        perror("initlogging");
       +                        return 1;
       +                }
       +        }
       +
       +        memset(&hints, 0, sizeof(hints));
       +        hints.ai_flags |= AI_PASSIVE;
       +        hints.ai_socktype = SOCK_STREAM;
       +        hints.ai_protocol = IPPROTO_TCP;
       +        hints.ai_family = AF_INET;
       +        if(getaddrinfo(bindip, port, &hints, &ai)) {
       +                perror("getaddrinfo");
       +                return 1;
       +        }
       +        if(ai == nil) {
       +                perror("getaddrinfo");
       +                return 1;
       +        }
       +
       +        list = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
       +        if(list < 0) {
       +                perror("socket");
       +                return 1;
       +        }
       +
       +        opt = 1;
       +        if(setsockopt(list, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
       +                perror("setsockopt");
       +                return 1;
       +        }
       +
       +        if(bind(list, ai->ai_addr, ai->ai_addrlen)) {
       +                perror("bind");
       +                return 1;
       +        }
       +
       +        if(listen(list, 255)) {
       +                perror("listen");
       +                return 1;
       +        }
       +
       +        freeaddrinfo(ai);
       +
       +        if(dropprivileges(gr, us) < 0) {
       +                perror("cannot drop privileges");
       +                return 1;
       +        }
       +
       +        if(dofork) {
       +                signal(SIGINT, SIG_IGN);
       +                signal(SIGQUIT, SIG_IGN);
       +        }
       +        signal(SIGCHLD, hndlsigchld);
       +
       +        cltlen = sizeof(clt);
       +        for(;;) {
       +                sock = accept(list, (struct sockaddr *)&clt, &cltlen);
       +                if(sock < 0) {
       +                        perror("accept");
       +                        close(list);
       +                        return 1;
       +                }
       +
       +                getnameinfo((struct sockaddr *)&clt, cltlen, clienth,
       +                                sizeof(clienth), clientp, sizeof(clientp),
       +                                NI_NUMERICHOST);
       +
       +                switch(fork()) {
       +                case -1:
       +                        perror("fork");
       +                        close(sock);
       +                        break;
       +                case 0: 
       +                        handlerequest(sock, base, ohost, sport, clienth,
       +                                                clientp);
       +                        return 1;
       +                default:
       +                        wait(&opt);
       +                        close(sock);
       +                        break;
       +                }
       +        }
       +
       +        close(list);
       +        if(logfile != nil)
       +                stoplogging(glfd);
       +        return 0;
       +}
       +
 (DIR) diff --git a/rc.d/Archlinux.conf.d b/rc.d/Archlinux.conf.d
       @@ -0,0 +1,4 @@
       +#
       +# Parameters to be passed to geomyidae 
       +#
       +GEOMYIDAE_ARGS="-u nobody -g nobody -b /srv/gopher -o 70 -l /var/log/geomyidae.log -h localhost"
 (DIR) diff --git a/rc.d/Archlinux.rc.d b/rc.d/Archlinux.rc.d
       @@ -0,0 +1,38 @@
       +#!/bin/bash
       +
       +. /etc/rc.conf
       +. /etc/rc.d/functions
       +. /etc/conf.d/geomyidae
       +
       +PID=`pidof -o %PPID /usr/bin/geomyidae`
       +case "$1" in
       +  start)
       +    stat_busy "Starting geomyidae"
       +    [ -z "$PID" ] && /usr/bin/geomyidae $GEOMYIDAE_ARGS 2>&1
       +    if [ $? -gt 0 ]; then
       +      stat_fail
       +    else
       +      PID=`pidof -o %PPID /usr/bin/geomyidae`
       +      echo $PID >/var/run/geomyidae.pid
       +      add_daemon geomyidae
       +      stat_done
       +    fi
       +    ;;
       +  stop)
       +    stat_busy "Stopping geomyidae"
       +    [ ! -z "$PID" ]  && kill $PID &>/dev/null
       +    if [ $? -gt 0 ]; then
       +      stat_fail
       +    else
       +      rm_daemon geomyidae 
       +      stat_done
       +    fi
       +    ;;
       +  restart)
       +    $0 stop
       +    $0 start
       +    ;;
       +  *)
       +    echo "usage: $0 {start|stop|restart}"  
       +esac
       +exit 0
 (DIR) diff --git a/rc.d/Gentoo.conf.d b/rc.d/Gentoo.conf.d
       @@ -0,0 +1,5 @@
       +#
       +# Parameters to be passed to geomyidae 
       +#
       +GEOMYIDAE_ARGS="-u gopherd -g gopherd -b /var/gopher -o 70 -l /var/log/geomyidae.log -h localhost"
       +
 (DIR) diff --git a/rc.d/Gentoo.init.d b/rc.d/Gentoo.init.d
       @@ -0,0 +1,17 @@
       +#!/sbin/runscript
       +# Copyright 1999-2010 Gentoo Foundation
       +# Distributed under the terms of the GNU General Public License v2
       +# $Header: $
       +
       +start(){
       +    ebegin "Starting geomyidae"
       +    [ -n "$GEOMYIDAE_ARGS" ] && GEOMYIDAE_ARGS="-- $GEOMYIDAE_ARGS"
       +    start-stop-daemon --start --pidfile /var/run/geomyidae.pid --exec /usr/sbin/geomyidae $GEOMYIDAE_ARGS
       +    eend $? "Failed to start geomyidae"
       +}
       +
       +stop(){
       +    ebegin "Stopping geomyidae"
       +    start-stop-daemon --stop --pidfile /var/run/geomyidae.pid
       +    eend $? "Failed to stop geomyidae"
       +}
 (DIR) diff --git a/rc.d/NetBSD.rc.d b/rc.d/NetBSD.rc.d
       @@ -0,0 +1,55 @@
       +#!/bin/sh
       +#
       +
       +# REQUIRE: local
       +# PROVIDE: geomyidae
       +
       +$_rc_subr_loaded . /etc/rc.subr
       +
       +name="geomyidae"
       +rcvar=$name
       +command="/usr/pkg/sbin/${name}"
       +
       +#####################################################
       +# Geomyidae Options Section - "?" => geomyidae(8)   #
       +#  Uncomment & define options (defaults are shown)  #
       +#####################################################
       +#
       +#LOGFILE="-l /var/log/gopherd.log"
       +#LOGLEVEL="-v 15"
       +#HTDOCS="-b /var/gopher"
       +#PORT="-p 70"
       +#SPORT="-o 70"
       +#USR="-u $USER"
       +#GRP="-g $GROUP"
       +#HOST="-h localhost"
       +#IP="-i 127.0.0.1"
       +
       +######################################################
       +# Now remove any UNDEFINED options from line below:  #
       +######################################################
       +#
       +command_args="$LOGFILE $LOGLEVEL $HTDOCS $PORT $SPORT $USR $GRP $HOST $IP"
       +
       +
       +######################################################
       +#  Uncomment this section if a PID file is desired   #
       +######################################################
       +
       +#pidfile="/var/run/${name}.pid"
       +#start_cmd="geomyidae_start"
       +#
       +#geomyidae_start()
       +#{
       +#        echo "Starting $name"
       +#        $command $command_args
       +#        pgrep -x $name > $pidfile
       +#}
       +
       +######################################################
       +#  Lastly, add the following to /etc/rc.conf:        #
       +#  "geomyidae=YES"  (without the quotes)             #
       +######################################################
       +
       +load_rc_config $name
       +run_rc_command "$1"
 (DIR) diff --git a/rc.d/README b/rc.d/README
       @@ -0,0 +1,5 @@
       +These are init scripts, used in various distribution, for Geomyidae.
       +
       +All files are examples sent in by users. Please review them before
       +using.
       +