[comp.protocols.appletalk] kboot v2.2 part 1 of 2

bobs@randvax.UUCP (Rober Schwartzkopf) (02/14/91)

Version 2.2 of kboot includes a new option that allows users
to force kboot daemons to reload kboxes even if they appear
to be up, and fixes a few bugs and documentation errors.  This
version no longer includes several copyrighted files I didn't
have permission to post originally.  These files are not needed
by kboot (I used them during the development process and
mistakenly included them in my original posting).  Please
delete any old copies of kboot (v2.1) and use this one.

Thank you,

Bob Schwartzkopf (bobs@rand.org)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  cmd.c icmp.c kboot.c nitlib.c
# Wrapped by bobs@chumley on Wed Feb 13 22:14:58 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'cmd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'cmd.c'\"
else
echo shar: Extracting \"'cmd.c'\" \(15515 characters\)
sed "s/^X//" >'cmd.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char	*RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/cmd.c,v 1.2 91/02/12 19:38:49 root Exp $";
X#endif lint
X
X/*
X * $Log:	cmd.c,v $
X * Revision 1.2  91/02/12  19:38:49  root
X * Removed unused commands.
X * 
X * Revision 1.1  91/01/29  17:36:59  root
X * Initial revision
X * 
X */
X
X/*
X * cmd.c - Send commands to kboxes.
X */
X
X#include <stdio.h>
X#include <syslog.h>
X#include <netdb.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/errno.h>
X#include <net/if.h>
X#include <netinet/in.h>
X#include <netinet/if_ether.h>
X#include <sys/time.h>
X#include <sys/timeb.h>
X#include "appletalk.h"
X#include "cmdidx.h"
X#include "kbox.h"
X#include "config.h"
X
Xextern struct hostent		*gethostbyaddr ();
Xextern char			*inet_ntoa ();
Xstruct kbox			*get_kbox ();
Xextern int			errno;
Xextern char			*sys_errlist[];
Xextern int			numkbox;
Xextern int			debug;
Xextern struct ether_addr	ebc;
Xextern struct ether_header	eh;
Xextern struct kbox		*kboxtab[HTSIZE];
Xextern long			atalkaddr;
Xextern unsigned char		kboxstate[STATE_LENGTH];
Xextern unsigned char		newstate[STATE_LENGTH];
Xextern char			*etcdir;
Xextern unsigned char		*zonelistp;
X
X#define HEX(i)			((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
X
X/*
X * Globals.
X */
Xint			(*recv_copyproc) () = NULL;
Xstruct ether_fastpath	fppkt;
Xstruct fp_promram	promram;
Xint			num_resp;
Xint			expected_resp;
Xint			destkbox;
Xstruct kbox		*kboxaddr[MAXKBOX];
Xstruct timeval		timeout;
X
X/*
X * Receive functions.  There should be a recv_ function for each send_
X * function.
X */
X
X/*
X * recv_who - Process who packet.  Algorithm is to look up the ethernet
X *   address in the ethers file and then add this kbox to the hash
X *   table it's not already there.  It would probably be more efficient
X *   to look up the ethernet address directly in a table hashed by ethernet
X *   address, however recv_who isn't called very often so I won't bother.
X */
Xrecv_who (p)
X
Xstruct fp_packet	*p;
X
X{
X  char		name[MAXHOSTNAME];
X  char		buf[20];
X  struct kbox	*kp;
X
X  if (ether_ntohost (name, &p->fp_shost) != 0) {
X      logerr ("recv_who: Can't find %s in ethers table\n",
X	      ether_ntoa (&p->fp_shost));
X      return;
X  }
X  if (kp = get_kbox (name)) {
X      if (!bcmp (&kp->ea, &p->fp_shost, sizeof(struct ether_addr))) {
X	  if (kp->aa == AT_Broadcast) {
X	      kp->aa = p->fp_lapsrc;
X	      kboxaddr[kp->aa] = kp;
X	      if (debug)
X	          fprintf (stderr, "recv_who: Adding kbox %s %s\n",
X			   name, ether_ntoa (&p->fp_shost));
X	      num_resp++;
X	  }
X      } else {
X	  strcpy (buf, ether_ntoa (&kp->ea));
X	  logerr ("recv_who: Mismatched ether address for %s: %s != %s\n",
X		  name, buf, ether_ntoa (&p->fp_shost));
X      }
X  } else if (debug)
X      fprintf (stderr, "recv_who: Unknown kbox %s %s\n",
X	       name, ether_ntoa (&p->fp_shost));
X}
X
X/*
X * recv_promram - Receive promram vector.  On sparc machines the
X *   fp_promram structure doesn't align properly, so copy the count
X *   field separately.
X */
Xrecv_promram (p)
X
Xstruct fp_packet	*p;
X
X{
X  bcopy (p->fp_data, &promram.fpr_count, sizeof(promram.fpr_count));
X  bcopy (&p->fp_data[sizeof(promram.fpr_count)], &promram.fpr_jtable,
X	 PROMRAMSIZE - sizeof(promram.fpr_count));
X  num_resp++;
X}
X
X/*
X * recv_getstate - Receive state vector.
X */
Xrecv_getstate (p)
X
Xstruct fp_packet	*p;
X
X{
X  bcopy (&p->fp_data[FPCOPYSIZE], kboxstate, STATE_LENGTH);
X  if (debug) {
X      fprintf (stderr, "recv_getstate: Received state...\n");
X      show_state (stderr, kboxstate);
X  }
X  num_resp++;
X}
X
X/*
X * inet_ntos - Translate ip address to hostname.
X */
Xchar *inet_ntos (addr)
X
Xunsigned char	*addr;
X
X{
X  struct in_addr	a;
X  struct hostent	*he;
X
X  bcopy (addr, &a.s_addr, 4);
X  if ((he = gethostbyaddr (&a, 4, AF_INET)) == NULL)
X      return (inet_ntoa (a));
X  else
X      return (he->h_name);
X}
X
X/*
X * show_state - Print state vector.
X */
Xshow_state (f, s)
X
XFILE		*f;
Xunsigned char	s[STATE_LENGTH];
X
X{
X  int	options;
X  int	i;
X  int	first;
X  long	l;
X  short	st;
X
X  fprintf (f, "\tAppletalk: %d.%d.%d Ethertalk: %d.%d.%d IPtalk: %d.%d.%d",
X	   s[O_ATNET], s[O_ATNET+1], s[O_NODE],
X	   s[O_ETNET], s[O_ETNET+1], s[O_ETNODE],
X	   s[O_UDPNET], s[O_UDPNET+1], s[O_UDPNODE]);
X  fprintf (f, " Bridge: %d\n", s[O_BRIDGE]);
X  fprintf (f, "\tEthernet: %s Name: \"%s\" File: \"%s\"\n",
X	   ether_ntoa (&s[O_ETHER]), &s[O_NAME], &s[O_FILE]);
X  fprintf (f, "\tConfig: \"%s\"\n", &s[O_CONFIG]);
X  fprintf (f, "\tATzone: \"%s\" ETzone: \"%s\" UDPzone: \"%s\"\n",
X	   &s[O_ATZONE], &s[O_ETZONE], &s[O_UDPZONE]);
X  fprintf (f, "\tPforce: %d Autoconfig: %s", s[O_PFORCE],
X	   (s[O_AUTOCONFIG] || s[O_AUTOCONFIG+1]) ? "yes" : "no");
X  fprintf (f, " Autoboot: %s",
X	   (s[O_AUTOBOOT] || s[O_AUTOBOOT+1]) ? "yes\n" : "no\n");
X  fprintf (f, "\tOptions: ");
X  bcopy (&s[O_OPTIONS], &options, sizeof(options));
X  if (options) {
X      for (first = 1, i = 0; i < 32; i++)
X	  if ((1 << i) & options)
X	      if (first) {
X		  first = 0;
X		  fprintf (f, "%d", i + 1);
X	      } else
X		  fprintf (f, ", %d", i+1);
X  } else
X      fprintf (f, "none");
X  bcopy (&s[O_SN], &l, sizeof (l));
X  bcopy (&s[O_TYPE], &st, sizeof (st));
X  fprintf (f, " Serial: %d Type: %d\n", l, st);
X  fprintf (f, "\tRouter: \"%s\"", inet_ntos (&s[O_IPDEFROUTER]));
X  fprintf (f, " ETip: \"%s\"", inet_ntos (&s[O_IPADDRESS]));
X  fprintf (f, " ATip: \"%s\"", inet_ntos (&s[O_ATIPADDRESS]));
X  fprintf (f, " Broadcast: \"%s\"\n", inet_ntos (&s[O_IPBROADCAST]));
X  fprintf (f, "\tSubnet: \"%s\"", inet_ntos (&s[O_IPSUBMASK]));
X  fprintf (f, " KIP: \"%s\"", inet_ntos (&s[O_IPKIPSERVER]));
X  fprintf (f, " Name: \"%s\"", inet_ntos (&s[O_NAMESERVER]));
X  fprintf (f, " File: \"%s\"\n", inet_ntos (&s[O_FILESERVER]));
X  bcopy (&s[O_LP1], &l, sizeof (l));
X  fprintf (f, "\tLocal1: 0x%x", l);
X  bcopy (&s[O_LP2], &l, sizeof (l));
X  fprintf (f, " Local2: 0x%x", l);
X  bcopy (&s[O_LP3], &l, sizeof (l));
X  fprintf (f, " Local3: 0x%x", l);
X  bcopy (&s[O_LP4], &l, sizeof (l));
X  fprintf (f, " Local4: 0x%x\n", l);
X  bcopy (&s[O_NDYNAMICS], &st, sizeof (st));
X  fprintf (f, "\tDynamics: %d", st);
X  bcopy (&s[O_NSTATICS], &st, sizeof (st));
X  fprintf (f, " Statics: %d", st);
X  bcopy (&s[O_ZONELIST], &l, sizeof (l));
X  fprintf (f, " Zonelist 0x%X\n", l);
X}
X
X/*
X * recv_gen - Generic receive routine.
X */
Xrecv_gen (p)
X
Xstruct fp_packet	*p;
X
X{
X  num_resp++;
X}
X
X/*
X * recv_pkt - Call appropriate function to deal with packet from fastpath.
X */
Xrecv_pkt (p)
X
Xstruct fp_packet	*p;
X
X{
X  char	buf[100];
X
X  if (p->fp_laptype != FP_TYPE) {
X      return;
X  }
X  if (destkbox != AT_Broadcast && p->fp_lapsrc != destkbox) {
X	/*
X	 * X_WHO responses from unconfigured fastpaths to broadcasts may come
X	 * in after we've already started talking to a real fastpath, so
X	 * just ignore all X_WHO responses with no error message.
X	 */
X      if (p->fp_scmd != X_WHO)
X	  logerr ("recv_pkt: Bogus response %d from %s\n",
X		  p->fp_scmd, ether_ntoa (&p->fp_shost));
X      return;
X  }
X  if (p->fp_cmd == FP_ACK) {
X      num_resp++;
X      return;
X  }
X  if (p->fp_cmd != FP_RESP)
X      return;
X  switch (p->fp_scmd) {
X    case X_COPYMEM :	if (recv_copyproc)
X			    (*recv_copyproc) (p);
X			break;
X
X    case X_PROMRAM :	recv_promram (p); break;
X
X    case X_WHO :	recv_who (p); break;
X
X    case X_RESET :	recv_gen ();
X			break;
X
X    default :		ether_ntohost (buf, &p->fp_shost);
X			logerr ("recv_pkt: Received %d from %s\n",
X				p->fp_scmd, buf);
X			break;
X  }
X}
X
X/*
X * Send procedures.  Those that have no parameters are macros that invoke
X * send_gen(), defined in kbox.h.
X */
X
X/*
X * send_who - Broadcast who packet.
X */
Xint send_who ()
X
X{
X  int	i;
X
X  for (i = 0; i < MAXKBOX; i++)
X      if (kboxaddr[i])
X        kboxaddr[i]->aa = AT_Broadcast;
X  nit_timeout (60, &timeout);
X  return (send_pkt (NULL, (int) FP_CMD, X_WHO, 0, 5, &timeout));
X}
X
X/*
X * send_boot - Download file to kbox.
X */
Xint send_boot (kp, zonedata, zonelen)
X
Xstruct kbox	*kp;
Xunsigned char	*zonedata;
Xint		zonelen;
X
X{
X  FILE	*f;
X  int	l;
X  int	ch;
X  int	cmd;
X  int	scmd;
X  char	fn[MAXFN];
X  int	size = 0;
X  int	lastlen;
X  int	lastaddr;
X
X  sprintf (fn, "%s/%s", etcdir, kp->bootfile);
X  if ((f = fopen (fn, "r")) == NULL) {
X      logerr ("send_boot: %s to %s - %s\n", fn, kp->name, sys_errlist[errno]);
X      return (0);
X  }
X  nit_timeout (30, &timeout);
X  while ((cmd = fgetc (f)) > 0) {
X      if (cmd != 'S') {
X	  logerr ("send_boot: Bad S record %d\n", cmd);
X	  return (-1);
X      }
X      scmd = fgetc (f);
X      if (scmd == '8') {
X	/*
X	 * With KSTAR 8.0 it is necessary to download a zonelist with
X	 * KSTAR.  The following code converts the zonelist read from
X	 * the config file written by the Fastpath Manager into
X	 * s-records and sends them to the kbox.  The address where
X	 * the zonelist is downloaded is the first even address after
X	 * the last s-record, which is the address of the last s-record
X	 * plus its length, rounded up to the nearest even address.
X	 * The first s-record describes the following data, it looks like:
X	 *
X	 *	short num_elements;
X	 *	struct {
X	 *	  short	type;
X	 *	  short length;
X	 *	} element[NUMELEMENTS];
X	 *
X	 * For a zonelist the type is 1.  The second s-record contains
X	 * the zonelist itself.  These extra s-records get sent right
X	 * before the last s-record, which seems to have scmd == 8.
X	 * Much of the information on the format of the s-records and
X	 * their location was reverse engineered from packet traces,
X	 * I don't guarantee this code to be correct, although it
X	 * works for me.
X	 */
X	  lastlen = atox (fppkt.fastpath_data, 2);
X	  lastaddr = atox (&fppkt.fastpath_data[2], 6);
X	  zonelistp = (unsigned char *) (lastaddr + lastlen - 4);
X	  if ((int) zonelistp % 2 == 1)
X	      zonelistp++;
X	  makeelemlist (fppkt.fastpath_data, zonelen);
X	  if (debug)
X	      fprintf (stderr, "send_boot: %s\n", fppkt.fastpath_data);
X	  if (send_pkt (kp, 'S', '2', strlen(fppkt.fastpath_data),
X			5, &timeout) != 1)
X	      return (0);
X	  makezonedata (fppkt.fastpath_data, zonedata, zonelen);
X	  if (debug)
X	      fprintf (stderr, "send_boot: %s\n", fppkt.fastpath_data);
X	  if (send_pkt (kp, 'S', '2', strlen(fppkt.fastpath_data),
X			5, &timeout) != 1)
X	      return (0);
X      }
X      l = 0;
X      while ((ch = fgetc (f)) > 0 && ch != '\r' && ch != '\n')
X	  fppkt.fastpath_data[l++] = ch;
X      size += l;
X      if (send_pkt (kp, cmd, scmd, l, 5, &timeout) != 1)
X	  return (0);
X  }
X  if (debug)
X      fprintf (stderr, "send_boot: Downloaded %d bytes\n", size);
X  return (1);
X}
X
X/*
X * atox - Convert ascii string of length l to hex.
X */
Xint atox (s, l)
X
Xchar	*s;
Xint	l;
X
X{
X  int	r = 0;
X  int	i;
X
X  for (i = 0; i < l; i++)
X      r = (r << 4) | ((s[i] >= '0' && s[i] <= '9') ? s[i] - '0' :
X		      (s[i] >= 'a' && s[i] <= 'f') ? s[i] - 'a' + 10 :
X		      s[i] - 'A' + 10);
X  return (r);
X}
X
X/*
X * csumsrec - Compute checksum for s-record.
X */
Xunsigned char csumsrec (s, l)
X
Xunsigned char	*s;
Xint		l;
X
X{
X  unsigned char	sum;
X  static char	buf[3];
X
X  sum = 0;
X  while (l--)
X      sum += *s++;
X  sum ^= 0xFF;
X  return (sum);
X}
X
X/*
X * makeelemlist - Make element list srecord.
X */
Xmakeelemlist (p, l)
X
Xunsigned char	*p;
Xint		l;
X
X{
X  static elemlist	el = {1, 1, 0};
X  unsigned char		buf[BUFSIZ];
X
X  el.bytes = l + 2;				/* Don't know why +2	*/
X  bcopy (&zonelistp, buf, sizeof (zonelistp));	/* First byte is length */
X  *buf = 4 + sizeof (el);			/* so overwrite it	*/
X  bcopy (&el, &buf[4], sizeof (el));
X  buf[4 + sizeof (el)] = csumsrec (buf, 4 + sizeof (el));
X  hexify (buf, p, 4 + sizeof (el) + 1);
X}
X
X/*
X * makezonedata - Make zone data srecord.
X */
Xmakezonedata (p, data, l)
X
Xunsigned char	*p;
Xunsigned char	*data;
Xint		l;
X
X{
X  unsigned char	*addr;
X  unsigned char	buf[BUFSIZ];
X
X  addr = zonelistp + sizeof (elemlist);
X  bcopy (&addr, buf, sizeof (addr));
X  *buf = 4 + l;
X  bcopy (data, &buf[4], l);
X  buf[4 + l] = csumsrec (buf, 4 + l);
X  hexify (buf, p, 4 + l + 1);
X}
X
X/*
X * hexify - Convert buffer to hex ascii characters.
X */
Xhexify (buf, p, len)
X
Xunsigned char	*buf;
Xunsigned char	*p;
Xint		len;
X
X{
X  int	i;
X
X  for (i = 0; i < len; i++) {
X      p[2 * i] = HEX (buf[i] >> 4);
X      p[2 * i + 1] = HEX (buf[i] & 0xF);
X  }
X  p[2 * len] = '\0';
X}
X
X
X/*
X * send_getstate - Get state vector.
X */
Xint send_getstate (kp)
X
Xstruct kbox	*kp;
X
X{
X  struct fp_copy	copy;
X
X  copy.fpc_from = (char *) promram.fpr_state;
X  copy.fpc_to = (char *) -1;
X  copy.fpc_count = STATE_LENGTH;
X  bcopy (&copy, fppkt.fastpath_data, FPCOPYSIZE);
X  recv_copyproc = recv_getstate;
X  nit_timeout (30, &timeout);
X  return (send_pkt (kp, (int) FP_CMD, X_COPYMEM, FPCOPYSIZE, 5, &timeout));
X}
X
X/*
X * send_putstate - Put state vector.
X */
Xint send_putstate (kp)
X
Xstruct kbox	*kp;
X
X{
X  struct fp_copy	copy;
X
X  copy.fpc_from = (char *) -1;
X  copy.fpc_to = (char *) promram.fpr_state;
X  copy.fpc_count = htons (STATE_LENGTH);
X  bcopy (&copy, fppkt.fastpath_data, FPCOPYSIZE);
X  newstate[O_NODE] = kboxstate[O_NODE];
X  bcopy (newstate, &fppkt.fastpath_data[FPCOPYSIZE], STATE_LENGTH);
X  if (debug) {
X      fprintf (stderr, "send_putstate: Sending state...\n");
X      show_state (stderr, newstate);
X  }
X  recv_copyproc = recv_gen;
X  nit_timeout (30, &timeout);
X  return (send_pkt (kp, (int) FP_CMD, X_COPYMEM,
X		    FPCOPYSIZE + STATE_LENGTH, 5, &timeout));
X}
X
X/*
X * send_gen - Generic send command.
X */
Xint send_gen (kp, scmd, retries)
X
Xstruct kbox	*kp;
Xint		scmd;
Xint		retries;
X
X{
X  nit_timeout (60, &timeout);
X  return (send_pkt (kp, (int) FP_CMD, scmd, 0, retries, &timeout));
X}
X
X/*
X * send_pkt - Send command packet (in fppkt).  Returns # of responders,
X *   or -1 on error.  If retries is 0, don't expect any response.
X */
Xint send_pkt (kp, cmd, scmd, len, retries, timeout)
X
Xstruct kbox	*kp;
Xint		cmd;
Xint		scmd;
Xint		len;
Xint		retries;
Xstruct timeval	*timeout;
X
X{
X  short			count;
X  int			h;
X  struct kbox		*p;
X  struct timeb		tstart;
X  struct timeb		tcur;
X  int			utotal;
X  int			ucur;
X
X  if (kp) {
X      if (kp->aa == AT_Broadcast) {
X	  logerr ("send_pkt: Invalid appletalk address for %s\n", kp->name);
X	  return (-1);
X      }
X      destkbox = kp->aa;
X      ether_copy (&kboxaddr[destkbox]->ea, &eh.ether_dhost);
X      if (retries == 0) {
X	  expected_resp = 0;
X	  retries = 1;
X      } else
X	  expected_resp = 1;
X  } else {
X      destkbox = AT_Broadcast;
X      ether_copy (&ebc, &eh.ether_dhost);
X      expected_resp = numkbox;
X  }
X  num_resp = 0;
X  fppkt.fastpath_lapdest = destkbox;
X  fppkt.fastpath_lapsrc = atalkaddr;
X  fppkt.fastpath_laptype = FP_TYPE;
X  fppkt.fastpath_cmd = cmd;
X  fppkt.fastpath_scmd = scmd;
X  count = htons (len + 4);
X  bcopy (&count, fppkt.fastpath_len, sizeof(count));
X  utotal = timeout->tv_sec * 1000000 + timeout->tv_usec;
X  for (count = 0; count < retries; count++) {
X      if (debug && count >= 1)
X	  fprintf (stderr, "send_pkt: Retransmitting cmd %d scmd %d\n",
X		   fppkt.fastpath_cmd, fppkt.fastpath_scmd);
X      nit_write (&eh, &fppkt, len + sizeof(struct ether_fastpath) - MAXFPPKT);
X      ftime (&tstart);
X      ucur = 0;
X      while (num_resp < expected_resp && utotal > ucur) {
X	  nit_dispatch (recv_pkt, 1, NULL, NULL, timeout);
X	  ftime (&tcur);
X	  ucur = (tcur.time - tstart.time) * 1000000 +
X		 (tcur.millitm - tstart.millitm) * 1000;
X      }
X      if (num_resp >= expected_resp)
X	  break;
X  }
X  if (num_resp != expected_resp)
X      if (destkbox == AT_Broadcast) {
X          for (h = 0; h < HTSIZE; h++)
X              for (p = kboxtab[h]; p; p = p->nxt)
X	          if (p->aa == AT_Broadcast)
X	              logerr ("send_pkt(%d,%d): No response from %s\n",
X			       cmd, scmd, p->name);
X      } else
X	  logerr ("send_pkt(%d,%d): No response from %s\n",
X		  cmd, scmd, kboxaddr[destkbox]->name);
X  return (num_resp);
X}
END_OF_FILE
if test 15515 -ne `wc -c <'cmd.c'`; then
    echo shar: \"'cmd.c'\" unpacked with wrong size!
