[net.sources] Netd

ry@cadre.UUCP (02/03/85)

echo x - addr.c
cat > addr.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/addr.c, Jan 19 23:46:24 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>


static char Hex[]="0123456789abcdef";

static PutHex( cpp, h )
   char **cpp;
   unsigned int h;
{
    *(*cpp)++ = Hex[ h & 0xf ];
}

static PutHexByte( cpp ,b )
  char **cpp;
  unsigned char b;
{
    PutHex( cpp ,(unsigned int)(b >> 4) );
    PutHex( cpp ,(unsigned int)b );
}

static PutHexShort( cpp ,s )
  char **cpp;
  unsigned short s;
{
    PutHexByte( cpp ,(unsigned char)(s >> 8) );
    PutHexByte( cpp ,(unsigned char)s );
}


AddrToString( addr, addrlen, string )
  struct sockaddr *addr;
  int addrlen;
  char *string;
{
    if (addrlen <= 0) {
	*string = 0;
	return;
    }

    switch ( addr->sa_family ) {

 	case AF_UNIX: {
	    struct sockaddr_un *un = ( struct sockaddr_un * ) addr;
	    addrlen -= sizeof( u_short );
	    bcopy( un->sun_path, string, addrlen );
	    string[ addrlen ] = 0;
	    break;
	}

     case AF_INET: { struct sockaddr_in *in = (struct sockaddr_in *) addr;
	    *string++ = '@';
	    PutHexByte( &string ,in->sin_addr.S_un.S_un_b.s_b4 );
	    PutHexByte( &string ,in->sin_addr.S_un.S_un_b.s_b3 );
	    PutHexByte( &string ,in->sin_addr.S_un.S_un_b.s_b2 );
	    PutHexByte( &string ,in->sin_addr.S_un.S_un_b.s_b1 );
	    PutHexShort( &string ,in->sin_port );
	    *string++ = 0;
	    break;
	}

     default: { int i;
	    *string++ = '#';
            PutHexShort( &string ,addr->sa_family );
	    for (i = 0; i < 14; i++)
		PutHexByte( &string ,(unsigned char)addr->sa_data[i] );
	    *string++ = 0;
	    break;
	}
    }
}

!Magic!Token!
echo x - addr2.c
cat > addr2.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/addr2.c, Jan 19 23:46:28 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>


StringToAddr2( string, addr, addrlen )
  char *string;
  struct sockaddr *addr;
  int *addrlen;
{
    bzero( addr ,sizeof( *addr ) );
    switch ( string[0] ) {
	case '*': {
	    struct servent *sp;
	    struct sockaddr_in *in = (struct sockaddr_in *) addr;
	    u_short port;
		if ( string[1] != '.' )
		    return -1;

		if ( sscanf( &string[2], "%hd", &port ) != 1 ) {
		    if ((sp = getservbyname( &string[2], 0 )) == 0 )
			return -1;
		    port = sp->s_port;
		} else port = htons( port );

		in->sin_family = AF_INET;
		in->sin_addr.s_addr = INADDR_ANY;
		in->sin_port = port;
		*addrlen = sizeof( struct sockaddr_in );
		break;
	}

	case '/': {
	    struct sockaddr_un *un = (struct sockaddr_un *) addr;
	    int len = strlen( string );
		if ( len > 14)
		    return -1;
		un->sun_family = AF_UNIX;
		bcopy( string ,un->sun_path ,len );
		*addrlen = len + sizeof(u_short);
		break;
	}

	case '-':
		*addrlen = 0;
		break;

	default:
		return -1;
    }
    return 0;
}
!Magic!Token!
echo x - addr3.c
cat > addr3.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/addr3.c, Jan 19 23:46:32 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>


static int GetHex( cpp, hp )
  char **cpp;
  unsigned int  *hp;
{
    if (**cpp >= '0' && **cpp <= '9') {
	*hp = *(*cpp)++ - '0';
	return 0;
    }
    if (**cpp >= 'a' && **cpp <= 'f') {
	*hp = (*(*cpp)++ - 'a') + 10;
	return 0;
    }
    return -1;
}

static int GetHexByte( cpp, bp )
  char **cpp;
  unsigned char *bp;
{
  unsigned int lo, hi;
    if (GetHex( cpp, &hi ) )
	return -1;
    if (GetHex( cpp, &lo ) )
	return -1;
    *bp = lo + ( hi << 4 );
    return 0;
}


static int GetHexShort( cpp, sp )
  char **cpp;
  unsigned short *sp;
{
  unsigned char lo, hi;

    if (GetHexByte( cpp, &hi ) )
	return -1;
    if (GetHexByte( cpp, &lo ) )
	return -1;
    *sp = lo + ( hi << 8 );
    return 0;
}

StringToAddr( string ,addr ,addrlen )
  char *string;
  struct sockaddr *addr;
  int  *addrlen;
{
    bzero( addr ,sizeof( *addr ) );
    switch (*string++) {
	case '/': {
	    struct sockaddr_un *un = (struct sockaddr_un *) addr;
	    int len = strlen( --string );
	    if ( len > 14)
		return -1;
	    un->sun_family = AF_UNIX;
	    bcopy( string ,un->sun_path ,len );
	    *addrlen = len + sizeof(u_short);
	    break;
	}
	case '@': {
	    struct sockaddr_in *in = (struct sockaddr_in *) addr;
	    in->sin_family = AF_INET;
	    in->sin_addr.s_addr = INADDR_ANY;

	    if (GetHexByte( &string ,&in->sin_addr.S_un.S_un_b.s_b4 )
	     || GetHexByte( &string ,&in->sin_addr.S_un.S_un_b.s_b3 )
	     || GetHexByte( &string ,&in->sin_addr.S_un.S_un_b.s_b2 )
	     || GetHexByte( &string ,&in->sin_addr.S_un.S_un_b.s_b1 )
	     || GetHexShort( &string ,&in->sin_port ))
		return -1;
	    *addrlen = sizeof( struct sockaddr_in );
	    break;
	}

	case '#': { int i;
	    if (GetHexShort( &string, &addr->sa_family ))
		return -1;
	    for (i = 0; i < 14; i++)
		if (GetHexByte( &string ,(unsigned char *)&addr->sa_data[i] ))
		    return -1;
	    *addrlen = sizeof( struct sockaddr );
	    break;
	}

	case 0:
	    *addrlen = 0;
	    break;

	default:
		return -1;
    }
    return 0;
}


!Magic!Token!
echo x - addr4.c
cat > addr4.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/addr4.c, Jan 19 23:46:36 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>

extern char *sprintf();

AddrToString4( addr, addrlen, string )
  struct sockaddr *addr;
  int addrlen;
  char *string;
{
    if (addrlen <= 0) {
	*string = 0;
	return;
    }

    switch ( addr->sa_family ) {

 	case AF_UNIX: {
	    struct sockaddr_un *un = ( struct sockaddr_un * ) addr;
	    addrlen -= sizeof( u_short );
	    bcopy( un->sun_path, string, addrlen );
	    string[ addrlen ] = 0;
	    break;
	}

     case AF_INET: { struct sockaddr_in *in = (struct sockaddr_in *) addr;
	    struct hostent *hp;
	    hp = gethostbyaddr( &in->sin_addr, sizeof(struct in_addr),
		in->sin_family );
	    if (hp == 0) { int i1, i2, i3, i4;
		    i1 = in->sin_addr.S_un.S_un_b.s_b1;
		    i2 = in->sin_addr.S_un.S_un_b.s_b2;
		    i3 = in->sin_addr.S_un.S_un_b.s_b3;
		    i4 = in->sin_addr.S_un.S_un_b.s_b4;
		    (void)sprintf(string,"%d.%d.%d.%d.%hd"
			,i1 ,i2 ,i3 ,i4 ,ntohs( in->sin_port ));
	    } else {
		    (void)sprintf( string ,"%s.%hd" 
			,hp->h_name ,ntohs( in->sin_port ));
	    }
	    break;
	}

     default: {
	    *string++ = 'X';
	    *string = 0;	
	    break;
	}
    }
}

!Magic!Token!
echo x - conf.c
cat > conf.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/conf.c, Jan 19 23:46:39 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include "image.h"
#include "disc.h"
#include "service.h"

extern char *ConfFile;

/*
 * reconfiguration code
 * call every sighup, and at startup
 */

SyncSigHup() {
  Image   *im;
  Service *sv;
  Disc    *di;
  char  *flds[ MAXFLDS + 1 ];
  int nf;
  char msg[256];
  
    LogMsg( "Reconfiguring..." );
    if (( im = OpenImage( ConfFile )) == 0 ) {
        LogMsg( "OpenImage %s failed" ,ConfFile );
        return;
    }
    ClearActiveDaemons();
    while ( nf = ImageToFeilds( im ,flds ,sizeof(flds)/sizeof(flds[0])) ) {
	if (( sv = MakeService( flds, nf ,msg )) == 0 ) {
	    LogMsg( "%s: %s; %s" ,ConfFile ,flds[0] ,msg );
	    continue;
	}
	if (( di = DiscLookUp( sv->type, sv->af, sv->pf )) == 0 ) {
	    LogMsg( "%s: service %s: unsupported" ,ConfFile ,flds[0] );
	    FreeService( sv );
	    continue;
	}
        MakeDaemon( di, sv );
    }
    CloseImage( im );
    KillNonActiveDaemons();
}



SyncSigTerm() {
    LogMsg( "caught SIGTERM" );
    ClearActiveDaemons();
    KillNonActiveDaemons();
    exit(0);
}
!Magic!Token!
echo x - daemon.c
cat > daemon.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/daemon.c, Jan 19 23:46:43 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include "service.h"
#include "disc.h"
#include "daemon.h"

extern char *sprintf(), *malloc();

int Limit; /* initalized by init.c */

static int Active; /* count of active daemons */

static struct {	/* must overlay Daemon structure */
    Daemon *succ, *pred;
}
  Head = {
    (Daemon *)&Head, (Daemon *)&Head
};

/*
 * create daemon and attaching service and disc structures
 */
