[comp.sources.unix] v21i096: An Automounter for NFS systems, Part08/13

rsalz@uunet.uu.net (Rich Salz) (04/11/90)

Submitted-by: Jan-Simon Pendry <jsp@doc.ic.ac.uk>
Posting-number: Volume 21, Issue 96
Archive-name: amd/part08

#! /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 8 (of 13)."
# Contents:  examples/amd.homes mtab.c opts.c srvr_nfs.c
# Wrapped by rsalz@papaya.bbn.com on Tue Apr 10 15:12:09 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'examples/amd.homes' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'examples/amd.homes'\"
else
echo shar: Extracting \"'examples/amd.homes'\" \(12180 characters\)
sed "s/^X//" >'examples/amd.homes' <<'END_OF_FILE'
X# /homes
Xzmacy26	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/zmacy26 \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xkevin	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/kpt \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xgrace	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/grace \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xaudit	type=link;fs=/etc/security/audit
Xygal	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/ygal \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xacwf	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/acwf \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xrgc	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/rgc \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xlsh	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/lsh \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xjsp	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=jsp \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xjpr	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/jpr \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xjjc	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/jjc \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xids	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/ids \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xmb	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/mb \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xdaemon	type=link;fs=/
Xteb	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=teb \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xshc	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=shc \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xmwg	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=mwg \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xmrs	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=mrs \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xjfc	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/jfc \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xdme	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=dme \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xccm	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/ccm \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xpt	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=dov/pt \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xds	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/ds \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xdg	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=dov/dg \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xwmvh	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=wmvh \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xroot	type=link;fs=/
Xlmjm	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/lmjm \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xsjk	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/sjk \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xmdr	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=mdr \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xkdr	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=kdr \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xbrg	-opts=rw,grpid,nosuid;rfs=/home/gummo;sublink=users/brg \
X	host=!gummo;type=nfs;rhost=gummo \
X	host=gummo;type=ufs;dev=/dev/xy0g
Xadh	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=adh \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xjs	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/js \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xca	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=diadem/ca \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xbh	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/bh \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xnobody	type=link;fs=/
Xingres	type=link;fs=/usr/ingres
Xtsem	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/tsem \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xpm2	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=pm2 \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xsm	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/sm \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xpm	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=pm \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xmd	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=md \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xjg	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/jg \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xphjk	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/phjk \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xiccp	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/iccp \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xsza	-opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=sza \
X	host=!ganymede;type=nfs;rhost=ganymede \
X	host=ganymede;type=ufs;dev=/dev/xy0h
Xclh	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/clh \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xnd	-opts=rw,grpid,nosuid;rfs=/home/gummo;sublink=users/nd \
X	host=!gummo;type=nfs;rhost=gummo \
X	host=gummo;type=ufs;dev=/dev/xy0g
Xmg	-opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=mg \
X	host=!ganymede;type=nfs;rhost=ganymede \
X	host=ganymede;type=ufs;dev=/dev/xy0h
Xbp	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/bp \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xsync	type=link;fs=/
Xnews	type=link;fs=/var/spool/news
Xshb	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/shb \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xrjq	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=rjq \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xfst	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=fst \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xeaa	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=dov/eaa \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xsw	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/sw \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xhf	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/hf \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xlkcl	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=lkcl \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xchlo	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/chlo \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xesh	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/esh \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xtm	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/tm \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xok	-opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=ok \
X	host=!ganymede;type=nfs;rhost=ganymede \
X	host=ganymede;type=ufs;dev=/dev/xy0h
Xja	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/ja \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xdp	-opts=rw,grpid,nosuid;rfs=/home/gummo;sublink=usersdiana \
X	host=!gummo;type=nfs;rhost=gummo \
X	host=gummo;type=ufs;dev=/dev/xy0g
Xzmact03	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/zmact03 \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xuucp	type=link;fs=/var/spool/uucppublic
Xsme	-opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=sme \
X	host=!ganymede;type=nfs;rhost=ganymede \
X	host=ganymede;type=ufs;dev=/dev/xy0h
Xrjc	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/rjc \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xpdg	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/pdg \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xdgb	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=dgb \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xdds	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/dds \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xih	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/ih \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xumacd20	-opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=umacd20 \
X	host=!ganymede;type=nfs;rhost=ganymede \
X	host=ganymede;type=ufs;dev=/dev/xy0h
Xsysdiag	type=link;fs=/usr/diag/sysdiag
Xgames	type=link;fs=/usr/games
Xsjv	-opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=sjv \
X	host=!ganymede;type=nfs;rhost=ganymede \
X	host=ganymede;type=ufs;dev=/dev/xy0h
Xll1	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/ll1 \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xksa	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/ksa \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xjvp	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/jvp \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xbin	type=link;fs=/bin
Xsa	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/sa \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xbt	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=samson/bt \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xwrdo	-opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=wrdo \
X	host=!ganymede;type=nfs;rhost=ganymede \
X	host=ganymede;type=ufs;dev=/dev/xy0h
Xthp	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=thp \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xsys	type=link;fs=/
Xssp	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/ssp \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xsph	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=ai/sph \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xpah	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=jim/pah \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xnjw	-opts=rw,grpid,nosuid;rfs=/home/dylan/dk2;sublink=njw \
X	host=!dylan;type=nfs;rhost=dylan \
X	host=dylan;type=ufs;dev=/dev/dsk/2s0
Xmwt	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=mwt \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xmjh	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/mjh \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xkpt	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/kpt \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xfcs	-opts=rw,grpid,nosuid;rfs=/home/ganymede;sublink=fcs \
X	host=!ganymede;type=nfs;rhost=ganymede \
X	host=ganymede;type=ufs;dev=/dev/xy0h
Xdwj	-opts=rw,grpid,nosuid;rfs=/home/achilles;sublink=dwj \
X	host=!achilles;type=nfs;rhost=achilles \
X	host=achilles;type=ufs;dev=/dev/xd0g
Xhd	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=others/hd \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
Xcw	-opts=rw,grpid,nosuid;rfs=/home/toytown;sublink=genesis/cw \
X	host=!toytown;type=nfs;rhost=toytown \
X	host=toytown;type=ufs;dev=/dev/xy1g
END_OF_FILE
if test 12180 -ne `wc -c <'examples/amd.homes'`; then
    echo shar: \"'examples/amd.homes'\" unpacked with wrong size!
