v21i098: An Automounter for NFS systems, Part10/13
Rich Salz
rsalz at uunet.uu.net
Wed Apr 11 23:25:57 AEST 1990
Submitted-by: Jan-Simon Pendry <jsp at doc.ic.ac.uk>
Posting-number: Volume 21, Issue 98
Archive-name: amd/part10
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 10 (of 13)."
# Contents: ChangeLog map.c
# Wrapped by rsalz at papaya.bbn.com on Tue Apr 10 15:12:14 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'ChangeLog' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'ChangeLog'\"
else
echo shar: Extracting \"'ChangeLog'\" \(21923 characters\)
sed "s/^X//" >'ChangeLog' <<'END_OF_FILE'
XThu Jan 11 16:56:41 1990 Jan-Simon Pendry (jsp at achilles)
X
X * Release 5.1c.
X
X * (amq*) has new options. -f flushes the map cache and -m prints
X information about mounted filesystem and fileservers.
X
XTue Jan 2 14:44:21 1990 Jan-Simon Pendry (jsp at achilles)
X
X * (util.c) am_mounted() patches the path for "direct" mounted
X filesystems - cosmetic.
X
X * (afs_ops.c) when possible sets a small kernel attribute cache
X timeout on the automount points.
X
X * (nfs_stubs.c) delete() and rmdir() operations implemented. Used
X when a mount point is timed out so the kernel name cache gets to
X know about the changes. Fixes most ESTALE errors.
X
X * (nfs_stubs.c) New do_readlink() function added. This is used to
X make sure that a filesystem is mounted at the time a link is read
X in the case of "direct" mounts. Done so that the length of the
X link is available when the initial getattr is done on the mountpoint.
X
X * (sfs_ops.c) Changed implementation to avoid race conditions.
X The link target is re-arranged so that sublink points to the
X target and fs always points at ".".
X
X * Fixed mount flag bug on Ultrix.
X
X * Added support from Sjoerd Mullender for Alliant FX/4 and Encore
X Multimax.
X
XThu Dec 7 17:55:29 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (afs_ops.c) dfs_readlink now does a new_ttl on the node it
X returns.
X
X * (afs_ops.c) next_nonerror_node now implements the task after
X which it is named.
X
XTue Nov 28 17:20:52 1989 Jan-Simon Pendry (jsp at achilles)
X
X * Release 5.1b.
X
X * (restart.c) Generates link nodes for any unrecognised filesystem
X types and then marks them so that they are never deleted (since
X they could never be automounted later).
X
X * (os-*.h) Irrelevant #undef's deleted.
X
X * (arch) Now knows about AIX on RTs.
X
X * (amq.c) Rationalised the output. Now only gives you what you
X asked for.
X
X * (am.h) New macro: FSRV_ISDOWN(fs), which checks whether a
X fileserver is down.
X
X * (afs_ops.c) When a mount fails due to a timeout the underlying
X filesystem is ripped away and replaced with an error fs. This
X avoids the possibility of being left with a single error reference
X to a valid mounted filesystem.
X
XThu Nov 23 18:04:29 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (nfs_start.c) Re-order bootstrap sequence to avoid potential
X deadlock if restart() ends up accessing one of the automount points.
X
X * (amq.c) Don't produce default mount output if one of the -l, -x
X or -D options was used.
X
X * (umount_fs.c) Add alternative unmount routine for 4.4 BSD.
X
XMon Nov 20 16:22:50 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (os-bsd44.h) Fixed redefinition of UMOUNT_FS.
X
X * (info_ndbm.c) Added missing #include <sys/stat.h>.
X
X * (mapc.c) Fixed typo in ifdef around gdbm config entry.
X
XSat Nov 18 16:39:13 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (util.c) If "/" is automounted, make sure it is never timed out.
X
X * (mtab.c) Missing clock invalidation added in read_mtab (from a file).
X
X * (mntfs.c) realloc_mntfs simplified.
X
X * (map.c) Closed a race condition during shutdown when second and
X subsequent duplicate mounts were deleted prematurely.
X
X * (afs_ops.c) Duplicate mounts are now given the correct return
X code.
X
XFri Nov 17 18:58:18 1989 Jan-Simon Pendry (jsp at achilles)
X
X * 5.1 Release.
X
XThu Nov 16 17:57:02 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (mntfs.c) Make sure inherit mntfs structures are not cached
X after last reference; otherwise a second reference to the
X inherited filesystem will get stuck on the inherit rather than the
X (now) fully mounted filesystem.
X
X * (am.c, nfs_start.c) After forking the server, make sure the
X parent does not exit until the automount points are mounted. This
X allows a clean sequence during system startup.
X
X * Initial port to 4.4 BSD. Several new configuration abstractions
X were added to make this port possible.
X
XThu Nov 9 21:42:14 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (afs_ops.c, opts.c) Added map logging to facilitate mount map
X debugging without needing a -DDEBUG version of Amd.
X
X * (afs_ops.c) Make sure the length of the fs_hostname mount
X parameter does not exceed MAXHOSTNAMESZ.
X
XWed Nov 8 13:44:02 1989 Jan-Simon Pendry (jsp at achilles)
X
X * Change the message log format to indicate the severity of the
X message to allow simpler analysis of the log file.
X
XTue Nov 7 14:11:36 1989 Jan-Simon Pendry (jsp at achilles)
X
X * 5.0 Patchlevel 11.
X
X * (os-bsd44.h) Initial guess at 4.4 BSD definitions.
X
X * (os-aux.h) Port for Macintosh II from Julian Onions.
X
X * (amq.c) Output formats cleaned up. AMQ_MNTTREE is still broken
X in amq_subr.c though.
X
X * (afs_ops.c) If a mount timed out, for example an NFS server was
X down at the time, it was possible for the error code to remain
X unset thus jamming that mount node in a state from which it could
X not recover. Just make sure that the mf_error field gets filled
X in when an error occurs.
X
X * (afs_ops.c) strsplit is run over /defaults to avoid problems
X with whitespace creeping in.
X
XSun Nov 5 11:50:51 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (util.c) am_mounted: Added missing initialisation of stats.s_mtime.
X
XFri Nov 3 17:33:02 1989 Jan-Simon Pendry (jsp at achilles)
X
X * 5.0 Patchlevel 10.
X
X * Changed the copyright.
X
XThu Nov 2 17:07:53 1989 Jan-Simon Pendry (jsp at achilles)
X
X * 5.0 Patchlevel 9.
X
X * (opts.c) new option syntax: == != :=
X
X * (nfs_ops.c) Less caching of filehandles. Now cached errors are
X discarded after use.
X
X * (mtab.c) now attempts to deal with a lack of open file slots (ENFILE).
X
X * (mount_fs.c) automount entries in the mount table now have a
X dev= entry in the same way as NFS and UFS.
X
X * (mntfs.c) mntfs nodes are now cached after the last reference
X and discarded <ALLOWED_MOUNT_TIME> seconds later. This avoids
X thrashing during a mount.
X
X * (mapc.c) map default cache mode is now selected with
X "mapdefault", not "default"
X
X * (amd.tex) numerous clarifications. Still more work required...
X
X * (amq_subr.c) now allows the -x option of amq to operate.
X
X * (afs_ops.c) afs_bgmount now keeps track of which filesystem
X needed retrying and ensures that the mount node in the
X continuation correctly points at an unmounted filesystem. This
X fixes a problem whereby a valid mounted filesystem could appear to
X have failed to mount.
X
X * Configure now gives more of a running commentary and checks
X whether os-type and arch actually worked.
X
X * Allow spurious ';'s in a mount location.
X
XFri Oct 27 14:03:31 1989 Jan-Simon Pendry (jsp at achilles)
X
X * foo=blah changed to foo:=blah, foo==blah and foo!=blah.
X
X * -l stderr changed to -l /dev/stderr.
X
XThu Oct 19 15:34:28 1989 Jan-Simon Pendry (jsp at achilles)
X
X * 5.0 Patchlevel 6.
X
X * LOG_INFO messages have been rationalised so that some
X statistics, graphs and so on can be generated.
X
X * Transaction ID's for RPC calls are now allocated by the
X individual callers, rather than from a central pool. This
X decreases the load on mount daemons and NFS servers since the
X same XID is used for retries when needed.
X
X * Many fine details of the new data structures have been changed.
X Some areas have been optimized.
X
XFri Oct 13 12:31:26 1989 Jan-Simon Pendry (jsp at achilles)
X
X * Restart code re-implemented to work with the new data structures.
X
X * Fine tuning applied to new NFS server modeling code.
X
XThu Oct 12 15:57:24 1989 Jan-Simon Pendry (jsp at achilles)
X
X * Added ${/var} and ${var/} variable expansions. The first gives
X the "basename" component of the variable, the latter gives the
X "dirname" component. Additionally, spurious /'s are deleted after
X the variable expansions is complete.
X
X * Added new -C option to allow the machine's cluster name to be
X given to amd. ${cluster} fetches the value and can be used as
X another selector.
X
X * Broken the major data struct (am_node) into three layers:
X am_node (one for each automount node), mntfs (one for each mounted
X filesystem) and fserver (one for each file server). Machine
X up/down state is maintained in the fserver layer. Filesystem
X mount/unmount state is maintained in the mntfs layer. This change
X fixes the last known major problem caused by the lack of a central
X focus for filesystem and fileserver status. There is a dummy file
X server layer for local filesystems (ufs, link, program, error).
X
XTue Oct 10 11:15:42 1989 Jan-Simon Pendry (jsp at achilles)
X
X * 5.0 Patchlevel 5.
X
X * (nfs_ops.c) the filehandle cache is now flushed when a
X filesystem is unmounted. This avoids ending up with stale
X information if a server bounces.
X
X * (clock.c) new module to implement callouts. Many other
X routines changed to use callouts instead of messing with ttl
X fields.
X
XSun Oct 1 17:08:20 1989 Jan-Simon Pendry (jsp at achilles)
X
X * 5.0 Patchlevel 3 & 4.
X
X * Numerous cleanups.
X
XWed Sep 13 14:30:05 1989 Jan-Simon Pendry (jsp at achilles)
X
X * 5.0 Patchlevel 2.
X
X * (nfs_ops.c) portmap information is not remembered beyond the
X basic filehandle cache interval. That avoids problems when a new
X portmap and/or rpc.mountd is started and the bound port changes.
X
X * (mapc.c) cache reloads are automatically done every hour.
X
X * Removed xlog macro in favour of plog() so that the log level
X can be reflected through to syslog(). log() routine renamed to
X plog() which takes an extra parameter indicating the log level.
X
XTue Sep 5 20:00:19 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (nfs_ops.c) when a server is known to be down, any cached file
X handles and port mapping informaton is flushed since that may have
X changed when it comes back up.
X
X * (map.c) timeout no longer attempts to unmount a hung mount point.
X
XMon Sep 4 14:49:18 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (afs_ops.c) a mount node which timed out during mount is now
X retained for the normal timeout interval rather than for a short
X period. This avoids wasting time retrying mounts from a server
X which is down.
X
X * (afs_ops.c) hung mounts are now detected and not used as a
X duplicate mount - something which defeated the replacement fs
X scheme.
X
X * (nfs_ops.c) keepalive's now back-off when a server has gone
X down.
X
XThu Aug 31 21:18:35 1989 Jan-Simon Pendry (jsp at achilles)
X
X * 5.0 Patchlevel 1.
X
X * Fixed several bugs which showed up in the keepalive
X implementation when a gateway went down causing
X a different sequence of errors than usual.
X
XWed Aug 30 11:29:21 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (amq.x) now uses a Sun assigned program number.
X
X * Revision 5.0 - can now start using metaconfig.
X
XTue Aug 29 14:36:48 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (os-u3_0.h, os-type) now knows about DECstations (mips).
X
X * (nfs_stubs.c) Added hooks to readlink entry point to call
X per-fs readlink routine if it exists, otherwise old behaviour.
X
X * (afs_ops.c) Added implementation of "type=direct". This is
X the same as "type=auto" but is itself the link to the
X mount point, rather than being a directory containing a list
X of links to mount points.
X
XMon Aug 28 17:48:15 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (afs_ops.c) Changed readdir to workaround a problem on
X ultrix 3 where it seems to forget that eof has been reached.
X
XThu Aug 24 15:17:55 1989 Jan-Simon Pendry (jsp at achilles)
X
X * Created "beta16".
X
X * (afs_ops.c) /defaults is located along with every key.
X this makes it possible to update the /defaults in
X a map and get to use it.
X
X * (mapc.c) added map cache synchronization support. if
X a file or ndbm map is updated the cache is junked so avoiding
X things getting out of sync.
X
XWed Aug 23 19:17:52 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (os-u3_0.h) new file to support Ultrix 3.0
X
X * (opts.c) allow environment variables to be accessed via
X the same ${env} syntax used for options & selectors.
X
XTue Aug 22 13:19:49 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (opts.c, get_args.c) added support for kernel architecture
X type to allow /usr/kvm to be automounted under SunOS 4.x.
X
X * (os-xinu43.h) updated for june '89 release of MORE/bsd.
X
X * (opts.c) fixed memory allocation problems where some strings
X may not have been strdup'ed before they were free'ed so causing
X the malloc arena to get into a twist. This caused core dumps on
X some machines and infinite loops on others.
X
X * (*.c) clock handling is now done by a macro. Global variable
X clock_valid is > 0 (ie the time) when valid, 0 if invalid.
X
X * (map.c) timeout code survived a complete rewrite and is now
X O(n) rather than O(n^2).
X
X * (info_hes.c) new database hooks for Hesiod nameserver.
X
X * (get_args.c) the local sub-domain is picked up from the
X hostname if it is not specifed with -d. The subdomain is
X then stripped from the hostname.
X
X * (am.c) when a SIGTERM is received, an immediate abort
X occurs - only the top-level automounts are unmounted; all
X other mounts stay -- use amd -r to restart.
X
X * (afs_ops.c) cleaned up key prefix handling. Again updated
X the "hostname" string passed to the kernel so that includes
X the hostname, pid and mount point.
X
XTue Aug 8 16:05:23 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (nfs_ops.c) changed the way the file handle cache is managed.
X No longer gets a race condition between something entering the
X cache and being used and discard.
X
XTue Jul 25 20:40:51 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (map.c) changed fh_to_mp2 so that it does not return
X ESTALE during shutdown. it returns ENOENT instead which
X avoids thrashing with the kernel.
X
XSun Jul 23 15:06:10 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (afs_ops.c) make sure the incoming key from the kernel
X does not contain any characters which could cause trouble
X during macro expansion (such as `"! etc).
X
X * (afs_ops.c) fixed contruction of "mtab" entry.
X
XFri Jul 21 11:01:05 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (afs_ops.c) some changes to support the new startup
X shutdown scheme.
X
X * (map.c) startup and shutdown are now done using the
X standard interfaces. Startup is done by creating a
X private cache map ";root;" and then doing lookups
X on all the names in it. Shutdown is done by forcibly
X timing out all the mount points including the automount
X points.
X
X * (info_*.c) modified to provide interface required by
X mapc.c module.
X
X * (mapc.c) new module to implement map caching. Caching
X can be controlled by an fs option. "all" means cache
X the entire map (if possible). "inc" means cache things
X incrementally. "none" means never cache things. Each
X map type has a default caching mode which is used if
X cache option "default" is used.
X
XWed Jul 19 16:14:52 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (sched.c) implements a general sleep/wakeup scheme and uses
X it for sub-process handling.
X
X * (nfs_start.c) task_notify() called from where it used to
X be called.
X
X * (nfs_ops.c) now implements a non-blocking rpc library.
X Everything in nfs_ops was changed to use it. This should
X not be in this file and will be moved later.
X
X * (map.c) if a mount point times out and it is deferred then
X issue a wakeup so that it can be retried.
X
X * (map.c) when creating a new mount point fetches the entry
X "/defaults" from the associated map if no other options are
X specified.
X
X * (am.c) implements the -p (print process id) option.
X
X * (afs_ops.c) a mount attempt now has a time-to-live of twenty
X seconds. if only deferred attempts are waiting after that
X interval the kernel gets sent ETIMEDOUT.
X
X * (afs_ops.c) the name by which the kernel knows the filesystem
X has changed from pid%d at host to /mountpoint at host. That looks
X better to users who get hit by it.
X
XFri Jul 14 18:46:16 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (afs_ops.c) now knows about defered mounts - mounts which
X are not in progress, not completed, and not failed.
X
X * (sched.c) added new entry point sched_ast(). This simulates
X a completed job. The basic idea is to let something else return
X to the main scheduling loop with a guarentee that it will be
X called back when some other action has taken place.
X
X * (nfs_ops.c) implemented a file handle cache. The nfs_init
X routine starts up a request for the filehandle and the mount
X routine uses it when it arrives.
X
XThu Jul 13 18:07:58 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (afs_ops.c) found a race condition between an error occuring
X and the am_node being timed out. Fixed by updating the
X time-to-live and keepalive counters in the node whenever
X AMF_MOUNTING is cleared. Also changed afs_lookuppn() so that
X it doesn't destroy the node when it returns the error code.
X This stops thrashing and the node is eventually timed out.
X Now the only way a node gets deleted is by the timeout code
X which seems more elegant.
X
XTue Jul 11 15:36:44 1989 Jan-Simon Pendry (jsp at achilles)
X
X * Created "beta15".
X
X * Fixed *all* references to "u2.2". Some where missed in
X the original change. They are now u2_2.
X
X * (mk-amd-map.c) new command. Converts plain files into
X ndbm databases for use by the info_ndbm module. Hooks
X included for future support for gdbm just as soon as I
X can get a copy.
X
XSun Jul 9 19:00:22 1989 Jan-Simon Pendry (jsp at achilles)
X
X * Created "beta14".
X
X * (get_info.c) code to handle yp and files now split into
X new files info_yp.c and info_file.c New support for ndbm
X databases is in info_ndbm.c. A table in get_info.c controls
X what and in which order things are searched.
X
X * (map.c, nfs_stubs.c) better handling for hung mount points.
X if a filehandle is passed in by the kernel which references
X a hung node, then try to find a replacement, possibly by calling
X lookup explicitly.
X
X * (*.c) use new xlog(level)(message) interface
X
XThu Jun 8 20:28:55 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (nfs_ops.c, ufs_ops.c) when compiled with DEBUG, display
X the fs options being used.
X
X * (am.c) make test for root a little more polite.
X
X * (get_args.c) update Usage message to include -r option.
X
XWed Jun 7 16:28:51 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (rpc_fwd.c) fwd_reply: if the recvfrom call fails because it
X is interrupted then try again.
X
XTue Jun 6 16:39:15 1989 Jan-Simon Pendry (jsp at achilles)
X
X * Created "beta12".
X
X * (afs_ops.c) inheriting mount option list from command line
X is now cumulative. A -foo on the command line is prepended
X to the default option list taken from the map. This can be
X used to override the ``default default'' options in opts.c.
X
X * (get_args.c, am.c) added new -r (restart) option. Restart of
X mounted filesystems is only done if this option is specified.
X Should *not* be specified in /etc/rc.local of course.
X
X * (yp_master.c) make the enumeration error message more verbose
X when debugging is enabled.
X
X * (rpc_fwd.c) rearranged some declarations at the top. Removed
X a spurious call to free which was causing grief on some systems,
X but not on Sun's. [This problem was the reason for implementing
X the -D mem option.]
X
X * (opts.c) make sure opt_key and opt_path are set to a zero
X length string unless otherwise specified. Previously they
X were are source of dangling pointers.
X
X * (nfs_ops.c) make sure that the allocated nfs_private identifiers
X are unique even when some filesystem are being restarted. This mean
X starting the basic allocation from 1, not zero.
X
X * (am.h, get_args.c, util.c) added definition and implmentation of
X a simple memory allocation trace (D_MEM).
X
X * (afs_ops.c) afs_lookuppn: tightened up memory allocation and
X delay string copying until last possible moment.
X
XMon Jun 5 18:01:18 1989 Jan-Simon Pendry (jsp at achilles)
X
X * (Makefile.com) diffs: added new rule to generate diffs
X between versions.
X
X * (get_info.c) search_file: added a new dlog() to note when
X wildcards are returned.
X
X * (afs_ops.c) afs_lookuppn: call to init_map specifies efs as
X the default ops structure. If the location list only contained
X defaults and no real mounts then this previously caused a null
X pointer dereference.
X
X * (map.c) last_used_map: Added new variable. Keeps track of the
X last used map, which may be wildly different from first_free_map.
X This fixes bugs in several routines in this file.
X
X * (util.c) mkdirs, rmdirs: Changed directory make/unmake. It is
X not possible to quickly determine how many directories need to
X be created or deleted, so we try to make as many as possible.
X
X * (opts.c) Added default values for rfs, rhost and fs.
X The new defaults guarentee unique names to allow the NFS
X keepalive stuff to work.
X
XSun Jun 4 16:12:15 1989 Jan-Simon Pendry (jsp at achilles)
X
X * First draft of documentation included in the next release.
X
X * Hooks for TFS added, though this still requires a lot of work.
X
X * Re-implemented option handling. Options are now allocated
X dynamically on a per-mount basis in the continuation structure.
X
X * Changed os type u2.2 to u2_2 to allow for regular expression
X matching in selectors.
X
X * Format of mount maps is now entirely different. Instead of
X guessing which filesystem type is being used, it is now explicitly
X stated along with the required options. Variable expansion is
X done on the options and selectors are also implemented. The
X requested name can also contain any of the selectors.
X
XWed May 24 15:21:39 1989 Jan-Simon Pendry (jsp at achilles)
X
X * Re-implemented NFS ping algorithm to use the new RPC forwarding
X system. This allowed a large amount of nfs_ops specific code
X to be removed from nfs_start.c and moved to nfs_ops.c.
X There is still no strategy for hung file systems. At the moment
X it will merely try to mount an alternative (or the same again)
X to the same place in the file system.
X
X * Added RPC forwarding package. This supports general RPC gatewaying
X over a UDP transport. The idea is to put a packet identifier into
X each outgoing RPC packet and then match that up in a database when
X a reply comes in. The database records the original packet identifier
X (so that it can be replaced), the source address for the packet and
X a function to call to do the forwarding.
X
X * ChangeLog added between beta8 and beta9. Should have done this sooner.
END_OF_FILE
if test 21923 -ne `wc -c <'ChangeLog'`; then
echo shar: \"'ChangeLog'\" unpacked with wrong size!
fi
# end of 'ChangeLog'
fi
if test -f 'map.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'map.c'\"
else
echo shar: Extracting \"'map.c'\" \(19814 characters\)
sed "s/^X//" >'map.c' <<'END_OF_FILE'
X/*
X * $Id: map.c,v 5.1.1.3 90/01/11 17:08:32 jsp Exp Locker: jsp $
X *
X * Copyright (c) 1990 Jan-Simon Pendry
X * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Jan-Simon Pendry at Imperial College, London.
X *
X * Redistribution and use in source and binary forms are permitted
X * provided that the above copyright notice and this paragraph are
X * duplicated in all such forms and that any documentation,
X * advertising materials, and other materials related to such
X * distribution and use acknowledge that the software was developed
X * by Imperial College of Science, Technology and Medicine, London, UK.
X * The names of the College and University may not be used to endorse
X * or promote products derived from this software without specific
X * prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X * %W% (Berkeley) %G%
X */
X
X#include "am.h"
X#include <sys/param.h> /* For NMOUNT */
X
X/*
X * Generation Numbers.
X *
X * Generation numbers are allocated to every node created
X * by amd. When a filehandle is computed and sent to the
X * kernel, the generation number makes sure that it is safe
X * to reallocate a node slot even when the kernel has a cached
X * reference to its old incarnation.
X * No garbage collection is done, since it is assumed that
X * there is no way that 2^32 generation numbers could ever
X * be allocated by a single run of amd - there is simply
X * not enough cpu time available.
X */
Xstatic unsigned int am_gen = 2; /* Initial generation number */
X#define new_gen() (am_gen++)
X
Xstruct am_node *exported_ap[NEXP_AP];
Xint first_free_map = 0; /* First available free slot */
Xint last_used_map = -1; /* Last unavailable used slot */
Xstatic int timeout_mp_id; /* Id from last call to timeout */
X
X/*
X * The root of the mount tree.
X */
Xstatic am_node *root_node;
X
X/*
X * Allocate a new mount slot and create
X * a new node.
X * Fills in the map number of the node,
X * but leaves everything else uninitialised.
X */
Xstruct am_node *exported_ap_alloc(P_void)
X{
X struct am_node *mp, **mpp;
X
X /*
X * First check if there are any slots left
X */
X if (first_free_map >= NEXP_AP)
X return 0;
X
X /*
X * Grab the next free slot
X */
X mpp = exported_ap + first_free_map;
X mp = *mpp = ALLOC(am_node);
X bzero((char *) mp, sizeof(*mp));
X
X mp->am_mapno = first_free_map++;
X
X /*
X * Update free pointer
X */
X while (first_free_map < NEXP_AP && exported_ap[first_free_map])
X first_free_map++;
X
X if (first_free_map > last_used_map)
X last_used_map = first_free_map - 1;
X
X#ifdef DEBUG
X /*dlog("alloc_exp: last_used_map = %d, first_free_map = %d\n",
X last_used_map, first_free_map);*/
X#endif
X
X return mp;
X}
X
X/*
X * Free a mount slot
X */
Xvoid exported_ap_free(mp)
Xstruct am_node *mp;
X{
X /*
X * Sanity check
X */
X if (!mp)
X return;
X
X /*
X * Zero the slot pointer to avoid double free's
X */
X exported_ap[mp->am_mapno] = 0;
X
X /*
X * Update the free and last_used indices
X */
X if (mp->am_mapno == last_used_map)
X while (last_used_map >= 0 && exported_ap[last_used_map] == 0)
X --last_used_map;
X
X if (first_free_map > mp->am_mapno)
X first_free_map = mp->am_mapno;
X
X#ifdef DEBUG
X /*dlog("free_exp: last_used_map = %d, first_free_map = %d\n",
X last_used_map, first_free_map);*/
X#endif
X
X /*
X * Free the mount node
X */
X free(mp);
X}
X
X/*
X * Insert mp into the correct place,
X * where p_mp is its parent node.
X * A new node gets placed as the youngest sibling
X * of any other children, and the parent's child
X * pointer is adjusted to point to the new child node.
X */
Xvoid insert_am(mp, p_mp)
Xam_node *mp;
Xam_node *p_mp;
X{
X /*
X * If this is going in at the root then flag it
X * so that it cannot be unmounted by amq.
X */
X if (p_mp == root_node)
X mp->am_flags |= AMF_ROOT;
X /*
X * Fill in n-way links
X */
X mp->am_parent = p_mp;
X mp->am_osib = p_mp->am_child;
X if (mp->am_osib)
X mp->am_osib->am_ysib = mp;
X p_mp->am_child = mp;
X}
X
X/*
X * Remove am from its place in the mount tree
X */
Xvoid remove_am(mp)
Xam_node *mp;
X{
X /*
X * 1. Consistency check
X */
X if (mp->am_child && mp->am_parent) {
X plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path);
X }
X
X /*
X * 2. Update parent's child pointer
X */
X if (mp->am_parent && mp->am_parent->am_child == mp)
X mp->am_parent->am_child = mp->am_osib;
X
X /*
X * 3. Unlink from sibling chain
X */
X if (mp->am_ysib)
X mp->am_ysib->am_osib = mp->am_osib;
X if (mp->am_osib)
X mp->am_osib->am_ysib = mp->am_ysib;
X}
X
X/*
X * Compute a new time to live value for a node.
X */
Xvoid new_ttl(mp)
Xam_node *mp;
X{
X mp->am_timeo_w = 0;
X
X mp->am_ttl = clocktime();
X mp->am_mnt->mf_fattr.atime.seconds = mp->am_ttl;
X mp->am_ttl += mp->am_timeo; /* sun's -tl option */
X}
X
X/*
X * Initialise an allocated mount node.
X * It is assumed that the mount node was bzero'd
X * before getting here so anything that would
X * be set to zero isn't done here.
X */
Xvoid init_map(mp, dir)
Xam_node *mp;
Xchar *dir;
X{
X /* mp->am_mapno initalised by exported_ap_alloc */
X mp->am_mnt = new_mntfs();
X mp->am_name = strdup(dir);
X mp->am_path = strdup(dir);
X /*mp->am_link = 0;*/
X /*mp->am_parent = 0;*/
X /*mp->am_ysib = 0;*/
X /*mp->am_osib = 0;*/
X /*mp->am_child = 0;*/
X /*mp->am_flags = 0;*/
X /*mp->am_error = 0;*/
X mp->am_gen = new_gen();
X /*mp->am_pref = 0;*/
X
X mp->am_timeo = am_timeo;
X new_ttl(mp);
X mp->am_stats.s_mtime = mp->am_mnt->mf_fattr.atime.seconds;
X /*mp->am_private = 0;*/
X}
X
X/*
X * Free a mount node.
X * The node must be already unmounted.
X */
Xvoid free_map(mp)
Xam_node *mp;
X{
X remove_am(mp);
X
X if (mp->am_link)
X free(mp->am_link);
X if (mp->am_name)
X free(mp->am_name);
X if (mp->am_path)
X free(mp->am_path);
X if (mp->am_pref)
X free(mp->am_pref);
X
X if (mp->am_mnt)
X free_mntfs(mp->am_mnt);
X
X if (mp->am_flags & AMF_MKPATH)
X rmdirs(mp->am_path);
X exported_ap_free(mp);
X}
X
X/*
X * Convert from file handle to
X * automount node.
X */
Xam_node *fh_to_mp3(fhp, rp, c_or_d)
Xnfs_fh *fhp;
Xint *rp;
Xint c_or_d;
X{
X struct am_fh *fp = (struct am_fh *) fhp;
X am_node *ap = 0;
X
X /*
X * Check process id matches
X * If it doesn't then it is probably
X * from an old kernel cached filehandle
X * which is now out of date.
X */
X if (fp->fhh_pid != mypid)
X goto drop;
X
X /*
X * Make sure the index is valid before
X * exported_ap is referenced.
X */
X if (fp->fhh_id < 0 || fp->fhh_id >= NEXP_AP)
X goto drop;
X
X /*
X * Get hold of the supposed mount node
X */
X ap = exported_ap[fp->fhh_id];
X
X /*
X * If it exists then maybe...
X */
X if (ap) {
X /*
X * Check the generation number in the node
X * matches the one from the kernel. If not
X * then the old node has been timed out and
X * a new one allocated.
X */
X if (ap->am_gen != fp->fhh_gen) {
X ap = 0;
X goto drop;
X }
X
X /*
X * If the node is hung then locate a new node
X * for it. This implements the replicated filesystem
X * retries.
X */
X if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) {
X int error;
X#ifdef DEBUG
X dlog("fh_to_mp3: %s (%s) is hung:- call lookup", ap->am_path, ap->am_mnt->mf_info);
X#endif
X /*
X * Update last access to original node. This
X * avoids timing it out and so sending ESTALE
X * back to the kernel.
X */
X new_ttl(ap);
X
X /*
X * Call the parent's lookup routine for an object
X * with the same name. This may return -1 in error
X * if a mount is in progress. In any case, if no
X * mount node is returned the error code is propagated
X * to the caller.
X */
X if (c_or_d == VLOOK_CREATE) {
X ap = (*ap->am_parent->am_mnt->mf_ops->lookuppn)(ap->am_parent,
X ap->am_name, &error, c_or_d);
X } else {
X ap = 0;
X error = ESTALE;
X }
X if (ap == 0) {
X *rp = error;
X return 0;
X }
X }
X /*
X * Disallow references to objects being unmounted, unless
X * they are automount points.
X */
X if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) &&
X !(ap->am_flags & AMF_ROOT)) {
X *rp = -1;
X return 0;
X }
X new_ttl(ap);
X }
X
Xdrop:
X if (!ap || !ap->am_mnt) {
X /*
X * If we are shutting down then it is likely
X * that this node has disappeared because of
X * a fast timeout. To avoid things thrashing
X * just pretend it doesn't exist at all. If
X * ESTALE is returned, some NFS clients just
X * keep retrying (stupid or what - if it's
X * stale now, what's it going to be in 5 minutes?)
X */
X if (amd_state == Finishing)
X *rp = ENOENT;
X else
X *rp = ESTALE;
X amd_stats.d_stale++;
X }
X
X return ap;
X}
X
Xam_node *fh_to_mp(fhp)
Xnfs_fh *fhp;
X{
X int dummy;
X return fh_to_mp2(fhp, &dummy);
X}
X
X/*
X * Convert from automount node to
X * file handle.
X */
Xvoid mp_to_fh(mp, fhp)
Xam_node *mp;
Xstruct nfs_fh *fhp;
X{
X struct am_fh *fp = (struct am_fh *) fhp;
X
X /*
X * Take the process id
X */
X fp->fhh_pid = mypid;
X /*
X * .. the map number
X */
X fp->fhh_id = mp->am_mapno;
X /*
X * .. and the generation number
X */
X fp->fhh_gen = mp->am_gen;
X /*
X * .. to make a "unique" triple that will never
X * be reallocated except across reboots (which doesn't matter)
X * or if we are unlucky enough to be given the same
X * pid as a previous amd (very unlikely).
X */
X}
X
Xstatic am_node *find_ap2(dir, mp)
Xchar *dir;
Xam_node *mp;
X{
X if (mp) {
X am_node *mp2;
X if (strcmp(mp->am_path, dir) == 0)
X return mp;
X
X if ((mp->am_mnt->mf_flags & MFF_MOUNTED) &&
X strcmp(mp->am_mnt->mf_mount, dir) == 0)
X return mp;
X
X mp2 = find_ap2(dir, mp->am_osib);
X if (mp2)
X return mp2;
X return find_ap2(dir, mp->am_child);
X }
X
X return 0;
X}
X
X/*
X * Find the mount node corresponding
X * to dir. dir can match either the
X * automount path or, if the node is
X * mounted, the mount location.
X */
Xam_node *find_ap(dir)
Xchar *dir;
X{
X int i;
X
X for (i = last_used_map; i >= 0; --i) {
X am_node *mp = exported_ap[i];
X if (mp && (mp->am_flags & AMF_ROOT)) {
X mp = find_ap2(dir, exported_ap[i]);
X if (mp)
X return mp;
X }
X }
X
X return 0;
X}
X
X/*
X * Get the filehandle for a particular named directory.
X * This is used during the bootstrap to tell the kernel
X * the filehandles of the initial automount points.
X */
Xnfs_fh *root_fh(dir)
Xchar *dir;
X{
X static nfs_fh nfh;
X am_node *mp = root_ap(dir, TRUE);
X if (mp) {
X mp_to_fh(mp, &nfh);
X return &nfh;
X }
X
X /*
X * Should never get here...
X */
X plog(XLOG_ERROR, "Can't find root filehandle for %s", dir);
X return 0;
X}
X
Xam_node *root_ap(dir, path)
Xchar *dir;
Xint path;
X{
X am_node *mp = find_ap(dir);
X if (mp && mp->am_parent == root_node)
X return mp;
X
X return 0;
X}
X
X/*
X * Mount a top level automount node
X * by calling lookup in the parent
X * (root) node which will cause the
X * automount node to be automounted (!)
X */
Xstatic void mount_auto_node(dir)
Xchar *dir;
X{
X int error = 0;
X (void) afs_ops.lookuppn(root_node, dir, &error, VLOOK_CREATE);
X if (error) {
X errno = error; /* XXX */
X plog(XLOG_ERROR, "Could not start server on %s: %m", dir);
X }
X}
X
X/*
X * Cause all the top-level mount nodes
X * to be automounted
X */
Xint mount_exported()
X{
X /*
X * Iterate over all the nodes to be started
X */
X return root_keyiter(mount_auto_node);
X}
X
X/*
X * Construct top-level node
X */
Xvoid make_root_node()
X{
X mntfs *root_mnt;
X char *rootmap = ROOT_MAP;
X root_node = exported_ap_alloc();
X
X init_map(root_node, "");
X root_mnt = find_mntfs(&afs_ops, (am_opts *) 0, "", rootmap, "");
X root_mnt->mf_mount = strealloc(root_mnt->mf_mount, pid_fsname);
X root_mnt->mf_private = (voidp) mapc_find(rootmap, "");
X root_mnt->mf_prfree = mapc_free;
X free_mntfs(root_node->am_mnt);
X root_node->am_mnt = root_mnt;
X root_node->am_flags |= AMF_NOTIMEOUT;
X root_mnt->mf_error = 0;
X}
X
X/*
X * Cause all the nodes to be unmounted by timing
X * them out.
X */
Xvoid umount_exported(P_void)
X{
X int i;
X for (i = last_used_map; i >= 0; --i) {
X am_node *mp = exported_ap[i];
X if (mp) {
X mntfs *mf = mp->am_mnt;
X if (mf->mf_flags & MFF_UNMOUNTING) {
X /*
X * If this node is being unmounted then
X * just ignore it. However, this could
X * prevent amd from finishing if the
X * unmount gets blocked since the am_node
X * will never be free'd. am_unmounted needs
X * telling about this possibility. - XXX
X */
X continue;
X }
X if (mf && mf->mf_ops == &dfs_ops) {
X /*
X * When shutting down this had better
X * look like a directory, otherwise it
X * can't be unmounted!
X */
X mf->mf_fattr.type = NFDIR;
X mf->mf_fattr.mode = NFSMODE_DIR | 0555;
X }
X if ((--immediate_abort < 0 && !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
X (mf->mf_flags & MFF_RESTART)) {
X /*
X * Just throw this node away without
X * bothering to unmount it. If the
X * server is not known to be up then
X * don't discard the mounted on directory
X * or Amd might hang...
X */
X if (mf->mf_server &&
X (mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) != FSF_VALID)
X mf->mf_flags &= ~MFF_MKMNT;
X am_unmounted(mp);
X } else {
X /*
X * Any other node gets forcibly
X * timed out
X */
X mp->am_flags &= ~AMF_NOTIMEOUT;
X mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
X mp->am_ttl = 0;
X mp->am_timeo = 1;
X mp->am_timeo_w = 0;
X }
X }
X }
X}
X
Xstatic int unmount_node P((am_node *mp));
Xstatic int unmount_node(mp)
Xam_node *mp;
X{
X mntfs *mf = mp->am_mnt;
X int error;
X
X if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) {
X /*
X * Just unlink
X */
X#ifdef DEBUG
X if (mf->mf_flags & MFF_ERROR)
X dlog("No-op unmount of error node %s", mf->mf_info);
X#endif
X error = 0;
X } else {
X#ifdef DEBUG
X dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info);
X#endif
X error = (*mf->mf_ops->umount_fs)(mp);
X }
X
X if (error) {
X#ifdef DEBUG
X errno = error; /* XXX */
X dlog("%s: unmount: %m", mf->mf_mount);
X#endif
X }
X
X return error;
X}
X
Xstatic int unmount_node_wrap P((voidp vp));
Xstatic int unmount_node_wrap(vp)
Xvoidp vp;
X{
X /*
X * This code should just say:
X * return unmount_node((am_node *) vp);
X *
X * However...
X * The kernel keeps a cached copy of filehandles,
X * and doesn't ever cache them (apparently). So
X * when Amd times out a node the kernel will have a
X * stale filehandle. When the kernel next uses the
X * filehandle it gets ESTALE.
X *
X * The workaround:
X * Arrange that when a node is removed an unlink or
X * rmdir is done on that path so that the kernel
X * cache is done. Yes - yuck.
X *
X * This can all be removed (and the background
X * unmount flag in sfs_ops) if/when the kernel does
X * something smarter.
X */
X am_node *mp = (am_node *) vp;
X int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR);
X int error = unmount_node(mp);
X if (error)
X return error;
X if (isauto && (int)amd_state < (int)Finishing) {
X int islink = (mp->am_mnt->mf_fattr.type == NFLNK);
X int isdir = (mp->am_mnt->mf_fattr.type == NFDIR);
X if (islink) {
X if (unlink(mp->am_path) < 0)
X return errno;
X } else if (isdir) {
X if (rmdir(mp->am_path) < 0)
X return errno;
X }
X }
X return 0;
X}
X
Xstatic void free_map_if_success(rc, term, closure)
Xint rc;
Xint term;
Xvoidp closure;
X{
X am_node *mp = (am_node *) closure;
X mntfs *mf = mp->am_mnt;
X
X /*
X * Not unmounting any more
X */
X mf->mf_flags &= ~MFF_UNMOUNTING;
X
X /*
X * If a timeout was defered because the underlying filesystem
X * was busy then arrange for a timeout as soon as possible.
X */
X if (mf->mf_flags & MFF_WANTTIMO) {
X mf->mf_flags &= ~MFF_WANTTIMO;
X reschedule_timeout_mp();
X }
X
X if (term) {
X plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term);
X#ifdef DEBUG
X /*
X * dbx likes to put a trap on exit().
X * Pretend it succeeded for now...
X */
X if (term == SIGTRAP) {
X am_unmounted(mp);
X }
X#endif
X amd_stats.d_uerr++;
X } else if (rc) {
X if (rc == EBUSY) {
X plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount);
X } else {
X errno = rc; /* XXX */
X plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path);
X }
X amd_stats.d_uerr++;
X } else {
X am_unmounted(mp);
X }
X
X /*
X * Wakeup anything waiting for this mount
X */
X wakeup((voidp) mf);
X}
X
Xstatic void unmount_mp(mp)
Xam_node *mp;
X{
X mntfs *mf = mp->am_mnt;
X#ifdef notdef
X plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
X#endif
X if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) &&
X (mf->mf_flags & MFF_MOUNTED) /* &&
X mf->mf_refc == 1 */) {
X if (FSRV_ISDOWN(mf->mf_server)) {
X /*
X * Don't try to unmount from a server that is known to be down
X */
X if (!(mf->mf_flags & MFF_LOGDOWN)) {
X /* Only log this once, otherwise gets a bit boring */
X plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);
X mf->mf_flags |= MFF_LOGDOWN;
X }
X } else {
X /* Clear logdown flag - since the server must be up */
X mf->mf_flags &= ~MFF_LOGDOWN;
X#ifdef DEBUG
X /*dlog("Will background the unmount attempt");*/
X#endif
X /*
X * Note that we are unmounting this node
X */
X mf->mf_flags |= MFF_UNMOUNTING;
X run_task(unmount_node_wrap, (voidp) mp,
X free_map_if_success, (voidp) mp);
X#ifdef DEBUG
X dlog("unmount attempt backgrounded");
X#endif
X }
X } else {
X#ifdef DEBUG
X dlog("Trying unmount in foreground");
X#endif
X mf->mf_flags |= MFF_UNMOUNTING;
X free_map_if_success(unmount_node(mp), 0, (voidp) mp);
X#ifdef DEBUG
X dlog("unmount attempt done");
X#endif
X }
X}
X
Xvoid timeout_mp()
X{
X#define NEVER (time_t) 0
X#define smallest_t(t1, t2) \
X (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)
X#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)
X
X int i;
X time_t t = NEVER;
X time_t now = clocktime();
X
X#ifdef DEBUG
X dlog("Timing out automount points...");
X#endif
X for (i = last_used_map; i >= 0; --i) {
X am_node *mp = exported_ap[i];
X mntfs *mf;
X /*
X * Just continue if nothing mounted, or can't be timed out.
X */
X if (!mp || (mp->am_flags & AMF_NOTIMEOUT))
X continue;
X /*
X * Pick up mounted filesystem
X */
X mf = mp->am_mnt;
X if (!mf)
X continue;
X /*
X * Don't delete last reference to a restarted filesystem.
X */
X if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1)
X continue;
X /*
X * If there is action on this filesystem then ignore it
X */
X if (!(mf->mf_flags & IGNORE_FLAGS)) {
X int expired = 0;
X mf->mf_flags &= ~MFF_WANTTIMO;
X#ifdef DEBUG
X /*dlog("t is initially @%d, zero in %d secs", t, t - now);*/
X#endif
X if (now >= mp->am_ttl) {
X expired = 1;
X /*
X * Move the ttl forward to avoid thrashing effects
X * on the next call to timeout!
X */
X /* sun's -tw option */
X if (mp->am_timeo_w < 4 * am_timeo_w)
X mp->am_timeo_w += am_timeo_w;
X mp->am_ttl = now + mp->am_timeo_w;
X }
X /*
X * If the next ttl is smallest, use that
X */
X t = smallest_t(t, mp->am_ttl);
X
X#ifdef DEBUG
X /*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/
X#endif
X
X if (!mp->am_child && mf->mf_error >= 0 && expired)
X unmount_mp(mp);
X } else if (mf->mf_flags & MFF_UNMOUNTING) {
X mf->mf_flags |= MFF_WANTTIMO;
X }
X }
X
X if (t == NEVER) {
X#ifdef DEBUG
X dlog("No further timeouts");
X#endif
X t = now + ONE_HOUR;
X }
X
X /*
X * Sanity check to avoid runaways.
X * Absolutely should never get this but
X * if you do without this trap amd will thrash.
X */
X if (t <= now) {
X t = now + 6; /* XXX */
X plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!");
X }
X /*
X * XXX - when shutting down, make things happen faster
X */
X if ((int)amd_state >= (int)Finishing)
X t = now + 1;
X#ifdef DEBUG
X dlog("Next mount timeout in %ds", t - now);
X#endif
X
X timeout_mp_id = timeout(t - now, timeout_mp, 0);
X
X#undef NEVER
X#undef smallest_t
X#undef IGNORE_FLAGS
X}
X
X/*
X * Cause timeout_mp to be called soonest
X */
Xvoid reschedule_timeout_mp()
X{
X if (timeout_mp_id)
X untimeout(timeout_mp_id);
X timeout_mp_id = timeout(0, timeout_mp, 0);
X}
END_OF_FILE
if test 19814 -ne `wc -c <'map.c'`; then
echo shar: \"'map.c'\" unpacked with wrong size!
fi
# end of 'map.c'
fi
echo shar: End of archive 10 \(of 13\).
cp /dev/null ark10isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 13 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
exit 0 # Just in case...
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list