MakeDaemon( di, sv )
  Disc *di;
  Service *sv;
{
  Daemon *dm;
  Service *sv2;

    for ( dm = Head.succ; dm != (Daemon *)&Head; dm = dm->succ ) {

	if (( dm->flags & D_ZOMBIE ) == D_ZOMBIE )
	    continue;

	if ( strcmp( sv->name, dm->service->name ) == 0 ) {
	    sv2 = dm->service;
	    if ( sv->type == sv2->type
	      && sv->af == sv2->af
	      && sv->pf == sv2->pf
	      && sv->addrlen == sv2->addrlen
	      && bcmp( &sv->addr, &sv2->addr, sizeof( sv->addr )) == 0 ) {
		dm->service = sv;
		FreeService( sv2 );
		dm->flags |= D_ACTIVE;
		return;
	     }

	     ( *dm->disc->shutdown )( dm );
             Active--;
	     sleep( 2 ); /* wait for children to dye */
	     break;
	}
    }

    if ( Active >= Limit ) {
	LogMsg( "%s: Over %d services" ,sv->name ,Limit );
	return;
    }
    if (( dm = (Daemon *) malloc( sizeof( Daemon ))) == 0 ) {
	LogMsg( "%s: out of memory" ,sv->name );
	return;
    }
    dm->succ = Head.succ;
    Head.succ->pred = dm;
    Head.succ = dm;
    dm->pred = (Daemon *)&Head;
    dm->service = sv;
    dm->disc = di;
    dm->refer = 0;
    dm->flags = D_ACTIVE;
    if ((*di->startup)( dm ) < 0)
	FreeDaemon( dm );
    else
	Active++;
}



/*
 *  free daemon and associated service structure
 */
FreeDaemon( dm )
  Daemon *dm;
{
    dm->flags |= D_ZOMBIE;
    dm->flags &= ~D_ACTIVE;
    if (dm->refer > 0) 
	return;
    dm->succ->pred = dm->pred;
    dm->pred->succ = dm->succ;
    FreeService( dm->service );
    free( (char *)dm );
}



ClearActiveDaemons()
{
  Daemon *dm;
    for ( dm = Head.succ; dm != (Daemon *)&Head; dm = dm->succ )
	dm->flags &= ~D_ACTIVE;
}


KillNonActiveDaemons()
{
  Daemon *dm;
    for ( dm = Head.succ; dm != (Daemon *)&Head; dm = dm->succ )
	if (( dm->flags & D_ACTIVE ) == 0 )
	    ( *dm->disc->shutdown )( dm );

}

!Magic!Token!
echo x - dgram.c
cat > dgram.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/dgram.c, Jan 19 23:46:47 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/stat.h>
#include "service.h"
#include "disc.h"
#include "daemon.h"
#include "syserr.h"

typedef caddr_t arg;

#ifdef DEBUG
extern int Debug;
#endif DEBUG

int DGramReady();
/*ARGSUSED*/
static DGramSigChild( ar, pid )
  arg ar;
  int pid;
{
  Daemon *dm = (Daemon *) ar;

    if ( --dm->refer == 0 && ( dm->flags & D_ZOMBIE ) == D_ZOMBIE )
	FreeDaemon( dm );
    else 
	IWait( dm->fd, DGramReady, (arg)dm );
}

/*ARGSUSED*/
static int DGramReady( ar, fd )
  arg ar;
  int fd;
{
  Daemon *dm = (Daemon *) ar;
  Service *sv = dm->service;
  int pid;
  char tmp[64], *args[NARGS], **cpp, **bpp;
  static char *envp[] = { "DISC=dgram", "ADDR=XXXXXXXXXXXXXXXXXXXXXXXXXX", 0 };

    for ( cpp = sv->args, bpp = args; *cpp; ) {
	if (**cpp != '@') {
	    *bpp++ = *cpp++;
	    continue;
	}
	AddrToString4( &sv->addr, sv->addrlen, *bpp++ = tmp );
	cpp++;
    }
    *bpp = 0;
    AddrToString( &sv->addr, sv->addrlen, &envp[1][5] );
    (void)fcntl( dm->fd, F_SETFD, 0 );
    pid = Process( sv ,dm->fd ,args ,envp );
    (void)fcntl( dm->fd, F_SETFD, 1 );
    if ( pid > 0 ) {
	dm->refer++;
	UnIWait( dm->fd );
	PWait( pid, DGramSigChild, (arg)dm );
    }
}



DGramStartUp( dm )
  Daemon *dm;
{
  Service *sv = dm->service;

#ifdef DEBUG
    if ( Debug )
	LogMsg("DGramStartUp; %s" ,sv->name );
#endif DEBUG
    if (( dm->fd = socket( sv->af ,sv->type ,sv->pf )) < 0 ) {
	LogMsg( "DGramStartUp; %s socket: %s" ,sv->name ,syserror );
	return -1;
    }
#ifndef notdef    /* 4.2 feature fix */
    {
        struct stat stb;
        if ( sv->addr.sa_family == AF_UNIX )
        if ( stat( sv->addr.sa_data, &stb ) >= 0 )
            if (( stb.st_mode & S_IFMT ) == S_IFSOCK )
                (void)unlink( sv->addr.sa_data );
    }
#endif notdef
    (void)fcntl( dm->fd ,F_SETFD ,1 );
    if ( bind( dm->fd ,&sv->addr ,sv->addrlen ) < 0 ) {
	LogMsg( "DGramStartUp; %s bind: %s" ,sv->name ,syserror );
	(void)close( dm->fd );
	return -1;
    }
    IWait( dm->fd ,DGramReady ,(arg)dm );
    return 0;
}

DGramShutDown( dm )
  Daemon *dm;
{
#ifdef DEBUG
  Service *sv = dm->service;
    if ( Debug )
	LogMsg( "DGramShutDown; %s" ,sv->name );
#endif DEBUG
    UnIWait( dm->fd );
    (void)close( dm->fd );
    KillProcsUseing( (arg) dm );
    FreeDaemon( dm );
}

!Magic!Token!
echo x - disc.c
cat > disc.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/disc.c, Jan 19 23:46:51 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include "disc.h"

extern int DGramStartUp()  ,DGramShutDown();
extern int StreamStartUp() ,StreamShutDown();
extern int RawStartUp()    ,RawShutDown();
#ifdef AF_XNET
extern int RawXNetStartUp() ,RawXNetShutDown();
#endif AF_XNET

Disc disc[] = {
     { SOCK_DGRAM  ,DISC_WILD ,DISC_WILD ,DGramStartUp   ,DGramShutDown   }
    ,{ SOCK_STREAM ,DISC_WILD ,DISC_WILD ,StreamStartUp  ,StreamShutDown  }
#ifdef AF_XNET
    ,{ SOCK_RAW	   ,AF_XNET   ,DISC_WILD ,RawXNetStartUp ,RawXNetShutDown }
#endif AF_XNET
    ,{ SOCK_STREAM ,DISC_WILD ,DISC_WILD ,RawStartUp     ,RawShutDown     }
    ,{ 0	   ,0	      ,0	 ,0              ,0               }
};


/*
 *	lookup discipline by socket type, address family and protocal family
 */
Disc *DiscLookUp( st, af, pf )
  int st, af, pf;
{
  Disc *d;

	for ( d = disc; d->startup != 0; d++ )
		if (( d->type == DISC_WILD    || d->type == st )
		 && ( d->af == DISC_WILD || d->af == af )
		 && ( d->pf == DISC_WILD   || d->pf == pf ))
			break;
	return d;
}


!Magic!Token!
echo x - disc2.c
cat > disc2.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/disc2.c, Jan 19 23:46:54 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include "table.h"

Table TableType[] = {
    { "stream" ,SOCK_STREAM }
   ,{ "dgram"  ,SOCK_DGRAM }
   ,{ "raw"    ,SOCK_RAW  }
   ,{ 0        ,0         }
};

Table TableAF[] = {
    { "unix"   ,AF_UNIX }
   ,{ "inet"   ,AF_INET }
#ifdef AF_XNET
   ,{ "xnet"   ,AF_XNET }
#endif AF_XNET
   ,{ 0        ,0       }
};

Table TablePF[] = {
    { "unspec" ,PF_UNSPEC }
   ,{ 0        ,0         }
};
!Magic!Token!
echo x - image.c
cat > image.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/image.c, Jan 19 23:46:58 1985 */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include "image.h"

extern char *malloc();

Image *OpenImage( file )
  char *file;
{
  struct stat stb;
  int fd;
  Image *im;

    if (( fd = open( file, O_RDONLY ,0 )) < 0 )
        return 0;
    if ( fstat( fd, &stb ) < 0 )
        return 0;
    if ((im = (Image *) malloc((unsigned)(sizeof(Image)+stb.st_size))) == 0 ) {
        (void)close( fd );
        return 0;
    }
    if (( im->length = read( fd ,im->buffer ,stb.st_size )) < 0 ) {
        free( (char *) im );
        (void)close( fd );
        return 0;
    }
    (void)close( fd );
    im->buffer[ im->length ] = 0;
    im->pointer = im->buffer;
    return im;
}

CloseImage( im )
  Image *im;
{
    free( (char *) im );
}

int ImageToFeilds( im ,flds ,nfld )
  Image *im;
  char **flds;
  int nfld;
{
  int n = 0;
  char *cp = im->pointer;

    for ( ;; ) {
            while ( *cp == ' ' || *cp == '\t' )
                *cp++ = 0;

	    if ( *cp == '#' ) {
                *cp++ = 0;
                while ( *cp && *cp++ != '\n' );
		if ( n != 0 )
		    break;
		continue;
	    }

            if ( *cp == 0 ) 
                break;

            if ( *cp == '\n' ) {
		*cp++ = 0;
		if ( n != 0 )
		    break;
		continue;
	    }

	    if ( n >= nfld ) {
                *cp++ = 0;
                while ( *cp && *cp++ != '\n' );
		break;
	    }

            flds[ n++ ] = cp;

            while ( *cp != 0 && *cp != ' ' && *cp != '#' 
                 && *cp != '\t' & *cp != '\n' )
                cp++;
    }
    im->pointer = cp;
    return n;
}
!Magic!Token!
echo x - init.c
cat > init.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/init.c, Jan 19 23:47:02 1985 */
#include <stdio.h>
#include <varargs.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include "syserr.h"

extern long lseek();
extern char *strcpy();
extern char *LogDir ,*Name ,*LogFile, *ExecDir;
extern int LogFd, KeepStderr ,KeepTTy ,LogShare, NoDate, Uid, Gid;
extern int Limit;

 /*
  *	append message to log file
  */
#ifdef lint
/*VARARGS0*/
/*ARGSUSED*/
LogMsg( format )
  char *format;