fi
# end of 'examples/amd.homes'
fi
if test -f 'mtab.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mtab.c'\"
else
echo shar: Extracting \"'mtab.c'\" \(12010 characters\)
sed "s/^X//" >'mtab.c' <<'END_OF_FILE'
X/*
X * $Id: mtab.c,v 5.1.1.3 90/01/11 17:11:26 jsp Exp Locker: jsp $
X *
X * Copyright (c) 1989 Jan-Simon Pendry
X * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
X * Copyright (c) 1989 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry at Imperial College, London.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Imperial College of Science, Technology and Medicine, London, UK.
X * The names of the College and University may not be used to endorse
X * or promote products derived from this software without specific
X * prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	%W% (Berkeley) %G%
X */
X
X#include "am.h"
X
X/*
X * Firewall /etc/mtab entries
X */
X#define	MTAB_STRIPNL
X
X/*
X * Do strict /etc/mtab locking
X */
X#define MTAB_LOCKING
X
X#ifdef READ_MTAB_FROM_FILE
X#ifdef USE_FCNTL
X#include <fcntl.h>
X#else
X#include <sys/file.h>
X#endif
X#endif
X
X#ifdef READ_MTAB_ULTRIX_STYLE
X#include <sys/mount.h>
X#include <sys/fs_types.h>
X#endif
X
X#ifdef READ_MTAB_BSD_STYLE
X#include <sys/mount.h>
X#endif
X
X#ifdef UPDATE_MTAB
X#include <sys/stat.h>
Xstatic FILE *mnt_file;
X
X/*
X * If the system is being trashed by something, then
X * opening mtab may fail with ENFILE.  So, go to sleep
X * for a second and try again. (Yes - this has happened to me.)
X *
X * Note that this *may* block the automounter, oh well. 
X * If we get to this state then things are badly wrong anyway...
X *
X * Give the system 10 seconds to recover but then give up.
X * Hopefully something else will exit and free up some file
X * table slots in that time.
X */
X#define	NFILE_RETRIES	10 /* seconds */
X
X#endif /* UPDATE_MTAB */
X
X#ifdef MTAB_LOCKING
X#ifdef LOCK_FCNTL
Xstatic int lock(fd)
X{
X	int rc;
X	struct flock lk;
X
X	lk.l_type = F_WRLCK;
X	lk.l_whence = 0;
X	lk.l_start = 0;
X	lk.l_len = 0;
X
Xagain:
X	rc = fcntl(fd, F_SETLKW, (caddr_t) &lk);
X	if (rc < 0 && (errno == EACCES || errno == EAGAIN)) {
X#ifdef DEBUG
X		dlog("Blocked, trying to obtain exclusive mtab lock");
X#endif
X		sleep(1);
X		goto again;
X	}
X	return rc;
X}
X#else
X#define lock(fd) (flock((fd), LOCK_EX))
X#endif
X#endif /* MTAB_LOCKING */
X
X#ifdef MTAB_STRIPNL
Xstatic void mtab_stripnl(s)
Xchar *s;
X{
X	do {
X		s = strchr(s, '\n');
X		if (s)
X			*s++ = ' ';
X	} while (s);
X}
X#endif
X
Xstatic struct mntent *mnt_dup(mp)
X#ifdef READ_MTAB_BSD_STYLE
Xstruct statfs *mp;
X#endif
X#ifdef READ_MTAB_ULTRIX_STYLE
Xstruct fs_data *mp;
X#endif
X#ifdef READ_MTAB_FROM_FILE
Xstruct mntent *mp;
X#endif
X{
X	struct mntent *new_mp = ALLOC(mntent);
X#ifdef READ_MTAB_BSD_STYLE
X	char *ty;
X	new_mp->mnt_fsname = strdup(mp->f_mntfromname);
X	new_mp->mnt_dir = strdup(mp->f_mntonname);
X	switch (mp->f_type) {
X	case MOUNT_UFS:  ty = MTAB_TYPE_UFS; break;
X	case MOUNT_NFS:  ty = MTAB_TYPE_NFS; break;
X	case MOUNT_MFS:  ty = MTAB_TYPE_MFS; break;
X	default:  ty = "unknown"; break;
X	}
X	new_mp->mnt_type = strdup(ty);
X	new_mp->mnt_opts = strdup("unset");
X	new_mp->mnt_freq = 0;
X	new_mp->mnt_passno = 0;
X#endif
X
X#ifdef READ_MTAB_ULTRIX_STYLE
X	new_mp->mnt_fsname = strdup(mp->fd_devname);
X	new_mp->mnt_dir = strdup(mp->fd_path);
X        if (mp->fd_fstype >= GT_NUMTYPES)
X                mp->fd_fstype = GT_UNKWN;
X        else if (gt_names[mp->fd_fstype] == 0)
X                mp->fd_fstype = GT_UNKWN;
X        new_mp->mnt_type = strdup(gt_names[mp->fd_fstype]);
X	new_mp->mnt_opts = strdup("unset");
X
X	new_mp->mnt_freq = 0;
X	new_mp->mnt_passno = mp->fd_dev;
X#endif
X
X#ifdef READ_MTAB_FROM_FILE
X	new_mp->mnt_fsname = strdup(mp->mnt_fsname);
X	new_mp->mnt_dir = strdup(mp->mnt_dir);
X	new_mp->mnt_type = strdup(mp->mnt_type);
X	new_mp->mnt_opts = strdup(mp->mnt_opts);
X
X	new_mp->mnt_freq = mp->mnt_freq;
X	new_mp->mnt_passno = mp->mnt_passno;
X#endif
X	return new_mp;
X}
X
Xvoid mnt_free(mp)
Xstruct mntent *mp;
X{
X	free(mp->mnt_fsname);
X	free(mp->mnt_dir);
X	free(mp->mnt_type);
X	free(mp->mnt_opts);
X	free((voidp) mp);
X}
X
X/*
X * Read a mount table into memory
X */
X
X#ifdef READ_MTAB_BSD_STYLE
Xmntlist *read_mtab(fs)
Xchar *fs;
X{
X	mntlist **mpp, *mhp;
X	struct statfs *mntbufp, *mntp;
X
X	int nloc = getmntinfo(&mntbufp);
X
X	if (nloc == 0) {
X		plog(XLOG_ERROR, "Can't read mount table");
X		return 0;
X	}
X
X	mpp = &mhp;
X	for (mntp = mntbufp; mntp < mntbufp + nloc; mntp++) {
X		/*
X		 * Allocate a new slot
X		 */
X		*mpp = ALLOC(mntlist);
X
X		/*
X		 * Copy the data returned by getmntent
X		 */
X		(*mpp)->mnt = mnt_dup(mntp);
X
X		/*
X		 * Move to next pointer
X		 */
X		mpp = &(*mpp)->mnext;
X	}
X
X	return mhp;
X}
X#endif /* READ_MTAB_BSD_STYLE */
X
X#ifdef READ_MTAB_ULTRIX_STYLE
Xmntlist *read_mtab(fs)
Xchar *fs;
X{
X	mntlist **mpp, *mhp;
X
X/* From: Piete Brooks <pb@cl.cam.ac.uk> */
X
X	int loc=0;
X#undef	NMOUNT
X#define	NMOUNT	20
X	struct fs_data mountbuffer[NMOUNT], *fs_data;
X	int ret;
X
X	mpp = &mhp;
X	while ((ret = getmountent(&loc, mountbuffer, NMOUNT)) > 0) {
X	        for (fs_data = mountbuffer; fs_data < &mountbuffer[ret]; fs_data++) {
X			/*
X			 * Allocate a new slot
X			 */
X			*mpp = ALLOC(mntlist);
X
X			/*
X			 * Copy the data returned by getmntent
X			 */
X			(*mpp)->mnt = mnt_dup(fs_data);
X
X			/*
X			 * Move to next pointer
X			 */
X			mpp = &(*mpp)->mnext;
X		}
X	}
X	if (ret < 0) {
X		plog(XLOG_ERROR, "getmountent: %m");
X		return 0;
X	}
X	*mpp = 0;
X
X	return mhp;
X}
X#endif /* READ_MTAB_ULTRIX_STYLE */
X
X#ifdef READ_MTAB_FROM_FILE
Xmntlist *read_mtab(fs)
Xchar *fs;
X{
X	mntlist **mpp, *mhp;
X
X	struct mntent *mep;
X	FILE *mfp = 0;
X
X#ifdef UPDATE_MTAB
X	/*
X	 * There is a possible race condition if two processes enter
X	 * this routine at the same time.  One will be blocked by the
X	 * exclusive lock below (or by the shared lock in setmntent)
X	 * and by the time the second process has the exclusive lock
X	 * it will be on the wrong underlying object.  To check for this
X	 * the mtab file is stat'ed before and after all the locking
X	 * sequence, and if it is a different file then we assume that
X	 * it may be the wrong file (only "may", since there is another
X	 * race between the initial stat and the setmntent).
X	 *
X	 * Simpler solutions to this problem are invited...
X	 */
X	int racing = 0;
X#ifdef MTAB_LOCKING
X	int rc;
X	int retries = 0;
X	struct stat st_before, st_after;
X#endif /* MTAB_LOCKING */
X
X	if (mnt_file) {
X#ifdef DEBUG
X		dlog("Forced close on %s in read_mtab", mtab);
X#endif /* DEBUG */
X		endmntent(mnt_file);
X		mnt_file = 0;
X	}
X
X#ifdef MTAB_LOCKING
Xagain:
X	if (mfp) {
X		endmntent(mfp);
X		mfp = 0;
X	}
X
X	clock_valid = 0;
X	if (stat(mtab, &st_before) < 0) {
X		plog(XLOG_ERROR, "%s: stat: %m", mtab);
X		if (errno == ESTALE) {
X			/* happens occasionally */
X			sleep(1);
X			goto again;
X		}
X		return 0;
X	}
X#endif /* MTAB_LOCKING */
X#endif /* UPDATE_MTAB */
X
Xeacces:
X	mfp = setmntent(mtab, "r+");
X	if (!mfp) {
X		/*
X		 * Since setmntent locks the descriptor, it
X		 * is possible it can fail... so retry if
X		 * needed.
X		 */
X		if (errno == EACCES || errno == EAGAIN) {
X#ifdef DEBUG
X			dlog("Blocked, trying to obtain exclusive mtab lock");
X#endif /* DEBUG */
X			goto eacces;
X		} else if (errno == ENFILE && retries++ < NFILE_RETRIES) {
X			sleep(1);
X			goto eacces;
X		}
X
X		plog(XLOG_ERROR, "setmntent(\"%s\", \"r+\"): %m", mtab);
X		return 0;
X	}
X
X#ifdef MTAB_LOCKING
X#ifdef UPDATE_MTAB
X	/*
X	 * At this point we have an exclusive lock on the mount list,
X	 * but it may be the wrong one so...
X	 */
X
X	/*
X	 * Need to get an exclusive lock on the current
X	 * mount table until we have a new copy written
X	 * out, when the lock is released in free_mntlist.
X	 * flock is good enough since the mount table is
X	 * not shared between machines.
X	 */
X	do
X		rc = lock(fileno(mfp));
X	while (rc < 0 && errno == EINTR);
X	if (rc < 0) {
X		plog(XLOG_ERROR, "Couldn't lock %s: %m", mtab);
X		endmntent(mfp);
X		return 0;
X	}
X	/*
X	 * Now check whether the mtab file has changed under our feet
X	 */
X	if (stat(mtab, &st_after) < 0) {
X		plog(XLOG_ERROR, "%s: stat", mtab);
X		goto again;
X	}
X
X	if (st_before.st_dev != st_after.st_dev ||
X		st_before.st_ino != st_after.st_ino) {
X			if (racing == 0) {
X				/* Sometimes print a warning */
X				plog(XLOG_WARNING,
X					"Possible mount table race - retrying %s", fs);
X			}
X			racing = (racing+1) & 3;
X			goto again;
X	}
X#endif /* UPDATE_MTAB */
X#endif /* MTAB_LOCKING */
X
X	mpp = &mhp;
X
X/*
X * XXX - In SunOS 4 there is (yet another) memory leak
X * which loses 1K the first time getmntent is called.
X * (jsp)
X */
X	while (mep = getmntent(mfp)) {
X		/*
X		 * Allocate a new slot
X		 */
X		*mpp = ALLOC(mntlist);
X
X		/*
X		 * Copy the data returned by getmntent
X		 */
X		(*mpp)->mnt = mnt_dup(mep);
X
X		/*
X		 * Move to next pointer
X		 */
X		mpp = &(*mpp)->mnext;
X	}
X	*mpp = 0;
X
X#ifdef UPDATE_MTAB
X	/*
X	 * If we are not updating the mount table then we
X	 * can free the resources held here, otherwise they
X	 * must be held until the mount table update is complete
X	 */
X	mnt_file = mfp;
X#else
X	endmntent(mfp);
X#endif /* UPDATE_MTAB */
X
X	return mhp;
X}
X#endif /* READ_MTAB_FROM_FILE */
X
X/*
X * Throw away a mount list
X */
Xvoid free_mntlist(mp)
Xmntlist *mp;
X{
X	mntlist *mp2;
X
X	while (mp2 = mp) {
X		mp = mp->mnext;
X		if (mp2->mnt)
X			mnt_free(mp2->mnt);
X		free(mp2);
X	}
X
X#ifdef UPDATE_MTAB
X	/*
X	 * Release file lock, by closing the file
X	 */
X	if (mnt_file) {
X		endmntent(mnt_file);
X		mnt_file = 0;
X	}
X#endif /* UPDATE_MTAB */
X}
X
X#ifdef UPDATE_MTAB
X/*
X * Write out a mount list
X */
Xvoid rewrite_mtab(mp)
Xmntlist *mp;
X{
X	FILE *mfp;
X
X	/*
X	 * Concoct a temporary name in the same
X	 * directory as the target mount table
X	 * so that rename() will work.
X	 */
X	char tmpname[64];
X	int retries;
X	int tmpfd;
X	char *cp;
X	char *mcp = mtab;
X	cp = strrchr(mcp, '/');
X	if (cp) {
X		bcopy(mcp, tmpname, cp - mcp);
X		tmpname[cp-mcp] = '\0';
X	} else {
X		plog(XLOG_WARNING, "No '/' in mtab (%s), using \".\" as tmp directory", mtab);
X		tmpname[0] = '.'; tmpname[1] = '\0';
X	}
X	strcat(tmpname, "/mtabXXXXXX");
X	mktemp(tmpname);
X	retries = 0;
Xenfile1:
X	if ((tmpfd = open(tmpname, O_RDWR|O_CREAT|O_TRUNC, 0644)) < 0) {
X		if (errno == ENFILE && retries++ < NFILE_RETRIES) {
X			sleep(1);
X			goto enfile1;
X		}
X		plog(XLOG_ERROR, "%s: open: %m", tmpname);
X		return;
X	}
X	if (close(tmpfd) < 0)
X		plog(XLOG_ERROR, "Couldn't close tmp file descriptor: %m");
X
X	retries = 0;
Xenfile2:
X	mfp = setmntent(tmpname, "w");
X	if (!mfp) {
X		if (errno == ENFILE && retries++ < NFILE_RETRIES) {
X			sleep(1);
X			goto enfile2;
X		}
X		plog(XLOG_ERROR, "setmntent(\"%s\", \"w\"): %m", tmpname);
X		return;
X	}
X
X	while (mp) {
X		if (mp->mnt)
X			if (addmntent(mfp, mp->mnt))
X				plog(XLOG_ERROR, "Can't write entry to %s", tmpname);
X		mp = mp->mnext;
X	}
X
X	endmntent(mfp);
X
X	/*
X	 * Rename temporary mtab to real mtab
X	 */
X	if (rename(tmpname, mtab) < 0)
X		plog(XLOG_ERROR, "rename %s to %s: %m", tmpname, mtab);
X}
X
X/*
X * Append a mntent structure to the
X * current mount table.
X */
Xvoid write_mntent(mp)
Xstruct mntent *mp;
X{
X	int retries = 0;
X	FILE *mfp;
Xenfile:
X	mfp = setmntent(mtab, "a");
X	if (mfp) {
X#ifdef MTAB_STRIPNL
X		mtab_stripnl(mp->mnt_opts);
X#endif /* MTAB_STRIPNL */
X		if (addmntent(mfp, mp))
X			plog(XLOG_ERROR, "Couldn't write %s: %m", mtab);
X		endmntent(mfp);
X	} else {
X		if (errno == ENFILE && retries < NFILE_RETRIES) {
X			sleep(1);
X			goto enfile;
X		}
X		plog(XLOG_ERROR, "setmntent(\"%s\", \"a\"): %m", mtab);
X	}
X}
X#endif /* UPDATE_MTAB */
X
X/*
X * Utility routine which determines the value of a
X * numeric option in the mount options (such as port=%d).
X * Returns 0 if the option is not specified.
X */
Xint hasmntval(mnt, opt)
Xstruct mntent *mnt;
Xchar *opt;
X{
X	char *str = hasmntopt(mnt, opt);
X	if (str) {
X		char *eq = strchr(str, '=');
X		if (eq)
X			return atoi(eq+1);
X		else
X			plog(XLOG_USER, "bad numeric option \"%s\" in \"%s\"", opt, str);
X	}
X
X	return 0;
X}
END_OF_FILE
if test 12010 -ne `wc -c <'mtab.c'`; then
    echo shar: \"'mtab.c'\" unpacked with wrong size!
