From 663d5a0f32ed8dfc091ffb6153161591ac6ba563 Mon Sep 17 00:00:00 2001 From: obrien Date: Sun, 23 Aug 1998 22:07:21 +0000 Subject: Virgin import of AMD (am-utils) v6.0a16 --- contrib/amd/AUTHORS | 190 + contrib/amd/BUGS | 73 + contrib/amd/COPYING | 37 + contrib/amd/ChangeLog | 3039 +++++++++ contrib/amd/INSTALL | 113 + contrib/amd/MIRRORS | 43 + contrib/amd/NEWS | 628 ++ contrib/amd/README | 105 + contrib/amd/TODO | 177 + contrib/amd/amd/am_ops.c | 441 ++ contrib/amd/amd/amd.8 | 352 ++ contrib/amd/amd/amd.c | 535 ++ contrib/amd/amd/amd.h | 303 + contrib/amd/amd/amfs_auto.c | 1595 +++++ contrib/amd/amd/amfs_direct.c | 106 + contrib/amd/amd/amfs_error.c | 150 + contrib/amd/amd/amfs_host.c | 686 +++ contrib/amd/amd/amfs_inherit.c | 200 + contrib/amd/amd/amfs_link.c | 141 + contrib/amd/amd/amfs_linkx.c | 104 + contrib/amd/amd/amfs_nfsl.c | 237 + contrib/amd/amd/amfs_nfsx.c | 532 ++ contrib/amd/amd/amfs_program.c | 191 + contrib/amd/amd/amfs_root.c | 99 + contrib/amd/amd/amfs_toplvl.c | 355 ++ contrib/amd/amd/amfs_union.c | 124 + contrib/amd/amd/amq_subr.c | 501 ++ contrib/amd/amd/amq_svc.c | 157 + contrib/amd/amd/autil.c | 418 ++ contrib/amd/amd/clock.c | 247 + contrib/amd/amd/conf.c | 939 +++ contrib/amd/amd/conf_parse.y | 159 + contrib/amd/amd/conf_tok.l | 186 + contrib/amd/amd/get_args.c | 389 ++ contrib/amd/amd/info_file.c | 265 + contrib/amd/amd/info_hesiod.c | 163 + contrib/amd/amd/info_ldap.c | 465 ++ contrib/amd/amd/info_ndbm.c | 141 + contrib/amd/amd/info_nis.c | 401 ++ contrib/amd/amd/info_nisplus.c | 321 + contrib/amd/amd/info_passwd.c | 195 + contrib/amd/amd/info_union.c | 149 + contrib/amd/amd/map.c | 1112 ++++ contrib/amd/amd/mapc.c | 1205 ++++ contrib/amd/amd/mntfs.c | 335 + contrib/amd/amd/nfs_prot_svc.c | 250 + contrib/amd/amd/nfs_start.c | 472 ++ contrib/amd/amd/nfs_subr.c | 610 ++ contrib/amd/amd/ops_TEMPLATE.c | 293 + contrib/amd/amd/ops_autofs.c | 1275 ++++ contrib/amd/amd/ops_cachefs.c | 247 + contrib/amd/amd/ops_cdfs.c | 206 + contrib/amd/amd/ops_efs.c | 164 + contrib/amd/amd/ops_lofs.c | 154 + contrib/amd/amd/ops_mfs.c | 55 + contrib/amd/amd/ops_nfs.c | 799 +++ contrib/amd/amd/ops_nfs3.c | 55 + contrib/amd/amd/ops_nullfs.c | 55 + contrib/amd/amd/ops_pcfs.c | 179 + contrib/amd/amd/ops_tfs.c | 55 + contrib/amd/amd/ops_tmpfs.c | 55 + contrib/amd/amd/ops_ufs.c | 173 + contrib/amd/amd/ops_umapfs.c | 55 + contrib/amd/amd/ops_unionfs.c | 55 + contrib/amd/amd/ops_xfs.c | 164 + contrib/amd/amd/opts.c | 1304 ++++ contrib/amd/amd/restart.c | 208 + contrib/amd/amd/rpc_fwd.c | 476 ++ contrib/amd/amd/sched.c | 300 + contrib/amd/amd/srvr_amfs_auto.c | 214 + contrib/amd/amd/srvr_nfs.c | 851 +++ contrib/amd/amq/amq.8 | 214 + contrib/amd/amq/amq.c | 938 +++ contrib/amd/amq/amq.h | 63 + contrib/amd/amq/amq_clnt.c | 208 + contrib/amd/amq/amq_xdr.c | 259 + contrib/amd/amq/pawd.1 | 72 + contrib/amd/amq/pawd.c | 296 + contrib/amd/conf/checkmount/checkmount_bsd44.c | 78 + contrib/amd/conf/fh_dref/fh_dref_freebsd22.h | 2 + contrib/amd/conf/hn_dref/hn_dref_default.h | 2 + contrib/amd/conf/mount/mount_freebsd3.c | 68 + contrib/amd/conf/mtab/mtab_bsd.c | 145 + contrib/amd/conf/nfs_prot/nfs_prot_freebsd2.h | 146 + contrib/amd/conf/nfs_prot/nfs_prot_freebsd3.h | 211 + contrib/amd/conf/sa_dref/sa_dref_bsd44.h | 5 + contrib/amd/conf/transp/transp_sockets.c | 399 ++ contrib/amd/conf/trap/trap_default.h | 2 + contrib/amd/conf/trap/trap_freebsd3.h | 3 + contrib/amd/conf/umount/umount_bsd44.c | 89 + contrib/amd/doc/am-utils.texi | 7816 ++++++++++++++++++++++++ contrib/amd/doc/stamp-vti | 3 + contrib/amd/doc/texinfo.tex | 4935 +++++++++++++++ contrib/amd/doc/version.texi | 3 + contrib/amd/fixmount/fixmount.8 | 159 + contrib/amd/fixmount/fixmount.c | 612 ++ contrib/amd/fsinfo/fsi_analyze.c | 670 ++ contrib/amd/fsinfo/fsi_data.h | 236 + contrib/amd/fsinfo/fsi_dict.c | 138 + contrib/amd/fsinfo/fsi_gram.y | 419 ++ contrib/amd/fsinfo/fsi_lex.l | 270 + contrib/amd/fsinfo/fsi_util.c | 693 +++ contrib/amd/fsinfo/fsinfo.8 | 101 + contrib/amd/fsinfo/fsinfo.c | 293 + contrib/amd/fsinfo/fsinfo.h | 131 + contrib/amd/fsinfo/wr_atab.c | 334 + contrib/amd/fsinfo/wr_bparam.c | 109 + contrib/amd/fsinfo/wr_dumpset.c | 96 + contrib/amd/fsinfo/wr_exportfs.c | 108 + contrib/amd/fsinfo/wr_fstab.c | 342 ++ contrib/amd/hlfsd/hlfsd.8 | 310 + contrib/amd/hlfsd/hlfsd.c | 953 +++ contrib/amd/hlfsd/hlfsd.h | 171 + contrib/amd/hlfsd/homedir.c | 799 +++ contrib/amd/hlfsd/nfs_prot_svc.c | 250 + contrib/amd/hlfsd/stubs.c | 530 ++ contrib/amd/include/am_compat.h | 260 + contrib/amd/include/am_defs.h | 1320 ++++ contrib/amd/include/am_utils.h | 956 +++ contrib/amd/include/am_xdr_func.h | 203 + contrib/amd/include/amq_defs.h | 157 + contrib/amd/libamu/amu.h | 78 + contrib/amd/libamu/hasmntopt.c | 119 + contrib/amd/libamu/misc_rpc.c | 168 + contrib/amd/libamu/mount_fs.c | 892 +++ contrib/amd/libamu/mtab.c | 121 + contrib/amd/libamu/nfs_prot_xdr.c | 59 + contrib/amd/libamu/util.c | 176 + contrib/amd/libamu/wire.c | 404 ++ contrib/amd/libamu/xdr_func.c | 1155 ++++ contrib/amd/libamu/xutil.c | 825 +++ contrib/amd/mk-amd-map/mk-amd-map.8 | 62 + contrib/amd/mk-amd-map/mk-amd-map.c | 356 ++ contrib/amd/scripts/Makefile.am | 49 + contrib/amd/scripts/Makefile.in | 379 ++ contrib/amd/scripts/am-eject.in | 52 + contrib/amd/scripts/amd.conf-sample | 94 + contrib/amd/scripts/amd.conf.5 | 539 ++ contrib/amd/scripts/amd2ldif.in | 58 + contrib/amd/scripts/amd2sun.in | 51 + contrib/amd/scripts/ctl-amd.in | 113 + contrib/amd/scripts/ctl-hlfsd.in | 101 + contrib/amd/scripts/expn.1 | 1370 +++++ contrib/amd/scripts/expn.in | 1370 +++++ contrib/amd/scripts/fix-amd-map.in | 52 + contrib/amd/scripts/fixrmtab | 24 + contrib/amd/scripts/lostaltmail.conf-sample | 84 + contrib/amd/scripts/lostaltmail.in | 648 ++ contrib/amd/scripts/wait4amd.in | 45 + contrib/amd/scripts/wait4amd2die.in | 49 + contrib/amd/tasks | 64 + contrib/amd/wire-test/wire-test.8 | 70 + contrib/amd/wire-test/wire-test.c | 133 + 153 files changed, 63365 insertions(+) create mode 100644 contrib/amd/AUTHORS create mode 100644 contrib/amd/BUGS create mode 100644 contrib/amd/COPYING create mode 100644 contrib/amd/ChangeLog create mode 100644 contrib/amd/INSTALL create mode 100644 contrib/amd/MIRRORS create mode 100644 contrib/amd/NEWS create mode 100644 contrib/amd/README create mode 100644 contrib/amd/TODO create mode 100644 contrib/amd/amd/am_ops.c create mode 100644 contrib/amd/amd/amd.8 create mode 100644 contrib/amd/amd/amd.c create mode 100644 contrib/amd/amd/amd.h create mode 100644 contrib/amd/amd/amfs_auto.c create mode 100644 contrib/amd/amd/amfs_direct.c create mode 100644 contrib/amd/amd/amfs_error.c create mode 100644 contrib/amd/amd/amfs_host.c create mode 100644 contrib/amd/amd/amfs_inherit.c create mode 100644 contrib/amd/amd/amfs_link.c create mode 100644 contrib/amd/amd/amfs_linkx.c create mode 100644 contrib/amd/amd/amfs_nfsl.c create mode 100644 contrib/amd/amd/amfs_nfsx.c create mode 100644 contrib/amd/amd/amfs_program.c create mode 100644 contrib/amd/amd/amfs_root.c create mode 100644 contrib/amd/amd/amfs_toplvl.c create mode 100644 contrib/amd/amd/amfs_union.c create mode 100644 contrib/amd/amd/amq_subr.c create mode 100644 contrib/amd/amd/amq_svc.c create mode 100644 contrib/amd/amd/autil.c create mode 100644 contrib/amd/amd/clock.c create mode 100644 contrib/amd/amd/conf.c create mode 100644 contrib/amd/amd/conf_parse.y create mode 100644 contrib/amd/amd/conf_tok.l create mode 100644 contrib/amd/amd/get_args.c create mode 100644 contrib/amd/amd/info_file.c create mode 100644 contrib/amd/amd/info_hesiod.c create mode 100644 contrib/amd/amd/info_ldap.c create mode 100644 contrib/amd/amd/info_ndbm.c create mode 100644 contrib/amd/amd/info_nis.c create mode 100644 contrib/amd/amd/info_nisplus.c create mode 100644 contrib/amd/amd/info_passwd.c create mode 100644 contrib/amd/amd/info_union.c create mode 100644 contrib/amd/amd/map.c create mode 100644 contrib/amd/amd/mapc.c create mode 100644 contrib/amd/amd/mntfs.c create mode 100644 contrib/amd/amd/nfs_prot_svc.c create mode 100644 contrib/amd/amd/nfs_start.c create mode 100644 contrib/amd/amd/nfs_subr.c create mode 100644 contrib/amd/amd/ops_TEMPLATE.c create mode 100644 contrib/amd/amd/ops_autofs.c create mode 100644 contrib/amd/amd/ops_cachefs.c create mode 100644 contrib/amd/amd/ops_cdfs.c create mode 100644 contrib/amd/amd/ops_efs.c create mode 100644 contrib/amd/amd/ops_lofs.c create mode 100644 contrib/amd/amd/ops_mfs.c create mode 100644 contrib/amd/amd/ops_nfs.c create mode 100644 contrib/amd/amd/ops_nfs3.c create mode 100644 contrib/amd/amd/ops_nullfs.c create mode 100644 contrib/amd/amd/ops_pcfs.c create mode 100644 contrib/amd/amd/ops_tfs.c create mode 100644 contrib/amd/amd/ops_tmpfs.c create mode 100644 contrib/amd/amd/ops_ufs.c create mode 100644 contrib/amd/amd/ops_umapfs.c create mode 100644 contrib/amd/amd/ops_unionfs.c create mode 100644 contrib/amd/amd/ops_xfs.c create mode 100644 contrib/amd/amd/opts.c create mode 100644 contrib/amd/amd/restart.c create mode 100644 contrib/amd/amd/rpc_fwd.c create mode 100644 contrib/amd/amd/sched.c create mode 100644 contrib/amd/amd/srvr_amfs_auto.c create mode 100644 contrib/amd/amd/srvr_nfs.c create mode 100644 contrib/amd/amq/amq.8 create mode 100644 contrib/amd/amq/amq.c create mode 100644 contrib/amd/amq/amq.h create mode 100644 contrib/amd/amq/amq_clnt.c create mode 100644 contrib/amd/amq/amq_xdr.c create mode 100644 contrib/amd/amq/pawd.1 create mode 100644 contrib/amd/amq/pawd.c create mode 100644 contrib/amd/conf/checkmount/checkmount_bsd44.c create mode 100644 contrib/amd/conf/fh_dref/fh_dref_freebsd22.h create mode 100644 contrib/amd/conf/hn_dref/hn_dref_default.h create mode 100644 contrib/amd/conf/mount/mount_freebsd3.c create mode 100644 contrib/amd/conf/mtab/mtab_bsd.c create mode 100644 contrib/amd/conf/nfs_prot/nfs_prot_freebsd2.h create mode 100644 contrib/amd/conf/nfs_prot/nfs_prot_freebsd3.h create mode 100644 contrib/amd/conf/sa_dref/sa_dref_bsd44.h create mode 100644 contrib/amd/conf/transp/transp_sockets.c create mode 100644 contrib/amd/conf/trap/trap_default.h create mode 100644 contrib/amd/conf/trap/trap_freebsd3.h create mode 100644 contrib/amd/conf/umount/umount_bsd44.c create mode 100644 contrib/amd/doc/am-utils.texi create mode 100644 contrib/amd/doc/stamp-vti create mode 100644 contrib/amd/doc/texinfo.tex create mode 100644 contrib/amd/doc/version.texi create mode 100644 contrib/amd/fixmount/fixmount.8 create mode 100644 contrib/amd/fixmount/fixmount.c create mode 100644 contrib/amd/fsinfo/fsi_analyze.c create mode 100644 contrib/amd/fsinfo/fsi_data.h create mode 100644 contrib/amd/fsinfo/fsi_dict.c create mode 100644 contrib/amd/fsinfo/fsi_gram.y create mode 100644 contrib/amd/fsinfo/fsi_lex.l create mode 100644 contrib/amd/fsinfo/fsi_util.c create mode 100644 contrib/amd/fsinfo/fsinfo.8 create mode 100644 contrib/amd/fsinfo/fsinfo.c create mode 100644 contrib/amd/fsinfo/fsinfo.h create mode 100644 contrib/amd/fsinfo/wr_atab.c create mode 100644 contrib/amd/fsinfo/wr_bparam.c create mode 100644 contrib/amd/fsinfo/wr_dumpset.c create mode 100644 contrib/amd/fsinfo/wr_exportfs.c create mode 100644 contrib/amd/fsinfo/wr_fstab.c create mode 100644 contrib/amd/hlfsd/hlfsd.8 create mode 100644 contrib/amd/hlfsd/hlfsd.c create mode 100644 contrib/amd/hlfsd/hlfsd.h create mode 100644 contrib/amd/hlfsd/homedir.c create mode 100644 contrib/amd/hlfsd/nfs_prot_svc.c create mode 100644 contrib/amd/hlfsd/stubs.c create mode 100644 contrib/amd/include/am_compat.h create mode 100644 contrib/amd/include/am_defs.h create mode 100644 contrib/amd/include/am_utils.h create mode 100644 contrib/amd/include/am_xdr_func.h create mode 100644 contrib/amd/include/amq_defs.h create mode 100644 contrib/amd/libamu/amu.h create mode 100644 contrib/amd/libamu/hasmntopt.c create mode 100644 contrib/amd/libamu/misc_rpc.c create mode 100644 contrib/amd/libamu/mount_fs.c create mode 100644 contrib/amd/libamu/mtab.c create mode 100644 contrib/amd/libamu/nfs_prot_xdr.c create mode 100644 contrib/amd/libamu/util.c create mode 100644 contrib/amd/libamu/wire.c create mode 100644 contrib/amd/libamu/xdr_func.c create mode 100644 contrib/amd/libamu/xutil.c create mode 100644 contrib/amd/mk-amd-map/mk-amd-map.8 create mode 100644 contrib/amd/mk-amd-map/mk-amd-map.c create mode 100644 contrib/amd/scripts/Makefile.am create mode 100644 contrib/amd/scripts/Makefile.in create mode 100644 contrib/amd/scripts/am-eject.in create mode 100644 contrib/amd/scripts/amd.conf-sample create mode 100644 contrib/amd/scripts/amd.conf.5 create mode 100755 contrib/amd/scripts/amd2ldif.in create mode 100755 contrib/amd/scripts/amd2sun.in create mode 100755 contrib/amd/scripts/ctl-amd.in create mode 100755 contrib/amd/scripts/ctl-hlfsd.in create mode 100644 contrib/amd/scripts/expn.1 create mode 100755 contrib/amd/scripts/expn.in create mode 100755 contrib/amd/scripts/fix-amd-map.in create mode 100755 contrib/amd/scripts/fixrmtab create mode 100644 contrib/amd/scripts/lostaltmail.conf-sample create mode 100755 contrib/amd/scripts/lostaltmail.in create mode 100755 contrib/amd/scripts/wait4amd.in create mode 100755 contrib/amd/scripts/wait4amd2die.in create mode 100644 contrib/amd/tasks create mode 100644 contrib/amd/wire-test/wire-test.8 create mode 100644 contrib/amd/wire-test/wire-test.c (limited to 'contrib/amd') diff --git a/contrib/amd/AUTHORS b/contrib/amd/AUTHORS new file mode 100644 index 0000000..e555a74 --- /dev/null +++ b/contrib/amd/AUTHORS @@ -0,0 +1,190 @@ +# -*- text -*- +PRIMARY AUTHORS AND MAJOR CONTRIBUTORS TO AM_UTILS: + +Original authors of amd were the Berkeley team and especially Jan-Simon +Pendry. Since then many people have contributed patches. + +This file lists the ones who contributed major code changes, in no +particular order, and I thank them all. This is of course not to diminish +the smaller contributes of the many others. Thank you all. + +* Erez Zadok + +The most significant changes were made by Erez Zadok in terms of bug fixes, +ports, and new features added. Erez Zadok is the current maintainer of +am-utils, as of January 1997. + +There is a mailing list dedicated to developers of am-utils. To subscribe +to it, send mail to majordomo@majordomo.cs.columbia.edu, with the body of +the message having the single line "subscribe amd-dev". + +* Randall S. Winchester + +May 7, 1997: contributed a special version of upl102 that included NFS V.3 +support. Some of the code was contributed by Christos Zoulas +. I (Erez) ported these changes to am-utils. + +September 12, 1997: lots of small prototype cleanups and fixes to numerous +files. + +January 27, 1998: support pid files in the amd.conf file. Provide base name +for hesiod zone files. Always use /etc/amd.conf if exists. + +* Hannes Reinecke + +Back in 1995, contributed code for linux. A new parser for file system +specific options that only exist under linux. + +* Leif Johansson + +June 22, 1997: minor patch to ensure that systems without an RE library work. + +June 23, 1997: mount options should be properly comma limited. + +July 10, 1997: info_ldap.c and prototype changes to all map _init and _mtime +functions. Contributed scripts/amd2ldif.pl. + +August 4, 1997: info_ldap.c fixes and adding two new amd.conf ldap +variables: ldap_cache_seconds and ldap_cache_maxmem. + +* Andreas Stolcke + +June 22, 1997: patches to ensure that proto= and vers= options work +properly in mount tables and can be overridden. Later on, more code +contribued to optimize the best combination of proto/vers. + +July 4, 1997: patches to get NFS V.3 working under irix5. + +September 9, 1997: initialize all fields of mntent_t structures to 0. + +October 2, 1997: don't log an RPC timeout as an error but only as an info +message. + +December 19, 1997: detected an FMR (Free Memory Read) in amd/mntfs.c, +uninit_mntfs(). + +* Danny Braniss + +July, 6 1997: contributed patches to hesiod on bsdi3. + +* Tom Schmidt + +July 10, 1997: Recommdation to include libgdbm if libc has no dbm_open. +Patches for netgrp(host) command. Mods to aux/config.guess to recognize +sun3. + +January 19, 1998: print correct -l option depending if system supports +syslog and/or syslog facilities. + +January 29, 1998: fix for 0.0.0.0 loopback on SunOS 3.X which defines +IFF_ROUTE instead of IFF_LOOPBACK. + +* Daniel S. Riley + +July 11, 1997: fixes to DU-4.0 to support string POSIX.1 signals, and struct +sockaddr with sa_len field. + +July 13, 1997: Move amd.conf parsing to before switch_option() on log/debug +options. Minor type wrt "ro" option in libamu/mount_fs.c. Added more +fillers of mnttab options, for acdirmax, acdirmin, acregmax, acregmin, noac, +grpid, nosuid, and actimo. + +* Roman Hodek + +July 23, 1997: Got lots of patches from the Debian Linux folks, who fixed +several generic bugs, and one serious one for Linux. The latter involved +using connected sockets for NFS mounts on kernels 1.3.10 and older. Roman's +work is baed on amd-upl102, and work from Ian Murdock +and Dominik Kubla . + +* Rainer Orth + +August 6, 1997: assorted fixes to support hesiod-1.3, solaris 2.4 (which I +already fixed but did not release yet), and support for $LDFLAGS at +configure/compile time. + +February 24, 1998: lots of patches for ultrix 4.3 port. + +February 28, 1998: lots of documentation fixes! + +* Jason Thorpe + +August 25, 1997: make amd work when talking to NIS+ servers in NIS +compatibility mode. Fix originally came from Matthieu Herrb +. + +* Chris Metcalf + +August 29, 1997: patch to make amd use FQHN for NFS/RPC authentication, +useful esp. for cross-domain NFS mounts. +September 2, 1997: if plock() succeeded, don't display errno string. + +* Enami Tsugutomo + +September 4, 1997: don't ping remote servers with NFS V.3 always, but V.2, +regardless of client's NFS version. (conf/transp/transp_sockets.c) + +* Dan Riley + +September 19, 1997: make sure that amd works with more secure portmappers +that do not allow forwarding of RPC messages to other services. + +* Wolfgang Rupprecht + +August 10, 1997: netbsd and other bsd systems have a mask flag for +pcfs_args (msdos mount). + +* Christos Zoulas + +September 25, 1997: fix to initialize uid/gid fields of pcfs_args_t on +netbsd. + +October 10, 1997: compile time cleanups of printf()s in hlfsd code. If nfs +server is down or does not support a portmapper call, then mark it down as +version 2, and try again later. + +* Bill Paul + +November 5, 1997: NFS v.3 support for AIX 4.2.1, which does *not* include +headers for this. Bill had to guess at the right structures, field names, +sizes, alignment, etc. + +* Stefan Vogel + +November 14, 1997: typo in the subscription instructions to amd-dev. + +* Guntram Wolski + +November 15, 1997: pointed out mismatching documentation for the -o option. + +* Michael Hucka + +January 11, 1997: pointed out reversed definition of NFS mount options vers +and proto. + +* Albert Chin + +January 12, 1998: minor bug in output of amd -H. + +* Thomas Richter + +January 13, 1998: use case insensitive comparisons for variables that need +it (such as all hostname related ones, and more). + +* Fred Korz + +January 30, 1998: minor typo fixed to tftp example in am-utils.texi. + +* Donald Buczek + +March 6, 1998: correctly inherit existing NFS V.3 mounts upon restart. + +March 17, 1998: compare log file name and syslog string with correct length. + +March 20, 1998: do not close stdout in case it gets reused elsewhere and to +allow startup script to redirect it. Set a temporary secure umask(0022) +before writing log file and restore it afterwards. + +* Matthew Crosby +April 20, 1998: allow arbitrary number of interfaces in wire listing. + diff --git a/contrib/amd/BUGS b/contrib/amd/BUGS new file mode 100644 index 0000000..125714d --- /dev/null +++ b/contrib/amd/BUGS @@ -0,0 +1,73 @@ +# -*- text -*- + + LIST OF KNOWN BUGS IN AM-UTILS OR OPERATING SYSTEMS + + +(1) mips-sgi-irix* + +[1A] known to have flakey NFS V.3 and TCP. Amd tends to hang or spin +infinitely after a few hours or days of use. Users must install recommended +patches from vendor. Patches help, but not all the time. Otherwise avoid +using NFS V.3 and TCP on these systems, by setting + + /defaults opts:=vers=2,proto=udp + +[1B] yp_all() leaks a file descriptor. Eventually amd runs out of file +descriptors and hangs. Am-utils circumvents this by using its own version +of yp_all which uses udp and iterats over NIS maps. The latter isn't as +reliable as yp_all() which uses TCP, but it is better than hanging. + + +(2) alpha-unknown-linux-gnu (RedHat Linux 4.2) + +hasmntopt(mnt, opt) can goes into an infinite loop if opt is any substring +of mnt->mnt_opts. Redhat 5.0 does not have this libc bug. Here is an +example program: + +#include +#include +main() +{ + struct mntent mnt; + char *cp; + mnt.mnt_opts = "intr,rw,port=1023,timeo=8,foo=br,retrans=110,indirect,map=/usr/local/AMD/etc/amd.proj,boo"; + cp = hasmntopt(&mnt, "ro"); + printf("cp = %s\n", cp); + exit(0); +} + + +(3) mips-dec-ultrix4.3 + +Rainer Orth reports + +[3A] At least the gcc 2.7.0 fixincludes-mangled needs a +forward declaration of struct utsname to avoid lots of gcc warnings: + +RCS file: RCS/utsname.h,v +retrieving revision 1.1 +diff -u -r1.1 utsname.h +--- utsname.h 1995/06/19 13:07:01 1.1 ++++ utsname.h 1998/01/27 12:34:26 +@@ -59,6 +59,7 @@ + #ifdef KERNEL + #include "../h/limits.h" + #else /* user mode */ ++struct utsname; + extern int uname _PARAMS((struct utsname *)); + #endif + #define __SYS_NMLN 32 + +[3B] It autoconfigures and compiles cleanly, but currently hangs after a +couple of hours without leaving any traces in the syslog output. + + +(4) powerpc-ibm-aix4.2.1.0 + +[4A] "Randall S. Winchester" reports that for amd to +start, you need to kill and restart rpc.mountd and possibly also make sure +that nfsd is running. Normally these are not required. + +[4B] "Stefan Vogel" reports that if your amq +executable dump core unexpectedly, then it may be a bug in gcc 2.7.x. +Upgrade to gcc 2.8.x or use IBM's xlC compiler. diff --git a/contrib/amd/COPYING b/contrib/amd/COPYING new file mode 100644 index 0000000..49783ec --- /dev/null +++ b/contrib/amd/COPYING @@ -0,0 +1,37 @@ +Copyright (c) 1997-1998 Erez Zadok +Copyright (c) 1989 Jan-Simon Pendry +Copyright (c) 1989 Imperial College of Science, Technology & Medicine +Copyright (c) 1989 The Regents of the University of California. +All rights reserved. + +This code is derived from software contributed to Berkeley by +Jan-Simon Pendry at Imperial College, London. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgment: + This product includes software developed by the University of + California, Berkeley and its contributors, as well as the Trustees of + Columbia University. +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/contrib/amd/ChangeLog b/contrib/amd/ChangeLog new file mode 100644 index 0000000..3a05928 --- /dev/null +++ b/contrib/amd/ChangeLog @@ -0,0 +1,3039 @@ +Thu Apr 23 00:22:17 1998 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a16 *** + ******************************************************************* + +Wed Apr 22 01:20:39 1998 Erez Zadok + + * aux/macros/check_mount_style.m4: define freebsd3 mount style. + + * aux/macros/check_mount_trap.m4: new mount trap for freebsd3. + + * aux/macros/check_mtype_printf_type.m4, + aux/macros/check_mtype_type.m4 (ac_cv_mtype_type,): freebsd3 (as + of snapshot 3.0-980311-SNAP) uses char * types for mount(2), not + integers, but I'll keep them as integers and do the mapping in + conf/mount/mount_freebsd3.c + + * minor new port to i386-pc-bsdi3.1. + + * minor new port to i386-unknown-netbsd1.3.1. + + * amd/opts.c: new option addopts:=ARG, which smartly merges ARG + options with whatever the /default ones for a key are. This + allows adding or overriding /default options individual keys. + + * amd/am_ops.c (ops_match): strdup/malloc string assigned to + opt_opts because it'll get free()'d upon next use. + (merge_opts): new function to merge two sets of options. + (ops_match): if addopts option exist, append and merge it to the + current default options. + +Tue Apr 21 12:54:59 1998 Erez Zadok + + * wire-test/wire-test.c (main): use dynamically allocated returned + string with list of interfaces. + + * amd/get_args.c (get_version_string): allocate enough space for + header version string and a list of network interfaces of any + length. + + * libamu/wire.c (print_wires): return dynamically allocated string + containing list of networks. Must be dynamic because some sites + had potentially dozens of network interfaces. Patch from Matthew + Crosby slightly modified. + +Mon Apr 20 00:37:20 1998 Erez Zadok + + * conf/nfs_prot/nfs_prot_irix5.h: underfine MNTTYPE_XFS because + irix 5.3 does not have full header definitions for it. + + * fsinfo/fsi_lex.l (yywrap): define yywrap if needed, and + undefined it when not needed (similar to amd/conf_tok.l) + + * hlfsd/hlfsd.h (ROOTID, SLINKID, INVALID): reduced maximum size + of these to unsigned short (because uid_t on some linux systems is + small). + + * released snapshot am-utils-6.0a16s10 + + * doc/am-utils.texi (opts Option): documented resvport mount + option. + +Sun Apr 19 18:17:03 1998 Erez Zadok + + * doc/am-utils.texi (-D-Option): document behavior of -D info and + especially what it does to hesiod (turn on RES_DEBUG). + + * scripts/amd.conf.5: document info debugging option. + + * libamu/xutil.c (dbg_opt): parse info debugging option. + + * include/am_utils.h (D_INFO): define new trace option. + + * Makefile.am (EXTRA_DIST): include list of official mirrors in + distribution. + + * libamu/wire.c (SIZE): in the simple case, just compute + sizeof(struct ifreq). + +Sun Apr 19 16:30:35 1998 Erez Zadok + + * amd/amd.c (daemon_mode): set a temporary secure umask(0022) + before writing log file and restore it afterwards. Patch from + Donald Buczek . + + * amd/get_args.c (get_args): + + * doc/am-utils.texi (-F Option), amd/amd.8: mention that amd.conf + file specified by -F is always processed last. + + * amd/amd.c (daemon_mode): do not fclose(stdout) so that the fd + won't be reused. Allows startup script to redirect stdout. Patch + from Donald Buczek . + + * libamu/xutil.c (switch_to_logfile): compare logfile name and + syslog string with correct length. Patch from Donald Buczek + . + + * amd/restart.c (restart): correctly inherit existing NFS V.3 + mounts upon restart. Patch from Donald Buczek + . + +Sat Apr 18 19:01:19 1998 Erez Zadok + + * using libtool 1.2 and automake 1.3 (with my patches). + + * aux/macros/opt_am_cflags.m4, */Makefile.in: rename AM_CFLAGS to + AMU_CFLAGS to avoid conflicts with automake-1.3. + +Sun Apr 5 23:09:08 1998 Erez Zadok + + * converted to using libtool-1.2. + +Tue Mar 10 16:52:09 1998 Erez Zadok + + * fsinfo/fsi_analyze.c (fixup_required_mount_info): replaced silly + for loop (ITER) which used to run only to initialize the variable + dd once and then break; with a simple assignment. + + * hlfsd/hlfsd.h: cleanup so it compiles with Solaris + /opt/SUNWspro/bin/cc, and use gid_t not int. + + * amd/mapc.c (mapc_sync): don't dereference pointer (so it + compiles with Solaris /opt/SUNWspro/bin/cc) + +Sun Mar 8 15:54:22 1998 Erez Zadok + + * aux/config.{guess,sub}: used from gcc-2.8.1. + +Sat Mar 7 15:33:27 1998 Erez Zadok + + * released snapshot am-utils-6.0a16s9 + + * INSTALL, doc/am-utils.texi (Supported Platforms): updated names + based on new output of new config.guess. + + * aux/config.{sub,guess}: used newer versions from gcc-2.8.0. + + * amd/amd.8,doc/am-utils.texi: document correct usage of default + /etc/amd.conf file. + + * fixmount/fixmount.c (inetresport,privsock): use some more + portable code from amq/amq.c. + + * amd/get_args.c (get_args): use default /etc/amd.conf file only + if no arguments had been passed to amd. + + * fixmount/fixmount.c (clnt_create_timeout): use tli/socket code + ala amq/amq.c so that fixmount will work on both types of systems. + + * amq/amq.c (main): do no close tcp socket before running udp try, + because we're not sure if it was opened at all. + + * mips-dec-ultrix* port merged in and cleaned up. + + * aux/configure.in: up minor shared library revision number, since + it has changed enough. + + * hlfsd/hlfsd.c (main): don't check for overlay mount option here, + as it is now done in compute_nfs_args(). Remove ultrix specific + code also because it was moved to compute_nfs_args(). + + * conf/mount/mount_svr4.c: removed DEBUG_MOUNT_SVR4 code, now that + we have more generic code in print_nfs_args(). + + * libamu/mount_fs.c (print_nfs_args): print maxlen of + nfs_args.addr, and also syncaddr (which is mostly NULL). Print + struct knetconfig from nfs_args->knconf. + + * aux/macros/mount_headers.m4 (define): do not check for ufs/cdfs + headers here, but in try_compile_anyfs.m4. + + * aux/macros/type_ufs_args.m4: move test for struct ufs_specific + (for ultrix) here from its own macro. + + * aux/macros/type_cdfs_args.m4: move test for struct iso_specific + (for ultrix) here from its own macro. + + * amd/ops_nfs.c (mount_nfs_fh): no need to run code again checking + for overlay mount option. Remove code which checks for overlay + option, as it is now done in compute_nfs_args(). + + * libamu/mount_fs.c (compute_mount_flags): move here code which + checks for overlay mount option which was in amd/amfs_toplvl.c: + mount_amfs_toplvl(). + +Wed Feb 7 15:35:51 1998 Rainer Orth + + * The following are Rainer's ChangeLog entries for his ultrix + port, added manually. -Erez. + + * merged Ultrix port with am-utils 6.0 a16s5: amd/ops_afs.c + (mount_toplvl) -> amd/amfs_toplvl.c (mount_amfs_toplvl) + + * include/am_defs.h: include cdfs specific mount headers avoid + duplication definition of gt_names[] in (Ultrix) + + * include/am_compat.h: define several mount options corresponding + to mount flags: pgthresh, hard (nfs), defperm, nodefperm, + noversion, rrip (cdfs), nocache, quota, sync (generic) removed + duplicate MNTTAB_OPT_RO definition + + * aux/macros/try_compile_anyfs.m4: include Ultrix specific + ufs/cdfs mount headers + + * aux/macros/mount_headers.m4: include several Ultrix/Digital UNIX + specific mount headers + + * aux/macros/check_{fs_mntent, mount_type}.m4: check for GT_* + mount types in mount headers (Ultrix) + + * aux/configure.in: Ultrix/Digital UNIX specific checks: new + headers, mount structures and fields, filesystem and mount types, + mount flags + + * aux/acconfig.h: placeholders for new mount options: quota + (generic), ro (nfs), defperm, nodefperm, noversion, rrip (cdfs) + cdfs, nfs, ufs mount structure fields new ufs, cdfs mount + structures + + * amd/ops_ufs.c (mount_ufs): Ultrix stores generic mount flags in + ufs_args.ufs_flags and has ufs specific pgthresh option + + * amd/ops_cdfs.c (mount_cdfs): handle Ultrix/Digital UNIX specific + CDFS mount flags and options + + * amd/ops_afs.c (mount_toplvl), amd/ops_nfs.c (mount_nfs_fh), + hlfsd/hlfsd.c (main): store generic mount flags in + nfs_args.gfs_flags, handle separate NFS ro flag + + * aux/macros/{check_mnt2_cdfs_opt, struct_iso_specific, + struct_ufs_specific}.m4: new files; check for Ultrix specific + mount structures + + * conf/trap/trap_ultrix.h: arg 3 to mount(2) is rwflag + + * aux/macros/type_auth_create_gidlist.m4 (ultrix*): + AUTH_CREATE_GIDLIST_TYPE is int (not short == gid_t) from a + comment in + + * include/am_defs.h: #define KERNEL to avoid definition of + gt_names[] conf/mtab/mtab_ultrix.c: #include before + to force single definition here + + * libamu/mount_fs.c (compute_nfs_args): Ultrix support for + nfs_args.gfs_flags moved to callers store mount options in + nap->optstr + + * include/am_defs.h: fix _am_mntent mnt_{type, opts} field + descriptions + + * aux/macros/mount_headers.m4, aux/macros/try_compile_nfs.m4: + include before AMU_NFS_PROTOCOL_HEADER for svc_req + definition in prototypes + + * aux/macros/mount_headers.m4: include before + AMU_NFS_PROTOCOL_HEADER: needs it for NFSERR_* + definitions + + * aux/aclocal: adapt for local perl path and $prefix + + * conf/nfs_prot/nfs_prot_ultrix.h: new file + + * aux/macros/check_nfs_prot_headers.m4: use nfs_prot_ultrix.h + + * aux/macros/mount_headers.m4, aux/macros/try_compile_nfs.m4, + aux/macros/try_compile_rpc.m4, include/am_defs.h: avoid multiple + inclusion of + +Sat Mar 7 13:56:05 1998 Erez Zadok + + * aux/configure.in: save state of config.cache and confdefs.h + (as dbgcf.h) at various points of the configure. + + * aux/macros/save_state.m4: new macro to save state of configure, + esp. useful in long ones. Saves confdefs.h and write $ac_cv_* + cache variables that are known so far. + + * released snapshot am-utils-6.0a16s8 + +1998-03-06 Erez Zadok + + * fsinfo/fsi_lex.l,amd/conf_tok.l: define ECHO after undefining + it, but only for flex. + +Fri Mar 6 17:23:17 1998 Erez Zadok + + * hlfsd/homedir.c (plt_print): change pathname of hlfsd dump file + to /usr/tmp/hlfsd.dump.XXXXXX, and use a safe method (if possible) + to write the dump file. + + * doc/am-utils.texi,amd/opts.c: rename all references to nomadic + functions to boolean functions, which is what they really are. + + * aux/configure.in: don't look for strcasecmp in libucb at all, + but rather complete it from libamu/strcasecmp.c as needed. + +Fri Mar 6 03:29:20 1998 Erez Zadok + + * conf/nfs_prot/nfs_prot_osf4.h: avoid conflicts with Irix's EFS. + + * libamu/wire.c (getwire): fix for 0.0.0.0 loopback on SunOS 3.X + which defines IFF_ROUTE instead of IFF_LOOPBACK. Patch from Tom + Schmidt . + + * released snapshot am-utils-6.0a16s7 + + * conf/nfs_prot/nfs_prot_hpux11.h: a first working port of amd to + hppa1.0-hp-hpux11.00.tgz. + +Thu Mar 5 21:59:03 1998 Erez Zadok + + * converted all sources to use mntent field names, and map mnttab + field names to mntent's. + + * include/am_defs.h (mnt_special): map struct mnttab field names + to struct mntent field names. + + * aux/macros/check_mount_trap.m4: hpux11's mount trap style is + identical to svr4/solaris2. + + * aux/macros/check_mount_style.m4: hpux11's mount style is + identical to svr4/solaris2. + + * aux/macros/check_network_transport_type.m4: hpux11 is a TLI + system! + + * aux/macros/check_nfs_sa_dref.m4: hpux11's NFS host address + dereferencing style is same as svr4. + + * aux/macros/check_nfs_fh_dref.m4: hpux11's NFS file fh + dereferencing style is same as svr4. + + * conf/transp/transp_tli.c (create_nfs_service): if failed to + getnetconfigent() of ticlts, then try udp (hpux11). + + * conf/nfs_prot/nfs_prot_hpux11.h: added correct definitions for + struct nfs_args, nfs_fh, and NFSMNT_* flags, taken from solaris + 2.5.1 (HP used them). + + * amd/rpc_fwd.c (fwd_init): don't use O_NDELAY for t_open() + because hpux11 doesn't like it. if t_open failed, print error + based on t_errlist, not sys_errlist. + +Wed Mar 4 22:01:55 1998 Erez Zadok + + * doc/am-utils.texi: lots of documentation fixes from Rainer Orth + . + +Sat Feb 28 22:16:35 1998 Erez Zadok + + * fsinfo/fsi_lex.l: undefine ECHO again, so it doesn't get used + later. + + * include/am_defs.h: defined the extern for ualarm() if it isn't + found, regardless if the function isn't found in standard + libraries, because otherwise libamu will include it. + +1998-02-28 Erez Zadok (per Ron Snyder) + + * initial port to hpux-11 completed. Compiles cleanly, but + probably does not work, because of missing NFS V.2/3 headers. + + * amd/conf_tok.l: cast yytext to char* when passed to strlen and + strdup, for hpux-11's ansi-cc compiler. + + * include/am_utils.h: renamed all xfree() to XFREE() to avoid + conflict with hpux-11's system headers. Also move (voidp) cast + from sources to inside the macro itself. + +Sat Feb 28 13:44:21 1998 Erez Zadok + + * released snapshot am-utils-6.0a16s6 + + * amd/info_nis.c (nis_isup): new function to test if NIS is up + without hanging amd. Used to ensure that amd does not clear the + maps when the expiration period arrived, if the service is down. + Otherwise it would be left with empty maps. It is better to stay + with possibly old information than none at all. + + * amd/mapc.c (mapc_sync): check to see if map service is up. + +Tue Feb 24 02:19:42 1998 Erez Zadok + + * aux/macros/check_lib2.m4 (AC_CHECK_LIB2): fix macro so it + includes auxiliary library only if needed. + +1998-02-22 Erez Zadok + + * amd/conf_tok.l: undefine ECHO again, so it doesn't get used + later. + +Sun Feb 22 01:41:08 1998 Erez Zadok + + * conf/nfs_prot/nfs_prot_osf2.h: port to alpha-dec-osf2.1 + completed. + + * conf/mtab/mtab_osf.c (mnt_dup): not all OSF have NFS3. + +Sat Feb 21 19:45:48 1998 Erez Zadok + + * doc/am-utils.texi (Network Host Filesystem): correct example for + type:=host map. + + * aux/macros/os_cflags.m4: only osf4 should compile with + -D_SOCKADDR_LEN. + + * aux/macros/check_nfs_prot_headers.m4: distinguish between OSF2 + and OSF4. + + * BUGS: include a new file listing known bugs. + +Sat Feb 21 03:50:48 1998 Erez Zadok + + * conf/nfs_prot/nfs_prot_linux.h: turn DES off on all linux + versions. + + * aux/macros/type_recvfrom_fromlen.m4: linux alpha should use + size_t for recvfrom fromlen arg. + +Sat Feb 21 03:33:59 1998 Erez Zadok + + * scripts/ctl-hlfsd.in: turn -D fork so primary process never + hangs. + +Sat Feb 21 02:45:51 1998 Erez Zadok + + * include/am_defs.h: don't include and + , just remaining definitions in + +Thu Jan 29 00:44:28 1998 Erez Zadok + + * released snapshot am-utils-6.0a16s5 + + * conf/mount/mount_irix6.c (mount_irix): pass {u,e,x}fs_args to + mount(2). + + * check for and include it when needed. + + * conf/mount/{mount_irix5.c,mount_irix6.c} (mount_irix): recognize + efs and xfs separately from "ufs". + + * amd/{ops_xfs.c,ops_efs.c}: new support for irix xfs/efs. + + * aux/configure.in: look for irix efs and xfs file systems. + + * scripts/amd.conf.5: new unmount_on_exit option documented. + + * doc/am-utils.texi (unmount_on_exit): new option documented. + + * amd/conf.c (gopt_unmount_on_exit): new function to handle new + amd.conf option. + + * amd/map.c (umount_exported): if global amd.conf flag + unmount_on_exit is on, then try to unmount all mounted (or + restartable) file systems. + + * amd/amd.c: if print_pid option is on, then normally print it to + stdout. If also pid_file is specified, then print the process ID + into that file. + + * amd/get_args.c (get_args): print correct -l option depending if + system supports syslog and/or syslog facilities. Patch from + Tom Schmidt . + + * doc/am-utils.texi (opts Option): updates for documentation for + new cdfs options defperm, nodefperm, noversion, rrip. + + * amd/ops_cdfs.c (mount_cdfs): support cdfs options defperm, + nodefperm, noversion, rrip. + + * conf/nfs_prot/nfs_prot_osf.h: need to look at + on osf. + + * aux/macros/{expand_cpp_hex.m4, expand_cpp_int.m4, + expand_cpp_string.m4}: use #error to make failed compilations + fail faster, rather than have the program fail during a run. + + * include/am_compat.h: added a few new cdfs options: rrip, + noversion, defperm, and nodefperm (used in OSF). + +Wed Jan 28 20:24:09 1998 Erez Zadok + + * released snapshot am-utils-6.0a16s4 + + * doc/am-utils.texi (Global Parameters): update manual for new + amd.conf global variable hesiod_base. + + * scripts/amd.conf.5: update man page for new amd.conf global + variable hesiod_base. + + * amd/get_args.c (get_args): use /etc/amd.conf file if exists by + default, else try command line options. Patch from Randall + S. Winchester . + +Wed Jan 28 12:20:56 1998 Erez Zadok + + * amd/info_hesiod.c (hesiod_search), amd/conf.c + (gopt_hesiod_base), amd/amd.h, amd/amd.c (init_global_options): + included patch from Randall S. Winchester , to + support a hesiod base name in the amd.conf file. + + * doc/am-utils.texi (pid_file Parameter): document new global + amd.conf parameter. + + * scripts/amd.conf.5: document new global option pid_file. + + * amd/amd.c (daemon_mode): if cannot open pid_file, continue to + run, but print error message. + + * amd/conf.c (gopt_pid_file), amd/amd.h, amd/amd.c (daemon_mode, + init_global_options): Included patch from Randall S. Winchester + , to support pid files in the amd.conf file. + + * amd/get_args.c (get_args): correct usage info on amd -t. + + * amd/*.c: massive file name and symbol name changes. All amd + file systems files and symbols are prefix with amfs_*. Now using + real name of file system: amfs_auto instead of afs, amfs_inherit + instead of ifs, amfs_linkx instead of sfsx, etc. This will enable + clear distinction between amd file system and generic ones like + nfs/ufs/pcfs/hsfs. Also, now we can implement true afs (Andrew + f/s) and DFS (Distributed f/s). + + * amd/amfs_union.c: unionfs for amd is always defined, no need to + #ifdef it. + +Mon Jan 26 16:51:38 1998 Erez Zadok + + * libamu/mount_fs.c (compute_nfs_args): set 'noconn' NFS option on + or off, based on the particular quirks of the OS in question. + + * aux/macros/check_nfs_socket_connection.m4: new macro to set the + correct wait of handling un/connected NFS sockets. + + * scripts/wait4amd.in: use rlogin instead of rsh. + + * amd/am_ops.c (ops_showfstypes): when showing F/S types in amd + -v, always show "nfs3" for NFS V.3. + +1998-01-25 Erez Zadok + + * lots of small fixes for solaris 2.6, since gcc 2.8.0 -Wall gets + more picky than 2.7.2.3 did. + +1998-01-24 Erez Zadok + + * include/am_utils.h (dlog): amuDebug macros reduced to shorter + forms. + +Fri Jan 23 18:38:30 1998 Erez Zadok + + * released snapshot am-utils-6.0a16s3 + + * include/am_defs.h: on Solaris 2.6, is included + in but since stdargs.h is used, and varargs.h + must not, fake a definition for varargs. + +Fri Jan 16 10:16:40 1998 Erez Zadok + + * README: show how to configure in additional support such as + hesiod using various --enable-* flags. + +Wed Jan 14 15:13:02 1998 Erez Zadok + + * aux/configure.in: look for strcasecmp(), and replace it if not + available. + + * amd/ops_nfsl.c (nfsl_match): host names should be compared using + case insensitive. + + * amd/opts.c: for each map variable, define if the comparison + needs to be done case insensitive. + + * include/am_utils.h (STRCEQ): a new macro to use strcasecmp(). + Patch from Thomas Richter + +1998-01-14 Erez Zadok + + * aux/configure.in: look for "isofs" as a possible mount type for + cdfs (RedHat Linux). + +Wed Jan 14 02:07:05 1998 Erez Zadok + + * conf/mount/mount_linux.c (parse_opts): don't look for cdfs mount + type if not defined. + + * conf/nfs_prot/nfs_prot_linux.h: don't define __FD_* macros if + already defined. + + * aux/configure.in: look for ext2fs before ufs, b/c some linux + have both. + +Mon Jan 12 15:43:20 1998 Erez Zadok + + * Makefile.am (snapshot): allow me to install snapshots into the + ftp directory. + + * scripts/ctl-hlfsd.in: don't turn on -D mem by default. + + * amd/get_args.c (get_args): minor bug in output of amd -H. + +Mon Jan 12 03:05:06 1998 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a15 *** + ******************************************************************* + +Sun Jan 11 15:06:34 1998 Erez Zadok + + * amd/conf.c (*_browsable_dirs): allow specifying + browsable_dirs=full, which will print *all* entries (other than + /default), including those with '*' and '/' characters. + + * amd/info_file.c (MAX_LINE_LEN): up maximum readdir chain length + to 1500. + + * doc/am-utils.texi: fixed reversed documentation for NFS mount + options vers and proto. + + * doc/Makefile.am (install-html): separate target just for + installing html files. Another new target "alldocs" is just for + installing all files needed for the am-utils home page. + + * scripts/amd.conf-sample: updated example for log_file. + + * scripts/amd.conf.5: updated for new way to declare new syslog + facility in the log_file option. + + * amd/amd.8: updated for new way to declare new syslog facility in + the -l option. + + * libamu/xutil.c (get_syslog_facility): allow users to specify the + syslog facility as an appended string to the log device. Ex. amd + -l syslog:local7 will use LOG_LOCAL7, while the older -l syslog + will use the default LOG_DAEMON facility. + + * amd/get_args.c (get_args): updated new syntax for amd -l + syslog:facility. + +Thu Jan 8 04:05:10 1998 Erez Zadok + + * aux/macros/host_macros.m4: don't confuse sun3 (sparc) with sun3 + (intel). + + * libamu/wire.c (print_wires): bug fix. Nullify output buffer + before appending to it, on systems with two or more network + interfaces. + + * conf/nfs_prot/nfs_prot_sunos5_3.h: add missing definition for + the mntent for cachefs. + + * include/am_defs.h: external definition for strstr() should use + const for both arguments. + + * aux/configure.in: add extern definitions for getwd() if missing. + + * include/am_defs.h: define the extern for strdup() even if the + function does not exist, for it will be filled in by + libamu/strdup.c + + * amq/pawd.c (cluster_server): don't use getccent() if the extern + for it isn't there. On hpux 10.20, the function is in libc, but + and struct cct_entry do not exist. + + * aux/configure.in: check for an extern for getccent() b/c some + hpux systems don't have it (hpux 10.20). + +Wed Jan 7 00:09:19 1998 Erez Zadok + + * doc/am-utils.texi (Amq -T option): manual documentation updates + for new amq options -T/-U. + + * amq/amq.8: updated man page for new amq options -T/-U. + + * amq/amq.c: two new switches to amq. -U will contact amd using + UDP only. -T will use TCP only. Normally amq will try TCP and + if that failed, will try UDP. + + * doc/am-utils.texi (pawd): manual documentation for pawd. + + * amq/pawd.1: new man page for pawd. + +Tue Jan 6 04:21:59 1998 Erez Zadok + + * amq/pawd.c: a new program, Print Automounter Working Directory, + to print the proper pathname of the cwd or any other pathname, + adjusted for automounter paths, while avoiding mount points. + + * aux/macros/localconfig.m4: trivial support for am-utils + maintainers to adjust some of the configuration of am-utils after + it has been auto-configured by putting whatever definitions you + wish in a file called localconfig.h, located in the top build + directory (the same one where config.h is created for you). + + * doc/am-utils.texi (Caching Filesystem): updated documents for + cachefs file system. + + * amd/ops_cachefs.c: initial cachefs support, for solaris. + type:=cachefs, requires cachedir:=/cache/dir/name to be defined + and initialized with cfsadmin -c. $rfs is backdir to be cached + from, and $fs is the local mount point of the cachefs. + + * conf/mount/mount_svr4.c (mount_svr4): support mounting of + cachefs file systems. + + * amd/ops_cdfs.c: cdfs should be named 'cdfs', not whatever the + mnttab type is. + +Mon Jan 5 23:22:49 1998 Erez Zadok + + * amd/opts.c: added support for new variable $cachedir. + + * include/am_utils.h: added opt_cachedir field to struct am_opts. + +Sat Jan 3 01:43:57 1998 Erez Zadok + + * amd/ops_nfsl.c (nfsl_ffserver, nfsl_match): also check if the + local hostname does not match $rhost, and if so, also assume + type:=nfs. + +Fri Jan 2 01:00:40 1998 Erez Zadok + + * updated all source files to add 1998 as a copyright year. + + * amd/ops_nfsl.c: new amd meta file system "type:=nfsl". Behaves + like type:=linkx if the pathname denoted by $fs exists, and like + type:=nfs if it does not. A convenient shortcut for the most + popular amd map entry. + + * amd/amd.c (main): amd should chdir to / before starting, to + avoid hanging on other NFS server if started elsewhere. + + * amd/ops_TEMPLATE.c: added an empty template file for developers + who wish to write new amd pseudo file systems. + +Thu Jan 1 00:27:28 1998 Erez Zadok + + * hlfsd/homedir.c (plt_init): make function exported, to save on + the unnecessary init_homedir() function which was removed. + (table_add): don't use xmalloc() when you can use strdup() + instead. + +Thu Jan 1 00:15:58 1998 Erez Zadok + + * hlfsd/homedir.c (hlfsd_endpwent): Don't actually run this + because we will be making more passwd calls afterwards. On + Solaris 2.5.1, making getpwent() calls after calling endpwent() + results in a memory leak! (and no, even Purify didn't detect + it...) + +Tue Dec 23 18:23:47 1997 Erez Zadok + + * hlfsd/hlfsd.c (main): Bug fix. Don't try to free() an + automatically allocated address. + + * amd/ops_afs.c (mount_toplvl): Bug fix. Don't try to free() an + automatically allocated address. + + * ALL SOURCES: change every direct call to free() to xfree(), so + it can be mapped to the right debugging function as needed. + + * include/am_utils.h: new free() policy. If debugging memory, + call dxfree(), which will print the file name and line number + where the free occurred and the pointer address. if only regular + debugging, then free() and reset the pointer to NULL so it cannot + be used afterwards inadvertently. If not DEBUG at all, then just + run free(). Three different #define macros set the right mapping. + + * libamu/xutil.c (dxfree): renamed function to dxfree(), so it can + be called only when debugging the memory. + +Tue Dec 23 04:24:28 1997 Erez Zadok + + * wire-test/wire-test.c (main): use xmalloc() not malloc(). + + * conf/transp/transp_tli.c (get_knetconfig): use xzalloc() not + calloc(). + + * conf/mtab/mtab_mach3.c (convert): use xzalloc() not calloc(). + + * conf/mount/mount_linux.c (parse_opts): use xmalloc() not + malloc(). + + * amd/info_ldap.c: use xmalloc() not malloc(). + + * libamu/xutil.c (xzalloc): new function to allocate memory and + zero its bytes. + + * amq/amq.c: amq does not need its own definition of xfree(). + + * aux/macros/opt_debug.m4: if used --enable-debug=mem, then also + look for function malloc_verify() in libmapmalloc.a, and function + mallinfo() in libmalloc. + + * libamu/xutil.c (checkup_mem): do not use mallinfo field + uordbytes, because it does not always exist. Rather, compute it + from other fields.. + + * include/am_utils.h: add external definition to xfree() function + used when debugging memory references. + +Mon Dec 22 03:01:30 1997 Erez Zadok + + * amd/ops_afs.c (afs_readdir_browsable): reduce the number of + bytes heuristically computed to be returned to the kernel. + Otherwise browsable_dirs fails on OpenBSD 2.2. + + * amd/mntfs.c (uninit_mntfs): bug fix. Moved freeing of + mf_private field to AFTER it gets used. + +Sat Dec 20 00:51:21 1997 Erez Zadok + + * amd/ops_host.c (host_umounted): don't use clnt_spcreateerror() + on systems that don't support it. + + * include/am_defs.h: add missing extern definition for free(). + + * aux/configure.in: check for external definition for free(). + + * libamu/Makefile.am: add to comment a mention of strstr as an + optional function. + + * libamu/xutil.c (switch_to_logfile): use openlog() options only + if they exist. + + * conf/transp/transp_sockets.c (get_nfs_version): don't use + clnt_spcreateerror if it does not exist. + + * aux/configure.in: check for missing functions clnt_create and + clnt_spcreateerror. Check for missing strstr, and complete + its code. Check for missing external definition for strstr. + + * aux/macros/host_macros.m4: normalize sun3* names. + + * Makefile.am: updates for new sunos3 files distributed. + + * conf/nfs_prot/nfs_prot_sunos3.h: new file. + + * conf/fh_dref/fh_dref_sunos3.h: new file. + + * aux/macros/check_nfs_prot_headers.m4: added sunos3 case. + + * aux/macros/check_nfs_fh_dref.m4: added sunos3 case. + + * doc/am-utils.texi (wire Selector Variable): updated manual for + adjusted variables wire, network, and netnumber, all using the + in_network() function. + +Fri Dec 19 04:37:36 1997 Erez Zadok + + * amd/opts.c: allow options to be processed by executing arbitrary + functions. Converted wire, network, and netnumber all to use the + nomadic function in_network. So from now on they perform a match + against all networks, not just primary. + + * initial port to alpha-unknown-linux-gnu, probably works, but + untested yet. + + * conf/nfs_prot/nfs_prot_linux.h: add special definitions for + __FD_* macros which for som strange reason do not get included + from on redhat alpha linux. Also turn off usage of + because it is incomplete on the same systems. + + * hlfsd/homedir.c (table_add): cast uid field to int, for + comparison. + + * include/am_defs.h: more coflicts with redhat alpha linux + "resolved". + + * aux/macros/{mount_headers,try_compile_anyfs,try_compile_nfs}.m4: + There's a conflict of definitions on redhat alpha linux between + and which must be avoided. + + * aux/configure.in: check for , which is in use on + redhat alpha linux. + + * doc/am-utils.texi (Selectors): added documentation to describe + the new "!" (negated) nomadic functions. + + * amd/opts.c (f_in_network): print debugging info that is correct, + rather than saying that any ARG is on a local network. + (eval_opts): added support for negating nomadic functions, by + prepending "!" to their name. Example, !exists(/foo/bar). + +Thu Dec 18 20:57:19 1997 Erez Zadok + + * include/am_compat.h: ensure that all NFS3 systems have the mount + table entries (and amd opts switches) "proto" and "vers". + + * hlfsd/homedir.c (table_add): added some debugging info to try + and track down a serious memory leak in hlfsd. + +1997-12-18 Erez Zadok + + * libamu/mount_fs.c (compute_nfs_args): OpenBSD 2.2 requires that + you do NOT set the noconn option, and use connected sockets + always. So I'm now forced not to set it at all, and have the user + specify it as "conn" or "noconn" in their /default entry. Argh... + Finally, it looks as if OpenBSD 2.2's NFS 3 implementation may be + buggy (TCP hangs with "short receive" kernel errors). I'd better + wait until they get it working in their version of the automounter + first. So I'm putting the "noconn" option back. + +Thu Dec 18 02:39:39 1997 Erez Zadok + + * libamu/mount_fs.c (compute_nfs_args): use maxgrps option and set + nfs_args field maxgrouplist accordingly. + + * include/am_compat.h (MNTTAB_OPT_MAXGROUPS): complete definition + for mount table entry for maxgroups based on NFS mount option + maxgrp. + + * aux/configure.in: put back testing for NFS mount option + "maxgrps". Added test for mount table entry "maxgroups". + + * libamu/mount_fs.c (compute_nfs_args): perform more careful tests + on nfs_proto, because it could be NULL. + + * doc/am-utils.texi (Selectors): added example of in_network() + selector. + + * aux/macros/check_hide_mount_type.m4: all hpux versions, + including 9.x, should use "ignore" as the mount type to hide from + amd. + +Wed Dec 17 13:09:21 1997 Erez Zadok + + * include/am_utils.h (NSTREQ): use new macro instead of strncmp() + every where in the sources. + +Wed Dec 17 01:15:01 1997 Erez Zadok + + * libamu/mount_fs.c (print_nfs_args): if -D trace is on, will + print as much info that is given in struct nfs_args as possible. + useful for detecting internal flags and options, as well as the + file handle used. + + * scripts/ctl-amd.in: look for amd.conf file in ${prefix}/etc + after /etc and before /etc/local. + +Tue Dec 16 18:51:36 1997 Erez Zadok + + * aux/configure.in, libamu/Makefile.am: added support for linking + with specific versions of libamu. Upped shared library version of + libamu to 1 (libamu.so.1.0.0) + + * include/am_defs.h: added external definition for mkstemp() as + needed. + + * minor new port to i386-unknown-netbsd1.3 (BETA version of + netbsd). + + * aux/config.guess: don't leave a trailing '.' on the system name + for NetBSD-1.3_BETA and similarly for OpenBSD. + + * conf/nfs_prot/nfs_prot_netbsd1_3.h: new header for the slight + differences in ypall calling conventions. + + * mk-amd-map/mk-amd-map.c (main): use mkstemp() whenever possible + in preference over mktemp(), b/c it is more secure. + + * aux/configure.in: check for mkstemp(), a more secure version of + mktemp(). + +Mon Dec 15 02:32:14 1997 Erez Zadok + + * amd/ops_nfs.c (mount_nfs_fh): Systems that include the mount + table "vers" option generally do not set the mnttab entry to + "nfs3", but to "nfs" and then they set "vers=3". Setting it to + "nfs3" works, but it may break some things like "df -t nfs" and + the "quota" program (esp. on Solaris and Irix). So on those + systems, set it to "nfs". + +Sat Dec 13 01:36:27 1997 Erez Zadok + + * doc/am-utils.texi (Distrib): updates for new ports, location of + am-utils' home page, and URL cross references (now supported by my + version of texi2html). + + * aux/macros/check_mtype_type.m4: also use string type for file + system mount types under nextstep for mount(2). + + * aux/macros/check_mtype_printf_type.m4}: nextstep can handle both + integer and string types for file system mount types in mount(2), + but it is better to use string types. + + * conf/nfs_prot/nfs_prot_nextstep.h: set emum nfsstat's NFS_OK to + 0, not 1! Otherwise, all NFS calls (esp. mount) return errno 1 + (EPERM) instead of 0 (OK). Fixes m68k-next-nextstep3 which now + works. + + * conf/nfs_prot/nfs_prot_bsdi2.h: set emum nfsstat's NFS_OK to 0, + not 1! Otherwise, all NFS calls (esp. mount) return errno 1 + (EPERM) instead of 0 (OK). + + * libamu/xdr_func.c (xdr_*): add debugging calls that are optioned + by -D trace (protocol trace). + +1997-12-11 Erez Zadok + + * A.m68k-next-nextstep3/amu_nfs_prot.h: define missing S_ISDIR + macro based on existence on others, and include . + +Thu Dec 11 14:14:38 1997 Erez Zadok + + * aux/macros/try_compile_nfs.m4 (AC_TRY_COMPILE): turn off + inclusion of which only affects nextstep3, on + which this header is broken (it tries to include non-existing + headers). + +Wed Dec 10 16:09:07 1997 Erez Zadok + + * libamu/mount_fs.c (mnt_flags): support either nfs or generic + mount option for grpid. + + * aux/configure.in: turn back on NFS mount option grpid. + +Sat Dec 6 04:36:05 1997 Erez Zadok + + * doc/Makefile.am (install-ps): added target to install postscript + file in the am-utils' home page, as well as a few other useful + files for the new am-utils Web page. + +Mon Nov 17 05:22:56 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a14 *** + ******************************************************************* + +Sun Nov 16 21:56:16 1997 Erez Zadok + + * doc/am-utils.texi (Supported Platforms): updated table of new + ports. + +Sat Nov 15 06:36:27 1997 Erez Zadok + + * libamu/mount_fs.c (compute_automounter_nfs_args): pass mnttab + options so that they can be printed in logs as needed. + + * doc/am-utils.texi (osver Parameter): updated for the correct + usage of the -o/-O options. + + * scripts/amd.conf.5: corrected info for -o/-O options. + + * amd/amd.8: updated man page for new -O op_sys_name option, and + corrected the usage of the -o op_sys_ver option + + * amd/get_args.c (get_args): added new amd option -O to override + OS name. + (get_args): updated usage string. Removed old -m option. Added + -o and -O options. + + * conf/nfs_prot/nfs_prot_irix5.h: add definition to FHSIZE in case + it is not there. Reportedly, irix 5.2 does not define it. + + * scripts/lostaltmail.in: removed references to unused $hack + variable. + + * aux/macros/check_nfs_prot_headers.m4: Patch from Chris Metcalf + to correctly set the nfs_prot headers + for solaris2.5. + + * doc/am-utils.texi (Distrib): typo in the subscription + instructions to amd-dev. Patch from Stefan Vogel + . + +1997-11-15 Erez Zadok + + * NFS3 works on powerpc-ibm-aix4.2.1.0. + + * libamu/mount_fs.c (compute_nfs_args): set fh3 variable to + static. Some compilers (gcc from egcs on aix 4.2.1) corrupt the + stack of an automatic variable when pointer to it is passed around + several times. + +Fri Nov 14 20:09:28 1997 Erez Zadok + + * libamu/xutil.c (real_plog): syslog like behavior for normal + logging. Will not print repeated strings, only a count "last + message repeated N times", but will always print something if + message is repeated more than 100 times. + + * scripts/lostaltmail.in: look for lostaltmail.conf files also in + /etc/global, /etc/os, and /etc/local (in that order). + +Mon Nov 10 03:03:17 1997 Erez Zadok + + * conf/mount/mount_aix.c (mount_aix3): add support for NFS V.3 + mounts. + + * aux/macros/struct_nfs_args.m4 (AC_TRY_COMPILE_NFS): test for + aix42_nfs_args, specially set in conf/nfs_prot/nfs_prot_aix4_2.h + + * conf/sa_dref/sa_dref_*.h: from now on, the "dst" argument to the + NFS_SA_DREF macro is a pointer to the structure that used to be + passed to it before. So now I have to dereference the pointer + before accessing its values. + + * hlfsd/hlfsd.c (main): use the new and cleaner + compute_nfs_args() and compute_automounter_nfs_args() functions. + + * amd/ops_nfs.c (mount_nfs_fh): use the new and cleaner + compute_nfs_args() and compute_automounter_nfs_args() functions. + + * amd/ops_afs.c (mount_toplvl): MAJOR CODE REVISION. Use the new + and cleaner compute_nfs_args() and compute_automounter_nfs_args() + functions. + + * libamu/mount_fs.c (compute_nfs_args): major code cleanup that + relates for struct nfs_args. A new function sets the numerous + possible flags and fields of nfs_args_t in an orderly fashion. + Code cleaned up, organized, and moved from amd/hlfsd into + libamu. This saves on overall size of code. + (compute_automounter_nfs_args): A variant of compute_nfs_args() + which sets special options/flags that need to be used when NFS + mounting an automounter's mount point. Used by hlfsd and amd. + + * amq/amq.c (get_secure_amd_client): don't print any more + "get_secure_amd_client: using TCP, port 12345". It's more + annoying than useful a message, even when assumed to be compiled + under DEBUG only. + +Thu Oct 30 14:33:38 1997 Erez Zadok + + * aux/macros/check_mnttab_type.m4: MAJOR BUG fixed for non-nfs + mount table entries. The code used to define the /etc/mnttab name + for file systems based on physical media (disk, cdrom, floppy) to + the generic name, rather than the OS specific name. For example + autoconf searches for all these types of mount table entries for a + floppy based file system: vfat pcfs pc msdos msdosfs fat. But if + it found any, it hard-coded the mnttab name to "pcfs" rather than + the actual name found! Same for ufs, cdfs, pcfs, tmpfs, lofs, + nullfs, unionfs, and umapfs. + + * aux/configure.in: also test for xfs (for newer Irix) when + looking for mount type names, numbers, etc of a disk-based ufs. + +Sun Oct 26 19:32:57 1997 Erez Zadok + + * amq/amq.c (main): use pmap_ping() to test if remote host is up. + This works better on bsdi2 and bsdi3, because their portmapper + does not appear to like forwarding operations (it is generaly + insecure). + +Sat Oct 25 04:55:56 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a13 *** + ******************************************************************* + +Fri Oct 24 05:04:37 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_ncr2.h: added missing definition for + struct datum typedef. + + * conf/nfs_prot/nfs_prot_netbsd.h: corrected typedef for + ypall_callback_fxn_t for netbsd. + + * aux/macros/type_auth_create_gidlist.m4: hpux10.10 uses int for + the 5th arg to authunix_create(), while before and after they used + gid_t. + + * conf/transp/transp_tli.c (amu_clnt_create_best_vers): don't use + clnt_create_timed() on older Solaris 2.3 systems that did not have + it. + + * conf/nfs_prot/nfs_prot_bsdi2.h: is for + kernel only on bsdi2, so do not include it. + +Fri Oct 24 00:29:42 1997 Erez Zadok + + * hlfsd/stubs.c (nfsproc_readlink_2_svc): avoid logging repeated + messages about resolution of mailboxes based on uid/gid. + + * scripts/ctl-hlfsd.in: check for alternate password file in + ${prefix}/etc/passwd and use it in hlfsd's startup. + +Thu Oct 23 22:48:50 1997 Erez Zadok + + * hlfsd/homedir.c (hlfsd_getpwent): added support for -P + passwdfile option. If hlfsd is started with -P passwdfile, then + the passwdfile is read and parsed just as a standard unix + passwd(4) file. Only the username, uid, and homedir fields are + read and checked. All the rest are ignored. No NIS/netgroup + support! + + * hlfsd/hlfsd.c (main): check if hlfsd is run as root after + parsing command line options, so that usage() can be printed when + -h is invoked. + +Wed Oct 22 00:16:39 1997 Erez Zadok + + * amd/nfs_start.c (mount_automounter): if autofs service listener + fails to initialize it is OK if using a test amd. + + * amd/opts.c (f_in_network): new nomadic function in_network(arg), + which returns TRUE if 'arg' is any one of this host's networks. + + * libamu/wire.c (getwire): rewritten parts of function, to store + all networks names and numbers in the order of the interface (not + in reverse). + +Mon Oct 20 01:59:25 1997 Erez Zadok + + * aux/configure.in: don't add ops_ufs.o on AIX twice. My code + would have worked had it not been due to AIX's buggy /bin/sh. + + * doc/Makefile.am (EXTRA_DIST): include am-utils.dvi and + am-utils.ps in the distribution sources. + (html): generate html documentation for + http://www.cs.columbia.edu/~ezk/am-utils/ + +Sun Oct 19 12:35:49 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_netbsd.h: override the definition of + ypall_callback_fxn_t. The NetBSD team compiles all sources with + gcc -Wall -Wmissing-prototypes -Wstrict-prototypes. + + * amd/info_nis.c: allow for override of ypall_callback_fxn_t + function typedef. + + * libamu/xutil.c (amu_release_controlling_tty): new function to + release the controlling tty in a clean and sane manner. No longer + using setpgid() b/c it may not work. Uses setsid(), + and ioctl() (in order). This new function is used in amd/amd.c + and hlfsd/hlfsd.c. Also avoid setpgrp(), because it works on some + systems, but on others it is the same as setpgid(). + +Sat Oct 18 23:42:40 1997 Erez Zadok + + * aux/acconfig.h: check for nfs mount option 'fsname'. Code for + it was in amd/ops_afs.c, amd/ops_nfs.c, and hlfsd/hlfsd.c, but + never used, because the configure test for fsname flag wasn't + used. This fixed a bug in HPUX 10, where syncer and manual mounts + left blank lines in /etc/mnttab. + + * aux/configure.in: check for nfs mount option 'fsname'. + +Fri Oct 17 13:30:27 1997 Erez Zadok + + * amd/ops_afs.c (mount_toplvl): turn on 'ignore' option in nfs + mount flags of toplvl mounts. Important esp. for HPUX 10. Now + hpux-10 will mount amd's mounts points as 'ignore' (by df). + + * aux/configure.in: check for NFS mount option 'ignore', useful in + HPUX 10. + +Thu Oct 16 03:28:33 1997 Erez Zadok + + * aux/macros/check_hide_mount_type.m4: hpux 10 should use "ignore" + mount type and not NFS, for the amd mount points. + + * conf/transp/transp_tli.c (amu_clnt_create_best_vers): don't log + an RPC timeout as an error, but just an info message. From + Andreas Stolcke + + * If the NFS server is down or does not support the portmapper + call (such as certain Novell NFS servers) we mark it as version 2 + and we let the nfs code deal with the case that is down. If when + the server comes back up, it can support NFS V.3 and/or TCP, it + will use those. From christos@deshaw.com (Christos Zoulas). + + * hlfsd/homedir.c (plt_print): various compile time cleanups to + printfs that take a long, but pass an int to print. From + christos@deshaw.com (Christos Zoulas). + + * aux/macros/func_bad_yp_all.m4 (ac_cv_func_yp_all_clean,): new + macro to determine if the OS has a bad yp_all(), based on the host + OS name. So far only irix (all versions) have a bad yp_all, so + they will use am_yp_all() instead (which is slower as it + enumerates manually all of the map's entries). + +Thu Oct 16 03:14:37 1997 Erez Zadok + + * amd/info_nis.c (am_yp_all): code for a replacement yp_all that + avoids using a file-descriptor leaking yp_all() on some systems + like irix. + +Wed Oct 15 21:52:35 1997 Erez Zadok + + * fsinfo/fsinfo.h: avoid redefining yywrap incorrectly on DU-4.x + systems using /usr/bin/flex. + + * amd/conf_tok.l (yywrap): avoid redefining yywrap for systems + that have a modified GNU flex which does define yywrap (DU-4.x). + +Fri Sep 26 14:25:29 1997 Erez Zadok + + * conf/checkmount/checkmount_bsd44.c: include prototype. + +Fri Sep 26 01:26:24 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a12 *** + ******************************************************************* + +Fri Sep 26 00:13:48 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_irix6.h: completely turn off all autofs + code in irix6 until it can be tested correctly + + * conf/transp/transp_tli.c (amu_clnt_create_best_vers): time out + on clnt_create for 3 seconds, rather than wait for the much longer + default. + + * conf/nfs_prot/nfs_prot_aix4_2.h: port to powerpc-ibm-aix4.2.1.0. + Includes NFS3, untested. + +Thu Sep 25 11:03:11 1997 Erez Zadok + + * amd/ops_pcfs.c (mount_pcfs): fill in uid/gid fields of + pcfs_args_t if they exist. + + * amd/ops_cdfs.c (mount_cdfs): fill in ssector field of + cdfs_args_t if it exists. + + * new minor ports hppa1.1-hp-hpux10.10, hppa1.1-hp-hpux9.05, + hppa1.1-hp-hpux9.07, m68k-hp-hpux9.00, and sparc-sun-sunos4.1.4. + +Wed Sep 24 00:48:05 1997 Erez Zadok + + * doc/am-utils.texi (wire-test): updated documentation for the new + option. + + * wire-test/wire-test.8: updated man page for new option. + + * wire-test/wire-test.c (main): added a test for various + combinations of NFS proto/vers to a remote/local host. + + * aux/macros/try_compile_anyfs.m4 (AC_TRY_COMPILE): include + and so that + freebsd will correctly set mount options for pcfs and cdfs. + + * amd/ops_pcfs.c (mount_pcfs): set mask field of pcfs_args to + 0777 (if field exists). + + * aux/macros/try_compile_anyfs.m4 (AC_TRY_COMPILE): include + if available. + + * minor new port: rs6000-ibm-aix4.1.4.0. + + * libamu/mount_fs.c (mount_fs): fixed bug that caused HPUX not to + write the "time" field in /etc/mnttab. + + * conf/mtab/mtab_file.c (mnt_dup): fixed typo in macro names for + detecting mnt_time field of mntent_t. + + * libamu/mtab.c (mnt_free): fixed typo in macro names for + detecting mnt_time field of mntent_t. + +Tue Sep 23 15:30:03 1997 Erez Zadok + + * conf/mtab/mtab_file.c (lock): Use flock() in preference over + fcntl() to lock the mtab file. + +Mon Sep 22 23:04:58 1997 Erez Zadok + + * conf/transp/transp_sockets.c (get_nfs_version): define + the try_again goto label only for NFS3. + (pmap_ping): assume timeout failure of clnt_stat. + + * libamu/xdr_func.c (xdr_groupnode, xdr_exportnode): cast to + "groups *". + +Mon Sep 22 20:34:33 1997 Erez Zadok + + * conf/transp/transp_sockets.c (pmap_ping): patch from Dan Riley + to make sure that amd works with more + secure portmappers that do not allow forwarding of RPC messages to + other services. + + * */Makefile.am: all source files should also depend on the new + include/am_xdr_func.h header. + + * include/am_xdr_func.h: new file as part of the code cleanup from + Christos Zoulas . + + * Lots of fixes from Christos Zoulas that + involved missing prototypes, cleaned up ones, and removal of + unused variables. + + * libamu/xdr_func.c (xdr_mountres3): some code cleanup. A switch + statement with only one case is unclean. + +Mon Sep 22 17:26:38 1997 Erez Zadok + + * amd/ops_fs.c (mount_fs): initialize mntent_t fields to + 0 so that all fields are initialized to zero at first. This way + SunOS 4.x and other systems don't get /etc/mtab entries with + random integers for the fsck/freq fields. Patch from Andreas + Stolcke . + +Mon Sep 22 00:34:19 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_sunos4.h: include so + that the important definition for HOSTNAMESZ will be found. + + * amd/ops_afs.c (mount_toplvl): limit hostname size to HOSTNAMESZ + (inside the nfs_args structure) if the system uses that macro. + Otherwise systems like SunOS refuse to NFS mount long pathnames + and result in ENAMETOOLONG errno's. + +Wed Sep 17 04:56:11 1997 Erez Zadok + + * doc/am-utils.texi (Supported Platforms): specify new support for + solaris 2.6, and hlfsd running on 2.5.1 too. + +Wed Sep 17 03:55:02 1997 Erez Zadok + + * conf/mount/mount_svr4.c (mount_svr4): don't attemt an autofs + mount if it is not supported or was turned off. + +Wed Sep 17 03:19:36 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_sunos4.h: fixed so that it will nfs mount + again. Apparently at some previous release SunOS 4 supported was + broken and all nfs mounts resulted in ESTALE. + +Wed Sep 17 00:26:25 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_sunos5_6.h: nfs protocol headers for + solaris 2.6. + + * aux/macros/check_nfs_prot_headers.m4: added solaris 2.6 nfs + protocol header selection. + +Sat Sep 13 14:31:51 1997 Erez Zadok + + * conf/transp/transp_tli.c (amu_clnt_create_best_vers): avoid + infinite loop. + +Sun Sep 7 18:23:23 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a11 *** + ******************************************************************* + +Fri Sep 5 11:55:10 1997 Erez Zadok + + * amd/amd.c (main): if plock() succeeded, don't try to display + errno message. Patch from Chris Metcalf + + + * hlfsd/homedir.c (table_add): make sure duplicate passwd entries + are ignored. Only the first entry should ever be used, because + that's how lookup in passwd database works. + + * conf/transp/transp_sockets.c (get_nfs_version): when determining + if a remote host is up or down, use NFS v.2. Fix suggested by + Enami Tsugutomo . + + * conf/transp/transp_tli.c (amu_clnt_create_best_vers): new + function to get the best possible NFS version, but also timeout + faster than normal defaults, so remote hosts which are down can be + detected in a reasonable time. + (get_nfs_version): use the new "best" function. + +Tue Sep 2 00:41:00 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a10 *** + ******************************************************************* + +Mon Sep 1 15:39:51 1997 Erez Zadok + + * conf/transp/transp_tli.c (get_nfs_version): don't use + clnt_tp_create_timed() on systems that don'e have it (Solaris 2.4 + and earlier). + + * aux/configure.in: test for existence of clnt_tp_create_timed(), + since Solaris 2.4 (and possibly earlier) do not have it. + +Mon Sep 1 15:23:18 1997 Erez Zadok + + * amd/ops_autofs.c (autofs_unmount_1_svc): only display rdevid + field if it exists (solaris 2.4's autofs does not have it). + +Mon Sep 1 14:45:09 1997 Erez Zadok + + * aux/macros/type_auth_create_gidlist.m4: a new test to determine + the correct type to the 5th argument of authunix_create(). + +Mon Sep 1 03:44:32 1997 Erez Zadok + + * libamu/xdr_func.c (xdr_umntrequest): add test for autofs + structure umntrequest, if it has the field rdevid. Seems Solaris + 2.4 and earlier didn't have it. + +Mon Sep 1 01:10:53 1997 Erez Zadok + + * hlfsd/hlfsd.c (hlfsd_init): moved initialization upwards, so it + can be done before primary process forks. + (main): bug fix: wait a bit to give child a chance to initialize. + Without this, hlfsd got into a busy infinite loop while, never + completing the mount. + + * amd/info_nis.c: patch from Jason Thorpe + to make amd works when talking to NIS+ servers in NIS + compatibility mode. + +Mon Sep 1 00:46:56 1997 Erez Zadok + + * amd/mapc.c (MAX_CHAIN): increased maximum chain size to 1024. + +Sun Aug 31 20:20:40 1997 Erez Zadok + + * amd/conf.c (gopt_fully_qualified_hosts): a new function to + process another new global variable. + + * amd/ops_nfs.c (make_nfs_auth): if a new global variable + fully_qualified_hosts is on, use FQHN in RPC/NFS authentications. + Patch from Chris Metcalf . + + * amd/conf.c (process_last_regular_map): If the amd.conf file only + has a [global] section (pretty useless IMHO), do not try to + process a map that does not exist. + + * scripts/amd.conf.5: fixed typos (repeated 'as' word). + + * doc/am-utils.texi: MAJOR DOCUMENTATION REVISION COMPLETED!!! + + * amd/conf.c (reset_cf_map): Bug fix. Reset 'tag' field of cfm + structure, so it does not carry over from map entry to another. + +Sat Aug 30 18:39:21 1997 Erez Zadok + + * amd/amd.c (main): fixed the meaning of the plock option. A bug + caused it to be reversed. + +Sat Aug 30 15:13:18 1997 Erez Zadok + + * hlfsd/stubs.c: don't initialize some statics here. They are + better initialized in hlfsd_init_filehandles(). + +Fri Aug 22 14:47:16 1997 Erez Zadok + + * amd/conf.c (gopt_show_statfs_entries): new function and a global + amd.conf key show_statfs_entries. Defaults to 'no'. If 'yes', + then all maps flagged as browsable will also show a count of the + number of entries (keys) in that map. + + * amd/nfs_subr.c (count_map_entries): new function to count number + of entries in a map. Now used if browsable is turned on in a map, + to return a count of available keys in a given map. + + * hlfsd/stubs.c (eq_fh): use correct memcmp(). BUG fixed! hlfsd + confused the file handles for ".", "..", and the symlink, causing + mess. + + * aux/macros/func_bad_memcmp.m4: new test, based on autoconf 2.12, + but also defines HAVE_BAD_MEMCMP, so I avoid linkage conflicts + with bad memcmp() in libc's (nextstep3). + +Thu Aug 21 17:38:41 1997 Erez Zadok + + * aux/configure.in: check if autofs_args_t has a field named + addr. Solaris has it for specifying the address of the daemon, + but Irix does not. So how does irix tell the kernel the daemon's + address? I suspect that it is hardcoded to "localhost" using a + "private well-known port" (#define AUTOFS_PORT 2048). + + * conf/nfs_prot/nfs_prot_linux.h: added missing autofs + definitions. + + * README.autofs: new file listing autofs support notes + + * very preliminary autofs code working. Call it pre-alpha + quality. + +Sun Aug 17 02:25:09 1997 Erez Zadok + + * amd/conf.c (ropt_mount_type, gopt_mount_type): don't accept + "autofs" if system does not support it. + + * amd/amd.c (main): log am-utils version string (same as amd -v) + at start of run. + + * conf/transp/transp_sockets.c (get_nfs_version): in order to tell + if a remote host is available, try to contact its portmapper and + timeout if no answer is received in 3 seconds. + +Thu Aug 14 16:12:04 1997 Erez Zadok + + * aux/macros/check_extern.m4 (pattern): use a simpler pattern for + match for external function definitions. The function could span + multiple lines, so only match the opening parenthesis, not the + closing one too. + + * aux/macros/os_cpp-flags.m4 (ac_cv_os_cppflags,): do NOT turn on + posix mode for nextstep3. It is broken. + + * amd/amd.c (init_global_options): run uname() only if + and uname(2) exist. + + * amd/rpc_fwd.c (fwd_packet): if remote host is down, the + forwarding socket is null, so declare this an error. + + * include/am_utils.h (AM_ERRNO_HOST_DOWN): find best errno to set + for when a remote host is down. Try, in order, "host down", "host + unreachable", "invalid argument". + + * amd/ops_nfs.c (discard_fh): don't dereference a null pointer + (happens when remote host is down, and fp->fh_fs is NULL). + (prime_nfs_fhandle_cache): ditto, and set fs flags to !FSF_VALID + and FSF_DOWN. + + * amd/sched.c: nobody uses "union wait" any more, or so it + appears, so clean up that code. + + * conf/transp/transp_tli.c (get_nfs_version): if remote host is + down, time it out faster than default (3 seconds). + (get_mount_client): free netconfig entry when done with it. + + * conf/nfs_prot/nfs_prot_nextstep.h: initial (and somewhat ugly) + port to nextstep3 (m68k-next-nextstep3). + + * fsinfo/Makefile.am (LDADD): needs to link with libamu in case + system does not have strdup(). + + * include/am_defs.h: complete external definition for getlogin() + if needed. + + * conf/transp/transp_tli.c (get_nfs_version): no need to keep + static versout variable. + + * amd/rpc_fwd.c (fwd_packet): if fwdto packet is null, remote + server is probably down. Don't use sendto() in that case. + + * buildall (default): run gmake if found, before trying plain + make. GNU make is always preferable. + +Tue Aug 12 21:23:58 1997 Erez Zadok + + * aux/macros/host_macros.m4: cleanup of os_version and os + overrides. Solaris 2.5.1 for example will come up as solaris2 and + 2.5.1, rather than sunos5 and 5.5.1. Both can be overridden in + the amd.conf file. + +Fri Aug 8 14:37:30 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a9 *** + ******************************************************************* + +Thu Aug 7 00:52:14 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_ncr2.h: new file, for NCR2 + (i486-ncr-sysv4.3.03) headers. Needed to complete missing stuff + from and . + + * scripts/amd.conf.5: new map page. + + * amd/info_hesiod.c: define extern for hesiod_resolve, since bsdi3 + does not. + + * amd/amd.8: updated man page. + + * amd/get_args.c (get_args): removed defunct -h option to amd. + + * amq/amq.8: updated man page. + + * amd/info_nisplus.c (nisplus_search): prototype fixes so Sun + SparcCompiler CC won't complain. + + * amd/info_hesiod.c (hesiod_search): small fixes to compile with + hesiod-1.3, as per Rainer Orth . + + * aux/macros/opt_ldflags.m4: new option added to configure + --enable-ldflags, to specify -L option for configuring/compiling. + The older one --enable-libs is now to be used only for -l options. + + * amd/ops_nfs.c (mount_nfs_fh): bug fixed. Should initialize + nc_protoname from nfs_proto if available for all TLI systems, not + just those that have NFS V3. + + * amd/info_ldap.c: ldap patches from Leif Johansson + , adding two new amd.conf ldap variables: + ldap_cache_seconds and ldap_cache_maxmem. + + * hlfsd/hlfsd.c (main): bug fixed. port number must be wrapped in + htons(). + +Sun Aug 3 17:20:05 1997 Erez Zadok + + * amd/nfs_start.c (mount_automounter): register amd with the rpc + program number that may have been overridden by amd.conf. + + * libamu/xutil.c (set_amd_program_number, get_amd_program_number): + allow storing and retrieving alternate amd program numbers. + + * amd/conf.c (gopt_portmap_program): new function to parse + amd.conf entry portmap_program=1234. + + * amq/amq.c (main): allow specifying an alternate rpc program + number for amd via -P prognum. + + * new amq RPC to get the process id of the running amd. This is + used in ctl-amd to quickly find the pid of the amd that is to be + killed. + + * expanded shared libraries support. Using GNU libtool-1.0, + am-utils now builds shared libraries on many platforms that have + support for it and proper compilers/linkers. See "INSTALL" file + for compatibility chart. + +Thu Jul 31 13:07:23 1997 Erez Zadok + + * fsinfo/fsi_lex.l: removed code that was in support of very old + versions of flex. No longer needed. + +Tue Jul 29 12:00:13 1997 Erez Zadok + + * amd/amd.c (init_global_options): find the kernel architecture + from uname() if possible. + +Mon Jul 28 03:53:59 1997 Erez Zadok + + * new working port: i386-unknown-openbsd2.1 + +Fri Jul 25 03:16:31 1997 Erez Zadok + + * working port: sparc-sun-solaris2.4. Had to fix fhandle_t from + structure to actual char[], because the structure was passed to + xdr_fhandle as data and not a pointer. Surprisingly, gcc + -fpcc-struct-return did not help. + + * conf/nfs_prot/nfs_prot_sunos5_4.h: special nfs protocol + definitions for solaris 2.4 have to be different from 2.3, and + different from 2.5. + + * libamu/xdr_fhstatus.c (xdr_fhstatus): minor code cleanup. + +Thu Jul 24 16:22:39 1997 Erez Zadok + + * conf/mount/mount_svr4.c (mount_svr4): use STREQ to compare mount + types, not ==. Fix from Christos Zoulas . + + * mk-amd-map/mk-amd-map.8: man page taken from bsd44. + +Thu Jul 24 00:01:55 1997 Erez Zadok + + * conf/mount/mount_linux.c: made the nfs error mapping code into a + small function. + +Wed Jul 23 16:11:49 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_linux.h (NFS_ERROR_MAPPING): special + error mappings from errno numbers to NFS errors. From Debian + Linux. + + * scripts/am-eject.in (fs): new script (taken from Debian Linux + folks) to auto-unmount floppy/cd devices before ejecting them. + + * fsinfo/wr_exportfs.c (write_exportfs): from Debian folks, pass + '5' as second arg to show_area_being_processed. I'm not sure why. + + * fsinfo/wr_atab.c (write_atab): from Debian folks, pass '5' as + second arg to show_area_being_processed. I'm not sure why. + + * conf/mount/mount_linux.c (parse_opts): as per Debian Linux, + ensure that you have a buffer in *xopts to strcat onto. + (mount_linux): fixed from Debian folks to ensure that NFS mount + sockets are connected only for kernels prior to 1.3.10 (avoids + hangs for multi-homed hosts). + + * amd/mapc.c (make_entry_chain): from Debian folks: don't skip + over amd map keys that have a prefix, and include the prefix in + the returned readdir(). + + * amd/info_passwd.c (passwd_init, passwd_search): format + enhancements from the Debian Linux folks. They added + - var0:=pw-prefix:=anydir + - var1:=pw-rhost:=dom3.dom2.dom1 + - var2:=pw-user:=user + - var3:=pw-home:=/anydir/dom1/dom2/dom3/user + + * new ports: sparc-sun-solaris2.4 and sparc-sun-sunos4.1.1. + + * amd/ops_afs.c (afs_retry): patches from Debian Linux. If + afs_mount timed out, then explicitly forbid further retries after + the timeout. (afs_bgmount): buf fix from Debian Linux. Timeout + values (17 and 5) were mistakenly swapped. + +Wed Jul 23 15:53:25 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_sunos5_3.h: turn off non-existent NFS V.3 + support for Solaris 2.4 (the header files incorrectly define parts + of the NFS V.3 protocol, but the kernel does not support it). + +Wed Jul 23 00:07:12 1997 Erez Zadok + + * amd/info_hesiod.c: minor cleanup to use hes_init and hesiod_init + for determining if using old or new hesiod libraries, + respectively. + + * amd/ops_nfs.c (mount_nfs_fh): If "noconn" option exists in NFS + V.3 then use non-connected sockets (both TCP and UDP). Otherwise + they cause hangs of mounts from multi-homed hosts when the return + route is not the same as the outgoing route (esp. on NetBSD + 1.2.1). If "conn" option was supplied, then don't turn on the + "noconn" mount option. Otherwise default to "noconn" mount + option. + + * aux/configure.in: better check for systems that need libgdbm and + + +Tue Jul 22 04:02:05 1997 Erez Zadok + + * hlfsd/hlfsd.c (main), amd/ops_afs.c (mount_toplvl): ensure that + mounts are hidden from df(1) on systems that keep mount tables in + kernel, such as osf1. + +Tue Jul 22 02:26:55 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a8 *** + ******************************************************************* + +Mon Jul 21 21:33:19 1997 Erez Zadok + + * hlfsd/hlfsd.c (main): bug fixed: forgot to set sin_family to + AF_INET when hlfsd mounts itself, thus getting an errno "protocol + family not supported". + +Mon Jul 21 20:46:59 1997 Erez Zadok + + * verified that amd on NetBSD 1.2.1 (i386) works, but the OS + itself is flaky. + + * verified that amd AIX 3 works w/ the new readdir() code. + +Mon Jul 21 18:59:30 1997 Erez Zadok + + * amd/mapc.c (maptypes): changed the default map caching type for + nis and ndbm maps to "MAPC_ALL", so that all possible entries will + be available to amd for browsable_dirs=yes. + +Mon Jul 21 18:04:16 1997 Erez Zadok + + * amd/ops_afs.c (afs_readdir, afs_readdir_browsable): split + afs_readdir into a browsable version and a non-browsable one. + Fixed bugs that resulted in an infinite nfs_readdir loop on the + localhost for some operating systems. + +Sat Jul 19 19:38:38 1997 Erez Zadok + + * amd/ops_afs.c (afs_readdir): fixed up the browsable code to + comply with nfs_readdir specs. It was returning all entries at + once, even if there was not enough space in the RPC packet. Now, + it sends a reasonably sized chunk, and sets static state to resume + it for the next continuation RPC of readdir. + + * amd/conf.c (set_conf_kv): fixed bug that resulted in the first + regular map not getting all of the [global] options defaulted from. + +Fri Jul 18 00:45:12 1997 Erez Zadok + + * amq/amq.c (main): fixed so that portmapper "ping" will only fail + upon an RPC timeout + + * scripts/ctl-{amd,hlfsd}.in (killproc): better method to find the + amd/hlfsd process to kill. + + * amd/ops_afs.c (mount_toplvl), hlfsd/hlfsd.c (main): code to + determine how to avoid df from seeing amd's toplvl mounts. Moved + from libamu/mount_fs.c and include/am_utils.h. Ensure that hlfsd + is hidden from df. + (mount_toplvl): fixed df types for irix. + +Thu Jul 17 21:59:45 1997 Erez Zadok + + * amq/amq.c (main): fixed bug that caused the 5 second timeout for + TLI amq using udp to be ignored. + (main): if amq cannot contact remote host's portmapper within 5 + seconds, timeout and fail faster than the default longer timeout + (this is for non-TLI systems). + +Thu Jul 17 17:08:13 1997 Erez Zadok + + * amq/amq.c (get_secure_amd_client): if amq cannot contact + remote host's portmapper within 5 seconds, timeout and fail faster + than the default TLI timeout of over 4 minutes. + + * amd/am_ops.c (ops_showfstypes): added styles for new bsd44 + file systems nullfs, unionfs, and umapfs. + (ops_show1): cleanup code and and reuse this function. + (vops): empty placeholders for nullfs, unionfs, and umapfs. + + * amd/ops_{nullfs, unionfs, umapfs}.c: 3 new empty templates for + bsd44 style file systems. + + * fsinfo/fsinfo.8: man page for fsinfo rewritten from bsd44 + sources. + + * amd/conf_tok.l, fsinof/fsi_lex.c: undefine ECHO to avoid + conflict with systems that define it in and also + define a conflicting one via lex. Newer versions of f/lex are ok. + +Wed Jul 16 00:17:45 1997 Erez Zadok + + * amd/ops_nfs.c (mount_nfs_fh): fill in nfs_args' fields + acdirmin/max and acregmin/max only if they exist. + + * aux/configure.in: test for nfs_args fields acdirmin and + acregmin. + +Tue Jul 15 17:24:09 1997 Erez Zadok + + * aux/configure.in: commented out checking for MNT2_GEN_OPT_* for + "nondev" and commented back in checking for "nodev". This was a + typo. + + * include/am_compat.h: more compatibility options: define "ro" + mnttab option all the time. Define "overlay" as needed. Added + more fillers of mnttab options (as per Daniel S. Riley + ), for acdirmax, acdirmin, acregmax, + acregmin, noac, grpid, nosuid, and actimo. + + * libamu/mount_fs.c (mnt_flags): fixed a typo in "ro" option as + per dsr@mail.lns.cornell.edu (Daniel S. Riley). Then cleaned up + the same code for other options in struct opt_tab. + +Mon Jul 14 22:36:37 1997 Erez Zadok + + * amd/get_args.c (get_args): moved amd.conf file parsing to before + the switching the default log/debug options. Suggested by + dsr@mail.lns.cornell.edu (Daniel S. Riley). + + * aux/update_build_version: new script to record the build version + of amd, along with the rest of the info thet comes up with amd -v. + +Sun Jul 13 00:30:24 1997 Erez Zadok + + * aux/macros/os_cflags.m4: new macro, to add additional + compilation options (also used during configuration), based on the + OS and the compiler. Used for solaris-2.6, osf, and irix6. + +Fri Jul 11 10:15:11 1997 Erez Zadok + + * amd/conf_tok.l, conf_parse.y: allow values of keys to include + white spaces, if they are double-quoted (key="some value") + + * amd/info_hesiod.c (hesiod_search): cleanup and minor bug fixes + of hesiod from Danny Braniss . + +Fri Jul 11 02:16:06 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a7 *** + ******************************************************************* + +Thu Jul 10 12:19:25 1997 Erez Zadok + + * include/am_defs.h: fill in extern definition of innetgr() in + case system headers don't. + + * aux/macros/path_prog_lex.m4 aux/configure.in: using macros that + will show the full pathname to yacc/bison and f/lex. Some systems + have older or bad versions of those and this way the user will + know for sure what is being invoked. + + * tasks: file populated with todo items. + + * scripts/amd2ldif.in: Script to convert amd maps to plain text + LDAP object files. Contributed by Leif Johansson + . + + * aux/config.guess: added recognition for sun3's running 4.2bsd, + from Tom Schmidt . Fixed one small typo. + + * amd/conf.c: several variables that were local to a map, were + also added to [global], where they apply to all maps. Each map + can then individually override those defaults. Flags + affected: browsable_dirs and mount_type. Options affected: + map_type, map_options, and search_path. + + * amd/amd.h: eliminated several global flags each of which took an + int, in favor of one global flags variable used as a bit field. + + * amd/amd.c (init_global_options): moved all global variables into + a single struct amu_global_options, so it is easier to add new + ones and/or identify existing ones. + + * amd/get_args.c (get_args): removed unused amd -m option. + + * amd/conf.c (gopt_cluster): added new amd.conf option for cluster + name, same as amd -C. + + * amd/info_ldap.c: LDAP info map functions from Leif Johansson + . + + * amd/conf.c (gopt_ldap_base, gopt_ldap_hostports): put in global + amd.conf options for ldap_base and ldap_hostports. + + * amd/opts.c (f_netgrp): new amd map function netgrp(ARG) to test + if the current host is in the ARG host netgroup. + + * aux/configure.in: some systems replaced dbm in libc with GNU's + libgdbm, so check for libgdbm, but only if dbm_open is not in + libc already. This was a recommendation from Tom Schmidt + . + + * conf/nfs_prot/nfs_prot_sunos5_3.h: port to sparc-sun-solaris2.3 + completed. + +Wed Jul 9 18:14:59 1997 Erez Zadok + + * port to sparc-unknown-netbsd1.2E done, not tested. Includes NFS + V.3. + +Tue Jul 8 17:35:07 1997 Erez Zadok + + * port to i386-unknown-freebsd3.0 done and working. Includes NFS + V.3. + + * aux/macros/check_nfs_fh_dref.m4: freebsd3 should use + file handle dereferencing style similar to freebsd22. + + * include/am_defs.h: need to include before + on freebsd3. + + * conf/nfs_prot/nfs_prot_freebsd3.h: new protocol header additions + for freeBSD 3.0. + +Tue Jul 8 16:53:41 1997 Erez Zadok + + * amd/info_nis.c (nis_reload): cast nis' callback function so + picky compilers won't complain. + + * libamu/xdr_mountres3.c (xdr_mountres3): make sure this function + gets compiled only if the system has NFS V3 and does not have + xdr_mountres3. + +Tue Jul 8 12:42:03 1997 Erez Zadok + + * COPYING: put in some legal stuff in this file. + +Mon Jul 7 19:10:44 1997 Erez Zadok + + * NFS V3 now works under Irix5, thanks to patches from + Andreas Stolcke . + + * conf/mount/mount_irix5.c: sparate mount_irix.c into an irix5 + version and an irix6 version, since irix5's NFS V3 code is broken + and hacky. + + * amd/info_hesiod.c (hs_zone_transfer): minor fixes to buffer + sizes for some hesiod queries. Patch from Danny Braniss + . + +Mon Jul 7 19:04:14 1997 Erez Zadok + + * amd/ops_nfs.c (mount_nfs_fh): fixed NFS V.3 support for bsdi3. + +Sun Jul 6 14:22:24 1997 Erez Zadok + + * aux/{configure.in,acconfig.h}: added checks for struct + nfs_args's fields proto and sotype (bsdi3). + + * amd/ops_nfs.c (mount_nfs_fh): added nfsv3 option to + nfs_args.flags for bsdi3. Set field proto to 0. Set sotype field + to SOCK_STREAM or SOCK_DGRAM. + + * aux/macros/check_mount_style.m4: add case for bsdi3. + + * amd/info_hesiod.c: got hesiod support for bsdi3. + +Sun Jul 6 11:14:47 1997 Erez Zadok + + * aux/configure.in: look for hesiod on libc (bsdi3) + + * amd/get_args.c (get_args): reformat usage so it fits in 80 + columns. + + * scripts/ctl-amd.in: changed directory name for optional tftpboot + map to /tftpboot/.amd. + +Sat Jul 5 17:46:45 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a6 *** + ******************************************************************* + +Sat Jul 5 03:17:09 1997 Erez Zadok + + * scripts/ctl-amd.in: include -T tag for tftpboot. + + * new port: mips-sgi-irix5.3. Compiled with gcc, but NFS V3 code + is broken and needs work on the specific nfs_args that irix5 uses + for V3 mounts. + +Sat Jul 5 01:44:25 1997 Erez Zadok + + * amd/get_args.c (get_args): new options amd -T tag. A map with + tag=foo matching the -T tag will be processed. All untagged maps + get processed all the time. + +Fri Jul 4 16:19:26 1997 Erez Zadok + + * aux/configure.in: need to check for strcasecmp in libucb (ncr2) + + * aux/macros/check_os_libs.m4: a new macro to set the usage of + libnsl and libsocket based on the OS. + + * libamu/mount_fs.c (mnt_flags): used MNTTAB_OPT_GRPID if it is + defined (problem on osf4). + + * conf/nfs_prot/nfs_prot_irix5.h: new file for irix5 headers. + + * include/am_defs.h, aux/macros/try_compile_nfs.m4, + aux/macros/mount_headers.m4: do include because it + failes on irix5. Rather, put in the individual + conf/nfs_prot/nfs_prot_*.h headers. + + * amd/conf.c: AIX3 doesn't like strdup() being passed a constant + char*, so cast all strdup()'s args to a non-const char*. + + * amd/mapc.c (root_newmap): don't try to strdup only a "const + char *". + +Fri Jul 4 15:47:10 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_sunos4.h: added rpc/rpc.h and + sys/errno.h. + +Thu Jul 3 17:49:00 1997 Erez Zadok + + * made sure am-utils compiles, links, and runs properly on Irix + 6.2 using "cc -32 -Wl,-woff," + + * aux/macros/check_lib2.m4: a bug fix version to autoconf 2.12 + AC_CHECK_LIB. If OTHER-LIBRARIES are defined and used, then add + them to $LIBS. + + * aux/configure.in: some cleanup of which libraries are needed. + Espectially ensure that libnsl is included only on Solaris, where + so far it is the only system on which it is absolutely necessary. + Also no longer need to include libc explicitly. + + * amd/amd.c,wire-test/wire-test.c (main): convert IP address to + network-long order before printing it. + + * wire-test/wire-test.c (main): also check and report on the IP + address of the local host, since some systems have bad versions of + get_myaddress, or ones that conflict with other versions in + multiple libraries (SunOS 4 and Irix especially). + +Wed Jul 2 18:19:02 1997 Erez Zadok + + * scripts/ctl-amd.in: don't use full pathname so killproc() works + better. Also run bsd44 and irix style ps programs. + + * aux/macros/check_lib_funcs.m4: bug fixed: used to define usage + of library no matter if it was found or not. + +Wed Jul 2 02:11:48 1997 Erez Zadok + + * aux/macros/check_mnt2_gen_opt.m4: turned back on the checking + for M_* macros, but ensure that is not included at + all so it won't conflict with other M_* macros. + +Tue Jul 1 21:16:51 1997 Erez Zadok + + * conf/mount/mount_irix.c (mount_irix): first arg to mount(2) on + irix should be "spec" (host:/path), not the dir of the mnt point. + + * amd/ops_afs.c (afs_lookuppn): bug in enable_default_selectors + fixed. If on, it essentially ignored the setting in a + selector-controlled /defaults if there were 2 or more entries in it. + +Tue Jul 1 12:23:38 1997 Erez Zadok + + * scripts/ctl-{amd,hlfsd}.in (killproc): if failed to find process + using BSD style ps, then try SVR4 style ps. + + * include/am_utils.h (amuDebug): renamed Debug macro to amuDebug + etc., to avoid conflicts with similar named macros in . + + * aux/configure.in, amd/info_ldap.c, etc.: put in all the autoconf + support needed for LDAP. Now the code has to be written mostly in + amd/info_ldap.c. + + * Included additional patches from Andreas Stolcke + to support using the best possible + combination of NFS version (2,3) and protocol (udp,tcp) for any + given host, since it appears that some Irix versions have NFS V3, + but do not support TCP. + + * scripts/ctl-amd.in: updated amd control script to look for and + use amd.conf file. + +Tue Jul 1 00:28:23 1997 Erez Zadok + + * amd/mapc.c (mapc_create): now, each map in the amd.conf can be + initialized off of a different type, or default to cycling through + all maps until one of them matches. + +Mon Jun 30 20:49:13 1997 Erez Zadok + + * amd/ops_afs.c (afs_readdir): per-map browsing (readdir) done. + if browsable_dirs=yes is set in the map section in amd.conf, that + map will return all entries back to a readdir(2). + +Sun Jun 29 16:22:11 1997 Erez Zadok + + * rudimentary amd.conf file support included. You may even + override things like os=sos5, to get "backwards" compatibilty with + upl102. + +Sat Jun 28 13:35:02 1997 Erez Zadok + + * amd/conf.c: new file to process amd.conf file. + + * amd/get_args.c (get_args): new options -H to print help. + + * moved enable_default_selectors to be amd.conf controlled, and + not compiler controlled. + + * amd/get_args.c (get_args): new options -F to parse an + amd configuration file. + +Wed Jun 25 23:15:42 1997 Erez Zadok + + * converted all files that used strcmp() == 0 or != 0 to using + the STREQ() macro. + +Mon Jun 23 22:31:14 1997 Erez Zadok + + * aux/macros/check_lib_funcs.m4: new M4 macro that can be used to + search for any number of functions in any given library. + +Mon Jun 23 01:04:23 1997 Erez Zadok + + * amd/mapc.c: Included patch from Leif Johansson + to ensure that systems without an RE + library can compile. + + * libamu/mount_fs.c (mount_fs): Included patch from Andreas + Stolcke , to ensure that mount options on + table are properly delimited by a comma. + + * amd/ops_nfs.c (mount_nfs_fh): Included patch from Andreas + Stolcke , to allow users to override the + proto= and vers= mount options. + +Sun Jun 22 01:00:11 1997 Eric Dana (edana@ncr2.bgs.com) + + * conf/nfs_prot/nfs_prot_svr4.h: port completed to + i486-ncr-sysv4.3.03. Assorted source cleanups done. + + * include/am_defs.h, aux/macros/mount_headers.m4: don't include + mnttab.h if sys/mnttab.h was already included, because on ncr2, + they contain conflicting entries for struct mnttab. + +Sat Jun 21 23:52:15 1997 Eric Dana (edana@ncr2.bgs.com) + + * aux/macros/check_nfs_prot_headers.m4: added support for ncr2. + +Fri Jun 20 06:14:17 1997 Erez Zadok + + * amd/*.c: lots of 64-bit "ugly" ports like casts to long ints. + + * aux/macros/struct_nfs_fh.m4: check for "struct nfssvcfh" because + on DU-4.0 it is better than the next one to be picked (nfsv2fh_t). + +Wed Jun 18 18:59:49 1997 Erez Zadok + + * aux/macros/struct_nfs_fh.m4 (AC_TRY_COMPILE_NFS): check for + nfsv2fh_t before fhandle_t becasue on bsdi2.1 the former is + better. + +Tue Jun 10 17:06:58 1997 Erez Zadok + + * amd/rpc_fwd.c (fwd_packet): TLI bug fix. if fwdto socket is + NULL, set the maxlen and len fields in netbuf to zero. + +Wed May 28 22:52:28 1997 Erez Zadok + + * scripts/fix-amd-map.in (name): replace all matching patterns on + line. + +Sun May 25 19:33:41 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a5 *** + ******************************************************************* + +Sun May 25 13:37:24 1997 Erez Zadok + + * amd/amq_subr.c (amqproc_getvers_1_svc): amq's RPC service + procedure now returns the full string that amd -v returns. + + * amd/get_args.c (get_version_string): new function to return + complete version/info string so it could be used more flexibly. + + * amd/am_ops.c (ops_showamfstypes, ops_showfstypes): put the list + of Fs types into a string buffer, rather than a FILE*. + + * amd/mapc.c (mapc_showtypes): put the list of map types into a + string buffer, rather than a FILE*. + +Sun May 25 01:25:36 1997 Erez Zadok + + * amd/get_args.c (get_args): amd -v also prints user who built + amd, hostname built on, and date of configuration. + +Sat May 24 13:40:50 1997 Erez Zadok + + * scripts/lostaltmail.conf-sample: sample lostaltmail + configuration file. + + * scripts/lostaltmail.in: new script lostaltmail used to redeliver + "lost" mail that hlfsd redirected to a temp location because the + primary home file system of the user was full. + + * scripts/amd2sun.in: new script amd2sun. Used to convert Sub + automount maps to amd maps. + + * scripts/ctl-hlfsd.in: new script ctl-hlfsd. Used to start, + stop, or restart hlfsd. + + * scripts/expn.1: man page for expn command. + + * scripts/ctl-amd.in: new script ctl-amd. Used to start, stop, or + restart amd. + + * scripts/expn.in: new script expn. Actually taken from David + Muir Sharnoff . Used by hlfsd's mail re-delivery + script. + + * scripts/wait4amd.in: new script wait4amd added. Waits for amd + to come up on a host, and then runs a command (rsh $hostname by + default). + + * scripts/Makefile.am: new directory now holds all shell/perl + scripts that belong to am-utils. + + * conf/mount/mount_linux.c (parse_opts): new parser for + linux-specific mounts. Handles fs-type specific mount-options + correctly. Currently implemented: msdos, iso9660. + + * amd/ops_pcfs.c (pcfs_ops): don't timeout cdfs mounts by default + (fix for linux). + + * amd/ops_cdfs.c (cdfs_ops): don't timeout cdfs mounts by default + (fix for linux). + + * amd/mapc.c (make_entry_chain): fixed bug that resulted in amd + core dumps upon "ls" of a mount point; an invalid pointer was + being returned and dereferenced. + + * port to Linux sparc working! + + * hlfsd/homedir.c (hlfsd_diskspace): close file descriptor if + failed to write test file, or else the fd will leak. + +Sun May 18 00:42:41 1997 Erez Zadok + + * amd/info_hesiod.c (hs_strip_our_domain): use strcasecmp() + instead of strcmp(). + + * Port to Digital Unix 4.0 (OSF) done. + + * hlfsd/hlfsd.c: renamed dirname to dir_name to avoid conflicts + with dirname() function in on OSF systems. + + * fsinfo/fsi_util.c (set_ether_if): take out extern defintion of + inet_addr(). It should come from instead. + + * conf/mtab/mtab_osf.c: fixed macros and added NFS V3 specs. + + * include/am_utils.h: renamed FIRST/LAST to AM_FIRST/AM_LAST to + avoid conflicts with DU 4.0 system header. + +Thu May 15 22:49:12 1997 Erez Zadok + + * libamu/mount_fs.c (mount_fs): pass along NFS version so I can + determine if to include additional options in the mount table file + entry (such as proto=tcp, and vers=3). + +Thu May 15 00:42:12 1997 Erez Zadok + + * libamu/mount_fs.c (mount_fs): include NFS version number in the + mount table options, as well as proto={tcp,udp}. + +Wed May 14 14:30:19 1997 Erez Zadok + + * NFS V3 code ported to most other systems, so it compiles for V2 + and V3 NFS systems. + + * NFS VERSION 3 support, first pass. Working for Solaris and + using TCP. + +Sun May 11 01:14:29 1997 Erez Zadok + + * amq/amq.c: many newline characters were missing from various + stderr printfs. + +Sat May 10 13:09:06 1997 Erez Zadok + + * conf/nfs_prot/nfs_prot_sunos5.h: protocol defintions for + Solaris, which include NFS V3 support. + + * conf/nfs_prot/nfs_prot_default.h: default NFS protocol headers. + + * conf/transp/transp_{tli,sockets}.c (get_mount_client): use NFS + protocol version while getting a mount client. + + * amd/ops_nfs.c (mount_nfs_fh): set the mount types, mnttab types, + file handle size, and proper file handle based on the correct NFS + version number. + + * conf/mount/mount_svr4.c (mount_svr4): support NFS3 mounts under + Solaris and other SVR4 systems. + + * amd/ops_nfs.c: store NFS file handle version and version + specific handle in struct fh_cache. + (got_nfs_fh): pick the correct RPC reply based on the NFS version + of the server. + (prime_nfs_fhandle_cache): figure out the right NFS file handle + for a node, but now include NFS protocol version information. + (call_mountd): set the correct version for the mount protocol, + based on the NFS protocol version. + (nfs_init): use the NFS protocol generic structure + am_nfs_handle_t. + + * include/am_utils.h: new structure am_nfs_handle_t to contain all + possible versions of NFS file handles. + + * amd/srvr_nfs.c (start_ping): ping program performs NFS version + specific pings. + (recompute_portmap): figure out the correct portmap version mount. + (nfs_keepalive): call start_ping() with the correct NFS version. + (find_nfs_srvr): if mount option "vers=" is given, use it. Get + the NFS server version and verify that it is up. + + * conf/transp/transp_{tli,sockets}.c (get_nfs_version): a new + function to find the best NFS version for a particular host. + + * libamu/amu.h: determine what is the highest version of NFS we + should try. + + * include/am_utils.h (NFS_VERSION3): added definition for NFS V3 + protocol number. + Added field fs_version to struct fserver, so we can now store the + server protocol version. + +Fri May 9 01:09:45 1997 Erez Zadok + + * aux/macros/check_field.m4 (AC_MOUNT_HEADERS): map '.' (dot) into + underscores too, so I can test for sub-fields. + + * libamu/wire.c: use test that checks for sub-fields of struct + ifreq. + +Sat May 6 10:20:17 2000 Erez Zadok + + * port to BSD/OS 3.0 completed! Many xdr_ functions were broken + into smaller files. M4 macros fixed to test for existence of + file systems using getvfsbyname(). + + * amd/sched.c (sigchld): signal handler must waitpid() for all + possible children. + + * hlfsd/homedir.c: signal handler must waitpid() for all possible + children. + + * aux/macros/check_restartable_signals.m4: new macro to determine + if need to reinstall signal handlers per OS is better than trying + to figure these out based on system macros. + +Fri May 5 19:23:28 2000 Erez Zadok + + * amd/ops_nfs.c (mount_nfs_fh): set nfs_args_t version number. + + * amd/ops_afs.c (mount_toplvl): set nfs_args_t version number. + + * amd/ops_nfs.c (mount_nfs_fh): process nfs mount option resvport + (must be supplied for bsdi 3.0) + + * libamu/wire.c: use HAVE_FIELD_STRUCT_IFREQ_IFR_ADDR (and + associated new macro) for determining the right way to compute the + size of the interface structure. + +Fri Apr 11 15:56:13 1997 Erez Zadok + + * aux/configure.in: need to include libc before libnsl if + get_myaddress() is available because on irix libnsl has a buggy + get_myaddress(). + + * include/am_defs.h: make sure REINSTATE_SIGNAL_HANDLER is defined + on Irix 6 (an SVR4 variant) + +Thu Mar 27 02:28:40 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a4 *** + ******************************************************************* + +Wed Mar 26 21:15:36 1997 Erez "HWank1" Zadok + + * amd/amq_subr.c (ok_security): turned off insecure code unless + user explicitly runs configure --enable-amq-mount. + + * hlfsd/hlfsd.c (main): use new protoypes dor create_nfs_service(). + + * amd/nfs_start.c (mount_automounter): use code that separately + creates the NFS and the amq service. Register tcp and udp + services for amd. + + * conf/transp/transp_*.c (create_amq_service): new function to + separately create the amq service for amd. Simplified prototypes + for create_nfs_service(). + +Wed Mar 19 20:40:56 1997 Erez Zadok + + ******************************************************************* + *** Released am-utils-6.0a3 *** + ******************************************************************* + +Wed Mar 19 17:49:18 1997 Erez Zadok + + * new port: rs6000-ibm-aix3.2.5 and rs6000-ibm-aix4.1.5.0. Lots + of small changes to support these two. + +Wed Mar 19 14:33:30 1997 Erez Zadok + + * conf/umount/umount_default.c (umount_fs): bug: unlock_mntlist() + should run if MOUNT_TABLE_ON_FILE, not otherwise. + +Mon Mar 17 22:02:43 1997 Erez Zadok + + * hlfsd/hlfsd.c (main): fill in fhsize field if exists + (freebsd-2.2). + + * amd/ops_{nfs,afs}.c (mount_toplvl): fill in fhsize field if + exists (freebsd-2.2). + +Sat Mar 15 19:37:48 1997 Erez "HWank1" Zadok + + * new port: i386-unknown-freebsd2.2. FreeBSD 2.2 and higher + changed the filehandle type in struct nfs_args from nfsv2fh_t to + u_char. + +Sat Mar 14 10:11:03 1997 Erez "HWank1" Zadok + + * SHARED LIBRARIES: too many change to list individually. Now, + libamu can be built as a shared library, and other programs link + with it. + +Tue Mar 11 22:24:09 1997 Erez "HWank1" Zadok + + * aux/macros/opt_shared.m4: new macro for setting options for + building shared am-utils libraries. + +Sun Mar 9 19:17:46 1997 Erez Zadok + + * fixmount/fixrmtab: cleaned up the script. + + * fixmount/Makefile.am (EXTRA_DIST): adde $(sbin_SCRIPTS) so that + fixrmtab gets distributed too. + + * conf/nfs_prot/nfs_prot_bsdi2.h: added support for MOUNTPROC_DUMP. + Added extern for xdr_mountlist(). + + * aux/configure.in: trimmed down many tests for MNT2_GEN_OPT, + MNT2_NFS_OPT, and MNTTAB_OPT that were not referenced anywhere in + the sources. + +Sat Mar 8 00:23:58 1997 Erez Zadok + + * fixmount/hlfsd ported to bsd44, hpux, and linux systems. + + * aux/macros/check_fixmount_style.m4: add check for bsd44 systems. + + * conf/fixmount/fixmount_default.c: use lockf() if flock() is + unavailable. + + * include/am_defs.h: include even if don't have + STDC_HEADERS defined (sunos4). + (seteuid): define seteuid() to be setresuid() for systems that + have but not the other (hpux). + + * aux/macros/check_extern.m4: test should include . + +Tue Mar 4 17:16:52 1997 Erez "HWank1" Zadok + + * lib/xutil.c (debug_option): moved from amd/getargs.c to this + more proper file. + + * include/am_utils.h: put in structure for debug options, for all + progams to use. + + * amd/get_args.c: moved structure for debug options out. + +Sun Mar 2 00:13:07 1997 Erez "HWank1" Zadok + + * ported fixmount. + + * lib/ualarm.c: replacement function for systems that don't have a + ualarm(). + + * ported fsinfo. + +Sun Mar 1 10:23:34 1997 Erez "HWank1" Zadok + + * ported mk-amd-map. + + * buildall: added -K option to buildall, to run mkconf. + +Fri Feb 28 01:10:25 1997 Erez "HWank1" Zadok + + ******************************************************************* + *** Released am-utils-6.0a2 *** + ******************************************************************* + +Thu Feb 27 13:58:59 1997 Erez "HWank1" Zadok + + * all *.[hcyl] files: add copyright line. + + * aux/macros/check_mount_type.m4: test for mount type for + linux-like systems, by checking for loadable or statically linked + kernel filesystem modules. + + * aux/macros/check_mnttab_type.m4: test for mount table entry + for linux-like systems, by checking for loadable or statically + linked kernel filesystem modules. + + * aux/configure.in: pcfs filesystems can use vfat type (linux) + + * aux/macros/check_fs_mntent.m4: test for filesystem existence for + linux-like systems, by checking for loadable or statically linked + kernel filesystem modules. + + * conf/trap/trap_hpux.h: ugly hack added because of stupide HPUX + 9.0 header files. This should be removed when HPUX 9.0 is deemed + defunct. + + * aux/acconfig.h: set an undefined variable for having an extern + to clnt_sperrno(). + + * include/am_defs.h: define extern for clnt_sperrno() if needed. + + * aux/configure.in: test for extern clnt_sperrno(). + + * aux/macros/check_nfs_fh_dref.m4: HPUX's NFS fhandle dref is + similar to irix. + + * aux/macros/check_mount_style.m4: use mount helper on HPUX. + + * aux/macros/check_mtype_type.m4: hpux's mount type is a char*, + not integer (but may be mapped to one later). + + * conf/mount/mount_hpux.c (mount_hpux): HPUX has confusing header + files. They have mount(2) and vfsmount(2) which don't take same + arguments, and they have string mount types MNTTYPE_* as well as + integer types MOUNT_*. So I need this new mount function to map + from string types to integer types for the vfsmount() function. + + * conf/trap/trap_hpux.h (MOUNT_TRAP): instead of calling + vfsmount(), call mount_hpux(). + +Thu Feb 27 03:34:14 1997 Erez "HWank1" Zadok + + * lib/mount_fs.c (mnt_flags): make sure SYNC option is on only if + both MNTTAB_OPT_SYNC and MNT2_GEN_OPT_SYNC are defined. + +Thu Feb 27 00:26:00 1997 Erez "HWank1" Zadok + + * conf/nfs_prot/nfs_prot_hpux.h: NFS protocol definitions for + hpux. + + * include/am_defs.h: no need to include rpc/auth.h or rpc/clnt.h. + + * aux/configure.in: no need to test for rpc/auth.h and rpc/clnt.h. + + * buildall: added ability to configure using other shells than + /bin/sh, on those systems where /bin/sh is buggy or limited + (HPUX). + + * aux/macros/struct_nfs_fh.m4: reinstated the macro but have it + defined am_nfs_fh, and also test for plain typedef "nfs_fh". + + * aux/acconfig.h: #undef am_nfs_fh, which is being defined by a + reinstated macro. + + * aux/configure.in: check for + + * include/am_defs.h: include (HPUX) if exists. + + * aux/macros/try_compile_nfs.m4: include (HPUX) if + exists. + + * aux/macros/mount_headers.m4 (define): removed some non-working + (on HPUX) code that attempts to recreate the fhandle_t rather than + load it up from system headers. Also added some NFS protocol + header inclusion. include (HPUX) if exists. + +Wed Feb 26 00:32:35 1997 Erez "HWank1" Zadok + + * aux/macros/mount_headers.m4 (define): Use M4 changequote to + ensure [] brackets are correctly used. + + * aux/macros/expand_cpp_{string,hex,int}.m4: encapsulate + multi-line M4 inclusions in []. + +Tue Feb 25 22:19:44 1997 Erez "HWank1" Zadok + + * conf/mtab/mtab_bsd.c (mnt_dup): use statfs field f_fstypename if + it exists. + + * aux/acconfig.h: HAVE_FIELD_STRUCT_STATFS_F_FSTYPENAME, new + config.h macro for field f_fstypename of struct statfs. + + * aux/configure.in: testing for field f_fstypename field of struct + statfs (NetBSD). + + * aux/acconfig.h: moved all of the "static" definitions out to a + fixed file called include/am_defs.h. Added to all */Makefile.am + files a dependency on am_defs.h. Created am_defs.h of course, and + then added #include to all of the source and header + files that required it. + +Mon Feb 24 01:27:02 1997 Erez Zadok + + * aux/acconfig.h: two more externals for xdr functions that may be + implemented by libamu. + + * conf/nfs_prot/nfs_prot_bsdi2.h: added missing RPC and XDR + definitions. + +Sun Feb 23 15:25:26 1997 Erez "HWank1" Zadok + + * buildall (default): added -D option for turning on even stricker + developer options. + + * */Makefile.am: make sure @AMU_NFS_PROT_HEADERS@ is used to + determine dependencies on optional NFS protocol headers. + + * aux/acconfig.h: define and use HAVE_NFS_PROT_HEADERS as needed. + + * aux/macros/check_nfs_prot_header.m4: new test to determine what + NFS protocol headers to use. + + * conf/nfs_prot/nfs_prot_{irix6,sunos4,bsdi2}.h: new headers to + complete missing system headers for NFS protocol definitions. + +Sun Feb 16 15:58:42 1997 Erez "HWank1" Zadok + + * amd/ops_nfs.c (mount_nfs_fh): encapsulated some more code in + #ifdef's as needed. + + * amd/ops_afs.c (mount_toplvl): make sure TIMEO/RETRANS code is + suitable #ifdef'ed. + + * include/am_compat.h: a couple more mnttab options + (timeo/retrans) setting just in case. + + * amd/autil.c (host_normalize): make sure hostent->h_name is + passed a non-const char *. + + * conf/mount/mount_linux.c (mount_linux): cleaned up a block of code. + + * {lib,amq,amd}/*.c (many functions): cast xdr_entry to + XDRPROC_T_TYPE. + + * lib/nfs_prot_svc.c (nfs_program_2): cast xdr_entry to + XDRPROC_T_TYPE. + + * lib/nfs_prot_xdr.c (xdr_entry): cast xdr_entry to + XDRPROC_T_TYPE. + + * lib/wire.c (getwire): Make sure safe assignment from const to + none is done. + +Sat Feb 15 19:38:51 1997 Erez "HWank1" Zadok + + * aux/macros/expand_cpp_int.m4: new macro for expanding integers. + + * aux/configure.in: added linux/fs.h support in configure and + several M4 macros. + + * conf/mount/mount_linux.c (mount_linux): use macro instead of + "ugly" fixed hex number for mount() arguments. + +Sat Feb 15 02:09:47 1997 Erez "HWank1" Zadok + + * amd/info_hesiod.c: removed macro HAVE_HS_ZONE_TRANSFER and + turned all of its code always on. That code always seems to + compile, as long as you have hesiod and libresolv. + + * amd/mapc.c: removed macro HAVE_HS_ZONE_TRANSFER and turned all + of its code always on. + + * aux/configure.in: removed superfluous test for hs_zone_transfer + function (will never find it because it is an amd-internal + function). + + * amd/mapc.c (maptypes): must used correct new name for am-utils' + hesiod initialization function: hesiod_am_init. + + * amd/info_hesiod.c (hesiod_am_init): renamed hesiod_init to + hesiod_am_init so as not to conflict with libhesiod's + hesiod_init() function. + + * aux/configure.in: added test and explicit inclusion of + libresolv.a for later resolution of library references with + libhesiod. + + * aux/macros/opt_cppflags.m4: new file. configure/compile C + preprocessor flags. + + * aux/macros/opt_libs.m4: new file. configure/compile library + flags. + + * Makefile.am (EXTRA_DIST_AUX): include two new macros + opt_cppflags.m4 and opt_libs.m4. + + * aux/configure.in: test for libhesiod needs to additional + libresolv to link completely. Additional configuration time + options added for setting initial CPPFLAGS and LIBS. + +Tue Feb 10 02:15:40 1997 Erez "HWank1" Zadok + + ******************************************************************* + *** Released am-utils-6.0a1 *** + ******************************************************************* + +Thu Feb 6 02:55:19 1997 Erez "HWank1" Zadok + + * amd/info_ndbm.c (ndbm_search,ndbm_init): fixed the code so that + it works on freebsd, where they map dbm_pagfno a non-existing + macro on purpose, to force you to port the code to Berkeley DB. + +Fri Jan 31 01:35:09 1997 Erez "HWank1" Zadok + + * amd/ops_afs.c (mount_toplvl): added a sleep(1) right before the + actual mount_toplvl, to avoid some possible race conditions. + +Thu Jan 30 02:31:49 1997 Erez "HWank1" Zadok + + * amd/rpc_fwd.c: removed all TLI (HAVE_T_OPEN) code. + +Wed Jan 29 18:25:07 1997 Erez "HWank1" Zadok + + * lib/wire.c (getwire): removed HAVE_T_OPEN (TLI code) + + * amd/amd.c (main): fix local address using htonl(). Free up + buffers allocated by netdir_*() functions. + +Wed Jan 22 23:53:24 1997 Erez "HWank1" Zadok + + * amd/fix-amd-map.in: new script that will convert old-style amd + maps to new one. + +Tue Jan 21 01:18:16 1997 Erez "HWank1" Zadok + + * FIRST AMD IN AM-UTILS FINALLY WORKS (mounts itself as toplvl, + and replies back to simple nfs/link type mount queries). + + * conf/mtab/mtab_svr4.c: reorganized the code in this file to be + easier to read, and fixed a few bugs with un/setting the lock file + descriptor. + +Wed Jan 8 15:27:49 1997 Erez "HWank1" Zadok + + * amd/sched.c: removed HAS_SVR3_SIGNALS code to handle older + signals in Svr3 systems. Only stellix ever used this. + + * amd/rpc_fwd.c (fwd_reply): removed all code that was triggered + by DYNAMIC_BUFFERS, since it was not in use. + +Tue Jan 7 00:45:59 1997 Erez "HWank1" Zadok + + * amd/opts.c (eval_opts): removed AMD_COMPAT code. Amd no longer + takes '=' sign as old selector. Fix your maps. + (deslashify): removed APOLLO code that treated two '//' as one. + +Sun Jan 5 01:25:09 1997 Erez "HWank1" Zadok + + * amd/ops_nfsx.c (nfsx_init): removed HARD_NFSX_ERRORS, code which + was not used. It made any submount error fail the whole group. + + * amd/ops_nfs.c (make_nfs_auth): removed code dependent on + HAS_NFS_QUALIFIED_NAMES. + (mount_nfs_fh): removed macro for NFS_ARGS_NEEDS_PATH, assuming it + is never on. So code that was triggered by #ifndef + NFS_ARGS_NEEDS_PATH (osf1, aix3, and bsd44 variants) may have to + be fixed later. + Removed all ULTRIX_HACK code. Ultrix is DEAD! + removed all PRESET_AC code, which was only on for Linux to preset + the attribute cache values (otherwise they default to zero). + (nfs_umounted): revobed KICK_KERNEL code (IRIX systems). Will + have to fixed up later. + (mount_nfs_fh): removed code that was never included, which + attempted to set the port on which amd's nfs mounts on. This + isn't supported by the ping algorithm yet. In any case, it is all + done in nfs_init(). + + * amd/srvr_nfs.c (find_nfs_srvr), amd/ops_nfs.c (mount_nfs_fh): + removed HAS_TCP_NFS code. The whole use of NFS V.3 with TCP or + specially hacked NFS V.2 that uses TCP (BSD 4.4 variants) will + have to be addressed later. + + * amd/nfs_subr.c (nfsproc_getattr_2): removed all code dependent + on PRECISE_SYMLINKS. + + * amd/mapc.c (mapc_meta_search): removed code that depended on + HAS_DEPOT. It is known buggy code. The whole DEPOT support needs + to be rethought. + (mapc_add_kv): ported code to use standard regular expression + (regexp) library. + + * amd/{map.c,ops_sfs.c,ops_ufs.c}: removed all code dependent on + FLUSH_KERNEL_NAME_CACHE and the macro itself. + +Sat Jan 4 15:46:58 1997 Erez "HWank1" Zadok + + * amd/map.c (exported_ap_alloc): removed all code triggered by + SHRINK_EXPORTED_AP and the macro itself. + + * amd/info_nis.c: removed HAS_NIS_RELOAD macro, and left the code + in all the time. Assuming that there is always NIS realod + available. + (yp_all_fixed): removed code for BROKEN_YP_ALL. If your yp_all() + function is broken such that it does not release filedescriptors + it created, then you are hosed. Get a fix for yp_all from your + vendor or switch operating systems. + +Tue Dec 31 15:34:36 1996 Erez "HWank1" Zadok + + * amd/info_hesiod.c: renamed macro HAS_HESIOD_RELOAD to + HAVE_HS_ZONE_TRANSFER. + +Mon Dec 30 17:33:23 1996 Erez "HWank1" Zadok + + * amd/{nfs,host}_ops.cremoved INFORM_MOUNTD macro, so its code is + always included. We should always try to inform the remove mount + daemon of mounts we performed. If we want an option for this, it + should be a run-time option. + + * amd/host_ops.c: removed all that optionally did not make the + directory mount points for amd. + + * HOST_EXEC code removed from everywhere. There is no indication + that it was used anywhere. If it needs to be used, then a + run-time switch should control it. + +Thu Dec 26 00:06:52 1996 Erez "HWank1" Zadok + + * amd/*_ops.c: removed all references to mntent_t's fields + mnt_freq and mnt_passno, since they are no longe rused (and never + have been). + + * amd/am_ops.c: removed function sunos4_match, which was off + anyway. This was one of the places where an '=' sign was allowed + as an assignment operator (which is now ':='). + + * amd/afs_ops.c (afs_bgmount): removed SUNOS4_COMPAT code which + was off anyway. This was one of the places where an '=' sign was + allowed as an assignment operator (which is now ':='). + +Tue Dec 24 01:53:52 1996 Erez "HWank1" Zadok + + * amq/amq.c: ported to am-utils. Working. + + * conf/mount/mount_svr4.c (mount_svr4): changed mount type on svr4 + to be string, as it should be (rather than a string mapped to int + and back mapped to string). + +Sun Dec 22 13:26:05 1996 Erez "HWank1" Zadok + + * lib/mount_fs.c (mount_fs): removed MNTINFO_PREF code. + + * lib/umount_fs.c: split this into three files: default, osf, and + bsd44, that are in conf/umount/umount_*.c. + +Thu Dec 19 17:33:46 1996 Erez "HWank1" Zadok + + * aux/configure.in, aux/aclocal.m4, aux/acconfig.h: added new + macro to automatically figure out if an external definition for + sys_errlist[] exists. + + * lib/xutil.c (xfree): removed "#undef free" because it's not + needed there. Any system that redefines free() needs help. + + * conf/mtab/mtab_file.c (REWRITE_MTAB_IN_PLACE): removed code that + was dependent on REWRITE_MTAB_IN_PLACE. It does not appear to be + in active use anywhere. If added later, it should be a run-time + configuration option. + + * conf/mtab/mtab_mach3.c: removed code that was #ifdef'ed not to + be MOUNT_TABLE_ON_FILE, since mach2 always stores its mount tables + in a file in /etc. + + * lib/util.c (str3cat): removed _AIX code. AIX should have a + working realloc, or else find a cleaner solution to this. + (mkdirs): removed SUNOS4_WORKAROUND code. This was to do a sync() + after immediately making directories so that fsck will be able to + fix the filesystem in the event of an immediate crash. This was + because a bug in UFS which is fixed by now. + + * lib/hutil.c (domain_strip): removed PARTIAL_DOMAINS triggered + code. Does not appear to be on and used anywhere. + (dofork): removed MACH3 code, b/c mach3 NFS bugs are fixed by now. + + * lib/resvport.c: split the binding of reserved ports code to a + separate file. A #define (HAVE_T_OPEN) separates the TLI (SVR4) + from the BSD code. + +Thu Dec 19 02:08:35 1996 Erez "HWank1" Zadok + + * lib/Makefile.am (amu_LIBADD): includs @LIBOBJS@ now, auto-filled + in by automake and configure, for optional sources that need to be + built as part of libamu.a. + + * aux/aclocal.m4: Make sure AC_CHECK_MOUNT_STYLE adds mountutil.o + to LIBOBJS. + + * lib/memcmp.c (memcmp): new file added to replace a possible bad + implementation of memcmp. + +Wed Dec 18 22:20:23 1996 Erez "HWank1" Zadok + + * converted the sources to use memset/memmove/memcmp instead of + bzero/becopy/bcmp. + + * ran all sources through gnu Indent w/ options specified in + aux/amindent. + +Wed Dec 11 22:19:29 1996 Erez "HWank1" Zadok + + * At this point the initial genration of config.h via autoconf and + some preliminary makefiles via automake is done. I will not begin + modifying sources, so it's a good time to document from here. diff --git a/contrib/amd/INSTALL b/contrib/amd/INSTALL new file mode 100644 index 0000000..7df423b --- /dev/null +++ b/contrib/amd/INSTALL @@ -0,0 +1,113 @@ +# -*- text -*- + am-utils 6.0 compatibility list + +For each system, list if it autoconfigures, compiles, or runs. Fill in +email id of person who confirms the fact. A missing entry means unverified. +A 'no' means verified broken. + +SYSTEM AUTOCONF COMPILE RUN SHLIB +========================= ======== ========= ======= ===== +alpha-dec-osf2.1 ezk ezk ezk +alpha-dec-osf4.0 ezk ezk dsr[3] +alphaev5-unknown-linux-gnu ezk ezk finkel ezk +hppa1.0-hp-hpux11.00 ezk ezk ezk +hppa1.1-hp-hpux10.10 ezk ezk ezk -ezk (!rpcsvc.so) +hppa1.1-hp-hpux10.20 ezk ezk ezk -ezk (!rpcsvc.so) +hppa1.1-hp-hpux9.01 ezk[4] ezk[4] nrh/ezk +hppa1.1-hp-hpux9.05 ezk[4] ezk[4] nrh/ezk +hppa1.1-hp-hpux9.07 ezk[4] ezk[4] nrh/ezk +i386-pc-bsdi2.1 ezk ezk ezk +i386-pc-bsdi3.0 ezk ezk ezk +i386-pc-bsdi3.1 ezk ezk ezk +i386-pc-solaris2.5.1 ezk ezk ezk ezk +i386-pc-solaris2.6 ezk ezk ezk ezk +i386-unknown-freebsd2.1.0 ezk ezk ezk +i386-unknown-freebsd2.2.1 ezk ezk ezk ezk +i386-unknown-freebsd3.0 ezk ezk ezk ezk +i386-unknown-netbsd1.2.1 ezk ezk ezk ezk +i386-unknown-netbsd1.3 ezk ezk ezk ezk +i386-unknown-netbsd1.3.1 ezk ezk ezk ezk +i386-unknown-openbsd2.1 ezk ezk ezk ezk +i486-ncr-sysv4.3.03 ezk ezk +i486-pc-linux-gnulibc1 ezk ezk ezk ezk +i586-pc-linux-gnulibc1 ezk ezk ezk ezk +i686-pc-linux-gnu ezk ezk ezk ezk +m68k-hp-hpux9.00 ezk[4] ezk[4] nrh/ezk +m68k-next-nextstep3 ezk ezk ezk +m68k-sun-sunos4.1.1 ezk ezk +mips-dec-ultrix4.3 ro ro ro +mips-sgi-irix5.2 +mips-sgi-irix5.3 ezk ezk ezk +mips-sgi-irix6.2 ezk[1] ezk[1] ezk[1] +mips-sgi-irix6.4 ezk ezk ezk ezk (!gcc) +powerpc-ibm-aix4.1.5.0 ezk ezk wpaul +powerpc-ibm-aix4.2.1.0 ezk ezk ezk +rs6000-ibm-aix3.2 ezk ezk ezk +rs6000-ibm-aix3.2.5 ezk ezk ezk +rs6000-ibm-aix4.1.4.0 ezk ezk +sparc-sun-solaris2.3 ezk ezk ezk +sparc-sun-solaris2.4 ezk ezk ezk ezk +sparc-sun-solaris2.5 ezk ezk ezk ezk +sparc-sun-solaris2.5.1 ezk ezk ezk ezk +sparc-sun-solaris2.6 ezk ezk[2] ezk ezk +sparc-sun-sunos4.1.1 ezk ezk ezk ezk +sparc-sun-sunos4.1.3 ezk ezk ezk ezk +sparc-sun-sunos4.1.3C ezk ezk ezk ezk +sparc-sun-sunos4.1.3_U1 ezk ezk ezk ezk +sparc-sun-sunos4.1.4 ezk ezk ezk ezk +sparc-unknown-linux-gnulibc1 ezk ezk ezk ezk +sparc-unknown-netbsd1.2E ezk ezk ezk + +EMAIL ID LEGEND: + +bking: Bevis R W King +dsr: Dan Riley +ezk: Erez Zadok +nrh: Nick Hall +stolke: Andreas Stolcke +wpaul: Bill Paul +finkel: Raphael Finkel +ro: Rainer Orth + + +FOOTNOTES: + +[1] If compiling with cc on Irix 6, then use + + CC="cc -32 -Wl,-woff,84" ./buildall + +to build (good) "old style" 32 bit code and suppress stupid linker warnings +about unused libraries. + +Also, to get NFS V3 working, you need these two patches from SGI: + + patch 1615: NFS over TCP + patch 2041: NFS roll-up patch + +and then add "-p tcp" to /etc/config/nfsd.options. + +[2] If compiling on Solaris 2.6, you need to add -D_LARGEFILE64_SOURCE to +CFLAGS to enable the 64bit file offset interface: + + make CFLAGS="-O2 -g -D_LARGEFILE64_SOURCE" + +If you're using the standard configure script, it will add this flag for you +automatically. + +[3] DU-4.0 may not use NFS (server-side) V3 by default. You may need to +adjust /etc/init.d/nfs, and change the nfsd startup line from to + + if /usr/sbin/nfsd $NUM_NFSD; then +to + if /usr/sbin/nfsd -t 8 -u 8 ; then + +[4] HPUX 9.X has a bad /bin/sh that runs out of fixed memory allocations. +If you use the configure script, you must run it as + + /bin/ksh ./configure + +Also, this system has a bad /bin/make that cannot handle VPATH well. You +cannot use --srcdir or the buildall script with it. I suggest you install +GNU make or configure locally with "/bin/ksh ./configure". + +Erez. diff --git a/contrib/amd/MIRRORS b/contrib/amd/MIRRORS new file mode 100644 index 0000000..6ea3dbf --- /dev/null +++ b/contrib/amd/MIRRORS @@ -0,0 +1,43 @@ +# -*- text -*- + + AM-UTILS-6.0 MIRRORS + +Note: in case of any problems accessing the individual FTP sites, please +contact their respective maintainers. If you wish to be added to the +official mirror list, please send mail to amd-dev@cs.columbia.edu with the +full URL, maintainer's email, and geographical location. + +U.S.A: + New York (Primary Site): + ftp://shekel.mcl.cs.columbia.edu/pub/am-utils + Maintainer: ezk@cs.columbia.edu + Maryland: + ftp://ftp.cs.umn.edu/pub/AMD + Maintainer: dokas@cs.umn.edu + Virginia (Newport News): +* ftp://www.ferginc.com/pub/unix/am-utils + Maintainer: Branson.Matheson@FergInc.com + +Europe: + Germany: + ftp://ftp.fu-berlin.de/pub/unix/network/am-utils + Maintainer: ftp-adm@ftp.fu-berlin.de + Sweden: + ftp://ftp.sunet.se/pub/unix/admin/am-utils + Maintainer: archive@ftp.sunet.se + Sweden: + ftp://ftp.matematik.su.se/pub/mirrors/shekel.mcl.cs.columbia.edu/pub/am-utils + Maintainer: lifj@matematik.su.se + UK: + ftp://sunsite.org.uk/packages/am-utils + Maintainer: lmjm@icparc.ic.ac.uk + +Asia: + Japan: + ftp://ftp.u-aizu.ac.jp/pub/net/amd/am-utils + Maintainer: ftp-admin@u-aizu.ac.jp + +Australia: + Melbourne: + ftp://ftp.sage-au.org.au/pub/network/filesystem/am-utils + Maintainer: mirror@ftp.sage-au.org.au diff --git a/contrib/amd/NEWS b/contrib/amd/NEWS new file mode 100644 index 0000000..f1df1e0 --- /dev/null +++ b/contrib/amd/NEWS @@ -0,0 +1,628 @@ +*** Notes specific to am-utils version 6.0a16: + +- new ports: + hppa1.0-hp-hpux11.00 (works, not NFS V.3 due to missing headers) + mips-dec-ultrix4.3 (working, unverified) + +- new minor ports: + i386-pc-bsdi3.1 + i386-unknown-netbsd1.3.1 + alpha-dec-osf2.1 + +- new options addopt:=ARG will "smartly" add and override options specified +in opts:= + +- new amd.conf options: + pid_file: specifies the file to store the PID + hesiod_base: specifies the base for the Hesiod service + unmount_on_exit: if 'yes' will attempt to unmount all file systems + when amd exits. + +- amd.conf file is parsed after all other command line options. If no +options specified at all, then use /etc/amd.conf by default. + +- some variables' values are now compared case-insensitive as per specs, +such as host names, domain names, and more. + +- NIS service uses a new isup() function to detect if the service is up +before using it. Used to ensure amd doesn't clear the existing maps before +reloading them, unless the remote info service is working. + +- new cdfs mount options: rrip, noversion, defperm, nodefperm (OSF) + +- support efs/xfs separately on irix + +- new -D info trace option to turn on info specific debugging, such as +RES_DEBUG for hesiod services. + +- document updates and fixes + +- new file MIRRORS lists official mirror sites (also in am-utils home page) + +- new file BUGS lists known amd/OS bugs + +- source restructuring: rename all Amd file-systems' sources to amfs_ARG.c +such that it matches the type:=ARG as well. Free names afs/dfs for Andrew +F/S and Distributed F/S. + +- checkpoint config.guess several times during the long configure, so that +if it is aborted midway, the bulk of the features discovered will be re-read +from the config.cache file. + +- more systems support shared libraries (libtool 1.2) + +- using automake 1.3 + more fixes + +- bugs fixed: + use dynamic buffer for list of interfaces, not fixed size + output of amd -H duplicated if >2 interfaces + -D mem for hlfsd not on by default (so it will daemonize) + linux looks for ext2fs before ufs + CDFS looks for 'isofs' mount type as well + compile on Solaris 2.6 with /opt/SUNWspro/bin/cc + various additional fixes which gcc 2.8.x reported + print syslog help string based on what's supported + correctly ignore loopback interface on SunOS 3.x + don't use -lucb for strcasecmp + hlfsd's dump file securely written in /usr/tmp/hlfsd.dump.XXXXXX + inherit NFS V.3 mounts correctly + write pid file securely + +*** Notes specific to am-utils version 6.0a15: + +- new ports: + alpha-unknown-linux-gnu: works + i386-unknown-netbsd1.3: fully working + *-sun-sunos3: compiles, not tested + +- updated ports: + m68k-next-nextstep3: cleaner compile, works. + +- new file system type nfsl (NFS Link). Uses nfs if file system is remote, +and link if it is local (based on if $rhost equals the host name). + +- support for Solaris cachefs. Requires setting fs, rfs, and a new variable +cachedir. See documentation for explanation, examples, and caveats. + +- support negated selector functions such as !exists(/foo/bar) + +- wire, network, netnumber, in_network() selectors now match against all +locally attached networks (by either name or number), not just the first two +interfaces. + +- new program pawd (and man page for it) --- Print Automounter Working +Directory, to print the proper pathname of the cwd or any other pathname, +adjusted for automounter paths, while avoiding mount points. + +- two new switches to amq: -U will force using UDP only; -T will force using +only TCP to communicate with amd. If neither (or both) are specified, amq +will try TCP first, and if that failed, will try UDP. + +- support syslog facilities, using "amd -l syslog:facility". Old behavior +when using only -l syslog is to use the LOG_DAEMON facility. + +- you may specify browsable_dirs=full, to get a listing of all entries +(other than /default), including those with '*' wildcard and '/' +characters. + +- amd -D trace now also includes as much of struct nfs_args as can be +displayed. Useful in figuring out what the kernel really gets during a +mount(2), as opposed to what the /etc/mnttab file says. -D trace also +traces the xdr_* functions. + +- support for versions of shared libamu version. upped version from 0.0.0 +to 1.0.0. each am-utils release that will change the library will also +update its version. + +- amd/ops_TEMPLATE.c: a new template file for those brave enough to try and +implement a new amd file system. Includes comments and other info useful +for developers. + +- if localconfig.h exists in the current directory during the run of +configure, it is included in all am-utils sources. This allows courageous +developers to make certain modifications during compilations, and especially +turn off undesired features (not very recommended). + +- documentation types and updates for all new features, ports, etc. + +- bugs fixed: + support NFS mount options grpid and maxgrps + nextstep: set NFS success code to 0 (NFS_OK), not 1 (EPERM) + bsdi2: set NFS success code to 0 (NFS_OK), not 1 (EPERM) + set NFS V.3 mount table names to "nfs" if vers/proto exist + use mkstemp() if possible (more secure) + ctl-amd looks for amd.conf in ${prefix}/etc after /etc + hpux: use "ignore" mount table type + openbsd2.2: turn off "noconn" mount option, so only connected used + fixed memory leak in hlfsd (don't setpwent after endpwent) + all NFS3 systems should have proto/vers mount/amd options + DEBUG_MEM compiles and prints something more useful + uninit_mntfs(): free() mf_private *after* it is used + browsable_readdir: fewer bytes sent back to kernel for each chunk + mount_toplvl: don't free() an automatic variable! + amd should chdir() to / before daemonzing (for core dumps etc) + cdfs should be called 'cdfs' not whatever the mnttab type is + amd -v: don't print "FS:" list twice when >=2 net interfaces + +*** Notes specific to am-utils version 6.0a14: + +- updated ports: + powerpc-ibm-aix4.2.1.0: NFS V.3 works + +- minor new ports: + sparc-sun-sunos4.1.3C + m68k-sun-sunos4.1.1 (sun3) + mips-sgi-irix5.2 + +- new option to amd, -O ARG, will override the operating systems *name* with +ARG. Corrected documentation for amd -o ARG --- it overrides the operating +system *version* and not the name as the docs incorrectly stated. + +- logging now behave more like syslog: will not print repeated strings, but +rather a count such as "last message repeated N times". (N will not exceed +100.) + +- restructured the code which deals with the numerous possible fields and +flags that are set in struct nfs_args. That code was moved to libamu as +the functions compute_nfs_args() and compute_automounter_nfs_args(). + +- bugs fixed: + mnttab name ufs/cdfs/pcfs/etc filesystems corrected + use pmap_ping for amq (a must for secure portmappers, bsdi2/3) + test for xfs (irix) as a disk-based filesystem + set correct nfs_prot headers for Solaris 2.5 + removed stale code from lostaltmail.in + lostaltmail will look for conf file in multiple locations + assorted documentation corrections + amq does not print "get_secure_amd_client" if run as root + +*** Notes specific to am-utils version 6.0a13: + +- new in_network(ARG) nomadic selector, true if ARG is the name (or number) +of any of this host's network interfaces. + +- removed variables primnetname, primnetnum, subsnetname, and subsnetnum. +(Kept "wire" and its alias "network", and "netnumber".) + +- include am-utils.dvi and am-utils.ps in distribution. + +- hlfsd supports new option -P ARG, for reading password map off of file +ARG. Allows you to use the hlfs redirector using paths other than user's +home directories. + +- use a replacement yp_all for some systems (irix) known to have a broken +one which leaks a file descriptor each time called. + +- if remote NFS server is down or does not support portmap, downgrade +machine to NFS V.2 and retry again later. + +- bugs: + don't redefine yywrap on systems using a modified flex + use correct "ignore" mnttab/mount option on hpux for df(1) + use nfs_args' fsname field (hpux) to avoid syncer/mount(1) problems + don't add ops_ufs.o twice to Makefile's $(OBJS) + don't fail if autofs listener fails to initialize + hlfsd should test if run as root after usage() and getopt + +- minor code cleanups for netbsd + +- html docs now in http://www.cs.columbia.edu/~ezk/am-utils/ + +- added README file in binaries ftp directory + +*** Notes specific to am-utils version 6.0a12: + +- minor or updated/broken ports fixed: + hppa1.1-hp-hpux10.10: compiles, untested (probably works). + hppa1.1-hp-hpux9.05: compiles, untested (probably works). + hppa1.1-hp-hpux9.07: compiles, untested (probably works). + m68k-hp-hpux9.00: compiles, untested (probably works). + rs6000-ibm-aix4.1.4.0: compiles, untested. + sparc-sun-solaris2.6: works w/ NFS V.3. + sparc-sun-sunos4.1.4: compiles, untested (probably works). + +- new ports: + powerpc-ibm-aix4.2.1.0: compiles w/ NFS V.3, untested. + +- wire-test also checks for combinations of NFS protocol/version from the +client to a remote (or local) host. + +- conf/mtab/mtab_file.c: use flock() to lock the file, and fcntl() if +flock() is not available. (Used to prefer fcntl() over flock().) + +- bug fixes: + tli get_nfs_version() gets into an infinite loop + tli get_nfs_version() should time out faster + sockets get_nfs_version() should work w/ secure portmappers + ESTALE returned for NFS mounts for SunOS 4.x fixed + do not exceed HOSTNAMESZ for nfs_args.hostname (get ENAMETOOLONG) + properly initialize some mntent_t fields (fsck, freq, mnt_time) + properly initialize some pcfs_args fields (mask, uid, gid) + properly initialize some cdfs_args fields (ssector) + +*** Notes specific to am-utils version 6.0a11: + +- bug fixes: + amd could not NFS mount v.2 servers from v.3 clients + hlfsd will only use first occurrence of home dir for same uid + +*** Notes specific to am-utils version 6.0a10: + +- MAJOR DOCUMENTATION UPDATE! (first time in 6 years) + +- new ports: + m68k-next-nextstep3: configures, compiles, not tested. + +- preliminary autofs support. See README.autofs for details. + +- new amd.conf [global] yes/no keywords: + show_statfs_entries: shows number of entries for df(1) + fully_qualified_hosts: use FQHN for NFS/RPC authentication + +- detect down remote hosts faster + +- log output of "amd -v" at startup + +- removed $osver override for solaris: now it is 2.5.1, not 5.5.1 + +- buildall will use gmake first if available + +- bugs fixed: + amd core dumped when remote host was down + allow up to 1024 entries back from readdir() + amd.conf works even if only [global] option defined + avoid using bad memcmp() implementations + fixed meaning of plock [global] option (was reversed) + hlfsd infinite loop unless compiled with --enable-debug + NIS code works with NIS+ servers in NIS compatibility mode + reset tag fields in amd.conf so they don't carry to other entries + +*** Notes specific to am-utils version 6.0a9: + +- new ports: + sparc-sun-solaris2.4: + configures/compiles, and runs (no NFS V3) + i386-unknown-openbsd2.1: + configures/compiles, runs (NFS V3) + +- updated ports: + i486-ncr-sysv4.3.03: configures/compiles, not tested + +- Multiple amd support: new amd.conf [global] key "portmap_program" can be +used to specify an alternate RPC program number for amd to un/register. +Allowed numbers range from 300019 to 300029. A matching new option for amq: +-P prognum, will use an alternate program number to contact. + +- man pages: + amd.conf.5 new + mk-amd-map.8 new + amd.8 updated + amq.8 updated + (other man pages required minor updates) + +- shared libraries support expanded. Using GNU libtool-1.0. You can build +a shared version of libamu, and link with it accordingly, by specifying +--enable-shared to configure. Default is --enable-static --disable-shared, +and you can mix and match. See "INSTALL" file for listing of systems on +which shared libraries seem to build and work fine. + +- new option: amq -p, will return the PID of the running amd (local or +remote). Uses a new RPC message. Useful especially in "ctl-amd stop". + +- new configure script options --enable-ldflags, for specifying -L flags. +The older --enable-libs is to be used only for -l options. + +- two new LDAP map options for amd.conf: ldap_cache_seconds and +ldap_cache_maxmem. + +- new script, am-eject from Debian linux's version of amd-upl102. + +- additional passwd map support using var[0-3], from Debian folks. + +- hesiod code cleanup. works for hesiod 1.3 as well as 3.0. + +- removed defunct -h option from amd. + +- started using automake-1.2. This fixed several bugs that caused some +versions of yacc/lex and non-GNU make to fail. + +- bug fixes: + amd/hlfsd mounts should be hidden from df(1) + use "noconn" option for nfs mounts (multi-homed hosts) + don't use connected sockets on linux before 1.3.10 (from Debian) + better checks for [gn]dbm + forbid excessive retries after timeouts (from Debian) + readdir(): don't skip over map entries with prefix, and include it + more assorted linux fixes from Debian folks + lofs mount on svr4 was broken + find default value of $karch from uname() not $arch + hlfsd failed to mount itself on some little-endians + + +*** Notes specific to am-utils version 6.0a8: + +- new ports: + i386-unknown-netbsd1.2.1: configures/compiles (with NFS V.3), works, + but some OS stability problems exist. + +- updated ports: + hppa1.1-hp-hpux9.01: + now tested and working + rs6000-ibm-aix3.2 and rs6000-ibm-aix3.2.5: + now tested and working + +- fixed browsable directories (readdir) code. + +- better methods to find amd/hlfsd pid to kill in ctl-{amd,hlfsd} + +- "ignore/auto" mount types fixed for irix, sunos, and others, so "df" does not +show amd mounts by default (but GNU df -a does). + +- each time amd is built, a new "build" version is incremented. See amd -v. + +- man page for fsinfo added + +- empty fillers for new file (bsd44) systems: nullfs, unionfs, umapfs. + +- when amd is not running, or portmapper is down, make amq timeout faster (5 +sec) than system default, usually 4-5 minutes. + +- bug fixes: + hlfsd mount got "protocol not supported" + first regular map in amd.conf didn't inherit global options + make "bad" versions of lex still work with amd/conf_parse.l + check for 'nodev' option, not 'nondev' + typo in "ro" option, and fillers to ac{reg,dir}{min,max} and others + amd.conf parsing done before switching default log/debug options + allow doubly-quoted values in amd.conf + hesiod-reload code cleanup + +- assorted code cleanup + + +*** Notes specific to am-utils version 6.0a7: + +- new ports: + i386-unknown-freebsd3.0: + fully functional with NFS V.3 + sparc-sun-solaris2.3: + fully functional (should work for 2.4) + sparc-unknown-netbsd1.2E: + configures/compiles (with NFS V.3), untested + +- updated ports: + i386-pc-bsdi3.0: + NFS V.3 works + look for hesiod in libc + mips-sgi-irix5.3: + fully functional with NFS V.3 + +- LDAP support! New [global] amd.conf options ldap_base and ldap_hostports. +Also includes a new script amd2ldif to convert amd maps into plain text LDAP +object files. + +- the following amd.conf variables: browsable_dirs, map_options, map_type, +mount_type, and search_path --- can now be specified in [global] as well as +the map entry itself. That way you can declare them only once in [global], +and override them as needed per map. + +- option "cluster" added to [global] (HPUX clusters ala "amd -C"). + +- assorted info_hesiod map fixes and cleanup. removed HESIOD_RELOAD code. + +- added netgrp(name) function to amd map syntax to see if current host is in +the netgroup. + +- removed unused option "amd -m". + +- filled in "tasks" file with todo items. + +- filled "COPYING" file with legal stuff. + +- cleanup: all global variables are now in one big structure (struct +amu_global_options) that's easy to identify and enhance. Also migrated +several flags that used be an integer each into one unsigned integer that's +used as a bit-flag. + +- big fixes: + xdr_mountres3 should compile only if has NFS V3 + lex/yacc macros show full pathname (to tell if correct one runs) + misc fixes/cleanup + + +*** Notes specific to am-utils version 6.0a6: + +- amd configuration file! + +See scripts/amd.conf-sample for help and some explanation. This new conf +file allows for the following new features: + + default selectors can be turned on/off globally. + browsable_dirs/readdir() support can be turned on per map. + search paths for file type maps. + can force the map type to file, nis, ndbm, etc. rather than default + to looking at all of them. + tag each map for "amd -T tag", useful for grouping maps. + can override $os and others (so if you don't like "sunos5" default + naming, set os=sos5 and it will work with your old maps). + and more goodies... + +- enable-default-selectors: No longer turned on by the configure script or +optionally compiled. Code made dynamic and can be turned on or off from the +amd.conf file. This code is off by default, and must be turned on by +amd.conf's [global] section. + +- new ports: + mips-sgi-irix5.3: configure/compile, not tested + i486-ncr-sysv4.3.03: configure/compile, not tested + +- updated ports: + alpha-dec-osf4.0: major code redone + sparc-sun-sunos4.1.3: fixed and working + mips-sgi-irix6.2: tested with gcc and "cc -32 -Wl,-woff,84" + mips-sgi-irix6.4: tested with gcc and "cc -32 -Wl,-woff,84" + +- better NFS3 port, including more support for proto= and vers=, and +automatic determination of proto/vers combination. + +- conf/nfs_prot/nfs_prot_*.h: all of the NFS protocol header files had to be +redone, because of the osf4 port. OSF used very different names for these, +and they conflicted with am-utils'. The only solution was to more or less +conform to OSF4's naming, and change all the others. + +- ctl-amd script: + improved to look for amd.conf in $prefix/etc and /etc + better methods for finding the pid of amd to kill + +- autoconf support for LDAP. amd/info_ldap.c needs to be written. + +- wire-test also reports the local IP address. Some systems have multiple, +buggy version of get_myaddress(), esp. SunOS and Irix. Note that Solaris +x86 has a buggy htonl(). + +- amd -H prints usage. + +- bugs fixed: + minor TLI problem in fwd_socket + mount options properly comma delimited + LIBS is set only to the right set of libraries to include + selectors-on-default code ignored last selector ent in /defaults + assorted code cleanups + + +*** Notes specific to am-utils version 6.0a5: + +- NFS Version 3 support!!! + + Works on Solaris 2.5.1. + Minimal testing done on Irix 6. + Compiles cleanly on DU-4.0 but no tests performed. + +Will fall back to V2 mounts when V3 is not available. Will also use TCP if +possible, UDP otherwise. + +- Ports to new platforms: + + alpha-dec-osf4.0 (not tested) + i386-pc-bsdi3.0 (tested and working) + i386-unknown-freebsd2.2.1 (tested and working) + sparc-unknown-linux-gnu (tested and working) + +- New scripts added: + + amd2sun: convert amd maps to Sun automount maps + ctl-amd: script to start/stop/restart amd + ctl-hlfsd: script to start/stop/restart hlfsd + expn: expand mail alias (used by hlfsd) + lostaltmail: redeliver "lost" mail redirected by hlfsd + lostaltmail.conf-sample: sample conf file for lostaltmail + wait4amd: run a command once amd is up on a host + wait4amd2die: wait for an amd process to die before returning + +- "amd -v" now includes more info and "amq -v" lists all of it. + +- new parser for linux specific mount options. + +- Main bugs fixed: + + "new toplvl readdir" bug caused amd to dump core + handler for SIGCHLD didn't check for all possible children + hlfsd leaking file descriptors when home file system was full + cdfs/pcfs mounts should not timeout by default + hesiod domain names should be compared in case-insensitive manner + several printfs in amq were missing \n + + +*** Notes specific to am-utils version 6.0a4: + +- amd services both TCP and UDP amq requests. This will help because of the +limited UDP message size. + +- "amq -M" code is disabled by default because it is insecure. It is +rarely used. Users who wish to use it should run +"configure --enable-amq-mount". + + +*** Notes specific to am-utils version 6.0a3: + +- New tested ports (configures, compiles, and runs): + + i386-unknown-freebsd2.2 + +- New ports (configures and compiles correctly, not tested): + + rs6000-ibm-aix3.2.5 + rs6000-ibm-aix4.1.5.0 + +- More am-utils programs ported to all existing platforms: hlfsd, fsinfo, +mk-amd-map, and fixmount. + +- Shared libraries: a new configure option --enable-shared will build a +shared libamu.so, link applications with it, and use it. Reduces binary +sizes by 20-30%. This is the first step towards loadable modules, as many +changes had to be done to be able to compile and use PIC code. This is code +that obviously needs to be generalized to be able to build shared libraries +on many other platforms. It was only tested on Solaris 5.5.1. + +- the file INSTALL contains the latest compatibility table of which +platforms am-utils configures, compiles and runs on. + +- Trimmed down the size of the configure script. Some tests that are not +used anywhere were removed. + + +*** Notes specific to am-utils version 6.0a2: + +- New ports (configures and compiles correctly, not tested): + + i386-pc-bsdi2.1 + hppa1.1-hp-hpux9.01 + hppa1.1-hp-hpux10.20 + +- new configure options: + + --enable-cppflags[=ARG] + configure/compile with ARG (-I) preprocessor flags + --enable-libs[=ARG] + configure/compile with ARG (-L/-l) library flags + +- filesystem, mount table entries, and mount type tests can now look in +/lib/modules and /proc/filesystems for statically/dyadically loadable kernel +modules (linux) + +- prefer vfat over msdos/pc/etc filesystem for PCFS. + +- moved all fixed headers to include/am_defs. Left only #define/#undef +entries in aux/acconfig.h. + +- make more sense of systems that have full, partial, or no NFS protocol +headers. + +- minor fixes for NetBSD (untested platform). + +- hesiod map fixed. + +- buildall -D: new option to run even stricter developer options. + +- lots of other bugs fixed (see ChangeLog). + + +*** Notes specific to am-utils version 6.0a1: + +I have it configure and build correctly for the following systems: + + i386-pc-solaris2.5.1 + i386-unknown-freebsd2.1.0 + mips-sgi-irix6.2 + sparc-sun-solaris2.5.1 + sparc-sun-sunos4.1.3 + +Amq, wire-test, and "amd -v" work on all of the above. A real running amd +was only tested and confirmed working on + + i386-pc-solaris2.5.1 + sparc-sun-solaris2.5.1 + +Many things are still missing: options, features, etc. But for now, let's +concentrate on getting the basic functionality working on the more popular +systems. diff --git a/contrib/amd/README b/contrib/amd/README new file mode 100644 index 0000000..7ced70b --- /dev/null +++ b/contrib/amd/README @@ -0,0 +1,105 @@ +# -*- text -*- + +This is an alpha version of amd. "Buyers" beware!!! + +See the file NEWS for news on this and previous releases. + +*** General Notes to alpha testers: + +[A] an an alpha testers, I expect you to be able to find certain things on +your own (especially look at the sources to figure out how things work). + +[B] if you intend to modify any files, first find out if the file you want +to modify gets autogenerated from some other place. If so, modify it at the +source. + +You can adjust some of the configuration of am-utils after it has been +auto-configured by putting whatever definitions you wish in a file called +localconfig.h, located in the top build directory (the same one where +config.h is created for you). + +[C] there are several ways you can build am-utils: + +(1) run the buildall script as follows: + + ./buildall + +This would build all the applications inside a special directory relative to +the root of the source tree, called A., where the <> +part is filled in by GNU's config.guess script. This is the preferred +method, for it will separate the build from the sources, and allow you to +run buildall for multiple architectures concurrently. + +You can run "buildall -h" to see what options it takes. + +(2) run the configure script such as: + + ./configure + +and then run + + make + +This would configure amd in the directory you've run the configure script +in, and the built it there. Run "make install" to install all the necessary +files. + +Note that this is good for building only one version of amd on one +architecture! Don't try this for multiple architectures. If you must, then +after doing one such build, run "make distclean" and then reconfigure for +another architecture. + +(3) run the configure script for build in a different location. Let's say +that /src/am-utils-6.0 is where you unpacked the sources. So you could + + mkdir /src/build/sunos5 + cd /src/build/sunos5 + /src/am-utils-6.0/configure --srcdir=/src/am-utils-6.0 + make + +This is a manual method that will let you build in any directory outside the +am-utils source tree. It requires that your "make" program understand +VPATH. This can be used multiple times to build am-utils concurrently in +multiple (but different) directories. In fact, the buildall script +described above. + +(4) If you need to configure am-utils with extra libraries and/or headers, +for example to add hesiod support, do so as follows: + + configure --enable-libs="-lhesiod -lresolv" \ + --enable-ldflags="-L/usr/local/hesiod/lib" \ + --enable-cppflags="-I/usr/local/hesiod/include" + +[D] If you modify any of the *.[chyl] sources in the directories amd, amq, +hlfsd, lib, etc, all you need to do to get a new version of am-utils is run +make. + +If you modify any of the files in the aux/ or conf/ directories, then you +must rebuild the configure script, Makefile.in files, aclocal.m4, etc. The +best way to do so is to run + + ./aux/mkconf +or + ./buildall -K + +To be a developer and be able to run mkconf, you must have autoconf-2.12, +GNU make-3.75 or later, and automake-1.2 (plus my fixes to it) installed on +your system. You may find my version of automake-1.2 where you ftp'ed this +version of am-utils. You may also need GNU libtool 1.0. + +After you've remade the basic configuration files you must rerun the +buildall script to rerun configure and then remake the binaries. + +Modifying M4 macros may not be very intuitive to anyone that has not done so +before. Let me know if you are having any problems with them. I fully +expect, at least initially, to have to be the sole developers of the M4 +macros and let others concentrate on C sources. + +[E] Report all bugs to amd-dev@majordomo.cs.columbia.edu. Avoid reporting +to my personal email address. It is important to involve the whole list in +bug fixes etc. + +Good luck. + +Erez Zadok, +Maintainer, am-utils. diff --git a/contrib/amd/TODO b/contrib/amd/TODO new file mode 100644 index 0000000..9d3b758 --- /dev/null +++ b/contrib/amd/TODO @@ -0,0 +1,177 @@ +# -*- text -*- + +Make a tasks file that people can pick jobs off of. + +take a look at am_compat.h and fix everything there... + +fix all $Id bla bla bla $ on every file. +add my own copyright 1997 etc. + +NOT NEEDED: convert DEBUG symbol to ENABLE_DEBUG +NOT NEEDED: convert DEBUG_MEM symbol to ENABLE_DEBUG_MEM + +Use these two somewhere: +AC_DEFINE(AM_UTILS_NAME_PACKAGE, "am-utils") +AC_DEFINE(AM_UTILS_VERSION, "6.0a1) + +check all "dnl XXX: in configure.in + +check for: INLINE, Const->const, P_void, VOIDP + +rename DEBUG_MTAB to DEBUG_MNTTAB +rename UPDATE_MTAB to MOUNT_TABLE_ON_FILE +rename HAS_NIS_MAPS to HAVE_MAP_NIS +rename HAS_TFS to HAVE_FS_TFS +rename SIG_HNDL_TYP to RETSIGTYPE + +remove HOST_EXEC #define from everywhere. add to am_ops.c a static flag +initialized_vops, which if not true, should set the host_ops vector field to +0 or host_umounted. This way let the feature be turned on if -h option to +amd is given. + +nuke all code that is ifdef'd SUNOS4_COMPAT + +rename NEED_MNTOPT_PARSER to HAVE_HASMNTOPT and cleanup the code. also take +the supplied code in amd/mount_fs.c and include it as the library function +libamd/hasmntopt.c + +TLI code needs to be fixed. + +a way to include a site-specific configuration file IFF it exists from +directory local/<${target}.h> + +replace #include WAIT with nothing (HAVE_SYS_WAIT_H?) + +replace SYS5_SIGNALS with HAVE_SYS_WAIT_H (which is on only if it sys/wait.h +exists and is using the newer "int" for type, not "union wait". The macro +AC_HEADER_SYS_WAIT turns on HAVE_SYS_WAIT_H iff wait*() functions are +posix.1 compliant. Make sure you don't remove SYS5_SIGNALS ifdef's that are +not related to wait*() syscalls. + +add username, hostname, and date at which time amd was compiled. + +No more need for MOUNT_HELPER_SOURCE. + +any code which is included by NEED_UMOUNT_FS, should be on iff +MOUNT_TABLE_ON_FILE is on. + +replace NFS_FH_FIELD with references fo ".fh" in calls to +NFS_FH_DREF(src, dst) macro + +For *EVERY* M4 Macro with case/esac, check that the $host_os case entries +are correct. + +I'm not using amd's regexp code. Instead, use generic system code. If the +system has posix style regexp functions, then change amd/map.c to use +correct new prototype. + +use HAVE_SVC_GETREQSET instead of RPC_4. + +replace all "jsp" in *.[hc] $Id$ with ezk. + +use MNTTAB_FILE_NAME instead of MOUNTED + +use MOUNT_TABLE_ON_FILE instead of READ_MTAB_FROM_FILE + +no more HAS_EMPTY_AUTOMOUNTS, which was used if a df(1) divide by zero bug +was invoked. Instead, change nfs_statfs() code to always return non-zero +values. Then nuke HAS_EMPTY_AUTOMOUNTS. + +REGEXP: use whatever regular expressionlibrary you have on the system, +including regexp.h if available, and using regcomp/regexec. Amd was written +with BSD regexps in mind, not Sys V, so if I use any of those, I have to +watch for correct usage. Otherwise, I can include the older include/re.h +and amd/re.c. Replace HAS_REGEXP with HAVE_REGEXEC. + +The regex code in amd/mapc.c has changed a lot. It probably has bugs. Must +test and debug it!!! + +# string name of filesystem in /etc/mnttab file +Use MNTTAB_TYPE_FOO instead of MTAB_TYPE_FOO. +# string name of mount option in /etc/mnttab file +Use MNTTAB_OPT_FOO instead of MNTOPT_FOO. +# string (or integer?) name of filesystem type in mount(2) syscall +Use MOUNT_TYPE_FOO instead of MNTTYPE_FOO or MOUNT_FOO. +# hex/number of FS mount option in nfs_args passed to mount(2) syscall +Use MNT2_NFS_OPT_FOO instead NFSMNT_FOO. +# hex/number of generic FS mount option directly passed to mount(2) syscall +Use MNT2_GEN_OPT_FOO instead of MS_FOO or M_FOO. + + +update AMD_COMPAT to 6.0 in include/am_utils.h + +convert all mem* functions b* functions (memset to bzero, etc.) or vice +verse. + +put my name/copyright on every src file + +change all struct mnttab/mntent to "mntent_t" + +cleanup lib/resvport.c (TLI vs. Sockets). TLI code is #defin'ed +HAVE_T_OPEN. +[ +setting MTAB_LOCK_FILE (mtab_svr4.c) should be an amd run-time configuration +option. + +change all UMOUNT_FS macros to umount_fs() fxn calls. + +remove getnetbyaddr() from lib/getnetbyaddr.c and then link w/ -lsocket + +take care of various (hlfsd et al) scripts in Makefile.am files. + +rename HOSTNAMESZ to MAXHOSTNAMELEN + +turn on all the NEW_TOPLVL_READDIR code (for "ls" to work in an amd point) + +change all NEW_DEFAULTS to ENABLE_DEFAULT_SELECTOTS (which is now on by +default) + +remove refereces to mnt_freq and mnt_passno in mntent_t since it's not in +use any more. + +remove all the (lint?) comments /*ARGSUSED */ + +change HAS_FOOFS to HAVE_AM_FS_FOO (for example HAS_NFSX -> HAVE_AM_FS_FOO), +but change HAS_UNION_FS to HAVE_AM_FS_UNION. + +some code uses #ifdef M_NEWTYPE to tell if mount(2)'s type field is "char *" +or int. Use MTYPE_TYPE declaration instead (not ifdef macro!) + +change DEBUG_MTAB to DEBUG_MNTTAB + +deal with the changes in values of $os, $arch, and $osver! + +replace SYS5_SIGNALS with REINSTATE_SIGNAL_HANDLER + +figure out how to auto-conf HAS_HESIOD_RELOAD (amd/info_hesiod.c). For now +I've used the macro HAVE_HS_ZONE_TRANSFER. + + + + +****************************************************************************** +PERL SCRIPT TO FIX OLD AMD MAPS: +- fix '=' to ':=' +- fix sos5 -> solaris2, etc. + +****************************************************************************** +USE AS IS: + +- SVC_IN_ARG_TYPE (change from SVC_IN_ARGS_TYPE, with an 'S') +- NFS_FH_TYPE +- MTYPE_TYPE +- MOUNT_TYPE_* NO!!! + +****************************************************************************** +NEW FEATURES: + +- autofs +- cachefs +- dbm/gdbm/db file maps +- add amd option -O (override) to override $os, $osver, $arch, $karch, etc. + +****************************************************************************** +DONE: + +HAS_TFS is gone and all of it's code too. +major code cleanup, removed if 0 code and if notdef diff --git a/contrib/amd/amd/am_ops.c b/contrib/amd/amd/am_ops.c new file mode 100644 index 0000000..918c3f1 --- /dev/null +++ b/contrib/amd/amd/am_ops.c @@ -0,0 +1,441 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: am_ops.c,v 5.2.2.1 1992/02/09 15:08:17 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* + * The order of these entries matters, since lookups in this table are done + * on a first-match basis. The entries below are a mixture of native + * filesystems supported by the OS (HAVE_FS_FOO), and some meta-filesystems + * supported by amd (HAVE_AM_FS_FOO). The order is set here in expected + * match-hit such that more popular filesystems are listed first (nfs is the + * most popular, followed by a symlink F/S) + */ +static am_ops *vops[] = +{ +#ifdef HAVE_FS_NFS + &nfs_ops, /* network F/S (version 2) */ +#endif /* HAVE_FS_NFS */ +#ifdef HAVE_AM_FS_LINK + &amfs_link_ops, /* symlink F/S */ +#endif /* HAVE_AM_FS_LINK */ + + /* + * Other amd-supported meta-filesystems. + */ +#ifdef HAVE_AM_FS_NFSX + &amfs_nfsx_ops, /* multiple-nfs F/S */ +#endif /* HAVE_AM_FS_NFSX */ +#ifdef HAVE_AM_FS_NFSL + &amfs_nfsl_ops, /* NFS with local link existence check */ +#endif /* HAVE_AM_FS_NFSL */ +#ifdef HAVE_AM_FS_HOST + &amfs_host_ops, /* multiple exported nfs F/S */ +#endif /* HAVE_AM_FS_HOST */ +#ifdef HAVE_AM_FS_LINKX + &amfs_linkx_ops, /* symlink F/S with link target verify */ +#endif /* HAVE_AM_FS_LINKX */ +#ifdef HAVE_AM_FS_PROGRAM + &amfs_program_ops, /* program F/S */ +#endif /* HAVE_AM_FS_PROGRAM */ +#ifdef HAVE_AM_FS_UNION + &amfs_union_ops, /* union F/S */ +#endif /* HAVE_AM_FS_UNION */ +#ifdef HAVE_AM_FS_INHERIT + &amfs_inherit_ops, /* inheritance F/S */ +#endif /* HAVE_AM_FS_INHERIT */ + + /* + * A few more native filesystems. + */ +#ifdef HAVE_FS_UFS + &ufs_ops, /* Unix F/S */ +#endif /* HAVE_FS_UFS */ +#ifdef HAVE_FS_XFS + &xfs_ops, /* Unix (irix) F/S */ +#endif /* HAVE_FS_XFS */ +#ifdef HAVE_FS_EFS + &efs_ops, /* Unix (irix) F/S */ +#endif /* HAVE_FS_EFS */ +#ifdef HAVE_FS_LOFS + &lofs_ops, /* loopback F/S */ +#endif /* HAVE_FS_LOFS */ +#ifdef HAVE_FS_CDFS + &cdfs_ops, /* CDROM/HSFS/ISO9960 F/S */ +#endif /* HAVE_FS_CDFS */ +#ifdef HAVE_FS_PCFS + &pcfs_ops, /* Floppy/MSDOS F/S */ +#endif /* HAVE_FS_PCFS */ +#ifdef HAVE_FS_CACHEFS + &cachefs_ops, /* caching F/S */ +#endif /* HAVE_FS_CACHEFS */ +#ifdef HAVE_FS_NULLFS +/* FILL IN */ /* null (loopback) F/S */ +#endif /* HAVE_FS_NULLFS */ +#ifdef HAVE_FS_UNIONFS +/* FILL IN */ /* union (bsd44) F/S */ +#endif /* HAVE_FS_UNIONFS */ +#ifdef HAVE_FS_UMAPFS +/* FILL IN */ /* uid/gid mapping F/S */ +#endif /* HAVE_FS_UMAPFS */ + + /* + * These 5 should be last, in the order: + * (1) amfs_auto + * (2) amfs_direct + * (3) amfs_toplvl + * (4) autofs + * (5) amfs_error + */ +#ifdef HAVE_AM_FS_AUTO + &amfs_auto_ops, /* Automounter F/S */ +#endif /* HAVE_AM_FS_AUTO */ +#ifdef HAVE_AM_FS_DIRECT + &amfs_direct_ops, /* direct-mount F/S */ +#endif /* HAVE_AM_FS_DIRECT */ +#ifdef HAVE_AM_FS_TOPLVL + &amfs_toplvl_ops, /* top-level mount F/S */ +#endif /* HAVE_AM_FS_TOPLVL */ +#ifdef HAVE_FS_AUTOFS + &autofs_ops, /* autofs mount F/S */ +#endif /* HAVE_FS_AUTOFS */ +#ifdef HAVE_AM_FS_ERROR + &amfs_error_ops, /* error F/S */ +#endif /* HAVE_AM_FS_ERROR */ + 0 +}; + + +void +ops_showamfstypes(char *buf) +{ + struct am_ops **ap; + int l = 0; + + buf[0] = '\0'; + for (ap = vops; *ap; ap++) { + strcat(buf, (*ap)->fs_type); + if (ap[1]) + strcat(buf, ", "); + l += strlen((*ap)->fs_type) + 2; + if (l > 60) { + l = 0; + strcat(buf, "\n "); + } + } +} + + +static void +ops_show1(char *buf, int *lp, const char *name) +{ + strcat(buf, name); + strcat(buf, ", "); + *lp += strlen(name) + 2; + if (*lp > 60) { + strcat(buf, "\t\n"); + *lp = 0; + } +} + + +void +ops_showfstypes(char *buf) +{ + int l = 0; + + buf[0] = '\0'; + +#ifdef MNTTAB_TYPE_AUTOFS + ops_show1(buf, &l, MNTTAB_TYPE_AUTOFS); +#endif /* MNTTAB_TYPE_AUTOFS */ + +#ifdef MNTTAB_TYPE_CACHEFS + ops_show1(buf, &l, MNTTAB_TYPE_CACHEFS); +#endif /* MNTTAB_TYPE_CACHEFS */ + +#ifdef MNTTAB_TYPE_CDFS + ops_show1(buf, &l, MNTTAB_TYPE_CDFS); +#endif /* MNTTAB_TYPE_CDFS */ + +#ifdef MNTTAB_TYPE_CFS + ops_show1(buf, &l, MNTTAB_TYPE_CFS); +#endif /* MNTTAB_TYPE_CFS */ + +#ifdef MNTTAB_TYPE_LOFS + ops_show1(buf, &l, MNTTAB_TYPE_LOFS); +#endif /* MNTTAB_TYPE_LOFS */ + +#ifdef MNTTAB_TYPE_EFS + ops_show1(buf, &l, MNTTAB_TYPE_EFS); +#endif /* MNTTAB_TYPE_EFS */ + +#ifdef MNTTAB_TYPE_MFS + ops_show1(buf, &l, MNTTAB_TYPE_MFS); +#endif /* MNTTAB_TYPE_MFS */ + +#ifdef MNTTAB_TYPE_NFS + ops_show1(buf, &l, MNTTAB_TYPE_NFS); +#endif /* MNTTAB_TYPE_NFS */ + +#ifdef MNTTAB_TYPE_NFS3 + ops_show1(buf, &l, "nfs3"); /* always hard-code as nfs3 */ +#endif /* MNTTAB_TYPE_NFS3 */ + +#ifdef MNTTAB_TYPE_NULLFS + ops_show1(buf, &l, MNTTAB_TYPE_NULLFS); +#endif /* MNTTAB_TYPE_NULLFS */ + +#ifdef MNTTAB_TYPE_PCFS + ops_show1(buf, &l, MNTTAB_TYPE_PCFS); +#endif /* MNTTAB_TYPE_PCFS */ + +#ifdef MNTTAB_TYPE_TFS + ops_show1(buf, &l, MNTTAB_TYPE_TFS); +#endif /* MNTTAB_TYPE_TFS */ + +#ifdef MNTTAB_TYPE_TMPFS + ops_show1(buf, &l, MNTTAB_TYPE_TMPFS); +#endif /* MNTTAB_TYPE_TMPFS */ + +#ifdef MNTTAB_TYPE_UFS + ops_show1(buf, &l, MNTTAB_TYPE_UFS); +#endif /* MNTTAB_TYPE_UFS */ + +#ifdef MNTTAB_TYPE_UMAPFS + ops_show1(buf, &l, MNTTAB_TYPE_UMAPFS); +#endif /* MNTTAB_TYPE_UMAPFS */ + +#ifdef MNTTAB_TYPE_UNIONFS + ops_show1(buf, &l, MNTTAB_TYPE_UNIONFS); +#endif /* MNTTAB_TYPE_UNIONFS */ + +#ifdef MNTTAB_TYPE_XFS + ops_show1(buf, &l, MNTTAB_TYPE_XFS); +#endif /* MNTTAB_TYPE_XFS */ + + /* terminate with a period, newline, and NULL */ + if (buf[strlen(buf)-1] == '\n') + buf[strlen(buf) - 4] = '\0'; + else + buf[strlen(buf) - 2] = '\0'; + strcat(buf, ".\n"); +} + + +/* + * return string option which is the reverse of opt. + * nosuid -> suid + * quota -> noquota + * ro -> rw + * etc. + * may return pointer to static buffer or subpointer within opt. + */ +static char * +reverse_option(const char *opt) +{ + static char buf[80]; + + /* sanity check */ + if (!opt) + return NULL; + + /* check special cases */ + /* XXX: if this gets too long, rewrite the code more flexibly */ + if (STREQ(opt, "ro")) return "rw"; + if (STREQ(opt, "rw")) return "ro"; + if (STREQ(opt, "bg")) return "fg"; + if (STREQ(opt, "fg")) return "bg"; + if (STREQ(opt, "soft")) return "hard"; + if (STREQ(opt, "hard")) return "soft"; + + /* check if string starts with 'no' and chop it */ + if (NSTREQ(opt, "no", 2)) { + strcpy(buf, &opt[2]); + } else { + /* finally return a string prepended with 'no' */ + strcpy(buf, "no"); + strcat(buf, opt); + } + return buf; +} + + +/* + * start with an empty string. for each opts1 option that is not + * in opts2, add it to the string (make sure the reverse of it + * isn't in either). finally add opts2. return new string. + * Both opts1 and opts2 must not be null! + * Caller must eventually free the string being returned. + */ +static char * +merge_opts(char *opts1, char *opts2) +{ + mntent_t mnt2; /* place holder for opts2 */ + char *newstr; /* new string to return (malloc'ed) */ + char *tmpstr; /* temp */ + char *eq; /* pointer to '=' within temp */ + char oneopt[80]; /* one option w/o value if any */ + char *revoneopt; /* reverse of oneopt */ + int len = strlen(opts1) + strlen(opts2) + 2; /* space for "," and NULL */ + char *s1 = strdup(opts1); /* copy of opts1 to munge */ + + /* initialization */ + mnt2.mnt_opts = opts2; + newstr = xmalloc(len); + newstr[0] = '\0'; + + for (tmpstr = strtok(s1, ","); + tmpstr; + tmpstr = strtok(NULL, ",")) { + /* copy option to temp buffer */ + strncpy(oneopt, tmpstr, 80); + oneopt[79] = '\0'; + /* if option has a value such as rsize=1024, chop the value part */ + if ((eq = strchr(oneopt, '='))) + eq[1] = '\0'; + /* find reverse option of oneopt */ + revoneopt = reverse_option(oneopt); + /* if option orits reverse exist in opts2, ignore it */ + if (hasmntopt(&mnt2, oneopt) || hasmntopt(&mnt2, revoneopt)) + continue; + /* add option to returned string */ + if (newstr && newstr[0]) { + strcat(newstr, ","); + strcat(newstr, tmpstr); + } else { + strcpy(newstr, tmpstr); + } + } + + /* finally, append opts2 itself */ + if (newstr && newstr[0]) { + strcat(newstr, ","); + strcat(newstr, opts2); + } else { + strcpy(newstr, opts2); + } + + XFREE(s1); + return newstr; +} + + +am_ops * +ops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map) +{ + am_ops **vp; + am_ops *rop = 0; + + /* + * First crack the global opts and the local opts + */ + if (!eval_fs_opts(fo, key, g_key, path, keym, map)) { + rop = &amfs_error_ops; + } else if (fo->opt_type == 0) { + plog(XLOG_USER, "No fs type specified (key = \"%s\", map = \"%s\")", keym, map); + rop = &amfs_error_ops; + } else { + /* + * Next find the correct filesystem type + */ + for (vp = vops; (rop = *vp); vp++) + if (STREQ(rop->fs_type, fo->opt_type)) + break; + if (!rop) { + plog(XLOG_USER, "fs type \"%s\" not recognized", fo->opt_type); + rop = &amfs_error_ops; + } + } + + /* + * Make sure we have a default mount option. + * Otherwise skip past any leading '-'. + */ + if (fo->opt_opts == 0) + fo->opt_opts = strdup("rw,defaults"); + else if (*fo->opt_opts == '-') { + /* + * We cannot simply do fo->opt_opts++ here since the opts + * module will try to free the pointer fo->opt_opts later. + * So just reallocate the thing -- stolcke 11/11/94 + */ + char *old = fo->opt_opts; + fo->opt_opts = strdup(old + 1); + XFREE(old); + } + + /* + * If addopts option was used, then append it to the + * current options. + */ + if (fo->opt_addopts) { + char *mergedstr; + mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts); + plog(XLOG_USER, "merge opts \"%s\" add \"%s\" => \"%s\"", + fo->opt_opts, fo->opt_addopts, mergedstr); + XFREE(fo->opt_opts); + fo->opt_opts = mergedstr; + } + + /* + * Check the filesystem is happy + */ + if (fo->fs_mtab) + XFREE(fo->fs_mtab); + + if ((fo->fs_mtab = (*rop->fs_match) (fo))) + return rop; + + /* + * Return error file system + */ + fo->fs_mtab = (*amfs_error_ops.fs_match) (fo); + return &amfs_error_ops; +} diff --git a/contrib/amd/amd/amd.8 b/contrib/amd/amd/amd.8 new file mode 100644 index 0000000..a738809 --- /dev/null +++ b/contrib/amd/amd/amd.8 @@ -0,0 +1,352 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1989 Jan-Simon Pendry +.\" Copyright (c) 1989 Imperial College of Science, Technology & Medicine +.\" Copyright (c) 1989 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jan-Simon Pendry at Imperial College, London. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" %W% (Berkeley) %G% +.\" +.\" $Id: amd.8,v 5.2.2.1 1992/02/09 15:11:11 jsp beta $ +.\" +.TH AMD 8 "3 November 1989" +.SH NAME +amd \- automatically mount file systems +.SH SYNOPSIS +.B amd +.B \-H +.br +.B amd +[ +.BI \-F " conf_file" +] +.br +.B amd +[ +.B \-nprvHS +] [ +.BI \-a " mount_point" +] [ +.BI \-c " duration" +] [ +.BI \-d " domain" +] [ +.BI \-k " kernel-arch" +] [ +.BI \-l " logfile" +] [ +.BI \-o " op_sys_ver" +] [ +.BI \-t " interval.interval" +] [ +.BI \-w " interval" +] [ +.BI \-x " log-option" +] [ +.BI \-y " YP-domain" +] [ +.BI \-C " cluster-name" +] [ +.BI \-D " option" +] [ +.BI \-F " conf_file" +] [ +.BI \-O " op_sys_name" +] [ +.BI \-T " tag" +] +[ +.I directory +.I mapname +.RI [ " \-map-options " ] +] .\|.\|. +.SH DESCRIPTION +.B Amd +is a daemon that automatically mounts filesystems +whenever a file or directory +within that filesystem is accessed. +Filesystems are automatically unmounted when they +appear to have become quiescent. +.LP +.B Amd +operates by attaching itself as an +.SM NFS +server to each of the specified +.IB directories . +Lookups within the specified directories +are handled by +.BR amd , +which uses the map defined by +.I mapname +to determine how to resolve the lookup. +Generally, this will be a host name, some filesystem information +and some mount options for the given filesystem. +.LP +In the first form depicted above, +.B amd +will print a short help string. In the second form, if no options are +specified, or the +.B -F +is used, +.B amd +will read configuration parameters from the file +.I conf_file +which defaults to +.BR /etc/amd.conf . +The last form is described below. +.SH OPTIONS + +.\"*******************************************************" + +.TP +.BI \-a " temporary-directory" +Specify an alternative location for the real mount points. +The default is +.BR /a . + +.TP +.BI \-c " duration" +Specify a +.IR duration , +in seconds, that a looked up name remains +cached when not in use. The default is 5 minutes. + +.TP +.BI \-d " domain" +Specify the local domain name. If this option is not +given the domain name is determined from the hostname. + +.TP +.BI \-k " kernel-arch" +Specifies the kernel architecture. This is used solely +to set the ${karch} selector. + +.TP +.BI \-l " logfile" +Specify a logfile in which to record mount and unmount events. +If +.I logfile +is the string +.B syslog +then the log messages will be sent to the system log daemon by +.IR syslog (3). +The default syslog facility used is LOG_DAEMON. If you +wish to change it, append its name to the log file name, delimited by a +single colon. For example, if +.I logfile +is the string +.B syslog:local7 +then +.B Amd +will log messages via +.IR syslog (3) +using the LOG_LOCAL7 facility (if it exists on the system). + +.TP +.B \-n +Normalize hostnames. +The name refereed to by ${rhost} is normalized relative to the +host database before being used. The effect is to translate +aliases into ``official'' names. + +.TP +.BI \-o " op_sys_ver" +Override the compiled-in version number of the operating system. Useful +when the built in version is not desired for backward compatibility reasons. +For example, if the build in version is ``2.5.1'', you can override it to +``5.5.1'', and use older maps that were written with the latter in mind. + +.TP +.B \-p +Print PID. +Outputs the process-id of +.B amd +to standard output where it can be saved into a file. + +.TP +.B \-r +Restart existing mounts. +.B Amd +will scan the mount file table to determine which filesystems +are currently mounted. Whenever one of these would have +been auto-mounted, +.B amd +.I inherits +it. + +.TP +.BI \-t " interval.interval" +Specify the +.IR interval , +in tenths of a second, between NFS/RPC/UDP retries. +The default is 0.8 seconds. +The second values alters the restransmit counter. +Useful defaults are supplied if either or both +values are missing. + +.TP +.B \-v +Version. Displays version and configuration information on standard error. + +.TP +.BI \-w " interval" +Specify an +.IR interval , +in seconds, between attempts to dismount +filesystems that have exceeded their cached times. +The default is 2 minutes. + +.TP +.BI \-x " options" +Specify run-time logging options. The options are a comma separated +list chosen from: fatal, error, user, warn, info, map, stats, all. + +.TP +.BI \-y " domain" +Specify an alternative NIS domain from which to fetch the NIS maps. +The default is the system domain name. This option is ignored if NIS +support is not available. + +.TP +.BI \-C " cluster-name" +Specify an alternative HP-UX cluster name to use. + +.TP +.BI \-D " option" +Select from a variety of debug options. Prefixing an +option with the strings +.B no +reverses the effect of that option. Options are cumulative. +The most useful option is +.BR all . +Since +.I \-D +is only used for debugging other options are not documented here: +the current supported set of options is listed by the \-v option +and a fuller description is available in the program source. + +.TP +.BI \-F " conf_file" +Specify an amd configuration file to use. See +.BR amd.conf (5) +for description of this file's format. This configuration file is used to +specify any options in lieu of typing many of them on the command line. The +.I amd.conf +file includes directives for every command line option amd has, and many +more that are only available via the configuration file facility. The +configuration file specified by this option is processed after all other +options had been processed, regardless of the actual location of this option +on the command line. + +.TP +.B \-H +Print help and usage string. + +.TP +.BI \-O " op_sys_name" +Override the compiled-in name of the operating system. Useful when the +built in name is not desired for backward compatibility reasons. For +example, if the build in name is ``sunos5'', you can override it to +``sos5'', and use older maps which were written with the latter in mind. + +.TP +.B \-S +Do not lock the running executable pages of amd into memory. To improve +amd's performance, systems that support the +.BR plock (3) +call, could lock the amd process into memory. This way there is less chance +the operating system will schedule, page out, and swap the amd process as +needed. This tends improves amd's performance, at the cost of reserving the +memory used by the amd process (making it unavailable for other processes). +If this behavior is not desired, use the +.B \-S +option. + +.TP +.BI \-T " tag" +Specify a tag to use with +.BR amd.conf (5). +All map entries tagged with +.I tag +will be processed. Map entries that are not tagged are always processed. +Map entries that are tagged with a tag other than +.I tag +will not be processed. + +.SH FILES +.PD 0 +.TP 5 +.B /a +directory under which filesystems are dynamically mounted +.TP 5 +.B /etc/amd.conf +default configuration file +.PD +.SH CAVEATS +Some care may be required when creating a mount map. +.LP +Symbolic links on an NFS filesystem can be incredibly inefficient. +In most implementations of NFS, their interpolations are not cached +by the kernel and each time a symlink is encountered during a +.I lookuppn +translation it costs an RPC call to the NFS server. +It would appear that a large improvement in real-time +performance could be gained by adding a cache somewhere. +Replacing symlinks with a suitable incarnation of the auto-mounter +results in a large real-time speedup, but also causes a large +number of process context switches. +.LP +A weird imagination is most useful to gain full advantage of all +the features. +.SH "SEE ALSO" +.BR amd.conf (5), +.BR amq (8), +.BR domainname (1), +.BR hostname (1), +.BR automount (8), +.BR mount (8), +.BR umount (8), +.BR mtab (5), +.BR syslog (3). +.LP +.I "Amd \- The 4.4 BSD Automounter" +.SH AUTHORS +Jan-Simon Pendry , Department of Computing, Imperial College, London, UK. +.P +Erez Zadok , Department of Computer Science, Columbia +University, New York, USA. +.P +Other authors and contributors to am-utils are listed in the +.B AUTHORS +file distributed with am-utils. diff --git a/contrib/amd/amd/amd.c b/contrib/amd/amd/amd.c new file mode 100644 index 0000000..7ef2ce7 --- /dev/null +++ b/contrib/amd/amd/amd.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amd.c,v 5.2.2.1 1992/02/09 15:08:15 jsp beta $ + * + */ + +/* + * Automounter + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +struct amu_global_options gopt; /* where global options are stored */ + +char pid_fsname[16 + MAXHOSTNAMELEN]; /* "kiska.southseas.nz:(pid%d)" */ +char *progname; /* "amd" */ +char *hostdomain = "unknown.domain"; +char hostname[MAXHOSTNAMELEN] = "localhost"; /* Hostname */ +char hostd[2 * MAXHOSTNAMELEN]; /* Host+domain */ +char *endian = ARCH_ENDIAN; /* Big or Little endian */ +char *cpu = HOST_CPU; /* CPU type */ +char *PrimNetName; /* name of primary network */ +char *PrimNetNum; /* number of primary network */ + +int foreground = 1; /* This is the top-level server */ +int immediate_abort; /* Should close-down unmounts be retried */ +int orig_umask; +int select_intr_valid; + +jmp_buf select_intr; +pid_t mypid; /* Current process id */ +serv_state amd_state; +struct amd_stats amd_stats; /* Server statistics */ +struct in_addr myipaddr; /* (An) IP address of this host */ +time_t do_mapc_reload = 0; /* mapc_reload() call required? */ + +#ifdef HAVE_SIGACTION +sigset_t masked_sigs; +#endif /* HAVE_SIGACTION */ + + +/* + * Signal handler: + * SIGINT - tells amd to do a full shutdown, including unmounting all + * filesystem. + * SIGTERM - tells amd to shutdown now. Just unmounts the automount nodes. + */ +static RETSIGTYPE +sigterm(int sig) +{ +#ifdef REINSTALL_SIGNAL_HANDLER + signal(sig, sigterm); +#endif /* REINSTALL_SIGNAL_HANDLER */ + + switch (sig) { + case SIGINT: + immediate_abort = 15; + break; + + case SIGTERM: + immediate_abort = -1; + /* fall through... */ + + default: + plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig); + break; + } + if (select_intr_valid) + longjmp(select_intr, sig); +} + + +/* + * Hook for cache reload. + * When a SIGHUP arrives it schedules a call to mapc_reload + */ +static RETSIGTYPE +sighup(int sig) +{ +#ifdef REINSTALL_SIGNAL_HANDLER + signal(sig, sighup); +#endif /* REINSTALL_SIGNAL_HANDLER */ + +#ifdef DEBUG + if (sig != SIGHUP) + dlog("spurious call to sighup"); +#endif /* DEBUG */ + /* + * Force a reload by zero'ing the timer + */ + if (amd_state == Run) + do_mapc_reload = 0; +} + + +static RETSIGTYPE +parent_exit(int sig) +{ + exit(0); +} + + +static int +daemon_mode(void) +{ + int bgpid; + +#ifdef HAVE_SIGACTION + struct sigaction sa, osa; + + sa.sa_handler = parent_exit; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGQUIT); + sigaction(SIGQUIT, &sa, &osa); +#else /* not HAVE_SIGACTION */ + signal(SIGQUIT, parent_exit); +#endif /* not HAVE_SIGACTION */ + + bgpid = background(); + + if (bgpid != 0) { + /* + * Now wait for the automount points to + * complete. + */ + for (;;) + pause(); + /* should never reache here */ + } +#ifdef HAVE_SIGACTION + sigaction(SIGQUIT, &osa, NULL); +#else /* not HAVE_SIGACTION */ + signal(SIGQUIT, SIG_DFL); +#endif /* not HAVE_SIGACTION */ + + /* + * Record our pid to make it easier to kill the correct amd. + */ + if (gopt.flags & CFM_PRINT_PID) { + if (STREQ(gopt.pid_file, "/dev/stdout")) { + printf("%ld\n", (long) mypid); + fflush(stdout); + /* do not fclose stdout */ + } else { + FILE *f; + mode_t prev_umask = umask(0022); /* set secure temporary umask */ + + f = fopen(gopt.pid_file, "w"); + if (f) { + fprintf(f, "%ld\n", (long) mypid); + (void) fclose(f); + } else { + fprintf(stderr, "cannot open %s (errno=%d)\n", gopt.pid_file, errno); + } + umask(prev_umask); /* restore umask */ + } + } + + /* + * Pretend we are in the foreground again + */ + foreground = 1; + + /* + * Dissociate from the controlling terminal + */ + amu_release_controlling_tty(); + + return getppid(); +} + + +/* + * Initialize global options structure. + */ +static void +init_global_options(void) +{ +#if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) + static struct utsname un; +#endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */ + + memset(&gopt, 0, sizeof(struct amu_global_options)); + + /* name of current architecture */ + gopt.arch = HOST_ARCH; + + /* automounter temp dir */ + gopt.auto_dir = "/a"; + + /* cluster name */ + gopt.cluster = NULL; + + /* + * kernel architecture: this you must get from uname() if possible. + */ +#if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) + if (uname(&un) >= 0) + gopt.karch = un.machine; + else +#endif /* defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME) */ + gopt.karch = HOST_ARCH; + + /* amd log file */ + gopt.logfile = NULL; + + /* operating system name */ + gopt.op_sys = HOST_OS_NAME; + + /* OS version */ + gopt.op_sys_ver = HOST_OS_VERSION; + + /* pid file */ + gopt.pid_file = "/dev/stdout"; + + /* local domain */ + gopt.sub_domain = NULL; + + /* NFS retransmit counter */ + gopt.amfs_auto_retrans = -1; + + /* NFS retry interval */ + gopt.amfs_auto_timeo = -1; + + /* cache duration */ + gopt.am_timeo = AM_TTL; + + /* dismount interval */ + gopt.am_timeo_w = AM_TTL_W; + + /* + * various CFM_* flags. + * by default, only the "plock" option is on (if available). + */ + gopt.flags = CFM_PROCESS_LOCK; + +#ifdef HAVE_MAP_HESIOD + /* Hesiod rhs zone */ + gopt.hesiod_base = "automount"; +#endif /* HAVE_MAP_HESIOD */ + +#ifdef HAVE_MAP_LDAP + /* LDAP base */ + gopt.ldap_base = NULL; + + /* LDAP host ports */ + gopt.ldap_hostports = NULL; + + /* LDAP cache */ + gopt.ldap_cache_seconds = 0; + gopt.ldap_cache_maxmem = 131072; +#endif /* HAVE_MAP_LDAP */ + +#ifdef HAVE_MAP_NIS + /* YP domain name */ + gopt.nis_domain = NULL; +#endif /* HAVE_MAP_NIS */ +} + + +int +main(int argc, char *argv[]) +{ + char *domdot, *verstr; + int ppid = 0; + int error; +#ifdef HAVE_SIGACTION + struct sigaction sa; +#endif /* HAVE_SIGACTION */ + + /* + * Make sure some built-in assumptions are true before we start + */ + assert(sizeof(nfscookie) >= sizeof(u_int)); + assert(sizeof(int) >= 4); + + /* + * Set processing status. + */ + amd_state = Start; + + /* + * Determine program name + */ + if (argv[0]) { + progname = strrchr(argv[0], '/'); + if (progname && progname[1]) + progname++; + else + progname = argv[0]; + } + if (!progname) + progname = "amd"; + + /* + * Initialise process id. This is kept + * cached since it is used for generating + * and using file handles. + */ + mypid = getpid(); + + /* + * Get local machine name + */ + if (gethostname(hostname, sizeof(hostname)) < 0) { + plog(XLOG_FATAL, "gethostname: %m"); + going_down(1); + } + + /* + * Check it makes sense + */ + if (!*hostname) { + plog(XLOG_FATAL, "host name is not set"); + going_down(1); + } + + /* + * Initialize global options structure. + */ + init_global_options(); + + /* + * Partially initialise hostd[]. This + * is completed in get_args(). + */ + if ((domdot = strchr(hostname, '.'))) { + /* + * Hostname already contains domainname. + * Split out hostname and domainname + * components + */ + *domdot++ = '\0'; + hostdomain = domdot; + } + strcpy(hostd, hostname); + + /* + * Trap interrupts for shutdowns. + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = sigterm; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGINT); + sigaddset(&(sa.sa_mask), SIGTERM); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); +#else /* not HAVE_SIGACTION */ + (void) signal(SIGINT, sigterm); +#endif /* not HAVE_SIGACTION */ + + /* + * Trap Terminate so that we can shutdown gracefully (some chance) + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = sigterm; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGTERM); + sigaction(SIGTERM, &sa, NULL); +#else /* not HAVE_SIGACTION */ + (void) signal(SIGTERM, sigterm); +#endif /* not HAVE_SIGACTION */ + + /* + * Hangups tell us to reload the cache + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = sighup; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGHUP); + sigaction(SIGHUP, &sa, NULL); +#else /* not HAVE_SIGACTION */ + (void) signal(SIGHUP, sighup); +#endif /* not HAVE_SIGACTION */ + + /* + * Trap Death-of-a-child. These allow us to + * pick up the exit status of backgrounded mounts. + * See "sched.c". + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = sigchld; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGCHLD); + sigaction(SIGCHLD, &sa, NULL); + + /* + * construct global "masked_sigs" used in nfs_start.c + */ + sigemptyset(&masked_sigs); + sigaddset(&masked_sigs, SIGHUP); + sigaddset(&masked_sigs, SIGCHLD); + sigaddset(&masked_sigs, SIGTERM); + sigaddset(&masked_sigs, SIGINT); +#else /* not HAVE_SIGACTION */ + (void) signal(SIGCHLD, sigchld); +#endif /* not HAVE_SIGACTION */ + + /* + * Fix-up any umask problems. Most systems default + * to 002 which is not too convenient for our purposes + */ + orig_umask = umask(0); + + /* + * Figure out primary network name + */ + getwire(&PrimNetName, &PrimNetNum); + + /* + * Determine command-line arguments + */ + get_args(argc, argv); + + /* + * Log version information. + */ + verstr = strtok(get_version_string(), "\n"); + plog(XLOG_INFO, "AM-UTILS VERSION INFORMATION:"); + while (verstr) { + plog(XLOG_INFO, verstr); + verstr = strtok(NULL, "\n"); + } + + /* + * Get our own IP address so that we + * can mount the automounter. + */ + amu_get_myaddress(&myipaddr); + plog(XLOG_INFO, "My ip addr is 0x%x", htonl(myipaddr.s_addr)); + + /* avoid hanging on other NFS servers if started elsewhere */ + if (chdir("/") < 0) + plog(XLOG_INFO, "cannot chdir to /: %m"); + + /* + * Now check we are root. + */ + if (geteuid() != 0) { + plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %d)", geteuid()); + going_down(1); + } + + /* + * Lock process text and data segment in memory. + */ +#ifdef HAVE_PLOCK + if (gopt.flags & CFM_PROCESS_LOCK) { + if (plock(PROCLOCK) != 0) { + plog(XLOG_WARNING, "Couldn't lock process text and data segment in memory: %m"); + } else { + plog(XLOG_INFO, "Locked process text and data segment in memory"); + } + } +#endif /* HAVE_PLOCK */ + +#ifdef HAVE_MAP_NIS + /* + * If the domain was specified then bind it here + * to circumvent any default bindings that may + * be done in the C library. + */ + if (gopt.nis_domain && yp_bind(gopt.nis_domain)) { + plog(XLOG_FATAL, "Can't bind to NIS domain \"%s\"", gopt.nis_domain); + going_down(1); + } +#endif /* HAVE_MAP_NIS */ + +#ifdef DEBUG + amuDebug(D_DAEMON) +#endif /* DEBUG */ + ppid = daemon_mode(); + + sprintf(pid_fsname, "%s:(pid%ld)", hostname, (long) mypid); + + do_mapc_reload = clocktime() + ONE_HOUR; + + /* + * Register automounter with system. + */ + error = mount_automounter(ppid); + if (error && ppid) + kill(SIGALRM, ppid); + going_down(error); + + abort(); + return 1; /* should never get here */ +} diff --git a/contrib/amd/amd/amd.h b/contrib/amd/amd/amd.h new file mode 100644 index 0000000..610dfe2 --- /dev/null +++ b/contrib/amd/amd/amd.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amd.h,v 1.1 1996/01/13 23:23:39 ezk Exp ezk $ + * + */ + +#ifndef _AMD_H +#define _AMD_H + + +/* + * MACROS: + */ + +/* options for amd.conf */ +#define CFM_BROWSABLE_DIRS 0x0001 +#define CFM_MOUNT_TYPE_AUTOFS 0x0002 +#define CFM_ENABLE_DEFAULT_SELECTORS 0x0004 +#define CFM_NORMALIZE_HOSTNAMES 0x0008 +#define CFM_PROCESS_LOCK 0x0010 +#define CFM_PRINT_PID 0x0020 +#define CFM_RESTART_EXISTING_MOUNTS 0x0040 +#define CFM_SHOW_STATFS_ENTRIES 0x0080 +#define CFM_FULLY_QUALIFIED_HOSTS 0x0100 +#define CFM_BROWSABLE_DIRS_FULL 0x0200 /* allow '/' in readdir() */ +#define CFM_UNMOUNT_ON_EXIT 0x0400 /* when amd finishing */ + +/* some systems (SunOS 4.x) neglect to define the mount null message */ +#ifndef MOUNTPROC_NULL +# define MOUNTPROC_NULL ((u_long)(0)) +#endif /* not MOUNTPROC_NULL */ + +/* Hash table size */ +#define NKVHASH (1 << 2) /* Power of two */ + +/* interval between forced retries of a mount */ +#define RETRY_INTERVAL 2 + +#define ereturn(x) { *error_return = x; return 0; } + + +/* + * TYPEDEFS: + */ + +typedef struct cf_map cf_map_t; +typedef struct kv kv; +/* + * Cache map operations + */ +typedef void add_fn(mnt_map *, char *, char *); +typedef int init_fn(mnt_map *, char *, time_t *); +typedef int mtime_fn(mnt_map *, char *, time_t *); +typedef int isup_fn(mnt_map *, char *); +typedef int reload_fn(mnt_map *, char *, add_fn *); +typedef int search_fn(mnt_map *, char *, char *, char **, time_t *); + + + +/* + * STRUCTURES: + */ + +/* global amd options that are manipulated by conf.c */ +struct amu_global_options { + char *arch; /* name of current architecture */ + char *auto_dir; /* automounter temp dir */ + char *cluster; /* cluster name */ + char *karch; /* kernel architecture */ + char *logfile; /* amd log file */ + char *op_sys; /* operating system name */ + char *op_sys_ver; /* OS version */ + char *pid_file; /* PID file */ + char *sub_domain; /* local domain */ + char *map_options; /* global map options */ + char *map_type; /* global map type */ + char *search_path; /* search path for maps */ + char *mount_type; /* mount type for map */ + u_int flags; /* various CFM_* flags */ + int amfs_auto_retrans; /* NFS retransmit counter */ + int amfs_auto_timeo; /* NFS retry interval */ + int am_timeo; /* cache duration */ + int am_timeo_w; /* dismount interval */ + int portmap_program; /* amd RPC program number */ +#ifdef HAVE_MAP_HESIOD + char *hesiod_base; /* Hesiod rhs */ +#endif /* HAVE_MAP_HESIOD */ +#ifdef HAVE_MAP_LDAP + char *ldap_base; /* LDAP base */ + char *ldap_hostports; /* LDAP host ports */ + long ldap_cache_seconds; /* LDAP internal cache - keep seconds */ + long ldap_cache_maxmem; /* LDAP internal cache - max memory (bytes) */ +#endif /* HAVE_MAP_LDAP */ +#ifdef HAVE_MAP_NIS + char *nis_domain; /* YP domain name */ +#endif /* HAVE_MAP_NIS */ +}; + +/* if you add anything here, update conf.c:reset_cf_map() */ +struct cf_map { + char *cfm_dir; /* /home, /u, /src */ + char *cfm_name; /* amd.home, /etc/amd.home ... */ + char *cfm_type; /* file, hesiod, ndbm, nis ... */ + char *cfm_opts; /* -cache:=all, etc. */ + char *cfm_search_path; /* /etc/local:/etc/amdmaps:/misc/yp */ + char *cfm_tag; /* optional map tag for amd -T */ + u_int cfm_flags; /* browsable_dirs? mount_type? */ +}; + +/* + * Key-value pair + */ +struct kv { + kv *next; + char *key; +#ifdef HAVE_REGEXEC + regex_t re; /* store the regexp from regcomp() */ +#endif /* HAVE_REGEXEC */ + char *val; +}; + +struct mnt_map { + qelem hdr; + int refc; /* Reference count */ + short flags; /* Allocation flags */ + short alloc; /* Allocation mode */ + time_t modify; /* Modify time of map */ + char *map_name; /* Name of this map */ + char *wildcard; /* Wildcard value */ + reload_fn *reload; /* Function to be used for reloads */ + isup_fn *isup; /* Is service up or not? (1=up, 0=down) */ + search_fn *search; /* Function to be used for searching */ + mtime_fn *mtime; /* Modify time function */ + kv *kvhash[NKVHASH]; /* Cached data */ + /* options available via amd conf file */ + char *cf_map_type; /* file, hesiod, ndbm, nis, etc. */ + char *cf_search_path; /* /etc/local:/etc/amdmaps:/misc/yp */ + void *map_data; /* Map data black box */ +}; + +/* + * Mounting a file system may take a significant period of time. The + * problem is that if this is done in the main process thread then + * the entire automounter could be blocked, possibly hanging lots of + * processes on the system. Instead we use a continuation scheme to + * allow mounts to be attempted in a sub-process. When the sub-process + * exits we pick up the exit status (by convention a UN*X error number) + * and continue in a notifier. The notifier gets handed a data structure + * and can then determine whether the mount was successful or not. If + * not, it updates the data structure and tries again until there are no + * more ways to try the mount, or some other permanent error occurs. + * In the mean time no RPC reply is sent, even after the mount is succesful. + * We rely on the RPC retry mechanism to resend the lookup request which + * can then be handled. + */ +struct continuation { + char **ivec; /* Current mount info */ + am_node *mp; /* Node we are trying to mount */ + char *key; /* Map key */ + char *info; /* Info string */ + char **xivec; /* Saved strsplit vector */ + char *auto_opts; /* Automount options */ + am_opts fs_opts; /* Filesystem options */ + char *def_opts; /* Default automount options */ + int retry; /* Try again? */ + int tried; /* Have we tried any yet? */ + time_t start; /* Time we started this mount */ + int callout; /* Callout identifier */ +}; + + +/* + * EXTERNALS: + */ + +/* Amq server global functions */ +extern amq_mount_info_list *amqproc_getmntfs_1_svc(voidp argp, struct svc_req *rqstp); +extern amq_mount_stats *amqproc_stats_1_svc(voidp argp, struct svc_req *rqstp); +extern amq_mount_tree_list *amqproc_export_1_svc(voidp argp, struct svc_req *rqstp); +extern amq_mount_tree_p *amqproc_mnttree_1_svc(voidp argp, struct svc_req *rqstp); +extern amq_string *amqproc_getvers_1_svc(voidp argp, struct svc_req *rqstp); +extern int *amqproc_getpid_1_svc(voidp argp, struct svc_req *rqstp); +extern int *amqproc_mount_1_svc(voidp argp, struct svc_req *rqstp); +extern int *amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp); +extern voidp amqproc_null_1_svc(voidp argp, struct svc_req *rqstp); +extern voidp amqproc_umnt_1_svc(voidp argp, struct svc_req *rqstp); + +/* other external definitions */ +extern am_nfs_fh *root_fh(char *dir); +extern am_node * autofs_lookuppn(am_node *mp, char *fname, int *error_return, int op); +extern am_node *find_ap(char *); +extern am_node *find_ap2(char *, am_node *); +extern bool_t xdr_amq_mount_info_qelem(XDR *xdrs, qelem *qhead); +extern fserver *find_nfs_srvr(mntfs *mf); +extern int auto_fmount(am_node *mp); +extern int auto_fumount(am_node *mp); +extern int mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf); +extern int process_last_regular_map(void); +extern int set_conf_kv(const char *section, const char *k, const char *v); +extern int try_mount(voidp mvp); +extern int yyparse (void); +extern nfsentry *make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable); +extern void amfs_auto_cont(int rc, int term, voidp closure); +extern void amfs_auto_mkcacheref(mntfs *mf); +extern void amfs_auto_retry(int rc, int term, voidp closure); +extern void assign_error_mntfs(am_node *mp); +extern void flush_srvr_nfs_cache(void); +extern void free_continuation(struct continuation *cp); +extern void mf_mounted(mntfs *mf); +extern void quick_reply(am_node *mp, int error); +extern void root_newmap(const char *, const char *, const char *, const cf_map_t *); + +/* amd global variables */ +extern FILE *yyin; +extern SVCXPRT *nfs_program_2_transp; /* For quick_reply() */ +extern char *conf_tag; +extern int NumChild; +extern int fwd_sock; +extern int select_intr_valid; +extern int usage; +extern int use_conf_file; /* use amd configuration file */ +extern jmp_buf select_intr; +extern qelem mfhead; +extern struct amu_global_options gopt; /* where global options are stored */ + +#ifdef HAVE_SIGACTION +extern sigset_t masked_sigs; +#endif /* HAVE_SIGACTION */ + +#if defined(HAVE_AM_FS_LINK) || defined(HAVE_AM_FS_LINKX) +extern char *amfs_link_match(am_opts *fo); +extern int amfs_link_fumount(mntfs *mf); +#endif /* defined(HAVE_AM_FS_LINK) || defined(HAVE_AM_FS_LINKX) */ + +#ifdef HAVE_AM_FS_NFSL +extern char *nfs_match(am_opts *fo); +#endif /* HAVE_AM_FS_NFSL */ + +#if defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3) +extern bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp); +#endif /* defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3) */ + +#ifdef HAVE_FS_AUTOFS +extern SVCXPRT *autofsxprt; +extern u_short autofs_port; + +extern int autofs_mount(am_node *mp); +extern int autofs_umount(am_node *mp); +extern int create_autofs_service(int *soAUTOFSp, u_short *autofs_portp, SVCXPRT **autofs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp)); +extern int svc_create_local_service(void (*dispatch) (), u_long prognum, u_long versnum, char *nettype, char *servname); +extern void autofs_mounted(mntfs *mf); +extern void autofs_program_1(struct svc_req *rqstp, SVCXPRT *transp); +#endif /* HAVE_FS_AUTOFS */ + +/* Unix file system (irix) */ +#ifdef HAVE_FS_XFS +extern am_ops xfs_ops; /* Un*x file system */ +#endif /* HAVE_FS_XFS */ + +/* Unix file system (irix) */ +#ifdef HAVE_FS_EFS +extern am_ops efs_ops; /* Un*x file system */ +#endif /* HAVE_FS_EFS */ + +#endif /* not _AMD_H */ diff --git a/contrib/amd/amd/amfs_auto.c b/contrib/amd/amd/amfs_auto.c new file mode 100644 index 0000000..0530142 --- /dev/null +++ b/contrib/amd/amd/amfs_auto.c @@ -0,0 +1,1595 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_auto.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Automount file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/**************************************************************************** + *** MACROS *** + ****************************************************************************/ +#define IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING) + +/* DEVELOPERS: turn this on for special debugging of readdir code */ +#undef DEBUG_READDIR + +/**************************************************************************** + *** STRUCTURES *** + ****************************************************************************/ + + + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ +static int amfs_auto_bgmount(struct continuation * cp, int mpe); +static int amfs_auto_mount(am_node *mp); +static int amfs_auto_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count, int fully_browsable); +static void amfs_auto_umounted(am_node *mp); + + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_auto_ops = +{ + "auto", + amfs_auto_match, + 0, /* amfs_auto_init */ + amfs_auto_mount, + 0, + amfs_auto_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, + 0, /* amfs_auto_readlink */ + 0, /* amfs_auto_mounted */ + amfs_auto_umounted, + find_amfs_auto_srvr, + FS_AMQINFO | FS_DIRECTORY +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ +/* + * AMFS_AUTO needs nothing in particular. + */ +char * +amfs_auto_match(am_opts *fo) +{ + char *p = fo->opt_rfs; + + if (!fo->opt_rfs) { + plog(XLOG_USER, "auto: no mount point named (rfs:=)"); + return 0; + } + if (!fo->opt_fs) { + plog(XLOG_USER, "auto: no map named (fs:=)"); + return 0; + } + + /* + * Swap round fs:= and rfs:= options + * ... historical (jsp) + */ + fo->opt_rfs = fo->opt_fs; + fo->opt_fs = p; + + /* + * mtab entry turns out to be the name of the mount map + */ + return strdup(fo->opt_rfs ? fo->opt_rfs : "."); +} + + + + +/* + * Build a new map cache for this node, or re-use + * an existing cache for the same map. + */ +void +amfs_auto_mkcacheref(mntfs *mf) +{ + char *cache; + + if (mf->mf_fo && mf->mf_fo->opt_cache) + cache = mf->mf_fo->opt_cache; + else + cache = "none"; + mf->mf_private = (voidp) mapc_find(mf->mf_info, cache, + mf->mf_fo->opt_maptype); + mf->mf_prfree = mapc_free; +} + + +/* + * Mount a sub-mount + */ +static int +amfs_auto_mount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + /* + * Pseudo-directories are used to provide some structure + * to the automounted directories instead + * of putting them all in the top-level automount directory. + * + * Here, just increment the parent's link count. + */ + mp->am_parent->am_fattr.na_nlink++; + + /* + * Info field of . means use parent's info field. + * Historical - not documented. + */ + if (mf->mf_info[0] == '.' && mf->mf_info[1] == '\0') + mf->mf_info = strealloc(mf->mf_info, mp->am_parent->am_mnt->mf_info); + + /* + * Compute prefix: + * + * If there is an option prefix then use that else + * If the parent had a prefix then use that with name + * of this node appended else + * Use the name of this node. + * + * That means if you want no prefix you must say so + * in the map. + */ + if (mf->mf_fo->opt_pref) { + /* allow pref:=null to set a real null prefix */ + if (STREQ(mf->mf_fo->opt_pref, "null")) { + mp->am_pref = ""; + } else { + /* + * the prefix specified as an option + */ + mp->am_pref = strdup(mf->mf_fo->opt_pref); + } + } else { + /* + * else the parent's prefix + * followed by the name + * followed by / + */ + char *ppref = mp->am_parent->am_pref; + if (ppref == 0) + ppref = ""; + mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/"); + } + + /* + * Attach a map cache + */ + amfs_auto_mkcacheref(mf); + + return 0; +} + + + + +/* + * Unmount an automount sub-node + */ +int +amfs_auto_umount(am_node *mp) +{ + return 0; +} + + +/* + * Unmount an automount node + */ +static void +amfs_auto_umounted(am_node *mp) +{ + /* + * If this is a pseudo-directory then just adjust the link count + * in the parent, otherwise call the generic unmount routine + */ + if (mp->am_parent && mp->am_parent->am_parent) + --mp->am_parent->am_fattr.na_nlink; +} + + +/* + * Discard an old continuation + */ +void +free_continuation(struct continuation *cp) +{ + if (cp->callout) + untimeout(cp->callout); + XFREE(cp->key); + XFREE(cp->xivec); + XFREE(cp->info); + XFREE(cp->auto_opts); + XFREE(cp->def_opts); + free_opts(&cp->fs_opts); + XFREE(cp); +} + + +/* + * Discard the underlying mount point and replace + * with a reference to an error filesystem. + */ +void +assign_error_mntfs(am_node *mp) +{ + if (mp->am_error > 0) { + /* + * Save the old error code + */ + int error = mp->am_error; + if (error <= 0) + error = mp->am_mnt->mf_error; + /* + * Discard the old filesystem + */ + free_mntfs(mp->am_mnt); + /* + * Allocate a new error reference + */ + mp->am_mnt = new_mntfs(); + /* + * Put back the error code + */ + mp->am_mnt->mf_error = error; + mp->am_mnt->mf_flags |= MFF_ERROR; + /* + * Zero the error in the mount point + */ + mp->am_error = 0; + } +} + + +/* + * The continuation function. This is called by + * the task notifier when a background mount attempt + * completes. + */ +void +amfs_auto_cont(int rc, int term, voidp closure) +{ + struct continuation *cp = (struct continuation *) closure; + mntfs *mf = cp->mp->am_mnt; + + /* + * Definitely not trying to mount at the moment + */ + mf->mf_flags &= ~MFF_MOUNTING; + + /* + * While we are mounting - try to avoid race conditions + */ + new_ttl(cp->mp); + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) mf); + + /* + * Check for termination signal or exit status... + */ + if (rc || term) { + am_node *xmp; + + if (term) { + /* + * Not sure what to do for an error code. + */ + mf->mf_error = EIO; /* XXX ? */ + mf->mf_flags |= MFF_ERROR; + plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term); + } else { + /* + * Check for exit status... + */ + mf->mf_error = rc; + mf->mf_flags |= MFF_ERROR; + errno = rc; /* XXX */ + if (!STREQ(cp->mp->am_mnt->mf_ops->fs_type, "linkx")) + plog(XLOG_ERROR, "%s: mount (amfs_auto_cont): %m", cp->mp->am_path); + } + + /* + * If we get here then that attempt didn't work, so + * move the info vector pointer along by one and + * call the background mount routine again + */ + amd_stats.d_merr++; + cp->ivec++; + xmp = cp->mp; + (void) amfs_auto_bgmount(cp, 0); + assign_error_mntfs(xmp); + } else { + /* + * The mount worked. + */ + am_mounted(cp->mp); + free_continuation(cp); + } + + reschedule_timeout_mp(); +} + + +/* + * Retry a mount + */ +void +amfs_auto_retry(int rc, int term, voidp closure) +{ + struct continuation *cp = (struct continuation *) closure; + int error = 0; + +#ifdef DEBUG + dlog("Commencing retry for mount of %s", cp->mp->am_path); +#endif /* DEBUG */ + + new_ttl(cp->mp); + + if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) { + /* + * The entire mount has timed out. Set the error code and skip past all + * the info vectors so that amfs_auto_bgmount will not have any more + * ways to try the mount, so causing an error. + */ + plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path); + error = ETIMEDOUT; + while (*cp->ivec) + cp->ivec++; + /* explicitly forbid further retries after timeout */ + cp->retry = FALSE; + } + if (error || !IN_PROGRESS(cp)) { + (void) amfs_auto_bgmount(cp, error); + } + reschedule_timeout_mp(); +} + + +/* + * Try to mount a file system. Can be called + * directly or in a sub-process by run_task. + */ +int +try_mount(voidp mvp) +{ + int error = 0; + am_node *mp = (am_node *) mvp; + mntfs *mf = mp->am_mnt; + + /* + * If the directory is not yet made and it needs to be made, then make it! + * This may be run in a background process in which case the flag setting + * won't be noticed later - but it is set anyway just after run_task is + * called. It should probably go away totally... + */ + if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_ops->fs_flags & FS_MKMNT) { + error = mkdirs(mf->mf_mount, 0555); + if (!error) + mf->mf_flags |= MFF_MKMNT; + } + + /* + * Mount it! + */ + error = mount_node(mp); + +#ifdef DEBUG + if (error > 0) { + errno = error; + dlog("amfs_auto call to mount_node failed: %m"); + } +#endif /* DEBUG */ + + return error; +} + + +/* + * Pick a file system to try mounting and + * do that in the background if necessary + * + For each location: + if it is new -defaults then + extract and process + continue; + fi + if it is a cut then + if a location has been tried then + break; + fi + continue; + fi + parse mount location + discard previous mount location if required + find matching mounted filesystem + if not applicable then + this_error = No such file or directory + continue + fi + if the filesystem failed to be mounted then + this_error = error from filesystem + elif the filesystem is mounting or unmounting then + this_error = -1 + elif the fileserver is down then + this_error = -1 + elif the filesystem is already mounted + this_error = 0 + break + fi + if no error on this mount then + this_error = initialise mount point + fi + if no error on this mount and mount is delayed then + this_error = -1 + fi + if this_error < 0 then + retry = true + fi + if no error on this mount then + make mount point if required + fi + if no error on this mount then + if mount in background then + run mount in background + return -1 + else + this_error = mount in foreground + fi + fi + if an error occured on this mount then + update stats + save error in mount point + fi + endfor + */ +static int +amfs_auto_bgmount(struct continuation * cp, int mpe) +{ + mntfs *mf = cp->mp->am_mnt; /* Current mntfs */ + mntfs *mf_retry = 0; /* First mntfs which needed retrying */ + int this_error = -1; /* Per-mount error */ + int hard_error = -1; + int mp_error = mpe; + + /* + * Try to mount each location. + * At the end: + * hard_error == 0 indicates something was mounted. + * hard_error > 0 indicates everything failed with a hard error + * hard_error < 0 indicates nothing could be mounted now + */ + for (; this_error && *cp->ivec; cp->ivec++) { + am_ops *p; + am_node *mp = cp->mp; + char *link_dir; + int dont_retry; + + if (hard_error < 0) + hard_error = this_error; + + this_error = -1; + + if (**cp->ivec == '-') { + /* + * Pick up new defaults + */ + if (cp->auto_opts && *cp->auto_opts) + cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec + 1); + else + cp->def_opts = strealloc(cp->def_opts, *cp->ivec + 1); +#ifdef DEBUG + dlog("Setting def_opts to \"%s\"", cp->def_opts); +#endif /* DEBUG */ + continue; + } + /* + * If a mount has been attempted, and we find + * a cut then don't try any more locations. + */ + if (STREQ(*cp->ivec, "/") || STREQ(*cp->ivec, "||")) { + if (cp->tried) { +#ifdef DEBUG + dlog("Cut: not trying any more locations for %s", + mp->am_path); +#endif /* DEBUG */ + break; + } + continue; + } + + /* match the operators */ + p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info); + + /* + * Find a mounted filesystem for this node. + */ + mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, + cp->fs_opts.opt_fs, + cp->fs_opts.fs_mtab, + cp->auto_opts, + cp->fs_opts.opt_opts, + cp->fs_opts.opt_remopts); + + p = mf->mf_ops; +#ifdef DEBUG + dlog("Got a hit with %s", p->fs_type); +#endif /* DEBUG */ + + /* + * Note whether this is a real mount attempt + */ + if (p == &amfs_error_ops) { + plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path); + if (this_error <= 0) + this_error = ENOENT; + continue; + } else { + if (cp->fs_opts.fs_mtab) { + plog(XLOG_MAP, "Trying mount of %s on %s fstype %s", + cp->fs_opts.fs_mtab, mp->am_path, p->fs_type); + } + cp->tried = TRUE; + } + + this_error = 0; + dont_retry = FALSE; + + if (mp->am_link) { + XFREE(mp->am_link); + mp->am_link = 0; + } + link_dir = mf->mf_fo->opt_sublink; + + if (link_dir && *link_dir) { + if (*link_dir == '/') { + mp->am_link = strdup(link_dir); + } else { + /* + * try getting fs option from continuation, not mountpoint! + * Don't try logging the string from mf, since it may be bad! + */ + if (cp->fs_opts.opt_fs != mf->mf_fo->opt_fs) + plog(XLOG_ERROR, "use %s instead of 0x%x", + cp->fs_opts.opt_fs, mf->mf_fo->opt_fs); + + mp->am_link = str3cat((char *) 0, + cp->fs_opts.opt_fs, "/", link_dir); + + normalize_slash(mp->am_link); + } + } + + if (mf->mf_error > 0) { + this_error = mf->mf_error; + } else if (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)) { + /* + * Still mounting - retry later + */ +#ifdef DEBUG + dlog("Duplicate pending mount fstype %s", p->fs_type); +#endif /* DEBUG */ + this_error = -1; + } else if (FSRV_ISDOWN(mf->mf_server)) { + /* + * Would just mount from the same place + * as a hung mount - so give up + */ +#ifdef DEBUG + dlog("%s is already hung - giving up", mf->mf_mount); +#endif /* DEBUG */ + mp_error = EWOULDBLOCK; + dont_retry = TRUE; + this_error = -1; + } else if (mf->mf_flags & MFF_MOUNTED) { +#ifdef DEBUG + dlog("duplicate mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + + /* + * Just call mounted() + */ + am_mounted(mp); + + this_error = 0; + break; + } + + /* + * Will usually need to play around with the mount nodes + * file attribute structure. This must be done here. + * Try and get things initialised, even if the fileserver + * is not known to be up. In the common case this will + * progress things faster. + */ + if (!this_error) { + /* + * Fill in attribute fields. + */ + if (mf->mf_ops->fs_flags & FS_DIRECTORY) + mk_fattr(mp, NFDIR); + else + mk_fattr(mp, NFLNK); + + mp->am_fattr.na_fileid = mp->am_gen; + + if (p->fs_init) + this_error = (*p->fs_init) (mf); + } + + /* + * Make sure the fileserver is UP before doing any more work + */ + if (!FSRV_ISUP(mf->mf_server)) { +#ifdef DEBUG + dlog("waiting for server %s to become available", mf->mf_server->fs_host); +#endif /* DEBUG */ + this_error = -1; + } + + if (!this_error && mf->mf_fo->opt_delay) { + /* + * If there is a delay timer on the mount + * then don't try to mount if the timer + * has not expired. + */ + int i = atoi(mf->mf_fo->opt_delay); + if (i > 0 && clocktime() < (cp->start + i)) { +#ifdef DEBUG + dlog("Mount of %s delayed by %ds", mf->mf_mount, i - clocktime() + cp->start); +#endif /* DEBUG */ + this_error = -1; + } + } + + if (this_error < 0 && !dont_retry) { + if (!mf_retry) + mf_retry = dup_mntfs(mf); + cp->retry = TRUE; + } + + if (!this_error) { + if (p->fs_flags & FS_MBACKGROUND) { + mf->mf_flags |= MFF_MOUNTING; /* XXX */ +#ifdef DEBUG + dlog("backgrounding mount of \"%s\"", mf->mf_mount); +#endif /* DEBUG */ + if (cp->callout) { + untimeout(cp->callout); + cp->callout = 0; + } + run_task(try_mount, (voidp) mp, amfs_auto_cont, (voidp) cp); + mf->mf_flags |= MFF_MKMNT; /* XXX */ + if (mf_retry) + free_mntfs(mf_retry); + return -1; + } else { +#ifdef DEBUG + dlog("foreground mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + this_error = try_mount((voidp) mp); + if (this_error < 0) { + if (!mf_retry) + mf_retry = dup_mntfs(mf); + cp->retry = TRUE; + } + } + } + + if (this_error >= 0) { + if (this_error > 0) { + amd_stats.d_merr++; + if (mf != mf_retry) { + mf->mf_error = this_error; + mf->mf_flags |= MFF_ERROR; + } + } + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) mf); + } + } + + if (this_error && cp->retry) { + free_mntfs(mf); + mf = cp->mp->am_mnt = mf_retry; + /* + * Not retrying again (so far) + */ + cp->retry = FALSE; + cp->tried = FALSE; + /* + * Start at the beginning. + * Rewind the location vector and + * reset the default options. + */ + cp->ivec = cp->xivec; + cp->def_opts = strealloc(cp->def_opts, cp->auto_opts); + /* + * Arrange that amfs_auto_bgmount is called + * after anything else happens. + */ +#ifdef DEBUG + dlog("Arranging to retry mount of %s", cp->mp->am_path); +#endif /* DEBUG */ + sched_task(amfs_auto_retry, (voidp) cp, (voidp) mf); + if (cp->callout) + untimeout(cp->callout); + cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf); + + cp->mp->am_ttl = clocktime() + RETRY_INTERVAL; + + /* + * Not done yet - so don't return anything + */ + return -1; + } + + if (hard_error < 0 || this_error == 0) + hard_error = this_error; + + /* + * Discard handle on duff filesystem. + * This should never happen since it + * should be caught by the case above. + */ + if (mf_retry) { + if (hard_error) + plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount); + free_mntfs(mf_retry); + } + + /* + * If we get here, then either the mount succeeded or + * there is no more mount information available. + */ + if (hard_error < 0 && mp_error) + hard_error = cp->mp->am_error = mp_error; + if (hard_error > 0) { + /* + * Set a small(ish) timeout on an error node if + * the error was not a time out. + */ + switch (hard_error) { + case ETIMEDOUT: + case EWOULDBLOCK: + cp->mp->am_timeo = 17; + break; + default: + cp->mp->am_timeo = 5; + break; + } + new_ttl(cp->mp); + } + + /* + * Make sure that the error value in the mntfs has a + * reasonable value. + */ + if (mf->mf_error < 0) { + mf->mf_error = hard_error; + if (hard_error) + mf->mf_flags |= MFF_ERROR; + } + + /* + * In any case we don't need the continuation any more + */ + free_continuation(cp); + + return hard_error; +} + + +/* + * Automount interface to RPC lookup routine + * Find the corresponding entry and return + * the file handle for it. + */ +am_node * +amfs_auto_lookuppn(am_node *mp, char *fname, int *error_return, int op) +{ + am_node *ap, *new_mp, *ap_hung; + char *info; /* Mount info - where to get the file system */ + char **ivec, **xivec; /* Split version of info */ + char *auto_opts; /* Automount options */ + int error = 0; /* Error so far */ + char path_name[MAXPATHLEN]; /* General path name buffer */ + char *pfname; /* Path for database lookup */ + struct continuation *cp; /* Continuation structure if need to mount */ + int in_progress = 0; /* # of (un)mount in progress */ + char *dflts; + mntfs *mf; + +#ifdef DEBUG + dlog("in amfs_auto_lookuppn"); +#endif /* DEBUG */ + + /* + * If the server is shutting down + * then don't return information + * about the mount point. + */ + if (amd_state == Finishing) { +#ifdef DEBUG + if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &amfs_direct_ops) { + dlog("%s mount ignored - going down", fname); + } else { + dlog("%s/%s mount ignored - going down", mp->am_path, fname); + } +#endif /* DEBUG */ + ereturn(ENOENT); + } + + /* + * Handle special case of "." and ".." + */ + if (fname[0] == '.') { + if (fname[1] == '\0') + return mp; /* "." is the current node */ + if (fname[1] == '.' && fname[2] == '\0') { + if (mp->am_parent) { +#ifdef DEBUG + dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path); +#endif /* DEBUG */ + return mp->am_parent; /* ".." is the parent node */ + } + ereturn(ESTALE); + } + } + + /* + * Check for valid key name. + * If it is invalid then pretend it doesn't exist. + */ + if (!valid_key(fname)) { + plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname); + ereturn(ENOENT); + } + + /* + * Expand key name. + * fname is now a private copy. + */ + fname = expand_key(fname); + + for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) { + /* + * Otherwise search children of this node + */ + if (FSTREQ(ap->am_name, fname)) { + mf = ap->am_mnt; + if (ap->am_error) { + error = ap->am_error; + continue; + } + /* + * If the error code is undefined then it must be + * in progress. + */ + if (mf->mf_error < 0) + goto in_progrss; + + /* + * Check for a hung node + */ + if (FSRV_ISDOWN(mf->mf_server)) { +#ifdef DEBUG + dlog("server hung"); +#endif /* DEBUG */ + error = ap->am_error; + ap_hung = ap; + continue; + } + /* + * If there was a previous error with this node + * then return that error code. + */ + if (mf->mf_flags & MFF_ERROR) { + error = mf->mf_error; + continue; + } + if (!(mf->mf_flags & MFF_MOUNTED) || (mf->mf_flags & MFF_UNMOUNTING)) { + in_progrss: + /* + * If the fs is not mounted or it is unmounting then there + * is a background (un)mount in progress. In this case + * we just drop the RPC request (return nil) and + * wait for a retry, by which time the (un)mount may + * have completed. + */ +#ifdef DEBUG + dlog("ignoring mount of %s in %s -- flags (%x) in progress", + fname, mf->mf_mount, mf->mf_flags); +#endif /* DEBUG */ + in_progress++; + continue; + } + + /* + * Otherwise we have a hit: return the current mount point. + */ +#ifdef DEBUG + dlog("matched %s in %s", fname, ap->am_path); +#endif /* DEBUG */ + XFREE(fname); + return ap; + } + } + + if (in_progress) { +#ifdef DEBUG + dlog("Waiting while %d mount(s) in progress", in_progress); +#endif /* DEBUG */ + XFREE(fname); + ereturn(-1); + } + + /* + * If an error occured then return it. + */ + if (error) { +#ifdef DEBUG + errno = error; /* XXX */ + dlog("Returning error: %m", error); +#endif /* DEBUG */ + XFREE(fname); + ereturn(error); + } + + /* + * If doing a delete then don't create again! + */ + switch (op) { + case VLOOK_DELETE: + ereturn(ENOENT); + + case VLOOK_CREATE: + break; + + default: + plog(XLOG_FATAL, "Unknown op to amfs_auto_lookuppn: 0x%x", op); + ereturn(EINVAL); + } + + /* + * If the server is going down then just return, + * don't try to mount any more file systems + */ + if ((int) amd_state >= (int) Finishing) { +#ifdef DEBUG + dlog("not found - server going down anyway"); +#endif /* DEBUG */ + XFREE(fname); + ereturn(ENOENT); + } + + /* + * If we get there then this is a reference to an, + * as yet, unknown name so we need to search the mount + * map for it. + */ + if (mp->am_pref) { + sprintf(path_name, "%s%s", mp->am_pref, fname); + pfname = path_name; + } else { + pfname = fname; + } + + mf = mp->am_mnt; + +#ifdef DEBUG + dlog("will search map info in %s to find %s", mf->mf_info, pfname); +#endif /* DEBUG */ + /* + * Consult the oracle for some mount information. + * info is malloc'ed and belongs to this routine. + * It ends up being free'd in free_continuation(). + * + * Note that this may return -1 indicating that information + * is not yet available. + */ + error = mapc_search((mnt_map *) mf->mf_private, pfname, &info); + if (error) { + if (error > 0) + plog(XLOG_MAP, "No map entry for %s", pfname); + else + plog(XLOG_MAP, "Waiting on map entry for %s", pfname); + XFREE(fname); + ereturn(error); + } +#ifdef DEBUG + dlog("mount info is %s", info); +#endif /* DEBUG */ + + /* + * Split info into an argument vector. + * The vector is malloc'ed and belongs to + * this routine. It is free'd in free_continuation() + */ + xivec = ivec = strsplit(info, ' ', '\"'); + + /* + * Default error code... + */ + if (ap_hung) + error = EWOULDBLOCK; + else + error = ENOENT; + + /* + * Allocate a new map + */ + new_mp = exported_ap_alloc(); + if (new_mp == 0) { + XFREE(xivec); + XFREE(info); + XFREE(fname); + ereturn(ENOSPC); + } + if (mf->mf_auto) + auto_opts = mf->mf_auto; + else + auto_opts = ""; + + auto_opts = strdup(auto_opts); + +#ifdef DEBUG + dlog("searching for /defaults entry"); +#endif /* DEBUG */ + if (mapc_search((mnt_map *) mf->mf_private, "/defaults", &dflts) == 0) { + char *dfl; + char **rvec; +#ifdef DEBUG + dlog("/defaults gave %s", dflts); +#endif /* DEBUG */ + if (*dflts == '-') + dfl = dflts + 1; + else + dfl = dflts; + + /* + * Chop the defaults up + */ + rvec = strsplit(dfl, ' ', '\"'); + + if (gopt.flags & CFM_ENABLE_DEFAULT_SELECTORS) { + /* + * Pick whichever first entry matched the list of selectors. + * Strip the selectors from the string, and assign to dfl the + * rest of the string. + */ + if (rvec) { + am_opts ap; + am_ops *pt; + char **sp = rvec; + while (*sp) { /* loop until you find something, if any */ + memset((char *) &ap, 0, sizeof(am_opts)); + pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults", + mp->am_parent->am_mnt->mf_info); + if (pt == &amfs_error_ops) { + plog(XLOG_MAP, "failed to match defaults for \"%s\"", *sp); + } else { + dfl = strip_selectors(*sp, "/defaults"); + plog(XLOG_MAP, "matched default selectors \"%s\"", dfl); + break; + } + ++sp; + } + } + } else { /* not enable_default_selectors */ + /* + * Extract first value + */ + dfl = rvec[0]; + } + + /* + * If there were any values at all... + */ + if (dfl) { + /* + * Log error if there were other values + */ + if (!(gopt.flags & CFM_ENABLE_DEFAULT_SELECTORS) && rvec[1]) { +# ifdef DEBUG + dlog("/defaults chopped into %s", dfl); +# endif /* DEBUG */ + plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info); + } + + /* + * Prepend to existing defaults if they exist, + * otherwise just use these defaults. + */ + if (*auto_opts && *dfl) { + char *nopts = (char *) xmalloc(strlen(auto_opts) + strlen(dfl) + 2); + sprintf(nopts, "%s;%s", dfl, auto_opts); + XFREE(auto_opts); + auto_opts = nopts; + } else if (*dfl) { + auto_opts = strealloc(auto_opts, dfl); + } + } + XFREE(dflts); + /* + * Don't need info vector any more + */ + XFREE(rvec); + } + + /* + * Fill it in + */ + init_map(new_mp, fname); + + /* + * Put it in the table + */ + insert_am(new_mp, mp); + + /* + * Fill in some other fields, + * path and mount point. + * + * bugfix: do not prepend old am_path if direct map + * William Sebok + */ + new_mp->am_path = str3cat(new_mp->am_path, + mf->mf_ops == &amfs_direct_ops ? "" : mp->am_path, + *fname == '/' ? "" : "/", fname); + +#ifdef DEBUG + dlog("setting path to %s", new_mp->am_path); +#endif /* DEBUG */ + + /* + * Take private copy of pfname + */ + pfname = strdup(pfname); + + /* + * Construct a continuation + */ + cp = ALLOC(struct continuation); + cp->callout = 0; + cp->mp = new_mp; + cp->xivec = xivec; + cp->ivec = ivec; + cp->info = info; + cp->key = pfname; + cp->auto_opts = auto_opts; + cp->retry = FALSE; + cp->tried = FALSE; + cp->start = clocktime(); + cp->def_opts = strdup(auto_opts); + memset((voidp) &cp->fs_opts, 0, sizeof(cp->fs_opts)); + + /* + * Try and mount the file system. If this succeeds immediately (possible + * for a ufs file system) then return the attributes, otherwise just + * return an error. + */ + error = amfs_auto_bgmount(cp, error); + reschedule_timeout_mp(); + if (!error) { + XFREE(fname); + return new_mp; + } + + /* + * Code for quick reply. If nfs_program_2_transp is set, then + * its the transp that's been passed down from nfs_program_2(). + * If new_mp->am_transp is not already set, set it by copying in + * nfs_program_2_transp. Once am_transp is set, quick_reply() can + * use it to send a reply to the client that requested this mount. + */ + if (nfs_program_2_transp && !new_mp->am_transp) { + new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); + *(new_mp->am_transp) = *nfs_program_2_transp; + } + if (error && (new_mp->am_mnt->mf_ops == &amfs_error_ops)) + new_mp->am_error = error; + + assign_error_mntfs(new_mp); + + XFREE(fname); + + ereturn(error); +} + + +/* + * Locate next node in sibling list which is mounted + * and is not an error node. + */ +am_node * +next_nonerror_node(am_node *xp) +{ + mntfs *mf; + + /* + * Bug report (7/12/89) from Rein Tollevik + * Fixes a race condition when mounting direct automounts. + * Also fixes a problem when doing a readdir on a directory + * containing hung automounts. + */ + while (xp && + (!(mf = xp->am_mnt) || /* No mounted filesystem */ + mf->mf_error != 0 || /* There was a mntfs error */ + xp->am_error != 0 || /* There was a mount error */ + !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */ + (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */ + ) + xp = xp->am_osib; + + return xp; +} + + +/* + * This readdir function which call a special version of it that allows + * browsing if browsable_dirs=yes was set on the map. + */ +int +amfs_auto_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count) +{ + u_int gen = *(u_int *) cookie; + am_node *xp; + mntent_t mnt; + + dp->dl_eof = FALSE; /* assume readdir not done */ + + /* check if map is browsable */ + if (mp->am_mnt && mp->am_mnt->mf_mopts) { + mnt.mnt_opts = mp->am_mnt->mf_mopts; + if (hasmntopt(&mnt, "fullybrowsable")) + return amfs_auto_readdir_browsable(mp, cookie, dp, ep, count, TRUE); + if (hasmntopt(&mnt, "browsable")) + return amfs_auto_readdir_browsable(mp, cookie, dp, ep, count, FALSE); + } + + if (gen == 0) { + /* + * In the default instance (which is used to start a search) we return + * "." and "..". + * + * This assumes that the count is big enough to allow both "." and ".." + * to be returned in a single packet. If it isn't (which would be + * fairly unbelievable) then tough. + */ +#ifdef DEBUG + dlog("default search"); +#endif /* DEBUG */ + /* + * Check for enough room. This is extremely approximate but is more + * than enough space. Really need 2 times: + * 4byte fileid + * 4byte cookie + * 4byte name length + * 4byte name + * plus the dirlist structure */ + if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp)))) + return EINVAL; + + xp = next_nonerror_node(mp->am_child); + dp->dl_entries = ep; + + /* construct "." */ + ep[0].ne_fileid = mp->am_gen; + ep[0].ne_name = "."; + ep[0].ne_nextentry = &ep[1]; + *(u_int *) ep[0].ne_cookie = 0; + + /* construct ".." */ + if (mp->am_parent) + ep[1].ne_fileid = mp->am_parent->am_gen; + else + ep[1].ne_fileid = mp->am_gen; + ep[1].ne_name = ".."; + ep[1].ne_nextentry = 0; + *(u_int *) ep[1].ne_cookie = + xp ? xp->am_gen : ~(u_int) 0; + + if (!xp) + dp->dl_eof = TRUE; /* by default assume readdir done */ + + return 0; + } +#ifdef DEBUG + dlog("real child"); +#endif /* DEBUG */ + + if (gen == ~(u_int) 0) { +#ifdef DEBUG + dlog("End of readdir in %s", mp->am_path); +#endif /* DEBUG */ + dp->dl_eof = TRUE; + dp->dl_entries = 0; + return 0; + } + + /* non-browsable directories code */ + xp = mp->am_child; + while (xp && xp->am_gen != gen) + xp = xp->am_osib; + + if (xp) { + int nbytes = count / 2; /* conservative */ + int todo = MAX_READDIR_ENTRIES; + dp->dl_entries = ep; + do { + am_node *xp_next = next_nonerror_node(xp->am_osib); + + if (xp_next) { + *(u_int *) ep->ne_cookie = xp_next->am_gen; + } else { + *(u_int *) ep->ne_cookie = ~(u_int) 0; + dp->dl_eof = TRUE; + } + + ep->ne_fileid = xp->am_gen; + ep->ne_name = xp->am_name; + nbytes -= sizeof(*ep) + 1; + if (xp->am_name) + nbytes -= strlen(xp->am_name); + + xp = xp_next; + + if (nbytes > 0 && !dp->dl_eof && todo > 1) { + ep->ne_nextentry = ep + 1; + ep++; + --todo; + } else { + todo = 0; + } + } while (todo > 0); + + ep->ne_nextentry = 0; + + return 0; + } + return ESTALE; +} + + +/* This one is called only if map is browsable */ +static int +amfs_auto_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count, int fully_browsable) +{ + u_int gen = *(u_int *) cookie; + int chain_length, i; + static nfsentry *te, *te_next; +#ifdef DEBUG_READDIR + nfsentry *ne; + static int j; +#endif /* DEBUG_READDIR */ + + dp->dl_eof = FALSE; /* assume readdir not done */ + +#ifdef DEBUG_READDIR + plog(XLOG_INFO, "amfs_auto_readdir_browsable gen=%u, count=%d", + gen, count); +#endif /* DEBUG_READDIR */ + + if (gen == 0) { + /* + * In the default instance (which is used to start a search) we return + * "." and "..". + * + * This assumes that the count is big enough to allow both "." and ".." + * to be returned in a single packet. If it isn't (which would be + * fairly unbelievable) then tough. + */ +#ifdef DEBUG + dlog("default search"); +#endif /* DEBUG */ + /* + * Check for enough room. This is extremely approximate but is more + * than enough space. Really need 2 times: + * 4byte fileid + * 4byte cookie + * 4byte name length + * 4byte name + * plus the dirlist structure */ + if (count < (2 * (2 * (sizeof(*ep) + sizeof("..") + 4) + sizeof(*dp)))) + return EINVAL; + + /* + * compute # of entries to send in this chain. + * heuristics: 128 bytes per entry. + * This is too much probably, but it seems to work better because + * of the re-entrant nature of nfs_readdir, and esp. on systems + * like OpenBSD 2.2. + */ + chain_length = count / 128; + + /* reset static state counters */ + te = te_next = NULL; + + dp->dl_entries = ep; + + /* construct "." */ + ep[0].ne_fileid = mp->am_gen; + ep[0].ne_name = "."; + ep[0].ne_nextentry = &ep[1]; + *(u_int *) ep[0].ne_cookie = 0; + + /* construct ".." */ + if (mp->am_parent) + ep[1].ne_fileid = mp->am_parent->am_gen; + else + ep[1].ne_fileid = mp->am_gen; + ep[1].ne_name = ".."; + ep[1].ne_nextentry = 0; + *(u_int *) ep[1].ne_cookie = ~(u_int) 0; + + /* + * If map is browsable, call a function make_entry_chain() to construct + * a linked list of unmounted keys, and return it. Then link the chain + * to the regular list. Get the chain only once, but return + * chunks of it each time. + */ + te = make_entry_chain(mp, dp->dl_entries, fully_browsable); + if (!te) + return 0; +#ifdef DEBUG_READDIR + j = 0; + for (ne=te; ne; ne=ne->ne_nextentry) + plog(XLOG_INFO, "gen1 key %4d \"%s\"", j++, ne->ne_name); +#endif /* DEBUG_READDIR */ + + /* return only "chain_length" entries */ + te_next = te; + for (i=1; ine_nextentry; + if (!te_next) + break; + } + if (te_next) { + nfsentry *te_saved = te_next->ne_nextentry; + te_next->ne_nextentry = NULL; /* terminate "te" chain */ + te_next = te_saved; /* save rest of "te" for next interation */ + dp->dl_eof = FALSE; /* tell readdir there's more */ + } else { + dp->dl_eof = TRUE; /* tell readdir that's it */ + } + ep[1].ne_nextentry = te; /* append this chunk of "te" chain */ +#ifdef DEBUG_READDIR + for (ne=te; ne; ne=ne->ne_nextentry) + plog(XLOG_INFO, "gen2 key %4d \"%s\"", j++, ne->ne_name); +#endif /* DEBUG_READDIR */ + return 0; + } /* end of "if (gen == 0)" statement */ + +#ifdef DEBUG + dlog("real child"); +#endif /* DEBUG */ + + if (gen == ~(u_int) 0) { +#ifdef DEBUG + dlog("End of readdir in %s", mp->am_path); +#endif /* DEBUG */ + dp->dl_eof = TRUE; + dp->dl_entries = 0; + return 0; + } + + /* + * If browsable directories, then continue serving readdir() with another + * chunk of entries, starting from where we left off (when gen was equal + * to 0). Once again, assume last chunk served to readdir. + */ + dp->dl_eof = TRUE; + dp->dl_entries = ep; + + te = te_next; /* reset 'te' from last saved te_next */ + if (!te) { /* another indicator of end of readdir */ + dp->dl_entries = 0; + return 0; + } + /* + * compute # of entries to send in this chain. + * heuristics: 128 bytes per entry. + */ + chain_length = count / 128; + + /* return only "chain_length" entries */ + for (i=1; ine_nextentry; + if (!te_next) + break; + } + if (te_next) { + nfsentry *te_saved = te_next->ne_nextentry; + te_next->ne_nextentry = NULL; /* terminate "te" chain */ + te_next = te_saved; /* save rest of "te" for next interation */ + dp->dl_eof = FALSE; /* tell readdir there's more */ + } + ep = te; /* send next chunk of "te" chain */ + dp->dl_entries = ep; +#ifdef DEBUG_READDIR + plog(XLOG_INFO, "dl_entries=0x%x, te_next=0x%x, dl_eof=%d", + dp->dl_entries, te_next, dp->dl_eof); + for (ne=te; ne; ne=ne->ne_nextentry) + plog(XLOG_INFO, "gen3 key %4d \"%s\"", j++, ne->ne_name); +#endif /* DEBUG_READDIR */ + return 0; +} + + +int +amfs_auto_fmount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + return (*mf->mf_ops->fmount_fs) (mf); +} + + +int +amfs_auto_fumount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + return (*mf->mf_ops->fumount_fs) (mf); +} diff --git a/contrib/amd/amd/amfs_direct.c b/contrib/amd/amd/amfs_direct.c new file mode 100644 index 0000000..1558ae0 --- /dev/null +++ b/contrib/amd/amd/amfs_direct.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_direct.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Direct file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ +static am_node *amfs_direct_readlink(am_node *mp, int *error_return); + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_direct_ops = +{ + "direct", + amfs_auto_match, + 0, /* amfs_direct_init */ + amfs_toplvl_mount, + 0, + amfs_toplvl_umount, + 0, + amfs_error_lookuppn, + amfs_error_readdir, + amfs_direct_readlink, + amfs_toplvl_mounted, + 0, /* amfs_auto_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ + +static am_node * +amfs_direct_readlink(am_node *mp, int *error_return) +{ + am_node *xp; + int rc = 0; + + xp = next_nonerror_node(mp->am_child); + if (!xp) { + if (!mp->am_mnt->mf_private) + amfs_auto_mkcacheref(mp->am_mnt); /* XXX */ + xp = amfs_auto_lookuppn(mp, mp->am_path + 1, &rc, VLOOK_CREATE); + } + if (xp) { + new_ttl(xp); /* (7/12/89) from Rein Tollevik */ + return xp; + } + if (amd_state == Finishing) + rc = ENOENT; + *error_return = rc; + return 0; +} diff --git a/contrib/amd/amd/amfs_error.c b/contrib/amd/amd/amfs_error.c new file mode 100644 index 0000000..ccb037b --- /dev/null +++ b/contrib/amd/amd/amfs_error.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_error.c,v 5.2.2.1 1992/02/09 15:08:21 jsp beta $ + * + */ + +/* + * Error file system. + * This is used as a last resort catchall if + * nothing else worked. EFS just returns lots + * of error codes, except for unmount which + * always works of course. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +static char * amfs_error_match(am_opts *fo); +static int amfs_error_fmount(mntfs *mf); +static int amfs_error_fumount(mntfs *mf); +static void amfs_error_umounted(am_node *mp); + + +/* + * Ops structure + */ +am_ops amfs_error_ops = +{ + "error", + amfs_error_match, + 0, /* amfs_error_init */ + amfs_auto_fmount, + amfs_error_fmount, + amfs_auto_fumount, + amfs_error_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_error_readlink */ + 0, /* amfs_error_mounted */ + amfs_error_umounted, + find_amfs_auto_srvr, + FS_DISCARD +}; + + + +/* + * EFS file system always matches + */ +static char * +amfs_error_match(am_opts *fo) +{ + return strdup("(error-hook)"); +} + + +static int +amfs_error_fmount(mntfs *mf) +{ + return ENOENT; +} + + +static int +amfs_error_fumount(mntfs *mf) +{ + /* + * Always succeed + */ + return 0; +} + + +/* + * EFS interface to RPC lookup() routine. + * Should never get here in the automounter. + * If we do then just give an error. + */ +am_node * +amfs_error_lookuppn(am_node *mp, char *fname, int *error_return, int op) +{ + *error_return = ESTALE; + return 0; +} + + +/* + * EFS interface to RPC readdir() routine. + * Should never get here in the automounter. + * If we do then just give an error. + */ +int +amfs_error_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count) +{ + return ESTALE; +} + + +/* + * umounted() callback for EFS. + * + * This prevents core-dumps on callbacks to error file-systems from + * nfsx_fumount. + */ +static void +amfs_error_umounted(am_node *mp) +{ + /* nothing to do */ +} diff --git a/contrib/amd/amd/amfs_host.c b/contrib/amd/amd/amfs_host.c new file mode 100644 index 0000000..6be259d --- /dev/null +++ b/contrib/amd/amd/amfs_host.c @@ -0,0 +1,686 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_host.c,v 5.2.2.2 1992/05/31 16:36:08 jsp Exp $ + * + */ + +/* + * NFS host file system. + * Mounts all exported filesystems from a given host. + * This has now degenerated into a mess but will not + * be rewritten. Amd 6 will support the abstractions + * needed to make this work correctly. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +static char *amfs_host_match(am_opts *fo); +static int amfs_host_fmount(mntfs *mf); +static int amfs_host_fumount(mntfs *mf); +static int amfs_host_init(mntfs *mf); +static void amfs_host_umounted(am_node *mp); + +/* + * Ops structure + */ +am_ops amfs_host_ops = +{ + "host", + amfs_host_match, + amfs_host_init, + amfs_auto_fmount, + amfs_host_fmount, + amfs_auto_fumount, + amfs_host_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_host_readlink */ + 0, /* amfs_host_mounted */ + amfs_host_umounted, + find_nfs_srvr, + FS_MKMNT | FS_BACKGROUND | FS_AMQINFO +}; + + +/* + * Determine the mount point: + * + * The next change we put in to better handle PCs. This is a bit + * disgusting, so you'd better sit down. We change the make_mntpt function + * to look for exported file systems without a leading '/'. If they don't + * have a leading '/', we add one. If the export is 'a:' through 'z:' + * (without a leading slash), we change it to 'a%' (or b% or z%). This + * allows the entire PC disk to be mounted. + */ +static void +make_mntpt(char *mntpt, const exports ex, const mntfs *mf) +{ + if (ex->ex_dir[0] == '/') { + if (ex->ex_dir[1] == 0) + strcpy(mntpt, (mf)->mf_mount); + else + sprintf(mntpt, "%s%s", mf->mf_mount, ex->ex_dir); + } else if (ex->ex_dir[0] >= 'a' && + ex->ex_dir[0] <= 'z' && + ex->ex_dir[1] == ':' && + ex->ex_dir[2] == '/' && + ex->ex_dir[3] == 0) + sprintf(mntpt, "%s/%c%%", mf->mf_mount, ex->ex_dir[0]); + else + sprintf(mntpt, "%s/%s", mf->mf_mount, ex->ex_dir); +} + + +/* + * Execute needs the same as NFS plus a helper command + */ +static char * +amfs_host_match(am_opts *fo) +{ + extern am_ops nfs_ops; + + /* + * Make sure rfs is specified to keep nfs_match happy... + */ + if (!fo->opt_rfs) + fo->opt_rfs = "/"; + + return (*nfs_ops.fs_match) (fo); +} + + +static int +amfs_host_init(mntfs *mf) +{ + fserver *fs; + u_short port; + + if (strchr(mf->mf_info, ':') == 0) + return ENOENT; + + /* + * This is primarily to schedule a wakeup so that as soon + * as our fileserver is ready, we can continue setting up + * the host filesystem. If we don't do this, the standard + * amfs_auto code will set up a fileserver structure, but it will + * have to wait for another nfs request from the client to come + * in before finishing. Our way is faster since we don't have + * to wait for the client to resend its request (which could + * take a second or two). + */ + /* + * First, we find the fileserver for this mntfs and then call + * nfs_srvr_port with our mntfs passed as the wait channel. + * nfs_srvr_port will check some things and then schedule + * it so that when the fileserver is ready, a wakeup is done + * on this mntfs. amfs_auto_cont() is already sleeping on this mntfs + * so as soon as that wakeup happens amfs_auto_cont() is called and + * this mount is retried. + */ + if ((fs = mf->mf_server)) + /* + * We don't really care if there's an error returned. + * Since this is just to help speed things along, the + * error will get handled properly elsewhere. + */ + (void) nfs_srvr_port(fs, &port, (voidp) mf); + + return 0; +} + + +static int +do_mount(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf) +{ + struct stat stb; + +#ifdef DEBUG + dlog("amfs_host: mounting fs %s on %s\n", fs_name, dir); +#endif /* DEBUG */ + + (void) mkdirs(dir, 0555); + if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) { + plog(XLOG_ERROR, "No mount point for %s - skipping", dir); + return ENOENT; + } + + return mount_nfs_fh(fhp, dir, fs_name, opts, mf); +} + + +static int +sortfun(const voidp x, const voidp y) +{ + exports *a = (exports *) x; + exports *b = (exports *) y; + + return strcmp((*a)->ex_dir, (*b)->ex_dir); +} + + +/* + * Get filehandle + */ +static int +fetch_fhandle(CLIENT * client, char *dir, am_nfs_handle_t *fhp, u_long nfs_version) +{ + struct timeval tv; + enum clnt_stat clnt_stat; + + /* + * Pick a number, any number... + */ + tv.tv_sec = 20; + tv.tv_usec = 0; + +#ifdef DEBUG + dlog("Fetching fhandle for %s", dir); +#endif /* DEBUG */ + + /* + * Call the mount daemon on the remote host to + * get the filehandle. Use NFS version specific call. + */ + + plog(XLOG_INFO, "fetch_fhandle: NFS version %d", nfs_version); +#ifdef HAVE_FS_NFS3 + if (nfs_version == NFS_VERSION3) { + memset((char *) &fhp->v3, 0, sizeof(fhp->v3)); + clnt_stat = clnt_call(client, + MOUNTPROC_MNT, + (XDRPROC_T_TYPE) xdr_dirpath, + (SVC_IN_ARG_TYPE) &dir, + (XDRPROC_T_TYPE) xdr_mountres3, + (SVC_IN_ARG_TYPE) &fhp->v3, + tv); + if (clnt_stat != RPC_SUCCESS) { + plog(XLOG_ERROR, "mountd rpc failed: %s", clnt_sperrno(clnt_stat)); + return EIO; + } + /* Check the status of the filehandle */ + if ((errno = fhp->v3.fhs_status)) { +#ifdef DEBUG + dlog("fhandle fetch for mount version 3 failed: %m"); +#endif /* DEBUG */ + return errno; + } + } else { /* not NFS_VERSION3 mount */ +#endif /* HAVE_FS_NFS3 */ + clnt_stat = clnt_call(client, + MOUNTPROC_MNT, + (XDRPROC_T_TYPE) xdr_dirpath, + (SVC_IN_ARG_TYPE) &dir, + (XDRPROC_T_TYPE) xdr_fhstatus, + (SVC_IN_ARG_TYPE) &fhp->v2, + tv); + if (clnt_stat != RPC_SUCCESS) { + char *msg = clnt_sperrno(clnt_stat); + plog(XLOG_ERROR, "mountd rpc failed: %s", msg); + return EIO; + } + /* Check status of filehandle */ + if (fhp->v2.fhs_status) { + errno = fhp->v2.fhs_status; +#ifdef DEBUG + dlog("fhandle fetch for mount version 1 failed: %m"); +#endif /* DEBUG */ + return errno; + } +#ifdef HAVE_FS_NFS3 + } /* end of "if (nfs_version == NFS_VERSION3)" statement */ +#endif /* HAVE_FS_NFS3 */ + + /* all is well */ + return 0; +} + + +/* + * Scan mount table to see if something already mounted + */ +static int +already_mounted(mntlist *mlist, char *dir) +{ + mntlist *ml; + + for (ml = mlist; ml; ml = ml->mnext) + if (STREQ(ml->mnt->mnt_dir, dir)) + return 1; + return 0; +} + + +/* + * Mount the export tree from a host + */ +static int +amfs_host_fmount(mntfs *mf) +{ + struct timeval tv2; + CLIENT *client; + enum clnt_stat clnt_stat; + int n_export; + int j, k; + exports exlist = 0, ex; + exports *ep = 0; + am_nfs_handle_t *fp = 0; + char *host; + int error = 0; + struct sockaddr_in sin; + int sock = RPC_ANYSOCK; + int ok = FALSE; + mntlist *mlist; + char fs_name[MAXPATHLEN], *rfs_dir; + char mntpt[MAXPATHLEN]; + struct timeval tv; + u_long mnt_version; + + /* + * Read the mount list + */ + mlist = read_mtab(mf->mf_mount, mnttab_file_name); + +#ifdef MOUNT_TABLE_ON_FILE + /* + * Unlock the mount list + */ + unlock_mntlist(); +#endif /* MOUNT_TABLE_ON_FILE */ + + /* + * Take a copy of the server hostname, address, and nfs version + * to mount version conversion. + */ + host = mf->mf_server->fs_host; + sin = *mf->mf_server->fs_ip; + plog(XLOG_INFO, "amfs_host_fmount: NFS version %d", mf->mf_server->fs_version); +#ifdef HAVE_FS_NFS3 + if (mf->mf_server->fs_version == NFS_VERSION3) + mnt_version = MOUNTVERS3; + else +#endif /* HAVE_FS_NFS3 */ + mnt_version = MOUNTVERS; + + /* + * The original 10 second per try timeout is WAY too large, especially + * if we're only waiting 10 or 20 seconds max for the response. + * That would mean we'd try only once in 10 seconds, and we could + * lose the transmitt or receive packet, and never try again. + * A 2-second per try timeout here is much more reasonable. + * 09/28/92 Mike Mitchell, mcm@unx.sas.com + */ + tv.tv_sec = 2; + tv.tv_usec = 0; + + /* + * Create a client attached to mountd + */ + client = get_mount_client(host, &sin, &tv, &sock, mnt_version); + if (client == NULL) { +#ifdef HAVE_CLNT_SPCREATEERROR + plog(XLOG_ERROR, "get_mount_client failed for %s: %s", + host, clnt_spcreateerror("")); +#else /* not HAVE_CLNT_SPCREATEERROR */ + plog(XLOG_ERROR, "get_mount_client failed for %s", host); +#endif /* not HAVE_CLNT_SPCREATEERROR */ + error = EIO; + goto out; + } + if (!nfs_auth) { + error = make_nfs_auth(); + if (error) + goto out; + } + client->cl_auth = nfs_auth; + +#ifdef DEBUG + dlog("Fetching export list from %s", host); +#endif /* DEBUG */ + + /* + * Fetch the export list + */ + tv2.tv_sec = 10; + tv2.tv_usec = 0; + clnt_stat = clnt_call(client, + MOUNTPROC_EXPORT, + (XDRPROC_T_TYPE) xdr_void, + 0, + (XDRPROC_T_TYPE) xdr_exports, + (SVC_IN_ARG_TYPE) & exlist, + tv2); + if (clnt_stat != RPC_SUCCESS) { + char *msg = clnt_sperrno(clnt_stat); + plog(XLOG_ERROR, "host_fmount rpc failed: %s", msg); + /* clnt_perror(client, "rpc"); */ + error = EIO; + goto out; + } + + /* + * Figure out how many exports were returned + */ + for (n_export = 0, ex = exlist; ex; ex = ex->ex_next) { + /* printf("export %s\n", ex->ex_dir); */ + n_export++; + } + + /* + * Allocate an array of pointers into the list + * so that they can be sorted. If the filesystem + * is already mounted then ignore it. + */ + ep = (exports *) xmalloc(n_export * sizeof(exports)); + for (j = 0, ex = exlist; ex; ex = ex->ex_next) { + make_mntpt(mntpt, ex, mf); + if (!already_mounted(mlist, mntpt)) + ep[j++] = ex; + } + n_export = j; + + /* + * Sort into order. + * This way the mounts are done in order down the tree, + * instead of any random order returned by the mount + * daemon (the protocol doesn't specify...). + */ + qsort(ep, n_export, sizeof(exports), sortfun); + + /* + * Allocate an array of filehandles + */ + fp = (am_nfs_handle_t *) xmalloc(n_export * sizeof(am_nfs_handle_t)); + + /* + * Try to obtain filehandles for each directory. + * If a fetch fails then just zero out the array + * reference but discard the error. + */ + for (j = k = 0; j < n_export; j++) { + /* Check and avoid a duplicated export entry */ + if (j > k && ep[k] && STREQ(ep[j]->ex_dir, ep[k]->ex_dir)) { +#ifdef DEBUG + dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir); +#endif /* DEBUG */ + ep[j] = 0; + } else { + k = j; + error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j], + mf->mf_server->fs_version); + if (error) + ep[j] = 0; + } + } + + /* + * Mount each filesystem for which we have a filehandle. + * If any of the mounts succeed then mark "ok" and return + * error code 0 at the end. If they all fail then return + * the last error code. + */ + strncpy(fs_name, mf->mf_info, sizeof(fs_name)); + if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) { + plog(XLOG_FATAL, "amfs_host_fmount: mf_info has no colon"); + error = EINVAL; + goto out; + } + ++rfs_dir; + for (j = 0; j < n_export; j++) { + ex = ep[j]; + if (ex) { + strcpy(rfs_dir, ex->ex_dir); + make_mntpt(mntpt, ex, mf); + if (do_mount(&fp[j], mntpt, fs_name, mf->mf_mopts, mf) == 0) + ok = TRUE; + } + } + + /* + * Clean up and exit + */ +out: + discard_mntlist(mlist); + if (ep) + XFREE(ep); + if (fp) + XFREE(fp); + if (sock != RPC_ANYSOCK) + (void) amu_close(sock); + if (client) + clnt_destroy(client); + if (exlist) + xdr_pri_free((XDRPROC_T_TYPE) xdr_exports, (caddr_t) &exlist); + if (ok) + return 0; + return error; +} + + +/* + * Return true if pref is a directory prefix of dir. + * + * XXX TODO: + * Does not work if pref is "/". + */ +static int +directory_prefix(char *pref, char *dir) +{ + int len = strlen(pref); + + if (!NSTREQ(pref, dir, len)) + return FALSE; + if (dir[len] == '/' || dir[len] == '\0') + return TRUE; + return FALSE; +} + + +/* + * Unmount a mount tree + */ +static int +amfs_host_fumount(mntfs *mf) +{ + mntlist *ml, *mprev; + int xerror = 0; + + /* + * Read the mount list + */ + mntlist *mlist = read_mtab(mf->mf_mount, mnttab_file_name); + +#ifdef MOUNT_TABLE_ON_FILE + /* + * Unlock the mount list + */ + unlock_mntlist(); +#endif /* MOUNT_TABLE_ON_FILE */ + + /* + * Reverse list... + */ + ml = mlist; + mprev = 0; + while (ml) { + mntlist *ml2 = ml->mnext; + ml->mnext = mprev; + mprev = ml; + ml = ml2; + } + mlist = mprev; + + /* + * Unmount all filesystems... + */ + for (ml = mlist; ml && !xerror; ml = ml->mnext) { + char *dir = ml->mnt->mnt_dir; + if (directory_prefix(mf->mf_mount, dir)) { + int error; +#ifdef DEBUG + dlog("amfs_host: unmounts %s", dir); +#endif /* DEBUG */ + /* + * Unmount "dir" + */ + error = UMOUNT_FS(dir, mnttab_file_name); + /* + * Keep track of errors + */ + if (error) { + if (!xerror) + xerror = error; + if (error != EBUSY) { + errno = error; + plog(XLOG_ERROR, "Tree unmount of %s failed: %m", ml->mnt->mnt_dir); + } + } else { + (void) rmdirs(dir); + } + } + } + + /* + * Throw away mount list + */ + discard_mntlist(mlist); + + /* + * Try to remount, except when we are shutting down. + */ + if (xerror && amd_state != Finishing) { + xerror = amfs_host_fmount(mf); + if (!xerror) { + /* + * Don't log this - it's usually too verbose + plog(XLOG_INFO, "Remounted host %s", mf->mf_info); + */ + xerror = EBUSY; + } + } + return xerror; +} + + +/* + * Tell mountd we're done. + * This is not quite right, because we may still + * have other filesystems mounted, but the existing + * mountd protocol is badly broken anyway. + */ +static void +amfs_host_umounted(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + char *host; + CLIENT *client; + enum clnt_stat clnt_stat; + struct sockaddr_in sin; + int sock = RPC_ANYSOCK; + struct timeval tv; + u_long mnt_version; + + if (mf->mf_error || mf->mf_refc > 1 || !mf->mf_server) + return; + + /* + * Take a copy of the server hostname, address, and NFS version + * to mount version conversion. + */ + host = mf->mf_server->fs_host; + sin = *mf->mf_server->fs_ip; + plog(XLOG_INFO, "amfs_host_umounted: NFS version %d", mf->mf_server->fs_version); +#ifdef HAVE_FS_NFS3 + if (mf->mf_server->fs_version == NFS_VERSION3) + mnt_version = MOUNTVERS3; + else +#endif /* HAVE_FS_NFS3 */ + mnt_version = MOUNTVERS; + + /* + * Create a client attached to mountd + */ + tv.tv_sec = 10; + tv.tv_usec = 0; + client = get_mount_client(host, &sin, &tv, &sock, mnt_version); + if (client == NULL) { +#ifdef HAVE_CLNT_SPCREATEERROR + plog(XLOG_ERROR, "get_mount_client failed for %s: %s", + host, clnt_spcreateerror("")); +#else /* not HAVE_CLNT_SPCREATEERROR */ + plog(XLOG_ERROR, "get_mount_client failed for %s", host); +#endif /* not HAVE_CLNT_SPCREATEERROR */ + goto out; + } + + if (!nfs_auth) { + if (make_nfs_auth()) + goto out; + } + client->cl_auth = nfs_auth; + +#ifdef DEBUG + dlog("Unmounting all from %s", host); +#endif /* DEBUG */ + + clnt_stat = clnt_call(client, + MOUNTPROC_UMNTALL, + (XDRPROC_T_TYPE) xdr_void, + 0, + (XDRPROC_T_TYPE) xdr_void, + 0, + tv); + if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_SYSTEMERROR) { + /* RPC_SYSTEMERROR seems to be returned for no good reason ... */ + char *msg = clnt_sperrno(clnt_stat); + plog(XLOG_ERROR, "unmount all from %s rpc failed: %s", host, msg, clnt_stat); + goto out; + } + +out: + if (sock != RPC_ANYSOCK) + (void) amu_close(sock); + if (client) + clnt_destroy(client); +} diff --git a/contrib/amd/amd/amfs_inherit.c b/contrib/amd/amd/amfs_inherit.c new file mode 100644 index 0000000..e9709bd --- /dev/null +++ b/contrib/amd/amd/amfs_inherit.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_inherit.c,v 5.2.2.1 1992/02/09 15:08:26 jsp beta $ + * + */ + +/* + * Inheritance file system. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * This implements a filesystem restart. + * + * This is a *gross* hack - it knows far too + * much about the way other parts of the + * system work. See restart.c too. + */ + +static char *amfs_inherit_match(am_opts *fo); +static int amfs_inherit_fmount(mntfs *mf); +static int amfs_inherit_fumount(mntfs *mf); +static int amfs_inherit_init(mntfs *mf); +static int amfs_inherit_mount(am_node *mp); + + +/* + * Ops structure + */ +am_ops amfs_inherit_ops = +{ + "inherit", + amfs_inherit_match, + amfs_inherit_init, + amfs_inherit_mount, + amfs_inherit_fmount, + amfs_auto_fumount, + amfs_inherit_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_inherit_readlink */ + 0, /* amfs_inherit_mounted */ + 0, /* amfs_inherit_umounted */ + find_amfs_auto_srvr, + FS_DISCARD +}; + + +/* + * This should never be called. + */ +static char * +amfs_inherit_match(am_opts *fo) +{ + plog(XLOG_FATAL, "amfs_inherit_match called!"); + return 0; +} + + +static int +amfs_inherit_init(mntfs *mf) +{ + mntfs *mf_link = (mntfs *) mf->mf_private; + + if (mf_link == 0) { + plog(XLOG_ERROR, "Remount collision on %s?", mf->mf_mount); + plog(XLOG_FATAL, "Attempting to init not-a-filesystem"); + return EINVAL; + } + + if (mf_link->mf_ops->fs_init) + return (*mf_link->mf_ops->fs_init) (mf_link); + return 0; +} + + +/* + * Take the linked mount point and + * propogate. + */ +static mntfs * +amfs_inherit_inherit(mntfs *mf) +{ + mntfs *mf_link = (mntfs *) mf->mf_private; + + if (mf_link == 0) { + plog(XLOG_FATAL, "Attempting to inherit not-a-filesystem"); + return 0; /* XXX */ + } + mf_link->mf_fo = mf->mf_fo; + + /* + * Discard the old map. + * Don't call am_unmounted since this + * node was never really mounted in the + * first place. + */ + mf->mf_private = 0; + free_mntfs(mf); + + /* + * Free the dangling reference + * to the mount link. + */ + free_mntfs(mf_link); + + /* + * Get a hold of the other entry + */ + mf_link->mf_flags &= ~MFF_RESTART; + + /* Say what happened */ + plog(XLOG_INFO, "restarting %s on %s", mf_link->mf_info, mf_link->mf_mount); + + return mf_link; +} + + +static int +amfs_inherit_mount(am_node *mp) +{ + mntfs *newmf = amfs_inherit_inherit(mp->am_mnt); + + if (newmf) { + mp->am_mnt = newmf; + /* + * XXX - must do the am_mounted call here + */ + if (newmf->mf_ops->fs_flags & FS_MBACKGROUND) + am_mounted(mp); + + new_ttl(mp); + return 0; + } + return EINVAL; +} + + +static int +amfs_inherit_fmount(mntfs *mf) +{ + am_node *mp = find_mf(mf); + + if (mp) + return amfs_inherit_mount(mp); + return amfs_inherit_inherit(mf) ? 0 : EINVAL; +} + + +static int +amfs_inherit_fumount(mntfs *mf) +{ + /* + * Always succeed + */ + return 0; +} diff --git a/contrib/amd/amd/amfs_link.c b/contrib/amd/amd/amfs_link.c new file mode 100644 index 0000000..251c5eb --- /dev/null +++ b/contrib/amd/amd/amfs_link.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_link.c,v 5.2.2.1 1992/02/09 15:09:04 jsp beta $ + * + */ + +/* + * Symbol-link file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* + * Ops structures + */ +am_ops amfs_link_ops = +{ + "link", + amfs_link_match, + 0, /* amfs_link_init */ + amfs_auto_fmount, + amfs_link_fmount, + amfs_auto_fumount, + amfs_link_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_link_readlink */ + 0, /* amfs_link_mounted */ + 0, /* amfs_link_umounted */ + find_amfs_auto_srvr, + 0 +}; + + +/* + * SFS needs a link. + */ +char * +amfs_link_match(am_opts *fo) +{ + + if (!fo->opt_fs) { + plog(XLOG_USER, "link: no fs specified"); + return 0; + } + + /* + * Bug report (14/12/89) from Jay Plett + * If an automount point has the same name as an existing + * link type mount Amd hits a race condition and either hangs + * or causes a symlink loop. + * + * If fs begins with a '/' change the opt_fs & opt_sublink + * fields so that the fs option doesn't end up pointing at + * an existing symlink. + * + * If sublink is nil then set sublink to fs + * else set sublink to fs / sublink + * + * Finally set fs to ".". + */ + if (*fo->opt_fs == '/') { + char *fullpath; + char *link = fo->opt_sublink; + if (link) { + if (*link == '/') + fullpath = strdup(link); + else + fullpath = str3cat((char *) 0, fo->opt_fs, "/", link); + } else { + fullpath = strdup(fo->opt_fs); + } + + if (fo->opt_sublink) + XFREE(fo->opt_sublink); + fo->opt_sublink = fullpath; + fo->opt_fs = str3cat(fo->opt_fs, ".", fullpath, ""); + } + + return strdup(fo->opt_fs); +} + + +int +amfs_link_fmount(mntfs *mf) +{ + /* + * Wow - this is hard to implement! :-) + */ + return 0; +} + + +int +amfs_link_fumount(mntfs *mf) +{ + return 0; +} diff --git a/contrib/amd/amd/amfs_linkx.c b/contrib/amd/amd/amfs_linkx.c new file mode 100644 index 0000000..e46206f --- /dev/null +++ b/contrib/amd/amd/amfs_linkx.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_linkx.c,v 5.2.2.1 1992/02/09 15:09:04 jsp beta $ + * + */ + +/* + * Symbol-link file system, with test that the target of the link exists. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward declarations */ +static int amfs_linkx_mount(am_node *mp); + +/* + * linkx operations + */ +struct am_ops amfs_linkx_ops = +{ + "linkx", + amfs_link_match, + 0, /* amfs_linkx_init */ + amfs_linkx_mount, + 0, + amfs_auto_fumount, + amfs_link_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_linkx_readlink */ + 0, /* amfs_linkx_mounted */ + 0, /* amfs_linkx_umounted */ + find_amfs_auto_srvr, + FS_MBACKGROUND +}; + + +static int +amfs_linkx_mount(am_node *mp) +{ + /* + * Check for existence of target. + */ + struct stat stb; + char *ln; + + if (mp->am_link) + ln = mp->am_link; + else /* should never occur */ + ln = mp->am_mnt->mf_mount; + + /* + * Use lstat, not stat, since we don't + * want to know if the ultimate target of + * a symlink chain exists, just the first. + */ + if (lstat(ln, &stb) < 0) + return errno; + + return 0; +} + diff --git a/contrib/amd/amd/amfs_nfsl.c b/contrib/amd/amd/amfs_nfsl.c new file mode 100644 index 0000000..8132afd --- /dev/null +++ b/contrib/amd/amd/amfs_nfsl.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_nfsl.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * NFSL: Network file system with local existence check. If the local + * path denoted by $rfs exists, it behaves as type:=link. + * + * Example: + * pkg type:=nfsl;rhost:=jonny;rfs:=/n/johnny/src/pkg;fs:=${rfs} + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* forward declarations */ +static char *amfs_nfsl_match(am_opts *fo); +static int amfs_nfsl_init(mntfs *mf); +static int amfs_nfsl_fmount(mntfs *mf); +static int amfs_nfsl_fumount(mntfs *mf); +static void amfs_nfsl_umounted(am_node *mp); +static fserver *amfs_nfsl_ffserver(mntfs *mf); + +/* + * NFS-Link operations + */ +am_ops amfs_nfsl_ops = +{ + "nfsl", /* name of file system */ + amfs_nfsl_match, /* match */ + amfs_nfsl_init, /* initialize */ + amfs_auto_fmount, /* mount vnode */ + amfs_nfsl_fmount, /* mount vfs */ + amfs_auto_fumount, /* unmount vnode */ + amfs_nfsl_fumount, /* unmount VFS */ + amfs_error_lookuppn, /* lookup path-name */ + amfs_error_readdir, /* read directory */ + 0, /* read link */ + 0, /* after-mount extra actions */ + amfs_nfsl_umounted, /* after-umount extra actions */ + amfs_nfsl_ffserver, /* find a file server */ + FS_MKMNT | FS_BACKGROUND | FS_AMQINFO /* flags */ +}; + + +/* + * Check that f/s has all needed fields. + * Returns: matched string if found, NULL otherwise. + */ +static char * +amfs_nfsl_match(am_opts *fo) +{ + char *cp = fo->opt_fs; + char *ho = fo->opt_rhost; + struct stat stb; + + if (!cp || !ho) { + plog(XLOG_USER, "amfs_nfsl: nost $fs and $rhost must be specified"); + return NULL; + } + + /* + * If this host is not the same as $rhost, or if link does not exist, + * perform nfs_match(), same as for type:=nfs. + * If link value exists (or same host), then perform amfs_link_match(), + * same as for linkx. + */ + if (!STRCEQ(ho, hostname)) { + plog(XLOG_INFO, "amfs_nfsl: \"%s\" is not local host, using type:=nfs", ho); + return nfs_match(fo); + } else if (lstat(cp, &stb) < 0) { + plog(XLOG_INFO, "amfs_nfsl: \"%s\" does not exist, using type:=nfs", cp); + return nfs_match(fo); + } else { + plog(XLOG_INFO, "amfs_nfsl: \"%s\" exists, using type:=link", cp); + return amfs_link_match(fo); + } +} + + +/* + * Initialize. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +amfs_nfsl_init(mntfs *mf) +{ + /* + * If a link, do nothing (same as type:=link). + * If non-link, do nfs_init (same as type:=nfs). + */ + if (mf->mf_flags & MFF_NFSLINK) { + return 0; + } else { + return nfs_init(mf); + } +} + + +/* + * Mount vfs. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +amfs_nfsl_fmount(mntfs *mf) +{ + /* + * If a link, do run amfs_link_fmount() (same as type:=link) + * If non-link, do nfs_fmount (same as type:=nfs). + */ + if (mf->mf_flags & MFF_NFSLINK) { + return amfs_link_fmount(mf); + } else { + return nfs_fmount(mf); + } +} + + +/* + * Unmount VFS. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +amfs_nfsl_fumount(mntfs *mf) +{ + /* + * If a link, do run amfs_link_fumount() (same as type:=link) + * If non-link, do nfs_fumount (same as type:=nfs). + */ + if (mf->mf_flags & MFF_NFSLINK) { + return amfs_link_fumount(mf); + } else { + return nfs_fumount(mf); + } +} + + +/* + * Async unmount callback function. + * After the base umount() succeeds, we may want to take extra actions, + * such as informing remote mount daemons that we've unmounted them. + * See amfs_auto_umounted(), host_umounted(), nfs_umounted(). + */ +static void +amfs_nfsl_umounted(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + /* + * If a link, do nothing (same as type:=link) + * If non-link, do nfs_fumount (same as type:=nfs). + */ + if (mf->mf_flags & MFF_NFSLINK) { + return; + } else { + nfs_umounted(mp); + /* + * MUST remove mount point directories, because if they remain + * behind, the next nfsl access will think they are a link + * type file system, and not NFS! (when it performs link target + * existence test) + */ + if (mf->mf_flags & MFF_MKMNT) + rmdirs(mf->mf_mount); + return; + } +} + + +/* + * Find a file server. + * Returns: fserver of found server, or NULL if not found. + */ +static fserver * +amfs_nfsl_ffserver(mntfs *mf) +{ + char *cp = mf->mf_fo->opt_fs; + char *ho = mf->mf_fo->opt_rhost; + struct stat stb; + + /* + * If this host is not the same as $rhost, or if link does not exist, + * perform find_nfs_srvr(), same as for type:=nfs. + * If link value exists (or same host), then perform + * find_amfs_auto_srvr(), same as for linkx. + */ + if (!STREQ(ho, hostname) || lstat(cp, &stb) < 0) { + return find_nfs_srvr(mf); + } else { + mf->mf_flags |= MFF_NFSLINK; + return find_amfs_auto_srvr(mf); + } +} diff --git a/contrib/amd/amd/amfs_nfsx.c b/contrib/amd/amd/amfs_nfsx.c new file mode 100644 index 0000000..272e10d --- /dev/null +++ b/contrib/amd/amd/amfs_nfsx.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_linxx.c,v 5.2.2.3 1992/05/31 16:13:07 jsp Exp $ + * + */ + +/* + * NFS hierarchical mounts + * + * TODO: Re-implement. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * The rfs field contains a list of mounts to be done from + * the remote host. + */ +typedef struct amfs_nfsx_mnt { + mntfs *n_mnt; + int n_error; +} amfs_nfsx_mnt; + +struct amfs_nfsx { + int nx_c; /* Number of elements in nx_v */ + amfs_nfsx_mnt *nx_v; /* Underlying mounts */ + amfs_nfsx_mnt *nx_try; +}; + +/* forward definitions */ +static char *amfs_nfsx_match(am_opts *fo); +static int amfs_nfsx_fmount (mntfs *); +static int amfs_nfsx_fmount(mntfs *mf); +static int amfs_nfsx_fumount(mntfs *mf); +static int amfs_nfsx_init(mntfs *mf); + +/* + * Ops structure + */ +am_ops amfs_nfsx_ops = +{ + "nfsx", + amfs_nfsx_match, + amfs_nfsx_init, + amfs_auto_fmount, + amfs_nfsx_fmount, + amfs_auto_fumount, + amfs_nfsx_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_nfsx_readlink */ + 0, /* amfs_nfsx_mounted */ + 0, /* amfs_nfsx_umounted */ + find_nfs_srvr, /* XXX */ + /* FS_UBACKGROUND| */ FS_AMQINFO +}; + + +static char * +amfs_nfsx_match(am_opts *fo) +{ + char *xmtab; + char *ptr; + int len; + + if (!fo->opt_rfs) { + plog(XLOG_USER, "amfs_nfsx: no remote filesystem specified"); + return FALSE; + } + + if (!fo->opt_rhost) { + plog(XLOG_USER, "amfs_nfsx: no remote host specified"); + return FALSE; + } + + /* set default sublink */ + if (fo->opt_sublink == 0) { + ptr = strchr(fo->opt_rfs, ','); + if (ptr && ptr != (fo->opt_rfs + 1)) + fo->opt_sublink = strnsave(fo->opt_rfs + 1, ptr - fo->opt_rfs - 1); + } + + /* + * Remove trailing ",..." from ${fs} + * After deslashifying, overwrite the end of ${fs} with "/" + * to make sure it is unique. + */ + if ((ptr = strchr(fo->opt_fs, ','))) + *ptr = '\0'; + deslashify(fo->opt_fs); + + /* + * Bump string length to allow trailing / + */ + len = strlen(fo->opt_fs); + fo->opt_fs = xrealloc(fo->opt_fs, len + 1 + 1); + ptr = fo->opt_fs + len; + + /* + * Make unique... + */ + *ptr++ = '/'; + *ptr = '\0'; + + /* + * Determine magic cookie to put in mtab + */ + xmtab = str3cat((char *) 0, fo->opt_rhost, ":", fo->opt_rfs); +#ifdef DEBUG + dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"", + fo->opt_rhost, fo->opt_rfs, fo->opt_fs); +#endif /* DEBUG */ + + return xmtab; +} + + +static void +amfs_nfsx_prfree(voidp vp) +{ + struct amfs_nfsx *nx = (struct amfs_nfsx *) vp; + int i; + + for (i = 0; i < nx->nx_c; i++) { + mntfs *m = nx->nx_v[i].n_mnt; + if (m) + free_mntfs(m); + } + + XFREE(nx->nx_v); + XFREE(nx); +} + + +static int +amfs_nfsx_init(mntfs *mf) +{ + /* + * mf_info has the form: + * host:/prefix/path,sub,sub,sub + */ + int i; + int glob_error; + struct amfs_nfsx *nx; + int asked_for_wakeup = 0; + + nx = (struct amfs_nfsx *) mf->mf_private; + + if (nx == 0) { + char **ivec; + char *info = 0; + char *host; + char *pref; + int error = 0; + + info = strdup(mf->mf_info); + host = strchr(info, ':'); + if (!host) { + error = EINVAL; + goto errexit; + } + pref = host +1; + host = info; + + /* + * Split the prefix off from the suffices + */ + ivec = strsplit(pref, ',', '\''); + + /* + * Count array size + */ + for (i = 0; ivec[i]; i++) ; + + nx = ALLOC(struct amfs_nfsx); + mf->mf_private = (voidp) nx; + mf->mf_prfree = amfs_nfsx_prfree; + + nx->nx_c = i - 1; /* i-1 because we don't want the prefix */ + nx->nx_v = (amfs_nfsx_mnt *) xmalloc(nx->nx_c * sizeof(amfs_nfsx_mnt)); + { + char *mp = 0; + char *xinfo = 0; + char *fs = mf->mf_fo->opt_fs; + char *rfs = 0; + for (i = 0; i < nx->nx_c; i++) { + char *path = ivec[i + 1]; + rfs = str3cat(rfs, pref, "/", path); + /* + * Determine the mount point. + * If this is the root, then don't remove + * the trailing slash to avoid mntfs name clashes. + */ + mp = str3cat(mp, fs, "/", rfs); + normalize_slash(mp); + deslashify(mp); + /* + * Determine the mount info + */ + xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path); + normalize_slash(xinfo); + if (pref[1] != '\0') + deslashify(xinfo); +#ifdef DEBUG + dlog("amfs_nfsx: init mount for %s on %s", xinfo, mp); +#endif /* DEBUG */ + nx->nx_v[i].n_error = -1; + nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts); + } + if (rfs) + XFREE(rfs); + if (mp) + XFREE(mp); + if (xinfo) + XFREE(xinfo); + } + + XFREE(ivec); + errexit: + if (info) + XFREE(info); + if (error) + return error; + } + + /* + * Iterate through the mntfs's and call + * the underlying init routine on each + */ + glob_error = 0; + + for (i = 0; i < nx->nx_c; i++) { + amfs_nfsx_mnt *n = &nx->nx_v[i]; + mntfs *m = n->n_mnt; + int error = (*m->mf_ops->fs_init) (m); + /* + * if you just "return error" here, you will have made a failure + * in any submounts to fail the whole group. There was old unused code + * here before. + */ + if (error > 0) + n->n_error = error; + + else if (error < 0) { + glob_error = -1; + if (!asked_for_wakeup) { + asked_for_wakeup = 1; + sched_task(wakeup_task, (voidp) mf, (voidp) m); + } + } + } + + return glob_error; +} + + +static void +amfs_nfsx_cont(int rc, int term, voidp closure) +{ + mntfs *mf = (mntfs *) closure; + struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private; + amfs_nfsx_mnt *n = nx->nx_try; + + n->n_mnt->mf_flags &= ~(MFF_ERROR | MFF_MOUNTING); + mf->mf_flags &= ~MFF_ERROR; + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) n->n_mnt); + + if (rc || term) { + if (term) { + /* + * Not sure what to do for an error code. + */ + plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term); + n->n_error = EIO; + } else { + /* + * Check for exit status + */ + errno = rc; /* XXX */ + plog(XLOG_ERROR, "%s: mount (amfs_nfsx_cont): %m", n->n_mnt->mf_mount); + n->n_error = rc; + } + free_mntfs(n->n_mnt); + n->n_mnt = new_mntfs(); + n->n_mnt->mf_error = n->n_error; + n->n_mnt->mf_flags |= MFF_ERROR; + } else { + /* + * The mount worked. + */ + mf_mounted(n->n_mnt); + n->n_error = 0; + } + + /* + * Do the remaining bits + */ + if (amfs_nfsx_fmount(mf) >= 0) { + wakeup((voidp) mf); + mf->mf_flags &= ~MFF_MOUNTING; + mf_mounted(mf); + } +} + + +static int +try_amfs_nfsx_mount(voidp mv) +{ + mntfs *mf = (mntfs *) mv; + int error; + + mf->mf_flags |= MFF_MOUNTING; + error = (*mf->mf_ops->fmount_fs) (mf); + mf->mf_flags &= ~MFF_MOUNTING; + + return error; +} + + +static int +amfs_nfsx_remount(mntfs *mf, int fg) +{ + struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private; + amfs_nfsx_mnt *n; + int glob_error = -1; + + for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { + mntfs *m = n->n_mnt; + if (n->n_error < 0) { + if (!(m->mf_flags & MFF_MKMNT) && m->mf_ops->fs_flags & FS_MKMNT) { + int error = mkdirs(m->mf_mount, 0555); + if (!error) + m->mf_flags |= MFF_MKMNT; + } + } + } + + /* + * Iterate through the mntfs's and mount each filesystem + * which is not yet mounted. + */ + for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { + mntfs *m = n->n_mnt; + if (n->n_error < 0) { + /* + * Check fmount entry pt. exists + * and then mount... + */ + if (!m->mf_ops->fmount_fs) { + n->n_error = EINVAL; + } else { +#ifdef DEBUG + dlog("calling underlying fmount on %s", m->mf_mount); +#endif /* DEBUG */ + if (!fg && foreground && (m->mf_ops->fs_flags & FS_MBACKGROUND)) { + m->mf_flags |= MFF_MOUNTING; /* XXX */ +#ifdef DEBUG + dlog("backgrounding mount of \"%s\"", m->mf_info); +#endif /* DEBUG */ + nx->nx_try = n; + run_task(try_amfs_nfsx_mount, (voidp) m, amfs_nfsx_cont, (voidp) mf); + n->n_error = -1; + return -1; + } else { +#ifdef DEBUG + dlog("foreground mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + n->n_error = (*m->mf_ops->fmount_fs) (m); + } + } + +#ifdef DEBUG + if (n->n_error > 0) { + errno = n->n_error; /* XXX */ + dlog("underlying fmount of %s failed: %m", m->mf_mount); + } +#endif /* DEBUG */ + + if (n->n_error == 0) { + glob_error = 0; + } else if (glob_error < 0) { + glob_error = n->n_error; + } + } + } + + return glob_error < 0 ? 0 : glob_error; +} + + +static int +amfs_nfsx_fmount(mntfs *mf) +{ + return amfs_nfsx_remount(mf, FALSE); +} + + +/* + * Unmount an NFS hierarchy. + * Note that this is called in the foreground + * and so may hang under extremely rare conditions. + */ +static int +amfs_nfsx_fumount(mntfs *mf) +{ + struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private; + amfs_nfsx_mnt *n; + int glob_error = 0; + + /* + * Iterate in reverse through the mntfs's and unmount each filesystem + * which is mounted. + */ + for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) { + mntfs *m = n->n_mnt; + /* + * If this node has not been messed with + * and there has been no error so far + * then try and unmount. + * If an error had occured then zero + * the error code so that the remount + * only tries to unmount those nodes + * which had been successfully unmounted. + */ + if (n->n_error == 0) { +#ifdef DEBUG + dlog("calling underlying fumount on %s", m->mf_mount); +#endif /* DEBUG */ + n->n_error = (*m->mf_ops->fumount_fs) (m); + if (n->n_error) { + glob_error = n->n_error; + n->n_error = 0; + } else { + /* + * Make sure remount gets this node + */ + n->n_error = -1; + } + } + } + + /* + * If any unmounts failed then remount the + * whole lot... + */ + if (glob_error) { + glob_error = amfs_nfsx_remount(mf, TRUE); + if (glob_error) { + errno = glob_error; /* XXX */ + plog(XLOG_USER, "amfs_nfsx: remount of %s failed: %m", mf->mf_mount); + } + glob_error = EBUSY; + } else { + /* + * Remove all the mount points + */ + for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { + mntfs *m = n->n_mnt; + am_node am; + + /* + * XXX: all the umounted handler needs is a + * mntfs pointer, so pass an am_node with the right + * pointer in it. + */ + memset((voidp) &am, 0, sizeof(am)); + am.am_mnt = m; +#ifdef DEBUG + dlog("calling underlying umounted on %s", m->mf_mount); +#endif /* DEBUG */ + (*m->mf_ops->umounted) (&am); + + if (n->n_error < 0) { + if (m->mf_ops->fs_flags & FS_MKMNT) { + (void) rmdirs(m->mf_mount); + m->mf_flags &= ~MFF_MKMNT; + } + } + free_mntfs(m); + n->n_mnt = 0; + n->n_error = -1; + } + } + + return glob_error; +} diff --git a/contrib/amd/amd/amfs_program.c b/contrib/amd/amd/amfs_program.c new file mode 100644 index 0000000..2bd0778 --- /dev/null +++ b/contrib/amd/amd/amfs_program.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_program.c,v 5.2.2.1 1992/02/09 15:08:56 jsp beta $ + * + */ + +/* + * Program file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward definitions */ +static char *amfs_program_match(am_opts *fo); +static int amfs_program_fmount(mntfs *mf); +static int amfs_program_fumount(mntfs *mf); +static int amfs_program_init(mntfs *mf); + +/* + * Ops structure + */ +am_ops amfs_program_ops = +{ + "program", + amfs_program_match, + amfs_program_init, + amfs_auto_fmount, + amfs_program_fmount, + amfs_auto_fumount, + amfs_program_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* amfs_program_readlink */ + 0, /* amfs_program_mounted */ + 0, /* amfs_program_umounted */ + find_amfs_auto_srvr, + FS_BACKGROUND | FS_AMQINFO +}; + + +/* + * Execute needs a mount and unmount command. + */ +static char * +amfs_program_match(am_opts *fo) +{ + char *prog; + + if (!fo->opt_mount || !fo->opt_unmount) { + plog(XLOG_USER, "program: no mount/unmount specified"); + return 0; + } + prog = strchr(fo->opt_mount, ' '); + + return strdup(prog ? prog + 1 : fo->opt_mount); +} + + +static int +amfs_program_init(mntfs *mf) +{ + /* + * Save unmount command + */ + if (mf->mf_refc == 1) { + mf->mf_private = (voidp) strdup(mf->mf_fo->opt_unmount); + mf->mf_prfree = (void (*)(voidp)) free; + } + + return 0; +} + + +static int +amfs_program_exec(char *info) +{ + char **xivec; + int error; + + /* + * Split copy of command info string + */ + info = strdup(info); + if (info == 0) + return ENOBUFS; + xivec = strsplit(info, ' ', '\''); + + /* + * Put stdout to stderr + */ + (void) fclose(stdout); + (void) dup(fileno(logfp)); + if (fileno(logfp) != fileno(stderr)) { + (void) fclose(stderr); + (void) dup(fileno(logfp)); + } + + /* + * Try the exec + */ +#ifdef DEBUG + amuDebug(D_FULL) { + char **cp = xivec; + plog(XLOG_DEBUG, "executing (un)mount command..."); + while (*cp) { + plog(XLOG_DEBUG, "arg[%d] = '%s'", cp - xivec, *cp); + cp++; + } + } +#endif /* DEBUG */ + + if (xivec[0] == 0 || xivec[1] == 0) { + errno = EINVAL; + plog(XLOG_USER, "1st/2nd args missing to (un)mount program"); + } else { + (void) execv(xivec[0], xivec + 1); + } + + /* + * Save error number + */ + error = errno; + plog(XLOG_ERROR, "exec failed: %m"); + + /* + * Free allocate memory + */ + XFREE(info); + XFREE(xivec); + + /* + * Return error + */ + return error; +} + + +static int +amfs_program_fmount(mntfs *mf) +{ + return amfs_program_exec(mf->mf_fo->opt_mount); +} + + +static int +amfs_program_fumount(mntfs *mf) +{ + return amfs_program_exec((char *) mf->mf_private); +} diff --git a/contrib/amd/amd/amfs_root.c b/contrib/amd/amd/amfs_root.c new file mode 100644 index 0000000..3c1cd17 --- /dev/null +++ b/contrib/amd/amd/amfs_root.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_root.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Root file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ +static int amfs_root_mount(am_node *mp); + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_root_ops = +{ + "root", + 0, /* amfs_root_match */ + 0, /* amfs_root_init */ + amfs_root_mount, + 0, + amfs_auto_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, + 0, /* amfs_root_readlink */ + 0, /* amfs_root_mounted */ + 0, /* amfs_root_umounted */ + find_amfs_auto_srvr, + FS_NOTIMEOUT | FS_AMQINFO | FS_DIRECTORY +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ + +/* + * Mount the root... + */ +static int +amfs_root_mount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + mf->mf_mount = strealloc(mf->mf_mount, pid_fsname); + mf->mf_private = (voidp) mapc_find(mf->mf_info, "", NULL); + mf->mf_prfree = mapc_free; + + return 0; +} diff --git a/contrib/amd/amd/amfs_toplvl.c b/contrib/amd/amd/amfs_toplvl.c new file mode 100644 index 0000000..f36c66f --- /dev/null +++ b/contrib/amd/amd/amfs_toplvl.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_toplvl.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Top-level file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ + + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_toplvl_ops = +{ + "toplvl", + amfs_auto_match, + 0, /* amfs_auto_init */ + amfs_toplvl_mount, + 0, + amfs_toplvl_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, /* browsable version of readdir() */ + 0, /* amfs_toplvl_readlink */ + amfs_toplvl_mounted, + 0, /* amfs_toplvl_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ + +/* + * Mount an automounter directory. + * The automounter is connected into the system + * as a user-level NFS server. mount_amfs_toplvl constructs + * the necessary NFS parameters to be given to the + * kernel so that it will talk back to us. + * + * NOTE: automounter mounts in themselves are using NFS Version 2. + */ +static int +mount_amfs_toplvl(char *dir, char *opts) +{ + char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; + int retry, error, genflags; + mntent_t mnt; + nfs_args_t nfs_args; + am_nfs_fh *fhp; + am_nfs_handle_t anh; + MTYPE_TYPE type = MOUNT_TYPE_NFS; +#ifndef HAVE_TRANSPORT_TYPE_TLI + u_short port; + struct sockaddr_in sin; +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = pid_fsname; + mnt.mnt_opts = opts; + + /* + * Make sure that amd's top-level NFS mounts are hidden by default + * from df. + * If they don't appear to support the either the "ignore" mnttab + * option entry, or the "auto" one, set the mount type to "nfs". + */ + mnt.mnt_type = HIDE_MOUNT_TYPE; + + retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); + if (retry <= 0) + retry = 2; /* XXX */ + + /* + * SET MOUNT ARGS + */ + /* + * get fhandle of remote path for automount point + */ + fhp = root_fh(dir); + if (!fhp) { + plog(XLOG_FATAL, "Can't find root file handle for %s", dir); + return EINVAL; + } + +#ifndef HAVE_TRANSPORT_TYPE_TLI + /* + * Create sockaddr to point to the local machine. 127.0.0.1 + * is not used since that will not work in HP-UX clusters and + * this is no more expensive. + */ + memset((voidp) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr = myipaddr; + port = hasmntval(&mnt, MNTTAB_OPT_PORT); + if (port) { + sin.sin_port = htons(port); + } else { + plog(XLOG_ERROR, "no port number specified for %s", dir); + return EINVAL; + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* + * Make a ``hostname'' string for the kernel + */ + sprintf(fs_hostname, "pid%ld@%s:%s", + (long) (foreground ? mypid : getppid()), + hostname, + dir); + /* + * Most kernels have a name length restriction (64 bytes)... + */ + if (strlen(fs_hostname) >= MAXHOSTNAMELEN) + strcpy(fs_hostname + MAXHOSTNAMELEN - 3, ".."); +#ifdef HOSTNAMESZ + /* + * ... and some of these restrictions are 32 bytes (HOSTNAMESZ) + * If you need to get the definition for HOSTNAMESZ found, you may + * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file. + */ + if (strlen(fs_hostname) >= HOSTNAMESZ) + strcpy(fs_hostname + HOSTNAMESZ - 3, ".."); +#endif /* HOSTNAMESZ */ + + /* + * Finally we can compute the mount genflags set above. + */ + genflags = compute_mount_flags(&mnt); + + /* setup the many fields and flags within nfs_args */ + memmove(&anh.v2.fhs_fh, fhp, sizeof(*fhp)); +#ifdef HAVE_TRANSPORT_TYPE_TLI + compute_nfs_args(&nfs_args, + &mnt, + genflags, + nfsncp, + NULL, /* remote host IP addr is set below */ + NFS_VERSION, /* version 2 */ + "udp", + &anh, + fs_hostname, + pid_fsname); + /* + * IMPORTANT: set the correct IP address AFTERWARDS. It cannot + * be done using the normal mechanism of compute_nfs_args(), because + * that one will allocate a new address and use NFS_SA_DREF() to copy + * parts to it, while assuming that the ip_addr passed is always + * a "struct sockaddr_in". That assumption is incorrect on TLI systems, + * because they define a special macro HOST_SELF which is DIFFERENT + * than localhost (127.0.0.1)! + */ + nfs_args.addr = &nfsxprt->xp_ltaddr; +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + compute_nfs_args(&nfs_args, + &mnt, + genflags, + &sin, + NFS_VERSION, /* version 2 */ + "udp", + &anh, + fs_hostname, + pid_fsname); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /************************************************************************* + * NOTE: while compute_nfs_args() works ok for regular NFS mounts * + * the toplvl one is not, and so some options must be corrected by hand * + * more carefully, *after* compute_nfs_args() runs. * + *************************************************************************/ + compute_automounter_nfs_args(&nfs_args, &mnt); + + /* This is it! Here we try to mount amd on its mount points */ +#ifdef DEBUG + amuDebug(D_TRACE) + print_nfs_args(&nfs_args, 0); +#endif /* DEBUG */ + error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, + 0, NULL, mnttab_file_name); + +#ifdef HAVE_TRANSPORT_TYPE_TLI + free_knetconfig(nfs_args.knconf); + /* + * local automounter mounts do not allocate a special address, so + * no need to XFREE(nfs_args.addr) under TLI. + */ +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + return error; +} + + +/* + * Mount the top-level + */ +int +amfs_toplvl_mount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + struct stat stb; + char opts[256], preopts[256]; + int error; + char *mnttype; + + /* + * Mounting the automounter. + * Make sure the mount directory exists, construct + * the mount options and call the mount_amfs_toplvl routine. + */ + + if (stat(mp->am_path, &stb) < 0) { + return errno; + } else if ((stb.st_mode & S_IFMT) != S_IFDIR) { + plog(XLOG_WARNING, "%s is not a directory", mp->am_path); + return ENOTDIR; + } + if (mf->mf_ops == &amfs_toplvl_ops) + mnttype = "indirect"; + else if (mf->mf_ops == &amfs_direct_ops) + mnttype = "direct"; +#ifdef HAVE_AM_FS_UNION + else if (mf->mf_ops == &amfs_union_ops) + mnttype = "union"; +#endif /* HAVE_AM_FS_UNION */ + else + mnttype = "auto"; + + /* + * Construct some mount options: + * + * Tack on magic map= option in mtab to emulate + * SunOS automounter behavior. + */ + preopts[0] = '\0'; +#ifdef MNTTAB_OPT_INTR + strcat(preopts, MNTTAB_OPT_INTR); + strcat(preopts, ","); +#endif /* MNTTAB_OPT_INTR */ +#ifdef MNTTAB_OPT_IGNORE + strcat(preopts, MNTTAB_OPT_IGNORE); + strcat(preopts, ","); +#endif /* MNTTAB_OPT_IGNORE */ + sprintf(opts, "%s%s,%s=%d,%s=%d,%s=%d,%s,map=%s", + preopts, + MNTTAB_OPT_RW, + MNTTAB_OPT_PORT, nfs_port, + MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo, + MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans, + mnttype, mf->mf_info); + + /* now do the mount */ + error = mount_amfs_toplvl(mf->mf_mount, opts); + if (error) { + errno = error; + plog(XLOG_FATAL, "mount_amfs_toplvl: %m"); + return error; + } + return 0; +} + + +void +amfs_toplvl_mounted(mntfs *mf) +{ + amfs_auto_mkcacheref(mf); +} + + +/* + * Unmount a top-level automount node + */ +int +amfs_toplvl_umount(am_node *mp) +{ + int error; + struct stat stb; + +again: + /* + * The lstat is needed if this mount is type=direct. + * When that happens, the kernel cache gets confused + * between the underlying type (dir) and the mounted + * type (link) and so needs to be re-synced before + * the unmount. This is all because the unmount system + * call follows links and so can't actually unmount + * a link (stupid!). It was noted that doing an ls -ld + * of the mount point to see why things were not working + * actually fixed the problem - so simulate an ls -ld here. + */ + if (lstat(mp->am_path, &stb) < 0) { +#ifdef DEBUG + dlog("lstat(%s): %m", mp->am_path); +#endif /* DEBUG */ + } + error = UMOUNT_FS(mp->am_path, mnttab_file_name); + if (error == EBUSY) { + plog(XLOG_WARNING, "amfs_toplvl_unmount retrying %s in 1s", mp->am_path); + sleep(1); /* XXX */ + goto again; + } + return error; +} diff --git a/contrib/amd/amd/amfs_union.c b/contrib/amd/amd/amfs_union.c new file mode 100644 index 0000000..95fc8fd --- /dev/null +++ b/contrib/amd/amd/amfs_union.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amfs_union.c,v 1.1 1997-1998/06/30 19:22:30 ezk Exp ezk $ + * + */ + +/* + * Union automounter file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/**************************************************************************** + *** FORWARD DEFINITIONS *** + ****************************************************************************/ +static void amfs_union_mounted(mntfs *mf); + + +/**************************************************************************** + *** OPS STRUCTURES *** + ****************************************************************************/ +am_ops amfs_union_ops = +{ + "union", + amfs_auto_match, + 0, /* amfs_auto_init */ + amfs_toplvl_mount, + 0, + amfs_toplvl_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, + 0, /* amfs_toplvl_readlink */ + amfs_union_mounted, + 0, /* amfs_toplvl_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY +}; + + +/* + * Create a reference to a union'ed entry + * XXX: this function may not be used anywhere... + */ +static int +create_amfs_union_node(char *dir, voidp arg) +{ + if (!STREQ(dir, "/defaults")) { + int error = 0; + (void) amfs_toplvl_ops.lookuppn(arg, dir, &error, VLOOK_CREATE); + if (error > 0) { + errno = error; /* XXX */ + plog(XLOG_ERROR, "Could not mount %s: %m", dir); + } + return error; + } + return 0; +} + + +static void +amfs_union_mounted(mntfs *mf) +{ + int i; + + amfs_auto_mkcacheref(mf); + + /* + * Having made the union mount point, + * populate all the entries... + */ + for (i = 0; i <= last_used_map; i++) { + am_node *mp = exported_ap[i]; + if (mp && mp->am_mnt == mf) { + /* return value from create_amfs_union_node is ignored by mapc_keyiter */ + (void) mapc_keyiter((mnt_map *) mp->am_mnt->mf_private, + (void (*)(char *, voidp)) create_amfs_union_node, + mp); + break; + } + } +} diff --git a/contrib/amd/amd/amq_subr.c b/contrib/amd/amd/amq_subr.c new file mode 100644 index 0000000..775ee81 --- /dev/null +++ b/contrib/amd/amd/amq_subr.c @@ -0,0 +1,501 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amq_subr.c,v 5.2.2.1 1992/02/09 15:08:18 jsp beta $ + * + */ +/* + * Auxilliary routines for amq tool + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward definitions */ +bool_t xdr_amq_mount_tree_node(XDR *xdrs, amq_mount_tree *objp); +bool_t xdr_amq_mount_subtree(XDR *xdrs, amq_mount_tree *objp); + + +voidp +amqproc_null_1_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +/* + * Return a sub-tree of mounts + */ +amq_mount_tree_p * +amqproc_mnttree_1_svc(voidp argp, struct svc_req *rqstp) +{ + static am_node *mp; + + mp = find_ap(*(char **) argp); + return (amq_mount_tree_p *) ∓ +} + + +/* + * Unmount a single node + */ +voidp +amqproc_umnt_1_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + am_node *mp = find_ap(*(char **) argp); + + if (mp) + forcibly_timeout_mp(mp); + + return (voidp) &res; +} + + +/* + * Return global statistics + */ +amq_mount_stats * +amqproc_stats_1_svc(voidp argp, struct svc_req *rqstp) +{ + return (amq_mount_stats *) &amd_stats; +} + + +/* + * Return the entire tree of mount nodes + */ +amq_mount_tree_list * +amqproc_export_1_svc(voidp argp, struct svc_req *rqstp) +{ + static amq_mount_tree_list aml; + + aml.amq_mount_tree_list_val = (amq_mount_tree_p *) &exported_ap[0]; + aml.amq_mount_tree_list_len = 1; /* XXX */ + + return &aml; +} + + +int * +amqproc_setopt_1_svc(voidp argp, struct svc_req *rqstp) +{ + static int rc; + amq_setopt *opt = (amq_setopt *) argp; + + rc = 0; + + switch (opt->as_opt) { + + case AMOPT_DEBUG: +#ifdef DEBUG + if (debug_option(opt->as_str)) +#endif /* DEBUG */ + rc = EINVAL; + break; + + case AMOPT_LOGFILE: + if (gopt.logfile && opt->as_str + && STREQ(gopt.logfile, opt->as_str)) { + if (switch_to_logfile(opt->as_str)) + rc = EINVAL; + } else { + rc = EACCES; + } + break; + + case AMOPT_XLOG: + if (switch_option(opt->as_str)) + rc = EINVAL; + break; + + case AMOPT_FLUSHMAPC: + if (amd_state == Run) { + plog(XLOG_INFO, "amq says flush cache"); + do_mapc_reload = 0; + flush_nfs_fhandle_cache((fserver *) 0); + flush_srvr_nfs_cache(); + } + break; + } + + return &rc; +} + + +amq_mount_info_list * +amqproc_getmntfs_1_svc(voidp argp, struct svc_req *rqstp) +{ + return (amq_mount_info_list *) &mfhead; /* XXX */ +} + +#ifdef ENABLE_AMQ_MOUNT +/* + * This is code that is vulnerable to IP spoofing attacks. Unless you + * absolutely need it, I suggest you do not enable it + * (using configure --enable-amq-mount) + */ +static int +ok_security(struct svc_req *rqstp) +{ + struct sockaddr_in *sin = (struct sockaddr_in *) NULL; + + if ((sin = amu_svc_getcaller(rqstp->rq_xprt)) == NULL) { + plog(XLOG_ERROR, "amu_svc_getcaller returned NULL"); + return(0); /* assume security is therefore not OK */ + } + + if (ntohs(sin->sin_port) >= 1024 || + !(sin->sin_addr.s_addr == htonl(0x7f000001) || + sin->sin_addr.s_addr == myipaddr.s_addr)) { + char dq[20]; + plog(XLOG_INFO, "AMQ request from %s.%d DENIED", + inet_dquad(dq, sin->sin_addr.s_addr), + ntohs(sin->sin_port)); + return (0); + } + + return (1); +} + + +int * +amqproc_mount_1_svc(voidp argp, struct svc_req *rqstp) +{ + static int rc; + char *s = *(amq_string *) argp; + char *cp; + + plog(XLOG_INFO, "amq requested mount of %s", s); + /* + * Minimalist security check. + */ + if (!ok_security(rqstp)) { + rc = EACCES; + return &rc; + } + /* + * Find end of key + */ + for (cp = (char *) s; *cp && (!isascii(*cp) || !isspace(*cp)); cp++) ; + + if (!*cp) { + plog(XLOG_INFO, "amqproc_mount: Invalid arguments"); + rc = EINVAL; + return &rc; + } + *cp++ = '\0'; + + /* + * Find start of value + */ + while (*cp && isascii(*cp) && isspace(*cp)) + cp++; + + root_newmap(s, cp, (char *) 0, NULL); + rc = mount_auto_node(s, (voidp) root_node); + if (rc < 0) + return 0; + return &rc; +} + +#else /* not ENABLE_AMQ_MOUNT */ + +int * +amqproc_mount_1_svc(voidp argp, struct svc_req *rqstp) +{ + static int rc; + char *s = *(amq_string *) argp; + + plog(XLOG_ERROR, "amq requested mount of %s, but code is disabled", s); + + rc = EINVAL; + return &rc; +} +#endif /* not ENABLE_AMQ_MOUNT */ + + +amq_string * +amqproc_getvers_1_svc(voidp argp, struct svc_req *rqstp) +{ + static amq_string res; + + res = get_version_string(); + return &res; +} + + +/* get PID of remote amd */ +int * +amqproc_getpid_1_svc(voidp argp, struct svc_req *rqstp) +{ + static int res; + + res = getpid(); + return &res; +} + + +/* + * XDR routines. + */ + + +bool_t +xdr_amq_setopt(XDR *xdrs, amq_setopt *objp) +{ + if (!xdr_enum(xdrs, (enum_t *) & objp->as_opt)) { + return (FALSE); + } + if (!xdr_string(xdrs, &objp->as_str, AMQ_STRLEN)) { + return (FALSE); + } + return (TRUE); +} + + +/* + * More XDR routines - Should be used for OUTPUT ONLY. + */ +bool_t +xdr_amq_mount_tree_node(XDR *xdrs, amq_mount_tree *objp) +{ + am_node *mp = (am_node *) objp; + + if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_info)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mp->am_path)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, mp->am_link ? &mp->am_link : &mp->am_mnt->mf_mount)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_ops->fs_type)) { + return (FALSE); + } + if (!xdr_long(xdrs, (long *) &mp->am_stats.s_mtime)) { + return (FALSE); + } + if (!xdr_u_short(xdrs, &mp->am_stats.s_uid)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_getattr)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_lookup)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_readdir)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_readlink)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mp->am_stats.s_statfs)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_subtree(XDR *xdrs, amq_mount_tree *objp) +{ + am_node *mp = (am_node *) objp; + + if (!xdr_amq_mount_tree_node(xdrs, objp)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) &mp->am_osib, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) &mp->am_child, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_tree(XDR *xdrs, amq_mount_tree *objp) +{ + am_node *mp = (am_node *) objp; + am_node *mnil = 0; + + if (!xdr_amq_mount_tree_node(xdrs, objp)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) &mnil, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) &mp->am_child, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_subtree)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_tree_p(XDR *xdrs, amq_mount_tree_p *objp) +{ + if (!xdr_pointer(xdrs, (char **) objp, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_tree)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_stats(XDR *xdrs, amq_mount_stats *objp) +{ + if (!xdr_int(xdrs, &objp->as_drops)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->as_stale)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->as_mok)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->as_merr)) { + return (FALSE); + } + if (!xdr_int(xdrs, &objp->as_uerr)) { + return (FALSE); + } + return (TRUE); +} + + + +bool_t +xdr_amq_mount_tree_list(XDR *xdrs, amq_mount_tree_list *objp) +{ + if (!xdr_array(xdrs, + (char **) &objp->amq_mount_tree_list_val, + (u_int *) &objp->amq_mount_tree_list_len, + ~0, + sizeof(amq_mount_tree_p), + (XDRPROC_T_TYPE) xdr_amq_mount_tree_p)) { + return (FALSE); + } + return (TRUE); +} + + + +/* + * Compute length of list + */ +bool_t +xdr_amq_mount_info_qelem(XDR *xdrs, qelem *qhead) +{ + mntfs *mf; + u_int len = 0; + + for (mf = AM_LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) { + if (!(mf->mf_ops->fs_flags & FS_AMQINFO)) + continue; + len++; + } + xdr_u_int(xdrs, &len); + + /* + * Send individual data items + */ + for (mf = AM_LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) { + int up; + if (!(mf->mf_ops->fs_flags & FS_AMQINFO)) + continue; + + if (!xdr_amq_string(xdrs, &mf->mf_ops->fs_type)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mf->mf_mount)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mf->mf_info)) { + return (FALSE); + } + if (!xdr_amq_string(xdrs, &mf->mf_server->fs_host)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mf->mf_error)) { + return (FALSE); + } + if (!xdr_int(xdrs, &mf->mf_refc)) { + return (FALSE); + } + if (mf->mf_server->fs_flags & FSF_ERROR) + up = 0; + else + switch (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) { + case FSF_DOWN | FSF_VALID: + up = 0; + break; + case FSF_VALID: + up = 1; + break; + default: + up = -1; + break; + } + if (!xdr_int(xdrs, &up)) { + return (FALSE); + } + } + return (TRUE); +} + + +bool_t +xdr_pri_free(XDRPROC_T_TYPE xdr_args, caddr_t args_ptr) +{ + XDR xdr; + + xdr.x_op = XDR_FREE; + return ((*xdr_args) (&xdr, (caddr_t *) args_ptr)); +} diff --git a/contrib/amd/amd/amq_svc.c b/contrib/amd/amd/amq_svc.c new file mode 100644 index 0000000..5e4c9fd --- /dev/null +++ b/contrib/amd/amd/amq_svc.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amq_svc.c,v 5.2.2.1 1992/02/09 15:09:26 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* typedefs */ +typedef char *(*amqsvcproc_t)(voidp, struct svc_req *); + + +void +amq_program_1(struct svc_req *rqstp, SVCXPRT *transp) +{ + union { + amq_string amqproc_mnttree_1_arg; + amq_string amqproc_umnt_1_arg; + amq_setopt amqproc_setopt_1_arg; + amq_string amqproc_mount_1_arg; + } argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + amqsvcproc_t local; + + switch (rqstp->rq_proc) { + + case AMQPROC_NULL: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (amqsvcproc_t) amqproc_null_1_svc; + break; + + case AMQPROC_MNTTREE: + xdr_argument = (xdrproc_t) xdr_amq_string; + xdr_result = (xdrproc_t) xdr_amq_mount_tree_p; + local = (amqsvcproc_t) amqproc_mnttree_1_svc; + break; + + case AMQPROC_UMNT: + xdr_argument = (xdrproc_t) xdr_amq_string; + xdr_result = (xdrproc_t) xdr_void; + local = (amqsvcproc_t) amqproc_umnt_1_svc; + break; + + case AMQPROC_STATS: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_amq_mount_stats; + local = (amqsvcproc_t) amqproc_stats_1_svc; + break; + + case AMQPROC_EXPORT: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_amq_mount_tree_list; + local = (amqsvcproc_t) amqproc_export_1_svc; + break; + + case AMQPROC_SETOPT: + xdr_argument = (xdrproc_t) xdr_amq_setopt; + xdr_result = (xdrproc_t) xdr_int; + local = (amqsvcproc_t) amqproc_setopt_1_svc; + break; + + case AMQPROC_GETMNTFS: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_amq_mount_info_qelem; + local = (amqsvcproc_t) amqproc_getmntfs_1_svc; + break; + + case AMQPROC_MOUNT: + xdr_argument = (xdrproc_t) xdr_amq_string; + xdr_result = (xdrproc_t) xdr_int; + local = (amqsvcproc_t) amqproc_mount_1_svc; + break; + + case AMQPROC_GETVERS: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_amq_string; + local = (amqsvcproc_t) amqproc_getvers_1_svc; + break; + + case AMQPROC_GETPID: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_int; + local = (amqsvcproc_t) amqproc_getpid_1_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + + memset((char *) &argument, 0, sizeof(argument)); + if (!svc_getargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) & argument)) { + svcerr_decode(transp); + return; + } + + result = (*local) (&argument, rqstp); + + if (result != NULL && !svc_sendreply(transp, + (XDRPROC_T_TYPE) xdr_result, + result)) { + svcerr_systemerr(transp); + } + + if (!svc_freeargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) & argument)) { + plog(XLOG_FATAL, "unable to free rpc arguments in amqprog_1"); + going_down(1); + } +} diff --git a/contrib/amd/amd/autil.c b/contrib/amd/amd/autil.c new file mode 100644 index 0000000..ca089bd --- /dev/null +++ b/contrib/amd/amd/autil.c @@ -0,0 +1,418 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: autil.c,v 5.2.2.2 1992/03/07 17:52:06 jsp Exp $ + * + */ + +/* + * utilities specified to amd, taken out of the older amd/util.c. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +int NumChild = 0; /* number of children of primary amd */ +static char invalid_keys[] = "\"'!;@ \t\n"; + +#ifdef HAVE_TRANSPORT_TYPE_TLI +# define PARENT_USLEEP_TIME 100000 /* 0.1 seconds */ +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + +char * +strealloc(char *p, char *s) +{ + int len = strlen(s) + 1; + + p = (char *) xrealloc((voidp) p, len); + + strcpy(p, s); +#ifdef DEBUG_MEM + malloc_verify(); +#endif /* DEBUG_MEM */ + return p; +} + + +char ** +strsplit(char *s, int ch, int qc) +{ + char **ivec; + int ic = 0; + int done = 0; + + ivec = (char **) xmalloc((ic + 1) * sizeof(char *)); + + while (!done) { + char *v; + + /* + * skip to split char + */ + while (*s && (ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch)) + *s++ = '\0'; + + /* + * End of string? + */ + if (!*s) + break; + + /* + * remember start of string + */ + v = s; + + /* + * skip to split char + */ + while (*s && !(ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch)) { + if (*s++ == qc) { + /* + * Skip past string. + */ + s++; + while (*s && *s != qc) + s++; + if (*s == qc) + s++; + } + } + + if (!*s) + done = 1; + *s++ = '\0'; + + /* + * save string in new ivec slot + */ + ivec[ic++] = v; + ivec = (char **) xrealloc((voidp) ivec, (ic + 1) * sizeof(char *)); +#ifdef DEBUG + amuDebug(D_STR) + plog(XLOG_DEBUG, "strsplit saved \"%s\"", v); +#endif /* DEBUG */ + } + +#ifdef DEBUG + amuDebug(D_STR) + plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic); +#endif /* DEBUG */ + + ivec[ic] = 0; + + return ivec; +} + + +/* + * Strip off the trailing part of a domain + * to produce a short-form domain relative + * to the local host domain. + * Note that this has no effect if the domain + * names do not have the same number of + * components. If that restriction proves + * to be a problem then the loop needs recoding + * to skip from right to left and do partial + * matches along the way -- ie more expensive. + */ +static void +domain_strip(char *otherdom, char *localdom) +{ + char *p1, *p2; + + if ((p1 = strchr(otherdom, '.')) && + (p2 = strchr(localdom, '.')) && + STREQ(p1 + 1, p2 + 1)) + *p1 = '\0'; +} + + +/* + * Normalize a host name + */ +void +host_normalize(char **chp) +{ + /* + * Normalize hosts is used to resolve host name aliases + * and replace them with the standard-form name. + * Invoked with "-n" command line option. + */ + if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) { + struct hostent *hp; + clock_valid = 0; + hp = gethostbyname(*chp); + if (hp && hp->h_addrtype == AF_INET) { +#ifdef DEBUG + dlog("Hostname %s normalized to %s", *chp, hp->h_name); +#endif /* DEBUG */ + *chp = strealloc(*chp, (char *) hp->h_name); + } + } + domain_strip(*chp, hostd); +} + + + +/* + * Keys are not allowed to contain " ' ! or ; to avoid + * problems with macro expansions. + */ +int +valid_key(char *key) +{ + while (*key) + if (strchr(invalid_keys, *key++)) + return FALSE; + return TRUE; +} + + +void +forcibly_timeout_mp(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + /* + * Arrange to timeout this node + */ + if (mf && ((mp->am_flags & AMF_ROOT) || + (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)))) { + if (!(mf->mf_flags & MFF_UNMOUNTING)) + plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path); + } else { + plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path); + mp->am_flags &= ~AMF_NOTIMEOUT; + mp->am_ttl = clocktime(); + reschedule_timeout_mp(); + } +} + + +void +mf_mounted(mntfs *mf) +{ + int quoted; + int wasmounted = mf->mf_flags & MFF_MOUNTED; + + if (!wasmounted) { + /* + * If this is a freshly mounted + * filesystem then update the + * mntfs structure... + */ + mf->mf_flags |= MFF_MOUNTED; + mf->mf_error = 0; + + /* + * Do mounted callback + */ + if (mf->mf_ops->mounted) { + (*mf->mf_ops->mounted) (mf); + } + mf->mf_fo = 0; + } + + /* + * Log message + */ + quoted = strchr(mf->mf_info, ' ') != 0; + plog(XLOG_INFO, "%s%s%s %s fstype %s on %s", + quoted ? "\"" : "", + mf->mf_info, + quoted ? "\"" : "", + wasmounted ? "referenced" : "mounted", + mf->mf_ops->fs_type, mf->mf_mount); +} + + +void +am_mounted(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + mf_mounted(mf); + + /* + * Patch up path for direct mounts + */ + if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &amfs_direct_ops) + mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", "."); + + /* + * Check whether this mount should be cached permanently + */ + if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) { + mp->am_flags |= AMF_NOTIMEOUT; + } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') { + mp->am_flags |= AMF_NOTIMEOUT; + } else { + mntent_t mnt; + if (mf->mf_mopts) { + mnt.mnt_opts = mf->mf_mopts; + if (hasmntopt(&mnt, "nounmount")) + mp->am_flags |= AMF_NOTIMEOUT; + if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0) + mp->am_timeo = gopt.am_timeo; + } + } + + /* + * If this node is a symlink then + * compute the length of the returned string. + */ + if (mp->am_fattr.na_type == NFLNK) + mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount); + + /* + * Record mount time + */ + mp->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime = clocktime(); + new_ttl(mp); + + /* + * Update mtime of parent node + */ + if (mp->am_parent && mp->am_parent->am_mnt) + mp->am_parent->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime; + + /* + * Now, if we can, do a reply to our NFS client here + * to speed things up. + */ + quick_reply(mp, 0); + + /* + * Update stats + */ + amd_stats.d_mok++; +} + + +int +mount_node(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + int error = 0; + + mf->mf_flags |= MFF_MOUNTING; + error = (*mf->mf_ops->mount_fs) (mp); + + mf = mp->am_mnt; + if (error >= 0) + mf->mf_flags &= ~MFF_MOUNTING; + if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) { + /* ...but see ifs_mount */ + am_mounted(mp); + } + + return error; +} + + +void +am_unmounted(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + + if (!foreground) /* firewall - should never happen */ + return; + + /* + * Do unmounted callback + */ + if (mf->mf_ops->umounted) + (*mf->mf_ops->umounted) (mp); + + /* + * Update mtime of parent node + */ + if (mp->am_parent && mp->am_parent->am_mnt) + mp->am_parent->am_fattr.na_mtime.nt_seconds = clocktime(); + + free_map(mp); +} + + +/* + * Fork the automounter + * + * TODO: Need a better strategy for handling errors + */ +static int +dofork(void) +{ + int pid; + +top: + pid = fork(); + + if (pid < 0) { /* fork error, retry in 1 second */ + sleep(1); + goto top; + } + if (pid == 0) { /* child process (foreground==false) */ + mypid = getpid(); + foreground = 0; + } else { /* parent process, has one more child */ + NumChild++; + } + + return pid; +} + + +int +background(void) +{ + int pid = dofork(); + + if (pid == 0) { +#ifdef DEBUG + dlog("backgrounded"); +#endif /* DEBUG */ + foreground = 0; + } + return pid; +} diff --git a/contrib/amd/amd/clock.c b/contrib/amd/amd/clock.c new file mode 100644 index 0000000..3c0494a --- /dev/null +++ b/contrib/amd/amd/clock.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: clock.c,v 5.2.2.1 1992/02/09 15:08:20 jsp beta $ + * + */ + +/* + * Callouts. + * + * Modelled on kernel object of the same name. + * See usual references. + * + * Use of a heap-based mechanism was rejected: + * 1. more complex implementation needed. + * 2. not obvious that a list is too slow for Amd. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +int timeout(u_int secs, void (*fn) (voidp), voidp closure); +void reschedule_timeouts(time_t now, time_t then); + +typedef struct callout callout; +struct callout { + callout *c_next; /* List of callouts */ + void (*c_fn) (voidp); /* Function to call */ + voidp c_closure; /* Closure to pass to call */ + time_t c_time; /* Time of call */ + int c_id; /* Unique identifier */ +}; + +static callout callouts; /* List of pending callouts */ +static callout *free_callouts; /* Cache of free callouts */ +static int nfree_callouts; /* Number on free list */ +static int callout_id; /* Next free callout identifier */ + +time_t next_softclock; /* Time of next call to softclock() */ + + +/* + * Number of callout slots we keep on the free list + */ +#define CALLOUT_FREE_SLOP 10 + +/* + * Global assumption: valid id's are non-zero. + */ +#define CID_ALLOC(struct ) (++callout_id) +#define CID_UNDEF (0) + + +static callout * +alloc_callout(void) +{ + callout *cp = free_callouts; + + if (cp) { + --nfree_callouts; + free_callouts = free_callouts->c_next; + return cp; + } + return ALLOC(struct callout); +} + + +static void +free_callout(callout *cp) +{ + if (nfree_callouts > CALLOUT_FREE_SLOP) { + XFREE(cp); + } else { + cp->c_next = free_callouts; + free_callouts = cp; + nfree_callouts++; + } +} + + +/* + * Schedule a callout. + * + * (*fn)(closure) will be called at clocktime() + secs + */ +int +timeout(u_int secs, void (*fn) (voidp), voidp closure) +{ + callout *cp, *cp2; + time_t t = clocktime() + secs; + + /* + * Allocate and fill in a new callout structure + */ + callout *cpnew = alloc_callout(); + cpnew->c_closure = closure; + cpnew->c_fn = fn; + cpnew->c_time = t; + cpnew->c_id = CID_ALLOC(struct ); + + if (t < next_softclock) + next_softclock = t; + + /* + * Find the correct place in the list + */ + for (cp = &callouts; (cp2 = cp->c_next); cp = cp2) + if (cp2->c_time >= t) + break; + + /* + * And link it in + */ + cp->c_next = cpnew; + cpnew->c_next = cp2; + + /* + * Return callout identifier + */ + return cpnew->c_id; +} + + +/* + * De-schedule a callout + */ +void +untimeout(int id) +{ + callout *cp, *cp2; + for (cp = &callouts; (cp2 = cp->c_next); cp = cp2) { + if (cp2->c_id == id) { + cp->c_next = cp2->c_next; + free_callout(cp2); + break; + } + } +} + + +/* + * Reschedule after clock changed + */ +void +reschedule_timeouts(time_t now, time_t then) +{ + callout *cp; + + for (cp = callouts.c_next; cp; cp = cp->c_next) { + if (cp->c_time >= now && cp->c_time <= then) { + plog(XLOG_WARNING, "job %d rescheduled to run immediately", cp->c_id); +#ifdef DEBUG + dlog("rescheduling job %d back %d seconds", cp->c_id, cp->c_time - now); +#endif /* DEBUG */ + next_softclock = cp->c_time = now; + } + } +} + + +/* + * Clock handler + */ +int +softclock(void) +{ + time_t now; + callout *cp; + + do { + if (task_notify_todo) + do_task_notify(); + + now = clocktime(); + + /* + * While there are more callouts waiting... + */ + while ((cp = callouts.c_next) && cp->c_time <= now) { + /* + * Extract first from list, save fn & closure and + * unlink callout from list and free. + * Finally call function. + * + * The free is done first because + * it is quite common that the + * function will call timeout() + * and try to allocate a callout + */ + void (*fn) (voidp) = cp->c_fn; + voidp closure = cp->c_closure; + + callouts.c_next = cp->c_next; + free_callout(cp); + (*fn) (closure); + } + + } while (task_notify_todo); + + /* + * Return number of seconds to next event, + * or 0 if there is no event. + */ + if ((cp = callouts.c_next)) + return cp->c_time - now; + return 0; +} diff --git a/contrib/amd/amd/conf.c b/contrib/amd/amd/conf.c new file mode 100644 index 0000000..a97b1b1 --- /dev/null +++ b/contrib/amd/amd/conf.c @@ -0,0 +1,939 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: conf.c,v 5.2.2.1 1992/02/09 15:08:23 jsp beta $ + * + */ + +/* + * Functions to handle the configuration file. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* + * MACROS: + */ +/* Turn on to show some info about maps being configured */ +/* #define DEBUG_CONF */ + +/* + * TYPEDEFS: + */ +typedef int (*OptFuncPtr)(const char *); + +/* + * STRUCTURES: + */ +struct _func_map { + char *name; + OptFuncPtr func; +}; + +/* + * FORWARD DECLARATIONS: + */ +static int gopt_arch(const char *val); +static int gopt_auto_dir(const char *val); +static int gopt_browsable_dirs(const char *val); +static int gopt_cache_duration(const char *val); +static int gopt_cluster(const char *val); +static int gopt_debug_options(const char *val); +static int gopt_dismount_interval(const char *val); +static int gopt_fully_qualified_hosts(const char *val); +static int gopt_hesiod_base(const char *val); +static int gopt_karch(const char *val); +static int gopt_ldap_base(const char *val); +static int gopt_ldap_cache_maxmem(const char *val); +static int gopt_ldap_cache_seconds(const char *val); +static int gopt_ldap_hostports(const char *val); +static int gopt_local_domain(const char *val); +static int gopt_log_file(const char *val); +static int gopt_log_options(const char *val); +static int gopt_map_options(const char *val); +static int gopt_map_type(const char *val); +static int gopt_mount_type(const char *val); +static int gopt_pid_file(const char *val); +static int gopt_portmap_program(const char *val); +static int gopt_nfs_retransmit_counter(const char *val); +static int gopt_nfs_retry_interval(const char *val); +static int gopt_nis_domain(const char *val); +static int gopt_normalize_hostnames(const char *val); +static int gopt_os(const char *val); +static int gopt_osver(const char *val); +static int gopt_plock(const char *val); +static int gopt_print_pid(const char *val); +static int gopt_print_version(const char *val); +static int gopt_restart_mounts(const char *val); +static int gopt_search_path(const char *val); +static int gopt_selectors_on_default(const char *val); +static int gopt_show_statfs_entries(const char *val); +static int gopt_unmount_on_exit(const char *val); +static int process_global_option(const char *key, const char *val); +static int process_regular_map(cf_map_t *cfm); +static int process_regular_option(const char *section, const char *key, const char *val, cf_map_t *cfm); +static int ropt_browsable_dirs(const char *val, cf_map_t *cfm); +static int ropt_map_name(const char *val, cf_map_t *cfm); +static int ropt_map_options(const char *val, cf_map_t *cfm); +static int ropt_map_type(const char *val, cf_map_t *cfm); +static int ropt_mount_type(const char *val, cf_map_t *cfm); +static int ropt_search_path(const char *val, cf_map_t *cfm); +static int ropt_tag(const char *val, cf_map_t *cfm); +static void reset_cf_map(cf_map_t *cfm); + + +/* + * STATIC VARIABLES: + */ +static cf_map_t cur_map; +static struct _func_map glob_functable[] = { + {"arch", gopt_arch}, + {"auto_dir", gopt_auto_dir}, + {"browsable_dirs", gopt_browsable_dirs}, + {"cache_duration", gopt_cache_duration}, + {"cluster", gopt_cluster}, + {"debug_options", gopt_debug_options}, + {"dismount_interval", gopt_dismount_interval}, + {"fully_qualified_hosts", gopt_fully_qualified_hosts}, + {"hesiod_base", gopt_hesiod_base}, + {"karch", gopt_karch}, + {"ldap_base", gopt_ldap_base}, + {"ldap_cache_maxmem", gopt_ldap_cache_maxmem}, + {"ldap_cache_seconds", gopt_ldap_cache_seconds}, + {"ldap_hostports", gopt_ldap_hostports}, + {"local_domain", gopt_local_domain}, + {"log_file", gopt_log_file}, + {"log_options", gopt_log_options}, + {"map_options", gopt_map_options}, + {"map_type", gopt_map_type}, + {"mount_type", gopt_mount_type}, + {"pid_file", gopt_pid_file}, + {"portmap_program", gopt_portmap_program}, + {"nfs_retransmit_counter", gopt_nfs_retransmit_counter}, + {"nfs_retry_interval", gopt_nfs_retry_interval}, + {"nis_domain", gopt_nis_domain}, + {"normalize_hostnames", gopt_normalize_hostnames}, + {"os", gopt_os}, + {"osver", gopt_osver}, + {"plock", gopt_plock}, + {"print_pid", gopt_print_pid}, + {"print_version", gopt_print_version}, + {"restart_mounts", gopt_restart_mounts}, + {"search_path", gopt_search_path}, + {"selectors_on_default", gopt_selectors_on_default}, + {"show_statfs_entries", gopt_show_statfs_entries}, + {"unmount_on_exit", gopt_unmount_on_exit}, + {NULL, NULL} +}; + + +/* + * Reset a map. + */ +static void +reset_cf_map(cf_map_t *cfm) +{ + if (!cfm) + return; + + if (cfm->cfm_dir) { + XFREE(cfm->cfm_dir); + cfm->cfm_dir = NULL; + } + + if (cfm->cfm_name) { + XFREE(cfm->cfm_name); + cfm->cfm_name = NULL; + } + + if (cfm->cfm_tag) { + XFREE(cfm->cfm_tag); + cfm->cfm_tag = NULL; + } + + /* + * reset/initialize a regular map's flags and other variables from the + * global ones, so that they are applied to all maps. Of course, each map + * can then override the flags individually. + * + * NOTES: + * (1): Will only work for maps that appear after [global]. + * (2): Also be careful not to free() a global option. + * (3): I'm doing direct char* pointer comparison, and not strcmp(). This + * is correct! + */ + + /* initialize map_type from [global] */ + if (cfm->cfm_type && cfm->cfm_type != gopt.map_type) + XFREE(cfm->cfm_type); + cfm->cfm_type = gopt.map_type; + + /* initialize map_opts from [global] */ + if (cfm->cfm_opts && cfm->cfm_opts != gopt.map_options) + XFREE(cfm->cfm_opts); + cfm->cfm_opts = gopt.map_options; + + /* initialize search_path from [global] */ + if (cfm->cfm_search_path && cfm->cfm_search_path != gopt.search_path) + XFREE(cfm->cfm_search_path); + cfm->cfm_search_path = gopt.search_path; + + /* + * Initialize flags that are common both to [global] and a local map. + */ + cfm->cfm_flags = gopt.flags & (CFM_BROWSABLE_DIRS | + CFM_BROWSABLE_DIRS_FULL | + CFM_MOUNT_TYPE_AUTOFS | + CFM_ENABLE_DEFAULT_SELECTORS); +} + + +/* + * Process configuration file options. + * Return 0 if OK, 1 otherwise. + */ +int +set_conf_kv(const char *section, const char *key, const char *val) +{ + int ret; + +#ifdef DEBUG_CONF + fprintf(stderr,"set_conf_kv: section=%s, key=%s, val=%s\n", + section, key, val); +#endif /* DEBUG_CONF */ + + /* + * If global section, process them one at a time. + */ + if (STREQ(section, "global")) { + /* + * Check if a regular map was configured before "global", + * and process it as needed. + */ + if (cur_map.cfm_dir) { + fprintf(stderr,"processing regular map \"%s\" before global one.\n", + section); + ret = process_regular_map(&cur_map); /* will reset map */ + if (ret != 0) + return ret; + } + + /* process the global option first */ + ret = process_global_option(key, val); + + /* reset default options for regular maps from just updated globals */ + if (ret == 0) + reset_cf_map(&cur_map); + + /* return status from the processing of the global option */ + return ret; + } + + /* + * otherwise save options and process a single map all at once. + */ + + /* check if we found a new map, so process one already collected */ + if (cur_map.cfm_dir && !STREQ(cur_map.cfm_dir, section)) { + ret = process_regular_map(&cur_map); /* will reset map */ + if (ret != 0) + return ret; + } + + /* now process a single entry of a regular map */ + return process_regular_option(section, key, val, &cur_map); +} + + +/* + * Process global section of configuration file options. + * Return 0 upon success, 1 otherwise. + */ +static int +process_global_option(const char *key, const char *val) +{ + struct _func_map *gfp; + + /* ensure that val is valid */ + if (!val || val[0] == '\0') + return 1; + + /* + * search for global function. + */ + for (gfp = glob_functable; gfp->name; gfp++) + if (FSTREQ(gfp->name, key)) + return (gfp->func)(val); + + fprintf(stderr, "conf: unknown global key: \"%s\"\n", key); + return 1; /* failed to match any command */ +} + + +static int +gopt_arch(const char *val) +{ + gopt.arch = strdup((char *)val); + return 0; +} + + +static int +gopt_auto_dir(const char *val) +{ + gopt.auto_dir = strdup((char *)val); + return 0; +} + + +static int +gopt_browsable_dirs(const char *val) +{ + if (STREQ(val, "full")) { + gopt.flags |= CFM_BROWSABLE_DIRS_FULL; + return 0; + } else if (STREQ(val, "yes")) { + gopt.flags |= CFM_BROWSABLE_DIRS; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_BROWSABLE_DIRS; + return 0; + } + + fprintf(stderr, "conf: unknown value to browsable_dirs \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_cache_duration(const char *val) +{ + gopt.am_timeo = atoi(val); + if (gopt.am_timeo <= 0) + gopt.am_timeo = AM_TTL; + return 0; +} + + +static int +gopt_cluster(const char *val) +{ + gopt.cluster = strdup((char *)val); + return 0; +} + + +static int +gopt_debug_options(const char *val) +{ +#ifdef DEBUG + usage += debug_option(strdup((char *)val)); + return 0; +#else /* not DEBUG */ + fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n", + progname); + return 1; +#endif /* not DEBUG */ +} + + +static int +gopt_dismount_interval(const char *val) +{ + gopt.am_timeo_w = atoi(val); + if (gopt.am_timeo_w <= 0) + gopt.am_timeo_w = AM_TTL_W; + return 0; +} + + +static int +gopt_fully_qualified_hosts(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_FULLY_QUALIFIED_HOSTS; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_FULLY_QUALIFIED_HOSTS; + return 0; + } + + fprintf(stderr, "conf: unknown value to fully_qualified_hosts \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_hesiod_base(const char *val) +{ +#ifdef HAVE_MAP_HESIOD + gopt.hesiod_base = strdup((char *)val); + return 0; +#else /* not HAVE_MAP_HESIOD */ + fprintf(stderr, "conf: hesiod_base option ignored. No Hesiod support available.\n"); + return 1; +#endif /* not HAVE_MAP_HESIOD */ +} + + +static int +gopt_karch(const char *val) +{ + gopt.karch = strdup((char *)val); + return 0; +} + + +static int +gopt_pid_file(const char *val) +{ + gopt.pid_file = strdup((char *)val); + return 0; +} + + +static int +gopt_local_domain(const char *val) +{ + gopt.sub_domain = strdup((char *)val); + return 0; +} + + +static int +gopt_ldap_base(const char *val) +{ +#ifdef HAVE_MAP_LDAP + gopt.ldap_base = strdup((char *)val); + return 0; +#else /* not HAVE_MAP_LDAP */ + fprintf(stderr, "conf: ldap_base option ignored. No LDAP support available.\n"); + return 1; +#endif /* not HAVE_MAP_LDAP */ +} + + +static int +gopt_ldap_cache_seconds(const char *val) +{ +#ifdef HAVE_MAP_LDAP + char *end; + + gopt.ldap_cache_seconds = strtol((char *)val, &end, 10); + if (end == val) { + fprintf(stderr, "conf: bad LDAP cache (seconds) option: %s\n",val); + return 1; + } + return 0; +#else /* not HAVE_MAP_LDAP */ + fprintf(stderr, "conf: ldap_cache option ignored. No LDAP support available.\n"); + return 1; +#endif /* not HAVE_MAP_LDAP */ +} + + +static int +gopt_ldap_cache_maxmem(const char *val) +{ +#ifdef HAVE_MAP_LDAP + char *end; + + gopt.ldap_cache_maxmem = strtol((char *)val, &end, 10); + if (end == val) { + fprintf(stderr, "conf: bad LDAP cache (maxmem) option: %s\n",val); + return 1; + } + return 0; +#else /* not HAVE_MAP_LDAP */ + fprintf(stderr, "conf: ldap_cache option ignored. No LDAP support available.\n"); + return 1; +#endif /* not HAVE_MAP_LDAP */ +} + + +static int +gopt_ldap_hostports(const char *val) +{ +#ifdef HAVE_MAP_LDAP + gopt.ldap_hostports = strdup((char *)val); + return 0; +#else /* not HAVE_MAP_LDAP */ + fprintf(stderr, "conf: ldap_hostports option ignored. No LDAP support available.\n"); + return 1; +#endif /* not HAVE_MAP_LDAP */ + +} + + +static int +gopt_log_file(const char *val) +{ + gopt.logfile = strdup((char *)val); + return 0; +} + + +static int +gopt_log_options(const char *val) +{ + usage += switch_option(strdup((char *)val)); + return 0; +} + + +static int +gopt_map_options(const char *val) +{ + gopt.map_options = strdup((char *)val); + return 0; +} + + +static int +gopt_map_type(const char *val) +{ + gopt.map_type = strdup((char *)val); + return 0; +} + + +static int +gopt_mount_type(const char *val) +{ + if (STREQ(val, "autofs")) { +#ifdef HAVE_FS_AUTOFS + gopt.flags |= CFM_MOUNT_TYPE_AUTOFS; + return 0; +#else /* not HAVE_FS_AUTOFS */ + fprintf(stderr, "conf: no autofs support available\n"); + return 1; +#endif /* not HAVE_FS_AUTOFS */ + } else if (STREQ(val, "nfs")) { + gopt.flags &= ~CFM_MOUNT_TYPE_AUTOFS; + return 0; + } + + fprintf(stderr, "conf: unknown value to mount_type \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_portmap_program(const char *val) +{ + gopt.portmap_program = atoi(val); + /* + * allow alternate program numbers to be no more than 10 offset from + * official amd program number (300019). + */ + if (gopt.portmap_program < AMQ_PROGRAM || + gopt.portmap_program > AMQ_PROGRAM + 10) { + gopt.portmap_program = AMQ_PROGRAM; + set_amd_program_number(gopt.portmap_program); + fprintf(stderr, "conf: illegal amd program numver \"%s\"\n", val); + return 1; + } + + set_amd_program_number(gopt.portmap_program); + return 0; /* all is OK */ +} + + +static int +gopt_nfs_retransmit_counter(const char *val) +{ + gopt.amfs_auto_retrans = atoi(val); + return 0; +} + + +static int +gopt_nfs_retry_interval(const char *val) +{ + gopt.amfs_auto_timeo = atoi(val); + return 0; +} + + +static int +gopt_nis_domain(const char *val) +{ +#ifdef HAVE_MAP_NIS + gopt.nis_domain = strdup((char *)val); + return 0; +#else /* not HAVE_MAP_NIS */ + fprintf(stderr, "conf: nis_domain option ignored. No NIS support available.\n"); + return 1; +#endif /* not HAVE_MAP_NIS */ +} + + +static int +gopt_normalize_hostnames(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_NORMALIZE_HOSTNAMES; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_NORMALIZE_HOSTNAMES; + return 0; + } + + fprintf(stderr, "conf: unknown value to normalize_hostnames \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_os(const char *val) +{ + gopt.op_sys = strdup((char *)val); + return 0; +} + + +static int +gopt_osver(const char *val) +{ + gopt.op_sys_ver = strdup((char *)val); + return 0; +} + + +static int +gopt_plock(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_PROCESS_LOCK; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_PROCESS_LOCK; + return 0; + } + + fprintf(stderr, "conf: unknown value to plock \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_print_pid(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_PRINT_PID; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_PRINT_PID; + return 0; + } + + fprintf(stderr, "conf: unknown value to print_pid \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_print_version(const char *val) +{ + if (STREQ(val, "yes")) { + fputs(get_version_string(), stderr); + return 0; + } else if (STREQ(val, "no")) { + return 0; + } + + fprintf(stderr, "conf: unknown value to print_version \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_restart_mounts(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_RESTART_EXISTING_MOUNTS; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_RESTART_EXISTING_MOUNTS; + return 0; + } + + fprintf(stderr, "conf: unknown value to restart_mounts \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_search_path(const char *val) +{ + gopt.search_path = strdup((char *)val); + return 0; +} + + +static int +gopt_selectors_on_default(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_ENABLE_DEFAULT_SELECTORS; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_ENABLE_DEFAULT_SELECTORS; + return 0; + } + + fprintf(stderr, "conf: unknown value to enable_default_selectors \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_show_statfs_entries(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_SHOW_STATFS_ENTRIES; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_SHOW_STATFS_ENTRIES; + return 0; + } + + fprintf(stderr, "conf: unknown value to show_statfs_entries \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +gopt_unmount_on_exit(const char *val) +{ + if (STREQ(val, "yes")) { + gopt.flags |= CFM_UNMOUNT_ON_EXIT; + return 0; + } else if (STREQ(val, "no")) { + gopt.flags &= ~CFM_UNMOUNT_ON_EXIT; + return 0; + } + + fprintf(stderr, "conf: unknown value to unmount_on_exit \"%s\"\n", val); + return 1; /* unknown value */ +} + + +/* + * Collect one entry for a regular map + */ +static int +process_regular_option(const char *section, const char *key, const char *val, cf_map_t *cfm) +{ + /* ensure that val is valid */ + if (!section || section[0] == '\0' || + !key || key[0] == '\0' || + !val || val[0] == '\0' || + !cfm) { + fprintf(stderr, "conf: process_regular_option: null entries\n"); + return 1; + } + + /* check if initializing a new map */ + if (!cfm->cfm_dir) + cfm->cfm_dir = strdup((char *)section); + + /* check for each possible field */ + if (STREQ(key, "browsable_dirs")) + return ropt_browsable_dirs(val, cfm); + + if (STREQ(key, "map_name")) + return ropt_map_name(val, cfm); + + if (STREQ(key, "map_options")) + return ropt_map_options(val, cfm); + + if (STREQ(key, "map_type")) + return ropt_map_type(val, cfm); + + if (STREQ(key, "mount_type")) + return ropt_mount_type(val, cfm); + + if (STREQ(key, "search_path")) + return ropt_search_path(val, cfm); + + if (STREQ(key, "tag")) + return ropt_tag(val, cfm); + + fprintf(stderr, "conf: unknown regular key \"%s\" for section \"%s\"\n", + key, section); + return 1; /* failed to match any command */ +} + + +static int +ropt_browsable_dirs(const char *val, cf_map_t *cfm) +{ + if (STREQ(val, "full")) { + cfm->cfm_flags |= CFM_BROWSABLE_DIRS_FULL; + return 0; + } else if (STREQ(val, "yes")) { + cfm->cfm_flags |= CFM_BROWSABLE_DIRS; + return 0; + } else if (STREQ(val, "no")) { + cfm->cfm_flags &= ~CFM_BROWSABLE_DIRS; + return 0; + } + + fprintf(stderr, "conf: unknown value to browsable_dirs \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +ropt_map_name(const char *val, cf_map_t *cfm) +{ + cfm->cfm_name = strdup((char *)val); + return 0; +} + + +static int +ropt_map_options(const char *val, cf_map_t *cfm) +{ + cfm->cfm_opts = strdup((char *)val); + return 0; +} + + +static int +ropt_map_type(const char *val, cf_map_t *cfm) +{ + cfm->cfm_type = strdup((char *)val); + return 0; +} + + +static int +ropt_mount_type(const char *val, cf_map_t *cfm) +{ + if (STREQ(val, "autofs")) { +#ifdef HAVE_FS_AUTOFS + cfm->cfm_flags |= CFM_MOUNT_TYPE_AUTOFS; + return 0; +#else /* not HAVE_FS_AUTOFS */ + fprintf(stderr, "conf: no autofs support available\n"); + return 1; +#endif /* not HAVE_FS_AUTOFS */ + } else if (STREQ(val, "nfs")) { + cfm->cfm_flags &= ~CFM_MOUNT_TYPE_AUTOFS; + return 0; + } + + fprintf(stderr, "conf: unknown value to mount_type \"%s\"\n", val); + return 1; /* unknown value */ +} + + +static int +ropt_search_path(const char *val, cf_map_t *cfm) +{ + cfm->cfm_search_path = strdup((char *)val); + return 0; +} + + +static int +ropt_tag(const char *val, cf_map_t *cfm) +{ + cfm->cfm_tag = strdup((char *)val); + return 0; +} + + +/* + * Process one collected map. + */ +static int +process_regular_map(cf_map_t *cfm) +{ + + if (!cfm->cfm_name) { + fprintf(stderr, "conf: map_name must be defined for map \"%s\"\n", cfm->cfm_dir); + return 1; + } + /* + * If map has no tag defined, process the map. + * If no conf_tag was set in amd -T, process all untagged entries. + * If a tag is defined, then process it only if it matches the map tag. + */ + if (!cfm->cfm_tag || + (conf_tag && STREQ(cfm->cfm_tag, conf_tag))) { +#ifdef DEBUG_CONF + fprintf(stderr, "processing map %s (flags=0x%x)...\n", + cfm->cfm_dir, cfm->cfm_flags); +#endif /* DEBUG_CONF */ + root_newmap(cfm->cfm_dir, + cfm->cfm_opts ? cfm->cfm_opts : "", + cfm->cfm_name, + cfm); + } else { + fprintf(stderr, "skipping map %s...\n", cfm->cfm_dir); + } + + reset_cf_map(cfm); + return 0; +} + + +/* + * Process last map in conf file (if any) + */ +int +process_last_regular_map(void) +{ + /* + * If the amd.conf file only has a [global] section (pretty useless + * IMHO), do not try to process a map that does not exist. + */ + if (!cur_map.cfm_dir) + return 0; + return process_regular_map(&cur_map); +} diff --git a/contrib/amd/amd/conf_parse.y b/contrib/amd/amd/conf_parse.y new file mode 100644 index 0000000..2a9877a --- /dev/null +++ b/contrib/amd/amd/conf_parse.y @@ -0,0 +1,159 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: conf_parse.y,v 5.2.2.1 1992/02/09 15:09:35 jsp beta $ + * + */ + +%{ +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +extern char *yytext; +extern int yylineno; +extern int yylex(void); + +static int yyerror(const char *s); +static int retval; +static char *header_section = NULL; /* start with no header section */ + +#define YYDEBUG 1 + +#define PARSE_DEBUG 0 + +#if PARSE_DEBUG +# define dprintf(f,s) fprintf(stderr, (f), yylineno, (s)) +# define amu_return(v) +#else +# define dprintf(f,s) +# define amu_return(v) return((v)) +#endif /* PARSE_DEBUG */ + +%} + +%union { +char *strtype; +} + +%token LEFT_BRACKET RIGHT_BRACKET EQUAL +%token NEWLINE +%token NONWS_STRING +%token NONWSEQ_STRING +%token QUOTED_NONWSEQ_STRING + +%start file +%% + +/****************************************************************************/ +file : { yydebug = PARSE_DEBUG; } newlines map_sections + | { yydebug = PARSE_DEBUG; } map_sections + ; + +newlines : NEWLINE + | NEWLINE newlines + ; + +map_sections : map_section + | map_section map_sections + ; + +map_section : sec_header kv_pairs + ; + +sec_header : LEFT_BRACKET NONWS_STRING RIGHT_BRACKET NEWLINE + { + if (yydebug) + fprintf(stderr, "sec_header1 = \"%s\"\n", $2); + header_section = $2; + } + ; + +kv_pairs : kv_pair + | kv_pair kv_pairs + ; + +kv_pair : NONWS_STRING EQUAL NONWS_STRING NEWLINE + { + if (yydebug) + fprintf(stderr,"parse1: key=\"%s\", val=\"%s\"\n", $1, $3); + retval = set_conf_kv(header_section, $1, $3); + if (retval != 0) { + yyerror("syntax error"); + YYABORT; + } + } + | NONWS_STRING EQUAL NONWSEQ_STRING NEWLINE + { + if (yydebug) + fprintf(stderr,"parse2: key=\"%s\", val=\"%s\"\n", $1, $3); + retval = set_conf_kv(header_section, $1, $3); + if (retval != 0) { + yyerror("syntax error"); + YYABORT; + } + } + | NONWS_STRING EQUAL QUOTED_NONWSEQ_STRING NEWLINE + { + if (yydebug) + fprintf(stderr,"parse3: key=\"%s\", val=\"%s\"\n", $1, $3); + retval = set_conf_kv(header_section, $1, $3); + if (retval != 0) { + yyerror("syntax error"); + YYABORT; + } + } + | NEWLINE + ; + +/****************************************************************************/ +%% + +static int +yyerror(const char *s) +{ + fprintf(stderr, "AMDCONF: %s on line %d (section %s)\n", + s, yylineno, + (header_section ? header_section : "null")); + exit(1); + return 1; /* to full compilers that insist on a return statement */ +} diff --git a/contrib/amd/amd/conf_tok.l b/contrib/amd/amd/conf_tok.l new file mode 100644 index 0000000..0ec067b --- /dev/null +++ b/contrib/amd/amd/conf_tok.l @@ -0,0 +1,186 @@ +%{ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: conf_tok.l,v 5.2.2.1 1992/02/09 15:09:36 jsp beta $ + * + */ + +/* + * Lexical analyzer for AMD configuration parser. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +/* + * Some systems include a definition for the macro ECHO in , + * and their (bad) version of lex defines it too at the very beginning of + * the generated lex.yy.c file (before it can be easily undefined), + * resulting in a conflict. So undefine it here before needed. + * Luckily, it does not appear that this macro is actually used in the rest + * of the generated lex.yy.c file. + */ +#ifdef ECHO +# undef ECHO +#endif /* ECHO */ +#include +#include +#include +/* and once again undefine this, just in case */ +#ifdef ECHO +# undef ECHO +#endif /* ECHO */ + +/* + * There are some things that need to be defined only if useing GNU flex. + * These must not be defined if using standard lex + */ +#ifdef FLEX_SCANNER +# ifndef ECHO +# define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +# endif /* not ECHO */ +int yylineno = 0; +#endif /* FLEX_SCANNER */ + +int yylex(void); +/* + * some systems such as DU-4.x have a different GNU flex in /usr/bin + * which automatically generates yywrap macros and symbols. So I must + * distinguish between them and when yywrap is actually needed. + */ +#ifndef yywrap +int yywrap(void); +#endif /* not yywrap */ + +#define TOK_DEBUG 0 + +#if TOK_DEBUG +# define dprintf(f,s) fprintf(stderr, (f), yylineno, (s)) +# define amu_return(v) +#else +# define dprintf(f,s) +# define amu_return(v) return((v)) +#endif /* TOK_DEBUG */ + +/* no need to use yyunput() or yywrap() */ +#define YY_NO_UNPUT +#define YY_SKIP_YYWRAP + +%} + +DIGIT [0-9] +ALPHA [A-Za-z] +ALPHANUM [A-Za-z0-9] +SYMBOL [A-Za-z0-9_-] +PATH [A-Za-z0-9_-/] +NONWSCHAR [^ \t\n\[\]=] +NONWSEQCHAR [^ \t\n\[\]] +NONNL [^\n] +NONQUOTE [^\"] + +%% + +\n { + yylineno++; + amu_return(NEWLINE); + } + +\[ { + dprintf("%8d: Left bracket \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(LEFT_BRACKET); + } + +\] { + dprintf("%8d: Right bracket \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(RIGHT_BRACKET); + } + += { + dprintf("%8d: Equal \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(EQUAL); + } + +[ \t]* { + dprintf("%8d: Whitespace \"%s\"\n", yytext); + } +"#"[^\n]*\n { + /* a comment line includes the terminating \n */ + yylineno++; + yytext[strlen((char *)yytext)-1] = '\0'; + dprintf("%8d: Comment \"%s\"\n", yytext); + } + +{NONWSCHAR}{NONWSCHAR}* { + dprintf("%8d: Non-WS string \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(NONWS_STRING); + } + +\"{NONQUOTE}{NONQUOTE}*\" { + dprintf("%8d: QUOTED-Non-WS-EQ string \"%s\"\n", yytext); + /* must strip quotes */ + yytext[strlen((char *)yytext)-1] = '\0'; + yylval.strtype = strdup((char *)&yytext[1]); + amu_return(QUOTED_NONWSEQ_STRING); + } + +{NONWSEQCHAR}{NONWSEQCHAR}* { + dprintf("%8d: Non-WS-EQ string \"%s\"\n", yytext); + yylval.strtype = strdup((char *)yytext); + amu_return(NONWSEQ_STRING); + } + +%% + +/* + * some systems such as DU-4.x have a different GNU flex in /usr/bin + * which automatically generates yywrap macros and symbols. So I must + * distinguish between them and when yywrap is actually needed. + */ +#ifndef yywrap +int yywrap(void) +{ + return 1; +} +#endif /* not yywrap */ diff --git a/contrib/amd/amd/get_args.c b/contrib/amd/amd/get_args.c new file mode 100644 index 0000000..b365ff7 --- /dev/null +++ b/contrib/amd/amd/get_args.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: get_args.c,v 5.2.2.1 1992/02/09 15:08:23 jsp beta $ + * + */ + +/* + * Argument decode + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* include auto-generated version file */ +#include + +char *conf_file = "/etc/amd.conf"; /* default amd configuration file */ +char *conf_tag = NULL; /* default conf file tags to use */ +int usage = 0; +int use_conf_file = 0; /* default don't use amd.conf file */ +char *mnttab_file_name = NULL; /* symbol must be available always */ +#ifdef DEBUG +int debug_flags = D_AMQ /* Register AMQ */ + | D_DAEMON; /* Enter daemon mode */ +#endif /* DEBUG */ + + +/* + * Return the version string (dynamic buffer) + */ +char * +get_version_string(void) +{ + static char *vers = NULL; + char tmpbuf[1024]; + char *wire_buf; + int wire_buf_len = 0; + + /* first get dynamic string listing all known networks */ + wire_buf = print_wires(); + if (wire_buf) + wire_buf_len = strlen(wire_buf); + + vers = xmalloc(2048 + wire_buf_len); + sprintf(vers, "%s\n%s\n%s\n%s\n", + "Copyright (c) 1997-1998 Erez Zadok", + "Copyright (c) 1990 Jan-Simon Pendry", + "Copyright (c) 1990 Imperial College of Science, Technology & Medicine", + "Copyright (c) 1990 The Regents of the University of California."); + sprintf(tmpbuf, "%s version %s (build %d).\n", + PACKAGE, VERSION, AMU_BUILD_VERSION); + strcat(vers, tmpbuf); + sprintf(tmpbuf, "Built by %s@%s on date %s.\n", + USER_NAME, HOST_NAME, CONFIG_DATE); + strcat(vers, tmpbuf); + sprintf(tmpbuf, "cpu=%s (%s-endian), arch=%s, karch=%s.\n", + cpu, endian, gopt.arch, gopt.karch); + strcat(vers, tmpbuf); + sprintf(tmpbuf, "full_os=%s, os=%s, osver=%s, vendor=%s.\n", + HOST_OS, gopt.op_sys, gopt.op_sys_ver, HOST_VENDOR); + strcat(vers, tmpbuf); + + strcat(vers, "Map support for: "); + mapc_showtypes(tmpbuf); + strcat(vers, tmpbuf); + strcat(vers, ".\nAMFS: "); + ops_showamfstypes(tmpbuf); + strcat(vers, tmpbuf); + strcat(vers, ".\nFS: "); + ops_showfstypes(tmpbuf); + strcat(vers, tmpbuf); + + /* append list of networks if available */ + if (wire_buf) { + strcat(vers, wire_buf); + XFREE(wire_buf); + } + + return vers; +} + + +void +get_args(int argc, char *argv[]) +{ + int opt_ch; + FILE *fp = stdin; + + /* if no arguments were passed, try to use /etc/amd.conf file */ + if (argc <= 1) + use_conf_file = 1; + + while ((opt_ch = getopt(argc, argv, "nprvSa:c:d:k:l:o:t:w:x:y:C:D:F:T:O:H")) != EOF) + switch (opt_ch) { + + case 'a': + if (*optarg != '/') { + fprintf(stderr, "%s: -a option must begin with a '/'\n", + progname); + exit(1); + } + gopt.auto_dir = optarg; + break; + + case 'c': + gopt.am_timeo = atoi(optarg); + if (gopt.am_timeo <= 0) + gopt.am_timeo = AM_TTL; + break; + + case 'd': + gopt.sub_domain = optarg; + break; + + case 'k': + gopt.karch = optarg; + break; + + case 'l': + gopt.logfile = optarg; + break; + + case 'n': + gopt.flags |= CFM_NORMALIZE_HOSTNAMES; + break; + + case 'o': + gopt.op_sys_ver = optarg; + break; + + case 'p': + gopt.flags |= CFM_PRINT_PID; + break; + + case 'r': + gopt.flags |= CFM_RESTART_EXISTING_MOUNTS; + break; + + case 't': + /* timeo.retrans */ + { + char *dot = strchr(optarg, '.'); + if (dot) + *dot = '\0'; + if (*optarg) { + gopt.amfs_auto_timeo = atoi(optarg); + } + if (dot) { + gopt.amfs_auto_retrans = atoi(dot + 1); + *dot = '.'; + } + } + break; + + case 'v': + fputs(get_version_string(), stderr); + exit(0); + break; + + case 'w': + gopt.am_timeo_w = atoi(optarg); + if (gopt.am_timeo_w <= 0) + gopt.am_timeo_w = AM_TTL_W; + break; + + case 'x': + usage += switch_option(optarg); + break; + + case 'y': +#ifdef HAVE_MAP_NIS + gopt.nis_domain = optarg; +#else /* not HAVE_MAP_NIS */ + plog(XLOG_USER, "-y: option ignored. No NIS support available."); +#endif /* not HAVE_MAP_NIS */ + break; + + case 'C': + gopt.cluster = optarg; + break; + + case 'D': +#ifdef DEBUG + usage += debug_option(optarg); +#else /* not DEBUG */ + fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n", progname); +#endif /* not DEBUG */ + break; + + case 'F': + conf_file = optarg; + use_conf_file = 1; + break; + + case 'H': + goto show_usage; + break; + + case 'O': + gopt.op_sys = optarg; + break; + + case 'S': + gopt.flags &= ~CFM_PROCESS_LOCK; /* turn process locking off */ + break; + + case 'T': + conf_tag = optarg; + break; + + default: + usage = 1; + break; + } + + /* + * amd.conf file: if not command-line arguments were used, or if -F was + * specified, then use that amd.conf file. If the file cannot be opened, + * abort amd. If it can be found, open it, parse it, and then close it. + */ + if (use_conf_file && conf_file) { + fp = fopen(conf_file, "r"); + if (!fp) { + char buf[128]; + sprintf(buf, "Amd configuration file (%s)", conf_file); + perror(buf); + exit(1); + } + yyin = fp; + yyparse(); + fclose(fp); + if (process_last_regular_map() != 0) + exit(1); + } + + /* make sure there are some default options defined */ + if (xlog_level_init == ~0) { + switch_option(""); + } +#ifdef DEBUG + usage += switch_option("debug"); +#endif /* DEBUG */ + + /* log information regarding amd.conf file */ + if (use_conf_file && conf_file) + plog(XLOG_INFO, "using configuration file %s", conf_file); + +#ifdef HAVE_MAP_LDAP + /* ensure that if ldap_base is specified, that also ldap_hostports is */ + if (gopt.ldap_hostports && !gopt.ldap_base) { + fprintf(stderr, "must specify both ldap_hostports and ldap_base\n"); + exit(1); + } +#endif /* HAVE_MAP_LDAP */ + + if (usage) + goto show_usage; + + while (optind <= argc - 2) { + char *dir = argv[optind++]; + char *map = argv[optind++]; + char *opts = ""; + if (argv[optind] && *argv[optind] == '-') + opts = &argv[optind++][1]; + + root_newmap(dir, opts, map, NULL); + } + + if (optind == argc) { + /* + * Append domain name to hostname. + * sub_domain overrides hostdomain + * if given. + */ + if (gopt.sub_domain) + hostdomain = gopt.sub_domain; + if (*hostdomain == '.') + hostdomain++; + strcat(hostd, "."); + strcat(hostd, hostdomain); + +#ifdef MOUNT_TABLE_ON_FILE +# ifdef DEBUG + if (debug_flags & D_MTAB) + mnttab_file_name = DEBUG_MNTTAB; + else +# endif /* DEBUG */ + mnttab_file_name = MNTTAB_FILE_NAME; +#else /* not MOUNT_TABLE_ON_FILE */ +# ifdef DEBUG + if (debug_flags & D_MTAB) + dlog("-D mtab option ignored"); +# endif /* DEBUG */ +#endif /* not MOUNT_TABLE_ON_FILE */ + + if (switch_to_logfile(gopt.logfile) != 0) + plog(XLOG_USER, "Cannot switch logfile"); + + /* + * If the kernel architecture was not specified + * then use the machine architecture. + */ + if (gopt.karch == 0) + gopt.karch = gopt.arch; + + if (gopt.cluster == 0) + gopt.cluster = hostdomain; + + if (gopt.amfs_auto_timeo <= 0) + gopt.amfs_auto_timeo = AMFS_AUTO_TIMEO; + if (gopt.amfs_auto_retrans <= 0) + gopt.amfs_auto_retrans = AMFS_AUTO_RETRANS; + if (gopt.amfs_auto_retrans <= 0) + gopt.amfs_auto_retrans = 3; /* XXX */ + return; + } + +show_usage: + fprintf(stderr, + "Usage: %s [-nprvHS] [-a mount_point] [-c cache_time] [-d domain]\n\ +\t[-k kernel_arch] [-l logfile%s\n\ +\t[-t timeout.retrans] [-w wait_timeout] [-C cluster_name]\n\ +\t[-o op_sys_ver] [-O op_sys_name]\n\ +\t[-F conf_file] [-T conf_tag]", progname, +#ifdef HAVE_SYSLOG +# ifdef LOG_DAEMON + "|\"syslog[:facility]\"]" +# else /* not LOG_DAEMON */ + "|\"syslog\"]" +# endif /* not LOG_DAEMON */ +#else /* not HAVE_SYSLOG */ + "]" +#endif /* not HAVE_SYSLOG */ + ); + +#ifdef HAVE_MAP_NIS + fputs(" [-y nis-domain]\n", stderr); +#else /* not HAVE_MAP_NIS */ + fputc('\n', stderr); +#endif /* HAVE_MAP_NIS */ + + show_opts('x', xlog_opt); +#ifdef DEBUG + show_opts('D', dbg_opt); +#endif /* DEBUG */ + fprintf(stderr, "\t[directory mapname [-map_options]] ...\n"); + exit(1); +} diff --git a/contrib/amd/amd/info_file.c b/contrib/amd/amd/info_file.c new file mode 100644 index 0000000..55c24bd --- /dev/null +++ b/contrib/amd/amd/info_file.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_file.c,v 5.2.2.1 1992/02/09 15:08:28 jsp beta $ + * + */ + +/* + * Get info from file + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +#define MAX_LINE_LEN 1500 + +/* forward declarations */ +int file_init(mnt_map *m, char *map, time_t *tp); +int file_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)); +int file_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp); +int file_mtime(mnt_map *m, char *map, time_t *tp); + + +static int +read_line(char *buf, int size, FILE * fp) +{ + int done = 0; + + do { + while (fgets(buf, size, fp)) { + int len = strlen(buf); + done += len; + if (len > 1 && buf[len - 2] == '\\' && + buf[len - 1] == '\n') { + int ch; + buf += len - 2; + size -= len - 2; + *buf = '\n'; + buf[1] = '\0'; + /* + * Skip leading white space on next line + */ + while ((ch = getc(fp)) != EOF && + isascii(ch) && isspace(ch)) ; + (void) ungetc(ch, fp); + } else { + return done; + } + } + } while (size > 0 && !feof(fp)); + + return done; +} + + +/* + * Try to locate a key in a file + */ +static int +search_or_reload_file(FILE * fp, char *map, char *key, char **val, mnt_map *m, void (*fn) (mnt_map *m, char *, char *)) +{ + char key_val[MAX_LINE_LEN]; + int chuck = 0; + int line_no = 0; + + while (read_line(key_val, sizeof(key_val), fp)) { + char *kp; + char *cp; + char *hash; + int len = strlen(key_val); + line_no++; + + /* + * Make sure we got the whole line + */ + if (key_val[len - 1] != '\n') { + plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map); + chuck = 1; + } else { + key_val[len - 1] = '\0'; + } + + /* + * Strip comments + */ + hash = strchr(key_val, '#'); + if (hash) + *hash = '\0'; + + /* + * Find start of key + */ + for (kp = key_val; *kp && isascii(*kp) && isspace((int)*kp); kp++) ; + + /* + * Ignore blank lines + */ + if (!*kp) + goto again; + + /* + * Find end of key + */ + for (cp = kp; *cp && (!isascii(*cp) || !isspace((int)*cp)); cp++) ; + + /* + * Check whether key matches + */ + if (*cp) + *cp++ = '\0'; + + if (fn || (*key == *kp && STREQ(key, kp))) { + while (*cp && isascii(*cp) && isspace((int)*cp)) + cp++; + if (*cp) { + /* + * Return a copy of the data + */ + char *dc = strdup(cp); + if (fn) { + (*fn) (m, strdup(kp), dc); + } else { + *val = dc; +#ifdef DEBUG + dlog("%s returns %s", key, dc); +#endif /* DEBUG */ + } + if (!fn) + return 0; + } else { + plog(XLOG_USER, "%s: line %d has no value field", map, line_no); + } + } + + again: + /* + * If the last read didn't get a whole line then + * throw away the remainder before continuing... + */ + if (chuck) { + while (fgets(key_val, sizeof(key_val), fp) && + !strchr(key_val, '\n')) ; + chuck = 0; + } + } + + return fn ? 0 : ENOENT; +} + + +static FILE * +file_open(char *map, time_t *tp) +{ + FILE *mapf = fopen(map, "r"); + + if (mapf && tp) { + struct stat stb; + if (fstat(fileno(mapf), &stb) < 0) + *tp = clocktime(); + else + *tp = stb.st_mtime; + } + return mapf; +} + + +int +file_init(mnt_map *m, char *map, time_t *tp) +{ + FILE *mapf = file_open(map, tp); + + if (mapf) { + fclose(mapf); + return 0; + } + return errno; +} + + +int +file_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)) +{ + FILE *mapf = file_open(map, (time_t *) 0); + + if (mapf) { + int error = search_or_reload_file(mapf, map, 0, 0, m, fn); + (void) fclose(mapf); + return error; + } + return errno; +} + + +int +file_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + time_t t; + FILE *mapf = file_open(map, &t); + + if (mapf) { + int error; + if (*tp < t) { + *tp = t; + error = -1; + } else { + error = search_or_reload_file(mapf, map, key, pval, 0, 0); + } + (void) fclose(mapf); + return error; + } + return errno; +} + + +int +file_mtime(mnt_map *m, char *map, time_t *tp) +{ + FILE *mapf = file_open(map, tp); + + if (mapf) { + (void) fclose(mapf); + return 0; + } + return errno; +} diff --git a/contrib/amd/amd/info_hesiod.c b/contrib/amd/amd/info_hesiod.c new file mode 100644 index 0000000..a4607e1 --- /dev/null +++ b/contrib/amd/amd/info_hesiod.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_hesiod.c,v 1.1 1997-1998/07/11 08:34:52 danny Exp danny $ + * + */ + +/* + * Get info from Hesiod + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +#define HES_PREFIX "hesiod." +#define HES_PREFLEN 7 + +#ifdef HAVE_HESIOD_INIT +/* bsdi3 does not define this extern in any header file */ +extern char **hesiod_resolve(void *context, const char *name, const char *type); + +static voidp hesiod_context; +#endif /* HAVE_HESIOD_INIT */ + +/* + * No easy way to probe the server - check the map name begins with "hesiod." + * Note: this name includes 'amu_' so as to not conflict with libhesiod's + * hesiod_init() function. + */ +int +amu_hesiod_init(mnt_map *m, char *map, time_t *tp) +{ +#ifdef DEBUG + dlog("amu_hesiod_init(%s)", map); +#endif /* DEBUG */ + *tp = 0; + +#ifdef HAVE_HESIOD_INIT + if(!hesiod_context && hesiod_init(&hesiod_context) != 0) + return ENOENT; +#endif /* HAVE_HESIOD_INIT */ + + return NSTREQ(map, HES_PREFIX, HES_PREFLEN) ? 0 : ENOENT; +} + + +/* + * Do a Hesiod nameserver call. + * Modify time is ignored by Hesiod - XXX + */ +int +hesiod_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + char hes_key[MAXPATHLEN]; + char **rvec; +#ifndef HAVE_HESIOD_INIT + int error; +#endif /* not HAVE_HESIOD_INIT */ + +#ifdef DEBUG + dlog("hesiod_search(m=%x, map=%s, key=%s, pval=%x tp=%x)", m, map, key, pval, tp); +#endif /* DEBUG */ + + sprintf(hes_key, "%s.%s", key, map + HES_PREFLEN); + + /* + * Call the resolver + */ +#ifdef DEBUG + dlog("Hesiod base is: %s\n", gopt.hesiod_base); + dlog("hesiod_search: hes_resolve(%s, %s)", hes_key, gopt.hesiod_base); + if (debug_flags & D_INFO) + _res.options |= RES_DEBUG; +#endif /* DEBUG */ + +#ifdef HAVE_HESIOD_INIT + /* new style hesiod */ + rvec = hesiod_resolve(hesiod_context, hes_key, gopt.hesiod_base); +#else /* not HAVE_HESIOD_INIT */ + rvec = hes_resolve(hes_key, gopt.hesiod_base); +#endif /* not HAVE_HESIOD_INIT */ + + /* + * If a reply was forthcoming then return + * it (and free subsequent replies) + */ + if (rvec && *rvec) { + *pval = *rvec; + while (*++rvec) + XFREE(*rvec); + return 0; + } + +#ifdef HAVE_HESIOD_INIT + /* new style hesiod */ + return errno; +#else /* not HAVE_HESIOD_INIT */ + /* + * Otherwise reflect the hesiod error into a Un*x error + */ +# ifdef DEBUG + dlog("hesiod_search: Error: %d", hes_error()); +# endif /* DEBUG */ + switch (hes_error()) { + case HES_ER_NOTFOUND: + error = ENOENT; + break; + case HES_ER_CONFIG: + error = EIO; + break; + case HES_ER_NET: + error = ETIMEDOUT; + break; + default: + error = EINVAL; + break; + } +# ifdef DEBUG + dlog("hesiod_search: Returning: %d", error); +# endif /* DEBUG */ + return error; +#endif /* not HAVE_HESIOD_INIT */ +} diff --git a/contrib/amd/amd/info_ldap.c b/contrib/amd/amd/info_ldap.c new file mode 100644 index 0000000..e2f0367 --- /dev/null +++ b/contrib/amd/amd/info_ldap.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_ldap.c,v 5.2.2.1 1992/02/09 15:08:29 jsp beta $ + * + */ + + +/* + * Get info from LDAP (Lightweight Directory Access Protocol) + * LDAP Home Page: http://www.umich.edu/~rsug/ldap/ + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* + * MACROS: + */ +#define AMD_LDAP_TYPE "ldap" +/* Time to live for an LDAP cached in an mnt_map */ +#define AMD_LDAP_TTL 3600 +#define AMD_LDAP_RETRIES 5 +#define AMD_LDAP_HOST "ldap" +#ifndef LDAP_PORT +# define LDAP_PORT 389 +#endif /* LDAP_PORT */ + +/* How timestamps are searched */ +#define AMD_LDAP_TSFILTER "(&(objectClass=amdmapTimestamp)(amdmapName=%s))" +/* How maps are searched */ +#define AMD_LDAP_FILTER "(&(objectClass=amdmap)(amdmapName=%s)(amdmapKey=%s))" +/* How timestamps are stored */ +#define AMD_LDAP_TSATTR "amdmaptimestamp" +/* How maps are stored */ +#define AMD_LDAP_ATTR "amdmapvalue" + +/* + * TYPEDEFS: + */ +typedef struct ald_ent ALD; +typedef struct cr_ent CR; +typedef struct he_ent HE; + +/* + * STRUCTURES: + */ +struct ald_ent { + LDAP *ldap; + HE *hostent; + CR *credentials; + time_t timestamp; +}; + +struct cr_ent { + char *who; + char *pw; + int method; +}; + +struct he_ent { + char *host; + int port; + struct he_ent *next; +}; + +/* + * FORWARD DECLARATIONS: + */ +static int amu_ldap_rebind(ALD *a); +static int get_ldap_timestamp(LDAP *ld, char *map, time_t *ts); + + +/* + * FUNCTIONS: + */ + +static void +he_free(HE *h) +{ + XFREE(h->host); + if (h->next != NULL) + he_free(h->next); + XFREE(h); +} + + +static HE * +string2he(char *s) +{ + char *c, *p; + HE *new, *old = NULL; + + if (s == NULL) + return (NULL); + for (p = s; p; p = strchr(p, ',')) { + if (old != NULL) { + new = (HE *) xmalloc(sizeof(HE)); + old->next = new; + old = new; + } else { + old = (HE *) xmalloc(sizeof(HE)); + old->next = NULL; + } + c = strchr(p, ':'); + if (c) { /* Host and port */ + *c++ = '\0'; + old->host = strdup(p); + old->port = atoi(c); + } else + old->host = strdup(p); + + } + return (old); +} + + +static void +cr_free(CR *c) +{ + XFREE(c->who); + XFREE(c->pw); + XFREE(c); +} + + +static void +ald_free(ALD *a) +{ + he_free(a->hostent); + cr_free(a->credentials); + if (a->ldap != NULL) + ldap_unbind(a->ldap); + XFREE(a); +} + + +int +amu_ldap_init(mnt_map *m, char *map, time_t *ts) +{ + ALD *aldh; + CR *creds; + + if (!STREQ(gopt.map_type, AMD_LDAP_TYPE)) { + return (ENOENT); + } +#ifdef DEBUG + else { + dlog("Map %s is ldap\n", map); + } +#endif /* DEBUG */ + + aldh = (ALD *) xmalloc(sizeof(ALD)); + creds = (CR *) xmalloc(sizeof(CR)); + + aldh->hostent = string2he(gopt.ldap_hostports); + if (aldh->hostent == NULL) { + plog(XLOG_USER, "Unable to parse hostport %s for ldap map %s", + gopt.ldap_hostports, map); + return (ENOENT); + } + creds->who = ""; + creds->pw = ""; + creds->method = LDAP_AUTH_SIMPLE; + aldh->credentials = creds; + aldh->timestamp = 0; +#ifdef DEBUG + dlog("Trying for %s:%d\n", aldh->hostent->host, aldh->hostent->port); +#endif /* DEBUG */ + if (amu_ldap_rebind(aldh)) { + ald_free(aldh); + return (ENOENT); + } + m->map_data = (void *) aldh; +#ifdef DEBUG + dlog("Bound to %s:%d\n", aldh->hostent->host, aldh->hostent->port); +#endif /* DEBUG */ + if (get_ldap_timestamp(aldh->ldap, map, ts)) + return (ENOENT); +#ifdef DEBUG + dlog("Got timestamp for map %s: %d\n", map, *ts); +#endif /* DEBUG */ + + return (0); +} + + +static int +amu_ldap_rebind(ALD *a) +{ + LDAP *ld; + HE *h; + CR *c = a->credentials; + time_t now = clocktime(); + + if (a->ldap != NULL) { + if ((a->timestamp - now) > AMD_LDAP_TTL) { +#ifdef DEBUG + dlog("Reestablishing ldap connection\n"); +#endif /* DEBUG */ + ldap_unbind(a->ldap); + a->timestamp = now; + } else + return (0); + } + + while (TRUE) { + for (h = a->hostent; h != NULL; h = h->next) { + if ((ld = ldap_open(h->host, h->port)) == NULL) { + plog(XLOG_WARNING, "Unable to ldap_open to %s:%d\n", h->host, h->port); + break; + } + if (ldap_bind_s(ld, c->who, c->pw, c->method) != LDAP_SUCCESS) { + plog(XLOG_WARNING, "Unable to ldap_bind to %s:%d as %s\n", + h->host, h->port, c->who); + break; + } + if (gopt.ldap_cache_seconds > 0) { + ldap_enable_cache(ld, gopt.ldap_cache_seconds, gopt.ldap_cache_maxmem); + a->ldap = ld; + a->timestamp = now; + return (0); + } + } + plog(XLOG_WARNING, "Exausted list of ldap servers, looping.\n"); + } + + plog(XLOG_USER, "Unable to (re)bind to any ldap hosts\n"); + return (ENOENT); +} + + +static int +get_ldap_timestamp(LDAP * ld, char *map, time_t *ts) +{ + struct timeval tv; + char **vals, *end; + char filter[MAXPATHLEN]; + int i, err, nentries = 0; + LDAPMessage *res, *entry; + + tv.tv_sec = 3; + tv.tv_usec = 0; + sprintf(filter, AMD_LDAP_TSFILTER, map); +#ifdef DEBUG + dlog("Getting timestamp for map %s\n", map); + dlog("Filter is: %s\n", filter); + dlog("Base is: %s\n", gopt.ldap_base); +#endif /* DEBUG */ + for (i = 0; i < AMD_LDAP_RETRIES; i++) { + err = ldap_search_st(ld, + gopt.ldap_base, + LDAP_SCOPE_SUBTREE, + filter, + 0, + 0, + &tv, + &res); + if (err == LDAP_SUCCESS) + break; + dlog("Timestamp search timed out, trying again...\n"); + } + + if (err != LDAP_SUCCESS) { + *ts = 0; + plog(XLOG_USER, "LDAP timestamp search failed: %s\n", + ldap_err2string(ld->ld_errno)); + return (ENOENT); + } + + nentries = ldap_count_entries(ld, res); + if (nentries == 0) { + plog(XLOG_USER, "No timestamp entry for map %s\n", map); + *ts = 0; + ldap_msgfree(res); + return (ENOENT); + } + + entry = ldap_first_entry(ld, res); + vals = ldap_get_values(ld, entry, AMD_LDAP_TSATTR); + if (ldap_count_values(vals) == 0) { + plog(XLOG_USER, "Missing timestamp value for map %s\n", map); + *ts = 0; + ldap_value_free(vals); + ldap_msgfree(res); + ldap_msgfree(entry); + return (ENOENT); + } +#ifdef DEBUG + dlog("TS value is:%s:\n", vals[0]); +#endif /* DEBUG */ + + if (vals[0]) { + *ts = (time_t) strtol(vals[0], &end, 10); + if (end == vals[0]) { + plog(XLOG_USER, "Unable to decode ldap timestamp %s for map %s\n", + vals[0], map); + err = ENOENT; + } + if (!*ts > 0) { + plog(XLOG_USER, "Nonpositive timestamp %d for map %s\n", + *ts, map); + err = ENOENT; + } + } else { + plog(XLOG_USER, "Empty timestamp value for map %s\n", map); + *ts = 0; + err = ENOENT; + } + + ldap_value_free(vals); + ldap_msgfree(res); + ldap_msgfree(entry); +#ifdef DEBUG + dlog("The timestamp for %s is %d (err=%d)\n", map, *ts, err); +#endif /* DEBUG */ + return (err); +} + + +int +amu_ldap_search(mnt_map *m, char *map, char *key, char **pval, time_t *ts) +{ + char **vals, filter[MAXPATHLEN]; + struct timeval tv; + int i, err, nvals = 0, nentries = 0; + LDAPMessage *entry, *res; + ALD *a = (ALD *) (m->map_data); + + tv.tv_sec = 2; + tv.tv_usec = 0; + if (a == NULL) { + plog(XLOG_USER, "LDAP panic: no map data\n"); + return (EIO); + } + if (amu_ldap_rebind(a)) /* Check that's the handle is still valid */ + return (ENOENT); + + sprintf(filter, AMD_LDAP_FILTER, map, key); +#ifdef DEBUG + dlog("Search with filter: %s\n", filter); +#endif /* DEBUG */ + for (i = 0; i < AMD_LDAP_RETRIES; i++) { + err = ldap_search_st(a->ldap, + gopt.ldap_base, + LDAP_SCOPE_SUBTREE, + filter, + 0, + 0, + &tv, + &res); + if (err == LDAP_SUCCESS) + break; + } + + switch (err) { + case LDAP_SUCCESS: + break; + case LDAP_NO_SUCH_OBJECT: +#ifdef DEBUG + dlog("No object\n"); +#endif /* DEBUG */ + ldap_msgfree(res); + return (ENOENT); + default: + plog(XLOG_USER, "LDAP search failed: %s\n", + ldap_err2string(a->ldap->ld_errno)); + ldap_msgfree(res); + return (EIO); + } + + nentries = ldap_count_entries(a->ldap, res); +#ifdef DEBUG + dlog("Search found %d entries\n", nentries); +#endif /* DEBUG */ + if (nentries == 0) { + ldap_msgfree(res); + return (ENOENT); + } + entry = ldap_first_entry(a->ldap, res); + vals = ldap_get_values(a->ldap, entry, AMD_LDAP_ATTR); + nvals = ldap_count_values(vals); + if (nvals == 0) { + plog(XLOG_USER, "Missing value for %s in map %s\n", key, map); + ldap_value_free(vals); + ldap_msgfree(res); + ldap_msgfree(entry); + return (EIO); + } +#ifdef DEBUG + dlog("Map %s, %s => %s\n", map, key, vals[0]); +#endif /* DEBUG */ + if (vals[0]) { + *pval = strdup(vals[0]); + err = 0; + } else { + plog(XLOG_USER, "Empty value for %s in map %s\n", key, map); + err = ENOENT; + } + ldap_msgfree(res); + ldap_msgfree(entry); + ldap_value_free(vals); + + return (err); +} + + +int +amu_ldap_mtime(mnt_map *m, char *map, time_t *ts) +{ + ALD *aldh = (ALD *) (m->map_data); + + if (aldh == NULL) { + dlog("LDAP panic: unable to find map data\n"); + return (ENOENT); + } + if (amu_ldap_rebind(aldh)) { + return (ENOENT); + } + if (get_ldap_timestamp(aldh->ldap, map, ts)) { + return (ENOENT); + } + return (0); +} diff --git a/contrib/amd/amd/info_ndbm.c b/contrib/amd/amd/info_ndbm.c new file mode 100644 index 0000000..0b93fa6 --- /dev/null +++ b/contrib/amd/amd/info_ndbm.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_ndbm.c,v 5.2.2.1 1992/02/09 15:08:31 jsp beta $ + * + */ + +/* + * Get info from NDBM map + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward declarations */ +int ndbm_init(mnt_map *m, char *map, time_t *tp); +int ndbm_mtime(mnt_map *m, char *map, time_t *tp); +int ndbm_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp); + + +static int +search_ndbm(DBM *db, char *key, char **val) +{ + datum k, v; + + k.dptr = key; + k.dsize = strlen(key) + 1; + v = dbm_fetch(db, k); + if (v.dptr) { + *val = strdup(v.dptr); + return 0; + } + return ENOENT; +} + + +int +ndbm_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + DBM *db; + + db = dbm_open(map, O_RDONLY, 0); + if (db) { + struct stat stb; + int error; +#ifdef DBM_SUFFIX + char dbfilename[256]; + + strcpy(dbfilename, map); + strcat(dbfilename, DBM_SUFFIX); + error = stat(dbfilename, &stb); +#else /* not DBM_SUFFIX */ + error = fstat(dbm_pagfno(db), &stb); +#endif /* not DBM_SUFFIX */ + if (!error && *tp < stb.st_mtime) { + *tp = stb.st_mtime; + error = -1; + } else { + error = search_ndbm(db, key, pval); + } + (void) dbm_close(db); + return error; + } + return errno; +} + + +int +ndbm_init(mnt_map *m, char *map, time_t *tp) +{ + DBM *db; + + db = dbm_open(map, O_RDONLY, 0); + if (db) { + struct stat stb; + int error; +#ifdef DBM_SUFFIX + char dbfilename[256]; + + strcpy(dbfilename, map); + strcat(dbfilename, DBM_SUFFIX); + error = stat(dbfilename, &stb); +#else /* not DBM_SUFFIX */ + error = fstat(dbm_pagfno(db), &stb); +#endif /* not DBM_SUFFIX */ + if (error < 0) + *tp = clocktime(); + else + *tp = stb.st_mtime; + dbm_close(db); + return 0; + } + return errno; +} + + +int +ndbm_mtime(mnt_map *m, char *map, time_t *tp) +{ + return ndbm_init(m,map, tp); +} diff --git a/contrib/amd/amd/info_nis.c b/contrib/amd/amd/info_nis.c new file mode 100644 index 0000000..eceb73a --- /dev/null +++ b/contrib/amd/amd/info_nis.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_nis.c,v 5.2.2.1 1992/02/09 15:08:32 jsp beta $ + * + */ + +/* + * Get info from NIS map + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * NIS+ servers in NIS compat mode don't have yp_order() + */ +static int has_yp_order = FALSE; + +/* forward declarations */ +int nis_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)); +int nis_search(mnt_map *m, char *map, char *key, char **val, time_t *tp); +int nis_init(mnt_map *m, char *map, time_t *tp); +int nis_mtime(mnt_map *m, char *map, time_t *tp); + +/* typedefs */ +typedef void (*nis_callback_fxn_t)(mnt_map *, char *, char *); +#ifndef DEFINED_YPALL_CALLBACK_FXN_T +typedef int (*ypall_callback_fxn_t)(); +#endif /* DEFINED_YPALL_CALLBACK_FXN_T */ + +struct nis_callback_data { + mnt_map *ncd_m; + char *ncd_map; + nis_callback_fxn_t ncd_fn; +}; + +/* Map to the right version of yp_all */ +#ifdef HAVE_BAD_YP_ALL +# define yp_all am_yp_all +static int am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback); +#endif /* HAVE_BAD_YP_ALL */ + + +/* + * Figure out the nis domain name + */ +static int +determine_nis_domain(void) +{ + static int nis_not_running = 0; + char default_domain[YPMAXDOMAIN]; + + if (nis_not_running) + return ENOENT; + + if (getdomainname(default_domain, sizeof(default_domain)) < 0) { + nis_not_running = 1; + plog(XLOG_ERROR, "getdomainname: %m"); + return EIO; + } + if (!*default_domain) { + nis_not_running = 1; + plog(XLOG_WARNING, "NIS domain name is not set. NIS ignored."); + return ENOENT; + } + gopt.nis_domain = strdup(default_domain); + + return 0; +} + + +/* + * Callback from yp_all + */ +static int +callback(int status, char *key, int kl, char *val, int vl, char *data) +{ + struct nis_callback_data *ncdp = (struct nis_callback_data *) data; + + if (status == YP_TRUE) { + + /* + * Add to list of maps + */ + char *kp = strnsave(key, kl); + char *vp = strnsave(val, vl); + (*ncdp->ncd_fn) (ncdp->ncd_m, kp, vp); + + /* + * We want more ... + */ + return FALSE; + + } else { + + /* + * NOMORE means end of map - otherwise log error + */ + if (status != YP_NOMORE) { + /* + * Check what went wrong + */ + int e = ypprot_err(status); + +#ifdef DEBUG + plog(XLOG_ERROR, "yp enumeration of %s: %s, status=%d, e=%d", + ncdp->ncd_map, yperr_string(e), status, e); +#else /* not DEBUG */ + plog(XLOG_ERROR, "yp enumeration of %s: %s", ncdp->ncd_map, yperr_string(e)); +#endif /* not DEBUG */ + } + return TRUE; + } +} + + +int +nis_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)) +{ + int error; + struct nis_callback_data data; + struct ypall_callback cbinfo; + + if (!gopt.nis_domain) { + error = determine_nis_domain(); + if (error) + return error; + } + data.ncd_m = m; + data.ncd_map = map; + data.ncd_fn = fn; + cbinfo.data = (voidp) &data; + cbinfo.foreach = (ypall_callback_fxn_t) callback; + + /* + * If you are using NIS and your yp_all function is "broken", you have to + * get it fixed. The bug in yp_all() is that it does not close a TCP + * connection to ypserv, and this ypserv runs out of open file descriptors, + * getting into an infinite loop, thus all YP clients eventually unbind + * and hang too. + */ + error = yp_all(gopt.nis_domain, map, &cbinfo); + + if (error) + plog(XLOG_ERROR, "error grabbing nis map of %s: %s", map, yperr_string(ypprot_err(error))); + return error; +} + + +/* + * Check if NIS is up, so we can determine if to clear the map or not. + * Test it by checking the yp order. + * Returns: 0 if NIS is down, 1 if it is up. + */ +int +nis_isup(mnt_map *m, char *map) +{ + YP_ORDER_OUTORDER_TYPE order; + int error; + static int last_status = 1; /* assume up by default */ + + if (has_yp_order) { + error = yp_order(gopt.nis_domain, map, &order); + if (error != 0) { + plog(XLOG_ERROR, + "nis_isup: error getting the order of map of %s: %s", + map, yperr_string(ypprot_err(error))); + last_status = 0; + return 0; /* NIS is down */ + } + } + if (last_status == 0) { /* if was down before */ + time_t dummy; + plog(XLOG_INFO, "nis_isup: NIS came back up for map %s", map); + /* XXX: do we really need to reinitialize nis? */ + error = nis_init(m, map, &dummy); + if (!error) + last_status = 1; + } + return 1; /* NIS is up */ +} + + +/* + * Try to locate a key using NIS. + */ +int +nis_search(mnt_map *m, char *map, char *key, char **val, time_t *tp) +{ + int outlen; + int res; + YP_ORDER_OUTORDER_TYPE order; + + /* + * Make sure domain initialised + */ + if (!gopt.nis_domain) { + int error = determine_nis_domain(); + if (error) + return error; + } + + + if (has_yp_order) { + /* + * Check if map has changed + */ + if (yp_order(gopt.nis_domain, map, &order)) + return EIO; + if ((time_t) order > *tp) { + *tp = (time_t) order; + return -1; + } + } else { + /* + * NIS+ server without yp_order + * Check if timeout has expired to invalidate the cache + */ + order = time(NULL); + if ((time_t)order - *tp > gopt.am_timeo) { + *tp = (time_t)order; + return(-1); + } + } + + /* + * Lookup key + */ + res = yp_match(gopt.nis_domain, map, key, strlen(key), val, &outlen); + + /* + * Do something interesting with the return code + */ + switch (res) { + case 0: + return 0; + + case YPERR_KEY: + return ENOENT; + + default: + plog(XLOG_ERROR, "%s: %s", map, yperr_string(res)); + return EIO; + } +} + + +int +nis_init(mnt_map *m, char *map, time_t *tp) +{ + YP_ORDER_OUTORDER_TYPE order; + int yp_order_result; + char *master; + + if (!gopt.nis_domain) { + int error = determine_nis_domain(); + if (error) + return error; + } + + /* + * To see if the map exists, try to find + * a master for it. + */ + yp_order_result = yp_order(gopt.nis_domain, map, &order); + switch (yp_order_result) { + case 0: + has_yp_order = TRUE; + *tp = (time_t) order; +#ifdef DEBUG + dlog("NIS master for %s@%s has order %d", map, gopt.nis_domain, order); +#endif /* DEBUG */ + break; + case YPERR_YPERR: + /* NIS+ server found ! */ + has_yp_order = FALSE; + /* try yp_master() instead */ + if (yp_master(gopt.nis_domain, map, &master)) { + return ENOENT; + } else { +#ifdef DEBUG + dlog("NIS master for %s@%s is a NIS+ server", map, gopt.nis_domain); +#endif /* DEBUG */ + /* Use fake timestamps */ + *tp = time(NULL); + } + break; + default: + return ENOENT; + } + return 0; +} + + +int +nis_mtime(mnt_map *m, char *map, time_t *tp) +{ + return nis_init(m, map, tp); +} + + +#ifdef HAVE_BAD_YP_ALL +/* + * If you are using NIS and your yp_all function is "broken", use an + * alternate code which avoids a bug in yp_all(). The bug in yp_all() is + * that it does not close a TCP connection to ypserv, and this ypserv runs + * out of open filedescriptors, getting into an infinite loop, thus all YP + * clients enevtually unbind and hang too. + * + * Systems known to be plagued with this bug: + * earlier SunOS 4.x + * all irix systems (at this time, up to 6.4 was checked) + * + * -Erez Zadok + * -James Tanis */ +static int +am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback) +{ + int i, j; + char *outkey, *outval; + int outkeylen, outvallen; + char *outkey_old; + int outkeylen_old; + + plog(XLOG_INFO, "NIS map %s reloading using am_yp_all", inmap); + + i = yp_first(indomain, inmap, &outkey, &outkeylen, &outval, &outvallen); + if (i) { + plog(XLOG_ERROR, "yp_first() returned error: %s\n", yperr_string(i)); + } + do { + j = (incallback->foreach)(YP_TRUE, + outkey, + outkeylen, + outval, + outvallen, + incallback->data); + if (j != FALSE) /* terminate loop */ + break; + outkey_old = outkey; + outkeylen_old = outkeylen; + i = yp_next(indomain, + inmap, + outkey_old, + outkeylen_old, + &outkey, + &outkeylen, + &outval, + &outvallen); + } while (!i); +#ifdef DEBUG + if (i) { + dlog("yp_next() returned error: %s\n", yperr_string(i)); + } +#endif /* DEBUG */ + if (i == YPERR_NOMORE) + return 0; + return i; +} +#endif /* HAVE_BAD_YP_ALL */ diff --git a/contrib/amd/amd/info_nisplus.c b/contrib/amd/amd/info_nisplus.c new file mode 100644 index 0000000..71f29e9 --- /dev/null +++ b/contrib/amd/amd/info_nisplus.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_nisplus.c,v 5.2.2.1 1992/02/09 15:08:32 jsp beta $ + * + */ + +/* + * Get info from NIS+ (version 3) map + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +#define NISPLUS_KEY "key=" +#define NISPLUS_ORGDIR ".org_dir" + +struct nis_callback_data { + mnt_map *ncd_m; + char *ncd_map; + void (*ncd_fn)(); +}; + +struct nisplus_search_callback_data { + nis_name key; + char *value; +}; + + +static int +nisplus_callback(const nis_name key, const nis_object *value, voidp opaquedata) +{ + char *kp = strnsave(ENTRY_VAL(value, 0), ENTRY_LEN(value, 0)); + char *vp = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1)); + struct nis_callback_data *data = (struct nis_callback_data *) opaquedata; + +#ifdef DEBUG + dlog("NISplus callback for <%s,%s>", kp, vp); +#endif /* DEBUG */ + + (*data->ncd_fn) (data->ncd_m, kp, vp); + + /* + * We want more ... + */ + return FALSE; +} + + +int +nisplus_reload(mnt_map *m, char *map, void (*fn) ()) +{ + int error = 0; + struct nis_callback_data data; + nis_result *result; + char *org; /* if map does not have ".org_dir" then append it */ + nis_name map_name; + + org = strstr(map, NISPLUS_ORGDIR); + if (org == NULL) + org = NISPLUS_ORGDIR; + else + org = ""; + + /* make some room for the NIS map_name */ + map_name = xmalloc(strlen(map) + sizeof(NISPLUS_ORGDIR)); + if (map_name == NULL) { + plog(XLOG_ERROR, "Unable to create map_name %s: %s", + map, strerror(ENOMEM)); + return ENOMEM; + } + sprintf(map_name, "%s%s", map, org); + + data.ncd_m = m; + data.ncd_map = map_name; + data.ncd_fn = fn; + +#ifdef DEBUG + dlog("NISplus reload for %s", map); +#endif /* DEBUG */ + + result = nis_list(map_name, + EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH, + (int (*)()) nisplus_callback, + &data); + + /* free off the NIS map_name */ + XFREE(map_name); + + if (result->status != NIS_SUCCESS && result->status != NIS_CBRESULTS) + error = 1; + + if (error) + plog(XLOG_ERROR, "error grabbing nisplus map of %s: %s", + map, + nis_sperrno(result->status)); + + nis_freeresult(result); + return error; +} + + +static int +nisplus_search_callback(const nis_name key, const nis_object *value, voidp opaquedata) +{ + struct nisplus_search_callback_data *data = (struct nisplus_search_callback_data *) opaquedata; + +#ifdef DEBUG + dlog("NISplus search callback for <%s>", ENTRY_VAL(value, 0)); + dlog("NISplus search callback value <%s>", ENTRY_VAL(value, 1)); +#endif /* DEBUG */ + + data->value = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1)); + return TRUE; +} + + +/* + * Try to locate a key using NIS+. + */ +int +nisplus_search(mnt_map *m, char *map, char *key, char **val, time_t *tp) +{ + nis_result *result; + int error = 0; + struct nisplus_search_callback_data data; + nis_name index; + char *org; /* if map does not have ".org_dir" then append it */ + + org = strstr(map, NISPLUS_ORGDIR); + if (org == NULL) + org = NISPLUS_ORGDIR; + else + org = ""; + + /* make some room for the NIS index */ + index = xmalloc(sizeof('[') /* for opening selection criteria */ + +sizeof(NISPLUS_KEY) + + strlen(key) + + sizeof(']') /* for closing selection criteria */ + +sizeof(',') /* + 1 for , separator */ + +strlen(map) + + sizeof(NISPLUS_ORGDIR) + ); + if (index == NULL) { + plog(XLOG_ERROR, + "Unable to create index %s: %s", + map, + strerror(ENOMEM)); + return ENOMEM; + } + sprintf(index, "[%s%s],%s%s", NISPLUS_KEY, key, map, org); + + data.key = key; + data.value = NULL; + +#ifdef DEBUG + dlog("NISplus search for %s", index); +#endif /* DEBUG */ + + result = nis_list(index, + EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH, + (int (*)()) nisplus_search_callback, + &data); + + /* free off the NIS index */ + XFREE(index); + + if (result == NULL) { + plog(XLOG_ERROR, "%s: %s", map, strerror(ENOMEM)); + return ENOMEM; + } + + /* + * Do something interesting with the return code + */ + switch (result->status) { + case NIS_SUCCESS: + case NIS_CBRESULTS: + + if (data.value == NULL) { + nis_object *value = result->objects.objects_val; +#ifdef DEBUG + dlog("NISplus search found "); + dlog("NISplus search for %s: %s(%d)", + map, nis_sperrno(result->status), result->status); +#endif /* DEBUG */ + + if (value != NULL) + data.value = strnsave(ENTRY_VAL(value, 1), ENTRY_LEN(value, 1)); + } + *val = data.value; + + if (*val) { + error = 0; +#ifdef DEBUG + dlog("NISplus search found %s", *val); +#endif /* DEBUG */ + } else { + error = ENOENT; +#ifdef DEBUG + dlog("NISplus search found nothing"); +#endif /* DEBUG */ + } + + *tp = 0; + break; + + case NIS_NOSUCHNAME: +#ifdef DEBUG + dlog("NISplus search returned %d", result->status); +#endif /* DEBUG */ + error = ENOENT; + break; + + default: + plog(XLOG_ERROR, "%s: %s", map, nis_sperrno(result->status)); + error = EIO; + break; + } + nis_freeresult(result); + + return error; +} + + +int +nisplus_init(mnt_map *m, char *map, time_t *tp) +{ + nis_result *result; + char *org; /* if map does not have ".org_dir" then append it */ + nis_name map_name; + int error = 0; + + org = strstr(map, NISPLUS_ORGDIR); + if (org == NULL) + org = NISPLUS_ORGDIR; + else + org = ""; + + /* make some room for the NIS map_name */ + map_name = xmalloc(strlen(map) + sizeof(NISPLUS_ORGDIR)); + if (map_name == NULL) { + plog(XLOG_ERROR, + "Unable to create map_name %s: %s", + map, + strerror(ENOMEM)); + return ENOMEM; + } + sprintf(map_name, "%s%s", map, org); + + result = nis_lookup(map_name, (EXPAND_NAME | FOLLOW_LINKS | FOLLOW_PATH)); + + /* free off the NIS map_name */ + XFREE(map_name); + + if (result == NULL) { + plog(XLOG_ERROR, "NISplus init <%s>: %s", map, strerror(ENOMEM)); + return ENOMEM; + } + + if (result->status != NIS_SUCCESS) { +#ifdef DEBUG + dlog("NISplus init <%s>: %s (%d)", + map, nis_sperrno(result->status), result->status); +#endif /* DEBUG */ + + error = ENOENT; + } + + *tp = 0; /* no time */ + nis_freeresult(result); + return error; +} + + +int +nisplus_mtime(mnt_map *m, char *map, time_t *tp) +{ + return nisplus_init(m,map, tp); +} diff --git a/contrib/amd/amd/info_passwd.c b/contrib/amd/amd/info_passwd.c new file mode 100644 index 0000000..32d92f4 --- /dev/null +++ b/contrib/amd/amd/info_passwd.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_passwd.c,v 5.2.2.1 1992/02/09 15:08:33 jsp beta $ + * + */ + +/* + * Get info from password "file" + * + * This is experimental and probably doesn't do what you expect. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +#define PASSWD_MAP "/etc/passwd" + +/* forward declarations */ +int passwd_init(mnt_map *m, char *map, time_t *tp); +int passwd_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp); + + +/* + * Nothing to probe - check the map name is PASSWD_MAP. + */ +int +passwd_init(mnt_map *m, char *map, time_t *tp) +{ + *tp = 0; + + /* + * Recognize the old format "PASSWD_MAP" + * Uses default return string + * "type:=nfs;rfs:=/${var0}/${var1};rhost:=${var1};sublink:=${var2};fs:=${autodir}${var3}" + */ + if (STREQ(map, PASSWD_MAP)) + return 0; + /* + * Recognize the new format "PASSWD_MAP:pval-format" + */ + if (!NSTREQ(map, PASSWD_MAP, sizeof(PASSWD_MAP) - 1)) + return ENOENT; + if (map[sizeof(PASSWD_MAP)-1] != ':') + return ENOENT; + + return 0; +} + + +/* + * Grab the entry via the getpwname routine + * Modify time is ignored by passwd - XXX + */ +int +passwd_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + char *dir = 0; + struct passwd *pw; + + if (STREQ(key, "/defaults")) { + *pval = strdup("type:=nfs"); + return 0; + } + pw = getpwnam(key); + + if (pw) { + /* + * We chop the home directory up as follows: + * /anydir/dom1/dom2/dom3/user + * + * and return + * rfs:=/anydir/dom3;rhost:=dom3.dom2.dom1;sublink:=user + * and now have + * var0:=pw-prefix:=anydir + * var1:=pw-rhost:=dom3.dom2.dom1 + * var2:=pw-user:=user + * var3:=pw-home:=/anydir/dom1/dom2/dom3/user + * + * This allows cross-domain entries in your passwd file. + * ... but forget about security! + */ + char *user; + char *p, *q; + char val[MAXPATHLEN]; + char rhost[MAXHOSTNAMELEN]; + dir = strdup(pw->pw_dir); + + /* + * Find user name. If no / then Invalid... + */ + user = strrchr(dir, '/'); + if (!user) + goto enoent; + *user++ = '\0'; + + /* + * Find start of host "path". If no / then Invalid... + */ + p = strchr(dir + 1, '/'); + if (!p) + goto enoent; + *p++ = '\0'; + + /* + * At this point, p is dom1/dom2/dom3 + * Copy, backwards, into rhost replacing + * / with . + */ + rhost[0] = '\0'; + do { + q = strrchr(p, '/'); + if (q) { + strcat(rhost, q + 1); + strcat(rhost, "."); + *q = '\0'; + } else { + strcat(rhost, p); + } + } while (q); + + /* + * Sanity check + */ + if (*rhost == '\0' || *user == '\0' || *dir == '\0') + goto enoent; + + /* + * Make up return string + */ + q = strchr(rhost, '.'); + if (q) + *q = '\0'; + p = strchr(map, ':'); + if (p) + p++; + else + p = "type:=nfs;rfs:=/${var0}/${var1};rhost:=${var1};sublink:=${var2};fs:=${autodir}${var3}"; + sprintf(val, "var0:=%s;var1:=%s;var2:=%s;var3:=%s;%s", + dir+1, rhost, user, pw->pw_dir, p); +#ifdef DEBUG + dlog("passwd_search: map=%s key=%s -> %s", map, key, val); +#endif /* DEBUG */ + if (q) + *q = '.'; + *pval = strdup(val); + return 0; + } + +enoent: + if (dir) + XFREE(dir); + + return ENOENT; +} diff --git a/contrib/amd/amd/info_union.c b/contrib/amd/amd/info_union.c new file mode 100644 index 0000000..7f757f9 --- /dev/null +++ b/contrib/amd/amd/info_union.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: info_union.c,v 5.2.2.1 1992/02/09 15:08:34 jsp beta $ + * + */ + +/* + * Get info from the system namespace + * + * NOTE: Cannot handle reads back through the automounter. + * THIS WILL CAUSE A DEADLOCK! + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +#define UNION_PREFIX "union:" +#define UNION_PREFLEN 6 + +/* forward declarations */ +int union_init(mnt_map *m, char *map, time_t *tp); +int union_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp); +int union_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)); + + +/* + * No way to probe - check the map name begins with "union:" + */ +int +union_init(mnt_map *m, char *map, time_t *tp) +{ + *tp = 0; + return NSTREQ(map, UNION_PREFIX, UNION_PREFLEN) ? 0 : ENOENT; +} + + +int +union_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + char *mapd = strdup(map + UNION_PREFLEN); + char **v = strsplit(mapd, ':', '\"'); + char **p; + + for (p = v; p[1]; p++) ; + *pval = xmalloc(strlen(*p) + 5); + sprintf(*pval, "fs:=%s", *p); + XFREE(mapd); + XFREE(v); + return 0; +} + + +int +union_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *)) +{ + char *mapd = strdup(map + UNION_PREFLEN); + char **v = strsplit(mapd, ':', '\"'); + char **dir; + + /* + * Add fake /defaults entry + */ + (*fn) (m, strdup("/defaults"), strdup("type:=link;opts:=nounmount;sublink:=${key}")); + + for (dir = v; *dir; dir++) { + int dlen; + struct dirent *dp; + + DIR *dirp = opendir(*dir); + if (!dirp) { + plog(XLOG_USER, "Cannot read directory %s: %m", *dir); + continue; + } + dlen = strlen(*dir); + +#ifdef DEBUG + dlog("Reading directory %s...", *dir); +#endif /* DEBUG */ + while ((dp = readdir(dirp))) { + char *val, *dpname = &dp->d_name[0]; + if (dpname[0] == '.' && + (dpname[1] == '\0' || + (dpname[1] == '.' && dpname[2] == '\0'))) + continue; + +#ifdef DEBUG + dlog("... gives %s", dp->d_name); +#endif /* DEBUG */ + val = xmalloc(dlen + 5); + sprintf(val, "fs:=%s", *dir); + (*fn) (m, strdup(dp->d_name), val); + } + closedir(dirp); + } + + /* + * Add wildcard entry + */ + { + char *val = xmalloc(strlen(dir[-1]) + 5); + + sprintf(val, "fs:=%s", dir[-1]); + (*fn) (m, strdup("*"), val); + } + XFREE(mapd); + XFREE(v); + return 0; +} diff --git a/contrib/amd/amd/map.c b/contrib/amd/amd/map.c new file mode 100644 index 0000000..20320d9 --- /dev/null +++ b/contrib/amd/amd/map.c @@ -0,0 +1,1112 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: map.c,v 5.2.2.2 1992/08/02 10:42:21 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +#define smallest_t(t1, t2) (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2) +#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART) +#define NEVER (time_t) 0 +#define new_gen() (am_gen++) + +/* + * Generation Numbers. + * + * Generation numbers are allocated to every node created + * by amd. When a filehandle is computed and sent to the + * kernel, the generation number makes sure that it is safe + * to reallocate a node slot even when the kernel has a cached + * reference to its old incarnation. + * No garbage collection is done, since it is assumed that + * there is no way that 2^32 generation numbers could ever + * be allocated by a single run of amd - there is simply + * not enough cpu time available. + */ +static u_int am_gen = 2; /* Initial generation number */ +static int timeout_mp_id; /* Id from last call to timeout */ + +am_node *root_node; /* The root of the mount tree */ +am_node **exported_ap = (am_node **) 0; +int exported_ap_size = 0; +int first_free_map = 0; /* First available free slot */ +int last_used_map = -1; /* Last unavailable used slot */ + + +/* + * This is the default attributes field which + * is copied into every new node to be created. + * The individual filesystem fs_init() routines + * patch the copy to represent the particular + * details for the relevant filesystem type + */ +static nfsfattr gen_fattr = +{ + NFLNK, /* type */ + NFSMODE_LNK | 0777, /* mode */ + 1, /* nlink */ + 0, /* uid */ + 0, /* gid */ + 0, /* size */ + 4096, /* blocksize */ + 0, /* rdev */ + 1, /* blocks */ + 0, /* fsid */ + 0, /* fileid */ + {0, 0}, /* atime */ + {0, 0}, /* mtime */ + {0, 0}, /* ctime */ +}; + +/* forward declarations */ +static int unmount_node(am_node *mp); +static void exported_ap_free(am_node *mp); +static void remove_am(am_node *mp); + + +/* + * Resize exported_ap map + */ +static int +exported_ap_realloc_map(int nsize) +{ + /* + * this shouldn't happen, but... + */ + if (nsize < 0 || nsize == exported_ap_size) + return 0; + + exported_ap = (am_node **) xrealloc((voidp) exported_ap, nsize * sizeof(am_node *)); + + if (nsize > exported_ap_size) + memset((char *) (exported_ap + exported_ap_size), 0, + (nsize - exported_ap_size) * sizeof(am_node *)); + exported_ap_size = nsize; + + return 1; +} + + +/* + * Allocate a new mount slot and create + * a new node. + * Fills in the map number of the node, + * but leaves everything else uninitialised. + */ +am_node * +exported_ap_alloc(void) +{ + am_node *mp, **mpp; + + /* + * First check if there are any slots left, realloc if needed + */ + if (first_free_map >= exported_ap_size) + if (!exported_ap_realloc_map(exported_ap_size + NEXP_AP)) + return 0; + + /* + * Grab the next free slot + */ + mpp = exported_ap + first_free_map; + mp = *mpp = ALLOC(struct am_node); + memset((char *) mp, 0, sizeof(*mp)); + + mp->am_mapno = first_free_map++; + + /* + * Update free pointer + */ + while (first_free_map < exported_ap_size && exported_ap[first_free_map]) + first_free_map++; + + if (first_free_map > last_used_map) + last_used_map = first_free_map - 1; + + return mp; +} + + +/* + * Free a mount slot + */ +static void +exported_ap_free(am_node *mp) +{ + /* + * Sanity check + */ + if (!mp) + return; + + /* + * Zero the slot pointer to avoid double free's + */ + exported_ap[mp->am_mapno] = 0; + + /* + * Update the free and last_used indices + */ + if (mp->am_mapno == last_used_map) + while (last_used_map >= 0 && exported_ap[last_used_map] == 0) + --last_used_map; + + if (first_free_map > mp->am_mapno) + first_free_map = mp->am_mapno; + + /* + * Free the mount node + */ + XFREE(mp); +} + + +/* + * Insert mp into the correct place, + * where p_mp is its parent node. + * A new node gets placed as the youngest sibling + * of any other children, and the parent's child + * pointer is adjusted to point to the new child node. + */ +void +insert_am(am_node *mp, am_node *p_mp) +{ + /* + * If this is going in at the root then flag it + * so that it cannot be unmounted by amq. + */ + if (p_mp == root_node) + mp->am_flags |= AMF_ROOT; + /* + * Fill in n-way links + */ + mp->am_parent = p_mp; + mp->am_osib = p_mp->am_child; + if (mp->am_osib) + mp->am_osib->am_ysib = mp; + p_mp->am_child = mp; +} + + +/* + * Remove am from its place in the mount tree + */ +static void +remove_am(am_node *mp) +{ + /* + * 1. Consistency check + */ + if (mp->am_child && mp->am_parent) { + plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path); + } + + /* + * 2. Update parent's child pointer + */ + if (mp->am_parent && mp->am_parent->am_child == mp) + mp->am_parent->am_child = mp->am_osib; + + /* + * 3. Unlink from sibling chain + */ + if (mp->am_ysib) + mp->am_ysib->am_osib = mp->am_osib; + if (mp->am_osib) + mp->am_osib->am_ysib = mp->am_ysib; +} + + +/* + * Compute a new time to live value for a node. + */ +void +new_ttl(am_node *mp) +{ + mp->am_timeo_w = 0; + mp->am_ttl = clocktime(); + mp->am_fattr.na_atime.nt_seconds = mp->am_ttl; + mp->am_ttl += mp->am_timeo; /* sun's -tl option */ +} + + +void +mk_fattr(am_node *mp, nfsftype vntype) +{ + switch (vntype) { + case NFDIR: + mp->am_fattr.na_type = NFDIR; + mp->am_fattr.na_mode = NFSMODE_DIR | 0555; + mp->am_fattr.na_nlink = 2; + mp->am_fattr.na_size = 512; + break; + case NFLNK: + mp->am_fattr.na_type = NFLNK; + mp->am_fattr.na_mode = NFSMODE_LNK | 0777; + mp->am_fattr.na_nlink = 1; + mp->am_fattr.na_size = 0; + break; + default: + plog(XLOG_FATAL, "Unknown fattr type %d - ignored", vntype); + break; + } +} + + +/* + * Initialise an allocated mount node. + * It is assumed that the mount node was b-zero'd + * before getting here so anything that would + * be set to zero isn't done here. + */ +void +init_map(am_node *mp, char *dir) +{ + /* + * mp->am_mapno is initialized by exported_ap_alloc + * other fields don't need to be set to zero. + */ + mp->am_mnt = new_mntfs(); + mp->am_name = strdup(dir); + mp->am_path = strdup(dir); + mp->am_gen = new_gen(); + + mp->am_timeo = gopt.am_timeo; + mp->am_attr.ns_status = NFS_OK; + mp->am_fattr = gen_fattr; + mp->am_fattr.na_fsid = 42; + mp->am_fattr.na_fileid = 0; + mp->am_fattr.na_atime.nt_seconds = clocktime(); + mp->am_fattr.na_atime.nt_useconds = 0; + mp->am_fattr.na_mtime = mp->am_fattr.na_ctime = mp->am_fattr.na_atime; + + new_ttl(mp); + mp->am_stats.s_mtime = mp->am_fattr.na_atime.nt_seconds; +} + + +/* + * Free a mount node. + * The node must be already unmounted. + */ +void +free_map(am_node *mp) +{ + + remove_am(mp); + + if (mp->am_link) + XFREE(mp->am_link); + if (mp->am_name) + XFREE(mp->am_name); + if (mp->am_path) + XFREE(mp->am_path); + if (mp->am_pref) + XFREE(mp->am_pref); + if (mp->am_transp) + XFREE(mp->am_transp); + + if (mp->am_mnt) + free_mntfs(mp->am_mnt); + + exported_ap_free(mp); +} + + +/* + * Convert from file handle to automount node. + */ +am_node * +fh_to_mp3(am_nfs_fh *fhp, int *rp, int c_or_d) +{ + struct am_fh *fp = (struct am_fh *) fhp; + am_node *ap = 0; + + /* + * Check process id matches + * If it doesn't then it is probably + * from an old kernel cached filehandle + * which is now out of date. + */ + if (fp->fhh_pid != mypid) + goto drop; + + /* + * Make sure the index is valid before + * exported_ap is referenced. + */ + if (fp->fhh_id < 0 || fp->fhh_id >= exported_ap_size) + goto drop; + + /* + * Get hold of the supposed mount node + */ + ap = exported_ap[fp->fhh_id]; + + /* + * If it exists then maybe... + */ + if (ap) { + /* + * Check the generation number in the node + * matches the one from the kernel. If not + * then the old node has been timed out and + * a new one allocated. + */ + if (ap->am_gen != fp->fhh_gen) { + ap = 0; + goto drop; + } + /* + * If the node is hung then locate a new node + * for it. This implements the replicated filesystem + * retries. + */ + if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) { + int error; + am_node *orig_ap = ap; + +#ifdef DEBUG + dlog("fh_to_mp3: %s (%s) is hung:- call lookup", + orig_ap->am_path, orig_ap->am_mnt->mf_info); +#endif /* DEBUG */ + + /* + * Update modify time of parent node. + * With any luck the kernel will re-stat + * the child node and get new information. + */ + orig_ap->am_fattr.na_mtime.nt_seconds = clocktime(); + + /* + * Call the parent's lookup routine for an object + * with the same name. This may return -1 in error + * if a mount is in progress. In any case, if no + * mount node is returned the error code is propagated + * to the caller. + */ + if (c_or_d == VLOOK_CREATE) { + ap = (*orig_ap->am_parent->am_mnt->mf_ops->lookuppn) + (orig_ap->am_parent, orig_ap->am_name, &error, c_or_d); + } else { + ap = 0; + error = ESTALE; + } + if (ap == 0) { + if (error < 0 && amd_state == Finishing) + error = ENOENT; + *rp = error; + return 0; + } + + /* + * Update last access to original node. This + * avoids timing it out and so sending ESTALE + * back to the kernel. + * XXX - Not sure we need this anymore (jsp, 90/10/6). + */ + new_ttl(orig_ap); + + } + + /* + * Disallow references to objects being unmounted, unless + * they are automount points. + */ + if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) && + !(ap->am_flags & AMF_ROOT)) { + if (amd_state == Finishing) + *rp = ENOENT; + else + *rp = -1; + return 0; + } + new_ttl(ap); + } + +drop: + if (!ap || !ap->am_mnt) { + /* + * If we are shutting down then it is likely + * that this node has disappeared because of + * a fast timeout. To avoid things thrashing + * just pretend it doesn't exist at all. If + * ESTALE is returned, some NFS clients just + * keep retrying (stupid or what - if it's + * stale now, what's it going to be in 5 minutes?) + */ + if (amd_state == Finishing) + *rp = ENOENT; + else + *rp = ESTALE; + amd_stats.d_stale++; + } + + return ap; +} + + +am_node * +fh_to_mp(am_nfs_fh *fhp) +{ + int dummy; + + return fh_to_mp2(fhp, &dummy); +} + + +/* + * Convert from automount node to file handle. + */ +void +mp_to_fh(am_node *mp, am_nfs_fh *fhp) +{ + struct am_fh *fp = (struct am_fh *) fhp; + + memset((char *) fhp, 0, sizeof(am_nfs_fh)); + + /* + * Take the process id + */ + fp->fhh_pid = mypid; + + /* + * ... the map number + */ + fp->fhh_id = mp->am_mapno; + + /* + * ... and the generation number + */ + fp->fhh_gen = mp->am_gen; + + /* + * ... to make a "unique" triple that will never + * be reallocated except across reboots (which doesn't matter) + * or if we are unlucky enough to be given the same + * pid as a previous amd (very unlikely). + */ +} + + +am_node * +find_ap2(char *dir, am_node *mp) +{ + if (mp) { + am_node *mp2; + if (STREQ(mp->am_path, dir)) + return mp; + + if ((mp->am_mnt->mf_flags & MFF_MOUNTED) && + STREQ(mp->am_mnt->mf_mount, dir)) + return mp; + + mp2 = find_ap2(dir, mp->am_osib); + if (mp2) + return mp2; + return find_ap2(dir, mp->am_child); + } + + return 0; +} + + +/* + * Find the mount node corresponding to dir. dir can match either the + * automount path or, if the node is mounted, the mount location. + */ +am_node * +find_ap(char *dir) +{ + int i; + + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + if (mp && (mp->am_flags & AMF_ROOT)) { + mp = find_ap2(dir, exported_ap[i]); + if (mp) { + return mp; + } + } + } + + return 0; +} + + +/* + * Find the mount node corresponding + * to the mntfs structure. + */ +am_node * +find_mf(mntfs *mf) +{ + int i; + + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + if (mp && mp->am_mnt == mf) + return mp; + } + + return 0; +} + + +/* + * Get the filehandle for a particular named directory. + * This is used during the bootstrap to tell the kernel + * the filehandles of the initial automount points. + */ +am_nfs_fh * +root_fh(char *dir) +{ + static am_nfs_fh nfh; + am_node *mp = root_ap(dir, TRUE); + if (mp) { + mp_to_fh(mp, &nfh); + /* + * Patch up PID to match main server... + */ + if (!foreground) { + long pid = getppid(); + ((struct am_fh *) &nfh)->fhh_pid = pid; +#ifdef DEBUG + dlog("root_fh substitutes pid %d", pid); +#endif /* DEBUG */ + } + return &nfh; + } + + /* + * Should never get here... + */ + plog(XLOG_ERROR, "Can't find root filehandle for %s", dir); + + return 0; +} + + +am_node * +root_ap(char *dir, int path) +{ + am_node *mp = find_ap(dir); + + if (mp && mp->am_parent == root_node) + return mp; + + return 0; +} + + +/* + * Timeout all nodes waiting on + * a given Fserver. + */ +void +map_flush_srvr(fserver *fs) +{ + int i; + int done = 0; + + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) { + plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host); + mp->am_ttl = clocktime(); + done = 1; + } + } + if (done) + reschedule_timeout_mp(); +} + + +/* + * Mount a top level automount node + * by calling lookup in the parent + * (root) node which will cause the + * automount node to be automounted. + */ +int +mount_auto_node(char *dir, voidp arg) +{ + int error = 0; + + (void) amfs_auto_ops.lookuppn((am_node *) arg, dir, &error, VLOOK_CREATE); + if (error > 0) { + errno = error; /* XXX */ + plog(XLOG_ERROR, "Could not mount %s: %m", dir); + } + return error; +} + + +/* + * Cause all the top-level mount nodes + * to be automounted + */ +int +mount_exported(void) +{ + /* + * Iterate over all the nodes to be started + */ + return root_keyiter((void (*)P((char *, voidp))) mount_auto_node, root_node); +} + + +/* + * Construct top-level node + */ +void +make_root_node(void) +{ + mntfs *root_mnt; + char *rootmap = ROOT_MAP; + root_node = exported_ap_alloc(); + + /* + * Allocate a new map + */ + init_map(root_node, ""); + + /* + * Allocate a new mounted filesystem + */ + root_mnt = find_mntfs(&amfs_root_ops, (am_opts *) 0, "", rootmap, "", "", ""); + + /* + * Replace the initial null reference + */ + free_mntfs(root_node->am_mnt); + root_node->am_mnt = root_mnt; + + /* + * Initialise the root + */ + if (root_mnt->mf_ops->fs_init) + (*root_mnt->mf_ops->fs_init) (root_mnt); + + /* + * Mount the root + */ + root_mnt->mf_error = (*root_mnt->mf_ops->mount_fs) (root_node); +} + + +/* + * Cause all the nodes to be unmounted by timing + * them out. + */ +void +umount_exported(void) +{ + int i; + + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + + if (mp) { + mntfs *mf = mp->am_mnt; + if (mf->mf_flags & MFF_UNMOUNTING) { + /* + * If this node is being unmounted then just ignore it. However, + * this could prevent amd from finishing if the unmount gets blocked + * since the am_node will never be free'd. am_unmounted needs + * telling about this possibility. - XXX + */ + continue; + } + + if (mf && !(mf->mf_ops->fs_flags & FS_DIRECTORY)) { + /* + * When shutting down this had better + * look like a directory, otherwise it + * can't be unmounted! + */ + mk_fattr(mp, NFDIR); + } + + if ((--immediate_abort < 0 && + !(mp->am_flags & AMF_ROOT) && mp->am_parent) || + (mf->mf_flags & MFF_RESTART)) { + + /* + * Just throw this node away without bothering to unmount it. If + * the server is not known to be up then don't discard the mounted + * on directory or Amd might hang... + */ + if (mf->mf_server && + (mf->mf_server->fs_flags & (FSF_DOWN | FSF_VALID)) != FSF_VALID) + mf->mf_flags &= ~MFF_MKMNT; + if (gopt.flags & CFM_UNMOUNT_ON_EXIT) { + plog(XLOG_INFO, "on-exit attempt to unmount %s", mf->mf_mount); + unmount_node(mp); + } + am_unmounted(mp); + + } else { + /* + * Any other node gets forcibly timed out. + */ + mp->am_flags &= ~AMF_NOTIMEOUT; + mp->am_mnt->mf_flags &= ~MFF_RSTKEEP; + mp->am_ttl = 0; + mp->am_timeo = 1; + mp->am_timeo_w = 0; + } + } + } +} + + +static int +unmount_node(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + int error; + + if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) { + /* + * Just unlink + */ +#ifdef DEBUG + if (mf->mf_flags & MFF_ERROR) + dlog("No-op unmount of error node %s", mf->mf_info); +#endif /* DEBUG */ + error = 0; + } else { +#ifdef DEBUG + dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info); +#endif /* DEBUG */ + error = (*mf->mf_ops->umount_fs) (mp); + } + + if (error) { + errno = error; /* XXX */ +#ifdef DEBUG + dlog("%s: unmount: %m", mf->mf_mount); +#endif /* DEBUG */ + } + + return error; +} + + +static int +unmount_node_wrap(voidp vp) +{ + return unmount_node((am_node *) vp); + + /* + * Below is the comment left from the old code + * that was dependent on the macro FLUSH_KERNEL_NAME_CACHE + */ + /* + * This code should just say: + * return unmount_node((am_node *) vp); + * + * However... + * The kernel keeps a cached copy of filehandles, + * and doesn't ever uncache them (apparently). So + * when Amd times out a node the kernel will have a + * stale filehandle. When the kernel next uses the + * filehandle it gets ESTALE. + * + * The workaround: + * Arrange that when a node is removed an unlink or + * rmdir is done on that path so that the kernel + * cache is done. Yes - yuck. + * + * This can all be removed (and the background + * unmount flag in amfs_link_ops) if/when the kernel does + * something smarter. + * + * If the unlink or rmdir failed then just log a warning, + * don't fail the unmount. This can occur if the kernel + * client code decides that the object is still referenced + * and should be renamed rather than discarded. + * + * There is still a race condition here... + * if another process is trying to access the same + * filesystem at the time we get here, then + * it will block, since the MF_UNMOUNTING flag will + * be set. That may, or may not, cause the entire + * system to deadlock. Hmmm... + */ +} + + +static void +free_map_if_success(int rc, int term, voidp closure) +{ + am_node *mp = (am_node *) closure; + mntfs *mf = mp->am_mnt; + + /* + * Not unmounting any more + */ + mf->mf_flags &= ~MFF_UNMOUNTING; + + /* + * If a timeout was defered because the underlying filesystem + * was busy then arrange for a timeout as soon as possible. + */ + if (mf->mf_flags & MFF_WANTTIMO) { + mf->mf_flags &= ~MFF_WANTTIMO; + reschedule_timeout_mp(); + } + if (term) { + plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term); +#if defined(DEBUG) && defined(SIGTRAP) + /* + * dbx likes to put a trap on exit(). + * Pretend it succeeded for now... + */ + if (term == SIGTRAP) { + am_unmounted(mp); + } +#endif /* DEBUG */ + amd_stats.d_uerr++; + } else if (rc) { + if (rc == EBUSY) { + plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount); + } else { + errno = rc; /* XXX */ + plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path); + } + amd_stats.d_uerr++; + } else { + am_unmounted(mp); + } + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) mf); +} + + +static int +unmount_mp(am_node *mp) +{ + int was_backgrounded = 0; + mntfs *mf = mp->am_mnt; + +#ifdef notdef + plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount); +#endif /* notdef */ + + if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) && + (mf->mf_flags & MFF_MOUNTED)) { + if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) { + /* + * Don't try to unmount from a server that is known to be down + */ + if (!(mf->mf_flags & MFF_LOGDOWN)) { + /* Only log this once, otherwise gets a bit boring */ + plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path); + mf->mf_flags |= MFF_LOGDOWN; + } + } else { + /* Clear logdown flag - since the server must be up */ + mf->mf_flags &= ~MFF_LOGDOWN; +#ifdef DEBUG + dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount); + /* dlog("Will background the unmount attempt"); */ +#endif /* DEBUG */ + /* + * Note that we are unmounting this node + */ + mf->mf_flags |= MFF_UNMOUNTING; + run_task(unmount_node_wrap, (voidp) mp, + free_map_if_success, (voidp) mp); + was_backgrounded = 1; +#ifdef DEBUG + dlog("unmount attempt backgrounded"); +#endif /* DEBUG */ + } + } else { +#ifdef DEBUG + dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount); + dlog("Trying unmount in foreground"); +#endif /* DEBUG */ + mf->mf_flags |= MFF_UNMOUNTING; + free_map_if_success(unmount_node(mp), 0, (voidp) mp); +#ifdef DEBUG + dlog("unmount attempt done"); +#endif /* DEBUG */ + } + + return was_backgrounded; +} + + +void +timeout_mp(voidp v) +{ + int i; + time_t t = NEVER; + time_t now = clocktime(); + int backoff = NumChild / 4; + +#ifdef DEBUG + dlog("Timing out automount points..."); +#endif /* DEBUG */ + + for (i = last_used_map; i >= 0; --i) { + am_node *mp = exported_ap[i]; + mntfs *mf; + + /* + * Just continue if nothing mounted, or can't be timed out. + */ + if (!mp || (mp->am_flags & AMF_NOTIMEOUT)) + continue; + + /* + * Pick up mounted filesystem + */ + mf = mp->am_mnt; + if (!mf) + continue; + + /* + * Don't delete last reference to a restarted filesystem. + */ + if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1) + continue; + + /* + * If there is action on this filesystem then ignore it + */ + if (!(mf->mf_flags & IGNORE_FLAGS)) { + int expired = 0; + mf->mf_flags &= ~MFF_WANTTIMO; + if (now >= mp->am_ttl) { + if (!backoff) { + expired = 1; + + /* + * Move the ttl forward to avoid thrashing effects + * on the next call to timeout! + */ + /* sun's -tw option */ + if (mp->am_timeo_w < 4 * gopt.am_timeo_w) + mp->am_timeo_w += gopt.am_timeo_w; + mp->am_ttl = now + mp->am_timeo_w; + + } else { + /* + * Just backoff this unmount for + * a couple of seconds to avoid + * many multiple unmounts being + * started in parallel. + */ + mp->am_ttl = now + backoff + 1; + } + } + + /* + * If the next ttl is smallest, use that + */ + t = smallest_t(t, mp->am_ttl); + + if (!mp->am_child && mf->mf_error >= 0 && expired) { + /* + * If the unmount was backgrounded then + * bump the backoff counter. + */ + if (unmount_mp(mp)) { + backoff = 2; + } + } + } else if (mf->mf_flags & MFF_UNMOUNTING) { + mf->mf_flags |= MFF_WANTTIMO; + } + } + + if (t == NEVER) { +#ifdef DEBUG + dlog("No further timeouts"); +#endif /* DEBUG */ + t = now + ONE_HOUR; + } + + /* + * Sanity check to avoid runaways. + * Absolutely should never get this but + * if you do without this trap amd will thrash. + */ + if (t <= now) { + t = now + 6; /* XXX */ + plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!"); + } + + /* + * XXX - when shutting down, make things happen faster + */ + if ((int) amd_state >= (int) Finishing) + t = now + 1; +#ifdef DEBUG + dlog("Next mount timeout in %ds", t - now); +#endif /* DEBUG */ + + timeout_mp_id = timeout(t - now, timeout_mp, 0); +} + + +/* + * Cause timeout_mp to be called soonest + */ +void +reschedule_timeout_mp(void) +{ + if (timeout_mp_id) + untimeout(timeout_mp_id); + timeout_mp_id = timeout(0, timeout_mp, 0); +} diff --git a/contrib/amd/amd/mapc.c b/contrib/amd/amd/mapc.c new file mode 100644 index 0000000..de95e13 --- /dev/null +++ b/contrib/amd/amd/mapc.c @@ -0,0 +1,1205 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: mapc.c,v 5.2.2.2 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Mount map cache + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * Make a duplicate reference to an existing map + */ +#define mapc_dup(m) ((m)->refc++, (m)) + +/* + * Map cache types + * default, none, incremental, all, regexp + * MAPC_RE implies MAPC_ALL and must be numerically + * greater. + */ +#define MAPC_DFLT 0x000 +#define MAPC_NONE 0x001 +#define MAPC_INC 0x002 +#define MAPC_ROOT 0x004 +#define MAPC_ALL 0x010 +#define MAPC_CACHE_MASK 0x0ff +#define MAPC_SYNC 0x100 + +#ifdef HAVE_REGEXEC +# define MAPC_RE 0x020 +# define MAPC_ISRE(m) ((m)->alloc == MAPC_RE) +#else /* not HAVE_REGEXEC */ +# define MAPC_ISRE(m) FALSE +#endif /* not HAVE_REGEXEC */ + +/* + * Lookup recursion + */ +#define MREC_FULL 2 +#define MREC_PART 1 +#define MREC_NONE 0 + +#define MAX_CHAIN 2048 + +static struct opt_tab mapc_opt[] = +{ + {"all", MAPC_ALL}, + {"default", MAPC_DFLT}, + {"inc", MAPC_INC}, + {"mapdefault", MAPC_DFLT}, + {"none", MAPC_NONE}, +#ifdef HAVE_REGEXEC + {"re", MAPC_RE}, + {"regexp", MAPC_RE}, +#endif /* HAVE_REGEXEC */ + {"sync", MAPC_SYNC}, + {0, 0} +}; + +/* + * Wildcard key + */ +static char wildcard[] = "*"; + +/* + * Map type + */ +typedef struct map_type map_type; +struct map_type { + char *name; /* Name of this map type */ + init_fn *init; /* Initialisation */ + reload_fn *reload; /* Reload or fill */ + isup_fn *isup; /* Is service up or not? (1=up, 0=down) */ + search_fn *search; /* Search for new entry */ + mtime_fn *mtime; /* Find modify time */ + int def_alloc; /* Default allocation mode */ +}; + +/* + * Map for root node + */ +static mnt_map *root_map; + +/* + * List of known maps + */ +qelem map_list_head = {&map_list_head, &map_list_head}; + +/* + * Configuration + */ + +/* forward definitions */ +static const char *get_full_path(const char *map, const char *path, const char *type); +static int mapc_meta_search(mnt_map *, char *, char **, int); +static void mapc_sync(mnt_map *); + +/* ROOT MAP */ +static int root_init(mnt_map *, char *, time_t *); + +/* ERROR MAP */ +static int error_init(mnt_map *, char *, time_t *); +static int error_reload(mnt_map *, char *, add_fn *); +static int error_search(mnt_map *, char *, char *, char **, time_t *); +static int error_mtime(mnt_map *, char *, time_t *); + +/* PASSWD MAPS */ +#ifdef HAVE_MAP_PASSWD +extern int passwd_init(mnt_map *, char *, time_t *); +extern int passwd_search(mnt_map *, char *, char *, char **, time_t *); +#endif /* HAVE_MAP_PASSWD */ + +/* HESIOD MAPS */ +#ifdef HAVE_MAP_HESIOD +extern int amu_hesiod_init(mnt_map *, char *map, time_t *tp); +extern int hesiod_search(mnt_map *, char *, char *, char **, time_t *); +#endif /* HAVE_MAP_HESIOD */ + +/* LDAP MAPS */ +#ifdef HAVE_MAP_LDAP +extern int amu_ldap_init(mnt_map *, char *map, time_t *tp); +extern int amu_ldap_search(mnt_map *, char *, char *, char **, time_t *); +extern int amu_ldap_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_LDAP */ + +/* UNION MAPS */ +#ifdef HAVE_MAP_UNION +extern int union_init(mnt_map *, char *, time_t *); +extern int union_search(mnt_map *, char *, char *, char **, time_t *); +extern int union_reload(mnt_map *, char *, add_fn *); +#endif /* HAVE_MAP_UNION */ + +/* Network Information Service PLUS (NIS+) */ +#ifdef HAVE_MAP_NISPLUS +extern int nisplus_init(mnt_map *, char *, time_t *); +extern int nisplus_reload(mnt_map *, char *, add_fn *); +extern int nisplus_search(mnt_map *, char *, char *, char **, time_t *); +extern int nisplus_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_NISPLUS */ + +/* Network Information Service (YP, Yellow Pages) */ +#ifdef HAVE_MAP_NIS +extern int nis_init(mnt_map *, char *, time_t *); +extern int nis_reload(mnt_map *, char *, add_fn *); +extern int nis_isup(mnt_map *, char *); +extern int nis_search(mnt_map *, char *, char *, char **, time_t *); +extern int nis_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_NIS */ + +/* NDBM MAPS */ +#ifdef HAVE_MAP_NDBM +extern int ndbm_init(mnt_map *, char *, time_t *); +extern int ndbm_search(mnt_map *, char *, char *, char **, time_t *); +extern int ndbm_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_NDBM */ + +/* FILE MAPS */ +#ifdef HAVE_MAP_FILE +extern int file_init(mnt_map *, char *, time_t *); +extern int file_reload(mnt_map *, char *, add_fn *); +extern int file_search(mnt_map *, char *, char *, char **, time_t *); +extern int file_mtime(mnt_map *, char *, time_t *); +#endif /* HAVE_MAP_FILE */ + + +/* note that the choice of MAPC_{INC,ALL} will affect browsable_dirs */ +static map_type maptypes[] = +{ + { + "root", + root_init, + error_reload, + NULL, /* isup function */ + error_search, + error_mtime, + MAPC_ROOT + }, +#ifdef HAVE_MAP_PASSWD + { + "passwd", + passwd_init, + error_reload, + NULL, /* isup function */ + passwd_search, + error_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_PASSWD */ +#ifdef HAVE_MAP_HESIOD + { + "hesiod", + amu_hesiod_init, + error_reload, + NULL, /* isup function */ + hesiod_search, + error_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_HESIOD */ +#ifdef HAVE_MAP_LDAP + { + "ldap", + amu_ldap_init, + error_reload, + NULL, /* isup function */ + amu_ldap_search, + amu_ldap_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_LDAP */ +#ifdef HAVE_MAP_UNION + { + "union", + union_init, + union_reload, + NULL, /* isup function */ + union_search, + error_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_UNION */ +#ifdef HAVE_MAP_NISPLUS + { + "nisplus", + nisplus_init, + nisplus_reload, + NULL, /* isup function */ + nisplus_search, + nisplus_mtime, + MAPC_INC + }, +#endif /* HAVE_MAP_NISPLUS */ +#ifdef HAVE_MAP_NIS + { + "nis", + nis_init, + nis_reload, + nis_isup, /* is NIS up or not? */ + nis_search, + nis_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_NIS */ +#ifdef HAVE_MAP_NDBM + { + "ndbm", + ndbm_init, + error_reload, + NULL, /* isup function */ + ndbm_search, + ndbm_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_NDBM */ +#ifdef HAVE_MAP_FILE + { + "file", + file_init, + file_reload, + NULL, /* isup function */ + file_search, + file_mtime, + MAPC_ALL + }, +#endif /* HAVE_MAP_FILE */ + { + "error", + error_init, + error_reload, + NULL, /* isup function */ + error_search, + error_mtime, + MAPC_NONE + }, +}; + + +/* + * Hash function + */ +static u_int +kvhash_of(char *key) +{ + u_int i, j; + + for (i = 0; (j = *key++); i += j) ; + + return i % NKVHASH; +} + + +void +mapc_showtypes(char *buf) +{ + map_type *mt; + char *sep = ""; + + buf[0] = '\0'; + for (mt = maptypes; mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); mt++) { + strcat(buf, sep); + strcat(buf, mt->name); + sep = ", "; + } +} + + +/* + * Add key and val to the map m. + * key and val are assumed to be safe copies + */ +void mapc_add_kv(mnt_map *m, char *key, char *val) +{ + kv **h; + kv *n; + int hash = kvhash_of(key); +#ifdef HAVE_REGEXEC + regex_t re; +#endif /* HAVE_REGEXEC */ + +#ifdef DEBUG + dlog("add_kv: %s -> %s", key, val); +#endif /* DEBUG */ + +#ifdef HAVE_REGEXEC + if (MAPC_ISRE(m)) { + char pattern[MAXPATHLEN]; + int retval; + + /* + * Make sure the string is bound to the start and end + */ + sprintf(pattern, "^%s$", key); + retval = regcomp(&re, pattern, REG_ICASE); + if (retval != 0) { + char errstr[256]; + + /* XXX: this code was recently ported, and must be tested -Erez */ + errstr[0] = '\0'; + regerror(retval, &re, errstr, 256); + plog(XLOG_USER, "error compiling RE \"%s\": %s", pattern, errstr); + return; + } + } +#endif /* HAVE_REGEXEC */ + + h = &m->kvhash[hash]; + n = ALLOC(struct kv); + n->key = key; +#ifdef HAVE_REGEXEC + memcpy(&n->re, &re, sizeof(regex_t)); +#endif /* HAVE_REGEXEC */ + n->val = val; + n->next = *h; + *h = n; +} + + +static void +mapc_repl_kv(mnt_map *m, char *key, char *val) +{ + kv *k; + + /* + * Compute the hash table offset + */ + k = m->kvhash[kvhash_of(key)]; + + /* + * Scan the linked list for the key + */ + while (k && !FSTREQ(k->key, key)) + k = k->next; + + if (k) { + XFREE(k->val); + k->val = val; + } else { + mapc_add_kv(m, key, val); + } +} + + +/* + * Search a map for a key. + * Calls map specific search routine. + * While map is out of date, keep re-syncing. + */ +static int +search_map(mnt_map *m, char *key, char **valp) +{ + int rc; + + do { + rc = (*m->search) (m, m->map_name, key, valp, &m->modify); + if (rc < 0) { + plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name); + mapc_sync(m); + } + } while (rc < 0); + + return rc; +} + + +/* + * Do a wildcard lookup in the map and + * save the result. + */ +static void +mapc_find_wildcard(mnt_map *m) +{ + /* + * Attempt to find the wildcard entry + */ + int rc = search_map(m, wildcard, &m->wildcard); + + if (rc != 0) + m->wildcard = 0; +} + + +/* + * Do a map reload + */ +static int +mapc_reload_map(mnt_map *m) +{ + int error; + +#ifdef DEBUG + dlog("calling map reload on %s", m->map_name); +#endif /* DEBUG */ + error = (*m->reload) (m, m->map_name, mapc_add_kv); + if (error) + return error; + m->wildcard = 0; + +#ifdef DEBUG + dlog("calling mapc_search for wildcard"); +#endif /* DEBUG */ + error = mapc_search(m, wildcard, &m->wildcard); + if (error) + m->wildcard = 0; + + return 0; +} + + +/* + * Create a new map + */ +static mnt_map * +mapc_create(char *map, char *opt, const char *type) +{ + mnt_map *m = ALLOC(struct mnt_map); + map_type *mt; + time_t modify; + int alloc = 0; + + cmdoption(opt, mapc_opt, &alloc); + + /* + * If using a configuration file, and the map_type is defined, then look + * for it, in the maptypes array. If found, initialize the map using that + * map_type. If not found, return error. If no map_type was defined, + * default to cycling through all maptypes. + */ + if (use_conf_file && type) { + /* find what type of map this one is */ + for (mt = maptypes; + mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); + mt++) { + if (STREQ(type, mt->name)) { + plog(XLOG_INFO, "initializing amd conf map %s of type %s", map, type); + if ((*mt->init) (m, map, &modify) == 0) { + break; + } else { + plog(XLOG_ERROR, "failed to initialize map %s", map); + error_init(m, map, &modify); + break; + } + } + } /* end of "for (mt =" loop */ + + } else { /* cycle through all known maptypes */ + + /* + * not using amd conf file or using it by w/o specifying map type + */ + for (mt = maptypes; + mt < maptypes + sizeof(maptypes) / sizeof(maptypes[0]); + mt++) { +#ifdef DEBUG + dlog("trying to initialize map %s of type %s ...", map, mt->name); +#endif /* DEBUG */ + if ((*mt->init) (m, map, &modify) == 0) { + break; + } + } + } /* end of "if (use_conf_file && (colpos = strchr ..." statement */ + + /* assert: mt in maptypes */ + + m->flags = alloc & ~MAPC_CACHE_MASK; + alloc &= MAPC_CACHE_MASK; + + if (alloc == MAPC_DFLT) + alloc = mt->def_alloc; + + switch (alloc) { + default: + plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt); + alloc = MAPC_INC; + /* fallthrough... */ + case MAPC_NONE: + case MAPC_INC: + case MAPC_ROOT: + break; + + case MAPC_ALL: + /* + * If there is no support for reload and it was requested + * then back off to incremental instead. + */ + if (mt->reload == error_reload) { + plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name); + alloc = MAPC_INC; + } + break; + +#ifdef HAVE_REGEXEC + case MAPC_RE: + if (mt->reload == error_reload) { + plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name); + mt = &maptypes[sizeof(maptypes) / sizeof(maptypes[0]) - 1]; + /* assert: mt->name == "error" */ + } + break; +#endif /* HAVE_REGEXEC */ + } + +#ifdef DEBUG + dlog("Map for %s coming from maptype %s", map, mt->name); +#endif /* DEBUG */ + + m->alloc = alloc; + m->reload = mt->reload; + m->isup = mt->isup; + m->modify = modify; + m->search = alloc >= MAPC_ALL ? error_search : mt->search; + m->mtime = mt->mtime; + memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); + m->map_name = strdup(map); + m->refc = 1; + m->wildcard = 0; + + /* + * synchronize cache with reality + */ + mapc_sync(m); + + return m; +} + + +/* + * Free the cached data in a map + */ +static void +mapc_clear(mnt_map *m) +{ + int i; + + /* + * For each of the hash slots, chain + * along free'ing the data. + */ + for (i = 0; i < NKVHASH; i++) { + kv *k = m->kvhash[i]; + while (k) { + kv *n = k->next; + XFREE(k->key); + if (k->val) + XFREE(k->val); + XFREE(k); + k = n; + } + } + + /* + * Zero the hash slots + */ + memset((voidp) m->kvhash, 0, sizeof(m->kvhash)); + + /* + * Free the wildcard if it exists + */ + if (m->wildcard) { + XFREE(m->wildcard); + m->wildcard = 0; + } +} + + +/* + * Find a map, or create one if it does not exist + */ +mnt_map * +mapc_find(char *map, char *opt, const char *maptype) +{ + mnt_map *m; + + /* + * Search the list of known maps to see if + * it has already been loaded. If it is found + * then return a duplicate reference to it. + * Otherwise make a new map as required and + * add it to the list of maps + */ + ITER(m, mnt_map, &map_list_head) + if (STREQ(m->map_name, map)) + return mapc_dup(m); + m = mapc_create(map, opt, maptype); + ins_que(&m->hdr, &map_list_head); + + return m; +} + + +/* + * Free a map. + */ +void +mapc_free(voidp v) +{ + mnt_map *m = v; + + /* + * Decrement the reference count. + * If the reference count hits zero + * then throw the map away. + */ + if (m && --m->refc == 0) { + mapc_clear(m); + XFREE(m->map_name); + rem_que(&m->hdr); + XFREE(m); + } +} + + +/* + * Search the map for the key. Put a safe (malloc'ed) copy in *pval or + * return an error code + */ +static int +mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse) +{ + int error = 0; + kv *k = 0; + + /* + * Firewall + */ + if (!m) { + plog(XLOG_ERROR, "Null map request for %s", key); + return ENOENT; + } + if (m->flags & MAPC_SYNC) { + /* + * Get modify time... + */ + time_t t; + error = (*m->mtime) (m, m->map_name, &t); + if (error || t > m->modify) { + m->modify = t; + plog(XLOG_INFO, "Map %s is out of date", m->map_name); + mapc_sync(m); + } + } + + if (!MAPC_ISRE(m)) { + /* + * Compute the hash table offset + */ + k = m->kvhash[kvhash_of(key)]; + + /* + * Scan the linked list for the key + */ + while (k && !FSTREQ(k->key, key)) + k = k->next; + + } + +#ifdef HAVE_REGEXEC + else if (recurse == MREC_FULL) { + /* + * Try for an RE match against the entire map. + * Note that this will be done in a "random" + * order. + */ + int i; + + for (i = 0; i < NKVHASH; i++) { + k = m->kvhash[i]; + while (k) { + int retval; + + /* XXX: this code was recently ported, and must be tested -Erez */ + retval = regexec(&k->re, key, 0, 0, 0); + if (retval == 0) { /* succeeded */ + break; + } else { /* failed to match, log error */ + char errstr[256]; + + errstr[0] = '\0'; + regerror(retval, &k->re, errstr, 256); + plog(XLOG_USER, "error matching RE \"%s\" against \"%s\": %s", + key, k->key, errstr); + } + k = k->next; + } + if (k) + break; + } + } +#endif /* HAVE_REGEXEC */ + + /* + * If found then take a copy + */ + if (k) { + if (k->val) + *pval = strdup(k->val); + else + error = ENOENT; + } else if (m->alloc >= MAPC_ALL) { + /* + * If the entire map is cached then this + * key does not exist. + */ + error = ENOENT; + } else { + /* + * Otherwise search the map. If we are + * in incremental mode then add the key + * to the cache. + */ + error = search_map(m, key, pval); + if (!error && m->alloc == MAPC_INC) + mapc_add_kv(m, strdup(key), strdup(*pval)); + } + + /* + * If an error, and a wildcard exists, + * and the key is not internal then + * return a copy of the wildcard. + */ + if (error > 0) { + if (recurse == MREC_FULL && !MAPC_ISRE(m)) { + char wildname[MAXPATHLEN]; + char *subp; + if (*key == '/') + return error; + /* + * Keep chopping sub-directories from the RHS + * and replacing with "/ *" and repeat the lookup. + * For example: + * "src/gnu/gcc" -> "src / gnu / *" -> "src / *" + */ + strcpy(wildname, key); + while (error && (subp = strrchr(wildname, '/'))) { + strcpy(subp, "/*"); +#ifdef DEBUG + dlog("mapc recurses on %s", wildname); +#endif /* DEBUG */ + error = mapc_meta_search(m, wildname, pval, MREC_PART); + if (error) + *subp = 0; + } + + if (error > 0 && m->wildcard) { + *pval = strdup(m->wildcard); + error = 0; + } + } + } + return error; +} + + +int +mapc_search(mnt_map *m, char *key, char **pval) +{ + return mapc_meta_search(m, key, pval, MREC_FULL); +} + + +/* + * Get map cache in sync with physical representation + */ +static void +mapc_sync(mnt_map *m) +{ + if (m->alloc != MAPC_ROOT) { + + /* do not clear map if map service is down */ + if (m->isup) { + if (!((*m->isup)(m, m->map_name))) { + plog(XLOG_ERROR, "mapc_sync: map %s is down: not clearing map", m->map_name); + return; + } + } + + mapc_clear(m); + + if (m->alloc >= MAPC_ALL) + if (mapc_reload_map(m)) + m->alloc = MAPC_INC; + /* + * Attempt to find the wildcard entry + */ + if (m->alloc < MAPC_ALL) + mapc_find_wildcard(m); + } +} + + +/* + * Reload all the maps + * Called when Amd gets hit by a SIGHUP. + */ +void +mapc_reload(void) +{ + mnt_map *m; + + /* + * For all the maps, + * Throw away the existing information. + * Do a reload + * Find the wildcard + */ + ITER(m, mnt_map, &map_list_head) + mapc_sync(m); +} + + +/* + * Root map. + * The root map is used to bootstrap amd. + * All the require top-level mounts are added + * into the root map and then the map is iterated + * and a lookup is done on all the mount points. + * This causes the top level mounts to be automounted. + */ +static int +root_init(mnt_map *m, char *map, time_t *tp) +{ + *tp = clocktime(); + return STREQ(map, ROOT_MAP) ? 0 : ENOENT; +} + + +/* + * Add a new entry to the root map + * + * dir - directory (key) + * opts - mount options + * map - map name + * cfm - optional amd configuration file map section structure + */ +void +root_newmap(const char *dir, const char *opts, const char *map, const cf_map_t *cfm) +{ + char str[MAXPATHLEN]; + + /* + * First make sure we have a root map to talk about... + */ + if (!root_map) + root_map = mapc_find(ROOT_MAP, "mapdefault", NULL); + + /* + * Then add the entry... + */ + + /* + * Here I plug in the code to process other amd.conf options like + * map_type, search_path, and flags (browsable_dirs, mount_type). + */ + + if (cfm) { + if (map) { + sprintf(str, "cache:=mapdefault;type:=%s;fs:=\"%s\"", + cfm->cfm_flags & CFM_MOUNT_TYPE_AUTOFS ? "autofs" : "toplvl", + get_full_path(map, cfm->cfm_search_path, cfm->cfm_type)); + if (opts && opts[0] != '\0') { + strcat(str, ";"); + strcat(str, opts); + } + if (cfm->cfm_flags & CFM_BROWSABLE_DIRS_FULL) + strcat(str, ";opts:=rw,fullybrowsable"); + if (cfm->cfm_flags & CFM_BROWSABLE_DIRS) + strcat(str, ";opts:=rw,browsable"); + if (cfm->cfm_type) { + strcat(str, ";maptype:="); + strcat(str, cfm->cfm_type); + } + } else { + strcpy(str, opts); + } + } else { + if (map) + sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s", + map, opts ? opts : ""); + else + strcpy(str, opts); + } + mapc_repl_kv(root_map, strdup((char *)dir), strdup(str)); +} + + +int +mapc_keyiter(mnt_map *m, void (*fn) (char *, voidp), voidp arg) +{ + int i; + int c = 0; + + for (i = 0; i < NKVHASH; i++) { + kv *k = m->kvhash[i]; + while (k) { + (*fn) (k->key, arg); + k = k->next; + c++; + } + } + + return c; +} + + +/* + * Iterate on the root map and call (*fn)() on the key of all the nodes. + * Finally throw away the root map. + */ +int +root_keyiter(void (*fn)(char *, voidp), voidp arg) +{ + if (root_map) { + int c = mapc_keyiter(root_map, fn, arg); + return c; + } + + return 0; +} + + +/* + * Was: NEW_TOPLVL_READDIR + * Search a chain for an entry with some name. + * -Erez Zadok + */ +static int +key_already_in_chain(char *keyname, const nfsentry *chain) +{ + const nfsentry *tmpchain = chain; + + while (tmpchain) { + if (keyname && tmpchain->ne_name && STREQ(keyname, tmpchain->ne_name)) + return 1; + tmpchain = tmpchain->ne_nextentry; + } + + return 0; +} + + +/* + * Create a chain of entries which are not linked. + * -Erez Zadok + */ +nfsentry * +make_entry_chain(am_node *mp, const nfsentry *current_chain, int fully_browsable) +{ + static u_int last_cookie = ~(u_int) 0 - 1; + static nfsentry chain[MAX_CHAIN]; + static int max_entries = MAX_CHAIN; + char *key; + int num_entries = 0, preflen = 0, i; + nfsentry *retval = (nfsentry *) NULL; + mntfs *mf; + mnt_map *mmp; + + if (!mp) { + plog(XLOG_DEBUG, "make_entry_chain: mp is (NULL)"); + return retval; + } + mf = mp->am_mnt; + if (!mf) { + plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt is (NULL)"); + return retval; + } + mmp = (mnt_map *) mf->mf_private; + if (!mmp) { + plog(XLOG_DEBUG, "make_entry_chain: mp->am_mnt->mf_private is (NULL)"); + return retval; + } + + /* iterate over keys */ + for (i = 0; i < NKVHASH; i++) { + kv *k; + for (k = mmp->kvhash[i]; k ; k = k->next) { + + /* + * Skip unwanted entries which are either not real entries or + * very difficult to interpret (wildcards...) This test needs + * lots of improvement. Any takers? + */ + key = k->key; + if (!key) + continue; + + /* Skip '*' */ + if (!fully_browsable && strchr(key, '*')) + continue; + + /* + * If the map has a prefix-string then check if the key starts with + * this * string, and if it does, skip over this prefix. + */ + if (preflen) { + if (!NSTREQ(key, mp->am_pref, preflen)) + continue; + key += preflen; + } + + /* no more '/' are allowed, unless browsable_dirs=full was used */ + if (!fully_browsable && strchr(key, '/')) + continue; + + /* no duplicates allowed */ + if (key_already_in_chain(key, current_chain)) + continue; + + /* fill in a cell and link the entry */ + if (num_entries >= max_entries) { + /* out of space */ + plog(XLOG_DEBUG, "make_entry_chain: no more space in chain"); + if (num_entries > 0) { + chain[num_entries - 1].ne_nextentry = 0; + retval = &chain[0]; + } + return retval; + } + + /* we have space. put entry in next cell */ + --last_cookie; + chain[num_entries].ne_fileid = (u_int) last_cookie; + *(u_int *) chain[num_entries].ne_cookie = + (u_int) last_cookie; + chain[num_entries].ne_name = key; + if (num_entries < max_entries - 1) { /* link to next one */ + chain[num_entries].ne_nextentry = &chain[num_entries + 1]; + } + ++num_entries; + } /* end of "while (k)" */ + } /* end of "for (i ... NKVHASH ..." */ + + /* terminate chain */ + if (num_entries > 0) { + chain[num_entries - 1].ne_nextentry = 0; + retval = &chain[0]; + } + + return retval; +} + + +/* + * Error map + */ +static int +error_init(mnt_map *m, char *map, time_t *tp) +{ + plog(XLOG_USER, "No source data for map %s", map); + *tp = 0; + + return 0; +} + + +static int +error_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp) +{ + return ENOENT; +} + + +static int +error_reload(mnt_map *m, char *map, add_fn *fn) +{ + return ENOENT; +} + + +static int +error_mtime(mnt_map *m, char *map, time_t *tp) +{ + *tp = 0; + + return 0; +} + + +/* + * Return absolute path of map, searched in a type-specific path. + * Note: uses a static buffer for returned data. + */ +static const char * +get_full_path(const char *map, const char *path, const char *type) +{ + char component[MAXPATHLEN], *str; + static char full_path[MAXPATHLEN]; + int len; + + /* for now, only file-type search paths are implemented */ + if (type && !STREQ(type, "file")) + return map; + + /* if null map, return it */ + if (!map) + return map; + + /* if map includes a '/', return it (absolute or relative path) */ + if (strchr(map, '/')) + return map; + + /* if path is empty, return map */ + if (!path) + return map; + + /* now break path into components, and search in each */ + strcpy(component, path); + + str = strtok(component, ":"); + do { + strcpy(full_path, str); + len = strlen(full_path); + if (full_path[len - 1] != '/') /* add trailing "/" if needed */ + strcat(full_path, "/"); + strcat(full_path, map); + if (access(full_path, R_OK) == 0) + return full_path; + str = strtok(NULL, ":"); + } while (str); + + return map; /* if found nothing, return map */ +} diff --git a/contrib/amd/amd/mntfs.c b/contrib/amd/amd/mntfs.c new file mode 100644 index 0000000..31fa331 --- /dev/null +++ b/contrib/amd/amd/mntfs.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: mntfs.c,v 5.2.2.2 1992/08/02 10:42:21 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +qelem mfhead = {&mfhead, &mfhead}; + +int mntfs_allocated; + + +mntfs * +dup_mntfs(mntfs *mf) +{ + if (mf->mf_refc == 0) { + if (mf->mf_cid) + untimeout(mf->mf_cid); + mf->mf_cid = 0; + } + mf->mf_refc++; + + return mf; +} + + +static void +init_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) +{ + mf->mf_ops = ops; + mf->mf_fo = mo; + mf->mf_mount = strdup(mp); + mf->mf_info = strdup(info); + mf->mf_auto = strdup(auto_opts); + mf->mf_mopts = strdup(mopts); + mf->mf_remopts = strdup(remopts); + mf->mf_refc = 1; + mf->mf_flags = 0; + mf->mf_error = -1; + mf->mf_cid = 0; + mf->mf_private = 0; + mf->mf_prfree = 0; + + if (ops->ffserver) + mf->mf_server = (*ops->ffserver) (mf); + else + mf->mf_server = 0; +} + + +static mntfs * +alloc_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) +{ + mntfs *mf = ALLOC(struct mntfs); + + init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts); + ins_que(&mf->mf_q, &mfhead); + mntfs_allocated++; + + return mf; +} + + +mntfs * +find_mntfs(am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) +{ + mntfs *mf; + +#ifdef DEBUG + dlog("Locating mntfs reference to %s", mp); +#endif /* DEBUG */ + + ITER(mf, mntfs, &mfhead) { + if (STREQ(mf->mf_mount, mp)) { + /* + * Handle cases where error ops are involved + */ + if (ops == &amfs_error_ops) { + /* + * If the existing ops are not amfs_error_ops + * then continue... + */ + if (mf->mf_ops != &amfs_error_ops) + continue; + else + return dup_mntfs(mf); + } else { /* ops != &amfs_error_ops */ + /* + * If the existing ops are amfs_error_ops + * then continue... + */ + if (mf->mf_ops == &amfs_error_ops) + continue; + } + + if ((mf->mf_flags & MFF_RESTART) && amd_state == Run) { + /* + * Restart a previously mounted filesystem. + */ + mntfs *mf2 = alloc_mntfs(&amfs_inherit_ops, mo, mp, info, auto_opts, mopts, remopts); +#ifdef DEBUG + dlog("Restarting filesystem %s", mf->mf_mount); +#endif /* DEBUG */ + + /* + * Remember who we are restarting + */ + mf2->mf_private = (voidp) dup_mntfs(mf); + mf2->mf_prfree = free_mntfs; + return mf2; + } + + mf->mf_fo = mo; + if (!(mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING))) { + fserver *fs; + mf->mf_flags &= ~MFF_ERROR; + mf->mf_error = -1; + mf->mf_auto = strealloc(mf->mf_auto, auto_opts); + mf->mf_mopts = strealloc(mf->mf_mopts, mopts); + mf->mf_remopts = strealloc(mf->mf_remopts, remopts); + mf->mf_info = strealloc(mf->mf_info, info); + + if (mf->mf_private && mf->mf_prfree) { + (*mf->mf_prfree) (mf->mf_private); + mf->mf_private = 0; + } + + fs = ops->ffserver ? (*ops->ffserver) (mf) : (fserver *) NULL; + if (mf->mf_server) + free_srvr(mf->mf_server); + mf->mf_server = fs; + } + return dup_mntfs(mf); + } + } + + return alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts); +} + + +mntfs * +new_mntfs(void) +{ + return alloc_mntfs(&amfs_error_ops, (am_opts *) 0, "//nil//", ".", "", "", ""); +} + + +static void +uninit_mntfs(mntfs *mf, int rmd) +{ + if (mf->mf_auto) + XFREE(mf->mf_auto); + if (mf->mf_mopts) + XFREE(mf->mf_mopts); + if (mf->mf_remopts) + XFREE(mf->mf_remopts); + if (mf->mf_info) + XFREE(mf->mf_info); + if (mf->mf_private && mf->mf_prfree) + (*mf->mf_prfree) (mf->mf_private); + + /* + * Clean up any directories that were made + */ + if (rmd && (mf->mf_flags & MFF_MKMNT)) + rmdirs(mf->mf_mount); + /* free mf_mount _AFTER_ removing the directories */ + if (mf->mf_mount) + XFREE(mf->mf_mount); + + /* + * Clean up the file server + */ + if (mf->mf_server) + free_srvr(mf->mf_server); + + /* + * Don't do a callback on this mount + */ + if (mf->mf_cid) { + untimeout(mf->mf_cid); + mf->mf_cid = 0; + } +} + + +static void +discard_mntfs(voidp v) +{ + mntfs *mf = v; + + rem_que(&mf->mf_q); + + /* + * Free memory + */ + uninit_mntfs(mf, TRUE); + XFREE(mf); + + --mntfs_allocated; +} + + +void +flush_mntfs(void) +{ + mntfs *mf; + + mf = AM_FIRST(mntfs, &mfhead); + while (mf != HEAD(mntfs, &mfhead)) { + mntfs *mf2 = mf; + mf = NEXT(mntfs, mf); + if (mf2->mf_refc == 0 && mf2->mf_cid) + discard_mntfs(mf2); + } +} + + +void +free_mntfs(voidp v) +{ + mntfs *mf = v; + + if (--mf->mf_refc == 0) { + if (mf->mf_flags & MFF_MOUNTED) { + int quoted; + mf->mf_flags &= ~MFF_MOUNTED; + + /* + * Record for posterity + */ + quoted = strchr(mf->mf_info, ' ') != 0; /* cheap */ + plog(XLOG_INFO, "%s%s%s %sed fstype %s from %s", + quoted ? "\"" : "", + mf->mf_info, + quoted ? "\"" : "", + mf->mf_error ? "discard" : "unmount", + mf->mf_ops->fs_type, mf->mf_mount); + } + + if (mf->mf_ops->fs_flags & FS_DISCARD) { +#ifdef DEBUG + dlog("Immediately discarding mntfs for %s", mf->mf_mount); +#endif /* DEBUG */ + discard_mntfs(mf); + + } else { + +#ifdef DEBUG + if (mf->mf_flags & MFF_RESTART) { + dlog("Discarding remount hook for %s", mf->mf_mount); + } else { + dlog("Discarding last mntfs reference to %s fstype %s", + mf->mf_mount, mf->mf_ops->fs_type); + } + if (mf->mf_flags & (MFF_MOUNTED | MFF_MOUNTING | MFF_UNMOUNTING)) + dlog("mntfs reference for %s still active", mf->mf_mount); +#endif /* DEBUG */ + mf->mf_cid = timeout(ALLOWED_MOUNT_TIME, discard_mntfs, (voidp) mf); + } + } +} + + +mntfs * +realloc_mntfs(mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts) +{ + mntfs *mf2; + + if (mf->mf_refc == 1 && mf->mf_ops == &amfs_inherit_ops && STREQ(mf->mf_mount, mp)) { + /* + * If we are inheriting then just return + * the same node... + */ + return mf; + } + + /* + * Re-use the existing mntfs if it is mounted. + * This traps a race in nfsx. + */ + if (mf->mf_ops != &amfs_error_ops && + (mf->mf_flags & MFF_MOUNTED) && + !FSRV_ISDOWN(mf->mf_server)) { + mf->mf_fo = mo; + return mf; + } + + mf2 = find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts); + free_mntfs(mf); + return mf2; +} diff --git a/contrib/amd/amd/nfs_prot_svc.c b/contrib/amd/amd/nfs_prot_svc.c new file mode 100644 index 0000000..e2b1c70 --- /dev/null +++ b/contrib/amd/amd/nfs_prot_svc.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_prot_svc.c,v 5.2.2.1 1992/02/09 15:09:30 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* external definitions */ +extern voidp nfsproc_null_2_svc(voidp, struct svc_req *); +extern nfsattrstat * nfsproc_getattr_2_svc(am_nfs_fh *, struct svc_req *); +extern nfsattrstat * nfsproc_setattr_2_svc(nfssattrargs *, struct svc_req *); +extern voidp nfsproc_root_2_svc(voidp, struct svc_req *); +extern nfsdiropres * nfsproc_lookup_2_svc(nfsdiropargs *, struct svc_req *); +extern nfsreadlinkres * nfsproc_readlink_2_svc(am_nfs_fh *, struct svc_req *); +extern nfsreadres * nfsproc_read_2_svc(nfsreadargs *, struct svc_req *); +extern voidp nfsproc_writecache_2_svc(voidp, struct svc_req *); +extern nfsattrstat * nfsproc_write_2_svc(nfswriteargs *, struct svc_req *); +extern nfsdiropres * nfsproc_create_2_svc(nfscreateargs *, struct svc_req *); +extern nfsstat * nfsproc_remove_2_svc(nfsdiropargs *, struct svc_req *); +extern nfsstat * nfsproc_rename_2_svc(nfsrenameargs *, struct svc_req *); +extern nfsstat * nfsproc_link_2_svc(nfslinkargs *, struct svc_req *); +extern nfsstat * nfsproc_symlink_2_svc(nfssymlinkargs *, struct svc_req *); +extern nfsdiropres * nfsproc_mkdir_2_svc(nfscreateargs *, struct svc_req *); +extern nfsstat * nfsproc_rmdir_2_svc(nfsdiropargs *, struct svc_req *); +extern nfsreaddirres * nfsproc_readdir_2_svc(nfsreaddirargs *, struct svc_req *); +extern nfsstatfsres * nfsproc_statfs_2_svc(am_nfs_fh *, struct svc_req *); + +/* global variables */ +SVCXPRT *nfs_program_2_transp; + +/* typedefs */ +typedef char *(*nfssvcproc_t)(voidp, struct svc_req *); + + +void +nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp) +{ + union { + am_nfs_fh nfsproc_getattr_2_arg; + nfssattrargs nfsproc_setattr_2_arg; + nfsdiropargs nfsproc_lookup_2_arg; + am_nfs_fh nfsproc_readlink_2_arg; + nfsreadargs nfsproc_read_2_arg; + nfswriteargs nfsproc_write_2_arg; + nfscreateargs nfsproc_create_2_arg; + nfsdiropargs nfsproc_remove_2_arg; + nfsrenameargs nfsproc_rename_2_arg; + nfslinkargs nfsproc_link_2_arg; + nfssymlinkargs nfsproc_symlink_2_arg; + nfscreateargs nfsproc_mkdir_2_arg; + nfsdiropargs fsproc_rmdir_2_arg; + nfsreaddirargs nfsproc_readdir_2_arg; + am_nfs_fh nfsproc_statfs_2_arg; + } argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + nfssvcproc_t local; + + nfs_program_2_transp = NULL; + + switch (rqstp->rq_proc) { + + case NFSPROC_NULL: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (nfssvcproc_t) nfsproc_null_2_svc; + break; + + case NFSPROC_GETATTR: + xdr_argument = (xdrproc_t) xdr_nfs_fh; + xdr_result = (xdrproc_t) xdr_attrstat; + local = (nfssvcproc_t) nfsproc_getattr_2_svc; + break; + + case NFSPROC_SETATTR: + xdr_argument = (xdrproc_t) xdr_sattrargs; + xdr_result = (xdrproc_t) xdr_attrstat; + local = (nfssvcproc_t) nfsproc_setattr_2_svc; + break; + + case NFSPROC_ROOT: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (nfssvcproc_t) nfsproc_root_2_svc; + break; + + case NFSPROC_LOOKUP: + xdr_argument = (xdrproc_t) xdr_diropargs; + xdr_result = (xdrproc_t) xdr_diropres; + local = (nfssvcproc_t) nfsproc_lookup_2_svc; + /* + * Cheap way to pass transp down to amfs_auto_lookuppn so it can + * be stored in the am_node structure and later used for + * quick_reply(). + */ + nfs_program_2_transp = transp; + break; + + case NFSPROC_READLINK: + xdr_argument = (xdrproc_t) xdr_nfs_fh; + xdr_result = (xdrproc_t) xdr_readlinkres; + local = (nfssvcproc_t) nfsproc_readlink_2_svc; + break; + + case NFSPROC_READ: + xdr_argument = (xdrproc_t) xdr_readargs; + xdr_result = (xdrproc_t) xdr_readres; + local = (nfssvcproc_t) nfsproc_read_2_svc; + break; + + case NFSPROC_WRITECACHE: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (nfssvcproc_t) nfsproc_writecache_2_svc; + break; + + case NFSPROC_WRITE: + xdr_argument = (xdrproc_t) xdr_writeargs; + xdr_result = (xdrproc_t) xdr_attrstat; + local = (nfssvcproc_t) nfsproc_write_2_svc; + break; + + case NFSPROC_CREATE: + xdr_argument = (xdrproc_t) xdr_createargs; + xdr_result = (xdrproc_t) xdr_diropres; + local = (nfssvcproc_t) nfsproc_create_2_svc; + break; + + case NFSPROC_REMOVE: + xdr_argument = (xdrproc_t) xdr_diropargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_remove_2_svc; + break; + + case NFSPROC_RENAME: + xdr_argument = (xdrproc_t) xdr_renameargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_rename_2_svc; + break; + + case NFSPROC_LINK: + xdr_argument = (xdrproc_t) xdr_linkargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_link_2_svc; + break; + + case NFSPROC_SYMLINK: + xdr_argument = (xdrproc_t) xdr_symlinkargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_symlink_2_svc; + break; + + case NFSPROC_MKDIR: + xdr_argument = (xdrproc_t) xdr_createargs; + xdr_result = (xdrproc_t) xdr_diropres; + local = (nfssvcproc_t) nfsproc_mkdir_2_svc; + break; + + case NFSPROC_RMDIR: + xdr_argument = (xdrproc_t) xdr_diropargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_rmdir_2_svc; + break; + + case NFSPROC_READDIR: + xdr_argument = (xdrproc_t) xdr_readdirargs; + xdr_result = (xdrproc_t) xdr_readdirres; + local = (nfssvcproc_t) nfsproc_readdir_2_svc; + break; + + case NFSPROC_STATFS: + xdr_argument = (xdrproc_t) xdr_nfs_fh; + xdr_result = (xdrproc_t) xdr_statfsres; + local = (nfssvcproc_t) nfsproc_statfs_2_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + + memset((char *) &argument, 0, sizeof(argument)); + if (!svc_getargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) &argument)) { + plog(XLOG_ERROR, + "NFS xdr decode failed for %d %d %d", + rqstp->rq_prog, rqstp->rq_vers, rqstp->rq_proc); + svcerr_decode(transp); + return; + } + result = (*local) (&argument, rqstp); + + nfs_program_2_transp = NULL; + + if (result != NULL && !svc_sendreply(transp, + (XDRPROC_T_TYPE) xdr_result, + result)) { + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) & argument)) { + plog(XLOG_FATAL, "unable to free rpc arguments in nfs_program_2"); + going_down(1); + } +} diff --git a/contrib/amd/amd/nfs_start.c b/contrib/amd/amd/nfs_start.c new file mode 100644 index 0000000..e5740f6 --- /dev/null +++ b/contrib/amd/amd/nfs_start.c @@ -0,0 +1,472 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_start.c,v 5.2.2.1 1992/02/09 15:08:51 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +#ifndef SELECT_MAXWAIT +# define SELECT_MAXWAIT 16 +#endif /* not SELECT_MAXWAIT */ + +SVCXPRT *nfsxprt; +u_short nfs_port; + +#ifdef HAVE_FS_AUTOFS +SVCXPRT *autofsxprt = NULL; +u_short autofs_port = 0; +#endif /* HAVE_FS_AUTOFS */ + +#ifndef HAVE_SIGACTION +# define MASKED_SIGS (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP)) +#endif /* not HAVE_SIGACTION */ + +#ifdef DEBUG +/* + * Check that we are not burning resources + */ +static void +checkup(void) +{ + + static int max_fd = 0; + static char *max_mem = 0; + + int next_fd = dup(0); + caddr_t next_mem = sbrk(0); + close(next_fd); + + if (max_fd < next_fd) { + dlog("%d new fds allocated; total is %d", + next_fd - max_fd, next_fd); + max_fd = next_fd; + } + if (max_mem < next_mem) { +#ifdef HAVE_GETPAGESIZE + dlog("%#x bytes of memory allocated; total is %#x (%ld pages)", + next_mem - max_mem, next_mem, + ((long) next_mem + getpagesize() - 1) / getpagesize()); +#else /* not HAVE_GETPAGESIZE */ + dlog("%#x bytes of memory allocated; total is %#x", + next_mem - max_mem, next_mem); +#endif /* not HAVE_GETPAGESIZE */ + max_mem = next_mem; + + } +} +#endif /* DEBUG */ + + +static int +#ifdef HAVE_SIGACTION +do_select(sigset_t smask, int fds, fd_set *fdp, struct timeval *tvp) +#else /* not HAVE_SIGACTION */ +do_select(int smask, int fds, fd_set *fdp, struct timeval *tvp) +#endif /* not HAVE_SIGACTION */ +{ + + int sig; + int nsel; + + if ((sig = setjmp(select_intr))) { + select_intr_valid = 0; + /* Got a signal */ + switch (sig) { + case SIGINT: + case SIGTERM: + amd_state = Finishing; + reschedule_timeout_mp(); + break; + } + nsel = -1; + errno = EINTR; + } else { + select_intr_valid = 1; + /* + * Invalidate the current clock value + */ + clock_valid = 0; + /* + * Allow interrupts. If a signal + * occurs, then it will cause a longjmp + * up above. + */ +#ifdef HAVE_SIGACTION + sigprocmask(SIG_SETMASK, &smask, NULL); +#else /* not HAVE_SIGACTION */ + (void) sigsetmask(smask); +#endif /* not HAVE_SIGACTION */ + + /* + * Wait for input + */ + nsel = select(fds, fdp, (fd_set *) 0, (fd_set *) 0, + tvp->tv_sec ? tvp : (struct timeval *) 0); + } + +#ifdef HAVE_SIGACTION + sigprocmask(SIG_BLOCK, &masked_sigs, NULL); +#else /* not HAVE_SIGACTION */ + (void) sigblock(MASKED_SIGS); +#endif /* not HAVE_SIGACTION */ + + /* + * Perhaps reload the cache? + */ + if (do_mapc_reload < clocktime()) { + mapc_reload(); + do_mapc_reload = clocktime() + ONE_HOUR; + } + return nsel; +} + + +/* + * Determine whether anything is left in + * the RPC input queue. + */ +static int +rpc_pending_now(void) +{ + struct timeval tvv; + int nsel; +#ifdef FD_SET + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(fwd_sock, &readfds); +#else /* not FD_SET */ + int readfds = (1 << fwd_sock); +#endif /* not FD_SET */ + + tvv.tv_sec = tvv.tv_usec = 0; + nsel = select(FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &tvv); + if (nsel < 1) + return (0); +#ifdef FD_SET + if (FD_ISSET(fwd_sock, &readfds)) + return (1); +#else /* not FD_SET */ + if (readfds & (1 << fwd_sock)) + return (1); +#endif /* not FD_SET */ + + return (0); +} + + +static serv_state +run_rpc(void) +{ +#ifdef HAVE_SIGACTION + sigset_t smask; + sigprocmask(SIG_BLOCK, &masked_sigs, &smask); +#else /* not HAVE_SIGACTION */ + int smask = sigblock(MASKED_SIGS); +#endif /* not HAVE_SIGACTION */ + + next_softclock = clocktime(); + + amd_state = Run; + + /* + * Keep on trucking while we are in Run mode. This state + * is switched to Quit after all the file systems have + * been unmounted. + */ + while ((int) amd_state <= (int) Finishing) { + struct timeval tvv; + int nsel; + time_t now; +#ifdef HAVE_SVC_GETREQSET + fd_set readfds; + + memmove(&readfds, &svc_fdset, sizeof(svc_fdset)); + FD_SET(fwd_sock, &readfds); +#else /* not HAVE_SVC_GETREQSET */ +# ifdef FD_SET + fd_set readfds; + FD_ZERO(&readfds); + readfds.fds_bits[0] = svc_fds; + FD_SET(fwd_sock, &readfds); +# else /* not FD_SET */ + int readfds = svc_fds | (1 << fwd_sock); +# endif /* not FD_SET */ +#endif /* not HAVE_SVC_GETREQSET */ + +#ifdef DEBUG + checkup(); +#endif /* DEBUG */ + + /* + * If the full timeout code is not called, + * then recompute the time delta manually. + */ + now = clocktime(); + + if (next_softclock <= now) { + if (amd_state == Finishing) + umount_exported(); + tvv.tv_sec = softclock(); + } else { + tvv.tv_sec = next_softclock - now; + } + tvv.tv_usec = 0; + + if (amd_state == Finishing && last_used_map < 0) { + flush_mntfs(); + amd_state = Quit; + break; + } + if (tvv.tv_sec <= 0) + tvv.tv_sec = SELECT_MAXWAIT; +#ifdef DEBUG + if (tvv.tv_sec) { + dlog("Select waits for %ds", tvv.tv_sec); + } else { + dlog("Select waits for Godot"); + } +#endif /* DEBUG */ + + nsel = do_select(smask, FD_SETSIZE, &readfds, &tvv); + + switch (nsel) { + case -1: + if (errno == EINTR) { +#ifdef DEBUG + dlog("select interrupted"); +#endif /* DEBUG */ + continue; + } + perror("select"); + break; + + case 0: + break; + + default: + /* + * Read all pending NFS responses at once to avoid having responses. + * queue up as a consequence of retransmissions. + */ +#ifdef FD_SET + if (FD_ISSET(fwd_sock, &readfds)) { + FD_CLR(fwd_sock, &readfds); +#else /* not FD_SET */ + if (readfds & (1 << fwd_sock)) { + readfds &= ~(1 << fwd_sock); +#endif /* not FD_SET */ + --nsel; + do { + fwd_reply(); + } while (rpc_pending_now() > 0); + } + + if (nsel) { + /* + * Anything left must be a normal + * RPC request. + */ +#ifdef HAVE_SVC_GETREQSET + svc_getreqset(&readfds); +#else /* not HAVE_SVC_GETREQSET */ +# ifdef FD_SET + svc_getreq(readfds.fds_bits[0]); +# else /* not FD_SET */ + svc_getreq(readfds); +# endif /* not FD_SET */ +#endif /* not HAVE_SVC_GETREQSET */ + } + break; + } + } + +#ifdef HAVE_SIGACTION + sigprocmask(SIG_SETMASK, &smask, NULL); +#else /* not HAVE_SIGACTION */ + (void) sigsetmask(smask); +#endif /* not HAVE_SIGACTION */ + + if (amd_state == Quit) + amd_state = Done; + + return amd_state; +} + + +int +mount_automounter(int ppid) +{ + /* + * Old code replaced by rpc-trash patch. + * Erez Zadok + int so = socket(AF_INET, SOCK_DGRAM, 0); + */ + SVCXPRT *udp_amqp = NULL, *tcp_amqp = NULL; + int nmount, ret; + int soNFS; + int udp_soAMQ, tcp_soAMQ; +#ifdef HAVE_TRANSPORT_TYPE_TLI + struct netconfig *udp_amqncp, *tcp_amqncp; +#endif /* HAVE_TRANSPORT_TYPE_TLI */ +#ifdef HAVE_FS_AUTOFS + int soAUTOFS; +#endif /* HAVE_FS_AUTOFS */ + + /* + * Create the nfs service for amd + */ +#ifdef HAVE_TRANSPORT_TYPE_TLI + ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); + if (ret != 0) + return ret; + ret = create_amq_service(&udp_soAMQ, &udp_amqp, &udp_amqncp, &tcp_soAMQ, &tcp_amqp, &tcp_amqncp); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); + if (ret != 0) + return ret; + ret = create_amq_service(&udp_soAMQ, &udp_amqp, &tcp_soAMQ, &tcp_amqp); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + if (ret != 0) + return ret; + +#ifdef HAVE_FS_AUTOFS + /* + * Create the autofs service for amd. + */ + plog(XLOG_INFO, "creating autofs service listener"); + ret = create_autofs_service(&soAUTOFS, &autofs_port, &autofsxprt, autofs_program_1); + /* if autofs service fails it is OK if using a test amd */ + if (ret != 0 && gopt.portmap_program == AMQ_PROGRAM) + return ret; +#endif /* HAVE_FS_AUTOFS */ + + /* + * Start RPC forwarding + */ + if (fwd_init() != 0) + return 3; + + /* + * Construct the root automount node + */ + make_root_node(); + + /* + * Pick up the pieces from a previous run + * This is likely to (indirectly) need the rpc_fwd package + * so it *must* come after the call to fwd_init(). + */ + if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS) + restart(); + + /* + * Mount the top-level auto-mountpoints + */ + nmount = mount_exported(); + + /* + * Now safe to tell parent that we are up and running + */ + if (ppid) + kill(ppid, SIGQUIT); + + if (nmount == 0) { + plog(XLOG_FATAL, "No work to do - quitting"); + amd_state = Done; + return 0; + } + +#ifdef DEBUG + amuDebug(D_AMQ) { +#endif /* DEBUG */ + /* + * Complete registration of amq (first TCP service then UDP) + */ + unregister_amq(); + +#ifdef HAVE_TRANSPORT_TYPE_TLI + ret = svc_reg(tcp_amqp, get_amd_program_number(), AMQ_VERSION, + amq_program_1, tcp_amqncp); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + ret = svc_register(tcp_amqp, get_amd_program_number(), AMQ_VERSION, + amq_program_1, IPPROTO_TCP); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + if (ret != 1) { + plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, tcp)", get_amd_program_number()); + return 3; + } + +#ifdef HAVE_TRANSPORT_TYPE_TLI + ret = svc_reg(udp_amqp, get_amd_program_number(), AMQ_VERSION, + amq_program_1, udp_amqncp); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + ret = svc_register(udp_amqp, get_amd_program_number(), AMQ_VERSION, + amq_program_1, IPPROTO_UDP); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + if (ret != 1) { + plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, udp)", get_amd_program_number()); + return 4; + } + +#ifdef DEBUG + } +#endif /* DEBUG */ + + /* + * Start timeout_mp rolling + */ + reschedule_timeout_mp(); + + /* + * Start the server + */ + if (run_rpc() != Done) { + plog(XLOG_FATAL, "run_rpc failed"); + amd_state = Done; + } + return 0; +} diff --git a/contrib/amd/amd/nfs_subr.c b/contrib/amd/amd/nfs_subr.c new file mode 100644 index 0000000..3de0861 --- /dev/null +++ b/contrib/amd/amd/nfs_subr.c @@ -0,0 +1,610 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_subr.c,v 5.2.2.1 1992/02/09 15:08:53 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * Convert from UN*X to NFS error code. + * Some systems like linux define their own (see + * conf/mount/mount_linux.h). + */ +#ifndef nfs_error +# define nfs_error(e) ((nfsstat)(e)) +#endif /* nfs_error */ + +/* forward declarations */ +static void count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail); + + +static char * +do_readlink(am_node *mp, int *error_return, nfsattrstat **attrpp) +{ + char *ln; + + /* + * If there is a readlink method, then use + * that, otherwise if a link exists use + * that, otherwise use the mount point. + */ + if (mp->am_mnt->mf_ops->readlink) { + int retry = 0; + mp = (*mp->am_mnt->mf_ops->readlink) (mp, &retry); + if (mp == 0) { + *error_return = retry; + return 0; + } + /* reschedule_timeout_mp(); */ + } + + if (mp->am_link) { + ln = mp->am_link; + } else { + ln = mp->am_mnt->mf_mount; + } + if (attrpp) + *attrpp = &mp->am_attr; + + return ln; +} + + +voidp +nfsproc_null_2_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +nfsattrstat * +nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) +{ + static nfsattrstat res; + am_node *mp; + int retry; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "getattr:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(argp, &retry); + if (mp == 0) { + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tretry=%d", retry); +#endif /* DEBUG */ + + if (retry < 0) + return 0; + res.ns_status = nfs_error(retry); + } else { + nfsattrstat *attrp = &mp->am_attr; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path, + attrp->ns_u.ns_attr_u.na_size); +#endif /* DEBUG */ + + mp->am_stats.s_getattr++; + return attrp; + } + +#ifndef MNT2_NFS_OPT_SYMTTL + /* + * This code is needed to defeat Solaris 2.4's (and newer) symlink values + * cache. It forces the last-modifed time of the symlink to be current. + * It is not needed if the O/S has an nfs flag to turn off the + * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez. + */ + if (++res.ns_u.ns_attr_u.na_mtime.nt_useconds == 0) + ++res.ns_u.ns_attr_u.na_mtime.nt_seconds; +#endif /* not MNT2_NFS_OPT_SYMTTL */ + + return &res; +} + + +nfsattrstat * +nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp) +{ + static nfsattrstat res; + + if (!fh_to_mp(&argp->sag_fhandle)) + res.ns_status = nfs_error(ESTALE); + else + res.ns_status = nfs_error(EROFS); + + return &res; +} + + +voidp +nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +nfsdiropres * +nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) +{ + static nfsdiropres res; + am_node *mp; + int retry; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "lookup:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(&argp->da_fhandle, &retry); + if (mp == 0) { + if (retry < 0) + return 0; + res.dr_status = nfs_error(retry); + } else { + int error; + am_node *ap; +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->da_name); +#endif /* DEBUG */ + ap = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &error, VLOOK_CREATE); + if (ap == 0) { + if (error < 0) { +#ifdef DEBUG + dlog("Not sending RPC reply"); +#endif /* DEBUG */ + amd_stats.d_drops++; + return 0; + } + res.dr_status = nfs_error(error); + } else { + mp_to_fh(ap, &res.dr_u.dr_drok_u.drok_fhandle); + res.dr_u.dr_drok_u.drok_attributes = ap->am_fattr; + res.dr_status = NFS_OK; + } + mp->am_stats.s_lookup++; + /* reschedule_timeout_mp(); */ + } + + return &res; +} + + +void +quick_reply(am_node *mp, int error) +{ + SVCXPRT *transp = mp->am_transp; + nfsdiropres res; + xdrproc_t xdr_result = (xdrproc_t) xdr_diropres; + + /* + * If there's a transp structure then we can reply to the client's + * nfs lookup request. + */ + if (transp) { + if (error == 0) { + /* + * Construct a valid reply to a lookup request. Same + * code as in nfsproc_lookup_2_svc() above. + */ + mp_to_fh(mp, &res.dr_u.dr_drok_u.drok_fhandle); + res.dr_u.dr_drok_u.drok_attributes = mp->am_fattr; + res.dr_status = NFS_OK; + } else + /* + * Return the error that was passed to us. + */ + res.dr_status = nfs_error(error); + + /* + * Send off our reply + */ + if (!svc_sendreply(transp, (XDRPROC_T_TYPE) xdr_result, (SVC_IN_ARG_TYPE) & res)) + svcerr_systemerr(transp); + + /* + * Free up transp. It's only used for one reply. + */ + XFREE(transp); + mp->am_transp = NULL; +#ifdef DEBUG + dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); +#endif /* DEBUG */ + } +} + + +nfsreadlinkres * +nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) +{ + static nfsreadlinkres res; + am_node *mp; + int retry; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "readlink:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(argp, &retry); + if (mp == 0) { + readlink_retry: + if (retry < 0) + return 0; + res.rlr_status = nfs_error(retry); + } else { + char *ln = do_readlink(mp, &retry, (nfsattrstat **) 0); + if (ln == 0) + goto readlink_retry; + res.rlr_status = NFS_OK; +#ifdef DEBUG + amuDebug(D_TRACE) + if (ln) + plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln); +#endif /* DEBUG */ + res.rlr_u.rlr_data_u = ln; + mp->am_stats.s_readlink++; + } + + return &res; +} + + +nfsreadres * +nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp) +{ + static nfsreadres res; + + memset((char *) &res, 0, sizeof(res)); + res.rr_status = nfs_error(EACCES); + + return &res; +} + + +voidp +nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +nfsattrstat * +nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp) +{ + static nfsattrstat res; + + if (!fh_to_mp(&argp->wra_fhandle)) + res.ns_status = nfs_error(ESTALE); + else + res.ns_status = nfs_error(EROFS); + + return &res; +} + + +nfsdiropres * +nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp) +{ + static nfsdiropres res; + + if (!fh_to_mp(&argp->ca_where.da_fhandle)) + res.dr_status = nfs_error(ESTALE); + else + res.dr_status = nfs_error(EROFS); + + return &res; +} + + +static nfsstat * +unlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp) +{ + static nfsstat res; + int retry; + + am_node *mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_DELETE); + if (mp == 0) { + if (retry < 0) + return 0; + res = nfs_error(retry); + goto out; + } + + if (mp->am_fattr.na_type != NFDIR) { + res = nfs_error(ENOTDIR); + goto out; + } + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name); +#endif /* DEBUG */ + + mp = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &retry, VLOOK_DELETE); + if (mp == 0) { + /* + * Ignore retries... + */ + if (retry < 0) + retry = 0; + /* + * Usual NFS workaround... + */ + else if (retry == ENOENT) + retry = 0; + res = nfs_error(retry); + } else { + forcibly_timeout_mp(mp); + res = NFS_OK; + } + +out: + return &res; +} + + +nfsstat * +nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) +{ + return unlink_or_rmdir(argp, rqstp, TRUE); +} + + +nfsstat * +nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp) +{ + static nfsstat res; + + if (!fh_to_mp(&argp->rna_from.da_fhandle) || !fh_to_mp(&argp->rna_to.da_fhandle)) + res = nfs_error(ESTALE); + /* + * If the kernel is doing clever things with referenced files + * then let it pretend... + */ + else if (NSTREQ(argp->rna_to.da_name, ".nfs", 4)) + res = NFS_OK; + /* + * otherwise a failure + */ + else + res = nfs_error(EROFS); + + return &res; +} + + +nfsstat * +nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp) +{ + static nfsstat res; + + if (!fh_to_mp(&argp->la_fhandle) || !fh_to_mp(&argp->la_to.da_fhandle)) + res = nfs_error(ESTALE); + else + res = nfs_error(EROFS); + + return &res; +} + + +nfsstat * +nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp) +{ + static nfsstat res; + + if (!fh_to_mp(&argp->sla_from.da_fhandle)) + res = nfs_error(ESTALE); + else + res = nfs_error(EROFS); + + return &res; +} + + +nfsdiropres * +nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp) +{ + static nfsdiropres res; + + if (!fh_to_mp(&argp->ca_where.da_fhandle)) + res.dr_status = nfs_error(ESTALE); + else + res.dr_status = nfs_error(EROFS); + + return &res; +} + + +nfsstat * +nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) +{ + return unlink_or_rmdir(argp, rqstp, FALSE); +} + + +nfsreaddirres * +nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp) +{ + static nfsreaddirres res; + static nfsentry e_res[MAX_READDIR_ENTRIES]; + am_node *mp; + int retry; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "readdir:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(&argp->rda_fhandle, &retry); + if (mp == 0) { + if (retry < 0) + return 0; + res.rdr_status = nfs_error(retry); + } else { +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path); +#endif /* DEBUG */ + res.rdr_status = nfs_error((*mp->am_mnt->mf_ops->readdir) + (mp, argp->rda_cookie, + &res.rdr_u.rdr_reply_u, e_res, argp->rda_count)); + mp->am_stats.s_readdir++; + } + + return &res; +} + + +nfsstatfsres * +nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) +{ + static nfsstatfsres res; + am_node *mp; + int retry; + mntent_t mnt; + +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "statfs:"); +#endif /* DEBUG */ + + mp = fh_to_mp2(argp, &retry); + if (mp == 0) { + if (retry < 0) + return 0; + res.sfr_status = nfs_error(retry); + } else { + nfsstatfsokres *fp; +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path); +#endif /* DEBUG */ + + /* + * just return faked up file system information + */ + fp = &res.sfr_u.sfr_reply_u; + + fp->sfrok_tsize = 1024; + fp->sfrok_bsize = 1024; + + /* check if map is browsable and show_statfs_entries=yes */ + if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) && + mp->am_mnt && mp->am_mnt->mf_mopts) { + mnt.mnt_opts = mp->am_mnt->mf_mopts; + if (hasmntopt(&mnt, "browsable")) { + count_map_entries(mp, + &fp->sfrok_blocks, + &fp->sfrok_bfree, + &fp->sfrok_bavail); + } + } else { + fp->sfrok_blocks = 0; /* set to 1 if you don't want empty automounts */ + fp->sfrok_bfree = 0; + fp->sfrok_bavail = 0; + } + + res.sfr_status = NFS_OK; + mp->am_stats.s_statfs++; + } + + return &res; +} + + +/* + * count how many total entries there are in a map, and how many + * of them are in use. + */ +static void +count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail) +{ + u_int blocks, bfree, bavail, i; + mntfs *mf; + mnt_map *mmp; + kv *k; + + blocks = bfree = bavail = 0; + if (!mp) + goto out; + mf = mp->am_mnt; + if (!mf) + goto out; + mmp = (mnt_map *) mf->mf_private; + if (!mmp) + goto out; + + /* iterate over keys */ + for (i = 0; i < NKVHASH; i++) { + for (k = mmp->kvhash[i]; k ; k = k->next) { + if (!k->key) + continue; + blocks++; + /* + * XXX: Need to count how many are actively in use and recompute + * bfree and bavail based on it. + */ + } + } + +out: + *out_blocks = blocks; + *out_bfree = bfree; + *out_bavail = bavail; +} diff --git a/contrib/amd/amd/ops_TEMPLATE.c b/contrib/amd/amd/ops_TEMPLATE.c new file mode 100644 index 0000000..7a60206 --- /dev/null +++ b/contrib/amd/amd/ops_TEMPLATE.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_TEMPLATE.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * An empty template for an amd pseudo filesystem "foofs". + */ + +/* + * NOTE: if this is an Amd file system, prepend "amfs_" to all foofs symbols + * and renamed the file name to amfs_foofs.c. If it is a native file system + * (such as pcfs, isofs, or ffs), then you can keep the names as is, and + * just rename the file to ops_foofs.c. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward declarations */ +static char * foofs_match(am_opts *fo); +static int foofs_init(mntfs *mf); +static int foofs_mount(am_node *mp); +static int foofs_fmount(mntfs *mf); +static int foofs_umount(am_node *mp); +static int foofs_fumount(mntfs *mf); +static am_node * foofs_lookuppn(am_node *mp, char *fname, int *error_return, int op); +static int foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count); +static am_node * foofs_readlink(am_node *mp, int *error_return); +static void foofs_mounted(mntfs *mf); +static void foofs_umounted(am_node *mp); +fserver * foofs_ffserver(mntfs *mf); + + +/* + * Foofs operations. + * Define only those you need, others set to 0 (NULL) + */ +am_ops foofs_ops = +{ + "foofs", /* name of file system */ + foofs_match, /* match */ + foofs_init, /* initialize */ + foofs_mount, /* mount vnode */ + foofs_fmount, /* mount vfs */ + foofs_umount, /* unmount vnode */ + foofs_fumount, /* unmount VFS */ + foofs_lookuppn, /* lookup path-name */ + foofs_readdir, /* read directory */ + foofs_readlink, /* read link */ + foofs_mounted, /* after-mount extra actions */ + foofs_umounted, /* after-umount extra actions */ + foofs_ffserver, /* find a file server */ + FS_MKMNT | FS_BACKGROUND | FS_AMQINFO /* flags */ +}; + + +/* + * Check that f/s has all needed fields. + * Returns: matched string if found, NULL otherwise. + */ +static char * +foofs_match(am_opts *fo) +{ + char *cp = "fill this with a way to find the match"; + + plog(XLOG_INFO, "entering foofs_match..."); + + if (cp) + return cp; /* OK */ + + return NULL; /* not OK */ +} + + +/* + * Initialize. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_init(mntfs *mf) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_init..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Mount vnode. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_mount(am_node *mp) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_mount..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Mount vfs. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_fmount(mntfs *mf) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_fmount..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Unmount vnode. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_umount(am_node *mp) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_umount..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Unmount VFS. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +foofs_fumount(mntfs *mf) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_fumount..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Lookup path-name. + * Returns: the am_node that was found, or NULL if failed. + * If failed, also fills in errno in error_return. + */ +static am_node * +foofs_lookuppn(am_node *mp, char *fname, int *error_return, int op) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_lookuppn..."); + + error = EPERM; /* XXX: fixme */ + + *error_return = error; + return NULL; +} + + +/* + * Read directory. + * Returns: 0 if OK, non-zero (errno) if failed. + * If OK, fills in ep with chain of directory entries. + */ +static int +foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_readdir..."); + + error = EPERM; /* XXX: fixme */ + return error; +} + + +/* + * Read link. + * Returns: am_node found, or NULL if not found. + * If failed, fills in errno in error_return. + */ +static am_node * +foofs_readlink(am_node *mp, int *error_return) +{ + int error = 0; + + plog(XLOG_INFO, "entering foofs_readlink..."); + + error = EPERM; /* XXX: fixme */ + + *error_return = error; + return NULL; +} + + +/* + * Async mount callback function. + * After the base mount went OK, sometimes + * there are additional actions that are needed. See union_mounted() and + * toplvl_mounted(). + */ +static void +foofs_mounted(mntfs *mf) +{ + plog(XLOG_INFO, "entering foofs_mounted..."); + + return; +} + + +/* + * Async unmount callback function. + * After the base umount() succeeds, we may want to take extra actions, + * such as informing remote mount daemons that we've unmounted them. + * See amfs_auto_umounted(), host_umounted(), nfs_umounted(). + */ +static void +foofs_umounted(am_node *mp) +{ + plog(XLOG_INFO, "entering foofs_umounted..."); + + return; +} + + +/* + * Find a file server. + * Returns: fserver of found server, or NULL if not found. + */ +fserver * +foofs_ffserver(mntfs *mf) +{ + plog(XLOG_INFO, "entering foofs_ffserver..."); + + return NULL; +} diff --git a/contrib/amd/amd/ops_autofs.c b/contrib/amd/amd/ops_autofs.c new file mode 100644 index 0000000..a566fc4 --- /dev/null +++ b/contrib/amd/amd/ops_autofs.c @@ -0,0 +1,1275 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_autofs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Automounter filesystem + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * CLUDGE: wrap whole file in HAVE_FS_AUTOFS, becasue + * not all systems with an automounter file system are supported + * by am-utils yet... + */ + +#ifdef HAVE_FS_AUTOFS + +/* + * MACROS: + */ +#ifndef AUTOFS_NULL +# define AUTOFS_NULL ((u_long)0) +#endif /* not AUTOFS_NULL */ + +/* + * VARIABLES: + */ + +/* forward declarations */ +static int mount_autofs(char *dir, char *opts); +static int autofs_mount_1_svc(struct mntrequest *mr, struct mntres *result, struct authunix_parms *cred); +static int autofs_unmount_1_svc(struct umntrequest *ur, struct umntres *result, struct authunix_parms *cred); + +/* externam declarations */ +extern bool_t xdr_mntrequest(XDR *, mntrequest *); +extern bool_t xdr_mntres(XDR *, mntres *); +extern bool_t xdr_umntrequest(XDR *, umntrequest *); +extern bool_t xdr_umntres(XDR *, umntres *); + +/* + * STRUCTURES: + */ + +/* Sun's kernel-based automounter-supporting file system */ +am_ops autofs_ops = +{ + "autofs", + amfs_auto_match, + 0, /* amfs_auto_init */ + autofs_mount, + 0, + autofs_umount, + 0, + amfs_auto_lookuppn, + amfs_auto_readdir, /* browsable version of readdir() */ + 0, /* autofs_readlink */ + autofs_mounted, + 0, /* autofs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY +}; + + +/**************************************************************************** + *** FUNCTIONS *** + ****************************************************************************/ + +/* + * Mount the top-level using autofs + */ +int +autofs_mount(am_node *mp) +{ + mntfs *mf = mp->am_mnt; + struct stat stb; + char opts[256], preopts[256]; + int error; + char *mnttype; + + /* + * Mounting the automounter. + * Make sure the mount directory exists, construct + * the mount options and call the mount_autofs routine. + */ + + if (stat(mp->am_path, &stb) < 0) { + return errno; + } else if ((stb.st_mode & S_IFMT) != S_IFDIR) { + plog(XLOG_WARNING, "%s is not a directory", mp->am_path); + return ENOTDIR; + } + if (mf->mf_ops == &autofs_ops) + mnttype = "indirect"; + else if (mf->mf_ops == &amfs_direct_ops) + mnttype = "direct"; +#ifdef HAVE_AM_FS_UNION + else if (mf->mf_ops == &amfs_union_ops) + mnttype = "union"; +#endif /* HAVE_AM_FS_UNION */ + else + mnttype = "auto"; + + /* + * Construct some mount options: + * + * Tack on magic map= option in mtab to emulate + * SunOS automounter behavior. + */ + preopts[0] = '\0'; +#ifdef MNTTAB_OPT_INTR + strcat(preopts, MNTTAB_OPT_INTR); + strcat(preopts, ","); +#endif /* MNTTAB_OPT_INTR */ +#ifdef MNTTAB_OPT_IGNORE + strcat(preopts, MNTTAB_OPT_IGNORE); + strcat(preopts, ","); +#endif /* MNTTAB_OPT_IGNORE */ + sprintf(opts, "%s%s,%s=%d,%s=%d,%s=%d,%s,map=%s", + preopts, + MNTTAB_OPT_RW, + MNTTAB_OPT_PORT, nfs_port, + MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo, + MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans, + mnttype, mf->mf_info); + + /* now do the mount */ + error = mount_autofs(mf->mf_mount, opts); + if (error) { + errno = error; + plog(XLOG_FATAL, "mount_autofs: %m"); + return error; + } + return 0; +} + + +void +autofs_mounted(mntfs *mf) +{ + amfs_auto_mkcacheref(mf); +} + + +/* + * Unmount a top-level automount node + */ +int +autofs_umount(am_node *mp) +{ + int error; + struct stat stb; + + /* + * The lstat is needed if this mount is type=direct. When that happens, + * the kernel cache gets confused between the underlying type (dir) and + * the mounted type (link) and so needs to be re-synced before the + * unmount. This is all because the unmount system call follows links and + * so can't actually unmount a link (stupid!). It was noted that doing an + * ls -ld of the mount point to see why things were not working actually + * fixed the problem - so simulate an ls -ld here. + */ + if (lstat(mp->am_path, &stb) < 0) { +#ifdef DEBUG + dlog("lstat(%s): %m", mp->am_path); +#endif /* DEBUG */ + } + error = UMOUNT_FS(mp->am_path, mnttab_file_name); + if (error == EBUSY && mp->am_flags & AMF_AUTOFS) { + plog(XLOG_WARNING, "autofs_unmount of %s busy (autofs). exit", mp->am_path); + error = 0; /* fake unmount was ok */ + } + return error; +} + + +/* + * Mount an automounter directory. + * The automounter is connected into the system + * as a user-level NFS server. mount_autofs constructs + * the necessary NFS parameters to be given to the + * kernel so that it will talk back to us. + */ +static int +mount_autofs(char *dir, char *opts) +{ + char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; + char *map_opt, buf[MAXHOSTNAMELEN]; + int retry, error, flags; + struct utsname utsname; + mntent_t mnt; + autofs_args_t autofs_args; + MTYPE_TYPE type = MOUNT_TYPE_AUTOFS; + + memset((voidp) &autofs_args, 0, sizeof(autofs_args)); /* Paranoid */ + + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = pid_fsname; + mnt.mnt_opts = opts; + mnt.mnt_type = type; + + retry = hasmntval(&mnt, "retry"); + if (retry <= 0) + retry = 2; /* XXX */ + + /* + * SET MOUNT ARGS + */ + if (uname(&utsname) < 0) { + strcpy(buf, "localhost.autofs"); + } else { + strcpy(buf, utsname.nodename); + strcat(buf, ".autofs"); + } +#ifdef HAVE_FIELD_AUTOFS_ARGS_T_ADDR + autofs_args.addr.buf = buf; + autofs_args.addr.len = strlen(autofs_args.addr.buf); + autofs_args.addr.maxlen = autofs_args.addr.len; +#endif /* HAVE_FIELD_AUTOFS_ARGS_T_ADDR */ + + autofs_args.path = dir; + autofs_args.opts = opts; + + map_opt = hasmntopt(&mnt, "map"); + if (map_opt) { + map_opt += sizeof("map="); /* skip the "map=" */ + if (map_opt == NULL) { + plog(XLOG_WARNING, "map= has a null map name. reset to amd.unknown"); + map_opt = "amd.unknown"; + } + } + autofs_args.map = map_opt; + + /* XXX: these I set arbitrarily... */ + autofs_args.mount_to = 300; + autofs_args.rpc_to = 60; + autofs_args.direct = 0; + + /* + * Make a ``hostname'' string for the kernel + */ + sprintf(fs_hostname, "pid%ld@%s:%s", foreground ? mypid : getppid(), + hostname, dir); + + /* + * Most kernels have a name length restriction. + */ + if (strlen(fs_hostname) >= MAXHOSTNAMELEN) + strcpy(fs_hostname + MAXHOSTNAMELEN - 3, ".."); + + /* + * Finally we can compute the mount flags set above. + */ + flags = compute_mount_flags(&mnt); + + /* + * This is it! Here we try to mount amd on its mount points. + */ + error = mount_fs(&mnt, flags, (caddr_t) &autofs_args, retry, type, 0, NULL, mnttab_file_name); + return error; +} + + +/****************************************************************************/ +/* autofs program dispatcher */ +void +autofs_program_1(struct svc_req *rqstp, SVCXPRT *transp) +{ + int ret; + union { + mntrequest autofs_mount_1_arg; + umntrequest autofs_umount_1_arg; + } argument; + union { + mntres mount_res; + umntres umount_res; + } result; + + bool_t (*xdr_argument)(), (*xdr_result)(); + int (*local)(); + + switch (rqstp->rq_proc) { + + case AUTOFS_NULL: + svc_sendreply(transp, + (XDRPROC_T_TYPE) xdr_void, + (SVC_IN_ARG_TYPE) NULL); + return; + + case AUTOFS_MOUNT: + xdr_argument = xdr_mntrequest; + xdr_result = xdr_mntres; + local = (int (*)()) autofs_mount_1_svc; + break; + + case AUTOFS_UNMOUNT: + xdr_argument = xdr_umntrequest; + xdr_result = xdr_umntres; + local = (int (*)()) autofs_unmount_1_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + + memset((char *) &argument, 0, sizeof(argument)); + if (!svc_getargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) &argument)) { + plog(XLOG_ERROR, + "AUTOFS xdr decode failed for %d %d %d", + rqstp->rq_prog, rqstp->rq_vers, rqstp->rq_proc); + svcerr_decode(transp); + return; + } + + ret = (*local) (&argument, &result, rqstp); + if (!svc_sendreply(transp, + (XDRPROC_T_TYPE) xdr_result, + (SVC_IN_ARG_TYPE) &result)) { + svcerr_systemerr(transp); + } + + if (!svc_freeargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) &argument)) { + plog(XLOG_FATAL, "unable to free rpc arguments in autofs_program_1"); + going_down(1); + } +} + + +static int +autofs_mount_1_svc(struct mntrequest *mr, struct mntres *result, struct authunix_parms *cred) +{ + int err = 0; + am_node *anp, *anp2; + + plog(XLOG_INFO, "XXX: autofs_mount_1_svc: %s:%s:%s:%s", + mr->map, mr->name, mr->opts, mr->path); + + /* look for map (eg. "/home") */ + anp = find_ap(mr->path); + if (!anp) { + plog(XLOG_ERROR, "map %s not found", mr->path); + err = ENOENT; + goto out; + } + /* turn on autofs in map flags */ + if (!(anp->am_flags & AMF_AUTOFS)) { + plog(XLOG_INFO, "turning on AMF_AUTOFS for node %s", mr->path); + anp->am_flags |= AMF_AUTOFS; + } + + /* + * Look for (and create if needed) the new node. + * + * If an error occurred, return it. If a -1 was returned, that indicates + * that a mount is in progress, so sleep a while (while the backgrounded + * mount is happening), and then signal the autofs to retry the mount. + * + * There's something I don't understand. I was thinking that this code + * here is the one which will succeed eventually and will send an RPC + * reply to the kernel, but apparently that happens somewhere else, not + * here. It works though, just that I don't know how. Arg. -Erez. + * */ + err = 0; + anp2 = autofs_lookuppn(anp, mr->name, &err, VLOOK_CREATE); + if (!anp2) { + if (err == -1) { /* then tell autofs to retry */ + sleep(1); + err = EAGAIN; + } + goto out; + } + +out: + result->status = err; + return err; +} + + +static int +autofs_unmount_1_svc(struct umntrequest *ur, struct umntres *result, struct authunix_parms *cred) +{ + int err = 0; + +#ifdef HAVE_FIELD_UMNTREQUEST_RDEVID + plog(XLOG_INFO, "XXX: autofs_unmount_1_svc: %d:%u:%lu:0x%x", + ur->isdirect, ur->devid, ur->rdevid, ur->next); +#else /* HAVE_FIELD_UMNTREQUEST_RDEVID */ + plog(XLOG_INFO, "XXX: autofs_unmount_1_svc: %d:%u:0x%x", + ur->isdirect, ur->devid, ur->next); +#endif /* HAVE_FIELD_UMNTREQUEST_RDEVID */ + + err = EINVAL; /* XXX: not implemented yet */ + goto out; + +out: + result->status = err; + return err; +} + + +/* + * Pick a file system to try mounting and + * do that in the background if necessary + * + For each location: + if it is new -defaults then + extract and process + continue; + fi + if it is a cut then + if a location has been tried then + break; + fi + continue; + fi + parse mount location + discard previous mount location if required + find matching mounted filesystem + if not applicable then + this_error = No such file or directory + continue + fi + if the filesystem failed to be mounted then + this_error = error from filesystem + elif the filesystem is mounting or unmounting then + this_error = -1 + elif the fileserver is down then + this_error = -1 + elif the filesystem is already mounted + this_error = 0 + break + fi + if no error on this mount then + this_error = initialise mount point + fi + if no error on this mount and mount is delayed then + this_error = -1 + fi + if this_error < 0 then + retry = true + fi + if no error on this mount then + make mount point if required + fi + if no error on this mount then + if mount in background then + run mount in background + return -1 + else + this_error = mount in foreground + fi + fi + if an error occured on this mount then + update stats + save error in mount point + fi + endfor + */ +static int +autofs_bgmount(struct continuation * cp, int mpe) +{ + mntfs *mf = cp->mp->am_mnt; /* Current mntfs */ + mntfs *mf_retry = 0; /* First mntfs which needed retrying */ + int this_error = -1; /* Per-mount error */ + int hard_error = -1; + int mp_error = mpe; + + /* + * Try to mount each location. + * At the end: + * hard_error == 0 indicates something was mounted. + * hard_error > 0 indicates everything failed with a hard error + * hard_error < 0 indicates nothing could be mounted now + */ + for (; this_error && *cp->ivec; cp->ivec++) { + am_ops *p; + am_node *mp = cp->mp; + char *link_dir; + int dont_retry; + + if (hard_error < 0) + hard_error = this_error; + + this_error = -1; + + if (**cp->ivec == '-') { + /* + * Pick up new defaults + */ + if (cp->auto_opts && *cp->auto_opts) + cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec + 1); + else + cp->def_opts = strealloc(cp->def_opts, *cp->ivec + 1); +#ifdef DEBUG + dlog("Setting def_opts to \"%s\"", cp->def_opts); +#endif /* DEBUG */ + continue; + } + /* + * If a mount has been attempted, and we find + * a cut then don't try any more locations. + */ + if (STREQ(*cp->ivec, "/") || STREQ(*cp->ivec, "||")) { + if (cp->tried) { +#ifdef DEBUG + dlog("Cut: not trying any more locations for %s", + mp->am_path); +#endif /* DEBUG */ + break; + } + continue; + } + + /* match the operators */ + p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info); + + /* + * Find a mounted filesystem for this node. + */ + mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, + cp->fs_opts.opt_fs, + cp->fs_opts.fs_mtab, + cp->auto_opts, + cp->fs_opts.opt_opts, + cp->fs_opts.opt_remopts); + + p = mf->mf_ops; +#ifdef DEBUG + dlog("Got a hit with %s", p->fs_type); +#endif /* DEBUG */ + + /* + * Note whether this is a real mount attempt + */ + if (p == &amfs_error_ops) { + plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path); + if (this_error <= 0) + this_error = ENOENT; + continue; + } else { + if (cp->fs_opts.fs_mtab) { + plog(XLOG_MAP, "Trying mount of %s on \"%s\" fstype %s", + cp->fs_opts.fs_mtab, mp->am_path, p->fs_type); + } + cp->tried = TRUE; + } + + this_error = 0; + dont_retry = FALSE; + + if (mp->am_link) { + XFREE(mp->am_link); + mp->am_link = 0; + } + link_dir = mf->mf_fo->opt_sublink; + + if (link_dir && *link_dir) { + if (*link_dir == '/') { + mp->am_link = strdup(link_dir); + } else { + /* + * try getting fs option from continuation, not mountpoint! + * Don't try logging the string from mf, since it may be bad! + */ + if (cp->fs_opts.opt_fs != mf->mf_fo->opt_fs) + plog(XLOG_ERROR, "use %s instead of 0x%x", + cp->fs_opts.opt_fs, mf->mf_fo->opt_fs); + + mp->am_link = str3cat((char *) 0, + cp->fs_opts.opt_fs, "/", link_dir); + + normalize_slash(mp->am_link); + } + } + + if (mf->mf_error > 0) { + this_error = mf->mf_error; + } else if (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)) { + /* + * Still mounting - retry later + */ +#ifdef DEBUG + dlog("Duplicate pending mount fstype %s", p->fs_type); +#endif /* DEBUG */ + this_error = -1; + } else if (FSRV_ISDOWN(mf->mf_server)) { + /* + * Would just mount from the same place + * as a hung mount - so give up + */ +#ifdef DEBUG + dlog("%s is already hung - giving up", mf->mf_mount); +#endif /* DEBUG */ + mp_error = EWOULDBLOCK; + dont_retry = TRUE; + this_error = -1; + } else if (mf->mf_flags & MFF_MOUNTED) { +#ifdef DEBUG + dlog("duplicate mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + + /* + * Just call mounted() + */ + am_mounted(mp); + + this_error = 0; + break; + } + + /* + * Will usually need to play around with the mount nodes + * file attribute structure. This must be done here. + * Try and get things initialised, even if the fileserver + * is not known to be up. In the common case this will + * progress things faster. + */ + if (!this_error) { + /* + * Fill in attribute fields. + */ + if (mf->mf_ops->fs_flags & FS_DIRECTORY) + mk_fattr(mp, NFDIR); + else + mk_fattr(mp, NFLNK); + + mp->am_fattr.na_fileid = mp->am_gen; + + if (p->fs_init) + this_error = (*p->fs_init) (mf); + } + + /* + * Make sure the fileserver is UP before doing any more work + */ + if (!FSRV_ISUP(mf->mf_server)) { +#ifdef DEBUG + dlog("waiting for server %s to become available", mf->mf_server->fs_host); +#endif /* DEBUG */ + this_error = -1; + } + + if (!this_error && mf->mf_fo->opt_delay) { + /* + * If there is a delay timer on the mount + * then don't try to mount if the timer + * has not expired. + */ + int i = atoi(mf->mf_fo->opt_delay); + if (i > 0 && clocktime() < (cp->start + i)) { +#ifdef DEBUG + dlog("Mount of %s delayed by %ds", mf->mf_mount, i - clocktime() + cp->start); +#endif /* DEBUG */ + this_error = -1; + } + } + + if (this_error < 0 && !dont_retry) { + if (!mf_retry) + mf_retry = dup_mntfs(mf); + cp->retry = TRUE; + } + + if (!this_error) + if (p->fs_flags & FS_MBACKGROUND) { + mf->mf_flags |= MFF_MOUNTING; /* XXX */ +#ifdef DEBUG + dlog("backgrounding mount of \"%s\"", mf->mf_mount); +#endif /* DEBUG */ + if (cp->callout) { + untimeout(cp->callout); + cp->callout = 0; + } + run_task(try_mount, (voidp) mp, amfs_auto_cont, (voidp) cp); + mf->mf_flags |= MFF_MKMNT; /* XXX */ + if (mf_retry) + free_mntfs(mf_retry); + return -1; + } else { +#ifdef DEBUG + dlog("foreground mount of \"%s\" ...", mf->mf_info); +#endif /* DEBUG */ + this_error = try_mount((voidp) mp); + if (this_error < 0) { + if (!mf_retry) + mf_retry = dup_mntfs(mf); + cp->retry = TRUE; + } + } + + if (this_error >= 0) { + if (this_error > 0) { + amd_stats.d_merr++; + if (mf != mf_retry) { + mf->mf_error = this_error; + mf->mf_flags |= MFF_ERROR; + } + } + + /* + * Wakeup anything waiting for this mount + */ + wakeup((voidp) mf); + } + } + + if (this_error && cp->retry) { + free_mntfs(mf); + mf = cp->mp->am_mnt = mf_retry; + /* + * Not retrying again (so far) + */ + cp->retry = FALSE; + cp->tried = FALSE; + /* + * Start at the beginning. + * Rewind the location vector and + * reset the default options. + */ + cp->ivec = cp->xivec; + cp->def_opts = strealloc(cp->def_opts, cp->auto_opts); + /* + * Arrange that autofs_bgmount is called + * after anything else happens. + */ +#ifdef DEBUG + dlog("Arranging to retry mount of %s", cp->mp->am_path); +#endif /* DEBUG */ + sched_task(amfs_auto_retry, (voidp) cp, (voidp) mf); + if (cp->callout) + untimeout(cp->callout); + cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf); + + cp->mp->am_ttl = clocktime() + RETRY_INTERVAL; + + /* + * Not done yet - so don't return anything + */ + return -1; + } + + if (hard_error < 0 || this_error == 0) + hard_error = this_error; + + /* + * Discard handle on duff filesystem. + * This should never happen since it + * should be caught by the case above. + */ + if (mf_retry) { + if (hard_error) + plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount); + free_mntfs(mf_retry); + } + + /* + * If we get here, then either the mount succeeded or + * there is no more mount information available. + */ + if (hard_error < 0 && mp_error) + hard_error = cp->mp->am_error = mp_error; + if (hard_error > 0) { + /* + * Set a small(ish) timeout on an error node if + * the error was not a time out. + */ + switch (hard_error) { + case ETIMEDOUT: + case EWOULDBLOCK: + cp->mp->am_timeo = 17; + break; + default: + cp->mp->am_timeo = 5; + break; + } + new_ttl(cp->mp); + } + + /* + * Make sure that the error value in the mntfs has a + * reasonable value. + */ + if (mf->mf_error < 0) { + mf->mf_error = hard_error; + if (hard_error) + mf->mf_flags |= MFF_ERROR; + } + + /* + * In any case we don't need the continuation any more + */ + free_continuation(cp); + + return hard_error; +} + + +/* + * Automount interface to RPC lookup routine + * Find the corresponding entry and return + * the file handle for it. + */ +am_node * +autofs_lookuppn(am_node *mp, char *fname, int *error_return, int op) +{ + am_node *ap, *new_mp, *ap_hung; + char *info; /* Mount info - where to get the file system */ + char **ivec, **xivec; /* Split version of info */ + char *auto_opts; /* Automount options */ + int error = 0; /* Error so far */ + char path_name[MAXPATHLEN]; /* General path name buffer */ + char apath[MAXPATHLEN]; /* authofs path (added space) */ + char *pfname; /* Path for database lookup */ + struct continuation *cp; /* Continuation structure if need to mount */ + int in_progress = 0; /* # of (un)mount in progress */ + char *dflts; + mntfs *mf; + +#ifdef DEBUG + dlog("in autofs_lookuppn"); +#endif /* DEBUG */ + + /* + * If the server is shutting down + * then don't return information + * about the mount point. + */ + if (amd_state == Finishing) { +#ifdef DEBUG + if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &amfs_direct_ops) + dlog("%s mount ignored - going down", fname); + else + dlog("%s/%s mount ignored - going down", mp->am_path, fname); +#endif /* DEBUG */ + ereturn(ENOENT); + } + + /* + * Handle special case of "." and ".." + */ + if (fname[0] == '.') { + if (fname[1] == '\0') + return mp; /* "." is the current node */ + if (fname[1] == '.' && fname[2] == '\0') { + if (mp->am_parent) { +#ifdef DEBUG + dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path); +#endif /* DEBUG */ + return mp->am_parent; /* ".." is the parent node */ + } + ereturn(ESTALE); + } + } + + /* + * Check for valid key name. + * If it is invalid then pretend it doesn't exist. + */ + if (!valid_key(fname)) { + plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname); + ereturn(ENOENT); + } + + /* + * Expand key name. + * fname is now a private copy. + */ + fname = expand_key(fname); + + for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) { + /* + * Otherwise search children of this node + */ + if (FSTREQ(ap->am_name, fname)) { + mf = ap->am_mnt; + if (ap->am_error) { + error = ap->am_error; + continue; + } + /* + * If the error code is undefined then it must be + * in progress. + */ + if (mf->mf_error < 0) + goto in_progrss; + + /* + * Check for a hung node + */ + if (FSRV_ISDOWN(mf->mf_server)) { +#ifdef DEBUG + dlog("server hung"); +#endif /* DEBUG */ + error = ap->am_error; + ap_hung = ap; + continue; + } + /* + * If there was a previous error with this node + * then return that error code. + */ + if (mf->mf_flags & MFF_ERROR) { + error = mf->mf_error; + continue; + } + if (!(mf->mf_flags & MFF_MOUNTED) || (mf->mf_flags & MFF_UNMOUNTING)) { + in_progrss: + /* + * If the fs is not mounted or it is unmounting then there + * is a background (un)mount in progress. In this case + * we just drop the RPC request (return nil) and + * wait for a retry, by which time the (un)mount may + * have completed. + */ +#ifdef DEBUG + dlog("ignoring mount of %s in %s -- flags (%x) in progress", + fname, mf->mf_mount, mf->mf_flags); +#endif /* DEBUG */ + in_progress++; + continue; + } + + /* + * Otherwise we have a hit: return the current mount point. + */ +#ifdef DEBUG + dlog("matched %s in %s", fname, ap->am_path); +#endif /* DEBUG */ + XFREE(fname); + return ap; + } + } + + if (in_progress) { +#ifdef DEBUG + dlog("Waiting while %d mount(s) in progress", in_progress); +#endif /* DEBUG */ + XFREE(fname); + ereturn(-1); + } + + /* + * If an error occured then return it. + */ + if (error) { +#ifdef DEBUG + errno = error; /* XXX */ + dlog("Returning error: %m", error); +#endif /* DEBUG */ + XFREE(fname); + ereturn(error); + } + + /* + * If doing a delete then don't create again! + */ + switch (op) { + case VLOOK_DELETE: + ereturn(ENOENT); + + case VLOOK_CREATE: + break; + + default: + plog(XLOG_FATAL, "Unknown op to autofs_lookuppn: 0x%x", op); + ereturn(EINVAL); + } + + /* + * If the server is going down then just return, + * don't try to mount any more file systems + */ + if ((int) amd_state >= (int) Finishing) { +#ifdef DEBUG + dlog("not found - server going down anyway"); +#endif /* DEBUG */ + XFREE(fname); + ereturn(ENOENT); + } + + /* + * If we get there then this is a reference to an, + * as yet, unknown name so we need to search the mount + * map for it. + */ + if (mp->am_pref) { + sprintf(path_name, "%s%s", mp->am_pref, fname); + pfname = path_name; + } else { + pfname = fname; + } + + mf = mp->am_mnt; + +#ifdef DEBUG + dlog("will search map info in %s to find %s", mf->mf_info, pfname); +#endif /* DEBUG */ + /* + * Consult the oracle for some mount information. + * info is malloc'ed and belongs to this routine. + * It ends up being free'd in free_continuation(). + * + * Note that this may return -1 indicating that information + * is not yet available. + */ + error = mapc_search((mnt_map *) mf->mf_private, pfname, &info); + if (error) { + if (error > 0) + plog(XLOG_MAP, "No map entry for %s", pfname); + else + plog(XLOG_MAP, "Waiting on map entry for %s", pfname); + XFREE(fname); + ereturn(error); + } +#ifdef DEBUG + dlog("mount info is %s", info); +#endif /* DEBUG */ + + /* + * Split info into an argument vector. + * The vector is malloc'ed and belongs to + * this routine. It is free'd in free_continuation() + */ + xivec = ivec = strsplit(info, ' ', '\"'); + + /* + * Default error code... + */ + if (ap_hung) + error = EWOULDBLOCK; + else + error = ENOENT; + + /* + * Allocate a new map + */ + new_mp = exported_ap_alloc(); + if (new_mp == 0) { + XFREE(xivec); + XFREE(info); + XFREE(fname); + ereturn(ENOSPC); + } + if (mf->mf_auto) + auto_opts = mf->mf_auto; + else + auto_opts = ""; + + auto_opts = strdup(auto_opts); + +#ifdef DEBUG + dlog("searching for /defaults entry"); +#endif /* DEBUG */ + if (mapc_search((mnt_map *) mf->mf_private, "/defaults", &dflts) == 0) { + char *dfl; + char **rvec; +#ifdef DEBUG + dlog("/defaults gave %s", dflts); +#endif /* DEBUG */ + if (*dflts == '-') + dfl = dflts + 1; + else + dfl = dflts; + + /* + * Chop the defaults up + */ + rvec = strsplit(dfl, ' ', '\"'); + + if (gopt.flags & CFM_ENABLE_DEFAULT_SELECTORS) { + /* + * Pick whichever first entry matched the list of selectors. + * Strip the selectors from the string, and assign to dfl the + * rest of the string. + */ + if (rvec) { + am_opts ap; + am_ops *pt; + char **sp = rvec; + while (*sp) { /* loop until you find something, if any */ + memset((char *) &ap, 0, sizeof(am_opts)); + pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults", + mp->am_parent->am_mnt->mf_info); + if (pt == &amfs_error_ops) { + plog(XLOG_MAP, "failed to match defaults for \"%s\"", *sp); + } else { + dfl = strip_selectors(*sp, "/defaults"); + plog(XLOG_MAP, "matched default selectors \"%s\"", dfl); + break; + } + ++sp; + } + } + } else { /* not enable_default_selectors */ + /* + * Extract first value + */ + dfl = rvec[0]; + } + + /* + * If there were any values at all... + */ + if (dfl) { + /* + * Log error if there were other values + */ + if (!(gopt.flags & CFM_ENABLE_DEFAULT_SELECTORS) && rvec[1]) { +# ifdef DEBUG + dlog("/defaults chopped into %s", dfl); +# endif /* DEBUG */ + plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info); + } + + /* + * Prepend to existing defaults if they exist, + * otherwise just use these defaults. + */ + if (*auto_opts && *dfl) { + char *nopts = (char *) xmalloc(strlen(auto_opts) + strlen(dfl) + 2); + sprintf(nopts, "%s;%s", dfl, auto_opts); + XFREE(auto_opts); + auto_opts = nopts; + } else if (*dfl) { + auto_opts = strealloc(auto_opts, dfl); + } + } + XFREE(dflts); + /* + * Don't need info vector any more + */ + XFREE(rvec); + } + + /* + * Fill it in + */ + init_map(new_mp, fname); + + /* + * Turn on autofs flag if needed. + */ + if (mp->am_flags & AMF_AUTOFS) { + new_mp->am_flags |= AMF_AUTOFS; + } + + /* + * Put it in the table + */ + insert_am(new_mp, mp); + + /* + * Fill in some other fields, + * path and mount point. + * + * bugfix: do not prepend old am_path if direct map + * William Sebok + */ + + strcpy(apath, fname); + strcat(apath, " "); + new_mp->am_path = str3cat(new_mp->am_path, + mf->mf_ops == &amfs_direct_ops ? "" : mp->am_path, + *fname == '/' ? "" : "/", + apath); + +#ifdef DEBUG + dlog("setting path to \"%s\"", new_mp->am_path); +#endif /* DEBUG */ + + /* + * Take private copy of pfname + */ + pfname = strdup(pfname); + + /* + * Construct a continuation + */ + cp = ALLOC(struct continuation); + cp->callout = 0; + cp->mp = new_mp; + cp->xivec = xivec; + cp->ivec = ivec; + cp->info = info; + cp->key = pfname; + cp->auto_opts = auto_opts; + cp->retry = FALSE; + cp->tried = FALSE; + cp->start = clocktime(); + cp->def_opts = strdup(auto_opts); + memset((voidp) &cp->fs_opts, 0, sizeof(cp->fs_opts)); + + /* + * Try and mount the file system. If this succeeds immediately (possible + * for a ufs file system) then return the attributes, otherwise just + * return an error. + */ + error = autofs_bgmount(cp, error); + reschedule_timeout_mp(); + if (!error) { + XFREE(fname); + return new_mp; + } + + /* + * Code for quick reply. If nfs_program_2_transp is set, then + * its the transp that's been passed down from nfs_program_2(). + * If new_mp->am_transp is not already set, set it by copying in + * nfs_program_2_transp. Once am_transp is set, quick_reply() can + * use it to send a reply to the client that requested this mount. + */ + if (nfs_program_2_transp && !new_mp->am_transp) { + new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); + *(new_mp->am_transp) = *nfs_program_2_transp; + } + if (error && (new_mp->am_mnt->mf_ops == &amfs_error_ops)) + new_mp->am_error = error; + + assign_error_mntfs(new_mp); + + XFREE(fname); + + ereturn(error); +} +#endif /* HAVE_FS_AUTOFS */ diff --git a/contrib/amd/amd/ops_cachefs.c b/contrib/amd/amd/ops_cachefs.c new file mode 100644 index 0000000..0c40085 --- /dev/null +++ b/contrib/amd/amd/ops_cachefs.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_cachefs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Caching filesystem (Solaris 2.x) + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward declarations */ +static char *cachefs_match(am_opts *fo); +static int cachefs_init(mntfs *mf); +static int cachefs_fmount(mntfs *mf); +static int cachefs_fumount(mntfs *mf); + + +/* + * Ops structure + */ +am_ops cachefs_ops = +{ + "cachefs", + cachefs_match, + cachefs_init, + amfs_auto_fmount, + cachefs_fmount, + amfs_auto_fumount, + cachefs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* cachefs_readlink */ + 0, /* post-mount actions */ + 0, /* post-umount actions */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * Check that f/s has all needed fields. + * Returns: matched string if found, NULL otherwise. + */ +static char * +cachefs_match(am_opts *fo) +{ + /* sanity check */ + if (!fo->opt_rfs || !fo->opt_fs || !fo->opt_cachedir) { + plog(XLOG_USER, "cachefs: must specify cachedir, rfs, and fs"); + return NULL; + } + +#ifdef DEBUG + dlog("CACHEFS: using cache directory \"%s\"", fo->opt_cachedir); +#endif /* DEBUG */ + + /* determine magic cookie to put in mtab */ + return strdup(fo->opt_cachedir); +} + + +/* + * Initialize. + * Returns: 0 if OK, non-zero (errno) if failed. + */ +static int +cachefs_init(mntfs *mf) +{ + /* + * Save cache directory name + */ + if (mf->mf_refc == 1) { + mf->mf_private = (voidp) strdup(mf->mf_fo->opt_cachedir); + mf->mf_prfree = (void (*)(voidp)) free; + } + + return 0; +} + + +/* + * mntpt is the mount point ($fs) [XXX: was 'dir'] + * backdir is the mounted pathname ($rfs) [XXX: was 'fs_name'] + * cachedir is the cache directory ($cachedir) + */ +static int +mount_cachefs(char *mntpt, char *backdir, char *cachedir, char *opts) +{ + cachefs_args_t ca; + mntent_t mnt; + int flags; + char *cp; + MTYPE_TYPE type = MOUNT_TYPE_CACHEFS; /* F/S mount type */ + + memset((voidp) &ca, 0, sizeof(ca)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = mntpt; + mnt.mnt_fsname = backdir; + mnt.mnt_type = MNTTAB_TYPE_CACHEFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + + /* Fill in cachefs mount arguments */ + + /* + * XXX: Caveats + * (1) cache directory is NOT checked for sanity beforehand, nor is it + * purged. Maybe it should be purged first? + * (2) cache directory is NOT locked. Should we? + */ + + /* mount flags */ + ca.cfs_options.opt_flags = CFS_WRITE_AROUND | CFS_ACCESS_BACKFS; + /* cache population size */ + ca.cfs_options.opt_popsize = DEF_POP_SIZE; /* default: 64K */ + /* filegrp size */ + ca.cfs_options.opt_fgsize = DEF_FILEGRP_SIZE; /* default: 256 */ + + /* CFS ID for file system (must be unique) */ + ca.cfs_fsid = cachedir; + + /* CFS fscdir name */ + memset(ca.cfs_cacheid, 0, sizeof(ca.cfs_cacheid)); + /* append cacheid and mountpoint */ + sprintf(ca.cfs_cacheid, "%s:%s", ca.cfs_fsid, mntpt); + /* convert '/' to '_' (Solaris does that...) */ + cp = ca.cfs_cacheid; + while ((cp = strpbrk(cp, "/")) != NULL) + *cp = '_'; + + /* path for this cache dir */ + ca.cfs_cachedir = cachedir; + + /* back filesystem dir */ + ca.cfs_backfs = backdir; + + /* same as nfs values (XXX: need to handle these options) */ + ca.cfs_acregmin = 0; + ca.cfs_acregmax = 0; + ca.cfs_acdirmin = 0; + ca.cfs_acdirmax = 0; + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, (caddr_t) &ca, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +cachefs_fmount(mntfs *mf) +{ + int error; + + error = mount_cachefs(mf->mf_mount, + mf->mf_fo->opt_rfs, + mf->mf_fo->opt_cachedir, + mf->mf_mopts); + if (error) { + errno = error; + /* according to Solaris, if errno==ESRCH, "options to not match" */ + if (error == ESRCH) + plog(XLOG_ERROR, "mount_cachefs: options to no match: %m"); + else + plog(XLOG_ERROR, "mount_cachefs: %m"); + return error; + } + + return 0; +} + + +static int +cachefs_fumount(mntfs *mf) +{ + int error; + + error = UMOUNT_FS(mf->mf_mount, mnttab_file_name); + + /* + * In the case of cachefs, we must fsck the cache directory. Otherwise, + * it will remain inconsistent, and the next cachefs mount will fail + * with the error "no space left on device" (ENOSPC). + * + * XXX: this is hacky! use fork/exec/wait instead... + */ + if (!error) { + char *cachedir = NULL; + char cmd[128]; + + cachedir = (char *) mf->mf_private; + plog(XLOG_INFO, "running fsck on cache directory \"%s\"", cachedir); + sprintf(cmd, "fsck -F cachefs %s", cachedir); + system(cmd); + } + + return error; +} diff --git a/contrib/amd/amd/ops_cdfs.c b/contrib/amd/amd/ops_cdfs.c new file mode 100644 index 0000000..3a143e2 --- /dev/null +++ b/contrib/amd/amd/ops_cdfs.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_cdfs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * High Sierra (CD-ROM) file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward declarations */ +static char *cdfs_match(am_opts *fo); +static int cdfs_fmount(mntfs *mf); +static int cdfs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops cdfs_ops = +{ + "cdfs", + cdfs_match, + 0, /* cdfs_init */ + amfs_auto_fmount, + cdfs_fmount, + amfs_auto_fumount, + cdfs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* cdfs_readlink */ + 0, /* cdfs_mounted */ + 0, /* cdfs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * CDFS needs remote filesystem. + */ +static char * +cdfs_match(am_opts *fo) +{ + if (!fo->opt_dev) { + plog(XLOG_USER, "cdfs: no source device specified"); + return 0; + } +#ifdef DEBUG + dlog("CDFS: mounting device \"%s\" on \"%s\"", + fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_cdfs(char *dir, char *fs_name, char *opts) +{ + cdfs_args_t cdfs_args; + mntent_t mnt; + int genflags, cdfs_flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_CDFS; + + memset((voidp) &cdfs_args, 0, sizeof(cdfs_args)); /* Paranoid */ + cdfs_flags = 0; + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_CDFS; + mnt.mnt_opts = opts; + +#if defined(MNT2_CDFS_OPT_DEFPERM) && defined(MNTTAB_OPT_DEFPERM) + if (hasmntopt(&mnt, MNTTAB_OPT_DEFPERM)) +# ifdef MNT2_CDFS_OPT_DEFPERM + cdfs_flags |= MNT2_CDFS_OPT_DEFPERM; +# else /* not MNT2_CDFS_OPT_DEFPERM */ + cdfs_flags &= ~MNT2_CDFS_OPT_NODEFPERM; +# endif /* not MNT2_CDFS_OPT_DEFPERM */ +#endif /* defined(MNT2_CDFS_OPT_DEFPERM) && defined(MNTTAB_OPT_DEFPERM) */ + +#if defined(MNT2_CDFS_OPT_NODEFPERM) && defined(MNTTAB_OPT_NODEFPERM) + if (hasmntopt(&mnt, MNTTAB_OPT_NODEFPERM)) + cdfs_flags |= MNT2_CDFS_OPT_NODEFPERM; +#endif /* MNTTAB_OPT_NODEFPERM */ + +#if defined(MNT2_CDFS_OPT_NOVERSION) && defined(MNTTAB_OPT_NOVERSION) + if (hasmntopt(&mnt, MNTTAB_OPT_NOVERSION)) + cdfs_flags |= MNT2_CDFS_OPT_NOVERSION; +#endif /* defined(MNT2_CDFS_OPT_NOVERSION) && defined(MNTTAB_OPT_NOVERSION) */ + +#if defined(MNT2_CDFS_OPT_RRIP) && defined(MNTTAB_OPT_RRIP) + if (hasmntopt(&mnt, MNTTAB_OPT_RRIP)) + cdfs_flags |= MNT2_CDFS_OPT_RRIP; +#endif /* defined(MNT2_CDFS_OPT_RRIP) && defined(MNTTAB_OPT_RRIP) */ + + genflags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_CDFS_ARGS_T_FLAGS + cdfs_args.flags = cdfs_flags; +#endif /* HAVE_FIELD_CDFS_ARGS_T_FLAGS */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_ISO_FLAGS + cdfs_args.iso_flags = genflags | cdfs_flags; +#endif /* HAVE_FIELD_CDFS_ARGS_T_ISO_FLAGS */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_ISO_PGTHRESH + cdfs_args.iso_pgthresh = hasmntval(&mnt, MNTTAB_OPT_PGTHRESH); +#endif /* HAVE_FIELD_CDFS_ARGS_T_ISO_PGTHRESH */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_FSPEC + cdfs_args.fspec = fs_name; +#endif /* HAVE_FIELD_CDFS_ARGS_T_FSPEC */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_NORRIP + /* XXX: need to provide norrip mount opt */ + cdfs_args.norrip = 0; /* use Rock-Ridge Protocol extensions */ +#endif /* HAVE_FIELD_CDFS_ARGS_T_NORRIP */ + +#ifdef HAVE_FIELD_CDFS_ARGS_T_SSECTOR + /* XXX: need to provide ssector mount option */ + cdfs_args.ssector = 0; /* use 1st session on disk */ +#endif /* HAVE_FIELD_CDFS_ARGS_T_SSECTOR */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, genflags, (caddr_t) &cdfs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +cdfs_fmount(mntfs *mf) +{ + int error; + + error = mount_cdfs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_cdfs: %m"); + return error; + } + return 0; +} + + +static int +cdfs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_efs.c b/contrib/amd/amd/ops_efs.c new file mode 100644 index 0000000..4f915f7 --- /dev/null +++ b/contrib/amd/amd/ops_efs.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_efs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * Irix UN*X file system: EFS (Extent File System) + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward declarations */ +static char *efs_match(am_opts *fo); +static int efs_fmount(mntfs *mf); +static int efs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops efs_ops = +{ + "efs", + efs_match, + 0, /* efs_init */ + amfs_auto_fmount, + efs_fmount, + amfs_auto_fumount, + efs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* efs_readlink */ + 0, /* efs_mounted */ + 0, /* efs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * EFS needs local filesystem and device. + */ +static char * +efs_match(am_opts *fo) +{ + + if (!fo->opt_dev) { + plog(XLOG_USER, "efs: no device specified"); + return 0; + } + +#ifdef DEBUG + dlog("EFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_efs(char *dir, char *fs_name, char *opts) +{ + efs_args_t efs_args; + mntent_t mnt; + int flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_EFS; + + memset((voidp) &efs_args, 0, sizeof(efs_args)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_EFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_EFS_ARGS_T_FLAGS + efs_args.flags = 0; /* XXX: fix this to correct flags */ +#endif /* HAVE_FIELD_EFS_ARGS_T_FLAGS */ +#ifdef HAVE_FIELD_EFS_ARGS_T_FSPEC + efs_args.fspec = fs_name; +#endif /* HAVE_FIELD_EFS_ARGS_T_FSPEC */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, (caddr_t) &efs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +efs_fmount(mntfs *mf) +{ + int error; + + error = mount_efs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_efs: %m"); + return error; + } + + return 0; +} + + +static int +efs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_lofs.c b/contrib/amd/amd/ops_lofs.c new file mode 100644 index 0000000..6555db5 --- /dev/null +++ b/contrib/amd/amd/ops_lofs.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_lofs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * Loopback file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward definitions */ +static char * lofs_match(am_opts *fo); +static int lofs_fmount(mntfs *mf); +static int lofs_fumount(mntfs *mf); +static int mount_lofs(char *dir, char *fs_name, char *opts); + + +/* + * Ops structure + */ +am_ops lofs_ops = +{ + "lofs", + lofs_match, + 0, /* lofs_init */ + amfs_auto_fmount, + lofs_fmount, + amfs_auto_fumount, + lofs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* lofs_readlink */ + 0, /* lofs_mounted */ + 0, /* lofs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * LOFS needs remote filesystem. + */ +static char * +lofs_match(am_opts *fo) +{ + if (!fo->opt_rfs) { + plog(XLOG_USER, "lofs: no source filesystem specified"); + return 0; + } +#ifdef DEBUG + dlog("LOFS: mounting fs \"%s\" on \"%s\"", + fo->opt_rfs, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_rfs); +} + + +static int +mount_lofs(char *dir, char *fs_name, char *opts) +{ + mntent_t mnt; + int flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_LOFS; + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_LOFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, NULL, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +lofs_fmount(mntfs *mf) +{ + int error; + + error = mount_lofs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_lofs: %m"); + return error; + } + return 0; +} + + +static int +lofs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_mfs.c b/contrib/amd/amd/ops_mfs.c new file mode 100644 index 0000000..f93c30b --- /dev/null +++ b/contrib/amd/amd/ops_mfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_mfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Memory file system (RAM filesystem) + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_nfs.c b/contrib/amd/amd/ops_nfs.c new file mode 100644 index 0000000..a7006b4 --- /dev/null +++ b/contrib/amd/amd/ops_nfs.c @@ -0,0 +1,799 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_nfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Network file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * Convert from nfsstat to UN*X error code + */ +#define unx_error(e) ((int)(e)) + +/* + * FH_TTL is the time a file handle will remain in the cache since + * last being used. If the file handle becomes invalid, then it + * will be flushed anyway. + */ +#define FH_TTL (5 * 60) /* five minutes */ +#define FH_TTL_ERROR (30) /* 30 seconds */ +#define FHID_ALLOC(struct) (++fh_id) + +/* + * The NFS layer maintains a cache of file handles. + * This is *fundamental* to the implementation and + * also allows quick remounting when a filesystem + * is accessed soon after timing out. + * + * The NFS server layer knows to flush this cache + * when a server goes down so avoiding stale handles. + * + * Each cache entry keeps a hard reference to + * the corresponding server. This ensures that + * the server keepalive information is maintained. + * + * The copy of the sockaddr_in here is taken so + * that the port can be twiddled to talk to mountd + * instead of portmap or the NFS server as used + * elsewhere. + * The port# is flushed if a server goes down. + * The IP address is never flushed - we assume + * that the address of a mounted machine never + * changes. If it does, then you have other + * problems... + */ +typedef struct fh_cache fh_cache; +struct fh_cache { + qelem fh_q; /* List header */ + voidp fh_wchan; /* Wait channel */ + int fh_error; /* Valid data? */ + int fh_id; /* Unique id */ + int fh_cid; /* Callout id */ + u_long fh_nfs_version; /* highest NFS version on host */ + am_nfs_handle_t fh_nfs_handle; /* Handle on filesystem */ + struct sockaddr_in fh_sin; /* Address of mountd */ + fserver *fh_fs; /* Server holding filesystem */ + char *fh_path; /* Filesystem on host */ +}; + +/* forward definitions */ +static int call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan); +static int fh_id = 0; + +/* globals */ +AUTH *nfs_auth; +qelem fh_head = {&fh_head, &fh_head}; + +/* + * Network file system operations + */ +am_ops nfs_ops = +{ + "nfs", + nfs_match, + nfs_init, + amfs_auto_fmount, + nfs_fmount, + amfs_auto_fumount, + nfs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* nfs_readlink */ + 0, /* nfs_mounted */ + nfs_umounted, + find_nfs_srvr, + FS_MKMNT | FS_BACKGROUND | FS_AMQINFO +}; + + +static fh_cache * +find_nfs_fhandle_cache(voidp idv, int done) +{ + fh_cache *fp, *fp2 = 0; + int id = (long) idv; /* for 64-bit archs */ + + ITER(fp, fh_cache, &fh_head) { + if (fp->fh_id == id) { + fp2 = fp; + break; + } + } + +#ifdef DEBUG + if (fp2) { + dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path); + } else { + dlog("fh cache search failed"); + } +#endif /* DEBUG */ + + if (fp2 && !done) { + fp2->fh_error = ETIMEDOUT; + return 0; + } + + return fp2; +} + + +/* + * Called when a filehandle appears + */ +static void +got_nfs_fh(voidp pkt, int len, struct sockaddr_in * sa, struct sockaddr_in * ia, voidp idv, int done) +{ + fh_cache *fp; + + fp = find_nfs_fhandle_cache(idv, done); + if (!fp) + return; + + /* + * retrieve the correct RPC reply for the file handle, based on the + * NFS protocol version. + */ +#ifdef HAVE_FS_NFS3 + if (fp->fh_nfs_version == NFS_VERSION3) + fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v3, + (XDRPROC_T_TYPE) xdr_mountres3); + else +#endif /* HAVE_FS_NFS3 */ + fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v2, + (XDRPROC_T_TYPE) xdr_fhstatus); + + if (!fp->fh_error) { +#ifdef DEBUG + dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); +#endif /* DEBUG */ + + /* + * Wakeup anything sleeping on this filehandle + */ + if (fp->fh_wchan) { +#ifdef DEBUG + dlog("Calling wakeup on %#x", fp->fh_wchan); +#endif /* DEBUG */ + wakeup(fp->fh_wchan); + } + } +} + + +void +flush_nfs_fhandle_cache(fserver *fs) +{ + fh_cache *fp; + + ITER(fp, fh_cache, &fh_head) { + if (fp->fh_fs == fs || fs == 0) { + fp->fh_sin.sin_port = (u_short) 0; + fp->fh_error = -1; + } + } +} + + +static void +discard_fh(voidp v) +{ + fh_cache *fp = v; + + rem_que(&fp->fh_q); + if (fp->fh_fs) { +#ifdef DEBUG + dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); +#endif /* DEBUG */ + free_srvr(fp->fh_fs); + } + if (fp->fh_path) + XFREE(fp->fh_path); + XFREE(fp); +} + + +/* + * Determine the file handle for a node + */ +static int +prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp wchan) +{ + fh_cache *fp, *fp_save = 0; + int error; + int reuse_id = FALSE; + +#ifdef DEBUG + dlog("Searching cache for %s:%s", fs->fs_host, path); +#endif /* DEBUG */ + + /* + * First search the cache + */ + ITER(fp, fh_cache, &fh_head) { + if (fs == fp->fh_fs && STREQ(path, fp->fh_path)) { + switch (fp->fh_error) { + case 0: + plog(XLOG_INFO, "prime_nfs_fhandle_cache: NFS version %d", fp->fh_nfs_version); +#ifdef HAVE_FS_NFS3 + if (fp->fh_nfs_version == NFS_VERSION3) + error = fp->fh_error = unx_error(fp->fh_nfs_handle.v3.fhs_status); + else +#endif /* HAVE_FS_NFS3 */ + error = fp->fh_error = unx_error(fp->fh_nfs_handle.v2.fhs_status); + if (error == 0) { + if (fhbuf) { +#ifdef HAVE_FS_NFS3 + if (fp->fh_nfs_version == NFS_VERSION3) + memmove((voidp) &(fhbuf->v3), (voidp) &(fp->fh_nfs_handle.v3), + sizeof(fp->fh_nfs_handle.v3)); + else +#endif /* HAVE_FS_NFS3 */ + memmove((voidp) &(fhbuf->v2), (voidp) &(fp->fh_nfs_handle.v2), + sizeof(fp->fh_nfs_handle.v2)); + } + if (fp->fh_cid) + untimeout(fp->fh_cid); + fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); + } else if (error == EACCES) { + /* + * Now decode the file handle return code. + */ + plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"", + fs->fs_host, path); + } else { + errno = error; /* XXX */ + plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m", + fs->fs_host, path); + } + + /* + * The error was returned from the remote mount daemon. + * Policy: this error will be cached for now... + */ + return error; + + case -1: + /* + * Still thinking about it, but we can re-use. + */ + fp_save = fp; + reuse_id = TRUE; + break; + + default: + /* + * Return the error. + * Policy: make sure we recompute if required again + * in case this was caused by a network failure. + * This can thrash mountd's though... If you find + * your mountd going slowly then: + * 1. Add a fork() loop to main. + * 2. Remove the call to innetgr() and don't use + * netgroups, especially if you don't use YP. + */ + error = fp->fh_error; + fp->fh_error = -1; + return error; + } + break; + } + } + + /* + * Not in cache + */ + if (fp_save) { + fp = fp_save; + /* + * Re-use existing slot + */ + untimeout(fp->fh_cid); + free_srvr(fp->fh_fs); + XFREE(fp->fh_path); + } else { + fp = ALLOC(struct fh_cache); + memset((voidp) fp, 0, sizeof(struct fh_cache)); + ins_que(&fp->fh_q, &fh_head); + } + if (!reuse_id) + fp->fh_id = FHID_ALLOC(struct ); + fp->fh_wchan = wchan; + fp->fh_error = -1; + fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); + + /* + * if fs->fs_ip is null, remote server is probably down. + */ + if (!fs->fs_ip) { + /* Mark the fileserver down and invalid again */ + fs->fs_flags &= ~FSF_VALID; + fs->fs_flags |= FSF_DOWN; + error = AM_ERRNO_HOST_DOWN; + return error; + } + + /* + * If the address has changed then don't try to re-use the + * port information + */ + if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) { + fp->fh_sin = *fs->fs_ip; + fp->fh_sin.sin_port = 0; + fp->fh_nfs_version = fs->fs_version; + } + fp->fh_fs = dup_srvr(fs); + fp->fh_path = strdup(path); + + error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan); + if (error) { + /* + * Local error - cache for a short period + * just to prevent thrashing. + */ + untimeout(fp->fh_cid); + fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR, + discard_fh, (voidp) fp); + fp->fh_error = error; + } else { + error = fp->fh_error; + } + + return error; +} + + +int +make_nfs_auth(void) +{ + AUTH_CREATE_GIDLIST_TYPE group_wheel = 0; + + /* Some NFS mounts (particularly cross-domain) require FQDNs to succeed */ + +#ifdef HAVE_TRANSPORT_TYPE_TLI + if (gopt.flags & CFM_FULLY_QUALIFIED_HOSTS) { + plog(XLOG_INFO, "Using NFS auth for fqhn \"%s\"", hostd); + nfs_auth = authsys_create(hostd, 0, 0, 1, &group_wheel); + } else { + nfs_auth = authsys_create_default(); + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + if (gopt.flags & CFM_FULLY_QUALIFIED_HOSTS) { + plog(XLOG_INFO, "Using NFS auth for fqhn \"%s\"", hostd); + nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel); + } else { + nfs_auth = authunix_create_default(); + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + if (!nfs_auth) + return ENOBUFS; + + return 0; +} + + +static int +call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan) +{ + struct rpc_msg mnt_msg; + int len; + char iobuf[8192]; + int error; + u_long mnt_version; + + if (!nfs_auth) { + error = make_nfs_auth(); + if (error) + return error; + } + + if (fp->fh_sin.sin_port == 0) { + u_short port; + error = nfs_srvr_port(fp->fh_fs, &port, wchan); + if (error) + return error; + fp->fh_sin.sin_port = port; + } + + /* find the right version of the mount protocol */ +#ifdef HAVE_FS_NFS3 + if (fp->fh_nfs_version == NFS_VERSION3) + mnt_version = MOUNTVERS3; + else +#endif /* HAVE_FS_NFS3 */ + mnt_version = MOUNTVERS; + plog(XLOG_INFO, "call_mountd: NFS version %d, mount version %d", + fp->fh_nfs_version, mnt_version); + + rpc_msg_init(&mnt_msg, MOUNTPROG, mnt_version, MOUNTPROC_NULL); + len = make_rpc_packet(iobuf, + sizeof(iobuf), + proc, + &mnt_msg, + (voidp) &fp->fh_path, + (XDRPROC_T_TYPE) xdr_nfspath, + nfs_auth); + + if (len > 0) { + error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id), + (voidp) iobuf, + len, + &fp->fh_sin, + &fp->fh_sin, + (voidp) ((long) fp->fh_id), /* for 64-bit archs */ + f); + } else { + error = -len; + } + +/* + * It may be the case that we're sending to the wrong MOUNTD port. This + * occurs if mountd is restarted on the server after the port has been + * looked up and stored in the filehandle cache somewhere. The correct + * solution, if we're going to cache port numbers is to catch the ICMP + * port unreachable reply from the server and cause the portmap request + * to be redone. The quick solution here is to invalidate the MOUNTD + * port. + */ + fp->fh_sin.sin_port = 0; + + return error; +} + + +/* + * NFS needs the local filesystem, remote filesystem + * remote hostname. + * Local filesystem defaults to remote and vice-versa. + */ +char * +nfs_match(am_opts *fo) +{ + char *xmtab; + + if (fo->opt_fs && !fo->opt_rfs) + fo->opt_rfs = fo->opt_fs; + if (!fo->opt_rfs) { + plog(XLOG_USER, "nfs: no remote filesystem specified"); + return NULL; + } + if (!fo->opt_rhost) { + plog(XLOG_USER, "nfs: no remote host specified"); + return NULL; + } + + /* + * Determine magic cookie to put in mtab + */ + xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2); + sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs); +#ifdef DEBUG + dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"", + fo->opt_rhost, fo->opt_rfs, fo->opt_fs); +#endif /* DEBUG */ + + return xmtab; +} + + +/* + * Initialize am structure for nfs + */ +int +nfs_init(mntfs *mf) +{ + int error; + am_nfs_handle_t fhs; + char *colon; + + if (mf->mf_private) + return 0; + + colon = strchr(mf->mf_info, ':'); + if (colon == 0) + return ENOENT; + + error = prime_nfs_fhandle_cache(colon + 1, mf->mf_server, &fhs, (voidp) mf); + if (!error) { + mf->mf_private = (voidp) ALLOC(am_nfs_handle_t); + mf->mf_prfree = (void (*)(voidp)) free; + memmove(mf->mf_private, (voidp) &fhs, sizeof(fhs)); + } + return error; +} + + +int +mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf) +{ + MTYPE_TYPE type; + char *colon; + char *xopts; + char host[MAXHOSTNAMELEN + MAXPATHLEN + 2]; + fserver *fs = mf->mf_server; + u_long nfs_version = fs->fs_version; + char *nfs_proto = fs->fs_proto; /* "tcp" or "udp" */ + int error; + int genflags; + int retry; + mntent_t mnt; + nfs_args_t nfs_args; + + /* + * Extract HOST name to give to kernel. + * Some systems like osf1/aix3/bsd44 variants may need old code + * for NFS_ARGS_NEEDS_PATH. + */ + if (!(colon = strchr(fs_name, ':'))) + return ENOENT; +#ifdef MOUNT_TABLE_ON_FILE + *colon = '\0'; +#endif /* MOUNT_TABLE_ON_FILE */ + strncpy(host, fs_name, sizeof(host)); +#ifdef MOUNT_TABLE_ON_FILE + *colon = ':'; +#endif /* MOUNT_TABLE_ON_FILE */ +#ifdef MAXHOSTNAMELEN + /* most kernels have a name length restriction */ + if (strlen(host) >= MAXHOSTNAMELEN) + strcpy(host + MAXHOSTNAMELEN - 3, ".."); +#endif /* MAXHOSTNAMELEN */ + + if (mf->mf_remopts && *mf->mf_remopts && !islocalnet(fs->fs_ip->sin_addr.s_addr)) + xopts = strdup(mf->mf_remopts); + else + xopts = strdup(opts); + + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_opts = xopts; + + /* + * Set mount types accordingly + */ +#ifndef HAVE_FS_NFS3 + type = MOUNT_TYPE_NFS; + mnt.mnt_type = MNTTAB_TYPE_NFS; +#else /* HAVE_FS_NFS3 */ + if (nfs_version == NFS_VERSION3) { + type = MOUNT_TYPE_NFS3; + /* + * Systems that include the mount table "vers" option generally do not + * set the mnttab entry to "nfs3", but to "nfs" and then they set + * "vers=3". Setting it to "nfs3" works, but it may break some things + * like "df -t nfs" and the "quota" program (esp. on Solaris and Irix). + * So on those systems, set it to "nfs". + * Note: MNTTAB_OPT_VERS is always set for NFS3 (see am_compat.h). + */ +# if defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) + mnt.mnt_type = MNTTAB_TYPE_NFS; +# else /* defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) */ + mnt.mnt_type = MNTTAB_TYPE_NFS3; +# endif /* defined(MNTTAB_OPT_VERS) && defined(MOUNT_TABLE_ON_FILE) */ + } else { + type = MOUNT_TYPE_NFS; + mnt.mnt_type = MNTTAB_TYPE_NFS; + } +#endif /* HAVE_FS_NFS3 */ + plog(XLOG_INFO, "mount_nfs_fh: NFS version %d", nfs_version); +#if defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI) + plog(XLOG_INFO, "mount_nfs_fh: using NFS transport %s", nfs_proto); +#endif /* defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI) */ + + retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); + if (retry <= 0) + retry = 1; /* XXX */ + + genflags = compute_mount_flags(&mnt); + + /* setup the many fields and flags within nfs_args */ +#ifdef HAVE_TRANSPORT_TYPE_TLI + compute_nfs_args(&nfs_args, + &mnt, + genflags, + NULL, /* struct netconfig *nfsncp */ + fs->fs_ip, + nfs_version, + nfs_proto, + fhp, + host, + fs_name); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + compute_nfs_args(&nfs_args, + &mnt, + genflags, + fs->fs_ip, + nfs_version, + nfs_proto, + fhp, + host, + fs_name); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* finally call the mounting function */ +#ifdef DEBUG + amuDebug(D_TRACE) + print_nfs_args(&nfs_args, nfs_version); +#endif /* DEBUG */ + error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, + nfs_version, nfs_proto, mnttab_file_name); + XFREE(xopts); + +#ifdef HAVE_TRANSPORT_TYPE_TLI + free_knetconfig(nfs_args.knconf); + if (nfs_args.addr) + XFREE(nfs_args.addr); /* allocated in compute_nfs_args() */ +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + return error; +} + + +static int +mount_nfs(char *dir, char *fs_name, char *opts, mntfs *mf) +{ + if (!mf->mf_private) { + plog(XLOG_ERROR, "Missing filehandle for %s", fs_name); + return EINVAL; + } + + return mount_nfs_fh((am_nfs_handle_t *) mf->mf_private, dir, fs_name, opts, mf); +} + + +int +nfs_fmount(mntfs *mf) +{ + int error = 0; + + error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf); + +#ifdef DEBUG + if (error) { + errno = error; + dlog("mount_nfs: %m"); + } +#endif /* DEBUG */ + + return error; +} + + +int +nfs_fumount(mntfs *mf) +{ + int error = UMOUNT_FS(mf->mf_mount, mnttab_file_name); + + /* + * Here is some code to unmount 'restarted' file systems. + * The restarted file systems are marked as 'nfs', not + * 'host', so we only have the map information for the + * the top-level mount. The unmount will fail (EBUSY) + * if there are anything else from the NFS server mounted + * below the mount-point. This code checks to see if there + * is anything mounted with the same prefix as the + * file system to be unmounted ("/a/b/c" when unmounting "/a/b"). + * If there is, and it is a 'restarted' file system, we unmount + * it. + * Added by Mike Mitchell, mcm@unx.sas.com, 09/08/93 + */ + if (error == EBUSY) { + mntfs *new_mf; + int len = strlen(mf->mf_mount); + int didsome = 0; + + ITER(new_mf, mntfs, &mfhead) { + if (new_mf->mf_ops != mf->mf_ops || + new_mf->mf_refc > 1 || + mf == new_mf || + ((new_mf->mf_flags & (MFF_MOUNTED | MFF_UNMOUNTING | MFF_RESTART)) == (MFF_MOUNTED | MFF_RESTART))) + continue; + + if (NSTREQ(mf->mf_mount, new_mf->mf_mount, len) && + new_mf->mf_mount[len] == '/') { + UMOUNT_FS(new_mf->mf_mount, mnttab_file_name); + didsome = 1; + } + } + if (didsome) + error = UMOUNT_FS(mf->mf_mount, mnttab_file_name); + } + if (error) + return error; + + return 0; +} + + +void +nfs_umounted(am_node *mp) +{ + /* + * Don't bother to inform remote mountd that we are finished. Until a + * full track of filehandles is maintained the mountd unmount callback + * cannot be done correctly anyway... + */ + mntfs *mf = mp->am_mnt; + fserver *fs; + char *colon, *path; + + if (mf->mf_error || mf->mf_refc > 1) + return; + + fs = mf->mf_server; + + /* + * Call the mount daemon on the server to announce that we are not using + * the fs any more. + * + * This is *wrong*. The mountd should be called when the fhandle is + * flushed from the cache, and a reference held to the cached entry while + * the fs is mounted... + */ + colon = path = strchr(mf->mf_info, ':'); + if (fs && colon) { + fh_cache f; + +#ifdef DEBUG + dlog("calling mountd for %s", mf->mf_info); +#endif /* DEBUG */ + *path++ = '\0'; + f.fh_path = path; + f.fh_sin = *fs->fs_ip; + f.fh_sin.sin_port = (u_short) 0; + f.fh_nfs_version = fs->fs_version; + f.fh_fs = fs; + f.fh_id = 0; + f.fh_error = 0; + prime_nfs_fhandle_cache(colon + 1, mf->mf_server, (am_nfs_handle_t *) 0, (voidp) mf); + call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0); + *colon = ':'; + } +} diff --git a/contrib/amd/amd/ops_nfs3.c b/contrib/amd/amd/ops_nfs3.c new file mode 100644 index 0000000..5db0713 --- /dev/null +++ b/contrib/amd/amd/ops_nfs3.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_nfs3.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Network file system version 3.0 + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_nullfs.c b/contrib/amd/amd/ops_nullfs.c new file mode 100644 index 0000000..bf2009f --- /dev/null +++ b/contrib/amd/amd/ops_nullfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_nullfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * The null filesystem in BSD-4.4 is similar to the loopback one. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_pcfs.c b/contrib/amd/amd/ops_pcfs.c new file mode 100644 index 0000000..e46b711 --- /dev/null +++ b/contrib/amd/amd/ops_pcfs.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_pcfs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * PC (MS-DOS) file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward definitions */ +static char *pcfs_match(am_opts *fo); +static int pcfs_fmount(mntfs *mf); +static int pcfs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops pcfs_ops = +{ + "pcfs", + pcfs_match, + 0, /* pcfs_init */ + amfs_auto_fmount, + pcfs_fmount, + amfs_auto_fumount, + pcfs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* pcfs_readlink */ + 0, /* pcfs_mounted */ + 0, /* pcfs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_UBACKGROUND | FS_AMQINFO +}; + + + +/* + * PCFS needs remote filesystem. + */ +static char * +pcfs_match(am_opts *fo) +{ + if (!fo->opt_dev) { + plog(XLOG_USER, "pcfs: no source device specified"); + return 0; + } +#ifdef DEBUG + dlog("PCFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_pcfs(char *dir, char *fs_name, char *opts) +{ + pcfs_args_t pcfs_args; + mntent_t mnt; + int flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_PCFS; + + memset((voidp) &pcfs_args, 0, sizeof(pcfs_args)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_PCFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_PCFS_ARGS_T_FSPEC + pcfs_args.fspec = fs_name; +#endif /* HAVE_FIELD_PCFS_ARGS_T_FSPEC */ + +#ifdef HAVE_FIELD_PCFS_ARGS_T_MASK + pcfs_args.mask = 0777; /* this may be the msdos file modes */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_MASK */ + +#ifdef HAVE_FIELD_PCFS_ARGS_T_UID + pcfs_args.uid = 0; /* root */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_UID */ + +#ifdef HAVE_FIELD_PCFS_ARGS_T_GID + pcfs_args.gid = 0; /* wheel */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_GID */ + +#ifdef HAVE_FIELD_PCFS_ARGS_T_SECONDSWEST + pcfs_args.secondswest = 0; /* XXX: fill in correct values */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_SECONDSWEST */ +#ifdef HAVE_FIELD_PCFS_ARGS_T_DSTTIME + pcfs_args.dsttime = 0; /* XXX: fill in correct values */ +#endif /* HAVE_FIELD_PCFS_ARGS_T_DSTTIME */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, (caddr_t) & pcfs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +pcfs_fmount(mntfs *mf) +{ + int error; + + error = mount_pcfs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_pcfs: %m"); + return error; + } + + return 0; +} + + +static int +pcfs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_tfs.c b/contrib/amd/amd/ops_tfs.c new file mode 100644 index 0000000..97cd18c --- /dev/null +++ b/contrib/amd/amd/ops_tfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_tfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Translucent file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_tmpfs.c b/contrib/amd/amd/ops_tmpfs.c new file mode 100644 index 0000000..ce1b4fd --- /dev/null +++ b/contrib/amd/amd/ops_tmpfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_tmpfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * TMPFS file system (combines RAM-fs and swap-fs) + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_ufs.c b/contrib/amd/amd/ops_ufs.c new file mode 100644 index 0000000..9883af1 --- /dev/null +++ b/contrib/amd/amd/ops_ufs.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_ufs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * UN*X file system + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward declarations */ +static char *ufs_match(am_opts *fo); +static int ufs_fmount(mntfs *mf); +static int ufs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops ufs_ops = +{ + "ufs", + ufs_match, + 0, /* ufs_init */ + amfs_auto_fmount, + ufs_fmount, + amfs_auto_fumount, + ufs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* ufs_readlink */ + 0, /* ufs_mounted */ + 0, /* ufs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * UFS needs local filesystem and device. + */ +static char * +ufs_match(am_opts *fo) +{ + + if (!fo->opt_dev) { + plog(XLOG_USER, "ufs: no device specified"); + return 0; + } + +#ifdef DEBUG + dlog("UFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_ufs(char *dir, char *fs_name, char *opts) +{ + ufs_args_t ufs_args; + mntent_t mnt; + int genflags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_UFS; + + memset((voidp) &ufs_args, 0, sizeof(ufs_args)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_UFS; + mnt.mnt_opts = opts; + + genflags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_UFS_ARGS_T_FLAGS + ufs_args.flags = genflags; /* XXX: is this correct? */ +#endif /* HAVE_FIELD_UFS_ARGS_T_FLAGS */ + +#ifdef HAVE_FIELD_UFS_ARGS_T_UFS_FLAGS + ufs_args.ufs_flags = genflags; /* XXX: is this correct? */ +#endif /* HAVE_FIELD_UFS_ARGS_T_UFS_FLAGS */ + +#ifdef HAVE_FIELD_UFS_ARGS_T_FSPEC + ufs_args.fspec = fs_name; +#endif /* HAVE_FIELD_UFS_ARGS_T_FSPEC */ + +#ifdef HAVE_FIELD_UFS_ARGS_T_UFS_PGTHRESH + ufs_args.ufs_pgthresh = hasmntval(&mnt, MNTTAB_OPT_PGTHRESH); +#endif /* HAVE_FIELD_UFS_ARGS_T_UFS_PGTHRESH */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, genflags, (caddr_t) &ufs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +ufs_fmount(mntfs *mf) +{ + int error; + + error = mount_ufs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_ufs: %m"); + return error; + } + + return 0; +} + + +static int +ufs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/ops_umapfs.c b/contrib/amd/amd/ops_umapfs.c new file mode 100644 index 0000000..b2dcd72 --- /dev/null +++ b/contrib/amd/amd/ops_umapfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_umapfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * uid/gid mapping filesystem. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_unionfs.c b/contrib/amd/amd/ops_unionfs.c new file mode 100644 index 0000000..24f7e1f --- /dev/null +++ b/contrib/amd/amd/ops_unionfs.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_unionfs.c,v 5.2.2.3 1992/08/02 10:42:21 jsp Exp $ + * + */ + +/* + * Union filesystem (ala BSD-4.4) + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* FEEL FREE TO INPLEMENT THIS... :-) */ diff --git a/contrib/amd/amd/ops_xfs.c b/contrib/amd/amd/ops_xfs.c new file mode 100644 index 0000000..1b4aab4 --- /dev/null +++ b/contrib/amd/amd/ops_xfs.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: ops_xfs.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $ + * + */ + +/* + * Irix UN*X file system: XFS (Extended File System) + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* forward declarations */ +static char * xfs_match(am_opts *fo); +static int xfs_fmount(mntfs *mf); +static int xfs_fumount(mntfs *mf); + +/* + * Ops structure + */ +am_ops xfs_ops = +{ + "xfs", + xfs_match, + 0, /* xfs_init */ + amfs_auto_fmount, + xfs_fmount, + amfs_auto_fumount, + xfs_fumount, + amfs_error_lookuppn, + amfs_error_readdir, + 0, /* xfs_readlink */ + 0, /* xfs_mounted */ + 0, /* xfs_umounted */ + find_amfs_auto_srvr, + FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO +}; + + +/* + * XFS needs local filesystem and device. + */ +static char * +xfs_match(am_opts *fo) +{ + + if (!fo->opt_dev) { + plog(XLOG_USER, "xfs: no device specified"); + return 0; + } + +#ifdef DEBUG + dlog("XFS: mounting device \"%s\" on \"%s\"", fo->opt_dev, fo->opt_fs); +#endif /* DEBUG */ + + /* + * Determine magic cookie to put in mtab + */ + return strdup(fo->opt_dev); +} + + +static int +mount_xfs(char *dir, char *fs_name, char *opts) +{ + xfs_args_t xfs_args; + mntent_t mnt; + int flags; + + /* + * Figure out the name of the file system type. + */ + MTYPE_TYPE type = MOUNT_TYPE_XFS; + + memset((voidp) &xfs_args, 0, sizeof(xfs_args)); /* Paranoid */ + + /* + * Fill in the mount structure + */ + memset((voidp) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir; + mnt.mnt_fsname = fs_name; + mnt.mnt_type = MNTTAB_TYPE_XFS; + mnt.mnt_opts = opts; + + flags = compute_mount_flags(&mnt); + +#ifdef HAVE_FIELD_XFS_ARGS_T_FLAGS + xfs_args.flags = 0; /* XXX: fix this to correct flags */ +#endif /* HAVE_FIELD_XFS_ARGS_T_FLAGS */ +#ifdef HAVE_FIELD_XFS_ARGS_T_FSPEC + xfs_args.fspec = fs_name; +#endif /* HAVE_FIELD_XFS_ARGS_T_FSPEC */ + + /* + * Call generic mount routine + */ + return mount_fs(&mnt, flags, (caddr_t) &xfs_args, 0, type, 0, NULL, mnttab_file_name); +} + + +static int +xfs_fmount(mntfs *mf) +{ + int error; + + error = mount_xfs(mf->mf_mount, mf->mf_info, mf->mf_mopts); + if (error) { + errno = error; + plog(XLOG_ERROR, "mount_xfs: %m"); + return error; + } + + return 0; +} + + +static int +xfs_fumount(mntfs *mf) +{ + return UMOUNT_FS(mf->mf_mount, mnttab_file_name); +} diff --git a/contrib/amd/amd/opts.c b/contrib/amd/amd/opts.c new file mode 100644 index 0000000..294cdb7 --- /dev/null +++ b/contrib/amd/amd/opts.c @@ -0,0 +1,1304 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: opts.c,v 5.2.2.4 1992/08/02 10:42:21 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * MACROS: + */ +#define NLEN 16 /* Length of longest option name (conservative) */ +#define S(x) (x) , (sizeof(x)-1) +/* + * The BUFSPACE macros checks that there is enough space + * left in the expansion buffer. If there isn't then we + * give up completely. This is done to avoid crashing the + * automounter itself (which would be a bad thing to do). + */ +#define BUFSPACE(ep, len) (((ep) + (len)) < expbuf+MAXPATHLEN) + +/* + * TYPEDEFS: + */ +typedef int (*IntFuncPtr) (char *); +typedef struct opt_apply opt_apply; +enum vs_opt { SelEQ, SelNE, VarAss }; + +/* + * STRUCTURES + */ +struct opt { + char *name; /* Name of the option */ + int nlen; /* Length of option name */ + char **optp; /* Pointer to option value string */ + char **sel_p; /* Pointer to selector value string */ + int (*fxn_p)(char *); /* Pointer to boolean function */ + int case_insensitive; /* How to do selector comparisons */ +}; + +struct opt_apply { + char **opt; + char *val; +}; + +struct functable { + char *name; + IntFuncPtr func; +}; + +/* + * FORWARD DEFINITSION: + */ +static int f_in_network(char *); +static int f_netgrp(char *); +static int f_exists(char *); +static int f_false(char *); +static int f_true(char *); + +/* + * STATICS: + */ +static struct am_opts fs_static; /* copy of the options to play with */ +static char NullStr[] = ""; +static char nullstr[] = ""; +static char *opt_dkey = NullStr; +static char *opt_host = hostname; +static char *opt_hostd = hostd; +static char *opt_key = nullstr; +static char *opt_keyd = nullstr; +static char *opt_map = nullstr; +static char *opt_path = nullstr; +static char *vars[8]; + + +/* + * Options in something corresponding to frequency of use so that + * first-match algorithm is sped up. + */ +static struct opt opt_fields[] = { + /* Name and length. + Option str. Selector str. boolean fxn. flags */ + { S("opts"), + &fs_static.opt_opts, 0, 0, FALSE }, + { S("host"), + 0, &opt_host, 0, TRUE }, + { S("hostd"), + 0, &opt_hostd, 0, TRUE }, + { S("type"), + &fs_static.opt_type, 0, 0, FALSE }, + { S("rhost"), + &fs_static.opt_rhost, 0, 0, TRUE }, + { S("rfs"), + &fs_static.opt_rfs, 0, 0, FALSE }, + { S("fs"), + &fs_static.opt_fs, 0, 0, FALSE }, + { S("key"), + 0, &opt_key, 0, FALSE }, + { S("map"), + 0, &opt_map, 0, FALSE }, + { S("sublink"), + &fs_static.opt_sublink, 0, 0, FALSE }, + { S("arch"), + 0, &gopt.arch, 0, TRUE }, + { S("dev"), + &fs_static.opt_dev, 0, 0, FALSE }, + { S("pref"), + &fs_static.opt_pref, 0, 0, FALSE }, + { S("autopref"), + &fs_static.opt_autopref,0, 0, FALSE }, + { S("path"), + 0, &opt_path, 0, FALSE }, + { S("autodir"), + 0, &gopt.auto_dir, 0, FALSE }, + { S("delay"), + &fs_static.opt_delay, 0, 0, FALSE }, + { S("domain"), + 0, &hostdomain, 0, TRUE }, + { S("karch"), + 0, &gopt.karch, 0, TRUE }, + { S("cluster"), + 0, &gopt.cluster, 0, TRUE }, + { S("wire"), + 0, 0, f_in_network, TRUE }, + { S("network"), + 0, 0, f_in_network, TRUE }, + { S("netnumber"), + 0, 0, f_in_network, TRUE }, + { S("byte"), + 0, &endian, 0, TRUE }, + { S("os"), + 0, &gopt.op_sys, 0, TRUE }, + { S("osver"), + 0, &gopt.op_sys_ver, 0, TRUE }, + { S("remopts"), + &fs_static.opt_remopts, 0, 0, FALSE }, + { S("mount"), + &fs_static.opt_mount, 0, 0, FALSE }, + { S("unmount"), + &fs_static.opt_unmount, 0, 0, FALSE }, + { S("cache"), + &fs_static.opt_cache, 0, 0, FALSE }, + { S("user"), + &fs_static.opt_user, 0, 0, FALSE }, + { S("group"), + &fs_static.opt_group, 0, 0, FALSE }, + { S(".key"), + 0, &opt_dkey, 0, FALSE }, + { S("key."), + 0, &opt_keyd, 0, FALSE }, + { S("maptype"), + &fs_static.opt_maptype, 0, 0, FALSE }, + { S("cachedir"), + &fs_static.opt_cachedir, 0, 0, FALSE }, + { S("addopts"), + &fs_static.opt_addopts, 0, 0, FALSE }, + { S("var0"), + &vars[0], 0, 0, FALSE }, + { S("var1"), + &vars[1], 0, 0, FALSE }, + { S("var2"), + &vars[2], 0, 0, FALSE }, + { S("var3"), + &vars[3], 0, 0, FALSE }, + { S("var4"), + &vars[4], 0, 0, FALSE }, + { S("var5"), + &vars[5], 0, 0, FALSE }, + { S("var6"), + &vars[6], 0, 0, FALSE }, + { S("var7"), + &vars[7], 0, 0, FALSE }, + { 0, 0, 0, 0, 0, FALSE }, +}; + +static struct functable functable[] = { + { "in_network", f_in_network }, + { "netgrp", f_netgrp }, + { "exists", f_exists }, + { "false", f_false }, + { "true", f_true }, + { 0, 0 }, +}; + +/* + * Specially expand the remote host name first + */ +static opt_apply rhost_expansion[] = +{ + {&fs_static.opt_rhost, "${host}"}, + {0, 0}, +}; + +/* + * List of options which need to be expanded + * Note that the order here _may_ be important. + */ +static opt_apply expansions[] = +{ + {&fs_static.opt_sublink, 0}, + {&fs_static.opt_rfs, "${path}"}, + {&fs_static.opt_fs, "${autodir}/${rhost}${rfs}"}, + {&fs_static.opt_opts, "rw"}, + {&fs_static.opt_remopts, "${opts}"}, + {&fs_static.opt_mount, 0}, + {&fs_static.opt_unmount, 0}, + {&fs_static.opt_cachedir, 0}, + {&fs_static.opt_addopts, 0}, + {0, 0}, +}; + +/* + * List of options which need to be free'ed before re-use + */ +static opt_apply to_free[] = +{ + {&fs_static.fs_glob, 0}, + {&fs_static.fs_local, 0}, + {&fs_static.fs_mtab, 0}, + {&fs_static.opt_sublink, 0}, + {&fs_static.opt_rfs, 0}, + {&fs_static.opt_fs, 0}, + {&fs_static.opt_rhost, 0}, + {&fs_static.opt_opts, 0}, + {&fs_static.opt_remopts, 0}, + {&fs_static.opt_mount, 0}, + {&fs_static.opt_unmount, 0}, + {&fs_static.opt_cachedir, 0}, + {&fs_static.opt_addopts, 0}, + {&vars[0], 0}, + {&vars[1], 0}, + {&vars[2], 0}, + {&vars[3], 0}, + {&vars[4], 0}, + {&vars[5], 0}, + {&vars[6], 0}, + {&vars[7], 0}, + {0, 0}, +}; + + +/* + * expand backslash escape sequences + */ +static char +backslash(char **p) +{ + char c; + + if ((*p)[1] == '\0') { + plog(XLOG_USER, "Empty backslash escape"); + return **p; + } + + if (**p == '\\') { + (*p)++; + switch (**p) { + case 'a': + c = '\007'; /* Bell */ + break; + case 'b': + c = '\010'; /* Backspace */ + break; + case 't': + c = '\011'; /* Horizontal Tab */ + break; + case 'n': + c = '\012'; /* New Line */ + break; + case 'v': + c = '\013'; /* Vertical Tab */ + break; + case 'f': + c = '\014'; /* Form Feed */ + break; + case 'r': + c = '\015'; /* Carriage Return */ + break; + case 'e': + c = '\033'; /* Escape */ + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int cnt, val, ch; + + for (cnt = 0, val = 0; cnt < 3; cnt++) { + ch = *(*p)++; + if (ch < '0' || ch > '7') { + (*p)--; + break; + } + val = (val << 3) | (ch - '0'); + } + + if ((val & 0xffffff00) != 0) + plog(XLOG_USER, + "Too large character constant %u\n", + val); + c = (char) val; + --(*p); + } + break; + + default: + c = **p; + break; + } + } else + c = **p; + + return c; +} + + +/* + * Skip to next option in the string + */ +static char * +opt(char **p) +{ + char *cp = *p; + char *dp = cp; + char *s = cp; + +top: + while (*cp && *cp != ';') { + if (*cp == '"') { + /* + * Skip past string + */ + for (cp++; *cp && *cp != '"'; cp++) + if (*cp == '\\') + *dp++ = backslash(&cp); + else + *dp++ = *cp; + if (*cp) + cp++; + } else { + *dp++ = *cp++; + } + } + + /* + * Skip past any remaining ';'s + */ + while (*cp == ';') + cp++; + + /* + * If we have a zero length string + * and there are more fields, then + * parse the next one. This allows + * sequences of empty fields. + */ + if (*cp && dp == s) + goto top; + + *dp = '\0'; + + *p = cp; + return s; +} + + +/* + * These routines add a new style of selector; function-style boolean + * operators. To add new ones, just define functions as in true, false, + * exists (below) and add them to the functable, above. + * + * Usage example: Some people have X11R5 local, some go to a server. I do + * this: + * + * * exists(/usr/pkg/${key});type:=link;fs:=/usr/pkg/${key} || \ + * -type:=nfs;rfs=/usr/pkg/${key} \ + * rhost:=server1 \ + * rhost:=server2 + * + * -Rens Troost + */ +static IntFuncPtr +functable_lookup(char *key) +{ + struct functable *fp; + + for (fp = functable; fp->name; fp++) + if (FSTREQ(fp->name, key)) + return (fp->func); + return (IntFuncPtr) NULL; +} + + +static int +eval_opts(char *opts, char *mapkey) +{ + /* + * Fill in the global structure fs_static by + * cracking the string opts. opts may be + * scribbled on at will. + */ + char *o = opts; + char *f; + + /* + * For each user-specified option + */ + while (*(f = opt(&o))) { + struct opt *op; + enum vs_opt vs_opt = VarAss; + char *eq = strchr(f, '='); + char *fx; + IntFuncPtr func; + char *opt = NULL; + + if (!eq || eq[1] == '\0' || eq == f) { + /* + * No value, is it a function call? + */ + char *arg = strchr(f, '('); + + if (!arg || arg[1] == '\0' || arg == f) { + /* + * No, just continue + */ + plog(XLOG_USER, "key %s: No value component in \"%s\"", mapkey, f); + continue; + } + + /* null-terminate the argument */ + *arg++ = '\0'; + fx = strchr(arg, ')'); + if (!arg || fx == arg) { + plog(XLOG_USER, "key %s: Malformed function in \"%s\"", mapkey, f); + continue; + } + *fx = '\0'; + + /* + * look up f in functable and pass it arg. + * func must return 0 on failure, and 1 on success. + */ + if ((func = functable_lookup(f))) { + if (!(*func) (arg)) { + return (0); + } + continue; + } else if (NSTREQ(f, "!", 1) && (func = functable_lookup(&f[1]))) { + /* then this is a negated prefixed function such as "!exists" */ + plog(XLOG_USER, "executing negated function %s", &f[1]); + if ((*func) (arg)) { + return (0); + } + continue; + } else { + plog(XLOG_USER, "key %s: unknown function \"%s\"", mapkey, f); + return (0); + } + + } + + /* + * Check what type of operation is happening + * !=, =! is SelNE + * == is SelEQ + * := is VarAss + */ + if (eq[-1] == '!') { /* != */ + vs_opt = SelNE; + eq[-1] = '\0'; + opt = eq + 1; + } else if (eq[-1] == ':') { /* := */ + vs_opt = VarAss; + eq[-1] = '\0'; + opt = eq + 1; + } else if (eq[1] == '=') { /* == */ + vs_opt = SelEQ; + eq[0] = '\0'; + opt = eq + 2; + } else if (eq[1] == '!') { /* =! */ + vs_opt = SelNE; + eq[0] = '\0'; + opt = eq + 2; + } + + /* + * For each recognized option + */ + for (op = opt_fields; op->name; op++) { + /* + * Check whether they match + */ + if (FSTREQ(op->name, f)) { + int selok; + switch (vs_opt) { + case SelEQ: + case SelNE: + if ((selok = (op->sel_p != NULL))) { + if (op->case_insensitive) { + selok = (STRCEQ(*op->sel_p, opt) == (vs_opt == SelNE)); + } else { + selok = (STREQ(*op->sel_p, opt) == (vs_opt == SelNE)); + } + } + if (selok) { + plog(XLOG_MAP, "key %s: map selector %s (=%s) did not %smatch %s", + mapkey, + op->name, + *op->sel_p, + vs_opt == SelNE ? "mis" : "", + opt); + return 0; + } + /* check if to apply a function */ + if (op->fxn_p && + ((*op->fxn_p)(opt) == (vs_opt == SelNE))) { + plog(XLOG_MAP, "key %s: map function %s did not %smatch %s", + mapkey, + op->name, + vs_opt == SelNE ? "mis" : "", + opt); + return 0; + } + break; + + case VarAss: + if (op->sel_p) { + plog(XLOG_USER, "key %s: Can't assign to a selector (%s)", + mapkey, op->name); + return 0; + } + *op->optp = opt; + break; + + } /* end of "switch (vs_opt)" statement */ + break; /* break out of for loop */ + } + } + + if (!op->name) + plog(XLOG_USER, "key %s: Unrecognized key/option \"%s\"", mapkey, f); + } + + return 1; +} + + +/* + * Skip to next option in the string, but don't scribble over the string. + * However, *p gets repointed to the start of the next string past ';'. + */ +static char * +opt_no_scribble(char **p) +{ + char *cp = *p; + char *dp = cp; + char *s = cp; + +top: + while (*cp && *cp != ';') { + if (*cp == '\"') { + /* + * Skip past string + */ + cp++; + while (*cp && *cp != '\"') + *dp++ = *cp++; + if (*cp) + cp++; + } else { + *dp++ = *cp++; + } + } + + /* + * Skip past any remaining ';'s + */ + while (*cp == ';') + cp++; + + /* + * If we have a zero length string + * and there are more fields, then + * parse the next one. This allows + * sequences of empty fields. + */ + if (*cp && dp == s) + goto top; + + *p = cp; + return s; +} + + +/* + * Strip any selectors from a string. Selectors are all assumed to be + * first in the string. This is used for the new /defaults method which will + * use selectors as well. + */ +char * +strip_selectors(char *opts, char *mapkey) +{ + /* + * Fill in the global structure fs_static by + * cracking the string opts. opts may be + * scribbled on at will. + */ + char *o = opts; + char *oo = opts; + char *f; + + /* + * Scan options. Note that the opt() function scribbles on the opt string. + */ + while (*(f = opt_no_scribble(&o))) { + enum vs_opt vs_opt = VarAss; + char *eq = strchr(f, '='); + + if (!eq || eq[1] == '\0' || eq == f) { + /* + * No option or assignment? Return as is. + */ + plog(XLOG_USER, "key %s: No option or assignment in \"%s\"", mapkey, f); + return o; + } + /* + * Check what type of operation is happening + * !=, =! is SelNE + * == is SelEQ + * := is VarAss + */ + if (eq[-1] == '!') { /* != */ + vs_opt = SelNE; + } else if (eq[-1] == ':') { /* := */ + vs_opt = VarAss; + } else if (eq[1] == '=') { /* == */ + vs_opt = SelEQ; + } else if (eq[1] == '!') { /* =! */ + vs_opt = SelNE; + } + switch (vs_opt) { + case SelEQ: + case SelNE: + /* Skip this selector, maybe there's another one following it */ + plog(XLOG_USER, "skipping selector to \"%s\"", o); + /* store previous match. it may have been the first assignment */ + oo = o; + break; + + case VarAss: + /* found the first assignment, return the string starting with it */ +#ifdef DEBUG + dlog("found first assignment past selectors \"%s\"", o); +#endif /* DEBUG */ + return oo; + } + } + + /* return the same string by default. should not happen. */ + return oo; +} + + +/***************************************************************************** + *** BOOLEAN FUNCTIONS (return 0 if false, 1 if true): *** + *****************************************************************************/ + +/* test if arg is any of this host's network names or numbers */ +static int +f_in_network(char *arg) +{ + int status; + + if (!arg) + return FALSE; + + status = is_network_member(arg); +#ifdef DEBUG + plog(XLOG_USER, "%s is %son a local network", + arg, (status ? "" : "not ")); +#endif /* DEBUG */ + return status; +} + + +/* test if this host is in netgroup (arg) */ +static int +f_netgrp(char *arg) +{ + int status; + + status = innetgr(arg, opt_host, NULL, NULL); +#ifdef DEBUG + plog(XLOG_USER, "netgrp = %s status = %d host = %s", arg, status, opt_host); +#endif /* DEBUG */ + return status; +} + + +/* test if file (arg) exists via lstat */ +static int +f_exists(char *arg) +{ + struct stat buf; + + if (lstat(arg, &buf) < 0) + return (0); + else + return (1); +} + + +/* always false */ +static int +f_false(char *arg) +{ + return (0); +} + + +/* always true */ +static int +f_true(char *arg) +{ + return (1); +} + + +/* + * Free an option + */ +static void +free_op(opt_apply *p, int b) +{ + if (*p->opt) { + XFREE(*p->opt); + *p->opt = 0; + } +} + + +/* + * Normalize slashes in the string. + */ +void +normalize_slash(char *p) +{ + char *f = strchr(p, '/'); + char *f0 = f; + + if (f) { + char *t = f; + do { + /* assert(*f == '/'); */ + if (f == f0 && f[0] == '/' && f[1] == '/') { + /* copy double slash iff first */ + *t++ = *f++; + *t++ = *f++; + } else { + /* copy a single / across */ + *t++ = *f++; + } + + /* assert(f[-1] == '/'); */ + /* skip past more /'s */ + while (*f == '/') + f++; + + /* assert(*f != '/'); */ + /* keep copying up to next / */ + while (*f && *f != '/') { + *t++ = *f++; + } + + /* assert(*f == 0 || *f == '/'); */ + + } while (*f); + *t = 0; /* derived from fix by Steven Glassman */ + } +} + + +/* + * Macro-expand an option. Note that this does not + * handle recursive expansions. They will go badly wrong. + * If sel is true then old expand selectors, otherwise + * don't expand selectors. + */ +static void +expand_op(opt_apply *p, int sel_p) +{ + static char expand_error[] = "No space to expand \"%s\""; + char expbuf[MAXPATHLEN + 1]; + char nbuf[NLEN + 1]; + char *ep = expbuf; + char *cp = *p->opt; + char *dp; + struct opt *op; +#ifdef DEBUG + char *cp_orig = *p->opt; +#endif /* DEBUG */ + + while ((dp = strchr(cp, '$'))) { + char ch; + /* + * First copy up to the $ + */ + { + int len = dp - cp; + + if (BUFSPACE(ep, len)) { + strncpy(ep, cp, len); + ep += len; + } else { + plog(XLOG_ERROR, expand_error, *p->opt); + goto out; + } + } + + cp = dp + 1; + ch = *cp++; + if (ch == '$') { + if (BUFSPACE(ep, 1)) { + *ep++ = '$'; + } else { + plog(XLOG_ERROR, expand_error, *p->opt); + goto out; + } + } else if (ch == '{') { + /* Expansion... */ + enum { + E_All, E_Dir, E_File, E_Domain, E_Host + } todo; + /* + * Find closing brace + */ + char *br_p = strchr(cp, '}'); + int len; + + /* + * Check we found it + */ + if (!br_p) { + /* + * Just give up + */ + plog(XLOG_USER, "No closing '}' in \"%s\"", *p->opt); + goto out; + } + len = br_p - cp; + + /* + * Figure out which part of the variable to grab. + */ + if (*cp == '/') { + /* + * Just take the last component + */ + todo = E_File; + cp++; + --len; + } else if (br_p[-1] == '/') { + /* + * Take all but the last component + */ + todo = E_Dir; + --len; + } else if (*cp == '.') { + /* + * Take domain name + */ + todo = E_Domain; + cp++; + --len; + } else if (br_p[-1] == '.') { + /* + * Take host name + */ + todo = E_Host; + --len; + } else { + /* + * Take the whole lot + */ + todo = E_All; + } + + /* + * Truncate if too long. Since it won't + * match anyway it doesn't matter that + * it has been cut short. + */ + if (len > NLEN) + len = NLEN; + + /* + * Put the string into another buffer so + * we can do comparisons. + */ + strncpy(nbuf, cp, len); + nbuf[len] = '\0'; + + /* + * Advance cp + */ + cp = br_p + 1; + + /* + * Search the option array + */ + for (op = opt_fields; op->name; op++) { + /* + * Check for match + */ + if (len == op->nlen && STREQ(op->name, nbuf)) { + char xbuf[NLEN + 3]; + char *val; + /* + * Found expansion. Copy + * the correct value field. + */ + if (!(!op->sel_p == !sel_p)) { + /* + * Copy the string across unexpanded + */ + sprintf(xbuf, "${%s%s%s}", + todo == E_File ? "/" : + todo == E_Domain ? "." : "", + nbuf, + todo == E_Dir ? "/" : + todo == E_Host ? "." : ""); + val = xbuf; + /* + * Make sure expansion doesn't + * munge the value! + */ + todo = E_All; + } else if (op->sel_p) { + val = *op->sel_p; + } else { + val = *op->optp; + } + + if (val) { + /* + * Do expansion: + * ${/var} means take just the last part + * ${var/} means take all but the last part + * ${.var} means take all but first part + * ${var.} means take just the first part + * ${var} means take the whole lot + */ + int vlen = strlen(val); + char *vptr = val; + switch (todo) { + case E_Dir: + vptr = strrchr(val, '/'); + if (vptr) + vlen = vptr - val; + vptr = val; + break; + case E_File: + vptr = strrchr(val, '/'); + if (vptr) { + vptr++; + vlen = strlen(vptr); + } else + vptr = val; + break; + case E_Domain: + vptr = strchr(val, '.'); + if (vptr) { + vptr++; + vlen = strlen(vptr); + } else { + vptr = ""; + vlen = 0; + } + break; + case E_Host: + vptr = strchr(val, '.'); + if (vptr) + vlen = vptr - val; + vptr = val; + break; + case E_All: + break; + } + + if (BUFSPACE(ep, vlen)) { + strcpy(ep, vptr); + ep += vlen; + } else { + plog(XLOG_ERROR, expand_error, *p->opt); + goto out; + } + } + /* + * Done with this variable + */ + break; + } + } + + /* + * Check that the search was succesful + */ + if (!op->name) { + /* + * If it wasn't then scan the + * environment for that name + * and use any value found + */ + char *env = getenv(nbuf); + + if (env) { + int vlen = strlen(env); + + if (BUFSPACE(ep, vlen)) { + strcpy(ep, env); + ep += vlen; + } else { + plog(XLOG_ERROR, expand_error, *p->opt); + goto out; + } +#ifdef DEBUG + amuDebug(D_STR) + plog(XLOG_DEBUG, "Environment gave \"%s\" -> \"%s\"", nbuf, env); +#endif /* DEBUG */ + } else { + plog(XLOG_USER, "Unknown sequence \"${%s}\"", nbuf); + } + } + } else { + /* + * Error, error + */ + plog(XLOG_USER, "Unknown $ sequence in \"%s\"", *p->opt); + } + } + +out: + /* + * Handle common case - no expansion + */ + if (cp == *p->opt) { + *p->opt = strdup(cp); + } else { + /* + * Finish off the expansion + */ + if (BUFSPACE(ep, strlen(cp))) { + strcpy(ep, cp); + /* ep += strlen(ep); */ + } else { + plog(XLOG_ERROR, expand_error, *p->opt); + } + + /* + * Save the exansion + */ + *p->opt = strdup(expbuf); + } + + normalize_slash(*p->opt); + +#ifdef DEBUG + amuDebug(D_STR) { + plog(XLOG_DEBUG, "Expansion of \"%s\"...", cp_orig); + plog(XLOG_DEBUG, "... is \"%s\"", *p->opt); + } +#endif /* DEBUG */ +} + + +/* + * Wrapper for expand_op + */ +static void +expand_opts(opt_apply *p, int sel_p) +{ + if (*p->opt) { + expand_op(p, sel_p); + } else if (p->val) { + /* + * Do double expansion, remembering + * to free the string from the first + * expansion... + */ + char *s = *p->opt = expand_key(p->val); + expand_op(p, sel_p); + XFREE(s); + } +} + + +/* + * Apply a function to a list of options + */ +static void +apply_opts(void (*op) (opt_apply *, int), opt_apply ppp[], int b) +{ + opt_apply *pp; + + for (pp = ppp; pp->opt; pp++) + (*op) (pp, b); +} + + +/* + * Free the option table + */ +void +free_opts(am_opts *fo) +{ + /* + * Copy in the structure we are playing with + */ + fs_static = *fo; + + /* + * Free previously allocated memory + */ + apply_opts(free_op, to_free, FALSE); +} + + +/* + * Expand lookup key + */ +char * +expand_key(char *key) +{ + opt_apply oa; + + oa.opt = &key; + oa.val = 0; + expand_opts(&oa, TRUE); + + return key; +} + + +/* + * Remove trailing /'s from a string + * unless the string is a single / (Steven Glassman) + * or unless it is two slashes // (Kevin D. Bond) + */ +void +deslashify(char *s) +{ + if (s && *s) { + char *sl = s + strlen(s); + + while (*--sl == '/' && sl > s) + *sl = '\0'; + } +} + + +int +eval_fs_opts(am_opts *fo, char *opts, char *g_opts, char *path, char *key, char *map) +{ + int ok = TRUE; + + free_opts(fo); + + /* + * Clear out the option table + */ + memset((voidp) &fs_static, 0, sizeof(fs_static)); + memset((voidp) vars, 0, sizeof(vars)); + memset((voidp) fo, 0, sizeof(*fo)); + + /* + * Set key, map & path before expansion + */ + opt_key = key; + opt_map = map; + opt_path = path; + + opt_dkey = strchr(key, '.'); + if (!opt_dkey) { + opt_dkey = NullStr; + opt_keyd = key; + } else { + opt_keyd = strnsave(key, opt_dkey - key); + opt_dkey++; + if (*opt_dkey == '\0') /* check for 'host.' */ + opt_dkey = NullStr; + } + + /* + * Expand global options + */ + fs_static.fs_glob = expand_key(g_opts); + + /* + * Expand local options + */ + fs_static.fs_local = expand_key(opts); + + /* + * Expand default (global) options + */ + if (!eval_opts(fs_static.fs_glob, key)) + ok = FALSE; + + /* + * Expand local options + */ + if (ok && !eval_opts(fs_static.fs_local, key)) + ok = FALSE; + + /* + * Normalise remote host name. + * 1. Expand variables + * 2. Normalize relative to host tables + * 3. Strip local domains from the remote host + * name before using it in other expansions. + * This makes mount point names and other things + * much shorter, while allowing cross domain + * sharing of mount maps. + */ + apply_opts(expand_opts, rhost_expansion, FALSE); + if (ok && fs_static.opt_rhost && *fs_static.opt_rhost) + host_normalize(&fs_static.opt_rhost); + + /* + * Macro expand the options. + * Do this regardless of whether we are accepting + * this mount - otherwise nasty things happen + * with memory allocation. + */ + apply_opts(expand_opts, expansions, FALSE); + + /* + * Strip trailing slashes from local pathname... + */ + deslashify(fs_static.opt_fs); + + /* + * ok... copy the data back out. + */ + *fo = fs_static; + + /* + * Clear defined options + */ + if (opt_keyd != key && opt_keyd != nullstr) + XFREE(opt_keyd); + opt_keyd = nullstr; + opt_dkey = NullStr; + opt_key = opt_map = opt_path = nullstr; + + return ok; +} diff --git a/contrib/amd/amd/restart.c b/contrib/amd/amd/restart.c new file mode 100644 index 0000000..572df86 --- /dev/null +++ b/contrib/amd/amd/restart.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: restart.c,v 5.2.2.2 1992/08/02 10:42:21 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* + * Handle an amd restart. + * + * Scan through the mount list finding all "interesting" mount points. + * Next hack up partial data structures and add the mounted file + * system to the list of known filesystems. This will leave a + * dangling reference to that filesystems, so when the filesystem is + * finally inherited, an extra "free" must be done on it. + * + * This module relies on internal details of other components. If + * you change something else make *sure* restart() still works. + */ +void +restart(void) +{ + /* + * Read the existing mount table + */ + mntlist *ml, *mlp; + + /* + * For each entry, find nfs, ufs or auto mounts + * and create a partial am_node to represent it. + */ + for (mlp = ml = read_mtab("restart", mnttab_file_name); + mlp; + mlp = mlp->mnext) { + mntent_t *me = mlp->mnt; + am_ops *fs_ops = 0; + if (STREQ(me->mnt_type, MNTTAB_TYPE_UFS)) { + /* + * UFS entry + */ + fs_ops = &ufs_ops; + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) { + /* + * NFS entry, or possibly an Amd entry... + * The mnt_fsname for daemon mount points is + * host:(pidXXX) + * or (seen on Solaris) + * host:daemon(pidXXX) + */ + char *colon = strchr(me->mnt_fsname, ':'); + + if (colon && strstr(colon, "(pid")) { + plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir); + fs_ops = &amfs_link_ops; + } else { + fs_ops = &nfs_ops; + } +#ifdef MNTTAB_TYPE_NFS3 + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS3)) { + fs_ops = &nfs_ops; +#endif /* MNTTAB_TYPE_NFS3 */ +#ifdef MNTTAB_TYPE_LOFS + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_LOFS)) { + fs_ops = &lofs_ops; +#endif /* MNTTAB_TYPE_LOFS */ +#ifdef MNTTAB_TYPE_CDFS + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_CDFS)) { + fs_ops = &cdfs_ops; +#endif /* MNTTAB_TYPE_CDFS */ +#ifdef MNTTAB_TYPE_PCFS + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_PCFS)) { + fs_ops = &pcfs_ops; +#endif /* MNTTAB_TYPE_PCFS */ +#ifdef MNTTAB_TYPE_MFS + } else if (STREQ(me->mnt_type, MNTTAB_TYPE_MFS)) { + /* + * MFS entry. Fake with a symlink. + */ + fs_ops = &amfs_link_ops; +#endif /* MNTTAB_TYPE_MFS */ + } else { + /* + * Catch everything else with symlinks to + * avoid recursive mounts. This is debatable... + */ + fs_ops = &amfs_link_ops; + } + + /* + * If we found something to do + */ + if (fs_ops) { + mntfs *mf; + am_opts mo; + char *cp; + cp = strchr(me->mnt_fsname, ':'); + + /* + * Partially fake up an opts structure + */ + mo.opt_rhost = 0; + mo.opt_rfs = 0; + if (cp) { + *cp = '\0'; + mo.opt_rhost = strdup(me->mnt_fsname); + mo.opt_rfs = strdup(cp + 1); + *cp = ':'; + } else if (fs_ops->ffserver == find_nfs_srvr) { + /* + * Prototype 4.4 BSD used to end up here - + * might as well keep the workaround for now + */ + plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname); + mo.opt_rhost = strdup(me->mnt_fsname); + mo.opt_rfs = strdup("/"); + me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/"); + } + mo.opt_fs = me->mnt_dir; + mo.opt_opts = me->mnt_opts; + + /* + * Make a new mounted filesystem + */ + mf = find_mntfs(fs_ops, &mo, me->mnt_dir, + me->mnt_fsname, "", me->mnt_opts, ""); + if (mf->mf_refc == 1) { + mf->mf_flags |= MFF_RESTART | MFF_MOUNTED; + mf->mf_error = 0; /* Already mounted correctly */ + mf->mf_fo = 0; + /* + * If the restarted type is a link then + * don't time out. + */ + if (fs_ops == &amfs_link_ops || fs_ops == &ufs_ops) + mf->mf_flags |= MFF_RSTKEEP; + if (fs_ops->fs_init) { + /* + * Don't care whether this worked since + * it is checked again when the fs is + * inherited. + */ + (void) (*fs_ops->fs_init) (mf); + } + plog(XLOG_INFO, "%s restarted fstype %s on %s", + me->mnt_fsname, fs_ops->fs_type, me->mnt_dir); + } else { + /* Something strange happened - two mounts at the same place! */ + free_mntfs(mf); + } + /* + * Clean up mo + */ + if (mo.opt_rhost) + XFREE(mo.opt_rhost); + if (mo.opt_rfs) + XFREE(mo.opt_rfs); + } + } + + /* + * Free the mount list + */ + free_mntlist(ml); +} diff --git a/contrib/amd/amd/rpc_fwd.c b/contrib/amd/amd/rpc_fwd.c new file mode 100644 index 0000000..7f3c59b --- /dev/null +++ b/contrib/amd/amd/rpc_fwd.c @@ -0,0 +1,476 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: rpc_fwd.c,v 5.2.2.1 1992/02/09 15:09:01 jsp beta $ + * + */ + +/* + * RPC packet forwarding + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * Note that the ID field in the external packet is only + * ever treated as a 32 bit opaque data object, so there + * is no need to convert to and from network byte ordering. + */ + +#define XID_ALLOC(struct ) (xid++) +#define MAX_PACKET_SIZE 8192 /* Maximum UDP packet size */ + +/* + * Each pending reply has an rpc_forward structure + * associated with it. These have a 15 second lifespan. + * If a new structure is required, then an expired + * one will be re-allocated if available, otherwise a fresh + * one is allocated. Whenever a reply is received the + * structure is discarded. + */ +typedef struct rpc_forward rpc_forward; +struct rpc_forward { + qelem rf_q; /* Linked list */ + time_t rf_ttl; /* Time to live */ + u_int rf_xid; /* Packet id */ + u_int rf_oldid; /* Original packet id */ + fwd_fun rf_fwd; /* Forwarding function */ + voidp rf_ptr; + struct sockaddr_in rf_sin; +}; + +/* + * Head of list of pending replies + */ +qelem rpc_head = {&rpc_head, &rpc_head}; +int fwd_sock; +static u_int xid; + + +/* + * Allocate a rely structure + */ +static rpc_forward * +fwd_alloc(void) +{ + time_t now = clocktime(); + rpc_forward *p = 0, *p2; + + /* + * First search for an existing expired one. + */ + ITER(p2, rpc_forward, &rpc_head) { + if (p2->rf_ttl <= now) { + p = p2; + break; + } + } + + /* + * If one couldn't be found then allocate + * a new structure and link it at the + * head of the list. + */ + if (p) { + /* + * Call forwarding function to say that + * this message was junked. + */ +#ifdef DEBUG + dlog("Re-using packet forwarding slot - id %#x", p->rf_xid); +#endif /* DEBUG */ + if (p->rf_fwd) + (*p->rf_fwd) (0, 0, 0, &p->rf_sin, p->rf_ptr, FALSE); + rem_que(&p->rf_q); + } else { + p = ALLOC(struct rpc_forward); + } + ins_que(&p->rf_q, &rpc_head); + + /* + * Set the time to live field + * Timeout in 43 seconds + */ + p->rf_ttl = now + 43; + + return p; +} + + +/* + * Free an allocated reply structure. + * First unlink it from the list, then + * discard it. + */ +static void +fwd_free(rpc_forward *p) +{ + rem_que(&p->rf_q); + XFREE(p); +} + + +/* + * Initialize the RPC forwarder + */ +int +fwd_init(void) +{ +#ifdef FIONBIO + int on = 1; +#endif /* FIONBIO */ + +#ifdef HAVE_TRANSPORT_TYPE_TLI + /* + * Create ping TLI socket (/dev/tcp and /dev/ticlts did not work) + * (HPUX-11 does not like using O_NDELAY in flags) + */ + fwd_sock = t_open("/dev/udp", O_RDWR|O_NONBLOCK, 0); + if (fwd_sock < 0) { + plog(XLOG_ERROR, "unable to create RPC forwarding TLI socket: %s", + t_errlist[t_errno]); + return errno; + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + /* + * Create ping socket + */ + fwd_sock = socket(AF_INET, SOCK_DGRAM, 0); + if (fwd_sock < 0) { + plog(XLOG_ERROR, "unable to create RPC forwarding socket: %m"); + return errno; + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* + * Some things we talk to require a priv port - so make one here + */ + if (bind_resv_port(fwd_sock, (u_short *) 0) < 0) + plog(XLOG_ERROR, "can't bind privileged port"); + + if (fcntl(fwd_sock, F_SETFL, FNDELAY) < 0 +#ifdef FIONBIO + && ioctl(fwd_sock, FIONBIO, &on) < 0 +#endif /* FIONBIO */ + ) { + plog(XLOG_ERROR, "Can't set non-block on forwarding socket: %m"); + return errno; + } + + return 0; +} + + +/* + * Locate a packet in the forwarding list + */ +static rpc_forward * +fwd_locate(u_int id) +{ + rpc_forward *p; + + ITER(p, rpc_forward, &rpc_head) { + if (p->rf_xid == id) + return p; + } + + return 0; +} + + +/* + * This is called to forward a packet to another + * RPC server. The message id is changed and noted + * so that when a reply appears we can tie it up + * correctly. Just matching the reply's source address + * would not work because it might come from a + * different address. + */ +int +fwd_packet(int type_id, voidp pkt, int len, struct sockaddr_in *fwdto, struct sockaddr_in *replyto, voidp i, fwd_fun cb) +{ + rpc_forward *p; + u_int *pkt_int; + int error; +#ifdef HAVE_TRANSPORT_TYPE_TLI + struct t_unitdata ud; +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + if ((int) amd_state >= (int) Finishing) + return ENOENT; + + /* + * See if the type_id is fully specified. + * If so, then discard any old entries + * for this id. + * Otherwise make sure the type_id is + * fully qualified by allocating an id here. + */ +#ifdef DEBUG + switch (type_id & RPC_XID_MASK) { + case RPC_XID_PORTMAP: + dlog("Sending PORTMAP request"); + break; + case RPC_XID_MOUNTD: + dlog("Sending MOUNTD request %#x", type_id); + break; + case RPC_XID_NFSPING: + dlog("Sending NFS ping"); + break; + default: + dlog("UNKNOWN RPC XID"); + break; + } +#endif /* DEBUG */ + + if (type_id & ~RPC_XID_MASK) { + p = fwd_locate(type_id); + if (p) { +#ifdef DEBUG + dlog("Discarding earlier rpc fwd handle"); +#endif /* DEBUG */ + fwd_free(p); + } + } else { +#ifdef DEBUG + dlog("Allocating a new xid..."); +#endif /* DEBUG */ + type_id = MK_RPC_XID(type_id, XID_ALLOC(struct )); + } + + p = fwd_alloc(); + if (!p) + return ENOBUFS; + + error = 0; + + pkt_int = (u_int *) pkt; + + /* + * Get the original packet id + */ + p->rf_oldid = *pkt_int; + + /* + * Replace with newly allocated id + */ + p->rf_xid = *pkt_int = type_id; + + /* + * The sendto may fail if, for example, the route + * to a remote host is lost because an intermediate + * gateway has gone down. Important to fill in the + * rest of "p" otherwise nasty things happen later... + */ +#ifdef DEBUG + { + char dq[20]; + if (p && fwdto) + dlog("Sending packet id %#x to %s.%d", + p->rf_xid, + inet_dquad(dq, fwdto->sin_addr.s_addr), + ntohs(fwdto->sin_port)); + } +#endif /* DEBUG */ + + /* if NULL, remote server probably down */ + if (!fwdto) { + error = AM_ERRNO_HOST_DOWN; + goto out; + } + +#ifdef HAVE_TRANSPORT_TYPE_TLI + ud.addr.buf = (char *) fwdto; + if (fwdto) /* if NULL, set sizes to zero */ + ud.addr.maxlen = ud.addr.len = sizeof(struct sockaddr_in); + else + ud.addr.maxlen = ud.addr.len = 0; + ud.opt.buf = (char *) NULL; + ud.opt.maxlen = ud.opt.len = 0; + ud.udata.buf = pkt; + ud.udata.maxlen = ud.udata.len = len; + if (t_sndudata(fwd_sock, &ud) < 0) { + plog(XLOG_ERROR,"fwd_packet failed: t_errno=%d, errno=%d",t_errno,errno); + error = errno; + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + if (sendto(fwd_sock, (char *) pkt, len, 0, + (struct sockaddr *) fwdto, sizeof(*fwdto)) < 0) + error = errno; +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* + * Save callback function and return address + */ +out: + p->rf_fwd = cb; + if (replyto) + p->rf_sin = *replyto; + else + memset((voidp) &p->rf_sin, 0, sizeof(p->rf_sin)); + p->rf_ptr = i; + + return error; +} + + +/* + * Called when some data arrives on the forwarding socket + */ +void +fwd_reply(void) +{ + int len; + u_int pkt[MAX_PACKET_SIZE / sizeof(u_int) + 1]; + u_int *pkt_int; + int rc; + rpc_forward *p; + struct sockaddr_in src_addr; + RECVFROM_FROMLEN_TYPE src_addr_len; +#ifdef HAVE_TRANSPORT_TYPE_TLI + struct t_unitdata ud; + int flags = 0; +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + /* + * Determine the length of the packet + */ + len = MAX_PACKET_SIZE; + + /* + * Read the packet and check for validity + */ +again: + src_addr_len = sizeof(src_addr); +#ifdef HAVE_TRANSPORT_TYPE_TLI + ud.addr.buf = (char *) &src_addr; + ud.addr.maxlen = ud.addr.len = src_addr_len; + ud.opt.buf = (char *) NULL; + ud.opt.maxlen = ud.opt.len = 0; + ud.udata.buf = (char *) pkt; + ud.udata.maxlen = ud.udata.len = len; + /* XXX: use flags accordingly such as if T_MORE set */ + rc = t_rcvudata(fwd_sock, &ud, &flags); + if (rc == 0) /* success, reset rc to length */ + rc = ud.udata.len; + else { + plog(XLOG_ERROR,"fwd_reply failed: t_errno=%d, errno=%d, flags=%d",t_errno,errno, flags); + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + rc = recvfrom(fwd_sock, + (char *) pkt, + len, + 0, + (struct sockaddr *) &src_addr, + &src_addr_len); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* + * XXX: in svr4, if the T_MORE bit of flags is set, what do + * we then do? -Erez + */ + if (rc < 0 || src_addr_len != sizeof(src_addr) || + src_addr.sin_family != AF_INET) { + if (rc < 0 && errno == EINTR) + goto again; + plog(XLOG_ERROR, "Error reading RPC reply: %m"); + goto out; + } + + /* + * Do no more work if finishing soon + */ + if ((int) amd_state >= (int) Finishing) + goto out; + + /* + * Find packet reference + */ + pkt_int = (u_int *) pkt; + +#ifdef DEBUG + switch (*pkt_int & RPC_XID_MASK) { + case RPC_XID_PORTMAP: + dlog("Receiving PORTMAP reply"); + break; + case RPC_XID_MOUNTD: + dlog("Receiving MOUNTD reply %#x", *pkt_int); + break; + case RPC_XID_NFSPING: + dlog("Receiving NFS ping %#x", *pkt_int); + break; + default: + dlog("UNKNOWN RPC XID"); + break; + } +#endif /* DEBUG */ + + p = fwd_locate(*pkt_int); + if (!p) { +#ifdef DEBUG + dlog("Can't forward reply id %#x", *pkt_int); +#endif /* DEBUG */ + goto out; + } + + if (p->rf_fwd) { + /* + * Put the original message id back + * into the packet. + */ + *pkt_int = p->rf_oldid; + + /* + * Call forwarding function + */ + (*p->rf_fwd) ((voidp) pkt, rc, &src_addr, &p->rf_sin, p->rf_ptr, TRUE); + } + + /* + * Free forwarding info + */ + fwd_free(p); + +out:; +} diff --git a/contrib/amd/amd/sched.c b/contrib/amd/amd/sched.c new file mode 100644 index 0000000..ffbe2c8 --- /dev/null +++ b/contrib/amd/amd/sched.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: sched.c,v 5.2.2.1 1992/02/09 15:09:02 jsp beta $ + * + */ + +/* + * Process scheduler + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +typedef struct pjob pjob; + +struct pjob { + qelem hdr; /* Linked list */ + int pid; /* Process ID of job */ + cb_fun cb_fun; /* Callback function */ + voidp cb_closure; /* Closure for callback */ + int w; /* everyone these days uses int, not a "union wait" */ + voidp wchan; /* Wait channel */ +}; + +/* globals */ +qelem proc_list_head = {&proc_list_head, &proc_list_head}; +qelem proc_wait_list = {&proc_wait_list, &proc_wait_list}; +int task_notify_todo; + + +void +ins_que(qelem *elem, qelem *pred) +{ + qelem *p = pred->q_forw; + + elem->q_back = pred; + elem->q_forw = p; + pred->q_forw = elem; + p->q_back = elem; +} + + +void +rem_que(qelem *elem) +{ + qelem *p = elem->q_forw; + qelem *p2 = elem->q_back; + + p2->q_forw = p; + p->q_back = p2; +} + + +static pjob * +sched_job(cb_fun cf, voidp ca) +{ + pjob *p = ALLOC(struct pjob); + + p->cb_fun = cf; + p->cb_closure = ca; + + /* + * Now place on wait queue + */ + ins_que(&p->hdr, &proc_wait_list); + + return p; +} + + +/* + * tf: The task to execute (ta is its arguments) + * cf: Continuation function (ca is its arguments) + */ +void +run_task(task_fun tf, voidp ta, cb_fun cf, voidp ca) +{ + pjob *p = sched_job(cf, ca); +#ifdef HAVE_SIGACTION + sigset_t new, mask; +#else /* not HAVE_SIGACTION */ + int mask; +#endif /* not HAVE_SIGACTION */ + + p->wchan = (voidp) p; + +#ifdef HAVE_SIGACTION + sigemptyset(&new); /* initialise signal set we wish to block */ + sigaddset(&new, SIGCHLD); /* only block on SIGCHLD */ + sigprocmask(SIG_BLOCK, &new, &mask); +#else /* not HAVE_SIGACTION */ + mask = sigblock(sigmask(SIGCHLD)); +#endif /* not HAVE_SIGACTION */ + + if ((p->pid = background())) { +#ifdef HAVE_SIGACTION + sigprocmask(SIG_SETMASK, &mask, NULL); +#else /* not HAVE_SIGACTION */ + sigsetmask(mask); +#endif /* not HAVE_SIGACTION */ + return; + } + + /* child code runs here, parent have returned to caller */ + + exit((*tf) (ta)); + /* firewall... */ + abort(); +} + + +/* + * Schedule a task to be run when woken up + */ +void +sched_task(cb_fun cf, voidp ca, voidp wchan) +{ + /* + * Allocate a new task + */ + pjob *p = sched_job(cf, ca); + +#ifdef DEBUG + dlog("SLEEP on %#x", wchan); +#endif /* DEBUG */ + p->wchan = wchan; + p->pid = 0; + memset((voidp) &p->w, 0, sizeof(p->w)); +} + + +static void +wakeupjob(pjob *p) +{ + rem_que(&p->hdr); + ins_que(&p->hdr, &proc_list_head); + task_notify_todo++; +} + + +void +wakeup(voidp wchan) +{ + pjob *p, *p2; + + if (!foreground) + return; + + /* + * Can't user ITER() here because + * wakeupjob() juggles the list. + */ + for (p = AM_FIRST(pjob, &proc_wait_list); + p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); + p = p2) { + if (p->wchan == wchan) { + wakeupjob(p); + } + } +} + + +void +wakeup_task(int rc, int term, voidp cl) +{ + wakeup(cl); +} + + +/* + * Run any pending tasks. + * This must be called with SIGCHLD disabled + */ +void +do_task_notify(void) +{ + /* + * Keep taking the first item off the list and processing it. + * + * Done this way because the the callback can, quite reasonably, + * queue a new task, so no local reference into the list can be + * held here. + */ + while (AM_FIRST(pjob, &proc_list_head) != HEAD(pjob, &proc_list_head)) { + pjob *p = AM_FIRST(pjob, &proc_list_head); + rem_que(&p->hdr); + /* + * This job has completed + */ + --task_notify_todo; + + /* + * Do callback if it exists + */ + if (p->cb_fun) { + /* these two trigraphs will ensure compatibity with strict POSIX.1 */ + (*p->cb_fun) (WIFEXITED(p->w) ? WEXITSTATUS(p->w) : 0, + WIFSIGNALED(p->w) ? WTERMSIG(p->w) : 0, + p->cb_closure); + } + XFREE(p); + } +} + + +RETSIGTYPE +sigchld(int sig) +{ + int w; /* everyone these days uses int, not a "union wait" */ + int pid; + +#ifdef HAVE_WAITPID + while ((pid = waitpid((pid_t) -1, &w, WNOHANG)) > 0) { +#else /* not HAVE_WAITPID */ + while ((pid = wait3( &w, WNOHANG, (struct rusage *) 0)) > 0) { +#endif /* not HAVE_WAITPID */ + pjob *p, *p2; + + if (WIFSIGNALED(w)) + plog(XLOG_ERROR, "Process %d exited with signal %d", + pid, WTERMSIG(w)); +#ifdef DEBUG + else + dlog("Process %d exited with status %d", + pid, WEXITSTATUS(w)); +#endif /* DEBUG */ + + for (p = AM_FIRST(pjob, &proc_wait_list); + p2 = NEXT(pjob, p), p != HEAD(pjob, &proc_wait_list); + p = p2) { + if (p->pid == pid) { + p->w = w; + wakeupjob(p); + break; + } + } /* end of for loop */ + +#ifdef DEBUG + if (!p) + dlog("can't locate task block for pid %d", pid); +#endif /* DEBUG */ + + /* + * Must count down children inside the while loop, otherwise we won't + * count them all, and NumChild (and later backoff) will be set + * incorrectly. SH/RUNIT 940519. + */ + if (--NumChild < 0) + NumChild = 0; + } /* end of "while wait..." loop */ + +#ifdef REINSTALL_SIGNAL_HANDLER + signal(sig, sigchld); +#endif /* REINSTALL_SIGNAL_HANDLER */ + + if (select_intr_valid) + longjmp(select_intr, sig); +} diff --git a/contrib/amd/amd/srvr_amfs_auto.c b/contrib/amd/amd/srvr_amfs_auto.c new file mode 100644 index 0000000..e77c591 --- /dev/null +++ b/contrib/amd/amd/srvr_amfs_auto.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: srvr_amfs_auto.c,v 5.2.2.1 1992/02/09 15:09:05 jsp beta $ + * + */ + +/* + * Automount FS server ("localhost") modeling + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* globals */ +qelem amfs_auto_srvr_list = {&amfs_auto_srvr_list, &amfs_auto_srvr_list}; + +/* statics */ +static fserver *localhost; + + +/* + * Find an nfs server for the local host + */ +fserver * +find_amfs_auto_srvr(mntfs *mf) +{ + fserver *fs = localhost; + + if (!fs) { + fs = ALLOC(struct fserver); + fs->fs_refc = 0; + fs->fs_host = strdup("localhost"); + fs->fs_ip = 0; + fs->fs_cid = 0; + fs->fs_pinger = 0; + fs->fs_flags = FSF_VALID; + fs->fs_type = "local"; + fs->fs_private = 0; + fs->fs_prfree = 0; + + ins_que(&fs->fs_q, &amfs_auto_srvr_list); + + srvrlog(fs, "starts up"); + + localhost = fs; + } + fs->fs_refc++; + + return fs; +} + + +/***************************************************************************** + *** GENERIC ROUTINES FOLLOW + *****************************************************************************/ + +/* + * Wakeup anything waiting for this server + */ +void +wakeup_srvr(fserver *fs) +{ + fs->fs_flags &= ~FSF_WANT; + wakeup((voidp) fs); +} + + +/* + * Called when final ttl of server has expired + */ +static void +timeout_srvr(voidp v) +{ + fserver *fs = v; + + /* + * If the reference count is still zero then + * we are free to remove this node + */ + if (fs->fs_refc == 0) { +#ifdef DEBUG + dlog("Deleting file server %s", fs->fs_host); +#endif /* DEBUG */ + if (fs->fs_flags & FSF_WANT) + wakeup_srvr(fs); + + /* + * Remove from queue. + */ + rem_que(&fs->fs_q); + /* + * (Possibly) call the private free routine. + */ + if (fs->fs_private && fs->fs_prfree) + (*fs->fs_prfree) (fs->fs_private); + + /* + * Free the net address + */ + if (fs->fs_ip) + XFREE(fs->fs_ip); + + /* + * Free the host name. + */ + XFREE(fs->fs_host); + + /* + * Discard the fserver object. + */ + XFREE(fs); + } +} + + +/* + * Free a file server + */ +void +free_srvr(fserver *fs) +{ + if (--fs->fs_refc == 0) { + /* + * The reference count is now zero, + * so arrange for this node to be + * removed in AM_TTL seconds if no + * other mntfs is referencing it. + */ + int ttl = (fs->fs_flags & (FSF_DOWN | FSF_ERROR)) ? 19 : AM_TTL; + +#ifdef DEBUG + dlog("Last hard reference to file server %s - will timeout in %ds", fs->fs_host, ttl); +#endif /* DEBUG */ + if (fs->fs_cid) { + untimeout(fs->fs_cid); + /* + * Turn off pinging - XXX + */ + fs->fs_flags &= ~FSF_PINGING; + } + + /* + * Keep structure lying around for a while + */ + fs->fs_cid = timeout(ttl, timeout_srvr, (voidp) fs); + + /* + * Mark the fileserver down and invalid again + */ + fs->fs_flags &= ~FSF_VALID; + fs->fs_flags |= FSF_DOWN; + } +} + + +/* + * Make a duplicate fserver reference + */ +fserver * +dup_srvr(fserver *fs) +{ + fs->fs_refc++; + return fs; +} + + +/* + * Log state change + */ +void srvrlog(fserver *fs, char *state) +{ + plog(XLOG_INFO, "file server %s type %s %s", fs->fs_host, fs->fs_type, state); +} diff --git a/contrib/amd/amd/srvr_nfs.c b/contrib/amd/amd/srvr_nfs.c new file mode 100644 index 0000000..22a2640 --- /dev/null +++ b/contrib/amd/amd/srvr_nfs.c @@ -0,0 +1,851 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: srvr_nfs.c,v 5.2.2.1 1992/02/09 15:09:06 jsp beta $ + * + */ + +/* + * NFS server modeling + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * Number of pings allowed to fail before host is declared down + * - three-fifths of the allowed mount time... + */ +#define MAX_ALLOWED_PINGS (3 + /* for luck ... */ 1) + +/* + * How often to ping when starting a new server + */ +#define FAST_NFS_PING 3 + +#if (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME +# error: sanity check failed in srvr_nfs.c +/* + * you cannot do things this way... + * sufficient fast pings must be given the chance to fail + * within the allowed mount time + */ +#endif /* (FAST_NFS_PING * MAX_ALLOWED_PINGS) >= ALLOWED_MOUNT_TIME */ + +#define NPXID_ALLOC(struct ) (++np_xid) + +/* structures and typedefs */ +typedef struct nfs_private { + u_short np_mountd; /* Mount daemon port number */ + char np_mountd_inval; /* Port *may* be invalid */ + int np_ping; /* Number of failed ping attempts */ + time_t np_ttl; /* Time when server is thought dead */ + int np_xid; /* RPC transaction id for pings */ + int np_error; /* Error during portmap request */ +} nfs_private; + +/* globals */ +qelem nfs_srvr_list = {&nfs_srvr_list, &nfs_srvr_list}; + +/* statics */ +static int np_xid; /* For NFS pings */ +static int ping_len; +static char ping_buf[sizeof(struct rpc_msg) + 32]; + +#if defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) +/* protocols we know about, in order of preference */ +static char *protocols[] = { "tcp", "udp", NULL }; +#endif /* defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */ + +/* forward definitions */ +static void nfs_keepalive(voidp); + + + +/* + * Flush any cached data + */ +void +flush_srvr_nfs_cache(void) +{ + fserver *fs = 0; + + ITER(fs, fserver, &nfs_srvr_list) { + nfs_private *np = (nfs_private *) fs->fs_private; + if (np) { + np->np_mountd_inval = TRUE; + np->np_error = -1; + } + } +} + + +/* + * Startup the NFS ping for a particular version. + */ +static void +start_ping(u_long nfs_version) +{ + XDR ping_xdr; + struct rpc_msg ping_msg; + + /* + * Non nfs mounts like /afs/glue.umd.edu have ended up here. + */ + if (nfs_version == 0) { + nfs_version = NFS_VERSION; + plog(XLOG_WARNING, "start_ping: nfs_version = 0 fixed"); + } + plog(XLOG_INFO, "start_ping: nfs_version: %d", nfs_version); + + rpc_msg_init(&ping_msg, NFS_PROGRAM, nfs_version, NFSPROC_NULL); + + /* + * Create an XDR endpoint + */ + xdrmem_create(&ping_xdr, ping_buf, sizeof(ping_buf), XDR_ENCODE); + + /* + * Create the NFS ping message + */ + if (!xdr_callmsg(&ping_xdr, &ping_msg)) { + plog(XLOG_ERROR, "Couldn't create ping RPC message"); + going_down(3); + } + /* + * Find out how long it is + */ + ping_len = xdr_getpos(&ping_xdr); + + /* + * Destroy the XDR endpoint - we don't need it anymore + */ + xdr_destroy(&ping_xdr); +} + + +/* + * Called when a portmap reply arrives + */ +static void +got_portmap(voidp pkt, int len, struct sockaddr_in * sa, struct sockaddr_in * ia, voidp idv, int done) +{ + fserver *fs2 = (fserver *) idv; + fserver *fs = 0; + + /* + * Find which fileserver we are talking about + */ + ITER(fs, fserver, &nfs_srvr_list) + if (fs == fs2) + break; + + if (fs == fs2) { + u_long port = 0; /* XXX - should be short but protocol is naff */ + int error = done ? pickup_rpc_reply(pkt, len, (voidp) &port, (XDRPROC_T_TYPE) xdr_u_long) : -1; + nfs_private *np = (nfs_private *) fs->fs_private; + + if (!error && port) { +#ifdef DEBUG + dlog("got port (%d) for mountd on %s", port, fs->fs_host); +#endif /* DEBUG */ + /* + * Grab the port number. Portmap sends back + * an u_long in native ordering, so it + * needs converting to a u_short in + * network ordering. + */ + np->np_mountd = htons((u_short) port); + np->np_mountd_inval = FALSE; + np->np_error = 0; + } else { +#ifdef DEBUG + dlog("Error fetching port for mountd on %s", fs->fs_host); + dlog("\t error=%d, port=%d", error, port); +#endif /* DEBUG */ + /* + * Almost certainly no mountd running on remote host + */ + np->np_error = error ? error : ETIMEDOUT; + } + + if (fs->fs_flags & FSF_WANT) + wakeup_srvr(fs); + } else if (done) { +#ifdef DEBUG + dlog("Got portmap for old port request"); +#endif /* DEBUG */ + } else { +#ifdef DEBUG + dlog("portmap request timed out"); +#endif /* DEBUG */ + } +} + + +/* + * Obtain portmap information + */ +static int +call_portmap(fserver *fs, AUTH * auth, u_long prog, u_long vers, u_long prot) +{ + struct rpc_msg pmap_msg; + int len; + char iobuf[UDPMSGSIZE]; + int error; + struct pmap pmap; + + rpc_msg_init(&pmap_msg, PMAPPROG, PMAPVERS, PMAPPROC_NULL); + pmap.pm_prog = prog; + pmap.pm_vers = vers; + pmap.pm_prot = prot; + pmap.pm_port = 0; + len = make_rpc_packet(iobuf, + sizeof(iobuf), + PMAPPROC_GETPORT, + &pmap_msg, + (voidp) &pmap, + (XDRPROC_T_TYPE) xdr_pmap, + auth); + if (len > 0) { + struct sockaddr_in sin; + memset((voidp) &sin, 0, sizeof(sin)); + sin = *fs->fs_ip; + sin.sin_port = htons(PMAPPORT); + error = fwd_packet(RPC_XID_PORTMAP, (voidp) iobuf, len, + &sin, &sin, (voidp) fs, got_portmap); + } else { + error = -len; + } + + return error; +} + + +static void +recompute_portmap(fserver *fs) +{ + int error; + u_long mnt_version; + + if (nfs_auth) + error = 0; + else + error = make_nfs_auth(); + + if (error) { + nfs_private *np = (nfs_private *) fs->fs_private; + np->np_error = error; + return; + } + + if (fs->fs_version == 0) + plog(XLOG_WARNING, "recompute_portmap: nfs_version = 0 fixed"); + + plog(XLOG_INFO, "recompute_portmap: NFS version %d", fs->fs_version); +#ifdef HAVE_FS_NFS3 + if (fs->fs_version == NFS_VERSION3) + mnt_version = MOUNTVERS3; + else +#endif /* HAVE_FS_NFS3 */ + mnt_version = MOUNTVERS; + + plog(XLOG_INFO, "Using MOUNT version: %d", mnt_version); + call_portmap(fs, nfs_auth, MOUNTPROG, mnt_version, (u_long) IPPROTO_UDP); +} + + +/* + * This is called when we get a reply to an RPC ping. + * The value of id was taken from the nfs_private + * structure when the ping was transmitted. + */ +static void +nfs_pinged(voidp pkt, int len, struct sockaddr_in * sp, struct sockaddr_in * tsp, voidp idv, int done) +{ + int xid = (long) idv; /* for 64-bit archs */ + fserver *fs; +#ifdef DEBUG + int found_map = 0; +#endif /* DEBUG */ + + if (!done) + return; + + /* + * For each node... + */ + ITER(fs, fserver, &nfs_srvr_list) { + nfs_private *np = (nfs_private *) fs->fs_private; + if (np->np_xid == xid && (fs->fs_flags & FSF_PINGING)) { + /* + * Reset the ping counter. + * Update the keepalive timer. + * Log what happened. + */ + if (fs->fs_flags & FSF_DOWN) { + fs->fs_flags &= ~FSF_DOWN; + if (fs->fs_flags & FSF_VALID) { + srvrlog(fs, "is up"); + } else { + if (np->np_ping > 1) + srvrlog(fs, "ok"); +#ifdef DEBUG + else + srvrlog(fs, "starts up"); +#endif /* DEBUG */ + fs->fs_flags |= FSF_VALID; + } + + map_flush_srvr(fs); + } else { + if (fs->fs_flags & FSF_VALID) { +#ifdef DEBUG + dlog("file server %s type nfs is still up", fs->fs_host); +#endif /* DEBUG */ + } else { + if (np->np_ping > 1) + srvrlog(fs, "ok"); + fs->fs_flags |= FSF_VALID; + } + } + + /* + * Adjust ping interval + */ + untimeout(fs->fs_cid); + fs->fs_cid = timeout(fs->fs_pinger, nfs_keepalive, (voidp) fs); + + /* + * Update ttl for this server + */ + np->np_ttl = clocktime() + + (MAX_ALLOWED_PINGS - 1) * FAST_NFS_PING + fs->fs_pinger - 1; + + /* + * New RPC xid... + */ + np->np_xid = NPXID_ALLOC(struct ); + + /* + * Failed pings is zero... + */ + np->np_ping = 0; + + /* + * Recompute portmap information if not known + */ + if (np->np_mountd_inval) + recompute_portmap(fs); + +#ifdef DEBUG + found_map++; +#endif /* DEBUG */ + break; + } + } + +#ifdef DEBUG + if (found_map == 0) + dlog("Spurious ping packet"); +#endif /* DEBUG */ +} + + +/* + * Called when no ping-reply received + */ +static void +nfs_timed_out(voidp v) +{ + fserver *fs = v; + nfs_private *np = (nfs_private *) fs->fs_private; + + /* + * Another ping has failed + */ + np->np_ping++; + + /* + * Not known to be up any longer + */ + if (FSRV_ISUP(fs)) { + fs->fs_flags &= ~FSF_VALID; + if (np->np_ping > 1) + srvrlog(fs, "not responding"); + } + + /* + * If ttl has expired then guess that it is dead + */ + if (np->np_ttl < clocktime()) { + int oflags = fs->fs_flags; + if ((fs->fs_flags & FSF_DOWN) == 0) { + /* + * Server was up, but is now down. + */ + srvrlog(fs, "is down"); + fs->fs_flags |= FSF_DOWN | FSF_VALID; + /* + * Since the server is down, the portmap + * information may now be wrong, so it + * must be flushed from the local cache + */ + flush_nfs_fhandle_cache(fs); + np->np_error = -1; + } else { + /* + * Known to be down + */ +#ifdef DEBUG + if ((fs->fs_flags & FSF_VALID) == 0) + srvrlog(fs, "starts down"); +#endif /* DEBUG */ + fs->fs_flags |= FSF_VALID; + } + if (oflags != fs->fs_flags && (fs->fs_flags & FSF_WANT)) + wakeup_srvr(fs); + } else { +#ifdef DEBUG + if (np->np_ping > 1) + dlog("%d pings to %s failed - at most %d allowed", np->np_ping, fs->fs_host, MAX_ALLOWED_PINGS); +#endif /* DEBUG */ + } + + /* + * Run keepalive again + */ + nfs_keepalive(fs); +} + + +/* + * Keep track of whether a server is alive + */ +static void +nfs_keepalive(voidp v) +{ + fserver *fs = v; + int error; + nfs_private *np = (nfs_private *) fs->fs_private; + int fstimeo = -1; + + /* + * Send an NFS ping to this node + */ + + if (ping_len == 0) + start_ping(fs->fs_version); + + /* + * Queue the packet... + */ + error = fwd_packet(MK_RPC_XID(RPC_XID_NFSPING, np->np_xid), + (voidp) ping_buf, + ping_len, + fs->fs_ip, + (struct sockaddr_in *) 0, + (voidp) ((long) np->np_xid), /* for 64-bit archs */ + nfs_pinged); + + /* + * See if a hard error occured + */ + switch (error) { + case ENETDOWN: + case ENETUNREACH: + case EHOSTDOWN: + case EHOSTUNREACH: + np->np_ping = MAX_ALLOWED_PINGS; /* immediately down */ + np->np_ttl = (time_t) 0; + /* + * This causes an immediate call to nfs_timed_out + * whenever the server was thought to be up. + * See +++ below. + */ + fstimeo = 0; + break; + + case 0: +#ifdef DEBUG + dlog("Sent NFS ping to %s", fs->fs_host); +#endif /* DEBUG */ + break; + } + + /* + * Back off the ping interval if we are not getting replies and + * the remote system is know to be down. + */ + switch (fs->fs_flags & (FSF_DOWN | FSF_VALID)) { + case FSF_VALID: /* Up */ + if (fstimeo < 0) /* +++ see above */ + fstimeo = FAST_NFS_PING; + break; + + case FSF_VALID | FSF_DOWN: /* Down */ + fstimeo = fs->fs_pinger; + break; + + default: /* Unknown */ + fstimeo = FAST_NFS_PING; + break; + } + +#ifdef DEBUG + dlog("NFS timeout in %d seconds", fstimeo); +#endif /* DEBUG */ + + fs->fs_cid = timeout(fstimeo, nfs_timed_out, (voidp) fs); +} + + +int +nfs_srvr_port(fserver *fs, u_short * port, voidp wchan) +{ + int error = -1; + if ((fs->fs_flags & FSF_VALID) == FSF_VALID) { + if ((fs->fs_flags & FSF_DOWN) == 0) { + nfs_private *np = (nfs_private *) fs->fs_private; + if (np->np_error == 0) { + *port = np->np_mountd; + error = 0; + } else { + error = np->np_error; + } + /* + * Now go get the port mapping again in case it changed. + * Note that it is used even if (np_mountd_inval) + * is True. The flag is used simply as an + * indication that the mountd may be invalid, not + * that it is known to be invalid. + */ + if (np->np_mountd_inval) + recompute_portmap(fs); + else + np->np_mountd_inval = TRUE; + } else { + error = EWOULDBLOCK; + } + } + if (error < 0 && wchan && !(fs->fs_flags & FSF_WANT)) { + /* + * If a wait channel is supplied, and no + * error has yet occured, then arrange + * that a wakeup is done on the wait channel, + * whenever a wakeup is done on this fs node. + * Wakeup's are done on the fs node whenever + * it changes state - thus causing control to + * come back here and new, better things to happen. + */ + fs->fs_flags |= FSF_WANT; + sched_task(wakeup_task, wchan, (voidp) fs); + } + return error; +} + + +static void +start_nfs_pings(fserver *fs, int pingval) +{ + if (!(fs->fs_flags & FSF_PINGING)) { + fs->fs_flags |= FSF_PINGING; + if (fs->fs_cid) + untimeout(fs->fs_cid); + if (pingval < 0) { + srvrlog(fs, "wired up"); + fs->fs_flags |= FSF_VALID; + fs->fs_flags &= ~FSF_DOWN; + } else { + nfs_keepalive(fs); + } + } else { +#ifdef DEBUG + dlog("Already running pings to %s", fs->fs_host); +#endif /* DEBUG */ + } +} + + +/* + * Find an nfs server for a host. + */ +fserver * +find_nfs_srvr(mntfs *mf) +{ + char *host = mf->mf_fo->opt_rhost; + char *nfs_proto = NULL; + fserver *fs; + int pingval; + mntent_t mnt; + nfs_private *np; + struct hostent *hp = 0; + struct sockaddr_in *ip; + u_long nfs_version = 0; /* default is no version specified */ +#ifdef MNTTAB_OPT_PROTO + char *rfsname = mf->mf_fo->opt_rfs; +#endif /* MNTTAB_OPT_PROTO */ + + /* + * Get ping interval from mount options. + * Current only used to decide whether pings + * are required or not. < 0 = no pings. + */ + mnt.mnt_opts = mf->mf_mopts; + pingval = hasmntval(&mnt, "ping"); + + /* + * Get the NFS version from the mount options. This is used + * to decide the highest NFS version to try. + */ +#ifdef MNTTAB_OPT_VERS + nfs_version = hasmntval(&mnt, MNTTAB_OPT_VERS); +#endif /* MNTTAB_OPT_VERS */ + +#ifdef MNTTAB_OPT_PROTO + { + char *proto_opt = hasmntopt(&mnt, MNTTAB_OPT_PROTO); + if (proto_opt) { + char **p; + + proto_opt += sizeof(MNTTAB_OPT_PROTO) - 1; /* skip the "proto" */ + + for (p = protocols; *p; p ++) + if (proto_opt[0] == '=' && + NSTREQ(&proto_opt[1], *p, strlen(*p))) { + nfs_proto = *p; + break; + } + if (*p == NULL) + plog(XLOG_WARNING, "ignoring unknown protocol option for %s:%s", + host, rfsname); + } + } +#endif /* MNTTAB_OPT_PROTO */ + + /* + * lookup host address and canonical name + */ + hp = gethostbyname(host); + + /* + * New code from Bob Harris + * Use canonical name to keep track of file server + * information. This way aliases do not generate + * multiple NFS pingers. (Except when we're normalizing + * hosts.) + */ + if (hp && !(gopt.flags & CFM_NORMALIZE_HOSTNAMES)) + host = (char *) hp->h_name; + + if (hp) { + switch (hp->h_addrtype) { + case AF_INET: + ip = ALLOC(struct sockaddr_in); + memset((voidp) ip, 0, sizeof(*ip)); + ip->sin_family = AF_INET; + memmove((voidp) &ip->sin_addr, (voidp) hp->h_addr, sizeof(ip->sin_addr)); + + ip->sin_port = htons(NFS_PORT); + break; + + default: + ip = 0; + break; + } + } else { + plog(XLOG_USER, "Unknown host: %s", host); + ip = 0; + } + + /* + * Get the NFS Version, and verify server is up. Probably no + * longer need to start server down below. + */ + if (ip) { +#ifdef HAVE_FS_NFS3 + /* + * Find the best combination of NFS version and protocol. + * When given a choice, use the highest available version, + * and use TCP over UDP if available. + */ + if (nfs_proto) + nfs_version = get_nfs_version(host, ip, nfs_version, nfs_proto); + else { + int best_nfs_version = 0; + int proto_nfs_version; + char **p; + + for (p = protocols; *p; p ++) { + proto_nfs_version = get_nfs_version(host, ip, nfs_version, *p); + + if (proto_nfs_version > best_nfs_version) { + best_nfs_version = proto_nfs_version; + nfs_proto = *p; + } + } + nfs_version = best_nfs_version; + } + + if (!nfs_version) { + /* + * If the NFS server is down or does not support the portmapper call + * (such as certain Novell NFS servers) we mark it as version 2 and we + * let the nfs code deal with the case that is down. If when the + * server comes back up, it can support NFS V.3 and/or TCP, it will + * use those. + */ + nfs_version = NFS_VERSION; + nfs_proto = "udp"; + } +#else /* not HAVE_FS_NFS3 */ + nfs_version = NFS_VERSION; +#endif /* not HAVE_FS_NFS3 */ + } + + if (!nfs_proto) + nfs_proto = "udp"; + + plog(XLOG_INFO, "Using NFS version %d, protocol %s on host %s", + nfs_version, nfs_proto, host); + + /* + * Try to find an existing fs server stucture for this host. + * Note that differing versions or protocols have their own structures. + * XXX: Need to fix the ping mechanism to actually use the NFS protocol + * chosen here (right now it always uses datagram sockets). + */ + ITER(fs, fserver, &nfs_srvr_list) { + if (STREQ(host, fs->fs_host) && + nfs_version == fs->fs_version && + STREQ(nfs_proto, fs->fs_proto)) { + /* + * following if statement from Mike Mitchell + * + * Initialize the ping data if we aren't pinging + * now. The np_ttl and np_ping fields are + * especially important. + */ + if (!(fs->fs_flags & FSF_PINGING)) { + np = (nfs_private *) fs->fs_private; + np->np_mountd_inval = TRUE; + np->np_xid = NPXID_ALLOC(struct ); + np->np_error = -1; + np->np_ping = 0; + /* + * Initially the server will be deemed dead + * after MAX_ALLOWED_PINGS of the fast variety + * have failed. + */ + np->np_ttl = MAX_ALLOWED_PINGS * FAST_NFS_PING + clocktime() - 1; + } + /* + * fill in the IP address -- this is only needed + * if there is a chance an IP address will change + * between mounts. + * Mike Mitchell, mcm@unx.sas.com, 09/08/93 + */ + if (hp && fs->fs_ip) + memmove((voidp) &fs->fs_ip->sin_addr, (voidp) hp->h_addr, sizeof(fs->fs_ip->sin_addr)); + + start_nfs_pings(fs, pingval); + fs->fs_refc++; + if (ip) + XFREE(ip); + return fs; + } + } + + /* + * Get here if we can't find an entry + */ + + /* + * Allocate a new server + */ + fs = ALLOC(struct fserver); + fs->fs_refc = 1; + fs->fs_host = strdup(hp ? hp->h_name : "unknown_hostname"); + if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) + host_normalize(&fs->fs_host); + fs->fs_ip = ip; + fs->fs_cid = 0; + if (ip) { + fs->fs_flags = FSF_DOWN; /* Starts off down */ + } else { + fs->fs_flags = FSF_ERROR | FSF_VALID; + mf->mf_flags |= MFF_ERROR; + mf->mf_error = ENOENT; + } + fs->fs_version = nfs_version; + fs->fs_proto = nfs_proto; + fs->fs_type = MNTTAB_TYPE_NFS; + fs->fs_pinger = AM_PINGER; + np = ALLOC(struct nfs_private); + memset((voidp) np, 0, sizeof(*np)); + np->np_mountd_inval = TRUE; + np->np_xid = NPXID_ALLOC(struct ); + np->np_error = -1; + + /* + * Initially the server will be deemed dead after + * MAX_ALLOWED_PINGS of the fast variety have failed. + */ + np->np_ttl = clocktime() + MAX_ALLOWED_PINGS * FAST_NFS_PING - 1; + fs->fs_private = (voidp) np; + fs->fs_prfree = (void (*)(voidp)) free; + + if (!(fs->fs_flags & FSF_ERROR)) { + /* + * Start of keepalive timer + */ + start_nfs_pings(fs, pingval); + } + + /* + * Add to list of servers + */ + ins_que(&fs->fs_q, &nfs_srvr_list); + + return fs; +} diff --git a/contrib/amd/amq/amq.8 b/contrib/amd/amq/amq.8 new file mode 100644 index 0000000..4084cdb --- /dev/null +++ b/contrib/amd/amq/amq.8 @@ -0,0 +1,214 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1990 Jan-Simon Pendry +.\" Copyright (c) 1990 Imperial College of Science, Technology & Medicine +.\" Copyright (c) 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jan-Simon Pendry at Imperial College, London. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" %W% (Berkeley) %G% +.\" +.\" $Id: amq.8,v 5.2.2.1 1992/02/09 15:11:15 jsp beta $ +.\" +.TH AMQ 8 "25 April 1989" +.SH NAME +amq \- automounter query tool +.SH SYNOPSIS +.B amq +[ +.BI \-fmpsuvTU +] [ +.BI \-h " hostname" +] [ +.BI \-l " log_file" +] [ +.BI \-x " log_options" +] [ +.BI \-D " debug_options" +] [ +.BI \-M " mountmap entry" +] [ +.BI \-P " program_number" +] [ +.I directory +] .\|.\|. +.SH DESCRIPTION +.B Amq +provides a simple way of determining the current state of +.B amd +program. +Communication is by +.SM RPC. +Three modes of operation are supported by the current protocol. By default +a list of mount points and auto-mounted filesystems is output. An +alternative host can be specified using the +.I \-h +option. +.LP +If +.I directory +names are given, as output by default, then per-filesystem +information is displayed. +.SH OPTIONS + +.TP +.B \-f +Ask the automounter to flush the internal caches. + +.TP +.BI \-h " hostname" +Specify an alternate host to query. By default the local host is used. In +an +.SM HP-UX +cluster, the root server is queried by default, since that is the system on +which the automounter is normally run. + +.TP +.BI \-l " log_file" +Tell amd to use +.I log_file +as the log file name. For security reasons, this must be the same log file +which amd used when started. This option is therefore only useful to +refresh amd's open file handle on the log file, so that it can be rotated +and compressed via daily cron jobs. + +.TP +.B \-m +Ask the automounter to provide a list of mounted filesystems, including the +number of references to each filesystem and any error which occurred while +mounting. + +.TP +.B \-p +Return the process ID of the remote or locally running amd. Useful when you +need to send a signal to the local amd process, and would rather not have to +search through the process table. This option is used in the +.I ctl-amd +script. + +.TP +.B \-s +Ask the automounter to provide system-wide mount statistics. + +.TP +.B \-u +Ask the automounter to unmount the filesystems named in +.I directory +instead of providing +information about them. Unmounts are requested, not forced. They merely +cause the mounted filesystem to timeout, which will be picked up by +.BR amd 's +main scheduler thus causing the normal timeout action to be taken. + +.TP +.B \-v +Ask the automounter for its version information. This is a subset of the +information output by +.BR amd 's +.I -v +option. + +.TP +.BI \-x " log_options" +Ask the automounter to use the logging options specified in +.I log_options +from now on. + +.TP +.BI \-D " log_options" +Ask the automounter to use the debugging options specified in +.I debug_options +from now on. + +.TP +.BI \-M " map_ent" +Pass a mount map entry to +.B amd +and wait for it to be evaluated, possible causing a mount. This option is +highly insecure. By default, amd and amq do not support it. You have to +configure am-utils with +.I \-\-enable\-amq\-mount +to enable this option. + +.TP +.BI \-P " program_number" +Contact an alternate running amd that had registered itself on a different +RPC +.I program_number +and apply all other operations to that instance of the automounter. This is +useful when you run multiple copies of amd, and need to manage each +one separately. If not specified, amq will use the default program number +for amd, 300019. For security reasons, the only alternate program numbers +amd can use range from 300019 to 300029, inclusive. + +.TP +.B \-T +Contact +.B amd +using the TCP transport only. Normally +.B amq +will try TCP, and if that failed, will try UDP. + +.TP +.B \-U +Contact +.B amd +using UDP (connectionless) transport only. Normally +.B amq +will try TCP, and if that failed, will try UDP. + +.SH FILES +.PD 0 +.TP 20 +.B amq.x +.SM RPC +protocol description. +.SH CAVEATS +.B Amq +uses a Sun registered +.SM RPC +program number (300019 decimal) which may not +be in the /etc/rpc database. +.SH "SEE ALSO" +.BR amd (8), +.BR ctl-amd (8), +.BR amd.conf (5). +.SH AUTHORS +Jan-Simon Pendry , Department of Computing, Imperial College, London, UK. +.P +Erez Zadok , Department of Computer Science, Columbia +University, New York, USA. +.P +Other authors and contributors to am-utils are listed in the +.B AUTHORS +file distributed with am-utils. diff --git a/contrib/amd/amq/amq.c b/contrib/amd/amq/amq.c new file mode 100644 index 0000000..7fba9b1 --- /dev/null +++ b/contrib/amd/amq/amq.c @@ -0,0 +1,938 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amq.c,v 5.2.2.1 1992/02/09 15:09:16 jsp beta $ + * + */ + +/* + * Automounter query tool + */ + +#ifndef lint +char copyright[] = "\ +@(#)Copyright (c) 1997-1998 Erez Zadok\n\ +@(#)Copyright (c) 1990 Jan-Simon Pendry\n\ +@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\ +@(#)Copyright (c) 1990 The Regents of the University of California.\n\ +@(#)All rights reserved.\n"; +#if __GNUC__ < 2 +static char rcsid[] = "$Id: amq.c,v 6.0 1997-1998/01/01 15:09:16 ezk $"; +static char sccsid[] = "%W% (Berkeley) %G%"; +#endif /* __GNUC__ < 2 */ +#endif /* not lint */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* locals */ +char *progname; +static int flush_flag; +static int minfo_flag; +static int getpid_flag; +static int unmount_flag; +static int stats_flag; +static int getvers_flag; +static int amd_program_number = AMQ_PROGRAM; +static int use_tcp_flag, use_udp_flag; +static char *debug_opts; +static char *amq_logfile; +static char *mount_map; +static char *xlog_optstr; +static char localhost[] = "localhost"; +static char *def_server = localhost; + +/* externals */ +extern int optind; +extern char *optarg; + +/* forward decalrations */ +#ifdef HAVE_TRANSPORT_TYPE_TLI +static CLIENT *get_secure_amd_client(char *host, struct timeval *tv, int *sock); +static int amq_bind_resv_port(int td, u_short *pp); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ +static int privsock(int ty); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + +/* dummy variables */ +char hostname[MAXHOSTNAMELEN]; +int orig_umask, foreground, debug_flags; +pid_t mypid; +serv_state amd_state; + +/* structures */ +enum show_opt { + Full, Stats, Calc, Short, ShowDone +}; + + +/* + * If (e) is Calc then just calculate the sizes + * Otherwise display the mount node on stdout + */ +static void +show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid) +{ + switch (e) { + case Calc: + { + int mw = strlen(mt->mt_mountinfo); + int dw = strlen(mt->mt_directory); + int tw = strlen(mt->mt_type); + if (mw > *mwid) + *mwid = mw; + if (dw > *dwid) + *dwid = dw; + if (tw > *twid) + *twid = tw; + } + break; + + case Full: + { + struct tm *tp = localtime((time_t *) &mt->mt_mounttime); + printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", + *dwid, *dwid, + *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ + *twid, *twid, + mt->mt_type, + *mwid, *mwid, + mt->mt_mountinfo, + mt->mt_mountpoint, + + mt->mt_mountuid, + mt->mt_getattr, + mt->mt_lookup, + mt->mt_readdir, + mt->mt_readlink, + mt->mt_statfs, + + tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, + tp->tm_mon + 1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec); + } + break; + + case Stats: + { + struct tm *tp = localtime((time_t *) &mt->mt_mounttime); + printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n", + *dwid, *dwid, + *mt->mt_directory ? mt->mt_directory : "/", /* XXX */ + + mt->mt_mountuid, + mt->mt_getattr, + mt->mt_lookup, + mt->mt_readdir, + mt->mt_readlink, + mt->mt_statfs, + + tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year, + tp->tm_mon + 1, tp->tm_mday, + tp->tm_hour, tp->tm_min, tp->tm_sec); + } + break; + + case Short: + { + printf("%-*.*s %-*.*s %-*.*s %s\n", + *dwid, *dwid, + *mt->mt_directory ? mt->mt_directory : "/", + *twid, *twid, + mt->mt_type, + *mwid, *mwid, + mt->mt_mountinfo, + mt->mt_mountpoint); + } + break; + + default: + break; + } +} + +/* + * Display a mount tree. + */ +static void +show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid) +{ + while (mt) { + show_mti(mt, e, mwid, dwid, pwid); + show_mt(mt->mt_next, e, mwid, dwid, pwid); + mt = mt->mt_child; + } +} + +static void +show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid) +{ + int i; + + switch (e) { + + case Calc: + { + for (i = 0; i < ml->amq_mount_info_list_len; i++) { + amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; + int mw = strlen(mi->mi_mountinfo); + int dw = strlen(mi->mi_mountpt); + int tw = strlen(mi->mi_type); + if (mw > *mwid) + *mwid = mw; + if (dw > *dwid) + *dwid = dw; + if (tw > *twid) + *twid = tw; + } + } + break; + + case Full: + { + for (i = 0; i < ml->amq_mount_info_list_len; i++) { + amq_mount_info *mi = &ml->amq_mount_info_list_val[i]; + printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s", + *mwid, *mwid, mi->mi_mountinfo, + *dwid, *dwid, mi->mi_mountpt, + *twid, *twid, mi->mi_type, + mi->mi_refc, mi->mi_fserver, + mi->mi_up > 0 ? "up" : + mi->mi_up < 0 ? "starting" : "down"); + if (mi->mi_error > 0) { + extern int sys_nerr; + if (mi->mi_error < sys_nerr) + printf(" (%s)", sys_errlist[mi->mi_error]); + else + printf(" (Error %d)", mi->mi_error); + } else if (mi->mi_error < 0) { + fputs(" (in progress)", stdout); + } + fputc('\n', stdout); + } + } + break; + + default: + break; + } +} + + +/* + * Display general mount statistics + */ +static void +show_ms(amq_mount_stats *ms) +{ + printf("\ +requests stale mount mount unmount\n\ +deferred fhandles ok failed failed\n\ +%-9d %-9d %-9d %-9d %-9d\n", + ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr); +} + + +#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) +static char * +cluster_server(void) +{ + struct cct_entry *cp; + + if (cnodeid() == 0) { + /* + * Not clustered + */ + return def_server; + } + while (cp = getccent()) + if (cp->cnode_type == 'r') + return cp->cnode_name; + + return def_server; +} +#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ + + +/* + * MAIN + */ +int +main(int argc, char *argv[]) +{ + int opt_ch; + int errs = 0; + char *server; + struct sockaddr_in server_addr; + int s; /* to pass the Amd security check, we must use a priv port */ + CLIENT *clnt = NULL; + struct hostent *hp; + int nodefault = 0; + struct timeval tv; +#ifndef HAVE_TRANSPORT_TYPE_TLI + enum clnt_stat cs; +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + + /* + * Compute program name + */ + if (argv[0]) { + progname = strrchr(argv[0], '/'); + if (progname && progname[1]) + progname++; + else + progname = argv[0]; + } + if (!progname) + progname = "amq"; + + /* + * Parse arguments + */ + while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:pP:TU")) != EOF) + switch (opt_ch) { + case 'f': + flush_flag = 1; + nodefault = 1; + break; + + case 'h': + def_server = optarg; + break; + + case 'l': + amq_logfile = optarg; + nodefault = 1; + break; + + case 'm': + minfo_flag = 1; + nodefault = 1; + break; + + case 'p': + getpid_flag = 1; + nodefault = 1; + break; + + case 's': + stats_flag = 1; + nodefault = 1; + break; + + case 'u': + unmount_flag = 1; + nodefault = 1; + break; + + case 'v': + getvers_flag = 1; + nodefault = 1; + break; + + case 'x': + xlog_optstr = optarg; + nodefault = 1; + break; + + case 'D': + debug_opts = optarg; + nodefault = 1; + break; + + case 'M': + mount_map = optarg; + nodefault = 1; + break; + + case 'P': + amd_program_number = atoi(optarg); + break; + + case 'T': + use_tcp_flag = 1; + break; + + case 'U': + use_udp_flag = 1; + break; + + default: + errs = 1; + break; + } + + if (optind == argc) { + if (unmount_flag) + errs = 1; + } + if (errs) { + show_usage: + fprintf(stderr, "\ +Usage: %s [-h host] [[-f] [-m] [-p] [-v] [-s]] | [[-u] directory ...]]\n\ +\t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts] [-M mapent]\n\ +\t[-P prognum] [-T] [-U]\n", progname); + exit(1); + } + + /* set use_udp and use_tcp flags both to on if none are defined */ + if (!use_tcp_flag && !use_udp_flag) + use_tcp_flag = use_udp_flag = 1; + +#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) + /* + * Figure out root server of cluster + */ + if (def_server == localhost) + server = cluster_server(); + else +#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */ + server = def_server; + + /* + * Get address of server + */ + if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) { + fprintf(stderr, "%s: Can't get address of %s\n", progname, server); + exit(1); + } + memset(&server_addr, 0, sizeof server_addr); + server_addr.sin_family = AF_INET; + if (hp) { + memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr, + sizeof(server_addr.sin_addr)); + } else { + /* fake "localhost" */ + server_addr.sin_addr.s_addr = htonl(0x7f000001); + } + + /* + * Create RPC endpoint + */ + tv.tv_sec = 5; /* 5 seconds for timeout or per retry */ + tv.tv_usec = 0; + +#ifdef HAVE_TRANSPORT_TYPE_TLI + clnt = get_secure_amd_client(server, &tv, &s); + if (!clnt && use_tcp_flag) /* try tcp first */ + clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp"); + if (!clnt && use_udp_flag) { /* try udp next */ + clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp"); + /* if ok, set timeout (valid for connectionless transports only) */ + if (clnt) + clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv); + } +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* first check if remote portmapper is up */ + cs = pmap_ping(&server_addr); + if (cs == RPC_TIMEDOUT) { + fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n", + progname, server, clnt_sperrno(cs)); + exit(1); + } + + /* portmapper exists: get remote amd info from it */ + if (!clnt && use_tcp_flag) { /* try tcp first */ + s = RPC_ANYSOCK; + clnt = clnttcp_create(&server_addr, amd_program_number, + AMQ_VERSION, &s, 0, 0); + } + if (!clnt && use_udp_flag) { /* try udp next */ + /* XXX: do we need to close(s) ? */ + s = privsock(SOCK_DGRAM); + clnt = clntudp_create(&server_addr, amd_program_number, + AMQ_VERSION, tv, &s); + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + if (!clnt) { + fprintf(stderr, "%s: ", progname); + clnt_pcreateerror(server); + exit(1); + } + + /* + * Control debugging + */ + if (debug_opts) { + int *rc; + amq_setopt opt; + opt.as_opt = AMOPT_DEBUG; + opt.as_str = debug_opts; + rc = amqproc_setopt_1(&opt, clnt); + if (rc && *rc < 0) { + fprintf(stderr, "%s: daemon not compiled for debug\n", progname); + errs = 1; + } else if (!rc || *rc > 0) { + fprintf(stderr, "%s: debug setting for \"%s\" failed\n", progname, debug_opts); + errs = 1; + } + } + + /* + * Control logging + */ + if (xlog_optstr) { + int *rc; + amq_setopt opt; + opt.as_opt = AMOPT_XLOG; + opt.as_str = xlog_optstr; + rc = amqproc_setopt_1(&opt, clnt); + if (!rc || *rc) { + fprintf(stderr, "%s: setting log level to \"%s\" failed\n", progname, xlog_optstr); + errs = 1; + } + } + + /* + * Control log file + */ + if (amq_logfile) { + int *rc; + amq_setopt opt; + opt.as_opt = AMOPT_LOGFILE; + opt.as_str = amq_logfile; + rc = amqproc_setopt_1(&opt, clnt); + if (!rc || *rc) { + fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", progname, amq_logfile); + errs = 1; + } + } + + /* + * Flush map cache + */ + if (flush_flag) { + int *rc; + amq_setopt opt; + opt.as_opt = AMOPT_FLUSHMAPC; + opt.as_str = ""; + rc = amqproc_setopt_1(&opt, clnt); + if (!rc || *rc) { + fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", progname, server); + errs = 1; + } + } + + /* + * Mount info + */ + if (minfo_flag) { + int dummy; + amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt); + if (ml) { + int mwid = 0, dwid = 0, twid = 0; + show_mi(ml, Calc, &mwid, &dwid, &twid); + mwid++; + dwid++; + twid++; + show_mi(ml, Full, &mwid, &dwid, &twid); + + } else { + fprintf(stderr, "%s: amd on %s cannot provide mount info\n", progname, server); + } + } + + /* + * Mount map + */ + if (mount_map) { + int *rc; + do { + rc = amqproc_mount_1(&mount_map, clnt); + } while (rc && *rc < 0); + if (!rc || *rc > 0) { + if (rc) + errno = *rc; + else + errno = ETIMEDOUT; + fprintf(stderr, "%s: could not start new ", progname); + perror("autmount point"); + } + } + + /* + * Get Version + */ + if (getvers_flag) { + amq_string *spp = amqproc_getvers_1((voidp) 0, clnt); + if (spp && *spp) { + fputs(*spp, stdout); + XFREE(*spp); + } else { + fprintf(stderr, "%s: failed to get version information\n", progname); + errs = 1; + } + } + + /* + * Get PID of amd + */ + if (getpid_flag) { + int *ip = amqproc_getpid_1((voidp) 0, clnt); + if (ip && *ip) { + printf("%d\n", *ip); + } else { + fprintf(stderr, "%s: failed to get PID of amd\n", progname); + errs = 1; + } + } + + /* + * Apply required operation to all remaining arguments + */ + if (optind < argc) { + do { + char *fs = argv[optind++]; + if (unmount_flag) { + /* + * Unmount request + */ + amqproc_umnt_1(&fs, clnt); + } else { + /* + * Stats request + */ + amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt); + if (mtp) { + amq_mount_tree *mt = *mtp; + if (mt) { + int mwid = 0, dwid = 0, twid = 0; + show_mt(mt, Calc, &mwid, &dwid, &twid); + mwid++; + dwid++, twid++; + printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n", + dwid, dwid, "What"); + show_mt(mt, Stats, &mwid, &dwid, &twid); + } else { + fprintf(stderr, "%s: %s not automounted\n", progname, fs); + } + xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp); + } else { + fprintf(stderr, "%s: ", progname); + clnt_perror(clnt, server); + errs = 1; + } + } + } while (optind < argc); + + } else if (unmount_flag) { + goto show_usage; + + } else if (stats_flag) { + amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt); + if (ms) { + show_ms(ms); + } else { + fprintf(stderr, "%s: ", progname); + clnt_perror(clnt, server); + errs = 1; + } + + } else if (!nodefault) { + amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt); + if (mlp) { + enum show_opt e = Calc; + int mwid = 0, dwid = 0, pwid = 0; + while (e != ShowDone) { + int i; + for (i = 0; i < mlp->amq_mount_tree_list_len; i++) { + show_mt(mlp->amq_mount_tree_list_val[i], + e, &mwid, &dwid, &pwid); + } + mwid++; + dwid++, pwid++; + if (e == Calc) + e = Short; + else if (e == Short) + e = ShowDone; + } + + } else { + fprintf(stderr, "%s: ", progname); + clnt_perror(clnt, server); + errs = 1; + } + } + exit(errs); + return errs; /* should never reache here */ +} + + +#ifdef HAVE_TRANSPORT_TYPE_TLI + +/* + * How to bind to reserved ports. + * TLI handle (socket) and port version. + */ +/* defined here so that it does not have to resolve it with libamu.a */ +static int +amq_bind_resv_port(int td, u_short *pp) +{ + int rc = -1, port; + struct t_bind *treq, *tret; + struct sockaddr_in *sin; + + treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); + if (!treq) { + plog(XLOG_ERROR, "t_alloc 1"); + return -1; + } + tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR); + if (!tret) { + t_free((char *) treq, T_BIND); + plog(XLOG_ERROR, "t_alloc 2"); + return -1; + } + memset((char *) treq->addr.buf, 0, treq->addr.len); + sin = (struct sockaddr_in *) treq->addr.buf; + sin->sin_family = AF_INET; + treq->qlen = 0; + treq->addr.len = treq->addr.maxlen; + errno = EADDRINUSE; + port = IPPORT_RESERVED; + + do { + --port; + sin->sin_port = htons(port); + rc = t_bind(td, treq, tret); + if (rc < 0) { + } else { + if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0) + break; + else + t_unbind(td); + } + } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2); + + if (pp) { + if (rc == 0) + *pp = port; + else + plog(XLOG_ERROR, "could not t_bind to any reserved port"); + } + t_free((char *) tret, T_BIND); + t_free((char *) treq, T_BIND); + return rc; +} + + +/* + * Create a secure rpc client attached to the amd daemon. + */ +static CLIENT * +get_secure_amd_client(char *host, struct timeval *tv, int *sock) +{ + CLIENT *client; + struct netbuf nb; + struct netconfig *nc, *pm_nc; + struct sockaddr_in sin; + + + nb.maxlen = sizeof(sin); + nb.buf = (char *) &sin; + + /* + * Ensure that remote portmapper is alive + * (must use connectionless netconfig). + */ + if ((pm_nc = getnetconfigent(NC_UDP)) != NULL) { + enum clnt_stat cs; + + cs = rpcb_rmtcall(pm_nc, + host, + amd_program_number, + AMQ_VERSION, + AMQPROC_NULL, + (XDRPROC_T_TYPE) xdr_void, + NULL, + (XDRPROC_T_TYPE) xdr_void, + NULL, + *tv, + NULL); + if (cs == RPC_TIMEDOUT) { + fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n", + progname, host, clnt_sperrno(cs)); + exit(1); + } + } + + /* + * First transport type to try: TCP + */ + if (use_tcp_flag) { + /* Find amd address on TCP */ + nc = getnetconfigent(NC_TCP); + if (!nc) { + fprintf(stderr, "getnetconfig for tcp failed: %s\n", nc_sperror()); + goto tryudp; + } + + if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) { + /* + * don't pring error messages here, since amd might legitimately + * serve udp only + */ + goto tryudp; + } + /* Create priviledged TCP socket */ + *sock = t_open(nc->nc_device, O_RDWR, 0); + + if (*sock < 0) { + fprintf(stderr, "t_open %s: %m\n", nc->nc_device); + goto tryudp; + } + if (amq_bind_resv_port(*sock, (u_short *) 0) < 0) + goto tryudp; + + client = clnt_vc_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0); + if (!client) { + fprintf(stderr, "clnt_vc_create failed"); + t_close(*sock); + goto tryudp; + } + /* tcp succeeded */ + return client; + } + +tryudp: + /* + * TCP failed so try UDP + */ + if (use_udp_flag) { + /* find amd address on UDP */ + nc = getnetconfigent(NC_UDP); + if (!nc) { + fprintf(stderr, "getnetconfig for udp failed: %s\n", nc_sperror()); + return NULL; + } + if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) { + fprintf(stderr, "%s\n", + clnt_spcreateerror("couldn't get amd address on udp")); + return NULL; + } + /* create priviledged UDP socket */ + *sock = t_open(nc->nc_device, O_RDWR, 0); + + if (*sock < 0) { + fprintf(stderr, "t_open %s: %m\n", nc->nc_device); + return NULL; /* neither tcp not udp succeeded */ + } + if (amq_bind_resv_port(*sock, (u_short *) 0) < 0) + return NULL; + + client = clnt_dg_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0); + if (!client) { + fprintf(stderr, "clnt_dg_create failed\n"); + t_close(*sock); + return NULL; /* neither tcp not udp succeeded */ + } + if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) { + fprintf(stderr, "clnt_control CLSET_RETRY_TIMEOUT for udp failed\n"); + clnt_destroy(client); + return NULL; /* neither tcp not udp succeeded */ + } + /* udp succeeded */ + return client; + } + + /* should never get here */ + return NULL; +} + +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + +/* + * inetresport creates a datagram socket and attempts to bind it to a + * secure port. + * returns: The bound socket, or -1 to indicate an error. + */ +static int +inetresport(int ty) +{ + int alport; + struct sockaddr_in addr; + int fd; + + /* Use internet address family */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + if ((fd = socket(AF_INET, ty, 0)) < 0) + return -1; + + for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) { + addr.sin_port = htons((u_short) alport); + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) + return fd; + if (errno != EADDRINUSE) { + close(fd); + return -1; + } + } + close(fd); + errno = EAGAIN; + return -1; +} + + +/* + * Privsock() calls inetresport() to attempt to bind a socket to a secure + * port. If inetresport() fails, privsock returns a magic socket number which + * indicates to RPC that it should make its own socket. + * returns: A privileged socket # or RPC_ANYSOCK. + */ +static int +privsock(int ty) +{ + int sock = inetresport(ty); + + if (sock < 0) { + errno = 0; + /* Couldn't get a secure port, let RPC make an insecure one */ + sock = RPC_ANYSOCK; + } + return sock; +} + +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ diff --git a/contrib/amd/amq/amq.h b/contrib/amd/amq/amq.h new file mode 100644 index 0000000..98f7383 --- /dev/null +++ b/contrib/amd/amq/amq.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amq.h,v 1.1 1996/01/13 23:23:39 ezk Exp ezk $ + * + */ + +#ifndef _AMQ_H +#define _AMQ_H + +/* + * external definitions for building amq + */ + +extern voidp amqproc_null_1(voidp argp, CLIENT *rqstp); +extern amq_mount_tree_p *amqproc_mnttree_1(amq_string *argp, CLIENT *rqstp); +extern voidp amqproc_umnt_1(amq_string *argp, CLIENT *rqstp); +extern amq_mount_stats *amqproc_stats_1(voidp argp, CLIENT *rqstp); +extern amq_mount_tree_list *amqproc_export_1(voidp argp, CLIENT *rqstp); +extern int *amqproc_setopt_1(amq_setopt *argp, CLIENT *rqstp); +extern amq_mount_info_list *amqproc_getmntfs_1(voidp argp, CLIENT *rqstp); +extern int *amqproc_mount_1(voidp argp, CLIENT *rqstp); +extern amq_string *amqproc_getvers_1(voidp argp, CLIENT *rqstp); +extern int *amqproc_getpid_1(voidp argp, CLIENT *rqstp); + +#endif /* not _AMQ_H */ diff --git a/contrib/amd/amq/amq_clnt.c b/contrib/amd/amq/amq_clnt.c new file mode 100644 index 0000000..7220cec --- /dev/null +++ b/contrib/amd/amq/amq_clnt.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amq_clnt.c,v 5.2.2.1 1992/02/09 15:09:24 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +static struct timeval TIMEOUT = {ALLOWED_MOUNT_TIME, 0}; + + +voidp +amqproc_null_1(voidp argp, CLIENT *clnt) +{ + static char res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_NULL, + (XDRPROC_T_TYPE) xdr_void, argp, + (XDRPROC_T_TYPE) xdr_void, &res, TIMEOUT) + != RPC_SUCCESS) { + return (NULL); + } + return ((voidp) &res); +} + + +amq_mount_tree_p * +amqproc_mnttree_1(amq_string *argp, CLIENT *clnt) +{ + static amq_mount_tree_p res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_MNTTREE, + (XDRPROC_T_TYPE) xdr_amq_string, (SVC_IN_ARG_TYPE) argp, + (XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (SVC_IN_ARG_TYPE) & res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + + +voidp +amqproc_umnt_1(amq_string *argp, CLIENT *clnt) +{ + static char res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_UMNT, + (XDRPROC_T_TYPE) xdr_amq_string, (SVC_IN_ARG_TYPE) argp, + (XDRPROC_T_TYPE) xdr_void, &res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return ((voidp) &res); +} + + +amq_mount_stats * +amqproc_stats_1(voidp argp, CLIENT *clnt) +{ + static amq_mount_stats res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_STATS, + (XDRPROC_T_TYPE) xdr_void, argp, + (XDRPROC_T_TYPE) xdr_amq_mount_stats, + (SVC_IN_ARG_TYPE) & res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + + +amq_mount_tree_list * +amqproc_export_1(voidp argp, CLIENT *clnt) +{ + static amq_mount_tree_list res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_EXPORT, + (XDRPROC_T_TYPE) xdr_void, argp, + (XDRPROC_T_TYPE) xdr_amq_mount_tree_list, + (SVC_IN_ARG_TYPE) & res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + + +int * +amqproc_setopt_1(amq_setopt *argp, CLIENT *clnt) +{ + static int res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_SETOPT, (XDRPROC_T_TYPE) xdr_amq_setopt, + (SVC_IN_ARG_TYPE) argp, (XDRPROC_T_TYPE) xdr_int, + (SVC_IN_ARG_TYPE) & res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + + +amq_mount_info_list * +amqproc_getmntfs_1(voidp argp, CLIENT *clnt) +{ + static amq_mount_info_list res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_GETMNTFS, (XDRPROC_T_TYPE) xdr_void, argp, + (XDRPROC_T_TYPE) xdr_amq_mount_info_list, + (SVC_IN_ARG_TYPE) & res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + + +int * +amqproc_mount_1(voidp argp, CLIENT *clnt) +{ + static int res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_MOUNT, (XDRPROC_T_TYPE) xdr_amq_string, argp, + (XDRPROC_T_TYPE) xdr_int, (SVC_IN_ARG_TYPE) & res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + + +amq_string * +amqproc_getvers_1(voidp argp, CLIENT *clnt) +{ + static amq_string res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_GETVERS, (XDRPROC_T_TYPE) xdr_void, argp, + (XDRPROC_T_TYPE) xdr_amq_string, (SVC_IN_ARG_TYPE) & res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + + +int * +amqproc_getpid_1(voidp argp, CLIENT *clnt) +{ + static int res; + + memset((char *) &res, 0, sizeof(res)); + if (clnt_call(clnt, AMQPROC_GETPID, (XDRPROC_T_TYPE) xdr_void, argp, + (XDRPROC_T_TYPE) xdr_int, (SVC_IN_ARG_TYPE) & res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} diff --git a/contrib/amd/amq/amq_xdr.c b/contrib/amd/amq/amq_xdr.c new file mode 100644 index 0000000..79a7294 --- /dev/null +++ b/contrib/amd/amq/amq_xdr.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amq_xdr.c,v 5.2.2.1 1992/02/09 15:09:23 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +bool_t +xdr_time_type(XDR *xdrs, time_type *objp) +{ + if (!xdr_long(xdrs, (long *) objp)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_tree(XDR *xdrs, amq_mount_tree *objp) +{ + + if (!xdr_amq_string(xdrs, &objp->mt_mountinfo)) { + return (FALSE); + } + + if (!xdr_amq_string(xdrs, &objp->mt_directory)) { + return (FALSE); + } + + if (!xdr_amq_string(xdrs, &objp->mt_mountpoint)) { + return (FALSE); + } + + if (!xdr_amq_string(xdrs, &objp->mt_type)) { + return (FALSE); + } + + if (!xdr_time_type(xdrs, &objp->mt_mounttime)) { + return (FALSE); + } + + if (!xdr_u_short(xdrs, &objp->mt_mountuid)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->mt_getattr)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->mt_lookup)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->mt_readdir)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->mt_readlink)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->mt_statfs)) { + return (FALSE); + } + + if (!xdr_pointer(xdrs, (char **) &objp->mt_next, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_tree)) { + return (FALSE); + } + + if (!xdr_pointer(xdrs, (char **) &objp->mt_child, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_tree)) { + return (FALSE); + } + + return (TRUE); +} + + +bool_t +xdr_amq_mount_tree_p(XDR *xdrs, amq_mount_tree_p *objp) +{ + if (!xdr_pointer(xdrs, (char **) objp, sizeof(amq_mount_tree), (XDRPROC_T_TYPE) xdr_amq_mount_tree)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_info(XDR *xdrs, amq_mount_info *objp) +{ + + if (!xdr_amq_string(xdrs, &objp->mi_type)) { + return (FALSE); + } + + if (!xdr_amq_string(xdrs, &objp->mi_mountpt)) { + return (FALSE); + } + + if (!xdr_amq_string(xdrs, &objp->mi_mountinfo)) { + return (FALSE); + } + + if (!xdr_amq_string(xdrs, &objp->mi_fserver)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->mi_error)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->mi_refc)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->mi_up)) { + return (FALSE); + } + + return (TRUE); +} + + +bool_t +xdr_amq_mount_info_list(XDR *xdrs, amq_mount_info_list *objp) +{ + if (!xdr_array(xdrs, + (char **) &objp->amq_mount_info_list_val, + (u_int *) &objp->amq_mount_info_list_len, + ~0, + sizeof(amq_mount_info), + (XDRPROC_T_TYPE) xdr_amq_mount_info)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_tree_list(XDR *xdrs, amq_mount_tree_list *objp) +{ + if (!xdr_array(xdrs, + (char **) &objp->amq_mount_tree_list_val, + (u_int *) &objp->amq_mount_tree_list_len, + ~0, + sizeof(amq_mount_tree_p), + (XDRPROC_T_TYPE) xdr_amq_mount_tree_p)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_mount_stats(XDR *xdrs, amq_mount_stats *objp) +{ + + if (!xdr_int(xdrs, &objp->as_drops)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->as_stale)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->as_mok)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->as_merr)) { + return (FALSE); + } + + if (!xdr_int(xdrs, &objp->as_uerr)) { + return (FALSE); + } + + return (TRUE); +} + + +bool_t +xdr_amq_opt(XDR *xdrs, amq_opt *objp) +{ + if (!xdr_enum(xdrs, (enum_t *) objp)) { + return (FALSE); + } + return (TRUE); +} + + +bool_t +xdr_amq_setopt(XDR *xdrs, amq_setopt *objp) +{ + + if (!xdr_amq_opt(xdrs, &objp->as_opt)) { + return (FALSE); + } + + if (!xdr_amq_string(xdrs, &objp->as_str)) { + return (FALSE); + } + + return (TRUE); +} + + +bool_t +xdr_pri_free(XDRPROC_T_TYPE xdr_args, caddr_t args_ptr) +{ + XDR xdr; + + xdr.x_op = XDR_FREE; + return ((*xdr_args) (&xdr, (caddr_t *) args_ptr)); +} diff --git a/contrib/amd/amq/pawd.1 b/contrib/amd/amq/pawd.1 new file mode 100644 index 0000000..d047372 --- /dev/null +++ b/contrib/amd/amq/pawd.1 @@ -0,0 +1,72 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1990 Jan-Simon Pendry +.\" Copyright (c) 1990 Imperial College of Science, Technology & Medicine +.\" Copyright (c) 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jan-Simon Pendry at Imperial College, London. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" %W% (Berkeley) %G% +.\" +.\" $Id: pawd.1,v 5.2.2.1 1992/02/09 15:11:15 jsp beta $ +.\" +.TH PAWD 1 "6 Jan 1998" +.SH NAME +pawd \- print automounter working directory +.SH SYNOPSIS +.B pawd +[ +.I path ... +] +.SH DESCRIPTION +.LP +.B pawd +is used to print the current working directory, adjusted to reflect proper +paths that can be reused to go through the automounter for the shortest +possible path. In particular, the path printed back does not include any +of +.BR Amd 's +local mount points. Using them is unsafe, because +.B Amd +may unmount managed file systems from the mount points, and thus including +them in paths may not always find the files within. +.P +Without any arguments, +.B pawd +will print the automounter adjusted current working directory. With any +number of arguments, it will print the adjusted path of each one of the +arguments. +.SH "SEE ALSO" +.BR amd (8), +.BR amq (8), +.BR pwd (1). diff --git a/contrib/amd/amq/pawd.c b/contrib/amd/amq/pawd.c new file mode 100644 index 0000000..86ed55f --- /dev/null +++ b/contrib/amd/amq/pawd.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: pawd.c,v 5.2.2.1 1992/02/09 15:09:16 jsp beta $ + * + */ + +/* + * pawd is similar to pwd, except that it returns more "natural" versions of + * pathnames for directories automounted with the amd automounter. If any + * arguments are given, the "more natural" form of the given pathnames are + * printed. + * + * Paul Anderson (paul@ed.lfcs) + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* dummy variables */ +char *progname; +char hostname[MAXHOSTNAMELEN]; +int orig_umask, foreground, debug_flags; +pid_t mypid; +serv_state amd_state; + +/* statics */ +static char *localhost="localhost"; +static char newdir[MAXPATHLEN]; +static char transform[MAXPATHLEN]; + +static int +find_mt(amq_mount_tree *mt, char *dir) +{ + while (mt) { + if (STREQ(mt->mt_type, "link") || STREQ(mt->mt_type, "nfs")) { + int len = strlen(mt->mt_mountpoint); + if (NSTREQ(mt->mt_mountpoint, dir, len) && + ((dir[len] == '\0') || (dir[len] == '/'))) { + char tmp_buf[MAXPATHLEN]; + strcpy(tmp_buf, mt->mt_directory); + strcat(tmp_buf, &dir[len]); + strcpy(newdir, tmp_buf); + return 1; + } + } + if (find_mt(mt->mt_next,dir)) + return 1; + mt = mt->mt_child; + } + return 0; +} + + +static int +find_mlp(amq_mount_tree_list *mlp, char *dir) +{ + int i; + + for (i = 0; i < mlp->amq_mount_tree_list_len; i++) { + if (find_mt(mlp->amq_mount_tree_list_val[i], dir)) + return 1; + } + return 0; +} + + +#ifdef HAVE_CNODEID +static char * +cluster_server(void) +{ +# ifdef HAVE_EXTERN_GETCCENT + struct cct_entry *cp; +# endif /* HAVE_EXTERN_GETCCENT */ + + if (cnodeid() == 0) + return localhost; + +# ifdef HAVE_EXTERN_GETCCENT + while ((cp = getccent())) + if (cp->cnode_type == 'r') + return cp->cnode_name; +# endif /* HAVE_EXTERN_GETCCENT */ + + return localhost; +} +#endif /* HAVE_CNODEID */ + + +/* DISK_HOME_HACK added by gdmr */ +#ifdef DISK_HOME_HACK +static char * +hack_name(char *dir) +{ + char partition[MAXPATHLEN]; + char username[MAXPATHLEN]; + char hesiod_lookup[MAXPATHLEN]; + char *to, *ch, *hes_name, *dot; + char **hes; + +#ifdef DEBUG + fprintf(stderr, "hack_name(%s)\n", dir); +#endif /* DEBUG */ + + if (dir[0] == '/' && dir[1] == 'a' && dir[2] == '/') { + /* Could be /a/server/disk/home/partition/user... */ + ch = dir + 3; + while (*ch && *ch != '/') ch++; /* Skip server */ + if (!NSTREQ(ch, "/disk/home/", 11)) + return NULL; /* Nope */ + /* Looking promising, next should be the partition name */ + ch += 11; + to = partition; + while (*ch && *ch != '/') *to++ = *ch++; + to = '\0'; + if (!(*ch)) + return NULL; /* Off the end */ + /* Now the username */ + ch++; + to = username; + while (*ch && *ch != '/') *to++ = *ch++; + to = '\0'; +#ifdef DEBUG + fprintf(stderr, "partition %s, username %s\n", partition, username); +#endif /* DEBUG */ + + sprintf(hesiod_lookup, "%s.homes-remote", username); + hes = hes_resolve(hesiod_lookup, "amd"); + if (!hes) + return NULL; +#ifdef DEBUG + fprintf(stderr, "hesiod -> <%s>\n", *hes); +#endif /* DEBUG */ + hes_name = strstr(*hes, "/homes/remote/"); + if (!hes_name) return NULL; + hes_name += 14; +#ifdef DEBUG + fprintf(stderr, "hesiod -> <%s>\n", hes_name); +#endif /* DEBUG */ + dot = hes_name; + while (*dot && *dot != '.') dot++; + *dot = '\0'; +#ifdef DEBUG + fprintf(stderr, "hesiod -> <%s>\n", hes_name); +#endif /* DEBUG */ + + if (strcmp(partition, hes_name)) return NULL; +#ifdef DEBUG + fprintf(stderr, "A match, munging....\n"); +#endif /* DEBUG */ + strcpy(transform, "/home/"); + strcat(transform, username); + if (*ch) strcat(transform, ch); +#ifdef DEBUG + fprintf(stderr, "Munged to <%s>\n", transform); +#endif /* DEBUG */ + return transform; + } + return NULL; +} +#endif /* DISK_HOME_HACK */ + + +/* + * The routine transform_dir(path) transforms pathnames of directories + * mounted with the amd automounter to produce a more "natural" version. + * The automount table is obtained from the local amd via the rpc interface + * and reverse lookups are repeatedly performed on the directory name + * substituting the name of the automount link for the value of the link + * whenever it occurs as a prefix of the directory name. + */ +static char * +transform_dir(char *dir) +{ +#ifdef DISK_HOME_HACK + char *ch; +#endif /* DISK_HOME_HACK */ + char *server; + struct sockaddr_in server_addr; + int s = RPC_ANYSOCK; + CLIENT *clnt; + struct hostent *hp; + amq_mount_tree_list *mlp; + struct timeval tmo = {10, 0}; + +#ifdef DISK_HOME_HACK + if (ch = hack_name(dir)) + return ch; +#endif /* DISK_HOME_HACK */ + +#ifdef HAVE_CNODEID + server = cluster_server(); +#else /* not HAVE_CNODEID */ + server = localhost; +#endif /* not HAVE_CNODEID */ + + if ((hp = gethostbyname(server)) == 0) + return dir; + memset(&server_addr, 0, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_addr = *(struct in_addr *) hp->h_addr; + + clnt = clntudp_create(&server_addr, AMQ_PROGRAM, AMQ_VERSION, tmo, &s); + if (clnt == 0) + return dir; + + strcpy(transform,dir); + while ( (mlp = amqproc_export_1((voidp)0, clnt)) && + find_mlp(mlp,transform) ) { + strcpy(transform,newdir); + } + return transform; +} + + +/* getawd() is a substitute for getwd() which transforms the path */ +static char * +getawd(char *path) +{ +#ifdef HAVE_GETCWD + char *wd = getcwd(path, MAXPATHLEN+1); +#else /* not HAVE_GETCWD */ + char *wd = getwd(path); +#endif /* not HAVE_GETCWD */ + + if (wd == NULL) { + return NULL; + } + strcpy(path, transform_dir(wd)); + return path; +} + + +int +main(int argc, char *argv[]) +{ + char tmp_buf[MAXPATHLEN], *wd; + + if (argc == 1) { + wd = getawd(tmp_buf); + if (wd == NULL) { + fprintf(stderr, "pawd: %s\n", tmp_buf); + exit(1); + } else { + fprintf(stdout, "%s\n", wd); + } + } else { + while (--argc) { + wd = transform_dir(*++argv); + fprintf(stdout, "%s\n", wd); + } + } + exit(0); +} + diff --git a/contrib/amd/conf/checkmount/checkmount_bsd44.c b/contrib/amd/conf/checkmount/checkmount_bsd44.c new file mode 100644 index 0000000..80276e6 --- /dev/null +++ b/contrib/amd/conf/checkmount/checkmount_bsd44.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: checkmount_bsd44.c,v 5.2.2.2 1992/05/31 16:35:45 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include + +extern int is_same_host(char *name1, char *name2, struct in_addr addr2); +int fixmount_check_mount(char *host, struct in_addr hostaddr, char *path); + +int +fixmount_check_mount(char *host, struct in_addr hostaddr, char *path) +{ + struct statfs *mntbufp, *mntp; + int nloc, i; + char *colon; + + /* read mount table from kernel */ + nloc = getmntinfo(&mntbufp, MNT_NOWAIT); + if (nloc <= 0) { + perror("getmntinfo"); + exit(1); + } + + mntp = mntbufp; + for (i=0; if_mntfromname, ':'))) { + *colon = '\0'; + if (STREQ(colon + 1, path) && + is_same_host(mntp->f_mntfromname, host, hostaddr)) + return 1; + } + } + + return 0; +} diff --git a/contrib/amd/conf/fh_dref/fh_dref_freebsd22.h b/contrib/amd/conf/fh_dref/fh_dref_freebsd22.h new file mode 100644 index 0000000..989561d --- /dev/null +++ b/contrib/amd/conf/fh_dref/fh_dref_freebsd22.h @@ -0,0 +1,2 @@ +/* $srcdir/conf/fh_dref/fh_dref_freebsd22.h */ +#define NFS_FH_DREF(dst, src) (dst) = (u_char *) (src) diff --git a/contrib/amd/conf/hn_dref/hn_dref_default.h b/contrib/amd/conf/hn_dref/hn_dref_default.h new file mode 100644 index 0000000..d495ea8 --- /dev/null +++ b/contrib/amd/conf/hn_dref/hn_dref_default.h @@ -0,0 +1,2 @@ +/* $srcdir/conf/hn_dref/hn_dref_default.h */ +#define NFS_HN_DREF(dst, src) (dst) = (src) diff --git a/contrib/amd/conf/mount/mount_freebsd3.c b/contrib/amd/conf/mount/mount_freebsd3.c new file mode 100644 index 0000000..5888ed9 --- /dev/null +++ b/contrib/amd/conf/mount/mount_freebsd3.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: mount_freebsd3.c,v 5.2.2.1 1992/02/09 15:10:08 jsp beta $ + * + */ + +/* + * FreeBSD 3.x (as of snapshot 3.0-980311-SNAP) Mount helper + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * Map from conventional mount arguments + * to FreeBSD 3.0 style arguments. + */ +int +mount_freebsd3(MTYPE_TYPE type, const char *dir, int flags, voidp data) +{ + char const *namelist[] = INITMOUNTNAMES; + + return mount(namelist[type], + dir, + flags, + data); +} diff --git a/contrib/amd/conf/mtab/mtab_bsd.c b/contrib/amd/conf/mtab/mtab_bsd.c new file mode 100644 index 0000000..100d7d5 --- /dev/null +++ b/contrib/amd/conf/mtab/mtab_bsd.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: mtab_bsd.c,v 5.2.2.2 1992/11/12 23:29:14 jsp Exp $ + * + */ + +/* + * BSD 4.4 systems don't write their mount tables on a file. Instead, they + * use a (better) system where the kernel keeps this state, and you access + * the mount tables via a known interface. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +static mntent_t * +mnt_dup(struct statfs *mp) +{ + mntent_t *new_mp = ALLOC(mntent_t); + char *ty; + + new_mp->mnt_fsname = strdup(mp->f_mntfromname); + new_mp->mnt_dir = strdup(mp->f_mntonname); + +#ifdef HAVE_FIELD_STRUCT_STATFS_F_FSTYPENAME + ty = mp->f_fstypename; +#else /* not HAVE_FIELD_STRUCT_STATFS_F_FSTYPENAME */ + switch (mp->f_type) { + +# if defined(MOUNT_UFS) && defined(MNTTAB_TYPE_UFS) + case MOUNT_UFS: + ty = MNTTAB_TYPE_UFS; + break; +# endif /* defined(MOUNT_UFS) && defined(MNTTAB_TYPE_UFS) */ + +# if defined(MOUNT_NFS) && defined(MNTTAB_TYPE_NFS) + case MOUNT_NFS: + ty = MNTTAB_TYPE_NFS; + break; +# endif /* defined(MOUNT_NFS) && defined(MNTTAB_TYPE_NFS) */ + +# if defined(MOUNT_MFS) && defined(MNTTAB_TYPE_MFS) + case MOUNT_MFS: + ty = MNTTAB_TYPE_MFS; + break; +# endif /* defined(MOUNT_MFS) && defined(MNTTAB_TYPE_MFS) */ + + default: + ty = "unknown"; + + break; + } +#endif /* not HAVE_FIELD_STRUCT_STATFS_F_FSTYPENAME */ + + new_mp->mnt_type = strdup(ty); + new_mp->mnt_opts = strdup("unset"); + new_mp->mnt_freq = 0; + new_mp->mnt_passno = 0; + + return new_mp; +} + + +/* + * Read a mount table into memory + */ +mntlist * +read_mtab(char *fs, const char *mnttabname) +{ + mntlist **mpp, *mhp; + struct statfs *mntbufp, *mntp; + + int nloc = getmntinfo(&mntbufp, MNT_NOWAIT); + + if (nloc == 0) { + plog(XLOG_ERROR, "Can't read mount table"); + return 0; + } + mpp = &mhp; + for (mntp = mntbufp; mntp < mntbufp + nloc; mntp++) { + /* + * Allocate a new slot + */ + *mpp = ALLOC(struct mntlist); + + /* + * Copy the data returned by getmntent + */ + (*mpp)->mnt = mnt_dup(mntp); + + /* + * Move to next pointer + */ + mpp = &(*mpp)->mnext; + } + + /* + * Terminate the list + */ + *mpp = 0; + + return mhp; +} diff --git a/contrib/amd/conf/nfs_prot/nfs_prot_freebsd2.h b/contrib/amd/conf/nfs_prot/nfs_prot_freebsd2.h new file mode 100644 index 0000000..e55e114 --- /dev/null +++ b/contrib/amd/conf/nfs_prot/nfs_prot_freebsd2.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_prot_freebsd2.h,v 1.1 1996/01/13 23:23:39 ezk Exp ezk $ + * + */ + +#ifndef _AMU_NFS_PROT_H +#define _AMU_NFS_PROT_H + +#ifdef HAVE_RPCSVC_NFS_PROT_H +# include +#endif /* HAVE_RPCSVC_NFS_PROT_H */ + +/* + * MACROS: + */ +#define dr_drok_u diropres +#define ca_where where +#define da_fhandle dir +#define da_name name +#define dl_entries entries +#define dl_eof eof +#define dr_status status +#define dr_u diropres_u +#define drok_attributes attributes +#define drok_fhandle file +#define fh_data data +#define la_fhandle from +#define la_to to +#define na_atime atime +#define na_ctime ctime +#define na_fileid fileid +#define na_fsid fsid +#define na_mode mode +#define na_mtime mtime +#define na_nlink nlink +#define na_size size +#define na_type type +#define ne_cookie cookie +#define ne_fileid fileid +#define ne_name name +#define ne_nextentry nextentry +#define ns_attr_u attributes +#define ns_status status +#define ns_u attrstat_u +#define nt_seconds seconds +#define nt_useconds useconds +#define rda_cookie cookie +#define rda_count count +#define rda_fhandle dir +#define rdr_reply_u reply +#define rdr_status status +#define rdr_u readdirres_u +#define rlr_data_u data +#define rlr_status status +#define rlr_u readlinkres_u +#define rna_from from +#define rna_to to +#define rr_status status +#define sag_fhandle file +#define sfr_reply_u reply +#define sfr_status status +#define sfr_u statfsres_u +#define sfrok_bavail bavail +#define sfrok_bfree bfree +#define sfrok_blocks blocks +#define sfrok_bsize bsize +#define sfrok_tsize tsize +#define sla_from from +#define wra_fhandle file + + +/* + * TYPEDEFS: + */ +typedef attrstat nfsattrstat; +typedef createargs nfscreateargs; +typedef dirlist nfsdirlist; +typedef diropargs nfsdiropargs; +typedef diropres nfsdiropres; +typedef entry nfsentry; +typedef fattr nfsfattr; +typedef ftype nfsftype; +typedef linkargs nfslinkargs; +typedef readargs nfsreadargs; +typedef readdirargs nfsreaddirargs; +typedef readdirres nfsreaddirres; +typedef readlinkres nfsreadlinkres; +typedef readres nfsreadres; +typedef renameargs nfsrenameargs; +typedef sattrargs nfssattrargs; +typedef statfsokres nfsstatfsokres; +typedef statfsres nfsstatfsres; +typedef symlinkargs nfssymlinkargs; +typedef writeargs nfswriteargs; + + +/* + * FreeBSD 2.2.x has NFS V3, but it does not define enough macros + * in the headers to automatically detect it. + * So fake it in the meant time. + */ +#if 0 +#define MOUNT_NFS3 MOUNT_NFS +#endif + + +#endif /* not _AMU_NFS_PROT_H */ diff --git a/contrib/amd/conf/nfs_prot/nfs_prot_freebsd3.h b/contrib/amd/conf/nfs_prot/nfs_prot_freebsd3.h new file mode 100644 index 0000000..915f014 --- /dev/null +++ b/contrib/amd/conf/nfs_prot/nfs_prot_freebsd3.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_prot_freebsd3.h,v 1.1 1996/01/13 23:23:39 ezk Exp ezk $ + * + */ + +#ifndef _AMU_NFS_PROT_H +#define _AMU_NFS_PROT_H + +#ifdef HAVE_RPCSVC_NFS_PROT_H +# include +#endif /* HAVE_RPCSVC_NFS_PROT_H */ +#ifdef HAVE_NFS_RPCV2_H +# include +#endif /* HAVE_NFS_RPCV2_H */ +#ifdef HAVE_NFS_NFS_H +# include +#endif /* HAVE_NFS_NFS_H */ + +/* + * MACROS: + */ +#define dr_drok_u diropres +#define ca_where where +#define da_fhandle dir +#define da_name name +#define dl_entries entries +#define dl_eof eof +#define dr_status status +#define dr_u diropres_u +#define drok_attributes attributes +#define drok_fhandle file +#define fh_data data +#define la_fhandle from +#define la_to to +#define na_atime atime +#define na_ctime ctime +#define na_fileid fileid +#define na_fsid fsid +#define na_mode mode +#define na_mtime mtime +#define na_nlink nlink +#define na_size size +#define na_type type +#define ne_cookie cookie +#define ne_fileid fileid +#define ne_name name +#define ne_nextentry nextentry +#define ns_attr_u attributes +#define ns_status status +#define ns_u attrstat_u +#define nt_seconds seconds +#define nt_useconds useconds +#define rda_cookie cookie +#define rda_count count +#define rda_fhandle dir +#define rdr_reply_u reply +#define rdr_status status +#define rdr_u readdirres_u +#define rlr_data_u data +#define rlr_status status +#define rlr_u readlinkres_u +#define rna_from from +#define rna_to to +#define rr_status status +#define sag_fhandle file +#define sfr_reply_u reply +#define sfr_status status +#define sfr_u statfsres_u +#define sfrok_bavail bavail +#define sfrok_bfree bfree +#define sfrok_blocks blocks +#define sfrok_bsize bsize +#define sfrok_tsize tsize +#define sla_from from +#define wra_fhandle file + + +/* + * TYPEDEFS: + */ +typedef attrstat nfsattrstat; +typedef createargs nfscreateargs; +typedef dirlist nfsdirlist; +typedef diropargs nfsdiropargs; +typedef diropres nfsdiropres; +typedef entry nfsentry; +typedef fattr nfsfattr; +typedef ftype nfsftype; +typedef linkargs nfslinkargs; +typedef readargs nfsreadargs; +typedef readdirargs nfsreaddirargs; +typedef readdirres nfsreaddirres; +typedef readlinkres nfsreadlinkres; +typedef readres nfsreadres; +typedef renameargs nfsrenameargs; +typedef sattrargs nfssattrargs; +typedef statfsokres nfsstatfsokres; +typedef statfsres nfsstatfsres; +typedef symlinkargs nfssymlinkargs; +typedef writeargs nfswriteargs; + + +/* + * + * FreeBSD 3.0 has NFS V3, but you need to regenrate the rpcsc header files + * as follows: + * cd /usr/local/rpcsvc + * rpcgen -DWANT_NFS3 mount.x + * rpcgen -DWANT_NFS3 nfs_prot.x + * But that's not expected of everyone, plus there are additional things + * needed so I define everything that's neede for NFS V3 here. + */ +#ifdef NFSMNT_NFSV3 + +# define MOUNT_NFS3 MOUNT_NFS +# define MNTOPT_NFS3 "nfs" + +#define FHSIZE3 64 /* size in bytes of a file handle (v3) */ +#define NFS3_FHSIZE 64 +#define MOUNTVERS3 ((unsigned long)(3)) +#define NFS_V3 ((unsigned long)(3)) + +typedef struct { + u_int fhandle3_len; + char *fhandle3_val; +} fhandle3; + +enum mountstat3 { + MNT3_OK = 0, + MNT3ERR_PERM = 1, + MNT3ERR_NOENT = 2, + MNT3ERR_IO = 5, + MNT3ERR_ACCES = 13, + MNT3ERR_NOTDIR = 20, + MNT3ERR_INVAL = 22, + MNT3ERR_NAMETOOLONG = 63, + MNT3ERR_NOTSUPP = 10004, + MNT3ERR_SERVERFAULT = 10006 +}; +typedef enum mountstat3 mountstat3; + +struct mountres3_ok { + fhandle3 fhandle; + struct { + u_int auth_flavors_len; + int *auth_flavors_val; + } auth_flavors; +}; +typedef struct mountres3_ok mountres3_ok; + +struct mountres3 { + mountstat3 fhs_status; + union { + mountres3_ok mountinfo; + } mountres3_u; +}; +typedef struct mountres3 mountres3; + +struct nfs_fh3 { + u_int fh3_length; + union nfs_fh3_u { + struct nfs_fh3_i { + fhandle_t fh3_i; + } nfs_fh3_i; + char data[NFS3_FHSIZE]; + } fh3_u; +}; +typedef struct nfs_fh3 nfs_fh3; + +#endif /* NFSMNT_NFSV3 */ + +#endif /* not _AMU_NFS_PROT_H */ diff --git a/contrib/amd/conf/sa_dref/sa_dref_bsd44.h b/contrib/amd/conf/sa_dref/sa_dref_bsd44.h new file mode 100644 index 0000000..e76c16b --- /dev/null +++ b/contrib/amd/conf/sa_dref/sa_dref_bsd44.h @@ -0,0 +1,5 @@ +/* $srcdir/conf/sa_dref/sa_dref_bsd44.h */ +#define NFS_SA_DREF(dst, src) { \ + (dst)->addr = (struct sockaddr *) (src); \ + (dst)->addrlen = sizeof(*src); \ + } diff --git a/contrib/amd/conf/transp/transp_sockets.c b/contrib/amd/conf/transp/transp_sockets.c new file mode 100644 index 0000000..45aa01e --- /dev/null +++ b/contrib/amd/conf/transp/transp_sockets.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: transp_sockets.c,v 5.2.2.2 1992/07/18 18:57:03 jsp Exp jsp $ + * + * Socket specific utilities. + * -Erez Zadok + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* + * find the IP address that can be used to connect to the local host + */ +void +amu_get_myaddress(struct in_addr *iap) +{ + struct sockaddr_in sin; + + memset((char *) &sin, 0, sizeof(sin)); + get_myaddress(&sin); + iap->s_addr = sin.sin_addr.s_addr; +} + + +/* + * How to bind to reserved ports. + */ +int +bind_resv_port(int so, u_short *pp) +{ + struct sockaddr_in sin; + int rc; + u_short port; + + memset((voidp) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + + port = IPPORT_RESERVED; + + do { + --port; + sin.sin_port = htons(port); + rc = bind(so, (struct sockaddr *) &sin, sizeof(sin)); + } while (rc < 0 && (int) port > IPPORT_RESERVED / 2); + + if (pp && rc == 0) + *pp = port; + + return rc; +} + + +/* + * close a descriptor, Sockets style + */ +int +amu_close(int fd) +{ + return close(fd); +} + + +/* + * Create an rpc client attached to the mount daemon. + */ +CLIENT * +get_mount_client(char *unused_host, struct sockaddr_in *sin, struct timeval *tv, int *sock, u_long mnt_version) +{ + CLIENT *client; + + /* + * First try a TCP socket + */ + if ((*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) > 0) { + /* + * Bind to a privileged port + */ + if (bind_resv_port(*sock, (u_short *) 0) < 0) + plog(XLOG_ERROR, "can't bind privileged port"); + + /* + * Find mountd port to connect to. + * Connect to mountd. + * Create a tcp client. + */ + if ((sin->sin_port = htons(pmap_getport(sin, MOUNTPROG, mnt_version, IPPROTO_TCP))) != 0) { + if (connect(*sock, (struct sockaddr *) sin, sizeof(*sin)) >= 0 + && ((client = clnttcp_create(sin, MOUNTPROG, mnt_version, sock, 0, 0)) != NULL)) + return client; + } + /* + * Failed so close socket + */ + (void) close(*sock); + } /* tcp socket opened */ + /* TCP failed so try UDP */ + if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + plog(XLOG_ERROR, "Can't create socket to connect to mountd: %m"); + *sock = RPC_ANYSOCK; + return NULL; + } + /* + * Bind to a privileged port + */ + if (bind_resv_port(*sock, (u_short *) 0) < 0) + plog(XLOG_ERROR, "can't bind privileged port"); + + /* + * Zero out the port - make sure we recompute + */ + sin->sin_port = 0; + + /* + * Make a UDP client + */ + if ((client = clntudp_create(sin, MOUNTPROG, mnt_version, *tv, sock)) == NULL) { + (void) close(*sock); + *sock = RPC_ANYSOCK; + return NULL; + } +#ifdef DEBUG + dlog("get_mount_client: Using udp, port %d", sin->sin_port); +#endif /* DEBUG */ + return client; +} + + +/* + * find the address of the caller of an RPC procedure. + */ +struct sockaddr_in * +amu_svc_getcaller(SVCXPRT *xprt) +{ + return svc_getcaller(xprt); +} + + +/* + * Bind NFS to a reserved port. + */ +static int +bindnfs_port(int so, u_short *nfs_portp) +{ + u_short port; + int error = bind_resv_port(so, &port); + + if (error == 0) + *nfs_portp = port; + return error; +} + + +/* + * Create the nfs service for amd + */ +int +create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp)) +{ + + *soNFSp = socket(AF_INET, SOCK_DGRAM, 0); + + if (*soNFSp < 0 || bindnfs_port(*soNFSp, nfs_portp) < 0) { + plog(XLOG_FATAL, "Can't create privileged nfs port"); + return 1; + } + + if ((*nfs_xprtp = svcudp_create(*soNFSp)) == NULL) { + plog(XLOG_FATAL, "cannot create rpc/udp service"); + return 2; + } + + if (!svc_register(*nfs_xprtp, NFS_PROGRAM, NFS_VERSION, dispatch_fxn, 0)) { + plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)"); + return 3; + } + + return 0; /* all is well */ +} + + +/* + * Create the amq service for amd (both TCP and UDP) + */ +int +create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPRT **tcp_amqpp) +{ + /* first create TCP service */ + if (tcp_soAMQp) { + *tcp_soAMQp = socket(AF_INET, SOCK_STREAM, 0); + if (*tcp_soAMQp < 0) { + plog(XLOG_FATAL, "cannot create tcp socket for amq service: %m"); + return 1; + } + + /* now create RPC service handle for amq */ + if (tcp_amqpp && + (*tcp_amqpp = svctcp_create(*tcp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) { + plog(XLOG_FATAL, "cannot create tcp service for amq: soAMQp=%d", *tcp_soAMQp); + return 2; + } + } + + /* next create UDP service */ + if (udp_soAMQp) { + *udp_soAMQp = socket(AF_INET, SOCK_DGRAM, 0); + if (*udp_soAMQp < 0) { + plog(XLOG_FATAL, "cannot create udp socket for amq service: %m"); + return 3; + } + + /* now create RPC service handle for amq */ + if (udp_amqpp && + (*udp_amqpp = svcudp_bufcreate(*udp_soAMQp, AMQ_SIZE, AMQ_SIZE)) == NULL) { + plog(XLOG_FATAL, "cannot create udp service for amq: soAMQp=%d", *udp_soAMQp); + return 4; + } + } + + return 0; /* all is well */ +} + + +/* + * Ping the portmapper on a remote system by calling the nullproc + */ +enum clnt_stat +pmap_ping(struct sockaddr_in *address) +{ + CLIENT *client; + enum clnt_stat clnt_stat = RPC_TIMEDOUT; /* assume failure */ + int socket = RPC_ANYSOCK; + struct timeval timeout; + + timeout.tv_sec = 3; + timeout.tv_usec = 0; + address->sin_port = htons(PMAPPORT); + client = clntudp_create(address, PMAPPROG, PMAPVERS, timeout, &socket); + if (client != (CLIENT *) NULL) { + clnt_stat = clnt_call(client, + PMAPPROC_NULL, + (XDRPROC_T_TYPE) xdr_void, + NULL, + (XDRPROC_T_TYPE) xdr_void, + NULL, + timeout); + clnt_destroy(client); + } + close(socket); + address->sin_port = 0; + + return clnt_stat; +} + + +/* + * Find the best NFS version for a host and protocol. + */ +u_long +get_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const char *proto) +{ + CLIENT *clnt; + int again = 0; + enum clnt_stat clnt_stat; + struct timeval tv; + int sock; + + /* + * If not set or set wrong, then try from NFS_VERS_MAX on down. If + * set, then try from nfs_version on down. + */ + if (nfs_version <= 0 || nfs_version > NFS_VERS_MAX) { + nfs_version = NFS_VERS_MAX; + again = 1; + } + tv.tv_sec = 3; /* retry every 3 seconds, but also timeout */ + tv.tv_usec = 0; + + /* + * First check if remote portmapper is up (verify if remote host is up). + */ + clnt_stat = pmap_ping(sin); + if (clnt_stat == RPC_TIMEDOUT) { + plog(XLOG_ERROR, "get_nfs_version: failed to contact portmapper on host \"%s\": %s", host, clnt_sperrno(clnt_stat)); + return 0; + } + +#ifdef HAVE_FS_NFS3 +try_again: +#endif /* HAVE_FS_NFS3 */ + + sock = RPC_ANYSOCK; + if (STREQ(proto, "tcp")) + clnt = clnttcp_create(sin, NFS_PROGRAM, nfs_version, &sock, 0, 0); + else if (STREQ(proto, "udp")) + clnt = clntudp_create(sin, NFS_PROGRAM, nfs_version, tv, &sock); + else + clnt = NULL; + + if (clnt == NULL) { +#ifdef HAVE_CLNT_SPCREATEERROR + plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s :%s", + nfs_version, proto, host, clnt_spcreateerror("")); +#else /* not HAVE_CLNT_SPCREATEERROR */ + plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s", + nfs_version, proto, host); +#endif /* not HAVE_CLNT_SPCREATEERROR */ + return 0; + } + + /* Try a couple times to verify the CLIENT handle. */ + tv.tv_sec = 6; + clnt_stat = clnt_call(clnt, + NFSPROC_NULL, + (XDRPROC_T_TYPE) xdr_void, + 0, + (XDRPROC_T_TYPE) xdr_void, + 0, + tv); + close(sock); + clnt_destroy(clnt); + if (clnt_stat != RPC_SUCCESS) { + if (again) { +#ifdef HAVE_FS_NFS3 + if (nfs_version == NFS_VERSION3) { + plog(XLOG_INFO, "get_nfs_version trying a lower version"); + nfs_version = NFS_VERSION; + again = 0; + } + goto try_again; +#endif /* HAVE_FS_NFS3 */ + } + plog(XLOG_INFO, "get_nfs_version NFS(%d,%s) failed for %s", + nfs_version, proto, host); + return 0; + } + + plog(XLOG_INFO, "get_nfs_version: returning (%d,%s) on host %s", + nfs_version, proto, host); + return nfs_version; +} + + +/* + * AUTOFS FUNCTIONS FOR SOCKETS: + */ +#ifdef HAVE_FS_AUTOFS +/* + * Create the nfs service for amd + */ +int +create_autofs_service(int *soAUTOFSp, u_short *autofs_portp, SVCXPRT **autofs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp)) +{ + /* NOT IMPLEMENTED! */ + return -1; +} +#endif /* HAVE_FS_AUTOFS */ diff --git a/contrib/amd/conf/trap/trap_default.h b/contrib/amd/conf/trap/trap_default.h new file mode 100644 index 0000000..a132b0e --- /dev/null +++ b/contrib/amd/conf/trap/trap_default.h @@ -0,0 +1,2 @@ +/* $srcdir/conf/trap/trap_default.h */ +#define MOUNT_TRAP(type, mnt, flags, mnt_data) mount(type, mnt->mnt_dir, flags, mnt_data) diff --git a/contrib/amd/conf/trap/trap_freebsd3.h b/contrib/amd/conf/trap/trap_freebsd3.h new file mode 100644 index 0000000..95c6642 --- /dev/null +++ b/contrib/amd/conf/trap/trap_freebsd3.h @@ -0,0 +1,3 @@ +/* $srcdir/conf/trap/trap_freebsd3.h */ +extern int mount_freebsd3(MTYPE_TYPE type, const char *dir, int flags, voidp data); +#define MOUNT_TRAP(type, mnt, flags, mnt_data) mount_freebsd3(type, mnt->mnt_dir, flags, mnt_data) diff --git a/contrib/amd/conf/umount/umount_bsd44.c b/contrib/amd/conf/umount/umount_bsd44.c new file mode 100644 index 0000000..4e241b3 --- /dev/null +++ b/contrib/amd/conf/umount/umount_bsd44.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: umount_bsd44.c,v 5.2.2.2 1993/01/27 07:32:45 jsp Exp $ + * + */ + +/* + * Unmounting filesystems under BSD 4.4. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +int +umount_fs(char *fs_name, const char *mnttabname) +{ + int error; + +eintr: + error = unmount(fs_name, 0); + if (error < 0) + error = errno; + + switch (error) { + case EINVAL: + case ENOTBLK: + case ENOENT: + plog(XLOG_WARNING, "unmount: %s is not mounted", fs_name); + error = 0; /* Not really an error */ + break; + + case EINTR: +#ifdef DEBUG + /* not sure why this happens, but it does. ask kirk one day... */ + dlog("%s: unmount: %m", fs_name); +#endif /* DEBUG */ + goto eintr; + +#ifdef DEBUG + default: + dlog("%s: unmount: %m", fs_name); + break; +#endif /* DEBUG */ + } + + return error; +} diff --git a/contrib/amd/doc/am-utils.texi b/contrib/amd/doc/am-utils.texi new file mode 100644 index 0000000..ca54503 --- /dev/null +++ b/contrib/amd/doc/am-utils.texi @@ -0,0 +1,7816 @@ +\input texinfo @c -*-texinfo-*- +@c +@c Copyright (c) 1997-1998 Erez Zadok +@c Copyright (c) 1989 Jan-Simon Pendry +@c Copyright (c) 1989 Imperial College of Science, Technology & Medicine +@c Copyright (c) 1989 The Regents of the University of California. +@c All rights reserved. +@c +@c This code is derived from software contributed to Berkeley by +@c Jan-Simon Pendry at Imperial College, London. +@c +@c Redistribution and use in source and binary forms, with or without +@c modification, are permitted provided that the following conditions +@c are met: +@c 1. Redistributions of source code must retain the above copyright +@c notice, this list of conditions and the following disclaimer. +@c 2. Redistributions in binary form must reproduce the above copyright +@c notice, this list of conditions and the following disclaimer in the +@c documentation and/or other materials provided with the distribution. +@c 3. All advertising materials mentioning features or use of this software +@c must display the following acknowledgment: +@c This product includes software developed by the University of +@c California, Berkeley and its contributors. +@c 4. Neither the name of the University nor the names of its contributors +@c may be used to endorse or promote products derived from this software +@c without specific prior written permission. +@c +@c THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +@c ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +@c IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +@c ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +@c FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +@c DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +@c OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +@c HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +@c LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +@c OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +@c +@c %W% (Berkeley) %G% +@c +@c $Id: am-utils.texi,v 6.0 1997/02/09 15:11:50 ezk beta $ +@c +@setfilename am-utils.info + +@include version.texi + +@c info directory entry +@direntry +* Am-utils: (am-utils). The Amd automounter suite of utilities +@end direntry + +@titlepage +@title Am-utils (4.4BSD Automounter Utilities) +@subtitle For version @value{VERSION}, @value{UPDATED} + +@author Erez Zadok +(Originally by Jan-Simon Pendry and Nick Williams) + +@page +Copyright @copyright{} 1997-1998 Erez Zadok +@* +Copyright @copyright{} 1989 Jan-Simon Pendry +@* +Copyright @copyright{} 1989 Imperial College of Science, Technology & Medicine +@* +Copyright @copyright{} 1989 The Regents of the University of California. +@sp +All Rights Reserved. +@vskip 1ex +Permission to copy this document, or any portion of it, as +necessary for use of this software is granted provided this +copyright notice and statement of permission are included. +@end titlepage +@page + +@c Define a new index for options. +@syncodeindex pg cp +@syncodeindex vr cp + +@ifinfo + +@c ################################################################ +@node Top, License, , (DIR) +Am-utils - The 4.4BSD Automounter Tool Suite +********************************************* + +Am-utils is the 4.4BSD Automounter Tool Suite, which includes the Amd +automounter, the Amq query and control program, the Hlfsd daemon, and +other tools. This Info file describes how to use and understand the +tools within Am-utils. +@end ifinfo + +@menu +* License:: Explains the terms and conditions for using + and distributing Am-utils. +* Distrib:: How to get the latest Am-utils distribution. +* Intro:: An introduction to Automounting concepts. +* History:: History of am-utils' development. +* Overview:: An overview of Amd. +* Supported Platforms:: Machines and Systems supported by Amd. +* Mount Maps:: Details of mount maps +* Amd Command Line Options:: All the Amd command line options explained. +* Filesystem Types:: The different mount types supported by Amd. +* Amd Configuration File:: The amd.conf file syntax and meaning. +* Run-time Administration:: How to start, stop and control Amd. +* FSinfo:: The FSinfo filesystem management tool. +* Hlfsd:: The Home-Link Filesystem server. +* Assorted Tools:: Other tools which come with am-utils. +* Examples:: Some examples showing how Amd might be used. +* Internals:: Implementation details. +* Acknowledgments & Trademarks:: Legal Notes + +Indexes +* Index:: An item for each concept. +@end menu + +@iftex +@unnumbered Preface + +This manual documents the use of the 4.4BSD automounter tool suite, +which includes @i{Amd}, @i{Amq}, @i{Hlfsd}, and other programs. This is +primarily a reference manual. While no tutorial exists, there are +examples available. @xref{Examples}. + +This manual comes in two forms: the published form and the Info form. +The Info form is for on-line perusal with the INFO program which is +distributed along with GNU texinfo package (a version of which is +available for GNU Emacs).@footnote{GNU packages can be found in +@url{ftp://ftp.gnu.org/pub/gnu/}.} Both forms contain substantially +the same text and are generated from a common source file, which is +distributed with the @i{Am-utils} source. +@end iftex + +@c ################################################################ +@node License, Distrib, Top, Top +@unnumbered License +@cindex License Information + +@i{Am-utils} is not in the public domain; it is copyrighted and there are +restrictions on its distribution. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +@enumerate + +@item +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +@item +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +@item +All advertising materials mentioning features or use of this software +must display the following acknowledgment: + +@cartouche +``This product includes software developed by the University of +California, Berkeley and its contributors, as well as the Trustees of +Columbia University.'' +@end cartouche + +@item +Neither the name of the University nor the names of its contributors may +be used to endorse or promote products derived from this software +without specific prior written permission. + +@end enumerate + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + +@c ################################################################ +@node Distrib, Intro, License, Top +@unnumbered Source Distribution +@cindex Source code distribution +@cindex Obtaining the source code + +The @i{Am-utils} home page is located in +@example +@url{http://www.cs.columbia.edu/~ezk/am-utils/} +@end example + +You can get the latest distribution version of @i{Am-utils} from +@example +@url{ftp://shekel.mcl.cs.columbia.edu/pub/am-utils/am-utils.tar.gz} +@end example + +Alpha and beta distributions are available in +@example +@url{ftp://shekel.mcl.cs.columbia.edu/pub/am-utils/}. +@end example + +Revision 5.2 was part of the 4.3BSD Reno distribution. + +Revision 5.3bsdnet, a late alpha version of 5.3, was part +of the BSD network version 2 distribution + +Revision 6.0 was made independently by @email{ezk@@cs.columbia.edu,Erez +Zadok} at the @uref{http://www.cs.columbia.edu/,Computer Science +Department} of @uref{http://www.columbia.edu/,Columbia University}, as +part of his @uref{http://www.cs.columbia.edu/~ezk/research/tp/thesis_proposal.html,PhD thesis work}. @xref{History} for more details. + +@unnumberedsec Bug Reports +@cindex Bug reports + +Before reporting a bug, see if it is a known one in the +@uref{http://www.cs.columbia.edu/~ezk/am-utils/BUGS.txt,bugs} file. +Send all bug reports to @email{amd-dev@@majordomo.cs.columbia.edu} +quoting the details of the release and your configuration. These can be +obtained by running the command @samp{amd -v}. It would greatly help if +you could provide a reproducible procedure for detecting the bug you are +reporting. + +Providing working patches is highly encouraged. Every patch +incorporated, however small, will get its author an honorable mention in +the @uref{http://www.cs.columbia.edu/~ezk/am-utils/AUTHORS.txt,authors +file}. + +@unnumberedsec Mailing List +@cindex Mailing list + +There are two mailing lists for people interested in keeping up-to-date +with developments. + +@c ############### + +@enumerate + +@item +The older list, @samp{amd-workers} is for general "how to" questions and +announcements. To subscribe, send a note to +@email{amd-workers-request@@majordomo.glue.umd.edu}.@footnote{Note that +the older address, @email{amd-workers-request@@acl.lanl.gov}, is +defunct.} To post a message to this list, send mail to +@email{amd-workers@@majordomo.glue.umd.edu}. + +@item +The developers only list, @samp{amd-dev} is for + +@itemize @minus +@item +announcements of alpha and beta releases of am-utils +@item +reporting of bugs and patches +@item +discussions of new features for am-utils +@item +implementation and porting issues +@end itemize + +To subscribe, send a note to @email{majordomo@@majordomo.cs.columbia.edu} +with the single body text line @samp{subscribe amd-dev}. To post a +message to this list, send mail to +@email{amd-dev@@majordomo.cs.columbia.edu}. To avoid as much spam as +possible, only subscribers to this list may post to it. + +Subscribers of @samp{amd-dev} are most suitable if they have the time +and resources to test new and buggy versions of amd, on as many +different platforms as possible. They should also be prepared to learn +and use the GNU Autoconf, Automake, and Libtool packages, and of course, +be very familiar with the complex code in the am-utils package. In +other words, subscribers on this list should be able to contribute +meaningfully to the development of amd. + +@end enumerate + +@c ################################################################ +@node Intro, History, Distrib, Top +@unnumbered Introduction +@cindex Introduction + +An @dfn{automounter} maintains a cache of mounted filesystems. +Filesystems are mounted on demand when they are first referenced, +and unmounted after a period of inactivity. + +@i{Amd} may be used as a replacement for Sun's automounter. The choice +of which filesystem to mount can be controlled dynamically with +@dfn{selectors}. Selectors allow decisions of the form ``hostname is +@var{this},'' or ``architecture is not @var{that}.'' Selectors may be +combined arbitrarily. @i{Amd} also supports a variety of filesystem +types, including NFS, UFS and the novel @dfn{program} filesystem. The +combination of selectors and multiple filesystem types allows identical +configuration files to be used on all machines thus reducing the +administrative overhead. + +@i{Amd} ensures that it will not hang if a remote server goes down. +Moreover, @i{Amd} can determine when a remote server has become +inaccessible and then mount replacement filesystems as and when they +become available. + +@i{Amd} contains no proprietary source code and has been ported to +numerous flavors of Unix. + +@c ################################################################ +@node History, Overview, Intro, Top +@unnumbered History +@cindex History + +The @i{Amd} package has been without an official maintainer since 1992. +Several people have stepped in to maintain it unofficially. Most +notable were the `upl' (Unofficial Patch Level) releases of @i{Amd}, +created by me (@email{ezk@@cs.columbia.edu,Erez Zadok}), and available from +@url{ftp://ftp.cs.columbia.edu/pub/amd/}. The last such unofficial +release was `upl102'. + +Through the process of patching and aging, it was becoming more and more +apparent that @i{Amd} was in much need of revitalizing. Maintaining +@i{Amd} had become a difficult task. I took it upon myself to cleanup +the code, so that it would be easier to port to new platforms, add new +features, keep up with the many new feature requests, and deal with the +never ending stream of bug reports. + +I have been working on such a release of @i{Amd} on and off since +January of 1996. The new suite of tools is currently named "am-utils" +(AutoMounter Utilities), in line with GNU naming conventions, befitting +the contents of the package. In October of 1996 I had received enough +offers to help me with this task that I decided to make a mailing list +for this group of people. Around the same time, @i{Amd} had become a +necessary part of my PhD thesis work, resulting in more work performed +on am-utils. + +Am-utils version 6.0 was numbered with a major new release number to +distinguish it from the last official release of @i{Amd} (5.x). Many +new features have been added such as a GNU @code{configure} system, NFS +Version 3, Autofs support, a run-time configuration file (`amd.conf'), +many new ports, more scripts and programs, as well as numerous bug +fixes. Another reason for the new major release number was to alert +users of am-utils that user-visible interfaces may have changed. In +order to make @i{Amd} work well for the next 10 years, and be easier to +maintain, it was necessary to remove old or unused features, change +various syntax files, etc. However, great care was taken to ensure the +maximum possible backwards compatibility. + +@c ################################################################ +@node Overview, Supported Platforms, History, Top +@chapter Overview + +@i{Amd} maintains a cache of mounted filesystems. Filesystems are +@dfn{demand-mounted} when they are first referenced, and unmounted after +a period of inactivity. @i{Amd} may be used as a replacement for Sun's +@b{automount}(8) program. It contains no proprietary source code and +has been ported to numerous flavors of Unix. @xref{Supported +Platforms}.@refill + +@i{Amd} was designed as the basis for experimenting with filesystem +layout and management. Although @i{Amd} has many direct applications it +is loaded with additional features which have little practical use. At +some point the infrequently used components may be removed to streamline +the production system. + +@c @i{Amd} supports the notion of @dfn{replicated} filesystems by evaluating +@c each member of a list of possible filesystem locations in parallel. +@c @i{Amd} checks that each cached mapping remains valid. Should a mapping be +@c lost -- such as happens when a fileserver goes down -- @i{Amd} automatically +@c selects a replacement should one be available. +@c +@menu +* Fundamentals:: +* Filesystems and Volumes:: +* Volume Naming:: +* Volume Binding:: +* Operational Principles:: +* Mounting a Volume:: +* Automatic Unmounting:: +* Keep-alives:: +* Non-blocking Operation:: +@end menu + +@node Fundamentals, Filesystems and Volumes, Overview, Overview +@comment node-name, next, previous, up +@section Fundamentals +@cindex Automounter fundamentals + +The fundamental concept behind @i{Amd} is the ability to separate the +name used to refer to a file from the name used to refer to its physical +storage location. This allows the same files to be accessed with the +same name regardless of where in the network the name is used. This is +very different from placing @file{/n/hostname} in front of the pathname +since that includes location dependent information which may change if +files are moved to another machine. + +By placing the required mappings in a centrally administered database, +filesystems can be re-organized without requiring changes to +configuration files, shell scripts and so on. + +@node Filesystems and Volumes, Volume Naming, Fundamentals, Overview +@comment node-name, next, previous, up +@section Filesystems and Volumes +@cindex Filesystem +@cindex Volume +@cindex Fileserver +@cindex sublink + +@i{Amd} views the world as a set of fileservers, each containing one or +more filesystems where each filesystem contains one or more +@dfn{volumes}. Here the term @dfn{volume} is used to refer to a +coherent set of files such as a user's home directory or a @TeX{} +distribution.@refill + +In order to access the contents of a volume, @i{Amd} must be told in +which filesystem the volume resides and which host owns the filesystem. +By default the host is assumed to be local and the volume is assumed to +be the entire filesystem. If a filesystem contains more than one +volume, then a @dfn{sublink} is used to refer to the sub-directory +within the filesystem where the volume can be found. + +@node Volume Naming, Volume Binding, Filesystems and Volumes, Overview +@comment node-name, next, previous, up +@section Volume Naming +@cindex Volume names +@cindex Network-wide naming +@cindex Replicated volumes +@cindex Duplicated volumes +@cindex Replacement volumes + +Volume names are defined to be unique across the entire network. A +volume name is the pathname to the volume's root as known by the users +of that volume. Since this name uniquely identifies the volume +contents, all volumes can be named and accessed from each host, subject +to administrative controls. + +Volumes may be replicated or duplicated. Replicated volumes contain +identical copies of the same data and reside at two or more locations in +the network. Each of the replicated volumes can be used +interchangeably. Duplicated volumes each have the same name but contain +different, though functionally identical, data. For example, +@samp{/vol/tex} might be the name of a @TeX{} distribution which varied +for each machine architecture.@refill + +@i{Amd} provides facilities to take advantage of both replicated and +duplicated volumes. Configuration options allow a single set of +configuration data to be shared across an entire network by taking +advantage of replicated and duplicated volumes. + +@i{Amd} can take advantage of replacement volumes by mounting them as +required should an active fileserver become unavailable. + +@node Volume Binding, Operational Principles, Volume Naming, Overview +@comment node-name, next, previous, up +@section Volume Binding +@cindex Volume binding +@cindex Unix namespace +@cindex Namespace +@cindex Binding names to filesystems + +Unix implements a namespace of hierarchically mounted filesystems. Two +forms of binding between names and files are provided. A @dfn{hard +link} completes the binding when the name is added to the filesystem. A +@dfn{soft link} delays the binding until the name is accessed. An +@dfn{automounter} adds a further form in which the binding of name to +filesystem is delayed until the name is accessed.@refill + +The target volume, in its general form, is a tuple (host, filesystem, +sublink) which can be used to name the physical location of any volume +in the network. + +When a target is referenced, @i{Amd} ignores the sublink element and +determines whether the required filesystem is already mounted. This is +done by computing the local mount point for the filesystem and checking +for an existing filesystem mounted at the same place. If such a +filesystem already exists then it is assumed to be functionally +identical to the target filesystem. By default there is a one-to-one +mapping between the pair (host, filesystem) and the local mount point so +this assumption is valid. + +@node Operational Principles, Mounting a Volume, Volume Binding, Overview +@comment node-name, next, previous, up +@section Operational Principles +@cindex Operational principles + +@i{Amd} operates by introducing new mount points into the namespace. +These are called @dfn{automount} points. The kernel sees these +automount points as NFS filesystems being served by @i{Amd}. Having +attached itself to the namespace, @i{Amd} is now able to control the +view the rest of the system has of those mount points. RPC calls are +received from the kernel one at a time. + +When a @dfn{lookup} call is received @i{Amd} checks whether the name is +already known. If it is not, the required volume is mounted. A +symbolic link pointing to the volume root is then returned. Once the +symbolic link is returned, the kernel will send all other requests +direct to the mounted filesystem. + +If a volume is not yet mounted, @i{Amd} consults a configuration +@dfn{mount-map} corresponding to the automount point. @i{Amd} then +makes a runtime decision on what and where to mount a filesystem based +on the information obtained from the map. + +@i{Amd} does not implement all the NFS requests; only those relevant +to name binding such as @dfn{lookup}, @dfn{readlink} and @dfn{readdir}. +Some other calls are also implemented but most simply return an error +code; for example @dfn{mkdir} always returns ``read-only filesystem''. + +@node Mounting a Volume, Automatic Unmounting, Operational Principles, Overview +@comment node-name, next, previous, up +@section Mounting a Volume +@cindex Mounting a volume +@cindex Location lists +@cindex Alternate locations +@cindex Mount retries +@cindex Background mounts + +Each automount point has a corresponding mount map. The mount map +contains a list of key--value pairs. The key is the name of the volume +to be mounted. The value is a list of locations describing where the +filesystem is stored in the network. In the source for the map the +value would look like + +@display +location1 location2 @dots{} locationN +@end display + +@i{Amd} examines each location in turn. Each location may contain +@dfn{selectors} which control whether @i{Amd} can use that location. +For example, the location may be restricted to use by certain hosts. +Those locations which cannot be used are ignored. + +@i{Amd} attempts to mount the filesystem described by each remaining +location until a mount succeeds or @i{Amd} can no longer proceed. The +latter can occur in three ways: + +@itemize @bullet +@item +If none of the locations could be used, or if all of the locations +caused an error, then the last error is returned. + +@item +If a location could be used but was being mounted in the background then +@i{Amd} marks that mount as being ``in progress'' and continues with +the next request; no reply is sent to the kernel. + +@item +Lastly, one or more of the mounts may have been @dfn{deferred}. A mount +is deferred if extra information is required before the mount can +proceed. When the information becomes available the mount will take +place, but in the mean time no reply is sent to the kernel. If the +mount is deferred, @i{Amd} continues to try any remaining locations. +@end itemize + +Once a volume has been mounted, @i{Amd} establishes a @dfn{volume +mapping} which is used to satisfy subsequent requests.@refill + +@node Automatic Unmounting, Keep-alives, Mounting a Volume, Overview +@comment node-name, next, previous, up +@section Automatic Unmounting + +To avoid an ever increasing number of filesystem mounts, @i{Amd} removes +volume mappings which have not been used recently. A time-to-live +interval is associated with each mapping and when that expires the +mapping is removed. When the last reference to a filesystem is removed, +that filesystem is unmounted. If the unmount fails, for example the +filesystem is still busy, the mapping is re-instated and its +time-to-live interval is extended. The global default for this grace +period is controlled by the @code{-w} command-line option (@pxref{-w +Option, -w}) or the @i{amd.conf} parameter @samp{dismount_interval} +(@pxref{dismount_interval Parameter}). It is also possible to set this +value on a per-mount basis (@pxref{opts Option, opts, opts}). + +Filesystems can be forcefully timed out using the @i{Amq} command. +@xref{Run-time Administration}. + +@node Keep-alives, Non-blocking Operation, Automatic Unmounting, Overview +@comment node-name, next, previous, up +@section Keep-alives +@cindex Keep-alives +@cindex Server crashes +@cindex NFS ping + +Use of some filesystem types requires the presence of a server on +another machine. If a machine crashes then it is of no concern to +processes on that machine that the filesystem is unavailable. However, +to processes on a remote host using that machine as a fileserver this +event is important. This situation is most widely recognized when an +NFS server crashes and the behavior observed on client machines is that +more and more processes hang. In order to provide the possibility of +recovery, @i{Amd} implements a @dfn{keep-alive} interval timer for some +filesystem types. Currently only NFS makes use of this service. + +The basis of the NFS keep-alive implementation is the observation that +most sites maintain replicated copies of common system data such as +manual pages, most or all programs, system source code and so on. If +one of those servers goes down it would be reasonable to mount one of +the others as a replacement. + +The first part of the process is to keep track of which fileservers are +up and which are down. @i{Amd} does this by sending RPC requests to the +servers' NFS @code{NullProc} and checking whether a reply is returned. +While the server state is uncertain the requests are re-transmitted at +three second intervals and if no reply is received after four attempts +the server is marked down. If a reply is received the fileserver is +marked up and stays in that state for 30 seconds at which time another +NFS ping is sent. + +Once a fileserver is marked down, requests continue to be sent every 30 +seconds in order to determine when the fileserver comes back up. During +this time any reference through @i{Amd} to the filesystems on that +server fail with the error ``Operation would block''. If a replacement +volume is available then it will be mounted, otherwise the error is +returned to the user. + +@c @i{Amd} keeps track of which servers are up and which are down. +@c It does this by sending RPC requests to the servers' NFS {\sc NullProc} and +@c checking whether a reply is returned. If no replies are received after a +@c short period, @i{Amd} marks the fileserver @dfn{down}. +@c RPC requests continue to be sent so that it will notice when a fileserver +@c comes back up. +@c ICMP echo packets \cite{rfc:icmp} are not used because it is the availability +@c of the NFS service that is important, not the existence of a base kernel. +@c Whenever a reference to a fileserver which is down is made via @i{Amd}, an alternate +@c filesystem is mounted if one is available. +@c +Although this action does not protect user files, which are unique on +the network, or processes which do not access files via @i{Amd} or +already have open files on the hung filesystem, it can prevent most new +processes from hanging. + +By default, fileserver state is not maintained for NFS/TCP mounts. The +remote fileserver is always assumed to be up. +@c +@c With a suitable combination of filesystem management and mount-maps, +@c machines can be protected against most server downtime. This can be +@c enhanced by allocating boot-servers dynamically which allows a diskless +@c workstation to be quickly restarted if necessary. Once the root filesystem +@c is mounted, @i{Amd} can be started and allowed to mount the remainder of +@c the filesystem from whichever fileservers are available. + +@node Non-blocking Operation, , Keep-alives, Overview +@comment node-name, next, previous, up +@section Non-blocking Operation +@cindex Non-blocking operation +@cindex Multiple-threaded server +@cindex RPC retries + +Since there is only one instance of @i{Amd} for each automount point, +and usually only one instance on each machine, it is important that it +is always available to service kernel calls. @i{Amd} goes to great +lengths to ensure that it does not block in a system call. As a last +resort @i{Amd} will fork before it attempts a system call that may block +indefinitely, such as mounting an NFS filesystem. Other tasks such as +obtaining filehandle information for an NFS filesystem, are done using a +purpose built non-blocking RPC library which is integrated with +@i{Amd}'s task scheduler. This library is also used to implement NFS +keep-alives (@pxref{Keep-alives}). + +Whenever a mount is deferred or backgrounded, @i{Amd} must wait for it +to complete before replying to the kernel. However, this would cause +@i{Amd} to block waiting for a reply to be constructed. Rather than do +this, @i{Amd} simply @dfn{drops} the call under the assumption that the +kernel RPC mechanism will automatically retry the request. + +@c ################################################################ +@node Supported Platforms, Mount Maps, Overview, Top +@comment node-name, next, previous, up +@chapter Supported Platforms +@cindex Supported Platforms +@cindex shared libraries +@cindex NFS V.3 support + +@i{Am-utils} has been ported to a wide variety of machines and operating +systems. @i{Am-utils}'s code works for little-endian and big-endian +machines, as well as 32 bit and 64 bit architectures. Furthermore, when +@i{Am-utils} ports to an Operating System on one architecture, it is generally +readily portable to the same Operating System on all platforms on which +it is available. + +The table below lists those platforms supported by the latest release. +The listing is based on the standard output from GNU's +@code{config.guess} script. Since significant changes have been made to +am-utils, not all systems listed here have been verified working for all +features. + +@multitable {Auto-Configured System Name} {Config} {Compile} {Amd} {NFS3} {Shlib} {Hlfsd} + +@item @b{Auto-Configured System Name} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab @b{Config} @tab @b{Compile} @tab @b{Amd} @tab @b{NFS3} @tab @b{Shlib} @tab @b{Hlfsd} + +@item @b{alpha-dec-osf2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab @tab @tab + +@item @b{alpha-dec-osf4.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab @tab + +@item @b{alphaev5-unknown-linux-gnu} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{hppa1.0-hp-hpux11.00} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab no @tab @tab + +@item @b{hppa1.1-hp-hpux10.10} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab no @tab + +@item @b{hppa1.1-hp-hpux10.20} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab no @tab + +@item @b{hppa1.1-hp-hpux9.01} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{hppa1.1-hp-hpux9.05} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{hppa1.1-hp-hpux9.07} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-pc-bsdi2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-pc-bsdi3.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-pc-bsdi3.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-pc-solaris2.5.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab yes + +@item @b{i386-pc-solaris2.6} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab yes + +@item @b{i386-unknown-freebsd2.1.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-unknown-freebsd2.2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{i386-unknown-freebsd3.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i386-unknown-netbsd1.2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i386-unknown-netbsd1.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i386-unknown-netbsd1.3.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i386-unknown-openbsd2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i486-ncr-sysv4.3.03} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab @tab yes @tab @tab + +@item @b{i486-pc-linux-gnulibc1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{i586-pc-linux-gnulinc1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{i686-pc-linux-gnu} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{m68k-hp-hpux9.00} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{m68k-sun-sunos4.1.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{m68k-next-nextstep3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{mips-dec-ultrix4.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{mips-sgi-irix5.2} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab @tab @tab @tab @tab @tab + +@item @b{mips-sgi-irix5.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab @tab + +@item @b{mips-sgi-irix6.2} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab @tab + +@item @b{mips-sgi-irix6.4} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{powerpc-ibm-aix4.1.5.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{powerpc-ibm-aix4.2.1.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab @tab + +@item @b{rs6000-ibm-aix3.2} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{rs6000-ibm-aix3.2.5} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{rs6000-ibm-aix4.1.4.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{rs6000-ibm-aix4.1.5.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{sparc-sun-solaris2.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{sparc-sun-solaris2.4} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-solaris2.5} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{sparc-sun-solaris2.5.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab yes + +@item @b{sparc-sun-solaris2.6} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab yes + +@item @b{sparc-sun-sunos4.1.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-sunos4.1.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-sunos4.1.3C} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-sunos4.1.3_U1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-sunos4.1.4} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-unknown-linux-gnulibc1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-unknown-netbsd1.2E} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab @tab @tab + +@end multitable + +See the @file{INSTALL} in the distribution for more specific details on +building and/or configuring for some systems. + +@c ################################################################ +@node Mount Maps, Amd Command Line Options, Supported Platforms, Top +@comment node-name, next, previous, up +@chapter Mount Maps +@cindex Mount maps +@cindex Automounter configuration maps +@cindex Mount information + +@i{Amd} has no built-in knowledge of machines or filesystems. +External @dfn{mount-maps} are used to provide the required information. +Specifically, @i{Amd} needs to know when and under what conditions it +should mount filesystems. + +The map entry corresponding to the requested name contains a list of +possible locations from which to resolve the request. Each location +specifies filesystem type, information required by that filesystem (for +example the block special device in the case of UFS), and some +information describing where to mount the filesystem (@pxref{fs Option}). A +location may also contain @dfn{selectors} (@pxref{Selectors}).@refill + +@menu +* Map Types:: +* Key Lookup:: +* Location Format:: +@end menu + +@node Map Types, Key Lookup, Mount Maps, Mount Maps +@comment node-name, next, previous, up +@section Map Types +@cindex Mount map types +@cindex Map types +@cindex Configuration map types +@cindex Types of mount map +@cindex Types of configuration map +@cindex Determining the map type + +A mount-map provides the run-time configuration information to @i{Amd}. +Maps can be implemented in many ways. Some of the forms supported by +@i{Amd} are regular files, ndbm databases, NIS maps, the @dfn{Hesiod} +name server, and even the password file. + +A mount-map @dfn{name} is a sequence of characters. When an automount +point is created a handle on the mount-map is obtained. For each map +type configured, @i{Amd} attempts to reference the map of the +appropriate type. If a map is found, @i{Amd} notes the type for future +use and deletes the reference, for example closing any open file +descriptors. The available maps are configured when @i{Amd} is built +and can be displayed by running the command @samp{amd -v}. + +When using an @i{Amd} configuration file (@pxref{Amd Configuration File}) +and the keyword @samp{map_type} (@pxref{map_type Parameter}), you may +force the map used to any type. + +By default, @i{Amd} caches data in a mode dependent on the type of map. +This is the same as specifying @samp{cache:=mapdefault} and selects a +suitable default cache mode depending on the map type. The individual +defaults are described below. The @var{cache} option can be specified +on automount points to alter the caching behavior (@pxref{Automount +Filesystem}).@refill + +The following map types have been implemented, though some are not +available on all machines. Run the command @samp{amd -v} to obtain a +list of map types configured on your machine. + +@menu +* File maps:: +* ndbm maps:: +* NIS maps:: +* NIS+ maps:: +* Hesiod maps:: +* Password maps:: +* Union maps:: +* LDAP maps:: +@end menu + +@node File maps, ndbm maps, Map Types, Map Types +@comment node-name, next, previous, up +@subsection File maps +@cindex File maps +@cindex Flat file maps +@cindex File map syntactic conventions + +When @i{Amd} searches a file for a map entry it does a simple scan of +the file and supports both comments and continuation lines. + +Continuation lines are indicated by a backslash character (@samp{\}) as +the last character of a line in the file. The backslash, newline character +@emph{and any leading white space on the following line} are discarded. A maximum +line length of 2047 characters is enforced after continuation lines are read +but before comments are stripped. Each line must end with +a newline character; that is newlines are terminators, not separators. +The following examples illustrate this: + +@example +key valA valB; \ + valC +@end example + +specifies @emph{three} locations, and is identical to + +@example +key valA valB; valC +@end example + +However, + +@example +key valA valB;\ + valC +@end example + +specifies only @emph{two} locations, and is identical to + +@example +key valA valB;valC +@end example + +After a complete line has been read from the file, including +continuations, @i{Amd} determines whether there is a comment on the +line. A comment begins with a hash (``@samp{#}'') character and +continues to the end of the line. There is no way to escape or change +the comment lead-in character. + +Note that continuation lines and comment support @dfn{only} apply to +file maps, or ndbm maps built with the @code{mk-amd-map} program. + +When caching is enabled, file maps have a default cache mode of +@code{all} (@pxref{Automount Filesystem}). + +@node ndbm maps, NIS maps, File maps, Map Types +@comment node-name, next, previous, up +@subsection ndbm maps +@cindex ndbm maps + +An ndbm map may be used as a fast access form of a file map. The program, +@code{mk-amd-map}, converts a normal map file into an ndbm database. +This program supports the same continuation and comment conventions that +are provided for file maps. Note that ndbm format files may @emph{not} +be sharable across machine architectures. The notion of speed generally +only applies to large maps; a small map, less than a single disk block, +is almost certainly better implemented as a file map. + +ndbm maps have a default cache mode of @samp{all} (@pxref{Automount Filesystem}). + +@node NIS maps, NIS+ maps, ndbm maps, Map Types +@comment node-name, next, previous, up +@subsection NIS maps +@cindex NIS (YP) maps + +When using NIS (formerly YP), an @i{Amd} map is implemented directly +by the underlying NIS map. Comments and continuation lines are +@emph{not} supported in the automounter and must be stripped when +constructing the NIS server's database. + +NIS maps have a default cache mode of @code{all} (@pxref{Automount +Filesystem}). + +The following rule illustrates what could be added to your NIS @file{Makefile}, +in this case causing the @file{amd.home} map to be rebuilt: +@example +$(YPTSDIR)/amd.home.time: $(ETCDIR)/amd.home + -@@sed -e "s/#.*$$//" -e "/^$$/d" $(ETCDIR)/amd.home | \ + awk '@{ \ + for (i = 1; i <= NF; i++) \ + if (i == NF) @{ \ + if (substr($$i, length($$i), 1) == "\\") \ + printf("%s", substr($$i, 1, length($$i) - 1)); \ + else \ + printf("%s\n", $$i); \ + @} \ + else \ + printf("%s ", $$i); \ + @}' | \ + $(MAKEDBM) - $(YPDBDIR)/amd.home; \ + touch $(YPTSDIR)/amd.home.time; \ + echo "updated amd.home"; \ + if [ ! $(NOPUSH) ]; then \ + $(YPPUSH) amd.home; \ + echo "pushed amd.home"; \ + else \ + : ; \ + fi +@end example + +Here @code{$(YPTSDIR)} contains the time stamp files, and @code{$(YPDBDIR)} contains +the dbm format NIS files. + +@node NIS+ maps, Hesiod maps, NIS maps, Map Types +@comment node-name, next, previous, up +@subsection NIS+ maps +@cindex NIS+ maps + +NIS+ maps do not support cache mode @samp{all} and, when caching is +enabled, have a default cache mode of @samp{inc}. + +XXX: FILL IN WITH AN EXAMPLE. + +@node Hesiod maps, Password maps, NIS+ maps, Map Types +@comment node-name, next, previous, up +@subsection Hesiod maps +@cindex Hesiod maps + +When the map name begins with the string @samp{hesiod.} lookups are made +using the @dfn{Hesiod} name server. The string following the dot is +used as a name qualifier and is prepended with the key being located. +The entire string is then resolved in the @code{automount} context, or +the @i{amd.conf} parameter @samp{hesiod_base} (@pxref{hesiod_base +Parameter}). For example, if the the key is @samp{jsp} and map name is +@samp{hesiod.homes} then @dfn{Hesiod} is asked to resolve +@samp{jsp.homes.automount}. + +Hesiod maps do not support cache mode @samp{all} and, when caching is +enabled, have a default cache mode of @samp{inc} (@pxref{Automount +Filesystem}). + +The following is an example of a @dfn{Hesiod} map entry: + +@example +jsp.homes.automount HS TXT "rfs:=/home/charm;rhost:=charm;sublink:=jsp" +njw.homes.automount HS TXT "rfs:=/home/dylan/dk2;rhost:=dylan;sublink:=njw" +@end example + +@node Password maps, Union maps, Hesiod maps, Map Types +@comment node-name, next, previous, up +@subsection Password maps +@cindex Password file maps +@cindex /etc/passwd maps +@cindex User maps, automatic generation +@cindex Automatic generation of user maps +@cindex Using the password file as a map + +The password map support is unlike the four previous map types. When +the map name is the string @file{/etc/passwd} @i{Amd} can lookup a user +name in the password file and re-arrange the home directory field to +produce a usable map entry. + +@i{Amd} assumes the home directory has the format +`@t{/}@i{anydir}@t{/}@i{dom1}@t{/../}@i{domN}@t{/}@i{login}'. +@c @footnote{This interpretation is not necessarily exactly what you want.} +It breaks this string into a map entry where @code{$@{rfs@}} has the +value `@t{/}@i{anydir}@t{/}@i{domN}', @code{$@{rhost@}} has the value +`@i{domN}@t{.}@i{...}@t{.}@i{dom1}', and @code{$@{sublink@}} has the +value @i{login}.@refill + +Thus if the password file entry was + +@example +/home/achilles/jsp +@end example + +the map entry used by @i{Amd} would be + +@example +rfs:=/home/achilles;rhost:=achilles;sublink:=jsp +@end example + +Similarly, if the password file entry was + +@example +/home/cc/sugar/mjh +@end example + +the map entry used by @i{Amd} would be + +@example +rfs:=/home/sugar;rhost:=sugar.cc;sublink:=jsp +@end example + +@node Union maps, LDAP maps , Password maps, Map Types +@comment node-name, next, previous, up +@subsection Union maps +@cindex Union file maps + +The union map support is provided specifically for use with the union +filesystem, @pxref{Union Filesystem}. + +It is identified by the string @samp{union:} which is followed by a +colon separated list of directories. The directories are read in order, +and the names of all entries are recorded in the map cache. Later +directories take precedence over earlier ones. The union filesystem +type then uses the map cache to determine the union of the names in all +the directories. + +@node LDAP maps, , Union maps, Map Types +@comment node-name, next, previous, up +@subsection LDAP maps +@cindex LDAP maps +@cindex Lightweight Directory Access Protocol + +LDAP (Lightweight Directory Access Protocol) maps do not support cache +mode @samp{all} and, when caching is enabled, have a default cache mode +of @samp{inc}. + +For example, an @i{Amd} map @samp{amd.home} that looks as follows: + +@example +/defaults opts:=rw,intr;type:=link + +zing -rhost:=shekel \ + host==shekel \ + host!=shekel;type:=nfs +@end example +@noindent +when converted to LDAP (@pxref{amd2ldif}), will result in the following +LDAP database: +@example +$ amd2ldif amd.home CUCS < amd.home +dn: cn=amdmap timestamp, CUCS +cn : amdmap timestamp +objectClass : amdmapTimestamp +amdmapTimestamp: 873071363 + +dn: cn=amdmap amd.home[/defaults], CUCS +cn : amdmap amd.home[/defaults] +objectClass : amdmap +amdmapName : amd.home +amdmapKey : /defaults +amdmapValue : opts:=rw,intr;type:=link + +dn: cn=amdmap amd.home[], CUCS +cn : amdmap amd.home[] +objectClass : amdmap +amdmapName : amd.home +amdmapKey : +amdmapValue : + +dn: cn=amdmap amd.home[zing], CUCS +cn : amdmap amd.home[zing] +objectClass : amdmap +amdmapName : amd.home +amdmapKey : zing +amdmapValue : -rhost:=shekel host==shekel host!=shekel;type:=nfs +@end example + +@c subsection Gdbm + +@node Key Lookup, Location Format, Map Types, Mount Maps +@comment node-name, next, previous, up +@section How keys are looked up +@cindex Key lookup +@cindex Map lookup +@cindex Looking up keys +@cindex How keys are looked up +@cindex Wildcards in maps + +The key is located in the map whose type was determined when the +automount point was first created. In general the key is a pathname +component. In some circumstances this may be modified by variable +expansion (@pxref{Variable Expansion}) and prefixing. If the automount +point has a prefix, specified by the @var{pref} option, then that is +prepended to the search key before the map is searched. + +If the map cache is a @samp{regexp} cache then the key is treated as an +egrep-style regular expression, otherwise a normal string comparison is +made. + +If the key cannot be found then a @dfn{wildcard} match is attempted. +@i{Amd} repeatedly strips the basename from the key, appends @samp{/*} and +attempts a lookup. Finally, @i{Amd} attempts to locate the special key @samp{*}. + +For example, the following sequence would be checked if @file{home/dylan/dk2} was +being located: + +@example + home/dylan/dk2 + home/dylan/* + home/* + * +@end example + +At any point when a wildcard is found, @i{Amd} proceeds as if an exact +match had been found and the value field is then used to resolve the +mount request, otherwise an error code is propagated back to the kernel. +(@pxref{Filesystem Types}).@refill + +@node Location Format, , Key Lookup, Mount Maps +@comment node-name, next, previous, up +@section Location Format +@cindex Location format +@cindex Map entry format +@cindex How locations are parsed + +The value field from the lookup provides the information required to +mount a filesystem. The information is parsed according to the syntax +shown below. + +@display +@i{location-list}: + @i{location-selection} + @i{location-list} @i{white-space} @t{||} @i{white-space} @i{location-selection} +@i{location-selection}: + @i{location} + @i{location-selection} @i{white-space} @i{location} +@i{location}: + @i{location-info} + @t{-}@i{location-info} + @t{-} +@i{location-info}: + @i{sel-or-opt} + @i{location-info}@t{;}@i{sel-or-opt} + @t{;} +@i{sel-or-opt}: + @i{selection} + @i{opt-ass} +@i{selection}: + selector@t{==}@i{value} + selector@t{!=}@i{value} +@i{opt-ass}: + option@t{:=}@i{value} +@i{white-space}: + space + tab +@end display + +Note that unquoted whitespace is not allowed in a location description. +White space is only allowed, and is mandatory, where shown with non-terminal +@i{white-space}. + +A @dfn{location-selection} is a list of possible volumes with which to +satisfy the request. @dfn{location-selection}s are separated by the +@samp{||} operator. The effect of this operator is to prevent use of +location-selections to its right if any of the location-selections on +its left were selected whether or not any of them were successfully +mounted (@pxref{Selectors}).@refill + +The location-selection, and singleton @dfn{location-list}, +@samp{type:=ufs;dev:=/dev/xd1g} would inform @i{Amd} to mount a UFS +filesystem from the block special device @file{/dev/xd1g}. + +The @dfn{sel-or-opt} component is either the name of an option required +by a specific filesystem, or it is the name of a built-in, predefined +selector such as the architecture type. The value may be quoted with +double quotes @samp{"}, for example +@samp{type:="ufs";dev:="/dev/xd1g"}. These quotes are stripped when the +value is parsed and there is no way to get a double quote into a value +field. Double quotes are used to get white space into a value field, +which is needed for the program filesystem (@pxref{Program Filesystem}).@refill + +@menu +* Map Defaults:: +* Variable Expansion:: +* Selectors:: +* Map Options:: +@end menu + +@node Map Defaults, Variable Expansion, Location Format, Location Format +@comment node-name, next, previous, up +@subsection Map Defaults +@cindex Map defaults +@cindex How to set default map parameters +@cindex Setting default map parameters + +A location beginning with a dash @samp{-} is used to specify default +values for subsequent locations. Any previously specified defaults in +the location-list are discarded. The default string can be empty in +which case no defaults apply. + +The location @samp{-fs:=/mnt;opts:=ro} would set the local mount point +to @file{/mnt} and cause mounts to be read-only by default. Defaults +specified this way are appended to, and so override, any global map +defaults given with @samp{/defaults}). + +@c +@c A @samp{/defaults} value @dfn{gdef} and a location list +@c \begin{quote} +@c $@samp{-}@dfn{def}_a $\verb*+ +$ @dfn{loc}_{a_1} $\verb*+ +$ @dfn{loc}_{a_2} $\verb*+ +$ @samp{-}@dfn{def}_b $\verb*+ +$ @dfn{loc}_{b_1} \ldots$ +@c \end{quote} +@c is equivalent to +@c \begin{quote} +@c $@samp{-}@dfn{gdef}@samp{;}@dfn{def}_a $\verb*+ +$ @dfn{loc}_{a_1} $\verb*+ +$ @dfn{loc}_{a_2} $\verb*+ +$ @samp{-}@dfn{gdef}@samp{;}@dfn{def}_b $\verb*+ +$ @dfn{loc}_{b_1} \ldots$ +@c \end{quote} +@c which is equivalent to +@c \begin{quote} +@c $@dfn{gdef}@samp{;}@dfn{def}_a@samp{;}@dfn{loc}_{a_1} $\verb*+ +$@dfn{gdef}@samp{;}@dfn{def}_a@samp{;}@dfn{loc}_{a_2} $\verb*+ +$@dfn{gdef}@samp{;}@dfn{def}_b@samp{;}@dfn{loc}_{b_1} \ldots$ +@c \end{quote} + +@node Variable Expansion, Selectors, Map Defaults, Location Format +@comment node-name, next, previous, up +@subsection Variable Expansion +@cindex Variable expansion +@cindex How variables are expanded +@cindex Pathname operators +@cindex Domain stripping +@cindex Domainname operators +@cindex Stripping the local domain name +@cindex Environment variables +@cindex How to access environment variables in maps + +To allow generic location specifications @i{Amd} does variable expansion +on each location and also on some of the option strings. Any option or +selector appearing in the form @code{$@dfn{var}} is replaced by the +current value of that option or selector. For example, if the value of +@code{$@{key@}} was @samp{bin}, @code{$@{autodir@}} was @samp{/a} and +@code{$@{fs@}} was `@t{$@{autodir@}}@t{/local/}@t{$@{key@}}' then +after expansion @code{$@{fs@}} would have the value @samp{/a/local/bin}. +Any environment variable can be accessed in a similar way.@refill + +Two pathname operators are available when expanding a variable. If the +variable name begins with @samp{/} then only the last component of the +pathname is substituted. For example, if @code{$@{path@}} was +@samp{/foo/bar} then @code{$@{/path@}} would be expanded to @samp{bar}. +Similarly, if the variable name ends with @samp{/} then all but the last +component of the pathname is substituted. In the previous example, +@code{$@{path/@}} would be expanded to @samp{/foo}.@refill + +Two domain name operators are also provided. If the variable name +begins with @samp{.} then only the domain part of the name is +substituted. For example, if @code{$@{rhost@}} was +@samp{swan.doc.ic.ac.uk} then @code{$@{.rhost@}} would be expanded to +@samp{doc.ic.ac.uk}. Similarly, if the variable name ends with @samp{.} +then only the host component is substituted. In the previous example, +@code{$@{rhost.@}} would be expanded to @samp{swan}.@refill + +Variable expansion is a two phase process. Before a location is parsed, +all references to selectors, @i{eg} @code{$@{path@}}, are expanded. The +location is then parsed, selections are evaluated and option assignments +recorded. If there were no selections or they all succeeded the +location is used and the values of the following options are expanded in +the order given: @var{sublink}, @var{rfs}, @var{fs}, @var{opts}, +@var{remopts}, @var{mount} and @var{unmount}. + +Note that expansion of option values is done after @dfn{all} assignments +have been completed and not in a purely left to right order as is done +by the shell. This generally has the desired effect but care must be +taken if one of the options references another, in which case the +ordering can become significant. + +There are two special cases concerning variable expansion: + +@enumerate +@item +before a map is consulted, any selectors in the name received +from the kernel are expanded. For example, if the request from the +kernel was for `@t{$@{arch@}}@t{.bin}' and the machine architecture +was @samp{vax}, the value given to @code{$@{key@}} would be +@samp{vax.bin}.@refill + +@item +the value of @code{$@{rhost@}} is expanded and normalized before the +other options are expanded. The normalization process strips any local +sub-domain components. For example, if @code{$@{domain@}} was +@samp{Berkeley.EDU} and @code{$@{rhost@}} was initially +@samp{snow.Berkeley.EDU}, after the normalization it would simply be +@samp{snow}. Hostname normalization is currently done in a +@emph{case-dependent} manner.@refill +@end enumerate + +@c====================================================================== +@node Selectors, Map Options, Variable Expansion, Location Format +@comment node-name, next, previous, up +@subsection Selectors +@cindex Selectors + +Selectors are used to control the use of a location. It is possible to +share a mount map between many machines in such a way that filesystem +location, architecture and operating system differences are hidden from +the users. A selector of the form @samp{arch==sun3;os==sunos4} would only +apply on Sun-3s running SunOS 4.x. + +Selectors can be negated by using @samp{!=} instead of @samp{==}. For +example to select a location on all non-Vax machines the selector +@samp{arch!=vax} would be used. + +Selectors are evaluated left to right. If a selector fails then that +location is ignored. Thus the selectors form a conjunction and the +locations form a disjunction. If all the locations are ignored or +otherwise fail then @i{Amd} uses the @dfn{error} filesystem +(@pxref{Error Filesystem}). This is equivalent to having a location +@samp{type:=error} at the end of each mount-map entry.@refill + +The default value of many of the selectors listed here can be overridden +by an @i{Amd} command line switch or in an @i{Amd} configuration file. +@xref{Amd Configuration File}. + +These are the selectors currently implemented. + +@menu +* arch Selector Variable:: +* autodir Selector Variable:: +* byte Selector Variable:: +* cluster Selector Variable:: +* domain Selector Variable:: +* host Selector Variable:: +* hostd Selector Variable:: +* karch Selector Variable:: +* os Selector Variable:: +* osver Selector Variable:: + +* key Selector Variable:: +* map Selector Variable:: +* netnumber Selector Variable:: +* network Selector Variable:: +* path Selector Variable:: +* wire Selector Variable:: + +* exists Selector Function:: +* false Selector Function:: +* netgrp Selector Function:: +* in_network Selector Function:: +* true Selector Function:: +@end menu + +@c ---------------------------------------------------------------- +@node arch Selector Variable, autodir Selector Variable, Selectors, Selectors +@comment node-name, next, previous, up +@subsubsection arch Selector Variable +@cindex arch Selector Variable +@cindex arch, mount selector +@cindex Mount selector; arch +@cindex Selector; arch + +The machine architecture which was automatically determined at compile +time. The architecture type can be displayed by running the command +@samp{amd -v}. @xref{Supported Platforms}.@refill + +@c ---------------------------------------------------------------- +@node autodir Selector Variable, byte Selector Variable, arch Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection autodir Selector Variable +@cindex autodir Selector Variable +@cindex autodir, mount selector +@cindex Mount selector; autodir +@cindex Selector; autodir + +The default directory under which to mount filesystems. This may be +changed by the @code{-a} command line option. @xref{fs Option}. + +@c ---------------------------------------------------------------- +@node byte Selector Variable, cluster Selector Variable, autodir Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection byte Selector Variable +@cindex byte Selector Variable +@cindex byte, mount selector +@cindex Mount selector; byte +@cindex Selector; byte + +The machine's byte ordering. This is either @samp{little}, indicating +little-endian, or @samp{big}, indicating big-endian. One possible use +is to share @samp{rwho} databases (@pxref{rwho servers}). Another is to +share ndbm databases, however this use can be considered a courageous +juggling act. + +@c ---------------------------------------------------------------- +@node cluster Selector Variable, domain Selector Variable, byte Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection cluster Selector Variable +@cindex cluster Selector Variable +@cindex cluster, mount selector +@cindex Mount selector; cluster +@cindex Selector; cluster + +This is provided as a hook for the name of the local cluster. This can +be used to decide which servers to use for copies of replicated +filesystems. @code{$@{cluster@}} defaults to the value of +@code{$@{domain@}} unless a different value is set with the @code{-C} +command line option. + +@c ---------------------------------------------------------------- +@node domain Selector Variable, host Selector Variable, cluster Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection domain Selector Variable +@cindex domain Selector Variable +@cindex domain, mount selector +@cindex Mount selector; domain +@cindex Selector; domain + +The local domain name as specified by the @code{-d} command line option. +@xref{host Selector Variable}. + +@c ---------------------------------------------------------------- +@node host Selector Variable, hostd Selector Variable, domain Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection host Selector Variable +@cindex host Selector Variable +@cindex host, mount selector +@cindex Mount selector; host +@cindex Selector; host + +The local hostname as determined by @b{gethostname}(2). If no domain +name was specified on the command line and the hostname contains a +period @samp{.} then the string before the period is used as the host +name, and the string after the period is assigned to @code{$@{domain@}}. +For example, if the hostname is @samp{styx.doc.ic.ac.uk} then +@code{host} would be @samp{styx} and @code{domain} would be +@samp{doc.ic.ac.uk}. @code{hostd} would be +@samp{styx.doc.ic.ac.uk}.@refill + +@c ---------------------------------------------------------------- +@node hostd Selector Variable, karch Selector Variable, host Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection hostd Selector Variable +@cindex hostd Selector Variable +@cindex hostd, mount selector +@cindex Mount selector; hostd +@cindex Selector; hostd + +This resolves to the @code{$@{host@}} and @code{$@{domain@}} +concatenated with a @samp{.} inserted between them if required. If +@code{$@{domain@}} is an empty string then @code{$@{host@}} and +@code{$@{hostd@}} will be identical. + +@c ---------------------------------------------------------------- +@node karch Selector Variable, os Selector Variable, hostd Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection karch Selector Variable +@cindex karch Selector Variable +@cindex karch, mount selector +@cindex Mount selector; karch +@cindex Selector; karch + +This is provided as a hook for the kernel architecture. This is used on +SunOS 4 and SunOS 5, for example, to distinguish between different +@samp{/usr/kvm} volumes. @code{$@{karch@}} defaults to the ``machine'' +value gotten from @b{uname}(2). If the @b{uname}(2) system call is not +available, the value of @code{$@{karch@}} defaults to that of +@code{$@{arch@}}. Finally, a different value can be set with the @code{-k} +command line option. + +@c ---------------------------------------------------------------- +@node os Selector Variable, osver Selector Variable, karch Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection os Selector Variable +@cindex os Selector Variable +@cindex os, mount selector +@cindex Mount selector; os +@cindex Selector; os + +The operating system. Like the machine architecture, this is +automatically determined at compile time. The operating system name can +be displayed by running the command @samp{amd -v}. @xref{Supported +Platforms}.@refill + +@c ---------------------------------------------------------------- +@node osver Selector Variable, key Selector Variable, os Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection osver Selector Variable +@cindex osver Selector Variable +@cindex osver, mount selector +@cindex Mount selector; osver +@cindex Selector; osver + +The operating system version. Like the machine architecture, this is +automatically determined at compile time. The operating system name can +be displayed by running the command @samp{amd -v}. @xref{Supported +Platforms}.@refill + +@c ---------------------------------------------------------------- +@ifhtml +
+@end ifhtml +@sp 3 +The following selectors are also provided. Unlike the other selectors, +they vary for each lookup. Note that when the name from the kernel is +expanded prior to a map lookup, these selectors are all defined as empty +strings. + +@c ---------------------------------------------------------------- +@node key Selector Variable, map Selector Variable, osver Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection key Selector Variable +@cindex key Selector Variable +@cindex key, mount selector +@cindex Mount selector; key +@cindex Selector; key + +The name being resolved. For example, if @file{/home} is an automount +point, then accessing @file{/home/foo} would set @code{$@{key@}} to the +string @samp{foo}. The key is prefixed by the @var{pref} option set in +the parent mount point. The default prefix is an empty string. If the +prefix was @file{blah/} then @code{$@{key@}} would be set to +@file{blah/foo}.@refill + +@c ---------------------------------------------------------------- +@node map Selector Variable, netnumber Selector Variable, key Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection map Selector Variable +@cindex map Selector Variable +@cindex map, mount selector +@cindex Mount selector; map +@cindex Selector; map + +The name of the mount map being used. + +@c ---------------------------------------------------------------- +@node netnumber Selector Variable, network Selector Variable, map Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection netnumber Selector Variable +@cindex netnumber Selector Variable +@cindex netnumber, mount selector +@cindex Mount selector; netnumber +@cindex Selector; netnumber + +This selector is identical to the @samp{in_network} selector function, +see @ref{in_network Selector Function}. It will match either the name +or number of @i{any} network interface on which this host is connected +to. The names and numbers of all attached interfaces are available from +the output of @samp{amd -v}. + +@c ---------------------------------------------------------------- +@node network Selector Variable, path Selector Variable, netnumber Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection network Selector Variable +@cindex network Selector Variable +@cindex network, mount selector +@cindex Mount selector; network +@cindex Selector; network + +This selector is identical to the @samp{in_network} selector function, +see @ref{in_network Selector Function}. It will match either the name +or number of @i{any} network interface on which this host is connected +to. The names and numbers of all attached interfaces are available from +the output of @samp{amd -v}. + +@c ---------------------------------------------------------------- +@node path Selector Variable, wire Selector Variable, network Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection path Selector Variable +@cindex path Selector Variable +@cindex path, mount selector +@cindex Mount selector; path +@cindex Selector; path + +The full pathname of the name being resolved. For example +@file{/home/foo} in the example above. + +@c ---------------------------------------------------------------- +@node wire Selector Variable, exists Selector Function, path Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection wire Selector Variable +@cindex wire Selector Variable +@cindex wire, mount selector +@cindex Mount selector; wire +@cindex Selector; wire + +This selector is identical to the @samp{in_network} selector function, +see @ref{in_network Selector Function}. It will match either the name +or number of @i{any} network interface on which this host is connected +to. The names and numbers of all attached interfaces are available from +the output of @samp{amd -v}. + +@c ---------------------------------------------------------------- +@ifhtml +
+@end ifhtml +@sp 2 +The following boolean functions are selectors which take an argument +@i{ARG}. They return a value of true or false, and thus do not need to +be compared with a value. Each of these may be negated by prepending +@samp{!} to their name. + +@c ---------------------------------------------------------------- +@node exists Selector Function, false Selector Function, wire Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection exists Selector Function +@cindex exists Selector Function +@cindex exists, boolean mount selector +@cindex !exists, boolean mount selector +@cindex Mount selector; exists +@cindex Selector; exists + +If the file listed by @i{ARG} exists (via @b{lstat}(2)), this function +evaluates to true. Otherwise it evaluates to false. + +@c ---------------------------------------------------------------- +@node false Selector Function, netgrp Selector Function, exists Selector Function, Selectors +@comment node-name, next, previous, up +@subsubsection false Selector Function +@cindex false Selector Function +@cindex false, boolean mount selector +@cindex !false, boolean mount selector +@cindex Mount selector; false +@cindex Selector; false + +Always evaluates to false. @i{ARG} is ignored. + +@c ---------------------------------------------------------------- +@node netgrp Selector Function, in_network Selector Function, false Selector Function, Selectors +@comment node-name, next, previous, up +@subsubsection netgrp Selector Function +@cindex netgrp Selector Function +@cindex netgrp, boolean mount selector +@cindex !netgrp, boolean mount selector +@cindex Mount selector; netgrp +@cindex Selector; netgrp + +If the current host as determined by the value of @code{$@{host@}} is a +member of the netgroup @i{ARG}, this selector evaluates to true. +Otherwise it evaluates to false. + +For example, suppose you have a netgroup @samp{ppp-hosts}, and for +reasons of performance, these have a local @file{/home} partition, while +all other clients on the faster network can access a shared home +directory. A common map to use for both might look like the following: + +@example +home/* netgrp(ppp-hosts);type:=link;fs:=/local/$@{key@} \ + !netgrp(ppp-hosts);type:=nfs;rhost=serv1;rfs:=/remote/$@{key@} +@end example + +@c ---------------------------------------------------------------- +@node in_network Selector Function, true Selector Function, netgrp Selector Function, Selectors +@comment node-name, next, previous, up +@subsubsection in_network Selector Function +@cindex in_network Selector Function +@cindex in_network, boolean mount selector +@cindex !in_network, boolean mount selector +@cindex Mount selector; in_network +@cindex Selector; in_network + +If the current host has any network interface that is locally attached +to the network specified in @i{ARG} (either via name or number), this +selector evaluates to true. Otherwise it evaluates to false. + +For example, suppose you have two servers that have an exportable +@file{/opt} that smaller clients can NFS mount. The two servers are +say, @samp{serv1} on network @samp{foo-net.site.com} and @samp{serv2} on +network @samp{123.4.5.0}. You can write a map to be used by all clients +that will attempt to mount the closest one as follows: + +@example +opt in_network(foo-net.site.com);rhost:=serv1;rfs:=/opt \ + in_network(123.4.5.0);rhost:=serv2;rfs:=/opt \ + rhost:=fallback-server +@end example + +@c ---------------------------------------------------------------- +@node true Selector Function, , in_network Selector Function, Selectors +@comment node-name, next, previous, up +@subsubsection true Selector Function +@cindex true Selector Function +@cindex true, boolean mount selector +@cindex !true, boolean mount selector +@cindex Mount selector; true +@cindex Selector; true + +Always evaluates to true. @i{ARG} is ignored. + +@c ================================================================ +@node Map Options, , Selectors, Location Format +@comment node-name, next, previous, up +@subsection Map Options +@cindex Map options +@cindex Setting map options + +Options are parsed concurrently with selectors. The difference is that +when an option is seen the string following the @samp{:=} is +recorded for later use. As a minimum the @var{type} option must be +specified. Each filesystem type has other options which must also be +specified. @xref{Filesystem Types}, for details on the filesystem +specific options.@refill + +Superfluous option specifications are ignored and are not reported +as errors. + +The following options apply to more than one filesystem type. + +@menu +* addopts Option:: +* delay Option:: +* fs Option:: +* opts Option:: +* remopts Option:: +* sublink Option:: +* type Option:: +@end menu + +@node addopts Option, delay Option, Map Options, Map Options +@comment node-name, next, previous, up +@subsubsection addopts Option +@cindex Setting additional options on a mount location +@cindex Overriding or adding options to a mount +@cindex addopts, mount option +@cindex Mount option; addopts + +This option adds additional options to default options normally +specified in the @samp{/defaults} entry or the defaults of the key entry +being processed (@xref{opts Option}). Normally when you specify +@samp{opts} in both the @samp{/defaults} and the map entry, the latter +overrides the former completely. But with @samp{addopts} it will +append the options and override any conflicting ones. + +Options which start with @samp{no} will override those with the same +name that do not start with @samp{no} and vice verse. Special handling +is given to inverted options such as @samp{soft} and @samp{hard}, +@samp{bg} and @samp{fg}, @samp{ro} and @samp{rw}, etc. + +For example, if the default options specified were +@example +opts:=rw,nosuid,intr,rsize=1024,wsize=1024,quota,posix +@end example + +and the ones specified in a map entry were + +@example +addopts:=grpid,suid,ro,rsize=2048,quota,nointr +@end example + +then the actual options used would be + +@example +wsize=1024,posix,grpid,suid,ro,rsize=2048,quota,nointr +@end example + +@node delay Option, fs Option, addopts Option, Map Options +@comment node-name, next, previous, up +@subsubsection delay Option +@cindex Setting a delay on a mount location +@cindex Delaying mounts from specific locations +@cindex Primary server +@cindex Secondary server +@cindex delay, mount option +@cindex Mount option; delay + +The delay, in seconds, before an attempt will be made to mount from the +current location. Auxiliary data, such as network address, file handles +and so on are computed regardless of this value. + +A delay can be used to implement the notion of primary and secondary +file servers. The secondary servers would have a delay of a few +seconds, thus giving the primary servers a chance to respond first. + +@node fs Option, opts Option, delay Option, Map Options +@comment node-name, next, previous, up +@subsubsection fs Option +@cindex Setting the local mount point +@cindex Overriding the default mount point +@cindex fs, mount option +@cindex Mount option; fs + +The local mount point. The semantics of this option vary between +filesystems. + +For NFS and UFS filesystems the value of @code{$@{fs@}} is used as the +local mount point. For other filesystem types it has other meanings +which are described in the section describing the respective filesystem +type. It is important that this string uniquely identifies the +filesystem being mounted. To satisfy this requirement, it should +contain the name of the host on which the filesystem is resident and the +pathname of the filesystem on the local or remote host. + +The reason for requiring the hostname is clear if replicated filesystems +are considered. If a fileserver goes down and a replacement filesystem +is mounted then the @dfn{local} mount point @dfn{must} be different from +that of the filesystem which is hung. Some encoding of the filesystem +name is required if more than one filesystem is to be mounted from any +given host. + +If the hostname is first in the path then all mounts from a particular +host will be gathered below a single directory. If that server goes +down then the hung mount points are less likely to be accidentally +referenced, for example when @b{getcwd}(3) traverses the namespace to +find the pathname of the current directory. + +The @samp{fs} option defaults to +@code{$@{autodir@}/$@{rhost@}$@{rfs@}}. In addition, +@samp{rhost} defaults to the local host name (@code{$@{host@}}) and +@samp{rfs} defaults to the value of @code{$@{path@}}, which is the full +path of the requested file; @samp{/home/foo} in the example above +(@pxref{Selectors}). @code{$@{autodir@}} defaults to @samp{/a} but may +be changed with the @code{-a} command line option. Sun's automounter +defaults to @samp{/tmp_mnt}. Note that there is no @samp{/} between +the @code{$@{rhost@}} and @code{$@{rfs@}} since @code{$@{rfs@}} begins +with a @samp{/}.@refill + +@node opts Option, remopts Option, fs Option, Map Options +@comment node-name, next, previous, up +@subsubsection opts Option +@cindex Setting system mount options +@cindex Passing parameters to the mount system call +@cindex mount system call +@cindex mount system call flags +@cindex The mount system call +@cindex opts, mount option +@cindex Mount option; opts + +The options to pass to the mount system call. A leading @samp{-} is +silently ignored. The mount options supported generally correspond to +those used by @b{mount}(8) and are listed below. Some additional +pseudo-options are interpreted by @i{Amd} and are also listed. + +Unless specifically overridden, each of the system default mount options +applies. Any options not recognized are ignored. If no options list is +supplied the string @samp{rw,defaults} is used and all the system +default mount options apply. Options which are not applicable for a +particular operating system are silently ignored. For example, only 4.4BSD +is known to implement the @code{compress} and @code{spongy} options. + +@table @code + +@item acdirmax=@var{n} +@cindex Mount flags; acdirmax +Set the maximum directory attribute cache timeout to @var{n}. + +@item acdirmin=@var{n} +@cindex Mount flags; acdirmin +Set the minimum directory attribute cache timeout to @var{n}. + +@item acregmax=@var{n} +@cindex Mount flags; acregmax +Set the maximum file attribute cache timeout to @var{n}. + +@item acregmin=@var{n} +@cindex Mount flags; acregmin +Set the minimum file attribute cache timeout to @var{n}. + +@item actimeo=@var{n} +@cindex Mount flags; actimeo +Set the overall attribute cache timeout to @var{n}. + +@item auto +@cindex Mount flags; auto +@itemx ignore +@cindex Mount flags; ignore +Ignore this mount by @b{df}(1). + +@item cache +@cindex Mount flags; cache +Allow data to be cached from a remote server for this mount. + +@item compress +@cindex Mount flags; compress +Use NFS compression protocol. + +@item defperm +@cindex Mount flags; defperm +Ignore the permission mode bits, and default file permissions to 0555, +UID 0, and GID 0. Useful for CD-ROMs formatted as ISO-9660. + +@item dev +@cindex Mount flags; dev +Allow local special devices on this filesystem. + +@item dumbtimr +@cindex Mount flags; dumbtimr +(XXX: a dumb timer?) + +@item fsid +@cindex Mount flags; fsid +Set ID of filesystem. + +@item grpid +@cindex Mount flags; grpid +Use BSD directory group-id semantics. + +@item int +@cindex Mount flags; int +@itemx intr +@cindex Mount flags; intr +Allow keyboard interrupts on hard mounts. + +@item multi +@cindex Mount flags; multi +Perform multi-component lookup on files. + +@item maxgroups +@cindex Mount flags; maxgroups +Set the maximum number of groups to allow for this mount. + +@item nfsv3 +@cindex Mount flags; nfsv3 +Use NFS Version 3 for this mount. + +@item noac +@cindex Mount flags; noac +Turn off the attribute cache. + +@item noauto +@cindex Mount flags; noauto +(XXX: No automatic what?) + +@item nocache +@cindex Mount flags; nocache +Do not allow data to be cached from a remote server for this +mount. + +@item noconn +@cindex Mount flags; noconn +Don't make a connection on datagram transports. + +@item nocto +@cindex Mount flags; nocto +No close-to-open consistency. + +@item nodefperm +@cindex Mount flags; nodefperm +Do not ignore the permission mode bits. Useful for CD-ROMS formatted as +ISO-9660. + +@item nodev +@cindex Mount flags; nodev +@itemx nodevs +@cindex Mount flags; nodevs +Don't allow local special devices on this filesystem. + +@item noint +@cindex Mount flags; noint +Do not allow keyboard interrupts for this mount + +@item nosub +@cindex Mount flags; nosub +Disallow mounts beneath this mount. + +@item nosuid +@cindex Mount flags; nosuid +Don't allow set-uid or set-gid executables on this filesystem. + +@item noversion +@cindex Mount flags; noversion +Strip the extension @samp{;#} from the version string of files recorded +on an ISO-9660 CD-ROM. + +@item overlay +@cindex Mount flags; overlay +Overlay this mount on top of an existing mount, if any. + +@item pgthresh=@var{n} +@cindex Mount flags; pgthresh +Set the paging threshold to @var{n} kilobytes. + +@item port=@var{n} +@cindex Mount flags; port +Set the NFS port to @var{n}. + +@item posix +@cindex Mount flags; posix +Turn on POSIX static pathconf for mounts. + +@item proto=@var{s} +@cindex Mount flags; proto +Use transport protocol @var{s} for NFS (can be @code{"tcp"} or @code{"udp"}). + +@item quota +@cindex Mount flags; quota +Enable quota checking on this mount. + +@item rdonly +@cindex Mount flags; rdonly +@itemx ro +@cindex Mount flags; ro +Mount this filesystem readonly. + +@item resvport +@cindex Mount flags; resvport +Use a reserved port (smaller than 1024) for remote NFS mounts. Most +systems assume that, but some allow for mounts to occur on non-reserved +ports. This causes problems when such a system tries to NFS mount one +that requires reserved ports. It is recommended that this option always +be on. + +@item retrans=@i{n} +@cindex Mount flags; retrans +The number of NFS retransmits made before a user error is generated by a +@samp{soft} mounted filesystem, and before a @samp{hard} mounted +filesystem reports @samp{NFS server @dfn{yoyo} not responding still +trying}. + +@item retry +@cindex Mount flags; retry +Set the NFS retry counter. + +@item rrip +@cindex Mount flags; rrip +Uses the Rock Ridge Interchange Protocol (RRIP) extensions to ISO-9660. + +@item rsize=@var{n} +@cindex Mount flags; rsize +The NFS read packet size. You may need to set this if you are using +NFS/UDP through a gateway or a slow link. + +@item rw +@cindex Mount flags; rw +Allow reads and writes on this filesystem. + +@item soft +@cindex Mount flags; soft +Give up after @dfn{retrans} retransmissions. + +@item spongy +@cindex Mount flags; spongy +Like @samp{soft} for status requests, and @samp{hard} for data transfers. + +@item suid +@cindex Mount flags; suid +Allow set-uid programs on this mount. + +@item symttl +@cindex Mount flags; symttl +Turn of the symbolic link cache time-to-live. + +@item sync +@cindex Mount flags; sync +Perform synchronous filesystem operations on this mount. + +@item tcp +@cindex Mount flags; tcp +Use TCP/IP instead of UDP/IP, ignored if the NFS implementation does not +support TCP/IP mounts. + +@item timeo=@var{n} +@cindex Mount flags; timeo +The NFS timeout, in tenth-seconds, before a request is retransmitted. + +@item vers=@var{n} +@cindex Mount flags; vers + Use NFS protocol version number @var{n} (can be 2 or 3). + +@item wsize=@var{n} +@cindex Mount flags; wsize +The NFS write packet size. You may need to set this if you are using +NFS/UDP through a gateway or a slow link. + +@end table + +The following options are implemented by @i{Amd}, rather than being +passed to the kernel. + +@table @code + +@item nounmount +@cindex Mount flags; nounmount +Configures the mount so that its time-to-live will +never expire. This is also the default for some filesystem types. +@c +@c Implementation broken: + +@item ping=@var{n} +@cindex Mount flags; ping +The interval, in seconds, between keep-alive pings. When four +consecutive pings have failed the mount point is marked as hung. This +interval defaults to 30 seconds. If the ping interval is less than zero, +no pings are sent and the host is assumed to be always +up. By default, pings are not sent for an NFS/TCP mount. + +@item retry=@var{n} +@cindex Mount flags; retry=@var{n} +The number of times to retry the mount system call. + +@item utimeout=@var{n} +@cindex Mount flags; utimeout=@var{n} +The interval, in seconds, by which the mount's +time-to-live is extended after an unmount attempt +has failed. In fact the interval is extended before the unmount is +attempted to avoid thrashing. The default value is 120 seconds (two +minutes) or as set by the @code{-w} command line option. + +@end table + +@node remopts Option, sublink Option, opts Option, Map Options +@comment node-name, next, previous, up +@subsubsection remopts Option +@cindex Setting system mount options for non-local networks +@cindex remopts, mount option +@cindex Mount option; remopts + +This option has the same use as @code{$@{opts@}} but applies only when +the remote host is on a non-local network. For example, when using NFS +across a gateway it is often necessary to use smaller values for the +data read and write sizes. This can simply be done by specifying the +small values in @var{remopts}. When a non-local host is accessed, the +smaller sizes will automatically be used. + +@i{Amd} determines whether a host is local by examining the network +interface configuration at startup. Any interface changes made after +@i{Amd} has been started will not be noticed. The likely effect will +be that a host may incorrectly be declared non-local. + +Unless otherwise set, the value of @code{$@{remopts@}} is the same as +the value of @code{$@{opts@}}. + +@node sublink Option, type Option, remopts Option, Map Options +@comment node-name, next, previous, up +@subsubsection sublink Option +@cindex Setting the sublink option +@cindex sublink, mount option +@cindex Mount option; sublink + +The subdirectory within the mounted filesystem to which the reference +should point. This can be used to prevent duplicate mounts in cases +where multiple directories in the same mounted filesystem are used. + +@node type Option, , sublink Option, Map Options +@comment node-name, next, previous, up +@subsubsection type Option +@cindex Setting the filesystem type option +@cindex type, mount option +@cindex Mount option; type + +The filesystem type to be used. @xref{Filesystem Types}, for a full +description of each type.@refill + +@c ################################################################ +@node Amd Command Line Options, Filesystem Types, Mount Maps, Top +@comment node-name, next, previous, up +@chapter @i{Amd} Command Line Options +@cindex Command line options, Amd +@cindex Amd command line options +@cindex Overriding defaults on the command line + +Many of @i{Amd}'s parameters can be set from the command line. The +command line is also used to specify automount points and maps. + +The general format of a command line is + +@example +amd [@i{options}] [@{ @i{directory} @i{map-name} [-@i{map-options}] @} ...] +@end example + +For each directory and map-name given or specified in the +@file{amd.conf} file, @i{Amd} establishes an automount point. The +@dfn{map-options} may be any sequence of options or +selectors---@pxref{Location Format}. The @dfn{map-options} apply only +to @i{Amd}'s mount point. + +@samp{type:=toplvl;cache:=mapdefault;fs:=$@{map@}} is the default value for the +map options. Default options for a map are read from a special entry in +the map whose key is the string @samp{/defaults}. When default options +are given they are prepended to any options specified in the mount-map +locations as explained in @ref{Map Defaults}. + +The @dfn{options} are any combination of those listed below. + +Once the command line has been parsed, the automount points are mounted. +The mount points are created if they do not already exist, in which case they +will be removed when @i{Amd} exits. +Finally, @i{Amd} disassociates itself from its controlling terminal and +forks into the background. + +Note: Even if @i{Amd} has been built with @samp{-DDEBUG} (via +@code{configure --enable-debug}), it will still background itself and +disassociate itself from the controlling terminal. To use a debugger it +is necessary to specify @samp{-D nodaemon} on the command line. +However, even with all of this, mounts and unmounts are performed in the +background, and @i{Amd} will always fork before doing them. Therefore, +debugging what happens closely during un/mounts is more challenging. + +@emph{All} of @i{Amd}'s command options (save @code{-F} and @code{-T}) +can be specified in the @file{amd.conf} file. @xref{Amd Configuration +File}. If @i{Amd} is invoked without any command line options, it will +default to using the configuration file @file{/etc/amd.conf}, if one +exists. + +@menu +* -a Option:: Automount directory. +* -c Option:: Cache timeout interval. +* -d Option:: Domain name. +* -k Option:: Kernel architecture. +* -l Option:: Log file. +* -n Option:: Hostname normalization. +* -o Option:: Operating system version. +* -p Option:: Output process id. +* -r Option:: Restart existing mounts. +* -t Option:: Kernel RPC timeout. +* -v Option:: Version information. +* -w Option:: Wait interval after failed unmount. +* -x Option:: Log options. +* -y Option:: NIS domain. +* -C-Option:: Cluster name. +* -D-Option:: Debug flags. +* -F Option:: Amd configuration file. +* -H Option:: Show brief help. +* -O-Option:: Operating system name. +* -S Option:: Lock executable pages in memory. +* -T-Option:: Set tag for configuration file. +@end menu + +@c ---------------------------------------------------------------- +@node -a Option, -c Option, Amd Command Line Options, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-a} @var{directory} +@cindex Automount directory +@cindex Setting the default mount directory + +Specifies the default mount directory. This option changes the variable +@code{$@{autodir@}} which otherwise defaults to @file{/a}. For example, +some sites prefer @file{/amd} or @file{/n}. + +@example +amd -a /amd ... +@end example + +@c ---------------------------------------------------------------- +@node -c Option, -d Option, -a Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-c} @var{cache-interval} +@cindex Cache interval +@cindex Interval before a filesystem times out +@cindex Setting the interval before a filesystem times out +@cindex Changing the interval before a filesystem times out + +Selects the period, in seconds, for which a name is cached by @i{Amd}. +If no reference is made to the volume in this period, @i{Amd} discards +the volume name to filesystem mapping. + +Once the last reference to a filesystem has been removed, @i{Amd} +attempts to unmount the filesystem. If the unmount fails the interval +is extended by a further period as specified by the @samp{-w} command +line option or by the @samp{utimeout} mount option. + +The default @dfn{cache-interval} is 300 seconds (five minutes). + +@c ---------------------------------------------------------------- +@node -d Option, -k Option, -c Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-d} @var{domain} +@cindex Domain name +@cindex Setting the local domain name +@cindex Overriding the local domain name + +Specifies the host's domain. This sets the internal variable +@code{$@{domain@}} and affects the @code{$@{hostd@}} variable. + +If this option is not specified and the hostname already contains the +local domain then that is used, otherwise the default value of +@code{$@{domain@}} is @samp{unknown.domain}. + +For example, if the local domain was @samp{doc.ic.ac.uk}, @i{Amd} could +be started as follows: + +@example +amd -d doc.ic.ac.uk ... +@end example + +@c ---------------------------------------------------------------- +@node -k Option, -l Option, -d Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-k} @var{kernel-architecture} +@cindex Setting the Kernel architecture + +Specifies the kernel architecture of the system. This is usually the +output of @samp{uname -m} (the ``machine'' value gotten from +@b{uname}(2)). If the @b{uname}(2) system call is not available, the +value of @code{$@{karch@}} defaults to that of @code{$@{arch@}}. + +The only effect of this option is to set the variable @code{$@{karch@}}. + +This option would be used as follows: + +@example +amd -k `arch -k` ... +@end example + +@c ---------------------------------------------------------------- +@node -l Option, -n Option, -k Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-l} @var{log-option} +@cindex Log filename +@cindex Setting the log file +@cindex Using syslog to log errors +@cindex syslog + +Selects the form of logging to be made. Several special @dfn{log-options} +are recognized. + +@enumerate +@item +If @dfn{log-option} is the string @samp{syslog}, @i{Amd} will use the +@b{syslog}(3) mechanism. If your system supports syslog facilities, then +the default facility used is @samp{LOG_DAEMON}. + +@item +@cindex syslog facility; specifying an alternate +When using syslog, if you wish to change the facility, append its name +to the log option name, delimited by a single colon. For example, if +@dfn{log-options} is the string @samp{syslog:local7} then @b{Amd} will +log messages via @b{syslog}(3) using the @samp{LOG_LOCAL7} facility. If +the facility name specified is not recognized, @i{Amd} will default to +@samp{LOG_DAEMON}. Note: while you can use any syslog facility +available on your system, it is generally a bad idea to use those +reserved for other services such as @samp{kern}, @samp{lpr}, +@samp{cron}, etc. + +@item +If @dfn{log-option} is the string @samp{/dev/stderr}, @i{Amd} will use +standard error, which is also the default target for log messages. To +implement this, @i{Amd} simulates the effect of the @samp{/dev/fd} +driver. +@end enumerate + +Any other string is taken as a filename to use for logging. Log +messages are appended to the file if it already exists, otherwise a new +file is created. The file is opened once and then held open, rather +than being re-opened for each message. + +Normally, when long-running daemons hold an open file descriptor on a +log file, it is impossible to ``rotate'' the log file and compress older +logs on a daily basis. The daemon needs to be told to discard (via +@b{close}(2)) its file handle, and re-open the log file. This is done +using @code{amq -l} @i{log-option}. @xref{Amq -l option}. + +If the @samp{syslog} option is specified but the system does not support +syslog or if the named file cannot be opened or created, @i{Amd} will +use standard error. Error messages generated before @i{Amd} has +finished parsing the command line are printed on standard error. + +Since @i{Amd} tends to generate a lot of logging information (especially +if debugging was turned on), and due to it being an important program +running on the system, it is usually best to log to a separate disk +file. In that case @i{Amd} would be started as follows: + +@example +amd -l /var/log/amd ... +@end example + +@c ---------------------------------------------------------------- +@node -n Option, -o Option, -l Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-n} +@cindex Hostname normalization +@cindex Aliased hostnames +@cindex Resolving aliased hostnames +@cindex Normalizing hostnames + +Normalizes the remote hostname before using it. Normalization is done +by replacing the value of @code{$@{rhost@}} with the (generally fully +qualified) primary name returned by a hostname lookup. + +This option should be used if several names are used to refer to a +single host in a mount map. + +@c ---------------------------------------------------------------- +@node -o Option, -p Option, -n Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-o} @var{op-sys-ver} +@cindex Operating System version +@cindex Setting the Operating System version + +Override the compiled-in version number of the operating system, with +@var{op-sys-ver}. Useful when the built-in version is not desired for +backward compatibility reasons. For example, if the built-in version is +@samp{2.5.1}, you can override it to @samp{5.5.1}, and use older maps +that were written with the latter in mind. + +@c ---------------------------------------------------------------- +@node -p Option, -r Option, -o Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-p} +@cindex Process id +@cindex Displaying the process id +@cindex process id of Amd daemon +@cindex pid file, creating with -p option +@cindex Creating a pid file + +Causes @i{Amd}'s process id to be printed on standard output. +This can be redirected to a suitable file for use with kill: + +@example +amd -p > /var/run/amd.pid ... +@end example + +This option only has an affect if @i{Amd} is running in daemon mode. +If @i{Amd} is started with the @code{-D nodaemon} debug flag, this +option is ignored. + +@c ---------------------------------------------------------------- +@node -r Option, -t Option, -p Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-r} +@cindex Restarting existing mounts +@cindex Picking up existing mounts + +Tells @i{Amd} to restart existing mounts (@pxref{Inheritance Filesystem}). +@c @dfn{This option will be made the default in the next release.} + +@c ---------------------------------------------------------------- +@node -t Option, -v Option, -r Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-t} @var{timeout.retransmit} +@cindex Setting Amd's RPC parameters + +Specifies the RPC @dfn{timeout} and @dfn{retransmit} intervals used by +the kernel to communicate to @i{Amd}. These are used to set the +@samp{timeo} and @samp{retrans} mount options. + +@i{Amd} relies on the kernel RPC retransmit mechanism to trigger mount +retries. The value of this parameter changes the retry interval. Too +long an interval gives poor interactive response, too short an interval +causes excessive retries. + +@c ---------------------------------------------------------------- +@node -v Option, -w Option, -t Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-v} +@cindex Version information +@cindex Discovering version information +@cindex How to discover your version of Amd + +Print version information on standard error and then exit. The output +is of the form: + +@example +Copyright (c) 1997-1998 Erez Zadok +Copyright (c) 1990 Jan-Simon Pendry +Copyright (c) 1990 Imperial College of Science, Technology & Medicine +Copyright (c) 1990 The Regents of the University of California. +am-utils version 6.0a15 (build 61). +Built by ezk@@cs.columbia.edu on date Wed Oct 22 15:21:03 EDT 1997. +cpu=sparc (big-endian), arch=sun4, karch=sun4u. +full_os=solaris2.5.1, os=sos5, osver=5.5.1, vendor=sun. +Map support for: root, passwd, union, nisplus, nis, ndbm, file, error. +AMFS: nfs, link, nfsx, nfsl, host, linkx, program, union, inherit, + ufs, lofs, hsfs, pcfs, auto, direct, toplvl, error. +FS: autofs, cachefs, cdfs, lofs, nfs, nfs3, pcfs, tfs, tmpfs, ufs. +Network 1: wire="mcl-lab-net.cs.columbia.edu" (netnumber=128.59.13). +Network 2: wire="14-net.cs.columbia.edu" (netnumber=128.59.14). +Network 3: wire="old-net.cs.columbia.edu" (netnumber=128.59.16). +@end example + +The information includes the version number, number of times @i{Amd} was +compiled on the local system, release date and name of the release. +Following come the cpu type, byte ordering, and the architecture and +kernel architecture as @code{$@{arch@}} and @code{$@{karch@}}, +respectively. The next line lists the full name of the system, the +variables @code{$@{os@}} and @code{$@{osver@}}, and the vendor's +name. @xref{Supported Platforms}. + +Then come a list of map types supported, filesystems internally +supported by @i{Amd} (AMFS), and generic filesystems available (FS). +Finally all known networks (if any) of this host are listed by name +and number. They are available via the variables +@code{$@{wire@}} or @code{$@{network@}}, and +@code{$@{netnumber@}} (@pxref{Selectors}) or the @samp{in_network} +selector function (@pxref{in_network Selector Function}). + +@c ---------------------------------------------------------------- +@node -w Option, -x Option, -v Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-w} @var{wait-timeout} +@cindex Setting the interval between unmount attempts +@cindex unmount attempt backoff interval + +Selects the interval in seconds between unmount attempts after the +initial time-to-live has expired. + +This defaults to 120 seconds (two minutes). + +@c ---------------------------------------------------------------- +@node -x Option, -y Option, -w Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-x} @var{opts} +@cindex Log message selection +@cindex Selecting specific log messages +@cindex How to select log messages +@cindex syslog priorities + +Specifies the type and verbosity of log messages. @dfn{opts} is +a comma separated list selected from the following options: + +@table @code +@item fatal +Fatal errors +@item error +Non-fatal errors +@item user +Non-fatal user errors +@item warn +Recoverable errors +@item warning +Alias for @code{warn} +@item info +Information messages +@item map +Mount map usage +@item stats +Additional statistics +@item all +All of the above +@end table + +Initially a set of default logging flags is enabled. This is as if +@samp{-x all,nomap,nostats} had been selected. The command line is +parsed and logging is controlled by the @code{-x} option. The very first +set of logging flags is saved and can not be subsequently disabled using +@i{Amq}. This default set of options is useful for general production +use.@refill + +The @samp{info} messages include details of what is mounted and +unmounted and when filesystems have timed out. If you want to have the +default set of messages without the @samp{info} messages then you simply +need @samp{-x noinfo}. The messages given by @samp{user} relate to +errors in the mount maps, so these are useful when new maps are +installed. The following table lists the syslog priorities used for each +of the message types.@refill + +@table @code +@item fatal +@samp{LOG_CRIT} +@item error +@samp{LOG_ERR} +@item user +@samp{LOG_WARNING} +@item warning +@samp{LOG_WARNING} +@item info +@samp{LOG_INFO} +@item debug +@samp{LOG_DEBUG} +@item map +@samp{LOG_DEBUG} +@item stats +@samp{LOG_INFO} +@end table + + +The options can be prefixed by the string @samp{no} to indicate +that this option should be turned off. For example, to obtain all +but @samp{info} messages the option @samp{-x all,noinfo} would be used. + +If @i{Amd} was built with debugging enabled the @code{debug} option is +automatically enabled regardless of the command line options. + +@c ---------------------------------------------------------------- +@node -y Option, -C-Option, -x Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-y} @var{NIS-domain} +@cindex NIS (YP) domain name +@cindex Overriding the NIS (YP) domain name +@cindex Setting the NIS (YP) domain name +@cindex YP domain name + +Selects an alternate NIS domain. This is useful for debugging and +cross-domain shared mounting. If this flag is specified, @i{Amd} +immediately attempts to bind to a server for this domain. +@c @i{Amd} refers to NIS maps when it starts, unless the @code{-m} option +@c is specified, and whenever required in a mount map. + +@c ---------------------------------------------------------------- +@node -C-Option, -D-Option, -y Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-C} @var{cluster-name} +@cindex Cluster names +@cindex Setting the cluster name + +Specifies the name of the cluster of which the local machine is a member. +The only effect is to set the variable @code{$@{cluster@}}. +The @dfn{cluster-name} is will usually obtained by running another command which uses +a database to map the local hostname into a cluster name. +@code{$@{cluster@}} can then be used as a selector to restrict mounting of +replicated data. +If this option is not given, @code{$@{cluster@}} has the same value as @code{$@{domain@}}. +This would be used as follows: + +@example +amd -C `clustername` ... +@end example + +@c ---------------------------------------------------------------- +@node -D-Option, -F Option, -C-Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-D} @var{opts} +@cindex Debug options +@cindex Setting debug flags + +Controls the verbosity and coverage of the debugging trace; @dfn{opts} +is a comma separated list of debugging options. The @code{-D} option is +only available if @i{Amd} was compiled with @samp{-DDEBUG}, or +configured with @code{configure --enable-debug}. The memory debugging +facilities (@samp{mem}) are only available if @i{Amd} was compiled with +@samp{-DDEBUG_MEM} (in addition to @samp{-DDEBUG}), or configured with +@code{configure --enable-debug=mem}. + +The most common options to use are @samp{-D trace} and @samp{-D test} +(which turns on all the useful debug options). As usual, every option +can be prefixed with @samp{no} to turn it off. + +@table @code +@item all +all options +@item amq +register for amq +@item daemon +enter daemon mode +@item fork +fork server +@item full +program trace +@item info +@cindex debugging hesiod resolver service +@cindex Hesiod: turning on RES_DEBUG +info service specific debugging (hesiod, nis, etc.) In the case of +hesiod maps, turns on the hesiod RES_DEBUG internal debugging option. +@item mem +trace memory allocations +@item mtab +use local @file{./mtab} file +@item str +debug string munging +@item test +full debug but no daemon +@item trace +protocol trace +@end table + +You may also refer to the program source for a more detailed explanation +of the available options. + +@c ---------------------------------------------------------------- +@node -F Option, -H Option, -D-Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-F} @var{conf-file} +@cindex Amd configuration file; specifying name +@cindex Amd configuration file +@cindex amd.conf file + +Specify an @i{Amd} configuration file @var{conf-file} to use. For a +description of the format and syntax, @pxref{Amd Configuration File}. +This configuration file is used to specify any options in lieu of typing +many of them on the command line. The @file{amd.conf} file includes +directives for every command line option @i{Amd} has, and many more that +are only available via the configuration file facility. The +configuration file specified by this option is processed after all other +options had been processed, regardless of the actual location of this +option on the command line. + +@c ---------------------------------------------------------------- +@node -H Option, -O-Option, -F Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-H} +@cindex Displaying brief help +@cindex Help; showing from Amd + +Print a brief help and usage string. + +@c ---------------------------------------------------------------- +@node -O-Option, -S Option, -H Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-O} @var{op-sys-name} +@cindex Operating System name +@cindex Setting the Operating System name + +Override the compiled-in name of the operating system, with +@var{op-sys-name}. Useful when the built-in name is not desired for +backward compatibility reasons. For example, if the build in name is +@samp{sunos5}, you can override it to the old name @samp{sos5}, and use +older maps which were written with the latter in mind. + +@c ---------------------------------------------------------------- +@node -S Option, -T-Option, -O-Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-S} +@cindex plock; using +@cindex locking executable pages in memory + +Do @emph{not} lock the running executable pages of @i{Amd} into memory. +To improve @i{Amd}'s performance, systems that support the @b{plock}(3) +call lock the @i{Amd} process into memory. This way there is less +chance the operating system will schedule, page out, and swap the +@i{Amd} process as needed. This tends to improve @i{Amd}'s performance, +at the cost of reserving the memory used by the @i{Amd} process (making +it unavailable for other processes). If this behavior is not desired, +use the @code{-S} option. + +@c ---------------------------------------------------------------- +@node -T-Option, , -S Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-T} @var{tag} +@cindex Tags for Amd configuration file +@cindex Configuration file; tags + +Specify a tag to use with @file{amd.conf}. All map entries tagged with +@var{tag} will be processed. Map entries that are not tagged are always +processed. Map entries that are tagged with a tag other than @var{tag} +will not be processed. + +@c ################################################################ +@node Filesystem Types, Amd Configuration File, Amd Command Line Options, Top +@comment node-name, next, previous, up +@chapter Filesystem Types +@cindex Filesystem types +@cindex Mount types +@cindex Types of filesystem + +To mount a volume, @i{Amd} must be told the type of filesystem to be +used. Each filesystem type typically requires additional information +such as the fileserver name for NFS. + +From the point of view of @i{Amd}, a @dfn{filesystem} is anything that +can resolve an incoming name lookup. An important feature is support +for multiple filesystem types. Some of these filesystems are +implemented in the local kernel and some on remote fileservers, whilst +the others are implemented internally by @i{Amd}.@refill + +The two common filesystem types are UFS and NFS. Four other user +accessible filesystems (@samp{link}, @samp{program}, @samp{auto} and +@samp{direct}) are also implemented internally by @i{Amd} and these are +described below. There are two additional filesystem types internal to +@i{Amd} which are not directly accessible to the user (@samp{inherit} +and @samp{error}). Their use is described since they may still have an +effect visible to the user.@refill + +@menu +* Network Filesystem:: A single NFS filesystem. +* Network Host Filesystem:: NFS mount a host's entire export tree. +* Network Filesystem Group:: An atomic group of NFS filesystems. +* Unix Filesystem:: Native disk filesystem. +* Caching Filesystem:: Caching from remote server filesystem. +* CD-ROM Filesystem:: ISO9660 CD ROM. +* Loopback Filesystem:: Local loopback-mount filesystem. +* Memory/RAM Filesystem:: A memory or RAM-based filesystem. +* Null Filesystem:: 4.4BSD's loopback-mount filesystem. +* Floppy Filesystem:: MS-DOS Floppy filesystem. +* Translucent Filesystem:: The directory merging filesystem. +* Shared Memory+Swap Filesystem:: Sun's tmpfs filesystem. +* User ID Mapping Filesystem:: 4.4BSD's umapfs filesystem. +* Program Filesystem:: Generic Program mounts. +* Symbolic Link Filesystem:: Local link. +* Symbolic Link Filesystem II:: Local link referencing existing filesystem. +* NFS-Link Filesystem:: Link if path exists, NFS otherwise. +* Automount Filesystem:: +* Direct Automount Filesystem:: +* Union Filesystem:: +* Error Filesystem:: +* Top-level Filesystem:: +* Autofs Filesystem:: Sun's kernel-based automounter filesystem. +* Root Filesystem:: +* Inheritance Filesystem:: +@end menu + +@c ---------------------------------------------------------------- +@node Network Filesystem, Network Host Filesystem, Filesystem Types, Filesystem Types +@comment node-name, next, previous, up +@section Network Filesystem (@samp{nfs}) +@cindex NFS +@cindex Mounting an NFS filesystem +@cindex How to mount and NFS filesystem +@cindex nfs, filesystem type +@cindex Filesystem type; nfs + +The @dfn{nfs} (@samp{type:=nfs}) filesystem type provides access to Sun's NFS. + +@noindent +The following options must be specified: + +@table @code +@cindex rhost, mount option +@cindex Mount option; rhost +@item rhost +the remote fileserver. This must be an entry in the hosts database. IP +addresses are not accepted. The default value is taken +from the local host name (@code{$@{host@}}) if no other value is +specified. + +@cindex rfs, mount option +@cindex Mount option; rfs +@item rfs +the remote filesystem. +If no value is specified for this option, an internal default of +@code{$@{path@}} is used. +@end table + +NFS mounts require a two stage process. First, the @dfn{file handle} of +the remote file system must be obtained from the server. Then a mount +system call must be done on the local system. @i{Amd} keeps a cache +of file handles for remote file systems. The cache entries have a +lifetime of a few minutes. + +If a required file handle is not in the cache, @i{Amd} sends a request +to the remote server to obtain it. @i{Amd} @dfn{does not} wait for +a response; it notes that one of the locations needs retrying, but +continues with any remaining locations. When the file handle becomes +available, and assuming none of the other locations was successfully +mounted, @i{Amd} will retry the mount. This mechanism allows several +NFS filesystems to be mounted in parallel. +@c @footnote{The mechanism +@c is general, however NFS is the only filesystem +@c for which the required hooks have been written.} +The first one which responds with a valid file handle will be used. + +@noindent +An NFS entry might be: + +@example +jsp host!=charm;type:=nfs;rhost:=charm;rfs:=/home/charm;sublink:=jsp +@end example + +The mount system call and any unmount attempts are always done +in a new task to avoid the possibility of blocking @i{Amd}. + +@c ---------------------------------------------------------------- +@node Network Host Filesystem, Network Filesystem Group, Network Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Network Host Filesystem (@samp{host}) +@cindex Network host filesystem +@cindex Mounting entire export trees +@cindex How to mount all NFS exported filesystems +@cindex host, filesystem type +@cindex Filesystem type; host + +@c NOTE: the current implementation of the @dfn{host} filesystem type +@c sometimes fails to maintain a consistent view of the remote mount tree. +@c This happens when the mount times out and only some of the remote mounts +@c are successfully unmounted. To prevent this from occurring, use the +@c @samp{nounmount} mount option. + +The @dfn{host} (@samp{type:=host}) filesystem allows access to the entire export tree of an +NFS server. The implementation is layered above the @samp{nfs} +implementation so keep-alives work in the same way. The only option +which needs to be specified is @samp{rhost} which is the name of the +fileserver to mount. + +The @samp{host} filesystem type works by querying the mount daemon on +the given fileserver to obtain its export list. @i{Amd} then obtains +filehandles for each of the exported filesystems. Any errors at this +stage cause that particular filesystem to be ignored. Finally each +filesystem is mounted. Again, errors are logged but ignored. One +common reason for mounts to fail is that the mount point does not exist. +Although @i{Amd} attempts to automatically create the mount point, it +may be on a remote filesystem to which @i{Amd} does not have write +permission. + +When an attempt to unmount a @samp{host} filesystem mount fails, @i{Amd} +remounts any filesystems which had successfully been unmounted. To do +this @i{Amd} queries the mount daemon again and obtains a fresh copy of +the export list. @i{Amd} then tries to mount any exported filesystems +which are not currently mounted. + +Sun's automounter provides a special @samp{-hosts} map. To achieve the +same effect with @i{Amd} requires two steps. First a mount map must +be created as follows: + +@example +* type:=host;rhost:=$@{key@};fs:=$@{autodir@}/$@{rhost@}/root +@end example + +@noindent +and then start @i{Amd} with the following command + +@example +amd /net net.map +@end example + +@noindent +where @samp{net.map} is the name of map described above. Note that the +value of @code{$@{fs@}} is overridden in the map. This is done to avoid +a clash between the mount tree and any other filesystem already mounted +from the same fileserver. + +If different mount options are needed for different hosts then +additional entries can be added to the map, for example + +@example +host2 opts:=ro,nosuid,soft +@end example + +@noindent +would soft mount @samp{host2} read-only. + +@c ---------------------------------------------------------------- +@node Network Filesystem Group, Unix Filesystem, Network Host Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Network Filesystem Group (@samp{nfsx}) +@cindex Network filesystem group +@cindex Atomic NFS mounts +@cindex Mounting an atomic group of NFS filesystems +@cindex How to mount an atomic group of NFS filesystems +@cindex nfsx, filesystem type +@cindex Filesystem type; nfsx + +The @dfn{nfsx} (@samp{type:=nfsx}) filesystem allows a group of filesystems to be mounted +from a single NFS server. The implementation is layered above the +@samp{nfs} implementation so keep-alives work in the same way. + +The options are the same as for the @samp{nfs} filesystem with one +difference. + +@noindent +The following options must be specified: + +@table @code +@item rhost +the remote fileserver. This must be an entry in the hosts database. IP +addresses are not accepted. The default value is taken from the local +host name (@code{$@{host@}}) if no other value is specified. + +@item rfs +as a list of filesystems to mount. The list is in the form of a comma +separated strings. +@end table + +@noindent +For example: + +@example +pub type:=nfsx;rhost:=gould;\ + rfs:=/public,/,graphics,usenet;fs:=$@{autodir@}/$@{rhost@}/root +@end example + +The first string defines the root of the tree, and is applied as a +prefix to the remaining members of the list which define the individual +filesystems. The first string is @emph{not} used as a filesystem name. +A parallel operation is used to determine the local mount points to +ensure a consistent layout of a tree of mounts. + +Here, the @emph{three} filesystems, @samp{/public}, +@samp{/public/graphics} and @samp{/public/usenet}, would be mounted.@refill + +A local mount point, @code{$@{fs@}}, @emph{must} be specified. The +default local mount point will not work correctly in the general case. +A suggestion is to use @samp{fs:=$@{autodir@}/$@{rhost@}/root}.@refill + +@c ---------------------------------------------------------------- +@node Unix Filesystem, Caching Filesystem, Network Filesystem Group, Filesystem Types +@comment node-name, next, previous, up +@section Unix Filesystem (@samp{ufs}, @samp{xfs}, or @samp{efs}) +@cindex Unix filesystem +@cindex UFS +@cindex XFS +@cindex EFS +@cindex Mounting a UFS filesystem +@cindex Mounting a local disk +@cindex How to mount a UFS filesystems +@cindex How to mount a local disk +@cindex Disk filesystems +@cindex ufs, filesystem type +@cindex Filesystem type; ufs +@cindex xfs, filesystem type +@cindex Filesystem type; xfs +@cindex efs, filesystem type +@cindex Filesystem type; efs + +The @dfn{ufs} (@samp{type:=ufs}) filesystem type provides access to the system's standard +disk filesystem---usually a derivative of the Berkeley Fast Filesystem. + +@noindent +The following option must be specified: + +@table @code +@cindex dev, mount option +@cindex Mount option; dev +@item dev +the block special device to be mounted. +@end table + +A UFS entry might be: + +@example +jsp host==charm;type:=ufs;dev:=/dev/sd0d;sublink:=jsp +@end example + +UFS is the default Unix disk-based file system, which Am-utils picks up +during the autoconfiguration phase. Some systems have more than one +type, such as IRIX, that comes with EFS (Extent File System) and XFS +(Extended File System). In those cases, you may explicitly set the file +system type, by using entries such: + +@example +ez1 type:=efs;dev:=/dev/xd0a +ez2 type:=xfs;dev:=/dev/sd3c +@end example + +@c ---------------------------------------------------------------- +@node Caching Filesystem, CD-ROM Filesystem, Unix Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Caching Filesystem (@samp{cachefs}) +@cindex Caching Filesystem +@cindex cachefs, filesystem type +@cindex Filesystem type; cachefs + +The @dfn{cachefs} (@samp{type:=cachefs}) filesystem caches files from +one location onto another, presumably providing faster access. It is +particularly useful to cache from a larger and remote (slower) NFS +partition to a smaller and local (faster) UFS directory. + +@noindent +The following options must be specified: + +@table @code +@cindex cachedir, mount option +@cindex Mount option; cachedir +@item cachedir +the directory where the cache is stored. +@item rfs +the path name to the ``back file system'' to be cached from. +@item fs +the ``front file system'' mount point to the cached files, where @i{Amd} +will set a symbolic link pointing to. +@end table + +A CacheFS entry for, say, the @file{/import} @i{Amd} mount point, might +be: + +@example +copt type:=cachefs;cachedir:=/cache;rfs:=/import/opt;fs:=/n/import/copt +@end example + +Access to the pathname @file{/import/copt} will follow a symbolic link +to @file{/n/import/copt}. The latter is the mount point for a caching +file system, that caches from @file{/import/opt} to @file{/cache}. + +@b{Caveats}: +@enumerate +@item This file system is currently only implemented for Solaris 2.x! +@item Before being used for the first time, the cache directory @i{must} be +initialized with @samp{cfsadmin -c @var{cachedir}}. See the manual page for +@b{cfsadmin}(1M) for more information. +@item The ``back file system'' mounted must be a complete file system, not +a subdirectory thereof; otherwise you will get an error ``Invalid Argument''. +@item If @i{Amd} aborts abnormally, the state of the cache may be +inconsistent, requiring running the command @file{fsck -F cachefs +@var{cachedir}}. Otherwise you will get the error ``No Space Left on Device''. +@end enumerate + +@c ---------------------------------------------------------------- +@node CD-ROM Filesystem, Loopback Filesystem, Caching Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section CD-ROM Filesystem (@samp{cdfs}) +@cindex CD-ROM Filesystem +@cindex cdfs, filesystem type +@cindex Filesystem type; cdfs + +The @dfn{cdfs} (@samp{type:=cdfs}) filesystem mounts a CD-ROM with an +ISO9660 format filesystem on it. + +@noindent +The following option must be specified: + +@table @code +@cindex dev, mount option +@cindex Mount option; dev +@item dev +the block special device to be mounted. +@end table + +A cdfs entry might be: + +@example +cdfs os==sunos4;type:=cdfs;dev:=/dev/sr0 \ + os==sunos5;type:=cdfs;dev:=/dev/dsk/c0t6d0s2 +@end example + +@c ---------------------------------------------------------------- +@node Loopback Filesystem, Memory/RAM Filesystem, CD-ROM Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Loopback Filesystem (@samp{lofs}) +@cindex Loopback Filesystem +@cindex lofs, filesystem type +@cindex Filesystem type; lofs + +The @dfn{lofs} (@samp{type:=lofs}) filesystem is also called the +loopback filesystem. It mounts a local directory on another, thus +providing mount-time binding to another location (unlike symbolic +links). + +The loopback filesystem is particularly useful within the context of a +chroot-ed directory (via @b{chroot}(2)), to provide access to +directories otherwise inaccessible. + +@noindent +The following option must be specified: + +@table @code +@cindex rfs, mount option +@cindex Mount option; rfs +@item rfs +the pathname to be mounted on top of @code{$@{fs@}}. +@end table + +Usually, the FTP server runs in a chroot-ed environment, for security +reasons. In this example, lofs is used to provide a subdirectory within +a user's home directory, also available for public ftp. + +@example +lofs type:=lofs;rfs:=/home/ezk/myftpdir;fs:=/usr/ftp/pub/ezk +@end example + +@c ---------------------------------------------------------------- +@node Memory/RAM Filesystem, Null Filesystem, Loopback Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Memory/RAM Filesystem (@samp{mfs}) +@cindex Memory/RAM Filesystem +@cindex mfs, filesystem type +@cindex Filesystem type; mfs + +The @dfn{mfs} (@samp{type:=mfs}) filesystem is available in 4.4BSD, +Linux, and other systems. It creates a filesystem in a portion of the +system's memory, thus providing very fast file (volatile) access. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node Null Filesystem, Floppy Filesystem, Memory/RAM Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Null Filesystem (@samp{nullfs}) +@cindex Null Filesystem +@cindex nullfs, filesystem type +@cindex Filesystem type; nullfs + +The @dfn{nullfs} (@samp{type:=nullfs}) filesystem is available from 4.4BSD, +and is very similar to the loopback filesystem, @dfn{lofs}. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node Floppy Filesystem, Translucent Filesystem, Null Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Floppy Filesystem (@samp{pcfs}) +@cindex Floppy Filesystem +@cindex pcfs, filesystem type +@cindex Filesystem type; pcfs + +The @dfn{pcfs} (@samp{type:=pcfs}) filesystem mounts a floppy previously +formatted for the MS-DOS format. + +@noindent +The following option must be specified: + +@table @code +@cindex dev, mount option +@cindex Mount option; dev +@item dev +the block special device to be mounted. +@end table + +A pcfs entry might be: + +@example +pcfs os==sunos4;type:=pcfs;dev:=/dev/fd0 \ + os==sunos5;type:=pcfs;dev:=/dev/diskette +@end example + +@c ---------------------------------------------------------------- +@node Translucent Filesystem, Shared Memory+Swap Filesystem, Floppy Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Translucent Filesystem (@samp{tfs}) +@cindex Translucent Filesystem +@cindex tfs, filesystem type +@cindex Filesystem type; tfs + +The @dfn{tfs} (@samp{type:=tfs}) filesystem is an older version of the +4.4BSD @dfn{unionfs}. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node Shared Memory+Swap Filesystem, User ID Mapping Filesystem, Translucent Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Shared Memory+Swap Filesystem (@samp{tmpfs}) +@cindex Shared Memory and Swap Filesystem +@cindex tmpfs, filesystem type +@cindex Filesystem type; tmpfs + +The @dfn{tmpfs} (@samp{type:=tmpfs}) filesystem shares memory between a +the swap device and the rest of the system. It is generally used to +provide a fast access @file{/tmp} directory, one that uses memory that +is otherwise unused. This filesystem is available in SunOS 4.x and 5.x. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node User ID Mapping Filesystem, Program Filesystem, Shared Memory+Swap Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section User ID Mapping Filesystem (@samp{umapfs}) +@cindex User ID Mapping Filesystem +@cindex umapfs, filesystem type +@cindex Filesystem type; umapfs + +The @dfn{umapfs} (@samp{type:=umapfs}) filesystem maps User IDs of file +ownership, and is available from 4.4BSD. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node Program Filesystem, Symbolic Link Filesystem, User ID Mapping Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Program Filesystem (@samp{program}) +@cindex Program filesystem +@cindex Mount a filesystem under program control +@cindex program, filesystem type +@cindex Filesystem type; program + +The @dfn{program} (@samp{type:=program}) filesystem type allows a program to be run whenever a +mount or unmount is required. This allows easy addition of support for +other filesystem types, such as MIT's Remote Virtual Disk (RVD) +which has a programmatic interface via the commands +@samp{rvdmount} and @samp{rvdunmount}. + +@noindent +The following options must be specified: + +@table @code +@cindex mount, mount option +@cindex Mount option; mount +@item mount +the program which will perform the mount. + +@cindex unmount, mount option +@cindex Mount option; unmount +@item unmount +the program which will perform the unmount. +@end table + +The exit code from these two programs is interpreted as a Unix error +code. As usual, exit code zero indicates success. To execute the +program @i{Amd} splits the string on whitespace to create an array of +substrings. Single quotes @samp{'} can be used to quote whitespace +if that is required in an argument. There is no way to escape or change +the quote character. + +To run the program @samp{rvdmount} with a host name and filesystem as +arguments would be specified by @samp{mount:="/etc/rvdmount rvdmount +fserver $@{path@}"}. + +The first element in the array is taken as the pathname of the program +to execute. The other members of the array form the argument vector to +be passed to the program, @dfn{including argument zero}. This means +that the split string must have at least two elements. The program is +directly executed by @i{Amd}, not via a shell. This means that scripts +must begin with a @code{#!} interpreter specification. + +If a filesystem type is to be heavily used, it may be worthwhile adding +a new filesystem type into @i{Amd}, but for most uses the program +filesystem should suffice. + +When the program is run, standard input and standard error are inherited +from the current values used by @i{Amd}. Standard output is a +duplicate of standard error. The value specified with the @code{-l} +command line option has no effect on standard error. + +@c ---------------------------------------------------------------- +@node Symbolic Link Filesystem, Symbolic Link Filesystem II, Program Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Symbolic Link Filesystem (@samp{link}) +@cindex Symbolic link filesystem +@cindex Referencing part of the local name space +@cindex Mounting part of the local name space +@cindex How to reference part of the local name space +@cindex link, filesystem type +@cindex symlink, link filesystem type +@cindex Filesystem type; link + +Each filesystem type creates a symbolic link to point from the volume +name to the physical mount point. The @samp{link} filesystem does the +same without any other side effects. This allows any part of the +machines name space to be accessed via @i{Amd}. + +One common use for the symlink filesystem is @file{/homes} which can be +made to contain an entry for each user which points to their +(auto-mounted) home directory. Although this may seem rather expensive, +it provides a great deal of administrative flexibility. + +@noindent +The following option must be defined: + +@table @code +@item fs +The value of @var{fs} option specifies the destination of the link, as +modified by the @var{sublink} option. If @var{sublink} is non-null, it +is appended to @code{$@{fs@}}@code{/} and the resulting string is used +as the target. +@end table + +The @samp{link} filesystem can be thought of as identical to the +@samp{ufs} filesystem but without actually mounting anything. + +An example entry might be: + +@example +jsp host==charm;type:=link;fs:=/home/charm;sublink:=jsp +@end example +which would return a symbolic link pointing to @file{/home/charm/jsp}. + +@c ---------------------------------------------------------------- +@node Symbolic Link Filesystem II, NFS-Link Filesystem, Symbolic Link Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Symbolic Link Filesystem II (@samp{linkx}) +@cindex Symbolic link filesystem II +@cindex Referencing an existing part of the local name space +@cindex Mounting an existing part of the local name space +@cindex How to reference an existing part of the local name space +@cindex linkx, filesystem type +@cindex symlink, linkx filesystem type +@cindex Filesystem type; linkx + +The @dfn{linkx} (@samp{type:=linkx}) filesystem type is identical to @samp{link} with the +exception that the target of the link must exist. Existence is checked +with the @b{lstat}(2) system call. + +The @samp{linkx} filesystem type is particularly useful for wildcard map +entries. In this case, a list of possible targets can be given and +@i{Amd} will choose the first one which exists on the local machine. + +@c ---------------------------------------------------------------- +@node NFS-Link Filesystem, Automount Filesystem, Symbolic Link Filesystem II, Filesystem Types +@comment node-name, next, previous, up +@section NFS-Link Filesystem (@samp{nfsl}) +@cindex NFS-Link filesystem II +@cindex Referencing an existing part of the name space if target exists +@cindex Mounting a remote part of the name space if target is missing +@cindex Symlink if target exists, NFS otherwise +@cindex nfsl, filesystem type +@cindex symlink, nfsl filesystem type +@cindex Filesystem type; nfsl + +The @dfn{nfsl} (@samp{type:=nfsl}) filesystem type is a combination of two others: +@samp{link} and @samp{nfs}. If the local host name is equal to the +value of @code{$@{rhost@}}, or if the target pathname listed in +@code{$@{fs@}} exists, @samp{nfsl} will behave exactly as +@samp{type:=link}, and refer to the target as a symbolic link. If the +local host name is not equal to the value of @code{$@{rhost@}}, or if +the target of the link does not exist, @i{Amd} will treat it as +@samp{type:=nfs}, and will mount a remote pathname for it. + +The @samp{nfsl} filesystem type is particularly useful as a shorthand +for the more cumbersome and yet one of the most popular @i{Amd} +entries. For example, you can simplify all map entries that look like: + +@example +zing -fs:=/n/shekel/u/zing \ + host!=shekel;type:=nfs;rhost:=shekel;rfs:=$@{fs@} \ + host==shekel;type:=link +@end example + +or + +@example +zing -fs:=/n/shekel/u/zing \ + exists($@{fs@});type:=link \ + !exists($@{fs@});type:=nfs;rhost:=shekel;rfs:=$@{fs@} +@end example + +into a shorter form + +@example +zing type:=nfsl;fs:=/n/shekel/u/zing;rhost:=shekel;rfs:=$@{fs@} +@end example + +Not just does it make the maps smaller and simpler, but it avoids +possible mistakes that often happen when forgetting to set up the two +entries (one for @samp{type:=nfs} and the other for @samp{type:=link}) +necessary to perform transparent mounts of existing or remote mounts. + +@c ---------------------------------------------------------------- +@node Automount Filesystem, Direct Automount Filesystem, NFS-Link Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Automount Filesystem (@samp{auto}) +@cindex Automount filesystem +@cindex Map cache types +@cindex Setting map cache parameters +@cindex How to set map cache parameters +@cindex How to start an indirect automount point +@cindex auto, filesystem type +@cindex Filesystem type; auto +@cindex SIGHUP signal +@cindex Map cache synchronizing +@cindex Synchronizing the map cache +@cindex Map cache options +@cindex Regular expressions in maps + +The @dfn{auto} (@samp{type:=auto}) filesystem type creates a new automount point below an +existing automount point. Top-level automount points appear as system +mount points. An automount mount point can also appear as a +sub-directory of an existing automount point. This allows some +additional structure to be added, for example to mimic the mount tree of +another machine. + +The following options may be specified: + +@table @code +@cindex cache, mount option +@cindex Mount option; cache +@item cache +specifies whether the data in this mount-map should be +cached. The default value is @samp{none}, in which case +no caching is done in order to conserve memory. +However, better performance and reliability can be obtained by caching +some or all of a mount-map. + +If the cache option specifies @samp{all}, +the entire map is enumerated when the mount point is created. + +If the cache option specifies @samp{inc}, caching is done incrementally +as and when data is required. +Some map types do not support cache mode @samp{all}, in which case @samp{inc} +is used whenever @samp{all} is requested. + +Caching can be entirely disabled by using cache mode @samp{none}. + +If the cache option specifies @samp{regexp} then the entire map will be +enumerated and each key will be treated as an egrep-style regular +expression. The order in which a cached map is searched does not +correspond to the ordering in the source map so the regular expressions +should be mutually exclusive to avoid confusion. + +Each mount map type has a default cache type, usually @samp{inc}, which +can be selected by specifying @samp{mapdefault}. + +The cache mode for a mount map can only be selected on the command line. +Starting @i{Amd} with the command: + +@example +amd /homes hesiod.homes -cache:=inc +@end example + +will cause @samp{/homes} to be automounted using the @dfn{Hesiod} name +server with local incremental caching of all successfully resolved names. + +All cached data is forgotten whenever @i{Amd} receives a @samp{SIGHUP} +signal and, if cache @samp{all} mode was selected, the cache will be +reloaded. This can be used to inform @i{Amd} that a map has been +updated. In addition, whenever a cache lookup fails and @i{Amd} needs +to examine a map, the map's modify time is examined. If the cache is +out of date with respect to the map then it is flushed as if a +@samp{SIGHUP} had been received. + +An additional option (@samp{sync}) may be specified to force @i{Amd} to +check the map's modify time whenever a cached entry is being used. For +example, an incremental, synchronized cache would be created by the +following command: + +@example +amd /homes hesiod.homes -cache:=inc,sync +@end example + +@item fs +specifies the name of the mount map to use for the new mount point. + +Arguably this should have been specified with the @code{$@{rfs@}} option but +we are now stuck with it due to historical accident. + +@c %If the string @samp{.} is used then the same map is used; +@c %in addition the lookup prefix is set to the name of the mount point followed +@c %by a slash @samp{/}. +@c %This is the same as specifying @samp{fs:=\$@{map@};pref:=\$@{key@}/}. +@c + +@item pref +alters the name that is looked up in the mount map. If +@code{$@{pref@}}, the @dfn{prefix}, is non-null then it is prepended to +the name requested by the kernel @dfn{before} the map is searched. +@end table + +The server @samp{dylan.doc.ic.ac.uk} has two user disks: +@samp{/dev/dsk/2s0} and @samp{/dev/dsk/5s0}. These are accessed as +@samp{/home/dylan/dk2} and @samp{/home/dylan/dk5} respectively. Since +@samp{/home} is already an automount point, this naming is achieved with +the following map entries:@refill + +@example +dylan type:=auto;fs:=$@{map@};pref:=$@{key@}/ +dylan/dk2 type:=ufs;dev:=/dev/dsk/2s0 +dylan/dk5 type:=ufs;dev:=/dev/dsk/5s0 +@end example + +@c ---------------------------------------------------------------- +@node Direct Automount Filesystem, Union Filesystem, Automount Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Direct Automount Filesystem (@samp{direct}) +@cindex Direct automount filesystem +@cindex How to start a direct automount point +@cindex direct, filesystem type +@cindex Filesystem type; direct + +The @dfn{direct} (@samp{type:=direct}) filesystem is almost identical to the automount +filesystem. Instead of appearing to be a directory of mount points, it +appears as a symbolic link to a mounted filesystem. The mount is done +at the time the link is accessed. @xref{Automount Filesystem} for a +list of required options. + +Direct automount points are created by specifying the @samp{direct} +filesystem type on the command line: + +@example +amd ... /usr/man auto.direct -type:=direct +@end example + +where @samp{auto.direct} would contain an entry such as: + +@example +usr/man -type:=nfs;rfs:=/usr/man \ + rhost:=man-server1 rhost:=man-server2 +@end example + +In this example, @samp{man-server1} and @samp{man-server2} are file +servers which export copies of the manual pages. Note that the key +which is looked up is the name of the automount point without the +leading @samp{/}. + +@c ---------------------------------------------------------------- +@node Union Filesystem, Error Filesystem, Direct Automount Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Union Filesystem (@samp{union}) +@cindex Union filesystem +@cindex union, filesystem type +@cindex Filesystem type; union + +The @dfn{union} (@samp{type:=union}) filesystem type allows the contents of several +directories to be merged and made visible in a single directory. This +can be used to overcome one of the major limitations of the Unix mount +mechanism which only allows complete directories to be mounted. + +For example, supposing @file{/tmp} and @file{/var/tmp} were to be merged +into a new directory called @file{/mtmp}, with files in @file{/var/tmp} +taking precedence. The following command could be used to achieve this +effect: + +@example +amd ... /mtmp union:/tmp:/var/tmp -type:=union +@end example + +Currently, the unioned directories must @emph{not} be automounted. That +would cause a deadlock. This seriously limits the current usefulness of +this filesystem type and the problem will be addressed in a future +release of @i{Amd}. + +Files created in the union directory are actually created in the last +named directory. This is done by creating a wildcard entry which points +to the correct directory. The wildcard entry is visible if the union +directory is listed, so allowing you to see which directory has +priority. + +The files visible in the union directory are computed at the time +@i{Amd} is started, and are not kept up-to-date with respect to the +underlying directories. Similarly, if a link is removed, for example +with the @samp{rm} command, it will be lost forever. + +@c ---------------------------------------------------------------- +@node Error Filesystem, Top-level Filesystem, Union Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Error Filesystem (@samp{error}) +@cindex Error filesystem +@cindex error, filesystem type +@cindex Filesystem type; error + +The @dfn{error} (@samp{type:=error}) filesystem type is used internally as a catch-all in the +case where none of the other filesystems was selected, or some other +error occurred. Lookups and mounts always fail with ``No such file or +directory''. All other operations trivially succeed. + +The error filesystem is not directly accessible. + +@c ---------------------------------------------------------------- +@node Top-level Filesystem, Autofs Filesystem, Error Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Top-level Filesystem (@samp{toplvl}) +@cindex Top level filesystem +@cindex toplvl, filesystem type +@cindex Filesystem type; toplvl + +The @dfn{toplvl} (@samp{type:=toplvl}) filesystems is derived from the @samp{auto} filesystem +and is used to mount the top-level automount nodes. Requests of this +type are automatically generated from the command line arguments and can +also be passed in by using the @code{-M} option of the @dfn{Amq} command. +That option is insecure, and is unavailable unless am-utils was +configured with @samp{--with-amq-mount}. + +@c ---------------------------------------------------------------- +@node Root Filesystem, Inheritance Filesystem, Autofs Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Root Filesystem (@samp{root}) +@cindex Root filesystem +@cindex root, filesystem type +@cindex Filesystem type; root + +The @dfn{root} (@samp{type:=root}) filesystem type acts as an internal +placeholder onto which @i{Amd} can pin @samp{toplvl} mounts. Only one +node of this type need ever exist and one is created automatically +during startup. The effect of having more than one root node is +undefined. + +The root filesystem is not directly accessible. + +@c ---------------------------------------------------------------- +@node Autofs Filesystem, Root Filesystem, Top-level Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Autofs Filesystem (@samp{autofs}) +@cindex Autofs filesystem +@cindex autofs, filesystem type +@cindex Filesystem type; autofs + +The @dfn{autofs} (@samp{type:=autofs}) filesystem uses Sun's kernel-based automounter +supporting filesystem for @i{Amd}'s mount points. Hence it is another +type of top level filesystem. + +The autofs filesystem is not directly accessible from @i{Amd} maps, but +only from the @file{amd.conf} file (@pxref{mount_type Parameter}). + +Note that Autofs support is still very early. See the distribution file +@file{README.autofs} for detail of what works and what does not. + +@c ---------------------------------------------------------------- +@node Inheritance Filesystem, , Root Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Inheritance Filesystem (@samp{inherit}) +@cindex Inheritance filesystem +@cindex Nodes generated on a restart +@cindex inherit, filesystem type +@cindex Filesystem type; inherit + +The @dfn{inheritance} (@samp{type:=inherit}) filesystem is not directly +accessible. Instead, internal mount nodes of this type are +automatically generated when @i{Amd} is started with the @code{-r} option. +At this time the system mount table is scanned to locate any filesystems +which are already mounted. If any reference to these filesystems is +made through @i{Amd} then instead of attempting to mount it, @i{Amd} +simulates the mount and @dfn{inherits} the filesystem. This allows a +new version of @i{Amd} to be installed on a live system simply by +killing the old daemon with @samp{SIGTERM} and starting the new one.@refill + +This filesystem type is not generally visible externally, but it is +possible that the output from @samp{amq -m} may list @samp{inherit} as +the filesystem type. This happens when an inherit operation cannot +be completed for some reason, usually because a fileserver is down. + +@c ################################################################ +@node Amd Configuration File, Run-time Administration, Filesystem Types, Top +@comment node-name, next, previous, up +@chapter Amd Configuration File +@cindex Amd Configuration File +@cindex amd.conf + +The @samp{amd.conf} file is the configuration file for @i{Amd}, as part +of the am-utils suite. This file contains runtime configuration +information for the @i{Amd} automounter program. + +@menu +* File Format:: +* The Global Section:: +* Regular Map Sections:: +* Common Parameters:: +* Global Parameters:: +* Regular Map Parameters:: +* amd.conf Examples:: +@end menu + +@c ================================================================ +@node File Format, The Global Section, Amd Configuration File, Amd Configuration File +@comment node-name, next, previous, up +@section File Format +@cindex amd.conf file format + +The @samp{amd.conf} file consists of sections and parameters. A section +begins with the name of the section in square brackets @samp{[]} and +continues until the next section begins or the end of the file is reached. +Sections contain parameters of the form @samp{name = value}. + +The file is line-based --- that is, each newline-terminated line +represents either a comment, a section name or a parameter. No +line-continuation syntax is available. + +Section names, parameter names and their values are case sensitive. + +Only the first equals sign in a parameter is significant. Whitespace +before or after the first equals sign is discarded. Leading, trailing +and internal whitespace in section and parameter names is irrelevant. +Leading and trailing whitespace in a parameter value is discarded. +Internal whitespace within a parameter value is not allowed, unless the +whole parameter value is quoted with double quotes as in @samp{name = +"some value"}. + +Any line beginning with a pound sign @samp{#} is ignored, as are lines +containing only whitespace. + +The values following the equals sign in parameters are all either a +string (no quotes needed if string does not include spaces) or a +boolean, which may be given as @samp{yes}/@samp{no}. Case is significant in all +values. Some items such as cache timeouts are numeric. + +@c ================================================================ +@node The Global Section, Regular Map Sections, File Format, Amd Configuration File +@comment node-name, next, previous, up +@section The Global Section +@cindex amd.conf global section + +The global section must be specified as @samp{[global]}. Parameters in +this section either apply to @i{Amd} as a whole, or to all other regular map +sections which follow. There should be only one global section defined +in one configuration file. + +It is highly recommended that this section be specified first in the +configuration file. If it is not, then regular map sections which +precede it will not use global values defined later. + +@c ================================================================ +@node Regular Map Sections, Common Parameters, The Global Section, Amd Configuration File +@comment node-name, next, previous, up +@section Regular Map Sections +@cindex amd.conf regular map sections + +Parameters in regular (non-global) sections apply to a single map entry. +For example, if the map section @samp{[/homes]} is defined, then all +parameters following it will be applied to the @file{/homes} +@i{Amd}-managed mount point. + +@c ================================================================ +@node Common Parameters, Global Parameters, Regular Map Sections, Amd Configuration File +@comment node-name, next, previous, up +@section Common Parameters +@cindex amd.conf common parameters + +These parameters can be specified either in the global or a map-specific +section. Entries specified in a map-specific section override the default +value or one defined in the global section. If such a common parameter is +specified only in the global section, it is applicable to all regular map +sections that follow. + +@menu +* browsable_dirs Parameter:: +* map_options Parameter:: +* map_type Parameter:: +* mount_type Parameter:: +* search_path Parameter:: +@end menu + +@c ---------------------------------------------------------------- +@node browsable_dirs Parameter, map_options Parameter, Common Parameters, Common Parameters +@comment node-name, next, previous, up +@subsection @t{browsable_dirs} Parameter +@cindex browsable_dirs Parameter + +(type=string, default=@samp{no}). If @samp{yes}, then @i{Amd}'s top-level +mount points will be browsable to @b{readdir}(3) calls. This means you +could run for example @b{ls}(1) and see what keys are available to mount +in that directory. Not all entries are made visible to @b{readdir}(3): +the @samp{/defaults} entry, wildcard entries, and those with a @file{/} +in them are not included. If you specify @samp{full} to this option, +all but the @samp{/defaults} entry will be visible. Note that if you run +a command which will attempt to @b{stat}(2) the entries, such as often +done by @samp{ls -l} or @samp{ls -F}, @i{Amd} will attempt to mount +@i{every} entry in that map. This is often called a ``mount storm''. + +@c ---------------------------------------------------------------- +@node map_options Parameter, map_type Parameter, browsable_dirs Parameter, Common Parameters +@comment node-name, next, previous, up +@subsection @t{map_options} Parameter +@cindex map_options Parameter + +(type=string, default no options). This option is the same as +specifying map options on the command line to @i{Amd}, such as +@samp{cache:=all}. + +@c ---------------------------------------------------------------- +@node map_type Parameter, mount_type Parameter, map_options Parameter, Common Parameters +@comment node-name, next, previous, up +@subsection @t{map_type} Parameter +@cindex map_type Parameter + +(type=string, default search all map types). If specified, @i{Amd} will +initialize the map only for the type given. This is useful to avoid the +default map search type used by @i{Amd} which takes longer and can have +undesired side-effects such as initializing NIS even if not used. +Possible values are + +@table @samp +@item file +plain files +@item hesiod +Hesiod name service from MIT +@item ldap +Lightweight Directory Access Protocol +@item ndbm +(New) dbm style hash files +@item nis +Network Information Services (version 2) +@item nisplus +Network Information Services Plus (version 3) +@item passwd +local password files +@item union +union maps +@end table + +@c ---------------------------------------------------------------- +@node mount_type Parameter, search_path Parameter, map_type Parameter, Common Parameters +@comment node-name, next, previous, up +@subsection @t{mount_type} Parameter +@cindex mount_type Parameter + +(type=string, default=@samp{nfs}). All @i{Amd} mount types default to NFS. +That is, @i{Amd} is an NFS server on the map mount points, for the local +host it is running on. If @samp{autofs} is specified, @i{Amd} will be +an autofs server for those mount points. + +@c ---------------------------------------------------------------- +@node search_path Parameter, , mount_type Parameter, Common Parameters +@comment node-name, next, previous, up +@subsection @t{search_path} Parameter +@cindex search_path Parameter + +(type=string, default no search path). This provides a +(colon-delimited) search path for file maps. Using a search path, +sites can allow for local map customizations and overrides, and can +distributed maps in several locations as needed. + +@c ================================================================ +@node Global Parameters, Regular Map Parameters, Common Parameters, Amd Configuration File +@comment node-name, next, previous, up +@section Global Parameters +@cindex amd.conf global parameters + +The following parameters are applicable to the @samp{[global]} section only. + +@menu +* arch Parameter:: +* auto_dir Parameter:: +* cache_duration Parameter:: +* cluster Parameter:: +* debug_options Parameter:: +* dismount_interval Parameter:: +* fully_qualified_hosts Parameter:: +* hesiod_base Parameter:: +* karch Parameter:: +* ldap_base Parameter:: +* ldap_cache_maxmem Parameter:: +* ldap_cache_seconds Parameter:: +* ldap_hostports Parameter:: +* local_domain Parameter:: +* log_file Parameter:: +* log_options Parameter:: +* nfs_retransmit_counter Parameter:: +* nfs_retry_interval Parameter:: +* nis_domain Parameter:: +* normalize_hostnames Parameter:: +* os Parameter:: +* osver Parameter:: +* pid_file Parameter:: +* plock Parameter:: +* portmap_program Parameter:: +* print_pid Parameter:: +* print_version Parameter:: +* restart_mounts Parameter:: +* selectors_on_default Parameter:: +* show_statfs_entries Parameter:: +* unmount_on_exit Parameter:: +@end menu + +@c ---------------------------------------------------------------- +@node arch Parameter, auto_dir Parameter, Global Parameters, Global Parameters +@comment node-name, next, previous, up +@subsection @t{arch} Parameter +@cindex arch Parameter + +(type=string, default to compiled in value). Allows you to override the +value of the @i{arch} @i{Amd} variable. + +@c ---------------------------------------------------------------- +@node auto_dir Parameter, cache_duration Parameter, arch Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{auto_dir} Parameter +@cindex auto_dir Parameter + +(type=string, default=@samp{/a}). Same as the @code{-a} option to @i{Amd}. +This sets the private directory where @i{Amd} will create +sub-directories for its real mount points. + +@c ---------------------------------------------------------------- +@node cache_duration Parameter, cluster Parameter, auto_dir Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{cache_duration} Parameter +@cindex cache_duration Parameter + +(type=numeric, default=300). Same as the @code{-c} option to +@i{Amd}. Sets the duration in seconds that looked up map entries remain +in the cache. + +@c ---------------------------------------------------------------- +@node cluster Parameter, debug_options Parameter, cache_duration Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{cluster} Parameter +@cindex cluster Parameter + +(type=string, default no cluster). Same as the @code{-C} option to +@i{Amd}. Specifies the alternate HP-UX cluster to use. + +@c ---------------------------------------------------------------- +@node debug_options Parameter, dismount_interval Parameter, cluster Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{debug_options} Parameter +@cindex debug_options Parameter + +(type=string, default no debug options). Same as the @code{-D} +option to @i{Amd}. Specify any debugging options for @i{Amd}. Works +only if am-utils was configured for debugging using the +@code{--enable-debug} option. The @samp{mem} option alone can be turned +on via @code{--enable-debug=mem}. Otherwise debugging options are +ignored. Options are comma delimited, and can be preceded by the string +@samp{no} to negate their meaning. You can get the list of supported +debugging options by running @code{amd -v}. Possible values are: + +@table @samp +@item all +all options +@item amq +register for amq +@item daemon +enter daemon mode +@item fork +fork server +@item full +program trace +@item mem +trace memory allocations +@item mtab +use local @file{./mtab} file +@item str +debug string munging +@item test +full debug but no daemon +@item trace +protocol trace +@end table + +@c ---------------------------------------------------------------- +@node dismount_interval Parameter, fully_qualified_hosts Parameter, debug_options Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{dismount_interval} Parameter +@cindex dismount_interval Parameter + +(type=numeric, default=120). Same as the @code{-w} option to +@i{Amd}. Specify in seconds, the time between attempts to dismount file +systems that have exceeded their cached times. + +@c ---------------------------------------------------------------- +@node fully_qualified_hosts Parameter, hesiod_base Parameter, dismount_interval Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{fully_qualified_hosts} Parameter +@cindex fully_qualified_hosts Parameter + +(type=string, default=@samp{no}). If @samp{yes}, @i{Amd} will perform RPC +authentication using fully-qualified host names. This is necessary for +some systems, and especially when performing cross-domain mounting. For +this function to work, the @i{Amd} variable @samp{$@{hostd@}} is used, +requiring that @samp{$@{domain@}} not be null. + +@c ---------------------------------------------------------------- +@node hesiod_base Parameter, karch Parameter, fully_qualified_hosts Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{hesiod_base} Parameter +@cindex hesiod_base Parameter + +(type=string, default=@samp{automount}). Specify the base name for +hesiod maps. + +@c ---------------------------------------------------------------- +@node karch Parameter, ldap_base Parameter, hesiod_base Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{karch} Parameter +@cindex karch Parameter + +(type=string, default to karch of the system). Same as the @code{-k} +option to @i{Amd}. Allows you to override the kernel-architecture of +your system. Useful for example on Sun (Sparc) machines, where you can +build one @i{Amd} binary, and run it on multiple machines, yet you want +each one to get the correct @i{karch} variable set (for example, sun4c, +sun4m, sun4u, etc.) Note that if not specified, @i{Amd} will use +@b{uname}(2) to figure out the kernel architecture of the machine. + +@c ---------------------------------------------------------------- +@node ldap_base Parameter, ldap_cache_maxmem Parameter, karch Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{ldap_base} Parameter +@cindex ldap_base Parameter + +(type=string, default not set). Specify the base name for +LDAP. + +@c ---------------------------------------------------------------- +@node ldap_cache_maxmem Parameter, ldap_cache_seconds Parameter, ldap_base Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{ldap_cache_maxmem} Parameter +@cindex ldap_cache_maxmem Parameter + +(type=numeric, default=131072). Specify the maximum memory @i{Amd} +should use to cache LDAP entries. + +@c ---------------------------------------------------------------- +@node ldap_cache_seconds Parameter, ldap_hostports Parameter, ldap_cache_maxmem Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{ldap_cache_seconds} Parameter +@cindex ldap_cache_seconds Parameter + +(type=numeric, default=0). Specify the number of seconds to keep +entries in the cache. + +@c ---------------------------------------------------------------- +@node ldap_hostports Parameter, local_domain Parameter, ldap_cache_seconds Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{ldap_hostports} Parameter +@cindex ldap_hostports Parameter + +(type=string, default not set). Specify +LDAP-specific values such as country and organization. + +@c ---------------------------------------------------------------- +@node local_domain Parameter, log_file Parameter, ldap_hostports Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{local_domain} Parameter +@cindex local_domain Parameter + +(type=string, default no sub-domain). Same as the @code{-d} option +to @i{Amd}. Specify the local domain name. If this option is not given +the domain name is determined from the hostname, by removing the first +component of the fully-qualified host name. + +@c ---------------------------------------------------------------- +@node log_file Parameter, log_options Parameter, local_domain Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{log_file} Parameter +@cindex log_file Parameter + +(type=string, default=@samp{stderr}). Same as the @code{-l} option to +@i{Amd}. Specify a file name to log @i{Amd} events to. +If the string @samp{/dev/stderr} is specified, +@i{Amd} will send its events to the standard error file descriptor. + +If the string @samp{syslog} is given, @i{Amd} will record its events +with the system logger @b{syslogd}(8). If your system supports syslog +facilities, then the default facility used is @samp{LOG_DAEMON}. + +When using syslog, if you wish to change the facility, append its name +to the option name, delimited by a single colon. For example, if it is +the string @samp{syslog:local7} then @i{Amd} will log messages via +@b{syslog}(3) using the @samp{LOG_LOCAL7} facility. If the facility +name specified is not recognized, @i{Amd} will default to @samp{LOG_DAEMON}. +Note: while you can use any syslog facility available on your system, it +is generally a bad idea to use those reserved for other services such as +@samp{kern}, @samp{lpr}, @samp{cron}, etc. + +@c ---------------------------------------------------------------- +@node log_options Parameter, nfs_retransmit_counter Parameter, log_file Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{log_options} Parameter +@cindex log_options Parameter + +(type=string, default no logging options). Same as the @code{-x} +option to @i{Amd}. Specify any logging options for @i{Amd}. Options +are comma delimited, and can be preceded by the string @samp{no} to +negate their meaning. The @samp{debug} logging option is only available +if am-utils was configured with @code{--enable-debug}. You can get the +list of supported debugging options by running @code{amd -v}. Possible +values are: + +@table @samp +@item all +all messages +@item debug +debug messages +@item error +non-fatal system errors +@item fatal +fatal errors +@item info +information +@item map +map errors +@item stats +additional statistical information +@item user +non-fatal user errors +@item warn +warnings +@item warning +warnings +@end table + +@c ---------------------------------------------------------------- +@node nfs_retransmit_counter Parameter, nfs_retry_interval Parameter, log_options Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{nfs_retransmit_counter} Parameter +@cindex nfs_retransmit_counter Parameter + +(type=numeric, default=110). Same as the @i{counter} part of the +@code{-t} @i{interval.counter} option to @i{Amd}. Specifies the +retransmit counter's value in @emph{tenths} of seconds. + +@c ---------------------------------------------------------------- +@node nfs_retry_interval Parameter, nis_domain Parameter, nfs_retransmit_counter Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{nfs_retry_interval} Parameter +@cindex nfs_retry_interval Parameter + +(type=numeric, default=8). Same as the @i{interval} part of the +@code{-t} @i{interval.counter} option to @i{Amd}. Specifies the +interval in @emph{tenths} of seconds, between NFS/RPC/UDP retries. + +@c ---------------------------------------------------------------- +@node nis_domain Parameter, normalize_hostnames Parameter, nfs_retry_interval Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{nis_domain} Parameter +@cindex nis_domain Parameter + +(type=string, default to local NIS domain name). Same as the +@code{-y} option to @i{Amd}. Specify an alternative NIS domain from +which to fetch the NIS maps. The default is the system domain name. +This option is ignored if NIS support is not available. + +@c ---------------------------------------------------------------- +@node normalize_hostnames Parameter, os Parameter, nis_domain Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{normalize_hostnames} Parameter +@cindex normalize_hostnames Parameter + +(type=boolean, default=@samp{no}). Same as the @code{-n} option to @i{Amd}. +If @samp{yes}, then the name referred to by @code{$@{rhost@}} is normalized +relative to the host database before being used. The effect is to +translate aliases into ``official'' names. + +@c ---------------------------------------------------------------- +@node os Parameter, osver Parameter, normalize_hostnames Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{os} Parameter +@cindex os Parameter + +(type=string, default to compiled in value). Same as the @code{-O} +option to @i{Amd}. Allows you to override the compiled-in name of the +operating system. Useful when the built-in name is not desired for +backward compatibility reasons. For example, if the built-in name is +@samp{sunos5}, you can override it to @samp{sos5}, and use older maps +which were written with the latter in mind. + +@c ---------------------------------------------------------------- +@node osver Parameter, pid_file Parameter, os Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{osver} Parameter +@cindex osver Parameter + +(type=string, default to compiled in value). Same as the @code{-o} +option to @i{Amd}. Allows you to override the compiled-in version +number of the operating system. Useful when the built-in version is not +desired for backward compatibility reasons. For example, if the build +in version is @samp{2.5.1}, you can override it to @samp{5.5.1}, and use +older maps that were written with the latter in mind. + +@c ---------------------------------------------------------------- +@node pid_file Parameter, plock Parameter, osver Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{pid_file} Parameter +@cindex pid_file Parameter + +(type=string, default=@samp{/dev/stdout}). Specify a file to store the process +ID of the running daemon into. If not specified, @i{Amd} will print its +process id onto the standard output. Useful for killing @i{Amd} after +it had run. Note that the PID of a running @i{Amd} can also be +retrieved via @i{Amq} (@pxref{Amq -p option}). + +This file is used only if the @samp{print_pid} option is on +(@pxref{print_pid Parameter}). + +@c ---------------------------------------------------------------- +@node plock Parameter, portmap_program Parameter, pid_file Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{plock} Parameter +@cindex plock Parameter + +(type=boolean, default=@samp{yes}). Same as the @code{-S} option to @i{Amd}. +If @samp{yes}, lock the running executable pages of @i{Amd} into memory. +To improve @i{Amd}'s performance, systems that support the @b{plock}(3) +call can lock the @i{Amd} process into memory. This way there is less +chance the operating system will schedule, page out, and swap the +@i{Amd} process as needed. This improves @i{Amd}'s performance, at the +cost of reserving the memory used by the @i{Amd} process (making it +unavailable for other processes). + +@c ---------------------------------------------------------------- +@node portmap_program Parameter, print_pid Parameter, plock Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{portmap_program} Parameter +@cindex portmap_program Parameter + +(type=numeric, default=300019). Specify an alternate Port-mapper RPC +program number, other than the official number. This is useful when +running multiple @i{Amd} processes. For example, you can run another +@i{Amd} in ``test'' mode, without affecting the primary @i{Amd} process +in any way. For safety reasons, the alternate program numbers that can +be specified must be in the range 300019-300029, inclusive. @i{Amq} has +an option @code{-P} which can be used to specify an alternate program +number of an @i{Amd} to contact. In this way, amq can fully control any +number of @i{Amd} processes running on the same host. + +@c ---------------------------------------------------------------- +@node print_pid Parameter, print_version Parameter, portmap_program Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{print_pid} Parameter +@cindex print_pid Parameter + +(type=boolean, default=@samp{no}). Same as the @code{-p} option to @i{Amd}. +If @samp{yes}, @i{Amd} will print its process ID upon starting. + +@c ---------------------------------------------------------------- +@node print_version Parameter, restart_mounts Parameter, print_pid Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{print_version} Parameter +@cindex print_version Parameter + +(type=boolean, default=@samp{no}). Same as the @code{-v} option to @i{Amd}, +but the version prints and @i{Amd} continues to run. If @samp{yes}, @i{Amd} +will print its version information string, which includes some +configuration and compilation values. + +@c ---------------------------------------------------------------- +@node restart_mounts Parameter, selectors_on_default Parameter, print_version Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{restart_mounts} Parameter +@cindex restart_mounts Parameter + +(type=boolean, default=@samp{no}). Same as the @code{-r} option to @i{Amd}. +If @samp{yes} @i{Amd} will scan the mount table to determine which file +systems are currently mounted. Whenever one of these would have been +auto-mounted, @i{Amd} inherits it. + +@c ---------------------------------------------------------------- +@node selectors_on_default Parameter, show_statfs_entries Parameter, restart_mounts Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{selectors_on_default} Parameter +@cindex selectors_on_default Parameter + +(type=boolean, default=@samp{no}). If @samp{yes}, then the @samp{/defaults} entry of +maps will be looked for and any selectors processed before setting defaults +for all other keys in that map. Useful when you want to set different +options for a complete map based on some parameters. For example, you +may want to better the NFS performance over slow slip-based networks as +follows: + +@example +/defaults \ + wire==slip-net;opts:=intr,rsize=1024,wsize=1024 \ + wire!=slip-net;opts:=intr,rsize=8192,wsize=8192 +@end example + +@c ---------------------------------------------------------------- +@node show_statfs_entries Parameter, unmount_on_exit Parameter , selectors_on_default Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{show_statfs_entries} Parameter +@cindex show_statfs_entries Parameter + +(type=boolean), default=@samp{no}). If @samp{yes}, then all maps which are +browsable will also show the number of entries (keys) they have when +@b{df}(1) runs. (This is accomplished by returning non-zero values to +the @b{statfs}(2) system call). + +@c ---------------------------------------------------------------- +@node unmount_on_exit Parameter, , show_statfs_entries Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{unmount_on_exit} Parameter +@cindex unmount_on_exit Parameter + +(type=boolean), default=@samp{no}). If @samp{yes}, then @i{Amd} will attempt +to unmount all file systems which it knows about. Normally it leaves +all (esp. NFS) mounted file systems intact. Note that @i{Amd} does not +know about file systems mounted before it starts up, unless the +@samp{restart_mounts} option is used (@pxref{restart_mounts Parameter}). + +@c ================================================================ +@node Regular Map Parameters, amd.conf Examples, Global Parameters, Amd Configuration File +@comment node-name, next, previous, up +@section Regular Map Parameters +@cindex amd.conf regular map parameters + +The following parameters are applicable only to regular map sections. + +@menu +* map_name Parameter:: +* tag Parameter:: +@end menu + +@c ---------------------------------------------------------------- +@node map_name Parameter, tag Parameter, Regular Map Parameters, Regular Map Parameters +@comment node-name, next, previous, up +@subsection map_name Parameter +@cindex map_name Parameter + +(type=string, must be specified). Name of the map where the keys are +located. + +@c ---------------------------------------------------------------- +@node tag Parameter, , map_name Parameter, Regular Map Parameters +@comment node-name, next, previous, up +@subsection tag Parameter +@cindex tag Parameter + +(type=string, default no tag). Each map entry in the configuration file +can be tagged. If no tag is specified, that map section will always be +processed by @i{Amd}. If it is specified, then @i{Amd} will process the map +if the @code{-T} option was given to @i{Amd}, and the value given to that +command-line option matches that in the map section. + +@c ================================================================ +@node amd.conf Examples, , Regular Map Parameters, Amd Configuration File +@comment node-name, next, previous, up +@section amd.conf Examples +@cindex amd.conf examples + +The following is the actual @code{amd.conf} file I use at the +Computer Science Department of Columbia University. + +@example +# GLOBAL OPTIONS SECTION +[ global ] +normalize_hostnames = no +print_pid = no +#pid_file = /var/run/amd.pid +restart_mounts = yes +#unmount_on_exit = yes +auto_dir = /n +log_file = /var/log/amd +log_options = all +#debug_options = all +plock = no +selectors_on_default = yes +# config.guess picks up "sunos5" and I don't want to edit my maps yet +os = sos5 +# if you print_version after setting up "os", it will show it. +print_version = no +map_type = file +search_path = /etc/amdmaps:/usr/lib/amd:/usr/local/AMD/lib +browsable_dirs = yes +fully_qualified_hosts = no + +# DEFINE AN AMD MOUNT POINT +[ /u ] +map_name = amd.u + +[ /proj ] +map_name = amd.proj + +[ /src ] +map_name = amd.src + +[ /misc ] +map_name = amd.misc + +[ /import ] +map_name = amd.import + +[ /tftpboot/.amd ] +tag = tftpboot +map_name = amd.tftpboot +@end example + +@c ################################################################ +@node Run-time Administration, FSinfo, Amd Configuration File, Top +@comment node-name, next, previous, up +@chapter Run-time Administration +@cindex Run-time administration +@cindex Amq command + +@menu +* Starting Amd:: +* Stopping Amd:: +* Restarting Amd:: +* Controlling Amd:: +@end menu + +@node Starting Amd, Stopping Amd, Run-time Administration, Run-time Administration +@comment node-name, next, previous, up +@section Starting @i{Amd} +@cindex Starting Amd +@cindex Additions to /etc/rc.local +@cindex /etc/rc.local additions +@cindex ctl-amd + +@i{Amd} is best started from @samp{/etc/rc.local} on BSD systems, or +from the appropriate start-level script in @samp{/etc/init.d} on System V +systems. + +@example +if [ -f /usr/local/sbin/ctl-amd ]; then + /usr/local/sbin/ctl-amd start; (echo -n ' amd') > /dev/console +fi +@end example + +@noindent +The shell script, @samp{ctl-amd} is used to start, stop, or restart +@i{Amd}. It is a relatively generic script. All options you want to +set should not be made in this script, but rather updated in the +@file{amd.conf} file. @xref{Amd Configuration File}. + +If you do not wish to use an @i{Amd} configuration file, you may start +@i{Amd} manually. For example, getting the map entries via NIS: + +@example +amd -r -l /var/log/amd `ypcat -k auto.master` +@end example + +@node Stopping Amd, Restarting Amd, Starting Amd, Run-time Administration +@comment node-name, next, previous, up +@section Stopping @i{Amd} +@cindex Stopping Amd +@cindex SIGTERM signal +@cindex SIGINT signal + +@i{Amd} stops in response to two signals. + +@table @samp +@item SIGTERM +causes the top-level automount points to be unmounted and then @i{Amd} +to exit. Any automounted filesystems are left mounted. They can be +recovered by restarting @i{Amd} with the @code{-r} command line option.@refill + +@item SIGINT +causes @i{Amd} to attempt to unmount any filesystems which it has +automounted, in addition to the actions of @samp{SIGTERM}. This signal +is primarily used for debugging.@refill +@end table + +Actions taken for other signals are undefined. + +The easiest and safest way to stop @i{Amd}, without having to find its +process ID by hand, is to use the @file{ctl-amd} script, as with: + +@example +ctl-amd stop +@end example + +@node Restarting Amd, Controlling Amd, Stopping Amd, Run-time Administration +@comment node-name, next, previous, up +@section Restarting @i{Amd} +@cindex Restarting Amd +@cindex Killing and starting Amd + +Before @i{Amd} can be started, it is vital to ensure that no other +@i{Amd} processes are managing any of the mount points, and that the +previous process(es) have terminated cleanly. When a terminating signal +is set to @i{Amd}, the automounter does @emph{not} terminate right then. +Rather, it starts by unmounting all of its managed mount mounts in the +background, and then terminates. It usually takes a few seconds for +this process to happen, but it can take an arbitrarily longer time. If +two or more @i{Amd} processes attempt to manage the same mount point, it +usually will result in a system lockup. + +The easiest and safest way to restart @i{Amd}, without having to find +its process ID by hand, sending it the @samp{SIGTERM} signal, waiting for @i{Amd} +to die cleanly, and verifying so, is to use the @file{ctl-amd} script, +as with: + +@example +ctl-amd restart +@end example + +The script will locate the process ID of @i{Amd}, kill it, and wait for +it to die cleanly before starting a new instance of the automounter. +@file{ctl-amd} will wait for a total of 30 seconds for @i{Amd} to die, +and will check once every 5 seconds if it had. + +@node Controlling Amd, , Restarting Amd, Run-time Administration +@comment node-name, next, previous, up +@section Controlling @i{Amd} +@cindex Controlling Amd +@cindex Discovering what is going on at run-time +@cindex Listing currently mounted filesystems + +It is sometimes desirable or necessary to exercise external control +over some of @i{Amd}'s internal state. To support this requirement, +@i{Amd} implements an RPC interface which is used by the @dfn{Amq} program. +A variety of information is available. + +@i{Amq} generally applies an operation, specified by a single letter option, +to a list of mount points. The default operation is to obtain statistics +about each mount point. This is similar to the output shown above +but includes information about the number and type of accesses to each +mount point. + +@menu +* Amq default:: Default command behavior. +* Amq -f option:: Flushing the map cache. +* Amq -h option:: Controlling a non-local host. +* Amq -l option:: Controlling the log file. +* Amq -m option:: Obtaining mount statistics. +* Amq -M-option:: Mounting a volume. +* Amq -p option:: Getting Amd's process ID. +* Amq -P-option:: Contacting alternate Amd processes. +* Amq -s option:: Obtaining global statistics. +* Amq -T option:: Use TCP transport. +* Amq -U-option:: Use UDP transport. +* Amq -u option:: Forcing volumes to time out. +* Amq -v option:: Version information. +* Other Amq options:: Three other special options. +@end menu + +@c ---------------------------------------------------------------- +@node Amq default, Amq -f option, Controlling Amd, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} default information + +With no arguments, @dfn{Amq} obtains a brief list of all existing +mounts created by @i{Amd}. This is different from the list displayed by +@b{df}(1) since the latter only includes system mount points. + +@noindent +The output from this option includes the following information: + +@itemize @bullet +@item +the automount point, +@item +the filesystem type, +@item +the mount map or mount information, +@item +the internal, or system mount point. +@end itemize + +@noindent +For example: + +@example +/ root "root" sky:(pid75) +/homes toplvl /usr/local/etc/amd.homes /homes +/home toplvl /usr/local/etc/amd.home /home +/homes/jsp nfs charm:/home/charm /a/charm/home/charm/jsp +/homes/phjk nfs toytown:/home/toytown /a/toytown/home/toytown/ai/phjk +@end example + +@noindent +If an argument is given then statistics for that volume name will +be output. For example: + +@example +What Uid Getattr Lookup RdDir RdLnk Statfs Mounted@@ +/homes 0 1196 512 22 0 30 90/09/14 12:32:55 +/homes/jsp 0 0 0 0 1180 0 90/10/13 12:56:58 +@end example + +@table @code +@item What +the volume name. + +@item Uid +ignored. + +@item Getattr +the count of NFS @dfn{getattr} requests on this node. This should only be +non-zero for directory nodes. + +@item Lookup +the count of NFS @dfn{lookup} requests on this node. This should only be +non-zero for directory nodes. + +@item RdDir +the count of NFS @dfn{readdir} requests on this node. This should only +be non-zero for directory nodes. + +@item RdLnk +the count of NFS @dfn{readlink} requests on this node. This should be +zero for directory nodes. + +@item Statfs +the count of NFS @dfn{statfs} requests on this node. This should only +be non-zero for top-level automount points. + +@item Mounted@@ +the date and time the volume name was first referenced. +@end table + +@c ---------------------------------------------------------------- +@node Amq -f option, Amq -h option, Amq default, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-f} option +@cindex Flushing the map cache +@cindex Map cache, flushing + +The @code{-f} option causes @i{Amd} to flush the internal mount map cache. +This is useful for example in Hesiod maps since @i{Amd} will not +automatically notice when they have been updated. The map cache can +also be synchronized with the map source by using the @samp{sync} option +(@pxref{Automount Filesystem}).@refill + +@c ---------------------------------------------------------------- +@node Amq -l option, Amq -m option, Amq -h option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-l} option +@cindex Resetting the Amd log file +@cindex Setting the Amd log file via Amq +@cindex Log file, resetting + +Tell @i{Amd} to use @i{log_file} as the log file name. For security +reasons, this @emph{must} be the same log file which @i{Amd} used when +started. This option is therefore only useful to refresh @i{Amd}'s open +file handle on the log file, so that it can be rotated and compressed +via daily cron jobs. + +@c ---------------------------------------------------------------- +@node Amq -h option, Amq -l option, Amq -f option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-h} option +@cindex Querying an alternate host + +By default the local host is used. In an HP-UX cluster the root server +is used since that is the only place in the cluster where @i{Amd} will +be running. To query @i{Amd} on another host the @code{-h} option should +be used. + +@c ---------------------------------------------------------------- +@node Amq -m option, Amq -M-option, Amq -l option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-m} option + +The @code{-m} option displays similar information about mounted +filesystems, rather than automount points. The output includes the +following information: + +@itemize @bullet +@item +the mount information, +@item +the mount point, +@item +the filesystem type, +@item +the number of references to this filesystem, +@item +the server hostname, +@item +the state of the file server, +@item +any error which has occurred. +@end itemize + +For example: + +@example +"root" truth:(pid602) root 1 localhost is up +hesiod.home /home toplvl 1 localhost is up +hesiod.vol /vol toplvl 1 localhost is up +hesiod.homes /homes toplvl 1 localhost is up +amy:/home/amy /a/amy/home/amy nfs 5 amy is up +swan:/home/swan /a/swan/home/swan nfs 0 swan is up (Permission denied) +ex:/home/ex /a/ex/home/ex nfs 0 ex is down +@end example + +When the reference count is zero the filesystem is not mounted but +the mount point and server information is still being maintained +by @i{Amd}. + +@c ---------------------------------------------------------------- +@node Amq -M-option, Amq -p option, Amq -m option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-M} option + +The @code{-M} option passes a new map entry to @i{Amd} and waits for it to +be evaluated, possibly causing a mount. For example, the following +command would cause @samp{/home/toytown} on host @samp{toytown} to be +mounted locally on @samp{/mnt/toytown}. + +@example +amq -M '/mnt/toytown type:=nfs;rfs:=/home/toytown;rhost:=toytown;fs:=$@{key@}' +@end example + +@i{Amd} applies some simple security checks before allowing this +operation. The check tests whether the incoming request is from a +privileged UDP port on the local machine. ``Permission denied'' is +returned if the check fails. + +This option is very insecure as it is vulnerable to attacks such as IP +Spoofing. In other words, it is relatively easy for an attacker who +really wants to, to make your @i{Amd} process mount any filesystem from +the Internet! Therefore, the @emph{complete} code which supports the +@code{-M} option in @i{Amd} and @i{Amq} is turned off by default. To turn +it on, you have to reconfigure am-utils with @code{configure +--enable-amq-mount}. Think twice before doing so, and use this option +only if you absolutely need to. + +A future release of @i{Amd} will include code to allow the @b{mount}(8) +command to mount automount points: + +@example +mount -t amd /vol hesiod.vol +@end example + +This will then allow @i{Amd} to be controlled from the standard system +filesystem mount list. + +@c ---------------------------------------------------------------- +@node Amq -p option, Amq -P-option, Amq -M-option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-p} option +@cindex Process ID; Amd +@cindex Amd's process ID +@cindex Amd's PID +@cindex PID; Amd + +Return the process ID of the remote or locally running @i{Amd}. Useful +when you need to send a signal to the local @i{Amd} process, and would +rather not have to search through the process table. This option is +used in the @file{ctl-amd} script. + +@c ---------------------------------------------------------------- +@node Amq -P-option, Amq -s option, Amq -p option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-P} option +@cindex Multiple Amd processes +@cindex Running multiple Amd +@cindex Debugging a new Amd configuration +@cindex RPC Program numbers; Amd + +Contact an alternate running @i{Amd} that had registered itself on a +different RPC @var{program_number} and apply all other operations to +that instance of the automounter. This is useful when you run multiple +copies of @i{Amd}, and need to manage each one separately. If not +specified, @i{Amq} will use the default program number for @i{Amd}, 300019. +For security reasons, the only alternate program numbers @i{Amd} can use +range from 300019 to 300029, inclusive. + +For example, to kill an alternate running @i{Amd}: + +@example +kill `amq -p -P 300020` +@end example + +@c ---------------------------------------------------------------- +@node Amq -s option, Amq -T option, Amq -P-option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-s} option +@cindex Global statistics +@cindex Statistics + +The @code{-s} option displays global statistics. If any other options are specified +or any filesystems named then this option is ignored. For example: + +@example +requests stale mount mount unmount +deferred fhandles ok failed failed +1054 1 487 290 7017 +@end example + +@table @samp +@item Deferred requests +are those for which an immediate reply could not be constructed. For +example, this would happen if a background mount was required. + +@item Stale filehandles +counts the number of times the kernel passes a stale filehandle to @i{Amd}. +Large numbers indicate problems. + +@item Mount ok +counts the number of automounts which were successful. + +@item Mount failed +counts the number of automounts which failed. + +@item Unmount failed +counts the number of times a filesystem could not be unmounted. Very +large numbers here indicate that the time between unmount attempts +should be increased. +@end table + +@c ---------------------------------------------------------------- +@node Amq -T option, Amq -U-option, Amq -s option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-T} option +@cindex Forcing Amq to use a TCP transport +@cindex TCP; using with Amq + +The @code{-T} option causes the @i{Amq} to contact @i{Amd} using the TCP +transport only (connection oriented). Normally, @i{Amq} will use TCP +first, and if that failed, will try UDP. + +@c ---------------------------------------------------------------- +@node Amq -U-option, Amq -u option, Amq -T option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-U} option +@cindex Forcing Amq to use a UDP transport +@cindex UDP; using with Amq + +The @code{-U} option causes the @i{Amq} to contact @i{Amd} using the UDP +transport only (connectionless). Normally, @i{Amq} will use TCP first, +and if that failed, will try UDP. + +@c ---------------------------------------------------------------- +@node Amq -u option, Amq -v option, Amq -U-option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-u} option +@cindex Forcing filesystem to time out +@cindex Unmounting a filesystem + +The @code{-u} option causes the time-to-live interval of the named mount +points to be expired, thus causing an unmount attempt. This is the only +safe way to unmount an automounted filesystem. It is not possible to +unmount a filesystem which has been mounted with the @samp{nounmount} +flag. + +@c The @code{-H} option informs @i{Amd} that the specified mount point has hung - +@c as if its keepalive timer had expired. + +@c ---------------------------------------------------------------- +@node Amq -v option, Other Amq options, Amq -u option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-v} option +@cindex Version information at run-time + +The @code{-v} option displays the version of @i{Amd} in a similar way to +@i{Amd}'s @code{-v} option. + +@c ---------------------------------------------------------------- +@node Other Amq options, , Amq -v option, Controlling Amd +@comment node-name, next, previous, up +@subsection Other @i{Amq} options +@cindex Logging options via Amq +@cindex Debugging options via Amq + +Two other operations are implemented. These modify the state of @i{Amd} +as a whole, rather than any particular filesystem. The @code{-x} and +@code{-D} options have exactly the same effect as @i{Amd}'s corresponding +command line options. + +When @i{Amd} receives a @code{-x} flag it limits the log options being +modified to those which were not enabled at startup. This prevents a +user turning @emph{off} any logging option which was specified at +startup, though any which have been turned on since then can still be +turned off. The @code{-D} option has a similar behavior. + +@c ################################################################ +@node FSinfo, Hlfsd, Run-time Administration, Top +@comment node-name, next, previous, up +@chapter FSinfo +@cindex FSinfo +@cindex Filesystem info package + +XXX: this chapter should be reviewed by someone knowledgeable with +fsinfo. + +@menu +* FSinfo Overview:: Introduction to FSinfo. +* Using FSinfo:: Basic concepts. +* FSinfo Grammar:: Language syntax, semantics and examples. +* FSinfo host definitions:: Defining a new host. +* FSinfo host attributes:: Definable host attributes. +* FSinfo filesystems:: Defining locally attached filesystems. +* FSinfo static mounts:: Defining additional static mounts. +* FSinfo automount definitions:: +* FSinfo Command Line Options:: +* FSinfo errors:: +@end menu + +@node FSinfo Overview, Using FSinfo, FSinfo, FSinfo +@comment node-name, next, previous, up +@section @i{FSinfo} overview +@cindex FSinfo overview + +@i{FSinfo} is a filesystem management tool. It has been designed to +work with @i{Amd} to help system administrators keep track of the ever +increasing filesystem namespace under their control. + +The purpose of @i{FSinfo} is to generate all the important standard +filesystem data files from a single set of input data. Starting with a +single data source guarantees that all the generated files are +self-consistent. One of the possible output data formats is a set of +@i{Amd} maps which can be used amongst the set of hosts described in the +input data. + +@i{FSinfo} implements a declarative language. This language is +specifically designed for describing filesystem namespace and physical +layouts. The basic declaration defines a mounted filesystem including +its device name, mount point, and all the volumes and access +permissions. @i{FSinfo} reads this information and builds an internal +map of the entire network of hosts. Using this map, many different data +formats can be produced including @file{/etc/fstab}, +@file{/etc/exports}, @i{Amd} mount maps and +@file{/etc/bootparams}.@refill + +@node Using FSinfo, FSinfo Grammar, FSinfo Overview, FSinfo +@comment node-name, next, previous, up +@section Using @i{FSinfo} +@cindex Using FSinfo + +The basic strategy when using @i{FSinfo} is to gather all the +information about all disks on all machines into one set of +declarations. For each machine being managed, the following data is +required: + +@itemize @bullet +@item +Hostname +@item +List of all filesystems and, optionally, their mount points. +@item +Names of volumes stored on each filesystem. +@item +NFS export information for each volume. +@item +The list of static filesystem mounts. +@end itemize + +The following information can also be entered into the same +configuration files so that all data can be kept in one place. + +@itemize @bullet +@item +List of network interfaces +@item +IP address of each interface +@item +Hardware address of each interface +@item +Dumpset to which each filesystem belongs +@item +and more @dots{} +@end itemize + +To generate @i{Amd} mount maps, the automount tree must also be defined +(@pxref{FSinfo automount definitions}). This will have been designed at +the time the volume names were allocated. Some volume names will not be +automounted, so @i{FSinfo} needs an explicit list of which volumes +should be automounted.@refill + +Hostnames are required at several places in the @i{FSinfo} language. It +is important to stick to either fully qualified names or unqualified +names. Using a mixture of the two will inevitably result in confusion. + +Sometimes volumes need to be referenced which are not defined in the set +of hosts being managed with @i{FSinfo}. The required action is to add a +dummy set of definitions for the host and volume names required. Since +the files generated for those particular hosts will not be used on them, +the exact values used is not critical. + +@node FSinfo Grammar, FSinfo host definitions, Using FSinfo, FSinfo +@comment node-name, next, previous, up +@section @i{FSinfo} grammar +@cindex FSinfo grammar +@cindex Grammar, FSinfo + +@i{FSinfo} has a relatively simple grammar. Distinct syntactic +constructs exist for each of the different types of data, though they +share a common flavor. Several conventions are used in the grammar +fragments below. + +The notation, @i{list(}@t{xxx}@i{)}, indicates a list of zero or more +@t{xxx}'s. The notation, @i{opt(}@t{xxx}@i{)}, indicates zero or one +@t{xxx}. Items in double quotes, @i{eg} @t{"host"}, represent input +tokens. Items in angle brackets, @i{eg} @var{}, represent +strings in the input. Strings need not be in double quotes, except to +differentiate them from reserved words. Quoted strings may include the +usual set of C ``@t{\}'' escape sequences with one exception: a +backslash-newline-whitespace sequence is squashed into a single space +character. To defeat this feature, put a further backslash at the start +of the second line. + +At the outermost level of the grammar, the input consists of a +sequence of host and automount declarations. These declarations are +all parsed before they are analyzed. This means they can appear in +any order and cyclic host references are possible. + +@example +fsinfo : @i{list(}fsinfo_attr@i{)} ; + +fsinfo_attr : host | automount ; +@end example + +@menu +* FSinfo host definitions:: +* FSinfo automount definitions:: +@end menu + +@node FSinfo host definitions, FSinfo host attributes, FSinfo Grammar, FSinfo +@comment node-name, next, previous, up +@section @i{FSinfo} host definitions +@cindex FSinfo host definitions +@cindex Defining a host, FSinfo + +A host declaration consists of three parts: a set of machine attribute +data, a list of filesystems physically attached to the machine, and a +list of additional statically mounted filesystems. + +@example +host : "host" host_data @i{list(}filesystem@i{@i{)}} @i{list(}mount@i{@i{)}} ; +@end example + +Each host must be declared in this way exactly once. Such things as the +hardware address, the architecture and operating system types and the +cluster name are all specified within the @dfn{host data}. + +All the disks the machine has should then be described in the @dfn{list +of filesystems}. When describing disks, you can specify what +@dfn{volname} the disk/partition should have and all such entries are +built up into a dictionary which can then be used for building the +automounter maps. + +The @dfn{list of mounts} specifies all the filesystems that should be +statically mounted on the machine. + +@menu +* FSinfo host attributes:: +* FSinfo filesystems:: +* FSinfo static mounts:: +@end menu + +@node FSinfo host attributes, FSinfo filesystems, FSinfo host definitions , FSinfo host definitions +@comment node-name, next, previous, up +@section @i{FSinfo} host attributes +@cindex FSinfo host attributes +@cindex Defining host attributes, FSinfo + +The host data, @dfn{host_data}, always includes the @dfn{hostname}. In +addition, several other host attributes can be given. + +@example +host_data : @var{} + | "@{" @i{list(}host_attrs@i{)} "@}" @var{} + ; + +host_attrs : host_attr "=" @var{} + | netif + ; + +host_attr : "config" + | "arch" + | "os" + | "cluster" + ; +@end example + +The @dfn{hostname} is, typically, the fully qualified hostname of the +machine. + +Examples: + +@example +host dylan.doc.ic.ac.uk + +host @{ + os = hpux + arch = hp300 +@} dougal.doc.ic.ac.uk +@end example + +The options that can be given as host attributes are shown below. + +@menu +* netif Option: FSinfo host netif: +* config Option: FSinfo host config: +* arch Option: FSinfo host arch: +* os Option: FSinfo host os: +* cluster Option: FSinfo host cluster: +@end menu + +@node FSinfo host netif, FSinfo host config, , FSinfo host attributes +@comment node-name, next, previous, up +@subsection netif Option + +This defines the set of network interfaces configured on the machine. +The interface attributes collected by @i{FSinfo} are the IP address, +subnet mask and hardware address. Multiple interfaces may be defined +for hosts with several interfaces by an entry for each interface. The +values given are sanity checked, but are currently unused for anything +else. + +@example +netif : "netif" @var{} "@{" @i{list(}netif_attrs@i{)} "@}" ; + +netif_attrs : netif_attr "=" @var{} ; + +netif_attr : "inaddr" | "netmask" | "hwaddr" ; +@end example + +Examples: + +@example +netif ie0 @{ + inaddr = 129.31.81.37 + netmask = 0xfffffe00 + hwaddr = "08:00:20:01:a6:a5" +@} + +netif ec0 @{ @} +@end example + +@node FSinfo host config, FSinfo host arch, FSinfo host netif, FSinfo host attributes +@comment node-name, next, previous, up +@subsection config Option +@cindex FSinfo config host attribute +@cindex config, FSinfo host attribute + +This option allows you to specify configuration variables for the +startup scripts (@file{rc} scripts). A simple string should immediately +follow the keyword. + +Example: + +@example +config "NFS_SERVER=true" +config "ZEPHYR=true" +@end example + +This option is currently unsupported. + +@node FSinfo host arch, FSinfo host os, FSinfo host config, FSinfo host attributes +@comment node-name, next, previous, up +@subsection arch Option +@cindex FSinfo arch host attribute +@cindex arch, FSinfo host attribute + +This defines the architecture of the machine. For example: + +@example +arch = hp300 +@end example + +This is intended to be of use when building architecture specific +mountmaps, however, the option is currently unsupported. + +@node FSinfo host os, FSinfo host cluster, FSinfo host arch, FSinfo host attributes +@comment node-name, next, previous, up +@subsection os Option +@cindex FSinfo os host attribute +@cindex os, FSinfo host attribute + +This defines the operating system type of the host. For example: + +@example +os = hpux +@end example + +This information is used when creating the @file{fstab} files, for +example in choosing which format to use for the @file{fstab} entries +within the file. + +@node FSinfo host cluster, , FSinfo host os, FSinfo host attributes +@comment node-name, next, previous, up +@subsection cluster Option +@cindex FSinfo cluster host attribute +@cindex cluster, FSinfo host attribute + +This is used for specifying in which cluster the machine belongs. For +example: + +@example +cluster = "theory" +@end example + +The cluster is intended to be used when generating the automount maps, +although it is currently unsupported. + +@node FSinfo filesystems, FSinfo static mounts, FSinfo host attributes, FSinfo host definitions +@comment node-name, next, previous, up +@section @i{FSinfo} filesystems +@cindex FSinfo filesystems + +The list of physically attached filesystems follows the machine +attributes. These should define all the filesystems available from this +machine, whether exported or not. In addition to the device name, +filesystems have several attributes, such as filesystem type, mount +options, and @samp{fsck} pass number which are needed to generate +@file{fstab} entries. + +@example +filesystem : "fs" @var{} "@{" @i{list(}fs_data@i{)} "@}" ; + +fs_data : fs_data_attr "=" @var{} + | mount + ; + +fs_data_attr + : "fstype" | "opts" | "passno" + | "freq" | "dumpset" | "log" + ; +@end example + +Here, @var{} is the device name of the disk (for example, +@file{/dev/dsk/2s0}). The device name is used for building the mount +maps and for the @file{fstab} file. The attributes that can be +specified are shown in the following section. + +The @i{FSinfo} configuration file for @code{dylan.doc.ic.ac.uk} is listed below. + +@example +host dylan.doc.ic.ac.uk + +fs /dev/dsk/0s0 @{ + fstype = swap +@} + +fs /dev/dsk/0s0 @{ + fstype = hfs + opts = rw,noquota,grpid + passno = 0; + freq = 1; + mount / @{ @} +@} + +fs /dev/dsk/1s0 @{ + fstype = hfs + opts = defaults + passno = 1; + freq = 1; + mount /usr @{ + local @{ + exportfs "dougal eden dylan zebedee brian" + volname /nfs/hp300/local + @} + @} +@} + +fs /dev/dsk/2s0 @{ + fstype = hfs + opts = defaults + passno = 1; + freq = 1; + mount default @{ + exportfs "toytown_clients hangers_on" + volname /home/dylan/dk2 + @} +@} + +fs /dev/dsk/3s0 @{ + fstype = hfs + opts = defaults + passno = 1; + freq = 1; + mount default @{ + exportfs "toytown_clients hangers_on" + volname /home/dylan/dk3 + @} +@} + +fs /dev/dsk/5s0 @{ + fstype = hfs + opts = defaults + passno = 1; + freq = 1; + mount default @{ + exportfs "toytown_clients hangers_on" + volname /home/dylan/dk5 + @} +@} +@end example + +@menu +* fstype Option: FSinfo filesystems fstype: +* opts Option: FSinfo filesystems opts: +* passno Option: FSinfo filesystems passno: +* freq Option: FSinfo filesystems freq: +* mount Option: FSinfo filesystems mount: +* dumpset Option: FSinfo filesystems dumpset: +* log Option: FSinfo filesystems log: +@end menu + +@node FSinfo filesystems fstype, FSinfo filesystems opts, , FSinfo filesystems +@comment node-name, next, previous, up +@subsection fstype Option +@cindex FSinfo fstype filesystems option +@cindex fstype, FSinfo filesystems option +@cindex export, FSinfo special fstype + +This specifies the type of filesystem being declared and will be placed +into the @file{fstab} file as is. The value of this option will be +handed to @code{mount} as the filesystem type---it should have such +values as @code{4.2}, @code{nfs} or @code{swap}. The value is not +examined for correctness. + +There is one special case. If the filesystem type is specified as +@samp{export} then the filesystem information will not be added to the +host's @file{fstab} information, but it will still be visible on the +network. This is useful for defining hosts which contain referenced +volumes but which are not under full control of @i{FSinfo}. + +Example: + +@example +fstype = swap +@end example + +@node FSinfo filesystems opts, FSinfo filesystems passno, FSinfo filesystems fstype, FSinfo filesystems +@comment node-name, next, previous, up +@subsection opts Option +@cindex FSinfo opts filesystems option +@cindex opts, FSinfo filesystems option + +This defines any options that should be given to @b{mount}(8) in the +@file{fstab} file. For example: + +@example +opts = rw,nosuid,grpid +@end example + +@node FSinfo filesystems passno, FSinfo filesystems freq, FSinfo filesystems opts, FSinfo filesystems +@comment node-name, next, previous, up +@subsection passno Option +@cindex FSinfo passno filesystems option +@cindex passno, FSinfo filesystems option + +This defines the @b{fsck}(8) pass number in which to check the +filesystem. This value will be placed into the @file{fstab} file. + +Example: + +@example +passno = 1 +@end example + +@node FSinfo filesystems freq, FSinfo filesystems mount, FSinfo filesystems passno, FSinfo filesystems +@comment node-name, next, previous, up +@subsection freq Option +@cindex FSinfo freq filesystems option +@cindex freq, FSinfo filesystems option + +This defines the interval (in days) between dumps. The value is placed +as is into the @file{fstab} file. + +Example: + +@example +freq = 3 +@end example + +@node FSinfo filesystems mount, FSinfo filesystems dumpset, FSinfo filesystems freq, FSinfo filesystems +@comment node-name, next, previous, up +@subsection mount Option +@cindex FSinfo mount filesystems option +@cindex mount, FSinfo filesystems option +@cindex exportfs, FSinfo mount option +@cindex volname, FSinfo mount option +@cindex sel, FSinfo mount option + +This defines the mountpoint at which to place the filesystem. If the +mountpoint of the filesystem is specified as @code{default}, then the +filesystem will be mounted in the automounter's tree under its volume +name and the mount will automatically be inherited by the automounter. + +Following the mountpoint, namespace information for the filesystem may +be described. The options that can be given here are @code{exportfs}, +@code{volname} and @code{sel}. + +The format is: + +@example +mount : "mount" vol_tree ; + +vol_tree : @i{list(}vol_tree_attr@i{)} ; + +vol_tree_attr + : @var{} "@{" @i{list(}vol_tree_info@i{)} vol_tree "@}" ; + +vol_tree_info + : "exportfs" @var{} + | "volname" @var{} + | "sel" @var{} + ; +@end example + +Example: + +@example +mount default @{ + exportfs "dylan dougal florence zebedee" + volname /vol/andrew +@} +@end example + +In the above example, the filesystem currently being declared will have +an entry placed into the @file{exports} file allowing the filesystem to +be exported to the machines @code{dylan}, @code{dougal}, @code{florence} +and @code{zebedee}. The volume name by which the filesystem will be +referred to remotely, is @file{/vol/andrew}. By declaring the +mountpoint to be @code{default}, the filesystem will be mounted on the +local machine in the automounter tree, where @i{Amd} will automatically +inherit the mount as @file{/vol/andrew}.@refill + +@table @samp +@item exportfs +a string defining which machines the filesystem may be exported to. +This is copied, as is, into the @file{exports} file---no sanity checking +is performed on this string.@refill + +@item volname +a string which declares the remote name by which to reference the +filesystem. The string is entered into a dictionary and allows you to +refer to this filesystem in other places by this volume name.@refill + +@item sel +a string which is placed into the automounter maps as a selector for the +filesystem.@refill + +@end table + +@node FSinfo filesystems dumpset, FSinfo filesystems log, FSinfo filesystems mount, FSinfo filesystems +@comment node-name, next, previous, up +@subsection dumpset Option +@cindex FSinfo dumpset filesystems option +@cindex dumpset, FSinfo filesystems option + +This provides support for Imperial College's local file backup tools and +is not documented further here. + +@node FSinfo filesystems log, , FSinfo filesystems dumpset, FSinfo filesystems +@comment node-name, next, previous, up +@subsection log Option +@cindex FSinfo log filesystems option +@cindex log, FSinfo filesystems option + +Specifies the log device for the current filesystem. This is ignored if +not required by the particular filesystem type. + +@node FSinfo static mounts, FSinfo automount definitions , FSinfo filesystems, FSinfo host definitions +@comment node-name, next, previous, up +@section @i{FSinfo} static mounts +@cindex FSinfo static mounts +@cindex Statically mounts filesystems, FSinfo + +Each host may also have a number of statically mounted filesystems. For +example, the host may be a diskless workstation in which case it will +have no @code{fs} declarations. In this case the @code{mount} +declaration is used to determine from where its filesystems will be +mounted. In addition to being added to the @file{fstab} file, this +information can also be used to generate a suitable @file{bootparams} +file.@refill + +@example +mount : "mount" @var{} @i{list(}localinfo@i{)} ; + +localinfo : localinfo_attr @var{} ; + +localinfo_attr + : "as" + | "from" + | "fstype" + | "opts" + ; +@end example + +The filesystem specified to be mounted will be searched for in the +dictionary of volume names built when scanning the list of hosts' +definitions. + +The attributes have the following semantics: +@table @samp +@item from @var{machine} +mount the filesystem from the machine with the hostname of +@dfn{machine}.@refill + +@item as @var{mountpoint} +mount the filesystem locally as the name given, in case this is +different from the advertised volume name of the filesystem. + +@item opts @var{options} +native @b{mount}(8) options. + +@item fstype @var{type} +type of filesystem to be mounted. +@end table + +An example: + +@example +mount /export/exec/hp300/local as /usr/local +@end example + +If the mountpoint specified is either @file{/} or @file{swap}, the +machine will be considered to be booting off the net and this will be +noted for use in generating a @file{bootparams} file for the host which +owns the filesystems. + +@node FSinfo automount definitions, FSinfo Command Line Options, FSinfo static mounts, FSinfo +@comment node-name, next, previous, up +@section Defining an @i{Amd} Mount Map in @i{FSinfo} +@cindex FSinfo automount definitions +@cindex Defining an Amd mount map, FSinfo + +The maps used by @i{Amd} can be constructed from @i{FSinfo} by defining +all the automount trees. @i{FSinfo} takes all the definitions found and +builds one map for each top level tree. + +The automount tree is usually defined last. A single automount +configuration will usually apply to an entire management domain. One +@code{automount} declaration is needed for each @i{Amd} automount point. +@i{FSinfo} determines whether the automount point is @dfn{direct} +(@pxref{Direct Automount Filesystem}) or @dfn{indirect} +(@pxref{Top-level Filesystem}). Direct automount points are +distinguished by the fact that there is no underlying +@dfn{automount_tree}.@refill + +@example +automount : "automount" @i{opt(}auto_opts@i{)} automount_tree ; + +auto_opts : "opts" @var{} ; + +automount_tree + : @i{list(}automount_attr@i{)} + ; + +automount_attr + : @var{} "=" @var{} + | @var{} "->" @var{} + | @var{} "@{" automount_tree "@}" + ; +@end example + +If @var{} is given, then it is the string to be placed in +the maps for @i{Amd} for the @code{opts} option. + +A @dfn{map} is typically a tree of filesystems, for example @file{home} +normally contains a tree of filesystems representing other machines in +the network. + +A map can either be given as a name representing an already defined +volume name, or it can be a tree. A tree is represented by placing +braces after the name. For example, to define a tree @file{/vol}, the +following map would be defined: + +@example +automount /vol @{ @} +@end example + +Within a tree, the only items that can appear are more maps. +For example: + +@example +automount /vol @{ + andrew @{ @} + X11 @{ @} +@} +@end example + +In this case, @i{FSinfo} will look for volumes named @file{/vol/andrew} +and @file{/vol/X11} and a map entry will be generated for each. If the +volumes are defined more than once, then @i{FSinfo} will generate +a series of alternate entries for them in the maps.@refill + +Instead of a tree, either a link (@var{name} @code{->} +@var{destination}) or a reference can be specified (@var{name} @code{=} +@var{destination}). A link creates a symbolic link to the string +specified, without further processing the entry. A reference will +examine the destination filesystem and optimize the reference. For +example, to create an entry for @code{njw} in the @file{/homes} map, +either of the two forms can be used:@refill + +@example +automount /homes @{ + njw -> /home/dylan/njw +@} +@end example + +or + +@example +automount /homes @{ + njw = /home/dylan/njw +@} +@end example + +In the first example, when @file{/homes/njw} is referenced from @i{Amd}, +a link will be created leading to @file{/home/dylan/njw} and the +automounter will be referenced a second time to resolve this filename. +The map entry would be: + +@example +njw type:=link;fs:=/home/dylan/njw +@end example + +In the second example, the destination directory is analyzed and found +to be in the filesystem @file{/home/dylan} which has previously been +defined in the maps. Hence the map entry will look like: + +@example +njw rhost:=dylan;rfs:=/home/dylan;sublink:=njw +@end example + +Creating only one symbolic link, and one access to @i{Amd}. + +@node FSinfo Command Line Options, FSinfo errors, FSinfo automount definitions, FSinfo +@comment node-name, next, previous, up +@section @i{FSinfo} Command Line Options +@cindex FSinfo command line options +@cindex Command line options, FSinfo + +@i{FSinfo} is started from the command line by using the command: + +@example +fsinfo [@i{options}] @i{files} ... +@end example + +The input to @i{FSinfo} is a single set of definitions of machines and +automount maps. If multiple files are given on the command-line, then +the files are concatenated together to form the input source. The files +are passed individually through the C pre-processor before being parsed. + +Several options define a prefix for the name of an output file. If the +prefix is not specified no output of that type is produced. The suffix +used will correspond either to the hostname to which a file belongs, or +to the type of output if only one file is produced. Dumpsets and the +@file{bootparams} file are in the latter class. To put the output into +a subdirectory simply put a @file{/} at the end of the prefix, making +sure that the directory has already been made before running +@i{Fsinfo}. + +@menu +* -a FSinfo Option:: Amd automount directory: +* -b FSinfo Option:: Prefix for bootparams files. +* -d FSinfo Option:: Prefix for dumpset data files. +* -e FSinfo Option:: Prefix for exports files. +* -f FSinfo Option:: Prefix for fstab files. +* -h FSinfo Option:: Local hostname. +* -m FSinfo Option:: Prefix for automount maps. +* -q FSinfo Option:: Ultra quiet mode. +* -v FSinfo Option:: Verbose mode. +* -I FSinfo Option:: Define new #include directory. +* -D-FSinfo Option:: Define macro. +* -U FSinfo Option:: Undefine macro. +@end menu + +@node -a FSinfo Option, -b FSinfo Option, FSinfo Command Line Options, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-a} @var{autodir} + +Specifies the directory name in which to place the automounter's +mountpoints. This defaults to @file{/a}. Some sites have the autodir set +to be @file{/amd}, and this would be achieved by: + +@example +fsinfo -a /amd ... +@end example + +@node -b FSinfo Option, -d FSinfo Option, -a FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-b} @var{bootparams} +@cindex bootparams, FSinfo prefix + +This specifies the prefix for the @file{bootparams} filename. If it is +not given, then the file will not be generated. The @file{bootparams} +file will be constructed for the destination machine and will be placed +into a file named @file{bootparams} and prefixed by this string. The +file generated contains a list of entries describing each diskless +client that can boot from the destination machine. + +As an example, to create a @file{bootparams} file in the directory +@file{generic}, the following would be used: + +@example +fsinfo -b generic/ ... +@end example + +@node -d FSinfo Option, -e FSinfo Option, -b FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-d} @var{dumpsets} +@cindex dumpset, FSinfo prefix + +This specifies the prefix for the @file{dumpsets} file. If it is not +specified, then the file will not be generated. The file will be for +the destination machine and will be placed into a filename +@file{dumpsets}, prefixed by this string. The @file{dumpsets} file is +for use by Imperial College's local backup system. + +For example, to create a @file{dumpsets} file in the directory @file{generic}, +then you would use the following: + +@example +fsinfo -d generic/ ... +@end example + +@node -e FSinfo Option, -f FSinfo Option, -d FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-e} @var{exportfs} +@cindex exports, FSinfo prefix + +Defines the prefix for the @file{exports} files. If it is not given, +then the file will not be generated. For each machine defined in the +configuration files as having disks, an @file{exports} file is +constructed and given a filename determined by the name of the machine, +prefixed with this string. If a machine is defined as diskless, then no +@file{exports} file will be created for it. The files contain entries +for directories on the machine that may be exported to clients. + +Example: To create the @file{exports} files for each diskfull machine +and place them into the directory @file{exports}: + +@example +fsinfo -e exports/ ... +@end example + +@node -f FSinfo Option, -h FSinfo Option, -e FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-f} @var{fstab} +@cindex fstab, FSinfo prefix + +This defines the prefix for the @file{fstab} files. The files will only +be created if this prefix is defined. For each machine defined in the +configuration files, a @file{fstab} file is created with the filename +determined by prefixing this string with the name of the machine. These +files contain entries for filesystems and partitions to mount at boot +time. + +Example, to create the files in the directory @file{fstabs}: + +@example +fsinfo -f fstabs/ ... +@end example + +@node -h FSinfo Option, -m FSinfo Option, -f FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-h} @var{hostname} +@cindex hostname, FSinfo command line option + +Defines the hostname of the destination machine to process for. If this +is not specified, it defaults to the local machine name, as returned by +@b{gethostname}(2). + +Example: + +@example +fsinfo -h dylan.doc.ic.ac.uk ... +@end example + +@node -m FSinfo Option, -q FSinfo Option, -h FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-m} @var{mount-maps} +@cindex maps, FSinfo command line option + +Defines the prefix for the automounter files. The maps will only be +produced if this prefix is defined. The mount maps suitable for the +network defined by the configuration files will be placed into files +with names calculated by prefixing this string to the name of each map. + +For example, to create the automounter maps and place them in the +directory @file{automaps}: + +@example +fsinfo -m automaps/ ... +@end example + +@node -q FSinfo Option, -v FSinfo Option, -m FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-q} +@cindex quiet, FSinfo command line option + +Selects quiet mode. @i{FSinfo} suppress the ``running commentary'' and +only outputs any error messages which are generated. + +@node -v FSinfo Option, -D-FSinfo Option, -q FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-v} +@cindex verbose, FSinfo command line option + +Selects verbose mode. When this is activated, the program will display +more messages, and display all the information discovered when +performing the semantic analysis phase. Each verbose message is output +to @file{stdout} on a line starting with a @samp{#} character. + +@node -D-FSinfo Option, -I FSinfo Option, -v FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-D} @var{name[=defn]} + +Defines a symbol @dfn{name} for the preprocessor when reading the +configuration files. Equivalent to @code{#define} directive. + +@node -I FSinfo Option, -U FSinfo Option, -D-FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-I} @var{directory} + +This option is passed into the preprocessor for the configuration files. +It specifies directories in which to find include files + +@node -U FSinfo Option, , -I FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-U} @var{name} + +Removes any initial definition of the symbol @dfn{name}. Inverse of the +@code{-D} option. + +@node FSinfo errors, , FSinfo Command Line Options, FSinfo +@comment node-name, next, previous, up +@section Errors produced by @i{FSinfo} +@cindex FSinfo error messages + +The following table documents the errors and warnings which @i{FSinfo} may produce. + +@table @t + +@item " expected +Occurs if an unescaped newline is found in a quoted string. + +@item ambiguous mount: @var{volume} is a replicated filesystem +If several filesystems are declared as having the same volume name, they +will be considered replicated filesystems. To mount a replicated +filesystem statically, a specific host will need to be named, to say +which particular copy to try and mount, else this error will +result. + +@item can't open @var{filename} for writing +Occurs if any errors are encountered when opening an output file. + +@item cannot determine localname since volname @var{volume} is not uniquely defined +If a volume is replicated and an attempt is made to mount the filesystem +statically without specifying a local mountpoint, @i{FSinfo} cannot +calculate a mountpoint, as the desired pathname would be +ambiguous. + +@item @var{device} has duplicate exportfs data +Produced if the @samp{exportfs} option is used multiple times within the +same branch of a filesystem definition. For example, if you attempt to +set the @samp{exportfs} data at different levels of the mountpoint +directory tree. + +@item dump frequency for @var{host}:@var{device} is non-zero +Occurs if @var{device} has its @samp{fstype} declared to be @samp{swap} +or @samp{export} and the @samp{dump} option is set to a value greater +than zero. Swap devices should not be dumped. + +@item duplicate host @var{hostname}! +If a host has more than one definition. + +@item end of file within comment +A comment was unterminated before the end of one of the configuration +files. + +@item @var{filename}: cannot open for reading +If a file specified on the command line as containing configuration data +could not be opened. + +@item @var{filesystem} has a volname but no exportfs data +Occurs when a volume name is declared for a file system, but the string +specifying what machines the filesystem can be exported to is +missing. + +@item fs field "@var{field-name}" already set +Occurs when multiple definitions are given for one of the attributes of a +host's filesystem. + +@item host field "@var{field-name}" already set +If duplicate definitions are given for any of the fields with a host +definition. + +@item @var{host}:@var{device} has more than one mount point +Occurs if the mount option for a host's filesystem specifies multiple +trees at which to place the mountpoint. + +@item @var{host}:@var{device} has no mount point +Occurs if the @samp{mount} option is not specified for a host's +filesystem. + +@item @var{host}:@var{device} needs field "@var{field-name}" +Occurs when a filesystem is missing a required field. @var{field-name} could +be one of @samp{fstype}, @samp{opts}, @samp{passno} or +@samp{mount}. + +@item @var{host}:mount field specified for swap partition +Occurs if a mountpoint is given for a filesystem whose type is declared +to be @samp{swap}. + +@item malformed IP dotted quad: @var{address} +If the Internet address of an interface is incorrectly specified. An +Internet address definition is handled to @b{inet_addr}(3N) to see if it +can cope. If not, then this message will be displayed. + +@item malformed netmask: @var{netmask} +If the netmask cannot be decoded as though it were a hexadecimal number, +then this message will be displayed. It will typically be caused by +incorrect characters in the @var{netmask} value. + +@item mount field "@var{field-name}" already set +Occurs when a static mount has multiple definitions of the same field. + +@item mount tree field "@var{field-name}" already set +Occurs when the @var{field-name} is defined more than once during the +definition of a filesystems mountpoint. + +@item netif field @var{field-name} already set +Occurs if you attempt to define an attribute of an interface more than +once. + +@item network booting requires both root and swap areas +Occurs if a machine has mount declarations for either the root partition +or the swap area, but not both. You cannot define a machine to only +partially boot via the network. + +@item no disk mounts on @var{hostname} +If there are no static mounts, nor local disk mounts specified for a +machine, this message will be displayed. + +@item no volname given for @var{host}:@var{device} +Occurs when a filesystem is defined to be mounted on @file{default}, but +no volume name is given for the file system, then the mountpoint cannot +be determined. + +@item not allowed '/' in a directory name +Occurs when a pathname with multiple directory elements is specified as +the name for an automounter tree. A tree should only have one name at +each level. + +@item pass number for @var{host}:@var{device} is non-zero +Occurs if @var{device} has its @samp{fstype} declared to be @samp{swap} +or @samp{export} and the @b{fsck}(8) pass number is set. Swap devices should not be +fsck'd. @xref{FSinfo filesystems fstype}. + +@item sub-directory @var{directory} of @var{directory-tree} starts with '/' +Within the filesystem specification for a host, if an element +@var{directory} of the mountpoint begins with a @samp{/} and it is not +the start of the tree. + +@item sub-directory of @var{directory-tree} is named "default" +@samp{default} is a keyword used to specify if a mountpoint should be +automatically calculated by @i{FSinfo}. If you attempt to specify a +directory name as this, it will use the filename of @file{default} but +will produce this warning. + +@item unknown \ sequence +Occurs if an unknown escape sequence is found inside a string. Within a +string, you can give the standard C escape sequences for strings, such +as newlines and tab characters. + +@item unknown directory attribute +If an unknown keyword is found while reading the definition of a host's +filesystem mount option. + +@item unknown filesystem attribute +Occurs if an unrecognized keyword is used when defining a host's +filesystems. + +@item unknown host attribute +Occurs if an unrecognized keyword is used when defining a host. + +@item unknown mount attribute +Occurs if an unrecognized keyword is found while parsing the list of +static mounts. + +@item unknown volname @var{volume} automounted @i{[} on @i{name} @i{]} +Occurs if @var{volume} is used in a definition of an automount map but the volume +name has not been declared during the host filesystem definitions. + +@item volname @var{volume} is unknown +Occurs if an attempt is made to mount or reference a volume name which +has not been declared during the host filesystem definitions. + +@item volname @var{volume} not exported from @var{machine} +Occurs if you attempt to mount the volume @var{volume} from a machine +which has not declared itself to have such a filesystem +available. + +@end table + +@c ################################################################ +@node Hlfsd, Assorted Tools, FSinfo, Top +@comment node-name, next, previous, up +@chapter Hlfsd +@pindex Hlfsd +@cindex Home-Link Filesystem + +@i{Hlfsd} is a daemon which implements a filesystem containing a +symbolic link to subdirectory within a user's home directory, depending +on the user which accessed that link. It was primarily designed to +redirect incoming mail to users' home directories, so that it can be read +from anywhere. It was designed and implemented by +@email{ezk@@cs.columbia.edu,Erez Zadok} and +@email{dupuy@@cs.columbia.edu,Alexander Dupuy}, at the +@uref{http://www.cs.columbia.edu/,Computer Science Department} of +@uref{http://www.columbia.edu/,Columbia University}. A +@uref{http://www.cs.columbia.edu/~ezk/research/hlfsd/hlfsd.html,paper} +on @i{Hlfsd} was presented at the Usenix LISA VII conference in 1993. + +@i{Hlfsd} operates by mounting itself as an NFS server for the directory +containing @i{linkname}, which defaults to @file{/hlfs/home}. Lookups +within that directory are handled by @i{Hlfsd}, which uses the +password map to determine how to resolve the lookup. The directory will +be created if it doesn't already exist. The symbolic link will be to +the accessing user's home directory, with @i{subdir} appended to it. If +not specified, @i{subdir} defaults to @file{.hlfsdir}. This directory +will also be created if it does not already exist. + +A @samp{SIGTERM} sent to @i{Hlfsd} will cause it to shutdown. A @samp{SIGHUP} will +flush the internal caches, and reload the password map. It will also +close and reopen the log file, to enable the original log file to be +removed or rotated. A @samp{SIGUSR1} will cause it to dump its internal table +of user IDs and home directories to the file @file{/tmp/hlfsddump}. + +@menu +* Introduction to Hlfsd:: +* Background to Mail Delivery:: +* Using Hlfsd:: +@end menu + +@c ================================================================ +@node Introduction to Hlfsd, Background to Mail Delivery, Hlfsd, Hlfsd +@comment node-name, next, previous, up +@section Introduction to Hlfsd +@cindex Introduction to Hlfsd +@cindex Hlfsd; introduction + +Electronic mail has become one of the major applications for many +computer networks, and use of this service is expected to increase over +time, as networks proliferate and become faster. Providing a convenient +environment for users to read, compose, and send electronic mail has +become a requirement for systems administrators (SAs). + +Widely used methods for handling mail usually require users to be logged +into a designated ``home'' machine, where their mailbox files reside. +Only on that one machine can they read newly arrived mail. Since users +have to be logged into that system to read their mail, they often find +it convenient to run all of their other processes on that system as +well, including memory and CPU-intensive jobs. For example, in our +department, we have allocated and configured several multi-processor +servers to handle such demanding CPU/memory applications, but these were +underutilized, in large part due to the inconvenience of not being able +to read mail on those machines. (No home directories were located on +these designated CPU-servers, since we did not want NFS service for +users' home directories to have to compete with CPU-intensive jobs. At the +same time, we discouraged users from running demanding applications on +their home machines.) + +Many different solutions have been proposed to allow users to read their +mail on any host. However, all of these solutions fail in one or more +of several ways: + +@itemize @bullet + +@item +they introduce new single points of failure + +@item +they require using different mail transfer agents (MTAs) or user agents +(UAs) + +@item +they do not solve the problem for all cases, i.e. the solution is only +partially successful for a particular environment. + +@end itemize + +We have designed a simple filesystem, called the @dfn{Home-Link File +System}, to provide the ability to deliver mail to users' home +directories, without modification to mail-related applications. We have +endeavored to make it as stable as possible. Of great importance to us +was to make sure the HLFS daemon, @file{hlfsd} , would not hang under +any circumstances, and would take the next-best action when faced with +problems. Compared to alternative methods, @i{Hlfsd} is a stable, more +general solution, and easier to install/use. In fact, in some ways, we +have even managed to improve the reliability and security of mail +service. + +Our server implements a small filesystem containing a symbolic link +to a subdirectory of the invoking user's home directory, and named symbolic +links to users' mailbox files. + +The @i{Hlfsd} server finds out the @var{uid} of the process that is +accessing its mount point, and resolves the pathname component @samp{home} as a +symbolic link to a subdirectory within the home directory given by the +@var{uid}'s entry in the password file. If the @var{gid} of the process +that attempts to access a mailbox file is a special one (called +HLFS_GID), then the server maps the name of the @emph{next} pathname +component directly to the user's mailbox. This is necessary so that +access to a mailbox file by users other than the owner can succeed. The +server has safety features in case of failures such as hung filesystems +or home directory filesystems that are inaccessible or full. + +On most of our machines, mail gets delivered to the directory +@file{/var/spool/mail}. Many programs, including UAs, depend on that +path. @i{Hlfsd} creates a directory @file{/mail}, and mounts itself on +top of that directory. @i{Hlfsd} implements the path name component +called @samp{home}, pointing to a subdirectory of the user's home directory. +We have made @file{/var/spool/mail} a symbolic link to +@file{/mail/home}, so that accessing @file{/var/spool/mail} actually +causes access to a subdirectory within a user's home directory. + +The following table shows an example of how resolving the pathname +@file{/var/mail/@i{NAME}} to @file{/users/ezk/.mailspool/@i{NAME}} proceeds. + +@multitable {Resolving Component} {Pathname left to resolve} {Value if symbolic link} + +@item @b{Resolving Component} +@tab @b{Pathname left to resolve} +@tab @b{Value if symbolic link} + +@item @t{/} +@tab @t{var/mail/}@i{NAME} + +@item @t{var/} +@tab @t{mail/}@i{NAME} + +@item @t{mail}@@ +@tab @t{/mail/home/}@i{NAME} +@tab @t{mail}@@ -> @t{/mail/home} + +@item @t{/} +@tab @t{mail/home/}@i{NAME} + +@item @t{mail/} +@tab @t{home/}@i{NAME} + +@item @t{home}@@ +@tab @i{NAME} +@tab @t{home}@@ -> @t{/users/ezk/.mailspool} + +@item @t{/} +@tab @t{users/ezk/.mailspool/}@i{NAME} + +@item @t{users/} +@tab @t{ezk/.mailspool/}@i{NAME} + +@item @t{ezk/} +@tab @t{.mailspool/}@i{NAME} + +@item @t{.mailspool/} +@tab @i{NAME} + +@item @i{NAME} + +@end multitable + +@c ================================================================ +@node Background to Mail Delivery, Using Hlfsd, Introduction to Hlfsd, Hlfsd +@comment node-name, next, previous, up +@section Background to Mail Delivery +@cindex Background to Mail Delivery +@cindex Hlfsd; background + +This section provides an in-depth discussion of why available methods +for delivering mail to home directories are not as good as the one used +by @i{Hlfsd}. + +@menu +* Single-Host Mail Spool Directory:: +* Centralized Mail Spool Directory:: +* Distributed Mail Spool Service:: +* Why Deliver Into the Home Directory?:: +@end menu + +@c ---------------------------------------------------------------- +@node Single-Host Mail Spool Directory, Centralized Mail Spool Directory, Background to Mail Delivery, Background to Mail Delivery +@comment node-name, next, previous, up +@subsection Single-Host Mail Spool Directory +@cindex Single-Host Mail Spool Directory + +The most common method for mail delivery is for mail to be appended to a +mailbox file in a standard spool directory on the designated ``mail +home'' machine of the user. The greatest advantage of this method is +that it is the default method most vendors provide with their systems, +thus very little (if any) configuration is required on the SA's part. +All they need to set up are mail aliases directing mail to the host on +which the user's mailbox file is assigned. (Otherwise, mail is +delivered locally, and users find mailboxes on many machines.) + +As users become more sophisticated, and aided by windowing systems, they +find themselves logging in on multiple hosts at once, performing several +tasks concurrently. They ask to be able to read their mail on any host +on the network, not just the one designated as their ``mail home''. + +@c ---------------------------------------------------------------- +@node Centralized Mail Spool Directory, Distributed Mail Spool Service, Single-Host Mail Spool Directory, Background to Mail Delivery +@comment node-name, next, previous, up +@subsection Centralized Mail Spool Directory +@cindex Centralized Mail Spool Directory + +A popular method for providing mail readability from any host is to have +all mail delivered to a mail spool directory on a designated +``mail-server'' which is exported via NFS to all of the hosts on the +network. Configuring such a system is relatively easy. On most +systems, the bulk of the work is a one-time addition to one or two +configuration files in @file{/etc}. The file-server's spool directory +is then hard-mounted across every machine on the local network. In +small environments with only a handful of hosts this can be an +acceptable solution. In our department, with a couple of hundred active +hosts and thousands of mail messages processed daily, this was deemed +completely unacceptable, as it introduced several types of problems: + +@table @b + +@item Scalability and Performance + +As more and more machines get added to the network, more mail traffic +has to go over NFS to and from the mail-server. Users like to run +mail-watchers, and read their mail often. The stress on the shared +infrastructure increases with every user and host added; loads on the +mail server would most certainly be high since all mail delivery goes +through that one machine.@footnote{ Delivery via NFS-mounted filesystems +may require usage of @samp{rpc.lockd} and @samp{rpc.statd} to provide +distributed file-locking, both of which are widely regarded as unstable +and unreliable. Furthermore, this will degrade performance, as local +processes as well as remote @samp{nfsd} processes are kept busy.} This +leads to lower reliability and performance. To reduce the number of +concurrent connections between clients and the server host, some SAs +have resorted to automounting the mail-spool directory. But this +solution only makes things worse: since users often run mail watchers, +and many popular applications such as @samp{trn}, @samp{emacs}, +@samp{csh} or @samp{ksh} check periodically for new mail, the +automounted directory would be effectively permanently mounted. If it +gets unmounted automatically by the automounter program, it is most +likely to get mounted shortly afterwards, consuming more I/O resources +by the constant cycle of mount and umount calls. + +@item Reliability + +The mail-server host and its network connectivity must be very reliable. +Worse, since the spool directory has to be hard-mounted,@footnote{No SA +in their right minds would soft-mount read/write partitions --- the +chances for data loss are too great.} many processes which access the +spool directory (various shells, @samp{login}, @samp{emacs}, etc.) +would be hung as long as connectivity to the mail-server is severed. To +improve reliability, SAs may choose to backup the mail-server's spool +partition several times a day. This may make things worse since reading +or delivering mail while backups are in progress may cause backups to be +inconsistent; more backups consume more backup-media resources, and +increase the load on the mail-server host. + +@end table + +@c ---------------------------------------------------------------- +@node Distributed Mail Spool Service, Why Deliver Into the Home Directory?, Centralized Mail Spool Directory, Background to Mail Delivery +@comment node-name, next, previous, up +@subsection Distributed Mail Spool Service +@cindex Distributed Mail Spool Service + +Despite the existence of a few systems that support delivery to users' +home directories, mail delivery to home directories hasn't caught on. +We believe the main reason is that there are too many programs that +``know'' where mailbox files reside. Besides the obvious (the delivery +program @file{/bin/mail} and mail readers like @file{/usr/ucb/Mail}, +@samp{mush}, @samp{mm}, etc.), other programs that know mailbox location +are login, from, almost every shell, @samp{xbiff}, @samp{xmailbox}, and +even some programs not directly related to mail, such as @samp{emacs} +and @samp{trn}. Although some of these programs can be configured to +look in different directories with the use of environment variables and +other resources, many of them cannot. The overall porting work is +significant. + +Other methods that have yet to catch on require the use of a special +mail-reading server, such as IMAP or POP. The main disadvantage of +these systems is that UAs need to be modified to use these services --- +a long and involved task. That is why they are not popular at this +time. + +Several other ideas have been proposed and even used in various +environments. None of them is robust. They are mostly very +specialized, inflexible, and do not extend to the general case. Some of +the ideas are plain bad, potentially leading to lost or corrupt mail: + +@table @b + +@item automounters + +Using an automounter such as @i{Amd} to provide a set of symbolic links +from the normal spool directory to user home directories is not +sufficient. UAs rename, unlink, and recreate the mailbox as a regular +file, therefore it must be a real file, not a symbolic link. +Furthermore, it must reside in a real directory which is writable by the +UAs and MTAs. This method may also require populating +@file{/var/spool/mail} with symbolic links and making sure they are +updated. Making @i{Amd} manage that directory directly fails, since +many various lock files need to be managed as well. Also, @i{Amd} does +not provide all of the NFS operations which are required to write mail +such as write, create, remove, and unlink. + +@item @code{$MAIL} + +Setting this variable to an automounted directory pointing to the user's +mail spool host only solves the problem for those programs which know +and use @code{$MAIL}. Many programs don't, therefore this solution is partial +and of limited flexibility. Also, it requires the SAs or the users to +set it themselves --- an added level of inconvenience and possible +failures. + +@item @t{/bin/mail} + +Using a different mail delivery agent could be the solution. One such +example is @samp{hdmail}. However, @samp{hdmail} still requires +modifying all UAs, the MTA's configuration, installing new daemons, and +changing login scripts. This makes the system less upgradable or +compatible with others, and adds one more complicated system for SAs to +deal with. It is not a complete solution because it still requires each +user have their @code{$MAIL} variable setup correctly, and that every program +use this variable. + +@end table + +@c ---------------------------------------------------------------- +@node Why Deliver Into the Home Directory?, , Distributed Mail Spool Service, Background to Mail Delivery +@comment node-name, next, previous, up +@subsection Why Deliver Into the Home Directory? +@cindex Why Deliver Into the Home Directory? +@cindex Hlfsd; Why Deliver Into the Home Directory? + +There are several major reasons why SAs might want to deliver mail +directly into the users' home directories: + +@table @b + +@item Location + +Many mail readers need to move mail from the spool directory to the +user's home directory. It speeds up this operation if the two are on +the same filesystem. If for some reason the user's home directory is +inaccessible, it isn't that useful to be able to read mail, since there +is no place to move it to. In some cases, trying to move mail to a +non-existent or hung filesystem may result in mail loss. + +@item Distribution + +Having all mail spool directories spread among the many more filesystems +minimizes the chances that complete environments will grind to a halt +when a single server is down. It does increase the chance that there +will be someone who is not able to read their mail when a machine is +down, but that is usually preferred to having no one be able to read +their mail because a centralized mail server is down. The problem of +losing some mail due to the (presumably) higher chances that a user's +machine is down is minimized in HLFS. + +@item Security + +Delivering mail to users' home directories has another advantage --- +enhanced security and privacy. Since a shared system mail spool +directory has to be world-readable and searchable, any user can see +whether other users have mail, when they last received new mail, or when +they last read their mail. Programs such as @samp{finger} display this +information, which some consider an infringement of privacy. While it +is possible to disable this feature of @samp{finger} so that remote +users cannot see a mailbox file's status, this doesn't prevent local +users from getting the information. Furthermore, there are more +programs which make use of this information. In shared environments, +disabling such programs has to be done on a system-wide basis, but with +mail delivered to users' home directories, users less concerned with +privacy who do want to let others know when they last received or read +mail can easily do so using file protection bits. + +@c Lastly, on systems that do not export their NFS filesystem with +@c @t{anon=0}, superusers are less likely to snoop around others' mail, as +@c they become ``nobodies'' across NFS. + +@end table + +In summary, delivering mail to home directories provides users the +functionality sought, and also avoids most of the problems just +discussed. + +@c ================================================================ +@node Using Hlfsd, , Background to Mail Delivery, Hlfsd +@comment node-name, next, previous, up +@section Using Hlfsd +@cindex Using Hlfsd +@cindex Hlfsd; using + +@menu +* Controlling Hlfsd:: +* Hlfsd Options:: +* Hlfsd Files:: +@end menu + +@c ---------------------------------------------------------------- +@node Controlling Hlfsd, Hlfsd Options, Using Hlfsd, Using Hlfsd +@comment node-name, next, previous, up +@subsection Controlling Hlfsd +@cindex Controlling Hlfsd +@cindex Hlfsd; controlling +@pindex ctl-hlfsd + +Much the same way @i{Amd} is controlled by @file{ctl-amd}, so does +@i{Hlfsd} get controlled by the @file{ctl-hlfsd} script: + +@table @t + +@item ctl-hlfsd start +Start a new @i{Hlfsd}. + +@item ctl-hlfsd stop +Stop a running @i{Hlfsd}. + +@item ctl-hlfsd restart +Stop a running @i{Hlfsd}, wait for 10 seconds, and then start a new +one. It is hoped that within 10 seconds, the previously running +@i{Hlfsd} terminate properly; otherwise, starting a second one could +cause system lockup. + +@end table + +For example, on our systems, we start @i{Hlfsd} within @file{ctl-hlfsd} +as follows on Solaris 2 systems: + +@example +hlfsd -a /var/alt_mail -x all -l /var/log/hlfsd /mail/home .mailspool +@end example + +The directory @file{/var/alt_mail} is a directory in the root partition +where alternate mail will be delivered into, when it cannot be delivered +into the user's home directory. + +Normal mail gets delivered into @file{/var/mail}, but on our systems, +that is a symbolic link to @file{/mail/home}. @file{/mail} is managed +by @i{Hlfsd}, which creates a dynamic symlink named @samp{home}, +pointing to the subdirectory @file{.mailspool} @emph{within} the +accessing user's home directory. This results in mail which normally +should go to @file{/var/mail/@code{$USER}}, to go to +@file{@code{$HOME}/.mailspool/@code{$USER}}. + +@i{Hlfsd} does not create the @file{/var/mail} symlink. This needs to +be created (manually) once on each host, by the system administrators, +as follows: + +@example +mv /var/mail /var/alt_mail +ln -s /mail/home /var/mail +@end example + +@c ---------------------------------------------------------------- +@node Hlfsd Options, Hlfsd Files, Controlling Hlfsd, Using Hlfsd +@comment node-name, next, previous, up +@subsection Hlfsd Options +@cindex Hlfsd Options +@cindex Hlfsd; Options + +@table @t + +@item -a @var{alt_dir} +Alternate directory. The name of the directory to which the symbolic +link returned by @i{Hlfsd} will point, if it cannot access the home +directory of the user. This defaults to @file{/var/hlfs}. This +directory will be created if it doesn't exist. It is expected that +either users will read these files, or the system administrators will +run a script to resend this ``lost mail'' to its owner. + +@item -c @var{cache-interval} +Caching interval. @i{Hlfsd} will cache the validity of home directories +for this interval, in seconds. Entries which have been verified within +the last @var{cache-interval} seconds will not be verified again, since +the operation could be expensive, and the entries are most likely still +valid. After the interval has expired, @i{Hlfsd} will re-verify the +validity of the user's home directory, and reset the cache time-counter. +The default value for @var{cache-interval} is 300 seconds (5 minutes). + +@item -f +Force fast startup. This option tells @i{Hlfsd} to skip startup-time +consistency checks such as existence of mount directory, alternate spool +directory, symlink to be hidden under the mount directory, their +permissions and validity. + +@item -g @var{group} +Set the special group HLFS_GID to @var{group}. Programs such as +@file{/usr/ucb/from} or @file{/usr/sbin/in.comsat}, which access the +mailboxes of other users, must be setgid @samp{HLFS_GID} to work properly. The +default group is @samp{hlfs}. If no group is provided, and there is no +group @samp{hlfs}, this feature is disabled. + +@item -h +Help. Print a brief help message, and exit. + +@item -i @var{reload-interval} +Map-reloading interval. Each @var{reload-interval} seconds, @i{Hlfsd} +will reload the password map. @i{Hlfsd} needs the password map for the +UIDs and home directory pathnames. @i{Hlfsd} schedules a @samp{SIGALRM} to +reload the password maps. A @samp{SIGHUP} sent to @i{Hlfsd} will force it to +reload the maps immediately. The default value for +@var{reload-interval} is 900 seconds (15 minutes.) + +@item -l @var{logfile} +Specify a log file to which @i{Hlfsd} will record events. If +@var{logfile} is the string @samp{syslog} then the log messages will be +sent to the system log daemon by @b{syslog}(3), using the @samp{LOG_DAEMON} +facility. This is also the default. + +@item -n +No verify. @i{Hlfsd} will not verify the validity of the symbolic link +it will be returning, or that the user's home directory contains +sufficient disk-space for spooling. This can speed up @i{Hlfsd} at the +cost of possibly returning symbolic links to home directories which are +not currently accessible or are full. By default, @i{Hlfsd} validates +the symbolic-link in the background. The @code{-n} option overrides the +meaning of the @code{-c} option, since no caching is necessary. + +@item -o @var{mount-options} +Mount options which @i{Hlfsd} will use to mount itself on top of +@var{dirname}. By default, @var{mount-options} is set to @samp{ro}. If +the system supports symbolic-link caching, default options are set +to @samp{ro,nocache}. + +@item -p +Print PID. Outputs the process-id of @i{Hlfsd} to standard output where +it can be saved into a file. + +@item -v +Version. Displays version information to standard error. + +@item -x @var{log-options} +Specify run-time logging options. The options are a comma separated +list chosen from: @samp{fatal}, @samp{error}, @samp{user}, @samp{warn}, @samp{info}, @samp{map}, @samp{stats}, @samp{all}. + +@item -C +Force @i{Hlfsd} to run on systems that cannot turn off the NFS +attribute-cache. Use of this option on those systems is discouraged, as +it may result in loss or misdelivery of mail. The option is ignored on +systems that can turn off the attribute-cache. + +@item -D @var{log-options} +Select from a variety of debugging options. Prefixing an option with +the string @samp{no} reverses the effect of that option. Options are +cumulative. The most useful option is @samp{all}. Since this option is +only used for debugging other options are not documented here. A fuller +description is available in the program source. A @samp{SIGUSR1} sent +to @i{Hlfsd} will cause it to dump its internal password map to the file +@file{/usr/tmp/hlfsd.dump.XXXXXX}, where @samp{XXXXXX} will be replaced +by a random string generated by @b{mktemp}(3) or (the more secure) +@b{mkstemp}(3). + +@item -P @var{password-file} +Read the user-name, user-id, and home directory information from the +file @var{password-file}. Normally, @i{Hlfsd} will use @b{getpwent}(3) +to read the password database. This option allows you to override the +default database, and is useful if you want to map users' mail files to +a directory other than their home directory. Only the username, uid, +and home-directory fields of the file @var{password-file} are read and +checked. All other fields are ignored. The file @var{password-file} +must otherwise be compliant with Unix Version 7 colon-delimited format +@b{passwd}(4). + +@end table + +@c ---------------------------------------------------------------- +@node Hlfsd Files, , Hlfsd Options, Using Hlfsd +@comment node-name, next, previous, up +@subsection Hlfsd Files +@cindex Hlfsd Files +@cindex Hlfsd; Files + +The following files are used by @i{Hlfsd}: + +@table @file + +@item /hlfs +directory under which @i{Hlfsd} mounts itself and manages the symbolic +link @file{home}. + +@item .hlfsdir +default sub-directory in the user's home directory, to which the +@file{home} symbolic link returned by @i{Hlfsd} points. + +@item /var/hlfs +directory to which @file{home} symbolic link returned by @i{Hlfsd} +points if it is unable to verify the that user's home directory is +accessible. + +@end table + +For discussion on other files used by @i{Hlfsd}, see @ref{lostaltmail} and +@ref{lostaltmail.conf-sample}. + +@c ################################################################ +@node Assorted Tools, Examples, Hlfsd, Top +@comment node-name, next, previous, up +@chapter Assorted Tools +@cindex Assorted Tools + +The following are additional utilities and scripts included with +am-utils, and get installed. + +@menu +* am-eject:: +* amd.conf-sample:: +* amd2ldif:: +* amd2sun:: +* ctl-amd:: +* ctl-hlfsd:: +* expn:: +* fix-amd-map:: +* fixmount:: +* fixrmtab:: +* lostaltmail:: +* lostaltmail.conf-sample:: +* mk-amd-map:: +* pawd:: +* wait4amd:: +* wait4amd2die:: +* wire-test:: +@end menu + +@c ---------------------------------------------------------------- +@node am-eject, amd.conf-sample, Assorted Tools, Assorted Tools +@comment node-name, next, previous, up +@section am-eject +@pindex am-eject + +A shell script unmounts a floppy or CD-ROM that is automounted, and +then attempts to eject the removable device. + +@c ---------------------------------------------------------------- +@node amd.conf-sample, amd2ldif, am-eject, Assorted Tools +@comment node-name, next, previous, up +@section amd.conf-sample +@pindex amd.conf-sample + +A sample @i{Amd} configuration file. @xref{Amd Configuration File}. + +@c ---------------------------------------------------------------- +@node amd2ldif, amd2sun, amd.conf-sample, Assorted Tools +@comment node-name, next, previous, up +@section amd2ldif +@pindex amd2ldif + +A script to convert @i{Amd} maps to LDAP input files. Use it as follows: + +@example +amd2ldif @i{mapname} @i{base} < @i{amd.mapfile} > @i{mapfile.ldif} +@end example + +@c ---------------------------------------------------------------- +@node amd2sun, ctl-amd, amd2ldif, Assorted Tools +@comment node-name, next, previous, up +@section amd2sun +@pindex amd2sun + +A script to convert @i{Amd} maps to Sun Automounter maps. Use it as +follows + +@example +amd2sun < @i{amd.mapfile} > @i{auto_mapfile} +@end example + +@c ---------------------------------------------------------------- +@node ctl-amd, ctl-hlfsd, amd2sun, Assorted Tools +@comment node-name, next, previous, up +@section ctl-amd +@pindex ctl-amd + +A script to start, stop, or restart @i{Amd}. Use it as follows: + +@table @t +@item ctl-amd start +Start a new @i{Amd} process. +@item ctl-amd stop +Stop the running @i{Amd}. +@item ctl-amd restart +Stop the running @i{Amd} (if any), safely wait for it to terminate, and +then start a new process --- only if the previous one died cleanly. +@end table + +@xref{Run-time Administration} for more details. + +@c ---------------------------------------------------------------- +@node ctl-hlfsd, expn, ctl-amd, Assorted Tools +@comment node-name, next, previous, up +@section ctl-hlfsd +@pindex ctl-hlfsd + +A script for controlling @i{Hlfsd}, much the same way @file{ctl-amd} +controls @i{Amd}. Use it as follows: + +@table @t +@item ctl-hlfsd start +Start a new @i{Hlfsd} process. +@item ctl-hlfsd stop +Stop the running @i{Hlfsd}. +@item ctl-hlfsd restart +Stop the running @i{Hlfsd} (if any), wait for 10 seconds for it to +terminate, and then start a new process --- only if the previous one +died cleanly. +@end table + +@xref{Hlfsd} for more details. + +@c ---------------------------------------------------------------- +@node expn, fix-amd-map, ctl-hlfsd, Assorted Tools +@comment node-name, next, previous, up +@section expn +@pindex expn + +A script to expand email addresses into their full name. It is +generally useful when using with the @file{lostaltmail} script, but is a +useful tools otherwise. + +@example +$ expn -v ezk@@cs.columbia.edu +ezk@@cs.columbia.edu -> + ezk@@shekel.mcl.cs.columbia.edu +ezk@@shekel.mcl.cs.columbia.edu -> + Erez Zadok <"| /usr/local/mh/lib/slocal -user ezk || exit 75> + Erez Zadok <\ezk> + Erez Zadok +@end example + +@c ---------------------------------------------------------------- +@node fix-amd-map, fixmount, expn, Assorted Tools +@comment node-name, next, previous, up +@section fix-amd-map +@pindex fix-amd-map + +Am-utils changed some of the syntax and default values of some +variables. For example, the default value for @samp{$@{os@}} for +Solaris 2.x (aka SunOS 5.x) systems used to be @samp{sos5}, it is now +more automatically generated from @file{config.guess} and its value is +@samp{sunos5}. + +This script converts older @i{Amd} maps to new ones. Use it as follows: + +@example +fix-amd-map < @i{old.map} > @i{new.map} +@end example + +@c ---------------------------------------------------------------- +@node fixmount, fixrmtab, fix-amd-map, Assorted Tools +@comment node-name, next, previous, up +@section fixmount +@pindex fixmount + +@samp{fixmount} is a variant of @b{showmount}(8) that can delete bogus +mount entries in remote @b{mountd}(8) daemons. This is useful to +cleanup otherwise ever-accumulating ``junk''. Use it for example: + +@example +fixmount -r @i{host} +@end example + +See the online manual page for @samp{fixmount} for more details of its +usage. + +@c ---------------------------------------------------------------- +@node fixrmtab, lostaltmail, fixmount, Assorted Tools +@comment node-name, next, previous, up +@section fixrmtab +@pindex fixrmtab + +A script to invalidate @file{/etc/rmtab} entries for hosts named. Also +restart mountd for changes to take effect. Use it for example: + +@example +fixrmtab @i{host1} @i{host2} @i{...} +@end example + +@c ---------------------------------------------------------------- +@node lostaltmail, lostaltmail.conf-sample, fixrmtab, Assorted Tools +@comment node-name, next, previous, up +@section lostaltmail +@pindex lostaltmail + +A script used with @i{Hlfsd} to resend any ``lost'' mail. @i{Hlfsd} +redirects mail which cannot be written into the user's home directory to +an alternate directory. This is useful to continue delivering mail, +even if the user's file system was unavailable, full, or over quota. +But, the mail which gets delivered to the alternate directory needs to +be resent to its respective users. This is what the @samp{lostaltmail} +script does. + +Use it as follows: + +@example +lostaltmail +@end example + +This script needs a configuration file @samp{lostaltmail.conf} set up +with the right parameters to properly work. @xref{Hlfsd} for more +details. + +@c ---------------------------------------------------------------- +@node lostaltmail.conf-sample, mk-amd-map, lostaltmail, Assorted Tools +@comment node-name, next, previous, up +@section lostaltmail.conf-sample +@pindex lostaltmail.conf-sample +@cindex lostaltmail; configuration file + +This is a text file with configuration parameters needed for the +@samp{lostaltmail} script. The script includes comments explaining each +of the configuration variables. See it for more information. Also +@pxref{Hlfsd} for general information. + +@c ---------------------------------------------------------------- +@node mk-amd-map, pawd, lostaltmail.conf-sample, Assorted Tools +@comment node-name, next, previous, up +@section mk-amd-map +@pindex mk-amd-map + +This program converts a normal @i{Amd} map file into an ndbm database +with the same prefix as the named file. Use it as follows: + +@example +mk-amd-map @i{mapname} +@end example + +@c ---------------------------------------------------------------- +@node pawd, wait4amd, mk-amd-map, Assorted Tools +@comment node-name, next, previous, up +@section pawd +@pindex pawd + +@i{Pawd} is used to print the current working directory, adjusted to +reflect proper paths that can be reused to go through the automounter +for the shortest possible path. In particular, the path printed back +does not include any of @i{Amd}'s local mount points. Using them is +unsafe, because @i{Amd} may unmount managed file systems from the mount +points, and thus including them in paths may not always find the files +within. + +Without any arguments, @i{Pawd} will print the automounter adjusted +current working directory. With any number of arguments, it will print +the adjusted path of each one of the arguments. + +@c ---------------------------------------------------------------- +@node wait4amd, wait4amd2die, pawd, Assorted Tools +@comment node-name, next, previous, up +@section wait4amd +@pindex wait4amd + +A script to wait for @i{Amd} to start on a particular host before +performing an arbitrary command. The command is executed repeatedly, +with 1 second intervals in between. You may interrupt the script using +@samp{^C} (or whatever keyboard sequence your terminal's @samp{intr} function +is bound to). + +Examples: + +@table @t +@item wait4amd saturn amq -p -h saturn +When @i{Amd} is up on host @samp{saturn}, get the process ID of that +running @i{Amd}. +@item wait4amd pluto rlogin pluto +Remote login to host @samp{pluto} when @i{Amd} is up on that host. It +is generally necessary to wait for @i{Amd} to properly start and +initialize on a remote host before logging in to it, because otherwise +user home directories may not be accessible across the network. +@item wait4amd pluto +A short-hand version of the previous command, since the most useful +reason for this script is to login to a remote host. I use it very +often when testing out new versions of @i{Amd}, and need to reboot hung +hosts. +@end table + +@c ---------------------------------------------------------------- +@node wait4amd2die, wire-test, wait4amd, Assorted Tools +@comment node-name, next, previous, up +@section wait4amd2die +@pindex wait4amd2die + +This script is used internally by @samp{ctl-amd} when used to restart +@i{Amd}. It waits for @i{Amd} to terminate. If it detected that +@i{Amd} terminated cleanly, this script will return an exist status of +zero. Otherwise, it will return a non-zero exit status. + +The script tests for @i{Amd}'s existence once every 5 seconds, six +times, for a total of 30 seconds. It will return a zero exist status as +soon as it detects that @i{Amd} dies. + +@c ---------------------------------------------------------------- +@node wire-test, , wait4amd2die, Assorted Tools +@comment node-name, next, previous, up +@section wire-test +@pindex wire-test + +A simple program to test if some of the most basic networking functions +in am-util's library @file{libamu} work. It also tests the combination +of NFS protocol and version number that are supported from the current +host, to a remote one. + +For example, in this test a machine which only supports NFS Version 2 is +contacting a remote host that can support the same version, but using +both UDP and TCP. If no host name is specified, @samp{wire-test} will +try @file{localhost}. + +@example +$ wire-test moisil +Network name is "mcl-lab-net.cs.columbia.edu" +Network number is "128.59.13" +Network name is "old-net.cs.columbia.edu" +Network number is "128.59.16" +My IP address is 0x7f000001. +NFS Version and protocol tests to host "moisil"... + testing vers=2, proto="udp" -> found version 2. + testing vers=3, proto="udp" -> failed! + testing vers=2, proto="tcp" -> found version 2. + testing vers=3, proto="tcp" -> failed! +@end example + +@c ################################################################ +@node Examples, Internals, Assorted Tools, Top +@comment node-name, next, previous, up +@chapter Examples + +@menu +* User Filesystems:: +* Home Directories:: +* Architecture Sharing:: +* Wildcard Names:: +* rwho servers:: +* /vol:: +* /defaults with selectors:: +* /tftpboot in a chroot-ed environment:: + +@end menu + +@node User Filesystems, Home Directories, Examples, Examples +@comment node-name, next, previous, up +@section User Filesystems +@cindex User filesystems +@cindex Mounting user filesystems + +With more than one fileserver, the directories most frequently +cross-mounted are those containing user home directories. A common +convention used at Imperial College is to mount the user disks under +@t{/home/}@i{machine}. + +Typically, the @samp{/etc/fstab} file contained a long list of entries +such as: + +@example +@i{machine}:/home/@i{machine} /home/@i{machine} nfs ... +@end example + +for each fileserver on the network. + +There are numerous problems with this system. The mount list can become +quite large and some of the machines may be down when a system is +booted. When a new fileserver is installed, @samp{/etc/fstab} must be +updated on every machine, the mount directory created and the filesystem +mounted. + +In many environments most people use the same few workstations, but +it is convenient to go to a colleague's machine and access your own +files. When a server goes down, it can cause a process on a client +machine to hang. By minimizing the mounted filesystems to only include +those actively being used, there is less chance that a filesystem will +be mounted when a server goes down. + +The following is a short extract from a map taken from a research fileserver +at Imperial College. + +Note the entry for @samp{localhost} which is used for users such as +the operator (@samp{opr}) who have a home directory on most machine as +@samp{/home/localhost/opr}. + +@example +/defaults opts:=rw,intr,grpid,nosuid +charm host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} \ + host==$@{key@};type:=ufs;dev:=/dev/xd0g +# +... + +# +localhost type:=link;fs:=$@{host@} +... +# +# dylan has two user disks so have a +# top directory in which to mount them. +# +dylan type:=auto;fs:=$@{map@};pref:=$@{key@}/ +# +dylan/dk2 host!=dylan;type:=nfs;rhost:=dylan;rfs:=/home/$@{key@} \ + host==dylan;type:=ufs;dev:=/dev/dsk/2s0 +# +dylan/dk5 host!=dylan;type:=nfs;rhost:=dylan;rfs:=/home/$@{key@} \ + host==dylan;type:=ufs;dev:=/dev/dsk/5s0 +... +# +toytown host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} \ + host==$@{key@};type:=ufs;dev:=/dev/xy1g +... +# +zebedee host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} \ + host==$@{key@};type:=ufs;dev:=/dev/dsk/1s0 +# +# Just for access... +# +gould type:=auto;fs:=$@{map@};pref:=$@{key@}/ +gould/staff host!=gould;type:=nfs;rhost:=gould;rfs:=/home/$@{key@} +# +gummo host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} +... +@end example + +This map is shared by most of the machines listed so on those +systems any of the user disks is accessible via a consistent name. +@i{Amd} is started with the following command + +@example +amd /home amd.home +@end example + +Note that when mounting a remote filesystem, the @dfn{automounted} +mount point is referenced, so that the filesystem will be mounted if +it is not yet (at the time the remote @samp{mountd} obtains the file handle). + +@node Home Directories, Architecture Sharing, User Filesystems, Examples +@comment node-name, next, previous, up +@section Home Directories +@cindex Home directories +@cindex Example of mounting home directories +@cindex Mount home directories + +One convention for home directories is to locate them in @samp{/homes} +so user @samp{jsp}'s home directory is @samp{/homes/jsp}. With more +than a single fileserver it is convenient to spread user files across +several machines. All that is required is a mount-map which converts +login names to an automounted directory. + +Such a map might be started by the command: + +@example +amd /homes amd.homes +@end example + +where the map @samp{amd.homes} contained the entries: + +@example +/defaults type:=link # All the entries are of type:=link +jsp fs:=/home/charm/jsp +njw fs:=/home/dylan/dk5/njw +... +phjk fs:=/home/toytown/ai/phjk +sjv fs:=/home/ganymede/sjv +@end example + +Whenever a login name is accessed in @samp{/homes} a symbolic link +appears pointing to the real location of that user's home directory. In +this example, @samp{/homes/jsp} would appear to be a symbolic link +pointing to @samp{/home/charm/jsp}. Of course, @samp{/home} would also +be an automount point. + +This system causes an extra level of symbolic links to be used. +Although that turns out to be relatively inexpensive, an alternative is +to directly mount the required filesystems in the @samp{/homes} +map. The required map is simple, but long, and its creation is best automated. +The entry for @samp{jsp} could be: + +@example +jsp -sublink:=$@{key@};rfs:=/home/charm \ + host==charm;type:=ufs;dev:=/dev/xd0g \ + host!=charm;type:=nfs;rhost:=charm +@end example + +This map can become quite big if it contains a large number of entries. +By combining two other features of @i{Amd} it can be greatly simplified. + +First the UFS partitions should be mounted under the control of +@samp{/etc/fstab}, taking care that they are mounted in the same place +that @i{Amd} would have automounted them. In most cases this would be +something like @samp{/a/@dfn{host}/home/@dfn{host}} and +@samp{/etc/fstab} on host @samp{charm} would have a line:@refill + +@example +/dev/xy0g /a/charm/home/charm 4.2 rw,nosuid,grpid 1 5 +@end example + +The map can then be changed to: + +@example +/defaults type:=nfs;sublink:=$@{key@};opts:=rw,intr,nosuid,grpid +jsp rhost:=charm;rfs:=/home/charm +njw rhost:=dylan;rfs:=/home/dylan/dk5 +... +phjk rhost:=toytown;rfs:=/home/toytown;sublink:=ai/$@{key@} +sjv rhost:=ganymede;rfs:=/home/ganymede +@end example + +This map operates as usual on a remote machine (@i{ie} @code{$@{host@}} +not equal to @code{$@{rhost@}}). On the machine where the filesystem is +stored (@i{ie} @code{$@{host@}} equal to @code{$@{rhost@}}), @i{Amd} +will construct a local filesystem mount point which corresponds to the +name of the locally mounted UFS partition. If @i{Amd} is started with +the @code{-r} option then instead of attempting an NFS mount, @i{Amd} will +simply inherit the UFS mount (@pxref{Inheritance Filesystem}). If +@code{-r} is not used then a loopback NFS mount will be made. This type of +mount is known to cause a deadlock on many systems. + +@node Architecture Sharing, Wildcard Names, Home Directories, Examples +@comment node-name, next, previous, up +@section Architecture Sharing +@cindex Architecture sharing +@cindex Sharing a fileserver between architectures +@cindex Architecture dependent volumes + +@c %At the moment some of the research machines have sets of software +@c %mounted in @samp{/vol}. This contains subdirectories for \TeX, +@c %system sources, local sources, prolog libraries and so on. +Often a filesystem will be shared by machines of different architectures. +Separate trees can be maintained for the executable images for each +architecture, but it may be more convenient to have a shared tree, +with distinct subdirectories. + +A shared tree might have the following structure on the fileserver (called +@samp{fserver} in the example): + +@example +local/tex +local/tex/fonts +local/tex/lib +local/tex/bin +local/tex/bin/sun3 +local/tex/bin/sun4 +local/tex/bin/hp9000 +... +@end example + +In this example, the subdirectories of @samp{local/tex/bin} should be +hidden when accessed via the automount point (conventionally @samp{/vol}). +A mount-map for @samp{/vol} to achieve this would look like: + +@example +/defaults sublink:=$@{/key@};rhost:=fserver;type:=link +tex type:=auto;fs:=$@{map@};pref:=$@{key@}/ +tex/fonts host!=fserver;type:=nfs;rfs:=/vol/tex \ + host==fserver;fs:=/usr/local/tex +tex/lib host!=fserver;type:=nfs;rfs:=/vol/tex \ + host==fserver;fs:=/usr/local/tex +tex/bin -sublink:=$@{/key@}/$@{arch@} \ + host!=fserver;type:=nfs;rfs:=/vol/tex \ + host:=fserver;fs:=/usr/local/tex +@end example + +When @samp{/vol/tex/bin} is referenced, the current machine architecture +is automatically appended to the path by the @code{$@{sublink@}} +variable. This means that users can have @samp{/vol/tex/bin} in their +@samp{PATH} without concern for architecture dependencies. + +@node Wildcard Names, rwho servers, Architecture Sharing, Examples +@comment node-name, next, previous, up +@section Wildcard Names & Replicated Servers + +By using the wildcard facility, @i{Amd} can @dfn{overlay} an existing +directory with additional entries. +The system files are usually mounted under @samp{/usr}. If instead, +@i{Amd} is mounted on @samp{/usr}, additional +names can be overlayed to augment or replace names in the ``master'' @samp{/usr}. +A map to do this would have the form: + +@example +local type:=auto;fs:=local-map +share type:=auto;fs:=share-map +* -type:=nfs;rfs:=/export/exec/$@{arch@};sublink:="$@{key@}" \ + rhost:=fserv1 rhost:=fserv2 rhost:=fserv3 +@end example + +Note that the assignment to @code{$@{sublink@}} is surrounded by double +quotes to prevent the incoming key from causing the map to be +misinterpreted. This map has the effect of directing any access to +@samp{/usr/local} or @samp{/usr/share} to another automount point. + +In this example, it is assumed that the @samp{/usr} files are replicated +on three fileservers: @samp{fserv1}, @samp{fserv2} and @samp{fserv3}. +For any references other than to @samp{local} and @samp{share} one of +the servers is used and a symbolic link to +@t{$@{autodir@}/$@{rhost@}/export/exec/$@{arch@}/@i{whatever}} is +returned once an appropriate filesystem has been mounted.@refill + +@node rwho servers, /vol, Wildcard Names, Examples +@comment node-name, next, previous, up +@section @samp{rwho} servers +@cindex rwho servers +@cindex Architecture specific mounts +@cindex Example of architecture specific mounts + +The @samp{/usr/spool/rwho} directory is a good candidate for automounting. +For efficiency reasons it is best to capture the rwho data on a small +number of machines and then mount that information onto a large number +of clients. The data written into the rwho files is byte order dependent +so only servers with the correct byte ordering can be used by a client: + +@example +/defaults type:=nfs +usr/spool/rwho -byte==little;rfs:=/usr/spool/rwho \ + rhost:=vaxA rhost:=vaxB \ + || -rfs:=/usr/spool/rwho \ + rhost:=sun4 rhost:=hp300 +@end example + +@node /vol, /defaults with selectors, rwho servers, Examples +@comment node-name, next, previous, up +@section @samp{/vol} +@cindex /vol +@cindex Catch-all mount point +@cindex Generic volume name + +@samp{/vol} is used as a catch-all for volumes which do not have other +conventional names. + +Below is part of the @samp{/vol} map for the domain @samp{doc.ic.ac.uk}. +The @samp{r+d} tree is used for new or experimental software that needs +to be available everywhere without installing it on all the fileservers. +Users wishing to try out the new software then simply include +@samp{/vol/r+d/@{bin,ucb@}} in their path.@refill + +The main tree resides on one host @samp{gould.doc.ic.ac.uk}, which has +different @samp{bin}, @samp{etc}, @samp{lib} and @samp{ucb} +sub-directories for each machine architecture. For example, +@samp{/vol/r+d/bin} for a Sun-4 would be stored in the sub-directory +@samp{bin/sun4} of the filesystem @samp{/usr/r+d}. When it was accessed +a symbolic link pointing to @samp{/a/gould/usr/r+d/bin/sun4} would be +returned.@refill + +@example +/defaults type:=nfs;opts:=rw,grpid,nosuid,intr,soft +wp -opts:=rw,grpid,nosuid;rhost:=charm \ + host==charm;type:=link;fs:=/usr/local/wp \ + host!=charm;type:=nfs;rfs:=/vol/wp +... +# +src -opts:=rw,grpid,nosuid;rhost:=charm \ + host==charm;type:=link;fs:=/usr/src \ + host!=charm;type:=nfs;rfs:=/vol/src +# +r+d type:=auto;fs:=$@{map@};pref:=r+d/ +# per architecture bin,etc,lib&ucb... +r+d/bin rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@} +r+d/etc rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@} +r+d/include rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@} +r+d/lib rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@} +r+d/man rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@} +r+d/src rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@} +r+d/ucb rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@} +# hades pictures +pictures -opts:=rw,grpid,nosuid;rhost:=thpfs \ + host==thpfs;type:=link;fs:=/nbsd/pictures \ + host!=thpfs;type:=nfs;rfs:=/nbsd;sublink:=pictures +# hades tools +hades -opts:=rw,grpid,nosuid;rhost:=thpfs \ + host==thpfs;type:=link;fs:=/nbsd/hades \ + host!=thpfs;type:=nfs;rfs:=/nbsd;sublink:=hades +# bsd tools for hp. +bsd -opts:=rw,grpid,nosuid;arch==hp9000;rhost:=thpfs \ + host==thpfs;type:=link;fs:=/nbsd/bsd \ + host!=thpfs;type:=nfs;rfs:=/nbsd;sublink:=bsd +@end example + +@node /defaults with selectors, /tftpboot in a chroot-ed environment, /vol, Examples +@comment node-name, next, previous, up +@section @samp{/defaults} with selectors +@cindex /defaults with selectors +@cindex selectors on default + +It is sometimes useful to have different defaults for a given map. To +achieve this, the @samp{/defaults} entry must be able to process normal +selectors. This feature is turned on by setting +@samp{selectors_on_default = yes} in the @file{amd.conf} file. +@xref{selectors_on_default Parameter}. + +In this example, I set different default NFS mount options for hosts +which are running over a slower network link. By setting a smaller size +for the NFS read and write buffer sizes, you can greatly improve remote +file service performance. + +@example +/defaults \ + wire==slip-net;opts:=rw,intr,rsize=1024,wsize=1024,timeo=20,retrans=10 \ + wire!=slip-net;opts:=rw,intr +@end example + +@node /tftpboot in a chroot-ed environment, , /defaults with selectors, Examples +@comment node-name, next, previous, up +@section @samp{/tftpboot} in a chroot-ed environment +@cindex /tftpboot in a chroot-ed environment +@cindex chroot: /tftpboot example + +In this complex example, we attempt to run an @i{Amd} process +@emph{inside} a chroot-ed environment. @samp{tftpd} (Trivial FTP) is +used to trivially retrieve files used to boot X-Terminals, Network +Printers, Network routers, diskless workstations, and other such +devices. For security reasons, @samp{tftpd} (and also @samp{ftpd}) +processes are run using the @b{chroot}(2) system call. This provides an +environment for these processes, where access to any files outside the +directory where the chroot-ed process runs is denied. + +For example, if you start @samp{tftpd} on your system with + +@example +chroot /tftpboot /usr/sbin/tftpd +@end example + +@noindent +then the @samp{tftpd} process will not be able to access any files +outside @file{/tftpboot}. This ensures that no one can retrieve files +such as @file{/etc/passwd} and run password crackers on it. + +Since the TFTP service works by broadcast, it is necessary to have at +least one TFTP server running on each subnet. If you have lots of files +that you need to make available for @samp{tftp}, and many subnets, it +could take significant amounts of disk space on each host serving them. + +A solution we implemented at Columbia University was to have every host +run @samp{tftpd}, but have those servers retrieve the boot files from +two replicated servers. Those replicated servers have special +partitions dedicated to the many network boot files. + +We start @i{Amd} as follows: + +@example +amd /tftpboot/.amd amd.tftpboot +@end example + +That is, @i{Amd} is serving the directory @file{/tftpboot/.amd}. The +@samp{tftp} server runs inside @file{/tftpboot} and is chroot-ed in that +directory too. The @file{amd.tftpboot} map looks like: + +@example +# +# Amd /tftpboot directory -> host map +# + +/defaults opts:=nosuid,ro,intr,soft;fs:=/tftpboot/import;type:=nfs + +tp host==lol;rfs:=/n/lol/import/tftpboot;type:=lofs \ + host==ober;rfs:=/n/ober/misc/win/tftpboot;type:=lofs \ + rhost:=ober;rfs:=/n/ober/misc/win/tftpboot \ + rhost:=lol;rfs:=/n/lol/import/tftpboot +@end example + +To help understand this example, I list a few of the file entries that +are created inside @file{/tftpboot}: + +@example +$ ls -la /tftpboot +dr-xr-xr-x 2 root 512 Aug 30 23:11 .amd +drwxrwsr-x 12 root 512 Aug 30 08:00 import +lrwxrwxrwx 1 root 33 Feb 27 1997 adminpr.cfg -> ./.amd/tp/hplj/adminpr.cfg +lrwxrwxrwx 1 root 22 Dec 5 1996 tekxp -> ./.amd/tp/xterms/tekxp +lrwxrwxrwx 1 root 1 Dec 5 1996 tftpboot -> . +@end example + +Here is an explanation of each of the entries listed above: + +@table @code + +@item .amd +This is the @i{Amd} mount point. Note that you do not need to run a +separate @i{Amd} process for the TFTP service. The @b{chroot}(2) system +call only protects against file access, but the same process can still +serve files and directories inside and outside the chroot-ed +environment, because @i{Amd} itself was not run in chroot-ed mode. + +@item import +This is the mount point where @i{Amd} will mount the directories +containing the boot files. The map is designed so that remote +directories will be NFS mounted (even if they are already mounted +elsewhere), and local directories are loopback mounted (since they are +not accessible outside the chroot-ed @file{/tftpboot} directory). + +@item adminpr.cfg +@itemx tekxp +Two manually created symbolic links to directories @emph{inside} the +@i{Amd}-managed directory. The crossing of the component @file{tp} will +cause @i{Amd} to automount one of the remote replicas. Once crossed, +access to files inside proceeds as usual. The @samp{adminpr.cfg} is a +configuration file for an HP Laser-Jet 4si printer, and the @samp{tekxp} +is a directory for Tektronix X-Terminal boot files. + +@item tftpboot +This innocent looking symlink is important. Usually, when devices boot +via the TFTP service, they perform the @samp{get file} command to +retrieve @var{file}. However, some devices assume that @samp{tftpd} +does not run in a chroot-ed environment, but rather ``unprotected'', and +thus use a full pathname for files to retrieve, as in @samp{get +/tftpboot/file}. This symlink effectively strips out the leading +@file{/tftpboot/}. + +@end table + +@c ################################################################ +@node Internals, Acknowledgments & Trademarks, Examples, Top +@comment node-name, next, previous, up +@chapter Internals + +Note that there are more error and logging messages possible than are +listed here. Most of them are self-explanatory. Refer to the program +sources for more details on the rest. + +@menu +* Log Messages:: +@end menu + +@node Log Messages, , Internals, Internals +@comment node-name, next, previous, up +@section Log Messages + +In the following sections a brief explanation is given of some of the +log messages made by @i{Amd}. Where the message is in @samp{typewriter} +font, it corresponds exactly to the message produced by @i{Amd}. Words +in @dfn{italic} are replaced by an appropriate string. Variables, +@code{$@{@i{var}@}}, indicate that the value of the appropriate variable is +output. + +Log messages are either sent directly to a file, +or logged via the @b{syslog}(3) mechanism. @xref{log_file Parameter} +In either case, entries in the file are of the form: +@example +@i{date-string} @i{hostname} @t{amd[}@i{pid}@t{]} @i{message} +@end example + +@menu +* Fatal errors:: +* Info messages:: +@end menu + +@node Fatal errors, Info messages, Log Messages, Log Messages +@comment node-name, next, previous, up +@subsection Fatal errors + +@i{Amd} attempts to deal with unusual events. Whenever it is not +possible to deal with such an error, @i{Amd} will log an appropriate +message and, if it cannot possibly continue, will either exit or abort. +These messages are selected by @samp{-x fatal} on the command line. +When @b{syslog}(3) is being used, they are logged with level +@samp{LOG_FATAL}. Even if @i{Amd} continues to operate it is likely to +remain in a precarious state and should be restarted at the earliest +opportunity. + +@table @t + +@item Attempting to inherit not-a-filesystem +The prototype mount point created during a filesystem restart did not +contain a reference to the restarted filesystem. This error ``should +never happen''. + +@item Can't bind to domain "@i{NIS-domain}" +A specific NIS domain was requested on the command line, but no server +for that domain is available on the local net. + +@item Can't determine IP address of this host (@i{hostname}) +When @i{Amd} starts it determines its own IP address. If this lookup +fails then @i{Amd} cannot continue. The hostname it looks up is that +obtained returned by @b{gethostname}(2) system call. + +@item Can't find root file handle for @i{automount point} +@i{Amd} creates its own file handles for the automount points. When it +mounts itself as a server, it must pass these file handles to the local +kernel. If the filehandle is not obtainable the mount point is ignored. +This error ``should never happen''. + +@item Must be root to mount filesystems (euid = @i{euid}) +To prevent embarrassment, @i{Amd} makes sure it has appropriate system +privileges. This amounts to having an euid of 0. The check is made +after argument processing complete to give non-root users a chance to +access the @code{-v} option. + +@item No work to do - quitting +No automount points were given on the command line and so there is no +work to do. + +@item Out of memory +While attempting to malloc some memory, the memory space available to +@i{Amd} was exhausted. This is an unrecoverable error. + +@item Out of memory in realloc +While attempting to realloc some memory, the memory space available to +@i{Amd} was exhausted. This is an unrecoverable error. + +@item cannot create rpc/udp service +Either the NFS or AMQ endpoint could not be created. + +@item gethostname: @i{description} +The @b{gethostname}(2) system call failed during startup. + +@item host name is not set +The @b{gethostname}(2) system call returned a zero length host name. +This can happen if @i{Amd} is started in single user mode just after +booting the system. + +@item ifs_match called! +An internal error occurred while restarting a pre-mounted filesystem. +This error ``should never happen''. + +@item mount_afs: @i{description} +An error occurred while @i{Amd} was mounting itself. + +@item run_rpc failed +Somehow the main NFS server loop failed. This error ``should never +happen''. + +@item unable to free rpc arguments in amqprog_1 +The incoming arguments to the AMQ server could not be free'ed. + +@item unable to free rpc arguments in nfs_program_1 +The incoming arguments to the NFS server could not be free'ed. + +@item unable to register (AMQ_PROGRAM, AMQ_VERSION, udp) +The AMQ server could not be registered with the local portmapper or the +internal RPC dispatcher. + +@item unable to register (NFS_PROGRAM, NFS_VERSION, 0) +The NFS server could not be registered with the internal RPC dispatcher. + +@end table + +XXX: This section needs to be updated + +@node Info messages, , Fatal errors, Log Messages +@comment node-name, next, previous, up +@subsection Info messages + +@i{Amd} generates information messages to record state changes. These +messages are selected by @samp{-x info} on the command line. When +@b{syslog}(3) is being used, they are logged with level @samp{LOG_INFO}. + +The messages listed below can be generated and are in a format suitable +for simple statistical analysis. @dfn{mount-info} is the string +that is displayed by @dfn{Amq} in its mount information column and +placed in the system mount table. + +@table @t + +@item "@t{$@{@i{path}@}}" forcibly timed out +An automount point has been timed out by the @i{Amq} command. + +@item "@t{$@{@i{path}@}}" has timed out +No access to the automount point has been made within the timeout +period. + +@item Filehandle denied for "$@{@i{rhost}@}:$@{@i{rfs}@}" +The mount daemon refused to return a file handle for the requested filesystem. + +@item Filehandle error for "$@{@i{rhost}@}:$@{@i{rfs}@}": @i{description} +The mount daemon gave some other error for the requested filesystem. + +@item Finishing with status @i{exit-status} +@i{Amd} is about to exit with the given exit status. + +@item Re-synchronizing cache for map @t{$@{@i{map}@}} +The named map has been modified and the internal cache is being re-synchronized. + +@item file server @t{$@{@i{rhost}@}} is down - timeout of "@t{$@{@i{path}@}}" ignored +An automount point has timed out, but the corresponding file server is +known to be down. This message is only produced once for each mount +point for which the server is down. + +@item file server @t{$@{@i{rhost}@}} type nfs is down +An NFS file server that was previously up is now down. + +@item file server @t{$@{@i{rhost}@}} type nfs is up +An NFS file server that was previously down is now up. + +@item file server @t{$@{@i{rhost}@}} type nfs starts down +A new NFS file server has been referenced and is known to be down. + +@item file server @t{$@{@i{rhost}@}} type nfs starts up +A new NFS file server has been referenced and is known to be up. + +@item mount of "@t{$@{@i{path}@}}" on @t{$@{@i{fs}@}} timed out +Attempts to mount a filesystem for the given automount point have failed +to complete within 30 seconds. + +@item @i{mount-info} mounted fstype @t{$@{@i{type}@}} on @t{$@{@i{fs}@}} +A new file system has been mounted. + +@item @i{mount-info} restarted fstype @t{$@{@i{type}@}} on @t{$@{@i{fs}@}} +@i{Amd} is using a pre-mounted filesystem to satisfy a mount request. + +@item @i{mount-info} unmounted fstype @t{$@{@i{type}@}} from @t{$@{@i{fs}@}} +A file system has been unmounted. + +@item @i{mount-info} unmounted fstype @t{$@{@i{type}@}} from @t{$@{@i{fs}@}} link @t{$@{@i{fs}@}}/@t{$@{@i{sublink}@}} +A file system of which only a sub-directory was in use has been unmounted. + +@item restarting @i{mount-info} on @t{$@{@i{fs}@}} +A pre-mounted file system has been noted. + +@end table + +XXX: This section needs to be updated + +@c ################################################################ +@node Acknowledgments & Trademarks, Index, Internals, Top +@comment node-name, next, previous, up +@unnumbered Acknowledgments & Trademarks + +Many thanks to the @email{amd-dev@@majordomo.cs.columbia.edu,Amd +Developers} mailing list through the months developing am-utils. These +members have contributed to the discussions, ideas, code and +documentation, and subjected their systems to alpha quality code. +Special thanks go to those +@uref{http://www.cs.columbia.edu/~ezk/am-utils/AUTHORS.txt,authors} who +have submitted patches. + +Thanks to the Formal Methods Group at Imperial College for suffering +patiently while @i{Amd} was being developed on their machines. + +Thanks to the many people who have helped with the development of +@i{Amd}, especially Piete Brooks at the Cambridge University Computing +Lab for many hours of testing, experimentation and discussion. + +Thanks to the @email{amd-workers@@majordomo.glue.umd.edu,Amd Workers} +mailing list members for many suggestions and bug reports to @i{Amd}. + +@itemize @bullet +@item +@b{DEC}, @b{VAX} and @b{Ultrix} are registered trademarks of Digital +Equipment Corporation. +@item +@b{AIX} and @b{IBM} are registered trademarks of International Business +Machines Corporation. +@item +@b{Sun}, @b{NFS} and @b{SunOS} are registered trademarks of Sun +Microsystems, Inc. +@item +@b{UNIX} is a registered trademark in the USA and other countries, +exclusively licensed through X/Open Company, Ltd. +@item +All other registered trademarks are owned by their respective owners. +@end itemize + +@c ################################################################ +@node Index, , Acknowledgments & Trademarks, Top +@comment node-name, next, previous, up +@unnumbered Index + +@printindex cp + +@contents +@bye + +@c ==================================================================== +@c ISPELL LOCAL WORDS: +@c LocalWords: setfilename amdref overfullrule settitle titlepage titlefont nz +@c LocalWords: authorfont vskip ifinfo iftex cindex unnumberedsec dfn xref vol +@c LocalWords: locationN pxref jpo nott concentrix Sjoerd sjoerd cwi Eitan vuw +@c LocalWords: Mizrotsky eitan shumuji dgux fpx scp hcx metcalf masala hlh OTS +@c LocalWords: Presnell srp cgl Trost trost ogi pyrOSx OSx tubsibr riscix iX +@c LocalWords: Piete pb Lindblad cjl ai umax utek xinu Mitchum D'Souza dsouza +@c LocalWords: mrc apu alliant aviion AViiON fps macII multimax tahoe vax emph +@c LocalWords: mapdefault valA valB valC YPTSDIR ETCDIR substr MAKEDBM YPDBDIR +@c LocalWords: NOPUSH njw dylan dk dylan njw anydir domN achilles mjh pref sel +@c LocalWords: gdef loc loc loc ldots autodir remopts rwho rwho styx styx yoyo +@c LocalWords: noindent gould rvdmount rvdunmount fserver mtmp unioned logfile +@c LocalWords: dmn esac phjk toytown toytown toytown toytown phjk RdDir RdLnk +@c LocalWords: volname attrs netif dougal inaddr hwaddr ec mountmaps passno xy +@c LocalWords: freq dumpset hfs brian florence localinfo fstabs automaps defn +@c LocalWords: localname fsck'd opr gummo sjv ganymede sjv fserv fserv fserv +@c LocalWords: vaxA vaxB wp thpfs nbsd asis ifs amqprog free'ed printindex gov +@c LocalWords: LocalWords syncodeindex Distrib bsdnet lanl AutoMounter acis ic +@c LocalWords: ac uk aix bsd Mullender nl il DG lcs hpux irix ucsf NeXT cse cl +@c LocalWords: mt FX hp ibm mips utils def def Domainname eg hostd getwd tmp +@c LocalWords: subsubsection rw grpid intr noconn nocto nodevs nosuid retrans +@c LocalWords: rsize tcp timeo nounmount utimeout DDEBUG nodaemon fd hostnames +@c LocalWords: pid Amd's pendry vangogh nfsx backoff stats nomap nostats CRIT +@c LocalWords: noinfo clustername RVD dsk dsk amq hostports osver statfs str +@c LocalWords: ou counter's amdmaps proj src tftpboot sh mv cd sbin ypcat inet +@c LocalWords: Getattr getattr localhost fhandles netmask fstype noquota addr +@c LocalWords: exportfs Dumpsets dumpsets pindex ldif fixmount fixrmtab euid +@c LocalWords: lostaltmail realloc netnumber itemx primnetnum primnetname ARG +@c LocalWords: subsnetname subsnetnum netgrp netgroup multitable Shlib dec osf +@c LocalWords: hppa pc bsdi freebsd netbsd openbsd ncr sysv rs acdirmax fsid +@c LocalWords: acdirmin acregmax acregmin actimeo dumbtimr nfsv noac noauto sd +@c LocalWords: nocache nodev noint nosub pgthresh posix rdonly suid symttl mfs +@c LocalWords: AMFS umapfs myftpdir unionfs es mapname mapfile mapfile slocal +@c LocalWords: mailspool saturn saturn notknown lol ober dr xr xr drwxrwsr cfg +@c LocalWords: lrwxrwxrwx adminpr hplj adminpr cfg tekxp xterms tekxp Dupuy tp +@c LocalWords: linkname hlfsddump dirname rmtab pluto rlogin direntry pg vr dn +@c LocalWords: maxmem hlfsdir xmailbox showmount cn amdmap amdmapName resvport +@c LocalWords: objectClass amdmapKey amdmapValue ln powerpc amdmapTimestamp ez +@c LocalWords: moisil FSinfo Libtool Unmounting sublink fileservers NullProc +@c LocalWords: gethostname mount's unmounts linkx remounts unmounting UAs SA's +@c LocalWords: mountpoint mountpoints unescaped UIDs util's overlayed uref EFS +@c LocalWords: serv maxgroups nfsl cachedir copt cfsadmin efs addopts fg +@c LocalWords: nointr diff --git a/contrib/amd/doc/stamp-vti b/contrib/amd/doc/stamp-vti new file mode 100644 index 0000000..225ecdb --- /dev/null +++ b/contrib/amd/doc/stamp-vti @@ -0,0 +1,3 @@ +@set UPDATED 22 April 1998 +@set EDITION 6.0a16 +@set VERSION 6.0a16 diff --git a/contrib/amd/doc/texinfo.tex b/contrib/amd/doc/texinfo.tex new file mode 100644 index 0000000..2ce38f9 --- /dev/null +++ b/contrib/amd/doc/texinfo.tex @@ -0,0 +1,4935 @@ +%% TeX macros to handle Texinfo files. +%% $Id: texinfo.tex,v 2.218 1997/07/26 19:12:35 karl Exp $ + +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, +% 94, 95, 96, 97 Free Software Foundation, Inc. + +%This texinfo.tex file is free software; you can redistribute it and/or +%modify it under the terms of the GNU General Public License as +%published by the Free Software Foundation; either version 2, or (at +%your option) any later version. + +%This texinfo.tex file is distributed in the hope that it will be +%useful, but WITHOUT ANY WARRANTY; without even the implied warranty +%of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%General Public License for more details. + +%You should have received a copy of the GNU General Public License +%along with this texinfo.tex file; see the file COPYING. If not, write +%to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +%Boston, MA 02111-1307, USA. + + +%In other words, you are welcome to use, share and improve this program. +%You are forbidden to forbid anyone else to use, share and improve +%what you give them. Help stamp out software-hoarding! + + +% Send bug reports to bug-texinfo@prep.ai.mit.edu. +% Please include a *precise* test case in each bug report. + + +% Make it possible to create a .fmt file just by loading this file: +% if the underlying format is not loaded, start by loading it now. +% Added by gildea November 1993. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi + +% This automatically updates the version number based on RCS. +\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}} +\deftexinfoversion$Revision: 2.218 $ +\message{Loading texinfo package [Version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{} + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv = \equiv +\let\ptexi=\i +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexstar=\* +\let\ptext=\t + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English. +\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi% +\def\putwordInfo{Info}% +\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi% +\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi% +\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi% +\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi% +\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi% +\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi% +\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi% +\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi% +\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi% + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} +\hyphenation{white-space} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset +\newdimen \normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\cornerlong \newdimen\cornerthick +\newdimen\topandbottommargin +\newdimen\outerhsize \newdimen\outervsize +\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks +\outerhsize=7in +%\outervsize=9.5in +% Alternative @smallbook page size is 9.25in +\outervsize=9.25in +\topandbottommargin=.75in + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \escapechar = `\\ % use backslash in output files. + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + \shipout\vbox{% + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingxxx.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 2\baselineskip + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \turnoffactive + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment. Type Return to continue.} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Type to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt \char '100}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt \char '173}} +\def\myrbrace {{\tt \char '175}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef@lbracecmd[\{]% + @gdef@rbracecmd[\}]% +@endgroup + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown +% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @enddots{} is an end-of-sentence ellipsis. +\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000} + +% @! is an end-of-sentence bang. +\gdef\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\gdef\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000 +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output some dots + +\def\dots{$\ldots$} + +% @page forces the start of a new page + +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other% +\parsearg \commentxxx} + +\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 } + +\let\c=\comment + +% @paragraphindent is defined for the Info formatting commands only. +\let\paragraphindent=\comment + +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% +\let\chapter=\relax +\let\unnumbered=\relax +\let\top=\relax +\let\unnumberedsec=\relax +\let\unnumberedsection=\relax +\let\unnumberedsubsec=\relax +\let\unnumberedsubsection=\relax +\let\unnumberedsubsubsec=\relax +\let\unnumberedsubsubsection=\relax +\let\section=\relax +\let\subsec=\relax +\let\subsubsec=\relax +\let\subsection=\relax +\let\subsubsection=\relax +\let\appendix=\relax +\let\appendixsec=\relax +\let\appendixsection=\relax +\let\appendixsubsec=\relax +\let\appendixsubsection=\relax +\let\appendixsubsubsec=\relax +\let\appendixsubsubsection=\relax +\let\contents=\relax +\let\smallbook=\relax +\let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifnottex{\doignore{ifnottex}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% Also ignore @macro ... @end macro. The user must run texi2dvi, +% which runs makeinfo to do macro expansion. Ignore @unmacro, too. +\def\macro{\doignore{macro}} +\let\unmacro = \comment + + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory = \comment + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + \long\def\doignoretext##1\end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % Ignore braces, too, so mismatched braces don't cause trouble. + \catcode`\{ = 9 + \catcode`\} = 9 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.ai.mit.edu/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}}% +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. Make sure the catcode of space is correct to avoid +% losing inside @example, for instance. +% +\def\set{\begingroup\catcode` =10 + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +\def\value{\begingroup + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \valuexxx} +\def\valuexxx#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {\{No value for ``#1''\}}% + \else + \csname SET#1\endcsname + \fi +\endgroup} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text +% following, through the first @end iftex (etc.). Make `@end iftex' +% (etc.) valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\def\ifnothtml{\conditionalsucceed{ifnothtml}} +\def\ifnotinfo{\conditionalsucceed{ifnotinfo}} +\defineunmatchedend{iftex} +\defineunmatchedend{ifnothtml} +\defineunmatchedend{ifnotinfo} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +\def\donoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\setref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\unnumbnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\appendixnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +% @refill is a no-op. +\let\refill=\relax + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \readauxfile + \opencontents + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + % Just to be on the safe side, close the input stream before the \input. + \openin 1 texinfo.cnf + \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi + \closein1 + \temp + % + \comment % Ignore the actual filename. +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + +% \def\macro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\macroxxx} +% \def\macroxxx#1#2 \end macro{% +% \expandafter\gdef\macrotemp#1{#2}% +% \endgroup} + +%\def\linemacro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\linemacroxxx} +%\def\linemacroxxx#1#2 \end linemacro{% +%\let\parsearg=\relax +%\edef\macrotempx{\csname M\butfirst\expandafter\string\macrotemp\endcsname}% +%\expandafter\xdef\macrotemp{\parsearg\macrotempx}% +%\expandafter\gdef\macrotempx#1{#2}% +%\endgroup} + +%\def\butfirst#1{} + + +\message{fonts,} + +% Font-change commands. + +% Texinfo supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +% Use Computer Modern fonts at \magstephalf (11pt). +\newcount\mainmagstep +\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples (9pt). +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\setfont\ninett\ttshape{9}{1000} +\setfont\indrm\rmshape{9}{1000} +\setfont\indit\slshape{9}{1000} +\let\indsl=\indit +\let\indtt=\ninett +\let\indttsl=\ninett +\let\indsf=\indrm +\let\indbf=\indrm +\setfont\indsc\scshape{10}{900} +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\setfont\titleit\itbshape{10}{\magstep4} +\setfont\titlesl\slbshape{10}{\magstep4} +\setfont\titlett\ttbshape{12}{\magstep3} +\setfont\titlettsl\ttslshape{10}{\magstep4} +\setfont\titlesf\sfbshape{17}{\magstep1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} + +% Chapter (and unnumbered) fonts (17.28pt). +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{17}{1000} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +% Subsection fonts (13.15pt). +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{1315} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts \setleading{12pt}} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartitalic +\let\dfn=\smartitalic +\let\emph=\smartitalic +\let\cite=\smartitalic + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp #1{`\tclose{#1}'\null} +\setfont\smallrm\rmshape{8}{1000} +\font\smallsy=cmsy9 +\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{% + \raise0.4pt\hbox{$\langle$}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{$\langle$}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{$\rangle$}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +\let\file=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ +\catcode`\-=\active +\catcode`\_=\active +\catcode`\|=\active +\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex} +% The following is used by \doprintindex to insure that long function names +% wrap around. It is necessary for - and _ to be active before the index is +% read from the file, as \entry parses the arguments long before \code is +% ever called. -- mycroft +% _ is always active; and it shouldn't be \let = to an _ that is a +% subscript character anyway. Then, @cindex @samp{_} (for example) +% fails. --karl +\global\def\indexbreaks{% + \catcode`\-=\active \let-\realdash +} +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\def\kbdinputstyle{\parsearg\kbdinputstylexxx} +\def\kbdinputstylexxx#1{% + \def\arg{#1}% + \ifx\arg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\arg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\arg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is kbdinputdistinct. (Too much of a hassle to call the macro, +% the catcodes are wrong for parsearg to work.) +\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl} + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% @url. Quotes do not seem necessary, so use \code. +\let\url=\code + +% @uref (abbreviation for `urlref') takes an optional second argument +% specifying the text to display. First (mandatory) arg is the url. +% Perhaps eventually put in a hypertex \special here. +% +\def\uref#1{\urefxxx #1,,\finish} +\def\urefxxx#1,#2,#3\finish{% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \unhbox0\ (\code{#1})% + \else + \code{#1}% + \fi +} + +% rms does not like the angle brackets --karl, 17may97. +% So now @email is just like @uref. +%\def\email#1{$\langle${\tt #1}$\rangle$} +\let\email=\uref + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of +% @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +\def\r#1{{\rm #1}} % roman font +% Use of \lowercase was suggested. +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @pounds{} is a sterling sign. +\def\pounds{{\it\$}} + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm +% I deinstalled the following change because \cmr12 is undefined. +% This change was not in the ChangeLog anyway. --rms. +% \let\subtitlerm=\cmr12 + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefonts\rm ##1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks \evenheadline % Token sequence for heading line of even pages +\newtoks \oddheadline % Token sequence for heading line of odd pages +\newtoks \evenfootline % Token sequence for footing line of even pages +\newtoks \oddfootline % Token sequence for footing line of odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -\baselineskip + \global\advance\vsize by -\baselineskip +} + +\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{\number\day\space +\ifcase\month\or +January\or February\or March\or April\or May\or June\or +July\or August\or September\or October\or November\or December\fi +\space\number\year} + +% Use this if you want the Month Day, Year style of output. +%\def\today{\ifcase\month\or +%January\or February\or March\or April\or May\or June\or +%July\or August\or September\or October\or November\or December\fi +%\space\number\day, \number\year} + +% @settitle line... specifies the title of the document, for headings +% It generates no output of its own + +\def\thistitle{No Title} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + + +\message{tables,} + +% @tabs -- simple alignment + +% These don't work. For one thing, \+ is defined as outer. +% So these macros cannot even be defined. + +%\def\tabs{\parsearg\tabszzz} +%\def\tabszzz #1{\settabs\+#1\cr} +%\def\tabline{\parsearg\tablinezzz} +%\def\tablinezzz #1{\+#1\cr} +%\def\&{&} + +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % Be sure we are not still in the middle of a paragraph. + %{\parskip = 0in + %\par + %}% + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. Since that + % text will be indented by \tableindent, we make the item text be in + % a zero-width box. + \noindent + \rlap{\hskip -\tableindent\box0}\ignorespaces% + \endgroup% + \itemxneedsnegativevskiptrue% + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +%% Contains a kludge to get @end[description] to work +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemsize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{In hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. +% +% For those who want to use more than one line's worth of words in +% the preamble, break the line within one argument and it +% will parse correctly, i.e., +% +% @multitable {Column 1 template} {Column 2 template} {Column 3 +% template} +% Not: +% @multitable {Column 1 template} {Column 2 template} +% {Column 3 template} + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multitable or @end multitable do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. + +%%%% +% Dimensions + +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +%%%% +% Macros used to set up halign preamble: +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +%% 2/1/96, to allow fractions to be given with more than one digit. +\def\pickupwholefraction#1 {\global\advance\colcount by1 % +\expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}% +\setuptable} + +\newcount\colcount +\def\setuptable#1{\def\firstarg{#1}% +\ifx\firstarg\xendsetuptable\let\go\relax% +\else + \ifx\firstarg\xcolumnfractions\global\setpercenttrue% + \else + \ifsetpercent + \let\go\pickupwholefraction % In this case arg of setuptable + % is the decimal point before the + % number given in percent of hsize. + % We don't need this so we don't use it. + \else + \global\advance\colcount by1 + \setbox0=\hbox{#1 }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi% + \fi% +\ifx\go\pickupwholefraction\else\let\go\setuptable\fi% +\fi\go} + +%%%% +% multitable syntax +\def\tab{&\hskip1sp\relax} % 2/2/96 + % tiny skip here makes sure this column space is + % maintained, even if it is never used. + + +%%%% +% @multitable ... @end multitable definitions: + +\def\multitable{\parsearg\dotable} + +\def\dotable#1{\bgroup +\let\item\cr +\tolerance=9500 +\hbadness=9500 +\setmultitablespacing +\parskip=\multitableparskip +\parindent=\multitableparindent +\overfullrule=0pt +\global\colcount=0\relax% +\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}% + % To parse everything between @multitable and @item : +\setuptable#1 \endsetuptable + % Need to reset this to 0 after \setuptable. +\global\colcount=0\relax% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. +\halign\bgroup&\global\advance\colcount by 1\relax% +\multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % If user has set preamble in terms of percent of \hsize + % we will use that dimension as the width of the column, and + % the \leftskip will keep entries from bumping into each other. + % Table will start at left margin and final column will justify at + % right margin. +\ifnum\colcount=1 +\else + \ifsetpercent + \else + % If user has set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: +\leftskip=\multitablecolspace +\fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively marking + % characters. + \noindent\ignorespaces##\unskip\multistrut}\cr + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. +\global\everycr{\noalign{% +% \filbreak%% keeps underfull box messages off when table breaks over pages. +% Maybe so, but it also creates really weird page breaks when the table +% breaks over pages Wouldn't \vfil be better? Wait until the problem +% manifests itself, so it can be fixed for real --karl. +\global\colcount=0\relax}} +} + +\def\setmultitablespacing{% test to see if user has set \multitablelinespace. +% If so, do nothing. If not, give it an appropriate dimension based on +% current baselineskip. +\ifdim\multitablelinespace=0pt +%% strut to put in table in case some entry doesn't have descenders, +%% to keep lines equally spaced +\let\multistrut = \strut +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\else +\gdef\multistrut{\vrule height\multitablelinespace depth\dp0 +width0pt\relax} \fi +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. + +\def\newindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +\def\synindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +% (Must be a way to avoid doing expansion at all, and thus not have to +% laboriously list every single command here.) +\def\@{@}% will be @@ when we switch to @ as escape char. +%\let\{ = \lbracecmd +%\let\} = \rbracecmd +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +%\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +%\def\char{\realbackslash char}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\result{\realbackslash result}% +\def\equiv{\realbackslash equiv}% +\def\expansion{\realbackslash expansion}% +\def\print{\realbackslash print}% +\def\error{\realbackslash error}% +\def\point{\realbackslash point}% +\def\copyright{\realbackslash copyright}% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\dotless##1{\realbackslash dotless {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\,##1{\realbackslash ,{##1}}% +\def\t##1{\realbackslash t {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\sc##1{\realbackslash sc {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\def\value##1{\realbackslash value {##1}}% +\unsepspaces +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\,=\indexdummyfont +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +\let\dotless=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +\def\@{@}% +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other +@gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. + +\let\SETmarginindex=\relax %initialize! +% workhorse for all \fooindexes +% #1 is name of index, #2 is stuff to put there +\def\doind #1#2{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio=0% We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + % First process the index-string with all font commands turned off + % to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2}}% + % + % Now produce the complete index entry, with both the sort key and the + % original text, including any font commands. + \toks0 = {#2}% + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + \temp + }% + }% + \penalty\count255 + }% +} + +\def\dosubind #1#2#3{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% +\def\rawbackslashxx{\indexbackslash}% +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2 #3}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}{#3}}}% +\temp }% +}\penalty\count10}} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\def\printindex{\parsearg\doprintindex} +\def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \indexfonts \rm + \tolerance = 9500 + \indexbreaks + % + % See if the index file exists and is nonempty. + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\rawbackslashxx}% + \catcode`\\ = 0 + \catcode`\@ = 11 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +% Same as \bigskipamount except no shrink. +% \balancecolumns gets confused if there is any shrink. +\newskip\initialskipamount \initialskipamount 12pt plus4pt + +\def\initial #1{% +{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt +\ifdim\lastskip<\initialskipamount +\removelastskip \penalty-200 \vskip \initialskipamount\fi +\line{\secbf#1\hfill}\kern 2pt\penalty10000}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry #1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent=2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {\global\setbox\partialpage = \vbox{% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case, we must prevent the second \partialpage from + % simply overwriting the first, causing us to lose the page. + % This will preserve it until a real output routine can ship it + % out. Generally, \partialpage will be empty when this runs and + % this will be a no-op. + \unvbox\partialpage + % + % Unvbox the main output page. + \unvbox255 + \kern-\topskip \kern\baselineskip + }}% + \eject + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize +} +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +\def\pagesofar{% + % Re-output the contents of the output page -- any previous material, + % followed by the two boxes we just split. + \unvbox\partialpage + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% +} +\def\enddoublecolumns{% + \output = {\balancecolumns}\eject % split what we have + \endgroup % started in \begindoublecolumns + % + % Back to normal single-column typesetting, but take account of the + % fact that we just accumulated some stuff on the output page. + \pagegoal = \vsize +} +\def\balancecolumns{% + % Called at the end of the double column material. + \setbox0 = \vbox{\unvbox255}% + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {\vbadness=10000 \loop + \global\setbox3=\copy0 + \global\setbox1=\vsplit3 to\dimen@ + \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt + \repeat}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +\newwrite\contentsfile +% This is called from \setfilename. +\def\opencontents{\openout\contentsfile = \jobname.toc } + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise + +\def\thischapter{} \def\thissection{} +\def\seccheck#1{\ifnum \pageno<0 + \errmessage{@#1 not allowed after generating table of contents}% +\fi} + +\def\chapternofonts{% + \let\rawbackslash=\relax + \let\frenchspacing=\relax + \def\result{\realbackslash result}% + \def\equiv{\realbackslash equiv}% + \def\expansion{\realbackslash expansion}% + \def\print{\realbackslash print}% + \def\TeX{\realbackslash TeX}% + \def\dots{\realbackslash dots}% + \def\result{\realbackslash result}% + \def\equiv{\realbackslash equiv}% + \def\expansion{\realbackslash expansion}% + \def\print{\realbackslash print}% + \def\error{\realbackslash error}% + \def\point{\realbackslash point}% + \def\copyright{\realbackslash copyright}% + \def\tt{\realbackslash tt}% + \def\bf{\realbackslash bf}% + \def\w{\realbackslash w}% + \def\less{\realbackslash less}% + \def\gtr{\realbackslash gtr}% + \def\hat{\realbackslash hat}% + \def\char{\realbackslash char}% + \def\tclose##1{\realbackslash tclose{##1}}% + \def\code##1{\realbackslash code{##1}}% + \def\samp##1{\realbackslash samp{##1}}% + \def\r##1{\realbackslash r{##1}}% + \def\b##1{\realbackslash b{##1}}% + \def\key##1{\realbackslash key{##1}}% + \def\file##1{\realbackslash file{##1}}% + \def\kbd##1{\realbackslash kbd{##1}}% + % These are redefined because @smartitalic wouldn't work inside xdef. + \def\i##1{\realbackslash i{##1}}% + \def\cite##1{\realbackslash cite{##1}}% + \def\var##1{\realbackslash var{##1}}% + \def\emph##1{\realbackslash emph{##1}}% + \def\dfn##1{\realbackslash dfn{##1}}% +} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + + +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{\seccheck{chapter}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash chapentry{\the\toks0}{\the\chapno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +}} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{\seccheck{appendix}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 \message{Appendix \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash chapentry{\the\toks0}% + {\putwordAppendix{} \appendixletter}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +}} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\def\centerchap{\parsearg\centerchapyyy} +\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + +\outer\def\top{\parsearg\unnumberedyyy} +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{\seccheck{unnumbered}% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the to achieve this: TeX expands \the only once, +% simply yielding the contents of the . +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash unnumbchapentry{\the\toks0}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +}} + +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{\seccheck{section}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash secentry % +{\the\toks0}{\the\chapno}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{\seccheck{appendixsection}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash secentry % +{\the\toks0}{\appendixletter}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{\seccheck{unnumberedsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash unnumbsecentry{\the\toks0}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{\seccheck{subsection}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash subsecentry % +{\the\toks0}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{\seccheck{appendixsubsec}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash subsecentry % +{\the\toks0}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}% +\plainsubsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash unnumbsubsecentry{\the\toks0}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{\seccheck{subsubsection}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash subsubsecentry{\the\toks0} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno} + {\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash subsubsecentry{\the\toks0}% + {\appendixletter} + {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}% +\plainsubsubsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash unnumbsubsubsecentry{\the\toks0}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and +% such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +% @heading, @subheading, @subsubheading. +\def\heading{\parsearg\plainsecheading} +\def\subheading{\parsearg\plainsubsecheading} +\def\subsubheading{\parsearg\plainsubsubsecheading} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{ +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{ +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain +\global\let\centerchapmacro=\centerchfplain} + +% Plain chapter opening. +% #1 is the text, #2 the chapter number or empty if unnumbered. +\def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% Plain opening for unnumbered. +\def\unnchfplain#1{\chfplain{#1}{}} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% +}} + +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\penalty 10000 % +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen +\global\let\centerchapmacro=\centerchfopen} + + +% Section titles. +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} +\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} +\def\plainsecheading#1{\sectionheading{sec}{}{#1}} + +% Subsection titles. +\newskip \subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} +\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} +\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + +% Subsubsection titles. +\let\subsubsecheadingskip = \subsecheadingskip +\let\subsubsecheadingbreak = \subsecheadingbreak +\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} +\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + +% Print any size section title. +% +% #1 is the section type (sec/subsec/subsubsec), #2 is the section +% number (maybe empty), #3 the text. +\def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak +} + + +\message{toc printing,} +% Finish up the main text and prepare to read what we've written +% to \contentsfile. + +\newskip\contentsrightmargin \contentsrightmargin=1in +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout \contentsfile + \ifnum \pageno>0 + \pageno = -1 % Request roman numbered pages. + \fi + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + % We can't do this, because then an actual ^ in a section + % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97. + %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. +} + + +% Normal (long) toc. +\outer\def\contents{% + \startcontents{\putwordTableofContents}% + \input \jobname.toc + \endgroup + \vfill \eject +} + +% And just the chapters. +\outer\def\summarycontents{% + \startcontents{\putwordShortContents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \endgroup + \vfill \eject +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +% +% \turnoffactive is for the sake of @" used for umlauts. +\def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + \entry{\turnoffactive #1}{\turnoffactive #2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup +\catcode `\\=0 \catcode `\{=1 \catcode `\}=2 +\catcode `\$=3 \catcode `\&=4 \catcode `\#=6 +\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie +\catcode `\%=14 +\catcode 43=12 % plus +\catcode`\"=12 +\catcode`\==12 +\catcode`\|=12 +\catcode`\<=12 +\catcode`\>=12 +\escapechar=`\\ +% +\let\,=\ptexcomma +\let\{=\ptexlbrace +\let\}=\ptexrbrace +\let\.=\ptexdot +\let\*=\ptexstar +\let\dots=\ptexdots +\def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% +\def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% +\def\@{@}% +\let\bullet=\ptexbullet +\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext +% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \cartouche: draw rectangle w/rounded corners around argument +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% To ending an @example-like environment, we first end the paragraph +% (via \afterenvbreak's vertical glue), and then the group. That way we +% keep the zero \parskip that the environments set -- \parskip glue +% will be inserted at the beginning of the next paragraph in the +% document, after the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup}% + +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + % Make @kbd do something special, if requested. + \let\kbdfont\kbdexamplefont + \rawbackslash % have \ input char produce \ char from current font + \gobble +} + +% Define the \E... control sequence only if we are inside the +% environment, so the error checking in \end will work. +% +% We must call \lisp last in the definition, since it reads the +% return following the @example (or whatever) command. +% +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} +\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% @smallexample and @smalllisp. This is not used unless the @smallbook +% command is given. Originally contributed by Pavel@xerox. +% +\def\smalllispx{\begingroup + \nonfillstart + \let\Esmalllisp = \nonfillfinish + \let\Esmallexample = \nonfillfinish + % + % Smaller fonts for small examples. + \indexfonts \tt + \rawbackslash % make \ output the \ character from the current font (tt) + \gobble +} + +% This is @display; same as @lisp except use roman font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% This is @format; same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @flushleft (same as @format) and @flushright. +% +\def\flushleft{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushleft = \nonfillfinish + \gobble +} +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested + \global\advance\parencount by 1 +} +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. + % also in that case restore the outer-level definition of (. + \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi + \global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 } +\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 } +\def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} +\def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\dimen3=\rightskip +\advance\dimen3 by -\defbodyindent +\noindent % +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 % +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 \advance \hsize by -\dimen3 +\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +\def\defmethparsebody #1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does. +% +\def\removeemptybraces\empty#1\relax{#1} + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + #1{\removeemptybraces#2\relax}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Function}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Macro}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Special Form}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypemethodx #1 {\errmessage{@deftypemethodx in invalid context}} +\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}} + +% @defmethod, and so on + +% @defop {Funny Method} foo-class frobnicate argument + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{} on #1}% +\defunargs {#3}\endgroup % +} + +% @deftypemethod foo-class return-type foo-method args +% +\def\deftypemethod{% + \defmethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader} +% +% #1 is the class name, #2 the data type, #3 the method name, #4 the args. +\def\deftypemethodheader#1#2#3#4{% + \deftypefnheaderx{Method on #1}{#2}#3 #4\relax +} + +% @defmethod == @defop Method + +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} + +\def\defmethodheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% entry in function index +\begingroup\defname {#2}{Method on #1}% +\defunargs {#3}\endgroup % +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype{} of #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{Instance Variable of #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{Variable}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{User Option}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name, perhaps followed by text that +% is actually part of the data type, which should not be put into the index. +\def\deftypevarheader #1#2{% +\dovarind#2 \relax% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} +\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\dovarind#3 \relax% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + + +\message{cross reference,} +% Define cross-reference macros +\newwrite \auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% \setref{foo} defines a cross-reference point named foo. + +\def\setref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ysectionnumberandtype}} + +\def\unnumbsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ynothing}} + +\def\appendixsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Yappendixletterandtype}} + +% \xref, \pxref, and \ref generate cross-references to specified points. +% For \xrefX, #1 is the node name, #2 the name of the Info +% cross-reference, #3 the printed node name, #4 the name of the Info +% file, #5 the name of the printed manual. All but the node name can be +% omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1>0pt% + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive \refx{#1-snt}{}}% + \space [\printednodename],\space + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \turnoffactive so that punctuation chars such as underscore +% work in node names. +\def\dosetq #1#2{{\let\folio=0 \turnoffactive +\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% +\next}} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + $\langle$un\-de\-fined$\rangle$% + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. +\def\xrdef #1#2{{% + \catcode`\'=\other + \expandafter\gdef\csname X#1\endcsname{#2}% +}} + +% Read the last existing aux file, if any. No error if none exists. +\def\readauxfile{\begingroup + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + \catcode`\@=\other + \catcode`\^=\other + % It was suggested to define this as 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + % `\+ does not work, so use 43. + \catcode43=\other + % Make the characters 128-255 be printing characters + {% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% + }% + % The aux file uses ' as the escape (for now). + % Turn off \ as an escape so we do not lose on + % entries which were dumped with control sequences in their names. + % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ + % Reference to such entries still does not work the way one would wish, + % but at least they do not bomb out when the aux file is read in. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\%=\other + \catcode`\'=0 + \catcode`\\=\other + % + \openin 1 \jobname.aux + \ifeof 1 \else + \closein 1 + \input \jobname.aux + \global\havexrefstrue + \global\warnedobstrue + \fi + % Open the new aux file. TeX will close it automatically at exit. + \openout\auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset and anything else that uses +% \parseargline fail inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\long\gdef\footnotezzz{\insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t + \else\let\next\f@t\fi \next} +\def\f@@t{\bgroup\aftergroup\@foot\let\next} +\def\f@t#1{#1\@foot} +\def\@foot{\strut\egroup} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = xepsf.tex +\ifeof 1 \else + \closein 1 + \def\epsfannounce{\toks0 = }% do not bother showing banner + \input epsf.tex +\fi +% +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://ftp.tug.org/tex/epsf.tex.} +% +% Only complain once about lack of epsf.tex. +\def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is just the usual extra ignored arg for parsing this stuff. +\def\imagexxx#1,#2,#3,#4\finish{% + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + \epsfbox{#1.eps}% +} + +% End of control word definitions. + + +\message{and turning on texinfo input format.} + +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% Set some numeric style parameters, for 8.5 x 11 format. + +\hsize = 6in +\hoffset = .25in +\newdimen\defaultparindent \defaultparindent = 15pt +\parindent = \defaultparindent +\parskip 3pt plus 2pt minus 1pt +\setleading{13.2pt} +\advance\topskip by 1.2cm + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness=10000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. This makes it come to about 9pt for the 8.5x11 format. +% +\ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% +\else + \emergencystretch = \hsize + \divide\emergencystretch by 45 +\fi + +% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) +\def\smallbook{ + \global\chapheadingskip = 15pt plus 4pt minus 2pt + \global\secheadingskip = 12pt plus 3pt minus 2pt + \global\subsecheadingskip = 9pt plus 2pt minus 2pt + % + \global\lispnarrowing = 0.3in + \setleading{12pt} + \advance\topskip by -1cm + \global\parskip 2pt plus 1pt + \global\hsize = 5in + \global\vsize=7.5in + \global\tolerance=700 + \global\hfuzz=1pt + \global\contentsrightmargin=0pt + \global\deftypemargin=0pt + \global\defbodyindent=.5cm + % + \global\pagewidth=\hsize + \global\pageheight=\vsize + % + \global\let\smalllisp=\smalllispx + \global\let\smallexample=\smalllispx + \global\def\Esmallexample{\Esmalllisp} +} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{ +\global\tolerance=700 +\global\hfuzz=1pt +\setleading{12pt} +\global\parskip 15pt plus 1pt + +\global\vsize= 53\baselineskip +\advance\vsize by \topskip +%\global\hsize= 5.85in % A4 wide 10pt +\global\hsize= 6.5in +\global\outerhsize=\hsize +\global\advance\outerhsize by 0.5in +\global\outervsize=\vsize +\global\advance\outervsize by 0.6in + +\global\pagewidth=\hsize +\global\pageheight=\vsize +} + +\bindingoffset=0pt +\normaloffset=\hoffset +\pagewidth=\hsize +\pageheight=\vsize + +% Allow control of the text dimensions. Parameters in order: textheight; +% textwidth; voffset; hoffset; binding offset; topskip. +% All require a dimension; +% header is additional; added length extends the bottom of the page. + +\def\changepagesizes#1#2#3#4#5#6{ + \global\vsize= #1 + \global\topskip= #6 + \advance\vsize by \topskip + \global\voffset= #3 + \global\hsize= #2 + \global\outerhsize=\hsize + \global\advance\outerhsize by 0.5in + \global\outervsize=\vsize + \global\advance\outervsize by 0.6in + \global\pagewidth=\hsize + \global\pageheight=\vsize + \global\normaloffset= #4 + \global\bindingoffset= #5} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex + {\global\tolerance=700 + \global\hfuzz=1pt + \setleading{12pt} + \global\parskip 15pt plus 1pt + \advance\baselineskip by 1.6pt + \changepagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm} + } + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{\afourpaper +\changepagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt \char '042}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt \char '176}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt \char '174}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} + +%% These look ok in all fonts, so just make them not special. The @rm below +%% makes sure that the current font starts out as the newly loaded cmr10 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c page-delimiter: "^\\\\message" +@c End: diff --git a/contrib/amd/doc/version.texi b/contrib/amd/doc/version.texi new file mode 100644 index 0000000..225ecdb --- /dev/null +++ b/contrib/amd/doc/version.texi @@ -0,0 +1,3 @@ +@set UPDATED 22 April 1998 +@set EDITION 6.0a16 +@set VERSION 6.0a16 diff --git a/contrib/amd/fixmount/fixmount.8 b/contrib/amd/fixmount/fixmount.8 new file mode 100644 index 0000000..f9a87f0 --- /dev/null +++ b/contrib/amd/fixmount/fixmount.8 @@ -0,0 +1,159 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1990 Jan-Simon Pendry +.\" Copyright (c) 1990 Imperial College of Science, Technology & Medicine +.\" Copyright (c) 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jan-Simon Pendry at Imperial College, London. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" %W% (Berkeley) %G% +.\" +.\" $Id: fixmount.8,v 5.2.2.1 1992/02/09 15:11:15 jsp beta $ +.\" +.TH FIXMOUNT 8L "26 Feb 1993" +.SH NAME +fixmount \- fix remote mount entries +.SH SYNOPSIS +.B fixmount +[ +.B \-adervq +] +[ +.B \-h +.I name +] +.I host +\&... +.SH DESCRIPTION +.IX "fixmount command" "" "\fLfixmount\fP \(em fix remote mount entries" +.LP +.B fixmount +is a variant of +.BR showmount (8) +that can delete bogus mount entries in remote +.BR mountd (8C) +daemons. +The actions specified by the options are performed for each +.I host +in turn. +.SH OPTIONS +.TP +.B \-a \-d \-e +These options work as in +.BR showmount (8) +except that only entries pertaining to the local host are printed. +.TP +.B \-r +Removes those remote mount entries on +.I host +that do not correspond to current mounts, i.e., which are left-over +from a crash or are the result of improper mount protocol. +The actuality of mounts is verified using the entries in +.BR /etc/mtab . +.TP +.B \-v +Verify remote mounts. Similar to +.B \-r +except that only a notification message is printed for each bogus entry +found. The remote mount table is not changed. +.TP +.B \-A +Issues a command to the remote mountd declaring that ALL of its filesystems +have been unmounted. This should be used with caution, as it removes all +remote mount entries pertaining to the local system, whether or not any +filesystems are still mounted locally. +.TP +.B \-q +Be quiet. +Suppresses error messages due to timeouts and "Program not registered", +i.e., due to remote hosts not supporting RPC or not running mountd. +.TP +.BI \-h \ name +Pretend the local hostname is +.IR name . +This is useful after the local hostname has been changed and rmtab entries +using the old name remain on a remote machine. +Unfortunately, most mountd's won't be able to successfully handle removal +of such entries, so this option is useful in combination with +.B \-v +only. +.br +This option also saves time as comparisons of remotely recorded and local +hostnames by address are avoided. +.SH FILES +.PD 0 +.TP 20 +.B /etc/mtab +List of current mounts. +.TP +.B /etc/rmtab +Backup file for remote mount entries on NFS server. +.PD +.SH "SEE ALSO" +.BR showmount (8), +.BR mtab (5), +.BR rmtab (5), +.BR mountd (8C). +.SH BUGS +No attempt is made to verify the information in +.B /etc/mtab +itself. +.PP +Since swap file mounts are not recorded in +.BR /etc/mtab , +a heuristic specific to SunOS is used to determine whether such a mount +is actual (replacing the string "swap" with "root" and verifying the resulting +path). +.PP +Symbolic links on the server will cause the path in the remote entry to differ +from the one in +.BR /etc/mtab . +To catch those cases, a filesystem is also deemed mounted if its +.I local +mount point is identical to the remote entry. +I.e., on a SunOS diskless client, +.B server:/export/share/sunos.4.1.1 +is actually +.BR /usr/share . +Since the local mount point is +.B /usr/share +as well this will be handled correctly. +.PP +There is no way to clear a stale entry in a remote mountd after the +local hostname (or whatever reverse name resolution returns for it) +has been changed. To take care of these cases, +the remote /etc/rmtab file has to be edited and mountd restarted. +.PP +The RPC timeouts for mountd calls can only be changed by recompiling. +The defaults are 2 seconds for client handle creation and 5 seconds for +RPC calls. diff --git a/contrib/amd/fixmount/fixmount.c b/contrib/amd/fixmount/fixmount.c new file mode 100644 index 0000000..9769a41 --- /dev/null +++ b/contrib/amd/fixmount/fixmount.c @@ -0,0 +1,612 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: fixmount.c,v 5.2.2.2 1992/05/31 16:35:45 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include + +#define CREATE_TIMEOUT 2 /* seconds */ +#define CALL_TIMEOUT 5 /* seconds */ + +#ifndef INADDR_NONE +# define INADDR_NONE 0xffffffff +#endif /* not INADDR_NONE */ + +/* Constant defs */ +#define ALL 1 +#define DIRS 2 + +#define DODUMP 0x1 +#define DOEXPORTS 0x2 +#define DOREMOVE 0x4 +#define DOVERIFY 0x8 +#define DOREMALL 0x10 + +extern int fixmount_check_mount(char *host, struct in_addr hostaddr, char *path); + +static char dir_path[NFS_MAXPATHLEN]; +static char localhost[] = "localhost"; +static char thishost[MAXHOSTNAMELEN] = ""; +static exports mntexports; +static int quiet = 0; +static int type = 0; +static jmp_buf before_rpc; +static mountlist mntdump; +static struct in_addr thisaddr; +static CLIENT *clnt_create_timeout(char *, struct timeval *); + +RETSIGTYPE create_timeout(int); +int is_same_host(char *, char *, struct in_addr); +int main(int, char *[]); +int remove_all(CLIENT *, char *); +int remove_mount(CLIENT *, char *, mountlist, int); +void fix_rmtab(CLIENT *, char *, mountlist, int, int); +void print_dump(mountlist); +void usage(void); + +/* dummy variables */ +char *progname; +char hostname[MAXHOSTNAMELEN]; +int orig_umask, foreground, debug_flags; +pid_t mypid; +serv_state amd_state; + +void +usage(void) +{ + fprintf(stderr, "usage: fixmount [-adervAqf] [-h hostname] host ...\n"); + exit(1); +} + + +/* + * Check hostname against other name and its IP address + */ +int +is_same_host(char *name1, char *name2, struct in_addr addr2) +{ + if (strcasecmp(name1, name2) == 0) { + return 1; + } else if (addr2.s_addr == INADDR_NONE) { + return 0; + } else { + static char lasthost[MAXHOSTNAMELEN] = ""; + static struct in_addr addr1; + struct hostent *he; + + /* + * To save nameserver lookups, and because this function + * is typically called repeatedly on the same names, + * cache the last lookup result and reuse it if possible. + */ + if (strcasecmp(name1, lasthost) == 0) { + return (addr1.s_addr == addr2.s_addr); + } else if (!(he = gethostbyname(name1))) { + return 0; + } else { + strncpy(lasthost, name1, sizeof(lasthost) - 1); + memcpy(&addr1, he->h_addr, sizeof(addr1)); + return (addr1.s_addr == addr2.s_addr); + } + } +} + + +/* + * Print the binary tree in inorder so that output is sorted. + */ +void +print_dump(mountlist mp) +{ + if (mp == NULL) + return; + if (is_same_host(mp->ml_hostname, thishost, thisaddr)) { + switch (type) { + case ALL: + printf("%s:%s\n", mp->ml_hostname, mp->ml_directory); + break; + case DIRS: + printf("%s\n", mp->ml_directory); + break; + default: + printf("%s\n", mp->ml_hostname); + break; + }; + } + if (mp->ml_next) + print_dump(mp->ml_next); +} + + +/* + * remove entry from remote rmtab + */ +int +remove_mount(CLIENT *client, char *host, mountlist ml, int fixit) +{ + enum clnt_stat estat; + struct timeval tv; + char *pathp = dir_path; + + strncpy(dir_path, ml->ml_directory, sizeof(dir_path)); + + if (!fixit) { + printf("%s: bogus mount %s:%s\n", host, ml->ml_hostname, ml->ml_directory); + fflush(stdout); + } else { + printf("%s: removing %s:%s\n", host, ml->ml_hostname, ml->ml_directory); + fflush(stdout); + + tv.tv_sec = CALL_TIMEOUT; + tv.tv_usec = 0; + + if ((estat = clnt_call(client, + MOUNTPROC_UMNT, + (XDRPROC_T_TYPE) xdr_dirpath, + (char *) &pathp, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + tv)) != RPC_SUCCESS) { + fprintf(stderr, "%s:%s MOUNTPROC_UMNT: ", + host, ml->ml_directory); + clnt_perrno(estat); + fflush(stderr); + return -1; + } + } + return 0; +} + + +/* + * fix mount list on remote host + */ +void +fix_rmtab(CLIENT *client, char *host, mountlist mp, int fixit, int force) +{ + mountlist p; + struct hostent *he; + struct in_addr hostaddr; + + /* + * Obtain remote address for comparisons + */ + if ((he = gethostbyname(host))) { + memcpy(&hostaddr, he->h_addr, sizeof(hostaddr)); + } else { + hostaddr.s_addr = INADDR_NONE; + } + + for (p = mp; p; p = p->ml_next) { + if (is_same_host(p->ml_hostname, thishost, thisaddr)) { + if (force || !fixmount_check_mount(host, hostaddr, p->ml_directory)) + remove_mount(client, host, p, fixit); + } + } +} + + +/* + * remove all entries from remote rmtab + */ +int +remove_all(CLIENT *client, char *host) +{ + enum clnt_stat estat; + struct timeval tv; + + printf("%s: removing ALL\n", host); + fflush(stdout); + + tv.tv_sec = CALL_TIMEOUT; + tv.tv_usec = 0; + + if ((estat = clnt_call(client, + MOUNTPROC_UMNTALL, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + tv)) != RPC_SUCCESS) { + /* + * RPC_SYSTEMERROR is returned even if all went well + */ + if (estat != RPC_SYSTEMERROR) { + fprintf(stderr, "%s MOUNTPROC_UMNTALL: ", host); + clnt_perrno(estat); + fflush(stderr); + return -1; + } + } + + return 0; +} + + +/* + * This command queries the NFS mount daemon for it's mount list and/or + * it's exports list and prints them out. + * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" + * for detailed information on the protocol. + */ +int +main(int argc, char *argv[]) +{ + AUTH *auth; + CLIENT *client; + char *host; + enum clnt_stat estat; + exports exp; + extern char *optarg; + extern int optind; + groups grp; + int ch; + int force = 0; + int morethanone; + register int rpcs = 0; + struct timeval tv; + + while ((ch = getopt(argc, argv, "adervAqfh:")) != EOF) + switch ((char) ch) { + + case 'a': + if (type == 0) { + type = ALL; + rpcs |= DODUMP; + } else + usage(); + break; + + case 'd': + if (type == 0) { + type = DIRS; + rpcs |= DODUMP; + } else + usage(); + break; + + case 'e': + rpcs |= DOEXPORTS; + break; + + case 'r': + rpcs |= DOREMOVE; + break; + + case 'A': + rpcs |= DOREMALL; + break; + + case 'v': + rpcs |= DOVERIFY; + break; + + case 'q': + quiet = 1; + break; + + case 'f': + force = 1; + break; + + case 'h': + strncpy(thishost, optarg, sizeof(thishost)); + thishost[sizeof(thishost) - 1] = '\0'; + break; + + case '?': + default: + usage(); + } + + if (optind == argc) + usage(); + + if (rpcs == 0) + rpcs = DODUMP; + + if (!*thishost) { + struct hostent *he; + + if (gethostname(thishost, sizeof(thishost)) < 0) { + perror("gethostname"); + exit(1); + } + + /* + * We need the hostname as it appears to the other side's + * mountd, so get our own hostname by reverse address + * resolution. + */ + if (!(he = gethostbyname(thishost))) { + fprintf(stderr, "gethostbyname failed on %s\n", + thishost); + exit(1); + } + memcpy(&thisaddr, he->h_addr, sizeof(thisaddr)); + if (!(he = gethostbyaddr((char *) &thisaddr, sizeof(thisaddr), + he->h_addrtype))) { + fprintf(stderr, "gethostbyaddr failed on %s\n", + inet_ntoa(thisaddr)); + exit(1); + } + strncpy(thishost, he->h_name, sizeof(thishost)); + thishost[sizeof(thishost) - 1] = '\0'; + } else { + thisaddr.s_addr = INADDR_NONE; + } + + if (!(auth = authunix_create_default())) { + fprintf(stderr, "couldn't create authentication handle\n"); + exit(1); + } + morethanone = (optind + 1 < argc); + + for (; optind < argc; optind++) { + + host = argv[optind]; + tv.tv_sec = CREATE_TIMEOUT; + tv.tv_usec = 0; + + if (!(client = clnt_create_timeout(host, &tv))) + continue; + + client->cl_auth = auth; + tv.tv_sec = CALL_TIMEOUT; + tv.tv_usec = 0; + + if (rpcs & (DODUMP | DOREMOVE | DOVERIFY)) + if ((estat = clnt_call(client, + MOUNTPROC_DUMP, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + (XDRPROC_T_TYPE) xdr_mountlist, + (char *) &mntdump, + tv)) != RPC_SUCCESS) { + fprintf(stderr, "%s: MOUNTPROC_DUMP: ", host); + clnt_perrno(estat); + fflush(stderr); + mntdump = NULL; + goto next; + } + if (rpcs & DOEXPORTS) + if ((estat = clnt_call(client, + MOUNTPROC_EXPORT, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + (XDRPROC_T_TYPE) xdr_exports, + (char *) &mntexports, + tv)) != RPC_SUCCESS) { + fprintf(stderr, "%s: MOUNTPROC_EXPORT: ", host); + clnt_perrno(estat); + fflush(stderr); + mntexports = NULL; + goto next; + } + + /* Now just print out the results */ + if ((rpcs & (DODUMP | DOEXPORTS)) && + morethanone) { + printf(">>> %s <<<\n", host); + fflush(stdout); + } + + if (rpcs & DODUMP) { + print_dump(mntdump); + } + + if (rpcs & DOEXPORTS) { + exp = mntexports; + while (exp) { + printf("%-35s", exp->ex_dir); + grp = exp->ex_groups; + if (grp == NULL) { + printf("Everyone\n"); + } else { + while (grp) { + printf("%s ", grp->gr_name); + grp = grp->gr_next; + } + printf("\n"); + } + exp = exp->ex_next; + } + } + + if (rpcs & DOVERIFY) + fix_rmtab(client, host, mntdump, 0, force); + + if (rpcs & DOREMOVE) + fix_rmtab(client, host, mntdump, 1, force); + + if (rpcs & DOREMALL) + remove_all(client, host); + + next: + if (mntdump) + (void) clnt_freeres(client, + (XDRPROC_T_TYPE) xdr_mountlist, + (char *) &mntdump); + if (mntexports) + (void) clnt_freeres(client, + (XDRPROC_T_TYPE) xdr_exports, + (char *) &mntexports); + + clnt_destroy(client); + } + exit(0); + return 0; /* should never reach here */ +} + + +RETSIGTYPE +create_timeout(int sig) +{ + signal(SIGALRM, SIG_DFL); + longjmp(before_rpc, 1); +} + + +#ifndef HAVE_TRANSPORT_TYPE_TLI +/* + * inetresport creates a datagram socket and attempts to bind it to a + * secure port. + * returns: The bound socket, or -1 to indicate an error. + */ +static int +inetresport(int ty) +{ + int alport; + struct sockaddr_in addr; + int fd; + + /* Use internet address family */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + if ((fd = socket(AF_INET, ty, 0)) < 0) + return -1; + + for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) { + addr.sin_port = htons((u_short) alport); + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) + return fd; + if (errno != EADDRINUSE) { + close(fd); + return -1; + } + } + close(fd); + errno = EAGAIN; + return -1; +} + + +/* + * Privsock() calls inetresport() to attempt to bind a socket to a secure + * port. If inetresport() fails, privsock returns a magic socket number which + * indicates to RPC that it should make its own socket. + * returns: A privileged socket # or RPC_ANYSOCK. + */ +static int +privsock(int ty) +{ + int sock = inetresport(ty); + + if (sock < 0) { + errno = 0; + /* Couldn't get a secure port, let RPC make an insecure one */ + sock = RPC_ANYSOCK; + } + return sock; +} +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + +static CLIENT * +clnt_create_timeout(char *host, struct timeval *tvp) +{ + CLIENT *clnt; + struct sockaddr_in host_addr; + struct hostent *hp; +#ifndef HAVE_TRANSPORT_TYPE_TLI + int s; +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + if (setjmp(before_rpc)) { + if (!quiet) { + fprintf(stderr, "%s: ", host); + clnt_perrno(RPC_TIMEDOUT); + fprintf(stderr, "\n"); + fflush(stderr); + } + return NULL; + } + signal(SIGALRM, create_timeout); + ualarm(tvp->tv_sec * 1000000 + tvp->tv_usec, 0); + + /* + * Get address of host + */ + if ((hp = gethostbyname(host)) == 0 && !STREQ(host, localhost)) { + fprintf(stderr, "can't get address of %s\n", host); + return NULL; + } + memset(&host_addr, 0, sizeof host_addr); + host_addr.sin_family = AF_INET; + if (hp) { + memmove((voidp) &host_addr.sin_addr, (voidp) hp->h_addr, + sizeof(host_addr.sin_addr)); + } else { + /* fake "localhost" */ + host_addr.sin_addr.s_addr = htonl(0x7f000001); + } + +#ifdef HAVE_TRANSPORT_TYPE_TLI + /* try TCP first (in case return data is large), then UDP */ + clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "tcp"); + if (!clnt) + clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "udp"); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + s = RPC_ANYSOCK; + clnt = clnttcp_create(&host_addr, MOUNTPROG, MOUNTVERS, &s, 0, 0); + if (!clnt) { + /* XXX: do we need to close(s) ? */ + s = privsock(SOCK_DGRAM); + clnt = clntudp_create(&host_addr, MOUNTPROG, MOUNTVERS, *tvp, &s); + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + if (!clnt) { + ualarm(0, 0); + if (!quiet) { + clnt_pcreateerror(host); + fflush(stderr); + } + return NULL; + } + + ualarm(0, 0); + return clnt; +} diff --git a/contrib/amd/fsinfo/fsi_analyze.c b/contrib/amd/fsinfo/fsi_analyze.c new file mode 100644 index 0000000..de29913 --- /dev/null +++ b/contrib/amd/fsinfo/fsi_analyze.c @@ -0,0 +1,670 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: fsi_analyze.c,v 5.2.2.1 1992/02/09 15:09:41 jsp beta $ + * + */ + +/* + * Analyze filesystem declarations + * + * Note: most of this is magic! + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include + +char *disk_fs_strings[] = +{ + "fstype", "opts", "dumpset", "passno", "freq", "mount", "log", 0, +}; + +char *mount_strings[] = +{ + "volname", "exportfs", 0, +}; + +char *fsmount_strings[] = +{ + "as", "volname", "fstype", "opts", "from", 0, +}; + +char *host_strings[] = +{ + "host", "netif", "config", "arch", "cluster", "os", 0, +}; + +char *ether_if_strings[] = +{ + "inaddr", "netmask", "hwaddr", 0, +}; + + +/* + * Strip off the trailing part of a domain + * to produce a short-form domain relative + * to the local host domain. + * Note that this has no effect if the domain + * names do not have the same number of + * components. If that restriction proves + * to be a problem then the loop needs recoding + * to skip from right to left and do partial + * matches along the way -- ie more expensive. + */ +void +domain_strip(char *otherdom, char *localdom) +{ + char *p1, *p2; + + if ((p1 = strchr(otherdom, '.')) && + (p2 = strchr(localdom, '.')) && + STREQ(p1 + 1, p2 + 1)) + *p1 = '\0'; +} + + +/* + * Take a little-endian domain name and + * transform into a big-endian Un*x pathname. + * For example: kiska.doc.ic -> ic/doc/kiska + */ +static char * +compute_hostpath(char *hn) +{ + char *p = strdup(hn); + char *d; + char path[MAXPATHLEN]; + + domain_strip(p, hostname); + path[0] = '\0'; + + do { + d = strrchr(p, '.'); + if (d) { + *d = 0; + strcat(path, d + 1); + strcat(path, "/"); + } else { + strcat(path, p); + } + } while (d); + + log("hostpath of '%s' is '%s'", hn, path); + + strcpy(p, path); + return p; +} + + +static dict_ent * +find_volname(char *nn) +{ + dict_ent *de; + char *p = strdup(nn); + char *q; + + do { + log("Searching for volname %s", p); + de = dict_locate(dict_of_volnames, p); + q = strrchr(p, '/'); + if (q) + *q = '\0'; + } while (!de && q); + + XFREE(p); + return de; +} + + +static void +show_required(ioloc *l, int mask, char *info, char *hostname, char *strings[]) +{ + int i; + log("mask left for %s:%s is %#x", hostname, info, mask); + + for (i = 0; strings[i]; i++) + if (ISSET(mask, i)) + lerror(l, "%s:%s needs field \"%s\"", hostname, info, strings[i]); +} + + +/* + * Check and fill in "exportfs" details. + * Make sure the m_exported field references + * the most local node with an "exportfs" entry. + */ +static int +check_exportfs(qelem *q, fsi_mount *e) +{ + fsi_mount *mp; + int errors = 0; + + ITER(mp, fsi_mount, q) { + if (ISSET(mp->m_mask, DM_EXPORTFS)) { + if (e) + lwarning(mp->m_ioloc, "%s has duplicate exportfs data", mp->m_name); + mp->m_exported = mp; + if (!ISSET(mp->m_mask, DM_VOLNAME)) + set_mount(mp, DM_VOLNAME, strdup(mp->m_name)); + } else { + mp->m_exported = e; + } + + /* + * Recursively descend the mount tree + */ + if (mp->m_mount) + errors += check_exportfs(mp->m_mount, mp->m_exported); + + /* + * If a volume name has been specified, but this node and none + * of its parents has been exported, report an error. + */ + if (ISSET(mp->m_mask, DM_VOLNAME) && !mp->m_exported) { + lerror(mp->m_ioloc, "%s has a volname but no exportfs data", mp->m_name); + errors++; + } + } + + return errors; +} + + +static int +analyze_dkmount_tree(qelem *q, fsi_mount *parent, disk_fs *dk) +{ + fsi_mount *mp; + int errors = 0; + + ITER(mp, fsi_mount, q) { + log("Mount %s:", mp->m_name); + if (parent) { + char n[MAXPATHLEN]; + sprintf(n, "%s/%s", parent->m_name, mp->m_name); + if (*mp->m_name == '/') + lerror(mp->m_ioloc, "sub-directory %s of %s starts with '/'", mp->m_name, parent->m_name); + else if (STREQ(mp->m_name, "default")) + lwarning(mp->m_ioloc, "sub-directory of %s is named \"default\"", parent->m_name); + log("Changing name %s to %s", mp->m_name, n); + XFREE(mp->m_name); + mp->m_name = strdup(n); + } + + mp->m_name_len = strlen(mp->m_name); + mp->m_parent = parent; + mp->m_dk = dk; + if (mp->m_mount) + analyze_dkmount_tree(mp->m_mount, mp, dk); + } + + return errors; +} + + +/* + * The mount tree is a singleton list + * containing the top-level mount + * point for a disk. + */ +static int +analyze_dkmounts(disk_fs *dk, qelem *q) +{ + int errors = 0; + fsi_mount *mp, *mp2 = 0; + int i = 0; + + /* + * First scan the list of subdirs to make + * sure there is only one - and remember it + */ + if (q) { + ITER(mp, fsi_mount, q) { + mp2 = mp; + i++; + } + } + + /* + * Check... + */ + if (i < 1) { + lerror(dk->d_ioloc, "%s:%s has no mount point", dk->d_host->h_hostname, dk->d_dev); + return 1; + } + + if (i > 1) { + lerror(dk->d_ioloc, "%s:%s has more than one mount point", dk->d_host->h_hostname, dk->d_dev); + errors++; + } + + /* + * Now see if a default mount point is required + */ + if (STREQ(mp2->m_name, "default")) { + if (ISSET(mp2->m_mask, DM_VOLNAME)) { + char nbuf[1024]; + compute_automount_point(nbuf, dk->d_host, mp2->m_volname); + XFREE(mp2->m_name); + mp2->m_name = strdup(nbuf); + log("%s:%s has default mount on %s", dk->d_host->h_hostname, dk->d_dev, mp2->m_name); + } else { + lerror(dk->d_ioloc, "no volname given for %s:%s", dk->d_host->h_hostname, dk->d_dev); + errors++; + } + } + + /* + * Fill in the disk mount point + */ + if (!errors && mp2 && mp2->m_name) + dk->d_mountpt = strdup(mp2->m_name); + else + dk->d_mountpt = strdup("error"); + + /* + * Analyze the mount tree + */ + errors += analyze_dkmount_tree(q, 0, dk); + + /* + * Analyze the export tree + */ + errors += check_exportfs(q, 0); + + return errors; +} + + +static void +fixup_required_disk_info(disk_fs *dp) +{ + /* + * "fstype" + */ + if (ISSET(dp->d_mask, DF_FSTYPE)) { + if (STREQ(dp->d_fstype, "swap")) { + + /* + * Fixup for a swap device + */ + if (!ISSET(dp->d_mask, DF_PASSNO)) { + dp->d_passno = 0; + BITSET(dp->d_mask, DF_PASSNO); + } else if (dp->d_freq != 0) { + lwarning(dp->d_ioloc, + "Pass number for %s:%s is non-zero", + dp->d_host->h_hostname, dp->d_dev); + } + + /* + * "freq" + */ + if (!ISSET(dp->d_mask, DF_FREQ)) { + dp->d_freq = 0; + BITSET(dp->d_mask, DF_FREQ); + } else if (dp->d_freq != 0) { + lwarning(dp->d_ioloc, + "dump frequency for %s:%s is non-zero", + dp->d_host->h_hostname, dp->d_dev); + } + + /* + * "opts" + */ + if (!ISSET(dp->d_mask, DF_OPTS)) + set_disk_fs(dp, DF_OPTS, strdup("swap")); + + /* + * "mount" + */ + if (!ISSET(dp->d_mask, DF_MOUNT)) { + qelem *q = new_que(); + fsi_mount *m = new_mount(); + + m->m_name = strdup("swap"); + m->m_mount = new_que(); + ins_que(&m->m_q, q->q_back); + dp->d_mount = q; + BITSET(dp->d_mask, DF_MOUNT); + } else { + lerror(dp->d_ioloc, "%s: mount field specified for swap partition", dp->d_host->h_hostname); + } + } else if (STREQ(dp->d_fstype, "export")) { + + /* + * "passno" + */ + if (!ISSET(dp->d_mask, DF_PASSNO)) { + dp->d_passno = 0; + BITSET(dp->d_mask, DF_PASSNO); + } else if (dp->d_passno != 0) { + lwarning(dp->d_ioloc, + "pass number for %s:%s is non-zero", + dp->d_host->h_hostname, dp->d_dev); + } + + /* + * "freq" + */ + if (!ISSET(dp->d_mask, DF_FREQ)) { + dp->d_freq = 0; + BITSET(dp->d_mask, DF_FREQ); + } else if (dp->d_freq != 0) { + lwarning(dp->d_ioloc, + "dump frequency for %s:%s is non-zero", + dp->d_host->h_hostname, dp->d_dev); + } + + /* + * "opts" + */ + if (!ISSET(dp->d_mask, DF_OPTS)) + set_disk_fs(dp, DF_OPTS, strdup("rw,defaults")); + + } + } +} + + +static void +fixup_required_mount_info(fsmount *fp, dict_ent *de) +{ + if (!ISSET(fp->f_mask, FM_FROM)) { + if (de->de_count != 1) { + lerror(fp->f_ioloc, "ambiguous mount: %s is a replicated filesystem", fp->f_volname); + } else { + dict_data *dd; + fsi_mount *mp = 0; + dd = AM_FIRST(dict_data, &de->de_q); + mp = (fsi_mount *) dd->dd_data; + if (!mp) + abort(); + fp->f_ref = mp; + set_fsmount(fp, FM_FROM, mp->m_dk->d_host->h_hostname); + log("set: %s comes from %s", fp->f_volname, fp->f_from); + } + } + + if (!ISSET(fp->f_mask, FM_FSTYPE)) { + set_fsmount(fp, FM_FSTYPE, strdup("nfs")); + log("set: fstype is %s", fp->f_fstype); + } + + if (!ISSET(fp->f_mask, FM_OPTS)) { + set_fsmount(fp, FM_OPTS, strdup("rw,nosuid,grpid,defaults")); + log("set: opts are %s", fp->f_opts); + } + + if (!ISSET(fp->f_mask, FM_LOCALNAME)) { + if (fp->f_ref) { + set_fsmount(fp, FM_LOCALNAME, strdup(fp->f_volname)); + log("set: localname is %s", fp->f_localname); + } else { + lerror(fp->f_ioloc, "cannot determine localname since volname %s is not uniquely defined", fp->f_volname); + } + } +} + + +/* + * For each disk on a host + * analyze the mount information + * and fill in any derivable + * details. + */ +static void +analyze_drives(host *hp) +{ + qelem *q = hp->h_disk_fs; + disk_fs *dp; + + ITER(dp, disk_fs, q) { + int req; + log("Disk %s:", dp->d_dev); + dp->d_host = hp; + fixup_required_disk_info(dp); + req = ~dp->d_mask & DF_REQUIRED; + if (req) + show_required(dp->d_ioloc, req, dp->d_dev, hp->h_hostname, disk_fs_strings); + analyze_dkmounts(dp, dp->d_mount); + } +} + + +/* + * Check that all static mounts make sense and + * that the source volumes exist. + */ +static void +analyze_mounts(host *hp) +{ + qelem *q = hp->h_mount; + fsmount *fp; + int netbootp = 0; + + ITER(fp, fsmount, q) { + char *p; + char *nn = strdup(fp->f_volname); + int req; + dict_ent *de = (dict_ent *) NULL; + int found = 0; + int matched = 0; + + if (ISSET(fp->f_mask, FM_DIRECT)) { + found = 1; + matched = 1; + } else + do { + p = 0; + de = find_volname(nn); + log("Mount: %s (trying %s)", fp->f_volname, nn); + + if (de) { + found = 1; + + /* + * Check that the from field is really exporting + * the filesystem requested. + * LBL: If fake mount, then don't care about + * consistency check. + */ + if (ISSET(fp->f_mask, FM_FROM) && !ISSET(fp->f_mask, FM_DIRECT)) { + dict_data *dd; + fsi_mount *mp2 = 0; + + ITER(dd, dict_data, &de->de_q) { + fsi_mount *mp = (fsi_mount *) dd->dd_data; + + if (STREQ(mp->m_dk->d_host->h_hostname, fp->f_from)) { + mp2 = mp; + break; + } + } + + if (mp2) { + fp->f_ref = mp2; + matched = 1; + break; + } + } else { + matched = 1; + break; + } + } + p = strrchr(nn, '/'); + if (p) + *p = 0; + } while (de && p); + XFREE(nn); + + if (!found) { + lerror(fp->f_ioloc, "volname %s unknown", fp->f_volname); + } else if (matched) { + + fixup_required_mount_info(fp, de); + req = ~fp->f_mask & FM_REQUIRED; + if (req) { + show_required(fp->f_ioloc, req, fp->f_volname, hp->h_hostname, + fsmount_strings); + } else if (STREQ(fp->f_localname, "/")) { + hp->h_netroot = fp; + netbootp |= FM_NETROOT; + } else if (STREQ(fp->f_localname, "swap")) { + hp->h_netswap = fp; + netbootp |= FM_NETSWAP; + } + + } else { + lerror(fp->f_ioloc, "volname %s not exported from %s", fp->f_volname, + fp->f_from ? fp->f_from : "anywhere"); + } + } + + if (netbootp && (netbootp != FM_NETBOOT)) + lerror(hp->h_ioloc, "network booting requires both root and swap areas"); +} + + +void +analyze_hosts(qelem *q) +{ + host *hp; + + show_area_being_processed("analyze hosts", 5); + + /* + * Check all drives + */ + ITER(hp, host, q) { + log("disks on host %s", hp->h_hostname); + show_new("ana-host"); + hp->h_hostpath = compute_hostpath(hp->h_hostname); + + if (hp->h_disk_fs) + analyze_drives(hp); + + } + + show_area_being_processed("analyze mounts", 5); + + /* + * Check static mounts + */ + ITER(hp, host, q) { + log("mounts on host %s", hp->h_hostname); + show_new("ana-mount"); + if (hp->h_mount) + analyze_mounts(hp); + + } +} + + +/* + * Check an automount request + */ +static void +analyze_automount(automount *ap) +{ + dict_ent *de = find_volname(ap->a_volname); + + if (de) { + ap->a_mounted = de; + } else { + if (STREQ(ap->a_volname, ap->a_name)) + lerror(ap->a_ioloc, "unknown volname %s automounted", ap->a_volname); + else + lerror(ap->a_ioloc, "unknown volname %s automounted on %s", ap->a_volname, ap->a_name); + } +} + + +static void +analyze_automount_tree(qelem *q, char *pref, int lvl) +{ + automount *ap; + + ITER(ap, automount, q) { + char nname[1024]; + + if (lvl > 0 || ap->a_mount) + if (ap->a_name[1] && strchr(ap->a_name + 1, '/')) + lerror(ap->a_ioloc, "not allowed '/' in a directory name"); + sprintf(nname, "%s/%s", pref, ap->a_name); + XFREE(ap->a_name); + ap->a_name = strdup(nname[1] == '/' ? nname + 1 : nname); + log("automount point %s:", ap->a_name); + show_new("ana-automount"); + + if (ap->a_mount) { + analyze_automount_tree(ap->a_mount, ap->a_name, lvl + 1); + } else if (ap->a_hardwiredfs) { + log("\thardwired from %s to %s", ap->a_volname, ap->a_hardwiredfs); + } else if (ap->a_volname) { + log("\tautomount from %s", ap->a_volname); + analyze_automount(ap); + } else if (ap->a_symlink) { + log("\tsymlink to %s", ap->a_symlink); + } else { + ap->a_volname = strdup(ap->a_name); + log("\timplicit automount from %s", ap->a_volname); + analyze_automount(ap); + } + } +} + + +void +analyze_automounts(qelem *q) +{ + auto_tree *tp; + + show_area_being_processed("analyze automount", 5); + + /* + * q is a list of automounts + */ + ITER(tp, auto_tree, q) + analyze_automount_tree(tp->t_mount, "", 0); +} diff --git a/contrib/amd/fsinfo/fsi_data.h b/contrib/amd/fsinfo/fsi_data.h new file mode 100644 index 0000000..07b7b9e --- /dev/null +++ b/contrib/amd/fsinfo/fsi_data.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: fsi_data.h,v 5.2.2.1 1992/02/09 15:09:53 jsp beta $ + * + */ + +typedef struct auto_tree auto_tree; +typedef struct automount automount; +typedef struct dict dict; +typedef struct dict_data dict_data; +typedef struct dict_ent dict_ent; +typedef struct disk_fs disk_fs; +typedef struct ether_if ether_if; +typedef struct fsmount fsmount; +typedef struct host host; +typedef struct ioloc ioloc; +typedef struct fsi_mount fsi_mount; + + +/* + * Automount tree + */ +struct automount { + qelem a_q; + ioloc *a_ioloc; + char *a_name; /* Automount key */ + char *a_volname; /* Equivalent volume to be referenced */ + char *a_symlink; /* Symlink representation */ + char *a_opts; /* opts for mounting */ + char *a_hardwiredfs; /* hack to bypass bogus fs definitions */ + qelem *a_mount; /* Tree representation */ + dict_ent *a_mounted; +}; + +/* + * List of automount trees + */ +struct auto_tree { + qelem t_q; + ioloc *t_ioloc; + char *t_defaults; + qelem *t_mount; +}; + +/* + * A host + */ +struct host { + qelem q; + int h_mask; + ioloc *h_ioloc; + fsmount *h_netroot, *h_netswap; +#define HF_HOST 0 + char *h_hostname; /* The full name of the host */ + char *h_lochost; /* The name of the host with local domains * + * * * stripped */ + char *h_hostpath; /* The filesystem path to the host (cf * * * + * compute_hostpath) */ +#define HF_ETHER 1 + qelem *h_ether; +#define HF_CONFIG 2 + qelem *h_config; +#define HF_ARCH 3 + char *h_arch; +#define HF_CLUSTER 4 + char *h_cluster; +#define HF_OS 5 + char *h_os; + qelem *h_disk_fs; + qelem *h_mount; +}; + +/* + * An ethernet interface + */ +struct ether_if { + qelem e_q; + int e_mask; + ioloc *e_ioloc; + char *e_if; +#define EF_INADDR 0 + struct in_addr e_inaddr; +#define EF_NETMASK 1 + u_long e_netmask; +#define EF_HWADDR 2 + char *e_hwaddr; +}; + +/* + * Disk filesystem structure. + * + * If the DF_* numbers are changed + * disk_fs_strings in analyze.c will + * need updating. + */ +struct disk_fs { + qelem d_q; + int d_mask; + ioloc *d_ioloc; + host *d_host; + char *d_mountpt; + char *d_dev; +#define DF_FSTYPE 0 + char *d_fstype; +#define DF_OPTS 1 + char *d_opts; +#define DF_DUMPSET 2 + char *d_dumpset; +#define DF_PASSNO 3 + int d_passno; +#define DF_FREQ 4 + int d_freq; +#define DF_MOUNT 5 + qelem *d_mount; +#define DF_LOG 6 + char *d_log; +}; + +#define DF_REQUIRED ((1< +#endif /* HAVE_CONFIG_H */ +#include +#include +#include + + +static int +dict_hash(char *k) +{ + u_int h; + + for (h = 0; *k; h += *k++) ; + return h % DICTHASH; +} + + +dict * +new_dict(void) +{ + dict *dp = CALLOC(struct dict); + + return dp; +} + + +static void +dict_add_data(dict_ent *de, char *v) +{ + dict_data *dd = CALLOC(struct dict_data); + + dd->dd_data = v; + ins_que(&dd->dd_q, de->de_q.q_back); + de->de_count++; +} + + +static dict_ent * +new_dict_ent(char *k) +{ + dict_ent *de = CALLOC(struct dict_ent); + + de->de_key = k; + init_que(&de->de_q); + return de; +} + + +dict_ent * +dict_locate(dict *dp, char *k) +{ + dict_ent *de = dp->de[dict_hash(k)]; + + while (de && !STREQ(de->de_key, k)) + de = de->de_next; + return de; +} + + +void +dict_add(dict *dp, char *k, char *v) +{ + dict_ent *de = dict_locate(dp, k); + + if (!de) { + dict_ent **dep = &dp->de[dict_hash(k)]; + de = new_dict_ent(k); + de->de_next = *dep; + *dep = de; + } + dict_add_data(de, v); +} + + +int +dict_iter(dict *dp, int (*fn) (qelem *)) +{ + int i; + int errors = 0; + + for (i = 0; i < DICTHASH; i++) { + dict_ent *de = dp->de[i]; + while (de) { + errors += (*fn) (&de->de_q); + de = de->de_next; + } + } + return errors; +} diff --git a/contrib/amd/fsinfo/fsi_gram.y b/contrib/amd/fsinfo/fsi_gram.y new file mode 100644 index 0000000..b325c77 --- /dev/null +++ b/contrib/amd/fsinfo/fsi_gram.y @@ -0,0 +1,419 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: fsi_gram.y,v 5.2.2.1 1992/02/09 15:09:35 jsp beta $ + * + */ + +%{ +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include + +extern qelem *list_of_hosts, *list_of_automounts; +%} + +%union { + auto_tree *a; + disk_fs *d; + ether_if *e; + host *h; + qelem *q; + char *s; + fsi_mount *m; + fsmount *f; +} + +%token tARCH +%token tAS +%token tAUTOMOUNT +%token tCLUSTER +%token tCONFIG +%token tDUMPSET +%token tEQ +%token tNFSEQ +%token tEXPORTFS +%token tFREQ +%token tFROM +%token tFS +%token tFSTYPE +%token tHWADDR +%token tINADDR +%token tHOST +%token tLOCALHOST +%token tLOG +%token tMOUNT +%token tNETMASK +%token tNETIF +%token tVOLNAME +%token tOPTS +%token tOS +%token tPASSNO +%token tDIRECT +%token tSEL +%token tSTR + +%start list_of_hosts + +%type automount +%type automount_tree +%type ether_attr +%type dir_tree_info +%type filesystem fs_info_list +%type host host_attr host_attr_list +%type list_of_hosts list_of_filesystems list_of_mounts dir_tree +%type localinfo_list +%type opt_auto_opts + +%% + +list_of_hosts : + /* empty */ + { $$ = new_que(); } + + | list_of_hosts host + { if ($2) ins_que((qelem *) $2, list_of_hosts->q_back); + $$ = $1; } + + | list_of_hosts automount + { if ($2) ins_que((qelem *) $2, list_of_automounts->q_back); + $$ = $1; } + ; + +/* + * A new host: + * + * host foo.domain + */ +host : + tHOST host_attr list_of_filesystems list_of_mounts + { $$ = $2; $$->h_disk_fs = $3; $$->h_mount = $4; } + + | error tHOST host_attr list_of_filesystems list_of_mounts + { $$ = $3; $$->h_disk_fs = $4; $$->h_mount = $5; } + + ; + +host_attr : + tSTR + { $$ = new_host(); set_host($$, HF_HOST, $1); } + + | '{' host_attr_list '}' tSTR + { $$ = $2; set_host($$, HF_HOST, $4); } + + ; + +host_attr_list : + /* empty */ + { $$ = new_host(); } + + | host_attr_list tNETIF tSTR '{' ether_attr '}' + { if ($5) { + $5->e_if = $3; + $$ = $1; set_host($$, HF_ETHER, (char *) $5); } + } + + | host_attr_list tCONFIG tSTR + { $$ = $1; set_host($$, HF_CONFIG, $3); } + + | host_attr_list tARCH '=' tSTR + { $$ = $1; set_host($$, HF_ARCH, $4); } + + | host_attr_list tOS '=' tSTR + { $$ = $1; set_host($$, HF_OS, $4); } + + | host_attr_list tCLUSTER '=' tSTR + { $$ = $1; set_host($$, HF_CLUSTER, $4); } + + | host_attr_list error '=' tSTR + { yyerror("unknown host attribute"); } + ; + +ether_attr : + /* empty */ + { $$ = new_ether_if(); } + + | ether_attr tINADDR '=' tSTR + { $$ = $1; set_ether_if($$, EF_INADDR, $4); } + | ether_attr tNETMASK '=' tSTR + { $$ = $1; set_ether_if($$, EF_NETMASK, $4); } + | ether_attr tHWADDR '=' tSTR + { $$ = $1; set_ether_if($$, EF_HWADDR, $4); } + ; + +/* + * A new automount tree: + * + * automount /mountpoint { ... } + */ +automount : + tAUTOMOUNT opt_auto_opts automount_tree + { if ($3) { + $$ = new_auto_tree($2, $3); + } else { + $$ = 0; + } + } + + | tAUTOMOUNT error + { $$ = 0; } + ; + +opt_auto_opts : + /* empty */ + { $$ = strdup(""); } + + | tOPTS tSTR + { $$ = $2; } + ; + +list_of_filesystems : + /* empty */ + { $$ = 0; } + + | list_of_filesystems filesystem + { if ($2) { + if ($1) + $$ = $1; + else + $$ = new_que(); + ins_que(&$2->d_q, $$->q_back); + } else { + $$ = $1; + } + } + ; + +/* + * A new filesystem: + * + * fs /dev/whatever { ... } + */ +filesystem : + tFS tSTR '{' fs_info_list '}' + { $4->d_dev = $2; $$ = $4; } + + | tFS error '}' + { $$ = (disk_fs *) 0; } + ; + +/* + * Per-filesystem information: + * + * fstype - the type of the filesystem (4.2, nfs, swap, export) + * opts - the mount options ("rw,grpid") + * passno - fsck pass number + * freq - dump frequency + * dumpset - tape set for filesystem dumps + * mount - where to mount this filesystem + * log - log device + */ +fs_info_list : + /* empty */ + { $$ = new_disk_fs(); } + + | fs_info_list tFSTYPE '=' tSTR + { $$ = $1; set_disk_fs($$, DF_FSTYPE, $4); } + + | fs_info_list tOPTS '=' tSTR + { $$ = $1; set_disk_fs($$, DF_OPTS, $4); } + + | fs_info_list tPASSNO '=' tSTR + { $$ = $1; set_disk_fs($$, DF_PASSNO, $4); } + + | fs_info_list tFREQ '=' tSTR + { $$ = $1; set_disk_fs($$, DF_FREQ, $4); } + + | fs_info_list tMOUNT dir_tree + { $$ = $1; set_disk_fs($$, DF_MOUNT, (char *) $3); } + + | fs_info_list tDUMPSET '=' tSTR + { $$ = $1; set_disk_fs($$, DF_DUMPSET, $4); } + + | fs_info_list tLOG '=' tSTR + { $$ = $1; set_disk_fs($$, DF_LOG, $4); } + + | fs_info_list error '=' tSTR + { yyerror("unknown filesystem attribute"); } + ; + +/* + * An automount tree: + * + * name = "volname" name is a reference to volname + * name -> "string" name is a link to "string" + * name nfsalias "string" name is a link to "string", string parsed as NFS + * pathname. + * name { ... } name is an automount tree + */ +automount_tree : + /* empty */ + { $$ = 0; } + + | automount_tree tSTR opt_auto_opts '=' tSTR + { automount *a = new_automount($2); + a->a_volname = $5; + a->a_opts = $3; + if ($1) + $$ = $1; + else + $$ = new_que(); + ins_que(&a->a_q, $$->q_back); + } + | automount_tree tSTR opt_auto_opts tNFSEQ tSTR + { automount *a = new_automount($2); + a->a_hardwiredfs = $5; + a->a_opts = $3; + if ($1) + $$ = $1; + else + $$ = new_que(); + ins_que(&a->a_q, $$->q_back); + } + + | automount_tree tSTR tEQ tSTR + { automount *a = new_automount($2); + a->a_symlink = $4; + if ($1) + $$ = $1; + else + $$ = new_que(); + ins_que(&a->a_q, $$->q_back); + } + + | automount_tree tSTR opt_auto_opts '{' automount_tree '}' + { automount *a = new_automount($2); + a->a_mount = $5; + a->a_opts = $3; + if ($1) + $$ = $1; + else + $$ = new_que(); + ins_que(&a->a_q, $$->q_back); + } + ; + +dir_tree : + /* empty */ + { $$ = 0; } + + | dir_tree tSTR '{' dir_tree_info dir_tree '}' + { $4->m_mount = $5; + $4->m_name = $2; + if ($2[0] != '/' && $2[1] && strchr($2+1, '/')) + yyerror("not allowed '/' in a directory name"); + if ($1) + $$ = $1; + else + $$ = new_que(); + ins_que(&$4->m_q, $$->q_back); + } + ; + +dir_tree_info : + /* empty */ + { $$ = new_mount(); } + + | dir_tree_info tEXPORTFS tSTR + { $$ = $1; set_mount($$, DM_EXPORTFS, $3); } + + | dir_tree_info tVOLNAME tSTR + { $$ = $1; set_mount($$, DM_VOLNAME, $3); } + + | dir_tree_info tSEL tSTR + { $$ = $1; set_mount($$, DM_SEL, $3); } + + | dir_tree_info error '=' tSTR + { yyerror("unknown directory attribute"); } + ; + +/* + * Additional mounts on a host + * + * mount "volname" ... + */ +list_of_mounts : + /* empty */ + { $$ = 0; } + + | list_of_mounts tMOUNT tSTR localinfo_list + { set_fsmount($4, FM_VOLNAME, $3); + if ($1) + $$ = $1; + else + $$ = new_que(); + ins_que(&$4->f_q, $$->q_back); + } + ; + +/* + * Mount info: + * + * from "hostname" - obtain the object from the named host + * as "string" - where to mount, if different from the volname + * opts "string" - mount options + * fstype "type" - type of filesystem mount, if not nfs + * direct - mount entry, no need to create ad-hoc hosts file + */ +localinfo_list : + /* empty */ + { $$ = new_fsmount(); } + + | localinfo_list tDIRECT + { $$ = $1; set_fsmount($$, FM_DIRECT, ""); } + + | localinfo_list tAS tSTR + { $$ = $1; set_fsmount($$, FM_LOCALNAME, $3); } + + | localinfo_list tFROM tSTR + { $$ = $1; set_fsmount($$, FM_FROM, $3); } + + | localinfo_list tFSTYPE tSTR + { $$ = $1; set_fsmount($$, FM_FSTYPE, $3); } + + | localinfo_list tOPTS tSTR + { $$ = $1; set_fsmount($$, FM_OPTS, $3); } + + | localinfo_list error '=' tSTR + { yyerror("unknown mount attribute"); } + ; diff --git a/contrib/amd/fsinfo/fsi_lex.l b/contrib/amd/fsinfo/fsi_lex.l new file mode 100644 index 0000000..98b1976 --- /dev/null +++ b/contrib/amd/fsinfo/fsi_lex.l @@ -0,0 +1,270 @@ +%{ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: fsi_lex.l,v 5.2.2.1 1992/02/09 15:09:36 jsp beta $ + * + */ + +/* + * Lexical analyzer for fsinfo. + * TODO: Needs rewriting. + */ + +#ifdef FLEX_SCANNER +static int yylineno; +# define INIT_STATE { \ + switch ((yy_start - 1) / 2) { \ + case 0: \ + BEGIN F; \ + break; \ + } \ +} + +#else /* not FLEX_SCANNER */ + +/* + * Using old lex... + */ +# define INIT_STATE { \ + switch (yybgin - yysvec - 1) { \ + case 0: \ + BEGIN F; \ + break; \ + } \ +} + +#endif /* end FLEX_SCANNER */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +/* + * Some systems include a definition for the macro ECHO in , + * and their (bad) version of lex defines it too at the very beginning of + * the generated lex.yy.c file (before it can be easily undefined), + * resulting in a conflict. So undefine it here before needed. + * Luckily, it does not appear that this macro is actually used in the rest + * of the generated lex.yy.c file. + */ +#ifdef ECHO +# undef ECHO +#endif /* ECHO */ +#include +#include +#include +#include +/* and once again undefine this, just in case */ +#ifdef ECHO +# undef ECHO +#endif /* ECHO */ + +/* + * There are some things that need to be defined only if useing GNU flex. + * These must not be defined if using standard lex + */ +#ifdef FLEX_SCANNER +# ifndef ECHO +# define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +# endif /* not ECHO */ +#endif /* FLEX_SCANNER */ + +/* + * some systems such as DU-4.x have a different GNU flex in /usr/bin + * which automatically generates yywrap macros and symbols. So I must + * distinguish between them and when yywrap is actually needed. + */ +#ifndef yywrap +int yywrap(void); +#endif /* not yywrap */ + +YYSTYPE yylval; +static char *fsi_filename; +static char *optr; +static char ostr[1024]; +static int find_resword(char *); +static int quoted; + +struct r { + char *rw; + int tok; +} rr[] = { + { "->", tEQ }, + { "arch", tARCH }, + { "as", tAS }, + { "automount", tAUTOMOUNT }, + { "cluster", tCLUSTER }, + { "config", tCONFIG }, + { "direct", tDIRECT }, + { "dumpset", tDUMPSET }, + { "exportfs", tEXPORTFS }, + { "freq", tFREQ }, + { "from", tFROM }, + { "fs", tFS }, + { "fstype", tFSTYPE }, + { "host", tHOST }, + { "hwaddr", tHWADDR }, + { "inaddr", tINADDR }, + { "localhost", tLOCALHOST }, + { "log", tLOG }, + { "mount", tMOUNT }, + { "netif", tNETIF }, + { "netmask", tNETMASK }, + { "nfsalias", tNFSEQ }, + { "opts", tOPTS }, + { "os", tOS }, + { "passno", tPASSNO }, + { "sel", tSEL }, + { "volname", tVOLNAME }, + { 0, 0 }, +}; +#define NRES_WORDS (sizeof(rr)/sizeof(rr[0])-1) + +%} + +%start F Q + +%% + INIT_STATE; /* witchcraft */ + +[^ \t\n"={}]+ { return find_resword(yytext); } /* dummy " */ +[ \t] ; +"\n" { yylineno++; } +[={}] { return *yytext; } + +\" { BEGIN Q; optr = ostr; quoted = 1; } +\n { yylineno++; yyerror("\" expected"); BEGIN F; } +\\b { *optr++ = '\b'; /* escape */ } +\\t { *optr++ = '\t'; /* escape */ } +\\\" { *optr++ = '\"'; /* escape */ } +\\\\ { *optr++ = '\\'; /* escape */ } +\\\n { yylineno++; /* continue */ } +\\r { *optr++ = '\r'; /* escape */ } +\\n { *optr++ = '\n'; /* escape */ } +\\f { *optr++ = '\f'; /* escape */ } +"\\ " { *optr++ = ' '; /* force space */ } +\\. { yyerror("Unknown \\ sequence"); } +([ \t]|"\\\n"){2,} { char *p = (char *) yytext-1; while ((p = strchr(p+1, '\n'))) yylineno++; } +\" { BEGIN F; quoted = 0; + *optr = '\0'; + yylval.s = strdup(ostr); + return tSTR; + } +. { *optr++ = *yytext; } + +%% + + +static int +find_resword(char *s) +{ + int tok = 0; + int l = 0, m = NRES_WORDS/2, h = NRES_WORDS-1; + int rc = 0; + + m = NRES_WORDS/2; + +#define FSTRCMP(p, q) ((*(p) == *(q)) ? strcmp((p)+1, (q)+1) : *(p) - *(q)) + + while ((l <= h) && (rc = FSTRCMP(s, rr[m].rw))) { + if (rc < 0) + h = m - 1; + else + l = m + 1; + m = (h + l) / 2; + } + + if (rc == 0) + tok = rr[m].tok; + + switch (tok) { + case tLOCALHOST: + s = "${host}"; + /* fall through... */ + case 0: + yylval.s = strdup(s); + tok = tSTR; + /* fall through... */ + default: + return tok; + } +} + + +int +yyerror(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + col_cleanup(0); + fprintf(stderr, "%s:%d: ", fsi_filename ? fsi_filename : "/dev/stdin", yylineno); + fprintf(stderr, fmt, ap); + fputc('\n', stderr); + parse_errors++; + va_end(ap); + return 0; + + /* this call will never happen */ + unput(0); +} + + +ioloc * +current_location(void) +{ + ioloc *ip = CALLOC(struct ioloc); + ip->i_line = yylineno; + ip->i_file = fsi_filename; + return ip; +} + + +/* + * some systems such as DU-4.x have a different GNU flex in /usr/bin + * which automatically generates yywrap macros and symbols. So I must + * distinguish between them and when yywrap is actually needed. + */ +#ifndef yywrap +int yywrap(void) +{ + return 1; +} +#endif /* not yywrap */ diff --git a/contrib/amd/fsinfo/fsi_util.c b/contrib/amd/fsinfo/fsi_util.c new file mode 100644 index 0000000..d69c459 --- /dev/null +++ b/contrib/amd/fsinfo/fsi_util.c @@ -0,0 +1,693 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: fsi_util.c,v 5.2.2.1 1992/02/09 15:09:39 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include + +/* static variables */ +static int show_range = 10; +static int col = 0; +static int total_shown = 0; +static int total_mmm = 8; + + +static int +col_output(int len) +{ + int wrapped = 0; + + col += len; + if (col > 77) { + fputc('\n', stdout); + col = len; + wrapped = 1; + } + return wrapped; +} + + +static void +show_total(void) +{ + if (total_mmm != -show_range + 1) { + char n[8]; + int len; + + if (total_mmm < 0) + fputc('*', stdout); + sprintf(n, "%d", total_shown); + len = strlen(n); + if (col_output(len)) + fputc(' ', stdout); + fputs(n, stdout); + fflush(stdout); + total_mmm = -show_range; + } +} + + +void +col_cleanup(int eoj) +{ + if (verbose < 0) + return; + if (eoj) { + show_total(); + fputs(")]", stdout); + } + if (col) { + fputc('\n', stdout); + col = 0; + } +} + + +/* + * Lots of ways of reporting errors... + */ +void +error(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + col_cleanup(0); + fprintf(stderr, "%s: Error, ", progname); + fprintf(stderr, fmt, ap); + fputc('\n', stderr); + errors++; + va_end(ap); +} + + +void +lerror(ioloc *l, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + col_cleanup(0); + fprintf(stderr, "%s:%d: ", l->i_file, l->i_line); + fprintf(stderr, fmt, ap); + fputc('\n', stderr); + errors++; + va_end(ap); +} + + +void +lwarning(ioloc *l, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + col_cleanup(0); + fprintf(stderr, "%s:%d: ", l->i_file, l->i_line); + fprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); +} + + +void +fatal(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + col_cleanup(1); + fprintf(stderr, "%s: Fatal, ", progname); + fprintf(stderr, fmt, ap); + fputc('\n', stderr); + va_end(ap); + exit(1); +} + + +/* + * Debug log + */ +void +log(char *fmt, ...) +{ + va_list ap; + + if (verbose > 0) { + va_start(ap, fmt); + fputc('#', stdout); + fprintf(stdout, "%s: ", progname); + fprintf(stdout, fmt, ap); + putc('\n', stdout); + va_end(ap); + } +} + + +void +info_hdr(FILE *ef, char *info) +{ + fprintf(ef, "# *** NOTE: This file contains %s info\n", info); +} + + +void +gen_hdr(FILE *ef, char *hn) +{ + fprintf(ef, "# *** NOTE: Only for use on %s\n", hn); +} + + +static void +make_banner(FILE *fp) +{ + time_t t = time((time_t *) 0); + char *cp = ctime(&t); + + fprintf(fp, + "\ +# *** This file was automatically generated -- DO NOT EDIT HERE ***\n\ +# \"%s\" run by %s@%s on %s\ +#\n\ +", + progname, username, hostname, cp); +} + + +void +show_new(char *msg) +{ + if (verbose < 0) + return; + + total_shown++; + if (total_mmm > show_range) { + show_total(); + } else if (total_mmm == 0) { + fputc('*', stdout); + fflush(stdout); + col += 1; + } + total_mmm++; +} + + +void +show_area_being_processed(char *area, int n) +{ + static char *last_area = 0; + + if (verbose < 0) + return; + if (last_area) { + if (total_shown) + show_total(); + fputs(")", stdout); + col += 1; + } + + if (!last_area || !STREQ(area, last_area)) { + if (last_area) { + col_cleanup(0); + total_shown = 0; + total_mmm = show_range + 1; + } + (void) col_output(strlen(area) + 2); + fprintf(stdout, "[%s", area); + last_area = area; + } + + fputs(" (", stdout); + col += 2; + show_range = n; + total_mmm = n + 1; + + fflush(stdout); +} + + +/* + * Open a file with the given prefix and name + */ +FILE * +pref_open(char *pref, char *hn, void (*hdr) (FILE *, char *), char *arg) +{ + char p[MAXPATHLEN]; + FILE *ef; + + sprintf(p, "%s%s", pref, hn); + log("Writing %s info for %s to %s", pref, hn, p); + ef = fopen(p, "w"); + if (ef) { + (*hdr) (ef, arg); + make_banner(ef); + } else { + error("can't open %s for writing", p); + } + + return ef; +} + + +int +pref_close(FILE *fp) +{ + return fclose(fp) == 0; +} + + +/* + * Determine where Amd would automount the host/volname pair + */ +void +compute_automount_point(char *buf, host *hp, char *vn) +{ + sprintf(buf, "%s/%s%s", autodir, hp->h_lochost, vn); +} + + +char * +xcalloc(int i, int s) +{ + char *p = (char *) calloc(i, (unsigned) s); + + if (!p) + fatal("Out of memory"); + return p; +} + + +/* + * Data constructors.. + */ +automount * +new_automount(char *name) +{ + automount *ap = CALLOC(struct automount); + + ap->a_ioloc = current_location(); + ap->a_name = name; + ap->a_volname = 0; + ap->a_mount = 0; + ap->a_opts = 0; + show_new("automount"); + return ap; +} + + +auto_tree * +new_auto_tree(char *def, qelem *ap) +{ + auto_tree *tp = CALLOC(struct auto_tree); + + tp->t_ioloc = current_location(); + tp->t_defaults = def; + tp->t_mount = ap; + show_new("auto_tree"); + return tp; +} + + +host * +new_host(void) +{ + host *hp = CALLOC(struct host); + + hp->h_ioloc = current_location(); + hp->h_mask = 0; + show_new("host"); + return hp; +} + + +void +set_host(host *hp, int k, char *v) +{ + int m = 1 << k; + + if (hp->h_mask & m) { + yyerror("host field \"%s\" already set", host_strings[k]); + return; + } + hp->h_mask |= m; + + switch (k) { + + case HF_HOST:{ + char *p = strdup(v); + dict_ent *de = dict_locate(dict_of_hosts, v); + + if (de) + yyerror("duplicate host %s!", v); + else + dict_add(dict_of_hosts, v, (char *) hp); + hp->h_hostname = v; + domain_strip(p, hostname); + if (strchr(p, '.') != 0) + XFREE(p); + else + hp->h_lochost = p; + } + break; + + case HF_CONFIG:{ + qelem *q; + qelem *vq = (qelem *) v; + + hp->h_mask &= ~m; + if (hp->h_config) + q = hp->h_config; + else + q = hp->h_config = new_que(); + ins_que(vq, q->q_back); + } + break; + + case HF_ETHER:{ + qelem *q; + qelem *vq = (qelem *) v; + + hp->h_mask &= ~m; + if (hp->h_ether) + q = hp->h_ether; + else + q = hp->h_ether = new_que(); + ins_que(vq, q->q_back); + } + break; + + case HF_ARCH: + hp->h_arch = v; + break; + + case HF_OS: + hp->h_os = v; + break; + + case HF_CLUSTER: + hp->h_cluster = v; + break; + + default: + abort(); + break; + } +} + + +ether_if * +new_ether_if(void) +{ + ether_if *ep = CALLOC(struct ether_if); + + ep->e_mask = 0; + ep->e_ioloc = current_location(); + show_new("ether_if"); + return ep; +} + + +void +set_ether_if(ether_if *ep, int k, char *v) +{ + int m = 1 << k; + + if (ep->e_mask & m) { + yyerror("netif field \"%s\" already set", ether_if_strings[k]); + return; + } + ep->e_mask |= m; + + switch (k) { + + case EF_INADDR:{ + ep->e_inaddr.s_addr = inet_addr(v); + if (ep->e_inaddr.s_addr == (u_long) - 1) + yyerror("malformed IP dotted quad: %s", v); + XFREE(v); + } + break; + + case EF_NETMASK:{ + u_long nm = 0; + + if ((sscanf(v, "0x%lx", &nm) == 1 || sscanf(v, "%lx", &nm) == 1) && nm != 0) + ep->e_netmask = htonl(nm); + else + yyerror("malformed netmask: %s", v); + XFREE(v); + } + break; + + case EF_HWADDR: + ep->e_hwaddr = v; + break; + + default: + abort(); + break; + } +} + + +void +set_disk_fs(disk_fs *dp, int k, char *v) +{ + int m = 1 << k; + + if (dp->d_mask & m) { + yyerror("fs field \"%s\" already set", disk_fs_strings[k]); + return; + } + dp->d_mask |= m; + + switch (k) { + + case DF_FSTYPE: + dp->d_fstype = v; + break; + + case DF_OPTS: + dp->d_opts = v; + break; + + case DF_DUMPSET: + dp->d_dumpset = v; + break; + + case DF_LOG: + dp->d_log = v; + break; + + case DF_PASSNO: + dp->d_passno = atoi(v); + XFREE(v); + break; + + case DF_FREQ: + dp->d_freq = atoi(v); + XFREE(v); + break; + + case DF_MOUNT: + dp->d_mount = &((fsi_mount *) v)->m_q; + break; + + default: + abort(); + break; + } +} + + +disk_fs * +new_disk_fs(void) +{ + disk_fs *dp = CALLOC(struct disk_fs); + + dp->d_ioloc = current_location(); + show_new("disk_fs"); + return dp; +} + + +void +set_mount(fsi_mount *mp, int k, char *v) +{ + int m = 1 << k; + + if (mp->m_mask & m) { + yyerror("mount tree field \"%s\" already set", mount_strings[k]); + return; + } + mp->m_mask |= m; + + switch (k) { + + case DM_VOLNAME: + dict_add(dict_of_volnames, v, (char *) mp); + mp->m_volname = v; + break; + + case DM_EXPORTFS: + mp->m_exportfs = v; + break; + + case DM_SEL: + mp->m_sel = v; + break; + + default: + abort(); + break; + } +} + + +fsi_mount * +new_mount(void) +{ + fsi_mount *fp = CALLOC(struct fsi_mount); + + fp->m_ioloc = current_location(); + show_new("mount"); + return fp; +} + + +void +set_fsmount(fsmount *fp, int k, char *v) +{ + int m = 1 << k; + + if (fp->f_mask & m) { + yyerror("mount field \"%s\" already set", fsmount_strings[k]); + return; + } + fp->f_mask |= m; + + switch (k) { + + case FM_LOCALNAME: + fp->f_localname = v; + break; + + case FM_VOLNAME: + fp->f_volname = v; + break; + + case FM_FSTYPE: + fp->f_fstype = v; + break; + + case FM_OPTS: + fp->f_opts = v; + break; + + case FM_FROM: + fp->f_from = v; + break; + + case FM_DIRECT: + break; + + default: + abort(); + break; + } +} + + +fsmount * +new_fsmount(void) +{ + fsmount *fp = CALLOC(struct fsmount); + + fp->f_ioloc = current_location(); + show_new("fsmount"); + return fp; +} + + +void +init_que(qelem *q) +{ + q->q_forw = q->q_back = q; +} + + +qelem * +new_que(void) +{ + qelem *q = CALLOC(qelem); + + init_que(q); + return q; +} + + +void +ins_que(qelem *elem, qelem *pred) +{ + qelem *p; + + p = pred->q_forw; + elem->q_back = pred; + elem->q_forw = p; + pred->q_forw = elem; + p->q_back = elem; +} + + +void +rem_que(qelem *elem) +{ + qelem *p, *p2; + + p = elem->q_forw; + p2 = elem->q_back; + + p2->q_forw = p; + p->q_back = p2; +} diff --git a/contrib/amd/fsinfo/fsinfo.8 b/contrib/amd/fsinfo/fsinfo.8 new file mode 100644 index 0000000..5a4eec5 --- /dev/null +++ b/contrib/amd/fsinfo/fsinfo.8 @@ -0,0 +1,101 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1993 Jan-Simon Pendry. +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)fsinfo.8 8.1 (Berkeley) 6/28/93 +.\" $Id: fsinfo.8,v 1.2 1994/06/13 20:50:18 mycroft Exp $ +.\" +.TH FSINFO 8 "June 28, 1993" +.SH NAME +fsinfo \- co-ordinate site-wide filesystem information +.SH SYNOPSIS +.B fsinfo +[ +.B \-v +] [ +.B \-a +.I autodir +] [ +.B \-b +.I bootparams +] [ +.B \-d +.I dumpsets +] [ +.B \-e +.I exports +] [ +.B \-f +.I fstabs +] [ +.B \-h +.I hostname +] [ +.B \-m +.I automounts +] [ +.B \-I +.I dir +] [ +.B \-D +.I string[=string]] +] [ +.B \-U +.I string[=string]] +] +.I config +.I ... +.SH DESCRIPTION +The +.B fsinfo +utility takes a set of system configuration information, and generates +a co-ordinated set of +.I amd +, +.I mount +and +.I mountd +configuration files. +.PP +The +.B fsinfo +command is fully described in the document +.I "Amd - The 4.4BSD Automounter" +.SH "SEE ALSO" +.BR amd (8), +.BR mount (8), +.BR mountd (8). +.SH HISTORY +The +.B fsinfo +command first appeared in 4.4BSD. diff --git a/contrib/amd/fsinfo/fsinfo.c b/contrib/amd/fsinfo/fsinfo.c new file mode 100644 index 0000000..e2632bf --- /dev/null +++ b/contrib/amd/fsinfo/fsinfo.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: fsinfo.c,v 5.2.2.1 1992/02/09 15:09:33 jsp beta $ + * + */ + +/* + * fsinfo + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include +#include + +/* globals */ +char **g_argv; +char *autodir = "/a"; +char *progname; +char *username; +char hostname[MAXHOSTNAMELEN + 1]; +char idvbuf[1024]; +dict *dict_of_hosts; +dict *dict_of_volnames; +int errors; +int file_io_errors; +int parse_errors; +int verbose; +qelem *list_of_automounts; +qelem *list_of_hosts; + +/* + * Output file prefixes + */ +char *bootparams_pref; +char *dumpset_pref; +char *exportfs_pref; +char *fstab_pref; +char *mount_pref; + +/* dummy variables */ +int orig_umask, foreground, debug_flags; +pid_t mypid; +serv_state amd_state; + + +/* + * Argument cracking... + */ +static void +fsi_get_args(int c, char *v[]) +{ + int ch; + int usage = 0; + char *iptr = idvbuf; + + /* + * Determine program name + */ + if (v[0]) { + progname = strrchr(v[0], '/'); + if (progname && progname[1]) + progname++; + else + progname = v[0]; + } + + if (!progname) + progname = "fsinfo"; + + while ((ch = getopt(c, v, "a:b:d:e:f:h:m:D:U:I:qv")) != EOF) + + switch (ch) { + + case 'a': + autodir = optarg; + break; + + case 'b': + if (bootparams_pref) + fatal("-b option specified twice"); + bootparams_pref = optarg; + break; + + case 'd': + if (dumpset_pref) + fatal("-d option specified twice"); + dumpset_pref = optarg; + break; + + case 'h': + strncpy(hostname, optarg, sizeof(hostname) - 1); + break; + + case 'e': + if (exportfs_pref) + fatal("-e option specified twice"); + exportfs_pref = optarg; + break; + + case 'f': + if (fstab_pref) + fatal("-f option specified twice"); + fstab_pref = optarg; + break; + + case 'm': + if (mount_pref) + fatal("-m option specified twice"); + mount_pref = optarg; + break; + + case 'q': + verbose = -1; + break; + + case 'v': + verbose = 1; + break; + + case 'I': + case 'D': + case 'U': + sprintf(iptr, "-%c%s ", ch, optarg); + iptr += strlen(iptr); + break; + + default: + usage++; + break; + } + + if (c != optind) { + g_argv = v + optind - 1; + if (yywrap()) + fatal("Cannot read any input files"); + } else { + usage++; + } + + if (usage) { + fprintf(stderr, + "\ +Usage: %s [-v] [-a autodir] [-h hostname] [-b bootparams] [-d dumpsets]\n\ +\t[-e exports] [-f fstabs] [-m automounts]\n\ +\t[-I dir] [-D|-U string[=string]] config ...\n", progname); + exit(1); + } + + if (g_argv[0]) + log("g_argv[0] = %s", g_argv[0]); + else + log("g_argv[0] = (nil)"); +} + + +/* + * Determine username of caller + */ +static char * +find_username(void) +{ + char *u = getlogin(); + + if (!u) { + struct passwd *pw = getpwuid(getuid()); + if (pw) + u = pw->pw_name; + } + + if (!u) + u = getenv("USER"); + if (!u) + u = getenv("LOGNAME"); + if (!u) + u = "root"; + + return strdup(u); +} + + +/* + * MAIN + */ +int +main(int argc, char *argv[]) +{ + /* + * Process arguments + */ + fsi_get_args(argc, argv); + + /* + * If no hostname given then use the local name + */ + if (!*hostname && gethostname(hostname, sizeof(hostname)) < 0) { + perror("gethostname"); + exit(1); + } + + /* + * Get the username + */ + username = find_username(); + + /* + * New hosts and automounts + */ + list_of_hosts = new_que(); + list_of_automounts = new_que(); + + /* + * New dictionaries + */ + dict_of_volnames = new_dict(); + dict_of_hosts = new_dict(); + + /* + * Parse input + */ + show_area_being_processed("read config", 11); + if (yyparse()) + errors = 1; + errors += file_io_errors + parse_errors; + + if (errors == 0) { + /* + * Do semantic analysis of input + */ + analyze_hosts(list_of_hosts); + analyze_automounts(list_of_automounts); + } + + /* + * Give up if errors + */ + if (errors == 0) { + /* + * Output data files + */ + + write_atab(list_of_automounts); + write_bootparams(list_of_hosts); + write_dumpset(list_of_hosts); + write_exportfs(list_of_hosts); + write_fstab(list_of_hosts); + } + col_cleanup(1); + + exit(errors); + return errors; /* should never reach here */ +} diff --git a/contrib/amd/fsinfo/fsinfo.h b/contrib/amd/fsinfo/fsinfo.h new file mode 100644 index 0000000..c02b673 --- /dev/null +++ b/contrib/amd/fsinfo/fsinfo.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: fsinfo.h,v 5.2.2.1 1992/02/09 15:09:51 jsp beta $ + * + */ + +extern FILE *pref_open(char *pref, char *hn, void (*hdr) (FILE *, char *), char *arg); +extern auto_tree *new_auto_tree(char *, qelem *); +extern automount *new_automount(char *); +extern char **g_argv; +extern char *autodir; +extern char *bootparams_pref; +extern char *disk_fs_strings[]; +extern char *dumpset_pref; +extern char *ether_if_strings[]; +extern char *exportfs_pref; +extern char *fsmount_strings[]; +extern char *fstab_pref; +extern char *host_strings[]; +extern char *mount_pref; +extern char *mount_strings[]; +extern char *progname; +extern char *username; +extern char *xcalloc(int, int); +extern char hostname[]; +extern char idvbuf[]; +extern dict *dict_of_hosts; +extern dict *dict_of_volnames; +extern dict *new_dict(void); +extern dict_ent *dict_locate(dict *, char *); +extern disk_fs *new_disk_fs(void); +extern ether_if *new_ether_if(void); +extern fsmount *new_fsmount(void); +extern host *new_host(void); +extern int dict_iter(dict *, int (*)(qelem *)); +extern int errors; +extern int file_io_errors; +extern int parse_errors; +extern int pref_close(FILE *fp); +extern int verbose; +extern ioloc *current_location(void); +extern fsi_mount *new_mount(void); +extern qelem *new_que(void); +extern void analyze_automounts(qelem *); +extern void analyze_hosts(qelem *); +extern void compute_automount_point(char *, host *, char *); +extern void dict_add(dict *, char *, char *); +extern void error(char *fmt, ...); +extern void fatal(char *fmt, ...); +extern void gen_hdr(FILE *ef, char *hn); +extern void info_hdr(FILE *ef, char *info); +extern void init_que(qelem *); +extern void ins_que(qelem *, qelem *); +extern void lerror(ioloc *l, char *fmt, ...); +extern void log(char *fmt, ...); +extern void lwarning(ioloc *l, char *fmt, ...); +extern void rem_que(qelem *); +extern void set_disk_fs(disk_fs *, int, char *); +extern void set_fsmount(fsmount *, int, char *); +extern void set_mount(fsi_mount *, int, char *); +extern void show_area_being_processed(char *area, int n); +extern void show_new(char *msg); +extern void warning(void); + +extern int yyerror(char *fmt, ...); +extern void domain_strip(char *otherdom, char *localdom); +/* + * some systems such as DU-4.x have a different GNU flex in /usr/bin + * which automatically generates yywrap macros and symbols. So I must + * distinguish between them and when yywrap is actually needed. + */ +#ifndef yywrap +extern int yywrap(void); +#endif /* not yywrap */ +extern int yyparse(void); +extern int write_atab(qelem *q); +extern int write_bootparams(qelem *q); +extern int write_dumpset(qelem *q); +extern int write_exportfs(qelem *q); +extern int write_fstab(qelem *q); +extern void col_cleanup(int eoj); +extern void set_host(host *hp, int k, char *v); +extern void set_ether_if(ether_if *ep, int k, char *v); +extern int yylex(void); + + +#define BITSET(m,b) ((m) |= (1<<(b))) +#define AM_FIRST(ty, q) ((ty *) ((q)->q_forw)) +#define HEAD(ty, q) ((ty *) q) +#define ISSET(m,b) ((m) & (1<<(b))) +#define ITER(v, ty, q) for ((v) = AM_FIRST(ty,(q)); (v) != HEAD(ty,(q)); (v) = NEXT(ty,(v))) +#define AM_LAST(ty, q) ((ty *) ((q)->q_back)) +#define NEXT(ty, q) ((ty *) (((qelem *) q)->q_forw)) diff --git a/contrib/amd/fsinfo/wr_atab.c b/contrib/amd/fsinfo/wr_atab.c new file mode 100644 index 0000000..be870c0 --- /dev/null +++ b/contrib/amd/fsinfo/wr_atab.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: wr_atab.c,v 5.2.2.1 1992/02/09 15:09:44 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include + + +/* + * Write a sequence of automount mount map entries + */ +static int +write_amount_info(FILE *af, automount *ap, int sk) +{ + int errors = 0; + + if (ap->a_mount) { + /* + * A pseudo-directory. + * This can also be a top-level directory, in which + * case the type:=auto is not wanted... + * + * type:=auto;fs:=${map};pref:=whatever/ + */ + automount *ap2; + if (strlen(ap->a_name) > sk) { + fprintf(af, "%s type:=auto;fs:=${map};pref:=%s/\n", + ap->a_name + sk, ap->a_name + sk); + } + ITER(ap2, automount, ap->a_mount) + errors += write_amount_info(af, ap2, sk); + } else if (ap->a_hardwiredfs) { + + /* + * A hardwired filesystem "hostname:path" + * rhost:=hostname;rfs:=path + */ + char *key = ap->a_name + sk; + char *hostname = ap->a_hardwiredfs; + char *path = strrchr(hostname, (int) ':'); + + if (path == NULL) { + fprintf(stderr, "%s: %s not an NFS filesystem\n", ap->a_name, ap->a_hardwiredfs); + errors++; + } else { + *path = '\0'; + path++; + + /* + * Output the map key + */ + fputs(key, af); + fprintf(af, " rhost:=%s", hostname); + fprintf(af, ";rfs:=%s", path); + if (ap->a_opts && !STREQ(ap->a_opts, "")) { + fprintf(af, ";%s", ap->a_opts); + } + fputc('\n', af); + path--; + *path = ':'; + } + } else if (ap->a_mounted) { + + /* + * A mounted partition + * type:=link [ link entries ] type:=nfs [ nfs entries ] + */ + dict_data *dd; + dict_ent *de = ap->a_mounted; + int done_type_link = 0; + char *key = ap->a_name + sk; + + /* + * Output the map key + */ + fputs(key, af); + + /* + * First output any Link locations that would not + * otherwise be correctly mounted. These refer + * to filesystem which are not mounted in the same + * place which the automounter would use. + */ + ITER(dd, dict_data, &de->de_q) { + fsi_mount *mp = (fsi_mount *) dd->dd_data; + /* + * If the mount point and the exported volname are the + * same then this filesystem will be recognised by + * the restart code - so we don't need to put out a + * special rule for it. + */ + if (mp->m_dk->d_host->h_lochost) { + char amountpt[1024]; + compute_automount_point(amountpt, mp->m_dk->d_host, mp->m_exported->m_volname); + if (!STREQ(mp->m_dk->d_mountpt, amountpt)) { + /* + * ap->a_volname is the name of the aliased volume + * mp->m_name is the mount point of the filesystem + * mp->m_volname is the volume name of the filesystems + */ + + /* + * Find length of key and volume names + */ + int avlen = strlen(ap->a_volname); + int mnlen = strlen(mp->m_volname); + + /* + * Make sure a -type:=link is output once + */ + if (!done_type_link) { + done_type_link = 1; + fputs(" -type:=link", af); + } + + /* + * Output a selector for the hostname, + * the device from which to mount and + * where to mount. This will correspond + * to the values output for the fstab. + */ + if (mp->m_dk->d_host->h_lochost) + fprintf(af, " host==%s", mp->m_dk->d_host->h_lochost); + else + fprintf(af, " hostd==%s", mp->m_dk->d_host->h_hostname); + fprintf(af, ";fs:=%s", mp->m_name); + + /* + * ... and a sublink if needed + */ + if (mnlen < avlen) { + char *sublink = ap->a_volname + mnlen + 1; + fprintf(af, "/%s", sublink); + } + fputs(" ||", af); + } + } + } + + /* + * Next do the NFS locations + */ + if (done_type_link) + fputs(" -", af); + + ITER(dd, dict_data, &de->de_q) { + fsi_mount *mp = (fsi_mount *) dd->dd_data; + int namelen = mp->m_name_len; + int exp_namelen = mp->m_exported->m_name_len; + int volnlen = strlen(ap->a_volname); + int mvolnlen = strlen(mp->m_volname); + + fputc(' ', af); + + /* + * Output any selectors + */ + if (mp->m_sel) + fprintf(af, "%s;", mp->m_sel); + + /* + * Print host and volname of exported filesystem + */ + fprintf(af, "rhost:=%s", + mp->m_dk->d_host->h_lochost ? + mp->m_dk->d_host->h_lochost : + mp->m_dk->d_host->h_hostname); + fprintf(af, ";rfs:=%s", mp->m_exported->m_volname); + if (ap->a_opts && !STREQ(ap->a_opts, "")) { + fprintf(af, ";%s", ap->a_opts); + } + + /* + * Now determine whether a sublink is required. + */ + if (exp_namelen < namelen || mvolnlen < volnlen) { + char sublink[1024]; + sublink[0] = '\0'; + if (exp_namelen < namelen) { + strcat(sublink, mp->m_name + exp_namelen + 1); + if (mvolnlen < volnlen) + strcat(sublink, "/"); + } + if (mvolnlen < volnlen) + strcat(sublink, ap->a_volname + mvolnlen + 1); + + fprintf(af, ";sublink:=%s", sublink); + } + } + fputc('\n', af); + } else if (ap->a_symlink) { + + /* + * A specific link. + * + * type:=link;fs:=whatever + */ + fprintf(af, "%s type:=link;fs:=%s\n", ap->a_name + sk, ap->a_symlink); + } + + return errors; +} + + +/* + * Write a single automount configuration file + */ +static int +write_amount( qelem *q, char *def) +{ + automount *ap; + int errors = 0; + int direct = 0; + + /* + * Output all indirect maps + */ + ITER(ap, automount, q) { + FILE *af; + char *p; + + /* + * If there is no a_mount node then this is really + * a direct mount, so just keep a count and continue. + * Direct mounts are output into a special file during + * the second pass below. + */ + if (!ap->a_mount) { + direct++; + continue; + } + + p = strrchr(ap->a_name, '/'); + if (!p) + p = ap->a_name; + else + p++; + + af = pref_open(mount_pref, p, gen_hdr, ap->a_name); + if (af) { + show_new(ap->a_name); + fputs("/defaults ", af); + if (*def) + fprintf(af, "%s;", def); + fputs("type:=nfs\n", af); + errors += write_amount_info(af, ap, strlen(ap->a_name) + 1); + errors += pref_close(af); + } + } + + /* + * Output any direct map entries which were found during the + * previous pass over the data. + */ + if (direct) { + FILE *af = pref_open(mount_pref, "direct.map", info_hdr, "direct mount"); + + if (af) { + show_new("direct mounts"); + fputs("/defaults ", af); + if (*def) + fprintf(af, "%s;", def); + fputs("type:=nfs\n", af); + ITER(ap, automount, q) + if (!ap->a_mount) + errors += write_amount_info(af, ap, 1); + errors += pref_close(af); + } + } + return errors; +} + + +/* + * Write all the needed automount configuration files + */ +int +write_atab(qelem *q) +{ + int errors = 0; + + if (mount_pref) { + auto_tree *tp; + show_area_being_processed("write automount", 5); + ITER(tp, auto_tree, q) + errors += write_amount(tp->t_mount, tp->t_defaults); + } + + return errors; +} diff --git a/contrib/amd/fsinfo/wr_bparam.c b/contrib/amd/fsinfo/wr_bparam.c new file mode 100644 index 0000000..fb4479c --- /dev/null +++ b/contrib/amd/fsinfo/wr_bparam.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: wr_bparam.c,v 5.2.2.1 1992/02/09 15:09:46 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include + + +/* + * Write a host/path in NFS format + */ +static int +write_nfsname(FILE *ef, fsmount *fp, char *hn) +{ + int errors = 0; + char *h = strdup(fp->f_ref->m_dk->d_host->h_hostname); + + domain_strip(h, hn); + fprintf(ef, "%s:%s", h, fp->f_volname); + XFREE(h); + return errors; +} + + +/* + * Write a bootparams entry for a host + */ +static int +write_boot_info(FILE *ef, host *hp) +{ + int errors = 0; + + fprintf(ef, "%s\troot=", hp->h_hostname); + errors += write_nfsname(ef, hp->h_netroot, hp->h_hostname); + fputs(" swap=", ef); + errors += write_nfsname(ef, hp->h_netswap, hp->h_hostname); + fputs("\n", ef); + + return 0; +} + + +/* + * Output a bootparams file + */ +int +write_bootparams(qelem *q) +{ + int errors = 0; + + if (bootparams_pref) { + FILE *ef = pref_open(bootparams_pref, "bootparams", info_hdr, "bootparams"); + if (ef) { + host *hp; + ITER(hp, host, q) + if (hp->h_netroot && hp->h_netswap) + errors += write_boot_info(ef, hp); + errors += pref_close(ef); + } else { + errors++; + } + } + + return errors; +} diff --git a/contrib/amd/fsinfo/wr_dumpset.c b/contrib/amd/fsinfo/wr_dumpset.c new file mode 100644 index 0000000..b33858d --- /dev/null +++ b/contrib/amd/fsinfo/wr_dumpset.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: wr_dumpset.c,v 5.2.2.1 1992/02/09 15:09:47 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include + + +static int +write_dumpset_info(FILE *ef, qelem *q) +{ + int errors = 0; + disk_fs *dp; + + ITER(dp, disk_fs, q) { + if (dp->d_dumpset) { + fprintf(ef, "%s\t%s:%-30s\t# %s\n", + dp->d_dumpset, + dp->d_host->h_lochost ? + dp->d_host->h_lochost : + dp->d_host->h_hostname, + dp->d_mountpt, + dp->d_dev); + } + } + return errors; +} + + +int +write_dumpset(qelem *q) +{ + int errors = 0; + + if (dumpset_pref) { + FILE *ef = pref_open(dumpset_pref, "dumpsets", info_hdr, "exabyte dumpset"); + if (ef) { + host *hp; + + ITER(hp, host, q) { + if (hp->h_disk_fs) { + errors += write_dumpset_info(ef, hp->h_disk_fs); + } + } + errors += pref_close(ef); + } else { + errors++; + } + } + + return errors; +} diff --git a/contrib/amd/fsinfo/wr_exportfs.c b/contrib/amd/fsinfo/wr_exportfs.c new file mode 100644 index 0000000..56d9bd5 --- /dev/null +++ b/contrib/amd/fsinfo/wr_exportfs.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: wr_exportfs.c,v 5.2.2.1 1992/02/09 15:09:48 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include + + +static int +write_export_info(FILE *ef, qelem *q, int errors) +{ + fsi_mount *mp; + + ITER(mp, fsi_mount, q) { + if (mp->m_mask & (1 << DM_EXPORTFS)) + fprintf(ef, "%s\t%s\n", mp->m_volname, mp->m_exportfs); + if (mp->m_mount) + errors += write_export_info(ef, mp->m_mount, 0); + } + + return errors; +} + + +static int +write_dkexports(FILE *ef, qelem *q) +{ + int errors = 0; + disk_fs *dp; + + ITER(dp, disk_fs, q) { + if (dp->d_mount) + errors += write_export_info(ef, dp->d_mount, 0); + } + + return errors; +} + + +int +write_exportfs(qelem *q) +{ + int errors = 0; + + if (exportfs_pref) { + host *hp; + + show_area_being_processed("write exportfs", 5); + ITER(hp, host, q) { + if (hp->h_disk_fs) { + FILE *ef = pref_open(exportfs_pref, hp->h_hostname, gen_hdr, hp->h_hostname); + if (ef) { + show_new(hp->h_hostname); + errors += write_dkexports(ef, hp->h_disk_fs); + errors += pref_close(ef); + } else { + errors++; + } + } + } + } + + return errors; +} diff --git a/contrib/amd/fsinfo/wr_fstab.c b/contrib/amd/fsinfo/wr_fstab.c new file mode 100644 index 0000000..49cbfc4 --- /dev/null +++ b/contrib/amd/fsinfo/wr_fstab.c @@ -0,0 +1,342 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: wr_fstab.c,v 5.2.2.1 1992/02/09 15:09:49 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include +#include + +#define GENERIC_OS_NAME "generic" + +/* forward definitions */ +static void write_aix1_dkfstab(FILE *ef, disk_fs *dp); +static void write_aix1_dkrmount(FILE *ef, char *hn, fsmount *fp); +static void write_aix3_dkfstab(FILE *ef, disk_fs *dp); +static void write_aix3_dkrmount(FILE *ef, char *hn, fsmount *fp); +static int write_dkfstab(FILE *ef, qelem *q, void (*output) (FILE *, disk_fs *)); +static int write_dkrmount(FILE *ef, qelem *q, char *hn, void (*output) (FILE *, char *, fsmount *)); +static void write_generic_dkfstab(FILE *ef, disk_fs *dp); +static void write_generic_dkrmount(FILE *ef, char *hn, fsmount *fp); +static void write_ultrix_dkfstab(FILE *ef, disk_fs *dp); +static void write_ultrix_dkrmount(FILE *ef, char *hn, fsmount *fp); + +/* ----------------------------------------------- */ + +static struct os_fstab_type { + char *os_name; + void (*op_fstab) (FILE *ef, disk_fs *dp); + void (*op_mount) (FILE *ef, char *hn, fsmount *fp); +} os_tabs[] = { + + { + "aix1", write_aix1_dkfstab, write_aix1_dkrmount + }, /* AIX 1 */ + { + "aix3", write_aix3_dkfstab, write_aix3_dkrmount + }, /* AIX 3 */ + { + "generic", write_generic_dkfstab, write_generic_dkrmount + }, /* Generic */ + { + "u2_0", write_ultrix_dkfstab, write_ultrix_dkrmount + }, /* Ultrix */ + { + "u3_0", write_ultrix_dkfstab, write_ultrix_dkrmount + }, /* Ultrix */ + { + "u4_0", write_ultrix_dkfstab, write_ultrix_dkrmount + }, /* Ultrix */ + { + 0, 0, 0 + } +}; + + +/* ---------- AIX 1 ------------------------------ */ + +/* + * AIX 1 format + */ +static void +write_aix1_dkfstab(FILE *ef, disk_fs *dp) +{ + char *hp = strdup(dp->d_host->h_hostname); + char *p = strchr(hp, '.'); + + if (p) + *p = '\0'; + + fprintf(ef, "\n%s:\n\tdev = %s\n\tvfs = %s\n\ttype = %s\n\tlog = %s\n\tvol = %s\n\topts = %s\n\tmount = true\n\tcheck = true\n\tfree = false\n", + dp->d_mountpt, + dp->d_dev, + dp->d_fstype, + dp->d_fstype, + dp->d_log, + dp->d_mountpt, + dp->d_opts); + XFREE(hp); +} + + +static void +write_aix1_dkrmount(FILE *ef, char *hn, fsmount *fp) +{ + char *h = strdup(fp->f_ref->m_dk->d_host->h_hostname); + char *hp = strdup(h); + char *p = strchr(hp, '.'); + + if (p) + *p = '\0'; + domain_strip(h, hn); + fprintf(ef, "\n%s:\n\tsite = %s\n\tdev = %s:%s\n\tvfs = %s\n\ttype = %s\n\tvol = %s\n\topts = %s\n\tmount = true\n\tcheck = true\n\tfree = false\n", + fp->f_localname, + hp, + h, + fp->f_volname, + fp->f_fstype, + fp->f_fstype, + fp->f_localname, + fp->f_opts); + + XFREE(hp); + XFREE(h); +} + + +/* ---------- AIX 3 ------------------------------ */ + +/* + * AIX 3 format + */ +static void +write_aix3_dkfstab(FILE *ef, disk_fs *dp) +{ + if (STREQ(dp->d_fstype, "jfs") && + NSTREQ(dp->d_dev, "/dev/", 5) && + !dp->d_log) + error("aix 3 needs a log device for journalled filesystem (jfs) mounts"); + + fprintf(ef, "\n%s:\n\tdev = %s\n\tvfs = %s\n\ttype = %s\n\tlog = %s\n\tvol = %s\n\topts = %s\n\tmount = true\n\tcheck = true\n\tfree = false\n", + dp->d_mountpt, + dp->d_dev, + dp->d_fstype, + dp->d_fstype, + dp->d_log, + dp->d_mountpt, + dp->d_opts); +} + + +static void +write_aix3_dkrmount(FILE *ef, char *hn, fsmount *fp) +{ + char *h = strdup(fp->f_ref->m_dk->d_host->h_hostname); + + domain_strip(h, hn); + fprintf(ef, "\n%s:\n\tdev = %s:%s\n\tvfs = %s\n\ttype = %s\n\tvol = %s\n\topts = %s\n\tmount = true\n\tcheck = true\n\tfree = false\n", + fp->f_localname, + h, + fp->f_volname, + fp->f_fstype, + fp->f_fstype, + fp->f_localname, + fp->f_opts); + + XFREE(h); +} + + +/* ---------- Ultrix ----------------------------- */ + +static void +write_ultrix_dkfstab(FILE *ef, disk_fs *dp) +{ + fprintf(ef, "%s:%s:%s:%s:%d:%d\n", + dp->d_dev, + dp->d_mountpt, + dp->d_fstype, + dp->d_opts, + dp->d_freq, + dp->d_passno); +} + + +static void +write_ultrix_dkrmount(FILE *ef, char *hn, fsmount *fp) +{ + char *h = strdup(fp->f_ref->m_dk->d_host->h_hostname); + + domain_strip(h, hn); + fprintf(ef, "%s@%s:%s:%s:%s:0:0\n", + fp->f_volname, + h, + fp->f_localname, + fp->f_fstype, + fp->f_opts); + XFREE(h); +} + + +/* ---------- Generic ---------------------------- */ + +/* + * Generic (BSD, SunOS, HPUX) format + */ +static void +write_generic_dkfstab(FILE *ef, disk_fs *dp) +{ + fprintf(ef, "%s %s %s %s %d %d\n", + dp->d_dev, + dp->d_mountpt, + dp->d_fstype, + dp->d_opts, + dp->d_freq, + dp->d_passno); +} + + +static void +write_generic_dkrmount(FILE *ef, char *hn, fsmount *fp) +{ + char *h; + + if (fp->f_ref) { + h = strdup(fp->f_ref->m_dk->d_host->h_hostname); + } else { + h = strdup(fp->f_from); + } + domain_strip(h, hn); + fprintf(ef, "%s:%s %s %s %s 0 0\n", + h, + fp->f_volname, + fp->f_localname, + fp->f_fstype, + fp->f_opts); + XFREE(h); +} + + +static struct os_fstab_type * +find_fstab_type(host *hp) +{ + struct os_fstab_type *op = 0; + char *os_name = 0; + +again:; + if (os_name == 0) { + if (ISSET(hp->h_mask, HF_OS)) + os_name = hp->h_os; + else + os_name = GENERIC_OS_NAME; + } + for (op = os_tabs; op->os_name; op++) + if (STREQ(os_name, op->os_name)) + return op; + + os_name = GENERIC_OS_NAME; + goto again; +} + + +static int +write_dkfstab(FILE *ef, qelem *q, void (*output) (FILE *, disk_fs *)) +{ + int errors = 0; + disk_fs *dp; + + ITER(dp, disk_fs, q) + if (!STREQ(dp->d_fstype, "export")) + (*output) (ef, dp); + + return errors; +} + + +static int +write_dkrmount(FILE *ef, qelem *q, char *hn, void (*output) (FILE *, char *, fsmount *)) +{ + int errors = 0; + fsmount *fp; + + ITER(fp, fsmount, q) + (*output) (ef, hn, fp); + + return errors; +} + + +int +write_fstab(qelem *q) +{ + int errors = 0; + + if (fstab_pref) { + host *hp; + + show_area_being_processed("write fstab", 4); + ITER(hp, host, q) { + if (hp->h_disk_fs || hp->h_mount) { + FILE *ef = pref_open(fstab_pref, hp->h_hostname, gen_hdr, hp->h_hostname); + if (ef) { + struct os_fstab_type *op = find_fstab_type(hp); + show_new(hp->h_hostname); + if (hp->h_disk_fs) + errors += write_dkfstab(ef, hp->h_disk_fs, op->op_fstab); + else + log("No local disk mounts on %s", hp->h_hostname); + + if (hp->h_mount) + errors += write_dkrmount(ef, hp->h_mount, hp->h_hostname, op->op_mount); + + pref_close(ef); + } + } else { + error("no disk mounts on %s", hp->h_hostname); + } + } + } + return errors; +} diff --git a/contrib/amd/hlfsd/hlfsd.8 b/contrib/amd/hlfsd/hlfsd.8 new file mode 100644 index 0000000..ecc7e3a --- /dev/null +++ b/contrib/amd/hlfsd/hlfsd.8 @@ -0,0 +1,310 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1989 Jan-Simon Pendry +.\" Copyright (c) 1989 Imperial College of Science, Technology & Medicine +.\" Copyright (c) 1989 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jan-Simon Pendry at Imperial College, London. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Id: hlfsd.8,v 1.2 1993/09/14 22:29:10 ezk Exp ezk $ +.\" +.\" HLFSD was written at Columbia University Computer Science Department, by +.\" Erez Zadok and Alexander Dupuy +.\" It is distributed under the same terms and conditions as AMD. +.\" +.TH HLFSD 8 "14 September 1993" +.SH NAME +hlfsd \- home-link file system daemon +.SH SYNOPSIS +.B hlfsd +[ +.B \-fhnpvC +] [ +.BI \-a " alt_dir" +] [ +.BI \-c " cache-interval" +] [ +.BI \-g " group" +] [ +.BI \-i " reload-interval" +] [ +.BI \-l " logfile" +] [ +.BI \-o " mount-options" +] [ +.BI \-x " log-options" +] [ +.BI \-D " debug-options" +] [ +.BI \-P " password-file" +] +[ +.I linkname +.RI [ " subdir " ] +] +.SH DESCRIPTION +.B Hlfsd +is a daemon which implements a filesystem containing a symbolic link to +subdirectory within a user's home directory, depending on the user +which accessed that link. It was primarily designed to redirect +incoming mail to users' home directories, so that it can read from +anywhere. +.LP +.B Hlfsd +operates by mounting itself as an +.SM NFS +server for the directory containing +.IR linkname , +which defaults to +.BR /hlfs/home . +Lookups within that directory are handled by +.BR hlfsd , +which uses the password map to determine how to resolve the lookup. +The directory will be created if it doesn't already exist. The symbolic link will be to the accessing user's home directory, with +.I subdir +appended to it. If not specified, +.I subdir +defaults to +.BR .hlfsdir . +This directory will also be created if it does not already exist. +.LP +A SIGTERM sent to +.B hlfsd +will cause it to shutdown. A SIGHUP will flush the internal +caches, and reload the password map. It will also close and +reopen the log file, to enable the original log file to be +removed or rotated. A SIGUSR1 will cause it to dump its internal +table of user IDs and home directories to the file +.BR /usr/tmp/hlfsd.dump.XXXXXX . +.SH OPTIONS +.TP +.BI \-a " alt_dir" +Alternate directory. The name of the directory to which +the symbolic link returned by +.B hlfsd +will point, if it cannot access the home directory of the user. This +defaults to +.BR /var/hlfs . +This directory will be created if it doesn't exist. It is expected +that either users will read these files, or the system administrators +will run a script to resend this "lost mail" to its owner. +.TP +.BI \-c " cache-interval" +Caching interval. +.B Hlfsd +will cache the validity of home directories for this interval, in +seconds. Entries which have been verified within the last +.I cache-interval +seconds will not be verified again, since the operation could +be expensive, and the entries are most likely still valid. +After the interval has expired, +.B hlfsd +will re-verify the validity of the user's home directory, and +reset the cache time-counter. The default value for +.I cache-interval +is 300 seconds (5 minutes). +.TP +.B \-f +Force fast startup. This option tells +.B hlfsd +to skip startup-time consistency checks such as existence of mount +directory, alternate spool directory, symlink to be hidden under the +mount directory, their permissions and validity. +.TP +.BI \-g " group" +Set the special group HLFS_GID to +.IR group . +Programs such as +.B from +or +.BR comsat , +which access the mailboxes of other users) must be setgid HLFS_GID to +work properly. The default group is "hlfs". If no group is provided, +and there is no group "hlfs", this feature is disabled. +.TP +.B \-h +Help. Print a brief help message, and exit. +.TP +.BI \-i " reload-interval" +Map-reloading interval. Each +.I reload-interval +seconds, +.B hlfsd +will reload the password map. +.B Hlfsd +needs the password map for the UIDs and home directory pathnames. +.B Hlfsd +schedules a SIGALRM to reload the password maps. A SIGHUP sent to +.B hlfsd +will force it to reload the maps immediately. The default +value for +.I reload-interval +is 900 seconds (15 minutes.) +.TP +.BI \-l " logfile" +Specify a log file to which +.B hlfsd +will record events. If +.I logfile +is the string +.B syslog +then the log messages will be sent to the system log daemon by +.IR syslog (3), +using the LOG_DAEMON facility. +This is also the default. +.TP +.B \-n +No verify. +.B Hlfsd +will not verify the validity of the symbolic link it will be +returning, or that the user's home directory contains +sufficient disk-space for spooling. This can speed up +.B hlfsd +at the cost of possibly returning symbolic links to home +directories which are not currently accessible or are full. +By default, +.B hlfsd +validates the symbolic-link in the background. +The +.B \-n +option overrides the meaning of the +.B \-c +option, since no caching is necessary. +.TP +.BI \-o " mount-options" +Mount options. Mount options which +.B hlfsd +will use to mount itself on top of +.I dirname. +By default, +.IR mount-options +is set to "ro". If the system supports symbolic-link caching, default +options are set to "ro,nocache". +.TP +.B \-p +Print PID. +Outputs the process-id of +.B hlfsd +to standard output where it can be saved into a file. +.TP +.B \-v +Version. Displays version information to standard error. +.TP +.BI \-x " log-options" +Specify run-time logging options. The options are a comma separated +list chosen from: fatal, error, user, warn, info, map, stats, all. +.TP +.BI \-C +Force +.B hlfsd +to run on systems that cannot turn off the NFS attribute-cache. Use of +this option on those systems is discouraged, as it may result in loss +or misdelivery of mail. The option is ignored on systems that can turn +off the attribute-cache. +.TP +.BI \-D " log-options" +Select from a variety of debugging options. Prefixing an +option with the string +.B no +reverses the effect of that option. Options are cumulative. +The most useful option is +.BR all . +Since this option is only used for debugging other options are not +documented here. A fuller description is available in the program +source. A SIGUSR1 sent to +.B hlfsd +will cause it to dump its internal password map to the file +.BR /usr/tmp/hlfsd.dump.XXXXXX . +.TP +.BI \-P " password-file" +Read the user-name, user-id, and home directory information from the file +.I password-file. +Normally, +.B hlfsd +will use +.IR getpwent (3) +to read the password database. This option allows you to override the +default database, and is useful if you want to map users' mail files to a +directory other than their home directory. Only the username, uid, and +home-directory fields of the file +.I password-file +are read and checked. All other fields are ignored. The file +.I password-file +must otherwise be compliant with Unix System 7 colon-delimited format +.IR passwd (4). +.SH FILES +.PD 0 +.TP 5 +.B /hlfs +directory under which +.B hlfsd +mounts itself and manages the symbolic link +.BR home . +.TP 5 +.B .hlfsdir +default sub-directory in the user's home directory, to which the +.B home +symbolic link returned by +.B hlfsd +points. +.TP 5 +.B /var/hlfs +directory to which +.B home +symbolic link returned by +.B hlfsd +points if it is unable to verify the that +user's home directory is accessible. +.SH "SEE ALSO" +.BR amd (8), +.BR automount (8), +.BR cron(8), +.BR getgrent (3), +.BR getpwent (3), +.BR mail(1), +.BR mnttab (4), +.BR mount (8), +.BR mtab (5), +.BR passwd (4), +.BR sendmail (8), +.BR umount (8). +.LP +.IR "HLFSD: Delivering Email to Your $HOME" , +in +.IR "Proc. LISA-VII, The 7th Usenix System Administration Conference" , +November 1993. +.SH AUTHORS +Erez Zadok , Computer Science Department, +Columbia University, New York City, New York, USA, and +Alexander Dupuy , System Management ARTS, +White Plains, New York, USA. diff --git a/contrib/amd/hlfsd/hlfsd.c b/contrib/amd/hlfsd/hlfsd.c new file mode 100644 index 0000000..388c65b --- /dev/null +++ b/contrib/amd/hlfsd/hlfsd.c @@ -0,0 +1,953 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: hlfsd.c,v 1.11 1994/11/06 00:19:52 ezk Exp ezk $ + * + * HLFSD was written at Columbia University Computer Science Department, by + * Erez Zadok and Alexander Dupuy + * It is being distributed under the same terms and conditions as amd does. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * STATIC VARIABLES: + */ +static RETSIGTYPE proceed(int); +static RETSIGTYPE reaper(int); +static RETSIGTYPE reload(int); +static char *hlfs_group = DEFAULT_HLFS_GROUP; +static char default_dir_name[] = DEFAULT_DIRNAME; +static char *dir_name = default_dir_name; +static int printpid = 0; +static int stoplight = 0; +static void hlfsd_init(void); +static void usage(void); + +static struct itimerval reloadinterval = { + {DEFAULT_INTERVAL, 0}, + {DEFAULT_INTERVAL, 0} +}; + +/* + * default mount options. + */ +static char default_mntopts[] = "ro,noac"; + +/* + * GLOBALS: + */ +SVCXPRT *nfsxprt; +char *alt_spooldir = ALT_SPOOLDIR; +char *home_subdir = HOME_SUBDIR; +char *logfile = DEFAULT_LOGFILE; +char *passwdfile = NULL; /* alternate passwd file to use */ +char *progname; +char *slinkname = 0; +char hostname[MAXHOSTNAMELEN] = "localhost"; +int cache_interval = DEFAULT_CACHE_INTERVAL; +int foreground = 1; /* This is the top-level server */ +gid_t hlfs_gid = (gid_t) INVALIDID; +int masterpid = 0; +int noverify = 0; +int orig_umask; +int serverpid = 0; +nfstime startup; +pid_t mypid; /* Current process id */ +serv_state amd_state; +u_short nfs_port; + +/* symbol must be available always */ +#ifdef MOUNT_TABLE_ON_FILE +char *mnttab_file_name = MNTTAB_FILE_NAME; +#else /* not MOUNT_TABLE_ON_FILE */ +char *mnttab_file_name = NULL; +#endif /* not MOUNT_TABLE_ON_FILE */ + +#ifdef DEBUG +int debug_flags = 0; +#endif /* DEBUG */ + +/* forward declarations */ +void hlfsd_going_down(int rc); + + +static void +usage(void) +{ + fprintf(stderr, + "Usage: %s [-Cfhnpv] [-a altdir] [-c cache-interval] [-g group]\n", + progname); + fprintf(stderr, "\t[-i interval] [-l logfile] [-o mntopts] [-P passwdfile]\n"); + show_opts('x', xlog_opt); +#ifdef DEBUG + show_opts('D', dbg_opt); +#endif /* DEBUG */ + fprintf(stderr, "\t[dir_name [subdir]]\n"); + exit(2); +} + + +int +main(int argc, char *argv[]) +{ + char *dot; + char *mntopts = (char *) NULL; + char hostpid_fs[MAXHOSTNAMELEN + 1 + 16]; /* room for ":(pid###)" */ + char progpid_fs[PROGNAMESZ + 1 + 11]; /* room for ":pid" */ + char preopts[128]; + int forcecache = 0; + int forcefast = 0; + int genflags = 0; + int opt, ret; + int opterrs = 0; + int retry; + int soNFS; /* NFS socket */ + int s = -99; + mntent_t mnt; + nfs_args_t nfs_args; + am_nfs_handle_t anh; + struct dirent *direntry; + struct group *grp; + struct stat stmodes; + DIR *mountdir; + MTYPE_TYPE type = MOUNT_TYPE_NFS; + +#ifdef HAVE_SIGACTION + struct sigaction sa; +#endif /* not HAVE_SIGACTION */ + +#ifndef HAVE_TRANSPORT_TYPE_TLI + struct sockaddr_in localsocket; +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + + /* get program name and truncate so we don't overflow progpid_fs */ + + if ((progname = strrchr(argv[0], '/')) != NULL) + progname++; + else + progname = argv[0]; + if ((int) strlen(progname) > PROGNAMESZ) /* truncate to reasonable size */ + progname[PROGNAMESZ] = '\0'; + + while ((opt = getopt(argc, argv, "a:c:CD:fg:hi:l:no:pP:x:v")) != EOF) + switch (opt) { + + case 'a': + if (!optarg || optarg[0] != '/') { + printf("%s: invalid directory for -a: %s\n", + progname, optarg); + exit(3); + } + alt_spooldir = optarg; + break; + + case 'c': + if (!atoi(optarg)) { + printf("%s: invalid interval for -c: %s\n", + progname, optarg); + exit(3); + } + cache_interval = atoi(optarg); + break; + + case 'C': + forcecache++; + break; + + case 'f': + forcefast++; + break; + + case 'g': + hlfs_group = optarg; + break; + + case 'i': + if (!atoi(optarg)) { + printf("%s: invalid interval for -i: %s\n", + progname, optarg); + exit(3); + } + reloadinterval.it_interval.tv_sec = atoi(optarg); + reloadinterval.it_value.tv_sec = atoi(optarg); + break; + + case 'l': + logfile = optarg; + break; + + case 'n': + noverify++; + break; + + case 'o': + mntopts = optarg; + break; + + case 'p': + printpid++; + break; + + case 'P': + passwdfile = optarg; + break; + + case 'v': + fprintf(stderr, "%s\n", HLFSD_VERSION); + exit(0); + + case 'x': + opterrs += switch_option(optarg); + break; + + case 'D': +#ifdef DEBUG + opterrs += debug_option(optarg); +#else /* not DEBUG */ + fprintf(stderr, "%s: not compiled with DEBUG -- sorry.\n", progname); +#endif /* not DEBUG */ + break; + + case 'h': + case '?': + opterrs++; + } + + /* set some default debugging options */ + if (xlog_level_init == ~0) + switch_option(""); + /* need my pid before any dlog/plog */ + mypid = getpid(); +#ifdef DEBUG + switch_option("debug"); +#endif /* DEBUG */ + +/* + * Terminate if did not ask to forcecache (-C) and hlfsd would not be able + * to set the minimum cache intervals. + */ +#if !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_FIELD_NFS_ARGS_T_ACREGMIN) + if (!forcecache) { + fprintf(stderr, "%s: will not be able to turn off attribute caches.\n", progname); + exit(1); + } +#endif /* !defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNT2_NFS_OPT_NOAC) && !defined(HAVE_FIELD_NFS_ARGS_T_ACREGMIN) */ + + + switch (argc - optind) { + case 2: + home_subdir = argv[optind + 1]; + case 1: + dir_name = argv[optind]; + case 0: + break; + default: + opterrs++; + } + + if (opterrs) + usage(); + + /* ensure that only root can run hlfsd */ + if (geteuid()) { + fprintf(stderr, "hlfsd can only be run as root\n"); + exit(1); + } + setbuf(stdout, (char *) NULL); + umask(0); + + /* find gid for hlfs_group */ + if ((grp = getgrnam(hlfs_group)) == (struct group *) NULL) { + fprintf(stderr, "%s: cannot get gid for group \"%s\".\n", + progname, hlfs_group); + } else { + hlfs_gid = grp->gr_gid; + } + + /* get hostname for logging and open log before we reset umask */ + gethostname(hostname, MAXHOSTNAMELEN); + if ((dot = strchr(hostname, '.')) != NULL) + *dot = '\0'; + if (logfile) + switch_to_logfile(logfile); + orig_umask = umask(0); + +#if defined(DEBUG) && !defined(MOUNT_TABLE_ON_FILE) + if (debug_flags & D_MTAB) + dlog("-D mtab option ignored"); +#endif /* defined(DEBUG) && !defined(MOUNT_TABLE_ON_FILE) */ + + /* avoid hanging on other NFS servers if started elsewhere */ + if (chdir("/") < 0) + fatal("cannot chdir to /: %m"); + + if (geteuid() != 0) + fatal("must be root to mount filesystems"); + + /* + * dir_name must match "^(/.*)/([^/]+)$", and is split at last '/' with + * slinkname = `basename $dir_name` - requires dir_name be writable + */ + + if (dir_name[0] != '/' + || ((slinkname = strrchr(dir_name, '/')), *slinkname++ = '\0', + (dir_name[0] == '\0' || slinkname[0] == '\0'))) { + if (slinkname) + *--slinkname = '/'; + printf("%s: invalid mount directory/link %s\n", + progname, dir_name); + exit(3); + } + + clock_valid = 0; /* invalidate logging clock */ + + if (!forcefast) { + /* make sure mount point exists and is at least mode 555 */ + if (stat(dir_name, &stmodes) < 0) + if (errno != ENOENT || mkdirs(dir_name, 0555) < 0 + || stat(dir_name, &stmodes) < 0) + fatalerror(dir_name); + + if ((stmodes.st_mode & 0555) != 0555) { + fprintf(stderr, "%s: directory %s not read/executable\n", + progname, dir_name); + plog(XLOG_WARNING, "directory %s not read/executable", + dir_name); + } + + /* warn if extraneous stuff will be hidden by mount */ + if ((mountdir = opendir(dir_name)) == NULL) + fatalerror(dir_name); + + while ((direntry = readdir(mountdir)) != NULL) { + if (!NSTREQ(".", direntry->d_name, NAMLEN(direntry)) && + !NSTREQ("..", direntry->d_name, NAMLEN(direntry)) && + !NSTREQ(slinkname, direntry->d_name, NAMLEN(direntry))) + break; + } + + if (direntry != NULL) { + fprintf(stderr, "%s: %s/%s will be hidden by mount\n", + progname, dir_name, direntry->d_name); + plog(XLOG_WARNING, "%s/%s will be hidden by mount\n", + dir_name, direntry->d_name); + } + closedir(mountdir); + + /* make sure alternate spool dir exists */ + if ((errno = mkdirs(alt_spooldir, OPEN_SPOOLMODE))) { + fprintf(stderr, "%s: cannot create alternate dir ", + progname); + perror(alt_spooldir); + plog(XLOG_ERROR, "cannot create alternate dir %s: %m", + alt_spooldir); + } + chmod(alt_spooldir, OPEN_SPOOLMODE); + + /* create failsafe link to alternate spool directory */ + slinkname[-1] = '/'; /* unsplit dir_name to include link */ + if (lstat(dir_name, &stmodes) == 0 && + (stmodes.st_mode & S_IFMT) != S_IFLNK) { + fprintf(stderr, "%s: failsafe %s not a symlink\n", + progname, dir_name); + plog(XLOG_WARNING, "failsafe %s not a symlink\n", + dir_name); + } else { + unlink(dir_name); + + if (symlink(alt_spooldir, dir_name) < 0) { + fprintf(stderr, + "%s: cannot create failsafe symlink %s -> ", + progname, dir_name); + perror(alt_spooldir); + plog(XLOG_WARNING, + "cannot create failsafe symlink %s -> %s: %m", + dir_name, alt_spooldir); + } + } + + slinkname[-1] = '\0'; /* resplit dir_name */ + } /* end of "if (!forcefast) {" */ + + /* + * Register hlfsd as an nfs service with the portmapper. + */ +#ifdef HAVE_TRANSPORT_TYPE_TLI + ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + if (ret != 0) + fatal("cannot create NFS service"); + +#ifdef HAVE_SIGACTION + sa.sa_handler = proceed; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGUSR2); + sigaction(SIGUSR2, &sa, NULL); +#else /* not HAVE_SIGACTION */ + signal(SIGUSR2, proceed); +#endif /* not HAVE_SIGACTION */ + + plog(XLOG_INFO, "Initializing hlfsd..."); + hlfsd_init(); /* start up child (forking) to run svc_run */ + +#ifdef HAVE_SIGACTION + sa.sa_handler = reaper; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGCHLD); + sigaction(SIGCHLD, &sa, NULL); +#else /* not HAVE_SIGACTION */ + signal(SIGCHLD, reaper); +#endif /* not HAVE_SIGACTION */ + +#ifdef DEBUG + /* + * In the parent, if -D nodaemon (or -D daemon) , we don't need to + * set this signal handler. + */ + amuDebug(D_DAEMON) { +#endif /* DEBUG */ + /* XXX: port to use pure svr4 signals */ + s = -99; + while (stoplight != SIGUSR2) { + plog(XLOG_INFO, "parent waits for child to setup (stoplight=%d)", stoplight); + s = sigpause(0); /* wait for child to set up */ + sleep(1); + } +#ifdef DEBUG + } +#endif /* DEBUG */ + + /* + * setup options to mount table (/etc/{mtab,mnttab}) entry + */ + sprintf(hostpid_fs, "%s:(pid%d)", hostname, masterpid); + memset((char *) &mnt, 0, sizeof(mnt)); + mnt.mnt_dir = dir_name; /* i.e., "/mail" */ + mnt.mnt_fsname = hostpid_fs; + if (mntopts) { + mnt.mnt_opts = mntopts; + } else { + strcpy(preopts, default_mntopts); + /* + * Turn off all kinds of attribute and symlink caches as + * much as possible. Also make sure that mount does not + * show up to df. + */ +#ifdef MNTTAB_OPT_INTR + strcat(preopts, ","); + strcat(preopts, MNTTAB_OPT_INTR); +#endif /* MNTTAB_OPT_INTR */ +#ifdef MNTTAB_OPT_IGNORE + strcat(preopts, ","); + strcat(preopts, MNTTAB_OPT_IGNORE); +#endif /* MNTTAB_OPT_IGNORE */ +#ifdef MNT2_GEN_OPT_CACHE + strcat(preopts, ",nocache"); +#endif /* MNT2_GEN_OPT_CACHE */ +#ifdef MNT2_NFS_OPT_SYMTTL + strcat(preopts, ",symttl=0"); +#endif /* MNT2_NFS_OPT_SYMTTL */ + mnt.mnt_opts = preopts; + } + + /* + * Make sure that amd's top-level NFS mounts are hidden by default + * from df. + * If they don't appear to support the either the "ignore" mnttab + * option entry, or the "auto" one, set the mount type to "nfs". + */ + mnt.mnt_type = HIDE_MOUNT_TYPE; + /* some systems don't have a mount type, but a mount flag */ + +#ifndef HAVE_TRANSPORT_TYPE_TLI + amu_get_myaddress(&localsocket.sin_addr); + localsocket.sin_family = AF_INET; + localsocket.sin_port = htons(nfsxprt->xp_port); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /* + * Update hostname field. + * Make some name prog:pid (i.e., hlfsd:174) for hostname + */ + sprintf(progpid_fs, "%s:%d", progname, masterpid); + + /* Most kernels have a name length restriction. */ + if ((int) strlen(progpid_fs) >= (int) MAXHOSTNAMELEN) + strcpy(progpid_fs + MAXHOSTNAMELEN - 3, ".."); + + genflags = compute_mount_flags(&mnt); + + retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); + if (retry <= 0) + retry = 1; /* XXX */ + + memmove(&anh.v2.fhs_fh, root_fhp, sizeof(*root_fhp)); +#ifdef HAVE_TRANSPORT_TYPE_TLI + compute_nfs_args(&nfs_args, + &mnt, + genflags, + nfsncp, + NULL, /* remote host IP addr is set below */ + NFS_VERSION, /* version 2 */ + "udp", /* XXX: shouldn't this be "udp"? */ + &anh, + progpid_fs, /* host name for kernel */ + hostpid_fs); /* filesystem name for kernel */ + /* + * IMPORTANT: set the correct IP address AFTERWARDS. It cannot + * be done using the normal mechanism of compute_nfs_args(), because + * that one will allocate a new address and use NFS_SA_DREF() to copy + * parts to it, while assuming that the ip_addr passed is always + * a "struct sockaddr_in". That assumption is incorrect on TLI systems, + * because they define a special macro HOST_SELF which is DIFFERENT + * than localhost (127.0.0.1)! + */ + nfs_args.addr = &nfsxprt->xp_ltaddr; +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + compute_nfs_args(&nfs_args, + &mnt, + genflags, + &localsocket, + NFS_VERSION, /* version 2 */ + "udp", /* XXX: shouldn't this be "udp"? */ + &anh, + progpid_fs, /* host name for kernel */ + hostpid_fs); /* filesystem name for kernel */ +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + /************************************************************************* + * NOTE: while compute_nfs_args() works ok for regular NFS mounts * + * the toplvl one is not, and so some options must be corrected by hand * + * more carefully, *after* compute_nfs_args() runs. * + *************************************************************************/ + compute_automounter_nfs_args(&nfs_args, &mnt); + + clock_valid = 0; /* invalidate logging clock */ + +/* + * The following code could be cleverly ifdef-ed, but I duplicated the + * mount_fs call three times for simplicity and readability. + */ +#ifdef DEBUG +/* + * For some reason, this mount may have to be done in the background, if I am + * using -D nodebug. I suspect that the actual act of mounting requires + * calling to hlfsd itself to invoke one or more of its nfs calls, to stat + * /mail. That means that even if you say -D nodaemon, at least the mount + * of hlfsd itself on top of /mail will be done in the background. + * The other alternative I have is to run svc_run, but set a special + * signal handler to perform the mount in N seconds via some alarm. + * -Erez Zadok. + */ + if (debug_flags & D_DAEMON) { /* asked for -D daemon */ + plog(XLOG_INFO, "parent NFS mounting hlfsd service points"); + if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name) < 0) + fatal("nfsmount: %m"); + } else { /* asked for -D nodaemon */ + if (fork() == 0) { /* child runs mount */ + mypid = getpid(); + foreground = 0; + plog(XLOG_INFO, "child NFS mounting hlfsd service points"); + if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 0, NULL, mnttab_file_name) < 0) { + fatal("nfsmount: %m"); + } + exit(0); /* all went well */ + } else { /* fork failed or parent running */ + plog(XLOG_INFO, "parent waiting 1sec for mount..."); + } + } +#else /* not DEBUG */ + plog(XLOG_INFO, "normal NFS mounting hlfsd service points"); + if (mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type, 2, "udp", mnttab_file_name) < 0) + fatal("nfsmount: %m"); +#endif /* not DEBUG */ + +#ifdef HAVE_TRANSPORT_TYPE_TLI + /* + * XXX: this free_knetconfig() was not done for hlfsd before, + * and apparently there was a reason for it, but why? -Erez + */ + free_knetconfig(nfs_args.knconf); + /* + * local automounter mounts do not allocate a special address, so + * no need to XFREE(nfs_args.addr) under TLI. + */ +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + + if (printpid) + printf("%d\n", masterpid); + + plog(XLOG_INFO, "hlfsd ready to serve"); +#ifdef DEBUG + /* + * If asked not to fork a daemon (-D nodaemon), then hlfsd_init() + * will not run svc_run. We must start svc_run here. + */ + dlog("starting no-daemon debugging svc_run"); + amuDebugNo(D_DAEMON) + svc_run(); +#endif /* DEBUG */ + + cleanup(0); /* should never happen here */ + return (0); /* everything went fine? */ +} + + +static void +hlfsd_init(void) +{ + int child = 0; +#ifdef HAVE_SIGACTION + struct sigaction sa; +#endif /* HAVE_SIGACTION */ + + clock_valid = 0; /* invalidate logging clock */ + + /* + * Initialize file handles. + */ + plog(XLOG_INFO, "initializing hlfsd file handles"); + hlfsd_init_filehandles(); + +#ifdef DEBUG + /* + * If -D daemon then we must fork. + */ + amuDebug(D_DAEMON) +#endif /* DEBUG */ + child = fork(); + + if (child < 0) + fatal("fork: %m"); + + if (child != 0) { /* parent process - save child pid */ + masterpid = child; + mypid = getpid(); /* for logging routines */ + return; + } + + /* + * CHILD CODE: + * initialize server + */ + + plog(XLOG_INFO, "initializing home directory database"); + plt_init(); /* initialize database */ + plog(XLOG_INFO, "home directory database initialized"); + + masterpid = serverpid = mypid = getpid(); /* for logging routines */ + + /* + * SIGALRM/SIGHUP: reload password database if timer expired + * or user sent HUP signal. + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = reload; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGALRM); + sigaddset(&(sa.sa_mask), SIGHUP); + sigaction(SIGALRM, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); +#else /* not HAVE_SIGACTION */ + signal(SIGALRM, reload); + signal(SIGHUP, reload); +#endif /* not HAVE_SIGACTION */ + + /* + * SIGTERM: cleanup and exit. + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = cleanup; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGTERM); + sigaction(SIGTERM, &sa, NULL); +#else /* not HAVE_SIGACTION */ + signal(SIGTERM, cleanup); +#endif /* not HAVE_SIGACTION */ + + /* + * SIGCHLD: interlock sycronization and testing + */ +#ifdef HAVE_SIGACTION + sa.sa_handler = interlock; + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGCHLD); + sigaction(SIGCHLD, &sa, NULL); +#else /* not HAVE_SIGACTION */ + signal(SIGCHLD, interlock); +#endif /* not HAVE_SIGACTION */ + + /* + * SIGUSR1: dump internal hlfsd maps/cache to file + */ +#ifdef HAVE_SIGACTION +# if defined(DEBUG) || defined(DEBUG_PRINT) + sa.sa_handler = plt_print; +# else /* not defined(DEBUG) || defined(DEBUG_PRINT) */ + sa.sa_handler = SIG_IGN; +# endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */ + sa.sa_flags = 0; + sigemptyset(&(sa.sa_mask)); + sigaddset(&(sa.sa_mask), SIGUSR1); + sigaction(SIGUSR1, &sa, NULL); +#else /* not HAVE_SIGACTION */ +# if defined(DEBUG) || defined(DEBUG_PRINT) + signal(SIGUSR1, plt_print); +# else /* not defined(DEBUG) || defined(DEBUG_PRINT) */ + signal(SIGUSR1, SIG_IGN); +# endif /* not defined(DEBUG) || defined(DEBUG_PRINT) */ +#endif /* not HAVE_SIGACTION */ + + if (setitimer(ITIMER_REAL, &reloadinterval, (struct itimerval *) 0) < 0) + fatal("setitimer: %m"); + + gettimeofday((struct timeval *) &startup, (struct timezone *) 0); + +#ifdef DEBUG + /* + * If -D daemon, then start serving here in the child, + * and the parent will exit. But if -D nodaemon, then + * skip this code and make sure svc_run is entered elsewhere. + */ + amuDebug(D_DAEMON) { +#endif /* DEBUG */ + + /* + * Dissociate from the controlling terminal + */ + amu_release_controlling_tty(); + + /* + * signal parent we are ready. parent should + * mount(2) and die. + */ + if (kill(getppid(), SIGUSR2) < 0) + fatal("kill: %m"); + plog(XLOG_INFO, "starting svc_run"); + svc_run(); + cleanup(0); /* should never happen, just in case */ +#ifdef DEBUG + } /* end of code that runs iff hlfsd daemonizes */ +#endif /* DEBUG */ + +} + + +static RETSIGTYPE +proceed(int signum) +{ + stoplight = signum; +} + + +static RETSIGTYPE +reload(int signum) +{ + int child; + int status; + + clock_valid = 0; /* invalidate logging clock */ + + if (getpid() != masterpid) + return; + + /* + * If received a SIGHUP, close and reopen the log file (so that it + * can be rotated) + */ + if (signum == SIGHUP && logfile) + switch_to_logfile(logfile); + + /* + * parent performs the reload, while the child continues to serve + * clients accessing the home dir link. + */ + if ((child = fork()) > 0) { + serverpid = child; /* parent runs here */ + mypid = getpid(); + + plt_init(); + + if (kill(child, SIGKILL) < 0) { + plog(XLOG_ERROR, "kill child: %m"); + } else { /* wait for child to die before continue */ + if (wait(&status) != child) { + /* + * I took out this line because it generates annoying output. It + * indicates a very small bug in hlfsd which is totally harmless. + * It causes hlfsd to work a bit harder than it should. + * Nevertheless, I intend on fixing it in a future release. + * -Erez Zadok + */ + /* plog(XLOG_ERROR, "unknown child"); */ + } + } + serverpid = masterpid; + } else if (child < 0) { + plog(XLOG_ERROR, "unable to fork: %m"); + } else { + /* let child handle requests while we reload */ + serverpid = getpid(); + mypid = getpid(); + } +} + + +RETSIGTYPE +cleanup(int signum) +{ + struct stat stbuf; + int umount_result; + + clock_valid = 0; /* invalidate logging clock */ + +#ifdef DEBUG + amuDebug(D_DAEMON) +#endif /* DEBUG */ + if (getpid() != masterpid) + return; + +#ifdef DEBUG + amuDebug(D_DAEMON) +#endif /* DEBUG */ + if (fork() != 0) { + masterpid = 0; + mypid = getpid(); + return; + } + mypid = getpid(); + + for (;;) { + while ((umount_result = UMOUNT_FS(dir_name, mnttab_file_name)) == EBUSY) { +#ifdef DEBUG + dlog("cleanup(): umount delaying for 10 seconds"); +#endif /* DEBUG */ + sleep(10); + } + if (stat(dir_name, &stbuf) == 0 && stbuf.st_ino == ROOTID) { + plog(XLOG_ERROR, "unable to unmount %s", dir_name); + plog(XLOG_ERROR, "suspending, unmount before terminating"); + kill(mypid, SIGSTOP); + continue; /* retry unmount */ + } + break; + } + +#ifdef DEBUG + dlog("cleanup(): killing processes and terminating"); + amuDebug(D_DAEMON) +#endif /* DEBUG */ + kill(masterpid, SIGKILL); + +#ifdef DEBUG + amuDebug(D_DAEMON) +#endif /* DEBUG */ + kill(serverpid, SIGKILL); + + plog(XLOG_INFO, "hlfsd terminating with status 0\n"); + exit(0); +} + + +static RETSIGTYPE +reaper(int signum) +{ + int result; + + if (wait(&result) == masterpid) { + exit(4); + } +} + + +void +hlfsd_going_down(int rc) +{ + int mypid = getpid(); + + if (mypid == masterpid) + cleanup(0); + else if (mypid == serverpid) + kill(masterpid, SIGTERM); + + exit(rc); +} + + +void +fatal(char *mess) +{ + if (logfile && !STREQ(logfile, "stderr")) { + char lessmess[128]; + int messlen; + + messlen = strlen(mess); + + if (!STREQ(&mess[messlen + 1 - sizeof(ERRM)], ERRM)) + fprintf(stderr, "%s: %s\n", progname, mess); + else { + strcpy(lessmess, mess); + lessmess[messlen - 4] = '\0'; + + if (errno < sys_nerr) + fprintf(stderr, "%s: %s: %s\n", progname, + lessmess, sys_errlist[errno]); + else + fprintf(stderr, "%s: %s: Error %d\n", + progname, lessmess, errno); + } + } + plog(XLOG_FATAL, mess); + + hlfsd_going_down(1); +} diff --git a/contrib/amd/hlfsd/hlfsd.h b/contrib/amd/hlfsd/hlfsd.h new file mode 100644 index 0000000..dec5d91 --- /dev/null +++ b/contrib/amd/hlfsd/hlfsd.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: hlfs.h,v 1.9 1993/09/13 15:11:00 ezk Exp $ + * + * HLFSD was written at Columbia University Computer Science Department, by + * Erez Zadok and Alexander Dupuy + * It is being distributed under the same terms and conditions as amd does. + */ + +#ifndef _HLFSD_HLFS_H +#define _HLFSD_HLFS_H + +/* + * MACROS AND CONSTANTS: + */ + +#define HLFSD_VERSION "hlfsd 1.1 (March 4, 1997-1998)" +#define PERS_SPOOLMODE 0755 +#define OPEN_SPOOLMODE 01777 +#define DOTSTRING "." + +/* + * ROOTID and SLINKID are the fixed "faked" node IDs (inodes) for + * the '.' (also '..') and the one symlink within the hlfs. + * They must always be unique, and should never match what a UID + * could be. + * They used to be -1 and -2, respectively. + * + * I used to cast these to (uid_t) but it failed to compile + * with /opt/SUNWspro/bin/cc because uid_t is long, while struct fattr's + * uid field is u_int. Then it failed to compile on some linux systems + * which define uid_t to be unsigned short, so I used the lowest common + * size which is unsigned short. + */ +#ifdef EXPERIMENTAL_UID_SIZE +#define UID_SHIFT 30 +# define ROOTID ((1 << UID_SHIFT) - 1) +# define SLINKID ((1 << UID_SHIFT) - 2) +# define INVALIDID ((1 << UID_SHIFT) - 3) +#else /* not EXPERIMENTAL_UID_SIZE */ +/* + * XXX: this will cause problems to systems with UIDs greater than + * MAX_UNSIGNED_SHORT-3. + */ +# define ROOTID (((unsigned short) ~0) - 1) +# define SLINKID (((unsigned short) ~0) - 2) +# define INVALIDID (((unsigned short) ~0) - 3) +#endif /* not EXPERIMENTAL_UID_SIZE */ + + +#define DOTCOOKIE 1 +#define DOTDOTCOOKIE 2 +#define SLINKCOOKIE 3 + +#define ALT_SPOOLDIR "/var/hlfs" /* symlink to use if others fail */ +#define HOME_SUBDIR ".hlfsdir" /* dirname in user's home dir */ +#define DEFAULT_DIRNAME "/hlfs/home" +#define DEFAULT_INTERVAL 900 /* secs b/t re-reads of the password maps */ +#define DEFAULT_CACHE_INTERVAL 300 /* secs during which assume a link is up */ +#define DEFAULT_HLFS_GROUP "hlfs" /* Group name for special hlfs_gid */ + +#define PROGNAMESZ (MAXHOSTNAMELEN - 5) + +#ifdef HAVE_SYSLOG +# define DEFAULT_LOGFILE "syslog" +#else /* not HAVE)_SYSLOG */ +# define DEFAULT_LOGFILE 0 +#endif /* not HAVE)_SYSLOG */ + +#define ERRM ": %m" +#define fatalerror(str) \ + (fatal (strcat (strnsave ((str), strlen ((str)) + sizeof (ERRM) - 1), ERRM))) + +/* + * TYPDEFS: + */ +typedef struct uid2home_t uid2home_t; +typedef struct username2uid_t username2uid_t; + + +/* + * STRUCTURES: + */ +struct uid2home_t { + uid_t uid; /* XXX: with or without UID_OFFSET? */ + pid_t child; + char *home; /* really allocated */ + char *uname; /* an xref ptr to username2uid_t->username */ + u_long last_access_time; + int last_status; /* 0=used $HOME/.hlfsspool; !0=used alt dir */ +}; + +struct username2uid_t { + char *username; /* really allocated */ + uid_t uid; /* XXX: with or without UID_OFFSET? */ + char *home; /* an xref ptr to uid2home_t->home */ +}; + +/* + * EXTERNALS: + */ +extern RETSIGTYPE cleanup(int); +extern RETSIGTYPE interlock(int); +extern SVCXPRT *nfs_program_2_transp; /* For quick_reply() */ +extern SVCXPRT *nfsxprt; +extern char *alt_spooldir; +extern char *home_subdir; +extern char *homedir(int); +extern char *mailbox(int, char *); +extern char *passwdfile; +extern char *slinkname; +extern char mboxfile[]; +extern gid_t hlfs_gid; +extern int cache_interval; +extern int noverify; +extern int serverpid; +extern int sys_nerr; +extern int untab_index(char *username); +extern am_nfs_fh *root_fhp; +extern am_nfs_fh root; +extern nfstime startup; +extern uid2home_t *plt_search(int); +extern username2uid_t *untab; /* user name table */ +extern void fatal(char *); +extern void plt_init(void); +extern void hlfsd_init_filehandles(void); + +#if defined(DEBUG) || defined(DEBUG_PRINT) +extern void plt_dump(uid2home_t *, pid_t); +extern void plt_print(int); +#endif /* defined(DEBUG) || defined(DEBUG_PRINT) */ + +#endif /* _HLFSD_HLFS_H */ diff --git a/contrib/amd/hlfsd/homedir.c b/contrib/amd/hlfsd/homedir.c new file mode 100644 index 0000000..d6df58e --- /dev/null +++ b/contrib/amd/hlfsd/homedir.c @@ -0,0 +1,799 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: homedir.c,v 1.16 1993/09/13 15:11:00 ezk Exp $ + * + * HLFSD was written at Columbia University Computer Science Department, by + * Erez Zadok and Alexander Dupuy + * It is being distributed under the same terms and conditions as amd does. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* + * STATIC VARIABLES AND FUNCTIONS: + */ +static FILE *passwd_fp = NULL; +static char pw_name[16], pw_dir[128]; +static int cur_pwtab_num = 0, max_pwtab_num = 0; +static int hlfsd_diskspace(char *); +static int hlfsd_stat(char *, struct stat *); +static int passwd_line = 0; +static int plt_reset(void); +static struct passwd passwd_ent; +static uid2home_t *lastchild; +static uid2home_t *pwtab; +static void delay(uid2home_t *, int); +static void table_add(int, char *, char *); + +/* GLOBAL FUNCTIONS */ +char *homeof(char *username); +int uidof(char *username); + +/* GLOBALS VARIABLES */ +char mboxfile[MAXPATHLEN]; +username2uid_t *untab; /* user name table */ + + +/* + * Return the home directory pathname for the user with uid "userid". + */ +char * +homedir(int userid) +{ + static char linkval[MAXPATHLEN + 1]; + static struct timeval tp; + uid2home_t *found; + char *homename; + struct stat homestat; + + clock_valid = 0; /* invalidate logging clock */ + + if ((int) userid == 0) { /* force superuser to use "/" as home */ + sprintf(linkval, "/%s", home_subdir); + return linkval; + } + if ((found = plt_search(userid)) == (uid2home_t *) NULL) { + return alt_spooldir; /* use alt spool for unknown uid */ + } + homename = found->home; + + if (homename[0] != '/' || homename[1] == '\0') { + found->last_status = 1; + return alt_spooldir; /* use alt spool for / or rel. home */ + } + sprintf(linkval, "%s/%s", homename, home_subdir); + + if (noverify) { + found->last_status = 0; + return linkval; + } + + /* + * To optimize hlfsd, we don't actually check the validity of the + * symlink if it has been in checked in the last N seconds. It is + * very likely that the link, machine, and filesystem are still + * valid, as long as N is small. But if N ls large, that may not be + * true. That's why the default N is 5 minutes, but we allow the + * user to override this value via a command line option. Note that + * we do not update the last_access_time each time it is accessed, + * but only once every N seconds. + */ + if (gettimeofday(&tp, (struct timezone *) NULL) < 0) { + tp.tv_sec = 0; + } else { + if ((tp.tv_sec - found->last_access_time) < cache_interval) { + if (found->last_status == 0) { + return linkval; + } else { + return alt_spooldir; + } + } else { + found->last_access_time = tp.tv_sec; + } + } + +#ifdef DEBUG + /* + * only run this forking code if asked for -D fork + * or if did not ask for -D nofork + */ + amuDebug(D_FORK) { +#endif /* DEBUG */ + /* fork child to process request if none in progress */ + if (found->child && kill(found->child, 0)) + found->child = 0; + + if (found->child) + delay(found, 5); /* wait a bit if in progress */ + if (found->child) { /* better safe than sorry - maybe */ + found->last_status = 1; + return alt_spooldir; + } + if ((found->child = fork()) < 0) { + found->last_status = 1; + return alt_spooldir; + } + if (found->child) { /* PARENT */ +#ifdef DEBUG + if (lastchild) + plog(XLOG_INFO, "cache spill uid = %d, pid = %d, home = %s", + lastchild->uid, lastchild->child, + lastchild->home); +#endif /* DEBUG */ + lastchild = found; + return (char *) NULL; /* return NULL to parent, so it can continue */ + } +#ifdef DEBUG + } /* end of Debug(D_FORK) */ +#endif /* DEBUG */ + + /* + * CHILD: (or parent if -D nofork) + * + * Check and create dir if needed. + * Check disk space and/or quotas too. + * + * We don't need to set the _last_status field of found after the fork + * in the child, b/c that information would be later determined in + * nfsproc_readlink_2() and the correct exit status would be returned + * to the parent upon SIGCHLD in interlock(). + * + */ + mypid = getpid(); /* for logging routines */ + if (seteuid(userid) < 0) { + plog(XLOG_WARNING, "could not seteuid to %d: %m", userid); + return linkval; + } + if (hlfsd_stat(linkval, &homestat) < 0) { + if (errno == ENOENT) { /* make the spool dir if possible */ + /* don't use recursive mkdirs here */ + if (mkdir(linkval, PERS_SPOOLMODE) < 0) { + seteuid(0); + plog(XLOG_WARNING, "can't make directory %s: %m", linkval); + return alt_spooldir; + } + /* fall through to testing the disk space / quota */ + } else { /* the home dir itself must not exist then */ + seteuid(0); + plog(XLOG_WARNING, "bad link to %s: %m", linkval); + return alt_spooldir; + } + } + + /* + * If gets here, then either the spool dir in the home dir exists, + * or it was just created. In either case, we now need to + * test if we can create a small file and write at least one + * byte into it. This will test that we have both enough inodes + * and disk blocks to spare, or they fall within the user's quotas too. + * We are still seteuid to the user at this point. + */ + if (hlfsd_diskspace(linkval) < 0) { + seteuid(0); + plog(XLOG_WARNING, "no more space in %s: %m", linkval); + return alt_spooldir; + } else { + seteuid(0); + return linkval; + } +} + + +static int +hlfsd_diskspace(char *path) +{ + char buf[MAXPATHLEN]; + int fd, len; + + clock_valid = 0; /* invalidate logging clock */ + + sprintf(buf, "%s/._hlfstmp_%lu", path, (long) getpid()); + if ((fd = open(buf, O_RDWR | O_CREAT, 0600)) < 0) { + plog(XLOG_ERROR, "cannot open %s: %m", buf); + return -1; + } + len = strlen(buf); + if (write(fd, buf, len) < len) { + plog(XLOG_ERROR, "cannot write \"%s\" (%d bytes) to %s : %m", buf, len, buf); + close(fd); + unlink(buf); /* cleanup just in case */ + return -1; + } + if (unlink(buf) < 0) { + plog(XLOG_ERROR, "cannot unlink %s : %m", buf); + } + close(fd); + return 0; +} + + +static int +hlfsd_stat(char *path, struct stat *statp) +{ + if (stat(path, statp) < 0) + return -1; + else if (!S_ISDIR(statp->st_mode)) { + errno = ENOTDIR; + return -1; + } + return 0; +} + + +static void +delay(uid2home_t *found, int secs) +{ + struct timeval tv; + +#ifdef DEBUG + if (found) + dlog("delaying on child %d for %d seconds", found->child, secs); +#endif /* DEBUG */ + + tv.tv_usec = 0; + + do { + tv.tv_sec = secs; + if (select(0, 0, 0, 0, &tv) == 0) + break; + } while (--secs && found->child); +} + + +/* + * This function is called when a child has terminated after + * servicing an nfs request. We need to check the exit status and + * update the last_status field of the requesting user. + */ +RETSIGTYPE +interlock(int signum) +{ + int child; + uid2home_t *lostchild; + int status; + +#ifdef HAVE_WAITPID + while ((child = waitpid((pid_t) -1, &status, WNOHANG)) > 0) { +#else /* not HAVE_WAITPID */ + while ((child = wait3(&status, WNOHANG, (struct rusage *) 0)) > 0) { +#endif /* not HAVE_WAITPID */ + + /* high chances this was the last child forked */ + if (lastchild && lastchild->child == child) { + lastchild->child = 0; + + if (WIFEXITED(status)) + lastchild->last_status = WEXITSTATUS(status); + lastchild = (uid2home_t *) NULL; + } else { + /* and if not, we have to search for it... */ + for (lostchild = pwtab; lostchild < &pwtab[cur_pwtab_num]; lostchild++) { + if (lostchild->child == child) { + if (WIFEXITED(status)) + lostchild->last_status = WEXITSTATUS(status); + lostchild->child = 0; + break; + } + } + } + } +} + + +/* + * PASSWORD AND USERNAME LOOKUP TABLES FUNCTIONS + */ + +/* + * get index of UserName table entry which matches username. + * must not return uid_t because we want to return a negative number. + */ +int +untab_index(char *username) +{ + int max, min, mid, cmp; + + max = cur_pwtab_num - 1; + min = 0; + + do { + mid = (max + min) / 2; + cmp = strcmp(untab[mid].username, username); + if (cmp == 0) /* record found! */ + return mid; + if (cmp > 0) + max = mid; + else + min = mid; + } while (max > min + 1); + + if (STREQ(untab[max].username, username)) + return max; + if (STREQ(untab[min].username, username)) + return min; + + /* if gets here then record was not found */ + return -1; +} + + +/* + * Don't make this return a uid_t, because we need to return negative + * numbers as well (error codes.) + */ +int +uidof(char *username) +{ + int idx; + + if ((idx = untab_index(username)) < 0) /* not found */ + return INVALIDID; /* an invalid user id */ + return untab[idx].uid; +} + + +/* + * Don't make this return a uid_t, because we need to return negative + * numbers as well (error codes.) + */ +char * +homeof(char *username) +{ + int idx; + + if ((idx = untab_index(username)) < 0) /* not found */ + return (char *) NULL; /* an invalid user id */ + return untab[idx].home; +} + + +char * +mailbox(int uid, char *username) +{ + char *home; + + if (uid < 0) + return (char *) NULL; /* not found */ + + if ((home = homeof(username)) == (char *) NULL) + return (char *) NULL; + if (STREQ(home, "/")) + sprintf(mboxfile, "/%s/%s", home_subdir, username); + else + sprintf(mboxfile, "%s/%s/%s", home, home_subdir, username); + return mboxfile; +} + + +static int +plt_compare_fxn(const voidp x, const voidp y) + +{ + uid2home_t *i = (uid2home_t *) x; + uid2home_t *j = (uid2home_t *) y; + + return i->uid - j->uid; +} + + +static int +unt_compare_fxn(const voidp x, const voidp y) +{ + username2uid_t *i = (username2uid_t *) x; + username2uid_t *j = (username2uid_t *) y; + + return strcmp(i->username, j->username); +} + + +/* perform initialization of user passwd database */ +static void +hlfsd_setpwent(void) +{ + if (!passwdfile) { + setpwent(); + return; + } + + passwd_fp = fopen(passwdfile, "r"); + if (!passwd_fp) { + plog(XLOG_ERROR, "unable to read passwd file %s: %m", passwdfile); + return; + } + plog(XLOG_INFO, "reading password entries from file %s", passwdfile); + + passwd_line = 0; + memset((char *) &passwd_ent, 0, sizeof(struct passwd)); + passwd_ent.pw_name = (char *) &pw_name; + passwd_ent.pw_dir = (char *) &pw_dir; +} + + +/* perform de-initialization of user passwd database */ +static void +hlfsd_endpwent(void) +{ + if (!passwdfile) { + /* + * Don't actually run this because we will be making more passwd calls + * afterwards. On Solaris 2.5.1, making getpwent() calls after calling + * endpwent() results in a memory leak! (and no, even Purify didn't + * detect it...) + * + endpwent(); + */ + return; + } + + if (passwd_fp) { + fclose(passwd_fp); + } +} + + +/* perform record reading/parsing of individual passwd database records */ +static struct passwd * +hlfsd_getpwent(void) +{ + char buf[256], *cp; + + /* check if to perform standard unix function */ + if (!passwdfile) { + return getpwent(); + } + + clock_valid = 0; /* invalidate logging clock */ + + /* return here to read another entry */ +readent: + + /* return NULL if reached end of file */ + if (feof(passwd_fp)) + return NULL; + + pw_name[0] = pw_dir[0] = '\0'; + + /* read records */ + buf[0] = '\0'; + fgets(buf, 256, passwd_fp); + passwd_line++; + if (!buf || buf[0] == '\0') + goto readent; + + /* read user name */ + cp = strtok(buf, ":"); + if (!cp || cp[0] == '\0') { + plog(XLOG_ERROR, "no user name on line %d of %s", passwd_line, passwdfile); + goto readent; + } + strcpy(pw_name, cp); /* will show up in passwd_ent.pw_name */ + + /* skip passwd */ + strtok(NULL, ":"); + + /* read uid */ + cp = strtok(NULL, ":"); + if (!cp || cp[0] == '\0') { + plog(XLOG_ERROR, "no uid on line %d of %s", passwd_line, passwdfile); + goto readent; + } + passwd_ent.pw_uid = atoi(cp); + + /* skip gid and gcos */ + strtok(NULL, ":"); + strtok(NULL, ":"); + + /* read home dir */ + cp = strtok(NULL, ":"); + if (!cp || cp[0] == '\0') { + plog(XLOG_ERROR, "no home dir on line %d of %s", passwd_line, passwdfile); + goto readent; + } + strcpy(pw_dir, cp); /* will show up in passwd_ent.pw_dir */ + + /* the rest of the fields are unimportant and not being considered */ + + plog(XLOG_USER, "hlfsd_getpwent: name=%s, uid=%d, dir=%s", + passwd_ent.pw_name, passwd_ent.pw_uid, passwd_ent.pw_dir); + + return &passwd_ent; +} + + +/* + * read and hash the passwd file or NIS map + */ +void +plt_init(void) +{ + struct passwd *pent_p; + + if (plt_reset() < 0) /* could not reset table. skip. */ + return; + + plog(XLOG_INFO, "reading password map"); + + hlfsd_setpwent(); /* prepare to read passwd entries */ + while ((pent_p = hlfsd_getpwent()) != (struct passwd *) NULL) { + table_add(pent_p->pw_uid, pent_p->pw_dir, pent_p->pw_name); + } + hlfsd_endpwent(); + + qsort((char *) pwtab, cur_pwtab_num, sizeof(uid2home_t), + plt_compare_fxn); + qsort((char *) untab, cur_pwtab_num, sizeof(username2uid_t), + unt_compare_fxn); + + plog(XLOG_INFO, "password map read and sorted"); +} + + +/* + * This is essentially so that we don't reset known good lookup tables when a + * YP server goes down. + */ +static int +plt_reset(void) +{ + int i; + + clock_valid = 0; /* invalidate logging clock */ + + hlfsd_setpwent(); + if (hlfsd_getpwent() == (struct passwd *) NULL) { + hlfsd_endpwent(); + return -1; /* did not reset table */ + } + hlfsd_endpwent(); + + lastchild = (uid2home_t *) NULL; + + if (max_pwtab_num > 0) /* was used already. cleanup old table */ + for (i = 0; i < cur_pwtab_num; ++i) { + if (pwtab[i].home) { + XFREE(pwtab[i].home); + pwtab[i].home = (char *) NULL; + } + pwtab[i].uid = INVALIDID; /* not a valid uid (yet...) */ + pwtab[i].child = (pid_t) 0; + pwtab[i].uname = (char *) NULL; /* only a ptr to untab[i].username */ + if (untab[i].username) { + XFREE(untab[i].username); + untab[i].username = (char *) NULL; + } + untab[i].uid = INVALIDID; /* invalid uid */ + untab[i].home = (char *) NULL; /* only a ptr to pwtab[i].home */ + } + cur_pwtab_num = 0; /* zero current size */ + + return 0; /* resetting ok */ +} + + +/* + * u: uid number + * h: home directory + * n: user ID name + */ +static void +table_add(int u, char *h, char *n) +{ + int i; + + clock_valid = 0; /* invalidate logging clock */ + + if (max_pwtab_num <= 0) { /* was never initialized */ + max_pwtab_num = 1; + pwtab = (uid2home_t *) xmalloc(max_pwtab_num * + sizeof(uid2home_t)); + memset((char *) &pwtab[0], 0, max_pwtab_num * sizeof(uid2home_t)); + untab = (username2uid_t *) xmalloc(max_pwtab_num * + sizeof(username2uid_t)); + memset((char *) &untab[0], 0, max_pwtab_num * sizeof(username2uid_t)); + } + + /* check if need more space. */ + if (cur_pwtab_num + 1 > max_pwtab_num) { + /* need more space in table */ + max_pwtab_num *= 2; + plog(XLOG_INFO, "reallocating table spaces to %d entries", max_pwtab_num); + pwtab = (uid2home_t *) xrealloc(pwtab, + sizeof(uid2home_t) * max_pwtab_num); + untab = (username2uid_t *) xrealloc(untab, + sizeof(username2uid_t) * + max_pwtab_num); + /* zero out newly added entries */ + for (i=cur_pwtab_num; i u) + max = mid; + else + min = mid; + } while (max > min + 1); + + if (pwtab[max].uid == u) + return &pwtab[max]; + if (pwtab[min].uid == u) + return &pwtab[min]; + + /* if gets here then record was not found */ + return (uid2home_t *) NULL; +} + + +#if defined(DEBUG) || defined(DEBUG_PRINT) +void +plt_print(int signum) +{ + FILE *dumpfile; + int dumpfd; + char dumptmp[] = "/usr/tmp/hlfsd.dump.XXXXXX"; + int i; + +#ifdef HAVE_MKSTEMP + dumpfd = mkstemp(dumptmp); +#else /* not HAVE_MKSTEMP */ + mktemp(dumptmp); + if (!dumptmp) { + plot(XLOG_ERROR, "cannot create temporary dump file"); + return; + } + dumpfd = open(dumptmp, O_RDONLY); +#endif /* not HAVE_MKSTEMP */ + if (dumpfd < 0) { + plog(XLOG_ERROR, "cannot open temporary dump file"); + return; + } + if ((dumpfile = fdopen(dumpfd, "a")) != NULL) { + plog(XLOG_INFO, "dumping internal state to file %s", dumptmp); + fprintf(dumpfile, "\n\nNew plt_dump():\n"); + for (i = 0; i < cur_pwtab_num; ++i) + fprintf(dumpfile, + "%4d %5lu %10lu %1d %4lu \"%s\" uname=\"%s\"\n", + i, + (long) pwtab[i].child, + pwtab[i].last_access_time, + pwtab[i].last_status, + (long) pwtab[i].uid, + pwtab[i].home, + pwtab[i].uname); + fprintf(dumpfile, "\nUserName table by plt_print():\n"); + for (i = 0; i < cur_pwtab_num; ++i) + fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i, + untab[i].username, (long) untab[i].uid, untab[i].home); + close(dumpfd); + fclose(dumpfile); + } +} + + +void +plt_dump(uid2home_t *lastc, pid_t this) +{ + FILE *dumpfile; + int i; + + if ((dumpfile = fopen("/var/tmp/hlfsdump", "a")) != NULL) { + fprintf(dumpfile, "\n\nNEW PLT_DUMP -- "); + fprintf(dumpfile, "lastchild->child=%d ", + (int) (lastc ? lastc->child : -999)); + fprintf(dumpfile, ", child from wait3=%lu:\n", (long) this); + for (i = 0; i < cur_pwtab_num; ++i) + fprintf(dumpfile, "%4d %5lu: %4lu \"%s\" uname=\"%s\"\n", i, + (long) pwtab[i].child, (long) pwtab[i].uid, + pwtab[i].home, pwtab[i].uname); + fprintf(dumpfile, "\nUserName table by plt_dump():\n"); + for (i = 0; i < cur_pwtab_num; ++i) + fprintf(dumpfile, "%4d : \"%s\" %4lu \"%s\"\n", i, + untab[i].username, (long) untab[i].uid, untab[i].home); + fprintf(dumpfile, "ezk: ent=%d, uid=%lu, home=\"%s\"\n", + untab_index("ezk"), + (long) untab[untab_index("ezk")].uid, + pwtab[untab[untab_index("ezk")].uid].home); + fprintf(dumpfile, "rezk: ent=%d, uid=%lu, home=\"%s\"\n", + untab_index("rezk"), + (long) untab[untab_index("rezk")].uid, + pwtab[untab[untab_index("rezk")].uid].home); + fclose(dumpfile); + } +} +#endif /* defined(DEBUG) || defined(DEBUG_PRINT) */ diff --git a/contrib/amd/hlfsd/nfs_prot_svc.c b/contrib/amd/hlfsd/nfs_prot_svc.c new file mode 100644 index 0000000..fc2e663 --- /dev/null +++ b/contrib/amd/hlfsd/nfs_prot_svc.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_prot_svc.c,v 5.2.2.1 1992/02/09 15:09:30 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* EXTERNAL FUNCTIONS */ +extern voidp nfsproc_null_2_svc(voidp, struct svc_req *); +extern nfsattrstat * nfsproc_getattr_2_svc(am_nfs_fh *, struct svc_req *); +extern nfsattrstat * nfsproc_setattr_2_svc(nfssattrargs *, struct svc_req *); +extern voidp nfsproc_root_2_svc(voidp, struct svc_req *); +extern nfsdiropres * nfsproc_lookup_2_svc(nfsdiropargs *, struct svc_req *); +extern nfsreadlinkres * nfsproc_readlink_2_svc(am_nfs_fh *, struct svc_req *); +extern nfsreadres * nfsproc_read_2_svc(nfsreadargs *, struct svc_req *); +extern voidp nfsproc_writecache_2_svc(voidp, struct svc_req *); +extern nfsattrstat * nfsproc_write_2_svc(nfswriteargs *, struct svc_req *); +extern nfsdiropres * nfsproc_create_2_svc(nfscreateargs *, struct svc_req *); +extern nfsstat * nfsproc_remove_2_svc(nfsdiropargs *, struct svc_req *); +extern nfsstat * nfsproc_rename_2_svc(nfsrenameargs *, struct svc_req *); +extern nfsstat * nfsproc_link_2_svc(nfslinkargs *, struct svc_req *); +extern nfsstat * nfsproc_symlink_2_svc(nfssymlinkargs *, struct svc_req *); +extern nfsdiropres * nfsproc_mkdir_2_svc(nfscreateargs *, struct svc_req *); +extern nfsstat * nfsproc_rmdir_2_svc(nfsdiropargs *, struct svc_req *); +extern nfsreaddirres * nfsproc_readdir_2_svc(nfsreaddirargs *, struct svc_req *); +extern nfsstatfsres * nfsproc_statfs_2_svc(am_nfs_fh *, struct svc_req *); + +/* GLOBALS */ +SVCXPRT *nfs_program_2_transp; + +/* TYPEDEFS */ +typedef char *(*nfssvcproc_t)(voidp, struct svc_req *); + + +void +nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp) +{ + union { + am_nfs_fh nfsproc_getattr_2_arg; + nfssattrargs nfsproc_setattr_2_arg; + nfsdiropargs nfsproc_lookup_2_arg; + am_nfs_fh nfsproc_readlink_2_arg; + nfsreadargs nfsproc_read_2_arg; + nfswriteargs nfsproc_write_2_arg; + nfscreateargs nfsproc_create_2_arg; + nfsdiropargs nfsproc_remove_2_arg; + nfsrenameargs nfsproc_rename_2_arg; + nfslinkargs nfsproc_link_2_arg; + nfssymlinkargs nfsproc_symlink_2_arg; + nfscreateargs nfsproc_mkdir_2_arg; + nfsdiropargs nfsproc_rmdir_2_arg; + nfsreaddirargs nfsproc_readdir_2_arg; + am_nfs_fh nfsproc_statfs_2_arg; + } argument; + char *result; + xdrproc_t xdr_argument, xdr_result; + nfssvcproc_t local; + + nfs_program_2_transp = NULL; + + switch (rqstp->rq_proc) { + + case NFSPROC_NULL: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (nfssvcproc_t) nfsproc_null_2_svc; + break; + + case NFSPROC_GETATTR: + xdr_argument = (xdrproc_t) xdr_nfs_fh; + xdr_result = (xdrproc_t) xdr_attrstat; + local = (nfssvcproc_t) nfsproc_getattr_2_svc; + break; + + case NFSPROC_SETATTR: + xdr_argument = (xdrproc_t) xdr_sattrargs; + xdr_result = (xdrproc_t) xdr_attrstat; + local = (nfssvcproc_t) nfsproc_setattr_2_svc; + break; + + case NFSPROC_ROOT: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (nfssvcproc_t) nfsproc_root_2_svc; + break; + + case NFSPROC_LOOKUP: + xdr_argument = (xdrproc_t) xdr_diropargs; + xdr_result = (xdrproc_t) xdr_diropres; + local = (nfssvcproc_t) nfsproc_lookup_2_svc; + /* + * Cheap way to pass transp down to afs_lookuppn so it can + * be stored in the am_node structure and later used for + * quick_reply(). + */ + nfs_program_2_transp = transp; + break; + + case NFSPROC_READLINK: + xdr_argument = (xdrproc_t) xdr_nfs_fh; + xdr_result = (xdrproc_t) xdr_readlinkres; + local = (nfssvcproc_t) nfsproc_readlink_2_svc; + break; + + case NFSPROC_READ: + xdr_argument = (xdrproc_t) xdr_readargs; + xdr_result = (xdrproc_t) xdr_readres; + local = (nfssvcproc_t) nfsproc_read_2_svc; + break; + + case NFSPROC_WRITECACHE: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = (xdrproc_t) xdr_void; + local = (nfssvcproc_t) nfsproc_writecache_2_svc; + break; + + case NFSPROC_WRITE: + xdr_argument = (xdrproc_t) xdr_writeargs; + xdr_result = (xdrproc_t) xdr_attrstat; + local = (nfssvcproc_t) nfsproc_write_2_svc; + break; + + case NFSPROC_CREATE: + xdr_argument = (xdrproc_t) xdr_createargs; + xdr_result = (xdrproc_t) xdr_diropres; + local = (nfssvcproc_t) nfsproc_create_2_svc; + break; + + case NFSPROC_REMOVE: + xdr_argument = (xdrproc_t) xdr_diropargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_remove_2_svc; + break; + + case NFSPROC_RENAME: + xdr_argument = (xdrproc_t) xdr_renameargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_rename_2_svc; + break; + + case NFSPROC_LINK: + xdr_argument = (xdrproc_t) xdr_linkargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_link_2_svc; + break; + + case NFSPROC_SYMLINK: + xdr_argument = (xdrproc_t) xdr_symlinkargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_symlink_2_svc; + break; + + case NFSPROC_MKDIR: + xdr_argument = (xdrproc_t) xdr_createargs; + xdr_result = (xdrproc_t) xdr_diropres; + local = (nfssvcproc_t) nfsproc_mkdir_2_svc; + break; + + case NFSPROC_RMDIR: + xdr_argument = (xdrproc_t) xdr_diropargs; + xdr_result = (xdrproc_t) xdr_nfsstat; + local = (nfssvcproc_t) nfsproc_rmdir_2_svc; + break; + + case NFSPROC_READDIR: + xdr_argument = (xdrproc_t) xdr_readdirargs; + xdr_result = (xdrproc_t) xdr_readdirres; + local = (nfssvcproc_t) nfsproc_readdir_2_svc; + break; + + case NFSPROC_STATFS: + xdr_argument = (xdrproc_t) xdr_nfs_fh; + xdr_result = (xdrproc_t) xdr_statfsres; + local = (nfssvcproc_t) nfsproc_statfs_2_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + + memset((char *) &argument, 0, sizeof(argument)); + if (!svc_getargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) &argument)) { + plog(XLOG_ERROR, + "NFS xdr decode failed for %d %d %d", + rqstp->rq_prog, rqstp->rq_vers, rqstp->rq_proc); + svcerr_decode(transp); + return; + } + result = (*local) (&argument, rqstp); + + nfs_program_2_transp = NULL; + + if (result != NULL && !svc_sendreply(transp, + (XDRPROC_T_TYPE) xdr_result, + result)) { + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, + (XDRPROC_T_TYPE) xdr_argument, + (SVC_IN_ARG_TYPE) & argument)) { + plog(XLOG_FATAL, "unable to free rpc arguments in nfs_program_2"); + going_down(1); + } +} diff --git a/contrib/amd/hlfsd/stubs.c b/contrib/amd/hlfsd/stubs.c new file mode 100644 index 0000000..2ead112 --- /dev/null +++ b/contrib/amd/hlfsd/stubs.c @@ -0,0 +1,530 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: stubs.c,v 1.10 1993/09/13 15:11:00 ezk Exp $ + * + * HLFSD was written at Columbia University Computer Science Department, by + * Erez Zadok and Alexander Dupuy + * It is being distributed under the same terms and conditions as amd does. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * STATIC VARIABLES: + */ +static nfsfattr rootfattr = {NFDIR, 0040555, 2, 0, 0, 512, 512, 0, + 1, 0, ROOTID}; +static nfsfattr slinkfattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0, + (NFS_MAXPATHLEN + 1) / 512, 0, SLINKID}; + /* user name file attributes */ +static nfsfattr un_fattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0, + (NFS_MAXPATHLEN + 1) / 512, 0, INVALIDID}; +static int getcreds(struct svc_req *, uid_t *, gid_t *); +static int started; +static am_nfs_fh slink; +static am_nfs_fh un_fhandle; + +/* + * GLOBALS: + */ +am_nfs_fh root; +am_nfs_fh *root_fhp = &root; + + +/* initialize NFS file handles for hlfsd */ +void +hlfsd_init_filehandles(void) +{ + u_int ui; + + ui = ROOTID; + memcpy(root.fh_data, &ui, sizeof(ui)); + + ui = SLINKID; + memcpy(slink.fh_data, &ui, sizeof(ui)); + + ui = INVALIDID; + memcpy(un_fhandle.fh_data, &ui, sizeof(ui)); +} + + +voidp +nfsproc_null_2_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +/* compare if two filehandles are equal */ +static int +eq_fh(const am_nfs_fh *fh1, const am_nfs_fh *fh2) +{ + return (!memcmp((char *) fh1, (char *) fh2, sizeof(am_nfs_fh))); +} + + +nfsattrstat * +nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) +{ + static nfsattrstat res; + uid_t uid = (uid_t) INVALIDID; + gid_t gid = (gid_t) INVALIDID; + + if (!started) { + started++; + rootfattr.na_ctime = startup; + rootfattr.na_mtime = startup; + slinkfattr.na_ctime = startup; + slinkfattr.na_mtime = startup; + un_fattr.na_ctime = startup; + un_fattr.na_mtime = startup; + } + + if (eq_fh(argp, &root)) { + res.ns_status = NFS_OK; + res.ns_u.ns_attr_u = rootfattr; + } else if (eq_fh(argp, &slink)) { + +#ifndef MNT2_NFS_OPT_SYMTTL + /* + * This code is needed to defeat Solaris 2.4's (and newer) symlink + * values cache. It forces the last-modifed time of the symlink to be + * current. It is not needed if the O/S has an nfs flag to turn off the + * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez. + */ + if (++slinkfattr.na_mtime.nt_useconds == 0) + ++slinkfattr.na_mtime.nt_seconds; +#endif /* not MNT2_NFS_OPT_SYMTTL */ + + res.ns_status = NFS_OK; + res.ns_u.ns_attr_u = slinkfattr; + } else { + + if (getcreds(rqstp, &uid, &gid) < 0) { + res.ns_status = NFSERR_STALE; + return &res; + } + if (gid != hlfs_gid) { + res.ns_status = NFSERR_STALE; + } else { + memset((char *) &uid, 0, sizeof(int)); + uid = *(u_int *) argp->fh_data; + if (plt_search(uid) != (uid2home_t *) NULL) { + res.ns_status = NFS_OK; + un_fattr.na_fileid = uid; + res.ns_u.ns_attr_u = un_fattr; +#ifdef DEBUG + dlog("nfs_getattr: succesful search for uid=%d, gid=%d", uid, gid); +#endif /* DEBUG */ + } else { /* not found */ + res.ns_status = NFSERR_STALE; + } + } + } + return &res; +} + + +nfsattrstat * +nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp) +{ + static nfsattrstat res = {NFSERR_ROFS}; + + return &res; +} + + +voidp +nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +nfsdiropres * +nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) +{ + static nfsdiropres res; + int idx; + uid_t uid = (uid_t) INVALIDID; + gid_t gid = (gid_t) INVALIDID; + + if (!started) { + started++; + rootfattr.na_ctime = startup; + rootfattr.na_mtime = startup; + slinkfattr.na_ctime = startup; + slinkfattr.na_mtime = startup; + un_fattr.na_ctime = startup; + un_fattr.na_mtime = startup; + } + + if (eq_fh(&argp->da_fhandle, &slink)) { + res.dr_status = NFSERR_NOTDIR; + return &res; + } + + if (eq_fh(&argp->da_fhandle, &root)) { + if (argp->da_name[0] == '.' && + (argp->da_name[1] == '\0' || + (argp->da_name[1] == '.' && + argp->da_name[2] == '\0'))) { + res.dr_u.dr_drok_u.drok_fhandle = root; + res.dr_u.dr_drok_u.drok_attributes = rootfattr; + res.dr_status = NFS_OK; + return &res; + } + + if (STREQ(argp->da_name, slinkname)) { + res.dr_u.dr_drok_u.drok_fhandle = slink; + res.dr_u.dr_drok_u.drok_attributes = slinkfattr; + res.dr_status = NFS_OK; + return &res; + } + + if (getcreds(rqstp, &uid, &gid) < 0 || gid != hlfs_gid) { + res.dr_status = NFSERR_NOENT; + return &res; + } + + /* if get's here, gid == hlfs_gid */ + if ((idx = untab_index(argp->da_name)) < 0) { + res.dr_status = NFSERR_NOENT; + return &res; + } else { /* entry found and gid is permitted */ + un_fattr.na_fileid = untab[idx].uid; + res.dr_u.dr_drok_u.drok_attributes = un_fattr; + memset((char *) &un_fhandle, 0, sizeof(am_nfs_fh)); + *(u_int *) un_fhandle.fh_data = (u_int) untab[idx].uid; + strncpy((char *) &un_fhandle.fh_data[sizeof(int)], + untab[idx].username, + sizeof(am_nfs_fh) - sizeof(int)); + res.dr_u.dr_drok_u.drok_fhandle = un_fhandle; + res.dr_status = NFS_OK; +#ifdef DEBUG + dlog("nfs_lookup: succesful lookup for uid=%d, gid=%d: username=%s", + uid, gid, untab[idx].username); +#endif /* DEBUG */ + return &res; + } + } /* end of "if (eq_fh(argp->dir.data, root.data)) {" */ + + res.dr_status = NFSERR_STALE; + return &res; +} + +static int +getcreds(struct svc_req *rp, uid_t *u, gid_t *g) +{ + struct authunix_parms *aup = (struct authunix_parms *) NULL; +#ifdef HAVE_RPC_AUTH_DES_H + struct authdes_cred *adp; +#endif /* HAVE_RPC_AUTH_DES_H */ + + switch (rp->rq_cred.oa_flavor) { + + case AUTH_UNIX: + aup = (struct authunix_parms *) rp->rq_clntcred; + *u = aup->aup_uid; + *g = aup->aup_gid; + break; + +#ifdef HAVE_RPC_AUTH_DES_H + case AUTH_DES: + adp = (struct authdes_cred *) rp->rq_clntcred; + *g = INVALIDID; /* some unknown group id */ + if (sscanf(adp->adc_fullname.name, "unix.%lu@", u) == 1) + break; + /* fall through */ +#endif /* HAVE_RPC_AUTH_DES_H */ + + default: + *u = *g = INVALIDID; /* just in case */ + svcerr_weakauth(nfsxprt); + return -1; + } + + return 0; /* everything is ok */ +} + + +nfsreadlinkres * +nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) +{ + static nfsreadlinkres res; + uid_t userid = (uid_t) INVALIDID; + gid_t groupid = hlfs_gid + 1; /* anything not hlfs_gid */ + int retval = 0; + char *path_val = (char *) NULL; + char *username; + static uid_t last_uid = (uid_t) INVALIDID; + + if (eq_fh(argp, &root)) { + res.rlr_status = NFSERR_ISDIR; + } else if (eq_fh(argp, &slink)) { + if (getcreds(rqstp, &userid, &groupid) < 0) + return (nfsreadlinkres *) NULL; + + gettimeofday((struct timeval *) &slinkfattr.na_atime, (struct timezone *) 0); + + res.rlr_status = NFS_OK; + if (groupid == hlfs_gid) { + res.rlr_u.rlr_data_u = DOTSTRING; + } else if (!(res.rlr_u.rlr_data_u = path_val = homedir(userid))) { + /* + * parent process (fork in homedir()) continues + * processing, by getting a NULL returned as a + * "special". Child returns result. + */ + return (nfsreadlinkres *) NULL; + } + + } else { /* check if asked for user mailbox */ + + if (getcreds(rqstp, &userid, &groupid) < 0) { + return (nfsreadlinkres *) NULL; + } + + if (groupid == hlfs_gid) { + memset((char *) &userid, 0, sizeof(int)); + userid = *(u_int *) argp->fh_data; + username = (char *) &argp->fh_data[sizeof(int)]; + if (!(res.rlr_u.rlr_data_u = mailbox(userid, username))) + return (nfsreadlinkres *) NULL; + } else { + res.rlr_status = NFSERR_STALE; + } + } + + /* print info, but try to avoid repetitions */ + if (userid != last_uid) { + plog(XLOG_USER, "mailbox for uid=%d, gid=%d is %s", + userid, groupid, (char *) res.rlr_u.rlr_data_u); + last_uid = userid; + } + + /* I don't think will pass this if -D nofork */ + if (serverpid == getpid()) + return &res; + + if (!svc_sendreply(nfsxprt, (XDRPROC_T_TYPE) xdr_readlinkres, (SVC_IN_ARG_TYPE) &res)) + svcerr_systemerr(nfsxprt); + + /* + * Child exists here. We need to determine which + * exist status to return. The exit status + * is gathered using wait() and determines + * if we returned $HOME/.hlfsspool or $ALTDIR. The parent + * needs this info so it can update the lookup table. + */ + if (path_val && alt_spooldir && STREQ(path_val, alt_spooldir)) + retval = 1; /* could not get real home dir (or uid 0 user) */ + else + retval = 0; + +#ifdef DEBUG + /* + * If asked for -D nofork, then must return the value, + * NOT exit, or else the main hlfsd server exits. + * Bug where is that status information being collected? + */ + amuDebugNo(D_FORK) + return &res; +#endif /* DEBUG */ + + exit(retval); +} + + +nfsreadres * +nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp) +{ + static nfsreadres res = {NFSERR_ACCES}; + + return &res; +} + + +voidp +nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp) +{ + static char res; + + return (voidp) &res; +} + + +nfsattrstat * +nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp) +{ + static nfsattrstat res = {NFSERR_ROFS}; + + return &res; +} + + +nfsdiropres * +nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp) +{ + static nfsdiropres res = {NFSERR_ROFS}; + + return &res; +} + + +nfsstat * +nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) +{ + static nfsstat res = {NFSERR_ROFS}; + + return &res; +} + + +nfsstat * +nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp) +{ + static nfsstat res = {NFSERR_ROFS}; + + return &res; +} + + +nfsstat * +nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp) +{ + static nfsstat res = {NFSERR_ROFS}; + + return &res; +} + + +nfsstat * +nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp) +{ + static nfsstat res = {NFSERR_ROFS}; + + return &res; +} + + +nfsdiropres * +nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp) +{ + static nfsdiropres res = {NFSERR_ROFS}; + + return &res; +} + + +nfsstat * +nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) +{ + static nfsstat res = {NFSERR_ROFS}; + + return &res; +} + + +nfsreaddirres * +nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp) +{ + static nfsreaddirres res; + static nfsentry slinkent = {SLINKID, 0, {SLINKCOOKIE}}; + static nfsentry dotdotent = {ROOTID, "..", {DOTDOTCOOKIE}, &slinkent}; + static nfsentry dotent = {ROOTID, ".", {DOTCOOKIE}, &dotdotent}; + + slinkent.ne_name = slinkname; + + if (eq_fh(&argp->rda_fhandle, &slink)) { + res.rdr_status = NFSERR_NOTDIR; + } else if (eq_fh(&argp->rda_fhandle, &root)) { + gettimeofday((struct timeval *) &rootfattr.na_atime, (struct timezone *) 0); + + res.rdr_status = NFS_OK; + switch (argp->rda_cookie[0]) { + case 0: + res.rdr_u.rdr_reply_u.dl_entries = &dotent; + break; + case DOTCOOKIE: + res.rdr_u.rdr_reply_u.dl_entries = &dotdotent; + break; + case DOTDOTCOOKIE: + res.rdr_u.rdr_reply_u.dl_entries = &slinkent; + break; + case SLINKCOOKIE: + res.rdr_u.rdr_reply_u.dl_entries = (nfsentry *) 0; + break; + } + res.rdr_u.rdr_reply_u.dl_eof = TRUE; + } else { + res.rdr_status = NFSERR_STALE; + } + return &res; +} + + +nfsstatfsres * +nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) +{ + static nfsstatfsres res = {NFS_OK}; + + res.sfr_u.sfr_reply_u.sfrok_tsize = 1024; + res.sfr_u.sfr_reply_u.sfrok_bsize = 1024; + + /* + * Some "df" programs automatically assume that file systems + * with zero blocks are meta-filesystems served by automounters. + */ + res.sfr_u.sfr_reply_u.sfrok_blocks = 0; + res.sfr_u.sfr_reply_u.sfrok_bfree = 0; + res.sfr_u.sfr_reply_u.sfrok_bavail = 0; + + return &res; +} diff --git a/contrib/amd/include/am_compat.h b/contrib/amd/include/am_compat.h new file mode 100644 index 0000000..ccb3528 --- /dev/null +++ b/contrib/amd/include/am_compat.h @@ -0,0 +1,260 @@ +/* + * am_compat.h: + * + * This file contains compatibility functions and macros, all of which + * should be auto-discovered, but for one reason or another (mostly + * brain-damage on the part of system designers and header files) they cannot. + * + * Each compatibility macro/function must include instructions on how/when + * it can be removed the am-utils code. + * + */ + +#ifndef _AM_COMPAT_H +# define _AM_COMPAT_H + +/* + * incomplete mount options definitions (sunos4, irix6, linux, etc.) + */ + + +/* + * Complete MNTTAB_OPT_* options based on MNT2_NFS_OPT_* mount options. + */ +#if defined(MNT2_NFS_OPT_ACDIRMAX) && !defined(MNTTAB_OPT_ACDIRMAX) +# define MNTTAB_OPT_ACDIRMAX "acdirmax" +#endif /* defined(MNT2_NFS_OPT_ACDIRMAX) && !defined(MNTTAB_OPT_ACDIRMAX) */ + +#if defined(MNT2_NFS_OPT_ACDIRMIN) && !defined(MNTTAB_OPT_ACDIRMIN) +# define MNTTAB_OPT_ACDIRMIN "acdirmin" +#endif /* defined(MNT2_NFS_OPT_ACDIRMIN) && !defined(MNTTAB_OPT_ACDIRMIN) */ + +#if defined(MNT2_NFS_OPT_ACREGMAX) && !defined(MNTTAB_OPT_ACREGMAX) +# define MNTTAB_OPT_ACREGMAX "acregmax" +#endif /* defined(MNT2_NFS_OPT_ACREGMAX) && !defined(MNTTAB_OPT_ACREGMAX) */ + +#if defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNTTAB_OPT_ACREGMIN) +# define MNTTAB_OPT_ACREGMIN "acregmin" +#endif /* defined(MNT2_NFS_OPT_ACREGMIN) && !defined(MNTTAB_OPT_ACREGMIN) */ + +#if !defined(MNTTAB_OPT_IGNORE) +/* SunOS 4.1.x and others define "noauto" option, but not "auto" */ +# if defined(MNTTAB_OPT_NOAUTO) && !defined(MNTTAB_OPT_AUTO) +# define MNTTAB_OPT_AUTO "auto" +# endif /* defined(MNTTAB_OPT_NOAUTO) && !defined(MNTTAB_OPT_AUTO) */ +#endif /* !defined(MNTTAB_OPT_IGNORE) */ + +#if defined(MNT2_NFS_OPT_NOAC) && !defined(MNTTAB_OPT_NOAC) +# define MNTTAB_OPT_NOAC "noac" +#endif /* defined(MNT2_NFS_OPT_NOAC) && !defined(MNTTAB_OPT_NOAC) */ + +#if defined(MNT2_NFS_OPT_NOCONN) && !defined(MNTTAB_OPT_NOCONN) +# define MNTTAB_OPT_NOCONN "noconn" +# ifndef MNTTAB_OPT_CONN +# define MNTTAB_OPT_CONN "conn" +# endif /* MNTTAB_OPT_CONN */ +#endif /* defined(MNT2_NFS_OPT_NOCONN) && !defined(MNTTAB_OPT_NOCONN) */ + +#if defined(MNT2_NFS_OPT_PGTHRESH) && !defined(MNTTAB_OPT_PGTHRESH) +# define MNTTAB_OPT_PGTHRESH "pgthresh" +#endif /* defined(MNT2_NFS_OPT_PGTHRESH) && !defined(MNTTAB_OPT_PGTHRESH) */ + +#if defined(MNT2_NFS_OPT_RETRANS) && !defined(MNTTAB_OPT_RETRANS) +# define MNTTAB_OPT_RETRANS "retrans" +#endif /* defined(MNT2_NFS_OPT_RETRANS) && !defined(MNTTAB_OPT_RETRANS) */ + +#if defined(MNT2_NFS_OPT_RSIZE) && !defined(MNTTAB_OPT_RSIZE) +# define MNTTAB_OPT_RSIZE "rsize" +#endif /* defined(MNT2_NFS_OPT_RSIZE) && !defined(MNTTAB_OPT_RSIZE) */ + +#if defined(MNT2_NFS_OPT_SOFT) && !defined(MNTTAB_OPT_SOFT) +# define MNTTAB_OPT_SOFT "soft" +# ifndef MNTTAB_OPT_HARD +# define MNTTAB_OPT_HARD "hard" +# endif /* not MNTTAB_OPT_HARD */ +#endif /* defined(MNT2_NFS_OPT_SOFT) && !defined(MNTTAB_OPT_SOFT) */ + +#if defined(MNT2_NFS_OPT_TIMEO) && !defined(MNTTAB_OPT_TIMEO) +# define MNTTAB_OPT_TIMEO "timeo" +#endif /* defined(MNT2_NFS_OPT_TIMEO) && !defined(MNTTAB_OPT_TIMEO) */ + +#if defined(MNT2_NFS_OPT_WSIZE) && !defined(MNTTAB_OPT_WSIZE) +# define MNTTAB_OPT_WSIZE "wsize" +#endif /* defined(MNT2_NFS_OPT_WSIZE) && !defined(MNTTAB_OPT_WSIZE) */ + +#if defined(MNT2_NFS_OPT_MAXGRPS) && !defined(MNTTAB_OPT_MAXGROUPS) +# define MNTTAB_OPT_MAXGROUPS "maxgroups" +#endif /* defined(MNT2_NFS_OPT_MAXGRPS) && !defined(MNTTAB_OPT_MAXGROUPS) */ + +/* + * Complete MNTTAB_OPT_* options based on MNT2_CDFS_OPT_* mount options. + */ +#if defined(MNT2_CDFS_OPT_DEFPERM) && !defined(MNTTAB_OPT_DEFPERM) +# define MNTTAB_OPT_DEFPERM "defperm" +#endif /* defined(MNT2_CDFS_OPT_DEFPERM) && !defined(MNTTAB_OPT_DEFPERM) */ + +#if defined(MNT2_CDFS_OPT_NODEFPERM) && !defined(MNTTAB_OPT_NODEFPERM) +# define MNTTAB_OPT_NODEFPERM "nodefperm" +/* + * DEC OSF/1 V3.x/Digital UNIX V4.0 have M_NODEFPERM only, but + * both mnttab ops. + */ +# ifndef MNTTAB_OPT_DEFPERM +# define MNTTAB_OPT_DEFPERM "defperm" +# endif /* not MNTTAB_OPT_DEFPERM */ +#endif /* defined(MNT2_CDFS_OPT_NODEFPERM) && !defined(MNTTAB_OPT_NODEFPERM) */ + +#if defined(MNT2_CDFS_OPT_NOVERSION) && !defined(MNTTAB_OPT_NOVERSION) +# define MNTTAB_OPT_NOVERSION "noversion" +#endif /* defined(MNT2_CDFS_OPT_NOVERSION) && !defined(MNTTAB_OPT_NOVERSION) */ + +#if defined(MNT2_CDFS_OPT_RRIP) && !defined(MNTTAB_OPT_RRIP) +# define MNTTAB_OPT_RRIP "rrip" +#endif /* defined(MNT2_CDFS_OPT_RRIP) && !defined(MNTTAB_OPT_RRIP) */ + +/* + * Complete MNTTAB_OPT_* options based on MNT2_GEN_OPT_* mount options. + */ +#if defined(MNT2_GEN_OPT_GRPID) && !defined(MNTTAB_OPT_GRPID) +# define MNTTAB_OPT_GRPID "grpid" +#endif /* defined(MNT2_GEN_OPT_GRPID) && !defined(MNTTAB_OPT_GRPID) */ + +#if defined(MNT2_GEN_OPT_NOCACHE) && !defined(MNTTAB_OPT_NOCACHE) +# define MNTTAB_OPT_NOCACHE "nocache" +#endif /* defined(MNT2_GEN_OPT_NOCACHE) && !defined(MNTTAB_OPT_NOCACHE) */ + +#if defined(MNT2_GEN_OPT_NOSUID) && !defined(MNTTAB_OPT_NOSUID) +# define MNTTAB_OPT_NOSUID "nosuid" +#endif /* defined(MNT2_GEN_OPT_NOSUID) && !defined(MNTTAB_OPT_NOSUID) */ + +#if defined(MNT2_GEN_OPT_OVERLAY) && !defined(MNTTAB_OPT_OVERLAY) +# define MNTTAB_OPT_OVERLAY "overlay" +#endif /* defined(MNT2_GEN_OPT_OVERLAY) && !defined(MNTTAB_OPT_OVERLAY) */ + +/* + * Complete MNTTAB_OPT_* options and their inverse based on MNT2_GEN_OPT_* + * options. + */ +#if defined(MNT2_GEN_OPT_NODEV) && !defined(MNTTAB_OPT_NODEV) +# define MNTTAB_OPT_NODEV "nodev" +/* this is missing under some versions of Linux */ +# ifndef MNTTAB_OPT_DEV +# define MNTTAB_OPT_DEV "dev" +# endif /* not MNTTAB_OPT_DEV */ +#endif /* defined(MNT2_GEN_OPT_NODEV) && !defined(MNTTAB_OPT_NODEV) */ + +#if defined(MNT2_GEN_OPT_NOEXEC) && !defined(MNTTAB_OPT_NOEXEC) +# define MNTTAB_OPT_NOEXEC "noexec" +/* this is missing under some versions of Linux */ +# ifndef MNTTAB_OPT_EXEC +# define MNTTAB_OPT_EXEC "exec" +# endif /* not MNTTAB_OPT_EXEC */ +#endif /* defined(MNT2_GEN_OPT_NOEXEC) && !defined(MNTTAB_OPT_NOEXEC) */ + +#if defined(MNT2_GEN_OPT_QUOTA) && !defined(MNTTAB_OPT_QUOTA) +# define MNTTAB_OPT_QUOTA "quota" +#endif /* defined(MNT2_GEN_OPT_QUOTA) && !defined(MNTTAB_OPT_QUOTA) */ + +#if defined(MNT2_GEN_OPT_SYNC) && !defined(MNTTAB_OPT_SYNC) +# define MNTTAB_OPT_SYNC "sync" +#endif /* defined(MNT2_GEN_OPT_SYNC) && !defined(MNTTAB_OPT_SYNC) */ + + +/* + * Add missing MNTTAB_OPT_* options. + */ +#ifndef MNTTAB_OPT_ACTIMEO +# define MNTTAB_OPT_ACTIMEO "actimeo" +#endif /* not MNTTAB_OPT_ACTIMEO */ + +#ifndef MNTTAB_OPT_INTR +# define MNTTAB_OPT_INTR "intr" +#endif /* not MNTTAB_OPT_INTR */ + +#ifndef MNTTAB_OPT_PORT +# define MNTTAB_OPT_PORT "port" +#endif /* not MNTTAB_OPT_PORT */ + +#ifndef MNTTAB_OPT_RETRANS +# define MNTTAB_OPT_RETRANS "retrans" +#endif /* not MNTTAB_OPT_RETRANS */ + +#ifndef MNTTAB_OPT_RETRY +# define MNTTAB_OPT_RETRY "retry" +#endif /* not MNTTAB_OPT_RETRY */ + +#ifndef MNTTAB_OPT_RO +# define MNTTAB_OPT_RO "ro" +#endif /* not MNTTAB_OPT_RO */ + +#ifndef MNTTAB_OPT_RSIZE +# define MNTTAB_OPT_RSIZE "rsize" +#endif /* not MNTTAB_OPT_RSIZE */ + +#ifndef MNTTAB_OPT_RW +# define MNTTAB_OPT_RW "rw" +#endif /* not MNTTAB_OPT_RW */ + +#ifndef MNTTAB_OPT_TIMEO +# define MNTTAB_OPT_TIMEO "timeo" +#endif /* not MNTTAB_OPT_TIMEO */ + +#ifndef MNTTAB_OPT_WSIZE +# define MNTTAB_OPT_WSIZE "wsize" +#endif /* not MNTTAB_OPT_WSIZE */ + + +/* + * Incomplete filesystem definitions (sunos4, irix6, solaris2) + */ +#if defined(HAVE_FS_CDFS) && defined(MOUNT_TYPE_CDFS) && !defined(MNTTYPE_CDFS) +# define MNTTYPE_CDFS "hsfs" +#endif /* defined(HAVE_FS_CDFS) && defined(MOUNT_TYPE_CDFS) && !defined(MNTTYPE_CDFS) */ + +#ifndef cdfs_args_t +/* + * Solaris has an HSFS filesystem, but does not define hsfs_args. + * XXX: the definition here for solaris is wrong, since under solaris, + * hsfs_args should be a single integer used as a bit-field for options. + * so this code has to be fixed later. -Erez. + */ +struct hsfs_args { + char *fspec; /* name of filesystem to mount */ + int norrip; +}; +# define cdfs_args_t struct hsfs_args +# define HAVE_FIELD_CDFS_ARGS_T_NORRIP +#endif /* not cdfs_args_t */ + +/* + * if does not define struct pc_args, assume integer bit-field (irix6) + */ +#if defined(HAVE_FS_PCFS) && !defined(pcfs_args_t) +# define pcfs_args_t u_int +#endif /* defined(HAVE_FS_PCFS) && !defined(pcfs_args_t) */ + +/* + * if does not define struct ufs_args, assume integer bit-field (linux) + */ +#if defined(HAVE_FS_UFS) && !defined(ufs_args_t) +# define ufs_args_t u_int +#endif /* defined(HAVE_FS_UFS) && !defined(ufs_args_t) */ + +#if defined(HAVE_FS_AUTOFS) && defined(MOUNT_TYPE_AUTOFS) && !defined(MNTTYPE_AUTOFS) +# define MNTTYPE_AUTOFS "autofs" +#endif /* defined(HAVE_FS_AUTOFS) && defined(MOUNT_TYPE_AUTOFS) && !defined(MNTTYPE_AUTOFS) */ + +/* + * If NFS3, then make sure that "proto" and "vers" mnttab options + * are available. + */ +#ifdef HAVE_FS_NFS3 +# ifndef MNTTAB_OPT_VERS +# define MNTTAB_OPT_VERS "vers" +# endif /* not MNTTAB_OPT_VERS */ +# ifndef MNTTAB_OPT_PROTO +# define MNTTAB_OPT_PROTO "proto" +# endif /* not MNTTAB_OPT_PROTO */ +#endif /* not HAVE_FS_NFS3 */ + +#endif /* not _AM_COMPAT_H */ diff --git a/contrib/amd/include/am_defs.h b/contrib/amd/include/am_defs.h new file mode 100644 index 0000000..690d033 --- /dev/null +++ b/contrib/amd/include/am_defs.h @@ -0,0 +1,1320 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: am_defs.h,v 1.1 1996/01/13 23:23:39 ezk Exp ezk $ + * + */ + +/* + * Definitions that are not specific to the am-utils package, but + * are rather generic, and can be used elsewhere. + */ + +#ifndef _AM_DEFS_H +#define _AM_DEFS_H + +/* + * Actions to take if ANSI C. + */ +#if STDC_HEADERS +# include +/* for function prototypes */ +# define P(x) x +# define P_void void +#else /* not STDC_HEADERS */ +/* empty function prototypes */ +# define P(x) () +# define P_void +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif /* not HAVE_STRCHR */ +char *strchr(), *strrchr(), *strdup(); +#endif /* not STDC_HEADERS */ + +/* + * How to handle signals of any type + */ +#ifdef HAVE_SYS_WAIT_H +# include +#endif /* HAVE_SYS_WAIT_H */ +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif /* not WEXITSTATUS */ +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif /* not WIFEXITED */ + +/* + * Actions to take regarding and . + */ +#if TIME_WITH_SYS_TIME +# include +# include +#else /* not TIME_WITH_SYS_TIME */ +# if HAVE_SYS_TIME_H +# include +# else /* not HAVE_SYS_TIME_H */ +# include +# endif /* not HAVE_SYS_TIME_H */ +#endif /* not TIME_WITH_SYS_TIME */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_MACHINE_ENDIAN_H +# include +#endif /* HAVE_MACHINE_ENDIAN_H */ + +/* + * Big-endian or little-endian? + */ +#ifdef WORDS_BIGENDIAN +# define ARCH_ENDIAN "big" +#else /* not WORDS_BIGENDIAN */ +# define ARCH_ENDIAN "little" +#endif /* not WORDS_BIGENDIAN */ + +/* + * Actions to take if HAVE_SYS_TYPES_H is defined. + */ +#if HAVE_SYS_TYPES_H +# include +#endif /* HAVE_SYS_TYPES_H */ + +/* + * Actions to take if HAVE_UNISTD_H is defined. + */ +#if HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ + +/* after , check if this is a POSIX.1 system */ +#ifdef _POSIX_VERSION +/* Code for POSIX.1 systems. */ +#endif /* _POSIX_VERSION */ + +/* + * Variable length argument lists. + * Must use only one of the two! + */ +#ifdef HAVE_STDARG_H +# include +/* + * On Solaris 2.6, is included in + * So this ensures that only one is included. + */ +# ifndef _SYS_VARARGS_H +# define _SYS_VARARGS_H +# endif /* not _SYS_VARARGS_H */ +#else /* not HAVE_STDARG_H */ +# ifdef HAVE_VARARGS_H +# include +# endif /* HAVE_VARARGS_H */ +#endif /* not HAVE_STDARG_H */ + +/* + * Pick the right header file and macros for directory processing functions. + */ +#if HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else /* not HAVE_DIRENT_H */ +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif /* HAVE_SYS_NDIR_H */ +# if HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ +# if HAVE_NDIR_H +# include +# endif /* HAVE_NDIR_H */ +#endif /* not HAVE_DIRENT_H */ + +/* + * Actions to take if HAVE_FCNTL_H is defined. + */ +#if HAVE_FCNTL_H +# include +#endif /* HAVE_FCNTL_H */ + +/* + * Actions to take if HAVE_MEMORY_H is defined. + */ +#if HAVE_MEMORY_H +# include +#endif /* HAVE_MEMORY_H */ + +/* + * Actions to take if HAVE_SYS_FILE_H is defined. + */ +#if HAVE_SYS_FILE_H +# include +#endif /* HAVE_SYS_FILE_H */ + +/* + * Actions to take if HAVE_SYS_IOCTL_H is defined. + */ +#if HAVE_SYS_IOCTL_H +# include +#endif /* HAVE_SYS_IOCTL_H */ + +/* + * Actions to take if HAVE_SYSLOG_H or HAVE_SYS_SYSLOG_H is defined. + */ +#ifdef HAVE_SYSLOG_H +# include +#else /* not HAVE_SYSLOG_H */ +# if HAVE_SYS_SYSLOG_H +# include +# endif /* HAVE_SYS_SYSLOG_H */ +#endif /* HAVE_SYSLOG_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_PARAM_H +# include +#endif /* HAVE_SYS_PARAM_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_SOCKET_H +# include +#endif /* HAVE_SYS_SOCKET_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_RPC_RPC_H +/* + * Turn on PORTMAP, so that additional header files would get included + * and the important definition for UDPMSGSIZE is included too. + */ +# ifndef PORTMAP +# define PORTMAP +# endif /* not PORTMAP */ +# include +# ifndef XDRPROC_T_TYPE +typedef bool_t (*xdrproc_t) __P ((XDR *, __ptr_t, ...)); +# endif /* not XDRPROC_T_TYPE */ +#endif /* HAVE_RPC_RPC_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_RPC_TYPES_H +# include +#endif /* HAVE_RPC_TYPES_H */ + +/* + * Actions to take if exists. + */ +/* Prevent multiple inclusion on Ultrix 4 */ +#if defined(HAVE_RPC_XDR_H) && !defined(__XDR_HEADER__) +# include +#endif /* defined(HAVE_RPC_XDR_H) && !defined(__XDR_HEADER__) */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_MALLOC_H +# include +#endif /* HAVE_MALLOC_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_MNTENT_H +/* some systems need before is included */ +# ifdef HAVE_STDIO_H +# include +# endif /* HAVE_STDIO_H */ +# include +#endif /* HAVE_MNTENT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_ERRNO_H +# include +extern int errno; +#endif /* HAVE_SYS_ERRNO_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FSID_H +# include +#endif /* HAVE_SYS_FSID_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_UTSNAME_H +# include +#endif /* HAVE_SYS_UTSNAME_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_MNTENT_H +# include +#endif /* HAVE_SYS_MNTENT_H */ + +/* + * Actions to take if exists. + * Should be included before because on some systems + * like Linux, it also defines "struct datum". + */ +#ifdef HAVE_NDBM_H +# include +# ifndef DATUM +/* ensure that struct datum is not included again from */ +# define DATUM +# endif /* not DATUM */ +#endif /* HAVE_NDBM_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NET_ERRNO_H +# include +#endif /* HAVE_NET_ERRNO_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NET_ROUTE_H +# include +#endif /* HAVE_NET_ROUTE_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_MBUF_H +# include +/* + * OSF4 (DU-4.0) defines m_next and m_data also in so I must + # undefine them here to avoid conflicts. + */ +# ifdef m_next +# undef m_next +# endif /* m_next */ +# ifdef m_data +# undef m_data +# endif /* m_data */ +/* + * AIX 3 defines MFREE and m_flags also in . + */ +# ifdef m_flags +# undef m_flags +# endif /* m_flags */ +# ifdef MFREE +# undef MFREE +# endif /* MFREE */ +#endif /* HAVE_SYS_MBUF_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NET_IF_H +# include +#endif /* HAVE_NET_IF_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NETDB_H +# include +#endif /* HAVE_NETDB_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NETDIR_H +# include +#endif /* HAVE_NETDIR_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NET_IF_VAR_H +# include +#endif /* HAVE_NET_IF_VAR_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NETINET_IF_ETHER_H +# include +#endif /* HAVE_NETINET_IF_ETHER_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NETINET_IN_H +# include +#endif /* HAVE_NETINET_IN_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_RPCSVC_YP_PROT_H +# include +#endif /* HAVE_RPCSVC_YP_PROT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_RPCSVC_YPCLNT_H +# include +#endif /* HAVE_RPCSVC_YPCLNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_UCRED_H +# include +#endif /* HAVE_SYS_UCRED_H */ + + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_MOUNT_H +/* + * Some operating systems must define these variables to get + * NFS and other definitions included. + */ +# ifndef NFSCLIENT +# define NFSCLIENT +# endif /* not NFSCLIENT */ +# ifndef NFS +# define NFS +# endif /* not NFS */ +# ifndef PCFS +# define PCFS +# endif /* not PCFS */ +# ifndef LOFS +# define LOFS +# endif /* not LOFS */ +# ifndef RFS +# define RFS +# endif /* not RFS */ +# ifndef MSDOSFS +# define MSDOSFS +# endif /* not MSDOSFS */ +# ifndef MFS +# define MFS +# endif /* not MFS */ +# ifndef CD9660 +# define CD9660 +# endif /* not CD9660 */ +# ifndef NFS +# define NFS +# endif /* not NFS */ +# include +#endif /* HAVE_SYS_MOUNT_H */ + +#ifdef HAVE_SYS_VMOUNT_H +# include +#endif /* HAVE_SYS_VMOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_LINUX_FS_H +/* + * There's a conflict of definitions on redhat alpha linux between + * and . + */ +# ifdef HAVE_SOCKETBITS_H +/* conflicts with */ +# define _LINUX_SOCKET_H +# undef BLKFLSBUF +# undef BLKGETSIZE +# undef BLKRAGET +# undef BLKRASET +# undef BLKROGET +# undef BLKROSET +# undef BLKRRPART +# undef MS_MGC_VAL +# undef MS_RMT_MASK +/* conflicts with */ +# undef WNOHANG +# undef WUNTRACED +/* conflicts with */ +# define _SYS_STATFS_H +# endif /* HAVE_SOCKETBITS_H */ +# include +#endif /* HAVE_LINUX_FS_H */ + +#ifdef HAVE_CDFS_CDFS_MOUNT_H +# include +#endif /* HAVE_CDFS_CDFS_MOUNT_H */ + +#ifdef HAVE_CDFS_CDFSMOUNT_H +# include +#endif /* HAVE_CDFS_CDFSMOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_LINUX_AUTO_FS_H +# include +#endif /* HAVE_LINUX_AUTO_FS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FS_AUTOFS_H +# include +#endif /* HAVE_SYS_FS_AUTOFS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FS_AUTOFS_PROT_H +# include +#endif /* HAVE_SYS_FS_AUTOFS_PROT_H */ + +/* + * NFS PROTOCOL HEADER FILES: + */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NFS_EXPORT_H +# include +#endif /* HAVE_NFS_EXPORT_H */ + +/**************************************************************************** + ** IMPORTANT!!! ** + ** We always include am-util's amu_nfs_prot.h. ** + ** That is actually defined in "conf/nfs_prot/nfs_prot_${host_os_name}.h" ** + ****************************************************************************/ +#include + +/* + * DO NOT INCLUDE THESE FILES: + * They conflicts with other NFS headers and are generally not needed. + */ +#ifdef DO_NOT_INCLUDE +# ifdef HAVE_NFS_NFS_CLNT_H +# include +# endif /* HAVE_NFS_NFS_CLNT_H */ +# ifdef HAVE_LINUX_NFS_H +# include +# endif /* HAVE_LINUX_NFS_H */ +#endif /* DO NOT INCLUDE */ + +/* + * Actions to take if one of the nfs headers exists. + */ +#ifdef HAVE_NFS_NFS_GFS_H +# include +#endif /* HAVE_NFS_NFS_GFS_H */ +#ifdef HAVE_NFS_MOUNT_H +# include +#endif /* HAVE_NFS_MOUNT_H */ +#ifdef HAVE_NFS_NFS_MOUNT_H_off +/* broken on netxtep3 (includes non-existing headers) */ +# include +#endif /* HAVE_NFS_NFS_MOUNT_H */ +#ifdef HAVE_NFS_PATHCONF_H +# include +#endif /* HAVE_NFS_PATHCONF_H */ +#ifdef HAVE_SYS_FS_NFS_MOUNT_H +# include +#endif /* HAVE_SYS_FS_NFS_MOUNT_H */ +#ifdef HAVE_SYS_FS_NFS_NFS_CLNT_H +# include +#endif /* HAVE_SYS_FS_NFS_NFS_CLNT_H */ +#ifdef HAVE_SYS_FS_NFS_CLNT_H +# include +#endif /* HAVE_SYS_FS_NFS_CLNT_H */ +#ifdef HAVE_LINUX_NFS_MOUNT_H +# include +#endif /* HAVE_LINUX_NFS_MOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_PWD_H +# include +#endif /* HAVE_PWD_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_HESIOD_H +# include +#endif /* HAVE_HESIOD_H */ + +/* + * Actions to take if exists. + * This header file is required before can be included. + */ +#ifdef HAVE_LBER_H +# include +#endif /* HAVE_LBER_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_LDAP_H +# include +#endif /* HAVE_LDAP_H */ + +/* + * Actions to take if exists. + * Should be included before . + */ +#ifdef HAVE_ARPA_NAMESER_H +# ifdef NOERROR +# undef NOERROR +# endif /* NOERROR */ +/* + * Conflicts with which is included from + * on Solaris 2.6 systems. So undefine it first. + */ +# ifdef T_UNSPEC +# undef T_UNSPEC +# endif /* T_UNSPEC */ +# include +#endif /* HAVE_ARPA_NAMESER_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_ARPA_INET_H +# include +#endif /* HAVE_ARPA_INET_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_RESOLV_H +# include +#endif /* HAVE_RESOLV_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_UIO_H +# include +#endif /* HAVE_SYS_UIO_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FS_CACHEFS_FS_H +# include +#endif /* HAVE_SYS_FS_CACHEFS_FS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FS_PC_FS_H +# include +#endif /* HAVE_SYS_FS_PC_FS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_MSDOSFS_MSDOSFSMOUNT_H +# include +#endif /* HAVE_MSDOSFS_MSDOSFSMOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FS_TMP_H +# include +#endif /* HAVE_SYS_FS_TMP_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FS_UFS_MOUNT_H +# include +#endif /* HAVE_SYS_FS_UFS_MOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FS_EFS_CLNT_H +# include +#endif /* HAVE_SYS_FS_EFS_CLNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FS_XFS_CLNT_H +# include +#endif /* HAVE_SYS_FS_XFS_CLNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_ASSERT_H +# include +#endif /* HAVE_ASSERT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_CFS_H +# include +#endif /* HAVE_CFS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_CLUSTER_H +# include +#endif /* HAVE_CLUSTER_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_CTYPE_H +# include +#endif /* HAVE_CTYPE_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_ERRNO_H +# include +#endif /* HAVE_ERRNO_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_GRP_H +# include +#endif /* HAVE_GRP_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_HSFS_HSFS_H +# include +#endif /* HAVE_HSFS_HSFS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_CDFS_CDFSMOUNT_H +# include +#endif /* HAVE_CDFS_CDFSMOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_ISOFS_CD9660_CD9660_MOUNT_H +# include +#endif /* HAVE_ISOFS_CD9660_CD9660_MOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_MOUNT_H +# include +#endif /* HAVE_MOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NSSWITCH_H +# include +#endif /* HAVE_NSSWITCH_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_RPC_AUTH_DES_H +# include +#endif /* HAVE_RPC_AUTH_DES_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_RPC_PMAP_CLNT_H +# include +#endif /* HAVE_RPC_PMAP_CLNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_RPC_PMAP_PROT_H +# include +#endif /* HAVE_RPC_PMAP_PROT_H */ + + +/* + * Actions to take if exists. + * AIX does not protect against this file doubly included, + * so I have to do my own protection here. + */ +#ifdef HAVE_RPCSVC_MOUNT_H +# ifndef _RPCSVC_MOUNT_H +# include +# endif /* not _RPCSVC_MOUNT_H */ +#endif /* HAVE_RPCSVC_MOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_RPCSVC_NIS_H +# include +#endif /* HAVE_RPCSVC_NIS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SETJMP_H +# include +#endif /* HAVE_SETJMP_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SIGNAL_H +# include +#endif /* HAVE_SIGNAL_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_CONFIG_H +# include +#endif /* HAVE_SYS_CONFIG_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_DG_MOUNT_H +# include +#endif /* HAVE_SYS_DG_MOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FS_TYPES_H +/* + * Define KERNEL here to avoid multiple definitions of gt_names[] on + * Ultrix 4.3. + */ +# define KERNEL +# include +# undef KERNEL +#endif /* HAVE_SYS_FS_TYPES_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_FSTYP_H +# include +#endif /* HAVE_SYS_FSTYP_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_LOCK_H +# include +#endif /* HAVE_SYS_LOCK_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_MACHINE_H +# include +#endif /* HAVE_SYS_MACHINE_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_MNTCTL_H +# include +#endif /* HAVE_SYS_MNTCTL_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_MNTTAB_H +# include +#endif /* HAVE_SYS_MNTTAB_H */ + +/* + * Actions to take if exists. + * Do not include it if MNTTAB is already defined because it probably + * came from and we do not want conflicting definitions. + */ +#if defined(HAVE_MNTTAB_H) && !defined(MNTTAB) +# include +#endif /* defined(HAVE_MNTTAB_H) && !defined(MNTTAB) */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_NETCONFIG_H +# include +/* Some systems (Solaris 2.5.1) don't declare this external */ +extern char *nc_sperror(void); +#endif /* HAVE_NETCONFIG_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_NETCONFIG_H +# include +#endif /* HAVE_SYS_NETCONFIG_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_PATHCONF_H +# include +#endif /* HAVE_SYS_PATHCONF_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_RESOURCE_H +# include +#endif /* HAVE_SYS_RESOURCE_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_SEMA_H +# include +#endif /* HAVE_SYS_SEMA_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif /* HAVE_SYS_SIGNAL_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_SOCKIO_H +# include +#endif /* HAVE_SYS_SOCKIO_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_SYSCALL_H +# include +#endif /* HAVE_SYS_SYSCALL_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_SYSLIMITS_H +# include +#endif /* HAVE_SYS_SYSLIMITS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_TIUSER_H +/* + * Some systems like AIX have multiple definitions for T_NULL and othersd + * that are defined first in . + */ +# ifdef HAVE_ARPA_NAMESER_H +# ifdef T_NULL +# undef T_NULL +# endif /* T_NULL */ +# ifdef T_UNSPEC +# undef T_UNSPEC +# endif /* T_UNSPEC */ +# ifdef T_IDLE +# undef T_IDLE +# endif /* T_IDLE */ +# endif /* HAVE_ARPA_NAMESER_H */ +# include +#endif /* HAVE_TIUSER_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_TIUSER_H +# include +#endif /* HAVE_SYS_TIUSER_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_STATFS_H +# include +#endif /* HAVE_SYS_STATFS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_VFS_H +# include +#endif /* HAVE_SYS_VFS_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_SYS_VMOUNT_H +# include +#endif /* HAVE_SYS_VMOUNT_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_UFS_UFS_MOUNT_H +# include +#endif /* HAVE_UFS_UFS_MOUNT_H */ + +/* + * Are S_ISDIR, S_ISREG, et al broken? If not, include . + * Turned off the not using sys/stat.h based on if the macros are + * "broken", because they incorrectly get reported as broken on + * ncr2. + */ +#ifndef STAT_MACROS_BROKEN_notused +/* + * RedHat Linux 4.2 (alpha) has a problem in the headers that causes + * dupicate definitions, and also some other nasty bugs. Upgrade to Redhat + * 5.0! + */ +# ifdef HAVE_SYS_STAT_H +/* avoid duplicates or conflicts with (RedHat alpha linux) */ +# if defined(S_IFREG) && defined(HAVE_STATBUF_H) +# include +# undef S_IFBLK +# undef S_IFCHR +# undef S_IFDIR +# undef S_IFIFO +# undef S_IFLNK +# undef S_IFMT +# undef S_IFREG +# undef S_IFSOCK +# undef S_IRGRP +# undef S_IROTH +# undef S_IRUSR +# undef S_IRWXG +# undef S_IRWXO +# undef S_IRWXU +# undef S_ISBLK +# undef S_ISCHR +# undef S_ISDIR +# undef S_ISFIFO +# undef S_ISGID +# undef S_ISLNK +# undef S_ISREG +# undef S_ISSOCK +# undef S_ISUID +# undef S_ISVTX +# undef S_IWGRP +# undef S_IWOTH +# undef S_IWUSR +# undef S_IXGRP +# undef S_IXOTH +# undef S_IXUSR +# endif /* defined(S_IFREG) && defined(HAVE_STATBUF_H) */ +# include +# endif /* HAVE_SYS_STAT_H */ +#endif /* not STAT_MACROS_BROKEN_notused */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_STDIO_H +# include +#endif /* HAVE_STDIO_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_STDLIB_H +# include +#endif /* HAVE_STDLIB_H */ + +/* + * Actions to take if exists. + */ +#ifdef HAVE_REGEX_H +# include +#endif /* HAVE_REGEX_H */ + + +/****************************************************************************/ +/* + * Specific macros we're looking for. + */ +#ifndef HAVE_MEMSET +# ifdef HAVE_BZERO +# define memset(ptr, val, len) bzero((ptr), (len)) +# else /* not HAVE_BZERO */ +# error Cannot find either memset or bzero! +# endif /* not HAVE_BZERO */ +#endif /* not HAVE_MEMSET */ + +#ifndef HAVE_MEMMOVE +# ifdef HAVE_BCOPY +# define memmove(to, from, len) bcopy((from), (to), (len)) +# else /* not HAVE_BCOPY */ +# error Cannot find either memmove or bcopy! +# endif /* not HAVE_BCOPY */ +#endif /* not HAVE_MEMMOVE */ + +/* + * memcmp() is more problematic: + * Systems that don't have it, but have bcmp(), will use bcmp() instead. + * Those that have it, but it is bad (SunOS 4 doesn't handle + * 8 bit comparisons correctly), will get to use am_memcmp(). + * Otherwise if you have memcmp() and it is good, use it. + */ +#ifdef HAVE_MEMCMP +# ifdef HAVE_BAD_MEMCMP +# define memcmp am_memcmp +extern int am_memcmp(const voidp s1, const voidp s2, size_t len); +# endif /* HAVE_BAD_MEMCMP */ +#else /* not HAVE_MEMCMP */ +# ifdef HAVE_BCMP +# define memcmp(a, b, len) bcmp((a), (b), (len)) +# endif /* HAVE_BCMP */ +#endif /* not HAVE_MEMCMP */ + +#ifndef HAVE_SETEUID +# ifdef HAVE_SETRESUID +# define seteuid(x) setresuid(-1,(x),-1) +# else /* not HAVE_SETRESUID */ +# error Cannot find either seteuid or setresuid! +# endif /* not HAVE_SETRESUID */ +#endif /* not HAVE_SETEUID */ + +/* + * Define type of mntent_t. + * Defaults to struct mntent, else struct mnttab. If neither is found, and + * the operating system does keep not mount tables in the kernel, then flag + * it as an error. If neither is found and the OS keeps mount tables in the + * kernel, then define our own version of mntent; it will be needed for amd + * to keep its own internal version of the mount tables. + */ +#ifdef HAVE_STRUCT_MNTENT +typedef struct mntent mntent_t; +#else /* not HAVE_STRUCT_MNTENT */ +# ifdef HAVE_STRUCT_MNTTAB +typedef struct mnttab mntent_t; +/* map struct mnttab field names to struct mntent field names */ +# define mnt_fsname mnt_special +# define mnt_dir mnt_mountp +# define mnt_opts mnt_mntopts +# define mnt_type mnt_fstype +# else /* not HAVE_STRUCT_MNTTAB */ +# ifdef MOUNT_TABLE_ON_FILE +# error Could not find definition for struct mntent or struct mnttab! +# else /* not MOUNT_TABLE_ON_FILE */ +typedef struct _am_mntent { + char *mnt_fsname; /* name of mounted file system */ + char *mnt_dir; /* file system path prefix */ + char *mnt_type; /* MNTTAB_TYPE_* */ + char *mnt_opts; /* MNTTAB_OPT_* */ + int mnt_freq; /* dump frequency, in days */ + int mnt_passno; /* pass number on parallel fsck */ +} mntent_t; +# endif /* not MOUNT_TABLE_ON_FILE */ +# endif /* not HAVE_STRUCT_MNTTAB */ +#endif /* not HAVE_STRUCT_MNTENT */ + + +/* + * Complete external definitions missing from some systems. + */ + +#ifndef HAVE_EXTERN_SYS_ERRLIST +extern const char * const sys_errlist[]; +#endif /* not HAVE_EXTERN_SYS_ERRLIST */ + +#ifndef HAVE_EXTERN_OPTARG +extern char *optarg; +extern int optind; +#endif /* not HAVE_EXTERN_OPTARG */ + +#if defined(HAVE_CLNT_SPERRNO) && !defined(HAVE_EXTERN_CLNT_SPERRNO) +extern char *clnt_sperrno(const enum clnt_stat num); +#endif /* defined(HAVE_CLNT_SPERRNO) && !defined(HAVE_EXTERN_CLNT_SPERRNO) */ + +#ifndef HAVE_EXTERN_FREE +extern void free(voidp); +#endif /* not HAVE_EXTERN_FREE */ + +#if defined(HAVE_GET_MYADDRESS) && !defined(HAVE_EXTERN_GET_MYADDRESS) +extern void get_myaddress(struct sockaddr_in *addr); +#endif /* defined(HAVE_GET_MYADDRESS) && !defined(HAVE_EXTERN_GET_MYADDRESS) */ + +#if defined(HAVE_GETDOMAINNAME) && !defined(HAVE_EXTERN_GETDOMAINNAME) +# if defined(HAVE_MAP_NIS) || defined(HAVE_MAP_NISPLUS) +extern int getdomainname(char *name, int namelen); +# endif /* defined(HAVE_MAP_NIS) || defined(HAVE_MAP_NISPLUS) */ +#endif /* defined(HAVE_GETDOMAINNAME) && !defined(HAVE_EXTERN_GETDOMAINNAME) */ + +#if defined(HAVE_GETDTABLESIZE) && !defined(HAVE_EXTERN_GETDTABLESIZE) +extern int getdtablesize(void); +#endif /* defined(HAVE_GETDTABLESIZE) && !defined(HAVE_EXTERN_GETDTABLESIZE) */ + +#if defined(HAVE_GETHOSTNAME) && !defined(HAVE_EXTERN_GETHOSTNAME) +extern int gethostname(char *name, int namelen); +#endif /* defined(HAVE_GETHOSTNAME) && !defined(HAVE_EXTERN_GETHOSTNAME) */ + +#if defined(HAVE_GETPAGESIZE) && !defined(HAVE_EXTERN_GETPAGESIZE) +extern int getpagesize(void); +#endif /* defined(HAVE_GETPAGESIZE) && !defined(HAVE_EXTERN_GETPAGESIZE) */ + +#ifndef HAVE_EXTERN_GETWD +extern char *getwd(char *s); +#endif /* not HAVE_EXTERN_GETWD */ + +#ifndef HAVE_EXTERN_INNETGR +extern int innetgr(char *, char *, char *, char *); +#endif /* not HAVE_EXTERN_INNETGR */ + +#if defined(HAVE_MKSTEMP) && !defined(HAVE_EXTERN_MKSTEMP) +extern int mkstemp(char *); +#endif /* defined(HAVE_MKSTEMP) && !defined(HAVE_EXTERN_MKSTEMP) */ + +#ifndef HAVE_EXTERN_SBRK +extern caddr_t sbrk(int incr); +#endif /* not HAVE_EXTERN_SBRK */ + +#ifndef HAVE_EXTERN_STRCASECMP +/* + * define this extern even if function does not exist, for it will + * be filled in by libamu/strcasecmp.c + */ +extern int strcasecmp(const char *s1, const char *s2); +#endif /* not HAVE_EXTERN_STRCASECMP */ + +#ifndef HAVE_EXTERN_STRDUP +/* + * define this extern even if function does not exist, for it will + * be filled in by libamu/strdup.c + */ +extern char *strdup(const char *s); +#endif /* not HAVE_EXTERN_STRDUP */ + +#if defined(HAVE_STRSTR) && !defined(HAVE_EXTERN_STRSTR) +extern char *strstr(const char *s1, const char *s2); +#endif /* defined(HAVE_STRSTR) && !defined(HAVE_EXTERN_STRSTR) */ + +#if defined(HAVE_USLEEP) && !defined(HAVE_EXTERN_USLEEP) +extern int usleep(u_int useconds); +#endif /* defined(HAVE_USLEEP) && !defined(HAVE_EXTERN_USLEEP) */ + +#ifndef HAVE_EXTERN_UALARM +extern u_int ualarm(u_int usecs, u_int interval); +#endif /* not HAVE_EXTERN_UALARM */ + +#if defined(HAVE_WAIT3) && !defined(HAVE_EXTERN_WAIT3) +extern int wait3(int *statusp, int options, struct rusage *rusage); +#endif /* defined(HAVE_WAIT3) && !defined(HAVE_EXTERN_WAIT3) */ + +#ifndef HAVE_EXTERN_XDR_OPAQUE_AUTH +extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *); +#endif /* not HAVE_EXTERN_XDR_OPAQUE_AUTH */ + +#ifndef HAVE_EXTERN_GETLOGIN +extern char *getlogin(void); +#endif /* not HAVE_EXTERN_GETLOGIN */ + +/****************************************************************************/ +/* + * amd-specific header files. + */ +#ifdef THIS_HEADER_FILE_IS_INCLUDED_ABOVE +# include +#endif /* THIS_HEADER_FILE_IS_INCLUDED_ABOVE */ +#include +#include +#include +/* compatibilty with old amd, while autoconfistating it */ +#include + + +/****************************************************************************/ +/* + * External defintions that depend on other macros available (or not) + * and those are probably declared in any of the above headers. + */ + +#ifndef HAVE_HASMNTOPT +extern char *hasmntopt(mntent_t *mnt, char *opt); +#endif /* not HAVE_HASMNTOPT */ + +/* + * include definitions of all possible xdr functions that are otherwise + * not defined elsewhere. + */ +#include + +#endif /* not _AM_DEFS_H */ diff --git a/contrib/amd/include/am_utils.h b/contrib/amd/include/am_utils.h new file mode 100644 index 0000000..f4e0ccf --- /dev/null +++ b/contrib/amd/include/am_utils.h @@ -0,0 +1,956 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: am_utils.h,v 1.1 1996/01/13 23:23:39 ezk Exp ezk $ + * + */ + +/* + * Definitions that are specific to the am-utils package. + */ + +#ifndef _AM_UTILS_H +#define _AM_UTILS_H + + +/**************************************************************************/ +/*** MACROS ***/ +/**************************************************************************/ + +/* + * General macros. + */ +#ifndef FALSE +# define FALSE 0 +#endif /* not FALSE */ +#ifndef TRUE +# define TRUE 1 +#endif /* not TRUE */ +#ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif /* not MAX */ +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif /* not MIN */ + +#define ONE_HOUR (60 * 60) /* One hour in seconds */ + +#ifndef MAXHOSTNAMELEN +# ifdef HOSTNAMESZ +# define MAXHOSTNAMELEN HOSTNAMESZ +# else /* not HOSTNAMESZ */ +# define MAXHOSTNAMELEN 64 +# endif /* not HOSTNAMESZ */ +#endif /* not MAXHOSTNAMELEN */ + +/* + * String comparison macros + */ +#define STREQ(s1, s2) (strcmp((s1), (s2)) == 0) +#define STRCEQ(s1, s2) (strcasecmp((s1), (s2)) == 0) +#define NSTREQ(s1, s2, n) (strncmp((s1), (s2), (n)) == 0) +#define FSTREQ(s1, s2) ((*(s1) == *(s2)) && STREQ((s1),(s2))) + +/* + * Logging options/flags + */ +#define XLOG_FATAL 0x0001 +#define XLOG_ERROR 0x0002 +#define XLOG_USER 0x0004 +#define XLOG_WARNING 0x0008 +#define XLOG_INFO 0x0010 +#define XLOG_DEBUG 0x0020 +#define XLOG_MAP 0x0040 +#define XLOG_STATS 0x0080 +#define XLOG_DEFSTR "all,nomap,nostats" /* Default log options */ +#define XLOG_ALL (XLOG_FATAL|XLOG_ERROR|XLOG_USER|XLOG_WARNING|XLOG_INFO|XLOG_MAP|XLOG_STATS) + +#define clocktime() (clock_valid ? clock_valid : time(&clock_valid)) + +#ifndef ROOT_MAP +# define ROOT_MAP "\"root\"" +#endif /* not ROOT_MAP */ + +#define NO_SUBNET "notknown" /* default subnet name for no subnet */ +#define NEXP_AP (1022) /* gdmr: was 254 */ +#define NEXP_AP_MARGIN (128) +#define MAX_READDIR_ENTRIES 16 + +/* + * Linked list macros + */ +#define AM_FIRST(ty, q) ((ty *) ((q)->q_forw)) +#define AM_LAST(ty, q) ((ty *) ((q)->q_back)) +#define NEXT(ty, q) ((ty *) (((qelem *) q)->q_forw)) +#define PREV(ty, q) ((ty *) (((qelem *) q)->q_back)) +#define HEAD(ty, q) ((ty *) q) +#define ITER(v, ty, q) \ + for ((v) = AM_FIRST(ty,(q)); (v) != HEAD(ty,(q)); (v) = NEXT(ty,(v))) + +/* allocate anything of type ty */ +#define ALLOC(ty) ((ty *) xmalloc(sizeof(ty))) +#define CALLOC(ty) ((ty *) xcalloc(1, sizeof(ty))) + +/* converting am-filehandles to mount-points */ +#define fh_to_mp2(fhp, rp) fh_to_mp3(fhp, rp, VLOOK_CREATE) + +/* + * Systems which have the mount table in a file need to read it before + * they can perform an unmount() system call. + */ +#define UMOUNT_FS(dir, mtb_name) umount_fs(dir, mtb_name) +/* imported via $srcdir/conf/umount/umount_*.c */ +extern int umount_fs(char *fs_name, const char *mnttabname); + +/* + * macros for automounter vfs/vnode operations. + */ +#define VLOOK_CREATE 0x1 +#define VLOOK_DELETE 0x2 +#define FS_DIRECTORY 0x0001 /* This looks like a dir, not a link */ +#define FS_MBACKGROUND 0x0002 /* Should background this mount */ +#define FS_NOTIMEOUT 0x0004 /* Don't bother with timeouts */ +#define FS_MKMNT 0x0008 /* Need to make the mount point */ +#define FS_UBACKGROUND 0x0010 /* Unmount in background */ +#define FS_BACKGROUND (FS_MBACKGROUND|FS_UBACKGROUND) +#define FS_DISCARD 0x0020 /* Discard immediately on last reference */ +#define FS_AMQINFO 0x0040 /* Amq is interested in this fs type */ + +/* + * macros for struct fserver. + */ +#define FSF_VALID 0x0001 /* Valid information available */ +#define FSF_DOWN 0x0002 /* This fileserver is thought to be down */ +#define FSF_ERROR 0x0004 /* Permanent error has occured */ +#define FSF_WANT 0x0008 /* Want a wakeup call */ +#define FSF_PINGING 0x0010 /* Already doing pings */ +#define FSRV_ISDOWN(fs) (((fs)->fs_flags & (FSF_DOWN|FSF_VALID)) == (FSF_DOWN|FSF_VALID)) +#define FSRV_ISUP(fs) (((fs)->fs_flags & (FSF_DOWN|FSF_VALID)) == (FSF_VALID)) + +/* + * macros for struct mntfs (list of mounted filesystems) + */ +#define MFF_MOUNTED 0x0001 /* Node is mounted */ +#define MFF_MOUNTING 0x0002 /* Mount is in progress */ +#define MFF_UNMOUNTING 0x0004 /* Unmount is in progress */ +#define MFF_RESTART 0x0008 /* Restarted node */ +#define MFF_MKMNT 0x0010 /* Delete this node's am_mount */ +#define MFF_ERROR 0x0020 /* This node failed to mount */ +#define MFF_LOGDOWN 0x0040 /* Logged that this mount is down */ +#define MFF_RSTKEEP 0x0080 /* Don't timeout this filesystem - restarted */ +#define MFF_WANTTIMO 0x0100 /* Need a timeout call when not busy */ +#ifdef HAVE_AM_FS_NFSL +# define MFF_NFSLINK 0x0200 /* nfsl type, and deemed a link */ +#endif /* HAVE_AM_FS_NFSL */ + +/* + * macros for struct am_node (map of auto-mount points). + */ +#define AMF_NOTIMEOUT 0x0001 /* This node never times out */ +#define AMF_ROOT 0x0002 /* This is a root node */ +#ifdef HAVE_FS_AUTOFS +# define AMF_AUTOFS 0x0004 /* this node is of type autofs */ +#endif /* HAVE_FS_AUTOFS */ + +/* + * The following values can be tuned... + */ +#define ALLOWED_MOUNT_TIME 40 /* 40s for a mount */ +#define AM_TTL (5 * 60) /* Default cache period */ +#define AM_TTL_W (2 * 60) /* Default unmount interval */ +#define AM_PINGER 30 /* NFS ping interval for live systems */ +#define AMFS_AUTO_TIMEO 8 /* Default amfs_auto timeout - .8s */ + +/* + * default amfs_auto retrans - 1/10th seconds + */ +#define AMFS_AUTO_RETRANS ((ALLOWED_MOUNT_TIME*10+5*gopt.amfs_auto_timeo)/gopt.amfs_auto_timeo * 2) + +/* + * RPC-related macros. + */ +#define RPC_XID_PORTMAP 0 +#define RPC_XID_MOUNTD 1 +#define RPC_XID_NFSPING 2 +#define RPC_XID_MASK (0x0f) /* 16 id's for now */ +#define MK_RPC_XID(type_id, uniq) ((type_id) | ((uniq) << 4)) + +/* + * What level of AMD are we backward compatible with? + * This only applies to externally visible characteristics. + * Rev.Minor.Branch.Patch (2 digits each) + */ +#define AMD_COMPAT 5000000 /* 5.0 */ + +/* + * Error to return if remote host is not available. + * Try, in order, "host down", "host unreachable", "invalid argument". + */ +#ifdef EHOSTDOWN +# define AM_ERRNO_HOST_DOWN EHOSTDOWN +# else /* not EHOSTDOWN */ +# ifdef EHOSTUNREACH +# define AM_ERRNO_HOST_DOWN EHOSTUNREACH +# else /* not EHOSTUNREACH */ +# define AM_ERRNO_HOST_DOWN EINVAL +# endif /* not EHOSTUNREACH */ +#endif /* not EHOSTDOWN */ + + +/**************************************************************************/ +/*** STRUCTURES AND TYPEDEFS ***/ +/**************************************************************************/ + +/* some typedefs must come first */ +typedef char *amq_string; +typedef struct mntfs mntfs; +typedef struct am_opts am_opts; +typedef struct am_ops am_ops; +typedef struct am_node am_node; +typedef struct _qelem qelem; +typedef struct mntlist mntlist; +typedef struct fserver fserver; + +/* + * Linked list + * (the name 'struct qelem' conflicts with linux's unistd.h) + */ +struct _qelem { + qelem *q_forw; + qelem *q_back; +}; + +/* + * Option tables + */ +struct opt_tab { + char *opt; + int flag; +}; + +/* + * Server states + */ +typedef enum { + Start, + Run, + Finishing, + Quit, + Done +} serv_state; + +/* + * Options + */ +struct am_opts { + char *fs_glob; /* Smashed copy of global options */ + char *fs_local; /* Expanded copy of local options */ + char *fs_mtab; /* Mount table entry */ + /* Other options ... */ + char *opt_dev; + char *opt_delay; + char *opt_dir; + char *opt_fs; + char *opt_group; + char *opt_mount; + char *opt_opts; + char *opt_remopts; + char *opt_pref; + char *opt_autopref; + char *opt_cache; + char *opt_rfs; + char *opt_rhost; + char *opt_sublink; + char *opt_type; + char *opt_unmount; + char *opt_user; + char *opt_maptype; /* map type: file, nis, hesiod, etc. */ + char *opt_cachedir; /* cache directory */ + char *opt_addopts; /* options to add to opt_opts */ +}; + +/* + * List of mounted filesystems + */ +struct mntfs { + qelem mf_q; /* List of mounted filesystems */ + am_ops *mf_ops; /* Operations on this mountpoint */ + am_opts *mf_fo; /* File opts */ + char *mf_mount; /* "/a/kiska/home/kiska" */ + char *mf_info; /* Mount info */ + char *mf_auto; /* Automount opts */ + char *mf_mopts; /* FS mount opts */ + char *mf_remopts; /* Remote FS mount opts */ + fserver *mf_server; /* File server */ + int mf_flags; /* Flags MFF_* */ + int mf_error; /* Error code from background mount */ + int mf_refc; /* Number of references to this node */ + int mf_cid; /* Callout id */ + void (*mf_prfree) (voidp); /* Free private space */ + voidp mf_private; /* Private - per-fs data */ +}; + +/* + * File Handle + * + * This is interpreted by indexing the exported array + * by fhh_id. + * + * The whole structure is mapped onto a standard fhandle_t + * when transmitted. + */ +struct am_fh { + int fhh_pid; /* process id */ + int fhh_id; /* map id */ + int fhh_gen; /* generation number */ +}; + +/* + * Multi-protocol NFS file handle + */ +union am_nfs_handle { + /* placeholder for V4 file handle */ +#ifdef HAVE_FS_NFS3 + struct mountres3 v3; /* NFS version 3 handle */ +#endif /* HAVE_FS_NFS3 */ + struct fhstatus v2; /* NFS version 2 handle */ +}; +typedef union am_nfs_handle am_nfs_handle_t; + +/* + * automounter vfs/vnode operations. + */ +typedef char *(*vfs_match) (am_opts *); +typedef int (*vfs_init) (mntfs *); +typedef int (*vmount_fs) (am_node *); +typedef int (*vfmount_fs) (mntfs *); +typedef int (*vumount_fs) (am_node *); +typedef int (*vfumount_fs) (mntfs *); +typedef am_node *(*vlookuppn) (am_node *, char *, int *, int); +typedef int (*vreaddir) (am_node *, nfscookie, nfsdirlist *, nfsentry *, int); +typedef am_node *(*vreadlink) (am_node *, int *); +typedef void (*vmounted) (mntfs *); +typedef void (*vumounted) (am_node *); +typedef fserver *(*vffserver) (mntfs *); + +struct am_ops { + char *fs_type; /* type of filesystems "nfsx" */ + vfs_match fs_match; /* fxn: match */ + vfs_init fs_init; /* fxn: initialization */ + vmount_fs mount_fs; /* fxn: mount vnode */ + vfmount_fs fmount_fs; /* fxn: mount VFS */ + vumount_fs umount_fs; /* fxn: unmount vnode */ + vfumount_fs fumount_fs; /* fxn: unmount VFS */ + vlookuppn lookuppn; /* fxn: lookup path-name */ + vreaddir readdir; /* fxn: read directory */ + vreadlink readlink; /* fxn: read link */ + vmounted mounted; /* fxn: after-mount extra actions */ + vumounted umounted; /* fxn: after-umount extra actions */ + vffserver ffserver; /* fxn: find a file server */ + int fs_flags; /* filesystem flags FS_* */ +}; + +typedef int (*task_fun) (voidp); +typedef void (*cb_fun) (int, int, voidp); +typedef void (*fwd_fun) P((voidp, int, struct sockaddr_in *, + struct sockaddr_in *, voidp, int)); + +/* + * List of mount table entries + */ +struct mntlist { + struct mntlist *mnext; + mntent_t *mnt; +}; + +/* + * Mount map + */ +typedef struct mnt_map mnt_map; + +/* + * Per-mountpoint statistics + */ +struct am_stats { + time_t s_mtime; /* Mount time */ + u_short s_uid; /* Uid of mounter */ + int s_getattr; /* Count of getattrs */ + int s_lookup; /* Count of lookups */ + int s_readdir; /* Count of readdirs */ + int s_readlink; /* Count of readlinks */ + int s_statfs; /* Count of statfs */ +}; +typedef struct am_stats am_stats; + +/* + * System statistics + */ +struct amd_stats { + int d_drops; /* Dropped requests */ + int d_stale; /* Stale NFS handles */ + int d_mok; /* Succesful mounts */ + int d_merr; /* Failed mounts */ + int d_uerr; /* Failed unmounts */ +}; +extern struct amd_stats amd_stats; + +/* + * List of fileservers + */ +struct fserver { + qelem fs_q; /* List of fileservers */ + int fs_refc; /* Number of references to this node */ + char *fs_host; /* Normalized hostname of server */ + struct sockaddr_in *fs_ip; /* Network address of server */ + int fs_cid; /* Callout id */ + int fs_pinger; /* Ping (keepalive) interval */ + int fs_flags; /* Flags */ + char *fs_type; /* File server type */ + u_long fs_version; /* NFS version of server (2, 3, etc.)*/ + char *fs_proto; /* NFS protocol of server (tcp, udp, etc.) */ + voidp fs_private; /* Private data */ + void (*fs_prfree) (voidp); /* Free private data */ +}; + +/* + * Map of auto-mount points. + */ +struct am_node { + int am_mapno; /* Map number */ + mntfs *am_mnt; /* Mounted filesystem */ + char *am_name; /* "kiska": name of this node */ + char *am_path; /* "/home/kiska": path of this node's mount point */ + char *am_link; /* "/a/kiska/home/kiska/this/that": link to sub-dir */ + am_node *am_parent; /* Parent of this node */ + am_node *am_ysib; /* Younger sibling of this node */ + am_node *am_osib; /* Older sibling of this node */ + am_node *am_child; /* First child of this node */ + nfsattrstat am_attr; /* File attributes */ +#define am_fattr am_attr.ns_u.ns_attr_u + int am_flags; /* Boolean flags AMF_* */ + int am_error; /* Specific mount error */ + time_t am_ttl; /* Time to live */ + int am_timeo_w; /* Wait interval */ + int am_timeo; /* Timeout interval */ + u_int am_gen; /* Generation number */ + char *am_pref; /* Mount info prefix */ + am_stats am_stats; /* Statistics gathering */ + SVCXPRT *am_transp; /* Info for quick reply */ +}; + + +/**************************************************************************/ +/*** EXTERNALS ***/ +/**************************************************************************/ + +/* + * Useful constants + */ +extern char *mnttab_file_name; /* Mount table */ +extern char *cpu; /* "CPU type" */ +extern char *endian; /* "big" */ +extern char *hostdomain; /* "southseas.nz" */ +extern char copyright[]; /* Copyright info */ +extern char hostd[]; /* "kiska.southseas.nz" */ +extern char pid_fsname[]; /* kiska.southseas.nz:(pid%d) */ +extern char version[]; /* Version info */ + +/* + * Global variables. + */ +extern AUTH *nfs_auth; /* Dummy uthorisation for remote servers */ +extern FILE *logfp; /* Log file */ +extern am_node **exported_ap; /* List of nodes */ +extern am_node *root_node; /* Node for "root" */ +extern char *PrimNetName; /* Name of primary connected network */ +extern char *PrimNetNum; /* Name of primary connected network */ +extern char *SubsNetName; /* Name of subsidiary connected network */ +extern char *SubsNetNum; /* Name of subsidiary connected network */ +extern char *progname; /* "amd"|"mmd" */ +extern char hostname[]; /* "kiska" */ +extern int first_free_map; /* First free node */ +extern int foreground; /* Foreground process */ +extern int immediate_abort; /* Should close-down unmounts be retried */ +extern int last_used_map; /* Last map being used for mounts */ +extern int orig_umask; /* umask() on startup */ +extern int task_notify_todo; /* Task notifier needs running */ +extern int xlog_level; /* Logging level */ +extern int xlog_level_init; +extern pid_t mypid; /* Current process id */ +extern serv_state amd_state; /* Should we go now */ +extern struct in_addr myipaddr; /* (An) IP address of this host */ +extern struct opt_tab xlog_opt[]; +extern time_t clock_valid; /* Clock needs recalculating */ +extern time_t do_mapc_reload; /* Flush & reload mount map cache */ +extern time_t next_softclock; /* Time to call softclock() */ +extern u_short nfs_port; /* Our NFS service port */ + +/* + * Global routines + */ +extern CLIENT *get_mount_client(char *unused_host, struct sockaddr_in *sin, struct timeval *tv, int *sock, u_long mnt_version); +extern RETSIGTYPE sigchld(int); +extern SVCXPRT *nfsxprt; +extern am_node *efs_lookuppn(am_node *, char *, int *, int); +extern am_node *exported_ap_alloc(void); +extern am_node *fh_to_mp(am_nfs_fh *); +extern am_node *fh_to_mp3(am_nfs_fh *, int *, int); +extern am_node *find_mf(mntfs *); +extern am_node *next_map(int *); +extern am_node *root_ap(char *, int); +extern am_ops *ops_match(am_opts *, char *, char *, char *, char *, char *); +extern bool_t xdr_amq_string(XDR *xdrs, amq_string *objp); +extern bool_t xdr_dirpath(XDR *xdrs, dirpath *objp); +extern char **strsplit(char *, int, int); +extern char *expand_key(char *); +extern char *get_version_string(void); +extern char *inet_dquad(char *, u_long); +extern char *print_wires(void); +extern char *str3cat(char *, char *, char *, char *); +extern char *strealloc(char *, char *); +extern char *strip_selectors(char *, char *); +extern char *strnsave(const char *, int); +extern fserver *dup_srvr(fserver *); +extern int amu_close(int fd); +extern int background(void); +extern int bind_resv_port(int, u_short *); +extern int cmdoption(char *, struct opt_tab *, int *); +extern int compute_mount_flags(mntent_t *); +extern int efs_readdir(am_node *, nfscookie, nfsdirlist *, nfsentry *, int); +extern int eval_fs_opts(am_opts *, char *, char *, char *, char *, char *); +extern int fwd_init(void); +extern int fwd_packet(int, voidp, int, struct sockaddr_in *, struct sockaddr_in *, voidp, fwd_fun); +extern int get_amd_program_number(void); +extern int hasmntval(mntent_t *, char *); +extern int is_network_member(const char *net); +extern int islocalnet(u_long); +extern int make_nfs_auth(void); +extern int make_rpc_packet(char *, int, u_long, struct rpc_msg *, voidp, XDRPROC_T_TYPE, AUTH *); +extern int mapc_keyiter(mnt_map *, void(*)(char *, voidp), voidp); +extern int mapc_search(mnt_map *, char *, char **); +extern int mkdirs(char *, int); +extern int mount_auto_node(char *, voidp); +extern int mount_automounter(int); +extern int mount_exported(void); +extern int mount_fs(mntent_t *, int, caddr_t, int, MTYPE_TYPE, u_long, const char *, const char *); +extern int mount_node(am_node *); +extern int nfs_srvr_port(fserver *, u_short *, voidp); +extern int pickup_rpc_reply(voidp, int, voidp, XDRPROC_T_TYPE); +extern int root_keyiter(void(*)(char *, voidp), voidp); +extern int softclock(void); +extern int switch_option(char *); +extern int switch_to_logfile(char *); +extern int timeout(u_int, void (*fn)(voidp), voidp); +extern int valid_key(char *); +extern mnt_map *mapc_find(char *, char *, const char *); +extern mntfs *dup_mntfs(mntfs *); +extern mntfs *find_mntfs(am_ops *, am_opts *, char *, char *, char *, char *, char *); +extern mntfs *new_mntfs(void); +extern mntfs *realloc_mntfs(mntfs *, am_ops *, am_opts *, char *, char *, char *, char *, char *); +extern mntlist *read_mtab(char *, const char *); +extern struct sockaddr_in *amu_svc_getcaller(SVCXPRT *xprt); +extern time_t time(time_t *); +extern void am_mounted(am_node *); +extern void am_unmounted(am_node *); +extern void amq_program_1(struct svc_req *rqstp, SVCXPRT * transp); +extern void amu_get_myaddress(struct in_addr *iap); +extern void amu_release_controlling_tty(void); +extern void compute_automounter_nfs_args(nfs_args_t *nap, mntent_t *mntp); +extern void deslashify(char *); +extern void discard_mntlist(mntlist *mp); +extern void do_task_notify(void); +extern void flush_mntfs(void); +extern void flush_nfs_fhandle_cache(fserver *); +extern void forcibly_timeout_mp(am_node *); +extern void free_map(am_node *); +extern void free_mntfs(voidp); +extern void free_mntlist(mntlist *); +extern void free_opts(am_opts *); +extern void free_srvr(fserver *); +extern void fwd_reply(void); +extern void get_args(int argc, char *argv[]); +extern void getwire(char **name1, char **number1); +extern void going_down(int); +extern void host_normalize(char **); +extern void init_map(am_node *, char *); +extern void ins_que(qelem *, qelem *); +extern void insert_am(am_node *, am_node *); +extern void make_root_node(void); +extern void map_flush_srvr(fserver *); +extern void mapc_add_kv(mnt_map *, char *, char *); +extern void mapc_free(voidp); +extern void mapc_reload(void); +extern void mapc_showtypes(char *buf); +extern void mk_fattr(am_node *, nfsftype); +extern void mnt_free(mntent_t *); +extern void mp_to_fh(am_node *, am_nfs_fh *); +extern void new_ttl(am_node *); +extern void nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp); +extern void normalize_slash(char *); +extern void ops_showamfstypes(char *buf); +extern void ops_showfstypes(char *outbuf); +extern void plog(int, char *,...); +extern void rem_que(qelem *); +extern void reschedule_timeout_mp(void); +extern void restart(void); +extern void rmdirs(char *); +extern void rpc_msg_init(struct rpc_msg *, u_long, u_long, u_long); +extern void run_task(task_fun, voidp, cb_fun, voidp); +extern void sched_task(cb_fun, voidp, voidp); +extern void set_amd_program_number(int program); +extern void show_opts(int ch, struct opt_tab *); +extern void show_rcs_info(const char *, char *); +extern void srvrlog(fserver *, char *); +extern void timeout_mp(voidp); +extern void umount_exported(void); +extern void unregister_amq(void); +extern void untimeout(int); +extern void wakeup(voidp); +extern void wakeup_srvr(fserver *); +extern void wakeup_task(int, int, voidp); +extern voidp xmalloc(int); +extern voidp xrealloc(voidp, int); +extern voidp xzalloc(int); +extern u_long get_nfs_version(char *host, struct sockaddr_in *sin, u_long nfs_version, const char *proto); + + +#ifdef MOUNT_TABLE_ON_FILE +extern void rewrite_mtab(mntlist *, const char *); +extern void unlock_mntlist(void); +extern void write_mntent(mntent_t *, const char *); +#endif /* MOUNT_TABLE_ON_FILE */ + +#if defined(HAVE_SYSLOG_H) || defined(HAVE_SYS_SYSLOG_H) +extern int syslogging; +#endif /* defined(HAVE_SYSLOG_H) || defined(HAVE_SYS_SYSLOG_H) */ + +#ifdef HAVE_TRANSPORT_TYPE_TLI + +extern void compute_nfs_args(nfs_args_t *nap, mntent_t *mntp, int genflags, struct netconfig *nfsncp, struct sockaddr_in *ip_addr, u_long nfs_version, char *nfs_proto, am_nfs_handle_t *fhp, char *host_name, char *fs_name); +extern int create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, struct netconfig **udp_amqncpp, int *tcp_soAMQp, SVCXPRT **tcp_amqpp, struct netconfig **tcp_amqncpp); +extern int create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp)); +extern int get_knetconfig(struct knetconfig **kncpp, struct netconfig *in_ncp, char *nc_protoname); +extern struct netconfig *nfsncp; +extern void free_knetconfig(struct knetconfig *kncp); + +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + +extern void compute_nfs_args(nfs_args_t *nap, mntent_t *mntp, int genflags, struct sockaddr_in *ip_addr, u_long nfs_version, char *nfs_proto, am_nfs_handle_t *fhp, char *host_name, char *fs_name); +extern enum clnt_stat pmap_ping(struct sockaddr_in *address); +extern int create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, int *tcp_soAMQp, SVCXPRT **tcp_amqpp); +extern int create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp)); + +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + +#ifndef HAVE_FIELD_STRUCT_FHSTATUS_FHS_FH +# define fhs_fh fhstatus_u.fhs_fhandle +#endif /* not HAVE_FIELD_STRUCT_FHSTATUS_FHS_FH */ + + +/**************************************************************************/ +/*** Generic file-system types, implemented as part of the native O/S. ***/ +/**************************************************************************/ + +/* + * Loopback File System + * Many systems can't support this, and in any case most of the + * functionality is available with Symlink FS. + */ +#ifdef HAVE_FS_LOFS +extern am_ops lofs_ops; +#endif /* HAVE_FS_LOFS */ + +/* + * CD-ROM File System (CD-ROM) + * (HSFS: High Sierra F/S on some machines) + * Many systems can't support this, and in any case most of the + * functionality is available with program FS. + */ +#ifdef HAVE_FS_CDFS +extern am_ops cdfs_ops; +#endif /* HAVE_FS_CDFS */ + +/* + * PC File System (MS-DOS) + * Many systems can't support this, and in any case most of the + * functionality is available with program FS. + */ +#ifdef HAVE_FS_PCFS +extern am_ops pcfs_ops; +#endif /* HAVE_FS_PCFS */ + +/* + * Caching File System (Solaris) + */ +#ifdef HAVE_FS_CACHEFS +extern am_ops cachefs_ops; +#endif /* HAVE_FS_CACHEFS */ + +/* + * Network File System + * Good, slow, NFS V.2. + */ +#ifdef HAVE_FS_NFS +extern am_ops nfs_ops; /* NFS */ +extern fserver *find_nfs_srvr (mntfs *); +extern int nfs_fmount(mntfs *mf); +extern int nfs_fumount(mntfs *mf); +extern int nfs_init(mntfs *mf); +extern qelem nfs_srvr_list; +extern void nfs_umounted(am_node *mp); +#endif /* HAVE_FS_NFS */ + + +/* + * Network File System: the new generation + * NFS V.3 + */ +#ifdef HAVE_FS_NFS3 +# ifndef NFS_VERSION3 +# define NFS_VERSION3 ((u_int) 3) +# endif /* not NFS_VERSION3 */ +#endif /* HAVE_FS_NFS3 */ + +/* + * Un*x File System + * Normal local disk file system. + */ +#ifdef HAVE_FS_UFS +extern am_ops ufs_ops; /* Un*x file system */ +#endif /* HAVE_FS_UFS */ + + +/**************************************************************************/ +/*** Automounter file-system types, implemented by amd. ***/ +/**************************************************************************/ + +/* + * Automount File System + */ +#ifdef HAVE_AM_FS_AUTO +extern am_ops amfs_auto_ops; /* Automount file system (this!) */ +extern am_ops amfs_toplvl_ops; /* Top-level automount file system */ +extern am_ops amfs_root_ops; /* Root file system */ +extern qelem amfs_auto_srvr_list; +extern am_node *amfs_auto_lookuppn(am_node *mp, char *fname, int *error_return, int op); +extern am_node *next_nonerror_node(am_node *xp); +extern char *amfs_auto_match(am_opts *fo); +extern fserver *find_amfs_auto_srvr(mntfs *); +extern int amfs_auto_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count); +extern int amfs_auto_umount(am_node *mp); +extern int amfs_auto_fmount(am_node *mp); +extern int amfs_auto_fumount(am_node *mp); +#endif /* HAVE_AM_FS_AUTO */ + +/* + * Toplvl Automount File System + */ +#ifdef HAVE_AM_FS_TOPLVL +extern am_ops amfs_toplvl_ops; /* Toplvl Automount file system */ +extern int amfs_toplvl_mount(am_node *mp); +extern int amfs_toplvl_umount(am_node *mp); +extern void amfs_toplvl_mounted(mntfs *mf); +#endif /* HAVE_AM_FS_TOPLVL */ + +/* + * Direct Automount File System + */ +#ifdef HAVE_AM_FS_DIRECT +extern am_ops amfs_direct_ops; /* Direct Automount file system (this too) */ +#endif /* HAVE_AM_FS_DIRECT */ + +/* + * Error File System + */ +#ifdef HAVE_AM_FS_ERROR +extern am_ops amfs_error_ops; /* Error file system */ +extern am_node *amfs_error_lookuppn(am_node *mp, char *fname, int *error_return, int op); +extern int amfs_error_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, int count); +#endif /* HAVE_AM_FS_ERROR */ + +/* + * Inheritance File System + */ +#ifdef HAVE_AM_FS_INHERIT +extern am_ops amfs_inherit_ops; /* Inheritance file system */ +#endif /* HAVE_AM_FS_INHERIT */ + +/* + * NFS mounts with local existence check. + */ +#ifdef HAVE_AM_FS_NFSL +extern am_ops amfs_nfsl_ops; /* NFSL */ +#endif /* HAVE_AM_FS_NFSL */ + +/* + * Multi-nfs mounts. + */ +#ifdef HAVE_AM_FS_NFSX +extern am_ops amfs_nfsx_ops; /* NFSX */ +#endif /* HAVE_AM_FS_NFSX */ + +/* + * NFS host - a whole tree. + */ +#ifdef HAVE_AM_FS_HOST +extern am_ops amfs_host_ops; /* NFS host */ +#endif /* HAVE_AM_FS_HOST */ + +/* + * Program File System + * This is useful for things like RVD. + */ +#ifdef HAVE_AM_FS_PROGRAM +extern am_ops amfs_program_ops; /* Program File System */ +#endif /* HAVE_AM_FS_PROGRAM */ + +/* + * Symbolic-link file system. + * A "filesystem" which is just a symbol link. + */ +#ifdef HAVE_AM_FS_LINK +extern am_ops amfs_link_ops; /* Symlink FS */ +extern int amfs_link_fmount(mntfs *mf); +#endif /* HAVE_AM_FS_LINK */ + +/* + * Symbolic-link file syste, which also checks that the target of + * the symlink exists. + * A "filesystem" which is just a symbol link. + */ +#ifdef HAVE_AM_FS_LINKX +extern am_ops amfs_linkx_ops; /* Symlink FS with existence check */ +#endif /* HAVE_AM_FS_LINKX */ + +/* + * Union file system + */ +#ifdef HAVE_AM_FS_UNION +extern am_ops amfs_union_ops; /* Union FS */ +#endif /* HAVE_AM_FS_UNION */ + +/* + * Autofs file system + */ +#ifdef HAVE_FS_AUTOFS +extern am_ops autofs_ops; /* (Sun) Autofs FS */ +#endif /* HAVE_FS_AUTOFS */ + + +/**************************************************************************/ +/*** DEBUGGING ***/ +/**************************************************************************/ + +/* + * DEBUGGING: + */ +#ifdef DEBUG + +# define D_ALL (~0) +# define D_DAEMON 0x0001 /* Enter daemon mode */ +# define D_TRACE 0x0002 /* Do protocol trace */ +# define D_FULL 0x0004 /* Do full trace */ +# define D_MTAB 0x0008 /* Use local mtab */ +# define D_AMQ 0x0010 /* Register amq program */ +# define D_STR 0x0020 /* Debug string munging */ +# ifdef DEBUG_MEM +# define D_MEM 0x0040 /* Trace memory allocations */ +# endif /* DEBUG_MEM */ +# define D_FORK 0x0080 /* Fork server */ + /* info service specific debugging (hesiod, nis, etc) */ +# define D_INFO 0x0100 + +/* + * Normally, don't enter daemon mode, and don't register amq + */ +# ifdef DEBUG_MEM +# define D_TEST (~(D_DAEMON|D_MEM|D_STR)) +# else /* not DEBUG_MEM */ +# define D_TEST (~(D_DAEMON|D_STR)) +# endif /* not DEBUG_MEM */ + +# define amuDebug(x) if (debug_flags & (x)) +# define dlog amuDebug(D_FULL) dplog +# define amuDebugNo(x) if (!(debug_flags & (x))) + +/* debugging mount-table file to use */ +# ifndef DEBUG_MNTTAB +# define DEBUG_MNTTAB "./mnttab" +# endif /* not DEBUG_MNTTAB */ + +# ifdef DEBUG_MEM +/* + * If debugging memory, then call a special freeing function that logs + * more info, and resets the pointer to NULL so it cannot be used again. + */ +# define XFREE(x) dxfree(__FILE__,__LINE__,x) +extern void dxfree(char *file, int line, voidp ptr); +extern void malloc_verify(void); +# else /* not DEBUG_MEM */ +/* + * If regular debugging, then free the pointer and reset to NULL. + * This should remain so for as long as am-utils is in alpha/beta testing. + */ +# define XFREE(x) do { free((voidp)x); x = NULL;} while (0) +# endif /* not DEBUG_MEM */ + +/* functions that depend solely on debugging */ +extern void print_nfs_args(const nfs_args_t *nap, u_long nfs_version); + +#else /* not DEBUG */ + +/* + * if not debugging, then simple perform free, and don't bother + * resetting the pointer. + */ +# define XFREE(x) free(x) + +#endif /* not DEBUG */ + +extern int debug_flags; /* Debug options */ +extern int debug_option (char *); +extern struct opt_tab dbg_opt[]; +extern void dplog(char *fmt, ...); + +/**************************************************************************/ +/*** MISC (stuff left to autoconfiscate) ***/ +/**************************************************************************/ + +#endif /* not _AM_UTILS_H */ diff --git a/contrib/amd/include/am_xdr_func.h b/contrib/amd/include/am_xdr_func.h new file mode 100644 index 0000000..9364002 --- /dev/null +++ b/contrib/amd/include/am_xdr_func.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: am_xdr_func.c,v 5.2.2.1 1992/02/09 15:08:40 ezk beta $ + * + */ + +/* + * Definitions of all possible xdr functions that are otherwise + * not defined elsewhere. + */ + +#ifndef _AM_XDR_FUNC_H +#define _AM_XDR_FUNC_H + +#ifndef HAVE_XDR_ATTRSTAT +bool_t xdr_attrstat(XDR *xdrs, nfsattrstat *objp); +#endif /* not HAVE_XDR_ATTRSTAT */ +#ifndef HAVE_XDR_CREATEARGS +bool_t xdr_createargs(XDR *xdrs, nfscreateargs *objp); +#endif /* not HAVE_XDR_CREATEARGS */ +#ifndef HAVE_XDR_DIRLIST +bool_t xdr_dirlist(XDR *xdrs, nfsdirlist *objp); +#endif /* not HAVE_XDR_DIRLIST */ +#ifndef HAVE_XDR_DIROPARGS +bool_t xdr_diropargs(XDR *xdrs, nfsdiropargs *objp); +#endif /* not HAVE_XDR_DIROPARGS */ +#ifndef HAVE_XDR_DIROPOKRES +bool_t xdr_diropokres(XDR *xdrs, nfsdiropokres *objp); +#endif /* not HAVE_XDR_DIROPOKRES */ +#ifndef HAVE_XDR_DIROPRES +bool_t xdr_diropres(XDR *xdrs, nfsdiropres *objp); +#endif /* not HAVE_XDR_DIROPRES */ +#ifndef HAVE_XDR_DIRPATH +bool_t xdr_dirpath(XDR *xdrs, dirpath *objp); +#endif /* not HAVE_XDR_DIRPATH */ +#ifndef HAVE_XDR_ENTRY +bool_t xdr_entry(XDR *xdrs, nfsentry *objp); +#endif /* not HAVE_XDR_ENTRY */ +#ifndef HAVE_XDR_EXPORTNODE +bool_t xdr_exportnode(XDR *xdrs, exportnode *objp); +#endif /* not HAVE_XDR_EXPORTNODE */ +#ifndef HAVE_XDR_EXPORTS +bool_t xdr_exports(XDR *xdrs, exports *objp); +#endif /* not HAVE_XDR_EXPORTS */ +#ifndef HAVE_XDR_FATTR +bool_t xdr_fattr(XDR *xdrs, nfsfattr *objp); +#endif /* not HAVE_XDR_FATTR */ +#ifndef HAVE_XDR_FHANDLE +bool_t xdr_fhandle(XDR *xdrs, fhandle objp); +#endif /* not HAVE_XDR_FHANDLE */ +#ifndef HAVE_XDR_FHSTATUS +bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp); +#endif /* not HAVE_XDR_FHSTATUS */ +#ifndef HAVE_XDR_FILENAME +bool_t xdr_filename(XDR *xdrs, filename *objp); +#endif /* not HAVE_XDR_FILENAME */ +#ifndef HAVE_XDR_FTYPE +bool_t xdr_ftype(XDR *xdrs, nfsftype *objp); +#endif /* not HAVE_XDR_FTYPE */ +#ifndef HAVE_XDR_GROUPNODE +bool_t xdr_groupnode(XDR *xdrs, groupnode *objp); +#endif /* not HAVE_XDR_GROUPNODE */ +#ifndef HAVE_XDR_GROUPS +bool_t xdr_groups(XDR *xdrs, groups objp); +#endif /* not HAVE_XDR_GROUPS */ +#ifndef HAVE_XDR_LINKARGS +bool_t xdr_linkargs(XDR *xdrs, nfslinkargs *objp); +#endif /* not HAVE_XDR_LINKARGS */ +#ifndef HAVE_XDR_MOUNTBODY +bool_t xdr_mountbody(XDR *xdrs, mountbody *objp); +#endif /* not HAVE_XDR_MOUNTBODY */ +#ifndef HAVE_XDR_MOUNTLIST +bool_t xdr_mountlist(XDR *xdrs, mountlist *objp); +#endif /* not HAVE_XDR_MOUNTLIST */ + +/* + * NFS3 XDR FUNCTIONS: + */ +#if defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3) +bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp); +bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp); +bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp); +bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp); +#endif /* defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3) */ + +#ifndef HAVE_XDR_NAME +bool_t xdr_name(XDR *xdrs, name *objp); +#endif /* not HAVE_XDR_NAME */ +#ifndef HAVE_XDR_NFS_FH +bool_t xdr_nfs_fh(XDR *xdrs, am_nfs_fh *objp); +#endif /* not HAVE_XDR_NFS_FH */ +#ifndef HAVE_XDR_NFSCOOKIE +bool_t xdr_nfscookie(XDR *xdrs, nfscookie objp); +#endif /* not HAVE_XDR_NFSCOOKIE */ +#ifndef HAVE_XDR_NFSPATH +bool_t xdr_nfspath(XDR *xdrs, nfspath *objp); +#endif /* not HAVE_XDR_NFSPATH */ +#ifndef HAVE_XDR_NFSSTAT +bool_t xdr_nfsstat(XDR *xdrs, nfsstat *objp); +#endif /* not HAVE_XDR_NFSSTAT */ +#ifndef HAVE_XDR_NFSTIME +bool_t xdr_nfstime(XDR *xdrs, nfstime *objp); +#endif /* not HAVE_XDR_NFSTIME */ +#ifndef HAVE_XDR_POINTER +bool_t xdr_pointer(register XDR *xdrs, char **objpp, u_int obj_size, XDRPROC_T_TYPE xdr_obj); +#endif /* not HAVE_XDR_POINTER */ +#ifndef HAVE_XDR_READARGS +bool_t xdr_readargs(XDR *xdrs, nfsreadargs *objp); +#endif /* not HAVE_XDR_READARGS */ +#ifndef HAVE_XDR_READDIRARGS +bool_t xdr_readdirargs(XDR *xdrs, nfsreaddirargs *objp); +#endif /* not HAVE_XDR_READDIRARGS */ +#ifndef HAVE_XDR_READDIRRES +bool_t xdr_readdirres(XDR *xdrs, nfsreaddirres *objp); +#endif /* not HAVE_XDR_READDIRRES */ +#ifndef HAVE_XDR_READLINKRES +bool_t xdr_readlinkres(XDR *xdrs, nfsreadlinkres *objp); +#endif /* not HAVE_XDR_READLINKRES */ +#ifndef HAVE_XDR_READOKRES +bool_t xdr_readokres(XDR *xdrs, nfsreadokres *objp); +#endif /* not HAVE_XDR_READOKRES */ +#ifndef HAVE_XDR_READRES +bool_t xdr_readres(XDR *xdrs, nfsreadres *objp); +#endif /* not HAVE_XDR_READRES */ +#ifndef HAVE_XDR_RENAMEARGS +bool_t xdr_renameargs(XDR *xdrs, nfsrenameargs *objp); +#endif /* not HAVE_XDR_RENAMEARGS */ +#ifndef HAVE_XDR_SATTR +bool_t xdr_sattr(XDR *xdrs, nfssattr *objp); +#endif /* not HAVE_XDR_SATTR */ +#ifndef HAVE_XDR_SATTRARGS +bool_t xdr_sattrargs(XDR *xdrs, nfssattrargs *objp); +#endif /* not HAVE_XDR_SATTRARGS */ +#ifndef HAVE_XDR_STATFSOKRES +bool_t xdr_statfsokres(XDR *xdrs, nfsstatfsokres *objp); +#endif /* not HAVE_XDR_STATFSOKRES */ +#ifndef HAVE_XDR_STATFSRES +bool_t xdr_statfsres(XDR *xdrs, nfsstatfsres *objp); +#endif /* not HAVE_XDR_STATFSRES */ +#ifndef HAVE_XDR_SYMLINKARGS +bool_t xdr_symlinkargs(XDR *xdrs, nfssymlinkargs *objp); +#endif /* not HAVE_XDR_SYMLINKARGS */ +#ifndef HAVE_XDR_WRITEARGS +bool_t xdr_writeargs(XDR *xdrs, nfswriteargs *objp); +#endif /* not HAVE_XDR_WRITEARGS */ + +/* + * AUTOFS XDR FUNCTIONS: + */ +#ifdef HAVE_FS_AUTOFS +# ifndef HAVE_XDR_MNTREQUEST +bool_t xdr_mntrequest(XDR *xdrs, mntrequest *objp); +# endif /* not HAVE_XDR_MNTREQUEST */ +# ifndef HAVE_XDR_MNTRES +bool_t xdr_mntres(XDR *xdrs, mntres *objp); +# endif /* not HAVE_XDR_MNTRES */ +# ifndef HAVE_XDR_UMNTREQUEST +bool_t xdr_umntrequest(XDR *xdrs, umntrequest *objp); +# endif /* not HAVE_XDR_UMNTREQUEST */ +# ifndef HAVE_XDR_UMNTRES +bool_t xdr_umntres(XDR *xdrs, umntres *objp); +# endif /* not HAVE_XDR_UMNTRES */ +#endif /* HAVE_FS_AUTOFS */ + +#endif /* not _AM_XDR_FUNC_H */ diff --git a/contrib/amd/include/amq_defs.h b/contrib/amd/include/amq_defs.h new file mode 100644 index 0000000..e2f941b --- /dev/null +++ b/contrib/amd/include/amq_defs.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amq_defs.h,v 1.1 1996/01/13 23:23:39 ezk Exp ezk $ + * + */ + +#ifndef _AMQ_DEFS_H +#define _AMQ_DEFS_H + +/* + * MACROS + */ +#ifndef AMQ_SIZE +# define AMQ_SIZE 16384 +#endif /* not AMQ_SIZE */ +#define AMQ_STRLEN 1024 +#define AMQ_PROGRAM ((u_long)300019) +#define AMQ_VERSION ((u_long)1) +#define AMQPROC_NULL ((u_long)0) +#define AMQPROC_MNTTREE ((u_long)1) +#define AMQPROC_UMNT ((u_long)2) +#define AMQPROC_STATS ((u_long)3) +#define AMQPROC_EXPORT ((u_long)4) +#define AMQPROC_SETOPT ((u_long)5) +#define AMQPROC_GETMNTFS ((u_long)6) +#define AMQPROC_MOUNT ((u_long)7) +#define AMQPROC_GETVERS ((u_long)8) +#define AMQPROC_GETPID ((u_long)9) + +/* + * TYPEDEFS + */ +typedef long *time_type; +typedef struct amq_mount_info amq_mount_info; +typedef struct amq_mount_stats amq_mount_stats; +typedef struct amq_mount_tree amq_mount_tree; +typedef struct amq_setopt amq_setopt; +typedef amq_mount_tree *amq_mount_tree_p; + +/* + * STRUCTURES: + */ +struct amq_mount_tree { + amq_string mt_mountinfo; + amq_string mt_directory; + amq_string mt_mountpoint; + amq_string mt_type; + time_type mt_mounttime; + u_short mt_mountuid; + int mt_getattr; + int mt_lookup; + int mt_readdir; + int mt_readlink; + int mt_statfs; + struct amq_mount_tree *mt_next; + struct amq_mount_tree *mt_child; +}; + +struct amq_mount_info { + amq_string mi_type; + amq_string mi_mountpt; + amq_string mi_mountinfo; + amq_string mi_fserver; + int mi_error; + int mi_refc; + int mi_up; +}; + +typedef struct { + u_int amq_mount_info_list_len; + amq_mount_info *amq_mount_info_list_val; +} amq_mount_info_list; + +typedef struct { + u_int amq_mount_tree_list_len; + amq_mount_tree_p *amq_mount_tree_list_val; +} amq_mount_tree_list; + +struct amq_mount_stats { + int as_drops; + int as_stale; + int as_mok; + int as_merr; + int as_uerr; +}; + +enum amq_opt { + AMOPT_DEBUG = 0, + AMOPT_LOGFILE = 1, + AMOPT_XLOG = 2, + AMOPT_FLUSHMAPC = 3 +}; +typedef enum amq_opt amq_opt; /* enum typedefs should be after enum */ + +struct amq_setopt { + amq_opt as_opt; + amq_string as_str; +}; + +/* + * EXTERNALS: + * + * external definitions for amqproc_*_1() have been moved off to private + * headers in lib/amu.h, amd/amd.h, etc. They have to be private since the + * same named functions appear in different places with different prototypes + * an functionality. + */ +extern bool_t xdr_amq_mount_info(XDR *xdrs, amq_mount_info *objp); +extern bool_t xdr_amq_mount_info_list(XDR *xdrs, amq_mount_info_list *objp); +extern bool_t xdr_amq_mount_stats(XDR *xdrs, amq_mount_stats *objp); +extern bool_t xdr_amq_mount_tree(XDR *xdrs, amq_mount_tree *objp); +extern bool_t xdr_amq_mount_tree_list(XDR *xdrs, amq_mount_tree_list *objp); +extern bool_t xdr_amq_mount_tree_p(XDR *xdrs, amq_mount_tree_p *objp); +extern bool_t xdr_amq_opt(XDR *xdrs, amq_opt *objp); +extern bool_t xdr_amq_setopt(XDR *xdrs, amq_setopt *objp); +extern bool_t xdr_pri_free(XDRPROC_T_TYPE xdr_args, caddr_t args_ptr); +extern bool_t xdr_time_type(XDR *xdrs, time_type *objp); + +#endif /* not _AMQ_DEFS_H */ diff --git a/contrib/amd/libamu/amu.h b/contrib/amd/libamu/amu.h new file mode 100644 index 0000000..f69b99e --- /dev/null +++ b/contrib/amd/libamu/amu.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: amu.h,v 1.1 1996/01/13 23:23:39 ezk Exp ezk $ + * + */ + +#ifndef _AMU_H +#define _AMU_H + +/* + * Decide what maximum level of NFS server to try and mount with. + */ +#ifdef HAVE_FS_NFS3 +# define NFS_VERS_MAX NFS_VERSION3 +#else /* not HAVE_FS_NFS3 */ +# define NFS_VERS_MAX NFS_VERSION +#endif /* not HAVE_FS_NFS3 */ + +/* some systems like ncr2 do not define this in */ +#ifndef MNTPATHLEN +# define MNTPATHLEN 1024 +#endif /* not MNTPATHLEN */ +#ifndef MNTNAMLEN +# define MNTNAMLEN 255 +#endif /* not MNTNAMLEN */ + +/* + * external definitions for building libamu.a + */ +extern voidp amqproc_null_1(voidp argp, CLIENT *rqstp); +extern amq_mount_tree_p *amqproc_mnttree_1(amq_string *argp, CLIENT *rqstp); +extern voidp amqproc_umnt_1(amq_string *argp, CLIENT *rqstp); +extern amq_mount_stats *amqproc_stats_1(voidp argp, CLIENT *rqstp); +extern amq_mount_tree_list *amqproc_export_1(voidp argp, CLIENT *rqstp); +extern int *amqproc_setopt_1(amq_setopt *argp, CLIENT *rqstp); +extern amq_mount_info_list *amqproc_getmntfs_1(voidp argp, CLIENT *rqstp); +extern int *amqproc_mount_1(voidp argp, CLIENT *rqstp); +extern amq_string *amqproc_getvers_1(voidp argp, CLIENT *rqstp); + +#endif /* not _AMU_H */ diff --git a/contrib/amd/libamu/hasmntopt.c b/contrib/amd/libamu/hasmntopt.c new file mode 100644 index 0000000..7cf9167 --- /dev/null +++ b/contrib/amd/libamu/hasmntopt.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without +n * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: hasmntopt.c,v 5.2.2.2 1992/05/31 16:35:45 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +#ifndef MNTMAXSTR +# define MNTMAXSTR 128 +#endif /* not MNTMAXSTR */ + + +/* + * Some systems don't provide these to the user, + * but amd needs them, so... + * + * From: Piete Brooks + */ + +static char * +nextmntopt(char **p) +{ + char *cp = *p; + char *rp; + + /* + * Skip past white space + */ + while (*cp && isspace(*cp)) + cp++; + + /* + * Word starts here + */ + rp = cp; + + /* + * Scan to send of string or separator + */ + while (*cp && *cp != ',') + cp++; + + /* + * If separator found the overwrite with nul char. + */ + if (*cp) { + *cp = '\0'; + cp++; + } + + /* + * Return value for next call + */ + *p = cp; + return rp; +} + +/* + * replacement for hasmntopt if the system does not have it. + */ +char * +hasmntopt(mntent_t *mnt, char *opt) +{ + char t[MNTMAXSTR]; + char *f; + char *o = t; + int l = strlen(opt); + + strcpy(t, mnt->mnt_opts); + + while (*(f = nextmntopt(&o))) + if (NSTREQ(opt, f, l)) + return f - t + mnt->mnt_opts; + + return 0; +} diff --git a/contrib/amd/libamu/misc_rpc.c b/contrib/amd/libamu/misc_rpc.c new file mode 100644 index 0000000..b6d23cd --- /dev/null +++ b/contrib/amd/libamu/misc_rpc.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: misc_rpc.c,v 5.2.2.1 1992/02/09 15:08:40 jsp beta $ + * + */ + +/* + * Additions to Sun RPC. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * Some systems renamed _seterr_reply to __seterr_reply (with two + * leading underscores) + */ +#if !defined(HAVE__SETERR_REPLY) && defined(HAVE___SETERR_REPLY) +# define _seterr_reply __seterr_reply +#endif /* !defined(HAVE__SETERR_REPLY) && defined(HAVE___SETERR_REPLY) */ + + +void +rpc_msg_init(struct rpc_msg *mp, u_long prog, u_long vers, u_long proc) +{ + /* + * Initialise the message + */ + memset((voidp) mp, 0, sizeof(*mp)); + mp->rm_xid = 0; + mp->rm_direction = CALL; + mp->rm_call.cb_rpcvers = RPC_MSG_VERSION; + mp->rm_call.cb_prog = prog; + mp->rm_call.cb_vers = vers; + mp->rm_call.cb_proc = proc; +} + + +/* + * Field reply to call to mountd + */ +int +pickup_rpc_reply(voidp pkt, int len, voidp where, XDRPROC_T_TYPE where_xdr) +{ + XDR reply_xdr; + int ok; + struct rpc_err err; + struct rpc_msg reply_msg; + int error = 0; + + /* memset((voidp) &err, 0, sizeof(err)); */ + memset((voidp) &reply_msg, 0, sizeof(reply_msg)); + memset((voidp) &reply_xdr, 0, sizeof(reply_xdr)); + + reply_msg.acpted_rply.ar_results.where = (caddr_t) where; + reply_msg.acpted_rply.ar_results.proc = where_xdr; + + xdrmem_create(&reply_xdr, pkt, len, XDR_DECODE); + + ok = xdr_replymsg(&reply_xdr, &reply_msg); + if (!ok) { + error = EIO; + goto drop; + } + _seterr_reply(&reply_msg, &err); + if (err.re_status != RPC_SUCCESS) { + error = EIO; + goto drop; + } + +drop: + if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED && + reply_msg.acpted_rply.ar_verf.oa_base) { + reply_xdr.x_op = XDR_FREE; + (void) xdr_opaque_auth(&reply_xdr, + &reply_msg.acpted_rply.ar_verf); + } + xdr_destroy(&reply_xdr); + + return error; +} + + +int +make_rpc_packet(char *buf, int buflen, u_long proc, struct rpc_msg *mp, voidp arg, XDRPROC_T_TYPE arg_xdr, AUTH *auth) +{ + XDR msg_xdr; + int len; + + xdrmem_create(&msg_xdr, buf, buflen, XDR_ENCODE); + + /* + * Basic protocol header + */ + if (!xdr_callhdr(&msg_xdr, mp)) + return -EIO; + + /* + * Called procedure number + */ + if (!xdr_enum(&msg_xdr, (enum_t *) & proc)) + return -EIO; + + /* + * Authorization + */ + if (!AUTH_MARSHALL(auth, &msg_xdr)) + return -EIO; + + /* + * Arguments + */ + if (!(*arg_xdr) (&msg_xdr, arg)) + return -EIO; + + /* + * Determine length + */ + len = xdr_getpos(&msg_xdr); + + /* + * Throw away xdr + */ + xdr_destroy(&msg_xdr); + + return len; +} diff --git a/contrib/amd/libamu/mount_fs.c b/contrib/amd/libamu/mount_fs.c new file mode 100644 index 0000000..948b18d --- /dev/null +++ b/contrib/amd/libamu/mount_fs.c @@ -0,0 +1,892 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: mount_fs.c,v 5.2.2.2 1992/05/31 16:35:45 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* ensure that mount table options are delimited by a comma */ +#define append_opts(old, new) { \ + if (*(old) != '\0') strcat(old, ","); \ + strcat(old, new); } + +/* + * Standard mount flags + */ +struct opt_tab mnt_flags[] = +{ +#if defined(MNT2_GEN_OPT_RDONLY) && defined(MNTTAB_OPT_RO) + {MNTTAB_OPT_RO, MNT2_GEN_OPT_RDONLY}, +#endif /* defined(MNT2_GEN_OPT_RDONLY) && defined(MNTTAB_OPT_RO) */ + +#if defined(MNT2_GEN_OPT_NOCACHE) && defined(MNTTAB_OPT_NOCACHE) + {MNTTAB_OPT_NOCACHE, MNT2_GEN_OPT_NOCACHE}, +#endif /* defined(MNT2_GEN_OPT_NOCACHE) && defined(MNTTAB_OPT_NOCACHE) */ + + /* the "grpid" mount option can be offered as generic of NFS */ +#ifdef MNTTAB_OPT_GRPID +# ifdef MNT2_GEN_OPT_GRPID + {MNTTAB_OPT_GRPID, MNT2_GEN_OPT_GRPID}, +# endif /* MNT2_GEN_OPT_GRPID */ +# ifdef MNT2_NFS_OPT_GRPID + {MNTTAB_OPT_GRPID, MNT2_NFS_OPT_GRPID}, +# endif /* MNT2_NFS_OPT_GRPID */ +#endif /* MNTTAB_OPT_GRPID */ + +#if defined(MNT2_GEN_OPT_MULTI) && defined(MNTTAB_OPT_MULTI) + {MNTTAB_OPT_MULTI, MNT2_GEN_OPT_MULTI}, +#endif /* defined(MNT2_GEN_OPT_MULTI) && defined(MNTTAB_OPT_MULTI) */ + +#if defined(MNT2_GEN_OPT_NODEV) && defined(MNTTAB_OPT_NODEV) + {MNTTAB_OPT_NODEV, MNT2_GEN_OPT_NODEV}, +#endif /* defined(MNT2_GEN_OPT_NODEV) && defined(MNTTAB_OPT_NODEV) */ + +#if defined(MNT2_GEN_OPT_NOEXEC) && defined(MNTTAB_OPT_NOEXEC) + {MNTTAB_OPT_NOEXEC, MNT2_GEN_OPT_NOEXEC}, +#endif /* defined(MNT2_GEN_OPT_NOEXEC) && defined(MNTTAB_OPT_NOEXEC) */ + +#if defined(MNT2_GEN_OPT_NOSUB) && defined(MNTTAB_OPT_NOSUB) + {MNTTAB_OPT_NOSUB, MNT2_GEN_OPT_NOSUB}, +#endif /* defined(MNT2_GEN_OPT_NOSUB) && defined(MNTTAB_OPT_NOSUB) */ + +#if defined(MNT2_GEN_OPT_NOSUID) && defined(MNTTAB_OPT_NOSUID) + {MNTTAB_OPT_NOSUID, MNT2_GEN_OPT_NOSUID}, +#endif /* defined(MNT2_GEN_OPT_NOSUID) && defined(MNTTAB_OPT_NOSUID) */ + +#if defined(MNT2_GEN_OPT_SYNC) && defined(MNTTAB_OPT_SYNC) + {MNTTAB_OPT_SYNC, MNT2_GEN_OPT_SYNC}, +#endif /* defined(MNT2_GEN_OPT_SYNC) && defined(MNTTAB_OPT_SYNC) */ + +#if defined(MNT2_GEN_OPT_OVERLAY) && defined(MNTTAB_OPT_OVERLAY) + {MNTTAB_OPT_OVERLAY, MNT2_GEN_OPT_OVERLAY}, +#endif /* defined(MNT2_GEN_OPT_OVERLAY) && defined(MNTTAB_OPT_OVERLAY) */ + + {0, 0} +}; + + +int +compute_mount_flags(mntent_t *mntp) +{ + struct opt_tab *opt; + int flags; + + /* start: this must come first */ +#ifdef MNT2_GEN_OPT_NEWTYPE + flags = MNT2_GEN_OPT_NEWTYPE; +#else /* not MNT2_GEN_OPT_NEWTYPE */ + /* Not all machines have MNT2_GEN_OPT_NEWTYPE (HP-UX 9.01) */ + flags = 0; +#endif /* not MNT2_GEN_OPT_NEWTYPE */ + +#if defined(MNT2_GEN_OPT_OVERLAY) && defined(MNTTAB_OPT_OVERLAY) + /* + * Overlay this amd mount (presumably on another amd which died + * before and left the machine hung). This will allow a new amd or + * hlfsd to be remounted on top of another one. + */ + if (hasmntopt(mntp, MNTTAB_OPT_OVERLAY)) { + flags |= MNT2_GEN_OPT_OVERLAY; + plog(XLOG_INFO, "using an overlay mount"); + } +#endif /* defined(MNT2_GEN_OVERLAY) && defined(MNTOPT_OVERLAY) */ + + /* + * Crack basic mount options + */ + for (opt = mnt_flags; opt->opt; opt++) { + flags |= hasmntopt(mntp, opt->opt) ? opt->flag : 0; + } + + return flags; +} + + +int +mount_fs(mntent_t *mnt, int flags, caddr_t mnt_data, int retry, MTYPE_TYPE type, u_long nfs_version, const char *nfs_proto, const char *mnttabname) +{ + int error = 0; +#ifdef MOUNT_TABLE_ON_FILE +# ifdef MNTTAB_OPT_DEV + struct stat stb; +# endif /* MNTTAB_OPT_DEV */ + char *zopts = NULL, *xopts = NULL; +# if defined(MNTTAB_OPT_DEV) || (defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS)) || defined(MNTTAB_OPT_PROTO) + char optsbuf[48]; +# endif /* defined(MNTTAB_OPT_DEV) || (defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS)) || defined(MNTTAB_OPT_PROTO) */ +#endif /* MOUNT_TABLE_ON_FILE */ +#ifdef DEBUG + char buf[80]; /* buffer for sprintf */ +#endif /* DEBUG */ + +#ifdef DEBUG + sprintf(buf, "%s%s%s", + "%s fstype ", MTYPE_PRINTF_TYPE, " (%s) flags %#x (%s)"); + dlog(buf, mnt->mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts); +#endif /* DEBUG */ + +again: + clock_valid = 0; + + error = MOUNT_TRAP(type, mnt, flags, mnt_data); + + if (error < 0) { + plog(XLOG_ERROR, "%s: mount: %m", mnt->mnt_dir); + /* + * The following code handles conditions which shouldn't + * occur. They are possible either because amd screws up + * in preparing for the mount, or because some human + * messed with the mount point. Both have been known to + * happen. -- stolcke 2/22/95 + */ + if (errno == ENOENT) { + /* + * Occasionally the mount point vanishes, probably + * due to some race condition. Just recreate it + * as necessary. + */ + errno = mkdirs(mnt->mnt_dir, 0555); + if (errno != 0 && errno != EEXIST) + plog(XLOG_ERROR, "%s: mkdirs: %m", mnt->mnt_dir); + else { + plog(XLOG_WARNING, "extra mkdirs required for %s", + mnt->mnt_dir); + error = MOUNT_TRAP(type, mnt, flags, mnt_data); + } + } else if (errno == EBUSY) { + /* + * Also, sometimes unmount isn't called, e.g., because + * our mountlist is garbled. This leaves old mount + * points around which need to be removed before we + * can mount something new in their place. + */ + errno = umount_fs(mnt->mnt_dir, mnttabname); + if (errno != 0) + plog(XLOG_ERROR, "%s: umount: %m", mnt->mnt_dir); + else { + plog(XLOG_WARNING, "extra umount required for %s", + mnt->mnt_dir); + error = MOUNT_TRAP(type, mnt, flags, mnt_data); + } + } + } + + if (error < 0 && --retry > 0) { + sleep(1); + goto again; + } + if (error < 0) { + return errno; + } + +#ifdef MOUNT_TABLE_ON_FILE + /* + * Allocate memory for options: + * dev=..., vers={2,3}, proto={tcp,udp} + */ + zopts = (char *) xmalloc(strlen(mnt->mnt_opts) + 48); + + /* copy standard options */ + xopts = mnt->mnt_opts; + + strcpy(zopts, xopts); + +# ifdef MNTTAB_OPT_DEV + /* add the extra dev= field to the mount table */ + if (lstat(mnt->mnt_dir, &stb) == 0) { + if (sizeof(stb.st_dev) == 2) /* e.g. SunOS 4.1 */ + sprintf(optsbuf, "%s=%04lx", + MNTTAB_OPT_DEV, (u_long) stb.st_dev & 0xffff); + else /* e.g. System Vr4 */ + sprintf(optsbuf, "%s=%08lx", + MNTTAB_OPT_DEV, (u_long) stb.st_dev); + append_opts(zopts, optsbuf); + } +# endif /* MNTTAB_OPT_DEV */ + +# if defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS) + /* + * add the extra vers={2,3} field to the mount table, + * unless already specified by user + */ + if (nfs_version == NFS_VERSION3 && + hasmntval(mnt, MNTTAB_OPT_VERS) != NFS_VERSION3) { + sprintf(optsbuf, "%s=%d", MNTTAB_OPT_VERS, NFS_VERSION3); + append_opts(zopts, optsbuf); + } +# endif /* defined(HAVE_FS_NFS3) && defined(MNTTAB_OPT_VERS) */ + +# ifdef MNTTAB_OPT_PROTO + /* + * add the extra proto={tcp,udp} field to the mount table, + * unless already specified by user. + */ + if (nfs_proto && !hasmntopt(mnt, MNTTAB_OPT_PROTO)) { + sprintf(optsbuf, "%s=%s", MNTTAB_OPT_PROTO, nfs_proto); + append_opts(zopts, optsbuf); + } +# endif /* MNTTAB_OPT_PROTO */ + + /* finally, store the options into the mount table structure */ + mnt->mnt_opts = zopts; + + /* + * Additional fields in mntent_t + * are fixed up here + */ +# ifdef HAVE_FIELD_MNTENT_T_MNT_CNODE + mnt->mnt_cnode = 0; +# endif /* HAVE_FIELD_MNTENT_T_MNT_CNODE */ + +# ifdef HAVE_FIELD_MNTENT_T_MNT_RO + mnt->mnt_ro = (hasmntopt(mnt, MNTTAB_OPT_RO) != NULL); +# endif /* HAVE_FIELD_MNTENT_T_MNT_RO */ + +# ifdef HAVE_FIELD_MNTENT_T_MNT_TIME +# ifdef HAVE_FIELD_MNTENT_T_MNT_TIME_STRING + { /* allocate enough space for a long */ + char *str = (char *) xmalloc(13 * sizeof(char)); + sprintf(str, "%ld", time((time_t *) NULL)); + mnt->mnt_time = str; + } +# else /* not HAVE_FIELD_MNTENT_T_MNT_TIME_STRING */ + mnt->mnt_time = time((time_t *) NULL); +# endif /* not HAVE_FIELD_MNTENT_T_MNT_TIME_STRING */ +# endif /* HAVE_FIELD_MNTENT_T_MNT_TIME */ + + write_mntent(mnt, mnttabname); + +# ifdef MNTTAB_OPT_DEV + if (xopts) { + XFREE(mnt->mnt_opts); + mnt->mnt_opts = xopts; + } +# endif /* MNTTAB_OPT_DEV */ +#endif /* MOUNT_TABLE_ON_FILE */ + + return 0; +} + + +/* + * Fill in the many possible fields and flags of struct nfs_args. + * + * nap: pre-allocted structure to fill in. + * mntp: mount entry structure (includes options) + * genflags: generic mount flags already determined + * nfsncp: (TLI only) netconfig entry for this NFS mount + * ip_addr: IP address of file server + * nfs_version: 2, 3, (4 in the future), or 0 if unknown + * nfs_proto: "udp", "tcp", or NULL. + * fhp: file handle structure pointer + * host_name: name of remote NFS host + * fs_name: remote file system name to mount + */ +void +#ifdef HAVE_TRANSPORT_TYPE_TLI +compute_nfs_args(nfs_args_t *nap, mntent_t *mntp, int genflags, struct netconfig *nfsncp, struct sockaddr_in *ip_addr, u_long nfs_version, char *nfs_proto, am_nfs_handle_t *fhp, char *host_name, char *fs_name) +#else /* not HAVE_TRANSPORT_TYPE_TLI */ +compute_nfs_args(nfs_args_t *nap, mntent_t *mntp, int genflags, struct sockaddr_in *ip_addr, u_long nfs_version, char *nfs_proto, am_nfs_handle_t *fhp, char *host_name, char *fs_name) +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ +{ + int acval = 0; +#ifdef HAVE_FS_NFS3 + static am_nfs_fh3 fh3; /* static, b/c gcc on aix corrupts stack */ +#endif /* HAVE_FS_NFS3 */ + + /* initialize just in case */ + memset((voidp) nap, 0, sizeof(nfs_args_t)); + + /************************************************************************/ + /*** FILEHANDLE DATA AND LENGTH ***/ + /************************************************************************/ +#ifdef HAVE_FS_NFS3 + if (nfs_version == NFS_VERSION3) { + memset((voidp) &fh3, 0, sizeof(am_nfs_fh3)); + fh3.fh3_length = fhp->v3.mountres3_u.mountinfo.fhandle.fhandle3_len; + memmove(fh3.fh3_u.data, + fhp->v3.mountres3_u.mountinfo.fhandle.fhandle3_val, + fh3.fh3_length); + +# if defined(HAVE_FIELD_NFS_ARGS_T_FHSIZE) || defined(HAVE_FIELD_NFS_ARGS_T_FH_LEN) + /* + * Some systems (Irix/bsdi3) have a separate field in nfs_args for + * the length of the file handle for NFS V3. They insist that + * the file handle set in nfs_args be plain bytes, and not + * include the length field. + */ + NFS_FH_DREF(nap->NFS_FH_FIELD, &(fh3.fh3_u.data)); +# else /* not defined(HAVE_FIELD_NFS_ARGS_T_FHSIZE) || defined(HAVE_FIELD_NFS_ARGS_T_FH_LEN) */ + NFS_FH_DREF(nap->NFS_FH_FIELD, &fh3); +# endif /* not defined(HAVE_FIELD_NFS_ARGS_T_FHSIZE) || defined(HAVE_FIELD_NFS_ARGS_T_FH_LEN) */ +# ifdef MNT2_NFS_OPT_NFSV3 + nap->flags |= MNT2_NFS_OPT_NFSV3; +# endif /* MNT2_NFS_OPT_NFSV3 */ + } else +#endif /* HAVE_FS_NFS3 */ + NFS_FH_DREF(nap->NFS_FH_FIELD, &(fhp->v2.fhs_fh)); + +#ifdef HAVE_FIELD_NFS_ARGS_T_FHSIZE +# ifdef HAVE_FS_NFS3 + if (nfs_version == NFS_VERSION3) + nap->fhsize = fh3.fh3_length; + else +# endif /* HAVE_FS_NFS3 */ + nap->fhsize = FHSIZE; +#endif /* HAVE_FIELD_NFS_ARGS_T_FHSIZE */ + + /* this is the version of the nfs_args structure, not of NFS! */ +#ifdef HAVE_FIELD_NFS_ARGS_T_FH_LEN +# ifdef HAVE_FS_NFS3 + if (nfs_version == NFS_VERSION3) + nap->fh_len = fh3.fh3_length; + else +# endif /* HAVE_FS_NFS3 */ + nap->fh_len = FHSIZE; +#endif /* HAVE_FIELD_NFS_ARGS_T_FH_LEN */ + + /************************************************************************/ + /*** HOST NAME ***/ + /************************************************************************/ + NFS_HN_DREF(nap->hostname, host_name); +#ifdef MNT2_NFS_OPT_HOSTNAME + nap->flags |= MNT2_NFS_OPT_HOSTNAME; +#endif /* MNT2_NFS_OPT_HOSTNAME */ + + /************************************************************************/ + /*** ATTRIBUTE CACHES ***/ + /************************************************************************/ + /* + * acval is set to 0 at the top of the function. If actimeo mount option + * exists and defined in mntopts, then it acval is set to it. + * If the value is non-zero, then we set all attribute cache fields to it. + * If acval is zero, it means it was never defined in mntopts or the + * actimeo mount option does not exist, in which case we check for + * individual mount options per attribute cache. + * Regardless of the value of acval, mount flags are set based directly + * on the values of the attribute caches. + */ +#ifdef MNTTAB_OPT_ACTIMEO + acval = hasmntval(mntp, MNTTAB_OPT_ACTIMEO); /* attr cache timeout (sec) */ +#endif /* MNTTAB_OPT_ACTIMEO */ + + if (acval) { +#ifdef HAVE_FIELD_NFS_ARGS_T_ACREGMIN + nap->acregmin = acval; /* min ac timeout for reg files (sec) */ + nap->acregmax = acval; /* max ac timeout for reg files (sec) */ +#endif /* HAVE_FIELD_NFS_ARGS_T_ACREGMIN */ +#ifdef HAVE_FIELD_NFS_ARGS_T_ACDIRMIN + nap->acdirmin = acval; /* min ac timeout for dirs (sec) */ + nap->acdirmax = acval; /* max ac timeout for dirs (sec) */ +#endif /* HAVE_FIELD_NFS_ARGS_T_ACDIRMIN */ + } else { +#ifdef MNTTAB_OPT_ACREGMIN + nap->acregmin = hasmntval(mntp, MNTTAB_OPT_ACREGMIN); +#endif /* MNTTAB_OPT_ACREGMIN */ +#ifdef MNTTAB_OPT_ACREGMAX + nap->acregmax = hasmntval(mntp, MNTTAB_OPT_ACREGMAX); +#endif /* MNTTAB_OPT_ACREGMAX */ +#ifdef MNTTAB_OPT_ACDIRMIN + nap->acdirmin = hasmntval(mntp, MNTTAB_OPT_ACDIRMIN); +#endif /* MNTTAB_OPT_ACDIRMIN */ +#ifdef MNTTAB_OPT_ACDIRMAX + nap->acdirmax = hasmntval(mntp, MNTTAB_OPT_ACDIRMAX); +#endif /* MNTTAB_OPT_ACDIRMAX */ + } /* end of "if (acval)" statement */ + +#ifdef MNT2_NFS_OPT_ACREGMIN + if (nap->acregmin) + nap->flags |= MNT2_NFS_OPT_ACREGMIN; +#endif /* MNT2_NFS_OPT_ACREGMIN */ +#ifdef MNT2_NFS_OPT_ACREGMAX + if (nap->acregmax) + nap->flags |= MNT2_NFS_OPT_ACREGMAX; +#endif /* MNT2_NFS_OPT_ACREGMAX */ +#ifdef MNT2_NFS_OPT_ACDIRMIN + if (nap->acdirmin) + nap->flags |= MNT2_NFS_OPT_ACDIRMIN; +#endif /* MNT2_NFS_OPT_ACDIRMIN */ +#ifdef MNT2_NFS_OPT_ACDIRMAX + if (nap->acdirmax) + nap->flags |= MNT2_NFS_OPT_ACDIRMAX; +#endif /* MNT2_NFS_OPT_ACDIRMAX */ + +#ifdef MNTTAB_OPT_NOAC /* don't cache attributes */ + if (hasmntopt(mntp, MNTTAB_OPT_NOAC) != NULL) + nap->flags |= MNT2_NFS_OPT_NOAC; +#endif /* MNTTAB_OPT_NOAC */ + + /************************************************************************/ + /*** IP ADDRESS OF REMOTE HOST ***/ + /************************************************************************/ + if (ip_addr) { +#ifdef HAVE_TRANSPORT_TYPE_TLI + nap->addr = ALLOC(struct netbuf); /* free()'ed at end of mount_nfs_fh() */ +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + NFS_SA_DREF(nap, ip_addr); + } + + /************************************************************************/ + /*** NFS PROTOCOL (UDP, TCP) AND VERSION ***/ + /************************************************************************/ +#ifdef MNT2_NFS_OPT_TCP + if (nfs_proto && STREQ(nfs_proto, "tcp")) + nap->flags |= MNT2_NFS_OPT_TCP; +#endif /* MNT2_NFS_OPT_TCP */ + +#ifdef HAVE_FIELD_NFS_ARGS_T_SOTYPE + /* bsdi3 uses this */ + if (nfs_proto) { + if (STREQ(nfs_proto, "tcp")) + nap->sotype = SOCK_STREAM; + else if (STREQ(nfs_proto, "udp")) + nap->sotype = SOCK_DGRAM; + } +#endif /* HAVE_FIELD_NFS_ARGS_T_SOTYPE */ + +#ifdef HAVE_FIELD_NFS_ARGS_T_PROTO + nap->proto = 0; /* bsdi3 sets this field to zero */ +# ifdef IPPROTO_TCP + if (nfs_proto) { + if (STREQ(nfs_proto, "tcp")) /* AIX 4.2.x needs this */ + nap->proto = IPPROTO_TCP; + else if (STREQ(nfs_proto, "udp")) + nap->proto = IPPROTO_UDP; + } +# endif /* IPPROTO_TCP */ +#endif /* HAVE_FIELD_NFS_ARGS_T_SOTYPE */ + +#ifdef HAVE_FIELD_NFS_ARGS_T_VERSION +# ifdef NFS_ARGSVERSION + nap->version = NFS_ARGSVERSION; /* BSDI 3.0 and OpenBSD 2.2 */ +# endif /* NFS_ARGSVERSION */ +# ifdef DG_MOUNT_NFS_VERSION + nap->version = DG_MOUNT_NFS_VERSION; /* dg-ux */ +# endif /* DG_MOUNT_NFS_VERSION */ +#endif /* HAVE_FIELD_NFS_ARGS_VERSION */ + + /************************************************************************/ + /*** OTHER NFS SOCKET RELATED OPTIONS AND FLAGS ***/ + /************************************************************************/ +#ifdef MNT2_NFS_OPT_NOCONN + /* check if user specified to use unconnected or connected sockets */ + if (hasmntopt(mntp, MNTTAB_OPT_NOCONN) != NULL) + nap->flags |= MNT2_NFS_OPT_NOCONN; + else if (hasmntopt(mntp, MNTTAB_OPT_CONN) != NULL) + nap->flags &= ~MNT2_NFS_OPT_NOCONN; + else { + /* + * Some OSs want you to set noconn always. Some want you to always turn + * it off. Others want you to turn it on/off only if NFS V.3 is used. + * And all of that changes from revision to another. This is + * particularly true of OpenBSD, NetBSD, and FreeBSD. So, rather than + * attempt to auto-detect this, I'm forced to "fix" it in the individual + * conf/nfs_prot/nfs_prot_*.h files. + */ +# ifdef USE_UNCONNECTED_NFS_SOCKETS + nap->flags |= MNT2_NFS_OPT_NOCONN; + plog(XLOG_WARNING, "noconn option exists, and was turned ON! (May cause NFS hangs on some systems...)"); +# endif /* USE_UNCONNECTED_NFS_SOCKETS */ +# ifdef USE_CONNECTED_NFS_SOCKETS + nap->flags &= ~MNT2_NFS_OPT_NOCONN; + plog(XLOG_WARNING, "noconn option exists, and was turned OFF! (May cause NFS hangs on some systems...)"); +# endif /* USE_CONNECTED_NFS_SOCKETS */ + } +#endif /* MNT2_NFS_OPT_NOCONN */ + +#ifdef MNT2_NFS_OPT_RESVPORT +# ifdef MNTTAB_OPT_RESVPORT + if (hasmntopt(mntp, MNTTAB_OPT_RESVPORT) != NULL) + nap->flags |= MNT2_NFS_OPT_RESVPORT; +# else /* not MNTTAB_OPT_RESVPORT */ + nap->flags |= MNT2_NFS_OPT_RESVPORT; +# endif /* not MNTTAB_OPT_RESVPORT */ +#endif /* MNT2_NFS_OPT_RESVPORT */ + + /************************************************************************/ + /*** OTHER FLAGS AND OPTIONS ***/ + /************************************************************************/ + +#ifdef HAVE_TRANSPORT_TYPE_TLI + /* set up syncaddr field */ + nap->syncaddr = (struct netbuf *) NULL; + + /* set up knconf field */ + if (get_knetconfig(&nap->knconf, nfsncp, nfs_proto) < 0) { + plog(XLOG_FATAL, "cannot fill knetconfig structure for nfs_args"); + going_down(1); + } + /* update the flags field for knconf */ + nap->flags |= MNT2_NFS_OPT_KNCONF; +#endif /* HAVE_TRANSPORT_TYPE_TLI */ + +#ifdef MNT2_NFS_OPT_FSNAME + nap->fsname = fs_name; + nap->flags |= MNT2_NFS_OPT_FSNAME; +#endif /* MNT2_NFS_OPT_FSNAME */ + + nap->rsize = hasmntval(mntp, MNTTAB_OPT_RSIZE); +#ifdef MNT2_NFS_OPT_RSIZE + if (nap->rsize) + nap->flags |= MNT2_NFS_OPT_RSIZE; +#endif /* MNT2_NFS_OPT_RSIZE */ + + nap->wsize = hasmntval(mntp, MNTTAB_OPT_WSIZE); +#ifdef MNT2_NFS_OPT_WSIZE + if (nap->wsize) + nap->flags |= MNT2_NFS_OPT_WSIZE; +#endif /* MNT2_NFS_OPT_WSIZE */ + + nap->timeo = hasmntval(mntp, MNTTAB_OPT_TIMEO); +#ifdef MNT2_NFS_OPT_TIMEO + if (nap->timeo) + nap->flags |= MNT2_NFS_OPT_TIMEO; +#endif /* MNT2_NFS_OPT_TIMEO */ + + nap->retrans = hasmntval(mntp, MNTTAB_OPT_RETRANS); +#ifdef MNT2_NFS_OPT_RETRANS + if (nap->retrans) + nap->flags |= MNT2_NFS_OPT_RETRANS; +#endif /* MNT2_NFS_OPT_RETRANS */ + +#ifdef MNT2_NFS_OPT_BIODS + if ((nap->biods = hasmntval(mntp, MNTTAB_OPT_BIODS))) + nap->flags |= MNT2_NFS_OPT_BIODS; +#endif /* MNT2_NFS_OPT_BIODS */ + + if (hasmntopt(mntp, MNTTAB_OPT_SOFT) != NULL) + nap->flags |= MNT2_NFS_OPT_SOFT; + +#ifdef MNT2_NFS_OPT_SPONGY + if (hasmntopt(mntp, MNTTAB_OPT_SPONGY) != NULL) { + nap->flags |= MNT2_NFS_OPT_SPONGY; + if (nap->flags & MNT2_NFS_OPT_SOFT) { + plog(XLOG_USER, "Mount opts soft and spongy are incompatible - soft ignored"); + nap->flags &= ~MNT2_NFS_OPT_SOFT; + } + } +#endif /* MNT2_NFS_OPT_SPONGY */ + +#if defined(MNT2_GEN_OPT_RONLY) && defined(MNT2_NFS_OPT_RONLY) + /* Ultrix has separate generic and NFS ro flags */ + if (genflags & MNT2_GEN_OPT_RONLY) + nap->flags |= MNT2_NFS_OPT_RONLY; +#endif /* defined(MNT2_GEN_OPT_RONLY) && defined(MNT2_NFS_OPT_RONLY) */ + +#ifdef MNTTAB_OPT_INTR + if (hasmntopt(mntp, MNTTAB_OPT_INTR) != NULL) + /* + * Either turn on the "allow interrupts" option, or + * turn off the "disallow interrupts" option" + */ +# ifdef MNT2_NFS_OPT_INT + nap->flags |= MNT2_NFS_OPT_INT; +# endif /* MNT2_NFS_OPT_INT */ +# ifdef MNT2_NFS_OPT_NOINT + nap->flags &= ~MNT2_NFS_OPT_NOINT; +# endif /* MNT2_NFS_OPT_NOINT */ +#endif /* MNTTAB_OPT_INTR */ + +#ifdef MNTTAB_OPT_NODEVS + if (hasmntopt(mntp, MNTTAB_OPT_NODEVS) != NULL) + nap->flags |= MNT2_NFS_OPT_NODEVS; +#endif /* MNTTAB_OPT_NODEVS */ + +#ifdef MNTTAB_OPT_COMPRESS + if (hasmntopt(mntp, MNTTAB_OPT_COMPRESS) != NULL) + nap->flags |= MNT2_NFS_OPT_COMPRESS; +#endif /* MNTTAB_OPT_COMPRESS */ + +#ifdef MNTTAB_OPT_PRIVATE /* mount private, single-client tree */ + if (hasmntopt(mntp, MNTTAB_OPT_PRIVATE) != NULL) + nap->flags |= MNT2_NFS_OPT_PRIVATE; +#endif /* MNTTAB_OPT_PRIVATE */ + +#ifdef MNTTAB_OPT_SYMTTL /* symlink cache time-to-live */ + if ((nap->symttl = hasmntval(mntp, MNTTAB_OPT_SYMTTL))) + nap->flags |= MNT2_NFS_OPT_SYMTTL; +#endif /* MNTTAB_OPT_SYMTTL */ + +#ifdef MNT2_NFS_OPT_PGTHRESH /* paging threshold */ + if ((nap->pg_thresh = hasmntval(mntp, MNTTAB_OPT_PGTHRESH))) + nap->flags |= MNT2_NFS_OPT_PGTHRESH; +#endif /* MNT2_NFS_OPT_PGTHRESH */ + +#if defined(MNT2_NFS_OPT_NOCTO) && defined(MNTTAB_OPT_NOCTO) + if (hasmntopt(mntp, MNTTAB_OPT_NOCTO) != NULL) + nap->flags |= MNT2_NFS_OPT_NOCTO; +#endif /* defined(MNT2_NFS_OPT_NOCTO) && defined(MNTTAB_OPT_NOCTO) */ + +#if defined(MNT2_NFS_OPT_POSIX) && defined(MNTTAB_OPT_POSIX) + if (hasmntopt(mntp, MNTTAB_OPT_POSIX) != NULL) { + nap->flags |= MNT2_NFS_OPT_POSIX; + nap->pathconf = NULL; + } +#endif /* MNT2_NFS_OPT_POSIX && MNTTAB_OPT_POSIX */ + +#if defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS) + nap->maxgrouplist = hasmntval(mntp, MNTTAB_OPT_MAXGROUPS); + if (nap->maxgrouplist != NULL) + nap->flags |= MNT2_NFS_OPT_MAXGRPS; +#endif /* defined(MNT2_NFS_OPT_MAXGRPS) && defined(MNTTAB_OPT_MAXGROUPS) */ + +#ifdef HAVE_FIELD_NFS_ARGS_T_OPTSTR + nap->optstr = mntp->mnt_opts; +#endif /* HAVE_FIELD_NFS_ARGS_T_OPTSTR */ + + /************************************************************************/ + /*** FINAL ACTIONS ***/ + /************************************************************************/ + +#ifdef HAVE_FIELD_NFS_ARGS_T_GFS_FLAGS + /* Ultrix stores generic flags in nfs_args.gfs_flags. */ + nap->gfs_flags = genflags; +#endif /* HAVE_FIELD_NFS_ARGS_T_FLAGS */ + + return; /* end of compute_nfs_args() function */ +} + + +/* + * Fill in special values for flags and fields of nfs_args, for an + * automounter NFS mount. + */ +void +compute_automounter_nfs_args(nfs_args_t *nap, mntent_t *mntp) +{ +#ifdef MNT2_NFS_OPT_SYMTTL + /* + * Don't let the kernel cache symbolic links we generate, or else lookups + * will bypass amd and fail to remount stuff as needed. + */ + plog(XLOG_INFO, "turning on NFS option symttl and setting value to %d", 0); + nap->flags |= MNT2_NFS_OPT_SYMTTL; + nap->symttl = 0; +#endif /* MNT2_NFS_OPT_SYMTTL */ + + /* + * This completes the flags for the HIDE_MOUNT_TYPE code above. + * Some systems don't have a mount type, but a mount flag. + */ +#ifdef MNT2_NFS_OPT_AUTO + nap->flags |= MNT2_NFS_OPT_AUTO; +#endif /* MNT2_NFS_OPT_AUTO */ +#ifdef MNT2_NFS_OPT_IGNORE + nap->flags |= MNT2_NFS_OPT_IGNORE; +#endif /* MNT2_NFS_OPT_IGNORE */ + +#ifdef MNT2_NFS_OPT_DUMBTIMR + /* + * Don't let the kernel start computing throughput of Amd The numbers will + * be meaningless because of the way Amd does mount retries. + */ + plog(XLOG_INFO, "%s: disabling nfs congestion window", mntp->mnt_dir); + nap->flags |= MNT2_NFS_OPT_DUMBTIMR; +#endif /* MNT2_NFS_OPT_DUMBTIMR */ + +#ifdef MNT2_NFS_OPT_NOAC + /* + * Don't cache attributes - they are changing under the kernel's feet. + * For example, IRIX5.2 will dispense with nfs lookup calls and hand stale + * filehandles to getattr unless we disable attribute caching on the + * automount points. + */ + nap->flags |= MNT2_NFS_OPT_NOAC; +#else /* not MNT2_NFS_OPT_NOAC */ + /* + * Setting these to 0 results in an error on some systems, which is why + * it's better to use "noac" if possible. + */ +# if defined(MNT2_NFS_OPT_ACREGMIN) && defined(MNT2_NFS_OPT_ACREGMAX) + nap->acregmin = nap->acregmax = 0; /* XXX: was 1, but why? */ + nap->flags |= MNT2_NFS_OPT_ACREGMIN | MNT2_NFS_OPT_ACREGMAX; +# endif /* defined(MNT2_NFS_OPT_ACREGMIN) && defined(MNT2_NFS_OPT_ACREGMAX) */ +# if defined(MNT2_NFS_OPT_ACDIRMIN) && defined(MNT2_NFS_OPT_ACDIRMAX) + nap->acdirmin = nap->acdirmax = 0; /* XXX: was 1, but why? */ + nap->flags |= MNT2_NFS_OPT_ACDIRMIN | MNT2_NFS_OPT_ACDIRMAX; +# endif /* defined(MNT2_NFS_OPT_ACDIRMIN) && defined(MNT2_NFS_OPT_ACDIRMAX) */ +#endif /* not MNT2_NFS_OPT_NOAC */ +} + + +#ifdef DEBUG +/* get string version (in hex) of identifier */ +static char * +get_hex_string(u_int len, const char *fhdata) +{ + int i; + static char buf[128]; /* better not go over it! */ + char str[16]; + short int arr[64]; + + if (!fhdata) + return NULL; + buf[0] = '\0'; + memset(&arr[0], 0, (64 * sizeof(short int))); + memcpy(&arr[0], &fhdata[0], len); + for (i=0; iaddr; + plog(XLOG_DEBUG, "NA->addr {netbuf} (maxlen=%d, len=%d) = \"%s\"", + nbp->maxlen, nbp->len, + get_hex_string(nbp->len, nbp->buf)); + nbp = nap->syncaddr; + plog(XLOG_DEBUG, "NA->syncaddr {netbuf} 0x%x", (int) nbp); + kncp = nap->knconf; + plog(XLOG_DEBUG, "NA->knconf->semantics %lu", kncp->knc_semantics); + plog(XLOG_DEBUG, "NA->knconf->protofmly \"%s\"", kncp->knc_protofmly); + plog(XLOG_DEBUG, "NA->knconf->proto \"%s\"", kncp->knc_proto); + plog(XLOG_DEBUG, "NA->knconf->rdev %lu", kncp->knc_rdev); + /* don't print knconf->unused field */ +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + sap = (struct sockaddr_in *) &nap->addr; + plog(XLOG_DEBUG, "NA->addr {sockaddr_in} (len=%d) = \"%s\"", + sizeof(struct sockaddr_in), + get_hex_string(sizeof(struct sockaddr_in), (const char *)sap)); +#ifdef HAVE_FIELD_STRUCT_SOCKADDR_SA_LEN_off + plog(XLOG_DEBUG, "NA->addr.sin_len = \"%d\"", sap->sin_len); +#endif /* HAVE_FIELD_STRUCT_SOCKADDR_SA_LEN */ + plog(XLOG_DEBUG, "NA->addr.sin_family = \"%d\"", sap->sin_family); + plog(XLOG_DEBUG, "NA->addr.sin_port = \"%d\"", sap->sin_port); + plog(XLOG_DEBUG, "NA->addr.sin_addr = \"%s\"", + get_hex_string(sizeof(struct in_addr), (const char *) &sap->sin_addr)); +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + plog(XLOG_DEBUG, "NA->hostname = \"%s\"", nap->hostname ? nap->hostname : "null"); +#ifdef MNT2_NFS_OPT_FSNAME + plog(XLOG_DEBUG, "NA->fsname = \"%s\"", nap->fsname ? nap->fsname : "null"); +#endif /* MNT2_NFS_OPT_FSNAME */ + +#ifdef HAVE_FIELD_NFS_ARGS_T_FHSIZE + plog(XLOG_DEBUG, "NA->fhsize = %d", nap->fhsize); + fhlen = nap->fhsize; +#endif /* HAVE_FIELD_NFS_ARGS_T_FHSIZE */ +#ifdef HAVE_FIELD_NFS_ARGS_T_FH_LEN + plog(XLOG_DEBUG, "NA->fh_len = %d", nap->fh_len); + fhlen = nap->fh_len; +#endif /* HAVE_FIELD_NFS_ARGS_T_FH_LEN */ + + /* + * XXX: need to figure out how to correctly print file handles, + * since some times they are pointers, and sometimes the real structure + * is stored in nfs_args. Even if it is a pointer, it can be the actual + * char[] array, or a structure containing multiple fields. + */ + plog(XLOG_DEBUG, "NA->filehandle = \"%s\"", + get_hex_string(fhlen, (const char *) &nap->NFS_FH_FIELD)); + +#ifdef HAVE_FIELD_NFS_ARGS_T_SOTYPE + plog(XLOG_DEBUG, "NA->sotype = %d", nap->sotype); +#endif /* HAVE_FIELD_NFS_ARGS_T_SOTYPE */ +#ifdef HAVE_FIELD_NFS_ARGS_T_PROTO + plog(XLOG_DEBUG, "NA->proto = %d", nap->proto); +#endif /* HAVE_FIELD_NFS_ARGS_T_PROTO */ +#ifdef HAVE_FIELD_NFS_ARGS_T_VERSION + plog(XLOG_DEBUG, "NA->version = %d", nap->version); +#endif /* HAVE_FIELD_NFS_ARGS_T_VERSION */ + + plog(XLOG_DEBUG, "NA->flags = 0x%x", nap->flags); + + plog(XLOG_DEBUG, "NA->rsize = %d", nap->rsize); + plog(XLOG_DEBUG, "NA->wsize = %d", nap->wsize); + plog(XLOG_DEBUG, "NA->timeo = %d", nap->timeo); + plog(XLOG_DEBUG, "NA->retrans = %d", nap->retrans); + +#ifdef HAVE_FIELD_NFS_ARGS_T_ACREGMIN + plog(XLOG_DEBUG, "NA->acregmin = %d", nap->acregmin); + plog(XLOG_DEBUG, "NA->acregmax = %d", nap->acregmax); + plog(XLOG_DEBUG, "NA->acdirmin = %d", nap->acdirmin); + plog(XLOG_DEBUG, "NA->acdirmax = %d", nap->acdirmax); +#endif /* HAVE_FIELD_NFS_ARGS_T_ACREGMIN */ +#ifdef MNTTAB_OPT_SYMTTL + plog(XLOG_DEBUG, "NA->symttl = %d", nap->symttl); +#endif /* MNTTAB_OPT_SYMTTL */ +#ifdef MNTTAB_OPT_PG_THRESH + plog(XLOG_DEBUG, "NA->pg_thresh = %d", nap->pg_thresh); +#endif /* MNTTAB_OPT_PG_THRESH */ + +#ifdef MNT2_NFS_OPT_BIODS + plog(XLOG_DEBUG, "NA->biods = %d", nap->biods); +#endif /* MNT2_NFS_OPT_BIODS */ + +} +#endif /* DEBUG */ diff --git a/contrib/amd/libamu/mtab.c b/contrib/amd/libamu/mtab.c new file mode 100644 index 0000000..20cae62 --- /dev/null +++ b/contrib/amd/libamu/mtab.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: mtab.c,v 5.2.2.1 1992/02/09 15:08:45 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* + * Firewall /etc/mtab entries + */ +void +mnt_free(mntent_t *mp) +{ + XFREE(mp->mnt_fsname); + XFREE(mp->mnt_dir); + XFREE(mp->mnt_type); + XFREE(mp->mnt_opts); + +#ifdef HAVE_FIELD_MNTENT_T_MNT_TIME +# ifdef HAVE_FIELD_MNTENT_T_MNT_TIME_STRING + XFREE(mp->mnt_time); +# endif /* HAVE_FIELD_MNTENT_T_MNT_TIME_STRING */ +#endif /* HAVE_FIELD_MNTENT_T_MNT_TIME */ + + XFREE(mp); +} + + +/* + * Discard memory allocated for mount list + */ +void +discard_mntlist(mntlist *mp) +{ + mntlist *mp2; + + while ((mp2 = mp)) { + mp = mp->mnext; + if (mp2->mnt) + mnt_free(mp2->mnt); + XFREE(mp2); + } +} + + +/* + * Throw away a mount list + */ +void +free_mntlist(mntlist *mp) +{ + discard_mntlist(mp); +#ifdef MOUNT_TABLE_ON_FILE + unlock_mntlist(); +#endif /* MOUNT_TABLE_ON_FILE */ +} + + +/* + * Utility routine which determines the value of a + * numeric option in the mount options (such as port=%d). + * Returns 0 if the option is not specified. + */ +int +hasmntval(mntent_t *mnt, char *opt) +{ + char *str = hasmntopt(mnt, opt); + + if (str) { + char *eq = strchr(str, '='); + if (eq) + return atoi(eq + 1); + else + plog(XLOG_USER, "bad numeric option \"%s\" in \"%s\"", opt, str); + } + return 0; +} diff --git a/contrib/amd/libamu/nfs_prot_xdr.c b/contrib/amd/libamu/nfs_prot_xdr.c new file mode 100644 index 0000000..2098b5d --- /dev/null +++ b/contrib/amd/libamu/nfs_prot_xdr.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1989 Jan-Simon Pendry + * Copyright (c) 1989 Imperial College of Science, Technology & Medicine + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: nfs_prot_xdr.c,v 5.2.2.1 1992/02/09 15:09:32 jsp beta $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +bool_t +xdr_amq_string(XDR *xdrs, amq_string *objp) +{ + if (!xdr_string(xdrs, objp, AMQ_STRLEN)) { + return (FALSE); + } + return (TRUE); +} diff --git a/contrib/amd/libamu/util.c b/contrib/amd/libamu/util.c new file mode 100644 index 0000000..1198347 --- /dev/null +++ b/contrib/amd/libamu/util.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: util.c,v 5.2.2.2 1992/03/07 17:52:06 jsp Exp $ + * + */ + +/* + * General Utilitiles. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +char * +strnsave(const char *str, int len) +{ + char *sp = (char *) xmalloc(len + 1); + memmove(sp, str, len); + sp[len] = 0; + + return sp; +} + + +/* + * Concatenate three strings and store in buffer pointed to + * by p, making p large enough to hold the strings + */ +char * +str3cat(char *p, char *s1, char *s2, char *s3) +{ + int l1 = strlen(s1); + int l2 = strlen(s2); + int l3 = strlen(s3); + + p = (char *) xrealloc(p, l1 + l2 + l3 + 1); + memmove(p, s1, l1); + memmove(p + l1, s2, l2); + memmove(p + l1 + l2, s3, l3 + 1); + return p; +} + + +/* + * Make all the directories in the path. + */ +int +mkdirs(char *path, int mode) +{ + /* + * take a copy in case path is in readonly store + */ + char *p2 = strdup(path); + char *sp = p2; + struct stat stb; + int error_so_far = 0; + + /* + * Skip through the string make the directories. + * Mostly ignore errors - the result is tested at the end. + * + * This assumes we are root so that we can do mkdir in a + * mode 555 directory... + */ + while ((sp = strchr(sp + 1, '/'))) { + *sp = '\0'; + if (mkdir(p2, mode) < 0) { + error_so_far = errno; + } else { +#ifdef DEBUG + dlog("mkdir(%s)", p2); +#endif /* DEBUG */ + } + *sp = '/'; + } + + if (mkdir(p2, mode) < 0) { + error_so_far = errno; + } else { +#ifdef DEBUG + dlog("mkdir(%s)", p2); +#endif /* DEBUG */ + } + + XFREE(p2); + + return stat(path, &stb) == 0 && + (stb.st_mode & S_IFMT) == S_IFDIR ? 0 : error_so_far; +} + + +/* + * Remove as many directories in the path as possible. + * Give up if the directory doesn't appear to have + * been created by Amd (not mode dr-x) or an rmdir + * fails for any reason. + */ +void +rmdirs(char *dir) +{ + char *xdp = strdup(dir); + char *dp; + + do { + struct stat stb; + /* + * Try to find out whether this was + * created by amd. Do this by checking + * for owner write permission. + */ + if (stat(xdp, &stb) == 0 && (stb.st_mode & 0200) == 0) { + if (rmdir(xdp) < 0) { + if (errno != ENOTEMPTY && + errno != EBUSY && + errno != EEXIST && + errno != EINVAL) + plog(XLOG_ERROR, "rmdir(%s): %m", xdp); + break; + } else { +#ifdef DEBUG + dlog("rmdir(%s)", xdp); +#endif /* DEBUG */ + } + } else { + break; + } + + dp = strrchr(xdp, '/'); + if (dp) + *dp = '\0'; + } while (dp && dp > xdp); + + XFREE(xdp); +} diff --git a/contrib/amd/libamu/wire.c b/contrib/amd/libamu/wire.c new file mode 100644 index 0000000..f610f92 --- /dev/null +++ b/contrib/amd/libamu/wire.c @@ -0,0 +1,404 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: wire.c,v 5.2.2.2 1992/06/07 18:06:46 jsp Exp jsp $ + * + */ + +/* + * This function returns the subnet (address&netmask) for the primary network + * interface. If the resulting address has an entry in the hosts file, the + * corresponding name is retuned, otherwise the address is returned in + * standard internet format. + * As a side-effect, a list of local IP/net address is recorded for use + * by the islocalnet() function. + * + * Derived from original by Paul Anderson (23/4/90) + * Updates from Dirk Grunwald (11/11/91) + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + + +/* + * List of locally connected networks + */ +typedef struct addrlist addrlist; +struct addrlist { + addrlist *ip_next; + u_long ip_addr; /* address of network */ + u_long ip_mask; + char *ip_net_num; /* number of network */ + char *ip_net_name; /* name of network */ +}; +static addrlist *localnets = NULL; + +#if defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK) +# define IFF_LOOPBACK IFF_LOCAL_LOOPBACK +#endif /* defined(IFF_LOCAL_LOOPBACK) && !defined(IFF_LOOPBACK) */ + +#if defined(HAVE_FIELD_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_FIELD_STRUCT_SOCKADDR_SA_LEN) +# define SIZE(ifr) (MAX((ifr)->ifr_addr.sa_len, sizeof((ifr)->ifr_addr)) + sizeof(ifr->ifr_name)) +#else /* not defined(HAVE_FIELD_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_FIELD_STRUCT_SOCKADDR_SA_LEN) */ +# define SIZE(ifr) sizeof(struct ifreq) +#endif /* not defined(HAVE_FIELD_STRUCT_IFREQ_IFR_ADDR) && defined(HAVE_FIELD_STRUCT_SOCKADDR_SA_LEN) */ + +#define C(x) ((x) & 0xff) +#define GFBUFLEN 1024 +#define clist (ifc.ifc_ifcu.ifcu_req) +#define count (ifc.ifc_len/sizeof(struct ifreq)) + + +/* return malloc'ed buffer. caller must free it */ +char * +print_wires(void) +{ + addrlist *al; + char s[256]; + int i; + char *buf; + int bufcount = 0; + int buf_size = 1024; + + buf = malloc(1024); + if (!buf) + return NULL; + + if (!localnets) { + sprintf(buf, "No networks.\n"); + return buf; + } + /* check if there's more than one network */ + if (!localnets->ip_next) { + sprintf(buf, + "Network: wire=\"%s\" (netnumber=%s).\n", + localnets->ip_net_name, localnets->ip_net_num); + return buf; + } + buf[0] = '\0'; /* null out buffer before appending */ + for (i = 1, al = localnets; al; al = al->ip_next, i++) { + sprintf(s, "Network %d: wire=\"%s\" (netnumber=%s).\n", + i, al->ip_net_name, al->ip_net_num); + bufcount += strlen(s); + if (bufcount > buf_size) { + buf_size *= 2; + buf = xrealloc(buf, buf_size); + } + strcat(buf, s); + } + return buf; +} + + +void +getwire(char **name1, char **number1) +{ + struct hostent *hp; + struct netent *np; + struct ifconf ifc; + struct ifreq *ifr; + caddr_t cp, cplim; + u_long address, netmask, subnet; + char buf[GFBUFLEN], *s; + int fd = -1; + u_long net; + u_long mask; + u_long subnetshift; + char netNumberBuf[64]; + addrlist *al = NULL, *tail = NULL; + +#ifndef SIOCGIFFLAGS + /* if cannot get interface flags, return nothing */ + plog(XLOG_ERROR, "getwire unable to get interface flags"); + localnets = NULL; + return; +#endif /* not SIOCGIFFLAGS */ + + /* + * Get suitable socket + */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + goto out; + + /* + * Fill in ifconf details + */ + memset(&buf[0], 0, GFBUFLEN); + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + + /* + * Get network interface configurations + */ + if (ioctl(fd, SIOCGIFCONF, (caddr_t) & ifc) < 0) + goto out; + + /* + * Upper bound on array + */ + cplim = buf + ifc.ifc_len; + + /* + * This is some magic to cope with both "traditional" and the + * new 4.4BSD-style struct sockaddrs. The new structure has + * variable length and a size field to support longer addresses. + * AF_LINK is a new definition for 4.4BSD. + */ + + /* + * Scan the list looking for a suitable interface + */ + for (cp = buf; cp < cplim; cp += SIZE(ifr)) { + ifr = (struct ifreq *) cp; + + if (ifr->ifr_addr.sa_family != AF_INET) + continue; + else + address = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; + + /* + * Get interface flags + */ + if (ioctl(fd, SIOCGIFFLAGS, (caddr_t) ifr) < 0) + continue; + + /* + * If the interface is a loopback, or its not running + * then ignore it. + */ +#ifdef IFF_LOOPBACK + if ((ifr->ifr_flags & IFF_LOOPBACK) != 0) + continue; +#endif /* IFF_LOOPBACK */ + /* + * Fix for 0.0.0.0 loopback on SunOS 3.X which defines IFF_ROUTE + * instead of IFF_LOOPBACK. + */ +#ifdef IFF_ROUTE + if (ifr->ifr_flags == (IFF_UP|IFF_RUNNING)) + continue; +#endif /* IFF_ROUTE */ + + /* if the interface is not UP or not RUNNING, skip it */ + if ((ifr->ifr_flags & IFF_RUNNING) == 0 || + (ifr->ifr_flags & IFF_UP) == 0) + continue; + + /* + * Get the netmask of this interface + */ + if (ioctl(fd, SIOCGIFNETMASK, (caddr_t) ifr) < 0) + continue; + + netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; + + /* + * Add interface to local network singly linked list + */ + al = ALLOC(struct addrlist); + al->ip_addr = address; + al->ip_mask = netmask; + al->ip_net_name = NO_SUBNET; /* fill in a bit later */ + al->ip_net_num = "0.0.0.0"; /* fill in a bit later */ + al->ip_next = NULL; + /* append to the end of the list */ + if (!localnets) { + localnets = tail = al; + tail->ip_next = NULL; + } else { + tail->ip_next = al; + tail = al; + } + + /* + * Figure out the subnet's network address + */ + subnet = address & netmask; + +#ifdef IN_CLASSA + subnet = htonl(subnet); + + if (IN_CLASSA(subnet)) { + mask = IN_CLASSA_NET; + subnetshift = 8; + } else if (IN_CLASSB(subnet)) { + mask = IN_CLASSB_NET; + subnetshift = 8; + } else { + mask = IN_CLASSC_NET; + subnetshift = 4; + } + + /* + * If there are more bits than the standard mask + * would suggest, subnets must be in use. + * Guess at the subnet mask, assuming reasonable + * width subnet fields. + * XXX: Or-in at least 1 byte's worth of 1s to make + * sure the top bits remain set. + */ + while (subnet & ~mask) + mask = (mask >> subnetshift) | 0xff000000; + + net = subnet & mask; + while ((mask & 1) == 0) + mask >>= 1, net >>= 1; + + /* + * Now get a usable name. + * First use the network database, + * then the host database, + * and finally just make a dotted quad. + */ + np = getnetbyaddr(net, AF_INET); + + /* the network address has been masked off */ + if ((subnet & 0xffffff) == 0) { + sprintf(netNumberBuf, "%lu", C(subnet >> 24)); + } else if ((subnet & 0xffff) == 0) { + sprintf(netNumberBuf, "%lu.%lu", + C(subnet >> 24), C(subnet >> 16)); + } else if ((subnet & 0xff) == 0) { + sprintf(netNumberBuf, "%lu.%lu.%lu", + C(subnet >> 24), C(subnet >> 16), + C(subnet >> 8)); + } else { + sprintf(netNumberBuf, "%lu.%lu.%lu.%lu", + C(subnet >> 24), C(subnet >> 16), + C(subnet >> 8), C(subnet)); + } + + /* fill in network number (string) */ + al->ip_net_num = strdup(netNumberBuf); + +#else /* not IN_CLASSA */ + /* This is probably very wrong. */ + np = getnetbyaddr(subnet, AF_INET); +#endif /* not IN_CLASSA */ + + if (np) + s = np->n_name; + else { + subnet = address & netmask; + hp = gethostbyaddr((char *) &subnet, 4, AF_INET); + if (hp) + s = (char *) hp->h_name; + else + s = inet_dquad(buf, subnet); + } + + /* fill in network name (string) */ + al->ip_net_name = strdup(s); + } + +out: + if (fd >= 0) + close(fd); + if (localnets) { + *name1 = localnets->ip_net_name; + *number1 = localnets->ip_net_num; + } else { + *name1 = NO_SUBNET; + *number1 = "0.0.0.0"; + } +} + + +/* + * Make a dotted quad from a 32bit IP address + * addr is in network byte order. + * sizeof(buf) needs to be at least 16. + */ +char * +inet_dquad(char *buf, u_long addr) +{ + addr = ntohl(addr); + sprintf(buf, "%ld.%ld.%ld.%ld", + ((addr >> 24) & 0xff), + ((addr >> 16) & 0xff), + ((addr >> 8) & 0xff), + ((addr >> 0) & 0xff)); + return buf; +} + + +/* + * Determine whether a network is on a local network + * (addr) is in network byte order. + */ +int +islocalnet(u_long addr) +{ + addrlist *al; +#ifdef DEBUG + char buf[16]; +#endif /* DEBUG */ + + for (al = localnets; al; al = al->ip_next) + if (((addr ^ al->ip_addr) & al->ip_mask) == 0) + return TRUE; + +#ifdef DEBUG + plog(XLOG_INFO, "%s is on a remote network", inet_dquad(buf, addr)); +#endif /* DEBUG */ + + return FALSE; +} + + +/* + * Determine whether a network name is one of the local networks + * of a host. + */ +int +is_network_member(const char *net) +{ + addrlist *al; + + for (al = localnets; al; al = al->ip_next) + if (STREQ(net, al->ip_net_name) || STREQ(net, al->ip_net_num)) + return TRUE; + + return FALSE; +} diff --git a/contrib/amd/libamu/xdr_func.c b/contrib/amd/libamu/xdr_func.c new file mode 100644 index 0000000..feafbae --- /dev/null +++ b/contrib/amd/libamu/xdr_func.c @@ -0,0 +1,1155 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: xdr_func.c,v 5.2.2.1 1992/02/09 15:08:40 jsp beta $ + * + */ + +/* + * Complete list of all possible xdr functions which may be needed. + */ +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +/* + * MACROS: + */ +#ifdef HAVE_FS_AUTOFS +# ifndef A_MAXNAME +# define A_MAXNAME 255 +# endif /* not A_MAXNAME */ +# ifndef A_MAXOPTS +# define A_MAXOPTS 255 +# endif /* not A_MAXOPTS */ +# ifndef A_MAXPATH +# define A_MAXPATH 1024 +# endif /* not A_MAXPATH */ +#endif /* HAVE_FS_AUTOFS */ + +/* forward definitions, are they needed? */ +extern bool_t xdr_exportnode(XDR *xdrs, exportnode *objp); +extern bool_t xdr_groupnode(XDR *xdrs, groupnode *objp); +extern bool_t xdr_name(XDR *xdrs, name *objp); + + +#ifndef HAVE_XDR_ATTRSTAT +bool_t +xdr_attrstat(XDR *xdrs, nfsattrstat *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_attrstat:"); +#endif /* DEBUG */ + + if (!xdr_nfsstat(xdrs, &objp->ns_status)) { + return (FALSE); + } + switch (objp->ns_status) { + case NFS_OK: + if (!xdr_fattr(xdrs, &objp->ns_u.ns_attr_u)) { + return (FALSE); + } + break; + default: + break; + } + return (TRUE); +} +#endif /* not HAVE_XDR_ATTRSTAT */ + + +#ifndef HAVE_XDR_CREATEARGS +bool_t +xdr_createargs(XDR *xdrs, nfscreateargs *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_createargs:"); +#endif /* DEBUG */ + + if (!xdr_diropargs(xdrs, &objp->ca_where)) { + return (FALSE); + } + if (!xdr_sattr(xdrs, &objp->ca_attributes)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_CREATEARGS */ + + +#ifndef HAVE_XDR_DIRLIST +bool_t +xdr_dirlist(XDR *xdrs, nfsdirlist *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_dirlist:"); +#endif /* DEBUG */ + + if (!xdr_pointer(xdrs, (char **) &objp->dl_entries, sizeof(nfsentry), (XDRPROC_T_TYPE) xdr_entry)) { + return (FALSE); + } + if (!xdr_bool(xdrs, &objp->dl_eof)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_DIRLIST */ + + +#ifndef HAVE_XDR_DIROPARGS +bool_t +xdr_diropargs(XDR *xdrs, nfsdiropargs *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_diropargs:"); +#endif /* DEBUG */ + + if (!xdr_nfs_fh(xdrs, &objp->da_fhandle)) { + return (FALSE); + } + if (!xdr_filename(xdrs, &objp->da_name)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_DIROPARGS */ + + +#ifndef HAVE_XDR_DIROPOKRES +bool_t +xdr_diropokres(XDR *xdrs, nfsdiropokres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_diropokres:"); +#endif /* DEBUG */ + + if (!xdr_nfs_fh(xdrs, &objp->drok_fhandle)) { + return (FALSE); + } + if (!xdr_fattr(xdrs, &objp->drok_attributes)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_DIROPOKRES */ + + +#ifndef HAVE_XDR_DIROPRES +bool_t +xdr_diropres(XDR *xdrs, nfsdiropres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_diropres:"); +#endif /* DEBUG */ + + if (!xdr_nfsstat(xdrs, &objp->dr_status)) { + return (FALSE); + } + switch (objp->dr_status) { + case NFS_OK: + if (!xdr_diropokres(xdrs, &objp->dr_u.dr_drok_u)) { + return (FALSE); + } + break; + default: + break; + } + return (TRUE); +} +#endif /* not HAVE_XDR_DIROPRES */ + + +#ifndef HAVE_XDR_DIRPATH +bool_t +xdr_dirpath(XDR *xdrs, dirpath *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_dirpath:"); +#endif /* DEBUG */ + + if (!xdr_string(xdrs, objp, MNTPATHLEN)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_DIRPATH */ + + +#ifndef HAVE_XDR_ENTRY +bool_t +xdr_entry(XDR *xdrs, nfsentry *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_entry:"); +#endif /* DEBUG */ + + if (!xdr_u_int(xdrs, &objp->ne_fileid)) { + return (FALSE); + } + if (!xdr_filename(xdrs, &objp->ne_name)) { + return (FALSE); + } + if (!xdr_nfscookie(xdrs, objp->ne_cookie)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **) &objp->ne_nextentry, sizeof(nfsentry), (XDRPROC_T_TYPE) xdr_entry)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_ENTRY */ + + +#ifndef HAVE_XDR_EXPORTNODE +bool_t +xdr_exportnode(XDR *xdrs, exportnode *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_exportnode:"); +#endif /* DEBUG */ + + if (!xdr_dirpath(xdrs, &objp->ex_dir)) { + return (FALSE); + } + /* + * This cast to (groups) is needed for Irix6. If you change it, it + * may produce a warning/error on other systems. + */ + if (!xdr_groups(xdrs, (groups) &objp->ex_groups)) { + return (FALSE); + } + if (!xdr_exports(xdrs, &objp->ex_next)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_EXPORTNODE */ + + +#ifndef HAVE_XDR_EXPORTS +bool_t +xdr_exports(XDR *xdrs, exports *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_exports:"); +#endif /* DEBUG */ + + if (!xdr_pointer(xdrs, (char **) objp, sizeof(exportnode), (XDRPROC_T_TYPE) xdr_exportnode)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_EXPORTS */ + + +#ifndef HAVE_XDR_FATTR +bool_t +xdr_fattr(XDR *xdrs, nfsfattr *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_fattr:"); +#endif /* DEBUG */ + + if (!xdr_ftype(xdrs, &objp->na_type)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_mode)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_nlink)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_uid)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_gid)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_size)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_blocksize)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_rdev)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_blocks)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_fsid)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->na_fileid)) { + return (FALSE); + } + if (!xdr_nfstime(xdrs, &objp->na_atime)) { + return (FALSE); + } + if (!xdr_nfstime(xdrs, &objp->na_mtime)) { + return (FALSE); + } + if (!xdr_nfstime(xdrs, &objp->na_ctime)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_FATTR */ + + +#ifndef HAVE_XDR_FHANDLE +bool_t +xdr_fhandle(XDR *xdrs, fhandle objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_fhandle:"); +#endif /* DEBUG */ + + if (!xdr_opaque(xdrs, objp, NFS_FHSIZE)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_FHANDLE */ + + +#ifndef HAVE_XDR_FHSTATUS +bool_t +xdr_fhstatus(XDR *xdrs, fhstatus *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_fhstatus:"); +#endif /* DEBUG */ + + if (!xdr_u_int(xdrs, &objp->fhs_status)) { + return (FALSE); + } + if (objp->fhs_status == 0 && !xdr_fhandle(xdrs, objp->fhs_fh)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_FHSTATUS */ + + +#ifndef HAVE_XDR_FILENAME +bool_t +xdr_filename(XDR *xdrs, filename *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_filename:"); +#endif /* DEBUG */ + + if (!xdr_string(xdrs, objp, NFS_MAXNAMLEN)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_FILENAME */ + + +#ifndef HAVE_XDR_FTYPE +bool_t +xdr_ftype(XDR *xdrs, nfsftype *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_ftype:"); +#endif /* DEBUG */ + + if (!xdr_enum(xdrs, (enum_t *) objp)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_FTYPE */ + + +#ifndef HAVE_XDR_GROUPNODE +bool_t +xdr_groupnode(XDR *xdrs, groupnode *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_groupnode:"); +#endif /* DEBUG */ + + if (!xdr_name(xdrs, &objp->gr_name)) { + return (FALSE); + } + /* + * This cast to (groups) is needed for Irix6. If you change it, it + * may produce a warning/error on other systems. + */ + if (!xdr_groups(xdrs, (groups) &objp->gr_next)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_GROUPNODE */ + + +#ifndef HAVE_XDR_GROUPS +bool_t +xdr_groups(XDR *xdrs, groups objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_groups:"); +#endif /* DEBUG */ + + if (!xdr_pointer(xdrs, (char **) objp, sizeof(groupnode), (XDRPROC_T_TYPE) xdr_groupnode)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_GROUPS */ + + +#ifndef HAVE_XDR_LINKARGS +bool_t +xdr_linkargs(XDR *xdrs, nfslinkargs *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_linkargs:"); +#endif /* DEBUG */ + + if (!xdr_nfs_fh(xdrs, &objp->la_fhandle)) { + return (FALSE); + } + if (!xdr_diropargs(xdrs, &objp->la_to)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_LINKARGS */ + + +#ifndef HAVE_XDR_MOUNTBODY +bool_t +xdr_mountbody(XDR *xdrs, mountbody *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_mountbody:"); +#endif /* DEBUG */ + + if (!xdr_name(xdrs, &objp->ml_hostname)) { + return (FALSE); + } + if (!xdr_dirpath(xdrs, &objp->ml_directory)) { + return (FALSE); + } + if (!xdr_mountlist(xdrs, &objp->ml_next)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_MOUNTBODY */ + + +#ifndef HAVE_XDR_MOUNTLIST +bool_t +xdr_mountlist(XDR *xdrs, mountlist *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_mountlist:"); +#endif /* DEBUG */ + + if (!xdr_pointer(xdrs, (char **) objp, sizeof(mountbody), (XDRPROC_T_TYPE) xdr_mountbody)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_MOUNTLIST */ + + +#if defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3) +/* + * This ifdef is a hack: this whole file needs to be compiled + * only if the system has NFS V3 and does not have the xdr_mountres3 + * function. Autoconf should pick this source file to compile only + * if these two conditions apply. + */ + +bool_t +xdr_fhandle3(XDR *xdrs, fhandle3 *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_fhandle3:"); +#endif /* DEBUG */ + + if (!xdr_bytes(xdrs, + (char **) &objp->fhandle3_val, + (u_int *) &objp->fhandle3_len, + FHSIZE3)) + return (FALSE); + return (TRUE); +} + + +bool_t +xdr_mountstat3(XDR *xdrs, mountstat3 *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_mountstat3:"); +#endif /* DEBUG */ + + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} + + +bool_t +xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_mountres3_ok:"); +#endif /* DEBUG */ + + if (!xdr_fhandle3(xdrs, &objp->fhandle)) + return (FALSE); + if (!xdr_array(xdrs, + (char **)&objp->auth_flavors.auth_flavors_val, + (u_int *) &objp->auth_flavors.auth_flavors_len, + ~0, + sizeof (int), + (xdrproc_t) xdr_int)) + return (FALSE); + return (TRUE); +} + + +bool_t +xdr_mountres3(XDR *xdrs, mountres3 *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_mountres3:"); +#endif /* DEBUG */ + + if (!xdr_mountstat3(xdrs, &objp->fhs_status)) + return (FALSE); + + if (objp->fhs_status == 0) { /* 0 == MNT_OK or MNT3_OK */ + if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo)) + return (FALSE); + } + return (TRUE); +} +#endif /* defined(HAVE_FS_NFS3) && !defined(HAVE_XDR_MOUNTRES3) */ + + +#ifndef HAVE_XDR_NAME +bool_t +xdr_name(XDR *xdrs, name *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_name:"); +#endif /* DEBUG */ + + if (!xdr_string(xdrs, objp, MNTNAMLEN)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_NAME */ + + +#ifndef HAVE_XDR_NFS_FH +bool_t +xdr_nfs_fh(XDR *xdrs, am_nfs_fh *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_nfs_fh:"); +#endif /* DEBUG */ + + if (!xdr_opaque(xdrs, (caddr_t) objp->fh_data, NFS_FHSIZE)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_NFS_FH */ + + +#ifndef HAVE_XDR_NFSCOOKIE +bool_t +xdr_nfscookie(XDR *xdrs, nfscookie objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_nfscookie:"); +#endif /* DEBUG */ + + if (!xdr_opaque(xdrs, objp, NFS_COOKIESIZE)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_NFSCOOKIE */ + + +#ifndef HAVE_XDR_NFSPATH +bool_t +xdr_nfspath(XDR *xdrs, nfspath *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_nfspath:"); +#endif /* DEBUG */ + + if (!xdr_string(xdrs, objp, NFS_MAXPATHLEN)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_NFSPATH */ + + +#ifndef HAVE_XDR_NFSSTAT +bool_t +xdr_nfsstat(XDR *xdrs, nfsstat *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_nfsstat:"); +#endif /* DEBUG */ + + if (!xdr_enum(xdrs, (enum_t *) objp)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_NFSSTAT */ + + +#ifndef HAVE_XDR_NFSTIME +bool_t +xdr_nfstime(XDR *xdrs, nfstime *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_nfstime:"); +#endif /* DEBUG */ + + if (!xdr_u_int(xdrs, (u_int *) &objp->nt_seconds)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, (u_int *) &objp->nt_useconds)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_NFSTIME */ + + +#ifndef HAVE_XDR_POINTER +bool_t +xdr_pointer(register XDR *xdrs, char **objpp, u_int obj_size, XDRPROC_T_TYPE xdr_obj) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_pointer:"); +#endif /* DEBUG */ + + + bool_t more_data; + + more_data = (*objpp != NULL); + if (!xdr_bool(xdrs, &more_data)) { + return (FALSE); + } + if (!more_data) { + *objpp = NULL; + return (TRUE); + } + + return (xdr_reference(xdrs, objpp, obj_size, xdr_obj)); +} +#endif /* not HAVE_XDR_POINTER */ + + +#ifndef HAVE_XDR_READARGS +bool_t +xdr_readargs(XDR *xdrs, nfsreadargs *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_readargs:"); +#endif /* DEBUG */ + + if (!xdr_nfs_fh(xdrs, &objp->ra_fhandle)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->ra_offset)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->ra_count)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->ra_totalcount)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_READARGS */ + + +#ifndef HAVE_XDR_READDIRARGS +bool_t +xdr_readdirargs(XDR *xdrs, nfsreaddirargs *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_readdirargs:"); +#endif /* DEBUG */ + + if (!xdr_nfs_fh(xdrs, &objp->rda_fhandle)) { + return (FALSE); + } + if (!xdr_nfscookie(xdrs, objp->rda_cookie)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->rda_count)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_READDIRARGS */ + + +#ifndef HAVE_XDR_READDIRRES +bool_t +xdr_readdirres(XDR *xdrs, nfsreaddirres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_readdirres:"); +#endif /* DEBUG */ + + if (!xdr_nfsstat(xdrs, &objp->rdr_status)) { + return (FALSE); + } + switch (objp->rdr_status) { + case NFS_OK: + if (!xdr_dirlist(xdrs, &objp->rdr_u.rdr_reply_u)) { + return (FALSE); + } + break; + default: + break; + } + return (TRUE); +} +#endif /* not HAVE_XDR_READDIRRES */ + + +#ifndef HAVE_XDR_READLINKRES +bool_t +xdr_readlinkres(XDR *xdrs, nfsreadlinkres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_readlinkres:"); +#endif /* DEBUG */ + + if (!xdr_nfsstat(xdrs, &objp->rlr_status)) { + return (FALSE); + } + switch (objp->rlr_status) { + case NFS_OK: + if (!xdr_nfspath(xdrs, &objp->rlr_u.rlr_data_u)) { + return (FALSE); + } + break; + default: + break; + } + return (TRUE); +} +#endif /* not HAVE_XDR_READLINKRES */ + + +#ifndef HAVE_XDR_READOKRES +bool_t +xdr_readokres(XDR *xdrs, nfsreadokres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_readokres:"); +#endif /* DEBUG */ + + if (!xdr_fattr(xdrs, &objp->raok_attributes)) { + return (FALSE); + } + if (!xdr_bytes(xdrs, + (char **) & objp->raok_u.raok_val_u, + (u_int *) & objp->raok_u.raok_len_u, + NFS_MAXDATA)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_READOKRES */ + + +#ifndef HAVE_XDR_READRES +bool_t +xdr_readres(XDR *xdrs, nfsreadres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_readres:"); +#endif /* DEBUG */ + + if (!xdr_nfsstat(xdrs, &objp->rr_status)) { + return (FALSE); + } + switch (objp->rr_status) { + case NFS_OK: + if (!xdr_readokres(xdrs, &objp->rr_u.rr_reply_u)) { + return (FALSE); + } + break; + default: + break; + } + return (TRUE); +} +#endif /* not HAVE_XDR_READRES */ + + +#ifndef HAVE_XDR_RENAMEARGS +bool_t +xdr_renameargs(XDR *xdrs, nfsrenameargs *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_renameargs:"); +#endif /* DEBUG */ + + if (!xdr_diropargs(xdrs, &objp->rna_from)) { + return (FALSE); + } + if (!xdr_diropargs(xdrs, &objp->rna_to)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_RENAMEARGS */ + + +#ifndef HAVE_XDR_SATTR +bool_t +xdr_sattr(XDR *xdrs, nfssattr *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_sattr:"); +#endif /* DEBUG */ + + if (!xdr_u_int(xdrs, &objp->sa_mode)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->sa_uid)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->sa_gid)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->sa_size)) { + return (FALSE); + } + if (!xdr_nfstime(xdrs, &objp->sa_atime)) { + return (FALSE); + } + if (!xdr_nfstime(xdrs, &objp->sa_mtime)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_SATTR */ + + +#ifndef HAVE_XDR_SATTRARGS +bool_t +xdr_sattrargs(XDR *xdrs, nfssattrargs *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_sattrargs:"); +#endif /* DEBUG */ + + if (!xdr_nfs_fh(xdrs, &objp->sag_fhandle)) { + return (FALSE); + } + if (!xdr_sattr(xdrs, &objp->sag_attributes)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_SATTRARGS */ + + +#ifndef HAVE_XDR_STATFSOKRES +bool_t +xdr_statfsokres(XDR *xdrs, nfsstatfsokres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_statfsokres:"); +#endif /* DEBUG */ + + if (!xdr_u_int(xdrs, &objp->sfrok_tsize)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->sfrok_bsize)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->sfrok_blocks)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->sfrok_bfree)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->sfrok_bavail)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_STATFSOKRES */ + + +#ifndef HAVE_XDR_STATFSRES +bool_t +xdr_statfsres(XDR *xdrs, nfsstatfsres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_statfsres:"); +#endif /* DEBUG */ + + if (!xdr_nfsstat(xdrs, &objp->sfr_status)) { + return (FALSE); + } + switch (objp->sfr_status) { + case NFS_OK: + if (!xdr_statfsokres(xdrs, &objp->sfr_u.sfr_reply_u)) { + return (FALSE); + } + break; + default: + break; + } + return (TRUE); +} +#endif /* not HAVE_XDR_STATFSRES */ + + +#ifndef HAVE_XDR_SYMLINKARGS +bool_t +xdr_symlinkargs(XDR *xdrs, nfssymlinkargs *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_symlinkargs:"); +#endif /* DEBUG */ + + if (!xdr_diropargs(xdrs, &objp->sla_from)) { + return (FALSE); + } + if (!xdr_nfspath(xdrs, &objp->sla_to)) { + return (FALSE); + } + if (!xdr_sattr(xdrs, &objp->sla_attributes)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_SYMLINKARGS */ + + +#ifndef HAVE_XDR_WRITEARGS +bool_t +xdr_writeargs(XDR *xdrs, nfswriteargs *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_writeargs:"); +#endif /* DEBUG */ + + if (!xdr_nfs_fh(xdrs, &objp->wra_fhandle)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->wra_beginoffset)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->wra_offset)) { + return (FALSE); + } + if (!xdr_u_int(xdrs, &objp->wra_totalcount)) { + return (FALSE); + } + if (!xdr_bytes(xdrs, + (char **) & objp->wra_u.wra_val_u, + (u_int *) & objp->wra_u.wra_len_u, + NFS_MAXDATA)) { + return (FALSE); + } + return (TRUE); +} +#endif /* not HAVE_XDR_WRITEARGS */ + + +/* + * AUTOFS XDR FUNCTIONS: + */ +#ifdef HAVE_FS_AUTOFS +# ifndef HAVE_XDR_MNTREQUEST +bool_t +xdr_mntrequest(XDR *xdrs, mntrequest *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_mntrequest:"); +#endif /* DEBUG */ + + if (!xdr_string(xdrs, &objp->name, A_MAXNAME)) + return (FALSE); + + if (!xdr_string(xdrs, &objp->map, A_MAXNAME)) + return (FALSE); + + if (!xdr_string(xdrs, &objp->opts, A_MAXOPTS)) + return (FALSE); + + if (!xdr_string(xdrs, &objp->path, A_MAXPATH)) + return (FALSE); + + return (TRUE); +} +# endif /* not HAVE_XDR_MNTREQUEST */ + + +# ifndef HAVE_XDR_MNTRES +bool_t +xdr_mntres(XDR *xdrs, mntres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_mntres:"); +#endif /* DEBUG */ + + if (!xdr_int(xdrs, &objp->status)) + return (FALSE); + + return (TRUE); +} +# endif /* not HAVE_XDR_MNTRES */ + + +# ifndef HAVE_XDR_UMNTREQUEST +bool_t +xdr_umntrequest(XDR *xdrs, umntrequest *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_umntrequest:"); +#endif /* DEBUG */ + + if (!xdr_int(xdrs, &objp->isdirect)) + return (FALSE); + + if (!xdr_u_int(xdrs, (u_int *) &objp->devid)) + return (FALSE); + +#ifdef HAVE_FIELD_UMNTREQUEST_RDEVID + if (!xdr_u_long(xdrs, &objp->rdevid)) + return (FALSE); +#endif /* HAVE_FIELD_UMNTREQUEST_RDEVID */ + + if (!xdr_pointer(xdrs, (char **) &objp->next, sizeof(umntrequest), (XDRPROC_T_TYPE) xdr_umntrequest)) + return (FALSE); + + return (TRUE); +} +# endif /* not HAVE_XDR_UMNTREQUEST */ + + +# ifndef HAVE_XDR_UMNTRES +bool_t +xdr_umntres(XDR *xdrs, umntres *objp) +{ +#ifdef DEBUG + amuDebug(D_TRACE) + plog(XLOG_DEBUG, "xdr_mntres:"); +#endif /* DEBUG */ + + if (!xdr_int(xdrs, &objp->status)) + return (FALSE); + + return (TRUE); +} +# endif /* not HAVE_XDR_UMNTRES */ +#endif /* HAVE_FS_AUTOFS */ diff --git a/contrib/amd/libamu/xutil.c b/contrib/amd/libamu/xutil.c new file mode 100644 index 0000000..15d2cee --- /dev/null +++ b/contrib/amd/libamu/xutil.c @@ -0,0 +1,825 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: xutil.c,v 1.1 1997-1998/01/11 21:06:22 ezk Exp ezk $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include +#include + +FILE *logfp = stderr; /* Log errors to stderr initially */ + +#ifdef HAVE_SYSLOG +int syslogging; +#endif /* HAVE_SYSLOG */ +int xlog_level = XLOG_ALL & ~XLOG_MAP & ~XLOG_STATS; +int xlog_level_init = ~0; +static int amd_program_number = AMQ_PROGRAM; + +time_t clock_valid = 0; +time_t xclock_valid = 0; + +#ifdef DEBUG_MEM +static int mem_bytes; +static int orig_mem_bytes; +#endif /* DEBUG_MEM */ + +/* forward definitions */ +static void real_plog(int lvl, char *fmt, va_list vargs); + +#ifdef DEBUG +/* + * List of debug options. + */ +struct opt_tab dbg_opt[] = +{ + {"all", D_ALL}, /* All */ + {"amq", D_AMQ}, /* Register for AMQ program */ + {"daemon", D_DAEMON}, /* Enter daemon mode */ + {"fork", D_FORK}, /* Fork server (nofork = don't fork) */ + {"full", D_FULL}, /* Program trace */ + /* info service specific debugging (hesiod, nis, etc) */ + {"info", D_INFO}, +# ifdef DEBUG_MEM + {"mem", D_MEM}, /* Trace memory allocations */ +# endif /* DEBUG_MEM */ + {"mtab", D_MTAB}, /* Use local mtab file */ + {"str", D_STR}, /* Debug string munging */ + {"test", D_TEST}, /* Full debug - but no daemon */ + {"trace", D_TRACE}, /* Protocol trace */ + {0, 0} +}; +#endif /* DEBUG */ + +/* + * List of log options + */ +struct opt_tab xlog_opt[] = +{ + {"all", XLOG_ALL}, /* All messages */ +#ifdef DEBUG + {"debug", XLOG_DEBUG}, /* Debug messages */ +#endif /* DEBUG */ /* DEBUG */ + {"error", XLOG_ERROR}, /* Non-fatal system errors */ + {"fatal", XLOG_FATAL}, /* Fatal errors */ + {"info", XLOG_INFO}, /* Information */ + {"map", XLOG_MAP}, /* Map errors */ + {"stats", XLOG_STATS}, /* Additional statistical information */ + {"user", XLOG_USER}, /* Non-fatal user errors */ + {"warn", XLOG_WARNING}, /* Warnings */ + {"warning", XLOG_WARNING}, /* Warnings */ + {0, 0} +}; + + +voidp +xmalloc(int len) +{ + voidp p; + int retries = 600; + + /* + * Avoid malloc's which return NULL for malloc(0) + */ + if (len == 0) + len = 1; + + do { + p = (voidp) malloc((unsigned) len); + if (p) { +#if defined(DEBUG) && defined(DEBUG_MEM) + amuDebug(D_MEM) + plog(XLOG_DEBUG, "Allocated size %d; block %#x", len, p); +#endif /* defined(DEBUG) && defined(DEBUG_MEM) */ + return p; + } + if (retries > 0) { + plog(XLOG_ERROR, "Retrying memory allocation"); + sleep(1); + } + } while (--retries); + + plog(XLOG_FATAL, "Out of memory"); + going_down(1); + + abort(); + + return 0; +} + + +/* like xmalloc, but zeros out the bytes */ +voidp +xzalloc(int len) +{ + voidp p = xmalloc(len); + + if (p) + memset(p, 0, len); + return p; +} + + +voidp +xrealloc(voidp ptr, int len) +{ +#if defined(DEBUG) && defined(DEBUG_MEM) + amuDebug(D_MEM) plog(XLOG_DEBUG, "Reallocated size %d; block %#x", len, ptr); +#endif /* defined(DEBUG) && defined(DEBUG_MEM) */ + + if (len == 0) + len = 1; + + if (ptr) + ptr = (voidp) realloc(ptr, (unsigned) len); + else + ptr = (voidp) xmalloc((unsigned) len); + + if (!ptr) { + plog(XLOG_FATAL, "Out of memory in realloc"); + going_down(1); + abort(); + } + return ptr; +} + + +#if defined(DEBUG) && defined(DEBUG_MEM) +void +dxfree(char *file, int line, voidp ptr) +{ + amuDebug(D_MEM) + plog(XLOG_DEBUG, "Free in %s:%d: block %#x", file, line, ptr); + /* this is the only place that must NOT use XFREE()!!! */ + free(ptr); + ptr = NULL; /* paranoid */ +} +#endif /* defined(DEBUG) && defined(DEBUG_MEM) */ + + +#ifdef DEBUG_MEM +static void +checkup_mem(void) +{ + struct mallinfo mi = mallinfo(); + u_long uordbytes = mi.uordblks * 4096; + + if (mem_bytes != uordbytes) { + if (orig_mem_bytes == 0) + mem_bytes = orig_mem_bytes = uordbytes; + else { + fprintf(logfp, "%s[%ld]: ", progname, (long) mypid); + if (mem_bytes < uordbytes) { + fprintf(logfp, "ALLOC: %ld bytes", uordbytes - mem_bytes); + } else { + fprintf(logfp, "FREE: %ld bytes", mem_bytes - uordbytes); + } + mem_bytes = uordbytes; + fprintf(logfp, ", making %d missing\n", mem_bytes - orig_mem_bytes); + } + } + malloc_verify(); +} +#endif /* DEBUG_MEM */ + + +/* + * Take a log format string and expand occurences of %m + * with the current error code taken from errno. + */ +static void +expand_error(char *f, char *e) +{ + extern int sys_nerr; + char *p; + int error = errno; + + for (p = f; (*e = *p); e++, p++) { + if (p[0] == '%' && p[1] == 'm') { + const char *errstr; + if (error < 0 || error >= sys_nerr) + errstr = NULL; + else + errstr = sys_errlist[error]; + if (errstr) + strcpy(e, errstr); + else + sprintf(e, "Error %d", error); + e += strlen(e) - 1; + p++; + } + } +} + + +/* + * Output the time of day and hostname to the logfile + */ +static void +show_time_host_and_name(int lvl) +{ + static time_t last_t = 0; + static char *last_ctime = 0; + time_t t = clocktime(); + char *sev; + + if (t != last_t) { + last_ctime = ctime(&t); + last_t = t; + } + switch (lvl) { + case XLOG_FATAL: + sev = "fatal:"; + break; + case XLOG_ERROR: + sev = "error:"; + break; + case XLOG_USER: + sev = "user: "; + break; + case XLOG_WARNING: + sev = "warn: "; + break; + case XLOG_INFO: + sev = "info: "; + break; + case XLOG_DEBUG: + sev = "debug:"; + break; + case XLOG_MAP: + sev = "map: "; + break; + case XLOG_STATS: + sev = "stats:"; + break; + default: + sev = "hmm: "; + break; + } + fprintf(logfp, "%15.15s %s %s[%ld]/%s ", + last_ctime + 4, hostname, + progname, + (long) mypid, + sev); +} + + +#ifdef DEBUG +/* + * Switch on/off debug options + */ +int +debug_option(char *opt) +{ + return cmdoption(opt, dbg_opt, &debug_flags); +} + + +void +dplog(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + real_plog(XLOG_DEBUG, fmt, ap); + va_end(ap); +} +#endif /* DEBUG */ + + +void +plog(int lvl, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + real_plog(lvl, fmt, ap); + va_end(ap); +} + + +static void +real_plog(int lvl, char *fmt, va_list vargs) +{ + char msg[1024]; + char efmt[1024]; + char *ptr = msg; + static char last_msg[1024]; + static int last_count = 0, last_lvl = 0; + + if (!(xlog_level & lvl)) + return; + +#ifdef DEBUG_MEM + checkup_mem(); +#endif /* DEBUG_MEM */ + + expand_error(fmt, efmt); + + vsprintf(ptr, efmt, vargs); + + ptr += strlen(ptr); + if (ptr[-1] == '\n') + *--ptr = '\0'; + +#ifdef HAVE_SYSLOG + if (syslogging) { + switch (lvl) { /* from mike */ + case XLOG_FATAL: + lvl = LOG_CRIT; + break; + case XLOG_ERROR: + lvl = LOG_ERR; + break; + case XLOG_USER: + lvl = LOG_WARNING; + break; + case XLOG_WARNING: + lvl = LOG_WARNING; + break; + case XLOG_INFO: + lvl = LOG_INFO; + break; + case XLOG_DEBUG: + lvl = LOG_DEBUG; + break; + case XLOG_MAP: + lvl = LOG_DEBUG; + break; + case XLOG_STATS: + lvl = LOG_INFO; + break; + default: + lvl = LOG_ERR; + break; + } + syslog(lvl, "%s", msg); + return; + } +#endif /* HAVE_SYSLOG */ + + *ptr++ = '\n'; + *ptr = '\0'; + + /* + * mimic syslog behavior: only write repeated strings if they differ + */ + switch (last_count) { + case 0: /* never printed at all */ + last_count = 1; + strncpy(last_msg, msg, 1024); + last_lvl = lvl; + show_time_host_and_name(lvl); /* mimic syslog header */ + fwrite(msg, ptr - msg, 1, logfp); + fflush(logfp); + break; + + case 1: /* item printed once, if same, don't repeat */ + if (STREQ(last_msg, msg)) { + last_count++; + } else { /* last msg printed once, new one differs */ + /* last_count remains at 1 */ + strncpy(last_msg, msg, 1024); + last_lvl = lvl; + show_time_host_and_name(lvl); /* mimic syslog header */ + fwrite(msg, ptr - msg, 1, logfp); + fflush(logfp); + } + break; + + case 100: + /* + * Don't allow repetitions longer than 100, so you can see when something + * cycles like crazy. + */ + show_time_host_and_name(last_lvl); + sprintf(last_msg, "last message repeated %d times\n", last_count); + fwrite(last_msg, strlen(last_msg), 1, logfp); + fflush(logfp); + last_count = 0; /* start from scratch */ + break; + + default: /* item repeated multiple times */ + if (STREQ(last_msg, msg)) { + last_count++; + } else { /* last msg repeated+skipped, new one differs */ + show_time_host_and_name(last_lvl); + sprintf(last_msg, "last message repeated %d times\n", last_count); + fwrite(last_msg, strlen(last_msg), 1, logfp); + strncpy(last_msg, msg, 1024); + last_count = 1; + last_lvl = lvl; + show_time_host_and_name(lvl); /* mimic syslog header */ + fwrite(msg, ptr - msg, 1, logfp); + fflush(logfp); + } + break; + } + +} + + +/* + * Display current debug options + */ +void +show_opts(int ch, struct opt_tab *opts) +{ + int i; + int s = '{'; + + fprintf(stderr, "\t[-%c {no}", ch); + for (i = 0; opts[i].opt; i++) { + fprintf(stderr, "%c%s", s, opts[i].opt); + s = ','; + } + fputs("}]\n", stderr); +} + + +int +cmdoption(char *s, struct opt_tab *optb, int *flags) +{ + char *p = s; + int errs = 0; + + while (p && *p) { + int neg; + char *opt; + struct opt_tab *dp, *dpn = 0; + + s = p; + p = strchr(p, ','); + if (p) + *p = '\0'; + + /* check for "no" prefix to options */ + if (s[0] == 'n' && s[1] == 'o') { + opt = s + 2; + neg = 1; + } else { + opt = s; + neg = 0; + } + + /* + * Scan the array of debug options to find the + * corresponding flag value. If it is found + * then set (or clear) the flag (depending on + * whether the option was prefixed with "no"). + */ + for (dp = optb; dp->opt; dp++) { + if (STREQ(opt, dp->opt)) + break; + if (opt != s && !dpn && STREQ(s, dp->opt)) + dpn = dp; + } + + if (dp->opt || dpn) { + if (!dp->opt) { + dp = dpn; + neg = !neg; + } + if (neg) + *flags &= ~dp->flag; + else + *flags |= dp->flag; + } else { + /* + * This will log to stderr when parsing the command line + * since any -l option will not yet have taken effect. + */ + plog(XLOG_USER, "option \"%s\" not recognised", s); + errs++; + } + + /* + * Put the comma back + */ + if (p) + *p++ = ','; + } + + return errs; +} + + +/* + * Switch on/off logging options + */ +int +switch_option(char *opt) +{ + int xl = xlog_level; + int rc = cmdoption(opt, xlog_opt, &xl); + + if (rc) { + rc = EINVAL; + } else { + /* + * Keep track of initial log level, and + * don't allow options to be turned off. + */ + if (xlog_level_init == ~0) + xlog_level_init = xl; + else + xl |= xlog_level_init; + xlog_level = xl; + } + return rc; +} + +/* + * get syslog facility to use. + * logfile can be "syslog", "syslog:daemon", "syslog:local7", etc. + */ +static int +get_syslog_facility(const char *logfile) +{ + char *facstr; + + /* parse facility string */ + facstr = strchr(logfile, ':'); + if (!facstr) /* log file was "syslog" */ + return LOG_DAEMON; + facstr++; + if (!facstr || facstr[0] == '\0') { /* log file was "syslog:" */ + plog(XLOG_WARNING, "null syslog facility, using LOG_DAEMON"); + return LOG_DAEMON; + } + +#ifdef LOG_KERN + if (STREQ(facstr, "kern")) + return LOG_KERN; +#endif /* not LOG_KERN */ +#ifdef LOG_USER + if (STREQ(facstr, "user")) + return LOG_USER; +#endif /* not LOG_USER */ +#ifdef LOG_MAIL + if (STREQ(facstr, "mail")) + return LOG_MAIL; +#endif /* not LOG_MAIL */ +#ifdef LOG_DAEMON + if (STREQ(facstr, "daemon")) + return LOG_DAEMON; +#endif /* not LOG_DAEMON */ +#ifdef LOG_AUTH + if (STREQ(facstr, "auth")) + return LOG_AUTH; +#endif /* not LOG_AUTH */ +#ifdef LOG_SYSLOG + if (STREQ(facstr, "syslog")) + return LOG_SYSLOG; +#endif /* not LOG_SYSLOG */ +#ifdef LOG_LPR + if (STREQ(facstr, "lpr")) + return LOG_LPR; +#endif /* not LOG_LPR */ +#ifdef LOG_NEWS + if (STREQ(facstr, "news")) + return LOG_NEWS; +#endif /* not LOG_NEWS */ +#ifdef LOG_UUCP + if (STREQ(facstr, "uucp")) + return LOG_UUCP; +#endif /* not LOG_UUCP */ +#ifdef LOG_CRON + if (STREQ(facstr, "cron")) + return LOG_CRON; +#endif /* not LOG_CRON */ +#ifdef LOG_LOCAL0 + if (STREQ(facstr, "local0")) + return LOG_LOCAL0; +#endif /* not LOG_LOCAL0 */ +#ifdef LOG_LOCAL1 + if (STREQ(facstr, "local1")) + return LOG_LOCAL1; +#endif /* not LOG_LOCAL1 */ +#ifdef LOG_LOCAL2 + if (STREQ(facstr, "local2")) + return LOG_LOCAL2; +#endif /* not LOG_LOCAL2 */ +#ifdef LOG_LOCAL3 + if (STREQ(facstr, "local3")) + return LOG_LOCAL3; +#endif /* not LOG_LOCAL3 */ +#ifdef LOG_LOCAL4 + if (STREQ(facstr, "local4")) + return LOG_LOCAL4; +#endif /* not LOG_LOCAL4 */ +#ifdef LOG_LOCAL5 + if (STREQ(facstr, "local5")) + return LOG_LOCAL5; +#endif /* not LOG_LOCAL5 */ +#ifdef LOG_LOCAL6 + if (STREQ(facstr, "local6")) + return LOG_LOCAL6; +#endif /* not LOG_LOCAL6 */ +#ifdef LOG_LOCAL7 + if (STREQ(facstr, "local7")) + return LOG_LOCAL7; +#endif /* not LOG_LOCAL7 */ + + /* didn't match anything else */ + plog(XLOG_WARNING, "unknown syslog facility \"%s\", using LOG_DAEMON", facstr); + return LOG_DAEMON; +} + + +/* + * Change current logfile + */ +int +switch_to_logfile(char *logfile) +{ + FILE *new_logfp = stderr; + + if (logfile) { +#ifdef HAVE_SYSLOG + syslogging = 0; +#endif /* HAVE_SYSLOG */ + + if (STREQ(logfile, "/dev/stderr")) + new_logfp = stderr; + else if (NSTREQ(logfile, "syslog", strlen("syslog"))) { + +#ifdef HAVE_SYSLOG + syslogging = 1; + new_logfp = stderr; + openlog(progname, + LOG_PID +# ifdef LOG_CONS + | LOG_CONS +# endif /* LOG_CONS */ +# ifdef LOG_NOWAIT + | LOG_NOWAIT +# endif /* LOG_NOWAIT */ +# ifdef LOG_DAEMON + , get_syslog_facility(logfile) +# endif /* LOG_DAEMON */ + ); +#else /* not HAVE_SYSLOG */ + plog(XLOG_WARNING, "syslog option not supported, logging unchanged"); +#endif /* not HAVE_SYSLOG */ + + } else { + (void) umask(orig_umask); + new_logfp = fopen(logfile, "a"); + umask(0); + } + } + + /* + * If we couldn't open a new file, then continue using the old. + */ + if (!new_logfp && logfile) { + plog(XLOG_USER, "%s: Can't open logfile: %m", logfile); + return 1; + } + + /* + * Close the previous file + */ + if (logfp && logfp != stderr) + (void) fclose(logfp); + logfp = new_logfp; + + return 0; +} + + +void +unregister_amq(void) +{ +#ifdef DEBUG + amuDebug(D_AMQ) +#endif /* DEBUG */ + /* find which instance of amd to unregister */ + pmap_unset(get_amd_program_number(), AMQ_VERSION); +} + + +void +going_down(int rc) +{ + if (foreground) { + if (amd_state != Start) { + if (amd_state != Done) + return; + unregister_amq(); + } + } + if (foreground) { + plog(XLOG_INFO, "Finishing with status %d", rc); + } else { +#ifdef DEBUG + dlog("background process exiting with status %d", rc); +#endif /* DEBUG */ + } + + exit(rc); +} + + +/* return the rpc program number under which amd was used */ +int +get_amd_program_number(void) +{ + return amd_program_number; +} + + +/* set the rpc program number used for amd */ +void +set_amd_program_number(int program) +{ + amd_program_number = program; +} + + +/* + * Release the controlling tty of the process pid. + * + * Algorithm: try these in order, if available, until one of them + * succeeds: setsid(), ioctl(fd, TIOCNOTTY, 0). + * Do not use setpgid(): on some OSs it may release the controlling tty, + * even if the man page does not mention it, but on other OSs it does not. + * Also avoid setpgrp(): it works on some systems, and on others it is + * identical to setpgid(). + */ +void +amu_release_controlling_tty(void) +{ +#ifdef TIOCNOTTY + int fd; +#endif /* TIOCNOTTY */ + +#ifdef HAVE_SETSID + if (setsid() < 0) { + plog(XLOG_WARNING, "Could not release controlling tty using setsid(): %m"); + } else { + plog(XLOG_INFO, "released controlling tty using setsid()"); + return; + } +#endif /* HAVE_SETSID */ + +#ifdef TIOCNOTTY + fd = open("/dev/tty", O_RDWR); + if (fd < 0) { + /* not an error if already no controlling tty */ + if (errno != ENXIO) + plog(XLOG_WARNING, "Could not open controlling tty: %m"); + } else { + if (ioctl(fd, TIOCNOTTY, 0) < 0 && errno != ENOTTY) + plog(XLOG_WARNING, "Could not disassociate tty (TIOCNOTTY): %m"); + else + plog(XLOG_INFO, "released controlling tty using ioctl(TIOCNOTTY)"); + close(fd); + } + return; +#endif /* not TIOCNOTTY */ + + plog(XLOG_ERROR, "unable to release controlling tty"); +} diff --git a/contrib/amd/mk-amd-map/mk-amd-map.8 b/contrib/amd/mk-amd-map/mk-amd-map.8 new file mode 100644 index 0000000..a6690b8 --- /dev/null +++ b/contrib/amd/mk-amd-map/mk-amd-map.8 @@ -0,0 +1,62 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1993 Jan-Simon Pendry +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)mk-amd-map.8 8.1 (Berkeley) 6/28/93 +.\" $Id: mk-amd-map.8,v 1.3 1997/05/29 01:48:43 cgd Exp $ +.\" +.TH MK-AMD-MAP 8 "June 28, 1993" +.SH NAME +.B mk-amd-map +\- create database maps for Amd +.SH SYNOPSIS +.B mk-amd-map +[ +.B \-p +] +.I mapname +.SH DESCRIPTION +.B mk-amd-map +creates the database maps used by the keyed map lookups in +amd(8). +It reads input from the named file +and outputs them to a correspondingly named +hashed database. +.TP +.B \-p +This +option prints the map on standard output instead of generating +a database. This is usually used to merge continuation lines +into one physical line. +.SH SEE ALSO +.BR amd (8). diff --git a/contrib/amd/mk-amd-map/mk-amd-map.c b/contrib/amd/mk-amd-map/mk-amd-map.c new file mode 100644 index 0000000..2b41540 --- /dev/null +++ b/contrib/amd/mk-amd-map/mk-amd-map.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: mk-amd-map.c,v 5.2.2.1 1992/02/09 15:09:18 jsp beta $ + */ + +/* + * Convert a file map into an ndbm map + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include + +/* dummy variables */ +char *progname; +char hostname[MAXHOSTNAMELEN]; +int orig_umask, foreground, debug_flags; +pid_t mypid; +serv_state amd_state; + + +#ifdef HAVE_MAP_NDBM + +static int +store_data(voidp db, char *k, char *v) +{ + datum key, val; + + key.dptr = k; + val.dptr = v; + key.dsize = strlen(k) + 1; + val.dsize = strlen(v) + 1; + return dbm_store((DBM *) db, key, val, DBM_INSERT); +} + + +/* + * Read one line from file. + */ +static int +read_line(char *buf, int size, FILE *fp) +{ + int done = 0; + + do { + while (fgets(buf, size, fp)) { + int len = strlen(buf); + + done += len; + if (len > 1 && buf[len - 2] == '\\' && buf[len - 1] == '\n') { + int ch; + buf += len - 2; + size -= len - 2; + *buf = '\n'; + buf[1] = '\0'; + + /* + * Skip leading white space on next line + */ + while ((ch = getc(fp)) != EOF && isascii(ch) && isspace(ch)) ; + (void) ungetc(ch, fp); + } else { + return done; + } + } + } while (size > 0 && !feof(fp)); + + return done; +} + + +/* + * Read through a map. + */ +static int +read_file(FILE *fp, char *map, voidp db) +{ + char key_val[2048]; + int chuck = 0; + int line_no = 0; + int errs = 0; + + while (read_line(key_val, sizeof(key_val), fp)) { + char *kp; + char *cp; + char *hash; + int len = strlen(key_val); + + line_no++; + + /* + * Make sure we got the whole line + */ + if (key_val[len - 1] != '\n') { + fprintf(stderr, "line %d in \"%s\" is too long", line_no, map); + chuck = 1; + } else { + key_val[len - 1] = '\0'; + } + + /* + * Strip comments + */ + hash = strchr(key_val, '#'); + if (hash) + *hash = '\0'; + + /* + * Find start of key + */ + for (kp = key_val; *kp && isascii(*kp) && isspace((int)*kp); kp++) ; + + /* + * Ignore blank lines + */ + if (!*kp) + goto again; + + /* + * Find end of key + */ + for (cp = kp; *cp && (!isascii(*cp) || !isspace((int)*cp)); cp++) ; + + /* + * Check whether key matches, or whether + * the entry is a wildcard entry. + */ + if (*cp) + *cp++ = '\0'; + while (*cp && isascii(*cp) && isspace((int)*cp)) + cp++; + if (*kp == '+') { + fprintf(stderr, "Can't interpolate %s\n", kp); + errs++; + } else if (*cp) { + if (db) { + if (store_data(db, kp, cp) < 0) { + fprintf(stderr, "Could store %s -> %s\n", kp, cp); + errs++; + } + } else { + printf("%s\t%s\n", kp, cp); + } + } else { + fprintf(stderr, "%s: line %d has no value field", map, line_no); + errs++; + } + + again: + /* + * If the last read didn't get a whole line then + * throw away the remainder before continuing... + */ + if (chuck) { + while (fgets(key_val, sizeof(key_val), fp) && + !strchr(key_val, '\n')) ; + chuck = 0; + } + } + return errs; +} + + +static int +remove_file(char *f) +{ + if (unlink(f) < 0 && errno != ENOENT) + return -1; + + return 0; +} + + +int +main(int argc, char *argv[]) +{ + FILE *mapf; + int mapfd = -1; + char *map; + int rc = 0; + DBM *mapd = NULL; + static char maptmp[] = "dbmXXXXXX"; + char maptpag[16], maptdir[16]; + char *mappag = (char *) NULL, *mapdir = (char *) NULL; + int len; + char *sl; + int printit = 0; + int usage = 0; + int ch; + extern int optind; + + /* test options */ + while ((ch = getopt(argc, argv, "p")) != EOF) + switch (ch) { + case 'p': + printit = 1; + break; + default: + usage++; + break; + } + + if (usage || optind != (argc - 1)) { + fputs("Usage: mk-amd-map [-p] file-map\n", stderr); + exit(1); + } + map = argv[optind]; + + /* test if can get to the map directory */ + sl = strrchr(map, '/'); + if (sl) { + *sl = '\0'; + if (chdir(map) < 0) { + fputs("Can't chdir to ", stderr); + perror(map); + exit(1); + } + map = sl + 1; + } + + if (!printit) { + len = strlen(map); + mappag = (char *) malloc(len + 5); + mapdir = (char *) malloc(len + 5); + if (!mappag || !mapdir) { + perror("mk-amd-map: malloc"); + exit(1); + } +#ifdef HAVE_MKSTEMP + mapfd = mkstemp(maptmp); +#else /* not HAVE_MKSTEMP */ + map = mktemp(maptmp); + if (!maptmp) { + fprintf(stderr, "cannot create temporary file\n"); + exit(1); + } + mapfd = open(map, O_RDONLY); +#endif /* not HAVE_MKSTEMP */ + + /* open DBM files */ + sprintf(maptpag, "%s.pag", maptmp); + sprintf(maptdir, "%s.dir", maptmp); + if (remove_file(maptpag) < 0 || remove_file(maptdir) < 0) { + fprintf(stderr, "Can't remove existing temporary files; %s and", maptpag); + perror(maptdir); + exit(1); + } + } + /* open and check if map file was opened OK */ + mapf = fdopen(mapfd, "r"); + if (mapf && !printit) + mapd = dbm_open(maptmp, O_RDWR|O_CREAT, 0444); + else + mapd = 0; + +#ifndef DEBUG + /* ignore ^C if debuggung is on (but why?) */ + signal(SIGINT, SIG_IGN); +#endif /* not DEBUG */ + + if (mapd || printit) { + int error = read_file(mapf, map, mapd); + (void) close(mapfd); + (void) fclose(mapf); + if (printit) { + if (error) { + fprintf(stderr, "Error creating ndbm map for %s\n", map); + rc = 1; + } + } else { + + if (error) { + fprintf(stderr, "Error reading source file %s\n", map); + rc = 1; + } else { + sprintf(mappag, "%s.pag", map); + sprintf(mapdir, "%s.dir", map); + if (rename(maptpag, mappag) < 0) { + fprintf(stderr, "Couldn't rename %s to ", maptpag); + perror(mappag); + /* Throw away the temporary map */ + unlink(maptpag); + unlink(maptdir); + rc = 1; + + } else if (rename(maptdir, mapdir) < 0) { + fprintf(stderr, "Couldn't rename %s to ", maptdir); + perror(mapdir); + /* Put the .pag file back */ + rename(mappag, maptpag); + /* Throw away remaining part of original map */ + unlink(mapdir); + fprintf(stderr, + "WARNING: existing map \"%s.{dir,pag}\" destroyed\n", + map); + rc = 1; + } + } + } + + } else { + fprintf(stderr, "Can't open \"%s.{dir,pag}\" for ", map); + perror("writing"); + rc = 1; + } + exit(rc); +} + +#else /* not HAVE_MAP_NDBM */ + +main() +{ + fputs("mk-amd-map: This system does not support hashed database files\n", stderr); + exit(1); +} + +#endif /* not HAVE_MAP_NDBM */ diff --git a/contrib/amd/scripts/Makefile.am b/contrib/amd/scripts/Makefile.am new file mode 100644 index 0000000..9ebd691 --- /dev/null +++ b/contrib/amd/scripts/Makefile.am @@ -0,0 +1,49 @@ +## Process this file with automake to produce Makefile.in + +# Package: am-utils +# Level: Makefile for scripts/ directory +# Author: Erez Zadok + +sbin_SCRIPTS = \ + am-eject \ + amd2ldif \ + amd2sun \ + ctl-amd \ + ctl-hlfsd \ + fixrmtab \ + fix-amd-map \ + lostaltmail \ + wait4amd \ + wait4amd2die + +bin_SCRIPTS = \ + expn + +sysconf_DATA = \ + amd.conf-sample \ + lostaltmail.conf-sample + +# man pages +man_MANS = \ + amd.conf.5 \ + expn.1 + +EXTRA_DIST = \ + am-eject.in \ + amd2ldif.in \ + amd2sun.in \ + ctl-amd.in \ + ctl-hlfsd.in \ + fixrmtab \ + fix-amd-map.in \ + lostaltmail.in \ + wait4amd.in \ + wait4amd2die.in \ + \ + expn.in \ + \ + amd.conf-sample \ + lostaltmail.conf-sample \ + $(man_MANS) + +CLEANFILES = $(sbin_SCRIPTS) $(bin_SCRIPTS) diff --git a/contrib/amd/scripts/Makefile.in b/contrib/amd/scripts/Makefile.in new file mode 100644 index 0000000..1c69cec --- /dev/null +++ b/contrib/amd/scripts/Makefile.in @@ -0,0 +1,379 @@ +# Makefile.in generated automatically by automake 1.3.1 from Makefile.am + +# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Package: am-utils +# Level: Makefile for scripts/ directory +# Author: Erez Zadok + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DISTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AR = @AR@ +CC = @CC@ +CPP = @CPP@ +LEX = @LEX@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_LDFLAGS = @LIBTOOL_LDFLAGS@ +LTALLOCA = @LTALLOCA@ +LTLIBOBJS = @LTLIBOBJS@ +PACKAGE = @PACKAGE@ +PERL = @PERL@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ + +sbin_SCRIPTS = \ + am-eject \ + amd2ldif \ + amd2sun \ + ctl-amd \ + ctl-hlfsd \ + fixrmtab \ + fix-amd-map \ + lostaltmail \ + wait4amd \ + wait4amd2die + +bin_SCRIPTS = \ + expn + +sysconf_DATA = \ + amd.conf-sample \ + lostaltmail.conf-sample + +# man pages +man_MANS = \ + amd.conf.5 \ + expn.1 + +EXTRA_DIST = \ + am-eject.in \ + amd2ldif.in \ + amd2sun.in \ + ctl-amd.in \ + ctl-hlfsd.in \ + fixrmtab \ + fix-amd-map.in \ + lostaltmail.in \ + wait4amd.in \ + wait4amd2die.in \ + \ + expn.in \ + \ + amd.conf-sample \ + lostaltmail.conf-sample \ + $(man_MANS) + +CLEANFILES = $(sbin_SCRIPTS) $(bin_SCRIPTS) +mkinstalldirs = $(SHELL) $(top_srcdir)/aux/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = am-eject amd2ldif amd2sun ctl-amd ctl-hlfsd expn \ +fix-amd-map lostaltmail wait4amd wait4amd2die +SCRIPTS = $(bin_SCRIPTS) $(sbin_SCRIPTS) + +man1dir = $(mandir)/man1 +man5dir = $(mandir)/man5 +MANS = $(man_MANS) + +NROFF = nroff +DATA = $(sysconf_DATA) + +DIST_COMMON = Makefile.am Makefile.in am-eject.in amd2ldif.in \ +amd2sun.in ctl-amd.in ctl-hlfsd.in expn.in fix-amd-map.in \ +lostaltmail.in wait4amd.in wait4amd2die.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP = --best +all: Makefile $(SCRIPTS) $(MANS) $(DATA) + +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/./aux/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --localdir=./aux --gnu --include-deps scripts/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +am-eject: $(top_builddir)/config.status am-eject.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +amd2ldif: $(top_builddir)/config.status amd2ldif.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +amd2sun: $(top_builddir)/config.status amd2sun.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +ctl-amd: $(top_builddir)/config.status ctl-amd.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +ctl-hlfsd: $(top_builddir)/config.status ctl-hlfsd.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +expn: $(top_builddir)/config.status expn.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +fix-amd-map: $(top_builddir)/config.status fix-amd-map.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +lostaltmail: $(top_builddir)/config.status lostaltmail.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +wait4amd: $(top_builddir)/config.status wait4amd.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +wait4amd2die: $(top_builddir)/config.status wait4amd2die.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status + +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \ + else if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \ + else :; fi; fi; \ + done + +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + list='$(bin_SCRIPTS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \ + done + +install-sbinSCRIPTS: $(sbin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_SCRIPTS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_SCRIPT) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \ + else if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \ + else :; fi; fi; \ + done + +uninstall-sbinSCRIPTS: + @$(NORMAL_UNINSTALL) + list='$(sbin_SCRIPTS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \ + done + +install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + +uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done + +install-man5: + $(mkinstalldirs) $(DESTDIR)$(man5dir) + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \ + done + +uninstall-man5: + @list='$(man5_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.5*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man5dir)/$$inst"; \ + rm -f $(DESTDIR)$(man5dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) install-man1 install-man5 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) uninstall-man1 uninstall-man5 + +install-sysconfDATA: $(sysconf_DATA) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sysconfdir) + @list='$(sysconf_DATA)'; for p in $$list; do \ + if test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(sysconfdir)/$$p; \ + else if test -f $$p; then \ + echo " $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$p"; \ + $(INSTALL_DATA) $$p $(DESTDIR)$(sysconfdir)/$$p; \ + fi; fi; \ + done + +uninstall-sysconfDATA: + @$(NORMAL_UNINSTALL) + list='$(sysconf_DATA)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sysconfdir)/$$p; \ + done +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = scripts + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done +info: +dvi: +check: all + $(MAKE) +installcheck: +install-exec: install-binSCRIPTS install-sbinSCRIPTS install-sysconfDATA + @$(NORMAL_INSTALL) + +install-data: install-man + @$(NORMAL_INSTALL) + +install: install-exec install-data all + @: + +uninstall: uninstall-binSCRIPTS uninstall-sbinSCRIPTS uninstall-man uninstall-sysconfDATA + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: + $(mkinstalldirs) $(DATADIR)$(bindir) $(DATADIR)$(sbindir) \ + $(DESTDIR)$(mandir)/man1 $(DESTDIR)$(mandir)/man5 \ + $(DATADIR)$(sysconfdir) + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-generic + +clean: clean-generic mostlyclean + +distclean: distclean-generic clean + -rm -f config.status + -rm -f libtool + +maintainer-clean: maintainer-clean-generic distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: uninstall-binSCRIPTS install-binSCRIPTS uninstall-sbinSCRIPTS \ +install-sbinSCRIPTS install-man1 uninstall-man1 install-man5 \ +uninstall-man5 install-man uninstall-man uninstall-sysconfDATA \ +install-sysconfDATA tags distdir info dvi installcheck install-exec \ +install-data install uninstall all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/contrib/amd/scripts/am-eject.in b/contrib/amd/scripts/am-eject.in new file mode 100644 index 0000000..ed7e2d0 --- /dev/null +++ b/contrib/amd/scripts/am-eject.in @@ -0,0 +1,52 @@ +#!/bin/sh +# auto-unmount floppy/cd directory before ejecting device +# script taken from Debian Linux's amd +# +# Package: am-utils-6.0 +# (Additional) author: Erez Zadok + +# set path +prefix=@prefix@ +exec_prefix=@exec_prefix@ +PATH=@sbindir@:@bindir@:/usr/ucb:/usr/bin:/bin:${PATH} +export PATH + +if [ $# -ne 1 ]; then + echo "Usage: $0 cd|fd" + exit 2 +fi + +# determine toplevel mount point of amd +fs=`amq | grep ' toplvl ' | cut -d' ' -f1` +if [ "$fs" = "" ]; then + echo "Cannot determine amd toplevel directory" + exit 2 +fi + +# append name of medium +case "$1" in + cd|fd) fs=$fs/$1;; + *) echo "Usage: $0 cd|fd"; exit 2;; +esac + +# is the medium mounted? +if amq | grep -q "^$fs" >/dev/null 2>&1; then + # if yes, try to unmount it + sync + amq -u $fs + sleep 2 + if amq | grep -q "^$fs" >/dev/null 2>&1; then + # failed, bail out + echo -n "Cannot unmount $fs; in use by:" + fuser -uv -m $fs + echo "" + exit 1 + fi +else + echo "$fs not mounted" +fi + +case $1 in + cd) eject;; # eject CD-ROM + fd) echo "Ok to remove disk";; +esac diff --git a/contrib/amd/scripts/amd.conf-sample b/contrib/amd/scripts/amd.conf-sample new file mode 100644 index 0000000..59ce1f8 --- /dev/null +++ b/contrib/amd/scripts/amd.conf-sample @@ -0,0 +1,94 @@ +# -*- text -*- +# A SAMPLE CONFIGURATION FILE FOR AMD + +############################################################################## +# GLOBAL OPTIONS SECTION (must be first in amd.conf file) +[ global ] +# (amd -n) +normalize_hostnames = yes | no +# (amd -p) +print_pid = yes | no +pid_file = /dev/stdout | /var/run/amd.pid +# (amd -r) +restart_mounts = yes | no +unmount_on_exit = no | yes +# (amd -a) +auto_dir = /a +# duration in seconds that a looked up name remain cached (amd -c) +cache_duration = 300 +# (amd -d) +local_domain = cs.columbia.edu +# (amd -k) +karch = sun4m +arch = sun4 +# if you don't like autoconf picking up "sunos5" as the os-type, override it +os = sos5 +# (amd -o) +osver = 2.5.1 +# if you print_version after setting up "os", it will show it. (amd -v) +print_version = yes | no + +# (amd -l) +log_file = /var/log/amd | syslog | syslog:facility +# NFS (RPC/UDP) retry interval, in tenths of secs (amd -t interval.counter) +nfs_retry_interval = 8 +nfs_retransmit_counter = 110 +# (amd -w) +dismount_interval = 120 +# (amd -y) +nis_domain = nisDom-CS.columbia.edu +# (amd -x) +log_options = fatal,error,user,warn,info,map,stats,all +# (amd -D) +debug_options = all,amq,daemon,fork,full,info,mem,mtab,str,test,trace +# (amd -S) +plock = no | yes +# selectors on /defaults are off by default +selectors_on_default = yes | no +# should browsable maps show number of entries to df/statfs (default=no) +show_statfs_entries = yes | no +# (hpux) cluster name (amd -C) +cluster = ??? +# LDAP (Lightweight Directory Access Protocol) options +ldap_base = ldap.your.domain:389 +ldap_hostports = "ou=Marketing, o=AMD Ltd, c=US" +ldap_cache_seconds = 0 (default) +ldap_cache_maxmem = 131072 (default) +# default base name for hesiod maps +hesiod_base = automount +# these 5 options can be overridden by each map individually +browsable_dirs = yes | no | full +map_options = cache:=all +map_type = file|hesiod|ndbm|nis|nisplus|passwd|union|ldap +mount_type = nfs | autofs +search_path = /etc/local:/etc/amdmaps:/misc/yp +# alternate RPC program number to register with the port mapper +portmap_program = 300019-300029 +# Use fully qualified host names +fully_qualified_hosts = yes | no + +############################################################################## +# DEFINE AN AMD MOUNT POINT +[ /home ] +# map name must be defined, all else are optional +map_name = /etc/amd.home | amd.home +map_options = cache:=all +# if map type is not defined, will search all map types (default) +map_type = file|hesiod|ndbm|nis|nisplus|passwd|union|ldap +search_path = /etc/local:/etc/amdmaps:/misc/yp +# an amd or autofs mount point +mount_type = nfs | autofs +browsable_dirs = yes | no +# an optional tag to be used with amd -T tag. untagged entries are always +# used. Tagged ones get used only if specified with "amd -T" +tag = test + +############################################################################## +# DEFINE ANOTHER AMD MOUNT POINT +[ /src ] +map_name = /usr/local/lib/amdmaps/amu.src +# regular amd (nfs) mount point (default) +# don't try the "autofs" type. It is not implemented yet. +mount_type = nfs + +############################################################################## diff --git a/contrib/amd/scripts/amd.conf.5 b/contrib/amd/scripts/amd.conf.5 new file mode 100644 index 0000000..2022fad --- /dev/null +++ b/contrib/amd/scripts/amd.conf.5 @@ -0,0 +1,539 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1990 Jan-Simon Pendry +.\" Copyright (c) 1990 Imperial College of Science, Technology & Medicine +.\" Copyright (c) 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jan-Simon Pendry at Imperial College, London. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" %W% (Berkeley) %G% +.\" +.\" $Id: amd.conf.5,v 5.2.2.1 1997/02/09 15:11:15 ezk beta $ +.\" +.TH AMQ.CONF 8 "7 August 1997" +.SH NAME +amd.conf \- amd configuration file +.SH SYNOPSIS +.B amd.conf +.SH DESCRIPTION +The +.B amd.conf +file is the configuration file for amd, as part of the am-utils suite. +.P +.B amd.conf +contains runtime configuration information for the +.B amd +automounter program. +.\" ************************************************************************** +.SH FILE FORMAT +.P +The file consists of sections and parameters. A section begins with the +name of the section in square brackets and continues until the next section +begins or the end the file is reached. Sections contain parameters of the +form 'name = value'. +.P +The file is line-based - that is, each newline-terminated line represents +either a comment, a section name or a parameter. No line-continuation +syntax is available. +.P +Section, parameter names and their values are case sensitive. +.P +Only the first equals sign in a parameter is significant. Whitespace before +or after the first equals sign is discarded. Leading, trailing and +internal whitespace in section and parameter names is irrelevant. Leading +and trailing whitespace in a parameter value is discarded. Internal +whitespace within a parameter value is not allowed, unless the whole +parameter value is quoted with double quotes as in 'name = "some value"'. +.P +Any line beginning with a pound sign (#) is ignored, as are lines containing +only whitespace. +.P +The values following the equals sign in parameters are all either a string +(no quotes needed if string does not include spaces) or a boolean, which may +be given as yes/no. Case is significant in all values. Some items such as +cache timeouts are numeric. +.\" ************************************************************************** +.SH SECTIONS +.SS The [global] section +Parameters in this section either apply to amd as a whole, or to all other +regular map sections which follow. There should be only one global section +defined in one configuration file. +.P +It is highly recommended that this section be specified first in the +configuration file. If it is not, then regular map sections which precede +it will not use global values defined later. + +.SS Regular [/map] sections +Parameters in regular (non-global) sections apply to a single map entry. +For example, if the map section +.B [/homes] +is defined, then all parameters following it will be applied to the +.I /homes +amd-managed mount point. +.\" ************************************************************************** +.SH PARAMETERS +.SS Parameters common to all sections +These parameters can be specified either in the global or a map specific +section. Entries specified in a map-specific section override the default +value or one defined in the global section. If such a common parameter is +specified only in the global section, it is applicable to all regular map +sections that follow. +.\" ************************************************************************** +.TP +.BR browsable_dirs " (string, default=no)" +If "yes", then amd's top-level mount points will be browsable to +.BR readdir (3) +calls. This means you could run for example +.BR ls (3) +and see what keys are available to mount in that directory. Not all entries +are made visible to readdir(3): the "/default" entry, wildcard +entries, and those with a "/" in them are not included. If you specify +"full" to this option, all but "/default" will be visible. +Note that if you run a command which will attempt to +.BR stat (2) +the entries, such as often done by "ls -l" or "ls -F", amd will attempt to +mount +.I every +entry in that map. This is often called a ``mount storm''. + +.TP +.BR map_options " (string, default no options)" +This option is the same as specifying map options on the command line to +amd, such as "cache:=all". + +.TP +.BR map_type " (string, default search all map types)" +If specified, amd will initialize the map only for the type given. This is +useful to avoid the default map search type used by amd which takes longer +and can have undesired side-effects such as initializing NIS even if not +used. Possible values are + +.nf +\fBfile\fR plain files +\fBhesiod\fR Hesiod name service from MIT +\fBldap\fR Lightweight Directory Access Protocol +\fBndbm\fR (New) dbm style hash files +\fBnis\fR Network Information Services (version 2) +\fBnisplus\fR Network Information Services Plus (version 3) +\fBpasswd\fR local password files +\fBunion\fR union maps +.fi + +.TP +.BR mount_type " (string, default=nfs)" +All amd mount types default to NFS. That is, amd is an NFS server on the +map mount points, for the local host it is running on. If "autofs" is +specified, amd will be an autofs server for those mount points. + +.TP +.BR search_path " (string, default no search path)" +This provides a (colon-delimited) search path for file maps. Using a search +path, sites can allow for local map customizations and overrides, and can +distributed maps in several locations as needed. + +.\" ************************************************************************** +.SS Parameters applicable to the global section only + +.TP +.BR arch " (string, default to compiled in value)" +Allows you to override the value of the +.I arch +amd variable. + +.TP +.BR auto_dir " (string, default=/a)" +Same as the +.B \-a +option to amd. This sets the private directory where amd will create +sub-directories for its real mount points. + +.TP +.BR cache_duration " (numeric, default=300)" +Same as the +.B \-c +option to amd. Sets the duration in seconds that looked up map entries +remain in the cache. + +.TP +.BR cluster " (string, default no cluster)" +Same as the +.B \-C +option to amd. Specifies the alternate HP-UX cluster to use. + +.TP +.BR debug_options " (string, default no debug options)" +Same as the +.B \-D +option to amd. Specify any debugging options for amd. Works only if +am-utils was configured for debugging using the --enable-debug option. The +"mem" option alone can be turned on via --enable-debug=mem. Otherwise +debugging options are ignored. Options are comma delimited, and can be +preceded by the string "no" to negate their meaning. You can get the list +of supported debugging options by running amd \-v. Possible values are: + +.nf +\fBall\fR all options +\fBamq\fR register for amq +\fBdaemon\fR enter daemon mode +\fBfork\fR fork server +\fBfull\fR program trace +\fBinfo\fR info service specific debugging (hesiod, nis, etc.) +\fBmem\fR trace memory allocations +\fBmtab\fR use local "./mtab" file +\fBstr\fR debug string munging +\fBtest\fR full debug but no daemon +\fBtrace\fR protocol trace +.fi + +.TP +.BR dismount_interval " (numeric, default=120)" +Same as the +.B \-w +option to amd. Specify in seconds, the time between attempts to dismount +file systems that have exceeded their cached times. + +.TP +.BR fully_qualified_hosts " (string, default=no)" +If "yes", +.I Amd +will perform RPC authentication using fully-qualified host names. This is +necessary for some systems, and especially when performing cross-domain +mounting. For this function to work, the +.I Amd +variable ${hostd} is used, requiring that ${domain} not be null. + +.TP +.BR hesiod_base " (string, default=automount)" +Specify the base name for hesiod maps. + +.TP +.BR karch " (string, default to karch of the system)" +Same as the +.B \-k +option to amd. Allows you to override the kernel-architecture of your +system. Useful for example on Sun (Sparc) machines, where you can build one +amd binary, and run it on multiple machines, yet you want each one to get +the correct +.I karch +variable set (for example, sun4c, sun4m, sun4u, etc.) Note that if not +specified, amd will use uname(2) to figure out the kernel architecture of +the machine. + +.TP +.BR ldap_base " (string, default not set)" +Specify the base name for LDAP. + +.TP +.BR ldap_cache_maxmem " (numeric, default=131072)" +Specify the maximum memory amd should use to cache LDAP entries. + +.TP +.BR ldap_cache_seconds " (numeric, default=0)" +Specify the number of seconds to keep entries in the cache. + +.TP +.BR ldap_hostports " (string, default not set)" +Specify LDAP-specific values such as country and organization. + +.TP +.BR local_domain " (string, default no sub-domain)" +Same as the +.B \-d +option to amd. Specify the local domain name. If this option is not given +the domain name is determined from the hostname, by removing the first +component of the fully-qualified host name. + +.TP +.BR log_file " (string, default=/dev/stderr)" +Same as the +.B \-l +option to amd. Specify a file name to log amd events to. +If the string +.B /dev/stderr +is specified, amd will send its events to the standard error file descriptor. +If the string +.B syslog +is given, amd will record its events with the system logger +.BR syslogd (8). +The default syslog facility used is LOG_DAEMON. If you +wish to change it, append its name to the log file name, delimited by a +single colon. For example, if +.I logfile +is the string +.B syslog:local7 +then amd will log messages via +.IR syslog (3) +using the LOG_LOCAL7 facility (if it exists on the system). + +.TP +.BR log_options " (string, default no logging options)" +Same as the +.B \-x +option to amd. Specify any logging options for amd. Options are comma +delimited, and can be preceded by the string "no" to negate their meaning. +The "debug" logging option is only available if am-utils was configured with +--enable-debug. You can get the list of supported debugging options by +running amd \-v. Possible values are: + +.nf +\fBall\fR all messages +\fBdebug\fR debug messages +\fBerror\fR non-fatal system errors +\fBfatal\fR fatal errors +\fBinfo\fR information +\fBmap\fR map errors +\fBstats\fR additional statistical information +\fBuser\fR non-fatal user errors +\fBwarn\fR warnings +\fBwarning\fR warnings +.fi + +.TP +.BR nfs_retransmit_counter " (numeric, default=110)" +Same as the +.I counter +part of the +.BI \-t " interval.counter" +option to amd. Specifies the retransmit counter's value in +.I tenths +of seconds. + +.TP +.BR nfs_retry_interval " (numeric, default=8)" +Same as the +.I interval +part of the +.BI \-t " interval.counter" +option to amd. Specifies the interval in +.I tenths +of seconds, between NFS/RPC/UDP retries. + +.TP +.BR nis_domain " (string, default to local NIS domain name)" +Same as the +.B \-y +option to amd. Specify an alternative NIS domain from which to fetch the +NIS maps. The default is the system domain name. This option is ignored if +NIS support is not available. + +.TP +.BR normalize_hostnames " (boolean, default=no)" +Same as the +.B \-n +option to amd. If "yes", then the name refereed to by ${rhost} is +normalized relative to the host database before being used. The effect is +to translate aliases into ``official'' names. + +.TP +.BR os " (string, default to compiled in value)" +Same as the +.B \-O +option to amd. Allows you to override the compiled-in name of the operating +system. Useful when the built-in name is not desired for backward +compatibility reasons. For example, if the build in name is ``sunos5'', you +can override it to ``sos5'', and use older maps which were written with the +latter in mind. + +.TP +.BR osver " (string, default to compiled in value)" +Same as the +.B \-o +option to amd. Override the compiled-in version number of the operating +system. Useful when the built in version is not desired for backward +compatibility reasons. For example, if the build in version is ``2.5.1'', +you can override it to ``5.5.1'', and use older maps that were written with +the latter in mind. + +.TP +.BR pid_file " (string, default=/dev/stdout)" +Specify a file to store the process ID of the running daemon into. If not +specified, amd will print its process id onto the standard output. Useful +for killing amd after it had run. Note that the PID of a running amd can +also be retrieved via +.B amq +.BR \-p . +This file is used only if the print_pid option is on. + +.TP +.BR plock " (boolean, default=yes)" +Same as the +.B \-S +option to amd. +If "yes", lock the running executable pages of amd into memory. To improve +amd's performance, systems that support the +.BR plock (3) +call can lock the amd process into memory. This way there is less chance it +the operating system will schedule, page out, and swap the amd process as +needed. This improves amd's performance, at the cost of reserving the +memory used by the amd process (making it unavailable for other processes). + +.TP +.BR portmap_program " (numeric, default=300019)" +Specify an alternate Port-mapper RPC program number, other than the official +number. This is useful when running multiple amd processes. For example, +you can run another amd in "test" mode, without affecting the primary amd +process in any way. For safety reasons, the alternate program numbers that +can be specified must be in the range 300019-300029, inclusive. +.B amq +has an option +.B -P +which can be used to specify an alternate program number of an amd to +contact. In this way, amq can fully control any number of amd processes +running on the same host. + +.TP +.BR print_pid " (boolean, default=no)" +Same as the +.B \-p +option to amd. If "yes", amd will print its process ID upon starting. + +.TP +.BR print_version " (boolean, default=no)" +Same as the +.B \-v +option to amd, but the version prints and amd continues to run. If "yes", +amd will print its version information string, which includes some +configuration and compilation values. + +.TP +.BR restart_mounts " (boolean, default=no)" +Same as the +.B \-r +option to amd. If "yes" +.B amd +will scan the mount table to determine which file systems are currently +mounted. Whenever one of these would have been auto-mounted, +.B amd +inherits it. + +.TP +.BR selectors_on_default " (boolean, default=no)" +If "yes", then the /default entry of maps will be look for and process any +selectors before setting defaults for all other keys in that map. Useful +when you want to set different options for a complete map based on some +parameters. For example, you may want to better the NFS performance over +slow slip-based networks as follows: + +.nf +/defaults \\ + wire==slip-net;opts:=intr,rsize=1024,wsize=1024 \\ + wire!=slip-net;opts:=intr,rsize=8192,wsize=8192 +.fi + +.TP +.BR show_statfs_entries " (boolean), default=no)" +If "yes", then all maps which are browsable will also show the number of +entries (keys) they have when "df" runs. (This is accomplished by returning +non-zero values to the statfs(2) system call). + +.TP +.BR unmount_on_exist " (boolean), default=no)" +If "yes", then amd will attempt to unmount all file systems which it knows +about. Normally amd leaves all (esp. NFS) mounted file systems intact. +Note that amd does not know about file systems mounted before it starts up, +unless the restart_mounts option or +.B \-r +flag are used. + +.\" ************************************************************************** +.SS Parameters applicable to regular map sections + +.TP +.BR map_name " (string, must be specified)" +Name of the map where the keys are located. + +.TP +.BR tag " (string, default no tag)" +Each map entry in the configuration file can be tagged. If no tag is +specified, that map section will always be processed by amd. If it is +specified, then amd will process the map if the +.B -T +option was given to amd, and the value given to that command-line option +matches that in the map section. + +.\" ************************************************************************** +.SH EXAMPLES +Here is a real amd configuration file I use daily. +.P +.nf +# GLOBAL OPTIONS SECTION +[ global ] +normalize_hostnames = no +print_pid = no +restart_mounts = yes +auto_dir = /n +log_file = /var/log/amd +log_options = all +#debug_options = all +plock = no +selectors_on_default = yes +# config.guess picks up "sunos5" and I don't want to edit my maps yet +os = sos5 +# if you print_version after setting up "os", it will show it. +print_version = no +map_type = file +search_path = /etc/amdmaps:/usr/lib/amd:/usr/local/AMD/lib +browsable_dirs = yes + +# DEFINE AN AMD MOUNT POINT +[ /u ] +map_name = amd.u + +[ /proj ] +map_name = amd.proj + +[ /src ] +map_name = amd.src + +[ /misc ] +map_name = amd.misc + +[ /import ] +map_name = amd.import + +[ /tftpboot/.amd ] +tag = tftpboot +map_name = amd.tftpboot +.fi +.\" ************************************************************************** +.SH "SEE ALSO" +.BR amd (8), +.BR amq (8), +.BR ctl-amd (8). +.SH AUTHORS +Erez Zadok , Department of Computer Science, Columbia +University, New York, USA. +.P +Other authors and contributors to am-utils are listed in the +.B AUTHORS +file distributed with am-utils. diff --git a/contrib/amd/scripts/amd2ldif.in b/contrib/amd/scripts/amd2ldif.in new file mode 100755 index 0000000..6d3c28a --- /dev/null +++ b/contrib/amd/scripts/amd2ldif.in @@ -0,0 +1,58 @@ +#!@PERL@ + +$usage=<mapfile.ldif + +mapname: name of the amd map beeing converted to ldif +base : The LDAP search base. Do not forget the quotes! + +This script should/could be used in a Makefile together +with ldif2ldbm(8C) to automagically update the ldap +databases and restart slapd whenever a master copy of +the maps have changed. Remember "cd /var/yp; make" ? +EOU + +my $fmt = "%-12s: %s\n"; +my $tfmt = "%-15s: %s\n"; +my $mapname = $ARGV[0] or die $usage; +my $base = $ARGV[1] or die $usage; +$time = time(); + +print "dn: cn=amdmap timestamp, $base\n"; +printf "$tfmt", "cn", "amdmap timestamp"; +printf "$tfmt", "objectClass", "amdmapTimestamp"; +printf "$tfmt", "amdmapTimestamp", $time; +print "\n"; + +my $line = ""; +my $done = 0; + +while () { + chomp; + if (/\s*(.+)\\\s*/) { + if ($line) { + $line .= " ".$1; + } else { + $line = $1; + } + $done = 0; + } else { + s/^\s+//g; + $line .= $_; + $done = 1; + } + if ($done) { + my @vals = split(/\s+/,$line); + my $key = shift @vals; + my $entry; + + print "dn: cn=amdmap $mapname\[$key\], $base\n"; + printf "$fmt","cn","amdmap $mapname\[$key\]"; + printf "$fmt","objectClass", "amdmap"; + printf "$fmt","amdmapName", $mapname; + printf "$fmt","amdmapKey", $key; + printf "$fmt","amdmapValue", join(' ',@vals); + print "\n"; + $line = ""; $done = 0; + } +} diff --git a/contrib/amd/scripts/amd2sun.in b/contrib/amd/scripts/amd2sun.in new file mode 100755 index 0000000..df69b09 --- /dev/null +++ b/contrib/amd/scripts/amd2sun.in @@ -0,0 +1,51 @@ +#!@PERL@ +# convert amd maps to Sun automount maps +# usage: amd2sun file +# +# Package: am-utils-6.0 +# Author: "Mark D. Baushke" + +print "# file created by amd2sun +# +# DO NOT EDIT THIS FILE AT ALL +# It is automatically generated from the amd mount map - edit that instead +# +"; +while (<>) { + print, next if /^#/; + chop; + $line = $_; + while ($line =~ /\\$/) { + chop $line; + $line2 = <>; + $line2 =~ s/^\s*//; + $line .= $line2; + chop $line; + } + + next unless $line =~ /^([^\s]+)\s+(.*)$/; + + $fs = $1; $rest=$2; + + if ($fs =~ /^\/defaults/) { + ($defopts = $rest) =~ s/^.*[\s;]opts:=([^;\s]+)[;\s]*.*$/\1/; + next; + } + + $opts=$defopts; + + if ($rest =~ /opts:=([^;\s]+)[;\s]/) { + $opts = $1; + } + + $opts =~ s/,ping=[-\d]+//g; + + ($rhost = $rest) =~ s/^.*[\s;]rhost:=([^;\s]+)[;\s]*.*$/\1/; + ($rfs = $rest) =~ s/^.*[\s;]rfs:=([^;\s]+)[;\s]*.*$/\1/; + + if ($rest =~ /sublink:=([^;\s]+)[;\s]/ ) { + $rfs .= "/$1"; + } + + print "$fs -$opts $rhost:$rfs\n"; +} diff --git a/contrib/amd/scripts/ctl-amd.in b/contrib/amd/scripts/ctl-amd.in new file mode 100755 index 0000000..665a7dd --- /dev/null +++ b/contrib/amd/scripts/ctl-amd.in @@ -0,0 +1,113 @@ +#!/bin/sh +# control starting, stopping, or restarting amd. +# usage: ctl-amd [start | stop | restart] +# +# Package: am-utils-6.0 +# Author: Erez Zadok + +# set path +prefix=@prefix@ +exec_prefix=@exec_prefix@ +PATH=@sbindir@:@bindir@:/usr/ucb:/usr/bin:/bin:${PATH} +export PATH + +# kill the named process(es) +killproc() +{ +# first try to get PID via an amq RPC +pid=`amq -p 2>/dev/null` +if test "$pid" != "" +then + kill $pid + return 0 +fi + +# try bsd style ps +pscmd="ps axc" +pid=`${pscmd} 2>/dev/null | grep "$1" | sed -e 's/^ *//' -e 's/ .*//'` +if test "$pid" != "" +then + kill $pid + return 0 +fi + +# try bsd44 style ps +pscmd="ps -x" +pid=`${pscmd} 2>/dev/null | grep "$1" | sed -e 's/^ *//' -e 's/ .*//'` +if test "$pid" != "" +then + kill $pid + return 0 +fi + +# try svr4 style ps +pscmd="ps -e" +pid=`${pscmd} 2>/dev/null | grep "$1" | sed -e 's/^ *//' -e 's/ .*//'` +if test "$pid" != "" +then + kill $pid + return 0 +fi + +# failed +return 1 +} + +# search for amd.conf file +CF_FILE="${prefix}/etc/amd.conf" +# any local copy of the conf file overrides the "global" one +if [ -f /etc/amd.conf ] +then + CF_FILE="/etc/amd.conf" +fi +if [ -f ${prefix}/etc/amd.conf ] +then + CF_FILE="${prefix}/etc/amd.conf" +fi +if [ -f /etc/local/amd.conf ] +then + CF_FILE="/etc/local/amd.conf" +fi + +# if have the directory /tftpboot/.amd, then add a tag to include it +CF_TAG="" +if [ -d /tftpboot/.amd ] +then + CF_TAG="-T tftpboot" +fi + +case "$1" in +'start') + # + # Start the amd automounter. + # + if [ -x @sbindir@/amd ] + then + # do not specify full path of amd so killproc() works + amd -F $CF_FILE $CF_TAG + fi + ;; + +'stop') + # prepend space to program name to ensure only amd process dies + killproc " amd" + ;; + +'restart') + # kill amd, wait for it to die, then restart + echo "killing amd..." + ctl-amd stop + wait4amd2die + if [ $? != 0 ] + then + echo "NOT restarting amd!" + else + echo "Restarting amd..." + ctl-amd start + fi + ;; + +*) + echo "Usage: @sbindir@/ctl-amd [ start | stop | restart ]" + ;; +esac diff --git a/contrib/amd/scripts/ctl-hlfsd.in b/contrib/amd/scripts/ctl-hlfsd.in new file mode 100755 index 0000000..a6e97f6 --- /dev/null +++ b/contrib/amd/scripts/ctl-hlfsd.in @@ -0,0 +1,101 @@ +#!/bin/sh +# control starting, stopping, or restarting hlfsd. +# usage: ctl-hlfsd [start | stop | restart] +# +# Package: am-utils-6.0 +# Author: Erez Zadok + +# set path +prefix=@prefix@ +exec_prefix=@exec_prefix@ +PATH=@sbindir@:@bindir@:/usr/ucb:/usr/bin:/bin:${PATH} +export PATH + +# kill the named process(es) +killproc() +{ +# try bsd style ps +pscmd="ps axc" +pid=`${pscmd} 2>/dev/null | grep "$1" | sed -e 's/^ *//' -e 's/ .*//'` +if test "$pid" != "" +then + kill $pid + return 0 +fi + +# try bsd44 style ps +pscmd="ps -x" +pid=`${pscmd} 2>/dev/null | grep "$1" | sed -e 's/^ *//' -e 's/ .*//'` +if test "$pid" != "" +then + kill $pid + return 0 +fi + +# try svr4 style ps +pscmd="ps -e" +pid=`${pscmd} 2>/dev/null | grep "$1" | sed -e 's/^ *//' -e 's/ .*//'` +if test "$pid" != "" +then + kill $pid + return 0 +fi + +# failed +return 1 +} + +# locate logs directory +if [ -d /var/log ]; then + logdir="/var/log" +else + logdir="/tmp" +fi + +# locate the mail spool directory +if [ -d /var/mail/. ]; then + maildir="/var/mail" + altmaildir="/var/alt_mail" +else + maildir="/usr/spool/mail" + altmaildir="/usr/spool/alt_mail" +fi + +# locate any optional password file +if [ -f ${prefix}/etc/passwd ]; then + PASSWD_FILE="-P ${prefix}/etc/passwd" +else + PASSWD_FILE="" +fi + +case "$1" in +'start') + # + # Start the hlfsd mail redirector service + # + if [ -x @sbindir@/hlfsd -a -h $maildir ] + then + echo @sbindir@/hlfsd ${PASSWD_FILE} -a $altmaildir -x all -D fork -l $logdir/hlfsd /mail/home .mailspool + @sbindir@/hlfsd ${PASSWD_FILE} -a $altmaildir -x all -D fork -l $logdir/hlfsd /mail/home .mailspool & + fi + ;; + +'stop') + # prepend space to program name to ensure only amd process dies + killproc " hlfsd" + ;; + +'restart') + # kill hlfsd, wait for it to die, then restart + echo "killing hlfsd..." + ctl-hlfsd stop + echo "Waiting for 10 seconds..." + sleep 10 # hope that's enough + echo "Restarting hlfsd..." + ctl-hlfsd start + ;; + +*) + echo "Usage: @sbindir@/ctl-hlfsd [ start | stop | restart ]" + ;; +esac diff --git a/contrib/amd/scripts/expn.1 b/contrib/amd/scripts/expn.1 new file mode 100644 index 0000000..b2bd1b6 --- /dev/null +++ b/contrib/amd/scripts/expn.1 @@ -0,0 +1,1370 @@ +#!@PERL@ +'di '; +'ds 00 \\"'; +'ig 00 '; +# +# THIS PROGRAM IS ITS OWN MANUAL PAGE. INSTALL IN man & bin. +# + +# hardcoded constants, should work fine for BSD-based systems +#require 'sys/socket.ph'; # perl 4 +use Socket; # perl 5 +$AF_INET = &AF_INET; +$SOCK_STREAM = &SOCK_STREAM; +$sockaddr = 'S n a4 x8'; + +# system requirements: +# must have 'nslookup' and 'hostname' programs. + +# $Header: /home/muir/bin/RCS/expn,v 3.9 1995/10/02 17:51:35 muir Exp muir $ + +# TODO: +# less magic should apply to command-line addresses +# less magic should apply to local addresses +# add magic to deal with cross-domain cnames + +# Checklist: (hard addresses) +# 250 Kimmo Suominen <"|/usr/local/mh/lib/slocal -user kim"@grendel.tac.nyc.ny.us> +# harry@hofmann.cs.Berkeley.EDU -> harry@tenet (.berkeley.edu) [dead] +# bks@cs.berkeley.edu -> shiva.CS (.berkeley.edu) [dead] +# dan@tc.cornell.edu -> brown@tiberius (.tc.cornell.edu) + +############################################################################# +# +# Copyright (c) 1993 David Muir Sharnoff +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the David Muir Sharnoff. +# 4. The name of David Sharnoff may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE DAVID MUIR SHARNOFF ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL DAVID MUIR SHARNOFF BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# This copyright notice derrived from material copyrighted by the Regents +# of the University of California. +# +# Contributions accepted. +# +############################################################################# + +# overall structure: +# in an effort to not trace each address individually, but rather +# ask each server in turn a whole bunch of questions, addresses to +# be expanded are queued up. +# +# This means that all accounting w.r.t. an address must be stored in +# various arrays. Generally these arrays are indexed by the +# string "$addr *** $server" where $addr is the address to be +# expanded "foo" or maybe "foo@bar" and $server is the hostname +# of the SMTP server to contact. +# + +# important global variables: +# +# @hosts : list of servers still to be contacted +# $server : name of the current we are currently looking at +# @users = $users{@hosts[0]} : addresses to expand at this server +# $u = $users[0] : the current address being expanded +# $names{"$users[0] *** $server"} : the 'name' associated with the address +# $mxbacktrace{"$users[0] *** $server"} : record of mx expansion +# $mx_secondary{$server} : other mx relays at the same priority +# $domainify_fallback{"$users[0] *** $server"} : alternative names to try +# instead of $server if $server doesn't work +# $temporary_redirect{"$users[0] *** $server"} : when trying alternates, +# temporarily channel all tries along current path +# $giveup{$server} : do not bother expanding addresses at $server +# $verbose : -v +# $watch : -w +# $vw : -v or -w +# $debug : -d +# $valid : -a +# $levels : -1 +# S : the socket connection to $server + +$have_nslookup = 1; # we have the nslookup program +$port = 'smtp'; +$av0 = $0; +$ENV{'PATH'} .= ":/usr/etc" unless $ENV{'PATH'} =~ m,/usr/etc,; +$ENV{'PATH'} .= ":/usr/ucb" unless $ENV{'PATH'} =~ m,/usr/ucb,; +select(STDERR); + +$0 = "$av0 - running hostname"; +chop($name = `hostname || uname -n`); + +$0 = "$av0 - lookup host FQDN and IP addr"; +($hostname,$aliases,$type,$len,$thisaddr) = gethostbyname($name); + +$0 = "$av0 - parsing args"; +$usage = "Usage: $av0 [-1avwd] user[\@host] [user2[host2] ...]"; +for $a (@ARGV) { + die $usage if $a eq "-"; + while ($a =~ s/^(-.*)([1avwd])/$1/) { + eval '$'."flag_$2 += 1"; + } + next if $a eq "-"; + die $usage if $a =~ /^-/; + &expn(&parse($a,$hostname,undef,1)); +} +$verbose = $flag_v; +$watch = $flag_w; +$vw = $flag_v + $flag_w; +$debug = $flag_d; +$valid = $flag_a; +$levels = $flag_1; + +die $usage unless @hosts; +if ($valid) { + if ($valid == 1) { + $validRequirement = 0.8; + } elsif ($valid == 2) { + $validRequirement = 1.0; + } elsif ($valid == 3) { + $validRequirement = 0.9; + } else { + $validRequirement = (1 - (1/($valid-3))); + print "validRequirement = $validRequirement\n" if $debug; + } +} + +$0 = "$av0 - building local socket"; +($name,$aliases,$proto) = getprotobyname('tcp'); +($name,$aliases,$port) = getservbyname($port,'tcp') + unless $port =~ /^\d+/; +$this = pack($sockaddr, &AF_INET, 0, $thisaddr); + +HOST: +while (@hosts) { + $server = shift(@hosts); + @users = split(' ',$users{$server}); + delete $users{$server}; + + # is this server already known to be bad? + $0 = "$av0 - looking up $server"; + if ($giveup{$server}) { + &giveup('mx domainify',$giveup{$server}); + next; + } + + # do we already have an mx record for this host? + next HOST if &mxredirect($server,*users); + + # look it up, or try for an mx. + $0 = "$av0 - gethostbyname($server)"; + + ($name,$aliases,$type,$len,$thataddr) = gethostbyname($server); + # if we can't get an A record, try for an MX record. + unless($thataddr) { + &mxlookup(1,$server,"$server: could not resolve name",*users); + next HOST; + } + + # get a connection, or look for an mx + $0 = "$av0 - socket to $server"; + $that = pack($sockaddr, &AF_INET, $port, $thataddr); + socket(S, &AF_INET, &SOCK_STREAM, $proto) + || die "socket: $!"; + $0 = "$av0 - bind to $server"; + bind(S, $this) + || die "bind $hostname,0: $!"; + $0 = "$av0 - connect to $server"; + print "debug = $debug server = $server\n" if $debug > 8; + if (! connect(S, $that) || ($debug == 10 && $server =~ /relay\d.UU.NET$/i)) { + $0 = "$av0 - $server: could not connect: $!\n"; + $emsg = $!; + unless (&mxlookup(0,$server,"$server: could not connect: $!",*users)) { + &giveup('mx',"$server: Could not connect: $emsg"); + } + next HOST; + } + select((select(S),$| = 1)[0]); # don't buffer output to S + + # read the greeting + $0 = "$av0 - talking to $server"; + &alarm("greeting with $server",''); + while() { + alarm(0); + print if $watch; + if (/^(\d+)([- ])/) { + if ($1 != 220) { + $0 = "$av0 - bad numeric response from $server"; + &alarm("giving up after bad response from $server",''); + &read_response($2,$watch); + alarm(0); + print STDERR "$server: NOT 220 greeting: $_" + if ($debug || $vw); + if (&mxlookup(0,$server,"$server: did not respond with a 220 greeting",*users)) { + close(S); + next HOST; + } + } + last if ($2 eq " "); + } else { + $0 = "$av0 - bad response from $server"; + print STDERR "$server: NOT 220 greeting: $_" + if ($debug || $vw); + unless (&mxlookup(0,$server,"$server: did not respond with SMTP codes",*users)) { + &giveup('',"$server: did not talk SMTP"); + } + close(S); + next HOST; + } + &alarm("greeting with $server",''); + } + alarm(0); + + # if this causes problems, remove it + $0 = "$av0 - sending helo to $server"; + &alarm("sending helo to $server",""); + &ps("helo $hostname"); + while() { + print if $watch; + last if /^\d+ /; + } + alarm(0); + + # try the users, one by one + USER: + while(@users) { + $u = shift(@users); + $0 = "$av0 - expanding $u [\@$server]"; + + # do we already have a name for this user? + $oldname = $names{"$u *** $server"}; + + print &compact($u,$server)." ->\n" if ($verbose && ! $valid); + if ($valid) { + # + # when running with -a, we delay taking any action + # on the results of our query until we have looked + # at the complete output. @toFinal stores expansions + # that will be final if we take them. @toExpn stores + # expnansions that are not final. @isValid keeps + # track of our ability to send mail to each of the + # expansions. + # + @isValid = (); + @toFinal = (); + @toExpn = (); + } + +# ($ecode,@expansion) = &expn_vrfy($u,$server); + (@foo) = &expn_vrfy($u,$server); + ($ecode,@expansion) = @foo; + if ($ecode) { + &giveup('',$ecode,$u); + last USER; + } + + for $s (@expansion) { + $s =~ s/[\n\r]//g; + $0 = "$av0 - parsing $server: $s"; + + $skipwatch = $watch; + + if ($s =~ /^[25]51([- ]).*<(.+)>/) { + print "$s" if $watch; + print "(pretending 250$1<$2>)" if ($debug && $watch); + print "\n" if $watch; + $s = "250$1<$2>"; + $skipwatch = 0; + } + + if ($s =~ /^250([- ])(.+)/) { + print "$s\n" if $skipwatch; + ($done,$addr) = ($1,$2); + ($newhost, $newaddr, $newname) = &parse($addr,$server,$oldname, $#expansion == 0); + print "($newhost, $newaddr, $newname) = &parse($addr, $server, $oldname)\n" if $debug; + if (! $newhost) { + # no expansion is possible w/o a new server to call + if ($valid) { + push(@isValid, &validAddr($newaddr)); + push(@toFinal,$newaddr,$server,$newname); + } else { + &verbose(&final($newaddr,$server,$newname)); + } + } else { + $newmxhost = &mx($newhost,$newaddr); + print "$newmxhost = &mx($newhost)\n" + if ($debug && $newhost ne $newmxhost); + $0 = "$av0 - parsing $newaddr [@$newmxhost]"; + print "levels = $levels, level{$u *** $server} = ".$level{"$u *** $server"}."\n" if ($debug > 1); + # If the new server is the current one, + # it would have expanded things for us + # if it could have. Mx records must be + # followed to compare server names. + # We are also done if the recursion + # count has been exceeded. + if (&trhost($newmxhost) eq &trhost($server) || ($levels && $level{"$u *** $server"} >= $levels)) { + if ($valid) { + push(@isValid, &validAddr($newaddr)); + push(@toFinal,$newaddr,$newmxhost,$newname); + } else { + &verbose(&final($newaddr,$newmxhost,$newname)); + } + } else { + # more work to do... + if ($valid) { + push(@isValid, &validAddr($newaddr)); + push(@toExpn,$newmxhost,$newaddr,$newname,$level{"$u *** $server"}); + } else { + &verbose(&expn($newmxhost,$newaddr,$newname,$level{"$u *** $server"})); + } + } + } + last if ($done eq " "); + next; + } + # 550 is a known code... Should the be + # included in -a output? Might be a bug + # here. Does it matter? Can assume that + # there won't be UNKNOWN USER responses + # mixed with valid users? + if ($s =~ /^(550)([- ])/) { + if ($valid) { + print STDERR "\@$server:$u ($oldname) USER UNKNOWN\n"; + } else { + &verbose(&final($u,$server,$oldname,"USER UNKNOWN")); + } + last if ($2 eq " "); + next; + } + # 553 is a known code... + if ($s =~ /^(553)([- ])/) { + if ($valid) { + print STDERR "\@$server:$u ($oldname) USER AMBIGUOUS\n"; + } else { + &verbose(&final($u,$server,$oldname,"USER AMBIGUOUS")); + } + last if ($2 eq " "); + next; + } + # 252 is a known code... + if ($s =~ /^(252)([- ])/) { + if ($valid) { + print STDERR "\@$server:$u ($oldname) REFUSED TO VRFY\n"; + } else { + &verbose(&final($u,$server,$oldname,"REFUSED TO VRFY")); + } + last if ($2 eq " "); + next; + } + &giveup('',"$server: did not grok '$s'",$u); + last USER; + } + + if ($valid) { + # + # now we decide if we are going to take these + # expansions or roll them back. + # + $avgValid = &average(@isValid); + print "avgValid = $avgValid\n" if $debug; + if ($avgValid >= $validRequirement) { + print &compact($u,$server)." ->\n" if $verbose; + while (@toExpn) { + &verbose(&expn(splice(@toExpn,0,4))); + } + while (@toFinal) { + &verbose(&final(splice(@toFinal,0,3))); + } + } else { + print "Tossing some valid to avoid invalid ".&compact($u,$server)."\n" if ($avgValid > 0.0 && ($vw || $debug)); + print &compact($u,$server)." ->\n" if $verbose; + &verbose(&final($u,$server,$newname)); + } + } + } + + &alarm("sending 'quit' to $server",''); + $0 = "$av0 - sending 'quit' to $server"; + &ps("quit"); + while() { + print if $watch; + last if /^\d+ /; + } + close(S); + alarm(0); +} + +$0 = "$av0 - printing final results"; +print "----------\n" if $vw; +select(STDOUT); +for $f (sort @final) { + print "$f\n"; +} +unlink("/tmp/expn$$"); +exit(0); + + +# abandon all attempts deliver to $server +# register the current addresses as the final ones +sub giveup +{ + local($redirect_okay,$reason,$user) = @_; + local($us,@so,$nh,@remaining_users); + local($pk,$file,$line); + ($pk, $file, $line) = caller; + + $0 = "$av0 - giving up on $server: $reason"; + # + # add back a user if we gave up in the middle + # + push(@users,$user) if $user; + # + # don't bother with this system anymore + # + unless ($giveup{$server}) { + $giveup{$server} = $reason; + print STDERR "$reason\n"; + } + print "Giveup at $file:$line!!! redirect okay = $redirect_okay; $reason\n" if $debug; + # + # Wait! + # Before giving up, see if there is a chance that + # there is another host to redirect to! + # (Kids, don't do this at home! Hacking is a dangerous + # crime and you could end up behind bars.) + # + for $u (@users) { + if ($redirect_okay =~ /\bmx\b/) { + next if &try_fallback('mx',$u,*server, + *mx_secondary, + *already_mx_fellback); + } + if ($redirect_okay =~ /\bdomainify\b/) { + next if &try_fallback('domainify',$u,*server, + *domainify_fallback, + *already_domainify_fellback); + } + push(@remaining_users,$u); + } + @users = @remaining_users; + for $u (@users) { + print &compact($u,$server)." ->\n" if ($verbose && $valid && $u); + &verbose(&final($u,$server,$names{"$u *** $server"},$reason)); + } +} +# +# This routine is used only within &giveup. It checks to +# see if we really have to giveup or if there is a second +# chance because we did something before that can be +# backtracked. +# +# %fallback{"$user *** $host"} tracks what is able to fallback +# %fellback{"$user *** $host"} tracks what has fallen back +# +# If there is a valid backtrack, then queue up the new possibility +# +sub try_fallback +{ + local($method,$user,*host,*fall_table,*fellback) = @_; + local($us,$fallhost,$oldhost,$ft,$i); + + if ($debug > 8) { + print "Fallback table $method:\n"; + for $i (sort keys %fall_table) { + print "\t'$i'\t\t'$fall_table{$i}'\n"; + } + print "Fellback table $method:\n"; + for $i (sort keys %fellback) { + print "\t'$i'\t\t'$fellback{$i}'\n"; + } + print "U: $user H: $host\n"; + } + + $us = "$user *** $host"; + if (defined $fellback{$us}) { + # + # Undo a previous fallback so that we can try again + # Nested fallbacks are avoided because they could + # lead to infinite loops + # + $fallhost = $fellback{$us}; + print "Already $method fell back from $us -> \n" if $debug; + $us = "$user *** $fallhost"; + $oldhost = $fallhost; + } elsif (($method eq 'mx') && (defined $mxbacktrace{$us}) && (defined $mx_secondary{$mxbacktrace{$us}})) { + print "Fallback an MX expansion $us -> \n" if $debug; + $oldhost = $mxbacktrace{$us}; + } else { + print "Oldhost($host, $us) = " if $debug; + $oldhost = $host; + } + print "$oldhost\n" if $debug; + if (((defined $fall_table{$us}) && ($ft = $us)) || ((defined $fall_table{$oldhost}) && ($ft = $oldhost))) { + print "$method Fallback = ".$fall_table{$ft}."\n" if $debug; + local(@so,$newhost); + @so = split(' ',$fall_table{$ft}); + $newhost = shift(@so); + print "Falling back ($method) $us -> $newhost (from $oldhost)\n" if $debug; + if ($method eq 'mx') { + if (! defined ($mxbacktrace{"$user *** $newhost"})) { + if (defined $mxbacktrace{"$user *** $oldhost"}) { + print "resetting oldhost $oldhost to the original: " if $debug; + $oldhost = $mxbacktrace{"$user *** $oldhost"}; + print "$oldhost\n" if $debug; + } + $mxbacktrace{"$user *** $newhost"} = $oldhost; + print "mxbacktrace $user *** $newhost -> $oldhost\n" if $debug; + } + $mx{&trhost($oldhost)} = $newhost; + } else { + $temporary_redirect{$us} = $newhost; + } + if (@so) { + print "Can still $method $us: @so\n" if $debug; + $fall_table{$ft} = join(' ',@so); + } else { + print "No more fallbacks for $us\n" if $debug; + delete $fall_table{$ft}; + } + if (defined $create_host_backtrack{$us}) { + $create_host_backtrack{"$user *** $newhost"} + = $create_host_backtrack{$us}; + } + $fellback{"$user *** $newhost"} = $oldhost; + &expn($newhost,$user,$names{$us},$level{$us}); + return 1; + } + delete $temporary_redirect{$us}; + $host = $oldhost; + return 0; +} +# return 1 if you could send mail to the address as is. +sub validAddr +{ + local($addr) = @_; + $res = &do_validAddr($addr); + print "validAddr($addr) = $res\n" if $debug; + $res; +} +sub do_validAddr +{ + local($addr) = @_; + local($urx) = "[-A-Za-z_.0-9+]+"; + + # \u + return 0 if ($addr =~ /^\\/); + # ?@h + return 1 if ($addr =~ /.\@$urx$/); + # @h:? + return 1 if ($addr =~ /^\@$urx\:./); + # h!u + return 1 if ($addr =~ /^$urx!./); + # u + return 1 if ($addr =~ /^$urx$/); + # ? + print "validAddr($addr) = ???\n" if $debug; + return 0; +} +# Some systems use expn and vrfy interchangeably. Some only +# implement one or the other. Some check expn against mailing +# lists and vrfy against users. It doesn't appear to be +# consistent. +# +# So, what do we do? We try everything! +# +# +# Ranking of result codes: good: 250, 251/551, 252, 550, anything else +# +# Ranking of inputs: best: user@host.domain, okay: user +# +# Return value: $error_string, @responses_from_server +sub expn_vrfy +{ + local($u,$server) = @_; + local(@c) = ('expn', 'vrfy'); + local(@try_u) = $u; + local(@ret,$code); + + if (($u =~ /(.+)@(.+)/) && (&trhost($2) eq &trhost($server))) { + push(@try_u,$1); + } + + TRY: + for $c (@c) { + for $try_u (@try_u) { + &alarm("${c}'ing $try_u on $server",'',$u); + &ps("$c $try_u"); + alarm(0); + $s = ; + if ($s eq '') { + return "$server: lost connection"; + } + if ($s !~ /^(\d+)([- ])/) { + return "$server: garbled reply to '$c $try_u'"; + } + if ($1 == 250) { + $code = 250; + @ret = ("",$s); + push(@ret,&read_response($2,$debug)); + return (@ret); + } + if ($1 == 551 || $1 == 251) { + $code = $1; + @ret = ("",$s); + push(@ret,&read_response($2,$debug)); + next; + } + if ($1 == 252 && ($code == 0 || $code == 550)) { + $code = 252; + @ret = ("",$s); + push(@ret,&read_response($2,$watch)); + next; + } + if ($1 == 550 && $code == 0) { + $code = 550; + @ret = ("",$s); + push(@ret,&read_response($2,$watch)); + next; + } + &read_response($2,$watch); + } + } + return "$server: expn/vrfy not implemented" unless @ret; + return @ret; +} +# sometimes the old parse routine (now parse2) didn't +# reject funky addresses. +sub parse +{ + local($oldaddr,$server,$oldname,$one_to_one) = @_; + local($newhost, $newaddr, $newname, $um) = &parse2($oldaddr,$server,$oldname,$one_to_one); + if ($newaddr =~ m,^["/],) { + return (undef, $oldaddr, $newname) if $valid; + return (undef, $um, $newname); + } + return ($newhost, $newaddr, $newname); +} + +# returns ($new_smtp_server,$new_address,$new_name) +# given a response from a SMTP server ($newaddr), the +# current host ($server), the old "name" and a flag that +# indicates if it is being called during the initial +# command line parsing ($parsing_args) +sub parse2 +{ + local($newaddr,$context_host,$old_name,$parsing_args) = @_; + local(@names) = $old_name; + local($urx) = "[-A-Za-z_.0-9+]+"; + local($unmangle); + + # + # first, separate out the address part. + # + + # + # [NAME] + # [NAME] <[(NAME)] ADDR + # ADDR [(NAME)] + # (NAME) ADDR + # [(NAME)] + # + if ($newaddr =~ /^\<(.*)\>$/) { + print "\n" if $debug; + ($newaddr) = &trim($1); + print "na = $newaddr\n" if $debug; + } + if ($newaddr =~ /^([^\<\>]*)\<([^\<\>]*)\>([^\<\>]*)$/) { + # address has a < > pair in it. + print "N:$1 N:$3\n" if $debug; + ($newaddr) = &trim($2); + unshift(@names, &trim($3,$1)); + print "na = $newaddr\n" if $debug; + } + if ($newaddr =~ /^([^\(\)]*)\(([^\(\)]*)\)([^\(\)]*)$/) { + # address has a ( ) pair in it. + print "A:$1 (N:$2) A:$3\n" if $debug; + unshift(@names,&trim($2)); + local($f,$l) = (&trim($1),&trim($3)); + if (($f && $l) || !($f || $l)) { + # address looks like: + # foo (bar) baz or (bar) + # not allowed! + print STDERR "Could not parse $newaddr\n" if $vw; + return(undef,$newaddr,&firstname(@names)); + } + $newaddr = $f if $f; + $newaddr = $l if $l; + print "newaddr now = $newaddr\n" if $debug; + } + # + # @foo:bar + # j%k@l + # a@b + # b!a + # a + # + $unmangle = $newaddr; + if ($newaddr =~ /^\@($urx)\:(.+)$/) { + print "(\@:)" if $debug; + # this is a bit of a cheat, but it seems necessary + return (&domainify($1,$context_host,$2),$2,&firstname(@names),$unmangle); + } + if ($newaddr =~ /^(.+)\@($urx)$/) { + print "(\@)" if $debug; + return (&domainify($2,$context_host,$newaddr),$newaddr,&firstname(@names),$unmangle); + } + if ($parsing_args) { + if ($newaddr =~ /^($urx)\!(.+)$/) { + return (&domainify($1,$context_host,$newaddr),$newaddr,&firstname(@names),$unmangle); + } + if ($newaddr =~ /^($urx)$/) { + return ($context_host,$newaddr,&firstname(@names),$unmangle); + } + print STDERR "Could not parse $newaddr\n"; + } + print "(?)" if $debug; + return(undef,$newaddr,&firstname(@names),$unmangle); +} +# return $u (@$server) unless $u includes reference to $server +sub compact +{ + local($u, $server) = @_; + local($se) = $server; + local($sp); + $se =~ s/(\W)/\\$1/g; + $sp = " (\@$server)"; + if ($u !~ /$se/i) { + return "$u$sp"; + } + return $u; +} +# remove empty (spaces don't count) members from an array +sub trim +{ + local(@v) = @_; + local($v,@r); + for $v (@v) { + $v =~ s/^\s+//; + $v =~ s/\s+$//; + push(@r,$v) if ($v =~ /\S/); + } + return(@r); +} +# using the host part of an address, and the server name, add the +# servers' domain to the address if it doesn't already have a +# domain. Since this sometimes fails, save a back reference so +# it can be unrolled. +sub domainify +{ + local($host,$domain_host,$u) = @_; + local($domain,$newhost); + + # cut of trailing dots + $host =~ s/\.$//; + $domain_host =~ s/\.$//; + + if ($domain_host !~ /\./) { + # + # domain host isn't, keep $host whatever it is + # + print "domainify($host,$domain_host) = $host\n" if $debug; + return $host; + } + + # + # There are several weird situtations that need to be + # accounted for. They have to do with domain relay hosts. + # + # Examples: + # host server "right answer" + # + # shiva.cs cs.berkeley.edu shiva.cs.berkeley.edu + # shiva cs.berkeley.edu shiva.cs.berekley.edu + # cumulus reed.edu @reed.edu:cumulus.uucp + # tiberius tc.cornell.edu tiberius.tc.cornell.edu + # + # The first try must always be to cut the domain part out of + # the server and tack it onto the host. + # + # A reasonable second try is to tack the whole server part onto + # the host and for each possible repeated element, eliminate + # just that part. + # + # These extra "guesses" get put into the %domainify_fallback + # array. They will be used to give addresses a second chance + # in the &giveup routine + # + + local(%fallback); + + local($long); + $long = "$host $domain_host"; + $long =~ tr/A-Z/a-z/; + print "long = $long\n" if $debug; + if ($long =~ s/^([^ ]+\.)([^ ]+) \2(\.[^ ]+\.[^ ]+)/$1$2$3/) { + # matches shiva.cs cs.berkeley.edu and returns shiva.cs.berkeley.edu + print "condensed fallback $host $domain_host -> $long\n" if $debug; + $fallback{$long} = 9; + } + + local($fh); + $fh = $domain_host; + while ($fh =~ /\./) { + print "FALLBACK $host.$fh = 1\n" if $debug > 7; + $fallback{"$host.$fh"} = 1; + $fh =~ s/^[^\.]+\.//; + } + + $fallback{"$host.$domain_host"} = 2; + + ($domain = $domain_host) =~ s/^[^\.]+//; + $fallback{"$host$domain"} = 6 + if ($domain =~ /\./); + + if ($host =~ /\./) { + # + # Host is already okay, but let's look for multiple + # interpretations + # + print "domainify($host,$domain_host) = $host\n" if $debug; + delete $fallback{$host}; + $domainify_fallback{"$u *** $host"} = join(' ',sort {$fallback{$b} <=> $fallback{$a};} keys %fallback) if %fallback; + return $host; + } + + $domain = ".$domain_host" + if ($domain !~ /\..*\./); + $newhost = "$host$domain"; + + $create_host_backtrack{"$u *** $newhost"} = $domain_host; + print "domainify($host,$domain_host) = $newhost\n" if $debug; + delete $fallback{$newhost}; + $domainify_fallback{"$u *** $newhost"} = join(' ',sort {$fallback{$b} <=> $fallback{$a};} keys %fallback) if %fallback; + if ($debug) { + print "fallback = "; + print $domainify_fallback{"$u *** $newhost"} + if defined($domainify_fallback{"$u *** $newhost"}); + print "\n"; + } + return $newhost; +} +# return the first non-empty element of an array +sub firstname +{ + local(@names) = @_; + local($n); + while(@names) { + $n = shift(@names); + return $n if $n =~ /\S/; + } + return undef; +} +# queue up more addresses to expand +sub expn +{ + local($host,$addr,$name,$level) = @_; + if ($host) { + $host = &trhost($host); + + if (($debug > 3) || (defined $giveup{$host})) { + unshift(@hosts,$host) unless $users{$host}; + } else { + push(@hosts,$host) unless $users{$host}; + } + $users{$host} .= " $addr"; + $names{"$addr *** $host"} = $name; + $level{"$addr *** $host"} = $level + 1; + print "expn($host,$addr,$name)\n" if $debug; + return "\t$addr\n"; + } else { + return &final($addr,'NONE',$name); + } +} +# compute the numerical average value of an array +sub average +{ + local(@e) = @_; + return 0 unless @e; + local($e,$sum); + for $e (@e) { + $sum += $e; + } + $sum / @e; +} +# print to the server (also to stdout, if -w) +sub ps +{ + local($p) = @_; + print ">>> $p\n" if $watch; + print S "$p\n"; +} +# return case-adjusted name for a host (for comparison purposes) +sub trhost +{ + # treat foo.bar as an alias for Foo.BAR + local($host) = @_; + local($trhost) = $host; + $trhost =~ tr/A-Z/a-z/; + if ($trhost{$trhost}) { + $host = $trhost{$trhost}; + } else { + $trhost{$trhost} = $host; + } + $trhost{$trhost}; +} +# re-queue users if an mx record dictates a redirect +# don't allow a user to be redirected more than once +sub mxredirect +{ + local($server,*users) = @_; + local($u,$nserver,@still_there); + + $nserver = &mx($server); + + if (&trhost($nserver) ne &trhost($server)) { + $0 = "$av0 - mx redirect $server -> $nserver\n"; + for $u (@users) { + if (defined $mxbacktrace{"$u *** $nserver"}) { + push(@still_there,$u); + } else { + $mxbacktrace{"$u *** $nserver"} = $server; + print "mxbacktrace{$u *** $nserver} = $server\n" + if ($debug > 1); + &expn($nserver,$u,$names{"$u *** $server"}); + } + } + @users = @still_there; + if (! @users) { + return $nserver; + } else { + return undef; + } + } + return undef; +} +# follow mx records, return a hostname +# also follow temporary redirections comming from &domainify and +# &mxlookup +sub mx +{ + local($h,$u) = @_; + + for (;;) { + if (defined $mx{&trhost($h)} && $h ne $mx{&trhost($h)}) { + $0 = "$av0 - mx expand $h"; + $h = $mx{&trhost($h)}; + return $h; + } + if ($u) { + if (defined $temporary_redirect{"$u *** $h"}) { + $0 = "$av0 - internal redirect $h"; + print "Temporary redirect taken $u *** $h -> " if $debug; + $h = $temporary_redirect{"$u *** $h"}; + print "$h\n" if $debug; + next; + } + $htr = &trhost($h); + if (defined $temporary_redirect{"$u *** $htr"}) { + $0 = "$av0 - internal redirect $h"; + print "temporary redirect taken $u *** $h -> " if $debug; + $h = $temporary_redirect{"$u *** $htr"}; + print "$h\n" if $debug; + next; + } + } + return $h; + } +} +# look up mx records with the name server. +# re-queue expansion requests if possible +# optionally give up on this host. +sub mxlookup +{ + local($lastchance,$server,$giveup,*users) = @_; + local(*T); + local(*NSLOOKUP); + local($nh, $pref,$cpref); + local($o0) = $0; + local($nserver); + local($name,$aliases,$type,$len,$thataddr); + local(%fallback); + + return 1 if &mxredirect($server,*users); + + if ((defined $mx{$server}) || (! $have_nslookup)) { + return 0 unless $lastchance; + &giveup('mx domainify',$giveup); + return 0; + } + + $0 = "$av0 - nslookup of $server"; + open(T,">/tmp/expn$$") || die "open > /tmp/expn$$: $!\n"; + print T "set querytype=MX\n"; + print T "$server\n"; + close(T); + $cpref = 1.0E12; + undef $nserver; + open(NSLOOKUP,"nslookup < /tmp/expn$$ 2>&1 |") || die "open nslookup: $!"; + while() { + print if ($debug > 2); + if (/mail exchanger = ([-A-Za-z_.0-9+]+)/) { + $nh = $1; + if (/preference = (\d+)/) { + $pref = $1; + if ($pref < $cpref) { + $nserver = $nh; + $cpref = $pref; + } elsif ($pref) { + $fallback{$pref} .= " $nh"; + } + } + } + if (/Non-existent domain/) { + # + # These addresss are hosed. Kaput! Dead! + # However, if we created the address in the + # first place then there is a chance of + # salvation. + # + 1 while(); + close(NSLOOKUP); + return 0 unless $lastchance; + &giveup('domainify',"$server: Non-existent domain",undef,1); + return 0; + } + + } + close(NSLOOKUP); + unlink("/tmp/expn$$"); + unless ($nserver) { + $0 = "$o0 - finished mxlookup"; + return 0 unless $lastchance; + &giveup('mx domainify',"$server: Could not resolve address"); + return 0; + } + + # provide fallbacks in case $nserver doesn't work out + if (defined $fallback{$cpref}) { + $mx_secondary{$server} = $fallback{$cpref}; + } + + $0 = "$av0 - gethostbyname($nserver)"; + ($name,$aliases,$type,$len,$thataddr) = gethostbyname($nserver); + + unless ($thataddr) { + $0 = $o0; + return 0 unless $lastchance; + &giveup('mx domainify',"$nserver: could not resolve address"); + return 0; + } + print "MX($server) = $nserver\n" if $debug; + print "$server -> $nserver\n" if $vw && !$debug; + $mx{&trhost($server)} = $nserver; + # redeploy the users + unless (&mxredirect($server,*users)) { + return 0 unless $lastchance; + &giveup('mx domainify',"$nserver: only one level of mx redirect allowed"); + return 0; + } + $0 = "$o0 - finished mxlookup"; + return 1; +} +# if mx expansion did not help to resolve an address +# (ie: foo@bar became @baz:foo@bar, then undo the +# expansion). +# this is only used by &final +sub mxunroll +{ + local(*host,*addr) = @_; + local($r) = 0; + print "looking for mxbacktrace{$addr *** $host}\n" + if ($debug > 1); + while (defined $mxbacktrace{"$addr *** $host"}) { + print "Unrolling MX expnasion: \@$host:$addr -> " + if ($debug || $verbose); + $host = $mxbacktrace{"$addr *** $host"}; + print "\@$host:$addr\n" + if ($debug || $verbose); + $r = 1; + } + return 1 if $r; + $addr = "\@$host:$addr" + if ($host =~ /\./); + return 0; +} +# register a completed expnasion. Make the final address as +# simple as possible. +sub final +{ + local($addr,$host,$name,$error) = @_; + local($he); + local($hb,$hr); + local($au,$ah); + + if ($error =~ /Non-existent domain/) { + # + # If we created the domain, then let's undo the + # damage... + # + if (defined $create_host_backtrack{"$addr *** $host"}) { + while (defined $create_host_backtrack{"$addr *** $host"}) { + print "Un&domainifying($host) = " if $debug; + $host = $create_host_backtrack{"$addr *** $host"}; + print "$host\n" if $debug; + } + $error = "$host: could not locate"; + } else { + # + # If we only want valid addresses, toss out + # bad host names. + # + if ($valid) { + print STDERR "\@$host:$addr ($name) Non-existent domain\n"; + return ""; + } + } + } + + MXUNWIND: { + $0 = "$av0 - final parsing of \@$host:$addr"; + ($he = $host) =~ s/(\W)/\\$1/g; + if ($addr !~ /@/) { + # addr does not contain any host + $addr = "$addr@$host"; + } elsif ($addr !~ /$he/i) { + # if host part really something else, use the something + # else. + if ($addr =~ m/(.*)\@([^\@]+)$/) { + ($au,$ah) = ($1,$2); + print "au = $au ah = $ah\n" if $debug; + if (defined $temporary_redirect{"$addr *** $ah"}) { + $addr = "$au\@".$temporary_redirect{"$addr *** $ah"}; + print "Rewrite! to $addr\n" if $debug; + next MXUNWIND; + } + } + # addr does not contain full host + if ($valid) { + if ($host =~ /^([^\.]+)(\..+)$/) { + # host part has a . in it - foo.bar + ($hb, $hr) = ($1, $2); + if ($addr =~ /\@([^\.\@]+)$/ && ($1 eq $hb)) { + # addr part has not . + # and matches beginning of + # host part -- tack on a + # domain name. + $addr .= $hr; + } else { + &mxunroll(*host,*addr) + && redo MXUNWIND; + } + } else { + &mxunroll(*host,*addr) + && redo MXUNWIND; + } + } else { + $addr = "${addr}[\@$host]" + if ($host =~ /\./); + } + } + } + $name = "$name " if $name; + $error = " $error" if $error; + if ($valid) { + push(@final,"$name<$addr>"); + } else { + push(@final,"$name<$addr>$error"); + } + "\t$name<$addr>$error\n"; +} + +sub alarm +{ + local($alarm_action,$alarm_redirect,$alarm_user) = @_; + alarm(3600); + $SIG{ALRM} = 'handle_alarm'; +} +# this involves one great big ugly hack. +# the "next HOST" unwinds the stack! +sub handle_alarm +{ + &giveup($alarm_redirect,"Timed out during $alarm_action",$alarm_user); + next HOST; +} + +# read the rest of the current smtp daemon's response (and toss it away) +sub read_response +{ + local($done,$watch) = @_; + local(@resp); + print $s if $watch; + while(($done eq "-") && ($s = ) && ($s =~ /^\d+([- ])/)) { + print $s if $watch; + $done = $1; + push(@resp,$s); + } + return @resp; +} +# print args if verbose. Return them in any case +sub verbose +{ + local(@tp) = @_; + print "@tp" if $verbose; +} +# to pass perl -w: +@tp; +$flag_a; +$flag_d; +$flag_1; +%already_domainify_fellback; +%already_mx_fellback; +&handle_alarm; +################### BEGIN PERL/TROFF TRANSITION +.00 ; + +'di +.nr nl 0-1 +.nr % 0 +.\\"'; __END__ +.\" ############## END PERL/TROFF TRANSITION +.TH EXPN 1 "March 11, 1993" +.AT 3 +.SH NAME +expn \- recursively expand mail aliases +.SH SYNOPSIS +.B expn +.RI [ -a ] +.RI [ -v ] +.RI [ -w ] +.RI [ -d ] +.RI [ -1 ] +.IR user [@ hostname ] +.RI [ user [@ hostname ]]... +.SH DESCRIPTION +.B expn +will use the SMTP +.B expn +and +.B vrfy +commands to expand mail aliases. +It will first look up the addresses you provide on the command line. +If those expand into addresses on other systems, it will +connect to the other systems and expand again. It will keep +doing this until no further expansion is possible. +.SH OPTIONS +The default output of +.B expn +can contain many lines which are not valid +email addresses. With the +.I -aa +flag, only expansions that result in legal addresses +are used. Since many mailing lists have an illegal +address or two, the single +.IR -a , +address, flag specifies that a few illegal addresses can +be mixed into the results. More +.I -a +flags vary the ratio. Read the source to track down +the formula. With the +.I -a +option, you should be able to construct a new mailing +list out of an existing one. +.LP +If you wish to limit the number of levels deep that +.B expn +will recurse as it traces addresses, use the +.I -1 +option. For each +.I -1 +another level will be traversed. So, +.I -111 +will traverse no more than three levels deep. +.LP +The normal mode of operation for +.B expn +is to do all of its work silently. +The following options make it more verbose. +It is not necessary to make it verbose to see what it is +doing because as it works, it changes its +.BR argv [0] +variable to reflect its current activity. +To see how it is expanding things, the +.IR -v , +verbose, flag will cause +.B expn +to show each address before +and after translation as it works. +The +.IR -w , +watch, flag will cause +.B expn +to show you its conversations with the mail daemons. +Finally, the +.IR -d , +debug, flag will expose many of the inner workings so that +it is possible to eliminate bugs. +.SH ENVIRONMENT +No enviroment variables are used. +.SH FILES +.PD 0 +.B /tmp/expn$$ +.B temporary file used as input to +.BR nslookup . +.SH SEE ALSO +.BR aliases (5), +.BR sendmail (8), +.BR nslookup (8), +RFC 823, and RFC 1123. +.SH BUGS +Not all mail daemons will implement +.B expn +or +.BR vrfy . +It is not possible to verify addresses that are served +by such daemons. +.LP +When attempting to connect to a system to verify an address, +.B expn +only tries one IP address. Most mail daemons +will try harder. +.LP +It is assumed that you are running domain names and that +the +.BR nslookup (8) +program is available. If not, +.B expn +will not be able to verify many addresses. It will also pause +for a long time unless you change the code where it says +.I $have_nslookup = 1 +to read +.I $have_nslookup = +.IR 0 . +.LP +Lastly, +.B expn +does not handle every valid address. If you have an example, +please submit a bug report. +.SH CREDITS +In 1986 or so, Jon Broome wrote a program of the same name +that did about the same thing. It has since suffered bit rot +and Jon Broome has dropped off the face of the earth! +(Jon, if you are out there, drop me a line) +.SH AVAILABILITY +The latest version of +.B expn +is available through anonymous ftp at +.IR ftp://ftp.idiom.com/pub/muir-programs/expn . +.SH AUTHOR +.I David Muir Sharnoff\ \ \ \ diff --git a/contrib/amd/scripts/expn.in b/contrib/amd/scripts/expn.in new file mode 100755 index 0000000..b2bd1b6 --- /dev/null +++ b/contrib/amd/scripts/expn.in @@ -0,0 +1,1370 @@ +#!@PERL@ +'di '; +'ds 00 \\"'; +'ig 00 '; +# +# THIS PROGRAM IS ITS OWN MANUAL PAGE. INSTALL IN man & bin. +# + +# hardcoded constants, should work fine for BSD-based systems +#require 'sys/socket.ph'; # perl 4 +use Socket; # perl 5 +$AF_INET = &AF_INET; +$SOCK_STREAM = &SOCK_STREAM; +$sockaddr = 'S n a4 x8'; + +# system requirements: +# must have 'nslookup' and 'hostname' programs. + +# $Header: /home/muir/bin/RCS/expn,v 3.9 1995/10/02 17:51:35 muir Exp muir $ + +# TODO: +# less magic should apply to command-line addresses +# less magic should apply to local addresses +# add magic to deal with cross-domain cnames + +# Checklist: (hard addresses) +# 250 Kimmo Suominen <"|/usr/local/mh/lib/slocal -user kim"@grendel.tac.nyc.ny.us> +# harry@hofmann.cs.Berkeley.EDU -> harry@tenet (.berkeley.edu) [dead] +# bks@cs.berkeley.edu -> shiva.CS (.berkeley.edu) [dead] +# dan@tc.cornell.edu -> brown@tiberius (.tc.cornell.edu) + +############################################################################# +# +# Copyright (c) 1993 David Muir Sharnoff +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the David Muir Sharnoff. +# 4. The name of David Sharnoff may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE DAVID MUIR SHARNOFF ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL DAVID MUIR SHARNOFF BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# This copyright notice derrived from material copyrighted by the Regents +# of the University of California. +# +# Contributions accepted. +# +############################################################################# + +# overall structure: +# in an effort to not trace each address individually, but rather +# ask each server in turn a whole bunch of questions, addresses to +# be expanded are queued up. +# +# This means that all accounting w.r.t. an address must be stored in +# various arrays. Generally these arrays are indexed by the +# string "$addr *** $server" where $addr is the address to be +# expanded "foo" or maybe "foo@bar" and $server is the hostname +# of the SMTP server to contact. +# + +# important global variables: +# +# @hosts : list of servers still to be contacted +# $server : name of the current we are currently looking at +# @users = $users{@hosts[0]} : addresses to expand at this server +# $u = $users[0] : the current address being expanded +# $names{"$users[0] *** $server"} : the 'name' associated with the address +# $mxbacktrace{"$users[0] *** $server"} : record of mx expansion +# $mx_secondary{$server} : other mx relays at the same priority +# $domainify_fallback{"$users[0] *** $server"} : alternative names to try +# instead of $server if $server doesn't work +# $temporary_redirect{"$users[0] *** $server"} : when trying alternates, +# temporarily channel all tries along current path +# $giveup{$server} : do not bother expanding addresses at $server +# $verbose : -v +# $watch : -w +# $vw : -v or -w +# $debug : -d +# $valid : -a +# $levels : -1 +# S : the socket connection to $server + +$have_nslookup = 1; # we have the nslookup program +$port = 'smtp'; +$av0 = $0; +$ENV{'PATH'} .= ":/usr/etc" unless $ENV{'PATH'} =~ m,/usr/etc,; +$ENV{'PATH'} .= ":/usr/ucb" unless $ENV{'PATH'} =~ m,/usr/ucb,; +select(STDERR); + +$0 = "$av0 - running hostname"; +chop($name = `hostname || uname -n`); + +$0 = "$av0 - lookup host FQDN and IP addr"; +($hostname,$aliases,$type,$len,$thisaddr) = gethostbyname($name); + +$0 = "$av0 - parsing args"; +$usage = "Usage: $av0 [-1avwd] user[\@host] [user2[host2] ...]"; +for $a (@ARGV) { + die $usage if $a eq "-"; + while ($a =~ s/^(-.*)([1avwd])/$1/) { + eval '$'."flag_$2 += 1"; + } + next if $a eq "-"; + die $usage if $a =~ /^-/; + &expn(&parse($a,$hostname,undef,1)); +} +$verbose = $flag_v; +$watch = $flag_w; +$vw = $flag_v + $flag_w; +$debug = $flag_d; +$valid = $flag_a; +$levels = $flag_1; + +die $usage unless @hosts; +if ($valid) { + if ($valid == 1) { + $validRequirement = 0.8; + } elsif ($valid == 2) { + $validRequirement = 1.0; + } elsif ($valid == 3) { + $validRequirement = 0.9; + } else { + $validRequirement = (1 - (1/($valid-3))); + print "validRequirement = $validRequirement\n" if $debug; + } +} + +$0 = "$av0 - building local socket"; +($name,$aliases,$proto) = getprotobyname('tcp'); +($name,$aliases,$port) = getservbyname($port,'tcp') + unless $port =~ /^\d+/; +$this = pack($sockaddr, &AF_INET, 0, $thisaddr); + +HOST: +while (@hosts) { + $server = shift(@hosts); + @users = split(' ',$users{$server}); + delete $users{$server}; + + # is this server already known to be bad? + $0 = "$av0 - looking up $server"; + if ($giveup{$server}) { + &giveup('mx domainify',$giveup{$server}); + next; + } + + # do we already have an mx record for this host? + next HOST if &mxredirect($server,*users); + + # look it up, or try for an mx. + $0 = "$av0 - gethostbyname($server)"; + + ($name,$aliases,$type,$len,$thataddr) = gethostbyname($server); + # if we can't get an A record, try for an MX record. + unless($thataddr) { + &mxlookup(1,$server,"$server: could not resolve name",*users); + next HOST; + } + + # get a connection, or look for an mx + $0 = "$av0 - socket to $server"; + $that = pack($sockaddr, &AF_INET, $port, $thataddr); + socket(S, &AF_INET, &SOCK_STREAM, $proto) + || die "socket: $!"; + $0 = "$av0 - bind to $server"; + bind(S, $this) + || die "bind $hostname,0: $!"; + $0 = "$av0 - connect to $server"; + print "debug = $debug server = $server\n" if $debug > 8; + if (! connect(S, $that) || ($debug == 10 && $server =~ /relay\d.UU.NET$/i)) { + $0 = "$av0 - $server: could not connect: $!\n"; + $emsg = $!; + unless (&mxlookup(0,$server,"$server: could not connect: $!",*users)) { + &giveup('mx',"$server: Could not connect: $emsg"); + } + next HOST; + } + select((select(S),$| = 1)[0]); # don't buffer output to S + + # read the greeting + $0 = "$av0 - talking to $server"; + &alarm("greeting with $server",''); + while() { + alarm(0); + print if $watch; + if (/^(\d+)([- ])/) { + if ($1 != 220) { + $0 = "$av0 - bad numeric response from $server"; + &alarm("giving up after bad response from $server",''); + &read_response($2,$watch); + alarm(0); + print STDERR "$server: NOT 220 greeting: $_" + if ($debug || $vw); + if (&mxlookup(0,$server,"$server: did not respond with a 220 greeting",*users)) { + close(S); + next HOST; + } + } + last if ($2 eq " "); + } else { + $0 = "$av0 - bad response from $server"; + print STDERR "$server: NOT 220 greeting: $_" + if ($debug || $vw); + unless (&mxlookup(0,$server,"$server: did not respond with SMTP codes",*users)) { + &giveup('',"$server: did not talk SMTP"); + } + close(S); + next HOST; + } + &alarm("greeting with $server",''); + } + alarm(0); + + # if this causes problems, remove it + $0 = "$av0 - sending helo to $server"; + &alarm("sending helo to $server",""); + &ps("helo $hostname"); + while() { + print if $watch; + last if /^\d+ /; + } + alarm(0); + + # try the users, one by one + USER: + while(@users) { + $u = shift(@users); + $0 = "$av0 - expanding $u [\@$server]"; + + # do we already have a name for this user? + $oldname = $names{"$u *** $server"}; + + print &compact($u,$server)." ->\n" if ($verbose && ! $valid); + if ($valid) { + # + # when running with -a, we delay taking any action + # on the results of our query until we have looked + # at the complete output. @toFinal stores expansions + # that will be final if we take them. @toExpn stores + # expnansions that are not final. @isValid keeps + # track of our ability to send mail to each of the + # expansions. + # + @isValid = (); + @toFinal = (); + @toExpn = (); + } + +# ($ecode,@expansion) = &expn_vrfy($u,$server); + (@foo) = &expn_vrfy($u,$server); + ($ecode,@expansion) = @foo; + if ($ecode) { + &giveup('',$ecode,$u); + last USER; + } + + for $s (@expansion) { + $s =~ s/[\n\r]//g; + $0 = "$av0 - parsing $server: $s"; + + $skipwatch = $watch; + + if ($s =~ /^[25]51([- ]).*<(.+)>/) { + print "$s" if $watch; + print "(pretending 250$1<$2>)" if ($debug && $watch); + print "\n" if $watch; + $s = "250$1<$2>"; + $skipwatch = 0; + } + + if ($s =~ /^250([- ])(.+)/) { + print "$s\n" if $skipwatch; + ($done,$addr) = ($1,$2); + ($newhost, $newaddr, $newname) = &parse($addr,$server,$oldname, $#expansion == 0); + print "($newhost, $newaddr, $newname) = &parse($addr, $server, $oldname)\n" if $debug; + if (! $newhost) { + # no expansion is possible w/o a new server to call + if ($valid) { + push(@isValid, &validAddr($newaddr)); + push(@toFinal,$newaddr,$server,$newname); + } else { + &verbose(&final($newaddr,$server,$newname)); + } + } else { + $newmxhost = &mx($newhost,$newaddr); + print "$newmxhost = &mx($newhost)\n" + if ($debug && $newhost ne $newmxhost); + $0 = "$av0 - parsing $newaddr [@$newmxhost]"; + print "levels = $levels, level{$u *** $server} = ".$level{"$u *** $server"}."\n" if ($debug > 1); + # If the new server is the current one, + # it would have expanded things for us + # if it could have. Mx records must be + # followed to compare server names. + # We are also done if the recursion + # count has been exceeded. + if (&trhost($newmxhost) eq &trhost($server) || ($levels && $level{"$u *** $server"} >= $levels)) { + if ($valid) { + push(@isValid, &validAddr($newaddr)); + push(@toFinal,$newaddr,$newmxhost,$newname); + } else { + &verbose(&final($newaddr,$newmxhost,$newname)); + } + } else { + # more work to do... + if ($valid) { + push(@isValid, &validAddr($newaddr)); + push(@toExpn,$newmxhost,$newaddr,$newname,$level{"$u *** $server"}); + } else { + &verbose(&expn($newmxhost,$newaddr,$newname,$level{"$u *** $server"})); + } + } + } + last if ($done eq " "); + next; + } + # 550 is a known code... Should the be + # included in -a output? Might be a bug + # here. Does it matter? Can assume that + # there won't be UNKNOWN USER responses + # mixed with valid users? + if ($s =~ /^(550)([- ])/) { + if ($valid) { + print STDERR "\@$server:$u ($oldname) USER UNKNOWN\n"; + } else { + &verbose(&final($u,$server,$oldname,"USER UNKNOWN")); + } + last if ($2 eq " "); + next; + } + # 553 is a known code... + if ($s =~ /^(553)([- ])/) { + if ($valid) { + print STDERR "\@$server:$u ($oldname) USER AMBIGUOUS\n"; + } else { + &verbose(&final($u,$server,$oldname,"USER AMBIGUOUS")); + } + last if ($2 eq " "); + next; + } + # 252 is a known code... + if ($s =~ /^(252)([- ])/) { + if ($valid) { + print STDERR "\@$server:$u ($oldname) REFUSED TO VRFY\n"; + } else { + &verbose(&final($u,$server,$oldname,"REFUSED TO VRFY")); + } + last if ($2 eq " "); + next; + } + &giveup('',"$server: did not grok '$s'",$u); + last USER; + } + + if ($valid) { + # + # now we decide if we are going to take these + # expansions or roll them back. + # + $avgValid = &average(@isValid); + print "avgValid = $avgValid\n" if $debug; + if ($avgValid >= $validRequirement) { + print &compact($u,$server)." ->\n" if $verbose; + while (@toExpn) { + &verbose(&expn(splice(@toExpn,0,4))); + } + while (@toFinal) { + &verbose(&final(splice(@toFinal,0,3))); + } + } else { + print "Tossing some valid to avoid invalid ".&compact($u,$server)."\n" if ($avgValid > 0.0 && ($vw || $debug)); + print &compact($u,$server)." ->\n" if $verbose; + &verbose(&final($u,$server,$newname)); + } + } + } + + &alarm("sending 'quit' to $server",''); + $0 = "$av0 - sending 'quit' to $server"; + &ps("quit"); + while() { + print if $watch; + last if /^\d+ /; + } + close(S); + alarm(0); +} + +$0 = "$av0 - printing final results"; +print "----------\n" if $vw; +select(STDOUT); +for $f (sort @final) { + print "$f\n"; +} +unlink("/tmp/expn$$"); +exit(0); + + +# abandon all attempts deliver to $server +# register the current addresses as the final ones +sub giveup +{ + local($redirect_okay,$reason,$user) = @_; + local($us,@so,$nh,@remaining_users); + local($pk,$file,$line); + ($pk, $file, $line) = caller; + + $0 = "$av0 - giving up on $server: $reason"; + # + # add back a user if we gave up in the middle + # + push(@users,$user) if $user; + # + # don't bother with this system anymore + # + unless ($giveup{$server}) { + $giveup{$server} = $reason; + print STDERR "$reason\n"; + } + print "Giveup at $file:$line!!! redirect okay = $redirect_okay; $reason\n" if $debug; + # + # Wait! + # Before giving up, see if there is a chance that + # there is another host to redirect to! + # (Kids, don't do this at home! Hacking is a dangerous + # crime and you could end up behind bars.) + # + for $u (@users) { + if ($redirect_okay =~ /\bmx\b/) { + next if &try_fallback('mx',$u,*server, + *mx_secondary, + *already_mx_fellback); + } + if ($redirect_okay =~ /\bdomainify\b/) { + next if &try_fallback('domainify',$u,*server, + *domainify_fallback, + *already_domainify_fellback); + } + push(@remaining_users,$u); + } + @users = @remaining_users; + for $u (@users) { + print &compact($u,$server)." ->\n" if ($verbose && $valid && $u); + &verbose(&final($u,$server,$names{"$u *** $server"},$reason)); + } +} +# +# This routine is used only within &giveup. It checks to +# see if we really have to giveup or if there is a second +# chance because we did something before that can be +# backtracked. +# +# %fallback{"$user *** $host"} tracks what is able to fallback +# %fellback{"$user *** $host"} tracks what has fallen back +# +# If there is a valid backtrack, then queue up the new possibility +# +sub try_fallback +{ + local($method,$user,*host,*fall_table,*fellback) = @_; + local($us,$fallhost,$oldhost,$ft,$i); + + if ($debug > 8) { + print "Fallback table $method:\n"; + for $i (sort keys %fall_table) { + print "\t'$i'\t\t'$fall_table{$i}'\n"; + } + print "Fellback table $method:\n"; + for $i (sort keys %fellback) { + print "\t'$i'\t\t'$fellback{$i}'\n"; + } + print "U: $user H: $host\n"; + } + + $us = "$user *** $host"; + if (defined $fellback{$us}) { + # + # Undo a previous fallback so that we can try again + # Nested fallbacks are avoided because they could + # lead to infinite loops + # + $fallhost = $fellback{$us}; + print "Already $method fell back from $us -> \n" if $debug; + $us = "$user *** $fallhost"; + $oldhost = $fallhost; + } elsif (($method eq 'mx') && (defined $mxbacktrace{$us}) && (defined $mx_secondary{$mxbacktrace{$us}})) { + print "Fallback an MX expansion $us -> \n" if $debug; + $oldhost = $mxbacktrace{$us}; + } else { + print "Oldhost($host, $us) = " if $debug; + $oldhost = $host; + } + print "$oldhost\n" if $debug; + if (((defined $fall_table{$us}) && ($ft = $us)) || ((defined $fall_table{$oldhost}) && ($ft = $oldhost))) { + print "$method Fallback = ".$fall_table{$ft}."\n" if $debug; + local(@so,$newhost); + @so = split(' ',$fall_table{$ft}); + $newhost = shift(@so); + print "Falling back ($method) $us -> $newhost (from $oldhost)\n" if $debug; + if ($method eq 'mx') { + if (! defined ($mxbacktrace{"$user *** $newhost"})) { + if (defined $mxbacktrace{"$user *** $oldhost"}) { + print "resetting oldhost $oldhost to the original: " if $debug; + $oldhost = $mxbacktrace{"$user *** $oldhost"}; + print "$oldhost\n" if $debug; + } + $mxbacktrace{"$user *** $newhost"} = $oldhost; + print "mxbacktrace $user *** $newhost -> $oldhost\n" if $debug; + } + $mx{&trhost($oldhost)} = $newhost; + } else { + $temporary_redirect{$us} = $newhost; + } + if (@so) { + print "Can still $method $us: @so\n" if $debug; + $fall_table{$ft} = join(' ',@so); + } else { + print "No more fallbacks for $us\n" if $debug; + delete $fall_table{$ft}; + } + if (defined $create_host_backtrack{$us}) { + $create_host_backtrack{"$user *** $newhost"} + = $create_host_backtrack{$us}; + } + $fellback{"$user *** $newhost"} = $oldhost; + &expn($newhost,$user,$names{$us},$level{$us}); + return 1; + } + delete $temporary_redirect{$us}; + $host = $oldhost; + return 0; +} +# return 1 if you could send mail to the address as is. +sub validAddr +{ + local($addr) = @_; + $res = &do_validAddr($addr); + print "validAddr($addr) = $res\n" if $debug; + $res; +} +sub do_validAddr +{ + local($addr) = @_; + local($urx) = "[-A-Za-z_.0-9+]+"; + + # \u + return 0 if ($addr =~ /^\\/); + # ?@h + return 1 if ($addr =~ /.\@$urx$/); + # @h:? + return 1 if ($addr =~ /^\@$urx\:./); + # h!u + return 1 if ($addr =~ /^$urx!./); + # u + return 1 if ($addr =~ /^$urx$/); + # ? + print "validAddr($addr) = ???\n" if $debug; + return 0; +} +# Some systems use expn and vrfy interchangeably. Some only +# implement one or the other. Some check expn against mailing +# lists and vrfy against users. It doesn't appear to be +# consistent. +# +# So, what do we do? We try everything! +# +# +# Ranking of result codes: good: 250, 251/551, 252, 550, anything else +# +# Ranking of inputs: best: user@host.domain, okay: user +# +# Return value: $error_string, @responses_from_server +sub expn_vrfy +{ + local($u,$server) = @_; + local(@c) = ('expn', 'vrfy'); + local(@try_u) = $u; + local(@ret,$code); + + if (($u =~ /(.+)@(.+)/) && (&trhost($2) eq &trhost($server))) { + push(@try_u,$1); + } + + TRY: + for $c (@c) { + for $try_u (@try_u) { + &alarm("${c}'ing $try_u on $server",'',$u); + &ps("$c $try_u"); + alarm(0); + $s = ; + if ($s eq '') { + return "$server: lost connection"; + } + if ($s !~ /^(\d+)([- ])/) { + return "$server: garbled reply to '$c $try_u'"; + } + if ($1 == 250) { + $code = 250; + @ret = ("",$s); + push(@ret,&read_response($2,$debug)); + return (@ret); + } + if ($1 == 551 || $1 == 251) { + $code = $1; + @ret = ("",$s); + push(@ret,&read_response($2,$debug)); + next; + } + if ($1 == 252 && ($code == 0 || $code == 550)) { + $code = 252; + @ret = ("",$s); + push(@ret,&read_response($2,$watch)); + next; + } + if ($1 == 550 && $code == 0) { + $code = 550; + @ret = ("",$s); + push(@ret,&read_response($2,$watch)); + next; + } + &read_response($2,$watch); + } + } + return "$server: expn/vrfy not implemented" unless @ret; + return @ret; +} +# sometimes the old parse routine (now parse2) didn't +# reject funky addresses. +sub parse +{ + local($oldaddr,$server,$oldname,$one_to_one) = @_; + local($newhost, $newaddr, $newname, $um) = &parse2($oldaddr,$server,$oldname,$one_to_one); + if ($newaddr =~ m,^["/],) { + return (undef, $oldaddr, $newname) if $valid; + return (undef, $um, $newname); + } + return ($newhost, $newaddr, $newname); +} + +# returns ($new_smtp_server,$new_address,$new_name) +# given a response from a SMTP server ($newaddr), the +# current host ($server), the old "name" and a flag that +# indicates if it is being called during the initial +# command line parsing ($parsing_args) +sub parse2 +{ + local($newaddr,$context_host,$old_name,$parsing_args) = @_; + local(@names) = $old_name; + local($urx) = "[-A-Za-z_.0-9+]+"; + local($unmangle); + + # + # first, separate out the address part. + # + + # + # [NAME] + # [NAME] <[(NAME)] ADDR + # ADDR [(NAME)] + # (NAME) ADDR + # [(NAME)] + # + if ($newaddr =~ /^\<(.*)\>$/) { + print "\n" if $debug; + ($newaddr) = &trim($1); + print "na = $newaddr\n" if $debug; + } + if ($newaddr =~ /^([^\<\>]*)\<([^\<\>]*)\>([^\<\>]*)$/) { + # address has a < > pair in it. + print "N:$1 N:$3\n" if $debug; + ($newaddr) = &trim($2); + unshift(@names, &trim($3,$1)); + print "na = $newaddr\n" if $debug; + } + if ($newaddr =~ /^([^\(\)]*)\(([^\(\)]*)\)([^\(\)]*)$/) { + # address has a ( ) pair in it. + print "A:$1 (N:$2) A:$3\n" if $debug; + unshift(@names,&trim($2)); + local($f,$l) = (&trim($1),&trim($3)); + if (($f && $l) || !($f || $l)) { + # address looks like: + # foo (bar) baz or (bar) + # not allowed! + print STDERR "Could not parse $newaddr\n" if $vw; + return(undef,$newaddr,&firstname(@names)); + } + $newaddr = $f if $f; + $newaddr = $l if $l; + print "newaddr now = $newaddr\n" if $debug; + } + # + # @foo:bar + # j%k@l + # a@b + # b!a + # a + # + $unmangle = $newaddr; + if ($newaddr =~ /^\@($urx)\:(.+)$/) { + print "(\@:)" if $debug; + # this is a bit of a cheat, but it seems necessary + return (&domainify($1,$context_host,$2),$2,&firstname(@names),$unmangle); + } + if ($newaddr =~ /^(.+)\@($urx)$/) { + print "(\@)" if $debug; + return (&domainify($2,$context_host,$newaddr),$newaddr,&firstname(@names),$unmangle); + } + if ($parsing_args) { + if ($newaddr =~ /^($urx)\!(.+)$/) { + return (&domainify($1,$context_host,$newaddr),$newaddr,&firstname(@names),$unmangle); + } + if ($newaddr =~ /^($urx)$/) { + return ($context_host,$newaddr,&firstname(@names),$unmangle); + } + print STDERR "Could not parse $newaddr\n"; + } + print "(?)" if $debug; + return(undef,$newaddr,&firstname(@names),$unmangle); +} +# return $u (@$server) unless $u includes reference to $server +sub compact +{ + local($u, $server) = @_; + local($se) = $server; + local($sp); + $se =~ s/(\W)/\\$1/g; + $sp = " (\@$server)"; + if ($u !~ /$se/i) { + return "$u$sp"; + } + return $u; +} +# remove empty (spaces don't count) members from an array +sub trim +{ + local(@v) = @_; + local($v,@r); + for $v (@v) { + $v =~ s/^\s+//; + $v =~ s/\s+$//; + push(@r,$v) if ($v =~ /\S/); + } + return(@r); +} +# using the host part of an address, and the server name, add the +# servers' domain to the address if it doesn't already have a +# domain. Since this sometimes fails, save a back reference so +# it can be unrolled. +sub domainify +{ + local($host,$domain_host,$u) = @_; + local($domain,$newhost); + + # cut of trailing dots + $host =~ s/\.$//; + $domain_host =~ s/\.$//; + + if ($domain_host !~ /\./) { + # + # domain host isn't, keep $host whatever it is + # + print "domainify($host,$domain_host) = $host\n" if $debug; + return $host; + } + + # + # There are several weird situtations that need to be + # accounted for. They have to do with domain relay hosts. + # + # Examples: + # host server "right answer" + # + # shiva.cs cs.berkeley.edu shiva.cs.berkeley.edu + # shiva cs.berkeley.edu shiva.cs.berekley.edu + # cumulus reed.edu @reed.edu:cumulus.uucp + # tiberius tc.cornell.edu tiberius.tc.cornell.edu + # + # The first try must always be to cut the domain part out of + # the server and tack it onto the host. + # + # A reasonable second try is to tack the whole server part onto + # the host and for each possible repeated element, eliminate + # just that part. + # + # These extra "guesses" get put into the %domainify_fallback + # array. They will be used to give addresses a second chance + # in the &giveup routine + # + + local(%fallback); + + local($long); + $long = "$host $domain_host"; + $long =~ tr/A-Z/a-z/; + print "long = $long\n" if $debug; + if ($long =~ s/^([^ ]+\.)([^ ]+) \2(\.[^ ]+\.[^ ]+)/$1$2$3/) { + # matches shiva.cs cs.berkeley.edu and returns shiva.cs.berkeley.edu + print "condensed fallback $host $domain_host -> $long\n" if $debug; + $fallback{$long} = 9; + } + + local($fh); + $fh = $domain_host; + while ($fh =~ /\./) { + print "FALLBACK $host.$fh = 1\n" if $debug > 7; + $fallback{"$host.$fh"} = 1; + $fh =~ s/^[^\.]+\.//; + } + + $fallback{"$host.$domain_host"} = 2; + + ($domain = $domain_host) =~ s/^[^\.]+//; + $fallback{"$host$domain"} = 6 + if ($domain =~ /\./); + + if ($host =~ /\./) { + # + # Host is already okay, but let's look for multiple + # interpretations + # + print "domainify($host,$domain_host) = $host\n" if $debug; + delete $fallback{$host}; + $domainify_fallback{"$u *** $host"} = join(' ',sort {$fallback{$b} <=> $fallback{$a};} keys %fallback) if %fallback; + return $host; + } + + $domain = ".$domain_host" + if ($domain !~ /\..*\./); + $newhost = "$host$domain"; + + $create_host_backtrack{"$u *** $newhost"} = $domain_host; + print "domainify($host,$domain_host) = $newhost\n" if $debug; + delete $fallback{$newhost}; + $domainify_fallback{"$u *** $newhost"} = join(' ',sort {$fallback{$b} <=> $fallback{$a};} keys %fallback) if %fallback; + if ($debug) { + print "fallback = "; + print $domainify_fallback{"$u *** $newhost"} + if defined($domainify_fallback{"$u *** $newhost"}); + print "\n"; + } + return $newhost; +} +# return the first non-empty element of an array +sub firstname +{ + local(@names) = @_; + local($n); + while(@names) { + $n = shift(@names); + return $n if $n =~ /\S/; + } + return undef; +} +# queue up more addresses to expand +sub expn +{ + local($host,$addr,$name,$level) = @_; + if ($host) { + $host = &trhost($host); + + if (($debug > 3) || (defined $giveup{$host})) { + unshift(@hosts,$host) unless $users{$host}; + } else { + push(@hosts,$host) unless $users{$host}; + } + $users{$host} .= " $addr"; + $names{"$addr *** $host"} = $name; + $level{"$addr *** $host"} = $level + 1; + print "expn($host,$addr,$name)\n" if $debug; + return "\t$addr\n"; + } else { + return &final($addr,'NONE',$name); + } +} +# compute the numerical average value of an array +sub average +{ + local(@e) = @_; + return 0 unless @e; + local($e,$sum); + for $e (@e) { + $sum += $e; + } + $sum / @e; +} +# print to the server (also to stdout, if -w) +sub ps +{ + local($p) = @_; + print ">>> $p\n" if $watch; + print S "$p\n"; +} +# return case-adjusted name for a host (for comparison purposes) +sub trhost +{ + # treat foo.bar as an alias for Foo.BAR + local($host) = @_; + local($trhost) = $host; + $trhost =~ tr/A-Z/a-z/; + if ($trhost{$trhost}) { + $host = $trhost{$trhost}; + } else { + $trhost{$trhost} = $host; + } + $trhost{$trhost}; +} +# re-queue users if an mx record dictates a redirect +# don't allow a user to be redirected more than once +sub mxredirect +{ + local($server,*users) = @_; + local($u,$nserver,@still_there); + + $nserver = &mx($server); + + if (&trhost($nserver) ne &trhost($server)) { + $0 = "$av0 - mx redirect $server -> $nserver\n"; + for $u (@users) { + if (defined $mxbacktrace{"$u *** $nserver"}) { + push(@still_there,$u); + } else { + $mxbacktrace{"$u *** $nserver"} = $server; + print "mxbacktrace{$u *** $nserver} = $server\n" + if ($debug > 1); + &expn($nserver,$u,$names{"$u *** $server"}); + } + } + @users = @still_there; + if (! @users) { + return $nserver; + } else { + return undef; + } + } + return undef; +} +# follow mx records, return a hostname +# also follow temporary redirections comming from &domainify and +# &mxlookup +sub mx +{ + local($h,$u) = @_; + + for (;;) { + if (defined $mx{&trhost($h)} && $h ne $mx{&trhost($h)}) { + $0 = "$av0 - mx expand $h"; + $h = $mx{&trhost($h)}; + return $h; + } + if ($u) { + if (defined $temporary_redirect{"$u *** $h"}) { + $0 = "$av0 - internal redirect $h"; + print "Temporary redirect taken $u *** $h -> " if $debug; + $h = $temporary_redirect{"$u *** $h"}; + print "$h\n" if $debug; + next; + } + $htr = &trhost($h); + if (defined $temporary_redirect{"$u *** $htr"}) { + $0 = "$av0 - internal redirect $h"; + print "temporary redirect taken $u *** $h -> " if $debug; + $h = $temporary_redirect{"$u *** $htr"}; + print "$h\n" if $debug; + next; + } + } + return $h; + } +} +# look up mx records with the name server. +# re-queue expansion requests if possible +# optionally give up on this host. +sub mxlookup +{ + local($lastchance,$server,$giveup,*users) = @_; + local(*T); + local(*NSLOOKUP); + local($nh, $pref,$cpref); + local($o0) = $0; + local($nserver); + local($name,$aliases,$type,$len,$thataddr); + local(%fallback); + + return 1 if &mxredirect($server,*users); + + if ((defined $mx{$server}) || (! $have_nslookup)) { + return 0 unless $lastchance; + &giveup('mx domainify',$giveup); + return 0; + } + + $0 = "$av0 - nslookup of $server"; + open(T,">/tmp/expn$$") || die "open > /tmp/expn$$: $!\n"; + print T "set querytype=MX\n"; + print T "$server\n"; + close(T); + $cpref = 1.0E12; + undef $nserver; + open(NSLOOKUP,"nslookup < /tmp/expn$$ 2>&1 |") || die "open nslookup: $!"; + while() { + print if ($debug > 2); + if (/mail exchanger = ([-A-Za-z_.0-9+]+)/) { + $nh = $1; + if (/preference = (\d+)/) { + $pref = $1; + if ($pref < $cpref) { + $nserver = $nh; + $cpref = $pref; + } elsif ($pref) { + $fallback{$pref} .= " $nh"; + } + } + } + if (/Non-existent domain/) { + # + # These addresss are hosed. Kaput! Dead! + # However, if we created the address in the + # first place then there is a chance of + # salvation. + # + 1 while(); + close(NSLOOKUP); + return 0 unless $lastchance; + &giveup('domainify',"$server: Non-existent domain",undef,1); + return 0; + } + + } + close(NSLOOKUP); + unlink("/tmp/expn$$"); + unless ($nserver) { + $0 = "$o0 - finished mxlookup"; + return 0 unless $lastchance; + &giveup('mx domainify',"$server: Could not resolve address"); + return 0; + } + + # provide fallbacks in case $nserver doesn't work out + if (defined $fallback{$cpref}) { + $mx_secondary{$server} = $fallback{$cpref}; + } + + $0 = "$av0 - gethostbyname($nserver)"; + ($name,$aliases,$type,$len,$thataddr) = gethostbyname($nserver); + + unless ($thataddr) { + $0 = $o0; + return 0 unless $lastchance; + &giveup('mx domainify',"$nserver: could not resolve address"); + return 0; + } + print "MX($server) = $nserver\n" if $debug; + print "$server -> $nserver\n" if $vw && !$debug; + $mx{&trhost($server)} = $nserver; + # redeploy the users + unless (&mxredirect($server,*users)) { + return 0 unless $lastchance; + &giveup('mx domainify',"$nserver: only one level of mx redirect allowed"); + return 0; + } + $0 = "$o0 - finished mxlookup"; + return 1; +} +# if mx expansion did not help to resolve an address +# (ie: foo@bar became @baz:foo@bar, then undo the +# expansion). +# this is only used by &final +sub mxunroll +{ + local(*host,*addr) = @_; + local($r) = 0; + print "looking for mxbacktrace{$addr *** $host}\n" + if ($debug > 1); + while (defined $mxbacktrace{"$addr *** $host"}) { + print "Unrolling MX expnasion: \@$host:$addr -> " + if ($debug || $verbose); + $host = $mxbacktrace{"$addr *** $host"}; + print "\@$host:$addr\n" + if ($debug || $verbose); + $r = 1; + } + return 1 if $r; + $addr = "\@$host:$addr" + if ($host =~ /\./); + return 0; +} +# register a completed expnasion. Make the final address as +# simple as possible. +sub final +{ + local($addr,$host,$name,$error) = @_; + local($he); + local($hb,$hr); + local($au,$ah); + + if ($error =~ /Non-existent domain/) { + # + # If we created the domain, then let's undo the + # damage... + # + if (defined $create_host_backtrack{"$addr *** $host"}) { + while (defined $create_host_backtrack{"$addr *** $host"}) { + print "Un&domainifying($host) = " if $debug; + $host = $create_host_backtrack{"$addr *** $host"}; + print "$host\n" if $debug; + } + $error = "$host: could not locate"; + } else { + # + # If we only want valid addresses, toss out + # bad host names. + # + if ($valid) { + print STDERR "\@$host:$addr ($name) Non-existent domain\n"; + return ""; + } + } + } + + MXUNWIND: { + $0 = "$av0 - final parsing of \@$host:$addr"; + ($he = $host) =~ s/(\W)/\\$1/g; + if ($addr !~ /@/) { + # addr does not contain any host + $addr = "$addr@$host"; + } elsif ($addr !~ /$he/i) { + # if host part really something else, use the something + # else. + if ($addr =~ m/(.*)\@([^\@]+)$/) { + ($au,$ah) = ($1,$2); + print "au = $au ah = $ah\n" if $debug; + if (defined $temporary_redirect{"$addr *** $ah"}) { + $addr = "$au\@".$temporary_redirect{"$addr *** $ah"}; + print "Rewrite! to $addr\n" if $debug; + next MXUNWIND; + } + } + # addr does not contain full host + if ($valid) { + if ($host =~ /^([^\.]+)(\..+)$/) { + # host part has a . in it - foo.bar + ($hb, $hr) = ($1, $2); + if ($addr =~ /\@([^\.\@]+)$/ && ($1 eq $hb)) { + # addr part has not . + # and matches beginning of + # host part -- tack on a + # domain name. + $addr .= $hr; + } else { + &mxunroll(*host,*addr) + && redo MXUNWIND; + } + } else { + &mxunroll(*host,*addr) + && redo MXUNWIND; + } + } else { + $addr = "${addr}[\@$host]" + if ($host =~ /\./); + } + } + } + $name = "$name " if $name; + $error = " $error" if $error; + if ($valid) { + push(@final,"$name<$addr>"); + } else { + push(@final,"$name<$addr>$error"); + } + "\t$name<$addr>$error\n"; +} + +sub alarm +{ + local($alarm_action,$alarm_redirect,$alarm_user) = @_; + alarm(3600); + $SIG{ALRM} = 'handle_alarm'; +} +# this involves one great big ugly hack. +# the "next HOST" unwinds the stack! +sub handle_alarm +{ + &giveup($alarm_redirect,"Timed out during $alarm_action",$alarm_user); + next HOST; +} + +# read the rest of the current smtp daemon's response (and toss it away) +sub read_response +{ + local($done,$watch) = @_; + local(@resp); + print $s if $watch; + while(($done eq "-") && ($s = ) && ($s =~ /^\d+([- ])/)) { + print $s if $watch; + $done = $1; + push(@resp,$s); + } + return @resp; +} +# print args if verbose. Return them in any case +sub verbose +{ + local(@tp) = @_; + print "@tp" if $verbose; +} +# to pass perl -w: +@tp; +$flag_a; +$flag_d; +$flag_1; +%already_domainify_fellback; +%already_mx_fellback; +&handle_alarm; +################### BEGIN PERL/TROFF TRANSITION +.00 ; + +'di +.nr nl 0-1 +.nr % 0 +.\\"'; __END__ +.\" ############## END PERL/TROFF TRANSITION +.TH EXPN 1 "March 11, 1993" +.AT 3 +.SH NAME +expn \- recursively expand mail aliases +.SH SYNOPSIS +.B expn +.RI [ -a ] +.RI [ -v ] +.RI [ -w ] +.RI [ -d ] +.RI [ -1 ] +.IR user [@ hostname ] +.RI [ user [@ hostname ]]... +.SH DESCRIPTION +.B expn +will use the SMTP +.B expn +and +.B vrfy +commands to expand mail aliases. +It will first look up the addresses you provide on the command line. +If those expand into addresses on other systems, it will +connect to the other systems and expand again. It will keep +doing this until no further expansion is possible. +.SH OPTIONS +The default output of +.B expn +can contain many lines which are not valid +email addresses. With the +.I -aa +flag, only expansions that result in legal addresses +are used. Since many mailing lists have an illegal +address or two, the single +.IR -a , +address, flag specifies that a few illegal addresses can +be mixed into the results. More +.I -a +flags vary the ratio. Read the source to track down +the formula. With the +.I -a +option, you should be able to construct a new mailing +list out of an existing one. +.LP +If you wish to limit the number of levels deep that +.B expn +will recurse as it traces addresses, use the +.I -1 +option. For each +.I -1 +another level will be traversed. So, +.I -111 +will traverse no more than three levels deep. +.LP +The normal mode of operation for +.B expn +is to do all of its work silently. +The following options make it more verbose. +It is not necessary to make it verbose to see what it is +doing because as it works, it changes its +.BR argv [0] +variable to reflect its current activity. +To see how it is expanding things, the +.IR -v , +verbose, flag will cause +.B expn +to show each address before +and after translation as it works. +The +.IR -w , +watch, flag will cause +.B expn +to show you its conversations with the mail daemons. +Finally, the +.IR -d , +debug, flag will expose many of the inner workings so that +it is possible to eliminate bugs. +.SH ENVIRONMENT +No enviroment variables are used. +.SH FILES +.PD 0 +.B /tmp/expn$$ +.B temporary file used as input to +.BR nslookup . +.SH SEE ALSO +.BR aliases (5), +.BR sendmail (8), +.BR nslookup (8), +RFC 823, and RFC 1123. +.SH BUGS +Not all mail daemons will implement +.B expn +or +.BR vrfy . +It is not possible to verify addresses that are served +by such daemons. +.LP +When attempting to connect to a system to verify an address, +.B expn +only tries one IP address. Most mail daemons +will try harder. +.LP +It is assumed that you are running domain names and that +the +.BR nslookup (8) +program is available. If not, +.B expn +will not be able to verify many addresses. It will also pause +for a long time unless you change the code where it says +.I $have_nslookup = 1 +to read +.I $have_nslookup = +.IR 0 . +.LP +Lastly, +.B expn +does not handle every valid address. If you have an example, +please submit a bug report. +.SH CREDITS +In 1986 or so, Jon Broome wrote a program of the same name +that did about the same thing. It has since suffered bit rot +and Jon Broome has dropped off the face of the earth! +(Jon, if you are out there, drop me a line) +.SH AVAILABILITY +The latest version of +.B expn +is available through anonymous ftp at +.IR ftp://ftp.idiom.com/pub/muir-programs/expn . +.SH AUTHOR +.I David Muir Sharnoff\ \ \ \ diff --git a/contrib/amd/scripts/fix-amd-map.in b/contrib/amd/scripts/fix-amd-map.in new file mode 100755 index 0000000..6746462 --- /dev/null +++ b/contrib/amd/scripts/fix-amd-map.in @@ -0,0 +1,52 @@ +#!@PERL@ +# +# fix an old-syntax amd map to new one +# +# takes any number of files on the command line, and produces +# a fixed map on stdout. +# +# Package: am-utils-6.0 +# Author: Erez Zadok +# + +############################################################################## +### MAINTAINER EDITABLE SECTION + +# Mappings of old names to new ones: +# Update when needed, do not forget commas but not on the last entry! +# For your convenience, this is the complete list of all OSs that were +# supported by amd-upl102, in their old names: +# +# 386bsd acis43 aix3 aoi aux bsd43 bsd44 bsdi11 +# concentrix dgux fpx4 freebsd hcx hlh42 hpux irix3 irix4 irix5 isc3 +# linux mach2 mach3 netbsd news4 next osf1 pyrOSx riscix riscos +# rtu6 sos3 sos4 sos5 stellix svr4 u2_2 u3_0 u4_0 u4_2 u4_3 u4_4 +# umax43 utek utx32 xinu43 +# +%mappings = ( + "sos4", "sunos4", + "sos5", "sunos5", + "freebsd", "freebsd2" +); + +############################################################################## +### DO NOT EDIT ANYTHING BELOW + +# This is a trivial parser and works as follows: +# (1) read each line +# (2) search of regexps that start with '=', continue with a word to replace +# and end with a non-value name (whitespace, ';', or newline +while (<>) { + # skip trivial lines + if ($_ =~ /^$/ || $_ =~ /^#/) { + print; + next; + } + # modify the line if needed + foreach $m (keys %mappings) { + $val = $mappings{$m}; + $_ =~ s/=$m([^a-zA-Z0-9_])/=$val$1/g; + } + # print the (possibly) modified line + print; +} diff --git a/contrib/amd/scripts/fixrmtab b/contrib/amd/scripts/fixrmtab new file mode 100755 index 0000000..33b7bcf --- /dev/null +++ b/contrib/amd/scripts/fixrmtab @@ -0,0 +1,24 @@ +#!/bin/sh +# +# Invalidate /etc/rmtab entries for hosts named. +# Restart mountd for changes to take effect. +# +# usage: fixrmtab host1 host2 ... +# +# Package: am-utils-6.0 +# Author: Andreas Stolcke + +#set -x + +RMTAB=/etc/rmtab +TMP=/tmp/rmtab.$$ + +if [ ! -f /etc/rmtab ]; then + exit 0 +fi + +for host in $* +do + sed -e '/^'$host':/s/^./#/' $RMTAB > $TMP && cp $TMP $RMTAB +done +rm -f $TMP diff --git a/contrib/amd/scripts/lostaltmail.conf-sample b/contrib/amd/scripts/lostaltmail.conf-sample new file mode 100644 index 0000000..a20158c --- /dev/null +++ b/contrib/amd/scripts/lostaltmail.conf-sample @@ -0,0 +1,84 @@ +# -*- perl -*- +############################################################################## +# # +# CONFIGURABLE VALUES # +# # +############################################################################## + +$MAILGRUNT="postmaster"; # To whom to send log mail if mail is prefered. + +$TMPDIR="/tmp/"; # Place lostmail can do its dirty work. + +$LOCAL_LOCK_EXT=".lock"; # Name of file local mailer uses to lock + # spool file. This the correct setting for + # /bin/mail + +$SYSTEM_FROM_ADDRESS="Mailer-Daemon"; + +$MAILDIR="/var/alt_mail"; # What directory should I run out of. +$MAILER='/usr/lib/sendmail -t'; # Which mailer should I use. + +$LOCALMAILJUNK='.*~|\#.*|core'; # Files name patterns that might appear in + # alt_mail and should be ignored. This REGEXP + # gets or'ed with $MAILJUNK below. + +$SMTPHOST='localhost'; # The name of a local host which speaks SMTP + # and knows *all* your aliases. You probably + # don't want to change this. If the machine + # running lost_alt mail doesn't run an SMTP, + # daemon then something is either wrong or you + # should be setting `noverify' to prevent + # SMTP verification. + +$HOSTNAME='localhost'; # Hostname to use for SMTP HELO + +# Subject of lost log mail message. Must define $MAILGRUNT. +# I overwrite this variable in the subroutine Clean_up. Please make sure I +# haven't noodle-headdly forgotten to remove that hack in the distribution! +# No newline here please. The script will insert it for you. +$LOG_SUBJECT="Log of lostmail resends"; + +############################################################################## +# # +# DEFAULTED CONFIGURATIONS # +# # +############################################################################## + +$LOGFILE="$TMPDIR" . "lostlog"; + + +# MAILJUNK is a pattern of ignorable alt_mail files which are either common +# to most platforms or actually produced by this script. You should customize +# this REGEXP by hacking at $LOCALMAILJUNK above. +$MAILJUNK='[a-z]\.[0-9]*|\.\.?|lost\+found'; + +$LOCKEXT=".lostlock"; # our lock file extension. Should not need to + # modify + +$MESSAGE_DELIM="^From[^:]"; # /bin/mail message delimiter. Your milage + # may differ + +$HEADER_BODY_DELIM="\n"; # RFC 822 header-body delimiter. + +$RESENT_TO="Resent-To: "; # +$RESENT_FROM="Resent-From: "; # Resent headers (RFC 822). +$RESENT_DATE="Resent-Date: "; # You probably don't want to muck with these. +$RESENT_INFO="X-Resent-Info: "; # (special one to alert folks about mail). + + +############################################################################## +# # +# LOSTMAIL DEFINITIONS (DON'T TOUCH) # +# # +############################################################################## + +$FALSE=0; +$TRUE=(! $FALSE); + +$OK=$TRUE; +$ABORT_RESEND=2; +$LOCK_RETRIES=10; # The number of seconds/retries lost mail + # should wait before requeing or aborting a + # resend. + +TRUE; # Ansures true return from include file. diff --git a/contrib/amd/scripts/lostaltmail.in b/contrib/amd/scripts/lostaltmail.in new file mode 100755 index 0000000..5ba454c --- /dev/null +++ b/contrib/amd/scripts/lostaltmail.in @@ -0,0 +1,648 @@ +#!@PERL@ -sw +# +# Package: am-utils-6.0 +# Author: James Tanis +# + +############################################################################ +# +# lostaltmail -- remail files files found alt_mail (or -a argument to hlfsd) to +# whomever should receive it. This version is for SMTP varient which +# support VRFY as a non-expanding verifier!!! (sendmail V8 is a an +# example). +# +# Usage: lostaltmail [-debug] [-nomail] [-noverify] +# +# GLOBAL VARIABLES (as if you care :-) ) +# Probably a very incomplete list. +# +# Everything in the config file for this program *and* ... +# +# $debug: set it from the command line with -debug. Does the obvious +# $nomail: set it from the command line with -nomail. *Not* implied by +# $debug +# $currentTO: The addresss we are currently checking on. Actually this is +# left over from an earlier version of lostaltmail and will hopefully +# go away. +# $noverify: set it from the address line. Avoid verification of $currentTO. +# This should be relatively safe as long as your are willing to +# endure bounces from mail that cannot be redelivered as opposed to +# just getting a warning. UNTESTED (but should work). +# +# $logopen: state variable indicating weather the log file (should there be +# one) is in fact open. +# +# @allentries: Array of all the directory entries in $MAILDIR +# @allnames: Array of all *likely* recipients. It is created from @allentries +# sans junk files (see $MAILJUNK and $LOCALMAILJUNK) +# @wanderers: Array of all the files associated with a *single* address +# which might need remailing. Should lostaltmail die unexpectedly, +# it might leave a temporary file containing messages it was +# currently trying to deliver. These will get picked and resent +# later. +# +# VRFY: Handle onto SMTP verification channel. Not to be confused with mail +# delivery; only verification occurs accross this handle. +# +############################################################################ + +############################################################################## +# # +# SMTP_SEND # +# # +############################################################################## +# +# Send a message to the smtp channel. Inserts the necessary NEWLINE if it +# does not exist; +# I stole this from myself. It shouldn nott be printing errors to STDERR, but +# this is a quick hack. +# +sub smtp_send { + local ($msg) = @_; + local ($length); + + $length=length($msg); + + if ( $msg !~ /^.*\n$/ ) { + $msg = $msg . "\n"; + $length++; + } + + + if ( ! syswrite (VRFY, $msg, $length)) { + print STDERR "Failing SMTP write: $msg"; + return 0; + } + + return 1; +} + +############################################################################## +# # +# SMTP_RECV # +# # +############################################################################## +# +# Read in lines from SMTP connection and return the final +# Really hideous -- please excuse. +# +sub smtp_recv { + local ($line,$rin, $win, $ein, $readbuf, $ret); + $readbuf = ""; + + $rin = $win = $ein = ''; # Null fd sets, + vec ($rin, fileno(VRFY), 1) = 1; # Stolen straight from the example; + $ein = $rin | $win; # This is probably useless + + +LINE_OF_INPUT: + while (1) { # Read in all the input + + if ((select ( $rin, $win, $ein, 600.0))[0] == 0 ) { + print "select returned -1" if ($debug); + return -1; # timeout + } + sysread (VRFY, $readbuf, 1024); + chop ($readbuf); + + foreach $line ( split('\n', $readbuf)) { + + # This loop is actually needed since V8 has a multi-line greet. + + ( $line =~ /^(\d\d\d).*/ && ($SMTP_retval=$1)) || + warn "Badly formed reply from SMTP peer: $line\n"; + + # Space after return code indicates EOT + + if ($line =~ /^\d\d\d /) { + $ret = $line; # Oddly $line is in a different context here; + # and thus we need to export it out of the + # while loop via $ret. + last LINE_OF_INPUT; + } + } # End of read. + } # End of input. + + return $ret; +} + + + + +############################################################################## +# # +# LOG_INFO # +# # +############################################################################## +# +# +# Opens appropriate logging file -- STDOUT (cron) or temp file (mail). +# +sub Log_info { + local($message) = @_; + + if ( !$logopened ) { + if ( $MAILGRUNT eq "" || $debug) { + open (LOGFILE, ">-") || die "Unable to open stdout"; + } + else { + # Snarf the log into a tmp file for final mailing to MAILGRUNT + $logfile = $LOGFILE . ".$$"; + open (LOGFILE, (">". "$logfile")) || die "Unable to create log file"; + } + } + + $logopened=1; # Note that the log is now open + + # Heart of the function. + print LOGFILE "$message"; + + print LOGFILE "\n" if ( index($message,"\n") == -1 ); +} + +############################################################################## +# # +# LOCK_FILE # +# # +############################################################################## + +# +# Tries to grab a lock on the supplied file name. +# Spins for a bit if it can't on the assumption that the lock will be released +# quickly. If it times out and it's allowed to requeue, it will defer +# until later, other wise write a message to loginfo. + +# If a recurring error or really unexpected situation arrises, return +# ABORT_RESEND +# +# PARAMETERS +# mailfile: path to the file to resend. +# should_requeue: BOOLEAN - TRUE if the mailfile should be put on the +# queue for a later retry if we can not finish +# now. + +sub Lock_file { + + local($mailfile,$should_requeue,$i,$new_lost_file) = @_; + +# We need to rename the current mailbox so that mail can loop back into it if +# the resent mail just gets looped right back to us. + $new_lost_file = $mailfile . ".$$"; + +# make a tmpfile name based on mailfile; + $lostlockfile = "$mailfile" . "$LOCKEXT"; + + if ( ! open(LOCKFILE, (">" . $lostlockfile)) ) { + printf(STDERR "Could not create lostlockfile for %s: %s\n", $mailfile,$!); + return $ABORT_RESEND; + } + close(LOCKFILE); + + $maillockfile = "$mailfile" . "$LOCAL_LOCK_EXT"; + + for ($i=0; $i < $LOCK_RETRIES && ! link ($lostlockfile, $maillockfile); + $i++) { + sleep(1); + } + + unlink($lostlockfile); # No matter what eliminate our cruft + + if ( $i == $LOCK_RETRIES ) { + &Log_info("Could not grab lock on: " . "$mailfile" . " :timed out"); + if ( $should_requeue ) { + &Log_info("Requeing " . "$mailfile" . " for later retry"); + $retry_list .= " $mailfile"; + } + else { + &Log_info("Giving up on: " . "$mailfile"); + } + + return $ABORT_RESEND; + } + + # We created the link and therefore have the lock + + if (rename ($mailfile, $new_lost_file) == 0 ){ + # Failed to rename file -- this is serious. + unlink($maillockfile); + return $ABORT_RESEND; + } + + unlink($maillockfile); + return $new_lost_file; + +} + +############################################################################## +# # +# PARSE NEXT MAIL MESSAGE # +# # +############################################################################## +# +# Parameters: +# mailfile: handle of mailfile to use. +# +# Parses the next message in the mail file and inserts it in $current_msg +# +sub Get_next_msg { + local($mailfile,$found_body_delimiter) = @_; + + # If this is the first message in the spool file, read the first line + # otherwise use the MESSAGE_DELIM line from the previous message (which we + # were forced to overread). + + $done=$FALSE; + $found_body_delimiter=$FALSE; + + # This if eats the very first "From " line and should never fire again. + if ( ! defined $current_msg ) {<$mailfile>}; + undef ($current_msg); # Erase the old message. + + + # Read the mailfile and pass through all the lines up until the next + # message delimiter. Kill any previous resend headers. + while ( <$mailfile> ) { + last if (/$MESSAGE_DELIM/); + next if ( !$found_body_delimiter && /[Rr][Ee][Ss][Ee][Nn][Tt]-.+:/); + if ( !$found_body_delimiter && /^$HEADER_BODY_DELIM/) { + &Splice_in_resent_headers(); + $found_body_delimiter=$TRUE; + } + if (defined($current_msg)) { + $current_msg .= $_; + } else { + $current_msg = $_; + } + } + + # Return TRUE when we have hit the end of the file. + if (!defined($_) || $_ eq "" ) { + return $TRUE; + } else { + return $FALSE; + } +} + +############################################################################## +# # +# SPLICE IN RESENT_HEADERS # +# # +############################################################################## +# +# Insert the Resent- headers at the *current location* of the message stream +# (In Engish, print out a few Resent-X: lines and return :-) ) +# In addition splice in the X-resent-info: header. + +# +# Paremters: None. +# Return: None +# +sub Splice_in_resent_headers { + local($date,$utctime,$weekday,$time,$month,$hostname); + + $current_msg .= "$RESENT_TO" . "$currentTO" . "\n"; + $current_msg .= "$RESENT_FROM" . "$SYSTEM_FROM_ADDRESS" . "\n"; + + # Calculate date and time. It is a bit of a shame to do this each time + # the time needs to be acurate. + + @utctime=gmtime(time); + + $weekday=(Sun,Mon,Tue,Wed,Thu,Fri,Sat)[$utctime[6]]; + + + # If the minutes or second do not take two columns each, patch em up. + if ( $utctime[1] < 10 ) { + if ( $utctime[0] < 10 ) { + $time=sprintf("%d:0%d:0%d",$utctime[2],$utctime[1],$utctime[0]); + } + else { + $time=sprintf("%d:0%d:%d",$utctime[2],$utctime[1],$utctime[0]); + } + } + else { + if ( $utctime[0] < 10 ) { + $time=sprintf("%d:%d:0%d",$utctime[2],$utctime[1],$utctime[0]); + } + else { + $time=sprintf("%d:%2d:%2d",$utctime[2],$utctime[1],$utctime[0]); + } + } + + $month=(Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)[$utctime[4]]; + + $date=sprintf("%s, %d %s %d %s UTC", $weekday, $utctime[3], $month, (($utctime[5] < 93 ? 20 : 19).$utctime[5]), $time); + + $current_msg .= "$RESENT_DATE" . $date . "\n"; + + if ( defined $RESENT_INFO && $RESENT_INFO ne "") { + $hostname=`uname -n`; + $current_msg .= "$RESENT_INFO" . "Lost mail resent from ". $hostname; + } + + return; +} + +############################################################################## +# # +# DO_REMAIL # +# # +############################################################################## +# +# Actually resends the mail. Talks to the process configured as $MAILER +# We need better handling. +# +sub Do_remail { + open (MAILER, "| $MAILER $currentTO") || return $ABORT_RESEND; + print MAILER $current_msg; + close (MAILER); +} + +############################################################################## +# # +# CLEAN_UP # +# # +############################################################################## +# +# Clean up my messes. +# +sub Clean_up { + local ($hostname); + + # Ugly local hack that you should never have seen, but I forgot to + # remove. Hopefully it did not kill you (I tried as you see), but you + # should eiter remove or update it for yourself. I find the message + # subject needs to have the hostname to be useful. + # + chop ($hostname=`uname -n`); + $LOG_SUBJECT="$LOG_SUBJECT from $hostname" if ( $hostname =~ /.*\.cs\.columbia\.edu/ ); + # + # End of ugly local hack + + # Mail any log info to MAILGRUNT. + if (defined($logfile) && $logfile ne "" ) { + close (LOGFILE); # Flush logfile output. + if ( -s $logfile ) { + open (MAILER, "| $MAILER $MAILGRUNT"); + + print MAILER "To: $MAILGRUNT\n"; + print MAILER "Subject: $LOG_SUBJECT\n"; + print MAILER "$HEADER_BODY_DELIM"; + + open (LOGFILE, "< $logfile"); + + while () { + print MAILER $_; + } + close (MAILER); + close (LOGFILE); + } + + unlink($logfile); + } + exit(0); +} + + +############################################################################## +# # +# COLLECT_WANDERERS # +# # +############################################################################## + +# +# Collects other files that appear to be mail file for the $currentTO +# but were not remailed successfully. +# +# Parameters: none (but uses $currentTO) +# Return: True if a old mail directory is found. False otherwise. +# Side effects: $wanderers set. +# +sub Collect_wanderers { + + undef (@wanderers); + + # Slurp in the directory and close. + + return ($found); +} + +############################################################################# +# # +# REMAIL ALL # +# # +############################################################################# + +# +# Takes an array of files that all seem to share a common repcipient and +# remails them if possible. +# +# Parameters: None (uses @wanderers). +# +sub Remail_all { + local($file,$i); + + $i=0; + foreach $file (@wanderers) { + if ( !open (LOSTFILE, "< $file")) { + &Log_info("Could not open " . "$file" . " for remailing"); + next; + } + + do { # Power loop! + $done = &Get_next_msg(LOSTFILE); # Retrieve the next message... + &Do_remail; # and remail it. + } until $done; + undef ($current_msg); # Erase the final remailed message. + + close(LOSTFILE); # Tidy up. + + unlink ($file); # Remove the remailed file + $i++; + } + +} + +############################################################################# +# # +# CHECK_USER # +# # +############################################################################# + +# +# Checks the password tables for the uid of $currentTO. If the user is +# uid 0 (ie *supposed* to get mail in altmail) or unknown the resend is +# aborted. +# +# +sub Check_user { + local (@passwdinfo); + undef (@passwdinfo); + + if ( !&vrfy_user($currentTO) ) { + &Log_info("Possible non user mail file: $currentTO"); + return $ABORT_RESEND; + } + + @passwdinfo = getpwnam($currentTO); + + print "Non user mailable mail: Name: $currentTO\n" + if ( $debug && ! defined @passwdinfo ); + + return !$ABORT_RESEND if ( ! defined @passwdinfo ); # A non user but evidently mailable + + print "Check User(): Name: $currentTO -- UID: $passwdinfo[2]\n" if ($debug); + + return $ABORT_RESEND if ( $passwdinfo[2] == 0 ); + + + return !$ABORT_RESEND; +} + +############################################################################# +# # +# VRFY USER # +# # +############################################################################# +# +# Use SMTP VRFY to insure that argument is in fact a legal mail id. +# Boolean: TRUE if mailable account, FALSE if not. + +sub vrfy_user { + + local ($mailname,$repl) = @_; + + if ( !&smtp_send("vrfy $mailname") ) { + &Log_info("Failed sending to vrfy smtp command for: $mailname"); + return 0; + } + + $repl = &smtp_recv; + + print "VRFY REPLY: $repl\n" if ($debug); + + return ( $repl =~ /^2\d\d/ ); + + +} + + +############################################################################# +# # +# MAIN PROC # +# # +############################################################################# + +# dummy code to shut up perl -w +$debug = 0 if !defined($debug); +print $nomail if $debug > 1; +print $RESENT_FROM if $debug > 1; +print $logopen if $debug > 1; +print $LOCAL_LOCK_EXT if $debug > 1; +print $RESENT_TO if $debug > 1; +print $LOCKEXT if $debug > 1; +print $RESENT_DATE if $debug > 1; +print $MESSAGE_DELIM if $debug > 1; +print $SMTP_retval if $debug > 1; +print $found if $debug > 1; +print $retry_list if $debug > 1; +print $MAILJUNK if $debug > 1; +print $noverify if $debug > 1; +print $SYSTEM_FROM_ADDRESS if $debug > 1; + +# BEGIN: stuff +$prefix="@prefix@"; +$CONFIGDIR="@sysconfdir@"; # Directory where global config lives +require "$CONFIGDIR/lostaltmail.conf" if (-f "$CONFIGDIR/lostaltmail.conf"); +require "/etc/global/lostaltmail.conf" if (-f "/etc/global/lostaltmail.conf"); +require "/etc/os/lostaltmail.conf" if (-f "/etc/os/lostaltmail.conf"); +require "/etc/local/lostaltmail.conf" if (-f "/etc/local/lostaltmail.conf"); + + +require "ctime.pl"; +use Socket; +#require "sys/socket.ph"; + +# SET some initial state variales +$logopen = 0; + +# +# Change to alt_dir +# +# Important!! This directory should be local. Folks will be responsible +# for finding this out for themselves. +# +chdir ( $MAILDIR ) || die "Cannot change to $MAILDIR (`x' bit not set?)"; + +# +# slurp in directory +# +opendir (MAIL, ".") || die "Cannot open $MAILDIR (`r' bit not set?)"; +@allentries= readdir (MAIL); +closedir (MAIL); +@allnames = grep (!/$LOCALMAILJUNK|$MAILJUNK/, @allentries); + +# Open chanel to SMTP for verification -- unless this option is +# configured off. + +if ( ! $noverify ) { + local($addr, $port,$sockaddr); + + socket (VRFY, &AF_INET, &SOCK_STREAM, 0) || + die "Could not create TCP socket (SMTP channel)"; + + $addr = (gethostbyname($SMTPHOST))[4]; # Just use the first addr + + die "Could not obtain STMP host ($SMTPHOST) address" + if ( $addr eq "" ); + + $port = (getservbyname('smtp','tcp'))[2]; # Get smtp port. + die "Could not obtain SMTP port number" if (!defined($port)); + + printf("SMTP: address: %s port: $port\n", + join ('.',unpack('C4',$addr))) if ($debug); + + $sockaddr = pack('n2C4x8',2, $port ,unpack('C4',$addr)); + + printf("Sockaddr: %s\n", join (' ',unpack('C14',$sockaddr))) if ($debug); + + connect (VRFY, $sockaddr) || + die "Could not connect to SMTP daemon on $SMTPHOST"; + + print "Establshed SMTP channel\n" if ($debug); + + &smtp_recv; # Greet wait + &smtp_send("helo $SMTPHOST"); # Helo message for picky SMTPs + &smtp_recv; # Helo reply + + # Connection is up and ready to VRFY +} + +# main stuff starts here +foreach $currentTO (@allnames) { + next if ( &Check_user == $ABORT_RESEND); + + undef (@wanderers); # Just reset this at each pass. + @wanderers=grep (/$currentTO\.\d+/, @allentries); + + $remail_file = &Lock_file($currentTO,$FALSE); # Need to lock the spool. + + next if ( $remail_file eq $ABORT_RESEND); # Could not get that lock + + push (@wanderers, $remail_file); # Try to resend "old" files. + print "List to remail: @wanderers\n" if ($debug); + # check if there is something to remail + &Remail_all if ( defined @wanderers && !$nomail); +} + +# this stuff should run at the end +foreach $file (grep (/$LOCALMAILJUNK/,@allentries)) { + + if ($debug) { + print "Would unlink $file\n" if ($debug); + } else { + unlink $file if (-f $file); + } + +} +&Clean_up; # Do a clean exit. diff --git a/contrib/amd/scripts/wait4amd.in b/contrib/amd/scripts/wait4amd.in new file mode 100755 index 0000000..5fd5030 --- /dev/null +++ b/contrib/amd/scripts/wait4amd.in @@ -0,0 +1,45 @@ +#!/bin/sh +# wait for amd to start up and then execute program +# usage: wait4amd [ [args ...]] +# If only hostname is supplied, command defaults to rsh $hostname +# +# Package: am-utils-6.0 +# Author: Erez Zadok + +#set -x + +if [ "X$1" = "X" ]; then + echo "Usage: wait4amd [ [args ...]]" + exit 1 +else + hostname=$1 + shift +fi + +# set path +prefix=@prefix@ +exec_prefix=@exec_prefix@ +PATH=@sbindir@:@bindir@:${PATH} +export PATH + +while true +do + amq -h $hostname > /dev/null 2>&1 + if [ $? != 0 ] + then + # failed + echo "Amd not up. Sleeping..." + sleep 5; + else + echo "Amd is active on host $hostname!" + cmd=$* + if [ -z "${cmd}" ] + then + cmd="rlogin $hostname" + fi + echo "Running: $cmd" + $cmd + echo "Sleep 1 second" + sleep 1 + fi +done diff --git a/contrib/amd/scripts/wait4amd2die.in b/contrib/amd/scripts/wait4amd2die.in new file mode 100755 index 0000000..d3541e7 --- /dev/null +++ b/contrib/amd/scripts/wait4amd2die.in @@ -0,0 +1,49 @@ +#!/bin/sh +# wait for amd to die on local host before returning from program. +# Usage: wait4amd2die [delay [count]] +# If not specified, delay=5 seconds and count=6 (total 30 seconds) +# If at end of total delay amd is till up, return 1; else return 0. +# +# Package: am-utils-6.0 +# Author: Erez Zadok + +#set -x + +# set path +prefix=@prefix@ +exec_prefix=@exec_prefix@ +PATH=@sbindir@:@bindir@:/usr/bin:/bin:${PATH} +export PATH + +# how long to wait? +if test -n "$1" +then + delay=$1 +else + delay=5 +fi +# how many times to delay +if test -n "$2" +then + count=$2 +else + count=6 +fi + +i=1 +maxcount=`expr $count + 1` +while [ $i != $maxcount ]; do + # run amq + @sbindir@/amq > /dev/null 2>&1 + if [ $? != 0 ] + then + # amq failed to run (because amd is dead) + echo "wait4amd2die: amd is down!" + exit 0 + fi + echo "wait4amd2die: delay $delay sec ($i of $count)..." + sleep $delay + i=`expr $i + 1` +done +echo "wait4amd2die: amd is still up..." +exit 1 diff --git a/contrib/amd/tasks b/contrib/amd/tasks new file mode 100644 index 0000000..a29b554 --- /dev/null +++ b/contrib/amd/tasks @@ -0,0 +1,64 @@ +# -*- text -*- + + AM-UTILS-6.0 TASKS TODO + +Please volunteer to do any of the following: + +- complete testing of untested platforms in INSTALL file + ncr2 + sunos 3.5 + +- autofs support: see README.autofs for details. + needs to be re-ported to solaris 2.6 (headers changed) + +- deal with everything that has XXX on it in the sources +- documentation update ("XXX: FILL IN" sections). + +- hlfsd should be able to not use /var/alt_mail, but send code 75 back to +sendmail (telling it to re-queue the mail and retry later). + +- compatibility with Sun's automount maps? + should be easier via the amd.conf file to specify type of map + perhaps done at the same time autofs support is done. + +- a selector ala if_exists() for networkmask(1.2.3.4/5.6.7.8), will match +against all known IP addresses of this host. + +- convert to using my own rpcgen .x files for amq/amq/nfs (v2 and v3) + +- support multiple "fail-over" NFS mounts in Solaris 2.6. + +- add LSM file + +- use packaging info for various OSs (such as RPM, Redhat Package Format) + +- $mindelay and $maxdelay in milliseconds + +- multiple nfsl should be matched if one matched and nfs mount failed. fall +through. +- fall through syntax? opts:=nofail,fallthrough? + +- random nfs rhost:={srv1, srv2, srv3} + +- after cutting next release dist, check that all files are there + +- nfslx, same as nfsl, but using linkx + +- find out why this sometimes works and sometimes not: + mcl -rhost:=minetta host!=${rhost};type:=nfs host==${rhost} + +- loadable info_*, amfs_*, and ops_* modules (lazy evaluation). + +- hlfsd for ~root/.mailspool (getpwnam("root")) +- hlfsd should daemonize even if -DDEBUG, then use -D nofork + +- fixmount should use generic code from transp/transp_{tli,sockets}.c + +- report netbsd/openbsd bugs in BUGS file + +- contribute patches to automake 1.3 + +- reverse notion of -F and other cmd-line options, so they override the +amd.conf file (right now amd.conf overrides cmd-line options). + +- y2k compliance. diff --git a/contrib/amd/wire-test/wire-test.8 b/contrib/amd/wire-test/wire-test.8 new file mode 100644 index 0000000..874ca92 --- /dev/null +++ b/contrib/amd/wire-test/wire-test.8 @@ -0,0 +1,70 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" Copyright (c) 1990 Jan-Simon Pendry +.\" Copyright (c) 1990 Imperial College of Science, Technology & Medicine +.\" Copyright (c) 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Jan-Simon Pendry at Imperial College, London. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" %W% (Berkeley) %G% +.\" +.\" $Id: fixmount.8,v 5.2.2.1 1992/02/09 15:11:15 jsp beta $ +.\" +.TH WIRE-TEST 8L "26 Feb 1993" +.SH NAME +wire-test \- test your network interfaces and local IP address +.SH SYNOPSIS +.B wire-test +[ +.I host +] +.SH DESCRIPTION +.LP +.B wire-test +is used to find out what amd thinks are the first two network +interfaces and network names/numbers used, as well as the IP address +used for amd to NFS-mount itself. + +If +.I host +is specified, then +.B wire-test +will test for the working combinations of NFS protocol and version from +the current client to the NFS server +.I host. +If not specified, +.I host +defaults to "localhost". + +.SH "SEE ALSO" +.BR amd (8). diff --git a/contrib/amd/wire-test/wire-test.c b/contrib/amd/wire-test/wire-test.c new file mode 100644 index 0000000..c53094b --- /dev/null +++ b/contrib/amd/wire-test/wire-test.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * Copyright (c) 1990 Jan-Simon Pendry + * Copyright (c) 1990 Imperial College of Science, Technology & Medicine + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Jan-Simon Pendry at Imperial College, London. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: wire-test.c,v 5.2.2.2 1992/06/07 18:06:46 jsp Exp jsp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ +#include + +#define STRMAX 100 + +/* dummy variables */ +char *progname, hostname[MAXHOSTNAMELEN]; +int orig_umask, foreground, debug_flags; +pid_t mypid; +serv_state amd_state; + +int +main(int argc, char **argv) +{ + char *networkName1, *networkNumber1; + struct in_addr myipaddr; /* (An) IP address of this host */ + char *testhost, *proto, *tmp_buf; + int nv, ret; + struct sockaddr_in *ip; + struct hostent *hp = 0; + + progname = argv[0]; + mypid = getpid(); + orig_umask = umask(0); + + if (gethostname(hostname, MAXHOSTNAMELEN) < 0) { + perror(argv[0]); + exit(1); + } + + /* get list of networks */ + getwire(&networkName1, &networkNumber1); + tmp_buf = print_wires(); + if (tmp_buf) { + fprintf(stderr, "%s", tmp_buf); + XFREE(tmp_buf); + } + + /* also print my IP address */ + amu_get_myaddress(&myipaddr); + fprintf(stderr, "My IP address is 0x%x.\n", (unsigned int) htonl(myipaddr.s_addr)); + + /* + * NFS VERSION/PROTOCOL TESTS: + * If argv[1] is specified perform nfs tests to that host, else use + * localhost. + */ + if (argc > 1) + testhost = argv[1]; + else + testhost = "localhost"; + hp = gethostbyname(testhost); + if (!hp) { + fprintf(stderr, "NFS vers/proto failed: no such hostname \"%s\"\n", testhost); + exit(1); + } + ip = (struct sockaddr_in *) xmalloc(sizeof(struct sockaddr_in)); + memset((voidp) ip, 0, sizeof(*ip)); + ip->sin_family = AF_INET; + memmove((voidp) &ip->sin_addr, (voidp) hp->h_addr, sizeof(ip->sin_addr)); + ip->sin_port = htons(NFS_PORT); + + xlog_level = 0; /* turn off debugging */ + fprintf(stderr, "NFS Version and protocol tests to host \"%s\"...\n", testhost); + proto = "udp"; + for (nv=2; nv<=3; ++nv) { + fprintf(stderr, "\ttesting vers=%d, proto=\"%s\" -> ", nv, proto); + ret = get_nfs_version(testhost, ip, nv, proto); + if (ret == 0) + fprintf(stderr, "failed!\n"); + else + fprintf(stderr, "found version %d.\n", ret); + } + + proto = "tcp"; + for (nv=2; nv<=3; ++nv) { + fprintf(stderr, "\ttesting vers=%d, proto=\"%s\" -> ", nv, proto); + ret = get_nfs_version(testhost, ip, nv, proto); + if (ret == 0) + fprintf(stderr, "failed!\n"); + else + fprintf(stderr, "found version %d.\n", ret); + } + + exit(0); + return 0; /* should never reach here */ +} -- cgit v1.1