#else lint
LogMsg( va_alist )
va_dcl
#endif lint
{
  va_list args;
  char	  *fmt, buf[1024]; /* blow away if line is bigger than buf */
  struct _iobuf _str;

#ifdef lint
    args = (va_list)0;
#else lint
	va_start( args );
#endif lint
	fmt = va_arg( args, char *);
	_str._flag = _IOWRT+_IOSTRG;
	_str._ptr = buf;
	_str._cnt = sizeof( buf );
	if (!NoDate) {
	      struct tm *tp;
              struct timeval tv;
              struct timezone tz;
		(void)gettimeofday( &tv, &tz );
		tp = localtime( (time_t *)&tv.tv_sec );
		fprintf( &_str ,"%02d/%02d %02d:%02d:%02d "
		    ,tp->tm_mon + 1 ,tp->tm_mday
		    ,tp->tm_hour ,tp->tm_min ,tp->tm_sec );
	}
	fprintf( &_str, "%s: ", Name );
	(void)_doprnt( fmt, args, &_str );
	va_end( args );
	*_str._ptr++ = '\n';
	if ( LogShare ) {
	    (void)flock( LogFd, LOCK_EX );
	    (void)lseek( LogFd, 0L, L_XTND );
	}
	(void)write( LogFd, buf, _str._ptr - buf );
	if ( LogShare )
	    (void)flock( LogFd, LOCK_UN );
}



/*
 *	initalization - open LogFile, create background
 */
Init() {
 int fd, topfd, pid;
 char  logpath[128];

	/*	close all but log descriptor		*/
	topfd = getdtablesize() - 1;
	Limit = topfd - 1; /* for daemon.c */
	for ( fd = topfd; fd >= 0; --fd)
		if (fd != LogFd)
			(void)close( fd );

	/*	change directory to our exec directory	*/
	if ( chdir( ExecDir ) < 0 ) {
	    LogMsg( "chdir %s; %s" ,ExecDir ,syserror );
	    exit( 10 );
	}

	/*	open LogFd as highest desc		*/
	if (!KeepStderr) {
	    if ( *LogDir )
	        (void)sprintf( logpath ,"%s/%s" ,LogDir ,LogFile );
	    else (void)strcpy( logpath, LogFile );
	    fd = open( logpath, O_WRONLY|O_APPEND );
	    if ( fd < 0 ) {
		fd = open( logpath, O_WRONLY|O_CREAT, LogShare ? 0660 : 0600 );
		if ( fd < 0 ) {
		    LogMsg( "open %s %s" ,logpath, syserror );
		    exit(3);
		}
	    }
	(void)close( LogFd );
	LogFd = fd;
	}

	fd = fcntl( LogFd ,F_DUPFD ,topfd );
	if (fd < 0) {
		LogMsg( "dup %s %s" ,KeepStderr ?"(stderr)":logpath ,syserror);
		exit(4);
	}
	(void)close( LogFd );
	LogFd = fd;

	/*	set close-on-exec flag for log desc	*/
	(void)fcntl( LogFd ,F_SETFD ,1 );

	if (!KeepTTy) {	
	/*	fork(), parent exits/child continues	*/
            pid = fork();
	    if ( pid < 0 ) {
		LogMsg( "fork failed %s" ,syserror );
		exit( 5 );
	    }
	    if ( pid != 0 ) {
		exit( 0 );
	    }
	/*	dissassociate from tty		*/
            fd = open( "/dev/tty" ,O_RDWR ,0 );
	    if ( fd >= 0 ) {
		(void)ioctl( fd ,(int)TIOCNOTTY ,(char *)0 );
		(void)close( fd );
	    }
	}
	Uid = getuid();
	Gid = getgid();
}
!Magic!Token!
echo x - libmain.c
cat > libmain.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/libmain.c, Jan 19 23:47:05 1985 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>

#ifndef lint
static char Version[] = "Netd 1.0, Copyright (c) 1985, Russell J. Yount" ;
#endif
main( argc ,argv )
  int argc;
  char **argv;
{
  struct sockaddr addr;
  int addrlen;
  char *string, *getenv();

    if (( string = getenv("ADDR")) == 0 ) {
	fprintf( stderr ,"%s: getenv ADDR\n" ,argv[0] );
	exit( 126 );
    }
    if ( StringToAddr( string, &addr, &addrlen )) {
	fprintf( stderr ,"%s: ???? ADDR=%s\n" ,argv[0] , string );
	exit( 127 );
    }
   doit( argc ,argv ,&addr ,addrlen );
   exit( 0 );
}
!Magic!Token!
echo x - main.c
cat > main.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/main.c, Jan 19 23:47:09 1985 */
#ifndef lint
static char Version[] = "Netd 1.0, Copyright (c) 1985, Russell J. Yount" ;
#endif
/*
 *	Copyright (c) 1985, Russell J. Yount, All rights reserved.
 *	Permission for distribution is granted provided no direct commercial
 *	advantage is gained and that this copyright notice and authors address
 *	appears on all copies.
 *
 *	Russell J. Yount
 *	(412) 624-3490
 *	Decision Systems Laboratory, University of Pittsburgh
 *	ry@cadre.arpa
 *	{decvax!idis,mi-cec,pitt,vax135,akgua,cmcl2,sun}!cadre!ry
 */
main( argc ,argv )
  int argc;
  char **argv;
{
  char *cp;
    while ( --argc > 0 ) {
	++argv;
	if ( argv[0][0] != '-' )
	    Usage();
	for ( cp = &argv[0][1]; *cp; cp++ ) {
	    if ( SetBOption( *cp ,1 ))
		continue;
	    if ( --argc > 0 && SetSOption( *cp ,*++argv ))
		continue;
            Usage();
        }
    }
    Init();
    LogMsg( "startup" );
    Mplx();
    LogMsg( "done main" );
    exit( 0 );
}
!Magic!Token!
echo x - mplx.c
cat > mplx.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/mplx.c, Jan 19 23:47:13 1985 */
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "syserr.h"

#ifdef DEBUG
extern int Debug;
#endif DEBUG

#define PROCESS
#define SELECT
#define ISELECT
/* #define OSELECT */
/* #define ESELECT */

typedef	int     ret;
typedef caddr_t arg;

#ifdef PROCESS
static struct {
    int pid;
    ret (*func)();
    arg argm;
}
  PSlot[ 256 ];
#endif PROCESS


#ifdef SELECT
static struct {
    struct {
        ret (*func)();
        arg argm;
    }
      inp ,out ,exc;
}
  DSel[ 20 ];

static struct {
    int inp ,out ,exc;
}
  DTest ,DReady;

int NDTest ,NDReady;
int DChange;
#endif SELECT


int CaughtSigChild ,CaughtSigTerm ,CaughtSigHup;


#ifdef ISELECT
IWait( d ,f ,a )
  int d;
  ret (*f)();
  arg  a;
{
#ifdef DEBUG
    if ( Debug )
	LogMsg( "IWait %d" ,d );
#endif DEBUG
    DTest.inp |= ( 1 << d );
    DSel[ d ].inp.func = f;
    DSel[ d ].inp.argm = a;
    DChange++;
}

UnIWait( d )
  int d;
{
#ifdef DEBUG
    if ( Debug )
	LogMsg( "IUnWait %d" ,d );
#endif DEBUG
    DTest.inp &= ~( 1 << d );
    DChange++;
}
#endif ISELECT



#ifdef OSELECT
OWait( d ,f ,a )
  int d;
  ret (*f)();
  arg  a;
{
    DTest.out |= ( 1 << d );
    DSel[ d ].out.func = f;
    DSel[ d ].out.argm = a;
    DChange++;
}

UnOWait( d )
  int d;
{
    DTest.out &= ~( 1 << d );
    DChange++;
}
#endif OSELECT



#ifdef ESELECT
EWait( d ,f ,a )
  int d;
  ret (*f)();
  arg  a;
{
    DTest.exc |= ( 1 << d );
    DSel[ d ].exc.func = f;
    DSel[ d ].exc.argm = a;
    DChange++;
}

UnEWait( d )
  int d;
{
    DTest.exc &= ~( 1 << d );
    DChange++;
}
#endif ESELECT

#ifdef PROCESS

#ifdef UNPROCESS
UnPWait( p )
  int p;
{
  int hv ,sv;

    hv = p % ( sizeof( PSlot ) / sizeof( PSlot[0] ));
    if ( PSlot[ hv ].pid != 0 ) 
        for ( sv = hv--; sv != hv; hv-- )
            if ( PSlot[ hv ].pid == 0 )
	        break;
    PSlot[ hv ].pid = 0;
}
#endif UNPROCESS

PWait( p ,f ,a )
  int p;
  ret (*f)();
  arg a;
{
  int hv ,sv;

    hv = p % ( sizeof( PSlot ) / sizeof( PSlot[0] ));
    if ( PSlot[ hv ].pid != 0 ) 
        for ( sv = hv--; sv != hv; hv-- )
            if ( PSlot[ hv ].pid == 0 )
	        break;
    PSlot[ hv ].pid = p;
    PSlot[ hv ].func = f;
    PSlot[ hv ].argm = a;
}

KillProcsUseing( a )
  arg a;
{
  int sn;
    for (sn = 0; sn < ( sizeof( PSlot ) / sizeof( PSlot[0] )); sn++)
        if ( PSlot[ sn ].pid != 0 && PSlot[ sn ].argm == a )
	    (void)kill( PSlot[ sn ].pid, SIGTERM );
}
#endif PROCESS

static SigHup() {
    CaughtSigHup++;
}

static SigChild() {
    CaughtSigChild++;
}

static SigTerm() {
    CaughtSigTerm++;
}

