v21i096: An Automounter for NFS systems, Part08/13
Rich Salz
rsalz at uunet.uu.net
Wed Apr 11 23:25:44 AEST 1990
Submitted-by: Jan-Simon Pendry <jsp at 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 at 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 at 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 at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list