rsalz@uunet.uu.net (Rich Salz) (04/11/90)
Submitted-by: Jan-Simon Pendry <jsp@doc.ic.ac.uk> Posting-number: Volume 21, Issue 97 Archive-name: amd/part09 #! /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 9 (of 13)." # Contents: am.h nfs_ops.c util.c # Wrapped by rsalz@papaya.bbn.com on Tue Apr 10 15:12:13 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'am.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'am.h'\" else echo shar: Extracting \"'am.h'\" \(17876 characters\) sed "s/^X//" >'am.h' <<'END_OF_FILE' X/* X * $Id: am.h,v 5.1.1.2 90/01/11 16:59:18 jsp Exp Locker: jsp $ X * X * Copyright (c) 1990 Jan-Simon Pendry X * Copyright (c) 1990 Imperial College of Science, Technology & Medicine X * Copyright (c) 1990 The Regents of the University of California. X * All rights reserved. X * X * This code is derived from software contributed to Berkeley by X * Jan-Simon Pendry at Imperial College, London. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by Imperial College of Science, Technology and Medicine, London, UK. X * The names of the College and University may not be used to endorse X * or promote products derived from this software without specific X * prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. X * X * %W% (Berkeley) %G% X */ X X/* X * Get this in now so that OS_HDR can use it X */ X#ifdef __STDC__ X#define P(x) x X#define P_void void X#else X#define P(x) () X#define P_void /* as nothing */ X#define const /* as nothing */ X#endif X X#ifdef __GNUC__ X#define INLINE /* __inline */ X#else X#define INLINE X#endif X X/* X * Pick up target dependent definitions X */ X#include "os-defaults.h" X#include OS_HDR X X#ifdef VOIDP Xtypedef void *voidp; X#else Xtypedef char *voidp; X#endif X X/* X * Global declarations X */ X#include <stdio.h> X#include <sys/param.h> X#include <sys/errno.h> Xextern int errno; X#include <sys/socket.h> X#include <rpc/rpc.h> X#include "nfs_prot.h" X#ifdef MNTENT_HDR X#include MNTENT_HDR X#endif X#include <sys/time.h> X#include <assert.h> X X#ifdef DEBUG_MEM X#include <malloc.h> X#endif X X#ifndef MAXHOSTNAMELEN X#define MAXHOSTNAMELEN 64 X#endif X X#ifndef MNTTYPE_AUTO X#define MNTTYPE_AUTO "auto" X#endif X X#ifndef FALSE X#define FALSE 0 X#define TRUE 1 X#endif X X#ifndef ROOT_MAP X#define ROOT_MAP "\"root\"" X#endif X X/* X * Flags from command line X */ Xextern int print_pid; /* Print pid to stdout */ Xextern int normalize_hosts; /* Normalize host names before use */ Xextern int restart_existing_mounts; X#ifdef HAS_YP_MAPS Xextern char *domain; /* YP domain to use */ X#endif Xextern FILE *logfp; /* Log file */ Xextern int xlog_level; /* Logging level */ X#ifdef HAS_SYSLOG Xextern int syslogging; /* Really using syslog */ X#endif Xextern int am_timeo; /* Cache period */ Xextern int afs_timeo; /* AFS timeout */ Xextern int afs_retrans; /* AFS retrans */ Xextern int am_timeo_w; /* Unmount timeout */ Xextern char *mtab; /* Mount table */ X X#define XLOG_FATAL 0x0001 X#define XLOG_ERROR 0x0002 X#define XLOG_USER 0x0004 X#define XLOG_WARNING 0x0008 X#define XLOG_INFO 0x0010 X#define XLOG_DEBUG 0x0020 X#define XLOG_MAP 0x0040 X#define XLOG_STATS 0x0080 X X#define XLOG_DEFSTR "all,nomap,nostats" /* Default log options */ X#define XLOG_ALL (XLOG_FATAL|XLOG_ERROR|XLOG_USER|XLOG_WARNING|XLOG_INFO|XLOG_MAP|XLOG_STATS) X X#ifdef DEBUG X#ifdef DEBUG_MEM X#define free(x) xfree(__FILE__,__LINE__,x) X#endif X X#define DEBUG_MTAB "./mtab" X Xextern int debug_flags; /* Debug options */ X X#define D_DAEMON 0x0001 /* Enter daemon mode */ X#define D_TRACE 0x0002 /* Do protocol trace */ X#define D_FULL 0x0004 /* Do full trace */ X#define D_MTAB 0x0008 /* Use local mtab */ X#define D_AMQ 0x0010 /* Register amq program */ X#define D_STR 0x0020 /* Debug string munging */ X#define D_MEM 0x0040 /* Trace memory allocations */ X X/* X * Normally, don't enter daemon mode, and don't register amq X */ X#define D_TEST (~(D_DAEMON|D_MEM|D_STR)) X#define D_ALL (~0) X X#define Debug(x) if (!(debug_flags & (x))) ; else X#define dlog Debug(D_FULL) dplog X#endif X Xtypedef enum { X Start, X Run, X Finishing, X Quit, X Done X} serv_state; X Xextern serv_state amd_state; /* Should we go now */ Xextern int immediate_abort; /* Should close-down unmounts be retried */ Xextern time_t do_mapc_reload; /* Flush & reload mount map cache */ X X/* X * Useful constants X */ Xextern char *progname; /* "amd" */ Xextern char pid_fsname[]; /* kiska.southseas.nz:(pid%d) */ Xextern char hostname[]; /* "kiska" */ Xextern char hostd[]; /* "kiska.southseas.nz" */ Xextern char *hostdomain; /* "southseas.nz" */ Xextern char *op_sys; /* "sos4" */ Xextern char *arch; /* "sun4" */ Xextern char *karch; /* "sun4c" */ Xextern char *cluster; /* "r+d-kluster" */ Xextern char *endian; /* "big" */ Xextern char *auto_dir; /* "/a" */ Xextern char version[]; /* Version info */ X Xtypedef struct am_ops am_ops; Xtypedef struct am_node am_node; Xtypedef struct am_opts am_opts; Xtypedef struct mntfs mntfs; Xtypedef struct fserver fserver; X X/* X * Global variables. X */ Xextern unsigned short nfs_port; /* Our NFS service port */ Xextern int mypid; /* Current process id */ Xextern struct in_addr myipaddr; /* (An) IP address of this host */ X Xextern int foreground; /* Foreground process */ Xextern int orig_umask; /* umask() on startup */ X#define clocktime() (clock_valid ? clock_valid : time(&clock_valid)) Xextern time_t time P((time_t *)); Xextern time_t clock_valid; /* Clock needs recalculating */ Xextern time_t next_softclock; /* Time to call softclock() */ Xextern int task_notify_todo; /* Task notifier needs running */ X#ifdef HAS_TFS Xextern int nfs_server_code_available; X#endif Xextern int last_used_map; /* Last map being used for mounts */ Xextern AUTH *nfs_auth; /* Dummy uthorisation for remote servers */ Xextern am_node *exported_ap[]; /* List of nodes */ Xextern int first_free_map; /* First free node */ X#define NEXP_AP (4 * NMOUNT) X Xtypedef int (*task_fun)P((voidp)); Xtypedef void (*cb_fun)P((int, int, voidp)); Xtypedef void (*fwd_fun)P((voidp, int, struct sockaddr_in *, X struct sockaddr_in *, voidp, int)); X X/* X * String comparison macros X */ X#define STREQ(s1, s2) (strcmp((s1), (s2)) == 0) X#define FSTREQ(s1, s2) ((*(s1) == *(s2)) && STREQ((s1),(s2))) X X/* X * Linked list X */ Xtypedef struct qelem qelem; Xstruct qelem { X qelem *q_forw; X qelem *q_back; X}; X#define FIRST(ty, q) ((ty *) ((q)->q_forw)) X#define LAST(ty, q) ((ty *) ((q)->q_back)) X#define NEXT(ty, q) ((ty *) (((qelem *) q)->q_forw)) X#define PREV(ty, q) ((ty *) (((qelem *) q)->q_back)) X#define HEAD(ty, q) ((ty *) q) X#define ITER(v, ty, q) \ X for ((v) = FIRST(ty,(q)); (v) != HEAD(ty,(q)); (v) = NEXT(ty,(v))) X X/* X * List of mount table entries X */ Xtypedef struct mntlist mntlist; Xstruct mntlist { X struct mntlist *mnext; X struct mntent *mnt; X}; X X/* X * Mount map X */ Xtypedef struct mnt_map mnt_map; X X/* X * Global routines X */ Xextern int atoi P((const char *)); /* C */ Xextern void am_mounted P((am_node*)); Xextern void am_unmounted P((am_node*)); Xextern int background(P_void); Xextern int bind_resv_port P((int, unsigned short*)); Xextern int compute_mount_flags P((struct mntent *)); Xextern int softclock(P_void); X#ifdef DEBUG Xextern int debug_option P((char*)); Xextern void dplog (); X/*extern void dplog P((char*, ...));*/ X#endif X/*extern void domain_strip P((char*, char*));*/ Xextern mntfs* dup_mntfs P((mntfs*)); Xextern fserver* dup_srvr P((fserver*)); Xextern int eval_fs_opts P((am_opts*, char*, char*, char*, char*, char*)); Xextern char* expand_key P((char*)); Xextern am_node* exported_ap_alloc(P_void); Xextern am_node* find_ap P((char*)); Xextern mntfs* find_mntfs P((am_ops*, am_opts*, char*, char*, char*)); Xextern void flush_mntfs(P_void); Xextern void free P((voidp)); /* C */ Xextern void free_mntfs P((mntfs*)); Xextern void free_opts P((am_opts*)); Xextern void free_map P((am_node*)); Xextern void free_mntlist P((mntlist*)); Xextern int fwd_init(P_void); Xextern int fwd_packet P((int, voidp, int, struct sockaddr_in *, X struct sockaddr_in *, voidp, fwd_fun)); Xextern void fwd_reply(P_void); Xextern void get_args P((int, char*[])); Xextern void going_down P((int)); X#ifdef NEED_MNTOPT_PARSER Xextern char *hasmntopt P((struct mntent*, char*)); X#endif Xextern int hasmntval P((struct mntent*, char*)); Xextern void host_normalize P((char **)); Xextern void init_map P((am_node*, char*)); Xextern void insert_am P((am_node*, am_node*)); Xextern void ins_que P((qelem*, qelem*)); Xextern void make_root_node(P_void); Xextern int make_rpc_packet P((char*, int, u_long, struct rpc_msg*, voidp, xdrproc_t, AUTH*)); Xextern void mapc_add_kv P((mnt_map*, char*, char*)); Xextern mnt_map* mapc_find P((char*, char*)); Xextern void mapc_free P((mnt_map*)); Xextern int mapc_search P((mnt_map*, char*, char**)); Xextern void mapc_reload(P_void); Xextern void mapc_showtypes P((FILE*)); Xextern int mkdirs P((char*, int)); Xextern void mnt_free P((struct mntent*)); Xextern int mount_automounter P((int)); Xextern int mount_exported(P_void); Xextern int mount_node P((am_node*)); Xextern mntfs* new_mntfs(P_void); Xextern void new_ttl P((am_node*)); Xextern am_node* next_map P((int*)); Xextern int nfs_srvr_port P((fserver*, u_short*, voidp)); Xextern int pickup_rpc_reply P((voidp, int, voidp, xdrproc_t)); Xextern void plog (); X/*extern void plog P((int, char*, ...));*/ Xextern mntlist* read_mtab P((char*)); Xextern mntfs* realloc_mntfs P((mntfs*, am_ops*, am_opts*, char*, char*, char*)); Xextern void rem_que P((qelem*)); Xextern void reschedule_timeout_mp(P_void); Xextern void restart(P_void); X#ifdef UPDATE_MTAB Xextern void rewrite_mtab P((mntlist *)); X#endif Xextern void rmdirs P((char*)); Xextern am_node* root_ap P((char*, int)); Xextern void root_newmap P((char*, char*, char*)); Xextern void rpc_msg_init P((struct rpc_msg*, u_long, u_long, u_long)); Xextern void run_task P((task_fun, voidp, cb_fun, voidp)); Xextern void sched_task P((cb_fun, voidp, voidp)); Xextern void show_rcs_info P((const char*, char*)); Xextern void sigchld P((int)); Xextern char* str3cat P((char*, char*, char*, char*)); Xextern char* strcat P((char*, const char*)); /* C */ Xextern char* strchr P((const char*, int)); /* C */ Xextern int strcmp P((const char*, const char*)); /* C */ Xextern char* strdup P((const char*)); Xextern int strlen P((const char*)); /* C */ Xextern char* strnsave P((const char*, int)); Xextern char* strrchr P((const char*, int)); /* C */ Xextern char* strealloc P((char*, char *)); Xextern char** strsplit P((char*, int)); Xextern int switch_option P((char*)); Xextern void task_notify(P_void); Xextern int timeout P((unsigned int, void (*fn)(), voidp)); Xextern void timeout_mp(P_void); Xextern void umount_exported(P_void); X/*extern int unmount_node P((am_node*)); Xextern int unmount_node_wrap P((voidp));*/ Xextern void unregister_amq(P_void); Xextern void untimeout P((int)); Xextern int valid_key P((char*)); Xextern void wakeup P((voidp)); Xextern void wakeup_task P((int,int,voidp)); Xextern void wakeup_srvr P((fserver*)); Xextern void write_mntent P((struct mntent*)); Xextern voidp xmalloc P((int)); Xextern voidp xrealloc P((voidp, int)); X X#define ALLOC(ty) ((struct ty *) xmalloc(sizeof(struct ty))) X X/* X * Options X */ Xstruct am_opts { X char *fs_glob; /* Smashed copy of global options */ X char *fs_local; /* Expanded copy of local options */ X char *fs_mtab; /* Mount table entry */ X /* Other options ... */ X char *opt_dev; X char *opt_delay; X char *opt_dir; X char *opt_fs; X char *opt_group; X char *opt_mount; X char *opt_opts; X char *opt_pref; X char *opt_cache; X char *opt_rfs; X char *opt_rhost; X char *opt_sublink; X char *opt_type; X char *opt_unmount; X char *opt_user; X}; X X/* X * File Handle X * X * This is interpreted by indexing the exported array X * by fhh_id. X * X * The whole structure is mapped onto a standard fhandle_t X * when transmitted. X */ Xstruct am_fh { X int fhh_pid; /* process id */ X int fhh_id; /* map id */ X int fhh_gen; /* generation number */ X}; X Xextern am_node *fh_to_mp P((nfs_fh*)); Xextern am_node *fh_to_mp3 P((nfs_fh*,int*,int)); Xextern void mp_to_fh P((am_node*, nfs_fh*)); X#define fh_to_mp2(fhp, rp) fh_to_mp3(fhp, rp, VLOOK_CREATE) X Xtypedef int (*vfs_match)P((am_opts*)); Xtypedef int (*vfs_init)P((mntfs*)); Xtypedef int (*vmount_fs)P((am_node*)); Xtypedef int (*vumount_fs)P((am_node*)); Xtypedef am_node*(*vlookuppn)P((am_node*, char*, int*, int)); Xtypedef int (*vreaddir)P((am_node*, nfscookie, dirlist*, entry*)); Xtypedef char* (*vreadlink)P((am_node*, int*)); Xtypedef int (*vmounted)P((mntfs*)); Xtypedef void (*vumounted)P((am_node*)); Xtypedef fserver*(*vffserver)P((mntfs*)); X Xstruct am_ops { X char *fs_type; X vfs_match fs_match; X vfs_init fs_init; X vmount_fs mount_fs; X vumount_fs umount_fs; X vlookuppn lookuppn; X vreaddir readdir; X vreadlink readlink; X vmounted mounted; X vumounted umounted; X vffserver ffserver; X int fs_flags; X qelem *srvr_list; X}; Xextern am_node *efs_lookuppn P((am_node*, char*, int*, int)); Xextern int efs_readdir P((am_node*, nfscookie, dirlist*, entry*)); X X#define VLOOK_CREATE 0x1 X#define VLOOK_DELETE 0x2 X X#define FS_RETRY 0x0001 /* Retry this type of mount */ X#define FS_MBACKGROUND 0x0002 /* Should background this mount */ X#define FS_NOTIMEOUT 0x0004 /* Don't bother with timeouts */ X#define FS_MKMNT 0x0008 /* Need to make the mkdir point */ X#define FS_UBACKGROUND 0x0010 /* Unmount in background */ X#define FS_BACKGROUND (FS_MBACKGROUND|FS_UBACKGROUND) X#define FS_DISCARD 0x0020 /* Discard immediately on last reference */ X#define FS_AMQINFO 0x0040 /* Amq is interested in this fs type */ X X#ifdef SUNOS4_COMPAT Xextern am_ops *sunos4_match P((am_opts*, char*, char*, char*, char*, char*)); X#endif Xextern am_ops *ops_match P((am_opts*, char*, char*, char*, char*, char*)); X#include "fs.h" X X/* X * Per-mountpoint statistics X */ Xstruct am_stats { X time_t s_mtime; /* Mount time */ X u_short s_uid; /* Uid of mounter */ X int s_getattr; /* Count of getattrs */ X int s_lookup; /* Count of lookups */ X int s_readdir; /* Count of readdirs */ X int s_readlink; /* Count of readlinks */ X int s_statfs; /* Count of statfs */ X}; Xtypedef struct am_stats am_stats; X X/* X * System statistics X */ Xstruct amd_stats { X int d_drops; /* Dropped requests */ X int d_stale; /* Stale NFS handles */ X int d_mok; /* Succesful mounts */ X int d_merr; /* Failed mounts */ X int d_uerr; /* Failed unmounts */ X}; Xextern struct amd_stats amd_stats; X X/* X * List of fileservers X */ Xstruct fserver { X qelem fs_q; /* List of fileservers */ X int fs_refc; /* Number of references to this node */ X char *fs_host; /* Normalized hostname of server */ X struct sockaddr_in *fs_ip; /* Network address of server */ X int fs_cid; /* Callout id */ X int fs_pinger; /* Ping (keepalive) interval */ X int fs_flags; /* Flags */ X voidp fs_private; /* Private data */ X void (*fs_prfree)(); /* Free private data */ X}; X#define FSF_VALID 0x0001 /* Valid information available */ X#define FSF_DOWN 0x0002 /* This fileserver is down */ X#define FSF_ERROR 0x0004 /* Permanent error has occured */ X#define FSF_WANT 0x0008 /* Want a wakeup call */ X#define FSF_PINGING 0x0010 /* Already doing pings */ X#define FSRV_ISDOWN(fs) (((fs)->fs_flags & (FSF_DOWN|FSF_VALID)) == (FSF_DOWN|FSF_VALID)) X X/* X * List of mounted filesystems X */ Xstruct mntfs { X qelem mf_q; /* List of mounted filesystems */ X am_ops *mf_ops; /* Operations on this mountpoint */ X am_opts *mf_fo; /* File opts */ X struct attrstat mf_attr; /* File attributes */ X#define mf_fattr mf_attr.attrstat_u.attributes X char *mf_mount; /* "/a/kiska/home/kiska" */ X char *mf_info; /* Mount info */ X char *mf_opts; /* Mount opts */ X fserver *mf_server; /* File server */ X int mf_flags; /* Flags */ X int mf_error; /* Error code from background mount */ X int mf_refc; /* Number of references to this node */ X int mf_cid; /* Callout id */ X void (*mf_prfree)(); /* Free private space */ X voidp mf_private; /* Private - per-fs data */ X}; X X#define MFF_MOUNTED 0x0001 /* Node is mounted */ X#define MFF_MOUNTING 0x0002 /* Mount is in progress */ X#define MFF_UNMOUNTING 0x0004 /* Unmount is in progress */ X#define MFF_RESTART 0x0008 /* Restarted node */ X#define MFF_MKMNT 0x0010 /* Delete this node's am_mount */ X#define MFF_ERROR 0x0020 /* This node failed to mount */ X#define MFF_LOGDOWN 0x0040 /* Logged that this mount is down */ X#define MFF_RSTKEEP 0x0080 /* Don't timeout this filesystem - restarted */ X#define MFF_WANTTIMO 0x0100 /* Need a timeout call when not busy */ X X/* X * Map of auto-mount points. X */ Xstruct am_node { X int am_mapno; /* Map number */ X mntfs *am_mnt; /* Mounted filesystem */ X char *am_name; /* "kiska" X Name of this node */ X char *am_path; /* "/home/kiska" X Path of this node's mount point */ X char *am_link; /* "/a/kiska/home/kiska/this/that" X Link to sub-directory */ X am_node *am_parent, /* Parent of this node */ X *am_ysib, /* Younger sibling of this node */ X *am_osib, /* Older sibling of this node */ X *am_child; /* First child of this node */ X int am_flags; /* Boolean flags */ X int am_error; /* Specific mount error */ X time_t am_ttl; /* Time to live */ X int am_timeo_w; /* Wait interval */ X int am_timeo; /* Timeout interval */ X unsigned int am_gen; /* Generation number */ X char *am_pref; /* Mount info prefix */ X am_stats am_stats; /* Statistics gathering */ X}; X X#define AMF_NOTIMEOUT 0x0001 /* This node never times out */ X#define AMF_ROOT 0x0002 /* This is a root node */ X#define AMF_MKPATH 0x0004 /* Delete this node's am_path */ X X#define ONE_HOUR (60 * 60) /* One hour in seconds */ X X/* X * The following values can be tuned... X */ X#define ALLOWED_MOUNT_TIME 30 /* 30s for a mount */ X#define AM_TTL (5 * 60) /* Default cache period */ X#define AM_TTL_W (2 * 60) /* Default unmount interval */ X#define AM_PINGER 3 /* NFS ping interval */ X#define AFS_TIMEO 8 /* Default afs timeout - .8s */ X#define AFS_RETRANS ((ALLOWED_MOUNT_TIME*10+2*afs_timeo)/afs_timeo) X /* Default afs timeout - 1/10th seconds */ X X#define RPC_XID_PORTMAP 0 X#define RPC_XID_MOUNTD 1 X#define RPC_XID_NFSPING 2 X#define RPC_XID_MASK (0x0f) /* 16 id's for now */ X#define MK_RPC_XID(type_id, uniq) ((type_id) | ((uniq) << 4)) END_OF_FILE if test 17876 -ne `wc -c <'am.h'`; then echo shar: \"'am.h'\" unpacked with wrong size! fi # end of 'am.h' fi if test -f 'nfs_ops.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'nfs_ops.c'\" else echo shar: Extracting \"'nfs_ops.c'\" \(14835 characters\) sed "s/^X//" >'nfs_ops.c' <<'END_OF_FILE' X/* X * $Id: nfs_ops.c,v 5.1.1.2 90/01/11 17:12:34 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 X#ifdef HAS_NFS X X#define NFS X#define NFSCLIENT X#ifdef NFS_3 Xtypedef nfs_fh fhandle_t; X#endif X#ifdef NFS_HDR X#include NFS_HDR X#endif X#include <sys/mount.h> X#include "mount.h" X X/* X * Network file system X */ X X/* X * Convert from nfsstat to UN*X error code X */ X#define unx_error(e) ((int)(e)) X X/* X * The NFS layer maintains a cache of file handles. X * This is *fundamental* to the implementation and X * also allows quick remounting when a filesystem X * is accessed soon after timing out. X * X * The NFS server layer knows to flush this cache X * when a server goes down so avoiding stale handles. X * X * Each cache entry keeps a hard reference to X * the corresponding server. This ensures that X * the server keepalive information is maintained. X * X * The copy of the sockaddr_in here is taken so X * that the port can be twiddled to talk to mountd X * instead of portmap or the NFS server as used X * elsewhere. X * The port# is flushed if a server goes down. X * The IP address is never flushed - we assume X * that the address of a mounted machine never X * changes. If it does, then you have other X * problems... X */ Xtypedef struct fh_cache fh_cache; Xstruct fh_cache { X qelem fh_q; /* List header */ X voidp fh_wchan; /* Wait channel */ X int fh_error; /* Valid data? */ X int fh_id; /* Unique id */ X int fh_cid; /* Callout id */ X struct fhstatus fh_handle; /* Handle on filesystem */ X struct sockaddr_in fh_sin; /* Address of mountd */ X fserver *fh_fs; /* Server holding filesystem */ X char *fh_path; /* Filesystem on host */ X}; X X/* X * FH_TTL is the time a file handle will remain in the cache since X * last being used. If the file handle becomes invalid, then it X * will be flushed anyway. X */ X#define FH_TTL (5 * 60) /* five minutes */ X#define FH_TTL_ERROR (30) /* 30 seconds */ X Xstatic int fh_id = 0; X#define FHID_ALLOC() (++fh_id) Xextern qelem fh_head; Xqelem fh_head = { &fh_head, &fh_head }; X Xstatic int call_mountd P((fh_cache*, unsigned long, fwd_fun, voidp)); X XAUTH *nfs_auth; X Xstatic fh_cache *find_fhandle_cache P((voidp idv, int done)); Xstatic fh_cache *find_fhandle_cache(idv, done) Xvoidp idv; Xint done; X{ X fh_cache *fp, *fp2 = 0; X int id = (int) idv; X X ITER(fp, fh_cache, &fh_head) { X if (fp->fh_id == id) { X fp2 = fp; X break; X } X } X X#ifdef DEBUG X if (fp2) { X dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path); X } else { X dlog("fh cache search failed"); X } X#endif X X if (fp2 && !done) { X fp2->fh_error = ETIMEDOUT; X return 0; X } X X return fp2; X} X X/* X * Called when a filehandle appears X */ Xstatic void got_nfs_fh P((voidp pkt, int len, struct sockaddr_in *sa, X struct sockaddr_in *ia, voidp idv, int done)); Xstatic void got_nfs_fh(pkt, len, sa, ia, idv, done) Xvoidp pkt; Xint len; Xstruct sockaddr_in *sa, *ia; Xvoidp idv; Xint done; X{ X fh_cache *fp = find_fhandle_cache(idv, done); X if (fp) { X fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_handle, xdr_fhstatus); X if (!fp->fh_error) { X#ifdef DEBUG X dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); X#endif X /* X * Wakeup anything sleeping on this filehandle X */ X if (fp->fh_wchan) { X#ifdef DEBUG X dlog("Calling wakeup on %#x", fp->fh_wchan); X#endif X wakeup(fp->fh_wchan); X } X } X } X} X Xvoid flush_fhandle_cache P((fserver *fs)); Xvoid flush_fhandle_cache(fs) Xfserver *fs; X{ X fh_cache *fp; X ITER(fp, fh_cache, &fh_head) { X if (fp->fh_fs == fs) { X fp->fh_sin.sin_port = (u_short) 0; X fp->fh_error = -1; X } X } X} X Xstatic void discard_fh P((fh_cache *fp)); Xstatic void discard_fh(fp) Xfh_cache *fp; X{ X rem_que(&fp->fh_q); X#ifdef DEBUG X dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path); X#endif X free_srvr(fp->fh_fs); X free(fp->fh_path); X free(fp); X} X X/* X * Determine the file handle for a node X */ Xstatic int prime_fhandle_cache P((char *path, fserver *fs, struct fhstatus *fhbuf, voidp wchan)); Xstatic int prime_fhandle_cache(path, fs, fhbuf, wchan) Xchar *path; Xfserver *fs; Xstruct fhstatus *fhbuf; Xvoidp wchan; X{ X fh_cache *fp, *fp_save = 0; X int error; X int reuse_id = FALSE; X X#ifdef DEBUG X dlog("Searching cache for %s:%s", fs->fs_host, path); X#endif X X /* X * First search the cache X */ X ITER(fp, fh_cache, &fh_head) { X if (fs == fp->fh_fs && strcmp(path, fp->fh_path) == 0) { X switch (fp->fh_error) { X case 0: X error = fp->fh_error = unx_error(fp->fh_handle.fhs_status); X if (error == 0) { X if (fhbuf) X bcopy((voidp) &fp->fh_handle, (voidp) fhbuf, X sizeof(fp->fh_handle)); X if (fp->fh_cid) X untimeout(fp->fh_cid); X fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); X } else if (error == EACCES) { X /* X * Now decode the file handle return code. X */ X plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"", X fs->fs_host, path); X } else { X errno = error; /* XXX */ X plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m", X fs->fs_host, path); X } X X /* X * The error was returned from the remote mount daemon. X * Policy: this error will be cached for now... X */ X return error; X X case -1: X /* X * Still thinking about it, but we can re-use. X */ X fp_save = fp; X reuse_id = TRUE; X break; X X default: X /* X * Return the error. X * Policy: make sure we recompute if required again X * in case this was caused by a network failure. X * This can thrash mountd's though... If you find X * your mountd going slowly then: X * 1. Add a fork() loop to main. X * 2. Remove the call to innetgr() and don't use X * netgroups, especially if you don't use YP. X */ X error = fp->fh_error; X fp->fh_error = -1; X return error; X } X break; X } X } X X /* X * Not in cache X */ X if (fp_save) { X fp = fp_save; X /* X * Re-use existing slot X */ X untimeout(fp->fh_cid); X free_srvr(fp->fh_fs); X free(fp->fh_path); X } else { X fp = ALLOC(fh_cache); X bzero((voidp) fp, sizeof(*fp)); X ins_que(&fp->fh_q, &fh_head); X } X if (!reuse_id) X fp->fh_id = FHID_ALLOC(); X fp->fh_wchan = wchan; X fp->fh_error = -1; X fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp); X X /* X * If the address has changed then don't try to re-use the X * port information X */ X if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) { X fp->fh_sin = *fs->fs_ip; X fp->fh_sin.sin_port = 0; X } X fp->fh_fs = dup_srvr(fs); X fp->fh_path = strdup(path); X X error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan); X if (error) { X /* X * Local error - cache for a short period X * just to prevent thrashing. X */ X untimeout(fp->fh_cid); X fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR, X discard_fh, (voidp) fp); X fp->fh_error = error; X } else { X error = fp->fh_error; X } X return error; X} X Xstatic int call_mountd P((fh_cache *fp, u_long proc, fwd_fun f, voidp wchan)); Xstatic int call_mountd(fp, proc, f, wchan) Xfh_cache *fp; Xu_long proc; Xfwd_fun f; Xvoidp wchan; X{ X struct rpc_msg mnt_msg; X int len; X char iobuf[8192]; X int error; X X if (!nfs_auth) { X nfs_auth = authunix_create_default(); X if (!nfs_auth) X return ENOBUFS; X } X X if (fp->fh_sin.sin_port == 0) { X u_short port; X error = nfs_srvr_port(fp->fh_fs, &port, wchan); X if (error) X return error; X fp->fh_sin.sin_port = port; X } X X rpc_msg_init(&mnt_msg, MOUNTPROG, MOUNTVERS, (unsigned long) 0); X len = make_rpc_packet(iobuf, sizeof(iobuf), proc, X &mnt_msg, (voidp) &fp->fh_path, xdr_nfspath, nfs_auth); X X if (len > 0) { X error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id), X (voidp) iobuf, len, &fp->fh_sin, &fp->fh_sin, (voidp) fp->fh_id, f); X } else { X error = -len; X } X return error; X} X X/*-------------------------------------------------------------------------*/ X X/* X * NFS needs the local filesystem, remote filesystem X * remote hostname. X * Local filesystem defaults to remote and vice-versa. X */ Xstatic int nfs_match(fo) Xam_opts *fo; X{ X if (fo->opt_fs && !fo->opt_rfs) X fo->opt_rfs = fo->opt_fs; X if (!fo->opt_rfs) { X plog(XLOG_USER, "nfs: no remote filesystem specified"); X return 0; X } X if (!fo->opt_rhost) { X plog(XLOG_USER, "nfs: no remote host specified"); X return 0; X } X /* X * Determine magic cookie to put in mtab X */ X fo->fs_mtab = (char *) xrealloc(fo->fs_mtab, strlen(fo->opt_rhost) + X strlen(fo->opt_rfs) + 2); X sprintf(fo->fs_mtab, "%s:%s", fo->opt_rhost, fo->opt_rfs); X#ifdef DEBUG X dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"", X fo->opt_rhost, fo->opt_rfs, fo->opt_fs); X#endif X X return 1; X} X X/* X * Initialise am structure for nfs X */ Xstatic int nfs_init(mf) Xmntfs *mf; X{ X int error; X char *colon = strchr(mf->mf_info, ':'); X if (colon == 0) X return ENOENT; X X error = prime_fhandle_cache(colon+1, mf->mf_server, (struct fhstatus *) 0, (voidp) mf); X X return error; X} X Xstatic mount_nfs(dir, fs_name, opts, mf) Xchar *dir; Xchar *fs_name; Xchar *opts; Xmntfs *mf; X{ X struct nfs_args nfs_args; X struct mntent mnt; X int retry; X struct fhstatus fhs; X int error; X char *colon; X char *path; X char host[MAXHOSTNAMELEN + MAXPATHLEN + 2]; X fserver *fs = mf->mf_server; X int flags; X#ifdef notdef X unsigned short port; X#endif X X MTYPE_TYPE type = MOUNT_TYPE_NFS; X X bzero((voidp) &nfs_args, sizeof(nfs_args)); /* Paranoid */ X X /* X * Extract host name to give to kernel X */ X if (!(colon = strchr(fs_name, ':'))) X return ENOENT; X#ifndef NFS_ARGS_NEEDS_PATH X *colon = '\0'; X#endif X strncpy(host, fs_name, sizeof(host)); X#ifndef NFS_ARGS_NEEDS_PATH X *colon = ':'; X#endif X path = colon + 1; X X bzero((voidp) &nfs_args, sizeof(nfs_args)); X X mnt.mnt_dir = dir; X mnt.mnt_fsname = fs_name; X mnt.mnt_type = MTAB_TYPE_NFS; X mnt.mnt_opts = opts; X mnt.mnt_freq = 0; X mnt.mnt_passno = 0; X X retry = hasmntval(&mnt, "retry"); X if (retry <= 0) X retry = 1; /* XXX */ X X/*again:*/ X#ifdef DEBUG X dlog("locating fhandle for %s", fs_name); X#endif X error = prime_fhandle_cache(path, mf->mf_server, &fhs, (voidp) 0); X X if (error) X return error; X X /* X * set mount args X */ X nfs_args.fh = (NFS_FH_TYPE) fhs.fhstatus_u.fhs_fhandle; X X#ifdef ULTRIX_HACK X nfs_args.optstr = mnt.mnt_opts; X#endif X X nfs_args.hostname = host; X nfs_args.flags |= NFSMNT_HOSTNAME; X#ifdef HOSTNAMESZ X /* X * Most kernels have a name length restriction. X */ X if (strlen(host) >= HOSTNAMESZ) X strcpy(host + HOSTNAMESZ - 3, ".."); X#endif X X if (nfs_args.rsize = hasmntval(&mnt, "rsize")) X nfs_args.flags |= NFSMNT_RSIZE; X X if (nfs_args.wsize = hasmntval(&mnt, "wsize")) X nfs_args.flags |= NFSMNT_WSIZE; X X if (nfs_args.timeo = hasmntval(&mnt, "timeo")) X nfs_args.flags |= NFSMNT_TIMEO; X X if (nfs_args.retrans = hasmntval(&mnt, "retrans")) X nfs_args.flags |= NFSMNT_RETRANS; X X#ifdef notdef X/* X * This isn't supported by the ping algorithm yet. X * In any case, it is all done in nfs_init(). X */ X if (port = hasmntval(&mnt, "port")) X sin.sin_port = htons(port); X else X sin.sin_port = htons(NFS_PORT); /* XXX should use portmapper */ X#endif X X if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL) X nfs_args.flags |= NFSMNT_SOFT; X X#ifdef MNTOPT_INTR X if (hasmntopt(&mnt, MNTOPT_INTR) != NULL) X nfs_args.flags |= NFSMNT_INT; X#endif X X#ifdef MNTOPT_NODEVS X if (hasmntopt(&mnt, MNTOPT_NODEVS) != NULL) X nfs_args.flags |= NFSMNT_NODEVS; X#endif X X#ifdef NFSMNT_PGTHRESH X if (nfs_args.pg_thresh = hasmntval(&mnt, "pgthresh")) X nfs_args.flags |= NFSMNT_PGTHRESH; X#endif X X nfs_args.addr = fs->fs_ip; X X flags = compute_mount_flags(&mnt); X X#ifdef ULTRIX_HACK X /* X * Ultrix passes the flags argument as part of the X * mount data structure, rather than using the X * flags argument to the system call. This is X * confusing... X */ X if (!(nfs_args.flags & NFSMNT_PGTHRESH)) { X nfs_args.pg_thresh = 64; /* 64k - XXX */ X nfs_args.flags |= NFSMNT_PGTHRESH; X } X nfs_args.gfs_flags = flags; X flags &= M_RDONLY; X if (flags & M_RDONLY) X nfs_args.flags |= NFSMNT_RONLY; X#endif X X return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type); X} X Xstatic int nfs_mount(mp) Xam_node *mp; X{ X mntfs *mf = mp->am_mnt; X X int error = mount_nfs(mf->mf_mount, mf->mf_info, X mf->mf_fo->opt_opts, mf); X X#ifdef DEBUG X if (error) { X errno = error; X dlog("mount_nfs: %m"); X } X#endif X return error; X} X Xstatic int nfs_umount(mp) Xam_node *mp; X{ X mntfs *mf = mp->am_mnt; X X int error = UMOUNT_FS(mf->mf_mount); X if (error) X return error; X X return 0; X} X Xstatic void nfs_umounted(mp) Xam_node *mp; X{ X#ifdef INFORM_MOUNTD X /* X * Don't bother to inform remote mountd X * that we are finished. Until a full X * track of filehandles is maintained X * the mountd unmount callback cannot X * be done correctly anyway... X */ X X mntfs *mf = mp->am_mnt; X fserver *fs; X char *colon, *path; X X if (mf->mf_error || mf->mf_refc > 1) X return; X X fs = mf->mf_server; X X /* X * Call the mount daemon on the server to X * announce that we are not using the fs any more. X * X * This is *wrong*. The mountd should be called X * when the fhandle is flushed from the cache, and X * a reference held to the cached entry while the X * fs is mounted... X */ X colon = path = strchr(mf->mf_info, ':'); X if (fs && colon) { X fh_cache f; X#ifdef DEBUG X dlog("calling mountd for %s", mf->mf_info); X#endif X *path++ = '\0'; X f.fh_path = path; X f.fh_sin = *fs->fs_ip; X f.fh_sin.sin_port = (u_short) 0; X f.fh_fs = fs; X f.fh_id = 0; X f.fh_error = 0; X (void) prime_fhandle_cache(colon+1, mf->mf_server, (struct fhstatus *) 0, (voidp) mf); X (void) call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0); X *colon = ':'; X } X#endif X} X X/* X * Network file system X */ Xam_ops nfs_ops = { X "nfs", X nfs_match, X nfs_init, X nfs_mount, X nfs_umount, X efs_lookuppn, X efs_readdir, X 0, /* nfs_readlink */ X 0, /* nfs_mounted */ X nfs_umounted, X find_nfs_srvr, X FS_MKMNT|FS_BACKGROUND|FS_AMQINFO, X &nfs_srvr_list, X}; X X#endif /* HAS_NFS */ END_OF_FILE if test 14835 -ne `wc -c <'nfs_ops.c'`; then echo shar: \"'nfs_ops.c'\" unpacked with wrong size! fi # end of 'nfs_ops.c' fi if test -f 'util.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util.c'\" else echo shar: Extracting \"'util.c'\" \(15603 characters\) sed "s/^X//" >'util.c' <<'END_OF_FILE' X/* X * $Id: util.c,v 5.1.1.3 90/01/11 17:23:29 jsp Exp Locker: jsp $ X * X * Copyright (c) 1990 Jan-Simon Pendry X * Copyright (c) 1990 Imperial College of Science, Technology & Medicine X * Copyright (c) 1990 The Regents of the University of California. X * All rights reserved. X * X * This code is derived from software contributed to Berkeley by X * Jan-Simon Pendry at Imperial College, London. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by Imperial College of Science, Technology and Medicine, London, UK. X * The names of the College and University may not be used to endorse X * or promote products derived from this software without specific X * prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. X * X * %W% (Berkeley) %G% X */ X X/* X * Utils X */ X X#include "am.h" X#ifdef HAS_SYSLOG X#include <syslog.h> X#endif X#include <ctype.h> X#include <sys/stat.h> X X#include <netdb.h> X X XINLINE Xchar *strnsave(str, len) Xconst char *str; Xint len; X{ X char *sp = (char *) xmalloc(len+1); X X bcopy(str, sp, len); X sp[len] = 0; X X return sp; X} X Xchar *strdup(s) Xconst char *s; X{ X return strnsave(s, strlen(s)); X} X X/* X * Concatenate three strings and store in buffer pointed to X * by p, making p large enough to hold the strings X */ Xchar *str3cat(p, s1, s2, s3) Xchar *p; Xchar *s1; Xchar *s2; Xchar *s3; X{ X int l1 = strlen(s1); X int l2 = strlen(s2); X int l3 = strlen(s3); X p = (char *) xrealloc(p, l1 + l2 + l3 + 1); X bcopy(s1, p, l1); X bcopy(s2, p + l1, l2); X bcopy(s3, p + l1 + l2, l3 + 1); X return p; X} X Xchar *strealloc(p, s) Xchar *p; Xchar *s; X{ X int len = strlen(s) + 1; X X p = (char *) xrealloc((voidp) p, len); X X strcpy(p, s); X#ifdef DEBUG_MEM X malloc_verify(); X#endif X return p; X} X Xvoidp xrealloc(ptr, len) Xvoidp ptr; Xint len; X{ X#if defined(DEBUG) && defined(DEBUG_MEM) X Debug(D_MEM) plog(XLOG_DEBUG, "Reallocated size %d; block %#x", len, ptr); X#endif X X if (ptr) X ptr = (voidp) realloc(ptr, (unsigned) len); X else X ptr = (voidp) xmalloc((unsigned) len); X X if (!ptr) { X plog(XLOG_FATAL, "Out of memory in realloc"); X going_down(1); X abort(); X } X return ptr; X} X Xchar **strsplit(s, qc) Xchar *s; Xint qc; X{ X char **ivec; X int ic = 0; X int done = 0; X X ivec = (char **) xmalloc((ic+1)*sizeof(char *)); X X while (!done) { X char *v; X /* X * skip white space X */ X while (*s && isascii(*s) && isspace(*s)) X s++; X X /* X * End of string? X */ X if (!*s) X break; X X /* X * remember start of string X */ X v = s; X X /* X * skip to white space X */ X while (*s && (!isascii(*s) || !isspace(*s))) { X if (*s++ == qc) { X /* X * Skip past string. X */ X s++; X while (*s && *s != qc) X s++; X if (*s == qc) X s++; X } X } X X if (!*s) X done = 1; X *s++ = '\0'; X X /* X * save string in new ivec slot X */ X ivec[ic++] = v; X ivec = (char **) xrealloc(ivec, (ic+1)*sizeof(char *)); X#ifdef DEBUG X Debug(D_STR) X plog(XLOG_DEBUG, "strsplit saved \"%s\"", v); X#endif X } X X#ifdef DEBUG X Debug(D_STR) X plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic); X#endif X X ivec[ic] = 0; X X return ivec; X} X X/* X * Strip off the trailing part of a domain X * to produce a short-form domain relative X * to the local host domain. X * Note that this has no effect if the domain X * names do not have the same number of X * components. If that restriction proves X * to be a problem then the loop needs recoding X * to skip from right to left and do partial X * matches along the way -- ie more expensive. X */ Xstatic void domain_strip P((char *otherdom, char *localdom)); Xstatic void domain_strip(otherdom, localdom) Xchar *otherdom, *localdom; X{ X char *p1 = otherdom-1; X char *p2 = localdom-1; X X do { X if (p1 = strchr(p1+1, '.')) X if (p2 = strchr(p2+1, '.')) X if (strcmp(p1+1, p2+1) == 0) { X *p1 = '\0'; X break; X } X } while (p1 && p2); X} X X/* X * Normalize a host name X */ Xvoid host_normalize P((char **chp)); Xvoid host_normalize(chp) Xchar **chp; X{ X /* X * Normalize hosts is used to resolve host name aliases X * and replace them with the standard-form name. X * Invoked with "-n" command line option. X */ X if (normalize_hosts) { X struct hostent *hp; X clock_valid = 0; X hp = gethostbyname(*chp); X if (hp && hp->h_addrtype == AF_INET) { X#ifdef DEBUG X dlog("Hostname %s normalized to %s", *chp, hp->h_name); X#endif X *chp = strealloc(*chp, hp->h_name); X } X } X domain_strip(*chp, hostd); X} X X/* X * Keys are not allowed to contain " ' ! or ; to avoid X * problems with macro expansions. X */ Xstatic char invalid_keys[] = "\"'!;@ \t\n"; Xint valid_key P((char *key)); Xint valid_key(key) Xchar *key; X{ X while (*key) X if (strchr(invalid_keys, *key++)) X return FALSE; X return TRUE; X} X Xvoid going_down P((int rc)); Xvoid going_down(rc) Xint rc; X{ X if (foreground) { X if (amd_state != Start) { X if (amd_state != Done) X return; X unregister_amq(); X } X } X if (foreground) { X plog(XLOG_INFO, "Finishing with status %d", rc); X } else { X#ifdef DEBUG X dlog("background process exiting with status %d", rc); X#endif X } X X exit(rc); X} X X#ifdef DEBUG_MEM Xstatic int mem_bytes; Xstatic int orig_mem_bytes; Xstatic void checkup_mem(P_void) X{ Xextern struct mallinfo __mallinfo; X if (mem_bytes != __mallinfo.uordbytes) { X if (orig_mem_bytes == 0) X mem_bytes = orig_mem_bytes = __mallinfo.uordbytes; X else { X fprintf(logfp, "%s[%d]: ", progname, mypid); X if (mem_bytes < __mallinfo.uordbytes) { X fprintf(logfp, "ALLOC: %d bytes", X __mallinfo.uordbytes - mem_bytes); X } else { X fprintf(logfp, "FREE: %d bytes", X mem_bytes - __mallinfo.uordbytes); X } X mem_bytes = __mallinfo.uordbytes; X fprintf(logfp, ", making %d missing\n", X mem_bytes - orig_mem_bytes); X } X } X malloc_verify(); X} X#endif X X/* X * Take a log format string and expand occurences of %m X * with the current error code take from errno. X */ XINLINE Xstatic void expand_error(f, e) Xchar *f; Xchar *e; X{ X extern int sys_nerr; X extern char *sys_errlist[]; X char *p; X int error = errno; X X for (p = f; *e = *p; e++, p++) { X if (p[0] == '%' && p[1] == 'm') { X char *errstr; X if (error < 0 || error >= sys_nerr) X errstr = 0; X else X errstr = sys_errlist[error]; X if (errstr) X strcpy(e, errstr); X else X sprintf(e, "Error %d", error); X e += strlen(e) - 1; X p++; X } X } X} X X/* X * Output the time of day and hostname to the logfile X */ Xstatic void show_time_host_and_name(lvl) Xint lvl; X{ Xstatic time_t last_t = 0; Xstatic char *last_ctime = 0; X time_t t = clocktime(); X char *sev; X extern char *ctime(); X X#if defined(DEBUG) && defined(PARANOID) Xextern char **gargv; X#endif X X if (t != last_t) { X last_ctime = ctime(&t); X last_t = t; X } X X switch (lvl) { X case XLOG_FATAL: sev = "fatal:"; break; X case XLOG_ERROR: sev = "error:"; break; X case XLOG_USER: sev = "user: "; break; X case XLOG_WARNING: sev = "warn: "; break; X case XLOG_INFO: sev = "info: "; break; X case XLOG_DEBUG: sev = "debug:"; break; X case XLOG_MAP: sev = "map: "; break; X case XLOG_STATS: sev = "stats:"; break; X default: sev = "hmm: "; break; X } X fprintf(logfp, "%15.15s %s %s[%d]/%s ", X last_ctime+4, hostname, X#if defined(DEBUG) && defined(PARANOID) X gargv[0], X#else X progname, X#endif X mypid, X sev); X} X X#ifdef DEBUG X/*VARARGS1*/ Xvoid dplog(fmt, j,s,_,p,e,n,d,r,y) Xchar *fmt; Xchar *j, *s, *_, *p, *e, *n, *d, *r, *y; X{ X plog(XLOG_DEBUG, fmt, j,s,_,p,e,n,d,r,y); X} X X#endif X/*VARARGS1*/ Xvoid plog(lvl, fmt, j,s,_,p,e,n,d,r,y) Xint lvl; Xchar *fmt; Xchar *j, *s, *_, *p, *e, *n, *d, *r, *y; X{ X char msg[1024]; X char efmt[1024]; X char *ptr = msg; X X if (!(xlog_level & lvl)) X return; X X#ifdef DEBUG_MEM X checkup_mem(); X#endif X X expand_error(fmt, efmt); X sprintf(ptr, efmt, j,s,_,p,e,n,d,r,y); X ptr += strlen(ptr); X if (ptr[-1] == '\n') X *--ptr = '\0'; X#ifdef HAS_SYSLOG X if (syslogging) { X switch(lvl) { /* from mike <mcooper@usc.edu> */ X case XLOG_FATAL: lvl = LOG_CRIT; break; X case XLOG_ERROR: lvl = LOG_ERR; break; X case XLOG_USER: lvl = LOG_WARNING; break; X case XLOG_WARNING: lvl = LOG_WARNING; break; X case XLOG_INFO: lvl = LOG_INFO; break; X case XLOG_DEBUG: lvl = LOG_DEBUG; break; X case XLOG_MAP: lvl = LOG_DEBUG; break; X case XLOG_STATS: lvl = LOG_INFO; break; X default: lvl = LOG_ERR; break; X } X syslog(lvl, "%s", msg); X return; X } X#endif X X *ptr++ = '\n'; X *ptr = '\0'; X X /* X * Mimic syslog header X */ X show_time_host_and_name(lvl); X fwrite(msg, ptr - msg, 1, logfp); X fflush(logfp); X} X Xint bind_resv_port P((int so, u_short *pp)); Xint bind_resv_port(so, pp) Xint so; Xu_short *pp; X{ X struct sockaddr_in sin; X int rc; X unsigned short port; X X bzero((voidp) &sin, sizeof(sin)); X sin.sin_family = AF_INET; X X port = IPPORT_RESERVED; X X do { X --port; X sin.sin_port = htons(port); X rc = bind(so, (struct sockaddr *) &sin, sizeof(sin)); X } while (rc < 0 && port > IPPORT_RESERVED/2); X X if (pp && rc == 0) X *pp = port; X return rc; X} X Xvoid forcibly_timeout_mp P((am_node *mp)); Xvoid forcibly_timeout_mp(mp) Xam_node *mp; X{ X mntfs *mf = mp->am_mnt; X /* X * Arrange to timeout this node X */ X if (mf && ((mp->am_flags & AMF_ROOT) || X (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)))) { X if (!(mf->mf_flags & MFF_UNMOUNTING)) X plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path); X } else { X plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path); X mp->am_flags &= ~AMF_NOTIMEOUT; X mp->am_ttl = clocktime(); X reschedule_timeout_mp(); X } X} X Xvoid am_mounted P((am_node *mp)); Xvoid am_mounted(mp) Xam_node *mp; X{ X mntfs *mf = mp->am_mnt; X int quoted; X mf->mf_flags |= MFF_MOUNTED; X mf->mf_error = 0; X X /* X * Patch up path for direct mounts X */ X if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &dfs_ops) X mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", "."); X X /* X * Check whether this mount should be cached permanently X */ X if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) { X mp->am_flags |= AMF_NOTIMEOUT; X } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') { X mp->am_flags |= AMF_NOTIMEOUT; X } else { X struct mntent mnt; X mnt.mnt_opts = mf->mf_fo->opt_opts; X if (hasmntopt(&mnt, "nounmount")) X mp->am_flags |= AMF_NOTIMEOUT; X if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0) X mp->am_timeo = am_timeo; X/* if ((mf->mf_server->fs_pinger = hasmntval(&mnt, "ping")) == 0) X mf->mf_server->fs_pinger = AM_PINGER; X*/ X } X X /* X * Do mounted callback X */ X if (mf->mf_ops->mounted) X (*mf->mf_ops->mounted)(mf); X X /* X * If this node is a symlink then X * compute the length of the returned string. X */ X if (mf->mf_fattr.type == NFLNK) X mf->mf_fattr.size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount); X X /* X * Record mount time X */ X mp->am_stats.s_mtime = clocktime(); X new_ttl(mp); X X /* X * Log message X */ X quoted = strchr(mf->mf_info, ' ') != 0; X plog(XLOG_INFO, "%s%s%s mounted fstype %s on %s", X quoted ? "\"" : "", X mf->mf_info, X quoted ? "\"" : "", X mf->mf_ops->fs_type, mf->mf_mount); X X /* X * Update stats X */ X amd_stats.d_mok++; X} X Xint mount_node P((am_node *mp)); Xint mount_node(mp) Xam_node *mp; X{ X mntfs *mf = mp->am_mnt; X int error; X X mf->mf_flags |= MFF_MOUNTING; X error = (*mf->mf_ops->mount_fs)(mp); X mf = mp->am_mnt; X mf->mf_flags &= ~MFF_MOUNTING; X if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) { X /* ...but see ifs_mount */ X am_mounted(mp); X } X X return error; X} X Xvoid am_unmounted P((am_node *mp)); Xvoid am_unmounted(mp) Xam_node *mp; X{ X mntfs *mf = mp->am_mnt; X X if (!foreground) /* firewall - should never happen */ X return; X X#ifdef DEBUG X /*dlog("in am_unmounted(), foreground = %d", foreground);*/ X#endif X X /* X * Do unmounted callback X */ X if (mf->mf_ops->umounted) X (*mf->mf_ops->umounted)(mp); X X free_map(mp); X} X X X/* X * Fork the automounter X * X * TODO: Need a better strategy for handling errors X */ Xstatic int dofork(P_void); XINLINE Xstatic int dofork() X{ X int pid; Xtop: X pid = fork(); X X if (pid < 0) { X sleep(1); X goto top; X } X X if (pid == 0) { X mypid = getpid(); X foreground = 0; X } X X return pid; X} X Xint background(P_void); Xint background() X{ X int pid = dofork(); X if (pid == 0) { X#ifdef DEBUG X dlog("backgrounded"); X#endif X foreground = 0; X } X X return pid; X} X Xint mkdirs P((char *path, int mode)); Xint mkdirs(path, mode) Xchar *path; Xint mode; X{ X /* X * take a copy in case path is in readonly store X */ X char *p2 = strdup(path); X char *sp = p2; X struct stat stb; X int error_so_far = 0; X X /* X * Skip through the string make the directories. X * Mostly ignore errors - the result is tested at the end. X * X * This assumes we are root so that we can do mkdir in a X * mode 555 directory... X */ X while (sp = strchr(sp+1, '/')) { X *sp = '\0'; X if (mkdir(p2, mode) < 0) { X error_so_far = errno; X } else { X#ifdef DEBUG X dlog("mkdir(%s)", p2); X#endif X } X *sp = '/'; X } X X if (mkdir(p2, mode) < 0) { X error_so_far = errno; X } else { X#ifdef DEBUG X dlog("mkdir(%s)", p2); X#endif X } X X /* X * Do a sync - if we do rmdirs() immediately X * and then the system crashes it leaves X * the filesystem in a state that fsck -p X * can't fix. (Observed more than once on X * SunOS 4 ...) X * X * This is an attempted workaround - XXX. X */ X sync(); X X free(p2); X X return stat(path, &stb) == 0 && X (stb.st_mode & S_IFMT) == S_IFDIR ? 0 : error_so_far; X} X Xvoid rmdirs P((char *dir)); Xvoid rmdirs(dir) Xchar *dir; X{ X char *xdp = strdup(dir); X char *dp; X X do { X struct stat stb; X /* X * Try to find out whether this was X * created by amd. Do this by checking X * for owner write permission. X */ X if (stat(xdp, &stb) == 0 && (stb.st_mode & 0200) == 0) { X if (rmdir(xdp) < 0) { X if (errno != ENOTEMPTY && errno != EBUSY && errno != EEXIST) X plog(XLOG_ERROR, "rmdir(%s): %m", xdp); X break; X } else { X#ifdef DEBUG X dlog("rmdir(%s)", xdp); X#endif X } X } else { X break; X } X dp = strrchr(xdp, '/'); X if (dp) X *dp = '\0'; X } while (dp && dp > xdp); X free(xdp); X} X X/* X * Because the internal clock is only used for X * timing out mounts, it does not have to be X * particularly accurate, so long as it does not run X * ahead of the real time. So, to reduce the system X * call overhead, repeated calls to gettimeofday() X * are replaced by calls to the macro clocktime(). X * If the global time (clock_valid) is zero then X * update_clocktime() is called to obtain the real time. X * Before any system calls that are likely to block for a X * significant time, the clock_valid value is set X * so that the clock is recomputed next time it is X * needed. X */ X Xtime_t clock_valid = 0; X#ifndef clocktime Xtime_t clocktime(P_void) X{ X return time(&clock_valid); X} X#endif X Xvoidp xmalloc(len) Xint len; X{ X voidp p; X int retries = 600; X X do { X p = (voidp) malloc((unsigned) len); X if (p) { X#if defined(DEBUG) && defined(DEBUG_MEM) X Debug(D_MEM) plog(XLOG_DEBUG, "Allocated size %d; block %#x", len, p); X#endif X return p; X } X if (retries > 0) { X plog(XLOG_ERROR, "Retrying memory allocation"); X sleep(1); X } X } while (--retries); X X plog(XLOG_FATAL, "Out of memory"); X going_down(1); X X abort(); X X return 0; X} X X#if defined(DEBUG) && defined(DEBUG_MEM) Xxfree(f, l, p) Xchar *f; Xint l; Xvoidp p; X{ X Debug(D_MEM) plog(XLOG_DEBUG, "Free in %s:%d: block %#x", f, l, p); X#undef free X free(p); X} X#endif END_OF_FILE if test 15603 -ne `wc -c <'util.c'`; then echo shar: \"'util.c'\" unpacked with wrong size! fi # end of 'util.c' fi echo shar: End of archive 9 \(of 13\). cp /dev/null ark9isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 13 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.