Mplx()
{
  int  sblk;

#ifdef SELECT
  int fd, msk;
#endif SELECT

#ifdef PROCESS
  union wait status;
  int hv ,sv ,pid;
#endif PROCESS

    (void)signal( SIGHUP, SigHup );
    (void)signal( SIGCHLD, SigChild );
    (void)signal( SIGTERM, SigTerm );
    CaughtSigHup++;
    for ( ;; ) {

	if ( CaughtSigHup ) {
	    CaughtSigHup = 0;
	    SyncSigHup();
	    continue;
	}

	if ( CaughtSigTerm ) {
#ifdef DEBUG
	    if ( Debug )
		LogMsg("mplx; caught sigterm");
#endif DEBUG
	    CaughtSigTerm = 0;
	    SyncSigTerm();
	    continue;
	}

        if ( CaughtSigChild ) {
#ifdef DEBUG
	    if ( Debug )
		LogMsg("mplx; caught sigchild");
#endif DEBUG
	    CaughtSigChild = 0;
            while ((pid = wait3( &status ,WNOHANG ,(struct rusage *)0))>0) {
#ifdef PROCESS
                hv = pid % ( sizeof( PSlot ) / sizeof( PSlot[0] ));
                if ( PSlot[ hv ].pid != pid ) 
                    for ( sv = hv--; sv != hv; hv-- )
	                if ( PSlot[ hv ].pid == pid )
			    break;
		( *PSlot[ hv ].func )( PSlot[ hv ].argm ,pid );
		PSlot[ hv ].pid = 0;
#endif PROCESS
            }
	    continue;
        }

#ifdef SELECT
	if ( DChange ) {
	    msk = DTest.inp | DTest.out | DTest.exc;
	    for ( NDTest = 0; msk; NDTest++ )
		msk >>= 1;
	    DChange = 0;
#ifdef DEBUG
	    if ( Debug )
		LogMsg( "mplx; DChanged; NDTest = %d", NDTest);
#endif DEBUG
	}
#ifdef DEBUG
        if ( Debug )
	    LogMsg( "mplx; DTest= %x,%x,%x", DTest.inp, DTest.out, DTest.exc );
#endif DEBUG
        if ( NDTest == 0 ) {
#ifdef DEBUG
	    if ( Debug )
		LogMsg("mplx; pause");
#endif DEBUG
            sigpause( 0 );
            continue;
        }

        DReady = DTest;
        NDReady = select( NDTest ,&DReady.inp ,&DReady.out ,&DReady.exc 
		,(struct timeval *)0 );
        if ( NDReady < 0 ) {
	    if ( errno == EINTR )
                continue;
	    LogMsg( "select %s" ,syserror );
	    LogMsg( "aborting...." );
	    exit( 0 );
	}
#ifdef DEBUG
	if ( Debug )
	    LogMsg( "mplx; %d selected" ,NDReady );
#endif DEBUG

	sblk = sigblock((1<<(SIGCHLD-1)) | (1<<(SIGHUP-1)) | (1<<(SIGTERM-1)));

#    ifdef ISELECT
        for ( fd = 0; DReady.inp; fd++ ,DReady.inp >>= 1 )
            if ( DReady.inp & 1 )
                ( *DSel[ fd ].inp.func )( DSel[ fd ].inp.argm ,fd );
#    endif ISELECT

#    ifdef OSELECT
        for ( fd = 0; DReady.out; fd++ ,DReady.out >>= 1 )
	    if ( DReady.out & 1 )
                ( *DSel[ fd ].out.func )( DSel[ fd ].out.argm ,fd );
#    endif OSELECT

#    ifdef ESELECT
        for ( fd = 0; DReady.exc; fd++ ,DReady.exc >>= 1 )
	    if ( DReady.exc & 1 )
                ( *DSel[ fd ].exc.func )( DSel[ fd ].exc.argm ,fd );
#    endif ESELECT
	(void)sigsetmask( sblk );
#endif SELECT
    }
}

!Magic!Token!
echo x - option.c
cat > option.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/option.c, Jan 19 23:47:16 1985 */
#ifdef lint
#	ifndef EXECDIR
#		define EXECDIR	"/usr/lib/netd"
#	endif  EXECDIR
#	ifndef LOGDIR
#		define LOGDIR	"/usr/adm"
#	endif LOGDIR
#	ifndef LOGFILE
#		define LOGFILE	"netd.log"
#	endif LOGFILE
#	ifndef CONFFILE
#		define CONFFILE "/etc/daemons"
#	endif CONFFILE
#	ifndef NAME
#		define NAME	"netd"
#	endif NAME
#endif lint

char *ExecDir = EXECDIR;
char *LogDir = LOGDIR;
char *LogFile = LOGFILE;
char *Name = NAME;
char *ConfFile = CONFFILE;
int   LogFd = 2;   /* fileno( stderr ) */
int   LogShare;
int   KeepStderr;
int   KeepTTy;
int   NoDate;

#ifdef DEBUG
int Debug; /* global */
#endif DEBUG
extern char *sprintf();

static struct {
    char flag;
    int *value;
} BOpt[] = {
    { 'e' ,&KeepStderr }
#ifdef DEBUG
   ,{ 'x' ,&Debug      }
#endif DEBUG
   ,{ 't' ,&KeepTTy    }
   ,{ 's' ,&LogShare   }
   ,{ 'n' ,&NoDate     }
   ,{  0  , 0 }
};

static struct {
    char flag;
    char **value;
    char *name;
} SOpt[] = {
    { 'd' ,&ExecDir    ,"execdir"  }
   ,{ 'm' ,&LogDir     ,"logdir"     }
   ,{ 'l' ,&LogFile    ,"logfile"    }
   ,{ 'c' ,&ConfFile   ,"conffile" }
   ,{ 'p' ,&Name       ,"logname"   }
   ,{  0  , 0 }
};

Usage() { int i; char buf[128], *cp;
    cp = buf;
    (void)sprintf( cp, "Usage: %s ", Name );
    cp += strlen( buf );
    if ( BOpt[0].flag ) {
	(void)sprintf( cp ,"[ -" );
        cp += 3;
        for ( i = 0; BOpt[i].flag; i++ )
	    *cp++ = BOpt[i].flag;
        (void)sprintf( cp ," ]" );
	cp += 2;
    }
    for (i = 0; SOpt[i].flag; i++) {
	(void)sprintf( cp, " [ -%c %s ]", SOpt[i].flag ,SOpt[i].name );
	cp = buf + strlen( buf );
    }
    *cp++ = '\n';
    (void)write( LogFd, buf, cp - buf );
    exit( 127 );
}



SetBOption( nm, va )
  char nm;
  int  va;
{
  int i;
    for (i = 0; BOpt[i].flag; i++)
        if (BOpt[i].flag == nm) {
	    *BOpt[i].value = va;
	    return 1;
	}
    return 0;
}



SetSOption( nm, va )
  char nm, *va;
{
  int i;
    for ( i = 0; SOpt[i].flag; i++ )
        if ( SOpt[i].flag == nm ) {
	    *SOpt[i].value = va;
	    return 1;
	}
    return 0;
}
!Magic!Token!
echo x - proc.c
cat > proc.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/proc.c, Jan 19 23:47:20 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include "service.h"

typedef caddr_t arg;

#ifdef DEBUG
extern int Debug;
#endif DEBUG
extern int LogFd;
extern int KeepStderr;

int Uid, Gid;	/* filled in by init() */

int Process( sv ,fd ,args ,envp )
  Service *sv;
  int     fd;
  char **args;
  char **envp;
{
  int pid, fd2;

#ifdef DEBUG
    if ( Debug )
	LogMsg("Process %s",sv->prog);
#endif DEBUG
    if (( pid = vfork()) != 0 )
        return pid;

    (void)sigsetmask( 0 );
    if ( fd != 0 ) {
	(void)close( 0 );
	(void)fcntl( fd ,F_DUPFD ,0 );
	(void)close( fd );
    }
    (void)close( 1 );
    (void)close( 2 );
    (void)dup2( 0 ,1 );
    switch ( *sv->log ) {
	case '-':	/* throw away output */
	    fd = open( "/dev/null", O_WRONLY|O_APPEND );
	    break;

	case '+':	/* append our logfile */
	    fd = LogFd;
	    (void)fcntl( LogFd ,F_SETFD ,0 );
	    if ( KeepStderr ) {
                fd2 = open( "/dev/tty" ,O_RDWR ,0 );
	        if ( fd2 >= 0 ) {
		    (void)ioctl( fd2 ,(int)TIOCNOTTY ,(char *)0 );
		    (void)close( fd2 );
	        }
	    }
	    break;
	
	default:	/* open logfile */
	    fd = open( sv->log, O_WRONLY|O_APPEND );
	    if (fd < 0 ) {
		LogMsg( "Can't open %s", sv->log );
		fd = open( "/dev/null", O_WRONLY );
	    }
	    break;
    }
    if ( fd != 2 ) {
	(void)dup2( fd ,2 );
	(void)close( fd );
    }
    if ( sv->nice ) (void)nice( sv->nice );
    if ( sv->uid != Uid ) (void)setuid( sv->uid );
    if ( sv->gid != Gid ) (void)setgid( sv->gid );
    execve( sv->prog ,args ,envp );
    LogMsg( "Child exec failed %s" ,sv->prog );
    sleep( 2 );
    _exit( 127 );
   /*NOTREACHED*/
}
!Magic!Token!
echo x - raw.c
cat > raw.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/raw.c, Jan 19 23:47:23 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/stat.h>
#include "service.h"
#include "disc.h"
#include "daemon.h"
#include "syserr.h"

typedef caddr_t arg;

#ifdef DEBUG
extern int Debug;
#endif DEBUG

int RawReady();

/*ARGSUSED*/
static RawSigChild( ar, pid )
  arg ar;
  int pid;
{
  Daemon *dm = (Daemon *) ar;

    if ( --dm->refer == 0 && ( dm->flags & D_ZOMBIE ) == D_ZOMBIE )
	FreeDaemon( dm );
    else 
	IWait( dm->fd, RawReady, (arg)dm );
}

/*ARGSUSED*/
static int RawReady( ar, fd )
  arg ar;
  int fd;
{
  Daemon *dm = (Daemon *) ar;
  Service *sv = dm->service;
  int pid;
  char tmp[64], *args[NARGS], **cpp, **bpp;
  static char *envp[] = { "DISC=dgram", "ADDR=XXXXXXXXXXXXXXXXXXXXXXXXXX", 0 };

    for ( cpp = sv->args, bpp = args; *cpp; ) {
	if (**cpp != '@') {
	    *bpp++ = *cpp++;
	    continue;
	}
	AddrToString4( &sv->addr, sv->addrlen, *bpp++ = tmp );
	cpp++;
    }
    *bpp = 0;
    AddrToString( &sv->addr, sv->addrlen, &envp[1][5] );
    (void)fcntl( dm->fd, F_SETFD, 0 );
    pid = Process( sv ,dm->fd ,args ,envp );
    (void)fcntl( dm->fd, F_SETFD, 1 );
    if ( pid > 0 ) {
	dm->refer++;
	UnIWait( dm->fd );
	PWait( pid, RawSigChild, (arg)dm );
    }
}