fi
# end of 'cmd.c'
fi
if test -f 'icmp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'icmp.c'\"
else
echo shar: Extracting \"'icmp.c'\" \(3355 characters\)
sed "s/^X//" >'icmp.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char	*RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/icmp.c,v 1.1 91/01/29 17:37:23 root Exp $";
X#endif lint
X
X/*
X * $Log:	icmp.c,v $
X * Revision 1.1  91/01/29  17:37:23  root
X * Initial revision
X * 
X */
X
X#include <stdio.h>
X#include <syslog.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <sys/errno.h>
X#include <netdb.h>
X#include <net/if.h>
X#include <netinet/in_systm.h>
X#include <netinet/in.h>
X#include <netinet/ip.h>
X#include <netinet/ip_icmp.h>
X#include <netinet/if_ether.h>
X#include "kbox.h"
X#include "config.h"
X
Xextern int	errno;
Xextern char	*sys_errlist[];
Xextern int	debug;
X
X/*
X * Globals.
X */
Xstruct icmp		icmp_pkt;
Xint			icmp_sock;
Xfd_set			icmp_fds;
X
X/*
X * icmp_init - Initialize icmp stuff.
X */
Xicmp_init ()
X
X{
X  if ((icmp_sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
X      logerr ("icmp_init: %s\n", sys_errlist[errno]);
X      exit (1);
X  }
X  FD_SET (icmp_sock, &icmp_fds);
X  icmp_pkt.icmp_type = ICMP_ECHO;
X  icmp_pkt.icmp_code = 0;
X  icmp_pkt.icmp_seq = 0;
X  icmp_pkt.icmp_id = (getpid () & 0xFFFF);
X}
X
X
X/*
X * in_cksum - Compute IP checksum.
X */
Xu_short in_cksum (a, l)
X
Xu_short	*a;
Xint	l;
X
X{
X  int	sum = 0;
X
X  while (l > 1) {
X      sum += *a++;
X      l -= 2;
X  }
X  if (l == 1)
X      sum += *(u_char *) a;
X  sum += (sum >> 16);
X  return ((~sum) & 0xFFFF);
X}
X
X/*
X * icmp_ping - Ping kbox.
X */
Xint icmp_ping (kp)
X
Xstruct kbox	*kp;
X
X{
X  struct sockaddr_in	dest;
X  struct sockaddr_in	from;
X  static struct timeval	icmp_timeout = {PINGTIMEOUT, 0};
X  char			buf[BUFSIZ];
X  struct ip		*ip;
X  struct icmp		*p;
X  int			i;
X  int			r;
X  fd_set		readfds;
X
X  icmp_pkt.icmp_seq++;
X  icmp_pkt.icmp_cksum = 0;
X  icmp_pkt.icmp_cksum = in_cksum (&icmp_pkt, sizeof (icmp_pkt));
X  bzero (&dest, sizeof (dest));
X  dest.sin_family = AF_INET;
X  dest.sin_addr.s_addr = kp->ip.sin_addr.s_addr;
X  for (i = 0; i < PINGRETRIES; i++) {
X      p = NULL;
X	/*
X	 * Send ping
X	 */
X      if (debug)
X	  fprintf (stderr, "icmp_ping: Pinging %s id %d seq %d\n",
X		   inet_ntoa (dest.sin_addr), icmp_pkt.icmp_id,
X		   icmp_pkt.icmp_seq);
X      if (sendto (icmp_sock, &icmp_pkt, sizeof (icmp_pkt), 0,
X		  &dest, sizeof (dest)) != sizeof (icmp_pkt)) {
X	  logerr ("icmp_ping: sendto - %s\n", sys_errlist[errno]);
X	  exit (1);
X      }
X	/*
X	 * Wait for reply
X	 */
Xwaitreply:
X      readfds = icmp_fds;
X      r = select (icmp_sock+1, &readfds, NULL, NULL, &icmp_timeout);
X      if (r < 0) {
X	  logerr ("icmp_ping: select - %s\n", sys_errlist[errno]);
X	  exit (1);
X      } else if (r == 0)
X	  continue;
X	/*
X	 * Read reply
X	 */
X      r = sizeof (from);
X      if (recvfrom (icmp_sock, buf, BUFSIZ, 0, &from, &r) <= 0) {
X	  logerr ("icmp_ping: recvfrom - %s\n", sys_errlist[errno]);
X	  exit (1);
X      }
X	/*
X	 * Verify reply
X	 */
X      ip = (struct ip *) buf;
X      p = (struct icmp *) (buf + (ip->ip_hl << 2));
X      if (p->icmp_type == ICMP_ECHOREPLY &&
X	  p->icmp_id == icmp_pkt.icmp_id &&
X	  p->icmp_seq == icmp_pkt.icmp_seq &&
X	  from.sin_addr.s_addr == kp->ip.sin_addr.s_addr) {
X	  if (debug)
X	      fprintf (stderr, "icmp_ping: Reply from %s id %d seq %d\n",
X		       inet_ntoa (from.sin_addr), p->icmp_id, p->icmp_seq);
X	  return (1);
X      } else {
X	  if (debug)
X	      fprintf (stderr, "icmp_ping: Discarding packet from %s\n",
X		       inet_ntoa (from.sin_addr));
X	  goto waitreply;
X      }
X  }
X  return (0);
X}
END_OF_FILE
if test 3355 -ne `wc -c <'icmp.c'`; then
    echo shar: \"'icmp.c'\" unpacked with wrong size!
fi
# end of 'icmp.c'
fi
if test -f 'kboot.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'kboot.c'\"
else
echo shar: Extracting \"'kboot.c'\" \(15749 characters\)
sed "s/^X//" >'kboot.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char	*RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/kboot.c,v 1.3 91/02/13 11:47:07 root Exp $";
X#endif lint
X
X/*
X * $Log:	kboot.c,v $
X * Revision 1.3  91/02/13  11:47:07  root
X * Accept rpc requests from privileged ports only.
X * 
X * Revision 1.2  91/02/12  19:27:39  root
X * Remove -m option, add -t.
X * 
X * Revision 1.1  91/01/29  17:37:26  root
X * Initial revision
X * 
X */
X
X/*
X * kboot - Boot and configure fastpaths over an ethernet.  Depends on NIT
X *	   interface in SunOS 4.x.
X *
X * Author: Bob Schwartzkopf, The RAND Corporation.  Based on an earlier
X *	   version written by Dan Tappan at BBN that ran under SunOS 3.x.
X *
X * Comments, suggestions, patches, bug reports, etc. may be sent to
X * bobs@rand.org.
X */
X
X#include <stdio.h>
X#include <syslog.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/errno.h>
X#include <sys/termios.h>
X#include <netdb.h>
X#include <net/if.h>
X#include <netinet/in.h>
X#include <netinet/if_ether.h>
X#include <rpc/rpc.h>
X#include "appletalk.h"
X#include "cmdidx.h"
X#include "kbox.h"
X#include "config.h"
X#include "patchlevel.h"
X#include "kboot.h"
X
X#define VERSION		2
X
Xextern char			*rindex ();
Xstruct kbox			*get_kbox ();
Xextern int			errno;
Xextern char			*sys_errlist[];
Xextern struct ether_addr	myether;
X
X/*
X * Globals.
X */
Xchar			*progname;
Xstruct ether_addr	ebc = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Xstruct ether_header	eh;
Xchar			*interface = NULL;
Xlong			atalkaddr;
Xchar			*etcdir = ETCDIR;
Xint			detached = 0;
Xint			debug = 0;
Xint			watchf = 0;
Xint			downloadf = 0;
Xint			configf = 0;
Xint			liststatef = 0;
Xint			savestatef = 0;
Xint			resetf = 0;
Xint			rbootf = 0;
Xstruct kbox		*kboxtab[HTSIZE];
Xint			numkbox;
Xunsigned char		kboxstate[STATE_LENGTH];
Xunsigned char		newstate[STATE_LENGTH];
Xunsigned char		zonedata[MAXZONELIST];
Xint			zonelen;
Xint			pinginterval = PINGINTERVAL;
Xunsigned char		*zonelistp;
X
Xmain (argc, argv)
X
Xint	argc;
Xchar	**argv;
X
X{
X  int		i;
X  char		c;
X  char		*name = NULL;
X  struct kbox	*kp;
X  char		*errmsg;
X  char		*rhost;
X
X  if ((progname = rindex (argv[0], '/')) == NULL)
X      progname = *argv;
X  else
X      progname++;
X  while (--argc > 0) {
X      argv++;
X      c = (*argv)[0] == '-' ? (*argv)[1] : (*argv)[0];
X      switch (c) {
X	case 'b' :
X	  if (argc <= 1)
X	      usage ();
X	  argv++; argc--;
X	  downloadf++;
X	  name = *argv;
X	  break;
X	case 'c' :
X	  if (argc <= 1)
X	      usage ();
X	  argv++; argc--;
X	  configf++;
X	  name = *argv;
X	  break;
X	case 'd' :
X	  debug++;
X	  break;
X	case 'i' :
X	  if (argc <= 1)
X	      usage ();
X	  argv++; argc--;
X	  interface = *argv;
X	  break;
X	case 'l' :
X	  if (argc <= 1)
X	      usage ();
X	  argv++; argc--;
X	  liststatef++;
X	  name = *argv;
X	  break;
X	case 'p' :
X	  if (argc <= 1)
X	      usage ();
X	  argv++; argc--;
X	  pinginterval = atoi (*argv);
X	  break;
X	case 'r' :
X	  if (argc <= 1)
X	      usage ();
X	  argv++; argc--;
X	  resetf++;
X	  name = *argv;
X	  break;
X	case 's' :
X	  if (argc <= 1)
X	      usage ();
X	  argv++; argc--;
X	  savestatef++;
X	  name = *argv;
X	  break;
X	case 't' :
X	  if (argc <= 1)
X	      usage ();
X	  argv++; argc--;
X	  rbootf++;
X	  name = *argv;
X	  if (argc > 1 && *argv[1] != '-') {
X	      argv++; argc--;
X	      rhost = *argv;
X	  } else
X	      rhost = NULL;
X	  break;
X	case 'v' :
X	  printf ("%s version %d.%d\n", progname, VERSION, PATCHLEVEL);
X	  exit (0);
X	case 'w' :
X	  watchf++;
X	  break;
X	default :
X	  usage ();
X	  break;
X      }
X  }
X  if (rbootf) {
X      kboot_reload (name, rhost);
X      exit (0);
X  }
X  if (watchf && !debug) {		/* Detach ourselves		*/
X      detached++;
X      if (fork ())
X	  exit (0);
X      if ((i = open ("/dev/tty", O_RDONLY)) >= 0)
X	  ioctl (i, TIOCNOTTY, 0);
X      i = getdtablesize ();
X      while (--i >= 0)
X	  close (i);
X      open ("/dev/null", 0);
X      dup2 (0, 1);
X      dup2 (0, 2);
X      openlog (progname, 0, LOG_DAEMON);
X      writepid ();
X  }
X  if ((i = getaa (NULL, &atalkaddr)) != 0) {
X      errmsg = clnt_sperrno (i);
X      logerr ("getaa: %s\n", errmsg);
X      exit (1);
X  }
X  if (debug)
X      fprintf (stderr, "main: Using appletalk address %d\n", atalkaddr);
X  nit_init (interface);
X  ht_init ();
X  readcf ();
X  ether_copy (&myether, &eh.ether_shost);
X  eh.ether_type = htons (P_AppleTalk);
X  if (watchf)
X      watch ();
X  else  {
X      if (!name)
X	  usage ();
X      if (!(kp = get_kbox (name))) {
X	  logerr ("main: No such kbox %s\n", name);
X	  exit (1);
X      }
X      nit_open (0, P_AppleTalk);
X      if (downloadf)
X	  download (kp);
X      else if (configf)
X	  config (kp);
X      else if (savestatef)
X	  savestate (kp);
X      else if (resetf)
X	  reset (kp);
X      else if (liststatef)
X	  liststate (kp);
X  }
X  exit (0);
X}
X
X/*
X * reconfig - Free old kbox hash table and reread config file.
X */
Xreconfig ()
X
X{
X  if (debug)
X      fprintf (stderr, "reconfig: Reading config file\n");
X  ht_free ();
X  readcf ();
X}
X
X/*
X * ping - Ping kboxes, reload any that don't respond or any that've
X *   been flagged for reloading.
X */
Xping ()
X
X{
X  int		i;
X  struct kbox	*kp;
X
X  for (i = 0; i < HTSIZE; i++)
X      for (kp = kboxtab[i]; kp; kp = kp->nxt)
X	  if (kp->reload || !icmp_ping (kp)) {
X	      logerr ("ping: Reloading %s\n", kp->name);
X	      nit_open (0, P_AppleTalk);
X	      download (kp);
X	      kp->reload = 0;
X	      nit_close ();
X	  }
X  alarm (pinginterval);
X}
X
X/*
X * watch - Watch kboxes, rebooting if not answering pings or if someone
X *   asks us to.
X */
Xwatch ()
X
X{
X  signal (SIGHUP, reconfig);
X  signal (SIGALRM, ping);
X  icmp_init ();
X  rpc_init ();
X  alarm (pinginterval);
X  svc_run ();
X}
X
X/*
X * download - Download kstar to kbox.
X */
Xdownload (kp)
X
Xstruct kbox	*kp;
X
X{
X  int	i;
X
X  if ((i = readstate (kp, newstate, zonedata)) != STATE_LENGTH) {
X      logerr ("config: State file wrong length %d for %s\n", i, kp->name);
X      return;
X  }
X  if (send_who () < 0)
X      return;
X  if (send_reset (kp) < 0)
X      return;
X  sleep (3);			/* Give kbox time to reset	*/
X  if (send_who () < 0)
X      return;
X  if (send_promram (kp) <= 0)
X      return;
X  if (send_boot (kp, zonedata, zonelen) <= 0)
X      return;
X  if (send_getstate (kp) <= 0)
X      return;
X  newstate[O_NODE] = kboxstate[O_NODE];
X  newstate[O_ETNODE] = kboxstate[O_ETNODE];
X  strcpy (&newstate[O_NAME], kp->name);
X  strcpy (&newstate[O_FILE], kp->bootfile);
X  strcpy (&newstate[O_CONFIG], kp->conffile);
X  if (debug)
X      fprintf (stderr, "download: Setting zonelist to %X\n", zonelistp);
X  bcopy (&zonelistp, &newstate[O_ZONELIST], sizeof (zonelistp));
X  if (send_putstate (kp) <= 0)
X      return;
X  send_execute (kp);
X}
X
X/*
X * config - Config kbox.
X */
Xconfig (kp)
X
Xstruct kbox	*kp;
X
X{
X  int	i;
X
X  if ((i = readstate (kp, newstate, zonedata)) != STATE_LENGTH) {
X      logerr ("config: State file wrong length %d for %s\n", i, kp->name);
X      return;
X  }
X  if (send_who () < 0)
X      return;
X  if (send_exprom (kp) < 0)
X      return;
X  if (send_who () < 0)
X      return;
X  if (send_promram (kp) <= 0)
X      return;
X  if (send_getstate (kp) <= 0)
X      return;
X  newstate[O_NODE] = kboxstate[O_NODE];
X  newstate[O_ETNODE] = kboxstate[O_ETNODE];
X  strncpy (&newstate[O_NAME], &kboxstate[O_NAME], NAMELEN);
X  strncpy (&newstate[O_FILE], &kboxstate[O_FILE], NAMELEN);
X  strncpy (&newstate[O_CONFIG], kp->conffile, CONFIGLEN);
X  if (send_putstate (kp) <= 0)
X      return;
X  if (send_who () < 0)
X      return;
X  send_execute (kp);
X}
X
X/*
X * savestate - Read state for kbox and save to file.
X */
Xsavestate (kp)
X
Xstruct kbox	*kp;
X
X{
X  char	fn[MAXFN];
X  int	fd;
X
X  if (send_who () < 0)
X      return;
X  if (send_promram (kp) <= 0)
X      return;
X  if (send_getstate (kp) <= 0)
X      return;
X  sprintf (fn, "%s/%s.state", etcdir, kp->name);
X  if ((fd = open (fn, O_WRONLY|O_CREAT, 0644)) == -1) {
X      logerr ("savestate: %s - %s\n", fn, sys_errlist[errno]);
X      return;
X  }
X  write (fd, kboxstate, STATE_LENGTH);
X  close (fd);
X}
X
X/*
X * liststate - Read state for kbox and print.
X */
Xliststate (kp)
X
Xstruct kbox	*kp;
X
X{
X  char	fn[MAXFN];
X  int	fd;
X
X  if (send_who () < 0)
X      return;
X  if (send_promram (kp) <= 0)
X      return;
X  if (send_getstate (kp) <= 0)
X      return;
X  show_state (stdout, kboxstate);
X}
X
X/*
X * reset - Reset kbox.
X */
Xreset (kp)
X
Xstruct kbox	*kp;
X
X{
X  if (send_who () < 0)
X      return;
X  send_reset (kp);
X}
X
X/*
X * writepid - Save pid to file.
X */
Xwritepid ()
X
X{
X  char	fn[MAXFN];
X  FILE	*f;
X
X  sprintf (fn, "%s/kboot.pid", etcdir);
X  if ((f = fopen (fn, "w")) == NULL)
X      logerr ("main: Can't write pid file %s\n", fn);
X  else {
X      fprintf (f, "%d\n", getpid ());
X      fclose (f);
X  }
X}
X
X/*
X * usage - Print usage and die.
X */
Xusage ()
X
X{
X  fprintf (stderr, "Usage: %s options\n", progname);
X  exit (1);
X}
X
X/*
X * hash - Return hash index into kbox hash table.
X */
Xint hash (s)
X
Xregister char	*s;
X
X{
X  register int	h;
X
X  while (*s)
X      h = (h << 1) ^ *s++;
X  return (h % HTSIZE);
X}
X
X/*
X * ht_init - Init kbox hash table.
X */
Xht_init ()
X
X{
X  int	i;
X
X  for (i = 0; i < HTSIZE; i++)
X      kboxtab[i] = NULL;
X}
X
X/*
X * ht_free - Clear out hash table.
X */
Xht_free ()
X
X{
X  int		i;
X  struct kbox	*kp;
X  struct kbox	*nkp;
X
X  for (i = 0; i < HTSIZE; i++) {
X      for (kp = kboxtab[i]; kp; kp = nkp) {
X	  nkp = kp->nxt;
X	  free (kp);
X      }
X      kboxtab[i] = NULL;
X  }
X}
X	  
X/*
X * add_kbox - Add kbox to hash table.
X */
Xadd_kbox (name, bootfile)
X
Xchar	*name;
Xchar	*bootfile;
X
X{
X  int			h;
X  struct kbox		*kp;
X  char			*p;
X  struct hostent	*he;
X  struct ether_addr	e;
X
X  if (ether_hostton (name, &e) != 0) {
X      logerr ("add_kbox: Can't find %s in ethers file\n", name);
X      return;
X  }
X  if ((he = gethostbyname (name)) == NULL) {
X      logerr ("add_kbox: Can't find %s in host table\n", name);
X      return;
X  }
X  if ((kp = (struct kbox *) malloc (sizeof (struct kbox))) == NULL) {
X      logerr ("add_kbox: No memory for %s in table\n", name);
X      exit (1);
X  }
X  h = hash (name);
X  kp->nxt = kboxtab[h];
X  kboxtab[h] = kp;
X  kp->reload = 0;
X  strcpy (kp->name, name);
X  strcpy (kp->bootfile, bootfile);
X  kp->aa = AT_Broadcast;	/* Set to bogus value until get from kb	*/
X  ether_copy (&e, &kp->ea);
X  bcopy (he->h_addr, &kp->ip.sin_addr.s_addr, he->h_length);
X}
X
X/*
X * get_kbox - Find kbox in hash table.
X */
Xstruct kbox *get_kbox (name)
X
Xchar	*name;
X
X{
X  register struct kbox	*kp;
X
X  kp = kboxtab[hash (name)];
X  while (kp)
X      if (!strcmp (name, kp->name))
X	  return (kp);
X      else
X	  kp = kp->nxt;
X  return (NULL);
X}
X
X/*
X * readcf - Read config file.
X */
Xreadcf ()
X
X
X{
X  FILE	*f;
X  char	fn[MAXFN];
X  char	name[MAXHOSTNAME];
X  char	bootfile[MAXFN];
X
X  sprintf (fn, "%s/kbootcf", etcdir);
X  if ((f = fopen (fn, "r")) == NULL) {
X      logerr ("readcf: %s - %s\n", fn, sys_errlist[errno]);
X      exit (1);
X  }
X  while (!feof (f)) {
X      numkbox++;
X      if (fscanf (f, "%s %s\n", name, bootfile) != 2) {
X	  logerr ("readcf: Badly formatted config file '%s' line %d\n",
X		  fn, numkbox);
X	  exit (1);
X      }
X      add_kbox (name, bootfile);
X  }
X  fclose (f);
X}
X
X/*
X * readstate - Read kbox config.  Returns length.  Looks for ascii file
X *   generated by fastpath manager first, then looks for binary file
X *   made by savestate().
X */
Xint readstate (kp, state, zonedata)
X
Xstruct kbox	*kp;
Xunsigned char	*state;
Xunsigned char	*zonedata;
X
X{
X  FILE		*f;
X  int		c;
X  unsigned char	*cp;
X  int		fd;
X  int		len;
X
X  zonelen = 0;
X  sprintf (kp->conffile, "%s/%s.config", etcdir, kp->name);
X  if ((f = fopen (kp->conffile, "r")) == NULL) {
X      sprintf (kp->conffile, "%s/%s.state", etcdir, kp->name);
X      if ((fd = open (kp->conffile, O_RDONLY)) == -1) {
X	  logerr ("readstate: Can't read state file for %s\n", kp->name);
X	  return;
X      }
X      len = read (fd, state, STATE_LENGTH);
X      close (fd);
X  } else {
X      cp = state;
X      len = 0;
X      while ((c = fgetc (f)) >= 0) {
X	  if (c == '*') {
X	      while ((c = fgetc (f)) >= 0 && c != '\n' && c != '\r');
X	      continue;
X	  }
X	  while (c >= 0 && c != '\n' && c != '\r') {
X	      *cp = fromhex (c) << 4;
X	      *cp++ |= fromhex (c = fgetc (f));
X	      c = fgetc (f);
X	  }
X	  if (cp - state == STATE_LENGTH) {
X	      zonelen = readzones (f, c, zonedata);
X	      break;
X	  }
X      }
X      fclose (f);
X      len = cp - state;
X  }
X  if (zonelen == 0) {
X      zonedata[0] = 0;
X      zonedata[1] = 0;
X      zonelen = 2;
X  }
X  return (len);
X}
X
X/*
X * readzones - Read zone list from config file, c is first char.
X */
Xint readzones (f, c, zonedata)
X
XFILE		*f;
Xint		c;
Xunsigned char	*zonedata;
X
X{
X  unsigned char	*cp;
X  unsigned char	*lenp;
X  short		numzones;
X
X  cp = zonedata + 2;			/* Skip # zones		*/
X  numzones = 0;
X  while ((c = fgetc (f)) >= 0) {
X      if (c == '\r' || c == '\n')
X	  continue;
X      if (c == '*') {
X	  while ((c = fgetc (f)) >= 0 && c != '\n' && c != '\r');
X	  continue;
X      }
X      lenp = cp++;
X      while (c >= 0 && c != '\n' && c != '\r') {
X	  *cp++ = c;
X	  c = fgetc (f);
X      }
X      *lenp = (cp - lenp) - 1;
X      numzones++;
X  }
X  bcopy (&numzones, zonedata, sizeof (numzones));
X  return (cp - zonedata);
X}
X
X/*
X * fromhex - Convert char from hex to decimal.
X */
Xint fromhex (c)
X
Xchar	c;
X
X{
X  if (c >= '0' && c <= '9')
X      return (c - '0');
X  else if (c >= 'a' && c <= 'f')
X      return (c - 'a' + 10);
X  else
X      return (c - 'A' + 10);
X}
X
X/*
X * kboot_rpcsvr - Handle rpc requests.
X */
Xkboot_rpcsvr (request, xprt)
X
Xstruct svc_req	*request;
XSVCXPRT		*xprt;
X
X{
X  struct sockaddr_in	*sa;
X  char			*kbox;
X  int			r;
X  struct kbox		*kp;
X
X  sa = svc_getcaller (xprt);
X  if (debug)
X      fprintf (stderr, "kboot_rpcsvr: Request %d from %s\n",
X	       request->rq_proc, inet_ntoa (sa->sin_addr));
X  if (sa->sin_port >= IPPORT_RESERVED) {
X      logerr ("kboot_rpcsvr: Bad port %d from %s\n",
X	      sa->sin_port, inet_ntoa (sa->sin_addr));
X      r = -1;
X      if (!svc_sendreply (xprt, xdr_int, (caddr_t) &r))
X	  logerr ("kboot_rpcsvr: svc_sendreply failed\n");
X      return;
X  }
X  switch (request->rq_proc) {
X    case NULLPROC:
X      if (!svc_sendreply (xprt, xdr_void, 0))
X	  logerr ("kboot_rpcsvr(NULLPROC): svc_sendreply failed\n");
X      break;
X
X    case KBOOTPROC_RELOAD:
X      kbox = NULL;
X      if (svc_getargs (xprt, xdr_wrapstring, &kbox)) {
X	  if (!(kp = get_kbox (kbox))) {
X	      logerr ("kboot_rpcsvr: No such kbox %s\n", kbox);
X	      r = -1;
X	  } else
X	      r = 0;
X      } else {
X	  logerr ("kboot_rpcsvr(RELOAD): svc_getargs failed\n");
X	  r = -1;
X      }
X      if (!svc_sendreply (xprt, xdr_int, (caddr_t) &r))
X	  logerr ("kboot_rpcsvr(RELOAD): svc_sendreply failed\n");
X      if (r >= 0) {
X	  kp->reload++;
X	  alarm (1);
X	  if (debug)
X	      fprintf (stderr, "kboot_rpcsvr: Requesting load of %s\n", kbox);
X      }
X      xdr_free (xdr_wrapstring, &kbox);
X      break;
X
X    default:
X      svcerr_noproc (xprt);
X      break;
X  }
X}
X
X/*
X * Initialize RPC stuff.
X */
Xrpc_init ()
X
X{
X  SVCXPRT	*xprt;
X
X  if ((xprt = svcudp_create (RPC_ANYSOCK)) == NULL) {
X      logerr ("rpc_init: svcudp_create failed\n");
X      exit (1);
X  }
X  pmap_unset (KBOOTPROG, KBOOTVERS);
X  if (!svc_register (xprt, KBOOTPROG, KBOOTVERS, kboot_rpcsvr, IPPROTO_UDP)) {
X      logerr ("rpc_init: Can't register %d %d\n", KBOOTPROG, KBOOTVERS);
X      exit (1);
X  }
X}
X
X/*
X * kboot_reload - Ask kboot on rhost to reload kbox.
X */
Xkboot_reload (kbox, rhost)
X
Xchar	*kbox;
Xchar	*rhost;
X
X{
X  int	s;
X  int	r;
X
X  if (rhost == NULL)
X      rhost = "localhost";
X  if (debug)
X      fprintf (stderr, "kboot_reload: Requesting reboot of %s on %s\n",
X	       kbox, rhost);
X/*
X * kboot will only accept rpc requests from privileged ports. callrpc
X * will use a privileged port by default if it can (we're root).
X */
X  if ((s = callrpc (rhost, KBOOTPROG, KBOOTVERS, KBOOTPROC_RELOAD,
X		    xdr_wrapstring, &kbox, xdr_int, &r)) != 0) {
X      clnt_perrno (s);
X      exit (1);
X  }
X  printf ("%s reload request %s\n", kbox, r == 0 ? "accepted" : "failed");
X}
END_OF_FILE
if test 15749 -ne `wc -c <'kboot.c'`; then
    echo shar: \"'kboot.c'\" unpacked with wrong size!
fi
# end of 'kboot.c'
fi
if test -f 'nitlib.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'nitlib.c'\"
else
echo shar: Extracting \"'nitlib.c'\" \(6314 characters\)
sed "s/^X//" >'nitlib.c' <<'END_OF_FILE'
X#ifndef lint
Xstatic char	*RCSid="$Header: /tmp_mnt/home/src/rand/etc/kboot/RCS/nitlib.c,v 1.2 91/02/12 19:38:10 root Exp $";
X#endif lint
X
X/*
X * $Log:	nitlib.c,v $
X * Revision 1.2  91/02/12  19:38:10  root
X * Don't call fdfunc() if NULL.
X * 
X * Revision 1.1  91/01/29  17:37:28  root
X * Initial revision
X * 
X */
X
X#include <stdio.h>
X#include <syslog.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <sys/file.h>
X#include <sys/signal.h>
X#include <netdb.h>
X#include <net/if.h>
X#include <sys/ioctl.h>
X#include <sys/stropts.h>
X#include <net/nit_if.h>
X#include <net/nit_pf.h>
X#include <netinet/in.h>
X#include <netinet/in_systm.h>
X#include <netinet/if_ether.h>
X#include <net/packetfilt.h>
X#include "config.h"
X
X#define MAXPKT		1500
X#define OFFSET(t,f)	((int) &(((t *) NULL)->f))
X
Xextern char	*malloc ();
Xextern char	*strdup ();
X
Xextern int	debug;
Xextern int	detached;
Xextern int	errno;
Xextern char	*sys_errlist[];
X
X/*
X * Globals.
X */
Xstruct ether_addr	myether;
Xint			nit_fd;
Xchar			nitbuf[MAXPKT];
Xint			numfds;
Xchar			*interface;
X
X/*
X * nit_init - Initialize nit library.
X */
Xnit_init (dev)
X
Xchar	*dev;
X
X{
X  struct ifconf		ifc;
X  int			s;
X  char			buf[BUFSIZ];
X
X  numfds = getdtablesize ();
X  if (dev == NULL) {
X      if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
X            logerr ("nit_init: socket - %s\n", sys_errlist[errno]);
X            exit(1);
X      }
X      ifc.ifc_len = BUFSIZ;
X      ifc.ifc_buf = buf;
X      if (ioctl (s, SIOCGIFCONF, (caddr_t) &ifc) < 0) {
X          logerr ("nit_init: ioctl(SIOCGIFCONF) - %s\n", sys_errlist[errno]);
X          exit(1);
X      }
X      close(s);
X      interface = strdup (ifc.ifc_req->ifr_name);
X  } else
X      interface = dev;
X  if (debug)
X      fprintf (stderr, "nit_init: Using interface %s\n", interface);
X}
X
X/*
X * nit_open - Open NIT device and bind to an interface.
X *   Prints an error and exits if there's a problem.
X */
Xnit_open (snaplen, pkttype)
X
Xint	snaplen;
Xint	pkttype;
X
X{
X  int			s;
X  struct packetfilt	pf;
X  u_short		*pfp;
X  struct ifreq		ifr;
X
X  if ((nit_fd = open ("/dev/nit", O_RDWR)) < 0) {	/* Open NIT dev	*/
X      logerr ("nit_open: open(/dev/nit) - %s\n", sys_errlist[errno]);
X      exit (1);
X  }
X  if (ioctl (nit_fd, I_SRDOPT, (caddr_t) RMSGD) < 0) {	/* Discrete msgs*/
X      logerr ("nit_open: ioctl(I_SRDOPT) - %s\n", sys_errlist[errno]);
X      exit (1);
X  }
X  if (pkttype) {
X      if (ioctl (nit_fd, I_PUSH, "pf") < 0) {	/* Setup packet filter	*/
X          logerr ("nit_open: ioctl(I_PUSH: pf) - %s\n", sys_errlist[errno]);
X          exit (1);
X      }
X      pfp = pf.Pf_Filter;
X      *pfp++ = ENF_PUSHWORD +
X	OFFSET (struct ether_header, ether_type) / sizeof (u_short);
X      *pfp++ = ENF_PUSHLIT | ENF_EQ;
X      *pfp++ = htons (pkttype);
X      pf.Pf_FilterLen = ((int) pfp - (int) pf.Pf_Filter) / sizeof (u_short);
X      if (ioctl (nit_fd, NIOCSETF, (caddr_t) &pf) < 0) {
X          logerr ("nit_open: ioctl(NIOCSETF) - %s\n", sys_errlist[errno]);
X          exit (1);
X      }
X  }
X  strncpy (ifr.ifr_name, interface, sizeof ifr.ifr_name);
X  ifr.ifr_name[sizeof ifr.ifr_name - 1] = '\0';
X  if (ioctl (nit_fd, NIOCBIND, &ifr) < 0) {
X      logerr ("nit_open: ioctl(NIOCBIND) - %s\n", sys_errlist[errno]);
X      exit(1);
X  }
X						/* Get ethernet address	*/
X  if (ioctl (nit_fd, SIOCGIFADDR, (caddr_t) &ifr) < 0) {
X      logerr ("nit_open: ioctl(SIOCGIFADDR) - %s\n", sys_errlist[errno]);
X      exit (1);
X  }
X  ether_copy (ifr.ifr_addr.sa_data, &myether);
X  if (snaplen > 0) {                            /* Set snapshot length  */
X      if (ioctl (nit_fd, NIOCSSNAP, (caddr_t) &snaplen) < 0) {
X          logerr ("nit_open: ioctl (NIOCSSNAP) - %s\n", sys_errlist[errno]);
X          exit (1);
X      }
X  }
X}
X
X/*
X * nit_close - Close nit file descriptor.
X */
Xnit_close ()
X
X{
X  close (nit_fd);
X}
X
X/*
X * timeout - Return timeval structure for timeout specified in ticks for
X *   reads from nit device.  Ticks are 1/60 of a second.  A timeout of 0
X *   means reads will not timeout.
X */
Xnit_timeout (ticks, tv)
X
Xint		ticks;
Xstruct timeval	*tv;
X
X{
X  tv->tv_sec = ticks / 60;			/* Set timeout		*/
X  tv->tv_usec = ((ticks * 1000000) / 60) % 1000000;
X}
X
X/*
X * nit_write - Send a raw ethernet packet.
X */
Xnit_write (eh, pkt, len)
X
Xstruct ether_header	*eh;
Xcaddr_t			pkt;
Xint			len;
X
X{
X  struct sockaddr	sa;
X  struct strbuf		cbuf;
X  struct strbuf		dbuf;
X
X  sa.sa_family = AF_UNSPEC;
X  bcopy (eh, sa.sa_data, sizeof (*eh));
X  cbuf.len = sizeof sa;
X  cbuf.buf = (caddr_t) &sa;
X  dbuf.len = len;
X  dbuf.buf = pkt;
X  if (putmsg (nit_fd, &cbuf, &dbuf, 0) < 0) {
X      logerr ("nit_write: putmsg - %s\n", sys_errlist[errno]);
X      exit (1);
X  }
X}
X
X/*
X * nit_dispatch - Read and process n packets.  If n is 0 read forever.
X *   Calls "func" for each packet with the arguments:
X *
X *	(*func) (pp, pl)
X *	  pp = packet pointer
X *	  pl = length of packet
X *
X *   If an application is waiting for input on other file descriptors
X *   they can be specified in "fds".  "fdfunc" will be called with
X *   the set of descriptors that have input waiting before the current
X *   packet is processed.  Returns 0 on timeout, 1 otherwise.
X */
Xint nit_dispatch (func, n, fds, fdfunc, timeout)
X
Xint		(*func)();
Xint		n;
Xfd_set		*fds;
Xint		(*fdfunc)();
Xstruct timeval	*timeout;
X
X{
X  int		i;
X  int		numpkts;
X  fd_set	fdset;
X  fd_set	rfds;
X
X  numpkts = 0;
X  if (fds)
X      fdset = *fds;
X  else
X      FD_ZERO (&fdset);
X  FD_SET (nit_fd, &fdset);
X  while (n == 0 || numpkts < n) {
X      rfds = fdset;
X      i = select (numfds, &rfds, NULL, NULL, timeout);
X      if (i == 0)
X	  return (0);			/* Timeout			*/
X      if (FD_ISSET (nit_fd, &rfds)) {
X	  numpkts++;
X	  FD_CLR (nit_fd, &rfds);
X	  if (i > 1)
X	      (*fdfunc) (&rfds);
X      } else if (fdfunc) {
X	  (*fdfunc) (&rfds);
X	  continue;
X      }
X      if ((i = read (nit_fd, nitbuf, MAXPKT)) < 0) {
X          lseek (nit_fd, 0, 0);		/* File pointer may've wrapped	*/
X          if ((i = read (nit_fd, nitbuf, MAXPKT)) < 0) {
X	      logerr ("nit_dispatch: read - %s\n", sys_errlist[errno]);
X	      exit (1);
X          }
X      }
X      (*func) (nitbuf, i);
X  }
X  return (1);
X}
X
X/*
X * logerr - Log error to stderr (if debug) or syslog.
X */
Xlogerr (fmt, a1, a2, a3)
X
Xchar	*fmt;
Xchar	*a1;
Xchar	*a2;
Xchar	*a3;
X
X{
X  if (detached)
X      syslog (LOG_ERR, fmt, a1, a2, a3);
X  else
X      fprintf (stderr, fmt, a1, a2, a3);
X}
END_OF_FILE
if test 6314 -ne `wc -c <'nitlib.c'`; then
    echo shar: \"'nitlib.c'\" unpacked with wrong size!
fi
# end of 'nitlib.c'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0