fi
# end of 'mtab.c'
fi
if test -f 'opts.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'opts.c'\"
else
echo shar: Extracting \"'opts.c'\" \(14812 characters\)
sed "s/^X//" >'opts.c' <<'END_OF_FILE'
X/*
X * $Id: opts.c,v 5.1 89/11/17 18:21:43 jsp Exp Locker: jsp $
X *
X * Copyright (c) 1989 Jan-Simon Pendry
X * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
X * Copyright (c) 1989 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry at Imperial College, London.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Imperial College of Science, Technology and Medicine, London, UK.
X * The names of the College and University may not be used to endorse
X * or promote products derived from this software without specific
X * prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	%W% (Berkeley) %G%
X */
X
X#include "am.h"
X
Xextern char *getenv P((char *));
X
X/*
X * static copy of the options with
X * which to play
X */
Xstatic struct am_opts fs_static;
X
Xstatic char *opt_host = hostname;
Xstatic char *opt_hostd = hostd;
Xstatic char nullstr[] = "";
Xstatic char *opt_key = nullstr;
Xstatic char *opt_map = nullstr;
Xstatic char *opt_path = nullstr;
X
X/*
X * Length of longest option name
X */
X#define	NLEN	16
X#define S(x) (x) , (sizeof(x)-1)
Xstatic struct opt {
X	char *name;		/* Name of the option */
X	int nlen;		/* Length of option name */
X	char **optp;		/* Pointer to option value string */
X	char **sel_p;		/* Pointer to selector value string */
X} opt_fields[] = {
X	/* Options in something corresponding to frequency of use */
X	{ S("opts"), &fs_static.opt_opts, 0 },
X	{ S("host"), 0, &opt_host },
X	{ S("hostd"), 0, &opt_hostd },
X	{ S("type"), &fs_static.opt_type, 0 },
X	{ S("rhost"), &fs_static.opt_rhost, 0 },
X	{ S("rfs"), &fs_static.opt_rfs, 0 },
X	{ S("fs"), &fs_static.opt_fs, 0 },
X	{ S("key"), 0, &opt_key },
X	{ S("map"), 0, &opt_map },
X	{ S("sublink"), &fs_static.opt_sublink, 0 },
X	{ S("arch"), 0, &arch },
X	{ S("dev"), &fs_static.opt_dev, 0 },
X	{ S("pref"), &fs_static.opt_pref, 0 },
X	{ S("path"), 0, &opt_path },
X	{ S("autodir"), 0, &auto_dir },
X	{ S("delay"), &fs_static.opt_delay, 0 },
X	{ S("domain"), 0, &hostdomain },
X	{ S("karch"), 0, &karch },
X	{ S("cluster"), 0, &cluster },
X	{ S("byte"), 0, &endian },
X	{ S("os"), 0, &op_sys },
X	{ S("mount"), &fs_static.opt_mount, 0 },
X	{ S("unmount"), &fs_static.opt_unmount, 0 },
X	{ S("cache"), &fs_static.opt_cache, 0 },
X	{ S("user"), &fs_static.opt_user, 0 },
X	{ S("group"), &fs_static.opt_group, 0 },
X	{ 0, 0, 0, 0 },
X};
X
Xtypedef struct opt_apply opt_apply;
Xstruct opt_apply {
X	char **opt;
X	char *val;
X};
X
X/*
X * Specially expand the remote host name first
X */
Xstatic opt_apply rhost_expansion[] = {
X	{ &fs_static.opt_rhost, "${host}" },
X	{ 0, 0 },
X};
X/*
X * List of options which need to be expanded
X * Note that this the order here _may_ be important.
X */
Xstatic opt_apply expansions[] = {
X/*	{ &fs_static.opt_dir, 0 },	*/
X	{ &fs_static.opt_sublink, 0 },
X	{ &fs_static.opt_rfs, "${path}" },
X	{ &fs_static.opt_fs, "${autodir}/${rhost}${rfs}" },
X	{ &fs_static.opt_opts, "rw" },
X	{ &fs_static.opt_mount, 0 },
X	{ &fs_static.opt_unmount, 0 },
X	{ 0, 0 },
X};
X
X/*
X * List of options which need to be free'ed before re-use
X */
Xstatic opt_apply to_free[] = {
X	{ &fs_static.fs_glob, 0 },
X	{ &fs_static.fs_local, 0 },
X	{ &fs_static.fs_mtab, 0 },
X/*	{ &fs_static.opt_dir, 0 },	*/
X	{ &fs_static.opt_sublink, 0 },
X	{ &fs_static.opt_rfs, 0 },
X	{ &fs_static.opt_fs, 0 },
X	{ &fs_static.opt_rhost, 0 },
X	{ &fs_static.opt_opts, 0 },
X	{ &fs_static.opt_mount, 0 },
X	{ &fs_static.opt_unmount, 0 },
X	{ 0, 0 },
X};
X
X/*
X * Skip to next option in the string
X */
Xstatic char *opt P((char**));
Xstatic char *opt(p)
Xchar **p;
X{
X	char *cp = *p;
X	char *dp = cp;
X	char *s = cp;
X
Xtop:
X	while (*cp && *cp != ';') {
X		if (*cp == '\"') {
X			/*
X			 * Skip past string
X			 */
X			cp++;
X			while (*cp && *cp != '\"')
X				*dp++ = *cp++;
X			if (*cp)
X				cp++;
X		} else {
X			*dp++ = *cp++;
X		}
X	}
X
X	/*
X	 * Skip past any remaining ';'s
X	 */
X	while (*cp == ';')
X		cp++;
X
X	/*
X	 * If we have a zero length string
X	 * and there are more fields, then
X	 * parse the next one.  This allows
X	 * sequences of empty fields.
X	 */
X	if (*cp && dp == s)
X		goto top;
X
X	*dp = '\0';
X
X	*p = cp;
X	return s;
X}
X
Xstatic int eval_opts P((char*));
Xstatic int eval_opts(opts)
Xchar *opts;
X{
X	/*
X	 * Fill in the global structure fs_static by
X	 * cracking the string opts.  opts may be
X	 * scribbled on at will.
X	 */
X	char *o = opts;
X	char *f;
X
X	/*
X	 * For each user-specified option
X	 */
X	while (*(f = opt(&o))) {
X		struct opt *op;
X		enum vs_opt { OldSyn, SelEQ, SelNE, VarAss } vs_opt;
X		char *eq = strchr(f, '=');
X		char *opt;
X		if (!eq || eq[1] == '\0' || eq == f) {
X			/*
X			 * No value, just continue
X			 */
X			plog(XLOG_USER, "No value component in \"%s\"", f);
X			continue;
X		}
X
X		/*
X		 * Check what type of operation is happening
X		 * !=, =!  is SelNE
X		 * == is SelEQ
X		 * := is VarAss
X		 * = is OldSyn (either SelEQ or VarAss)
X		 */
X		if (eq[-1] == '!') {		/* != */
X			vs_opt = SelNE;
X			eq[-1] = '\0';
X			opt = eq + 1;
X		} else if (eq[-1] == ':') {	/* := */
X			vs_opt = VarAss;
X			eq[-1] = '\0';
X			opt = eq + 1;
X		} else if (eq[1] == '=') {	/* == */
X			vs_opt = SelEQ;
X			eq[0] = '\0';
X			opt = eq + 2;
X		} else if (eq[1] == '!') {	/* =! */
X			vs_opt = SelNE;
X			eq[0] = '\0';
X			opt = eq + 2;
X		} else {			/* = */
X			vs_opt = OldSyn;
X			eq[0] = '\0';
X			opt = eq + 1;
X		}
X
X		/*
X		 * For each recognised option
X		 */
X		for (op = opt_fields; op->name; op++) {
X			/*
X			 * Check whether they match
X			 */
X			if (FSTREQ(op->name, f)) {
X				switch (vs_opt) {
X#if AMD_COMPAT <= 5000108
X				case OldSyn:
X					if (!op->sel_p) {
X						*op->optp = opt;
X						break;
X					}
X					/* fall through ... */
X#endif /* 5000108 */
X				case SelEQ:
X				case SelNE:
X					if (op->sel_p && (STREQ(*op->sel_p, opt) == (vs_opt == SelNE))) {
X						plog(XLOG_MAP, "map selector %s (=%s) did not %smatch %s",
X							op->name,
X							*op->sel_p,
X							vs_opt == SelNE ? "not " : "",
X							opt);
X						return 0;
X					}
X					break;
X
X				case VarAss:
X					if (op->sel_p) {
X						plog(XLOG_USER, "Can't assign to a selector (%s)", op->name);
X						return 0;
X					}
X					*op->optp = opt;
X					break;
X				}
X				break;
X			}
X		}
X
X		if (!op->name)
X			plog(XLOG_USER, "Unrecognised key \"%s\"", f);
X	}
X
X	return 1;
X}
X
X/*
X * Free an option
X */
Xstatic void free_op P((opt_apply*, int));
X/*ARGSUSED*/
Xstatic void free_op(p, b)
Xopt_apply *p;
Xint b;
X{
X	if (*p->opt) {
X		free(*p->opt);
X		*p->opt = 0;
X	}
X}
X
X/*
X * Macro-expand an option.  Note that this does not
X * handle recursive expansions.  They will go badly wrong.
X * If sel is true then old expand selectors, otherwise
X * don't expand selectors.
X */
Xstatic void expand_op P((opt_apply*, int));
Xstatic void expand_op(p, sel_p)
Xopt_apply *p;
Xint sel_p;
X{
X/*
X * The BUFSPACE macros checks that there is enough space
X * left in the expansion buffer.  If there isn't then we
X * give up completely.  This is done to avoid crashing the
X * automounter itself (which would be a bad thing to do).
X */
X#define BUFSPACE(ep, len) (((ep) + (len)) < expbuf+MAXPATHLEN)
Xstatic char expand_error[] = "No space to expand \"%s\"";
X
X	char expbuf[MAXPATHLEN];
X	char nbuf[NLEN+1];
X	char *ep = expbuf;
X	char *cp = *p->opt;
X	char *dp;
X#ifdef DEBUG
X	char *cp_orig = *p->opt;
X#endif
X	struct opt *op;
X
X	while (dp = strchr(cp, '$')) {
X		char ch;
X		/*
X		 * First copy up to the $
X		 */
X		{ int len = dp - cp;
X		  if (BUFSPACE(ep, len)) {
X			strncpy(ep, cp, len);
X			ep += len;
X		  } else {
X			plog(XLOG_ERROR, expand_error, *p->opt);
X			goto out;
X		  }
X		}
X		cp = dp + 1;
X		ch = *cp++;
X		if (ch == '$') {
X			if (BUFSPACE(ep, 1)) {
X				*ep++ = '$';
X			} else {
X				plog(XLOG_ERROR, expand_error, *p->opt);
X				goto out;
X			}
X		} else if (ch == '{') {
X			/* Expansion... */
X			enum { E_All, E_Dir, E_File } todo;
X			/*
X			 * Find closing brace
X			 */
X			char *br_p = strchr(cp, '}');
X			int len;
X			/*
X			 * Check we found it
X			 */
X			if (!br_p) {
X				/*
X				 * Just give up
X				 */
X				plog(XLOG_USER, "No closing '}' in \"%s\"", *p->opt);
X				goto out;
X			}
X			len = br_p - cp;
X			/*
X			 * Figure out which part of the variable to grab.
X			 */
X			if (*cp == '/') {
X				/*
X				 * Just take the last component
X				 */
X				todo = E_File;
X				cp++;
X				--len;
X			} else if (br_p[-1] == '/') {
X				/*
X				 * Take all but the last component
X				 */
X				todo = E_Dir;
X				--len;
X			} else {
X				/*
X				 * Take the whole lot
X				 */
X				todo = E_All;
X			}
X			/*
X			 * Truncate if too long.  Since it won't
X			 * match anyway it doesn't matter that
X			 * it has been cut short.
X			 */
X			if (len > NLEN)
X				len = NLEN;
X			/*
X			 * Put the string into another buffer so
X			 * we can do comparisons.
X			 */
X			strncpy(nbuf, cp, len);
X			nbuf[len] = '\0';
X			/*
X			 * Advance cp
X			 */
X			cp = br_p + 1;
X			/*
X			 * Search the option array
X			 */
X			for (op = opt_fields; op->name; op++) {
X				/*
X				 * Check for match
X				 */
X				if (len == op->nlen && STREQ(op->name, nbuf)) {
X					char xbuf[NLEN+3];
X					char *val;
X					/*
X					 * Found expansion.  Copy
X					 * the correct value field.
X					 */
X					if (!(!op->sel_p == !sel_p)) {
X						/*
X						 * Copy the string across unexpanded
X						 */
X						sprintf(xbuf, "${%s%s%s}",
X							todo == E_File ? "/" : "",
X							nbuf,
X							todo == E_Dir ? "/" : "");
X						val = xbuf;
X					} else if (op->sel_p) {
X						val = *op->sel_p;
X					} else {
X						val = *op->optp;
X					}
X					if (val) {
X						/*
X						 * Do expansion:
X						 * ${/var} means take just the last part
X						 * ${var/} means take all but the last part
X						 * ${var} means take the whole lot
X						 */
X						int vlen = strlen(val);
X						char *vptr = val;
X						switch (todo) {
X						case E_Dir:
X							vptr = strchr(val, '/');
X							if (vptr)
X								vlen = vptr - val;
X							vptr = val;
X							break;
X						case E_File:
X							vptr = strchr(val, '/');
X							if (vptr) {
X								vptr++;
X								vlen = strlen(vptr);
X							}
X							break;
X						}
X#ifdef DEBUG
X					/*dlog("Expanding \"%s\" to \"%s\"", nbuf, val);*/
X#endif
X						if (BUFSPACE(ep, vlen)) {
X							strcpy(ep, vptr);
X							ep += vlen;
X						} else {
X							plog(XLOG_ERROR, expand_error, *p->opt);
X							goto out;
X						}
X					}
X					/*
X					 * Done with this variable
X					 */
X					break;
X				}
X			}
X			/*
X			 * Check that the search was succesful
X			 */
X			if (!op->name) {
X				/*
X				 * If it wasn't then scan the
X				 * environment for that name
X				 * and use any value found
X				 */
X				char *env = getenv(nbuf);
X				if (env) {
X					int vlen = strlen(env);
X
X					if (BUFSPACE(ep, vlen)) {
X						strcpy(ep, env);
X						ep += vlen;
X					} else {
X						plog(XLOG_ERROR, expand_error, *p->opt);
X						goto out;
X					}
X#ifdef DEBUG
X					Debug(D_STR)
X					plog(XLOG_DEBUG, "Environment gave \"%s\" -> \"%s\"", nbuf, env);
X#endif
X				} else {
X					plog(XLOG_USER, "Unknown sequence \"${%s}\"", nbuf);
X				}
X			}
X		} else {
X			/*
X			 * Error, error
X			 */
X			plog(XLOG_USER, "Unknown $ sequence in \"%s\"", *p->opt);
X		}
X	}
X
Xout:
X	/*
X	 * Handle common case - no expansion
X	 */
X	if (cp == *p->opt) {
X		*p->opt = strdup(cp);
X	} else {
X		/*
X		 * Finish off the expansion
X		 */
X		if (BUFSPACE(ep, strlen(cp))) {
X			strcpy(ep, cp);
X			/*ep += strlen(ep);*/
X		} else {
X			plog(XLOG_ERROR, expand_error, *p->opt);
X		}
X
X		/*
X		 * Save the exansion
X		 */
X		*p->opt = strdup(expbuf);
X	}
X
X	/*
X	 * Normalize slashes in the string.
X	 */
X	{ char *f = strchr(*p->opt, '/');
X	  if (f) {
X		char *t = f;
X		do {
X			/* assert(*f == '/'); */
X			/* copy a single / across */
X			*t++ = *f++;
X
X			/* assert(f[-1] == '/'); */
X			/* skip past more /'s */
X			while (*f == '/')
X				f++;
X
X			/* assert(*f != '/'); */
X			/* keep copying up to next / */
X			do {
X				*t++ = *f++;
X			} while (*f && *f != '/');
X
X			/* assert(*f == 0 || *f == '/'); */
X
X		} while (*f);
X	  }
X	}
X	  
X#ifdef DEBUG
X	Debug(D_STR) {
X		plog(XLOG_DEBUG, "Expansion of \"%s\"...", cp_orig);
X		plog(XLOG_DEBUG, "... is \"%s\"", *p->opt);
X	}
X#endif
X}
X
X/*
X * Wrapper for expand_op
X */
Xstatic void expand_opts P((opt_apply*, int));
Xstatic void expand_opts(p, sel_p)
Xopt_apply *p;
Xint sel_p;
X{
X	if (*p->opt) {
X		expand_op(p, sel_p);
X	} else if (p->val) {
X		/*
X		 * Do double expansion, remembering
X		 * to free the string from the first
X		 * expansion...
X		 */
X		char *s = *p->opt = expand_key(p->val);
X		expand_op(p, sel_p);
X		free(s);
X	}
X}
X
X/*
X * Apply a function to a list of options
X */
Xstatic void apply_opts(op, ppp, b)
Xvoid (*op)();
Xopt_apply ppp[];
Xint b;
X{
X	opt_apply *pp;
X	for (pp = ppp; pp->opt; pp++)
X		(*op)(pp, b);
X}
X
X/*
X * Free the option table
X */
Xvoid free_opts(fo)
Xam_opts *fo;
X{
X	/*
X	 * Copy in the structure we are playing with
X	 */
X	fs_static = *fo;
X
X	/*
X	 * Free previously allocated memory
X	 */
X	apply_opts(free_op, to_free, FALSE);
X}
X
X/*
X * Expand lookup key
X */
Xchar *expand_key(key)
Xchar *key;
X{
X	opt_apply oa;
X
X	oa.opt = &key; oa.val = 0;
X	expand_opts(&oa, TRUE);
X
X	return key;
X}
X
Xint eval_fs_opts(fo, opts, g_opts, path, key, map)
Xam_opts *fo;
Xchar *opts, *g_opts, *path, *key, *map;
X{
X	int ok = TRUE;
X
X	free_opts(fo);
X
X	/*
X	 * Clear out the option table
X	 */
X	bzero((voidp) &fs_static, sizeof(fs_static));
X	bzero((voidp) fo, sizeof(*fo));
X
X	/*
X	 * Set key before expansion
X	 */
X	opt_key = key;
X	opt_map = map;
X	opt_path = path;
X
X	/*
X	 * Expand global options
X	 */
X	fs_static.fs_glob = expand_key(g_opts);
X
X	/*
X	 * Expand local options
X	 */
X	fs_static.fs_local = expand_key(opts);
X
X	/*
X	 * Expand default (global) options
X	 */
X	if (!eval_opts(fs_static.fs_glob))
X		ok = FALSE;
X
X	/*
X	 * Expand local options
X	 */
X	if (ok && !eval_opts(fs_static.fs_local))
X		ok = FALSE;
X
X	/*
X	 * Normalise remote host name.
X	 * 1.  Expand variables
X	 * 2.  Normalize relative to host tables
X	 * 3.  Strip local domains from the remote host
X	 *     name before using it in other expansions.
X	 *     This makes mount point names and other things
X	 *     much shorter, while allowing cross domain
X	 *     sharing of mount maps.
X	 */
X	apply_opts(expand_opts, rhost_expansion, FALSE);
X	if (ok && fs_static.opt_rhost && *fs_static.opt_rhost)
X		host_normalize(&fs_static.opt_rhost);
X
X	/*
X	 * Macro expand the options.
X	 * Do this regardless of whether we are accepting
X	 * this mount - otherwise nasty things happen
X	 * with memory allocation.
X	 */
X	apply_opts(expand_opts, expansions, FALSE);
X
X	/*
X	 * ok... copy the data back out.
X	 */
X	*fo = fs_static;
X
X	/*
X	 * Clear defined options
X	 */
X	opt_key = opt_map = opt_path = nullstr;
X
X	return ok;
X}
END_OF_FILE
if test 14812 -ne `wc -c <'opts.c'`; then
    echo shar: \"'opts.c'\" unpacked with wrong size!