RawStartUp( dm )
  Daemon *dm;
{
  Service *sv = dm->service;

#ifdef DEBUG
    if ( Debug )
	LogMsg("RawStartUp; %s" ,sv->name );
#endif DEBUG
    if (( dm->fd = socket( sv->af ,sv->type ,sv->pf )) < 0 ) {
	LogMsg( "RawStartUp; %s socket: %s" ,sv->name ,syserror );
	return -1;
    }
#ifndef notdef    /* 4.2 feature fix */
    if (sv->addrlen > 2) {
        struct stat stb;
        if ( sv->addr.sa_family == AF_UNIX )
        if ( stat( sv->addr.sa_data, &stb ) >= 0 )
            if (( stb.st_mode & S_IFMT ) == S_IFSOCK )
                (void)unlink( sv->addr.sa_data );
    }
#endif notdef
    (void)fcntl( dm->fd ,F_SETFD ,1 );
    if ( sv->addrlen > 2 && bind( dm->fd ,&sv->addr ,sv->addrlen ) < 0 ) {
	LogMsg( "RawStartUp; %s bind: %s" ,sv->name ,syserror );
	(void)close( dm->fd );
	return -1;
    }
    IWait( dm->fd ,RawReady ,(arg)dm );
    return 0;
}

RawShutDown( dm )
  Daemon *dm;
{
#ifdef DEBUG
  Service *sv = dm->service;
    if ( Debug )
	LogMsg( "RawShutDown; %s" ,sv->name );
#endif DEBUG
    UnIWait( dm->fd );
    (void)close( dm->fd );
    KillProcsUseing( (arg) dm );
    FreeDaemon( dm );
}

!Magic!Token!
echo x - service.c
cat > service.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/service.c, Jan 19 23:47:27 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include "service.h"
#include "table.h"
#include "disc2.h"

extern char *malloc(), *sprintf(), *rindex();
extern char *LogDir;

Service *MakeService( flds ,nflds ,msg ) 
  char **flds;
  int  nflds;
  char *msg;
{
  Service *sv;
  struct passwd *pw;
  struct group  *gr;
  struct stat stb;
  char *bp ,*cp, *sp, *pp, *dp, tmp[256];
  int cc ,i ,j;

    if ( nflds < MINFLDS || nflds > MAXFLDS ) {
        (void)sprintf( msg, "syntax error" );
	return 0;
    }
    if (( sv = (Service *) malloc( sizeof( Service ))) == 0 ) {
        (void)sprintf( msg, "out of memory" );
        return 0;
    }
    cp = sv->strings;
    cc = sizeof( sv->strings );
    bp = flds[0];
    sv->name = cp;
    do {
	if ( cc-- <= 0 ) {
            (void)sprintf( msg, "out of string space" );
            free((char *)sv);
            return 0;
	}
    } while (*cp++ = *bp++);
    sv->log = cp;
    if ( flds[8][0] == '-' || flds[8][0] == '+' ) {
	bp = flds[8];
    } else {
	bp = dp = tmp;
	if ( flds[8][0] != '/' && *LogDir ) {
	    for (sp = LogDir; *sp ; *dp++ = *sp++);
	    *dp++ = '/';
	}
        for (sp = flds[8]; *sp ; sp++ )
	    if ( *sp == '$' )
	        for ( pp = flds[0]; *pp; *dp++ = *pp++);
	    else
		*dp++ = *sp;
        *dp++ = 0;
    }
    do {
        if ( cc-- <= 0 ) {
            (void)sprintf( msg, "out of string space" );
            free((char *)sv);
            return 0;
	}
    } while (*cp++ = *bp++);

    if (( sv->type = TableLookUp( TableType ,flds[1] )) < 0 ) {
        (void)sprintf( msg, "unsupported type %s" ,flds[1] );
        free((char *)sv);
        return 0;
    }

    if (( sv->af = TableLookUp( TableAF ,flds[2] )) < 0 ) {
        (void)sprintf( msg, "unsupported af %s" ,flds[2] );
        free((char *)sv);
        return 0;
    }

    if (( sv->pf = TableLookUp( TablePF ,flds[3] )) < 0 ) {
        (void)sprintf( msg, "unsupported pf %s" ,flds[3] );
        free((char *)sv);
        return 0;
    }

    if ( StringToAddr2( flds[4], &sv->addr, &sv->addrlen )) {
	(void)sprintf( msg, "address format error %s", flds[4] );
	free((char *)sv);
	return 0;
    }

    for ( i = 0, j = 9; j < nflds; j++, i++ ) {
        sv->args[ i ] = cp;
        bp = flds[ j ];
        do {
	    if ( cc-- <= 0 ) {
                (void)sprintf( msg, "out of string space" );
                free((char *)sv);
                return 0;
	    }
        } while (*cp++ = *bp++);
    }
    sv->args[ i ] = 0;
    sv->prog = sv->args[ 0 ];
    cp = rindex( sv->args[ 0 ] ,'/' );
    if ( cp )
	sv->args[ 0 ] = cp + 1;

    if ( sscanf( flds[7] ,"%hd" ,&sv->nice ) != 1 
      || sv->nice > 20 || sv->nice < -20 ) {
        (void)sprintf( msg, "invalid nice %s" ,flds[7] );
        free((char *)sv);
        return 0;
    }

    if ( stat( sv->prog, &stb ) < 0 ) {
	(void)sprintf( msg, "program does not exist" );
	free((char *)sv);
	return 0;
    }
    if (( stb.st_mode & S_IEXEC ) == 0 ) {
	(void)sprintf( msg, "program is not executable" );
	free((char *)sv);
	return 0;
    }

    if ( strcmp( flds[6], "-" ) == 0 )
	sv->gid = stb.st_gid;
    else if ( sscanf( flds[6], "%hd", &sv->gid ) != 1 ) {
        if (( gr = getgrnam( flds[6] )) == 0 ) {
            (void)sprintf( msg, "unknown group %s" ,flds[6] );
            free((char *)sv);
            return 0;
        }
        sv->gid = gr->gr_gid;
    }

    if ( strcmp( flds[5], "-" ) == 0 )
	sv->uid = stb.st_uid;
    else if ( sscanf( flds[5], "%hd", &sv->uid ) != 1 ) {
         if (( pw = getpwnam( flds[5] )) == 0 ) {
            (void)sprintf( msg, "unknown user %s" , flds[5] );
            free((char *)sv);
            return 0;
	}
        sv->uid = pw->pw_uid;
    }

    return sv;
}



FreeService( sv )
  Service *sv;
{
    free((char *) sv );
}
!Magic!Token!
echo x - stream.c
cat > stream.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/stream.c, Jan 19 23:47:31 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/stat.h>
#include "service.h"
#include "disc.h"
#include "daemon.h"
#include "syserr.h"

typedef caddr_t arg;

#ifdef DEBUG
extern int Debug;
#endif DEBUG

/*ARGSUSED*/
static StreamSigChild( ar, pid )
  arg ar;
  int pid;
{
  Daemon *dm = (Daemon *) ar;

#ifdef DEBUG
    if ( Debug )
	LogMsg("Stream sigchild");
#endif DEBUG
    if ( --dm->refer < 0 && ( dm->flags & D_ZOMBIE ) == D_ZOMBIE )
	FreeDaemon( dm );
	/* NOP */
}

/*ARGSUSED*/
static StreamAccept( ar, fd )
  arg ar;
  int fd;
{
  Daemon *dm = (Daemon *) ar;
  Service *sv = dm->service;
  int fd2, pid;
  struct sockaddr from;
  int fromlen = sizeof( from );
  char tmp[64], *args[NARGS], **cpp, **bpp;
  static char *envp[] = { "DISC=stream","ADDR=XXXXXXXXXXXXXXXXXXXXXXXXX", 0 };

#ifdef DEBUG
    if ( Debug )
	LogMsg("Stream accept");
#endif DEBUG
    if (( fd2 = accept( dm->fd, &from, &fromlen )) < 0 ) {
	LogMsg( "StreamAccept; %s accept %s" ,sv->name ,syserror );
	return;
    }
    for ( cpp = sv->args, bpp = args; *cpp; ) {
	if (**cpp != '@') {
	    *bpp++ = *cpp++;
	    continue;
	}
	AddrToString4( &from, fromlen, *bpp++ = tmp );
	cpp++;
    }
    *bpp = 0;
    AddrToString( &from, fromlen, &envp[1][5] );
    pid = Process( sv, fd2 ,args ,envp );
    (void)close( fd2 );
    if ( pid > 0 ) {
	dm->refer++;
	PWait( pid, StreamSigChild, (arg)dm );
    }
}



StreamStartUp( dm )
  Daemon *dm;
{
  Service *sv = dm->service;

#ifdef DEBUG
    if ( Debug )
	LogMsg("StreamStartUp; %s" ,sv->name );
#endif DEBUG
    if (( dm->fd = socket( sv->af ,sv->type ,sv->pf )) < 0 ) {
	LogMsg( "StreamStartUp; %s socket: %s" ,sv->name ,syserror );
	return -1;
    }
#ifndef notdef    /* 4.2 feature fix */
    {
        struct stat stb;
        if ( sv->addr.sa_family == AF_UNIX )
        if ( stat( sv->addr.sa_data, &stb ) >= 0 )
            if (( stb.st_mode & S_IFMT ) == S_IFSOCK )
                (void)unlink( sv->addr.sa_data );
    }
#endif notdef
    (void)fcntl( dm->fd ,F_SETFD ,1 );
    if ( bind( dm->fd ,&sv->addr ,sv->addrlen ) < 0 ) {
	LogMsg( "StreamStartUp; %s bind: %s" ,sv->name ,syserror );
	(void)close( dm->fd );
	return -1;
    }
    if ( listen( dm->fd ,SOMAXCONN ) < 0 ) {
	LogMsg( "StreamStartUp; %s listen: %s" ,sv->name ,syserror );
	(void)close( dm->fd );
	return -1;
    }
    IWait( dm->fd ,StreamAccept ,(arg)dm );
    return 0;
}

StreamShutDown( dm )
  Daemon *dm;
{
#ifdef DEBUG
  Service *sv = dm->service;
    if ( Debug )
	LogMsg( "StreamShutDown; %s" ,sv->name );
#endif DEBUG
    UnIWait( dm->fd );
    (void)close( dm->fd );
    FreeDaemon( dm );
}

!Magic!Token!
echo x - table.c
cat > table.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/table.c, Jan 19 23:47:34 1985 */
#include "table.h"

int TableLookUp( tp, nm )
  Table *tp;
  char *nm;
{
    while ( tp->name ) {
	if ( strcmp( tp->name, nm ) == 0 )
	    return tp->value;
	tp++;
    }
/*  return -1; */
    return atoi( nm );	/* permit integer use also */
}
!Magic!Token!
echo x - xnet.c
cat > xnet.c << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/xnet.c, Jan 19 23:47:38 1985 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/stat.h>
#include "service.h"
#include "disc.h"
#include "daemon.h"
#include "syserr.h"

/*VARARGS0*/
LogMsg();

#ifdef AF_XNET
typedef caddr_t arg;

