Subject: v21i096: An Automounter for NFS systems, Part08/13 Newsgroups: comp.sources.unix Approved: rsalz@uunet.UU.NET X-Checksum-Snefru: 588935f5 bebcb818 9ce08e0c 4e7e876d Submitted-by: Jan-Simon Pendry 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 '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 X#else X#include X#endif X#endif X X#ifdef READ_MTAB_ULTRIX_STYLE X#include X#include X#endif X X#ifdef READ_MTAB_BSD_STYLE X#include X#endif X X#ifdef UPDATE_MTAB X#include 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 */ 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 X#include 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...