fi
# end of 'opts.c'
fi
if test -f 'srvr_nfs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'srvr_nfs.c'\"
else
echo shar: Extracting \"'srvr_nfs.c'\" \(11929 characters\)
sed "s/^X//" >'srvr_nfs.c' <<'END_OF_FILE'
X/*
X * $Id: srvr_nfs.c,v 5.1.1.2 90/01/11 17:21:08 jsp Exp Locker: jsp $
X *
X * Copyright (c) 1990 Jan-Simon Pendry
X * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry at Imperial College, London.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Imperial College of Science, Technology and Medicine, London, UK.
X * The names of the College and University may not be used to endorse
X * or promote products derived from this software without specific
X * prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	%W% (Berkeley) %G%
X */
X
X/*
X * NFS server modeling
X */
X
X#include "am.h"
X#include <netdb.h>
X#include <rpc/pmap_prot.h>
X#include "mount.h"
X
Xextern qelem nfs_srvr_list;
Xqelem nfs_srvr_list = { &nfs_srvr_list, &nfs_srvr_list };
X
Xtypedef struct nfs_private {
X	u_short np_mountd;	/* Mount daemon port number */
X	int np_ping;		/* Number of failed ping attempts */
X	int np_xid;		/* RPC transaction id for pings */
X	int np_error;		/* Error during portmap request */
X} nfs_private;
X
Xstatic int np_xid;	/* For NFS pings */
X#define	NPXID_ALLOC()	(++np_xid)
X/*#define	NPXID_ALLOC()	((++np_xid&0x0fffffff) == 0 ? npxid_gc() : np_xid)*/
X
X/*
X * Number of pings allowed to fail before host is declared down
X * - three-fifths of the allowed mount time...
X */
X#define	MAX_ALLOWED_PINGS	((((ALLOWED_MOUNT_TIME + 5 * AM_PINGER - 1) * 3) / 5) / AM_PINGER)
X/*
X * How often to ping when starting a new server
X */
X#define	FAST_NFS_PING		3
X
Xstatic int ping_len;
Xstatic char ping_buf[sizeof(struct rpc_msg) + 32];
X
X/*
X * Startup the NFS ping
X */
Xstatic void start_ping()
X{
X	XDR ping_xdr;
X	struct rpc_msg ping_msg;
X
X	rpc_msg_init(&ping_msg, NFS_PROGRAM, NFS_VERSION, NFSPROC_NULL);
X
X	/*
X	 * Create an XDR endpoint
X	 */
X	xdrmem_create(&ping_xdr, ping_buf, sizeof(ping_buf), XDR_ENCODE);
X
X	/*
X	 * Create the NFS ping message
X	 */
X	if (!xdr_callmsg(&ping_xdr, &ping_msg)) {
X		plog(XLOG_ERROR, "Couldn't create ping RPC message");
X		going_down(3);
X	}
X
X	/*
X	 * Find out how long it is
X	 */
X	ping_len = xdr_getpos(&ping_xdr);
X
X	/*
X	 * Destroy the XDR endpoint - we don't need it anymore
X	 */
X	xdr_destroy(&ping_xdr);
X}
X
X
X/*
X * Called when a portmap reply arrives
X */
Xstatic void got_portmap(pkt, len, sa, ia, idv, done)
Xvoidp pkt;
Xint len;
Xstruct sockaddr_in *sa, *ia;
Xvoidp idv;
Xint done;
X{
X	fserver *fs2 = (fserver *) idv;
X	fserver *fs = 0;
X	ITER(fs, fserver, &nfs_srvr_list)
X		if (fs == fs2)
X			break;
X
X	if (fs == fs2) {
X		u_long port = 0;	/* XXX - should be short but protocol is naff */
X		int error = done ? pickup_rpc_reply(pkt, len, (voidp) &port, xdr_u_long) : -1;
X		nfs_private *np = (nfs_private *) fs->fs_private;
X		if (!error && port) {
X#ifdef DEBUG
X			dlog("got port (%d) for mountd on %s", port, fs->fs_host);
X#endif
X			/*
X			 * Grab the port number.  Portmap sends back
X			 * an unsigned long in native ordering, so it
X			 * needs converting to a unsigned short in
X			 * network ordering.
X			 */
X			np->np_mountd = htons((u_short) port);
X			np->np_error = 0;
X		} else {
X#ifdef DEBUG
X			dlog("Error fetching port for mountd on %s", fs->fs_host);
X#endif
X			/*
X			 * Almost certainly no mountd running on remote host
X			 */
X			np->np_error = error ? error : ETIMEDOUT;
X		}
X		if (fs->fs_flags & FSF_WANT)
X			wakeup_srvr(fs);
X	} else if (done) {
X#ifdef DEBUG
X		dlog("Got portmap for old port request");
X#endif
X	} else {
X#ifdef DEBUG
X		dlog("portmap request timed out");
X#endif
X	}
X}
X
X/*
X * Obtain portmap information
X */
Xstatic int call_portmap(fs, auth, prog, vers, prot)
Xfserver *fs;
XAUTH *auth;
Xunsigned long prog, vers, prot;
X{
X	struct rpc_msg pmap_msg;
X	int len;
X	char iobuf[UDPMSGSIZE];
X	int error;
X	struct pmap pmap;
X
X	rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, (unsigned long) 0);
X	pmap.pm_prog = prog;
X	pmap.pm_vers = vers;
X	pmap.pm_prot = prot;
X	pmap.pm_port = 0;
X	len = make_rpc_packet(iobuf, sizeof(iobuf), PMAPPROC_GETPORT,
X			&pmap_msg, (voidp) &pmap, xdr_pmap, auth);
X	if (len > 0) {
X		struct sockaddr_in sin;
X		bzero((voidp) &sin, sizeof(sin));
X		sin = *fs->fs_ip;
X		sin.sin_port = htons(PMAPPORT);
X		error = fwd_packet(RPC_XID_PORTMAP, (voidp) iobuf, len,
X				&sin, &sin, (voidp) fs, got_portmap);
X	} else {
X		error = -len;
X	}
X	return error;
X}
X
Xstatic void nfs_keepalive P((fserver*));
X
X/*
X * This is called when we get a reply to an RPC ping.
X * The value of id wass taken from the nfs_private
X * structure when the ping was transmitted.
X */
X/*ARGSUSED*/
Xstatic void nfs_pinged(pkt, len, sp, tsp, idv, done)
Xvoidp pkt;
Xint len;
Xstruct sockaddr_in *sp, *tsp;
Xvoidp idv;
Xint done;
X{
X	int xid = (int) idv;
X	fserver *fs;
X	int found_map = 0;
X
X	if (!done)
X		return;
X
X	/*
X	 * For each node...
X	 */
X	ITER(fs, fserver, &nfs_srvr_list) {
X		nfs_private *np = (nfs_private *) fs->fs_private;
X		if (np->np_xid == xid) {
X			/*
X			 * Reset the ping counter.
X			 * Update the keepalive timer.
X			 * Log what happened.
X			 */
X			if (fs->fs_flags & FSF_DOWN) {
X				fs->fs_flags &= ~FSF_DOWN;
X				if (fs->fs_flags & FSF_VALID) {
X					plog(XLOG_INFO, "file server %s type nfs is up", fs->fs_host);
X				} else {
X					plog(XLOG_INFO, "file server %s type nfs starts up", fs->fs_host);
X					fs->fs_flags |= FSF_VALID;
X				}
X				/*if (fs->fs_flags & FSF_WANT)
X					wakeup_srvr(fs);*/
X			} else {
X#ifdef DEBUG
X				dlog("file server %s type nfs is still up", fs->fs_host);
X#endif
X			}
X
X			/*
X			 * Speed up the pings again
X			 */
X			if (np->np_ping >= MAX_ALLOWED_PINGS) {
X				untimeout(fs->fs_cid);
X				fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, (voidp) fs);
X			}
X
X			/*
X			 * New RPC xid...
X			 */
X			np->np_xid = NPXID_ALLOC();
X
X			/*
X			 * Failed pings is zero...
X			 */
X			np->np_ping = 0;
X
X			/*
X			 * Recompute portmap information if not known
X			 */
X			if (np->np_error < 0) {
X				if (!nfs_auth)
X					nfs_auth = authunix_create_default();
X				if (!nfs_auth)
X					np->np_error = ENOBUFS;
X				else
X					call_portmap(fs, nfs_auth, MOUNTPROG,
X						MOUNTVERS, (unsigned long) IPPROTO_UDP);
X			}
X			found_map++;
X			break;
X		}
X	}
X
X#ifdef DEBUG
X	if (found_map == 0)
X		dlog("Spurious ping packet");
X#endif
X}
X
X
X/*
X * Keep track of whether a server is alive
X */
Xstatic void nfs_keepalive(fs)
Xfserver *fs;
X{
X	int error;
X	nfs_private *np = (nfs_private *) fs->fs_private;
X	int fstimeo;
X
X	/*
X	 * Send an NFS ping to this node
X	 */
X
X	if (ping_len == 0)
X		start_ping();
X
X	/*
X	 * Queue the packet...
X	 */
X	error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), (voidp) ping_buf,
X		ping_len, fs->fs_ip, (struct sockaddr_in *) 0, (voidp) np->np_xid, nfs_pinged);
X
X	/*
X	 * See if a hard error occured
X	 */
X	switch (error) {
X	case ENETDOWN:
X	case ENETUNREACH:
X	case EHOSTDOWN:
X	case EHOSTUNREACH:
X		np->np_ping = MAX_ALLOWED_PINGS;	/* immediately down */
X		break;
X
X	case 0:
X#ifdef DEBUG
X		dlog("Sent NFS ping to %s", fs->fs_host);
X#endif
X		break;
X	}
X
X	/*
X	 * If N pings have failed then guess that it is dead
X	 */
X	if (np->np_ping >= MAX_ALLOWED_PINGS) {
X		if (!(fs->fs_flags & FSF_VALID)) {
X			/*
X			 * Starts off down
X			 */
X			plog(XLOG_INFO, "file server %s type nfs starts down", fs->fs_host);
X			fs->fs_flags |= FSF_VALID;
X			if (fs->fs_flags & FSF_WANT)
X				wakeup_srvr(fs);
X		}
X
X		if ((fs->fs_flags & FSF_DOWN) == 0) {
X			/*
X			 * Server was up, but is now down.
X			 */
X			plog(XLOG_INFO, "file server %s type nfs is down", fs->fs_host);
X			fs->fs_flags |= FSF_DOWN;
X			if (fs->fs_flags & FSF_WANT)
X				wakeup_srvr(fs);
X			/*
X			 * Since the server is down, the portmap
X			 * information may now be wrong, so it
X			 * must be flushed from the local cache
X			 */
X			flush_fhandle_cache(fs);
X			np->np_error = -1;
X			np->np_ping = 1;
X		}
X	} else {
X		np->np_ping++;
X#ifdef DEBUG
X		if (np->np_ping > 1)
X			dlog("%d pings to %s failed - max %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS);
X#endif
X	}
X
X	/*
X	 * Back off the ping interval if we are not getting replies and
X	 * the remote system is know to be down.
X	 */
X	switch (fs->fs_flags & (FSF_DOWN|FSF_VALID)) {
X	case FSF_VALID:			/* Up */
X		fstimeo = fs->fs_pinger;
X		break;
X	case FSF_VALID|FSF_DOWN:	/* Down */
X		fstimeo = np->np_ping * fs->fs_pinger;
X		break;
X	default:			/* Unknown */
X		fstimeo = FAST_NFS_PING;
X		break;
X	}
X	fs->fs_cid = timeout(fstimeo, nfs_keepalive, (voidp) fs);
X}
X
Xint nfs_srvr_port(fs, port, wchan)
Xfserver *fs;
Xu_short *port;
Xvoidp wchan;
X{
X	int error = -1;
X	if ((fs->fs_flags & FSF_VALID) == FSF_VALID) {
X		if ((fs->fs_flags & FSF_DOWN) == 0) {
X			nfs_private *np = (nfs_private *) fs->fs_private;
X			if (np->np_error == 0) {
X				*port = np->np_mountd;
X				/*
X				 * Now go get it again in case it changed
X				 */
X				np->np_error = -1;
X				error = 0;
X			} else {
X				error = np->np_error;
X			}
X		} else {
X			error = EWOULDBLOCK;
X		}
X	}
X	if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) {
X		/*
X		 * If a wait channel is supplied, and no
X		 * error has yet occured, then arrange
X		 * that a wakeup is done on the wait channel,
X		 * whenever a wakeup is done on this fs node.
X		 * Wakeup's are done on the fs node whenever
X		 * it changes state - thus causing control to
X		 * come back here and new, better things to happen.
X		 */
X		fs->fs_flags |= FSF_WANT;
X		sched_task(wakeup_task, wchan, (voidp) fs);
X	}
X	return error;
X}
X
Xstatic void start_nfs_pings(fs)
Xfserver *fs;
X{
X	if (!(fs->fs_flags & FSF_PINGING)) {
X		fs->fs_flags |= FSF_PINGING;
X		if (fs->fs_cid)
X			untimeout(fs->fs_cid);
X		nfs_keepalive(fs);
X	} else {
X#ifdef DEBUG
X		dlog("Already running pings to %s", fs->fs_host);
X#endif
X	}
X}
X
X/*
X * Find an nfs server for a host.
X */
Xfserver *find_nfs_srvr(mf)
Xmntfs *mf;
X{
X	fserver *fs;
X	struct hostent *hp = 0;
X	char *host = mf->mf_fo->opt_rhost;
X	struct sockaddr_in *ip;
X	nfs_private *np;
X
Xtop:
X	/*
X	 * Scan the list of known servers looking
X	 * for one with the same name
X	 */
X	ITER(fs, fserver, &nfs_srvr_list) {
X		if (STREQ(host, fs->fs_host)) {
X			start_nfs_pings(fs);
X			fs->fs_refc++;
X			return fs;
X		}
X	}
X
X	/*
X	 * If the name is not known, it may be
X	 * because it was an alternate name for
X	 * the same machine.  So do a lookup and
X	 * try again with the primary name if that
X	 * is different.
X	 * All that assuming it wasn't normalized
X	 * earlier of course...
X	 */
X	if (hp == 0) {
X		hp = gethostbyname(host);
X		if (hp && !STREQ(host, hp->h_name) && !normalize_hosts) {
X			host = hp->h_name;
X			goto top;
X		}
X	}
X
X	/*
X	 * Get here if we can't find an entry
X	 */
X	if (hp) {
X		switch (hp->h_addrtype) {
X		case AF_INET:
X			ip = ALLOC(sockaddr_in);
X			bzero((voidp) ip, sizeof(*ip));
X			ip->sin_family = AF_INET;
X			ip->sin_addr = *(struct in_addr *) hp->h_addr;
X			ip->sin_port = htons(NFS_PORT);
X			break;
X
X		default:
X			ip = 0;
X			break;
X		}
X	} else {
X		ip = 0;
X	}
X
X	/*
X	 * Allocate a new server
X	 */
X	fs = ALLOC(fserver);
X	fs->fs_refc = 1;
X	fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname");
X	fs->fs_ip = ip;
X	fs->fs_cid = 0;
X	if (ip) {
X		fs->fs_flags = FSF_DOWN;	/* Starts off down */
X	} else {
X		fs->fs_flags = FSF_ERROR|FSF_VALID;
X		mf->mf_flags |= MFF_ERROR;
X		mf->mf_error = ENOENT;
X	}
X	fs->fs_pinger = AM_PINGER;
X	np = ALLOC(nfs_private);
X	np->np_xid = NPXID_ALLOC();
X	bzero((voidp) np, sizeof(*np));
X	np->np_error = -1;
X	fs->fs_private = (voidp) np;
X	fs->fs_prfree = free;
X
X	if (!(fs->fs_flags & FSF_ERROR)) {
X		/*
X		 * Start of keepalive timer
X		 */
X		start_nfs_pings(fs);
X	}
X
X	/*
X	 * Add to list of servers
X	 */
X	ins_que(&fs->fs_q, &nfs_srvr_list);
X
X	return fs;
X}
END_OF_FILE
if test 11929 -ne `wc -c <'srvr_nfs.c'`; then
    echo shar: \"'srvr_nfs.c'\" unpacked with wrong size!
fi
# end of 'srvr_nfs.c'
fi
echo shar: End of archive 8 \(of 13\).
cp /dev/null ark8isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 13 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.