#ifdef DEBUG
extern int Debug;
#endif DEBUG
int RawXNetReady();

/*ARGSUSED*/
static RawXNetSigChild( ar, pid )
  arg ar;
  int pid;
{
  Daemon *dm = (Daemon *) ar;

    if ( --dm->refer == 0 && ( dm->flags & D_ZOMBIE ) == D_ZOMBIE )
	FreeDaemon( dm );
    else 
        IWait( dm->fd, RawXNetReady, (arg)dm );
}

/*ARGSUSED*/
static int RawXNetReady( ar, fd )
  arg ar;
  int fd;
{
  Daemon *dm = (Daemon *) ar;
  Service *sv = dm->service;
  int pid;
  char tmp[64], *args[NARGS], **cpp, **bpp;
  static char *envp[] = { "DISC=rxnet", "ADDR=XXXXXXXXXXXXXXXXXXXXXXXXXX", 0 };

    for ( cpp = sv->args, bpp = args; *cpp; ) {
	if (**cpp != '@') {
	    *bpp++ = *cpp++;
	    continue;
	}
	AddrToString4( &sv->addr, sv->addrlen, *bpp++ = tmp );
	cpp++;
    }
    *bpp = 0;
    AddrToString( &sv->addr, sv->addrlen, &envp[1][5] );
    (void)fcntl( dm->fd, F_SETFD, 0 );
    pid = Process( sv ,dm->fd ,args ,envp );
    (void)fcntl( dm->fd, F_SETFD, 1 );
    if ( pid > 0 ) {
	dm->refer++;
	UnIWait( dm->fd );
	PWait( pid, RawXNetSigChild, (arg)dm );
    }
}



RawXNetStartUp( dm )
  Daemon *dm;
{
  Service *sv = dm->service;

#ifdef DEBUG
    if ( Debug )
	LogMsg("RawXNetStartUp; %s" ,sv->name );
#endif DEBUG
    if (( dm->fd = socket( sv->af ,sv->type ,sv->pf )) < 0 ) {
	LogMsg( "RawXNetStartUp; %s socket: %s" ,sv->name ,syserror );
	return -1;
    }
    (void)fcntl( dm->fd ,F_SETFD ,1 );
    IWait( dm->fd ,RawXNetReady ,(arg)dm );
    return 0;
}

RawXNetShutDown( dm )
  Daemon *dm;
{
#ifdef DEBUG
  Service *sv = dm->service;
    if ( Debug )
	LogMsg( "RawXNetShutDown; %s" ,sv->name );
#endif DEBUG
    UnIWait( dm->fd );
    (void)close( dm->fd );
    KillProcsUseing( (arg) dm );
    FreeDaemon( dm );
}
#endif AF_XNET
!Magic!Token!

ry@cadre.UUCP (02/03/85)

echo x - daemons.5l.man
cat > daemons.5l.man << '!Magic!Token!'
.TH DAEMONS 5l  "15 January 1985"
.CA 4
.SH NAME
daemons \- netd daemon data base
.SH DESCRIPTION
The
.I daemons
file contains information regarding
the known services which are handled
by the
.I netd
server.
For each service a single line should be present
with the following information:
.HP 10
official service name
.br
.ns
.HP 10
socket type
.br
.ns
.HP 10
address family
.br
.ns
.HP 10
protocol family
.br
.ns
.HP 10
address
.br
.ns
.HP 10
user
.br
.ns
.HP 10
group
.br
.ns
.HP 10
nice
.br
.ns
.HP 10
log file name
.br
.ns
.HP 10
program
.br
.ns
.HP 10
optional arguments
.br
.PP
The 
.I service name
is a unique name for the service.
.I Socket type
, 
.I address family
, and 
.I protocol family
are used when creating
socket for service.
The 
.I address
differs depending on 
.I address family
and 
.I socket type.
It can be given as a '-' when an address is not needed.
Both the 
.I user 
and 
.I group 
can be short integers or names such as found in
/etc/passwd or /etc/group or a '-' which uses translates to programs
ownership and group membership
and determine the actual 
.B uid 
and 
.B gid 
under which the program will
be executed.
.I Nice
is the integer nice ( see
.I setpriority(2)
) value at which the program will be executed.
The 
.I log file
may also be specified as a '-' for /dev/null, an '+' to append
.I
netd's
log file, or may contain a '$' which will have the service name
substituted for it.
An '@' in the optional arguments is substituted with the address to which the
socket is bound, in printable form.
.SH EXAMPLES
.PP
Here are a few lines from a sample configuration file:
.PP
.nf
.na
.ta 0.5i
# INTERNET SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
  exec    stream inet unspec *.exec       root daemon 0    -     rexecd @
  login   stream inet unspec *.login      root daemon 0    -     rlogind @
  syslog  dgram  inet unspec *.syslog     root daemon 0    $.log syslog
.fi
.ad
.SH FILES
%CONFFILE
.SH "SEE ALSO"
netd(8l), passwd(5), group(5), services(5)
.SH AUTHOR
Russell J. Yount
.SH BUGS



!Magic!Token!
echo x - netd.8l.man
cat > netd.8l.man << '!Magic!Token!'
.TH NETD 8L "8 January 1985"
.CA 4
.SH NAME
netd \- network daemon server
.SH SYNOPSIS
.B netd
[
.B \-extsn
] [
.B \-l 
.I logfile
] [
.B \-m 
.I logdir
]
.br
.B netd
[
.B \-d 
.I execdir
] [
.B \-c 
.I conffile
] [
.B \-p 
.I logname
]
.br
.SH DESCRIPTION
.I Netd
is a generic daemon server through which specific
service daemons are invoked as needed. Incoming requests for
service are intercepted by
.I netd
which creates a process and passes the appropriate parameters to
that process.
One or more
.I netd's
are started by either
.I /etc/rc
or
.I /etc/rc.local
at boot time.
.I Netd
reads a configuration file (the default is
.I /etc/deamons
) to determine the priority, process and user groups, and
logs activity of the specific service invoked.

Programs started by
.I netd
will have stdin and stdout attached to the socket and stderr attached to
the service's logfile. In its environment,
the variable
.B DISC
will be set to the services
.I netd
discipline and 
.B ADDR 
will be set to the address of the socket.
.PP
When
.I netd
receives a SIGHUP signal it rereads the configuration file
and reconfigures.
When
.I Netd
receives a SIGTERM signal it exits.
.PP
The following options are available.
.IP \-c
specify configuration file
.IP \-d
specify server directory
.IP \-e
log to 
.I stderr
.IP \-l
specify log file name
.IP \-m
specify log file directory
.IP \-n
do not date logfile entries
.IP \-p
specify program name to use in logging (default is %NAME)
.IP \-s
locking appends to logfile
.IP \-t
keep tty association
.IP \-x
turn on debugging information (option only available
when selected at compile time)
.PP
.SH FILES
.br
%CONFFILE - default configuration file
.br
%EXECDIR - default server directory
.br
%LOGDIR - default log directory
.br
%LOGFILE - default log file
.SH "SEE ALSO"
rc(4), daemons(5)
.SH AUTHOR
Russell J. Yount
.SH FEATURES
Each
.I netd
has a limit of about 18 services each due to
limits on number of open file descriptors. Only a small number
of arguments may be specified in the configuration file, to increase
this number 
.I netd
must be recompiled.
.SH BUGS
.I
Netd
may fail to reconfigure properly when SIGHUP
is receive if there are active datagram services
that ignore SIGTERM. This is a temporary problem
and is corrected by next SIGHUP received after
active datagram service exits.
!Magic!Token!
echo x - EXAMPLE.dms
cat > EXAMPLE.dms << '!Magic!Token!'
#
#	EXAMPLE NETD DAEMONS CONFIGURATION FILE
#
#
#	Format of daemons file is as follows, one per line
#
#	   NAME TYPE AF PF ADDRESS UID GID NICE LOG PROGRAM
#	where
#		NAME is a unique service name
#		TYPE is the socket type used
#		AF is the socket address family used
#		PF is the socket protocol family used or unspec
#		ADDRESS differs with AF or can left a - if unused
#		UID is the username or user-id the program will execute as
#		GID is the groupname or group-id the program will execute as
#		NICE is nice level the progam will execute at
#		LOG will be stderr of program, may be either - for /dev/null,
#		  + to append to netd's logfile or a filename, if the filename
#		  contains a $ the $ will be expanded to be the services name
#		PROGRAM is the program name and arguments, any @ argument will
#		  be expanded to be the connected address. The is a compile
#		  time limit on number of arguments.
#	
#
#
#
# INTERNET SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
  ftp     stream inet unspec *.ftp        root daemon 0    -     ftpd @
  telnet  stream inet unspec *.telnet     root daemon 0    -     telnetd @
  exec    stream inet unspec *.exec       root daemon 0    -     rexecd @
  login   stream inet unspec *.login      root daemon 0    -     rlogind @
  shell   stream inet unspec *.shell      root daemon 0    -     rshd @
  printer stream inet unspec *.printer    root daemon 0    -     lpd @
  rfile   stream inet unspec *.rfile      root daemon 0    $.log rfiled
  daytime stream inet unspec *.daytime    root daemon 0    -     daytimed
  talk    dgram  inet unspec *.talk       root daemon 0    -     talkd
  comsat  dgram  inet unspec *.biff       root daemon 0    -     comsat
  syslog  dgram  inet unspec *.syslog     root daemon 0    $.log syslog
  echo    dgram  inet unspec *.echo       root daemon 0    $.log echod
#  time    stream inet unspec *.time       root daemon 0    $.log timed
#  sink    dgram  inet unspec *.sink       root daemon 0    $.log sinkd
#
# UNIX SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
  lpd     stream unix unspec /dev/printer root daemon 0    -     lpd @
#
# PERQ SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
  xtime   raw    xnet 1792   -            root daemon 0    -     xtimed
  xftp    raw    xnet 256    -            root daemon 0    $.log xftpd
#
# DEVELOPMENT SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
#  xxxx    raw    inet unspec *.780        xxxx xxxxxx 0    -     xxxx
#  yyyy    raw    inet unspec -            yyyy yyyyyy 0    -     yyyy
#
#
!Magic!Token!
echo x - cadre.dms
cat > cadre.dms << '!Magic!Token!'
#
#	NETD CONFIGURATION FILE FOR CADRE.ARPA
#
#
# INTERNET SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
  ftp     stream inet unspec *.ftp        root daemon 0    -     ftpd @
  telnet  stream inet unspec *.telnet     root daemon 0    -     telnetd @
  exec    stream inet unspec *.exec       root daemon 0    -     rexecd @
  login   stream inet unspec *.login      root daemon 0    -     rlogind @
  shell   stream inet unspec *.shell      root daemon 0    -     rshd @
  printer stream inet unspec *.printer    root daemon 4    -     lpd @
  rfile   stream inet unspec *.rfile      root daemon 0    -     rfiled
  daytime stream inet unspec *.daytime    root daemon 0    -     daytimed
  finger  stream inet unspec *.finger     root daemon 0    -     fingerd
  talk    dgram  inet unspec *.talk       root daemon 0    -     talkd
  comsat  dgram  inet unspec *.biff       root daemon 0    -     comsat
  syslog  dgram  inet unspec *.syslog     root daemon 0    $.log syslog
  echo    dgram  inet unspec *.echo       root daemon 0    $.log echod
  sink    dgram  inet unspec *.sink       root daemon 0    $.log sinkd
  clock   dgram  inet unspec *.clock      root daemon 0    $.log clockd
#
# UNIX SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
  lpd     stream unix unspec /dev/printer root daemon 4    -     lpd @
#
# PERQ SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
  xtime   raw    xnet 1792   -            root daemon 0    -     xtimed
  xftp    raw    xnet 256    -            root daemon 0    $.log xftpd
#
!Magic!Token!
echo x - prodigal.dms
cat > prodigal.dms << '!Magic!Token!'
#
#	NETD CONFIGURATION FILE FOR PRODIGAL.ARPA
#
#
# INTERNET SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
  ftp     stream inet unspec *.ftp        root daemon 0    -     ftpd @
  telnet  stream inet unspec *.telnet     root daemon 0    -     telnetd @
  exec    stream inet unspec *.exec       root daemon 0    -     rexecd @
  login   stream inet unspec *.login      root daemon 0    -     rlogind @
  shell   stream inet unspec *.shell      root daemon 0    -     rshd @
  printer stream inet unspec *.printer    root daemon 0    -     lpd @
  rfile   stream inet unspec *.rfile      root daemon 0    -     rfiled
  daytime stream inet unspec *.daytime    root daemon 0    -     daytimed
  finger  stream inet unspec *.finger     root daemon 0    -     fingerd
  talk    dgram  inet unspec *.talk       root daemon 0    -     talkd
  comsat  dgram  inet unspec *.biff       root daemon 0    -     comsat
  syslog  dgram  inet unspec *.syslog     root daemon 0    $.log syslog
  echo    dgram  inet unspec *.echo       root daemon 0    $.log echod
  sink    dgram  inet unspec *.sink       root daemon 0    $.log sinkd
  clock   dgram  inet unspec *.clock      root daemon 0    $.log clockd
#
# UNIX SERVICES
# NAME    TYPE   AF   PF     ADDRESS      UID  GID    NICE LOG   PROGRAM
# ----    ------ ---- ------ -------      ---  ---    ---- ---   -------
  lpd     stream unix unspec /dev/printer root daemon 0    -     lpd @
#
!Magic!Token!
echo x - INSTALL.doc
cat > INSTALL.doc << '!Magic!Token!'
INSTALLATION:

Look at the Makefile, it installs 4 files:
	/usr/man/manl/netd.8l	- the manual entry for netd
	/usr/lib/libnd.a	- library used to compile servers
	/etc/netd		- the daemon program
	/etc/daemons		- the configuration for your site

also creating a directory (if it does not exist):
	/usr/lib/netd		- where server programs reside

If these paths do not agree with your tastes:
	Edit the Makefile. It has four sections to it.
	The middle section is altered by "make make" and
	the tail end is created by "make depend". It will
	create backup copies of itself when "make or depend" is used.


Type "make depend" followed by "make".

The file EXAMPLE.dms shows a typical configuration.
Copy it to a file with your site name and the extension ".dms",
editing it as appropriate.
Nroff the file netd.8l if you want for more information.

Type "make install"

You should now compile the server programs and install them
on /usr/lib/netd (or whatever you changed it to be)

REMEMBER: to terminate daemons netd will now replace!

Execute /etc/netd as root and check its logfile.

The file RC.doc has the lines that should be added to either
/etc/rc.local or /etc/rc to startup netd at boot time.

!Magic!Token!
echo x - RC.doc
cat > RC.doc << '!Magic!Token!'
if [ -f /etc/netd ]; then
	/etc/netd
fi
!Magic!Token!
echo x - README
cat > README << '!Magic!Token!'
NETD - Network Service Daemon, Version 1.0, Jan 24, 1985

Copyright (c) 1985, Russell J. Yount, All rights reserved.
Permission for distribution is granted provided no direct commercial
advantage is gained and that this copyright notice and authors address
appears on all copies.
	
	Netd is a network server, it listens at mutiple
network addresses for either datagrams or connects and then
fires up the appropriate programs attached to the socket.
Read the file INSTALL.doc for netd installation instructions.
The file SERVER.doc should shed some light on servers use/creation.

				Russ


Russell J. Yount
(412) 624-3490
Decision Systems Laboratory, University of Pittsburgh
ry@cadre.arpa
{decvax!idis,mi-cec,pitt,vax135,akgua,cmcl2,sun}!cadre!ry
!Magic!Token!
echo x - SERVER.doc
cat > SERVER.doc << '!Magic!Token!'
NETD SERVERS NOTES

Server execution by netd:
	Executed with uid/gid/nice as set in configuration file.
	Working directory is same as servers directory.
	No tty association normally, this can be altered with command options.
	Stdin and stdout is attached to socket.
	Stderr is attached to logfile which may be /dev/null.
	All other descriptors are closed.
	The programs environment contains only variables 
	"ADDR" and "DISC" as set by netd.

The library libnd.a contains a main which uses the
environment variable ADDR to get any address passed to it.
It then calls doit() passing argc,argv from main along with
a the sockets address and address length. (See libmain.c)

There may be multiple server programs executing on a connection oriented
services, but only one on a connectionless services. In either case it is
the server process itself which must terminate itself, not netd.
Connectionless services that are activated in burstes shoud likely
wait around a while before exiting to be sure their really finished.

WARNING:
	WHEN DEBUGING CONNECTIONLESS SERVICES, 
	IF YOUR SERVICE NEVER READS INCOMING DATA
	BEFORE EXITING YOU WILL GET A VERY HIGH
	LOAD AVERAGE DUE TO NETD'S REPEATED EXEC'S
	OF SERVER.


!Magic!Token!
echo x - XNET.doc
cat > XNET.doc << '!Magic!Token!'
Unfinished 10Mbs ethernet at dsl, used to talk with perq workstations.
Addresses are funny. Should finished route and bind problems.
Completely #ifdef AF_XNET so as to still compile without kernel modes.

!Magic!Token!
echo x - daemon.h
cat > daemon.h << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/daemon.h, Jan 19 23:47:41 1985 */
#define	D_ZOMBIE 01
#define	D_ACTIVE 02

typedef struct _d Daemon;
struct _d {
    Daemon  *succ, *pred;
    Service *service;
    Disc    *disc;
    int      fd;
    int      flags;
    int      refer;
};

!Magic!Token!
echo x - disc.h
cat > disc.h << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/disc.h, Jan 19 23:47:45 1985 */
#define	DISC_WILD	-1

typedef int (*Func)();

typedef struct {
	int	type;
	int	af;
	int	pf;
	Func	startup;
	Func	shutdown;
}
    Disc;


Disc *DiscLookUp();
!Magic!Token!
echo x - disc2.h
cat > disc2.h << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/disc2.h, Jan 19 23:47:49 1985 */
Table TableType[];
Table TableAF[];
Table TablePF[];
!Magic!Token!
echo x - image.h
cat > image.h << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/image.h, Jan 19 23:47:52 1985 */
typedef struct {
    int   length;
    char *pointer;
    char  buffer[1];	/* variable length */
}
    Image;

Image *OpenImage();
!Magic!Token!
echo x - service.h
cat > service.h << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/service.h, Jan 19 23:47:56 1985 */
#define	MINFLDS	10
#define	NARGS	4

#define	MAXFLDS ( MINFLDS + NARGS - 1 )

typedef struct {
    char    *name;
    int     af, pf, type;
    struct  sockaddr addr;
    int     addrlen;
    short   uid, gid, nice;
    char    *prog;
    char    *args[ NARGS ];
    char    *log;
    char    strings[ 100 ];
}
    Service;


Service *MakeService();
!Magic!Token!
echo x - syserr.h
cat > syserr.h << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/syserr.h, Jan 19 23:48:00 1985 */
extern	int	errno;
extern	char	*sys_errlist[];
extern  int	sys_nerr;

#define	syserror ((errno >= sys_nerr) ? "unknown" : sys_errlist[ errno ])
!Magic!Token!
echo x - table.h
cat > table.h << '!Magic!Token!'
/* netd 1.0, /usr/src/net.dsl/netd/table.h, Jan 19 23:48:03 1985 */
typedef struct {
    char *name;
    int value;
}
    Table;
!Magic!Token!
echo x - Makefile
cat > Makefile << '!Magic!Token!'
### BEGIN HEADER, DO NOT REMOVE THIS LINE
# netd 1.0, /usr/src/net.dsl/Makefile, Jan 19 23:47:50 1985
#
# Our Name
MAKEFILE=Makefile
#
# Where we belong
BIN=${DEST}/usr/local
ETC=${DEST}/etc
LIB=${DEST}/usr/lib
ADM=${DEST}/usr/adm
MAN=${DEST}/usr/man
#
# Owner of all installed files
OWNER=network
GROUP=daemon
#
#
# Complete list of source files, broken in two for usenet pdp-11's (>64K)
SOURCE1= ${CFILES} ${SFILES} ${YFILES} ${LFILES}
SOURCE2= ${MFILES} ${XFILES} ${DFILES} ${HFILES} ${MAKEFILE}
#
# CC and LD options
#    for debugging use
#	LDFLAGS=-g
#	CCFLAGS=-g -DDEBUG -DNAME......
#
INCLUDE=.
LDFLAGS=-s
CCFLAGS=-O \
	-DNAME='"${NAME}"' -DLOGDIR='"${LOGDIR}"' \
	-DEXECDIR='"${EXECDIR}"' -DLOGFILE='"${LOGFILE}"' \
	-DCONFFILE='"${CONFFILE}"' -DNAME='"${NAME}"'
#
# Where to tar sources
TARDEV=netd.tar
SHAR=netd.shar
MAGIC='!Magic!Token!'
#
# Package defaults
NAME=netd
CONFFILE= ${ETC}/daemons
LOGFILE=  netd.log
LOGDIR=	  ${ADM}
EXECDIR=  ${LIB}/netd
#
#
# The Section below following line is created by "make make"
### END HEADER, DO NOT REMOVE THIS LINE
CFILES= addr.c addr2.c addr3.c addr4.c conf.c daemon.c dgram.c disc.c disc2.c image.c init.c libmain.c main.c mplx.c option.c proc.c raw.c service.c stream.c table.c xnet.c
HFILES= daemon.h disc.h disc2.h image.h service.h syserr.h table.h
LFILES=
YFILES=
DFILES= INSTALL.doc RC.doc README SERVER.doc XNET.doc
MFILES= daemons.5l.man netd.8l.man
XFILES= EXAMPLE.dms cadre.dms prodigal.dms
SFILES=
OFILES= addr.o addr2.o addr3.o addr4.o conf.o daemon.o dgram.o disc.o disc2.o image.o init.o libmain.o main.o mplx.o option.o proc.o raw.o service.o stream.o table.o xnet.o
### BEGIN BODY, DO NOT REMOVE THIS LINE
#
# Everything we will need to create
ALL= netd libnd.a netd.8l daemons.5l
OBJS1=	addr.o addr2.o addr4.o conf.o daemon.o dgram.o disc.o disc2.o \
	image.o init.o main.o mplx.o option.o proc.o raw.o service.o \
	stream.o table.o xnet.o
OBJS2=	addr3.o libmain.o
#
# How to do it
all: ${ALL}

.c.o: ;	cc ${CCFLAGS} -c $*.c

# Edit manual entries to reflect installation
netd.8l: ${MFILES}
	for i in ${MFILES}; do \
	    sed	-e 's;%NAME;${NAME};' \
		-e 's;%LOGDIR;${LOGDIR};' \
		-e 's;%EXECDIR;${EXECDIR};' \
		-e 's;%LOGFILE;${LOGFILE};' \
		-e 's;%CONFFILE;${CONFFILE};' \
	       < $$i > `echo $$i | sed -e 's/\.man//g'` ; \
	done

# the daemon 
netd: ${OBJS1} ; cc ${OBJS1} ${LDFLAGS} -o netd

# the library for compiling servers
libnd.a: ${OBJS2} 
	ar cru libnd.a ${OBJS2}
	ranlib libnd.a

#
# To be tidy?
lint:
	lint ${CFILES}
	@echo ignore mutiple main

# How to install it, the `hostname.dms` file must exist by now
install: netd libnd.a netd.8l
	-mkdir ${EXECDIR}
	chown ${OWNER} ${EXECDIR}
	chgrp ${GROUP} ${EXECDIR}
	chmod 755 ${EXECDIR}
	install -o ${OWNER} -g ${GROUP} -m 644 -c `hostname`.dms ${CONFFILE}
	-install -o ${OWNER} -g ${GROUP} -m 644 -c netd.8l ${MAN}/manl/netd.8l
	-install -o ${OWNER} -g ${GROUP} -m 644 -c daemons.5l ${MAN}/manl/daemons.5l
	install -o ${OWNER} -g ${GROUP} -m 644 -c libnd.a ${LIB}/libnd.a
	install -o ${OWNER} -g ${GROUP} -m 755 -c netd ${ETC}/netd
	ranlib ${LIB}/libnd.a
	ls -gl ${LIB}/libnd.a ${ETC}/netd ${CONFFILE} \
		${MAN}/manl/daemons.5l ${MAN}/manl/netd.8l

#
# Purge from system
clobber:
	cd ${MAN}/manl; rm -f netd.8l
	cd ${ETC}; rm -f netd daemons
	cd ${LIB}; rm -f libnd.a
#
# Clean up everything
clean: ; rm -f ${OFILES} ${ALL}
#
# Clean up others
purge: ; rm -f ${TARDEV} ${SHAR}
#
# Tar all sources
tar: ${SOURCE1} ${SOURCE2}; tar cf ${TARDEV} ${SOURCE1} ${SOURCE2}
#
# Make a shar File
shar: ${SOURCE1} ${SOURCE2}
	rm -f ${SHAR}.1 ${SHAR}.2
	for i in ${SOURCE1}; do\
		echo "echo x - $$i" >> ${SHAR}.1;\
		echo "cat > $$i << ${MAGIC}" >> ${SHAR}.1;\
		cat $$i >> ${SHAR}.1;\
		echo ${MAGIC} >> ${SHAR}.1;\
	done
	for i in ${SOURCE2}; do\
		echo "echo x - $$i" >> ${SHAR}.2;\
		echo "cat > $$i << ${MAGIC}" >> ${SHAR}.2;\
		cat $$i >> ${SHAR}.2;\
		echo ${MAGIC} >> ${SHAR}.2;\
	done
	ls -l ${SHAR}.1 ${SHAR}.2
#
# Be carefull to save original
${MAKEFILE}.org: ; cp ${MAKEFILE} ${MAKEFILE}.org
#
# Create a new makefile after looking at file on current directory
make: ${MAKEFILE}.org
	sed -n -e '/^### BEGIN HEADER/,/^### END HEADER/p' \
		< ${MAKEFILE}			> ${MAKEFILE}.new
	echo CFILES= `ls [a-zA-Z]*.c`		>> ${MAKEFILE}.new
	echo HFILES= `ls [a-zA-Z]*.h`		>> ${MAKEFILE}.new
	echo LFILES= `ls [a-zA-Z]*.l`		>> ${MAKEFILE}.new
	echo YFILES= `ls [a-zA-Z]*.y`		>> ${MAKEFILE}.new
	echo DFILES= `ls README [a-zA-Z]*.doc`	>> ${MAKEFILE}.new
	echo MFILES= `ls [a-zA-Z]*.man`		>> ${MAKEFILE}.new
	echo XFILES= `ls [a-zA-Z]*.dms`		>> ${MAKEFILE}.new
	echo SFILES= `ls [a-zA-Z]*.sh`		>> ${MAKEFILE}.new
	echo OFILES= `ls [a-zA-Z]*.c | sed -e 's/\.c/.o/g'` >> ${MAKEFILE}.new
	sed -n -e '/^### BEGIN BODY/,/^### END BODY/p' \
		< ${MAKEFILE} >> ${MAKEFILE}.new
	mv $(MAKEFILE) $(MAKEFILE).bak
	mv $(MAKEFILE).new $(MAKEFILE)
	@echo remember to '"make depend"'

# Create a dependency list for makefile
depend: ${MAKEFILE}.org
	sed -n -e '1,/^### END BODY/p' < $(MAKEFILE) > $(MAKEFILE).new
	-for i in $(YACCFILES) $(LEXFILES) $(CFILES) $(FFILES) ; do \
		base=`expr $$i ':' '\(.*\).[cylf]$$'`; \
		suffix=`expr $$i ':' '.*\.\([cylf]\)$$'`;\
		if /bin/test $$suffix = l ; then\
			lex $$i;\
			mv lex.yy.c $$base.c;\
			suffix=c;\
			echo "$$base.c:	$$base.l" >> $(MAKEFILE).new;\
		elif /bin/test $$suffix = y ; then\
			yacc $(YFLAGS) $$i;\
			mv y.tab.c $$base.c;\
			suffix=c;\
			echo "$$base.c:	$$base.y" >> $(MAKEFILE).new;\
			echo "y.tab.h:	$$base.y" >> $(MAKEFILE).new;\
		fi;\
		$(CC) $(CLOCALFLAGS) -I$(INCLUDE) -E $$base.$$suffix |\
		grep '^# [0-9][0-9]* ".*"$$' > /tmp/grep$$$$;\
		sed -e 's/.*"\(.*\)"$$/\1/' -e 's/^.\///' < /tmp/grep$$$$ |\
		sort -u |\
		awk\
			"BEGIN { line=\"$$base.o: \"}\
			{\
				if(length(line \$$0)>63)\
				{\
					print line,\"\\\\\";\
					line=\"	\"\$$0\
				}\
				else\
					line=line\" \"\$$0\
			}\
			END { print line}"\
		>> $(MAKEFILE).new;\
	done;\
	rm /tmp/grep$$$$
	mv $(MAKEFILE) $(MAKEFILE).bak
	mv $(MAKEFILE).new $(MAKEFILE)
#
# The section below following line is created by "make depend"
### END BODY, DO NOT REMOVE THIS LINE
!Magic!Token!

medin@ucbvax.ARPA (Milo Medin) (02/06/85)

Uh, I think you guys should realize that we at berkeley have an inet 
daemon as well, quite similar to this stuff, but ours will be distributed
in the upcoming new 4.2 release.  So, if you intend to upgrade
to the new BSD, I'd suggest waiting for ours...


					Milo

mark@tove.UUCP (Mark Weiser) (02/08/85)

In article <4624@ucbvax.ARPA> medin@ucbvax.ARPA (Milo Medin) writes:
>Uh, I think you guys should realize that we at berkeley have an inet 
>daemon as well, quite similar to this stuff, but ours will be distributed
>in the upcoming new 4.2 release.  So, if you intend to upgrade
>to the new BSD, I'd suggest waiting for ours...
>
>
>					Milo

How about leaking some ordering information ahead of time so those of us
with incredibily long lead times to P.O. or license signature can
try to get the ball rolling?
New license needed?
Cost?

-- 
Spoken: Mark Weiser 	ARPA:	mark@maryland	Phone: +1-301-454-7817
CSNet:	mark@umcp-cs 	UUCP:	{seismo,allegra}!umcp-cs!mark
USPS: Computer Science Dept., University of Maryland, College Park, MD 20742

medin@ucbvax.ARPA (Milo Medin) (02/10/85)

> How about leaking some ordering information ahead of time so those of us
> with incredibily long lead times to P.O. or license signature can
> try to get the ball rolling?
> New license needed?
> Cost?
> 
> -- 
> Spoken: Mark Weiser 	ARPA:	mark@maryland	Phone: +1-301-454-7817
> CSNet:	mark@umcp-cs 	UUCP:	{seismo,allegra}!umcp-cs!mark
> USPS: Computer Science Dept., University of Maryland, College Park, MD 20742

Well, what can I say?  I mentioned that to prevent some waste
of people's time.  I know certain things about the release, but
I am not part of the group that is involved with the distribution.
I am sure when the time comes people will know about it.  If
you saw the paper in last summer's usenix conference about 
performance increases, thats all in there, plus a bit more.
It's well worth upgrading to in my opinion.  But as I am not
part of the distribution group, it would be inappropriate to
comment on P.O.'s or new licensing requirements.  

				Milo